From 38dd5348b37ce3086137c8126a9b22982115c020 Mon Sep 17 00:00:00 2001 From: Adrian Cole <64215+codefromthecrypt@users.noreply.github.com> Date: Mon, 9 Sep 2024 18:17:21 +0800 Subject: [PATCH 001/769] docs(readme): improve custom `base_url` example (#1694) OPENAI_BASE_URL defaults to https://api.openai.com/v1, so if you add a replacement and forget to append the /v1, it will result in 404s --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 525c1b5aaf..d0cc9040a5 100644 --- a/README.md +++ b/README.md @@ -567,7 +567,7 @@ from openai import OpenAI, DefaultHttpxClient client = OpenAI( # Or use the `OPENAI_BASE_URL` env var - base_url="http://my.test.server.example.com:8083", + base_url="http://my.test.server.example.com:8083/v1", http_client=DefaultHttpxClient( proxies="http://my.test.proxy.example.com", transport=httpx.HTTPTransport(local_address="0.0.0.0"), From 3cf4acc65466ae77cab9d622fe1b46cbfdf05d45 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 9 Sep 2024 14:31:32 +0000 Subject: [PATCH 002/769] chore: add docstrings to raw response properties (#1696) --- src/openai/resources/audio/audio.py | 22 +++++++++++++++++++ src/openai/resources/audio/speech.py | 22 +++++++++++++++++++ src/openai/resources/audio/transcriptions.py | 22 +++++++++++++++++++ src/openai/resources/audio/translations.py | 22 +++++++++++++++++++ src/openai/resources/batches.py | 22 +++++++++++++++++++ src/openai/resources/beta/assistants.py | 22 +++++++++++++++++++ src/openai/resources/beta/beta.py | 22 +++++++++++++++++++ src/openai/resources/beta/threads/messages.py | 22 +++++++++++++++++++ .../resources/beta/threads/runs/runs.py | 22 +++++++++++++++++++ .../resources/beta/threads/runs/steps.py | 22 +++++++++++++++++++ src/openai/resources/beta/threads/threads.py | 22 +++++++++++++++++++ .../beta/vector_stores/file_batches.py | 22 +++++++++++++++++++ .../resources/beta/vector_stores/files.py | 22 +++++++++++++++++++ .../beta/vector_stores/vector_stores.py | 22 +++++++++++++++++++ src/openai/resources/chat/chat.py | 22 +++++++++++++++++++ src/openai/resources/chat/completions.py | 22 +++++++++++++++++++ src/openai/resources/completions.py | 22 +++++++++++++++++++ src/openai/resources/embeddings.py | 22 +++++++++++++++++++ src/openai/resources/files.py | 22 +++++++++++++++++++ .../resources/fine_tuning/fine_tuning.py | 22 +++++++++++++++++++ .../resources/fine_tuning/jobs/checkpoints.py | 22 +++++++++++++++++++ src/openai/resources/fine_tuning/jobs/jobs.py | 22 +++++++++++++++++++ src/openai/resources/images.py | 22 +++++++++++++++++++ src/openai/resources/models.py | 22 +++++++++++++++++++ src/openai/resources/moderations.py | 22 +++++++++++++++++++ src/openai/resources/uploads/parts.py | 22 +++++++++++++++++++ src/openai/resources/uploads/uploads.py | 22 +++++++++++++++++++ 27 files changed, 594 insertions(+) diff --git a/src/openai/resources/audio/audio.py b/src/openai/resources/audio/audio.py index 537ad573d0..18bd7b812c 100644 --- a/src/openai/resources/audio/audio.py +++ b/src/openai/resources/audio/audio.py @@ -47,10 +47,21 @@ def speech(self) -> Speech: @cached_property def with_raw_response(self) -> AudioWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return AudioWithRawResponse(self) @cached_property def with_streaming_response(self) -> AudioWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return AudioWithStreamingResponse(self) @@ -69,10 +80,21 @@ def speech(self) -> AsyncSpeech: @cached_property def with_raw_response(self) -> AsyncAudioWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return AsyncAudioWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncAudioWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return AsyncAudioWithStreamingResponse(self) diff --git a/src/openai/resources/audio/speech.py b/src/openai/resources/audio/speech.py index a0df9ec487..6085ae8afe 100644 --- a/src/openai/resources/audio/speech.py +++ b/src/openai/resources/audio/speech.py @@ -31,10 +31,21 @@ class Speech(SyncAPIResource): @cached_property def with_raw_response(self) -> SpeechWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return SpeechWithRawResponse(self) @cached_property def with_streaming_response(self) -> SpeechWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return SpeechWithStreamingResponse(self) def create( @@ -104,10 +115,21 @@ def create( class AsyncSpeech(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncSpeechWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return AsyncSpeechWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncSpeechWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return AsyncSpeechWithStreamingResponse(self) async def create( diff --git a/src/openai/resources/audio/transcriptions.py b/src/openai/resources/audio/transcriptions.py index 1ee962411c..a6009143d4 100644 --- a/src/openai/resources/audio/transcriptions.py +++ b/src/openai/resources/audio/transcriptions.py @@ -29,10 +29,21 @@ class Transcriptions(SyncAPIResource): @cached_property def with_raw_response(self) -> TranscriptionsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return TranscriptionsWithRawResponse(self) @cached_property def with_streaming_response(self) -> TranscriptionsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return TranscriptionsWithStreamingResponse(self) def create( @@ -125,10 +136,21 @@ def create( class AsyncTranscriptions(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncTranscriptionsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return AsyncTranscriptionsWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncTranscriptionsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return AsyncTranscriptionsWithStreamingResponse(self) async def create( diff --git a/src/openai/resources/audio/translations.py b/src/openai/resources/audio/translations.py index ed97ccf840..7ec647fb6b 100644 --- a/src/openai/resources/audio/translations.py +++ b/src/openai/resources/audio/translations.py @@ -28,10 +28,21 @@ class Translations(SyncAPIResource): @cached_property def with_raw_response(self) -> TranslationsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return TranslationsWithRawResponse(self) @cached_property def with_streaming_response(self) -> TranslationsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return TranslationsWithStreamingResponse(self) def create( @@ -109,10 +120,21 @@ def create( class AsyncTranslations(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncTranslationsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return AsyncTranslationsWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncTranslationsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return AsyncTranslationsWithStreamingResponse(self) async def create( diff --git a/src/openai/resources/batches.py b/src/openai/resources/batches.py index 7152fac622..a8a0ba4bbc 100644 --- a/src/openai/resources/batches.py +++ b/src/openai/resources/batches.py @@ -30,10 +30,21 @@ class Batches(SyncAPIResource): @cached_property def with_raw_response(self) -> BatchesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return BatchesWithRawResponse(self) @cached_property def with_streaming_response(self) -> BatchesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return BatchesWithStreamingResponse(self) def create( @@ -224,10 +235,21 @@ def cancel( class AsyncBatches(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncBatchesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return AsyncBatchesWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncBatchesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return AsyncBatchesWithStreamingResponse(self) async def create( diff --git a/src/openai/resources/beta/assistants.py b/src/openai/resources/beta/assistants.py index 441390d24b..1e57944eb3 100644 --- a/src/openai/resources/beta/assistants.py +++ b/src/openai/resources/beta/assistants.py @@ -35,10 +35,21 @@ class Assistants(SyncAPIResource): @cached_property def with_raw_response(self) -> AssistantsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return AssistantsWithRawResponse(self) @cached_property def with_streaming_response(self) -> AssistantsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return AssistantsWithStreamingResponse(self) def create( @@ -410,10 +421,21 @@ def delete( class AsyncAssistants(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncAssistantsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return AsyncAssistantsWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncAssistantsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return AsyncAssistantsWithStreamingResponse(self) async def create( diff --git a/src/openai/resources/beta/beta.py b/src/openai/resources/beta/beta.py index 479c97c471..a7d3e707c8 100644 --- a/src/openai/resources/beta/beta.py +++ b/src/openai/resources/beta/beta.py @@ -54,10 +54,21 @@ def threads(self) -> Threads: @cached_property def with_raw_response(self) -> BetaWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return BetaWithRawResponse(self) @cached_property def with_streaming_response(self) -> BetaWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return BetaWithStreamingResponse(self) @@ -80,10 +91,21 @@ def threads(self) -> AsyncThreads: @cached_property def with_raw_response(self) -> AsyncBetaWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return AsyncBetaWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncBetaWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return AsyncBetaWithStreamingResponse(self) diff --git a/src/openai/resources/beta/threads/messages.py b/src/openai/resources/beta/threads/messages.py index f0832515ce..4901174329 100644 --- a/src/openai/resources/beta/threads/messages.py +++ b/src/openai/resources/beta/threads/messages.py @@ -32,10 +32,21 @@ class Messages(SyncAPIResource): @cached_property def with_raw_response(self) -> MessagesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return MessagesWithRawResponse(self) @cached_property def with_streaming_response(self) -> MessagesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return MessagesWithStreamingResponse(self) def create( @@ -295,10 +306,21 @@ def delete( class AsyncMessages(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncMessagesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return AsyncMessagesWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncMessagesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return AsyncMessagesWithStreamingResponse(self) async def create( diff --git a/src/openai/resources/beta/threads/runs/runs.py b/src/openai/resources/beta/threads/runs/runs.py index 4f39912e62..807027a644 100644 --- a/src/openai/resources/beta/threads/runs/runs.py +++ b/src/openai/resources/beta/threads/runs/runs.py @@ -63,10 +63,21 @@ def steps(self) -> Steps: @cached_property def with_raw_response(self) -> RunsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return RunsWithRawResponse(self) @cached_property def with_streaming_response(self) -> RunsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return RunsWithStreamingResponse(self) @overload @@ -1414,10 +1425,21 @@ def steps(self) -> AsyncSteps: @cached_property def with_raw_response(self) -> AsyncRunsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return AsyncRunsWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncRunsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return AsyncRunsWithStreamingResponse(self) @overload diff --git a/src/openai/resources/beta/threads/runs/steps.py b/src/openai/resources/beta/threads/runs/steps.py index 3d2d40a3fb..5d6d55f9d9 100644 --- a/src/openai/resources/beta/threads/runs/steps.py +++ b/src/openai/resources/beta/threads/runs/steps.py @@ -28,10 +28,21 @@ class Steps(SyncAPIResource): @cached_property def with_raw_response(self) -> StepsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return StepsWithRawResponse(self) @cached_property def with_streaming_response(self) -> StepsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return StepsWithStreamingResponse(self) def retrieve( @@ -171,10 +182,21 @@ def list( class AsyncSteps(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncStepsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return AsyncStepsWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncStepsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return AsyncStepsWithStreamingResponse(self) async def retrieve( diff --git a/src/openai/resources/beta/threads/threads.py b/src/openai/resources/beta/threads/threads.py index 4c95c484cc..031121e5cc 100644 --- a/src/openai/resources/beta/threads/threads.py +++ b/src/openai/resources/beta/threads/threads.py @@ -72,10 +72,21 @@ def messages(self) -> Messages: @cached_property def with_raw_response(self) -> ThreadsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return ThreadsWithRawResponse(self) @cached_property def with_streaming_response(self) -> ThreadsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return ThreadsWithStreamingResponse(self) def create( @@ -895,10 +906,21 @@ def messages(self) -> AsyncMessages: @cached_property def with_raw_response(self) -> AsyncThreadsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return AsyncThreadsWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncThreadsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return AsyncThreadsWithStreamingResponse(self) async def create( diff --git a/src/openai/resources/beta/vector_stores/file_batches.py b/src/openai/resources/beta/vector_stores/file_batches.py index a350ed0bea..d1f9c872e4 100644 --- a/src/openai/resources/beta/vector_stores/file_batches.py +++ b/src/openai/resources/beta/vector_stores/file_batches.py @@ -35,10 +35,21 @@ class FileBatches(SyncAPIResource): @cached_property def with_raw_response(self) -> FileBatchesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return FileBatchesWithRawResponse(self) @cached_property def with_streaming_response(self) -> FileBatchesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return FileBatchesWithStreamingResponse(self) def create( @@ -353,10 +364,21 @@ def upload_and_poll( class AsyncFileBatches(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncFileBatchesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return AsyncFileBatchesWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncFileBatchesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return AsyncFileBatchesWithStreamingResponse(self) async def create( diff --git a/src/openai/resources/beta/vector_stores/files.py b/src/openai/resources/beta/vector_stores/files.py index ba43519c75..fe43bb3488 100644 --- a/src/openai/resources/beta/vector_stores/files.py +++ b/src/openai/resources/beta/vector_stores/files.py @@ -31,10 +31,21 @@ class Files(SyncAPIResource): @cached_property def with_raw_response(self) -> FilesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return FilesWithRawResponse(self) @cached_property def with_streaming_response(self) -> FilesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return FilesWithStreamingResponse(self) def create( @@ -332,10 +343,21 @@ def upload_and_poll( class AsyncFiles(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncFilesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return AsyncFilesWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncFilesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return AsyncFilesWithStreamingResponse(self) async def create( diff --git a/src/openai/resources/beta/vector_stores/vector_stores.py b/src/openai/resources/beta/vector_stores/vector_stores.py index c93b3bc41f..06e26852b4 100644 --- a/src/openai/resources/beta/vector_stores/vector_stores.py +++ b/src/openai/resources/beta/vector_stores/vector_stores.py @@ -58,10 +58,21 @@ def file_batches(self) -> FileBatches: @cached_property def with_raw_response(self) -> VectorStoresWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return VectorStoresWithRawResponse(self) @cached_property def with_streaming_response(self) -> VectorStoresWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return VectorStoresWithStreamingResponse(self) def create( @@ -325,10 +336,21 @@ def file_batches(self) -> AsyncFileBatches: @cached_property def with_raw_response(self) -> AsyncVectorStoresWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return AsyncVectorStoresWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncVectorStoresWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return AsyncVectorStoresWithStreamingResponse(self) async def create( diff --git a/src/openai/resources/chat/chat.py b/src/openai/resources/chat/chat.py index d14d055506..dc23a15a8e 100644 --- a/src/openai/resources/chat/chat.py +++ b/src/openai/resources/chat/chat.py @@ -23,10 +23,21 @@ def completions(self) -> Completions: @cached_property def with_raw_response(self) -> ChatWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return ChatWithRawResponse(self) @cached_property def with_streaming_response(self) -> ChatWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return ChatWithStreamingResponse(self) @@ -37,10 +48,21 @@ def completions(self) -> AsyncCompletions: @cached_property def with_raw_response(self) -> AsyncChatWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return AsyncChatWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncChatWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return AsyncChatWithStreamingResponse(self) diff --git a/src/openai/resources/chat/completions.py b/src/openai/resources/chat/completions.py index dc577d6251..ec76bfdf52 100644 --- a/src/openai/resources/chat/completions.py +++ b/src/openai/resources/chat/completions.py @@ -36,10 +36,21 @@ class Completions(SyncAPIResource): @cached_property def with_raw_response(self) -> CompletionsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return CompletionsWithRawResponse(self) @cached_property def with_streaming_response(self) -> CompletionsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return CompletionsWithStreamingResponse(self) @overload @@ -707,10 +718,21 @@ def create( class AsyncCompletions(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncCompletionsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return AsyncCompletionsWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncCompletionsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return AsyncCompletionsWithStreamingResponse(self) @overload diff --git a/src/openai/resources/completions.py b/src/openai/resources/completions.py index 0812000f78..091fb5657a 100644 --- a/src/openai/resources/completions.py +++ b/src/openai/resources/completions.py @@ -31,10 +31,21 @@ class Completions(SyncAPIResource): @cached_property def with_raw_response(self) -> CompletionsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return CompletionsWithRawResponse(self) @cached_property def with_streaming_response(self) -> CompletionsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return CompletionsWithStreamingResponse(self) @overload @@ -562,10 +573,21 @@ def create( class AsyncCompletions(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncCompletionsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return AsyncCompletionsWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncCompletionsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return AsyncCompletionsWithStreamingResponse(self) @overload diff --git a/src/openai/resources/embeddings.py b/src/openai/resources/embeddings.py index 773b6f0968..71c2a18a24 100644 --- a/src/openai/resources/embeddings.py +++ b/src/openai/resources/embeddings.py @@ -27,10 +27,21 @@ class Embeddings(SyncAPIResource): @cached_property def with_raw_response(self) -> EmbeddingsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return EmbeddingsWithRawResponse(self) @cached_property def with_streaming_response(self) -> EmbeddingsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return EmbeddingsWithStreamingResponse(self) def create( @@ -128,10 +139,21 @@ def parser(obj: CreateEmbeddingResponse) -> CreateEmbeddingResponse: class AsyncEmbeddings(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncEmbeddingsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return AsyncEmbeddingsWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncEmbeddingsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return AsyncEmbeddingsWithStreamingResponse(self) async def create( diff --git a/src/openai/resources/files.py b/src/openai/resources/files.py index a240e1d886..e24eeec711 100644 --- a/src/openai/resources/files.py +++ b/src/openai/resources/files.py @@ -42,10 +42,21 @@ class Files(SyncAPIResource): @cached_property def with_raw_response(self) -> FilesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return FilesWithRawResponse(self) @cached_property def with_streaming_response(self) -> FilesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return FilesWithStreamingResponse(self) def create( @@ -324,10 +335,21 @@ def wait_for_processing( class AsyncFiles(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncFilesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return AsyncFilesWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncFilesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return AsyncFilesWithStreamingResponse(self) async def create( diff --git a/src/openai/resources/fine_tuning/fine_tuning.py b/src/openai/resources/fine_tuning/fine_tuning.py index 0404fed6ec..c386de3c2a 100644 --- a/src/openai/resources/fine_tuning/fine_tuning.py +++ b/src/openai/resources/fine_tuning/fine_tuning.py @@ -24,10 +24,21 @@ def jobs(self) -> Jobs: @cached_property def with_raw_response(self) -> FineTuningWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return FineTuningWithRawResponse(self) @cached_property def with_streaming_response(self) -> FineTuningWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return FineTuningWithStreamingResponse(self) @@ -38,10 +49,21 @@ def jobs(self) -> AsyncJobs: @cached_property def with_raw_response(self) -> AsyncFineTuningWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return AsyncFineTuningWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncFineTuningWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return AsyncFineTuningWithStreamingResponse(self) diff --git a/src/openai/resources/fine_tuning/jobs/checkpoints.py b/src/openai/resources/fine_tuning/jobs/checkpoints.py index 67f5739a02..8b5e905ea5 100644 --- a/src/openai/resources/fine_tuning/jobs/checkpoints.py +++ b/src/openai/resources/fine_tuning/jobs/checkpoints.py @@ -24,10 +24,21 @@ class Checkpoints(SyncAPIResource): @cached_property def with_raw_response(self) -> CheckpointsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return CheckpointsWithRawResponse(self) @cached_property def with_streaming_response(self) -> CheckpointsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return CheckpointsWithStreamingResponse(self) def list( @@ -84,10 +95,21 @@ def list( class AsyncCheckpoints(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncCheckpointsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return AsyncCheckpointsWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncCheckpointsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return AsyncCheckpointsWithStreamingResponse(self) def list( diff --git a/src/openai/resources/fine_tuning/jobs/jobs.py b/src/openai/resources/fine_tuning/jobs/jobs.py index 5cef7bcd22..ca4799e7ac 100644 --- a/src/openai/resources/fine_tuning/jobs/jobs.py +++ b/src/openai/resources/fine_tuning/jobs/jobs.py @@ -43,10 +43,21 @@ def checkpoints(self) -> Checkpoints: @cached_property def with_raw_response(self) -> JobsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return JobsWithRawResponse(self) @cached_property def with_streaming_response(self) -> JobsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return JobsWithStreamingResponse(self) def create( @@ -323,10 +334,21 @@ def checkpoints(self) -> AsyncCheckpoints: @cached_property def with_raw_response(self) -> AsyncJobsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return AsyncJobsWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncJobsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return AsyncJobsWithStreamingResponse(self) async def create( diff --git a/src/openai/resources/images.py b/src/openai/resources/images.py index 0913b572cb..e9629d48fd 100644 --- a/src/openai/resources/images.py +++ b/src/openai/resources/images.py @@ -29,10 +29,21 @@ class Images(SyncAPIResource): @cached_property def with_raw_response(self) -> ImagesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return ImagesWithRawResponse(self) @cached_property def with_streaming_response(self) -> ImagesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return ImagesWithStreamingResponse(self) def create_variation( @@ -275,10 +286,21 @@ def generate( class AsyncImages(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncImagesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return AsyncImagesWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncImagesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return AsyncImagesWithStreamingResponse(self) async def create_variation( diff --git a/src/openai/resources/models.py b/src/openai/resources/models.py index e76c496ffa..d6062de230 100644 --- a/src/openai/resources/models.py +++ b/src/openai/resources/models.py @@ -23,10 +23,21 @@ class Models(SyncAPIResource): @cached_property def with_raw_response(self) -> ModelsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return ModelsWithRawResponse(self) @cached_property def with_streaming_response(self) -> ModelsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return ModelsWithStreamingResponse(self) def retrieve( @@ -125,10 +136,21 @@ def delete( class AsyncModels(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncModelsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return AsyncModelsWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncModelsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return AsyncModelsWithStreamingResponse(self) async def retrieve( diff --git a/src/openai/resources/moderations.py b/src/openai/resources/moderations.py index b9ad9972f0..5283554373 100644 --- a/src/openai/resources/moderations.py +++ b/src/openai/resources/moderations.py @@ -26,10 +26,21 @@ class Moderations(SyncAPIResource): @cached_property def with_raw_response(self) -> ModerationsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return ModerationsWithRawResponse(self) @cached_property def with_streaming_response(self) -> ModerationsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return ModerationsWithStreamingResponse(self) def create( @@ -86,10 +97,21 @@ def create( class AsyncModerations(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncModerationsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return AsyncModerationsWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncModerationsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return AsyncModerationsWithStreamingResponse(self) async def create( diff --git a/src/openai/resources/uploads/parts.py b/src/openai/resources/uploads/parts.py index 3ec2592b1e..d46e5ea1bb 100644 --- a/src/openai/resources/uploads/parts.py +++ b/src/openai/resources/uploads/parts.py @@ -27,10 +27,21 @@ class Parts(SyncAPIResource): @cached_property def with_raw_response(self) -> PartsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return PartsWithRawResponse(self) @cached_property def with_streaming_response(self) -> PartsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return PartsWithStreamingResponse(self) def create( @@ -91,10 +102,21 @@ def create( class AsyncParts(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncPartsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return AsyncPartsWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncPartsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return AsyncPartsWithStreamingResponse(self) async def create( diff --git a/src/openai/resources/uploads/uploads.py b/src/openai/resources/uploads/uploads.py index 5eecef4d4b..96a531a8e4 100644 --- a/src/openai/resources/uploads/uploads.py +++ b/src/openai/resources/uploads/uploads.py @@ -50,10 +50,21 @@ def parts(self) -> Parts: @cached_property def with_raw_response(self) -> UploadsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return UploadsWithRawResponse(self) @cached_property def with_streaming_response(self) -> UploadsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return UploadsWithStreamingResponse(self) @overload @@ -332,10 +343,21 @@ def parts(self) -> AsyncParts: @cached_property def with_raw_response(self) -> AsyncUploadsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ return AsyncUploadsWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncUploadsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ return AsyncUploadsWithStreamingResponse(self) @overload From fee1040459c4c7b2dbfd43fa2c85192cd3e2eae0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 9 Sep 2024 14:41:46 +0000 Subject: [PATCH 003/769] docs(readme): add section on determining installed version (#1697) --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index d0cc9040a5..8c73fdd82a 100644 --- a/README.md +++ b/README.md @@ -639,6 +639,17 @@ We take backwards-compatibility seriously and work hard to ensure you can rely o We are keen for your feedback; please open an [issue](https://www.github.com/openai/openai-python/issues) with questions, bugs, or suggestions. +### Determining the installed version + +If you've upgraded to the latest version but aren't seeing any new features you were expecting then your python environment is likely still using an older version. + +You can determine the version that is being used at runtime with: + +```py +import openai +print(openai.__version__) +``` + ## Requirements Python 3.7 or higher. From 6b07089ae031d64805c2e5eb6a33624ff0e64e84 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 9 Sep 2024 14:42:18 +0000 Subject: [PATCH 004/769] release: 1.44.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 14 ++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index ba2c5854ee..1ee5dee6dd 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.44.0" + ".": "1.44.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 849d7b5e0b..47fa2d9208 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## 1.44.1 (2024-09-09) + +Full Changelog: [v1.44.0...v1.44.1](https://github.com/openai/openai-python/compare/v1.44.0...v1.44.1) + +### Chores + +* add docstrings to raw response properties ([#1696](https://github.com/openai/openai-python/issues/1696)) ([1d2a19b](https://github.com/openai/openai-python/commit/1d2a19b0e8acab54c35ef2171d33321943488fdc)) + + +### Documentation + +* **readme:** add section on determining installed version ([#1697](https://github.com/openai/openai-python/issues/1697)) ([0255735](https://github.com/openai/openai-python/commit/0255735930d9c657c78e85e7f03fd1eb98a1e378)) +* **readme:** improve custom `base_url` example ([#1694](https://github.com/openai/openai-python/issues/1694)) ([05eec8a](https://github.com/openai/openai-python/commit/05eec8a0b7fcdc8651021f2e685214a353b861d1)) + ## 1.44.0 (2024-09-06) Full Changelog: [v1.43.1...v1.44.0](https://github.com/openai/openai-python/compare/v1.43.1...v1.44.0) diff --git a/pyproject.toml b/pyproject.toml index 5d9d09e7da..d4b7d2b210 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.44.0" +version = "1.44.1" 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 6be1f93a0f..39c7f63e1e 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.44.0" # x-release-please-version +__version__ = "1.44.1" # x-release-please-version From 23b96159c080d6c9b413a69548d325aa40315b95 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Tue, 10 Sep 2024 16:46:51 +0100 Subject: [PATCH 005/769] feat(errors): include completion in LengthFinishReasonError (#1701) --- src/openai/_exceptions.py | 23 +++++++++++++++---- src/openai/lib/_parsing/_completions.py | 2 +- src/openai/lib/streaming/chat/_completions.py | 4 +++- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/openai/_exceptions.py b/src/openai/_exceptions.py index f44f90b52f..e326ed9578 100644 --- a/src/openai/_exceptions.py +++ b/src/openai/_exceptions.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Any, Optional, cast +from typing import TYPE_CHECKING, Any, Optional, cast from typing_extensions import Literal import httpx @@ -10,6 +10,9 @@ from ._utils import is_dict from ._models import construct_type +if TYPE_CHECKING: + from .types.chat import ChatCompletion + __all__ = [ "BadRequestError", "AuthenticationError", @@ -130,10 +133,20 @@ class InternalServerError(APIStatusError): class LengthFinishReasonError(OpenAIError): - def __init__(self) -> None: - super().__init__( - f"Could not parse response content as the length limit was reached", - ) + completion: ChatCompletion + """The completion that caused this error. + + Note: this will *not* be a complete `ChatCompletion` object when streaming as `usage` + will not be included. + """ + + def __init__(self, *, completion: ChatCompletion) -> None: + msg = "Could not parse response content as the length limit was reached" + if completion.usage: + msg += f" - {completion.usage}" + + super().__init__(msg) + self.completion = completion class ContentFilterFinishReasonError(OpenAIError): diff --git a/src/openai/lib/_parsing/_completions.py b/src/openai/lib/_parsing/_completions.py index 2ef1bf3553..f1fa9f2b55 100644 --- a/src/openai/lib/_parsing/_completions.py +++ b/src/openai/lib/_parsing/_completions.py @@ -69,7 +69,7 @@ def parse_chat_completion( choices: list[ParsedChoice[ResponseFormatT]] = [] for choice in chat_completion.choices: if choice.finish_reason == "length": - raise LengthFinishReasonError() + raise LengthFinishReasonError(completion=chat_completion) if choice.finish_reason == "content_filter": raise ContentFilterFinishReasonError() diff --git a/src/openai/lib/streaming/chat/_completions.py b/src/openai/lib/streaming/chat/_completions.py index 342a5e2b95..a4b0f856f7 100644 --- a/src/openai/lib/streaming/chat/_completions.py +++ b/src/openai/lib/streaming/chat/_completions.py @@ -394,7 +394,9 @@ def _accumulate_chunk(self, chunk: ChatCompletionChunk) -> ParsedChatCompletionS if has_parseable_input(response_format=self._response_format, input_tools=self._input_tools): if choice.finish_reason == "length": - raise LengthFinishReasonError() + # at the time of writing, `.usage` will always be `None` but + # we include it here in case that is changed in the future + raise LengthFinishReasonError(completion=completion_snapshot) if choice.finish_reason == "content_filter": raise ContentFilterFinishReasonError() From a6e9db84c1952c856c8449536714b7a7daa22d2e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 12 Sep 2024 14:11:58 +0000 Subject: [PATCH 006/769] fix(types): correctly mark stream discriminator as optional (#1706) --- src/openai/types/beta/thread_create_and_run_params.py | 2 +- src/openai/types/beta/threads/run_create_params.py | 2 +- src/openai/types/beta/threads/run_submit_tool_outputs_params.py | 2 +- src/openai/types/chat/completion_create_params.py | 2 +- src/openai/types/completion_create_params.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/openai/types/beta/thread_create_and_run_params.py b/src/openai/types/beta/thread_create_and_run_params.py index cd3d9f29d4..370c2f9bce 100644 --- a/src/openai/types/beta/thread_create_and_run_params.py +++ b/src/openai/types/beta/thread_create_and_run_params.py @@ -332,7 +332,7 @@ class TruncationStrategy(TypedDict, total=False): """ -class ThreadCreateAndRunParamsNonStreaming(ThreadCreateAndRunParamsBase): +class ThreadCreateAndRunParamsNonStreaming(ThreadCreateAndRunParamsBase, total=False): stream: Optional[Literal[False]] """ If `true`, returns a stream of events that happen during the Run as server-sent diff --git a/src/openai/types/beta/threads/run_create_params.py b/src/openai/types/beta/threads/run_create_params.py index 8bb73ddc78..7c5f571d58 100644 --- a/src/openai/types/beta/threads/run_create_params.py +++ b/src/openai/types/beta/threads/run_create_params.py @@ -225,7 +225,7 @@ class TruncationStrategy(TypedDict, total=False): """ -class RunCreateParamsNonStreaming(RunCreateParamsBase): +class RunCreateParamsNonStreaming(RunCreateParamsBase, total=False): stream: Optional[Literal[False]] """ If `true`, returns a stream of events that happen during the Run as server-sent diff --git a/src/openai/types/beta/threads/run_submit_tool_outputs_params.py b/src/openai/types/beta/threads/run_submit_tool_outputs_params.py index ccb5e5e97e..147728603a 100644 --- a/src/openai/types/beta/threads/run_submit_tool_outputs_params.py +++ b/src/openai/types/beta/threads/run_submit_tool_outputs_params.py @@ -31,7 +31,7 @@ class ToolOutput(TypedDict, total=False): """ -class RunSubmitToolOutputsParamsNonStreaming(RunSubmitToolOutputsParamsBase): +class RunSubmitToolOutputsParamsNonStreaming(RunSubmitToolOutputsParamsBase, total=False): stream: Optional[Literal[False]] """ If `true`, returns a stream of events that happen during the Run as server-sent diff --git a/src/openai/types/chat/completion_create_params.py b/src/openai/types/chat/completion_create_params.py index 91435dcedd..b86dab742b 100644 --- a/src/openai/types/chat/completion_create_params.py +++ b/src/openai/types/chat/completion_create_params.py @@ -262,7 +262,7 @@ class Function(TypedDict, total=False): ResponseFormat: TypeAlias = Union[ResponseFormatText, ResponseFormatJSONObject, ResponseFormatJSONSchema] -class CompletionCreateParamsNonStreaming(CompletionCreateParamsBase): +class CompletionCreateParamsNonStreaming(CompletionCreateParamsBase, total=False): stream: Optional[Literal[False]] """If set, partial message deltas will be sent, like in ChatGPT. diff --git a/src/openai/types/completion_create_params.py b/src/openai/types/completion_create_params.py index 9fe22fe3c9..6c112b3902 100644 --- a/src/openai/types/completion_create_params.py +++ b/src/openai/types/completion_create_params.py @@ -160,7 +160,7 @@ class CompletionCreateParamsBase(TypedDict, total=False): """ -class CompletionCreateParamsNonStreaming(CompletionCreateParamsBase): +class CompletionCreateParamsNonStreaming(CompletionCreateParamsBase, total=False): stream: Optional[Literal[False]] """Whether to stream back partial progress. From 2bfec1a2f0be308053924ba673398cd18a038422 Mon Sep 17 00:00:00 2001 From: Stainless Bot Date: Thu, 12 Sep 2024 16:54:32 +0000 Subject: [PATCH 007/769] feat(api): add o1 models (#1708) See https://platform.openai.com/docs/guides/reasoning for details. --- .stats.yml | 2 +- src/openai/resources/beta/assistants.py | 24 +-- src/openai/resources/beta/chat/completions.py | 8 + .../resources/beta/threads/runs/runs.py | 36 ++-- src/openai/resources/beta/threads/threads.py | 36 ++-- src/openai/resources/chat/completions.py | 172 ++++++++++++------ src/openai/resources/fine_tuning/jobs/jobs.py | 4 +- src/openai/types/beta/assistant.py | 6 +- .../types/beta/assistant_create_params.py | 6 +- .../types/beta/assistant_update_params.py | 6 +- src/openai/types/beta/file_search_tool.py | 15 +- .../types/beta/file_search_tool_param.py | 15 +- .../beta/thread_create_and_run_params.py | 6 +- src/openai/types/beta/threads/run.py | 6 +- .../types/beta/threads/run_create_params.py | 6 +- .../types/chat/completion_create_params.py | 30 ++- src/openai/types/chat_model.py | 7 +- src/openai/types/completion_usage.py | 11 +- .../types/fine_tuning/job_create_params.py | 2 +- tests/api_resources/chat/test_completions.py | 4 + tests/lib/chat/test_completions.py | 8 +- tests/lib/chat/test_completions_streaming.py | 2 +- 22 files changed, 253 insertions(+), 159 deletions(-) diff --git a/.stats.yml b/.stats.yml index 903c159960..de3167f3a8 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 68 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-85a85e0c08de456441431c0ae4e9c078cc8f9748c29430b9a9058340db6389ee.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-501122aa32adaa2abb3d4487880ab9cdf2141addce2e6c3d1bd9bb6b44c318a8.yml diff --git a/src/openai/resources/beta/assistants.py b/src/openai/resources/beta/assistants.py index 1e57944eb3..5d8c6ec331 100644 --- a/src/openai/resources/beta/assistants.py +++ b/src/openai/resources/beta/assistants.py @@ -100,11 +100,11 @@ def create( and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which guarantees the model will match your supplied JSON schema. Learn - more in the + Outputs which ensures the model will match your supplied JSON schema. Learn more + in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the + Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the message the model generates is valid JSON. **Important:** when using JSON mode, you **must** also instruct the model to @@ -250,11 +250,11 @@ def update( and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which guarantees the model will match your supplied JSON schema. Learn - more in the + Outputs which ensures the model will match your supplied JSON schema. Learn more + in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the + Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the message the model generates is valid JSON. **Important:** when using JSON mode, you **must** also instruct the model to @@ -486,11 +486,11 @@ async def create( and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which guarantees the model will match your supplied JSON schema. Learn - more in the + Outputs which ensures the model will match your supplied JSON schema. Learn more + in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the + Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the message the model generates is valid JSON. **Important:** when using JSON mode, you **must** also instruct the model to @@ -636,11 +636,11 @@ async def update( and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which guarantees the model will match your supplied JSON schema. Learn - more in the + Outputs which ensures the model will match your supplied JSON schema. Learn more + in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the + Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the message the model generates is valid JSON. **Important:** when using JSON mode, you **must** also instruct the model to diff --git a/src/openai/resources/beta/chat/completions.py b/src/openai/resources/beta/chat/completions.py index 07eda27b76..ea3526778d 100644 --- a/src/openai/resources/beta/chat/completions.py +++ b/src/openai/resources/beta/chat/completions.py @@ -42,6 +42,7 @@ def parse( functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, logprobs: Optional[bool] | NotGiven = NOT_GIVEN, + max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, @@ -121,6 +122,7 @@ class MathResponse(BaseModel): functions=functions, logit_bias=logit_bias, logprobs=logprobs, + max_completion_tokens=max_completion_tokens, max_tokens=max_tokens, n=n, parallel_tool_calls=parallel_tool_calls, @@ -157,6 +159,7 @@ def stream( functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, logprobs: Optional[bool] | NotGiven = NOT_GIVEN, + max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, @@ -216,6 +219,7 @@ def stream( functions=functions, logit_bias=logit_bias, logprobs=logprobs, + max_completion_tokens=max_completion_tokens, max_tokens=max_tokens, n=n, parallel_tool_calls=parallel_tool_calls, @@ -254,6 +258,7 @@ async def parse( functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, logprobs: Optional[bool] | NotGiven = NOT_GIVEN, + max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, @@ -333,6 +338,7 @@ class MathResponse(BaseModel): functions=functions, logit_bias=logit_bias, logprobs=logprobs, + max_completion_tokens=max_completion_tokens, max_tokens=max_tokens, n=n, parallel_tool_calls=parallel_tool_calls, @@ -369,6 +375,7 @@ def stream( functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, logprobs: Optional[bool] | NotGiven = NOT_GIVEN, + max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, @@ -429,6 +436,7 @@ def stream( functions=functions, logit_bias=logit_bias, logprobs=logprobs, + max_completion_tokens=max_completion_tokens, max_tokens=max_tokens, n=n, parallel_tool_calls=parallel_tool_calls, diff --git a/src/openai/resources/beta/threads/runs/runs.py b/src/openai/resources/beta/threads/runs/runs.py index 807027a644..3fb1cc77aa 100644 --- a/src/openai/resources/beta/threads/runs/runs.py +++ b/src/openai/resources/beta/threads/runs/runs.py @@ -167,11 +167,11 @@ def create( and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which guarantees the model will match your supplied JSON schema. Learn - more in the + Outputs which ensures the model will match your supplied JSON schema. Learn more + in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the + Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the message the model generates is valid JSON. **Important:** when using JSON mode, you **must** also instruct the model to @@ -311,11 +311,11 @@ def create( and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which guarantees the model will match your supplied JSON schema. Learn - more in the + Outputs which ensures the model will match your supplied JSON schema. Learn more + in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the + Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the message the model generates is valid JSON. **Important:** when using JSON mode, you **must** also instruct the model to @@ -451,11 +451,11 @@ def create( and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which guarantees the model will match your supplied JSON schema. Learn - more in the + Outputs which ensures the model will match your supplied JSON schema. Learn more + in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the + Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the message the model generates is valid JSON. **Important:** when using JSON mode, you **must** also instruct the model to @@ -1529,11 +1529,11 @@ async def create( and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which guarantees the model will match your supplied JSON schema. Learn - more in the + Outputs which ensures the model will match your supplied JSON schema. Learn more + in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the + Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the message the model generates is valid JSON. **Important:** when using JSON mode, you **must** also instruct the model to @@ -1673,11 +1673,11 @@ async def create( and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which guarantees the model will match your supplied JSON schema. Learn - more in the + Outputs which ensures the model will match your supplied JSON schema. Learn more + in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the + Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the message the model generates is valid JSON. **Important:** when using JSON mode, you **must** also instruct the model to @@ -1813,11 +1813,11 @@ async def create( and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which guarantees the model will match your supplied JSON schema. Learn - more in the + Outputs which ensures the model will match your supplied JSON schema. Learn more + in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the + Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the message the model generates is valid JSON. **Important:** when using JSON mode, you **must** also instruct the model to diff --git a/src/openai/resources/beta/threads/threads.py b/src/openai/resources/beta/threads/threads.py index 031121e5cc..49b0e4b37e 100644 --- a/src/openai/resources/beta/threads/threads.py +++ b/src/openai/resources/beta/threads/threads.py @@ -335,11 +335,11 @@ def create_and_run( and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which guarantees the model will match your supplied JSON schema. Learn - more in the + Outputs which ensures the model will match your supplied JSON schema. Learn more + in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the + Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the message the model generates is valid JSON. **Important:** when using JSON mode, you **must** also instruct the model to @@ -469,11 +469,11 @@ def create_and_run( and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which guarantees the model will match your supplied JSON schema. Learn - more in the + Outputs which ensures the model will match your supplied JSON schema. Learn more + in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the + Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the message the model generates is valid JSON. **Important:** when using JSON mode, you **must** also instruct the model to @@ -599,11 +599,11 @@ def create_and_run( and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which guarantees the model will match your supplied JSON schema. Learn - more in the + Outputs which ensures the model will match your supplied JSON schema. Learn more + in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the + Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the message the model generates is valid JSON. **Important:** when using JSON mode, you **must** also instruct the model to @@ -1169,11 +1169,11 @@ async def create_and_run( and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which guarantees the model will match your supplied JSON schema. Learn - more in the + Outputs which ensures the model will match your supplied JSON schema. Learn more + in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the + Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the message the model generates is valid JSON. **Important:** when using JSON mode, you **must** also instruct the model to @@ -1303,11 +1303,11 @@ async def create_and_run( and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which guarantees the model will match your supplied JSON schema. Learn - more in the + Outputs which ensures the model will match your supplied JSON schema. Learn more + in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the + Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the message the model generates is valid JSON. **Important:** when using JSON mode, you **must** also instruct the model to @@ -1433,11 +1433,11 @@ async def create_and_run( and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which guarantees the model will match your supplied JSON schema. Learn - more in the + Outputs which ensures the model will match your supplied JSON schema. Learn more + in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the + Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the message the model generates is valid JSON. **Important:** when using JSON mode, you **must** also instruct the model to diff --git a/src/openai/resources/chat/completions.py b/src/openai/resources/chat/completions.py index ec76bfdf52..e9267b1f03 100644 --- a/src/openai/resources/chat/completions.py +++ b/src/openai/resources/chat/completions.py @@ -64,6 +64,7 @@ def create( functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, logprobs: Optional[bool] | NotGiven = NOT_GIVEN, + max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, @@ -132,13 +133,17 @@ def create( returns the log probabilities of each output token returned in the `content` of `message`. + max_completion_tokens: An upper bound for the number of tokens that can be generated for a completion, + including visible output tokens and + [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). + max_tokens: The maximum number of [tokens](/tokenizer) that can be generated in the chat - completion. + completion. This value can be used to control + [costs](https://openai.com/api/pricing/) for text generated via API. - The total length of input tokens and generated tokens is limited by the model's - context length. - [Example Python code](https://cookbook.openai.com/examples/how_to_count_tokens_with_tiktoken) - for counting tokens. + This value is now deprecated in favor of `max_completion_tokens`, and is not + compatible with + [o1 series models](https://platform.openai.com/docs/guides/reasoning). n: How many chat completion choices to generate for each input message. Note that you will be charged based on the number of generated tokens across all of the @@ -161,11 +166,11 @@ def create( all GPT-3.5 Turbo models newer than `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which guarantees the model will match your supplied JSON schema. Learn - more in the + Outputs which ensures the model will match your supplied JSON schema. Learn more + in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the + Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the message the model generates is valid JSON. **Important:** when using JSON mode, you **must** also instruct the model to @@ -185,8 +190,11 @@ def create( service_tier: Specifies the latency tier to use for processing the request. This parameter is relevant for customers subscribed to the scale tier service: - - If set to 'auto', the system will utilize scale tier credits until they are - exhausted. + - If set to 'auto', and the Project is Scale tier enabled, the system will + utilize scale tier credits until they are exhausted. + - If set to 'auto', and the Project is not Scale tier enabled, the request will + be processed using the default service tier with a lower uptime SLA and no + latency guarentee. - If set to 'default', the request will be processed using the default service tier with a lower uptime SLA and no latency guarentee. - When not set, the default behavior is 'auto'. @@ -261,6 +269,7 @@ def create( functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, logprobs: Optional[bool] | NotGiven = NOT_GIVEN, + max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, @@ -335,13 +344,17 @@ def create( returns the log probabilities of each output token returned in the `content` of `message`. + max_completion_tokens: An upper bound for the number of tokens that can be generated for a completion, + including visible output tokens and + [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). + max_tokens: The maximum number of [tokens](/tokenizer) that can be generated in the chat - completion. + completion. This value can be used to control + [costs](https://openai.com/api/pricing/) for text generated via API. - The total length of input tokens and generated tokens is limited by the model's - context length. - [Example Python code](https://cookbook.openai.com/examples/how_to_count_tokens_with_tiktoken) - for counting tokens. + This value is now deprecated in favor of `max_completion_tokens`, and is not + compatible with + [o1 series models](https://platform.openai.com/docs/guides/reasoning). n: How many chat completion choices to generate for each input message. Note that you will be charged based on the number of generated tokens across all of the @@ -364,11 +377,11 @@ def create( all GPT-3.5 Turbo models newer than `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which guarantees the model will match your supplied JSON schema. Learn - more in the + Outputs which ensures the model will match your supplied JSON schema. Learn more + in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the + Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the message the model generates is valid JSON. **Important:** when using JSON mode, you **must** also instruct the model to @@ -388,8 +401,11 @@ def create( service_tier: Specifies the latency tier to use for processing the request. This parameter is relevant for customers subscribed to the scale tier service: - - If set to 'auto', the system will utilize scale tier credits until they are - exhausted. + - If set to 'auto', and the Project is Scale tier enabled, the system will + utilize scale tier credits until they are exhausted. + - If set to 'auto', and the Project is not Scale tier enabled, the request will + be processed using the default service tier with a lower uptime SLA and no + latency guarentee. - If set to 'default', the request will be processed using the default service tier with a lower uptime SLA and no latency guarentee. - When not set, the default behavior is 'auto'. @@ -457,6 +473,7 @@ def create( functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, logprobs: Optional[bool] | NotGiven = NOT_GIVEN, + max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, @@ -531,13 +548,17 @@ def create( returns the log probabilities of each output token returned in the `content` of `message`. + max_completion_tokens: An upper bound for the number of tokens that can be generated for a completion, + including visible output tokens and + [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). + max_tokens: The maximum number of [tokens](/tokenizer) that can be generated in the chat - completion. + completion. This value can be used to control + [costs](https://openai.com/api/pricing/) for text generated via API. - The total length of input tokens and generated tokens is limited by the model's - context length. - [Example Python code](https://cookbook.openai.com/examples/how_to_count_tokens_with_tiktoken) - for counting tokens. + This value is now deprecated in favor of `max_completion_tokens`, and is not + compatible with + [o1 series models](https://platform.openai.com/docs/guides/reasoning). n: How many chat completion choices to generate for each input message. Note that you will be charged based on the number of generated tokens across all of the @@ -560,11 +581,11 @@ def create( all GPT-3.5 Turbo models newer than `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which guarantees the model will match your supplied JSON schema. Learn - more in the + Outputs which ensures the model will match your supplied JSON schema. Learn more + in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the + Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the message the model generates is valid JSON. **Important:** when using JSON mode, you **must** also instruct the model to @@ -584,8 +605,11 @@ def create( service_tier: Specifies the latency tier to use for processing the request. This parameter is relevant for customers subscribed to the scale tier service: - - If set to 'auto', the system will utilize scale tier credits until they are - exhausted. + - If set to 'auto', and the Project is Scale tier enabled, the system will + utilize scale tier credits until they are exhausted. + - If set to 'auto', and the Project is not Scale tier enabled, the request will + be processed using the default service tier with a lower uptime SLA and no + latency guarentee. - If set to 'default', the request will be processed using the default service tier with a lower uptime SLA and no latency guarentee. - When not set, the default behavior is 'auto'. @@ -652,6 +676,7 @@ def create( functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, logprobs: Optional[bool] | NotGiven = NOT_GIVEN, + max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, @@ -687,6 +712,7 @@ def create( "functions": functions, "logit_bias": logit_bias, "logprobs": logprobs, + "max_completion_tokens": max_completion_tokens, "max_tokens": max_tokens, "n": n, "parallel_tool_calls": parallel_tool_calls, @@ -746,6 +772,7 @@ async def create( functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, logprobs: Optional[bool] | NotGiven = NOT_GIVEN, + max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, @@ -814,13 +841,17 @@ async def create( returns the log probabilities of each output token returned in the `content` of `message`. + max_completion_tokens: An upper bound for the number of tokens that can be generated for a completion, + including visible output tokens and + [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). + max_tokens: The maximum number of [tokens](/tokenizer) that can be generated in the chat - completion. + completion. This value can be used to control + [costs](https://openai.com/api/pricing/) for text generated via API. - The total length of input tokens and generated tokens is limited by the model's - context length. - [Example Python code](https://cookbook.openai.com/examples/how_to_count_tokens_with_tiktoken) - for counting tokens. + This value is now deprecated in favor of `max_completion_tokens`, and is not + compatible with + [o1 series models](https://platform.openai.com/docs/guides/reasoning). n: How many chat completion choices to generate for each input message. Note that you will be charged based on the number of generated tokens across all of the @@ -843,11 +874,11 @@ async def create( all GPT-3.5 Turbo models newer than `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which guarantees the model will match your supplied JSON schema. Learn - more in the + Outputs which ensures the model will match your supplied JSON schema. Learn more + in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the + Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the message the model generates is valid JSON. **Important:** when using JSON mode, you **must** also instruct the model to @@ -867,8 +898,11 @@ async def create( service_tier: Specifies the latency tier to use for processing the request. This parameter is relevant for customers subscribed to the scale tier service: - - If set to 'auto', the system will utilize scale tier credits until they are - exhausted. + - If set to 'auto', and the Project is Scale tier enabled, the system will + utilize scale tier credits until they are exhausted. + - If set to 'auto', and the Project is not Scale tier enabled, the request will + be processed using the default service tier with a lower uptime SLA and no + latency guarentee. - If set to 'default', the request will be processed using the default service tier with a lower uptime SLA and no latency guarentee. - When not set, the default behavior is 'auto'. @@ -943,6 +977,7 @@ async def create( functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, logprobs: Optional[bool] | NotGiven = NOT_GIVEN, + max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, @@ -1017,13 +1052,17 @@ async def create( returns the log probabilities of each output token returned in the `content` of `message`. + max_completion_tokens: An upper bound for the number of tokens that can be generated for a completion, + including visible output tokens and + [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). + max_tokens: The maximum number of [tokens](/tokenizer) that can be generated in the chat - completion. + completion. This value can be used to control + [costs](https://openai.com/api/pricing/) for text generated via API. - The total length of input tokens and generated tokens is limited by the model's - context length. - [Example Python code](https://cookbook.openai.com/examples/how_to_count_tokens_with_tiktoken) - for counting tokens. + This value is now deprecated in favor of `max_completion_tokens`, and is not + compatible with + [o1 series models](https://platform.openai.com/docs/guides/reasoning). n: How many chat completion choices to generate for each input message. Note that you will be charged based on the number of generated tokens across all of the @@ -1046,11 +1085,11 @@ async def create( all GPT-3.5 Turbo models newer than `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which guarantees the model will match your supplied JSON schema. Learn - more in the + Outputs which ensures the model will match your supplied JSON schema. Learn more + in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the + Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the message the model generates is valid JSON. **Important:** when using JSON mode, you **must** also instruct the model to @@ -1070,8 +1109,11 @@ async def create( service_tier: Specifies the latency tier to use for processing the request. This parameter is relevant for customers subscribed to the scale tier service: - - If set to 'auto', the system will utilize scale tier credits until they are - exhausted. + - If set to 'auto', and the Project is Scale tier enabled, the system will + utilize scale tier credits until they are exhausted. + - If set to 'auto', and the Project is not Scale tier enabled, the request will + be processed using the default service tier with a lower uptime SLA and no + latency guarentee. - If set to 'default', the request will be processed using the default service tier with a lower uptime SLA and no latency guarentee. - When not set, the default behavior is 'auto'. @@ -1139,6 +1181,7 @@ async def create( functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, logprobs: Optional[bool] | NotGiven = NOT_GIVEN, + max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, @@ -1213,13 +1256,17 @@ async def create( returns the log probabilities of each output token returned in the `content` of `message`. + max_completion_tokens: An upper bound for the number of tokens that can be generated for a completion, + including visible output tokens and + [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). + max_tokens: The maximum number of [tokens](/tokenizer) that can be generated in the chat - completion. + completion. This value can be used to control + [costs](https://openai.com/api/pricing/) for text generated via API. - The total length of input tokens and generated tokens is limited by the model's - context length. - [Example Python code](https://cookbook.openai.com/examples/how_to_count_tokens_with_tiktoken) - for counting tokens. + This value is now deprecated in favor of `max_completion_tokens`, and is not + compatible with + [o1 series models](https://platform.openai.com/docs/guides/reasoning). n: How many chat completion choices to generate for each input message. Note that you will be charged based on the number of generated tokens across all of the @@ -1242,11 +1289,11 @@ async def create( all GPT-3.5 Turbo models newer than `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which guarantees the model will match your supplied JSON schema. Learn - more in the + Outputs which ensures the model will match your supplied JSON schema. Learn more + in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the + Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the message the model generates is valid JSON. **Important:** when using JSON mode, you **must** also instruct the model to @@ -1266,8 +1313,11 @@ async def create( service_tier: Specifies the latency tier to use for processing the request. This parameter is relevant for customers subscribed to the scale tier service: - - If set to 'auto', the system will utilize scale tier credits until they are - exhausted. + - If set to 'auto', and the Project is Scale tier enabled, the system will + utilize scale tier credits until they are exhausted. + - If set to 'auto', and the Project is not Scale tier enabled, the request will + be processed using the default service tier with a lower uptime SLA and no + latency guarentee. - If set to 'default', the request will be processed using the default service tier with a lower uptime SLA and no latency guarentee. - When not set, the default behavior is 'auto'. @@ -1334,6 +1384,7 @@ async def create( functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, logprobs: Optional[bool] | NotGiven = NOT_GIVEN, + max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, @@ -1369,6 +1420,7 @@ async def create( "functions": functions, "logit_bias": logit_bias, "logprobs": logprobs, + "max_completion_tokens": max_completion_tokens, "max_tokens": max_tokens, "n": n, "parallel_tool_calls": parallel_tool_calls, diff --git a/src/openai/resources/fine_tuning/jobs/jobs.py b/src/openai/resources/fine_tuning/jobs/jobs.py index ca4799e7ac..44abf1cfe1 100644 --- a/src/openai/resources/fine_tuning/jobs/jobs.py +++ b/src/openai/resources/fine_tuning/jobs/jobs.py @@ -114,7 +114,7 @@ def create( job parameters should produce the same results, but may differ in rare cases. If a seed is not specified, one will be generated for you. - suffix: A string of up to 18 characters that will be added to your fine-tuned model + suffix: A string of up to 64 characters that will be added to your fine-tuned model name. For example, a `suffix` of "custom-model-name" would produce a model name like @@ -405,7 +405,7 @@ async def create( job parameters should produce the same results, but may differ in rare cases. If a seed is not specified, one will be generated for you. - suffix: A string of up to 18 characters that will be added to your fine-tuned model + suffix: A string of up to 64 characters that will be added to your fine-tuned model name. For example, a `suffix` of "custom-model-name" would produce a model name like diff --git a/src/openai/types/beta/assistant.py b/src/openai/types/beta/assistant.py index c6a0a4cfcf..b4da08745d 100644 --- a/src/openai/types/beta/assistant.py +++ b/src/openai/types/beta/assistant.py @@ -90,11 +90,11 @@ class Assistant(BaseModel): and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which guarantees the model will match your supplied JSON schema. Learn - more in the + Outputs which ensures the model will match your supplied JSON schema. Learn more + in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the + Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the message the model generates is valid JSON. **Important:** when using JSON mode, you **must** also instruct the model to diff --git a/src/openai/types/beta/assistant_create_params.py b/src/openai/types/beta/assistant_create_params.py index c1360b5b66..eca4da0a2b 100644 --- a/src/openai/types/beta/assistant_create_params.py +++ b/src/openai/types/beta/assistant_create_params.py @@ -58,11 +58,11 @@ class AssistantCreateParams(TypedDict, total=False): and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which guarantees the model will match your supplied JSON schema. Learn - more in the + Outputs which ensures the model will match your supplied JSON schema. Learn more + in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the + Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the message the model generates is valid JSON. **Important:** when using JSON mode, you **must** also instruct the model to diff --git a/src/openai/types/beta/assistant_update_params.py b/src/openai/types/beta/assistant_update_params.py index ade565819f..5396233937 100644 --- a/src/openai/types/beta/assistant_update_params.py +++ b/src/openai/types/beta/assistant_update_params.py @@ -50,11 +50,11 @@ class AssistantUpdateParams(TypedDict, total=False): and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which guarantees the model will match your supplied JSON schema. Learn - more in the + Outputs which ensures the model will match your supplied JSON schema. Learn more + in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the + Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the message the model generates is valid JSON. **Important:** when using JSON mode, you **must** also instruct the model to diff --git a/src/openai/types/beta/file_search_tool.py b/src/openai/types/beta/file_search_tool.py index 4015b3da09..aee6593e89 100644 --- a/src/openai/types/beta/file_search_tool.py +++ b/src/openai/types/beta/file_search_tool.py @@ -9,16 +9,16 @@ class FileSearchRankingOptions(BaseModel): - ranker: Optional[Literal["auto", "default_2024_08_21"]] = None - """The ranker to use for the file search. + score_threshold: float + """The score threshold for the file search. - If not specified will use the `auto` ranker. + All values must be a floating point number between 0 and 1. """ - score_threshold: Optional[float] = None - """The score threshold for the file search. + ranker: Optional[Literal["auto", "default_2024_08_21"]] = None + """The ranker to use for the file search. - All values must be a floating point number between 0 and 1. + If not specified will use the `auto` ranker. """ @@ -38,6 +38,9 @@ class FileSearch(BaseModel): ranking_options: Optional[FileSearchRankingOptions] = None """The ranking options for the file search. + If not specified, the file search tool will use the `auto` ranker and a + score_threshold of 0. + See the [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search/customizing-file-search-settings) for more information. diff --git a/src/openai/types/beta/file_search_tool_param.py b/src/openai/types/beta/file_search_tool_param.py index 97e651b0da..5ce91207ba 100644 --- a/src/openai/types/beta/file_search_tool_param.py +++ b/src/openai/types/beta/file_search_tool_param.py @@ -8,16 +8,16 @@ class FileSearchRankingOptions(TypedDict, total=False): - ranker: Literal["auto", "default_2024_08_21"] - """The ranker to use for the file search. + score_threshold: Required[float] + """The score threshold for the file search. - If not specified will use the `auto` ranker. + All values must be a floating point number between 0 and 1. """ - score_threshold: float - """The score threshold for the file search. + ranker: Literal["auto", "default_2024_08_21"] + """The ranker to use for the file search. - All values must be a floating point number between 0 and 1. + If not specified will use the `auto` ranker. """ @@ -37,6 +37,9 @@ class FileSearch(TypedDict, total=False): ranking_options: FileSearchRankingOptions """The ranking options for the file search. + If not specified, the file search tool will use the `auto` ranker and a + score_threshold of 0. + See the [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search/customizing-file-search-settings) for more information. diff --git a/src/openai/types/beta/thread_create_and_run_params.py b/src/openai/types/beta/thread_create_and_run_params.py index 370c2f9bce..20d525fa1a 100644 --- a/src/openai/types/beta/thread_create_and_run_params.py +++ b/src/openai/types/beta/thread_create_and_run_params.py @@ -98,11 +98,11 @@ class ThreadCreateAndRunParamsBase(TypedDict, total=False): and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which guarantees the model will match your supplied JSON schema. Learn - more in the + Outputs which ensures the model will match your supplied JSON schema. Learn more + in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the + Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the message the model generates is valid JSON. **Important:** when using JSON mode, you **must** also instruct the model to diff --git a/src/openai/types/beta/threads/run.py b/src/openai/types/beta/threads/run.py index 0579e229d8..5abc1de295 100644 --- a/src/openai/types/beta/threads/run.py +++ b/src/openai/types/beta/threads/run.py @@ -172,11 +172,11 @@ class Run(BaseModel): and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which guarantees the model will match your supplied JSON schema. Learn - more in the + Outputs which ensures the model will match your supplied JSON schema. Learn more + in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the + Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the message the model generates is valid JSON. **Important:** when using JSON mode, you **must** also instruct the model to diff --git a/src/openai/types/beta/threads/run_create_params.py b/src/openai/types/beta/threads/run_create_params.py index 7c5f571d58..824cb1a041 100644 --- a/src/openai/types/beta/threads/run_create_params.py +++ b/src/openai/types/beta/threads/run_create_params.py @@ -111,11 +111,11 @@ class RunCreateParamsBase(TypedDict, total=False): and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which guarantees the model will match your supplied JSON schema. Learn - more in the + Outputs which ensures the model will match your supplied JSON schema. Learn more + in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the + Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the message the model generates is valid JSON. **Important:** when using JSON mode, you **must** also instruct the model to diff --git a/src/openai/types/chat/completion_create_params.py b/src/openai/types/chat/completion_create_params.py index b86dab742b..4ed89b00f5 100644 --- a/src/openai/types/chat/completion_create_params.py +++ b/src/openai/types/chat/completion_create_params.py @@ -87,15 +87,22 @@ class CompletionCreateParamsBase(TypedDict, total=False): `content` of `message`. """ + max_completion_tokens: Optional[int] + """ + An upper bound for the number of tokens that can be generated for a completion, + including visible output tokens and + [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). + """ + max_tokens: Optional[int] """ The maximum number of [tokens](/tokenizer) that can be generated in the chat - completion. + completion. This value can be used to control + [costs](https://openai.com/api/pricing/) for text generated via API. - The total length of input tokens and generated tokens is limited by the model's - context length. - [Example Python code](https://cookbook.openai.com/examples/how_to_count_tokens_with_tiktoken) - for counting tokens. + This value is now deprecated in favor of `max_completion_tokens`, and is not + compatible with + [o1 series models](https://platform.openai.com/docs/guides/reasoning). """ n: Optional[int] @@ -130,11 +137,11 @@ class CompletionCreateParamsBase(TypedDict, total=False): all GPT-3.5 Turbo models newer than `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which guarantees the model will match your supplied JSON schema. Learn - more in the + Outputs which ensures the model will match your supplied JSON schema. Learn more + in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the + Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the message the model generates is valid JSON. **Important:** when using JSON mode, you **must** also instruct the model to @@ -160,8 +167,11 @@ class CompletionCreateParamsBase(TypedDict, total=False): This parameter is relevant for customers subscribed to the scale tier service: - - If set to 'auto', the system will utilize scale tier credits until they are - exhausted. + - If set to 'auto', and the Project is Scale tier enabled, the system will + utilize scale tier credits until they are exhausted. + - If set to 'auto', and the Project is not Scale tier enabled, the request will + be processed using the default service tier with a lower uptime SLA and no + latency guarentee. - If set to 'default', the request will be processed using the default service tier with a lower uptime SLA and no latency guarentee. - When not set, the default behavior is 'auto'. diff --git a/src/openai/types/chat_model.py b/src/openai/types/chat_model.py index 09bc081f7a..f8438c75c8 100644 --- a/src/openai/types/chat_model.py +++ b/src/openai/types/chat_model.py @@ -5,9 +5,14 @@ __all__ = ["ChatModel"] ChatModel: TypeAlias = Literal[ + "o1-preview", + "o1-preview-2024-09-12", + "o1-mini", + "o1-mini-2024-09-12", "gpt-4o", - "gpt-4o-2024-05-13", "gpt-4o-2024-08-06", + "gpt-4o-2024-05-13", + "chatgpt-4o-latest", "gpt-4o-mini", "gpt-4o-mini-2024-07-18", "gpt-4-turbo", diff --git a/src/openai/types/completion_usage.py b/src/openai/types/completion_usage.py index ac09afd479..a4b9116e35 100644 --- a/src/openai/types/completion_usage.py +++ b/src/openai/types/completion_usage.py @@ -1,9 +1,15 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from typing import Optional from .._models import BaseModel -__all__ = ["CompletionUsage"] +__all__ = ["CompletionUsage", "CompletionTokensDetails"] + + +class CompletionTokensDetails(BaseModel): + reasoning_tokens: Optional[int] = None + """Tokens generated by the model for reasoning.""" class CompletionUsage(BaseModel): @@ -15,3 +21,6 @@ class CompletionUsage(BaseModel): total_tokens: int """Total number of tokens used in the request (prompt + completion).""" + + completion_tokens_details: Optional[CompletionTokensDetails] = None + """Breakdown of tokens used in a completion.""" diff --git a/src/openai/types/fine_tuning/job_create_params.py b/src/openai/types/fine_tuning/job_create_params.py index e9be2ef1ca..8f5ea86274 100644 --- a/src/openai/types/fine_tuning/job_create_params.py +++ b/src/openai/types/fine_tuning/job_create_params.py @@ -50,7 +50,7 @@ class JobCreateParams(TypedDict, total=False): suffix: Optional[str] """ - A string of up to 18 characters that will be added to your fine-tuned model + A string of up to 64 characters that will be added to your fine-tuned model name. For example, a `suffix` of "custom-model-name" would produce a model name like diff --git a/tests/api_resources/chat/test_completions.py b/tests/api_resources/chat/test_completions.py index 0b89fbf9cd..c44703a434 100644 --- a/tests/api_resources/chat/test_completions.py +++ b/tests/api_resources/chat/test_completions.py @@ -55,6 +55,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: ], logit_bias={"foo": 0}, logprobs=True, + max_completion_tokens=0, max_tokens=0, n=1, parallel_tool_calls=True, @@ -175,6 +176,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: ], logit_bias={"foo": 0}, logprobs=True, + max_completion_tokens=0, max_tokens=0, n=1, parallel_tool_calls=True, @@ -314,6 +316,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn ], logit_bias={"foo": 0}, logprobs=True, + max_completion_tokens=0, max_tokens=0, n=1, parallel_tool_calls=True, @@ -434,6 +437,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn ], logit_bias={"foo": 0}, logprobs=True, + max_completion_tokens=0, max_tokens=0, n=1, parallel_tool_calls=True, diff --git a/tests/lib/chat/test_completions.py b/tests/lib/chat/test_completions.py index d67d5129cd..e7b9c4f1fd 100644 --- a/tests/lib/chat/test_completions.py +++ b/tests/lib/chat/test_completions.py @@ -74,7 +74,7 @@ def test_parse_nothing(client: OpenAI, respx_mock: MockRouter, monkeypatch: pyte object='chat.completion', service_tier=None, system_fingerprint='fp_845eaabc1f', - usage=CompletionUsage(completion_tokens=28, prompt_tokens=14, total_tokens=42) + usage=CompletionUsage(completion_tokens=28, completion_tokens_details=None, prompt_tokens=14, total_tokens=42) ) """ ) @@ -129,7 +129,7 @@ class Location(BaseModel): object='chat.completion', service_tier=None, system_fingerprint='fp_2a322c9ffc', - usage=CompletionUsage(completion_tokens=14, prompt_tokens=17, total_tokens=31) + usage=CompletionUsage(completion_tokens=14, completion_tokens_details=None, prompt_tokens=17, total_tokens=31) ) """ ) @@ -186,7 +186,7 @@ class Location(BaseModel): object='chat.completion', service_tier=None, system_fingerprint='fp_2a322c9ffc', - usage=CompletionUsage(completion_tokens=14, prompt_tokens=17, total_tokens=31) + usage=CompletionUsage(completion_tokens=14, completion_tokens_details=None, prompt_tokens=17, total_tokens=31) ) """ ) @@ -368,7 +368,7 @@ class CalendarEvent: object='chat.completion', service_tier=None, system_fingerprint='fp_2a322c9ffc', - usage=CompletionUsage(completion_tokens=17, prompt_tokens=32, total_tokens=49) + usage=CompletionUsage(completion_tokens=17, completion_tokens_details=None, prompt_tokens=32, total_tokens=49) ) """ ) diff --git a/tests/lib/chat/test_completions_streaming.py b/tests/lib/chat/test_completions_streaming.py index c3dd69ad57..5ad1f084d2 100644 --- a/tests/lib/chat/test_completions_streaming.py +++ b/tests/lib/chat/test_completions_streaming.py @@ -155,7 +155,7 @@ def on_event(stream: ChatCompletionStream[Location], event: ChatCompletionStream object='chat.completion', service_tier=None, system_fingerprint='fp_845eaabc1f', - usage=CompletionUsage(completion_tokens=14, prompt_tokens=17, total_tokens=31) + usage=CompletionUsage(completion_tokens=14, completion_tokens_details=None, prompt_tokens=17, total_tokens=31) ) """ ) From 48026f3a39b9e1423681ac7a35e68992d230d85a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 12 Sep 2024 17:03:58 +0000 Subject: [PATCH 008/769] release: 1.45.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 14 ++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 1ee5dee6dd..6d2723c72a 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.44.1" + ".": "1.45.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 47fa2d9208..8382675b73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## 1.45.0 (2024-09-12) + +Full Changelog: [v1.44.1...v1.45.0](https://github.com/openai/openai-python/compare/v1.44.1...v1.45.0) + +### Features + +* **api:** add o1 models ([#1708](https://github.com/openai/openai-python/issues/1708)) ([06bd42e](https://github.com/openai/openai-python/commit/06bd42e77121a6abd4826a79ce1848812d956576)) +* **errors:** include completion in LengthFinishReasonError ([#1701](https://github.com/openai/openai-python/issues/1701)) ([b0e3256](https://github.com/openai/openai-python/commit/b0e32562aff9aceafec994d3b047f7c2a9f11524)) + + +### Bug Fixes + +* **types:** correctly mark stream discriminator as optional ([#1706](https://github.com/openai/openai-python/issues/1706)) ([80f02f9](https://github.com/openai/openai-python/commit/80f02f9e5f83fac9cd2f4172b733a92ad01399b2)) + ## 1.44.1 (2024-09-09) Full Changelog: [v1.44.0...v1.44.1](https://github.com/openai/openai-python/compare/v1.44.0...v1.44.1) diff --git a/pyproject.toml b/pyproject.toml index d4b7d2b210..178c3db355 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.44.1" +version = "1.45.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 39c7f63e1e..0d8ebf418b 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.44.1" # x-release-please-version +__version__ = "1.45.0" # x-release-please-version From f63234732869d0511a7fc19c240ab19bec5de717 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 13 Sep 2024 15:30:06 +0000 Subject: [PATCH 009/769] docs: update CONTRIBUTING.md (#1710) --- CONTRIBUTING.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 354d21b2d2..5a6639b8fc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -31,13 +31,13 @@ $ pip install -r requirements-dev.lock ## Modifying/Adding code -Most of the SDK is generated code, and any modified code will be overridden on the next generation. The -`src/openai/lib/` and `examples/` directories are exceptions and will never be overridden. +Most of the SDK is generated code. Modifications to code will be persisted between generations, but may +result in merge conflicts between manual patches and changes from the generator. The generator will never +modify the contents of the `src/openai/lib/` and `examples/` directories. ## Adding and running examples -All files in the `examples/` directory are not modified by the Stainless generator and can be freely edited or -added to. +All files in the `examples/` directory are not modified by the generator and can be freely edited or added to. ```bash # add an example to examples/.py From 803a7f3b16ec959fe04e1ae83ca3808faf8acffb Mon Sep 17 00:00:00 2001 From: Stainless Bot Date: Mon, 16 Sep 2024 12:05:27 +0000 Subject: [PATCH 010/769] chore(internal): bump ruff (#1714) --- requirements-dev.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.lock b/requirements-dev.lock index f4797f432b..e5e63ed037 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -141,7 +141,7 @@ requests==2.31.0 respx==0.20.2 rich==13.7.1 # via inline-snapshot -ruff==0.5.6 +ruff==0.6.5 setuptools==68.2.2 # via nodeenv six==1.16.0 From b5897bdf1fe3d300438b87c23d57611f3c2dad3a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 16 Sep 2024 12:24:14 +0000 Subject: [PATCH 011/769] chore(internal): update spec link (#1716) --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index de3167f3a8..2fc39385e9 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 68 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-501122aa32adaa2abb3d4487880ab9cdf2141addce2e6c3d1bd9bb6b44c318a8.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-ff407aa10917e62f2b0c12d1ad2c4f1258ed083bd45753c70eaaf5b1cf8356ae.yml From dbe51995f2f0431bba63e4422f61f09fddbe0375 Mon Sep 17 00:00:00 2001 From: Stainless Bot Date: Mon, 16 Sep 2024 12:46:46 +0000 Subject: [PATCH 012/769] chore(internal): bump pyright / mypy version (#1717) --- requirements-dev.lock | 4 ++-- src/openai/_utils/_utils.py | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/requirements-dev.lock b/requirements-dev.lock index e5e63ed037..a47de9656a 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -83,7 +83,7 @@ msal==1.29.0 # via msal-extensions msal-extensions==1.2.0 # via azure-identity -mypy==1.7.1 +mypy==1.11.2 mypy-extensions==1.0.0 # via black # via mypy @@ -125,7 +125,7 @@ pygments==2.18.0 # via rich pyjwt==2.8.0 # via msal -pyright==1.1.374 +pyright==1.1.380 pytest==7.1.1 # via pytest-asyncio pytest-asyncio==0.21.1 diff --git a/src/openai/_utils/_utils.py b/src/openai/_utils/_utils.py index 2fc5a1c65a..0bba17caad 100644 --- a/src/openai/_utils/_utils.py +++ b/src/openai/_utils/_utils.py @@ -363,12 +363,13 @@ def file_from_path(path: str) -> FileTypes: def get_required_header(headers: HeadersLike, header: str) -> str: lower_header = header.lower() - if isinstance(headers, Mapping): - for k, v in headers.items(): + if is_mapping_t(headers): + # mypy doesn't understand the type narrowing here + for k, v in headers.items(): # type: ignore if k.lower() == lower_header and isinstance(v, str): return v - """ to deal with the case where the header looks like Stainless-Event-Id """ + # to deal with the case where the header looks like Stainless-Event-Id intercaps_header = re.sub(r"([^\w])(\w)", lambda pat: pat.group(1) + pat.group(2).upper(), header.capitalize()) for normalized_header in [header, lower_header, header.upper(), intercaps_header]: From 73f9fda59561e35ae839c66dcc30b785e1629e58 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 16 Sep 2024 12:47:09 +0000 Subject: [PATCH 013/769] release: 1.45.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 15 +++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 6d2723c72a..c37d66f738 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.45.0" + ".": "1.45.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 8382675b73..b1f344cfb3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## 1.45.1 (2024-09-16) + +Full Changelog: [v1.45.0...v1.45.1](https://github.com/openai/openai-python/compare/v1.45.0...v1.45.1) + +### Chores + +* **internal:** bump pyright / mypy version ([#1717](https://github.com/openai/openai-python/issues/1717)) ([351af85](https://github.com/openai/openai-python/commit/351af85c5b813391910301a5049edddc8c9e70dd)) +* **internal:** bump ruff ([#1714](https://github.com/openai/openai-python/issues/1714)) ([aceaf64](https://github.com/openai/openai-python/commit/aceaf641eedd092ed42e4aaf031e8cfbf37e4212)) +* **internal:** update spec link ([#1716](https://github.com/openai/openai-python/issues/1716)) ([ca58c7f](https://github.com/openai/openai-python/commit/ca58c7f83a7cede0367dec2500127573c9b00d1f)) + + +### Documentation + +* update CONTRIBUTING.md ([#1710](https://github.com/openai/openai-python/issues/1710)) ([4d45eb5](https://github.com/openai/openai-python/commit/4d45eb5eb794bcc5076c022be09e06fae103abcc)) + ## 1.45.0 (2024-09-12) Full Changelog: [v1.44.1...v1.45.0](https://github.com/openai/openai-python/compare/v1.44.1...v1.45.0) diff --git a/pyproject.toml b/pyproject.toml index 178c3db355..7828d0f0e1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.45.0" +version = "1.45.1" 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 0d8ebf418b..1b29a53bb6 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.45.0" # x-release-please-version +__version__ = "1.45.1" # x-release-please-version From 192b8f2b6a49f462e48c1442858931875524ab49 Mon Sep 17 00:00:00 2001 From: Dan Corin Date: Mon, 16 Sep 2024 09:52:22 -0400 Subject: [PATCH 014/769] docs(readme): add examples for chat with image content (#1703) --- README.md | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/README.md b/README.md index 8c73fdd82a..9e9628ff83 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,48 @@ we recommend using [python-dotenv](https://pypi.org/project/python-dotenv/) to add `OPENAI_API_KEY="My API Key"` to your `.env` file so that your API Key is not stored in source control. +### Vision + +With a hosted image: + +```python +response = client.chat.completions.create( + model="gpt-4o-mini", + messages=[ + { + "role": "user", + "content": [ + {"type": "text", "text": prompt}, + { + "type": "image_url", + "image_url": {"url": f"{img_url}"}, + }, + ], + } + ], +) +``` + +With the image as a base64 encoded string: + +```python +response = client.chat.completions.create( + model="gpt-4o-mini", + messages=[ + { + "role": "user", + "content": [ + {"type": "text", "text": prompt}, + { + "type": "image_url", + "image_url": {"url": f"data:{img_type};base64,{img_b64_str}"}, + }, + ], + } + ], +) +``` + ### Polling Helpers When interacting with the API some actions such as starting a Run and adding files to vector stores are asynchronous and take time to complete. The SDK includes From 4b3023466df27de4d19a93b4efbd14977254ecc0 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Tue, 17 Sep 2024 17:30:18 +0100 Subject: [PATCH 015/769] feat(client): add ._request_id property to object responses (#1707) --- README.md | 18 ++++++++++++++ src/openai/_legacy_response.py | 7 ++++-- src/openai/_models.py | 34 ++++++++++++++++++++++++++- src/openai/_response.py | 12 +++++++--- tests/test_legacy_response.py | 21 +++++++++++++++++ tests/test_response.py | 43 ++++++++++++++++++++++++++++++++++ 6 files changed, 129 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 9e9628ff83..c47bdd54c5 100644 --- a/README.md +++ b/README.md @@ -417,6 +417,24 @@ Error codes are as followed: | >=500 | `InternalServerError` | | N/A | `APIConnectionError` | +## Request IDs + +> For more information on debugging requests, see [these docs](https://platform.openai.com/docs/api-reference/debugging-requests) + +All object responses in the SDK provide a `_request_id` property which is added from the `x-request-id` response header so that you can quickly log failing requests and report them back to OpenAI. + +```python +completion = await client.chat.completions.create( + messages=[{"role": "user", "content": "Say this is a test"}], model="gpt-4" +) +print(completion._request_id) # req_123 +``` + +Note that unlike other properties that use an `_` prefix, the `_request_id` property +*is* public. Unless documented otherwise, *all* other `_` prefix properties, +methods and modules are *private*. + + ### Retries Certain errors are automatically retried 2 times by default, with a short exponential backoff. diff --git a/src/openai/_legacy_response.py b/src/openai/_legacy_response.py index c42fb8b83e..c7dbd54e23 100644 --- a/src/openai/_legacy_response.py +++ b/src/openai/_legacy_response.py @@ -25,7 +25,7 @@ from ._types import NoneType from ._utils import is_given, extract_type_arg, is_annotated_type -from ._models import BaseModel, is_basemodel +from ._models import BaseModel, is_basemodel, add_request_id from ._constants import RAW_RESPONSE_HEADER from ._streaming import Stream, AsyncStream, is_stream_class_type, extract_stream_chunk_type from ._exceptions import APIResponseValidationError @@ -138,8 +138,11 @@ class MyModel(BaseModel): if is_given(self._options.post_parser): parsed = self._options.post_parser(parsed) + if isinstance(parsed, BaseModel): + add_request_id(parsed, self.request_id) + self._parsed_by_type[cache_key] = parsed - return parsed + return cast(R, parsed) @property def headers(self) -> httpx.Headers: diff --git a/src/openai/_models.py b/src/openai/_models.py index d386eaa3a4..d6f42d3d4d 100644 --- a/src/openai/_models.py +++ b/src/openai/_models.py @@ -2,7 +2,7 @@ import os import inspect -from typing import TYPE_CHECKING, Any, Type, Union, Generic, TypeVar, Callable, cast +from typing import TYPE_CHECKING, Any, Type, Union, Generic, TypeVar, Callable, Optional, cast from datetime import date, datetime from typing_extensions import ( Unpack, @@ -94,6 +94,23 @@ def model_fields_set(self) -> set[str]: class Config(pydantic.BaseConfig): # pyright: ignore[reportDeprecated] extra: Any = pydantic.Extra.allow # type: ignore + if TYPE_CHECKING: + _request_id: Optional[str] = None + """The ID of the request, returned via the X-Request-ID header. Useful for debugging requests and reporting issues to OpenAI. + + This will **only** be set for the top-level response object, it will not be defined for nested objects. For example: + + ```py + completion = await client.chat.completions.create(...) + completion._request_id # req_id_xxx + completion.usage._request_id # raises `AttributeError` + ``` + + Note: unlike other properties that use an `_` prefix, this property + *is* public. Unless documented otherwise, all other `_` prefix properties, + methods and modules are *private*. + """ + def to_dict( self, *, @@ -662,6 +679,21 @@ def set_pydantic_config(typ: Any, config: pydantic.ConfigDict) -> None: setattr(typ, "__pydantic_config__", config) # noqa: B010 +def add_request_id(obj: BaseModel, request_id: str | None) -> None: + obj._request_id = request_id + + # in Pydantic v1, using setattr like we do above causes the attribute + # to be included when serializing the model which we don't want in this + # case so we need to explicitly exclude it + if not PYDANTIC_V2: + try: + exclude_fields = obj.__exclude_fields__ # type: ignore + except AttributeError: + cast(Any, obj).__exclude_fields__ = {"_request_id", "__exclude_fields__"} + else: + cast(Any, obj).__exclude_fields__ = {*(exclude_fields or {}), "_request_id", "__exclude_fields__"} + + # our use of subclasssing here causes weirdness for type checkers, # so we just pretend that we don't subclass if TYPE_CHECKING: diff --git a/src/openai/_response.py b/src/openai/_response.py index f9d91786f6..20ce69ac8a 100644 --- a/src/openai/_response.py +++ b/src/openai/_response.py @@ -26,7 +26,7 @@ from ._types import NoneType from ._utils import is_given, extract_type_arg, is_annotated_type, extract_type_var_from_base -from ._models import BaseModel, is_basemodel +from ._models import BaseModel, is_basemodel, add_request_id from ._constants import RAW_RESPONSE_HEADER, OVERRIDE_CAST_TO_HEADER from ._streaming import Stream, AsyncStream, is_stream_class_type, extract_stream_chunk_type from ._exceptions import OpenAIError, APIResponseValidationError @@ -315,8 +315,11 @@ class MyModel(BaseModel): if is_given(self._options.post_parser): parsed = self._options.post_parser(parsed) + if isinstance(parsed, BaseModel): + add_request_id(parsed, self.request_id) + self._parsed_by_type[cache_key] = parsed - return parsed + return cast(R, parsed) def read(self) -> bytes: """Read and return the binary response content.""" @@ -419,8 +422,11 @@ class MyModel(BaseModel): if is_given(self._options.post_parser): parsed = self._options.post_parser(parsed) + if isinstance(parsed, BaseModel): + add_request_id(parsed, self.request_id) + self._parsed_by_type[cache_key] = parsed - return parsed + return cast(R, parsed) async def read(self) -> bytes: """Read and return the binary response content.""" diff --git a/tests/test_legacy_response.py b/tests/test_legacy_response.py index 3c2df53e58..a6fec9f2de 100644 --- a/tests/test_legacy_response.py +++ b/tests/test_legacy_response.py @@ -66,6 +66,27 @@ def test_response_parse_custom_model(client: OpenAI) -> None: assert obj.bar == 2 +def test_response_basemodel_request_id(client: OpenAI) -> None: + response = LegacyAPIResponse( + raw=httpx.Response( + 200, + headers={"x-request-id": "my-req-id"}, + content=json.dumps({"foo": "hello!", "bar": 2}), + ), + client=client, + stream=False, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + obj = response.parse(to=CustomModel) + assert obj._request_id == "my-req-id" + assert obj.foo == "hello!" + assert obj.bar == 2 + assert obj.to_dict() == {"foo": "hello!", "bar": 2} + + def test_response_parse_annotated_type(client: OpenAI) -> None: response = LegacyAPIResponse( raw=httpx.Response(200, content=json.dumps({"foo": "hello!", "bar": 2})), diff --git a/tests/test_response.py b/tests/test_response.py index b7d88bdbde..97c56e0035 100644 --- a/tests/test_response.py +++ b/tests/test_response.py @@ -156,6 +156,49 @@ async def test_async_response_parse_custom_model(async_client: AsyncOpenAI) -> N assert obj.bar == 2 +def test_response_basemodel_request_id(client: OpenAI) -> None: + response = APIResponse( + raw=httpx.Response( + 200, + headers={"x-request-id": "my-req-id"}, + content=json.dumps({"foo": "hello!", "bar": 2}), + ), + client=client, + stream=False, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + obj = response.parse(to=CustomModel) + assert obj._request_id == "my-req-id" + assert obj.foo == "hello!" + assert obj.bar == 2 + assert obj.to_dict() == {"foo": "hello!", "bar": 2} + + +@pytest.mark.asyncio +async def test_async_response_basemodel_request_id(client: OpenAI) -> None: + response = AsyncAPIResponse( + raw=httpx.Response( + 200, + headers={"x-request-id": "my-req-id"}, + content=json.dumps({"foo": "hello!", "bar": 2}), + ), + client=client, + stream=False, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + obj = await response.parse(to=CustomModel) + assert obj._request_id == "my-req-id" + assert obj.foo == "hello!" + assert obj.bar == 2 + assert obj.to_dict() == {"foo": "hello!", "bar": 2} + + def test_response_parse_annotated_type(client: OpenAI) -> None: response = APIResponse( raw=httpx.Response(200, content=json.dumps({"foo": "hello!", "bar": 2})), From bcf9fcc36149921f216d49ac84ee1aa9c15c5a86 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Sep 2024 16:34:47 +0000 Subject: [PATCH 016/769] release: 1.46.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index c37d66f738..4b6cc3c898 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.45.1" + ".": "1.46.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index b1f344cfb3..c1f852327c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 1.46.0 (2024-09-17) + +Full Changelog: [v1.45.1...v1.46.0](https://github.com/openai/openai-python/compare/v1.45.1...v1.46.0) + +### Features + +* **client:** add ._request_id property to object responses ([#1707](https://github.com/openai/openai-python/issues/1707)) ([8b3da05](https://github.com/openai/openai-python/commit/8b3da05a35b33245aec98693a0540ace6218a61b)) + + +### Documentation + +* **readme:** add examples for chat with image content ([#1703](https://github.com/openai/openai-python/issues/1703)) ([192b8f2](https://github.com/openai/openai-python/commit/192b8f2b6a49f462e48c1442858931875524ab49)) + ## 1.45.1 (2024-09-16) Full Changelog: [v1.45.0...v1.45.1](https://github.com/openai/openai-python/compare/v1.45.0...v1.45.1) diff --git a/pyproject.toml b/pyproject.toml index 7828d0f0e1..a3bd81cad5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.45.1" +version = "1.46.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 1b29a53bb6..ccd62dc230 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.45.1" # x-release-please-version +__version__ = "1.46.0" # x-release-please-version From 349b7f6c3bbe54bfe0c9e3652782f822ff2f1ab6 Mon Sep 17 00:00:00 2001 From: Krista Pratico Date: Wed, 18 Sep 2024 11:51:55 -0700 Subject: [PATCH 017/769] chore(streaming): silence pydantic model_dump warnings (#1722) --- src/openai/lib/streaming/_assistants.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/openai/lib/streaming/_assistants.py b/src/openai/lib/streaming/_assistants.py index 7445f9a96d..183754177a 100644 --- a/src/openai/lib/streaming/_assistants.py +++ b/src/openai/lib/streaming/_assistants.py @@ -906,11 +906,11 @@ def accumulate_run_step( merged = accumulate_delta( cast( "dict[object, object]", - snapshot.model_dump(exclude_unset=True), + snapshot.model_dump(exclude_unset=True, warnings=False), ), cast( "dict[object, object]", - data.delta.model_dump(exclude_unset=True), + data.delta.model_dump(exclude_unset=True, warnings=False), ), ) run_step_snapshots[snapshot.id] = cast(RunStep, construct_type(type_=RunStep, value=merged)) @@ -948,7 +948,7 @@ def accumulate_event( construct_type( # mypy doesn't allow Content for some reason type_=cast(Any, MessageContent), - value=content_delta.model_dump(exclude_unset=True), + value=content_delta.model_dump(exclude_unset=True, warnings=False), ), ), ) @@ -957,11 +957,11 @@ def accumulate_event( merged = accumulate_delta( cast( "dict[object, object]", - block.model_dump(exclude_unset=True), + block.model_dump(exclude_unset=True, warnings=False), ), cast( "dict[object, object]", - content_delta.model_dump(exclude_unset=True), + content_delta.model_dump(exclude_unset=True, warnings=False), ), ) current_message_snapshot.content[content_delta.index] = cast( From bd1e9e2fa7869c429f8ff727ba72b9675710edc9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 19 Sep 2024 14:48:19 +0000 Subject: [PATCH 018/769] fix(client): handle domains with underscores (#1726) --- src/openai/_base_client.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index f374449dbc..2545ddf967 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -490,12 +490,17 @@ def _build_request( if not files: files = cast(HttpxRequestFiles, ForceMultipartDict()) + prepared_url = self._prepare_url(options.url) + if "_" in prepared_url.host: + # work around https://github.com/encode/httpx/discussions/2880 + kwargs["extensions"] = {"sni_hostname": prepared_url.host.replace("_", "-")} + # TODO: report this error to httpx return self._client.build_request( # pyright: ignore[reportUnknownMemberType] headers=headers, timeout=self.timeout if isinstance(options.timeout, NotGiven) else options.timeout, method=options.method, - url=self._prepare_url(options.url), + url=prepared_url, # the `Query` type that we use is incompatible with qs' # `Params` type as it needs to be typed as `Mapping[str, object]` # so that passing a `TypedDict` doesn't cause an error. From 6172976b16821b24194a05e3e3fe5cb2342a2b4b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 19 Sep 2024 14:48:52 +0000 Subject: [PATCH 019/769] release: 1.46.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 4b6cc3c898..d89af66b28 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.46.0" + ".": "1.46.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index c1f852327c..3f1c96e6d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 1.46.1 (2024-09-19) + +Full Changelog: [v1.46.0...v1.46.1](https://github.com/openai/openai-python/compare/v1.46.0...v1.46.1) + +### Bug Fixes + +* **client:** handle domains with underscores ([#1726](https://github.com/openai/openai-python/issues/1726)) ([cd194df](https://github.com/openai/openai-python/commit/cd194dfdc418a84589bd903357cba349e9ad3e78)) + + +### Chores + +* **streaming:** silence pydantic model_dump warnings ([#1722](https://github.com/openai/openai-python/issues/1722)) ([30f84b9](https://github.com/openai/openai-python/commit/30f84b96081ac37f60e40a75d765dbbf563b61b3)) + ## 1.46.0 (2024-09-17) Full Changelog: [v1.45.1...v1.46.0](https://github.com/openai/openai-python/compare/v1.45.1...v1.46.0) diff --git a/pyproject.toml b/pyproject.toml index a3bd81cad5..b505880f11 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.46.0" +version = "1.46.1" 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 ccd62dc230..197a24ea67 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.46.0" # x-release-please-version +__version__ = "1.46.1" # x-release-please-version From 3765cc2c6a8c90376a41d5daeb7f2f100f81f8a5 Mon Sep 17 00:00:00 2001 From: Stainless Bot Date: Thu, 19 Sep 2024 16:11:56 +0000 Subject: [PATCH 020/769] feat(client): send retry count header --- src/openai/_base_client.py | 102 ++++++++++++++++++++----------------- src/openai/lib/azure.py | 4 +- tests/test_client.py | 16 ++++++ 3 files changed, 74 insertions(+), 48 deletions(-) diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index 2545ddf967..77e82026ef 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -401,14 +401,7 @@ def _make_status_error( ) -> _exceptions.APIStatusError: raise NotImplementedError() - def _remaining_retries( - self, - remaining_retries: Optional[int], - options: FinalRequestOptions, - ) -> int: - return remaining_retries if remaining_retries is not None else options.get_max_retries(self.max_retries) - - def _build_headers(self, options: FinalRequestOptions) -> httpx.Headers: + def _build_headers(self, options: FinalRequestOptions, *, retries_taken: int = 0) -> httpx.Headers: custom_headers = options.headers or {} headers_dict = _merge_mappings(self.default_headers, custom_headers) self._validate_headers(headers_dict, custom_headers) @@ -420,6 +413,9 @@ def _build_headers(self, options: FinalRequestOptions) -> httpx.Headers: if idempotency_header and options.method.lower() != "get" and idempotency_header not in headers: headers[idempotency_header] = options.idempotency_key or self._idempotency_key() + if retries_taken > 0: + headers.setdefault("x-stainless-retry-count", str(retries_taken)) + return headers def _prepare_url(self, url: str) -> URL: @@ -441,6 +437,8 @@ def _make_sse_decoder(self) -> SSEDecoder | SSEBytesDecoder: def _build_request( self, options: FinalRequestOptions, + *, + retries_taken: int = 0, ) -> httpx.Request: if log.isEnabledFor(logging.DEBUG): log.debug("Request options: %s", model_dump(options, exclude_unset=True)) @@ -456,7 +454,7 @@ def _build_request( else: raise RuntimeError(f"Unexpected JSON data type, {type(json_data)}, cannot merge with `extra_body`") - headers = self._build_headers(options) + headers = self._build_headers(options, retries_taken=retries_taken) params = _merge_mappings(self.default_query, options.params) content_type = headers.get("Content-Type") files = options.files @@ -939,12 +937,17 @@ def request( stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: + if remaining_retries is not None: + retries_taken = options.get_max_retries(self.max_retries) - remaining_retries + else: + retries_taken = 0 + return self._request( cast_to=cast_to, options=options, stream=stream, stream_cls=stream_cls, - remaining_retries=remaining_retries, + retries_taken=retries_taken, ) def _request( @@ -952,7 +955,7 @@ def _request( *, cast_to: Type[ResponseT], options: FinalRequestOptions, - remaining_retries: int | None, + retries_taken: int, stream: bool, stream_cls: type[_StreamT] | None, ) -> ResponseT | _StreamT: @@ -964,8 +967,8 @@ def _request( cast_to = self._maybe_override_cast_to(cast_to, options) options = self._prepare_options(options) - retries = self._remaining_retries(remaining_retries, options) - request = self._build_request(options) + remaining_retries = options.get_max_retries(self.max_retries) - retries_taken + request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} @@ -983,11 +986,11 @@ def _request( except httpx.TimeoutException as err: log.debug("Encountered httpx.TimeoutException", exc_info=True) - if retries > 0: + if remaining_retries > 0: return self._retry_request( input_options, cast_to, - retries, + retries_taken=retries_taken, stream=stream, stream_cls=stream_cls, response_headers=None, @@ -998,11 +1001,11 @@ def _request( except Exception as err: log.debug("Encountered Exception", exc_info=True) - if retries > 0: + if remaining_retries > 0: return self._retry_request( input_options, cast_to, - retries, + retries_taken=retries_taken, stream=stream, stream_cls=stream_cls, response_headers=None, @@ -1026,13 +1029,13 @@ def _request( except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code log.debug("Encountered httpx.HTTPStatusError", exc_info=True) - if retries > 0 and self._should_retry(err.response): + if remaining_retries > 0 and self._should_retry(err.response): err.response.close() return self._retry_request( input_options, cast_to, - retries, - err.response.headers, + retries_taken=retries_taken, + response_headers=err.response.headers, stream=stream, stream_cls=stream_cls, ) @@ -1051,26 +1054,26 @@ def _request( response=response, stream=stream, stream_cls=stream_cls, - retries_taken=options.get_max_retries(self.max_retries) - retries, + retries_taken=retries_taken, ) def _retry_request( self, options: FinalRequestOptions, cast_to: Type[ResponseT], - remaining_retries: int, - response_headers: httpx.Headers | None, *, + retries_taken: int, + response_headers: httpx.Headers | None, stream: bool, stream_cls: type[_StreamT] | None, ) -> ResponseT | _StreamT: - remaining = remaining_retries - 1 - if remaining == 1: + remaining_retries = options.get_max_retries(self.max_retries) - retries_taken + if remaining_retries == 1: log.debug("1 retry left") else: - log.debug("%i retries left", remaining) + log.debug("%i retries left", remaining_retries) - timeout = self._calculate_retry_timeout(remaining, options, response_headers) + timeout = self._calculate_retry_timeout(remaining_retries, options, response_headers) log.info("Retrying request to %s in %f seconds", options.url, timeout) # In a synchronous context we are blocking the entire thread. Up to the library user to run the client in a @@ -1080,7 +1083,7 @@ def _retry_request( return self._request( options=options, cast_to=cast_to, - remaining_retries=remaining, + retries_taken=retries_taken + 1, stream=stream, stream_cls=stream_cls, ) @@ -1512,12 +1515,17 @@ async def request( stream_cls: type[_AsyncStreamT] | None = None, remaining_retries: Optional[int] = None, ) -> ResponseT | _AsyncStreamT: + if remaining_retries is not None: + retries_taken = options.get_max_retries(self.max_retries) - remaining_retries + else: + retries_taken = 0 + return await self._request( cast_to=cast_to, options=options, stream=stream, stream_cls=stream_cls, - remaining_retries=remaining_retries, + retries_taken=retries_taken, ) async def _request( @@ -1527,7 +1535,7 @@ async def _request( *, stream: bool, stream_cls: type[_AsyncStreamT] | None, - remaining_retries: int | None, + retries_taken: int, ) -> ResponseT | _AsyncStreamT: if self._platform is None: # `get_platform` can make blocking IO calls so we @@ -1542,8 +1550,8 @@ async def _request( cast_to = self._maybe_override_cast_to(cast_to, options) options = await self._prepare_options(options) - retries = self._remaining_retries(remaining_retries, options) - request = self._build_request(options) + remaining_retries = options.get_max_retries(self.max_retries) - retries_taken + request = self._build_request(options, retries_taken=retries_taken) await self._prepare_request(request) kwargs: HttpxSendArgs = {} @@ -1559,11 +1567,11 @@ async def _request( except httpx.TimeoutException as err: log.debug("Encountered httpx.TimeoutException", exc_info=True) - if retries > 0: + if remaining_retries > 0: return await self._retry_request( input_options, cast_to, - retries, + retries_taken=retries_taken, stream=stream, stream_cls=stream_cls, response_headers=None, @@ -1574,11 +1582,11 @@ async def _request( except Exception as err: log.debug("Encountered Exception", exc_info=True) - if retries > 0: + if retries_taken > 0: return await self._retry_request( input_options, cast_to, - retries, + retries_taken=retries_taken, stream=stream, stream_cls=stream_cls, response_headers=None, @@ -1596,13 +1604,13 @@ async def _request( except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code log.debug("Encountered httpx.HTTPStatusError", exc_info=True) - if retries > 0 and self._should_retry(err.response): + if remaining_retries > 0 and self._should_retry(err.response): await err.response.aclose() return await self._retry_request( input_options, cast_to, - retries, - err.response.headers, + retries_taken=retries_taken, + response_headers=err.response.headers, stream=stream, stream_cls=stream_cls, ) @@ -1621,26 +1629,26 @@ async def _request( response=response, stream=stream, stream_cls=stream_cls, - retries_taken=options.get_max_retries(self.max_retries) - retries, + retries_taken=retries_taken, ) async def _retry_request( self, options: FinalRequestOptions, cast_to: Type[ResponseT], - remaining_retries: int, - response_headers: httpx.Headers | None, *, + retries_taken: int, + response_headers: httpx.Headers | None, stream: bool, stream_cls: type[_AsyncStreamT] | None, ) -> ResponseT | _AsyncStreamT: - remaining = remaining_retries - 1 - if remaining == 1: + remaining_retries = options.get_max_retries(self.max_retries) - retries_taken + if remaining_retries == 1: log.debug("1 retry left") else: - log.debug("%i retries left", remaining) + log.debug("%i retries left", remaining_retries) - timeout = self._calculate_retry_timeout(remaining, options, response_headers) + timeout = self._calculate_retry_timeout(remaining_retries, options, response_headers) log.info("Retrying request to %s in %f seconds", options.url, timeout) await anyio.sleep(timeout) @@ -1648,7 +1656,7 @@ async def _retry_request( return await self._request( options=options, cast_to=cast_to, - remaining_retries=remaining, + retries_taken=retries_taken + 1, stream=stream, stream_cls=stream_cls, ) diff --git a/src/openai/lib/azure.py b/src/openai/lib/azure.py index ef64137de4..5d21f10b70 100644 --- a/src/openai/lib/azure.py +++ b/src/openai/lib/azure.py @@ -53,13 +53,15 @@ class BaseAzureClient(BaseClient[_HttpxClientT, _DefaultStreamT]): def _build_request( self, options: FinalRequestOptions, + *, + retries_taken: int = 0, ) -> httpx.Request: if options.url in _deployments_endpoints and is_mapping(options.json_data): model = options.json_data.get("model") if model is not None and not "/deployments" in str(self.base_url): options.url = f"/deployments/{model}{options.url}" - return super()._build_request(options) + return super()._build_request(options, retries_taken=retries_taken) class AzureOpenAI(BaseAzureClient[httpx.Client, Stream[Any]], OpenAI): diff --git a/tests/test_client.py b/tests/test_client.py index 054ae0ff4e..567a6ec59f 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -788,6 +788,10 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: ) assert response.retries_taken == failures_before_success + if failures_before_success == 0: + assert "x-stainless-retry-count" not in response.http_request.headers + else: + assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @@ -818,6 +822,10 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: model="gpt-4o", ) as response: assert response.retries_taken == failures_before_success + if failures_before_success == 0: + assert "x-stainless-retry-count" not in response.http_request.headers + else: + assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success class TestAsyncOpenAI: @@ -1582,6 +1590,10 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: ) assert response.retries_taken == failures_before_success + if failures_before_success == 0: + assert "x-stainless-retry-count" not in response.http_request.headers + else: + assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @@ -1613,3 +1625,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: model="gpt-4o", ) as response: assert response.retries_taken == failures_before_success + if failures_before_success == 0: + assert "x-stainless-retry-count" not in response.http_request.headers + else: + assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success From eab2e5a396ae5d114cf63cb26f30070ccad8b0b1 Mon Sep 17 00:00:00 2001 From: Stainless Bot Date: Thu, 19 Sep 2024 16:26:25 +0000 Subject: [PATCH 021/769] chore(types): improve type name for embedding models (#1730) --- .stats.yml | 2 +- api.md | 2 +- src/openai/resources/embeddings.py | 9 ++++----- src/openai/types/__init__.py | 1 + src/openai/types/embedding_create_params.py | 4 +++- src/openai/types/embedding_model.py | 7 +++++++ 6 files changed, 17 insertions(+), 8 deletions(-) create mode 100644 src/openai/types/embedding_model.py diff --git a/.stats.yml b/.stats.yml index 2fc39385e9..0151c5a105 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 68 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-ff407aa10917e62f2b0c12d1ad2c4f1258ed083bd45753c70eaaf5b1cf8356ae.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-de1981b64ac229493473670d618500c6362c195f1057eb7de00bd1bc9184fbd5.yml diff --git a/api.md b/api.md index 32c0fb9efc..2498340328 100644 --- a/api.md +++ b/api.md @@ -70,7 +70,7 @@ Methods: Types: ```python -from openai.types import CreateEmbeddingResponse, Embedding +from openai.types import CreateEmbeddingResponse, Embedding, EmbeddingModel ``` Methods: diff --git a/src/openai/resources/embeddings.py b/src/openai/resources/embeddings.py index 71c2a18a24..c91e6cc13a 100644 --- a/src/openai/resources/embeddings.py +++ b/src/openai/resources/embeddings.py @@ -16,9 +16,8 @@ from .._extras import numpy as np, has_numpy from .._resource import SyncAPIResource, AsyncAPIResource from .._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from .._base_client import ( - make_request_options, -) +from .._base_client import make_request_options +from ..types.embedding_model import EmbeddingModel from ..types.create_embedding_response import CreateEmbeddingResponse __all__ = ["Embeddings", "AsyncEmbeddings"] @@ -48,7 +47,7 @@ def create( self, *, input: Union[str, List[str], Iterable[int], Iterable[Iterable[int]]], - model: Union[str, Literal["text-embedding-ada-002", "text-embedding-3-small", "text-embedding-3-large"]], + model: Union[str, EmbeddingModel], dimensions: int | NotGiven = NOT_GIVEN, encoding_format: Literal["float", "base64"] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, @@ -160,7 +159,7 @@ async def create( self, *, input: Union[str, List[str], Iterable[int], Iterable[Iterable[int]]], - model: Union[str, Literal["text-embedding-ada-002", "text-embedding-3-small", "text-embedding-3-large"]], + model: Union[str, EmbeddingModel], dimensions: int | NotGiven = NOT_GIVEN, encoding_format: Literal["float", "base64"] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, diff --git a/src/openai/types/__init__.py b/src/openai/types/__init__.py index ad9284fbd5..4dbc1b6b7b 100644 --- a/src/openai/types/__init__.py +++ b/src/openai/types/__init__.py @@ -26,6 +26,7 @@ from .file_deleted import FileDeleted as FileDeleted from .file_purpose import FilePurpose as FilePurpose from .model_deleted import ModelDeleted as ModelDeleted +from .embedding_model import EmbeddingModel as EmbeddingModel from .images_response import ImagesResponse as ImagesResponse from .completion_usage import CompletionUsage as CompletionUsage from .file_list_params import FileListParams as FileListParams diff --git a/src/openai/types/embedding_create_params.py b/src/openai/types/embedding_create_params.py index 930b3b7914..1548cdbd77 100644 --- a/src/openai/types/embedding_create_params.py +++ b/src/openai/types/embedding_create_params.py @@ -5,6 +5,8 @@ from typing import List, Union, Iterable from typing_extensions import Literal, Required, TypedDict +from .embedding_model import EmbeddingModel + __all__ = ["EmbeddingCreateParams"] @@ -20,7 +22,7 @@ class EmbeddingCreateParams(TypedDict, total=False): for counting tokens. """ - model: Required[Union[str, Literal["text-embedding-ada-002", "text-embedding-3-small", "text-embedding-3-large"]]] + model: Required[Union[str, EmbeddingModel]] """ID of the model to use. You can use the diff --git a/src/openai/types/embedding_model.py b/src/openai/types/embedding_model.py new file mode 100644 index 0000000000..075ff97644 --- /dev/null +++ b/src/openai/types/embedding_model.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["EmbeddingModel"] + +EmbeddingModel: TypeAlias = Literal["text-embedding-ada-002", "text-embedding-3-small", "text-embedding-3-large"] From 45315a7a7fef522a56b4c86558f2e07ebea4f71a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Sep 2024 05:04:20 +0000 Subject: [PATCH 022/769] release: 1.47.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index d89af66b28..dc9bcb375c 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.46.1" + ".": "1.47.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f1c96e6d5..021be7ef4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 1.47.0 (2024-09-20) + +Full Changelog: [v1.46.1...v1.47.0](https://github.com/openai/openai-python/compare/v1.46.1...v1.47.0) + +### Features + +* **client:** send retry count header ([21b0c00](https://github.com/openai/openai-python/commit/21b0c0043406d81971f87455e5a48b17935dc346)) + + +### Chores + +* **types:** improve type name for embedding models ([#1730](https://github.com/openai/openai-python/issues/1730)) ([4b4eb2b](https://github.com/openai/openai-python/commit/4b4eb2b37877728d2124ad5651ceebf615c0ab28)) + ## 1.46.1 (2024-09-19) Full Changelog: [v1.46.0...v1.46.1](https://github.com/openai/openai-python/compare/v1.46.0...v1.46.1) diff --git a/pyproject.toml b/pyproject.toml index b505880f11..5288d5aa10 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.46.1" +version = "1.47.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 197a24ea67..509df1e880 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.46.1" # x-release-please-version +__version__ = "1.47.0" # x-release-please-version From 5b2dbcd9ba17a4cb897697d90e66175b640e5780 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Mon, 23 Sep 2024 11:18:41 +0100 Subject: [PATCH 023/769] fix(pydantic v1): avoid warnings error --- src/openai/_compat.py | 2 ++ src/openai/lib/streaming/_assistants.py | 11 ++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/openai/_compat.py b/src/openai/_compat.py index c0dd8c1ee5..78851277eb 100644 --- a/src/openai/_compat.py +++ b/src/openai/_compat.py @@ -136,12 +136,14 @@ def model_dump( exclude: IncEx = None, exclude_unset: bool = False, exclude_defaults: bool = False, + warnings: bool = True, ) -> dict[str, Any]: if PYDANTIC_V2: return model.model_dump( exclude=exclude, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, + warnings=warnings, ) return cast( "dict[str, Any]", diff --git a/src/openai/lib/streaming/_assistants.py b/src/openai/lib/streaming/_assistants.py index 183754177a..103e4c40aa 100644 --- a/src/openai/lib/streaming/_assistants.py +++ b/src/openai/lib/streaming/_assistants.py @@ -8,6 +8,7 @@ import httpx from ..._utils import is_dict, is_list, consume_sync_iterator, consume_async_iterator +from ..._compat import model_dump from ..._models import construct_type from ..._streaming import Stream, AsyncStream from ...types.beta import AssistantStreamEvent @@ -906,11 +907,11 @@ def accumulate_run_step( merged = accumulate_delta( cast( "dict[object, object]", - snapshot.model_dump(exclude_unset=True, warnings=False), + model_dump(snapshot, exclude_unset=True, warnings=False), ), cast( "dict[object, object]", - data.delta.model_dump(exclude_unset=True, warnings=False), + model_dump(data.delta, exclude_unset=True, warnings=False), ), ) run_step_snapshots[snapshot.id] = cast(RunStep, construct_type(type_=RunStep, value=merged)) @@ -948,7 +949,7 @@ def accumulate_event( construct_type( # mypy doesn't allow Content for some reason type_=cast(Any, MessageContent), - value=content_delta.model_dump(exclude_unset=True, warnings=False), + value=model_dump(content_delta, exclude_unset=True, warnings=False), ), ), ) @@ -957,11 +958,11 @@ def accumulate_event( merged = accumulate_delta( cast( "dict[object, object]", - block.model_dump(exclude_unset=True, warnings=False), + model_dump(block, exclude_unset=True, warnings=False), ), cast( "dict[object, object]", - content_delta.model_dump(exclude_unset=True, warnings=False), + model_dump(content_delta, exclude_unset=True, warnings=False), ), ) current_message_snapshot.content[content_delta.index] = cast( From 89e5a010b22136f0f16eff5ec33105f4d3e273eb Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Sep 2024 10:20:25 +0000 Subject: [PATCH 024/769] release: 1.47.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index dc9bcb375c..fea051a9dd 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.47.0" + ".": "1.47.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 021be7ef4c..823e9886d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.47.1 (2024-09-23) + +Full Changelog: [v1.47.0...v1.47.1](https://github.com/openai/openai-python/compare/v1.47.0...v1.47.1) + +### Bug Fixes + +* **pydantic v1:** avoid warnings error ([1e8e7d1](https://github.com/openai/openai-python/commit/1e8e7d1f01a4ab4153085bc20484a19613d993b3)) + ## 1.47.0 (2024-09-20) Full Changelog: [v1.46.1...v1.47.0](https://github.com/openai/openai-python/compare/v1.46.1...v1.47.0) diff --git a/pyproject.toml b/pyproject.toml index 5288d5aa10..e4b8a967e0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.47.0" +version = "1.47.1" 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 509df1e880..cad4b7f76c 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.47.0" # x-release-please-version +__version__ = "1.47.1" # x-release-please-version From fd1ed4b5e3828a14074018a30ce42d3960741ccd Mon Sep 17 00:00:00 2001 From: Stainless Bot Date: Tue, 24 Sep 2024 14:58:33 +0000 Subject: [PATCH 025/769] chore(internal): use `typing_extensions.overload` instead of `typing` (#1740) --- src/openai/resources/beta/threads/runs/runs.py | 4 ++-- src/openai/resources/beta/threads/threads.py | 4 ++-- src/openai/resources/chat/completions.py | 4 ++-- src/openai/resources/completions.py | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/openai/resources/beta/threads/runs/runs.py b/src/openai/resources/beta/threads/runs/runs.py index 3fb1cc77aa..a4cbcc57e4 100644 --- a/src/openai/resources/beta/threads/runs/runs.py +++ b/src/openai/resources/beta/threads/runs/runs.py @@ -3,9 +3,9 @@ from __future__ import annotations import typing_extensions -from typing import List, Union, Iterable, Optional, overload +from typing import List, Union, Iterable, Optional from functools import partial -from typing_extensions import Literal +from typing_extensions import Literal, overload import httpx diff --git a/src/openai/resources/beta/threads/threads.py b/src/openai/resources/beta/threads/threads.py index 49b0e4b37e..acc0fe9bda 100644 --- a/src/openai/resources/beta/threads/threads.py +++ b/src/openai/resources/beta/threads/threads.py @@ -2,9 +2,9 @@ from __future__ import annotations -from typing import Union, Iterable, Optional, overload +from typing import Union, Iterable, Optional from functools import partial -from typing_extensions import Literal +from typing_extensions import Literal, overload import httpx diff --git a/src/openai/resources/chat/completions.py b/src/openai/resources/chat/completions.py index e9267b1f03..05cfaacd83 100644 --- a/src/openai/resources/chat/completions.py +++ b/src/openai/resources/chat/completions.py @@ -3,8 +3,8 @@ from __future__ import annotations import inspect -from typing import Dict, List, Union, Iterable, Optional, overload -from typing_extensions import Literal +from typing import Dict, List, Union, Iterable, Optional +from typing_extensions import Literal, overload import httpx import pydantic diff --git a/src/openai/resources/completions.py b/src/openai/resources/completions.py index 091fb5657a..49198d2687 100644 --- a/src/openai/resources/completions.py +++ b/src/openai/resources/completions.py @@ -2,8 +2,8 @@ from __future__ import annotations -from typing import Dict, List, Union, Iterable, Optional, overload -from typing_extensions import Literal +from typing import Dict, List, Union, Iterable, Optional +from typing_extensions import Literal, overload import httpx From 102fce4f363d9996ef40b81cbe79fd29c3e7ccc1 Mon Sep 17 00:00:00 2001 From: Stainless Bot Date: Wed, 25 Sep 2024 12:43:48 +0000 Subject: [PATCH 026/769] fix(audio): correct response_format translations type (#1743) --- .DS_Store | Bin 0 -> 6148 bytes .stats.yml | 2 +- api.md | 2 +- src/openai/resources/audio/transcriptions.py | 14 ++++++++------ src/openai/resources/audio/translations.py | 14 ++++++++------ src/openai/types/__init__.py | 1 + .../types/audio/transcription_create_params.py | 7 ++++--- .../types/audio/translation_create_params.py | 7 ++++--- src/openai/types/audio_response_format.py | 7 +++++++ tests/api_resources/audio/test_translations.py | 8 ++++---- 10 files changed, 38 insertions(+), 24 deletions(-) create mode 100644 .DS_Store create mode 100644 src/openai/types/audio_response_format.py diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..c88a062b05be4fd1d362b3e4c6a7481e718b69d0 GIT binary patch literal 6148 zcmeH~O$x$5422WzLU7Zi%h`AUZ!n0Spcima5J4*Vx1OW>k_m#k8KJGkN^pg011%5 z4-v3?8#bF)Wh4O-Ab}?V`#vPNX$~z_{nLTqBLK8P*$r!-C7{U)&>UK-q5{*H9yD6j z#}KP~J2b_)99pW@cF`C;crrWIXQgOGwy`I%~QMGk}L;X0y%TE9jyNVZZH|!@{KyzrRiVBQB0*--!1inh( E0rZ6u#{d8T literal 0 HcmV?d00001 diff --git a/.stats.yml b/.stats.yml index 0151c5a105..e8bca3c6d8 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 68 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-de1981b64ac229493473670d618500c6362c195f1057eb7de00bd1bc9184fbd5.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-073331021d48db6af646a3552ab0c682efe31b7fb4e59a109ed1ba539f9b89c5.yml diff --git a/api.md b/api.md index 2498340328..eae17d8d84 100644 --- a/api.md +++ b/api.md @@ -114,7 +114,7 @@ Methods: Types: ```python -from openai.types import AudioModel +from openai.types import AudioModel, AudioResponseFormat ``` ## Transcriptions diff --git a/src/openai/resources/audio/transcriptions.py b/src/openai/resources/audio/transcriptions.py index a6009143d4..fd042d1ac3 100644 --- a/src/openai/resources/audio/transcriptions.py +++ b/src/openai/resources/audio/transcriptions.py @@ -8,6 +8,7 @@ import httpx from ... import _legacy_response +from ...types import AudioResponseFormat from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven, FileTypes from ..._utils import ( extract_files, @@ -22,6 +23,7 @@ from ..._base_client import make_request_options from ...types.audio_model import AudioModel from ...types.audio.transcription import Transcription +from ...types.audio_response_format import AudioResponseFormat __all__ = ["Transcriptions", "AsyncTranscriptions"] @@ -53,7 +55,7 @@ def create( model: Union[str, AudioModel], language: str | NotGiven = NOT_GIVEN, prompt: str | NotGiven = NOT_GIVEN, - response_format: Literal["json", "text", "srt", "verbose_json", "vtt"] | NotGiven = NOT_GIVEN, + response_format: AudioResponseFormat | NotGiven = NOT_GIVEN, temperature: float | NotGiven = NOT_GIVEN, timestamp_granularities: List[Literal["word", "segment"]] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -83,8 +85,8 @@ def create( [prompt](https://platform.openai.com/docs/guides/speech-to-text/prompting) should match the audio language. - response_format: The format of the transcript output, in one of these options: `json`, `text`, - `srt`, `verbose_json`, or `vtt`. + response_format: The format of the output, in one of these options: `json`, `text`, `srt`, + `verbose_json`, or `vtt`. temperature: The sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and @@ -160,7 +162,7 @@ async def create( model: Union[str, AudioModel], language: str | NotGiven = NOT_GIVEN, prompt: str | NotGiven = NOT_GIVEN, - response_format: Literal["json", "text", "srt", "verbose_json", "vtt"] | NotGiven = NOT_GIVEN, + response_format: AudioResponseFormat | NotGiven = NOT_GIVEN, temperature: float | NotGiven = NOT_GIVEN, timestamp_granularities: List[Literal["word", "segment"]] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -190,8 +192,8 @@ async def create( [prompt](https://platform.openai.com/docs/guides/speech-to-text/prompting) should match the audio language. - response_format: The format of the transcript output, in one of these options: `json`, `text`, - `srt`, `verbose_json`, or `vtt`. + response_format: The format of the output, in one of these options: `json`, `text`, `srt`, + `verbose_json`, or `vtt`. temperature: The sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and diff --git a/src/openai/resources/audio/translations.py b/src/openai/resources/audio/translations.py index 7ec647fb6b..fe08dd550e 100644 --- a/src/openai/resources/audio/translations.py +++ b/src/openai/resources/audio/translations.py @@ -7,6 +7,7 @@ import httpx from ... import _legacy_response +from ...types import AudioResponseFormat from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven, FileTypes from ..._utils import ( extract_files, @@ -21,6 +22,7 @@ from ..._base_client import make_request_options from ...types.audio_model import AudioModel from ...types.audio.translation import Translation +from ...types.audio_response_format import AudioResponseFormat __all__ = ["Translations", "AsyncTranslations"] @@ -51,7 +53,7 @@ def create( file: FileTypes, model: Union[str, AudioModel], prompt: str | NotGiven = NOT_GIVEN, - response_format: str | NotGiven = NOT_GIVEN, + response_format: AudioResponseFormat | NotGiven = NOT_GIVEN, temperature: float | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -75,8 +77,8 @@ def create( [prompt](https://platform.openai.com/docs/guides/speech-to-text/prompting) should be in English. - response_format: The format of the transcript output, in one of these options: `json`, `text`, - `srt`, `verbose_json`, or `vtt`. + response_format: The format of the output, in one of these options: `json`, `text`, `srt`, + `verbose_json`, or `vtt`. temperature: The sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and @@ -143,7 +145,7 @@ async def create( file: FileTypes, model: Union[str, AudioModel], prompt: str | NotGiven = NOT_GIVEN, - response_format: str | NotGiven = NOT_GIVEN, + response_format: AudioResponseFormat | NotGiven = NOT_GIVEN, temperature: float | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -167,8 +169,8 @@ async def create( [prompt](https://platform.openai.com/docs/guides/speech-to-text/prompting) should be in English. - response_format: The format of the transcript output, in one of these options: `json`, `text`, - `srt`, `verbose_json`, or `vtt`. + response_format: The format of the output, in one of these options: `json`, `text`, `srt`, + `verbose_json`, or `vtt`. temperature: The sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and diff --git a/src/openai/types/__init__.py b/src/openai/types/__init__.py index 4dbc1b6b7b..6223be883d 100644 --- a/src/openai/types/__init__.py +++ b/src/openai/types/__init__.py @@ -38,6 +38,7 @@ from .batch_create_params import BatchCreateParams as BatchCreateParams from .batch_request_counts import BatchRequestCounts as BatchRequestCounts from .upload_create_params import UploadCreateParams as UploadCreateParams +from .audio_response_format import AudioResponseFormat as AudioResponseFormat from .image_generate_params import ImageGenerateParams as ImageGenerateParams from .upload_complete_params import UploadCompleteParams as UploadCompleteParams from .embedding_create_params import EmbeddingCreateParams as EmbeddingCreateParams diff --git a/src/openai/types/audio/transcription_create_params.py b/src/openai/types/audio/transcription_create_params.py index a825fefecb..5ac2bb91e5 100644 --- a/src/openai/types/audio/transcription_create_params.py +++ b/src/openai/types/audio/transcription_create_params.py @@ -7,6 +7,7 @@ from ..._types import FileTypes from ..audio_model import AudioModel +from ..audio_response_format import AudioResponseFormat __all__ = ["TranscriptionCreateParams"] @@ -41,10 +42,10 @@ class TranscriptionCreateParams(TypedDict, total=False): should match the audio language. """ - response_format: Literal["json", "text", "srt", "verbose_json", "vtt"] + response_format: AudioResponseFormat """ - The format of the transcript output, in one of these options: `json`, `text`, - `srt`, `verbose_json`, or `vtt`. + The format of the output, in one of these options: `json`, `text`, `srt`, + `verbose_json`, or `vtt`. """ temperature: float diff --git a/src/openai/types/audio/translation_create_params.py b/src/openai/types/audio/translation_create_params.py index 054996a134..6859ed9d30 100644 --- a/src/openai/types/audio/translation_create_params.py +++ b/src/openai/types/audio/translation_create_params.py @@ -7,6 +7,7 @@ from ..._types import FileTypes from ..audio_model import AudioModel +from ..audio_response_format import AudioResponseFormat __all__ = ["TranslationCreateParams"] @@ -33,10 +34,10 @@ class TranslationCreateParams(TypedDict, total=False): should be in English. """ - response_format: str + response_format: AudioResponseFormat """ - The format of the transcript output, in one of these options: `json`, `text`, - `srt`, `verbose_json`, or `vtt`. + The format of the output, in one of these options: `json`, `text`, `srt`, + `verbose_json`, or `vtt`. """ temperature: float diff --git a/src/openai/types/audio_response_format.py b/src/openai/types/audio_response_format.py new file mode 100644 index 0000000000..f8c8d45945 --- /dev/null +++ b/src/openai/types/audio_response_format.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["AudioResponseFormat"] + +AudioResponseFormat: TypeAlias = Literal["json", "text", "srt", "verbose_json", "vtt"] diff --git a/tests/api_resources/audio/test_translations.py b/tests/api_resources/audio/test_translations.py index f5c6c68f0b..b048a1af12 100644 --- a/tests/api_resources/audio/test_translations.py +++ b/tests/api_resources/audio/test_translations.py @@ -30,8 +30,8 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: translation = client.audio.translations.create( file=b"raw file contents", model="whisper-1", - prompt="string", - response_format="string", + prompt="prompt", + response_format="json", temperature=0, ) assert_matches_type(Translation, translation, path=["response"]) @@ -79,8 +79,8 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> translation = await async_client.audio.translations.create( file=b"raw file contents", model="whisper-1", - prompt="string", - response_format="string", + prompt="prompt", + response_format="json", temperature=0, ) assert_matches_type(Translation, translation, path=["response"]) From 5449e208bcf1bcf6c4a25a33f2144c7bfd8acdb3 Mon Sep 17 00:00:00 2001 From: Stainless Bot Date: Wed, 25 Sep 2024 12:45:37 +0000 Subject: [PATCH 027/769] feat(client): allow overriding retry count header (#1745) --- src/openai/_base_client.py | 6 +- tests/test_client.py | 150 +++++++++++++++++++++++++++++++++---- 2 files changed, 138 insertions(+), 18 deletions(-) diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index 77e82026ef..c4c9803e74 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -413,8 +413,10 @@ 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() - if retries_taken > 0: - headers.setdefault("x-stainless-retry-count", str(retries_taken)) + # Don't set the retry count header if it was 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): + headers["x-stainless-retry-count"] = str(retries_taken) return headers diff --git a/tests/test_client.py b/tests/test_client.py index 567a6ec59f..463174465c 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -788,10 +788,71 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: ) assert response.retries_taken == failures_before_success - if failures_before_success == 0: - assert "x-stainless-retry-count" not in response.http_request.headers - else: - assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success + assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success + + @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) + @mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) + @pytest.mark.respx(base_url=base_url) + def test_omit_retry_count_header( + self, client: OpenAI, failures_before_success: int, respx_mock: MockRouter + ) -> None: + client = client.with_options(max_retries=4) + + nb_retries = 0 + + def retry_handler(_request: httpx.Request) -> httpx.Response: + nonlocal nb_retries + if nb_retries < failures_before_success: + nb_retries += 1 + return httpx.Response(500) + return httpx.Response(200) + + respx_mock.post("/chat/completions").mock(side_effect=retry_handler) + + response = client.chat.completions.with_raw_response.create( + messages=[ + { + "content": "string", + "role": "system", + } + ], + model="gpt-4o", + extra_headers={"x-stainless-retry-count": Omit()}, + ) + + assert len(response.http_request.headers.get_list("x-stainless-retry-count")) == 0 + + @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) + @mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) + @pytest.mark.respx(base_url=base_url) + def test_overwrite_retry_count_header( + self, client: OpenAI, failures_before_success: int, respx_mock: MockRouter + ) -> None: + client = client.with_options(max_retries=4) + + nb_retries = 0 + + def retry_handler(_request: httpx.Request) -> httpx.Response: + nonlocal nb_retries + if nb_retries < failures_before_success: + nb_retries += 1 + return httpx.Response(500) + return httpx.Response(200) + + respx_mock.post("/chat/completions").mock(side_effect=retry_handler) + + response = client.chat.completions.with_raw_response.create( + messages=[ + { + "content": "string", + "role": "system", + } + ], + model="gpt-4o", + extra_headers={"x-stainless-retry-count": "42"}, + ) + + assert response.http_request.headers.get("x-stainless-retry-count") == "42" @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @@ -822,10 +883,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: model="gpt-4o", ) as response: assert response.retries_taken == failures_before_success - if failures_before_success == 0: - assert "x-stainless-retry-count" not in response.http_request.headers - else: - assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success + assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success class TestAsyncOpenAI: @@ -1590,10 +1648,73 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: ) assert response.retries_taken == failures_before_success - if failures_before_success == 0: - assert "x-stainless-retry-count" not in response.http_request.headers - else: - assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success + assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success + + @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) + @mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) + @pytest.mark.respx(base_url=base_url) + @pytest.mark.asyncio + async def test_omit_retry_count_header( + self, async_client: AsyncOpenAI, failures_before_success: int, respx_mock: MockRouter + ) -> None: + client = async_client.with_options(max_retries=4) + + nb_retries = 0 + + def retry_handler(_request: httpx.Request) -> httpx.Response: + nonlocal nb_retries + if nb_retries < failures_before_success: + nb_retries += 1 + return httpx.Response(500) + return httpx.Response(200) + + respx_mock.post("/chat/completions").mock(side_effect=retry_handler) + + response = await client.chat.completions.with_raw_response.create( + messages=[ + { + "content": "string", + "role": "system", + } + ], + model="gpt-4o", + extra_headers={"x-stainless-retry-count": Omit()}, + ) + + assert len(response.http_request.headers.get_list("x-stainless-retry-count")) == 0 + + @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) + @mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) + @pytest.mark.respx(base_url=base_url) + @pytest.mark.asyncio + async def test_overwrite_retry_count_header( + self, async_client: AsyncOpenAI, failures_before_success: int, respx_mock: MockRouter + ) -> None: + client = async_client.with_options(max_retries=4) + + nb_retries = 0 + + def retry_handler(_request: httpx.Request) -> httpx.Response: + nonlocal nb_retries + if nb_retries < failures_before_success: + nb_retries += 1 + return httpx.Response(500) + return httpx.Response(200) + + respx_mock.post("/chat/completions").mock(side_effect=retry_handler) + + response = await client.chat.completions.with_raw_response.create( + messages=[ + { + "content": "string", + "role": "system", + } + ], + model="gpt-4o", + extra_headers={"x-stainless-retry-count": "42"}, + ) + + assert response.http_request.headers.get("x-stainless-retry-count") == "42" @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @@ -1625,7 +1746,4 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: model="gpt-4o", ) as response: assert response.retries_taken == failures_before_success - if failures_before_success == 0: - assert "x-stainless-retry-count" not in response.http_request.headers - else: - assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success + assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success From 864eafca8f9626c13a5864c133ca620d1cbecf89 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Sep 2024 13:21:13 +0000 Subject: [PATCH 028/769] release: 1.48.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 18 ++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index fea051a9dd..3f47f4bc2b 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.47.1" + ".": "1.48.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 823e9886d8..d89151074b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ # Changelog +## 1.48.0 (2024-09-25) + +Full Changelog: [v1.47.1...v1.48.0](https://github.com/openai/openai-python/compare/v1.47.1...v1.48.0) + +### Features + +* **client:** allow overriding retry count header ([#1745](https://github.com/openai/openai-python/issues/1745)) ([9f07d4d](https://github.com/openai/openai-python/commit/9f07d4dbd6f24108a1f5e0309037318858f5a229)) + + +### Bug Fixes + +* **audio:** correct response_format translations type ([#1743](https://github.com/openai/openai-python/issues/1743)) ([b912108](https://github.com/openai/openai-python/commit/b9121089c696bc943323e2e75d4706401d809aaa)) + + +### Chores + +* **internal:** use `typing_extensions.overload` instead of `typing` ([#1740](https://github.com/openai/openai-python/issues/1740)) ([2522bd5](https://github.com/openai/openai-python/commit/2522bd59f7b5e903e4fc856a4c5dbdbe66bba37f)) + ## 1.47.1 (2024-09-23) Full Changelog: [v1.47.0...v1.47.1](https://github.com/openai/openai-python/compare/v1.47.0...v1.47.1) diff --git a/pyproject.toml b/pyproject.toml index e4b8a967e0..05f957cac0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.47.1" +version = "1.48.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 cad4b7f76c..66109f354b 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.47.1" # x-release-please-version +__version__ = "1.48.0" # x-release-please-version From 9feadd8274809fff9ff1e36a0c90d45566ed46e2 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Thu, 26 Sep 2024 11:34:40 +0100 Subject: [PATCH 029/769] chore(internal): update test snapshots (#1749) --- ...661f4f5bea321c0aac9e164f2ed3e409aebc48.bin | 102 ----- ...2625e557f9e6763bd8c03bcd88e220149a3367.bin | 224 ----------- ...cf4aa41fc428937c231e17c3460f3237f6a018.bin | 28 -- ...6aea6d0356b63140161758a2e576d4e3092cfa.bin | 36 -- ...f8d591fb691ebac56f5ae39a22cc7d455c5353.bin | 28 ++ ...849decc68d3f63bd38172889367e1afb1e04f7.bin | 22 ++ ...fd3deafe041da94d541071009596234d8c84a6.bin | 36 -- ...3dfcc25dc2f57a5e05eb5cc46c70b51d8845c2.bin | 52 --- ...af1246f55edb6ad95fa24059f160996b68866d.bin | 10 + ...f7868df0b6d8a02dfcd23f6bc7196cf0eadb6e.bin | 28 -- ...6dd33878095c68badc6b6654a69769b391a1c1.bin | 30 ++ ...f0afcd22d4f0e85418ab38ee24d2a570a84ff0.bin | 10 - ...5e65923f182256b6e6b752950a3aaa2ad2320a.bin | 36 ++ ...542b954b37d9dfd1910b964ddebc9677e6ae85.bin | 12 + ...9d46ee41408a688758219f3f58ac1ee2084db3.bin | 28 -- ...5dfafc1d712c253b42bafe07991b3058541016.bin | 156 -------- ...6ad615ed8d8f649888ebfddfbc3ee151f44d46.bin | 28 ++ ...f60f7f745f1a56d82e62f58031cc2add502380.bin | 100 +++++ ...613bdb9c4a2ad8262027d158cc94e6f9765164.bin | 12 - ...05d4daf7e8ad6d61ffa406ab5361fe36a8d5b1.bin | 36 ++ ...f8694b77f608de5e2a3799276be06ce3fbb15b.bin | 30 -- ...8bb74642d23ac1ca13fe37cb6e889b66f759f6.bin | 362 ++++++++++++++++++ ...81772c3010c10b37e8af3996fbdbbecb3c32a2.bin | 22 -- ...47020a9d875eb7ce644a0ff355581690a4cbfd.bin | 68 ++++ ...7688be2f6ca0849a6e4f17851b517310841d9b.bin | 52 +++ tests/lib/chat/test_completions.py | 132 ++++--- tests/lib/chat/test_completions_streaming.py | 263 ++++++------- 27 files changed, 970 insertions(+), 973 deletions(-) delete mode 100644 .inline-snapshot/external/038a5c69c34c9513021b52aa61661f4f5bea321c0aac9e164f2ed3e409aebc48.bin delete mode 100644 .inline-snapshot/external/0898f3d1651e3244eeb3651d012625e557f9e6763bd8c03bcd88e220149a3367.bin delete mode 100644 .inline-snapshot/external/0a00cd46c61030ff70241d432dcf4aa41fc428937c231e17c3460f3237f6a018.bin delete mode 100644 .inline-snapshot/external/15ae68f793c7b390fc8af9e21a6aea6d0356b63140161758a2e576d4e3092cfa.bin create mode 100644 .inline-snapshot/external/173417d553406f034f643e5db3f8d591fb691ebac56f5ae39a22cc7d455c5353.bin create mode 100644 .inline-snapshot/external/2018feb66ae13fcf5333d61b95849decc68d3f63bd38172889367e1afb1e04f7.bin delete mode 100644 .inline-snapshot/external/24aaf30663f9a568a0e77970b4fd3deafe041da94d541071009596234d8c84a6.bin delete mode 100644 .inline-snapshot/external/453df473e96274dd8ab61ab4d13dfcc25dc2f57a5e05eb5cc46c70b51d8845c2.bin create mode 100644 .inline-snapshot/external/4cc50a6135d254573a502310e6af1246f55edb6ad95fa24059f160996b68866d.bin delete mode 100644 .inline-snapshot/external/4d75e4d7c3e0b532a67fb2114ff7868df0b6d8a02dfcd23f6bc7196cf0eadb6e.bin create mode 100644 .inline-snapshot/external/569c877e69429d4cbc1577d2cd6dd33878095c68badc6b6654a69769b391a1c1.bin delete mode 100644 .inline-snapshot/external/69363a555f8ea9b6eee0bb022af0afcd22d4f0e85418ab38ee24d2a570a84ff0.bin create mode 100644 .inline-snapshot/external/7e5ea4d12e7cc064399b6631415e65923f182256b6e6b752950a3aaa2ad2320a.bin create mode 100644 .inline-snapshot/external/83b060bae42eb41c4f1edbb7c1542b954b37d9dfd1910b964ddebc9677e6ae85.bin delete mode 100644 .inline-snapshot/external/83d3d003e6fdaa69b7a398440f9d46ee41408a688758219f3f58ac1ee2084db3.bin delete mode 100644 .inline-snapshot/external/a0c4f0be184e8234cdc0e3abae5dfafc1d712c253b42bafe07991b3058541016.bin create mode 100644 .inline-snapshot/external/a247c49c5fcd492bfb7a02a3306ad615ed8d8f649888ebfddfbc3ee151f44d46.bin create mode 100644 .inline-snapshot/external/a491adda08c3d4fde95f5b2ee3f60f7f745f1a56d82e62f58031cc2add502380.bin delete mode 100644 .inline-snapshot/external/be1089999ca5f1e63b149447f1613bdb9c4a2ad8262027d158cc94e6f9765164.bin create mode 100644 .inline-snapshot/external/c6aa7e397b7123c3501f25df3a05d4daf7e8ad6d61ffa406ab5361fe36a8d5b1.bin delete mode 100644 .inline-snapshot/external/ca015b8b1ebaac98be76f2f855f8694b77f608de5e2a3799276be06ce3fbb15b.bin create mode 100644 .inline-snapshot/external/d615580118391ee13492193e3a8bb74642d23ac1ca13fe37cb6e889b66f759f6.bin delete mode 100644 .inline-snapshot/external/dae1b261f19722801adc82a13181772c3010c10b37e8af3996fbdbbecb3c32a2.bin create mode 100644 .inline-snapshot/external/e2aad469b71d1d4894ff833ea147020a9d875eb7ce644a0ff355581690a4cbfd.bin create mode 100644 .inline-snapshot/external/f82268f2fefd5cfbc7eeb59c297688be2f6ca0849a6e4f17851b517310841d9b.bin diff --git a/.inline-snapshot/external/038a5c69c34c9513021b52aa61661f4f5bea321c0aac9e164f2ed3e409aebc48.bin b/.inline-snapshot/external/038a5c69c34c9513021b52aa61661f4f5bea321c0aac9e164f2ed3e409aebc48.bin deleted file mode 100644 index a5a0aeb4c0..0000000000 --- a/.inline-snapshot/external/038a5c69c34c9513021b52aa61661f4f5bea321c0aac9e164f2ed3e409aebc48.bin +++ /dev/null @@ -1,102 +0,0 @@ -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"I'm"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" unable"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" to"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" provide"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" real"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"-time"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" updates"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" including"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" current"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" weather"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" information"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"."},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" For"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" the"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" latest"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" weather"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" San"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" Francisco"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" I"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" recommend"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" checking"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" a"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" reliable"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" weather"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" website"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" or"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" app"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" such"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" as"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" the"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" Weather"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" Channel"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" BBC"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" Weather"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" or"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" a"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" local"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" San"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" Francisco"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" news"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" station"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"."},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}]} - -data: {"id":"chatcmpl-9tXjg9DdaOfymTPDrSLfxslQEH0C2","object":"chat.completion.chunk","created":1723024748,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[],"usage":{"prompt_tokens":14,"completion_tokens":47,"total_tokens":61}} - -data: [DONE] - diff --git a/.inline-snapshot/external/0898f3d1651e3244eeb3651d012625e557f9e6763bd8c03bcd88e220149a3367.bin b/.inline-snapshot/external/0898f3d1651e3244eeb3651d012625e557f9e6763bd8c03bcd88e220149a3367.bin deleted file mode 100644 index 4b42ada8d2..0000000000 --- a/.inline-snapshot/external/0898f3d1651e3244eeb3651d012625e557f9e6763bd8c03bcd88e220149a3367.bin +++ /dev/null @@ -1,224 +0,0 @@ -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"\n"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" {\n"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"location"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"San"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" Francisco"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" CA"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"\",\n"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"forecast"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"_date"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"202"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"3"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"-"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"11"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"-"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"02"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"\",\n"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"weather"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" {\n"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"temperature"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" {\n"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"current"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"N"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"/A"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"\",\n"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"high"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"N"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"/A"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"\",\n"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"low"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"N"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"/A"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"\"\n"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" },\n"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"condition"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"N"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"/A"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"\",\n"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"humidity"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"N"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"/A"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"\",\n"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"wind"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"_speed"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"N"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"/A"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"\"\n"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" },\n"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"note"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"Please"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" check"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" a"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" reliable"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" weather"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" service"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" for"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" the"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" most"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" current"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" information"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":".\"\n"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" }"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}]} - -data: {"id":"chatcmpl-9tXjrL8ZwahfIfWjgwcnHRzZrzVL4","object":"chat.completion.chunk","created":1723024759,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[],"usage":{"prompt_tokens":19,"completion_tokens":108,"total_tokens":127}} - -data: [DONE] - diff --git a/.inline-snapshot/external/0a00cd46c61030ff70241d432dcf4aa41fc428937c231e17c3460f3237f6a018.bin b/.inline-snapshot/external/0a00cd46c61030ff70241d432dcf4aa41fc428937c231e17c3460f3237f6a018.bin deleted file mode 100644 index 73de9d6cbc..0000000000 --- a/.inline-snapshot/external/0a00cd46c61030ff70241d432dcf4aa41fc428937c231e17c3460f3237f6a018.bin +++ /dev/null @@ -1,28 +0,0 @@ -data: {"id":"chatcmpl-9tXjmhJIrvp7TBeVxzzxmx8pp2UGY","object":"chat.completion.chunk","created":1723024754,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"role":"assistant","content":null,"refusal":""},"logprobs":{"content":null,"refusal":[]},"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjmhJIrvp7TBeVxzzxmx8pp2UGY","object":"chat.completion.chunk","created":1723024754,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"refusal":"I'm"},"logprobs":{"content":null,"refusal":[{"token":"I'm","logprob":-0.0016157961,"bytes":[73,39,109],"top_logprobs":[]}]},"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjmhJIrvp7TBeVxzzxmx8pp2UGY","object":"chat.completion.chunk","created":1723024754,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"refusal":" sorry"},"logprobs":{"content":null,"refusal":[{"token":" sorry","logprob":-0.78663874,"bytes":[32,115,111,114,114,121],"top_logprobs":[]}]},"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjmhJIrvp7TBeVxzzxmx8pp2UGY","object":"chat.completion.chunk","created":1723024754,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"refusal":","},"logprobs":{"content":null,"refusal":[{"token":",","logprob":-0.0000779144,"bytes":[44],"top_logprobs":[]}]},"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjmhJIrvp7TBeVxzzxmx8pp2UGY","object":"chat.completion.chunk","created":1723024754,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"refusal":" I"},"logprobs":{"content":null,"refusal":[{"token":" I","logprob":-0.5234622,"bytes":[32,73],"top_logprobs":[]}]},"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjmhJIrvp7TBeVxzzxmx8pp2UGY","object":"chat.completion.chunk","created":1723024754,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"refusal":" cannot"},"logprobs":{"content":null,"refusal":[{"token":" cannot","logprob":-0.52499557,"bytes":[32,99,97,110,110,111,116],"top_logprobs":[]}]},"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjmhJIrvp7TBeVxzzxmx8pp2UGY","object":"chat.completion.chunk","created":1723024754,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"refusal":" assist"},"logprobs":{"content":null,"refusal":[{"token":" assist","logprob":-0.015198289,"bytes":[32,97,115,115,105,115,116],"top_logprobs":[]}]},"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjmhJIrvp7TBeVxzzxmx8pp2UGY","object":"chat.completion.chunk","created":1723024754,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"refusal":" with"},"logprobs":{"content":null,"refusal":[{"token":" with","logprob":-0.00071648485,"bytes":[32,119,105,116,104],"top_logprobs":[]}]},"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjmhJIrvp7TBeVxzzxmx8pp2UGY","object":"chat.completion.chunk","created":1723024754,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"refusal":" that"},"logprobs":{"content":null,"refusal":[{"token":" that","logprob":-0.008114983,"bytes":[32,116,104,97,116],"top_logprobs":[]}]},"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjmhJIrvp7TBeVxzzxmx8pp2UGY","object":"chat.completion.chunk","created":1723024754,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"refusal":" request"},"logprobs":{"content":null,"refusal":[{"token":" request","logprob":-0.0013802331,"bytes":[32,114,101,113,117,101,115,116],"top_logprobs":[]}]},"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjmhJIrvp7TBeVxzzxmx8pp2UGY","object":"chat.completion.chunk","created":1723024754,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"refusal":"."},"logprobs":{"content":null,"refusal":[{"token":".","logprob":-3.4121115e-6,"bytes":[46],"top_logprobs":[]}]},"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjmhJIrvp7TBeVxzzxmx8pp2UGY","object":"chat.completion.chunk","created":1723024754,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}]} - -data: {"id":"chatcmpl-9tXjmhJIrvp7TBeVxzzxmx8pp2UGY","object":"chat.completion.chunk","created":1723024754,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[],"usage":{"prompt_tokens":17,"completion_tokens":11,"total_tokens":28}} - -data: [DONE] - diff --git a/.inline-snapshot/external/15ae68f793c7b390fc8af9e21a6aea6d0356b63140161758a2e576d4e3092cfa.bin b/.inline-snapshot/external/15ae68f793c7b390fc8af9e21a6aea6d0356b63140161758a2e576d4e3092cfa.bin deleted file mode 100644 index 1bcca1fceb..0000000000 --- a/.inline-snapshot/external/15ae68f793c7b390fc8af9e21a6aea6d0356b63140161758a2e576d4e3092cfa.bin +++ /dev/null @@ -1,36 +0,0 @@ -data: {"id":"chatcmpl-9tXji2y8kKxlOO3muVvfdJ7ECJVlD","object":"chat.completion.chunk","created":1723024750,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXji2y8kKxlOO3muVvfdJ7ECJVlD","object":"chat.completion.chunk","created":1723024750,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"{\""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXji2y8kKxlOO3muVvfdJ7ECJVlD","object":"chat.completion.chunk","created":1723024750,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"city"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXji2y8kKxlOO3muVvfdJ7ECJVlD","object":"chat.completion.chunk","created":1723024750,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"\":\""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXji2y8kKxlOO3muVvfdJ7ECJVlD","object":"chat.completion.chunk","created":1723024750,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"San"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXji2y8kKxlOO3muVvfdJ7ECJVlD","object":"chat.completion.chunk","created":1723024750,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" Francisco"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXji2y8kKxlOO3muVvfdJ7ECJVlD","object":"chat.completion.chunk","created":1723024750,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"\",\""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXji2y8kKxlOO3muVvfdJ7ECJVlD","object":"chat.completion.chunk","created":1723024750,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"temperature"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXji2y8kKxlOO3muVvfdJ7ECJVlD","object":"chat.completion.chunk","created":1723024750,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXji2y8kKxlOO3muVvfdJ7ECJVlD","object":"chat.completion.chunk","created":1723024750,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"68"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXji2y8kKxlOO3muVvfdJ7ECJVlD","object":"chat.completion.chunk","created":1723024750,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":",\""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXji2y8kKxlOO3muVvfdJ7ECJVlD","object":"chat.completion.chunk","created":1723024750,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"units"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXji2y8kKxlOO3muVvfdJ7ECJVlD","object":"chat.completion.chunk","created":1723024750,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"\":\""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXji2y8kKxlOO3muVvfdJ7ECJVlD","object":"chat.completion.chunk","created":1723024750,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"f"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXji2y8kKxlOO3muVvfdJ7ECJVlD","object":"chat.completion.chunk","created":1723024750,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"\"}"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXji2y8kKxlOO3muVvfdJ7ECJVlD","object":"chat.completion.chunk","created":1723024750,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}]} - -data: {"id":"chatcmpl-9tXji2y8kKxlOO3muVvfdJ7ECJVlD","object":"chat.completion.chunk","created":1723024750,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[],"usage":{"prompt_tokens":17,"completion_tokens":14,"total_tokens":31}} - -data: [DONE] - diff --git a/.inline-snapshot/external/173417d553406f034f643e5db3f8d591fb691ebac56f5ae39a22cc7d455c5353.bin b/.inline-snapshot/external/173417d553406f034f643e5db3f8d591fb691ebac56f5ae39a22cc7d455c5353.bin new file mode 100644 index 0000000000..49c6dce93f --- /dev/null +++ b/.inline-snapshot/external/173417d553406f034f643e5db3f8d591fb691ebac56f5ae39a22cc7d455c5353.bin @@ -0,0 +1,28 @@ +data: {"id":"chatcmpl-ABfw4IfQfCCrcuybFm41wJyxjbkz7","object":"chat.completion.chunk","created":1727346172,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"role":"assistant","content":null,"refusal":""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw4IfQfCCrcuybFm41wJyxjbkz7","object":"chat.completion.chunk","created":1727346172,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"refusal":"I'm"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw4IfQfCCrcuybFm41wJyxjbkz7","object":"chat.completion.chunk","created":1727346172,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"refusal":" sorry"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw4IfQfCCrcuybFm41wJyxjbkz7","object":"chat.completion.chunk","created":1727346172,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"refusal":","},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw4IfQfCCrcuybFm41wJyxjbkz7","object":"chat.completion.chunk","created":1727346172,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"refusal":" I"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw4IfQfCCrcuybFm41wJyxjbkz7","object":"chat.completion.chunk","created":1727346172,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"refusal":" can't"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw4IfQfCCrcuybFm41wJyxjbkz7","object":"chat.completion.chunk","created":1727346172,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"refusal":" assist"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw4IfQfCCrcuybFm41wJyxjbkz7","object":"chat.completion.chunk","created":1727346172,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"refusal":" with"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw4IfQfCCrcuybFm41wJyxjbkz7","object":"chat.completion.chunk","created":1727346172,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"refusal":" that"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw4IfQfCCrcuybFm41wJyxjbkz7","object":"chat.completion.chunk","created":1727346172,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"refusal":" request"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw4IfQfCCrcuybFm41wJyxjbkz7","object":"chat.completion.chunk","created":1727346172,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"refusal":"."},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw4IfQfCCrcuybFm41wJyxjbkz7","object":"chat.completion.chunk","created":1727346172,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}]} + +data: {"id":"chatcmpl-ABfw4IfQfCCrcuybFm41wJyxjbkz7","object":"chat.completion.chunk","created":1727346172,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[],"usage":{"prompt_tokens":79,"completion_tokens":11,"total_tokens":90,"completion_tokens_details":{"reasoning_tokens":0}}} + +data: [DONE] + diff --git a/.inline-snapshot/external/2018feb66ae13fcf5333d61b95849decc68d3f63bd38172889367e1afb1e04f7.bin b/.inline-snapshot/external/2018feb66ae13fcf5333d61b95849decc68d3f63bd38172889367e1afb1e04f7.bin new file mode 100644 index 0000000000..871970676f --- /dev/null +++ b/.inline-snapshot/external/2018feb66ae13fcf5333d61b95849decc68d3f63bd38172889367e1afb1e04f7.bin @@ -0,0 +1,22 @@ +data: {"id":"chatcmpl-ABfwERreu9s99xXsVuOWtIB2UOx62","object":"chat.completion.chunk","created":1727346182,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_143bb8492c","choices":[{"index":0,"delta":{"role":"assistant","content":null,"tool_calls":[{"index":0,"id":"call_4XzlGBLtUe9dy3GVNV4jhq7h","type":"function","function":{"name":"get_weather","arguments":""}}],"refusal":null},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwERreu9s99xXsVuOWtIB2UOx62","object":"chat.completion.chunk","created":1727346182,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_143bb8492c","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\""}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwERreu9s99xXsVuOWtIB2UOx62","object":"chat.completion.chunk","created":1727346182,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_143bb8492c","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"city"}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwERreu9s99xXsVuOWtIB2UOx62","object":"chat.completion.chunk","created":1727346182,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_143bb8492c","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\":\""}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwERreu9s99xXsVuOWtIB2UOx62","object":"chat.completion.chunk","created":1727346182,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_143bb8492c","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"New"}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwERreu9s99xXsVuOWtIB2UOx62","object":"chat.completion.chunk","created":1727346182,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_143bb8492c","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":" York"}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwERreu9s99xXsVuOWtIB2UOx62","object":"chat.completion.chunk","created":1727346182,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_143bb8492c","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":" City"}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwERreu9s99xXsVuOWtIB2UOx62","object":"chat.completion.chunk","created":1727346182,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_143bb8492c","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\"}"}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwERreu9s99xXsVuOWtIB2UOx62","object":"chat.completion.chunk","created":1727346182,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_143bb8492c","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"tool_calls"}]} + +data: {"id":"chatcmpl-ABfwERreu9s99xXsVuOWtIB2UOx62","object":"chat.completion.chunk","created":1727346182,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_143bb8492c","choices":[],"usage":{"prompt_tokens":44,"completion_tokens":16,"total_tokens":60,"completion_tokens_details":{"reasoning_tokens":0}}} + +data: [DONE] + diff --git a/.inline-snapshot/external/24aaf30663f9a568a0e77970b4fd3deafe041da94d541071009596234d8c84a6.bin b/.inline-snapshot/external/24aaf30663f9a568a0e77970b4fd3deafe041da94d541071009596234d8c84a6.bin deleted file mode 100644 index 49962cff27..0000000000 --- a/.inline-snapshot/external/24aaf30663f9a568a0e77970b4fd3deafe041da94d541071009596234d8c84a6.bin +++ /dev/null @@ -1,36 +0,0 @@ -data: {"id":"chatcmpl-9tXjnXkjzholyB3ceNegQC7g5zP57","object":"chat.completion.chunk","created":1723024755,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"role":"assistant","content":null,"tool_calls":[{"index":0,"id":"call_7PhhveOvvpPK53s1fV8TWhoV","type":"function","function":{"name":"GetWeatherArgs","arguments":""}}],"refusal":null},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjnXkjzholyB3ceNegQC7g5zP57","object":"chat.completion.chunk","created":1723024755,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\""}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjnXkjzholyB3ceNegQC7g5zP57","object":"chat.completion.chunk","created":1723024755,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"city"}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjnXkjzholyB3ceNegQC7g5zP57","object":"chat.completion.chunk","created":1723024755,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\":\""}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjnXkjzholyB3ceNegQC7g5zP57","object":"chat.completion.chunk","created":1723024755,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"Ed"}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjnXkjzholyB3ceNegQC7g5zP57","object":"chat.completion.chunk","created":1723024755,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"inburgh"}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjnXkjzholyB3ceNegQC7g5zP57","object":"chat.completion.chunk","created":1723024755,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\",\""}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjnXkjzholyB3ceNegQC7g5zP57","object":"chat.completion.chunk","created":1723024755,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"country"}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjnXkjzholyB3ceNegQC7g5zP57","object":"chat.completion.chunk","created":1723024755,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\":\""}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjnXkjzholyB3ceNegQC7g5zP57","object":"chat.completion.chunk","created":1723024755,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"GB"}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjnXkjzholyB3ceNegQC7g5zP57","object":"chat.completion.chunk","created":1723024755,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\",\""}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjnXkjzholyB3ceNegQC7g5zP57","object":"chat.completion.chunk","created":1723024755,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"units"}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjnXkjzholyB3ceNegQC7g5zP57","object":"chat.completion.chunk","created":1723024755,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\":\""}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjnXkjzholyB3ceNegQC7g5zP57","object":"chat.completion.chunk","created":1723024755,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"c"}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjnXkjzholyB3ceNegQC7g5zP57","object":"chat.completion.chunk","created":1723024755,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\"}"}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjnXkjzholyB3ceNegQC7g5zP57","object":"chat.completion.chunk","created":1723024755,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"tool_calls"}]} - -data: {"id":"chatcmpl-9tXjnXkjzholyB3ceNegQC7g5zP57","object":"chat.completion.chunk","created":1723024755,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[],"usage":{"prompt_tokens":76,"completion_tokens":24,"total_tokens":100}} - -data: [DONE] - diff --git a/.inline-snapshot/external/453df473e96274dd8ab61ab4d13dfcc25dc2f57a5e05eb5cc46c70b51d8845c2.bin b/.inline-snapshot/external/453df473e96274dd8ab61ab4d13dfcc25dc2f57a5e05eb5cc46c70b51d8845c2.bin deleted file mode 100644 index adcdddd317..0000000000 --- a/.inline-snapshot/external/453df473e96274dd8ab61ab4d13dfcc25dc2f57a5e05eb5cc46c70b51d8845c2.bin +++ /dev/null @@ -1,52 +0,0 @@ -data: {"id":"chatcmpl-9tXjpPLJgivc9nyuBCCWX8HNg9L2J","object":"chat.completion.chunk","created":1723024757,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"role":"assistant","content":null},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjpPLJgivc9nyuBCCWX8HNg9L2J","object":"chat.completion.chunk","created":1723024757,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"id":"call_lQnnsesjFMWMQ5IeWPHzR4th","type":"function","function":{"name":"GetWeatherArgs","arguments":""}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjpPLJgivc9nyuBCCWX8HNg9L2J","object":"chat.completion.chunk","created":1723024757,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\"ci"}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjpPLJgivc9nyuBCCWX8HNg9L2J","object":"chat.completion.chunk","created":1723024757,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"ty\": "}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjpPLJgivc9nyuBCCWX8HNg9L2J","object":"chat.completion.chunk","created":1723024757,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\"Edinb"}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjpPLJgivc9nyuBCCWX8HNg9L2J","object":"chat.completion.chunk","created":1723024757,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"urgh"}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjpPLJgivc9nyuBCCWX8HNg9L2J","object":"chat.completion.chunk","created":1723024757,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\", \"c"}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjpPLJgivc9nyuBCCWX8HNg9L2J","object":"chat.completion.chunk","created":1723024757,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"ountry"}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjpPLJgivc9nyuBCCWX8HNg9L2J","object":"chat.completion.chunk","created":1723024757,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\": \""}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjpPLJgivc9nyuBCCWX8HNg9L2J","object":"chat.completion.chunk","created":1723024757,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"UK\", "}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjpPLJgivc9nyuBCCWX8HNg9L2J","object":"chat.completion.chunk","created":1723024757,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\"units"}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjpPLJgivc9nyuBCCWX8HNg9L2J","object":"chat.completion.chunk","created":1723024757,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\": \""}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjpPLJgivc9nyuBCCWX8HNg9L2J","object":"chat.completion.chunk","created":1723024757,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"c\"}"}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjpPLJgivc9nyuBCCWX8HNg9L2J","object":"chat.completion.chunk","created":1723024757,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"id":"call_2xjOUgaCdiwAcl9ZBL9LyMUU","type":"function","function":{"name":"get_stock_price","arguments":""}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjpPLJgivc9nyuBCCWX8HNg9L2J","object":"chat.completion.chunk","created":1723024757,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"function":{"arguments":"{\"ti"}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjpPLJgivc9nyuBCCWX8HNg9L2J","object":"chat.completion.chunk","created":1723024757,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"function":{"arguments":"cker\""}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjpPLJgivc9nyuBCCWX8HNg9L2J","object":"chat.completion.chunk","created":1723024757,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"function":{"arguments":": \"AAP"}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjpPLJgivc9nyuBCCWX8HNg9L2J","object":"chat.completion.chunk","created":1723024757,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"function":{"arguments":"L\", "}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjpPLJgivc9nyuBCCWX8HNg9L2J","object":"chat.completion.chunk","created":1723024757,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"function":{"arguments":"\"exch"}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjpPLJgivc9nyuBCCWX8HNg9L2J","object":"chat.completion.chunk","created":1723024757,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"function":{"arguments":"ange\":"}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjpPLJgivc9nyuBCCWX8HNg9L2J","object":"chat.completion.chunk","created":1723024757,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"function":{"arguments":" \"NA"}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjpPLJgivc9nyuBCCWX8HNg9L2J","object":"chat.completion.chunk","created":1723024757,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"function":{"arguments":"SDAQ\""}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjpPLJgivc9nyuBCCWX8HNg9L2J","object":"chat.completion.chunk","created":1723024757,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"function":{"arguments":"}"}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjpPLJgivc9nyuBCCWX8HNg9L2J","object":"chat.completion.chunk","created":1723024757,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"tool_calls"}]} - -data: {"id":"chatcmpl-9tXjpPLJgivc9nyuBCCWX8HNg9L2J","object":"chat.completion.chunk","created":1723024757,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[],"usage":{"prompt_tokens":149,"completion_tokens":60,"total_tokens":209}} - -data: [DONE] - diff --git a/.inline-snapshot/external/4cc50a6135d254573a502310e6af1246f55edb6ad95fa24059f160996b68866d.bin b/.inline-snapshot/external/4cc50a6135d254573a502310e6af1246f55edb6ad95fa24059f160996b68866d.bin new file mode 100644 index 0000000000..c3392883be --- /dev/null +++ b/.inline-snapshot/external/4cc50a6135d254573a502310e6af1246f55edb6ad95fa24059f160996b68866d.bin @@ -0,0 +1,10 @@ +data: {"id":"chatcmpl-ABfw3Oqj8RD0z6aJiiX37oTjV2HFh","object":"chat.completion.chunk","created":1727346171,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_7568d46099","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw3Oqj8RD0z6aJiiX37oTjV2HFh","object":"chat.completion.chunk","created":1727346171,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_7568d46099","choices":[{"index":0,"delta":{"content":"{\""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw3Oqj8RD0z6aJiiX37oTjV2HFh","object":"chat.completion.chunk","created":1727346171,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_7568d46099","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"length"}]} + +data: {"id":"chatcmpl-ABfw3Oqj8RD0z6aJiiX37oTjV2HFh","object":"chat.completion.chunk","created":1727346171,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_7568d46099","choices":[],"usage":{"prompt_tokens":79,"completion_tokens":1,"total_tokens":80,"completion_tokens_details":{"reasoning_tokens":0}}} + +data: [DONE] + diff --git a/.inline-snapshot/external/4d75e4d7c3e0b532a67fb2114ff7868df0b6d8a02dfcd23f6bc7196cf0eadb6e.bin b/.inline-snapshot/external/4d75e4d7c3e0b532a67fb2114ff7868df0b6d8a02dfcd23f6bc7196cf0eadb6e.bin deleted file mode 100644 index 008d5882ec..0000000000 --- a/.inline-snapshot/external/4d75e4d7c3e0b532a67fb2114ff7868df0b6d8a02dfcd23f6bc7196cf0eadb6e.bin +++ /dev/null @@ -1,28 +0,0 @@ -data: {"id":"chatcmpl-9tXjkxJ4omrCOJoVbZIgaPWZS8TLD","object":"chat.completion.chunk","created":1723024752,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"role":"assistant","content":null,"refusal":""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjkxJ4omrCOJoVbZIgaPWZS8TLD","object":"chat.completion.chunk","created":1723024752,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"refusal":"I'm"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjkxJ4omrCOJoVbZIgaPWZS8TLD","object":"chat.completion.chunk","created":1723024752,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"refusal":" sorry"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjkxJ4omrCOJoVbZIgaPWZS8TLD","object":"chat.completion.chunk","created":1723024752,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"refusal":","},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjkxJ4omrCOJoVbZIgaPWZS8TLD","object":"chat.completion.chunk","created":1723024752,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"refusal":" I"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjkxJ4omrCOJoVbZIgaPWZS8TLD","object":"chat.completion.chunk","created":1723024752,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"refusal":" cannot"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjkxJ4omrCOJoVbZIgaPWZS8TLD","object":"chat.completion.chunk","created":1723024752,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"refusal":" assist"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjkxJ4omrCOJoVbZIgaPWZS8TLD","object":"chat.completion.chunk","created":1723024752,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"refusal":" with"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjkxJ4omrCOJoVbZIgaPWZS8TLD","object":"chat.completion.chunk","created":1723024752,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"refusal":" that"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjkxJ4omrCOJoVbZIgaPWZS8TLD","object":"chat.completion.chunk","created":1723024752,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"refusal":" request"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjkxJ4omrCOJoVbZIgaPWZS8TLD","object":"chat.completion.chunk","created":1723024752,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"refusal":"."},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjkxJ4omrCOJoVbZIgaPWZS8TLD","object":"chat.completion.chunk","created":1723024752,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}]} - -data: {"id":"chatcmpl-9tXjkxJ4omrCOJoVbZIgaPWZS8TLD","object":"chat.completion.chunk","created":1723024752,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[],"usage":{"prompt_tokens":17,"completion_tokens":11,"total_tokens":28}} - -data: [DONE] - diff --git a/.inline-snapshot/external/569c877e69429d4cbc1577d2cd6dd33878095c68badc6b6654a69769b391a1c1.bin b/.inline-snapshot/external/569c877e69429d4cbc1577d2cd6dd33878095c68badc6b6654a69769b391a1c1.bin new file mode 100644 index 0000000000..47dd73151c --- /dev/null +++ b/.inline-snapshot/external/569c877e69429d4cbc1577d2cd6dd33878095c68badc6b6654a69769b391a1c1.bin @@ -0,0 +1,30 @@ +data: {"id":"chatcmpl-ABfw5GEVqPbLY576l46FZDQoNJ2KC","object":"chat.completion.chunk","created":1727346173,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"role":"assistant","content":null,"refusal":""},"logprobs":{"content":null,"refusal":[]},"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw5GEVqPbLY576l46FZDQoNJ2KC","object":"chat.completion.chunk","created":1727346173,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"refusal":"I'm"},"logprobs":{"content":null,"refusal":[{"token":"I'm","logprob":-0.0012038043,"bytes":[73,39,109],"top_logprobs":[]}]},"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw5GEVqPbLY576l46FZDQoNJ2KC","object":"chat.completion.chunk","created":1727346173,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"refusal":" very"},"logprobs":{"content":null,"refusal":[{"token":" very","logprob":-0.8438816,"bytes":[32,118,101,114,121],"top_logprobs":[]}]},"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw5GEVqPbLY576l46FZDQoNJ2KC","object":"chat.completion.chunk","created":1727346173,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"refusal":" sorry"},"logprobs":{"content":null,"refusal":[{"token":" sorry","logprob":-3.4121115e-6,"bytes":[32,115,111,114,114,121],"top_logprobs":[]}]},"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw5GEVqPbLY576l46FZDQoNJ2KC","object":"chat.completion.chunk","created":1727346173,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"refusal":","},"logprobs":{"content":null,"refusal":[{"token":",","logprob":-0.000033809047,"bytes":[44],"top_logprobs":[]}]},"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw5GEVqPbLY576l46FZDQoNJ2KC","object":"chat.completion.chunk","created":1727346173,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"refusal":" but"},"logprobs":{"content":null,"refusal":[{"token":" but","logprob":-0.038048144,"bytes":[32,98,117,116],"top_logprobs":[]}]},"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw5GEVqPbLY576l46FZDQoNJ2KC","object":"chat.completion.chunk","created":1727346173,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"refusal":" I"},"logprobs":{"content":null,"refusal":[{"token":" I","logprob":-0.0016109125,"bytes":[32,73],"top_logprobs":[]}]},"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw5GEVqPbLY576l46FZDQoNJ2KC","object":"chat.completion.chunk","created":1727346173,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"refusal":" can't"},"logprobs":{"content":null,"refusal":[{"token":" can't","logprob":-0.0073532974,"bytes":[32,99,97,110,39,116],"top_logprobs":[]}]},"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw5GEVqPbLY576l46FZDQoNJ2KC","object":"chat.completion.chunk","created":1727346173,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"refusal":" assist"},"logprobs":{"content":null,"refusal":[{"token":" assist","logprob":-0.0020837625,"bytes":[32,97,115,115,105,115,116],"top_logprobs":[]}]},"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw5GEVqPbLY576l46FZDQoNJ2KC","object":"chat.completion.chunk","created":1727346173,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"refusal":" with"},"logprobs":{"content":null,"refusal":[{"token":" with","logprob":-0.00318354,"bytes":[32,119,105,116,104],"top_logprobs":[]}]},"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw5GEVqPbLY576l46FZDQoNJ2KC","object":"chat.completion.chunk","created":1727346173,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"refusal":" that"},"logprobs":{"content":null,"refusal":[{"token":" that","logprob":-0.0017186158,"bytes":[32,116,104,97,116],"top_logprobs":[]}]},"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw5GEVqPbLY576l46FZDQoNJ2KC","object":"chat.completion.chunk","created":1727346173,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"refusal":"."},"logprobs":{"content":null,"refusal":[{"token":".","logprob":-0.57687104,"bytes":[46],"top_logprobs":[]}]},"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw5GEVqPbLY576l46FZDQoNJ2KC","object":"chat.completion.chunk","created":1727346173,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}]} + +data: {"id":"chatcmpl-ABfw5GEVqPbLY576l46FZDQoNJ2KC","object":"chat.completion.chunk","created":1727346173,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[],"usage":{"prompt_tokens":79,"completion_tokens":12,"total_tokens":91,"completion_tokens_details":{"reasoning_tokens":0}}} + +data: [DONE] + diff --git a/.inline-snapshot/external/69363a555f8ea9b6eee0bb022af0afcd22d4f0e85418ab38ee24d2a570a84ff0.bin b/.inline-snapshot/external/69363a555f8ea9b6eee0bb022af0afcd22d4f0e85418ab38ee24d2a570a84ff0.bin deleted file mode 100644 index 852a7758f9..0000000000 --- a/.inline-snapshot/external/69363a555f8ea9b6eee0bb022af0afcd22d4f0e85418ab38ee24d2a570a84ff0.bin +++ /dev/null @@ -1,10 +0,0 @@ -data: {"id":"chatcmpl-9tXjkSxyTVUSWZRJFSZJgWBHzh2c3","object":"chat.completion.chunk","created":1723024752,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjkSxyTVUSWZRJFSZJgWBHzh2c3","object":"chat.completion.chunk","created":1723024752,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"{\""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjkSxyTVUSWZRJFSZJgWBHzh2c3","object":"chat.completion.chunk","created":1723024752,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"length"}]} - -data: {"id":"chatcmpl-9tXjkSxyTVUSWZRJFSZJgWBHzh2c3","object":"chat.completion.chunk","created":1723024752,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[],"usage":{"prompt_tokens":17,"completion_tokens":1,"total_tokens":18}} - -data: [DONE] - diff --git a/.inline-snapshot/external/7e5ea4d12e7cc064399b6631415e65923f182256b6e6b752950a3aaa2ad2320a.bin b/.inline-snapshot/external/7e5ea4d12e7cc064399b6631415e65923f182256b6e6b752950a3aaa2ad2320a.bin new file mode 100644 index 0000000000..801db2adf2 --- /dev/null +++ b/.inline-snapshot/external/7e5ea4d12e7cc064399b6631415e65923f182256b6e6b752950a3aaa2ad2320a.bin @@ -0,0 +1,36 @@ +data: {"id":"chatcmpl-ABfw1e5abtU8OwGr15vOreYVb2MiF","object":"chat.completion.chunk","created":1727346169,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw1e5abtU8OwGr15vOreYVb2MiF","object":"chat.completion.chunk","created":1727346169,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"{\""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw1e5abtU8OwGr15vOreYVb2MiF","object":"chat.completion.chunk","created":1727346169,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"city"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw1e5abtU8OwGr15vOreYVb2MiF","object":"chat.completion.chunk","created":1727346169,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\":\""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw1e5abtU8OwGr15vOreYVb2MiF","object":"chat.completion.chunk","created":1727346169,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"San"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw1e5abtU8OwGr15vOreYVb2MiF","object":"chat.completion.chunk","created":1727346169,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" Francisco"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw1e5abtU8OwGr15vOreYVb2MiF","object":"chat.completion.chunk","created":1727346169,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\",\""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw1e5abtU8OwGr15vOreYVb2MiF","object":"chat.completion.chunk","created":1727346169,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"temperature"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw1e5abtU8OwGr15vOreYVb2MiF","object":"chat.completion.chunk","created":1727346169,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw1e5abtU8OwGr15vOreYVb2MiF","object":"chat.completion.chunk","created":1727346169,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"61"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw1e5abtU8OwGr15vOreYVb2MiF","object":"chat.completion.chunk","created":1727346169,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":",\""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw1e5abtU8OwGr15vOreYVb2MiF","object":"chat.completion.chunk","created":1727346169,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"units"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw1e5abtU8OwGr15vOreYVb2MiF","object":"chat.completion.chunk","created":1727346169,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\":\""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw1e5abtU8OwGr15vOreYVb2MiF","object":"chat.completion.chunk","created":1727346169,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"f"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw1e5abtU8OwGr15vOreYVb2MiF","object":"chat.completion.chunk","created":1727346169,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\"}"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw1e5abtU8OwGr15vOreYVb2MiF","object":"chat.completion.chunk","created":1727346169,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}]} + +data: {"id":"chatcmpl-ABfw1e5abtU8OwGr15vOreYVb2MiF","object":"chat.completion.chunk","created":1727346169,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[],"usage":{"prompt_tokens":79,"completion_tokens":14,"total_tokens":93,"completion_tokens_details":{"reasoning_tokens":0}}} + +data: [DONE] + diff --git a/.inline-snapshot/external/83b060bae42eb41c4f1edbb7c1542b954b37d9dfd1910b964ddebc9677e6ae85.bin b/.inline-snapshot/external/83b060bae42eb41c4f1edbb7c1542b954b37d9dfd1910b964ddebc9677e6ae85.bin new file mode 100644 index 0000000000..e9f34b6334 --- /dev/null +++ b/.inline-snapshot/external/83b060bae42eb41c4f1edbb7c1542b954b37d9dfd1910b964ddebc9677e6ae85.bin @@ -0,0 +1,12 @@ +data: {"id":"chatcmpl-ABfw5EzoqmfXjnnsXY7Yd8OC6tb3c","object":"chat.completion.chunk","created":1727346173,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":{"content":[],"refusal":null},"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw5EzoqmfXjnnsXY7Yd8OC6tb3c","object":"chat.completion.chunk","created":1727346173,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"Foo"},"logprobs":{"content":[{"token":"Foo","logprob":-0.0025094282,"bytes":[70,111,111],"top_logprobs":[]}],"refusal":null},"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw5EzoqmfXjnnsXY7Yd8OC6tb3c","object":"chat.completion.chunk","created":1727346173,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"!"},"logprobs":{"content":[{"token":"!","logprob":-0.26638845,"bytes":[33],"top_logprobs":[]}],"refusal":null},"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw5EzoqmfXjnnsXY7Yd8OC6tb3c","object":"chat.completion.chunk","created":1727346173,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}]} + +data: {"id":"chatcmpl-ABfw5EzoqmfXjnnsXY7Yd8OC6tb3c","object":"chat.completion.chunk","created":1727346173,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[],"usage":{"prompt_tokens":9,"completion_tokens":2,"total_tokens":11,"completion_tokens_details":{"reasoning_tokens":0}}} + +data: [DONE] + diff --git a/.inline-snapshot/external/83d3d003e6fdaa69b7a398440f9d46ee41408a688758219f3f58ac1ee2084db3.bin b/.inline-snapshot/external/83d3d003e6fdaa69b7a398440f9d46ee41408a688758219f3f58ac1ee2084db3.bin deleted file mode 100644 index 05e08e3475..0000000000 --- a/.inline-snapshot/external/83d3d003e6fdaa69b7a398440f9d46ee41408a688758219f3f58ac1ee2084db3.bin +++ /dev/null @@ -1,28 +0,0 @@ -data: {"id":"chatcmpl-9tXjq87CydgLGv4TnzV0EVDybqjCA","object":"chat.completion.chunk","created":1723024758,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_baa7103b2c","choices":[{"index":0,"delta":{"role":"assistant","content":null,"tool_calls":[{"index":0,"id":"call_pVHYsU0gmSfX5TqxOyVbB2ma","type":"function","function":{"name":"get_weather","arguments":""}}],"refusal":null},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjq87CydgLGv4TnzV0EVDybqjCA","object":"chat.completion.chunk","created":1723024758,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_baa7103b2c","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\""}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjq87CydgLGv4TnzV0EVDybqjCA","object":"chat.completion.chunk","created":1723024758,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_baa7103b2c","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"city"}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjq87CydgLGv4TnzV0EVDybqjCA","object":"chat.completion.chunk","created":1723024758,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_baa7103b2c","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\":\""}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjq87CydgLGv4TnzV0EVDybqjCA","object":"chat.completion.chunk","created":1723024758,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_baa7103b2c","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"San"}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjq87CydgLGv4TnzV0EVDybqjCA","object":"chat.completion.chunk","created":1723024758,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_baa7103b2c","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":" Francisco"}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjq87CydgLGv4TnzV0EVDybqjCA","object":"chat.completion.chunk","created":1723024758,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_baa7103b2c","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\",\""}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjq87CydgLGv4TnzV0EVDybqjCA","object":"chat.completion.chunk","created":1723024758,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_baa7103b2c","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"state"}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjq87CydgLGv4TnzV0EVDybqjCA","object":"chat.completion.chunk","created":1723024758,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_baa7103b2c","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\":\""}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjq87CydgLGv4TnzV0EVDybqjCA","object":"chat.completion.chunk","created":1723024758,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_baa7103b2c","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"CA"}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjq87CydgLGv4TnzV0EVDybqjCA","object":"chat.completion.chunk","created":1723024758,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_baa7103b2c","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\"}"}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjq87CydgLGv4TnzV0EVDybqjCA","object":"chat.completion.chunk","created":1723024758,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_baa7103b2c","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"tool_calls"}]} - -data: {"id":"chatcmpl-9tXjq87CydgLGv4TnzV0EVDybqjCA","object":"chat.completion.chunk","created":1723024758,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_baa7103b2c","choices":[],"usage":{"prompt_tokens":48,"completion_tokens":19,"total_tokens":67}} - -data: [DONE] - diff --git a/.inline-snapshot/external/a0c4f0be184e8234cdc0e3abae5dfafc1d712c253b42bafe07991b3058541016.bin b/.inline-snapshot/external/a0c4f0be184e8234cdc0e3abae5dfafc1d712c253b42bafe07991b3058541016.bin deleted file mode 100644 index df20d6fda5..0000000000 --- a/.inline-snapshot/external/a0c4f0be184e8234cdc0e3abae5dfafc1d712c253b42bafe07991b3058541016.bin +++ /dev/null @@ -1,156 +0,0 @@ -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"content":"{\""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":1,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":1,"delta":{"content":"{\""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"content":"city"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":1,"delta":{"content":"city"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"role":"assistant","content":null,"refusal":""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":"I'm"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"content":"\":\""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":1,"delta":{"content":"\":\""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":" sorry"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"content":"San"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":1,"delta":{"content":"San"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":","},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"content":" Francisco"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":1,"delta":{"content":" Francisco"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":" but"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"content":"\",\""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":1,"delta":{"content":"\",\""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":" I"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":" can't"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"content":"temperature"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":1,"delta":{"content":"temperature"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":1,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":" accurately"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":" provide"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"content":"63"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"content":",\""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":1,"delta":{"content":"58"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":1,"delta":{"content":"."},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":" the"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"content":"units"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":1,"delta":{"content":"6"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":" current"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"content":"\":\""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":1,"delta":{"content":",\""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":" weather"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"content":"f"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":1,"delta":{"content":"units"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":" for"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{"content":"\"}"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":1,"delta":{"content":"\":\""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":" San"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":1,"delta":{"content":"f"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":" Francisco"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":1,"delta":{"content":"\"}"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":" as"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":" my"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":" data"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":" is"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":" up"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":" to"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":" October"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":" "},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":"202"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":"3"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":"."},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":" You"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":" can"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":" try"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":" checking"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":" a"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":" reliable"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":" weather"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":" website"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":" or"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":" app"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":" for"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":" real"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":"-time"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":" updates"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{"refusal":"."},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":1,"delta":{},"logprobs":null,"finish_reason":"stop"}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[{"index":2,"delta":{},"logprobs":null,"finish_reason":"stop"}]} - -data: {"id":"chatcmpl-9tXjjpr5ZWilqbUE2tn3H1lwvMnDu","object":"chat.completion.chunk","created":1723024751,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_2a322c9ffc","choices":[],"usage":{"prompt_tokens":17,"completion_tokens":71,"total_tokens":88}} - -data: [DONE] - diff --git a/.inline-snapshot/external/a247c49c5fcd492bfb7a02a3306ad615ed8d8f649888ebfddfbc3ee151f44d46.bin b/.inline-snapshot/external/a247c49c5fcd492bfb7a02a3306ad615ed8d8f649888ebfddfbc3ee151f44d46.bin new file mode 100644 index 0000000000..b44d334ac5 --- /dev/null +++ b/.inline-snapshot/external/a247c49c5fcd492bfb7a02a3306ad615ed8d8f649888ebfddfbc3ee151f44d46.bin @@ -0,0 +1,28 @@ +data: {"id":"chatcmpl-ABfwCgi41eStOcARjZq97ohCEGBPO","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":0,"delta":{"role":"assistant","content":null,"tool_calls":[{"index":0,"id":"call_CTf1nWJLqSeRgDqaCG27xZ74","type":"function","function":{"name":"get_weather","arguments":""}}],"refusal":null},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCgi41eStOcARjZq97ohCEGBPO","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\""}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCgi41eStOcARjZq97ohCEGBPO","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"city"}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCgi41eStOcARjZq97ohCEGBPO","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\":\""}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCgi41eStOcARjZq97ohCEGBPO","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"San"}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCgi41eStOcARjZq97ohCEGBPO","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":" Francisco"}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCgi41eStOcARjZq97ohCEGBPO","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\",\""}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCgi41eStOcARjZq97ohCEGBPO","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"state"}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCgi41eStOcARjZq97ohCEGBPO","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\":\""}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCgi41eStOcARjZq97ohCEGBPO","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"CA"}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCgi41eStOcARjZq97ohCEGBPO","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\"}"}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCgi41eStOcARjZq97ohCEGBPO","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"tool_calls"}]} + +data: {"id":"chatcmpl-ABfwCgi41eStOcARjZq97ohCEGBPO","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[],"usage":{"prompt_tokens":48,"completion_tokens":19,"total_tokens":67,"completion_tokens_details":{"reasoning_tokens":0}}} + +data: [DONE] + diff --git a/.inline-snapshot/external/a491adda08c3d4fde95f5b2ee3f60f7f745f1a56d82e62f58031cc2add502380.bin b/.inline-snapshot/external/a491adda08c3d4fde95f5b2ee3f60f7f745f1a56d82e62f58031cc2add502380.bin new file mode 100644 index 0000000000..160e65de49 --- /dev/null +++ b/.inline-snapshot/external/a491adda08c3d4fde95f5b2ee3f60f7f745f1a56d82e62f58031cc2add502380.bin @@ -0,0 +1,100 @@ +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":0,"delta":{"content":"{\""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":1,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":1,"delta":{"content":"{\""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":2,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":2,"delta":{"content":"{\""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":0,"delta":{"content":"city"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":1,"delta":{"content":"city"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":2,"delta":{"content":"city"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":0,"delta":{"content":"\":\""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":1,"delta":{"content":"\":\""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":2,"delta":{"content":"\":\""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":0,"delta":{"content":"San"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":1,"delta":{"content":"San"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":2,"delta":{"content":"San"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":0,"delta":{"content":" Francisco"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":1,"delta":{"content":" Francisco"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":2,"delta":{"content":" Francisco"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":0,"delta":{"content":"\",\""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":1,"delta":{"content":"\",\""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":2,"delta":{"content":"\",\""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":0,"delta":{"content":"temperature"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":1,"delta":{"content":"temperature"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":1,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":2,"delta":{"content":"temperature"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":2,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":0,"delta":{"content":"65"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":0,"delta":{"content":",\""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":1,"delta":{"content":"61"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":1,"delta":{"content":",\""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":2,"delta":{"content":"59"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":2,"delta":{"content":",\""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":0,"delta":{"content":"units"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":1,"delta":{"content":"units"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":2,"delta":{"content":"units"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":0,"delta":{"content":"\":\""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":1,"delta":{"content":"\":\""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":2,"delta":{"content":"\":\""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":0,"delta":{"content":"f"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":1,"delta":{"content":"f"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":2,"delta":{"content":"f"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":0,"delta":{"content":"\"}"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":1,"delta":{"content":"\"}"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":2,"delta":{"content":"\"}"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":1,"delta":{},"logprobs":null,"finish_reason":"stop"}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[{"index":2,"delta":{},"logprobs":null,"finish_reason":"stop"}]} + +data: {"id":"chatcmpl-ABfw2KKFuVXmEJgVwYfBvejMAdWtq","object":"chat.completion.chunk","created":1727346170,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_b40fb1c6fb","choices":[],"usage":{"prompt_tokens":79,"completion_tokens":42,"total_tokens":121,"completion_tokens_details":{"reasoning_tokens":0}}} + +data: [DONE] + diff --git a/.inline-snapshot/external/be1089999ca5f1e63b149447f1613bdb9c4a2ad8262027d158cc94e6f9765164.bin b/.inline-snapshot/external/be1089999ca5f1e63b149447f1613bdb9c4a2ad8262027d158cc94e6f9765164.bin deleted file mode 100644 index f2a8158310..0000000000 --- a/.inline-snapshot/external/be1089999ca5f1e63b149447f1613bdb9c4a2ad8262027d158cc94e6f9765164.bin +++ /dev/null @@ -1,12 +0,0 @@ -data: {"id":"chatcmpl-9tXjliCPGY1wrAHNJ4DBnWJxKYyuf","object":"chat.completion.chunk","created":1723024753,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":{"content":[],"refusal":null},"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjliCPGY1wrAHNJ4DBnWJxKYyuf","object":"chat.completion.chunk","created":1723024753,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"Foo"},"logprobs":{"content":[{"token":"Foo","logprob":-0.0067602484,"bytes":[70,111,111],"top_logprobs":[]}],"refusal":null},"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjliCPGY1wrAHNJ4DBnWJxKYyuf","object":"chat.completion.chunk","created":1723024753,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"."},"logprobs":{"content":[{"token":".","logprob":-2.4962392,"bytes":[46],"top_logprobs":[]}],"refusal":null},"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjliCPGY1wrAHNJ4DBnWJxKYyuf","object":"chat.completion.chunk","created":1723024753,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}]} - -data: {"id":"chatcmpl-9tXjliCPGY1wrAHNJ4DBnWJxKYyuf","object":"chat.completion.chunk","created":1723024753,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[],"usage":{"prompt_tokens":9,"completion_tokens":2,"total_tokens":11}} - -data: [DONE] - diff --git a/.inline-snapshot/external/c6aa7e397b7123c3501f25df3a05d4daf7e8ad6d61ffa406ab5361fe36a8d5b1.bin b/.inline-snapshot/external/c6aa7e397b7123c3501f25df3a05d4daf7e8ad6d61ffa406ab5361fe36a8d5b1.bin new file mode 100644 index 0000000000..f20333fbef --- /dev/null +++ b/.inline-snapshot/external/c6aa7e397b7123c3501f25df3a05d4daf7e8ad6d61ffa406ab5361fe36a8d5b1.bin @@ -0,0 +1,36 @@ +data: {"id":"chatcmpl-ABfw8AOXnoa2kzy11vVTSjuQhHCQr","object":"chat.completion.chunk","created":1727346176,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_7568d46099","choices":[{"index":0,"delta":{"role":"assistant","content":null,"tool_calls":[{"index":0,"id":"call_c91SqDXlYFuETYv8mUHzz6pp","type":"function","function":{"name":"GetWeatherArgs","arguments":""}}],"refusal":null},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw8AOXnoa2kzy11vVTSjuQhHCQr","object":"chat.completion.chunk","created":1727346176,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_7568d46099","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\""}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw8AOXnoa2kzy11vVTSjuQhHCQr","object":"chat.completion.chunk","created":1727346176,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_7568d46099","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"city"}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw8AOXnoa2kzy11vVTSjuQhHCQr","object":"chat.completion.chunk","created":1727346176,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_7568d46099","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\":\""}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw8AOXnoa2kzy11vVTSjuQhHCQr","object":"chat.completion.chunk","created":1727346176,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_7568d46099","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"Ed"}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw8AOXnoa2kzy11vVTSjuQhHCQr","object":"chat.completion.chunk","created":1727346176,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_7568d46099","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"inburgh"}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw8AOXnoa2kzy11vVTSjuQhHCQr","object":"chat.completion.chunk","created":1727346176,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_7568d46099","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\",\""}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw8AOXnoa2kzy11vVTSjuQhHCQr","object":"chat.completion.chunk","created":1727346176,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_7568d46099","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"country"}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw8AOXnoa2kzy11vVTSjuQhHCQr","object":"chat.completion.chunk","created":1727346176,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_7568d46099","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\":\""}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw8AOXnoa2kzy11vVTSjuQhHCQr","object":"chat.completion.chunk","created":1727346176,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_7568d46099","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"UK"}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw8AOXnoa2kzy11vVTSjuQhHCQr","object":"chat.completion.chunk","created":1727346176,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_7568d46099","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\",\""}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw8AOXnoa2kzy11vVTSjuQhHCQr","object":"chat.completion.chunk","created":1727346176,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_7568d46099","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"units"}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw8AOXnoa2kzy11vVTSjuQhHCQr","object":"chat.completion.chunk","created":1727346176,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_7568d46099","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\":\""}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw8AOXnoa2kzy11vVTSjuQhHCQr","object":"chat.completion.chunk","created":1727346176,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_7568d46099","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"c"}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw8AOXnoa2kzy11vVTSjuQhHCQr","object":"chat.completion.chunk","created":1727346176,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_7568d46099","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\"}"}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw8AOXnoa2kzy11vVTSjuQhHCQr","object":"chat.completion.chunk","created":1727346176,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_7568d46099","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"tool_calls"}]} + +data: {"id":"chatcmpl-ABfw8AOXnoa2kzy11vVTSjuQhHCQr","object":"chat.completion.chunk","created":1727346176,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_7568d46099","choices":[],"usage":{"prompt_tokens":76,"completion_tokens":24,"total_tokens":100,"completion_tokens_details":{"reasoning_tokens":0}}} + +data: [DONE] + diff --git a/.inline-snapshot/external/ca015b8b1ebaac98be76f2f855f8694b77f608de5e2a3799276be06ce3fbb15b.bin b/.inline-snapshot/external/ca015b8b1ebaac98be76f2f855f8694b77f608de5e2a3799276be06ce3fbb15b.bin deleted file mode 100644 index c0a355f9d1..0000000000 --- a/.inline-snapshot/external/ca015b8b1ebaac98be76f2f855f8694b77f608de5e2a3799276be06ce3fbb15b.bin +++ /dev/null @@ -1,30 +0,0 @@ -data: {"id":"chatcmpl-9tXmMGFPkLS0t0u0895fzYOblnfYa","object":"chat.completion.chunk","created":1723024914,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"role":"assistant","content":null,"refusal":""},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXmMGFPkLS0t0u0895fzYOblnfYa","object":"chat.completion.chunk","created":1723024914,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"refusal":"I'm"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXmMGFPkLS0t0u0895fzYOblnfYa","object":"chat.completion.chunk","created":1723024914,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"refusal":" sorry"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXmMGFPkLS0t0u0895fzYOblnfYa","object":"chat.completion.chunk","created":1723024914,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"refusal":","},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXmMGFPkLS0t0u0895fzYOblnfYa","object":"chat.completion.chunk","created":1723024914,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"refusal":" but"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXmMGFPkLS0t0u0895fzYOblnfYa","object":"chat.completion.chunk","created":1723024914,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"refusal":" I"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXmMGFPkLS0t0u0895fzYOblnfYa","object":"chat.completion.chunk","created":1723024914,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"refusal":" can't"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXmMGFPkLS0t0u0895fzYOblnfYa","object":"chat.completion.chunk","created":1723024914,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"refusal":" assist"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXmMGFPkLS0t0u0895fzYOblnfYa","object":"chat.completion.chunk","created":1723024914,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"refusal":" with"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXmMGFPkLS0t0u0895fzYOblnfYa","object":"chat.completion.chunk","created":1723024914,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"refusal":" that"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXmMGFPkLS0t0u0895fzYOblnfYa","object":"chat.completion.chunk","created":1723024914,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"refusal":" request"},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXmMGFPkLS0t0u0895fzYOblnfYa","object":"chat.completion.chunk","created":1723024914,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"refusal":"."},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXmMGFPkLS0t0u0895fzYOblnfYa","object":"chat.completion.chunk","created":1723024914,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}]} - -data: {"id":"chatcmpl-9tXmMGFPkLS0t0u0895fzYOblnfYa","object":"chat.completion.chunk","created":1723024914,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[],"usage":{"prompt_tokens":17,"completion_tokens":12,"total_tokens":29}} - -data: [DONE] - diff --git a/.inline-snapshot/external/d615580118391ee13492193e3a8bb74642d23ac1ca13fe37cb6e889b66f759f6.bin b/.inline-snapshot/external/d615580118391ee13492193e3a8bb74642d23ac1ca13fe37cb6e889b66f759f6.bin new file mode 100644 index 0000000000..aee8650c72 --- /dev/null +++ b/.inline-snapshot/external/d615580118391ee13492193e3a8bb74642d23ac1ca13fe37cb6e889b66f759f6.bin @@ -0,0 +1,362 @@ +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\n"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" {\n"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"location"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"San"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" Francisco"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" CA"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\",\n"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"weather"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" {\n"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"temperature"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"18"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"°C"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\",\n"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"condition"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"Part"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"ly"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" Cloud"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"y"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\",\n"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"humidity"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"72"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"%\",\n"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"wind"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"Speed"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"15"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" km"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"/h"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\",\n"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"wind"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"Direction"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"NW"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\"\n"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" },\n"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"forecast"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" [\n"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" {\n"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"day"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"Monday"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\",\n"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"high"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"20"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"°C"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\",\n"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"low"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"14"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"°C"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\",\n"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"condition"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"Sunny"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\"\n"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" },\n"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" {\n"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"day"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"Tuesday"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\",\n"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"high"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"19"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"°C"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\",\n"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"low"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"15"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"°C"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\",\n"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"condition"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"Mostly"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" Cloud"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"y"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\"\n"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" },\n"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" {\n"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"day"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"Wednesday"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\",\n"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"high"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"18"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"°C"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\",\n"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"low"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"14"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"°C"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\",\n"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"condition"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\":"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"Cloud"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"y"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"\"\n"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" }\n"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" ]\n"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" }\n"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}]} + +data: {"id":"chatcmpl-ABfwCjPMi0ubw56UyMIIeNfJzyogq","object":"chat.completion.chunk","created":1727346180,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[],"usage":{"prompt_tokens":19,"completion_tokens":177,"total_tokens":196,"completion_tokens_details":{"reasoning_tokens":0}}} + +data: [DONE] + diff --git a/.inline-snapshot/external/dae1b261f19722801adc82a13181772c3010c10b37e8af3996fbdbbecb3c32a2.bin b/.inline-snapshot/external/dae1b261f19722801adc82a13181772c3010c10b37e8af3996fbdbbecb3c32a2.bin deleted file mode 100644 index f0911c575d..0000000000 --- a/.inline-snapshot/external/dae1b261f19722801adc82a13181772c3010c10b37e8af3996fbdbbecb3c32a2.bin +++ /dev/null @@ -1,22 +0,0 @@ -data: {"id":"chatcmpl-9tXjtfxZZh2FYaFVxXKf2jiqNDiSo","object":"chat.completion.chunk","created":1723024761,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"role":"assistant","content":null,"tool_calls":[{"index":0,"id":"call_5uxEBMFySqqQGu02I5QHA8k6","type":"function","function":{"name":"get_weather","arguments":""}}],"refusal":null},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjtfxZZh2FYaFVxXKf2jiqNDiSo","object":"chat.completion.chunk","created":1723024761,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\""}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjtfxZZh2FYaFVxXKf2jiqNDiSo","object":"chat.completion.chunk","created":1723024761,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"city"}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjtfxZZh2FYaFVxXKf2jiqNDiSo","object":"chat.completion.chunk","created":1723024761,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\":\""}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjtfxZZh2FYaFVxXKf2jiqNDiSo","object":"chat.completion.chunk","created":1723024761,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"New"}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjtfxZZh2FYaFVxXKf2jiqNDiSo","object":"chat.completion.chunk","created":1723024761,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":" York"}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjtfxZZh2FYaFVxXKf2jiqNDiSo","object":"chat.completion.chunk","created":1723024761,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":" City"}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjtfxZZh2FYaFVxXKf2jiqNDiSo","object":"chat.completion.chunk","created":1723024761,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\"}"}}]},"logprobs":null,"finish_reason":null}]} - -data: {"id":"chatcmpl-9tXjtfxZZh2FYaFVxXKf2jiqNDiSo","object":"chat.completion.chunk","created":1723024761,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"tool_calls"}]} - -data: {"id":"chatcmpl-9tXjtfxZZh2FYaFVxXKf2jiqNDiSo","object":"chat.completion.chunk","created":1723024761,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[],"usage":{"prompt_tokens":44,"completion_tokens":16,"total_tokens":60}} - -data: [DONE] - diff --git a/.inline-snapshot/external/e2aad469b71d1d4894ff833ea147020a9d875eb7ce644a0ff355581690a4cbfd.bin b/.inline-snapshot/external/e2aad469b71d1d4894ff833ea147020a9d875eb7ce644a0ff355581690a4cbfd.bin new file mode 100644 index 0000000000..b68ca8a3d9 --- /dev/null +++ b/.inline-snapshot/external/e2aad469b71d1d4894ff833ea147020a9d875eb7ce644a0ff355581690a4cbfd.bin @@ -0,0 +1,68 @@ +data: {"id":"chatcmpl-ABfw031mOJeYCSHe4yI2ZjOA6kMJL","object":"chat.completion.chunk","created":1727346168,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw031mOJeYCSHe4yI2ZjOA6kMJL","object":"chat.completion.chunk","created":1727346168,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"I'm"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw031mOJeYCSHe4yI2ZjOA6kMJL","object":"chat.completion.chunk","created":1727346168,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" unable"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw031mOJeYCSHe4yI2ZjOA6kMJL","object":"chat.completion.chunk","created":1727346168,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" to"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw031mOJeYCSHe4yI2ZjOA6kMJL","object":"chat.completion.chunk","created":1727346168,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" provide"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw031mOJeYCSHe4yI2ZjOA6kMJL","object":"chat.completion.chunk","created":1727346168,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" real"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw031mOJeYCSHe4yI2ZjOA6kMJL","object":"chat.completion.chunk","created":1727346168,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"-time"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw031mOJeYCSHe4yI2ZjOA6kMJL","object":"chat.completion.chunk","created":1727346168,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" weather"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw031mOJeYCSHe4yI2ZjOA6kMJL","object":"chat.completion.chunk","created":1727346168,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" updates"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw031mOJeYCSHe4yI2ZjOA6kMJL","object":"chat.completion.chunk","created":1727346168,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"."},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw031mOJeYCSHe4yI2ZjOA6kMJL","object":"chat.completion.chunk","created":1727346168,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" To"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw031mOJeYCSHe4yI2ZjOA6kMJL","object":"chat.completion.chunk","created":1727346168,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" get"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw031mOJeYCSHe4yI2ZjOA6kMJL","object":"chat.completion.chunk","created":1727346168,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" the"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw031mOJeYCSHe4yI2ZjOA6kMJL","object":"chat.completion.chunk","created":1727346168,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" current"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw031mOJeYCSHe4yI2ZjOA6kMJL","object":"chat.completion.chunk","created":1727346168,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" weather"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw031mOJeYCSHe4yI2ZjOA6kMJL","object":"chat.completion.chunk","created":1727346168,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw031mOJeYCSHe4yI2ZjOA6kMJL","object":"chat.completion.chunk","created":1727346168,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" San"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw031mOJeYCSHe4yI2ZjOA6kMJL","object":"chat.completion.chunk","created":1727346168,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" Francisco"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw031mOJeYCSHe4yI2ZjOA6kMJL","object":"chat.completion.chunk","created":1727346168,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw031mOJeYCSHe4yI2ZjOA6kMJL","object":"chat.completion.chunk","created":1727346168,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" I"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw031mOJeYCSHe4yI2ZjOA6kMJL","object":"chat.completion.chunk","created":1727346168,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" recommend"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw031mOJeYCSHe4yI2ZjOA6kMJL","object":"chat.completion.chunk","created":1727346168,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" checking"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw031mOJeYCSHe4yI2ZjOA6kMJL","object":"chat.completion.chunk","created":1727346168,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" a"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw031mOJeYCSHe4yI2ZjOA6kMJL","object":"chat.completion.chunk","created":1727346168,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" reliable"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw031mOJeYCSHe4yI2ZjOA6kMJL","object":"chat.completion.chunk","created":1727346168,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" weather"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw031mOJeYCSHe4yI2ZjOA6kMJL","object":"chat.completion.chunk","created":1727346168,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" website"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw031mOJeYCSHe4yI2ZjOA6kMJL","object":"chat.completion.chunk","created":1727346168,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" or"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw031mOJeYCSHe4yI2ZjOA6kMJL","object":"chat.completion.chunk","created":1727346168,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" a"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw031mOJeYCSHe4yI2ZjOA6kMJL","object":"chat.completion.chunk","created":1727346168,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" weather"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw031mOJeYCSHe4yI2ZjOA6kMJL","object":"chat.completion.chunk","created":1727346168,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":" app"},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw031mOJeYCSHe4yI2ZjOA6kMJL","object":"chat.completion.chunk","created":1727346168,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"content":"."},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfw031mOJeYCSHe4yI2ZjOA6kMJL","object":"chat.completion.chunk","created":1727346168,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}]} + +data: {"id":"chatcmpl-ABfw031mOJeYCSHe4yI2ZjOA6kMJL","object":"chat.completion.chunk","created":1727346168,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[],"usage":{"prompt_tokens":14,"completion_tokens":30,"total_tokens":44,"completion_tokens_details":{"reasoning_tokens":0}}} + +data: [DONE] + diff --git a/.inline-snapshot/external/f82268f2fefd5cfbc7eeb59c297688be2f6ca0849a6e4f17851b517310841d9b.bin b/.inline-snapshot/external/f82268f2fefd5cfbc7eeb59c297688be2f6ca0849a6e4f17851b517310841d9b.bin new file mode 100644 index 0000000000..3b111d5e61 --- /dev/null +++ b/.inline-snapshot/external/f82268f2fefd5cfbc7eeb59c297688be2f6ca0849a6e4f17851b517310841d9b.bin @@ -0,0 +1,52 @@ +data: {"id":"chatcmpl-ABfwAwrNePHUgBBezonVC6MX3zd63","object":"chat.completion.chunk","created":1727346178,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"role":"assistant","content":null},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwAwrNePHUgBBezonVC6MX3zd63","object":"chat.completion.chunk","created":1727346178,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"id":"call_JMW1whyEaYG438VE1OIflxA2","type":"function","function":{"name":"GetWeatherArgs","arguments":""}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwAwrNePHUgBBezonVC6MX3zd63","object":"chat.completion.chunk","created":1727346178,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\"ci"}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwAwrNePHUgBBezonVC6MX3zd63","object":"chat.completion.chunk","created":1727346178,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"ty\": "}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwAwrNePHUgBBezonVC6MX3zd63","object":"chat.completion.chunk","created":1727346178,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\"Edinb"}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwAwrNePHUgBBezonVC6MX3zd63","object":"chat.completion.chunk","created":1727346178,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"urgh"}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwAwrNePHUgBBezonVC6MX3zd63","object":"chat.completion.chunk","created":1727346178,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\", \"c"}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwAwrNePHUgBBezonVC6MX3zd63","object":"chat.completion.chunk","created":1727346178,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"ountry"}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwAwrNePHUgBBezonVC6MX3zd63","object":"chat.completion.chunk","created":1727346178,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\": \""}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwAwrNePHUgBBezonVC6MX3zd63","object":"chat.completion.chunk","created":1727346178,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"GB\", "}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwAwrNePHUgBBezonVC6MX3zd63","object":"chat.completion.chunk","created":1727346178,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\"units"}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwAwrNePHUgBBezonVC6MX3zd63","object":"chat.completion.chunk","created":1727346178,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\": \""}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwAwrNePHUgBBezonVC6MX3zd63","object":"chat.completion.chunk","created":1727346178,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"c\"}"}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwAwrNePHUgBBezonVC6MX3zd63","object":"chat.completion.chunk","created":1727346178,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"id":"call_DNYTawLBoN8fj3KN6qU9N1Ou","type":"function","function":{"name":"get_stock_price","arguments":""}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwAwrNePHUgBBezonVC6MX3zd63","object":"chat.completion.chunk","created":1727346178,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"function":{"arguments":"{\"ti"}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwAwrNePHUgBBezonVC6MX3zd63","object":"chat.completion.chunk","created":1727346178,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"function":{"arguments":"cker\""}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwAwrNePHUgBBezonVC6MX3zd63","object":"chat.completion.chunk","created":1727346178,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"function":{"arguments":": \"AAP"}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwAwrNePHUgBBezonVC6MX3zd63","object":"chat.completion.chunk","created":1727346178,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"function":{"arguments":"L\", "}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwAwrNePHUgBBezonVC6MX3zd63","object":"chat.completion.chunk","created":1727346178,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"function":{"arguments":"\"exch"}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwAwrNePHUgBBezonVC6MX3zd63","object":"chat.completion.chunk","created":1727346178,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"function":{"arguments":"ange\":"}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwAwrNePHUgBBezonVC6MX3zd63","object":"chat.completion.chunk","created":1727346178,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"function":{"arguments":" \"NA"}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwAwrNePHUgBBezonVC6MX3zd63","object":"chat.completion.chunk","created":1727346178,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"function":{"arguments":"SDAQ\""}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwAwrNePHUgBBezonVC6MX3zd63","object":"chat.completion.chunk","created":1727346178,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"function":{"arguments":"}"}}]},"logprobs":null,"finish_reason":null}]} + +data: {"id":"chatcmpl-ABfwAwrNePHUgBBezonVC6MX3zd63","object":"chat.completion.chunk","created":1727346178,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"tool_calls"}]} + +data: {"id":"chatcmpl-ABfwAwrNePHUgBBezonVC6MX3zd63","object":"chat.completion.chunk","created":1727346178,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_5050236cbd","choices":[],"usage":{"prompt_tokens":149,"completion_tokens":60,"total_tokens":209,"completion_tokens_details":{"reasoning_tokens":0}}} + +data: [DONE] + diff --git a/tests/lib/chat/test_completions.py b/tests/lib/chat/test_completions.py index e7b9c4f1fd..d66630fa3a 100644 --- a/tests/lib/chat/test_completions.py +++ b/tests/lib/chat/test_completions.py @@ -43,7 +43,7 @@ def test_parse_nothing(client: OpenAI, respx_mock: MockRouter, monkeypatch: pyte ], ), content_snapshot=snapshot( - '{"id": "chatcmpl-9tXjSozlYq8oGdlRH3vgLsiUNRg8c", "object": "chat.completion", "created": 1723024734, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": "I\'m unable to provide real-time weather updates. To find out the current weather in San Francisco, please check a reliable weather website or app.", "refusal": null}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 14, "completion_tokens": 28, "total_tokens": 42}, "system_fingerprint": "fp_845eaabc1f"}' + '{"id": "chatcmpl-ABfvaueLEMLNYbT8YzpJxsmiQ6HSY", "object": "chat.completion", "created": 1727346142, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": "I\'m unable to provide real-time weather updates. To get the current weather in San Francisco, I recommend checking a reliable weather website or app like the Weather Channel or a local news station.", "refusal": null}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 14, "completion_tokens": 37, "total_tokens": 51, "completion_tokens_details": {"reasoning_tokens": 0}}, "system_fingerprint": "fp_b40fb1c6fb"}' ), mock_client=client, respx_mock=respx_mock, @@ -58,8 +58,8 @@ def test_parse_nothing(client: OpenAI, respx_mock: MockRouter, monkeypatch: pyte index=0, logprobs=None, message=ParsedChatCompletionMessage[NoneType]( - content="I'm unable to provide real-time weather updates. To find out the current weather in San -Francisco, please check a reliable weather website or app.", + content="I'm unable to provide real-time weather updates. To get the current weather in San Francisco, I +recommend checking a reliable weather website or app like the Weather Channel or a local news station.", function_call=None, parsed=None, refusal=None, @@ -68,13 +68,18 @@ def test_parse_nothing(client: OpenAI, respx_mock: MockRouter, monkeypatch: pyte ) ) ], - created=1723024734, - id='chatcmpl-9tXjSozlYq8oGdlRH3vgLsiUNRg8c', + created=1727346142, + id='chatcmpl-ABfvaueLEMLNYbT8YzpJxsmiQ6HSY', model='gpt-4o-2024-08-06', object='chat.completion', service_tier=None, - system_fingerprint='fp_845eaabc1f', - usage=CompletionUsage(completion_tokens=28, completion_tokens_details=None, prompt_tokens=14, total_tokens=42) + system_fingerprint='fp_b40fb1c6fb', + usage=CompletionUsage( + completion_tokens=37, + completion_tokens_details=CompletionTokensDetails(reasoning_tokens=0), + prompt_tokens=14, + total_tokens=51 + ) ) """ ) @@ -99,7 +104,7 @@ class Location(BaseModel): response_format=Location, ), content_snapshot=snapshot( - '{"id": "chatcmpl-9tXjTNupyDe7nL1Z8eOO6BdSyrHAD", "object": "chat.completion", "created": 1723024735, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": "{\\"city\\":\\"San Francisco\\",\\"temperature\\":56,\\"units\\":\\"f\\"}", "refusal": null}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 17, "completion_tokens": 14, "total_tokens": 31}, "system_fingerprint": "fp_2a322c9ffc"}' + '{"id": "chatcmpl-ABfvbtVnTu5DeC4EFnRYj8mtfOM99", "object": "chat.completion", "created": 1727346143, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": "{\\"city\\":\\"San Francisco\\",\\"temperature\\":65,\\"units\\":\\"f\\"}", "refusal": null}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 79, "completion_tokens": 14, "total_tokens": 93, "completion_tokens_details": {"reasoning_tokens": 0}}, "system_fingerprint": "fp_5050236cbd"}' ), mock_client=client, respx_mock=respx_mock, @@ -114,22 +119,27 @@ class Location(BaseModel): index=0, logprobs=None, message=ParsedChatCompletionMessage[Location]( - content='{"city":"San Francisco","temperature":56,"units":"f"}', + content='{"city":"San Francisco","temperature":65,"units":"f"}', function_call=None, - parsed=Location(city='San Francisco', temperature=56.0, units='f'), + parsed=Location(city='San Francisco', temperature=65.0, units='f'), refusal=None, role='assistant', tool_calls=[] ) ) ], - created=1723024735, - id='chatcmpl-9tXjTNupyDe7nL1Z8eOO6BdSyrHAD', + created=1727346143, + id='chatcmpl-ABfvbtVnTu5DeC4EFnRYj8mtfOM99', model='gpt-4o-2024-08-06', object='chat.completion', service_tier=None, - system_fingerprint='fp_2a322c9ffc', - usage=CompletionUsage(completion_tokens=14, completion_tokens_details=None, prompt_tokens=17, total_tokens=31) + system_fingerprint='fp_5050236cbd', + usage=CompletionUsage( + completion_tokens=14, + completion_tokens_details=CompletionTokensDetails(reasoning_tokens=0), + prompt_tokens=79, + total_tokens=93 + ) ) """ ) @@ -156,7 +166,7 @@ class Location(BaseModel): response_format=Location, ), content_snapshot=snapshot( - '{"id": "chatcmpl-9y39Q2jGzWmeEZlm5CoNVOuQzcxP4", "object": "chat.completion", "created": 1724098820, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": "{\\"city\\":\\"San Francisco\\",\\"temperature\\":62,\\"units\\":\\"f\\"}", "refusal": null}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 17, "completion_tokens": 14, "total_tokens": 31}, "system_fingerprint": "fp_2a322c9ffc"}' + '{"id": "chatcmpl-ABfvcC8grKYsRkSoMp9CCAhbXAd0b", "object": "chat.completion", "created": 1727346144, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": "{\\"city\\":\\"San Francisco\\",\\"temperature\\":65,\\"units\\":\\"f\\"}", "refusal": null}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 88, "completion_tokens": 14, "total_tokens": 102, "completion_tokens_details": {"reasoning_tokens": 0}}, "system_fingerprint": "fp_b40fb1c6fb"}' ), mock_client=client, respx_mock=respx_mock, @@ -171,22 +181,27 @@ class Location(BaseModel): index=0, logprobs=None, message=ParsedChatCompletionMessage[Location]( - content='{"city":"San Francisco","temperature":62,"units":"f"}', + content='{"city":"San Francisco","temperature":65,"units":"f"}', function_call=None, - parsed=Location(city='San Francisco', temperature=62.0, units='f'), + parsed=Location(city='San Francisco', temperature=65.0, units='f'), refusal=None, role='assistant', tool_calls=[] ) ) ], - created=1724098820, - id='chatcmpl-9y39Q2jGzWmeEZlm5CoNVOuQzcxP4', + created=1727346144, + id='chatcmpl-ABfvcC8grKYsRkSoMp9CCAhbXAd0b', model='gpt-4o-2024-08-06', object='chat.completion', service_tier=None, - system_fingerprint='fp_2a322c9ffc', - usage=CompletionUsage(completion_tokens=14, completion_tokens_details=None, prompt_tokens=17, total_tokens=31) + system_fingerprint='fp_b40fb1c6fb', + usage=CompletionUsage( + completion_tokens=14, + completion_tokens_details=CompletionTokensDetails(reasoning_tokens=0), + prompt_tokens=88, + total_tokens=102 + ) ) """ ) @@ -217,7 +232,7 @@ class ColorDetection(BaseModel): response_format=ColorDetection, ), content_snapshot=snapshot( - '{"id": "chatcmpl-9vK4UZVr385F2UgZlP1ShwPn2nFxG", "object": "chat.completion", "created": 1723448878, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": "{\\"color\\":\\"red\\",\\"hex_color_code\\":\\"#FF0000\\"}", "refusal": null}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 18, "completion_tokens": 14, "total_tokens": 32}, "system_fingerprint": "fp_845eaabc1f"}' + '{"id": "chatcmpl-ABfvjIatz0zrZu50gRbMtlp0asZpz", "object": "chat.completion", "created": 1727346151, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": "{\\"color\\":\\"red\\",\\"hex_color_code\\":\\"#FF0000\\"}", "refusal": null}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 109, "completion_tokens": 14, "total_tokens": 123, "completion_tokens_details": {"reasoning_tokens": 0}}, "system_fingerprint": "fp_5050236cbd"}' ), mock_client=client, respx_mock=respx_mock, @@ -264,7 +279,7 @@ class Location(BaseModel): response_format=Location, ), content_snapshot=snapshot( - '{"id": "chatcmpl-9tXjUrNFyyjSB2FJ842TMDNRM6Gen", "object": "chat.completion", "created": 1723024736, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": "{\\"city\\":\\"San Francisco\\",\\"temperature\\":58,\\"units\\":\\"f\\"}", "refusal": null}, "logprobs": null, "finish_reason": "stop"}, {"index": 1, "message": {"role": "assistant", "content": "{\\"city\\":\\"San Francisco\\",\\"temperature\\":58,\\"units\\":\\"f\\"}", "refusal": null}, "logprobs": null, "finish_reason": "stop"}, {"index": 2, "message": {"role": "assistant", "content": "{\\"city\\":\\"San Francisco\\",\\"temperature\\":63,\\"units\\":\\"f\\"}", "refusal": null}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 17, "completion_tokens": 42, "total_tokens": 59}, "system_fingerprint": "fp_845eaabc1f"}' + '{"id": "chatcmpl-ABfvp8qzboW92q8ONDF4DPHlI7ckC", "object": "chat.completion", "created": 1727346157, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": "{\\"city\\":\\"San Francisco\\",\\"temperature\\":64,\\"units\\":\\"f\\"}", "refusal": null}, "logprobs": null, "finish_reason": "stop"}, {"index": 1, "message": {"role": "assistant", "content": "{\\"city\\":\\"San Francisco\\",\\"temperature\\":65,\\"units\\":\\"f\\"}", "refusal": null}, "logprobs": null, "finish_reason": "stop"}, {"index": 2, "message": {"role": "assistant", "content": "{\\"city\\":\\"San Francisco\\",\\"temperature\\":63.0,\\"units\\":\\"f\\"}", "refusal": null}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 79, "completion_tokens": 44, "total_tokens": 123, "completion_tokens_details": {"reasoning_tokens": 0}}, "system_fingerprint": "fp_b40fb1c6fb"}' ), mock_client=client, respx_mock=respx_mock, @@ -278,9 +293,9 @@ class Location(BaseModel): index=0, logprobs=None, message=ParsedChatCompletionMessage[Location]( - content='{"city":"San Francisco","temperature":58,"units":"f"}', + content='{"city":"San Francisco","temperature":64,"units":"f"}', function_call=None, - parsed=Location(city='San Francisco', temperature=58.0, units='f'), + parsed=Location(city='San Francisco', temperature=64.0, units='f'), refusal=None, role='assistant', tool_calls=[] @@ -291,9 +306,9 @@ class Location(BaseModel): index=1, logprobs=None, message=ParsedChatCompletionMessage[Location]( - content='{"city":"San Francisco","temperature":58,"units":"f"}', + content='{"city":"San Francisco","temperature":65,"units":"f"}', function_call=None, - parsed=Location(city='San Francisco', temperature=58.0, units='f'), + parsed=Location(city='San Francisco', temperature=65.0, units='f'), refusal=None, role='assistant', tool_calls=[] @@ -304,7 +319,7 @@ class Location(BaseModel): index=2, logprobs=None, message=ParsedChatCompletionMessage[Location]( - content='{"city":"San Francisco","temperature":63,"units":"f"}', + content='{"city":"San Francisco","temperature":63.0,"units":"f"}', function_call=None, parsed=Location(city='San Francisco', temperature=63.0, units='f'), refusal=None, @@ -338,7 +353,7 @@ class CalendarEvent: response_format=CalendarEvent, ), content_snapshot=snapshot( - '{"id": "chatcmpl-9wdGqXkJJARAz7rOrLH5u5FBwLjF3", "object": "chat.completion", "created": 1723761008, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": "{\\"name\\":\\"Science Fair\\",\\"date\\":\\"Friday\\",\\"participants\\":[\\"Alice\\",\\"Bob\\"]}", "refusal": null}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 32, "completion_tokens": 17, "total_tokens": 49}, "system_fingerprint": "fp_2a322c9ffc"}' + '{"id": "chatcmpl-ABfvqhz4uUUWsw8Ohw2Mp9B4sKKV8", "object": "chat.completion", "created": 1727346158, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": "{\\"name\\":\\"Science Fair\\",\\"date\\":\\"Friday\\",\\"participants\\":[\\"Alice\\",\\"Bob\\"]}", "refusal": null}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 92, "completion_tokens": 17, "total_tokens": 109, "completion_tokens_details": {"reasoning_tokens": 0}}, "system_fingerprint": "fp_7568d46099"}' ), mock_client=client, respx_mock=respx_mock, @@ -362,13 +377,18 @@ class CalendarEvent: ) ) ], - created=1723761008, - id='chatcmpl-9wdGqXkJJARAz7rOrLH5u5FBwLjF3', + created=1727346158, + id='chatcmpl-ABfvqhz4uUUWsw8Ohw2Mp9B4sKKV8', model='gpt-4o-2024-08-06', object='chat.completion', service_tier=None, - system_fingerprint='fp_2a322c9ffc', - usage=CompletionUsage(completion_tokens=17, completion_tokens_details=None, prompt_tokens=32, total_tokens=49) + system_fingerprint='fp_7568d46099', + usage=CompletionUsage( + completion_tokens=17, + completion_tokens_details=CompletionTokensDetails(reasoning_tokens=0), + prompt_tokens=92, + total_tokens=109 + ) ) """ ) @@ -389,7 +409,7 @@ def test_pydantic_tool_model_all_types(client: OpenAI, respx_mock: MockRouter, m response_format=Query, ), content_snapshot=snapshot( - '{"id": "chatcmpl-9tXjVJVCLTn7CWFhpjETixvvApCk3", "object": "chat.completion", "created": 1723024737, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": null, "tool_calls": [{"id": "call_Un4g0IXeQGOyqKBS3zhqNCox", "type": "function", "function": {"name": "Query", "arguments": "{\\"table_name\\":\\"orders\\",\\"columns\\":[\\"id\\",\\"status\\",\\"expected_delivery_date\\",\\"delivered_at\\",\\"shipped_at\\",\\"ordered_at\\"],\\"conditions\\":[{\\"column\\":\\"ordered_at\\",\\"operator\\":\\">=\\",\\"value\\":\\"2022-05-01\\"},{\\"column\\":\\"ordered_at\\",\\"operator\\":\\"<=\\",\\"value\\":\\"2022-05-31\\"},{\\"column\\":\\"status\\",\\"operator\\":\\"=\\",\\"value\\":\\"fulfilled\\"},{\\"column\\":\\"delivered_at\\",\\"operator\\":\\">\\",\\"value\\":{\\"column_name\\":\\"expected_delivery_date\\"}}],\\"order_by\\":\\"asc\\"}"}}], "refusal": null}, "logprobs": null, "finish_reason": "tool_calls"}], "usage": {"prompt_tokens": 195, "completion_tokens": 114, "total_tokens": 309}, "system_fingerprint": "fp_845eaabc1f"}' + '{"id": "chatcmpl-ABfvtNiaTNUF6OymZUnEFc9lPq9p1", "object": "chat.completion", "created": 1727346161, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": null, "tool_calls": [{"id": "call_NKpApJybW1MzOjZO2FzwYw0d", "type": "function", "function": {"name": "Query", "arguments": "{\\"name\\":\\"May 2022 Fulfilled Orders Not Delivered on Time\\",\\"table_name\\":\\"orders\\",\\"columns\\":[\\"id\\",\\"status\\",\\"expected_delivery_date\\",\\"delivered_at\\",\\"shipped_at\\",\\"ordered_at\\",\\"canceled_at\\"],\\"conditions\\":[{\\"column\\":\\"ordered_at\\",\\"operator\\":\\">=\\",\\"value\\":\\"2022-05-01\\"},{\\"column\\":\\"ordered_at\\",\\"operator\\":\\"<=\\",\\"value\\":\\"2022-05-31\\"},{\\"column\\":\\"status\\",\\"operator\\":\\"=\\",\\"value\\":\\"fulfilled\\"},{\\"column\\":\\"delivered_at\\",\\"operator\\":\\">\\",\\"value\\":{\\"column_name\\":\\"expected_delivery_date\\"}}],\\"order_by\\":\\"asc\\"}"}}], "refusal": null}, "logprobs": null, "finish_reason": "tool_calls"}], "usage": {"prompt_tokens": 512, "completion_tokens": 132, "total_tokens": 644, "completion_tokens_details": {"reasoning_tokens": 0}}, "system_fingerprint": "fp_7568d46099"}' ), mock_client=client, respx_mock=respx_mock, @@ -410,10 +430,11 @@ def test_pydantic_tool_model_all_types(client: OpenAI, respx_mock: MockRouter, m tool_calls=[ ParsedFunctionToolCall( function=ParsedFunction( - arguments='{"table_name":"orders","columns":["id","status","expected_delivery_date","delivered_at"," -shipped_at","ordered_at"],"conditions":[{"column":"ordered_at","operator":">=","value":"2022-05-01"},{"column":"ordered_ -at","operator":"<=","value":"2022-05-31"},{"column":"status","operator":"=","value":"fulfilled"},{"column":"delivered_at -","operator":">","value":{"column_name":"expected_delivery_date"}}],"order_by":"asc"}', + arguments='{"name":"May 2022 Fulfilled Orders Not Delivered on +Time","table_name":"orders","columns":["id","status","expected_delivery_date","delivered_at","shipped_at","ordered_at"," +canceled_at"],"conditions":[{"column":"ordered_at","operator":">=","value":"2022-05-01"},{"column":"ordered_at","operato +r":"<=","value":"2022-05-31"},{"column":"status","operator":"=","value":"fulfilled"},{"column":"delivered_at","operator" +:">","value":{"column_name":"expected_delivery_date"}}],"order_by":"asc"}', name='Query', parsed_arguments=Query( columns=[ @@ -422,7 +443,8 @@ def test_pydantic_tool_model_all_types(client: OpenAI, respx_mock: MockRouter, m , , , - + , + ], conditions=[ Condition(column='ordered_at', operator=='>, value='2022-05-01'), @@ -434,12 +456,12 @@ def test_pydantic_tool_model_all_types(client: OpenAI, respx_mock: MockRouter, m value=DynamicValue(column_name='expected_delivery_date') ) ], - name=None, + name='May 2022 Fulfilled Orders Not Delivered on Time', order_by=, table_name= ) ), - id='call_Un4g0IXeQGOyqKBS3zhqNCox', + id='call_NKpApJybW1MzOjZO2FzwYw0d', type='function' ) ] @@ -470,7 +492,7 @@ class Location(BaseModel): response_format=Location, ), content_snapshot=snapshot( - '{"id": "chatcmpl-9tXjYACgVKixKdMv2nVQqDVELkdSF", "object": "chat.completion", "created": 1723024740, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": "{\\"", "refusal": null}, "logprobs": null, "finish_reason": "length"}], "usage": {"prompt_tokens": 17, "completion_tokens": 1, "total_tokens": 18}, "system_fingerprint": "fp_2a322c9ffc"}' + '{"id": "chatcmpl-ABfvvX7eB1KsfeZj8VcF3z7G7SbaA", "object": "chat.completion", "created": 1727346163, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": "{\\"", "refusal": null}, "logprobs": null, "finish_reason": "length"}], "usage": {"prompt_tokens": 79, "completion_tokens": 1, "total_tokens": 80, "completion_tokens_details": {"reasoning_tokens": 0}}, "system_fingerprint": "fp_7568d46099"}' ), mock_client=client, respx_mock=respx_mock, @@ -496,7 +518,7 @@ class Location(BaseModel): response_format=Location, ), content_snapshot=snapshot( - '{"id": "chatcmpl-9tXm7FnIj3hSot5xM4c954MIePle0", "object": "chat.completion", "created": 1723024899, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": null, "refusal": "I\'m very sorry, but I can\'t assist with that request."}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 17, "completion_tokens": 13, "total_tokens": 30}, "system_fingerprint": "fp_845eaabc1f"}' + '{"id": "chatcmpl-ABfvwoKVWPQj2UPlAcAKM7s40GsRx", "object": "chat.completion", "created": 1727346164, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": null, "refusal": "I\'m very sorry, but I can\'t assist with that."}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 79, "completion_tokens": 12, "total_tokens": 91, "completion_tokens_details": {"reasoning_tokens": 0}}, "system_fingerprint": "fp_5050236cbd"}' ), mock_client=client, respx_mock=respx_mock, @@ -513,7 +535,7 @@ class Location(BaseModel): content=None, function_call=None, parsed=None, - refusal="I'm very sorry, but I can't assist with that request.", + refusal="I'm very sorry, but I can't assist with that.", role='assistant', tool_calls=[] ) @@ -544,7 +566,7 @@ class GetWeatherArgs(BaseModel): ], ), content_snapshot=snapshot( - '{"id": "chatcmpl-9tXjbQ9V0l5XPlynOJHKvrWsJQymO", "object": "chat.completion", "created": 1723024743, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": null, "tool_calls": [{"id": "call_EEaIYq8aTdiDWro8jILNl3XK", "type": "function", "function": {"name": "GetWeatherArgs", "arguments": "{\\"city\\":\\"Edinburgh\\",\\"country\\":\\"GB\\",\\"units\\":\\"c\\"}"}}], "refusal": null}, "logprobs": null, "finish_reason": "tool_calls"}], "usage": {"prompt_tokens": 76, "completion_tokens": 24, "total_tokens": 100}, "system_fingerprint": "fp_2a322c9ffc"}' + '{"id": "chatcmpl-ABfvx6Z4dchiW2nya1N8KMsHFrQRE", "object": "chat.completion", "created": 1727346165, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": null, "tool_calls": [{"id": "call_Y6qJ7ofLgOrBnMD5WbVAeiRV", "type": "function", "function": {"name": "GetWeatherArgs", "arguments": "{\\"city\\":\\"Edinburgh\\",\\"country\\":\\"UK\\",\\"units\\":\\"c\\"}"}}], "refusal": null}, "logprobs": null, "finish_reason": "tool_calls"}], "usage": {"prompt_tokens": 76, "completion_tokens": 24, "total_tokens": 100, "completion_tokens_details": {"reasoning_tokens": 0}}, "system_fingerprint": "fp_e45dabd248"}' ), mock_client=client, respx_mock=respx_mock, @@ -566,11 +588,11 @@ class GetWeatherArgs(BaseModel): tool_calls=[ ParsedFunctionToolCall( function=ParsedFunction( - arguments='{"city":"Edinburgh","country":"GB","units":"c"}', + arguments='{"city":"Edinburgh","country":"UK","units":"c"}', name='GetWeatherArgs', - parsed_arguments=GetWeatherArgs(city='Edinburgh', country='GB', units='c') + parsed_arguments=GetWeatherArgs(city='Edinburgh', country='UK', units='c') ), - id='call_EEaIYq8aTdiDWro8jILNl3XK', + id='call_Y6qJ7ofLgOrBnMD5WbVAeiRV', type='function' ) ] @@ -615,7 +637,7 @@ class GetStockPrice(BaseModel): ], ), content_snapshot=snapshot( - '{"id": "chatcmpl-9tXjcnIvzZDXRfLfbVTPNL5963GWw", "object": "chat.completion", "created": 1723024744, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": null, "tool_calls": [{"id": "call_ECSuZ8gcNPPwgt24me91jHsJ", "type": "function", "function": {"name": "GetWeatherArgs", "arguments": "{\\"city\\": \\"Edinburgh\\", \\"country\\": \\"UK\\", \\"units\\": \\"c\\"}"}}, {"id": "call_Z3fM2sNBBGILhMtimk5Y3RQk", "type": "function", "function": {"name": "get_stock_price", "arguments": "{\\"ticker\\": \\"AAPL\\", \\"exchange\\": \\"NASDAQ\\"}"}}], "refusal": null}, "logprobs": null, "finish_reason": "tool_calls"}], "usage": {"prompt_tokens": 149, "completion_tokens": 60, "total_tokens": 209}, "system_fingerprint": "fp_845eaabc1f"}' + '{"id": "chatcmpl-ABfvyvfNWKcl7Ohqos4UFrmMs1v4C", "object": "chat.completion", "created": 1727346166, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": null, "tool_calls": [{"id": "call_fdNz3vOBKYgOIpMdWotB9MjY", "type": "function", "function": {"name": "GetWeatherArgs", "arguments": "{\\"city\\": \\"Edinburgh\\", \\"country\\": \\"GB\\", \\"units\\": \\"c\\"}"}}, {"id": "call_h1DWI1POMJLb0KwIyQHWXD4p", "type": "function", "function": {"name": "get_stock_price", "arguments": "{\\"ticker\\": \\"AAPL\\", \\"exchange\\": \\"NASDAQ\\"}"}}], "refusal": null}, "logprobs": null, "finish_reason": "tool_calls"}], "usage": {"prompt_tokens": 149, "completion_tokens": 60, "total_tokens": 209, "completion_tokens_details": {"reasoning_tokens": 0}}, "system_fingerprint": "fp_b40fb1c6fb"}' ), mock_client=client, respx_mock=respx_mock, @@ -637,11 +659,11 @@ class GetStockPrice(BaseModel): tool_calls=[ ParsedFunctionToolCall( function=ParsedFunction( - arguments='{"city": "Edinburgh", "country": "UK", "units": "c"}', + arguments='{"city": "Edinburgh", "country": "GB", "units": "c"}', name='GetWeatherArgs', - parsed_arguments=GetWeatherArgs(city='Edinburgh', country='UK', units='c') + parsed_arguments=GetWeatherArgs(city='Edinburgh', country='GB', units='c') ), - id='call_ECSuZ8gcNPPwgt24me91jHsJ', + id='call_fdNz3vOBKYgOIpMdWotB9MjY', type='function' ), ParsedFunctionToolCall( @@ -650,7 +672,7 @@ class GetStockPrice(BaseModel): name='get_stock_price', parsed_arguments=GetStockPrice(exchange='NASDAQ', ticker='AAPL') ), - id='call_Z3fM2sNBBGILhMtimk5Y3RQk', + id='call_h1DWI1POMJLb0KwIyQHWXD4p', type='function' ) ] @@ -695,7 +717,7 @@ def test_parse_strict_tools(client: OpenAI, respx_mock: MockRouter, monkeypatch: ], ), content_snapshot=snapshot( - '{"id": "chatcmpl-9tXjfjETDIqeYvDjsuGACbwdY0xsr", "object": "chat.completion", "created": 1723024747, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": null, "tool_calls": [{"id": "call_7ZZPctBXQWexQlIHSrIHMVUq", "type": "function", "function": {"name": "get_weather", "arguments": "{\\"city\\":\\"San Francisco\\",\\"state\\":\\"CA\\"}"}}], "refusal": null}, "logprobs": null, "finish_reason": "tool_calls"}], "usage": {"prompt_tokens": 48, "completion_tokens": 19, "total_tokens": 67}, "system_fingerprint": "fp_2a322c9ffc"}' + '{"id": "chatcmpl-ABfvzdvCI6RaIkiEFNjqGXCSYnlzf", "object": "chat.completion", "created": 1727346167, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": null, "tool_calls": [{"id": "call_CUdUoJpsWWVdxXntucvnol1M", "type": "function", "function": {"name": "get_weather", "arguments": "{\\"city\\":\\"San Francisco\\",\\"state\\":\\"CA\\"}"}}], "refusal": null}, "logprobs": null, "finish_reason": "tool_calls"}], "usage": {"prompt_tokens": 48, "completion_tokens": 19, "total_tokens": 67, "completion_tokens_details": {"reasoning_tokens": 0}}, "system_fingerprint": "fp_5050236cbd"}' ), mock_client=client, respx_mock=respx_mock, @@ -721,7 +743,7 @@ def test_parse_strict_tools(client: OpenAI, respx_mock: MockRouter, monkeypatch: name='get_weather', parsed_arguments={'city': 'San Francisco', 'state': 'CA'} ), - id='call_7ZZPctBXQWexQlIHSrIHMVUq', + id='call_CUdUoJpsWWVdxXntucvnol1M', type='function' ) ] diff --git a/tests/lib/chat/test_completions_streaming.py b/tests/lib/chat/test_completions_streaming.py index 5ad1f084d2..ce402cd158 100644 --- a/tests/lib/chat/test_completions_streaming.py +++ b/tests/lib/chat/test_completions_streaming.py @@ -48,7 +48,7 @@ def test_parse_nothing(client: OpenAI, respx_mock: MockRouter, monkeypatch: pyte }, ], ), - content_snapshot=snapshot(external("038a5c69c34c*.bin")), + content_snapshot=snapshot(external("e2aad469b71d*.bin")), mock_client=client, respx_mock=respx_mock, ) @@ -61,9 +61,8 @@ def test_parse_nothing(client: OpenAI, respx_mock: MockRouter, monkeypatch: pyte index=0, logprobs=None, message=ParsedChatCompletionMessage[NoneType]( - content="I'm unable to provide real-time updates, including current weather information. For the latest -weather in San Francisco, I recommend checking a reliable weather website or app such as the Weather Channel, BBC -Weather, or a local San Francisco news station.", + content="I'm unable to provide real-time weather updates. To get the current weather in San Francisco, I +recommend checking a reliable weather website or a weather app.", function_call=None, parsed=None, refusal=None, @@ -77,9 +76,8 @@ def test_parse_nothing(client: OpenAI, respx_mock: MockRouter, monkeypatch: pyte assert print_obj(listener.get_event_by_type("content.done"), monkeypatch) == snapshot( """\ ContentDoneEvent[NoneType]( - content="I'm unable to provide real-time updates, including current weather information. For the latest weather in -San Francisco, I recommend checking a reliable weather website or app such as the Weather Channel, BBC Weather, or a -local San Francisco news station.", + content="I'm unable to provide real-time weather updates. To get the current weather in San Francisco, I recommend +checking a reliable weather website or a weather app.", parsed=None, type='content.done' ) @@ -111,7 +109,7 @@ def on_event(stream: ChatCompletionStream[Location], event: ChatCompletionStream ], response_format=Location, ), - content_snapshot=snapshot(external("15ae68f793c7*.bin")), + content_snapshot=snapshot(external("7e5ea4d12e7c*.bin")), mock_client=client, respx_mock=respx_mock, on_event=on_event, @@ -140,30 +138,35 @@ def on_event(stream: ChatCompletionStream[Location], event: ChatCompletionStream index=0, logprobs=None, message=ParsedChatCompletionMessage[Location]( - content='{"city":"San Francisco","temperature":68,"units":"f"}', + content='{"city":"San Francisco","temperature":61,"units":"f"}', function_call=None, - parsed=Location(city='San Francisco', temperature=68.0, units='f'), + parsed=Location(city='San Francisco', temperature=61.0, units='f'), refusal=None, role='assistant', tool_calls=[] ) ) ], - created=1723024750, - id='chatcmpl-9tXji2y8kKxlOO3muVvfdJ7ECJVlD', + created=1727346169, + id='chatcmpl-ABfw1e5abtU8OwGr15vOreYVb2MiF', model='gpt-4o-2024-08-06', object='chat.completion', service_tier=None, - system_fingerprint='fp_845eaabc1f', - usage=CompletionUsage(completion_tokens=14, completion_tokens_details=None, prompt_tokens=17, total_tokens=31) + system_fingerprint='fp_5050236cbd', + usage=CompletionUsage( + completion_tokens=14, + completion_tokens_details=CompletionTokensDetails(reasoning_tokens=0), + prompt_tokens=79, + total_tokens=93 + ) ) """ ) assert print_obj(listener.get_event_by_type("content.done"), monkeypatch) == snapshot( """\ ContentDoneEvent[Location]( - content='{"city":"San Francisco","temperature":68,"units":"f"}', - parsed=Location(city='San Francisco', temperature=68.0, units='f'), + content='{"city":"San Francisco","temperature":61,"units":"f"}', + parsed=Location(city='San Francisco', temperature=61.0, units='f'), type='content.done' ) """ @@ -191,7 +194,7 @@ class Location(BaseModel): n=3, response_format=Location, ), - content_snapshot=snapshot(external("a0c4f0be184e*.bin")), + content_snapshot=snapshot(external("a491adda08c3*.bin")), mock_client=client, respx_mock=respx_mock, ) @@ -211,36 +214,22 @@ class Location(BaseModel): "chunk", "content.delta", "chunk", - "refusal.delta", - "chunk", - "refusal.delta", - "chunk", "content.delta", "chunk", "content.delta", "chunk", - "refusal.delta", - "chunk", "content.delta", "chunk", "content.delta", "chunk", - "refusal.delta", - "chunk", "content.delta", "chunk", "content.delta", "chunk", - "refusal.delta", - "chunk", "content.delta", "chunk", "content.delta", "chunk", - "refusal.delta", - "chunk", - "refusal.delta", - "chunk", "content.delta", "chunk", "content.delta", @@ -249,10 +238,6 @@ class Location(BaseModel): "chunk", "content.delta", "chunk", - "refusal.delta", - "chunk", - "refusal.delta", - "chunk", "content.delta", "chunk", "content.delta", @@ -261,95 +246,57 @@ class Location(BaseModel): "chunk", "content.delta", "chunk", - "refusal.delta", - "chunk", "content.delta", "chunk", "content.delta", "chunk", - "refusal.delta", - "chunk", "content.delta", "chunk", "content.delta", "chunk", - "refusal.delta", - "chunk", "content.delta", "chunk", "content.delta", "chunk", - "refusal.delta", - "chunk", "content.delta", "chunk", "content.delta", "chunk", - "refusal.delta", - "chunk", "content.delta", "chunk", - "refusal.delta", - "chunk", "content.delta", "chunk", - "refusal.delta", - "chunk", - "refusal.delta", - "chunk", - "refusal.delta", - "chunk", - "refusal.delta", - "chunk", - "refusal.delta", - "chunk", - "refusal.delta", - "chunk", - "refusal.delta", - "chunk", - "refusal.delta", - "chunk", - "refusal.delta", - "chunk", - "refusal.delta", - "chunk", - "refusal.delta", - "chunk", - "refusal.delta", - "chunk", - "refusal.delta", - "chunk", - "refusal.delta", + "content.delta", "chunk", - "refusal.delta", + "content.delta", "chunk", - "refusal.delta", + "content.delta", "chunk", - "refusal.delta", + "content.delta", "chunk", - "refusal.delta", + "content.delta", "chunk", - "refusal.delta", + "content.delta", "chunk", - "refusal.delta", + "content.delta", "chunk", - "refusal.delta", + "content.delta", "chunk", - "refusal.delta", + "content.delta", "chunk", - "refusal.delta", + "content.delta", "chunk", - "refusal.delta", + "content.delta", "chunk", - "refusal.delta", + "content.delta", "chunk", - "refusal.delta", + "content.delta", "chunk", "content.done", "chunk", "content.done", "chunk", - "refusal.done", + "content.done", "chunk", ] ) @@ -361,9 +308,9 @@ class Location(BaseModel): index=0, logprobs=None, message=ParsedChatCompletionMessage[Location]( - content='{"city":"San Francisco","temperature":63,"units":"f"}', + content='{"city":"San Francisco","temperature":65,"units":"f"}', function_call=None, - parsed=Location(city='San Francisco', temperature=63.0, units='f'), + parsed=Location(city='San Francisco', temperature=65.0, units='f'), refusal=None, role='assistant', tool_calls=[] @@ -374,9 +321,9 @@ class Location(BaseModel): index=1, logprobs=None, message=ParsedChatCompletionMessage[Location]( - content='{"city":"San Francisco","temperature":58.6,"units":"f"}', + content='{"city":"San Francisco","temperature":61,"units":"f"}', function_call=None, - parsed=Location(city='San Francisco', temperature=58.6, units='f'), + parsed=Location(city='San Francisco', temperature=61.0, units='f'), refusal=None, role='assistant', tool_calls=[] @@ -387,11 +334,10 @@ class Location(BaseModel): index=2, logprobs=None, message=ParsedChatCompletionMessage[Location]( - content=None, + content='{"city":"San Francisco","temperature":59,"units":"f"}', function_call=None, - parsed=None, - refusal="I'm sorry, but I can't accurately provide the current weather for San Francisco as my data is up to -October 2023. You can try checking a reliable weather website or app for real-time updates.", + parsed=Location(city='San Francisco', temperature=59.0, units='f'), + refusal=None, role='assistant', tool_calls=[] ) @@ -421,7 +367,7 @@ class Location(BaseModel): max_tokens=1, response_format=Location, ), - content_snapshot=snapshot(external("69363a555f8e*.bin")), + content_snapshot=snapshot(external("4cc50a6135d2*.bin")), mock_client=client, respx_mock=respx_mock, ) @@ -445,13 +391,13 @@ class Location(BaseModel): ], response_format=Location, ), - content_snapshot=snapshot(external("ca015b8b1eba*.bin")), + content_snapshot=snapshot(external("173417d55340*.bin")), mock_client=client, respx_mock=respx_mock, ) assert print_obj(listener.get_event_by_type("refusal.done"), monkeypatch) == snapshot("""\ -RefusalDoneEvent(refusal="I'm sorry, but I can't assist with that request.", type='refusal.done') +RefusalDoneEvent(refusal="I'm sorry, I can't assist with that request.", type='refusal.done') """) assert print_obj(listener.stream.get_final_completion().choices, monkeypatch) == snapshot( @@ -465,7 +411,7 @@ class Location(BaseModel): content=None, function_call=None, parsed=None, - refusal="I'm sorry, but I can't assist with that request.", + refusal="I'm sorry, I can't assist with that request.", role='assistant', tool_calls=[] ) @@ -488,7 +434,7 @@ def test_content_logprobs_events(client: OpenAI, respx_mock: MockRouter, monkeyp ], logprobs=True, ), - content_snapshot=snapshot(external("be1089999ca5*.bin")), + content_snapshot=snapshot(external("83b060bae42e*.bin")), mock_client=client, respx_mock=respx_mock, ) @@ -497,25 +443,25 @@ def test_content_logprobs_events(client: OpenAI, respx_mock: MockRouter, monkeyp [ LogprobsContentDeltaEvent( content=[ - ChatCompletionTokenLogprob(bytes=[70, 111, 111], logprob=-0.0067602484, token='Foo', top_logprobs=[]) + ChatCompletionTokenLogprob(bytes=[70, 111, 111], logprob=-0.0025094282, token='Foo', top_logprobs=[]) ], snapshot=[ - ChatCompletionTokenLogprob(bytes=[70, 111, 111], logprob=-0.0067602484, token='Foo', top_logprobs=[]) + ChatCompletionTokenLogprob(bytes=[70, 111, 111], logprob=-0.0025094282, token='Foo', top_logprobs=[]) ], type='logprobs.content.delta' ), LogprobsContentDeltaEvent( - content=[ChatCompletionTokenLogprob(bytes=[46], logprob=-2.4962392, token='.', top_logprobs=[])], + content=[ChatCompletionTokenLogprob(bytes=[33], logprob=-0.26638845, token='!', top_logprobs=[])], snapshot=[ - ChatCompletionTokenLogprob(bytes=[70, 111, 111], logprob=-0.0067602484, token='Foo', top_logprobs=[]), - ChatCompletionTokenLogprob(bytes=[46], logprob=-2.4962392, token='.', top_logprobs=[]) + ChatCompletionTokenLogprob(bytes=[70, 111, 111], logprob=-0.0025094282, token='Foo', top_logprobs=[]), + ChatCompletionTokenLogprob(bytes=[33], logprob=-0.26638845, token='!', top_logprobs=[]) ], type='logprobs.content.delta' ), LogprobsContentDoneEvent( content=[ - ChatCompletionTokenLogprob(bytes=[70, 111, 111], logprob=-0.0067602484, token='Foo', top_logprobs=[]), - ChatCompletionTokenLogprob(bytes=[46], logprob=-2.4962392, token='.', top_logprobs=[]) + ChatCompletionTokenLogprob(bytes=[70, 111, 111], logprob=-0.0025094282, token='Foo', top_logprobs=[]), + ChatCompletionTokenLogprob(bytes=[33], logprob=-0.26638845, token='!', top_logprobs=[]) ], type='logprobs.content.done' ) @@ -529,13 +475,13 @@ def test_content_logprobs_events(client: OpenAI, respx_mock: MockRouter, monkeyp index=0, logprobs=ChoiceLogprobs( content=[ - ChatCompletionTokenLogprob(bytes=[70, 111, 111], logprob=-0.0067602484, token='Foo', top_logprobs=[]), - ChatCompletionTokenLogprob(bytes=[46], logprob=-2.4962392, token='.', top_logprobs=[]) + ChatCompletionTokenLogprob(bytes=[70, 111, 111], logprob=-0.0025094282, token='Foo', top_logprobs=[]), + ChatCompletionTokenLogprob(bytes=[33], logprob=-0.26638845, token='!', top_logprobs=[]) ], refusal=None ), message=ParsedChatCompletionMessage[NoneType]( - content='Foo.', + content='Foo!', function_call=None, parsed=None, refusal=None, @@ -566,7 +512,7 @@ class Location(BaseModel): logprobs=True, response_format=Location, ), - content_snapshot=snapshot(external("0a00cd46c610*.bin")), + content_snapshot=snapshot(external("569c877e6942*.bin")), mock_client=client, respx_mock=respx_mock, ) @@ -583,6 +529,7 @@ class Location(BaseModel): 'logprobs.refusal.delta', 'logprobs.refusal.delta', 'logprobs.refusal.delta', + 'logprobs.refusal.delta', 'logprobs.refusal.done' ] """) @@ -595,53 +542,59 @@ class Location(BaseModel): logprobs=ChoiceLogprobs( content=None, refusal=[ - ChatCompletionTokenLogprob(bytes=[73, 39, 109], logprob=-0.0016157961, token="I'm", top_logprobs=[]), + ChatCompletionTokenLogprob(bytes=[73, 39, 109], logprob=-0.0012038043, token="I'm", top_logprobs=[]), + ChatCompletionTokenLogprob( + bytes=[32, 118, 101, 114, 121], + logprob=-0.8438816, + token=' very', + top_logprobs=[] + ), ChatCompletionTokenLogprob( bytes=[32, 115, 111, 114, 114, 121], - logprob=-0.78663874, + logprob=-3.4121115e-06, token=' sorry', top_logprobs=[] ), - ChatCompletionTokenLogprob(bytes=[44], logprob=-7.79144e-05, token=',', top_logprobs=[]), - ChatCompletionTokenLogprob(bytes=[32, 73], logprob=-0.5234622, token=' I', top_logprobs=[]), + ChatCompletionTokenLogprob(bytes=[44], logprob=-3.3809047e-05, token=',', top_logprobs=[]), + ChatCompletionTokenLogprob( + bytes=[32, 98, 117, 116], + logprob=-0.038048144, + token=' but', + top_logprobs=[] + ), + ChatCompletionTokenLogprob(bytes=[32, 73], logprob=-0.0016109125, token=' I', top_logprobs=[]), ChatCompletionTokenLogprob( - bytes=[32, 99, 97, 110, 110, 111, 116], - logprob=-0.52499557, - token=' cannot', + bytes=[32, 99, 97, 110, 39, 116], + logprob=-0.0073532974, + token=" can't", top_logprobs=[] ), ChatCompletionTokenLogprob( bytes=[32, 97, 115, 115, 105, 115, 116], - logprob=-0.015198289, + logprob=-0.0020837625, token=' assist', top_logprobs=[] ), ChatCompletionTokenLogprob( bytes=[32, 119, 105, 116, 104], - logprob=-0.00071648485, + logprob=-0.00318354, token=' with', top_logprobs=[] ), ChatCompletionTokenLogprob( bytes=[32, 116, 104, 97, 116], - logprob=-0.008114983, + logprob=-0.0017186158, token=' that', top_logprobs=[] ), - ChatCompletionTokenLogprob( - bytes=[32, 114, 101, 113, 117, 101, 115, 116], - logprob=-0.0013802331, - token=' request', - top_logprobs=[] - ), - ChatCompletionTokenLogprob(bytes=[46], logprob=-3.4121115e-06, token='.', top_logprobs=[]) + ChatCompletionTokenLogprob(bytes=[46], logprob=-0.57687104, token='.', top_logprobs=[]) ] ), message=ParsedChatCompletionMessage[Location]( content=None, function_call=None, parsed=None, - refusal="I'm sorry, I cannot assist with that request.", + refusal="I'm very sorry, but I can't assist with that.", role='assistant', tool_calls=[] ) @@ -670,7 +623,7 @@ class GetWeatherArgs(BaseModel): openai.pydantic_function_tool(GetWeatherArgs), ], ), - content_snapshot=snapshot(external("24aaf30663f9*.bin")), + content_snapshot=snapshot(external("c6aa7e397b71*.bin")), mock_client=client, respx_mock=respx_mock, ) @@ -691,11 +644,11 @@ class GetWeatherArgs(BaseModel): tool_calls=[ ParsedFunctionToolCall( function=ParsedFunction( - arguments='{"city":"Edinburgh","country":"GB","units":"c"}', + arguments='{"city":"Edinburgh","country":"UK","units":"c"}', name='GetWeatherArgs', - parsed_arguments=GetWeatherArgs(city='Edinburgh', country='GB', units='c') + parsed_arguments=GetWeatherArgs(city='Edinburgh', country='UK', units='c') ), - id='call_7PhhveOvvpPK53s1fV8TWhoV', + id='call_c91SqDXlYFuETYv8mUHzz6pp', index=0, type='function' ) @@ -722,11 +675,11 @@ class GetWeatherArgs(BaseModel): tool_calls=[ ParsedFunctionToolCall( function=ParsedFunction( - arguments='{"city":"Edinburgh","country":"GB","units":"c"}', + arguments='{"city":"Edinburgh","country":"UK","units":"c"}', name='GetWeatherArgs', - parsed_arguments=GetWeatherArgs(city='Edinburgh', country='GB', units='c') + parsed_arguments=GetWeatherArgs(city='Edinburgh', country='UK', units='c') ), - id='call_7PhhveOvvpPK53s1fV8TWhoV', + id='call_c91SqDXlYFuETYv8mUHzz6pp', index=0, type='function' ) @@ -771,7 +724,7 @@ class GetStockPrice(BaseModel): ), ], ), - content_snapshot=snapshot(external("453df473e962*.bin")), + content_snapshot=snapshot(external("f82268f2fefd*.bin")), mock_client=client, respx_mock=respx_mock, ) @@ -792,11 +745,11 @@ class GetStockPrice(BaseModel): tool_calls=[ ParsedFunctionToolCall( function=ParsedFunction( - arguments='{"city": "Edinburgh", "country": "UK", "units": "c"}', + arguments='{"city": "Edinburgh", "country": "GB", "units": "c"}', name='GetWeatherArgs', - parsed_arguments=GetWeatherArgs(city='Edinburgh', country='UK', units='c') + parsed_arguments=GetWeatherArgs(city='Edinburgh', country='GB', units='c') ), - id='call_lQnnsesjFMWMQ5IeWPHzR4th', + id='call_JMW1whyEaYG438VE1OIflxA2', index=0, type='function' ), @@ -806,7 +759,7 @@ class GetStockPrice(BaseModel): name='get_stock_price', parsed_arguments=GetStockPrice(exchange='NASDAQ', ticker='AAPL') ), - id='call_2xjOUgaCdiwAcl9ZBL9LyMUU', + id='call_DNYTawLBoN8fj3KN6qU9N1Ou', index=1, type='function' ) @@ -822,11 +775,11 @@ class GetStockPrice(BaseModel): [ ParsedFunctionToolCall( function=ParsedFunction( - arguments='{"city": "Edinburgh", "country": "UK", "units": "c"}', + arguments='{"city": "Edinburgh", "country": "GB", "units": "c"}', name='GetWeatherArgs', - parsed_arguments=GetWeatherArgs(city='Edinburgh', country='UK', units='c') + parsed_arguments=GetWeatherArgs(city='Edinburgh', country='GB', units='c') ), - id='call_lQnnsesjFMWMQ5IeWPHzR4th', + id='call_JMW1whyEaYG438VE1OIflxA2', index=0, type='function' ), @@ -836,7 +789,7 @@ class GetStockPrice(BaseModel): name='get_stock_price', parsed_arguments=GetStockPrice(exchange='NASDAQ', ticker='AAPL') ), - id='call_2xjOUgaCdiwAcl9ZBL9LyMUU', + id='call_DNYTawLBoN8fj3KN6qU9N1Ou', index=1, type='function' ) @@ -878,7 +831,7 @@ def test_parse_strict_tools(client: OpenAI, respx_mock: MockRouter, monkeypatch: } ], ), - content_snapshot=snapshot(external("83d3d003e6fd*.bin")), + content_snapshot=snapshot(external("a247c49c5fcd*.bin")), mock_client=client, respx_mock=respx_mock, ) @@ -903,7 +856,7 @@ def test_parse_strict_tools(client: OpenAI, respx_mock: MockRouter, monkeypatch: name='get_weather', parsed_arguments={'city': 'San Francisco', 'state': 'CA'} ), - id='call_pVHYsU0gmSfX5TqxOyVbB2ma', + id='call_CTf1nWJLqSeRgDqaCG27xZ74', index=0, type='function' ) @@ -928,7 +881,7 @@ def test_non_pydantic_response_format(client: OpenAI, respx_mock: MockRouter, mo ], response_format={"type": "json_object"}, ), - content_snapshot=snapshot(external("0898f3d1651e*.bin")), + content_snapshot=snapshot(external("d61558011839*.bin")), mock_client=client, respx_mock=respx_mock, ) @@ -941,10 +894,12 @@ def test_non_pydantic_response_format(client: OpenAI, respx_mock: MockRouter, mo index=0, logprobs=None, message=ParsedChatCompletionMessage[NoneType]( - content='\\n {\\n "location": "San Francisco, CA",\\n "forecast_date": "2023-11-02",\\n "weather": {\\n -"temperature": {\\n "current": "N/A",\\n "high": "N/A",\\n "low": "N/A"\\n },\\n "condition": -"N/A",\\n "humidity": "N/A",\\n "wind_speed": "N/A"\\n },\\n "note": "Please check a reliable weather -service for the most current information."\\n }', + content='\\n {\\n "location": "San Francisco, CA",\\n "weather": {\\n "temperature": "18°C",\\n +"condition": "Partly Cloudy",\\n "humidity": "72%",\\n "windSpeed": "15 km/h",\\n "windDirection": "NW"\\n +},\\n "forecast": [\\n {\\n "day": "Monday",\\n "high": "20°C",\\n "low": "14°C",\\n +"condition": "Sunny"\\n },\\n {\\n "day": "Tuesday",\\n "high": "19°C",\\n "low": "15°C",\\n +"condition": "Mostly Cloudy"\\n },\\n {\\n "day": "Wednesday",\\n "high": "18°C",\\n "low": +"14°C",\\n "condition": "Cloudy"\\n }\\n ]\\n }\\n', function_call=None, parsed=None, refusal=None, @@ -975,7 +930,7 @@ def test_allows_non_strict_tools_but_no_parsing( } ], ), - content_snapshot=snapshot(external("dae1b261f197*.bin")), + content_snapshot=snapshot(external("2018feb66ae1*.bin")), mock_client=client, respx_mock=respx_mock, ) @@ -1010,7 +965,7 @@ def test_allows_non_strict_tools_but_no_parsing( name='get_weather', parsed_arguments=None ), - id='call_5uxEBMFySqqQGu02I5QHA8k6', + id='call_4XzlGBLtUe9dy3GVNV4jhq7h', index=0, type='function' ) From 56e64d9a17024f8ffcaee7172d4d6c6e1614f60c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 26 Sep 2024 17:25:28 +0000 Subject: [PATCH 030/769] feat(api): add omni-moderation model (#1750) --- .stats.yml | 2 +- api.md | 9 ++- src/openai/resources/moderations.py | 49 +++++++------ src/openai/types/__init__.py | 3 + src/openai/types/moderation.py | 70 ++++++++++++++++++- src/openai/types/moderation_create_params.py | 26 +++---- .../types/moderation_image_url_input_param.py | 20 ++++++ src/openai/types/moderation_model.py | 4 +- .../moderation_multi_modal_input_param.py | 13 ++++ .../types/moderation_text_input_param.py | 15 ++++ tests/api_resources/test_moderations.py | 4 +- 11 files changed, 172 insertions(+), 43 deletions(-) create mode 100644 src/openai/types/moderation_image_url_input_param.py create mode 100644 src/openai/types/moderation_multi_modal_input_param.py create mode 100644 src/openai/types/moderation_text_input_param.py diff --git a/.stats.yml b/.stats.yml index e8bca3c6d8..0998368a4c 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 68 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-073331021d48db6af646a3552ab0c682efe31b7fb4e59a109ed1ba539f9b89c5.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-17ddd746c775ca4d4fbe64e5621ac30756ef09c061ff6313190b6ec162222d4c.yml diff --git a/api.md b/api.md index eae17d8d84..29db54f0fd 100644 --- a/api.md +++ b/api.md @@ -158,7 +158,14 @@ Methods: Types: ```python -from openai.types import Moderation, ModerationModel, ModerationCreateResponse +from openai.types import ( + Moderation, + ModerationImageURLInput, + ModerationModel, + ModerationMultiModalInput, + ModerationTextInput, + ModerationCreateResponse, +) ``` Methods: diff --git a/src/openai/resources/moderations.py b/src/openai/resources/moderations.py index 5283554373..8b73da57b2 100644 --- a/src/openai/resources/moderations.py +++ b/src/openai/resources/moderations.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import List, Union +from typing import List, Union, Iterable import httpx @@ -19,6 +19,7 @@ from .._base_client import make_request_options from ..types.moderation_model import ModerationModel from ..types.moderation_create_response import ModerationCreateResponse +from ..types.moderation_multi_modal_input_param import ModerationMultiModalInputParam __all__ = ["Moderations", "AsyncModerations"] @@ -46,7 +47,7 @@ def with_streaming_response(self) -> ModerationsWithStreamingResponse: def create( self, *, - input: Union[str, List[str]], + input: Union[str, List[str], Iterable[ModerationMultiModalInputParam]], model: Union[str, ModerationModel] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -55,20 +56,19 @@ def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> ModerationCreateResponse: - """ - Classifies if text is potentially harmful. + """Classifies if text and/or image inputs are potentially harmful. - Args: - input: The input text to classify + Learn more in + the [moderation guide](https://platform.openai.com/docs/guides/moderation). - model: Two content moderations models are available: `text-moderation-stable` and - `text-moderation-latest`. + Args: + input: Input (or inputs) to classify. Can be a single string, an array of strings, or + an array of multi-modal input objects similar to other models. - The default is `text-moderation-latest` which will be automatically upgraded - over time. This ensures you are always using our most accurate model. If you use - `text-moderation-stable`, we will provide advanced notice before updating the - model. Accuracy of `text-moderation-stable` may be slightly lower than for - `text-moderation-latest`. + model: The content moderation model you would like to use. Learn more in + [the moderation guide](https://platform.openai.com/docs/guides/moderation), and + learn about available models + [here](https://platform.openai.com/docs/models/moderation). extra_headers: Send extra headers @@ -117,7 +117,7 @@ def with_streaming_response(self) -> AsyncModerationsWithStreamingResponse: async def create( self, *, - input: Union[str, List[str]], + input: Union[str, List[str], Iterable[ModerationMultiModalInputParam]], model: Union[str, ModerationModel] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -126,20 +126,19 @@ async def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> ModerationCreateResponse: - """ - Classifies if text is potentially harmful. + """Classifies if text and/or image inputs are potentially harmful. - Args: - input: The input text to classify + Learn more in + the [moderation guide](https://platform.openai.com/docs/guides/moderation). - model: Two content moderations models are available: `text-moderation-stable` and - `text-moderation-latest`. + Args: + input: Input (or inputs) to classify. Can be a single string, an array of strings, or + an array of multi-modal input objects similar to other models. - The default is `text-moderation-latest` which will be automatically upgraded - over time. This ensures you are always using our most accurate model. If you use - `text-moderation-stable`, we will provide advanced notice before updating the - model. Accuracy of `text-moderation-stable` may be slightly lower than for - `text-moderation-latest`. + model: The content moderation model you would like to use. Learn more in + [the moderation guide](https://platform.openai.com/docs/guides/moderation), and + learn about available models + [here](https://platform.openai.com/docs/models/moderation). extra_headers: Send extra headers diff --git a/src/openai/types/__init__.py b/src/openai/types/__init__.py index 6223be883d..7677be01b2 100644 --- a/src/openai/types/__init__.py +++ b/src/openai/types/__init__.py @@ -46,4 +46,7 @@ from .moderation_create_params import ModerationCreateParams as ModerationCreateParams from .create_embedding_response import CreateEmbeddingResponse as CreateEmbeddingResponse from .moderation_create_response import ModerationCreateResponse as ModerationCreateResponse +from .moderation_text_input_param import ModerationTextInputParam as ModerationTextInputParam from .image_create_variation_params import ImageCreateVariationParams as ImageCreateVariationParams +from .moderation_image_url_input_param import ModerationImageURLInputParam as ModerationImageURLInputParam +from .moderation_multi_modal_input_param import ModerationMultiModalInputParam as ModerationMultiModalInputParam diff --git a/src/openai/types/moderation.py b/src/openai/types/moderation.py index 5aa691823a..e4ec182ce2 100644 --- a/src/openai/types/moderation.py +++ b/src/openai/types/moderation.py @@ -1,11 +1,13 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from typing import List +from typing_extensions import Literal from pydantic import Field as FieldInfo from .._models import BaseModel -__all__ = ["Moderation", "Categories", "CategoryScores"] +__all__ = ["Moderation", "Categories", "CategoryAppliedInputTypes", "CategoryScores"] class Categories(BaseModel): @@ -36,6 +38,20 @@ class Categories(BaseModel): orientation, disability status, or caste. """ + illicit: bool + """ + Content that includes instructions or advice that facilitate the planning or + execution of wrongdoing, or that gives advice or instruction on how to commit + illicit acts. For example, "how to shoplift" would fit this category. + """ + + illicit_violent: bool = FieldInfo(alias="illicit/violent") + """ + Content that includes instructions or advice that facilitate the planning or + execution of wrongdoing that also includes violence, or that gives advice or + instruction on the procurement of any weapon. + """ + self_harm: bool = FieldInfo(alias="self-harm") """ Content that promotes, encourages, or depicts acts of self-harm, such as @@ -72,6 +88,47 @@ class Categories(BaseModel): """Content that depicts death, violence, or physical injury in graphic detail.""" +class CategoryAppliedInputTypes(BaseModel): + harassment: List[Literal["text"]] + """The applied input type(s) for the category 'harassment'.""" + + harassment_threatening: List[Literal["text"]] = FieldInfo(alias="harassment/threatening") + """The applied input type(s) for the category 'harassment/threatening'.""" + + hate: List[Literal["text"]] + """The applied input type(s) for the category 'hate'.""" + + hate_threatening: List[Literal["text"]] = FieldInfo(alias="hate/threatening") + """The applied input type(s) for the category 'hate/threatening'.""" + + illicit: List[Literal["text"]] + """The applied input type(s) for the category 'illicit'.""" + + illicit_violent: List[Literal["text"]] = FieldInfo(alias="illicit/violent") + """The applied input type(s) for the category 'illicit/violent'.""" + + self_harm: List[Literal["text", "image"]] = FieldInfo(alias="self-harm") + """The applied input type(s) for the category 'self-harm'.""" + + self_harm_instructions: List[Literal["text", "image"]] = FieldInfo(alias="self-harm/instructions") + """The applied input type(s) for the category 'self-harm/instructions'.""" + + self_harm_intent: List[Literal["text", "image"]] = FieldInfo(alias="self-harm/intent") + """The applied input type(s) for the category 'self-harm/intent'.""" + + sexual: List[Literal["text", "image"]] + """The applied input type(s) for the category 'sexual'.""" + + sexual_minors: List[Literal["text"]] = FieldInfo(alias="sexual/minors") + """The applied input type(s) for the category 'sexual/minors'.""" + + violence: List[Literal["text", "image"]] + """The applied input type(s) for the category 'violence'.""" + + violence_graphic: List[Literal["text", "image"]] = FieldInfo(alias="violence/graphic") + """The applied input type(s) for the category 'violence/graphic'.""" + + class CategoryScores(BaseModel): harassment: float """The score for the category 'harassment'.""" @@ -85,6 +142,12 @@ class CategoryScores(BaseModel): hate_threatening: float = FieldInfo(alias="hate/threatening") """The score for the category 'hate/threatening'.""" + illicit: float + """The score for the category 'illicit'.""" + + illicit_violent: float = FieldInfo(alias="illicit/violent") + """The score for the category 'illicit/violent'.""" + self_harm: float = FieldInfo(alias="self-harm") """The score for the category 'self-harm'.""" @@ -111,6 +174,11 @@ class Moderation(BaseModel): categories: Categories """A list of the categories, and whether they are flagged or not.""" + category_applied_input_types: CategoryAppliedInputTypes + """ + A list of the categories along with the input type(s) that the score applies to. + """ + category_scores: CategoryScores """A list of the categories along with their scores as predicted by model.""" diff --git a/src/openai/types/moderation_create_params.py b/src/openai/types/moderation_create_params.py index 337682194d..3193fd9c2d 100644 --- a/src/openai/types/moderation_create_params.py +++ b/src/openai/types/moderation_create_params.py @@ -2,26 +2,28 @@ from __future__ import annotations -from typing import List, Union +from typing import List, Union, Iterable from typing_extensions import Required, TypedDict from .moderation_model import ModerationModel +from .moderation_multi_modal_input_param import ModerationMultiModalInputParam __all__ = ["ModerationCreateParams"] class ModerationCreateParams(TypedDict, total=False): - input: Required[Union[str, List[str]]] - """The input text to classify""" + input: Required[Union[str, List[str], Iterable[ModerationMultiModalInputParam]]] + """Input (or inputs) to classify. - model: Union[str, ModerationModel] + Can be a single string, an array of strings, or an array of multi-modal input + objects similar to other models. """ - Two content moderations models are available: `text-moderation-stable` and - `text-moderation-latest`. - - The default is `text-moderation-latest` which will be automatically upgraded - over time. This ensures you are always using our most accurate model. If you use - `text-moderation-stable`, we will provide advanced notice before updating the - model. Accuracy of `text-moderation-stable` may be slightly lower than for - `text-moderation-latest`. + + model: Union[str, ModerationModel] + """The content moderation model you would like to use. + + Learn more in + [the moderation guide](https://platform.openai.com/docs/guides/moderation), and + learn about available models + [here](https://platform.openai.com/docs/models/moderation). """ diff --git a/src/openai/types/moderation_image_url_input_param.py b/src/openai/types/moderation_image_url_input_param.py new file mode 100644 index 0000000000..9a69a6a257 --- /dev/null +++ b/src/openai/types/moderation_image_url_input_param.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ModerationImageURLInputParam", "ImageURL"] + + +class ImageURL(TypedDict, total=False): + url: Required[str] + """Either a URL of the image or the base64 encoded image data.""" + + +class ModerationImageURLInputParam(TypedDict, total=False): + image_url: Required[ImageURL] + """Contains either an image URL or a data URL for a base64 encoded image.""" + + type: Required[Literal["image_url"]] + """Always `image_url`.""" diff --git a/src/openai/types/moderation_model.py b/src/openai/types/moderation_model.py index f549aeeb7a..64954c4547 100644 --- a/src/openai/types/moderation_model.py +++ b/src/openai/types/moderation_model.py @@ -4,4 +4,6 @@ __all__ = ["ModerationModel"] -ModerationModel: TypeAlias = Literal["text-moderation-latest", "text-moderation-stable"] +ModerationModel: TypeAlias = Literal[ + "omni-moderation-latest", "omni-moderation-2024-09-26", "text-moderation-latest", "text-moderation-stable" +] diff --git a/src/openai/types/moderation_multi_modal_input_param.py b/src/openai/types/moderation_multi_modal_input_param.py new file mode 100644 index 0000000000..4314e7b031 --- /dev/null +++ b/src/openai/types/moderation_multi_modal_input_param.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import TypeAlias + +from .moderation_text_input_param import ModerationTextInputParam +from .moderation_image_url_input_param import ModerationImageURLInputParam + +__all__ = ["ModerationMultiModalInputParam"] + +ModerationMultiModalInputParam: TypeAlias = Union[ModerationImageURLInputParam, ModerationTextInputParam] diff --git a/src/openai/types/moderation_text_input_param.py b/src/openai/types/moderation_text_input_param.py new file mode 100644 index 0000000000..e5da53337b --- /dev/null +++ b/src/openai/types/moderation_text_input_param.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ModerationTextInputParam"] + + +class ModerationTextInputParam(TypedDict, total=False): + text: Required[str] + """A string of text to classify.""" + + type: Required[Literal["text"]] + """Always `text`.""" diff --git a/tests/api_resources/test_moderations.py b/tests/api_resources/test_moderations.py index 94b9ecd31b..bbdeb63e49 100644 --- a/tests/api_resources/test_moderations.py +++ b/tests/api_resources/test_moderations.py @@ -28,7 +28,7 @@ def test_method_create(self, client: OpenAI) -> None: def test_method_create_with_all_params(self, client: OpenAI) -> None: moderation = client.moderations.create( input="I want to kill them.", - model="text-moderation-stable", + model="omni-moderation-2024-09-26", ) assert_matches_type(ModerationCreateResponse, moderation, path=["response"]) @@ -71,7 +71,7 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None: async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: moderation = await async_client.moderations.create( input="I want to kill them.", - model="text-moderation-stable", + model="omni-moderation-2024-09-26", ) assert_matches_type(ModerationCreateResponse, moderation, path=["response"]) From 70edb2134913569677b40ed514a3520e31bd9f25 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 26 Sep 2024 17:26:01 +0000 Subject: [PATCH 031/769] release: 1.49.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 3f47f4bc2b..5153ca9d4c 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.48.0" + ".": "1.49.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index d89151074b..4a8156c611 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 1.49.0 (2024-09-26) + +Full Changelog: [v1.48.0...v1.49.0](https://github.com/openai/openai-python/compare/v1.48.0...v1.49.0) + +### Features + +* **api:** add omni-moderation model ([#1750](https://github.com/openai/openai-python/issues/1750)) ([05b50da](https://github.com/openai/openai-python/commit/05b50da5428d5c7b5ea09626bcd88f8423762bf8)) + + +### Chores + +* **internal:** update test snapshots ([#1749](https://github.com/openai/openai-python/issues/1749)) ([42f054e](https://github.com/openai/openai-python/commit/42f054ee7afa8ce8316c2ecd90608a0f7e13bfdd)) + ## 1.48.0 (2024-09-25) Full Changelog: [v1.47.1...v1.48.0](https://github.com/openai/openai-python/compare/v1.47.1...v1.48.0) diff --git a/pyproject.toml b/pyproject.toml index 05f957cac0..aa4c7c1d76 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.48.0" +version = "1.49.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 66109f354b..32d54fb9d0 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.48.0" # x-release-please-version +__version__ = "1.49.0" # x-release-please-version From e1aeeb0ee62965687c8d0dd00e9e39e54be9498c Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Thu, 26 Sep 2024 23:12:51 +0100 Subject: [PATCH 032/769] chore(pydantic v1): exclude specific properties when rich printing (#1751) --- src/openai/_models.py | 10 +++++++++- tests/lib/chat/_utils.py | 11 +++-------- tests/test_legacy_response.py | 4 ++++ tests/test_response.py | 4 ++++ tests/utils.py | 13 +++++++++++++ 5 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/openai/_models.py b/src/openai/_models.py index d6f42d3d4d..710401defd 100644 --- a/src/openai/_models.py +++ b/src/openai/_models.py @@ -2,7 +2,7 @@ import os import inspect -from typing import TYPE_CHECKING, Any, Type, Union, Generic, TypeVar, Callable, Optional, cast +from typing import TYPE_CHECKING, Any, Type, Tuple, Union, Generic, TypeVar, Callable, Optional, cast from datetime import date, datetime from typing_extensions import ( Unpack, @@ -10,6 +10,7 @@ ClassVar, Protocol, Required, + Sequence, ParamSpec, TypedDict, TypeGuard, @@ -72,6 +73,8 @@ P = ParamSpec("P") +ReprArgs = Sequence[Tuple[Optional[str], Any]] + @runtime_checkable class _ConfigProtocol(Protocol): @@ -94,6 +97,11 @@ def model_fields_set(self) -> set[str]: class Config(pydantic.BaseConfig): # pyright: ignore[reportDeprecated] extra: Any = pydantic.Extra.allow # type: ignore + @override + def __repr_args__(self) -> ReprArgs: + # we don't want these attributes to be included when something like `rich.print` is used + return [arg for arg in super().__repr_args__() if arg[0] not in {"_request_id", "__exclude_fields__"}] + if TYPE_CHECKING: _request_id: Optional[str] = None """The ID of the request, returned via the X-Request-ID header. Useful for debugging requests and reporting issues to OpenAI. diff --git a/tests/lib/chat/_utils.py b/tests/lib/chat/_utils.py index dcc32b17fd..af08db417c 100644 --- a/tests/lib/chat/_utils.py +++ b/tests/lib/chat/_utils.py @@ -1,14 +1,14 @@ from __future__ import annotations -import io import inspect from typing import Any, Iterable from typing_extensions import TypeAlias -import rich import pytest import pydantic +from ...utils import rich_print_str + ReprArgs: TypeAlias = "Iterable[tuple[str | None, Any]]" @@ -26,12 +26,7 @@ def __repr_args__(self: pydantic.BaseModel) -> ReprArgs: with monkeypatch.context() as m: m.setattr(pydantic.BaseModel, "__repr_args__", __repr_args__) - buf = io.StringIO() - - console = rich.console.Console(file=buf, width=120) - console.print(obj) - - string = buf.getvalue() + string = rich_print_str(obj) # we remove all `fn_name..` occurences # so that we can share the same snapshots between diff --git a/tests/test_legacy_response.py b/tests/test_legacy_response.py index a6fec9f2de..f50a77c24d 100644 --- a/tests/test_legacy_response.py +++ b/tests/test_legacy_response.py @@ -11,6 +11,8 @@ from openai._base_client import FinalRequestOptions from openai._legacy_response import LegacyAPIResponse +from .utils import rich_print_str + class PydanticModel(pydantic.BaseModel): ... @@ -85,6 +87,8 @@ def test_response_basemodel_request_id(client: OpenAI) -> None: assert obj.foo == "hello!" assert obj.bar == 2 assert obj.to_dict() == {"foo": "hello!", "bar": 2} + assert "_request_id" not in rich_print_str(obj) + assert "__exclude_fields__" not in rich_print_str(obj) def test_response_parse_annotated_type(client: OpenAI) -> None: diff --git a/tests/test_response.py b/tests/test_response.py index 97c56e0035..e1fe332f2f 100644 --- a/tests/test_response.py +++ b/tests/test_response.py @@ -18,6 +18,8 @@ from openai._streaming import Stream from openai._base_client import FinalRequestOptions +from .utils import rich_print_str + class ConcreteBaseAPIResponse(APIResponse[bytes]): ... @@ -175,6 +177,8 @@ def test_response_basemodel_request_id(client: OpenAI) -> None: assert obj.foo == "hello!" assert obj.bar == 2 assert obj.to_dict() == {"foo": "hello!", "bar": 2} + assert "_request_id" not in rich_print_str(obj) + assert "__exclude_fields__" not in rich_print_str(obj) @pytest.mark.asyncio diff --git a/tests/utils.py b/tests/utils.py index 165f4e5bfd..8d5397f28e 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -1,5 +1,6 @@ from __future__ import annotations +import io import os import inspect import traceback @@ -8,6 +9,8 @@ from datetime import date, datetime from typing_extensions import Literal, get_args, get_origin, assert_type +import rich + from openai._types import Omit, NoneType from openai._utils import ( is_dict, @@ -138,6 +141,16 @@ def _assert_list_type(type_: type[object], value: object) -> None: assert_type(inner_type, entry) # type: ignore +def rich_print_str(obj: object) -> str: + """Like `rich.print()` but returns the string instead""" + buf = io.StringIO() + + console = rich.console.Console(file=buf, width=120) + console.print(obj) + + return buf.getvalue() + + @contextlib.contextmanager def update_env(**new_env: str | Omit) -> Iterator[None]: old = os.environ.copy() From 152a8bda1b1db21377496b36ff26ab127a27b221 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Thu, 26 Sep 2024 23:32:48 +0100 Subject: [PATCH 033/769] feat(structured outputs): add support for accessing raw responses (#1748) --- src/openai/resources/beta/chat/completions.py | 246 +++++++++++++----- tests/lib/chat/test_completions.py | 177 ++++++++++++- 2 files changed, 355 insertions(+), 68 deletions(-) diff --git a/src/openai/resources/beta/chat/completions.py b/src/openai/resources/beta/chat/completions.py index ea3526778d..da6f189929 100644 --- a/src/openai/resources/beta/chat/completions.py +++ b/src/openai/resources/beta/chat/completions.py @@ -2,16 +2,21 @@ from __future__ import annotations -from typing import Dict, List, Union, Iterable, Optional +from typing import Dict, List, Type, Union, Iterable, Optional, cast from functools import partial from typing_extensions import Literal import httpx +from .... import _legacy_response from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper from ...._streaming import Stream from ....types.chat import completion_create_params +from ...._base_client import make_request_options from ....lib._parsing import ( ResponseFormatT, validate_input_tools as _validate_input_tools, @@ -20,6 +25,7 @@ ) from ....types.chat_model import ChatModel from ....lib.streaming.chat import ChatCompletionStreamManager, AsyncChatCompletionStreamManager +from ....types.chat.chat_completion import ChatCompletion from ....types.chat.chat_completion_chunk import ChatCompletionChunk from ....types.chat.parsed_chat_completion import ParsedChatCompletion from ....types.chat.chat_completion_tool_param import ChatCompletionToolParam @@ -31,6 +37,25 @@ class Completions(SyncAPIResource): + @cached_property + def with_raw_response(self) -> CompletionsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return CompletionsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> CompletionsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return CompletionsWithStreamingResponse(self) + def parse( self, *, @@ -113,39 +138,55 @@ class MathResponse(BaseModel): **(extra_headers or {}), } - raw_completion = self._client.chat.completions.create( - messages=messages, - model=model, - response_format=_type_to_response_format(response_format), - frequency_penalty=frequency_penalty, - function_call=function_call, - functions=functions, - logit_bias=logit_bias, - logprobs=logprobs, - max_completion_tokens=max_completion_tokens, - max_tokens=max_tokens, - n=n, - parallel_tool_calls=parallel_tool_calls, - presence_penalty=presence_penalty, - seed=seed, - service_tier=service_tier, - stop=stop, - stream_options=stream_options, - temperature=temperature, - tool_choice=tool_choice, - tools=tools, - top_logprobs=top_logprobs, - top_p=top_p, - user=user, - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - ) - return _parse_chat_completion( - response_format=response_format, - chat_completion=raw_completion, - input_tools=tools, + def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseFormatT]: + return _parse_chat_completion( + response_format=response_format, + chat_completion=raw_completion, + input_tools=tools, + ) + + return self._post( + "/chat/completions", + body=maybe_transform( + { + "messages": messages, + "model": model, + "frequency_penalty": frequency_penalty, + "function_call": function_call, + "functions": functions, + "logit_bias": logit_bias, + "logprobs": logprobs, + "max_completion_tokens": max_completion_tokens, + "max_tokens": max_tokens, + "n": n, + "parallel_tool_calls": parallel_tool_calls, + "presence_penalty": presence_penalty, + "response_format": _type_to_response_format(response_format), + "seed": seed, + "service_tier": service_tier, + "stop": stop, + "stream": False, + "stream_options": stream_options, + "temperature": temperature, + "tool_choice": tool_choice, + "tools": tools, + "top_logprobs": top_logprobs, + "top_p": top_p, + "user": user, + }, + completion_create_params.CompletionCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=parser, + ), + # we turn the `ChatCompletion` instance into a `ParsedChatCompletion` + # in the `parser` function above + cast_to=cast(Type[ParsedChatCompletion[ResponseFormatT]], ChatCompletion), + stream=False, ) def stream( @@ -247,6 +288,25 @@ def stream( class AsyncCompletions(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncCompletionsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncCompletionsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncCompletionsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncCompletionsWithStreamingResponse(self) + async def parse( self, *, @@ -329,39 +389,55 @@ class MathResponse(BaseModel): **(extra_headers or {}), } - raw_completion = await self._client.chat.completions.create( - messages=messages, - model=model, - response_format=_type_to_response_format(response_format), - frequency_penalty=frequency_penalty, - function_call=function_call, - functions=functions, - logit_bias=logit_bias, - logprobs=logprobs, - max_completion_tokens=max_completion_tokens, - max_tokens=max_tokens, - n=n, - parallel_tool_calls=parallel_tool_calls, - presence_penalty=presence_penalty, - seed=seed, - service_tier=service_tier, - stop=stop, - stream_options=stream_options, - temperature=temperature, - tool_choice=tool_choice, - tools=tools, - top_logprobs=top_logprobs, - top_p=top_p, - user=user, - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - ) - return _parse_chat_completion( - response_format=response_format, - chat_completion=raw_completion, - input_tools=tools, + def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseFormatT]: + return _parse_chat_completion( + response_format=response_format, + chat_completion=raw_completion, + input_tools=tools, + ) + + return await self._post( + "/chat/completions", + body=await async_maybe_transform( + { + "messages": messages, + "model": model, + "frequency_penalty": frequency_penalty, + "function_call": function_call, + "functions": functions, + "logit_bias": logit_bias, + "logprobs": logprobs, + "max_completion_tokens": max_completion_tokens, + "max_tokens": max_tokens, + "n": n, + "parallel_tool_calls": parallel_tool_calls, + "presence_penalty": presence_penalty, + "response_format": _type_to_response_format(response_format), + "seed": seed, + "service_tier": service_tier, + "stop": stop, + "stream": False, + "stream_options": stream_options, + "temperature": temperature, + "tool_choice": tool_choice, + "tools": tools, + "top_logprobs": top_logprobs, + "top_p": top_p, + "user": user, + }, + completion_create_params.CompletionCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=parser, + ), + # we turn the `ChatCompletion` instance into a `ParsedChatCompletion` + # in the `parser` function above + cast_to=cast(Type[ParsedChatCompletion[ResponseFormatT]], ChatCompletion), + stream=False, ) def stream( @@ -461,3 +537,39 @@ def stream( response_format=response_format, input_tools=tools, ) + + +class CompletionsWithRawResponse: + def __init__(self, completions: Completions) -> None: + self._completions = completions + + self.parse = _legacy_response.to_raw_response_wrapper( + completions.parse, + ) + + +class AsyncCompletionsWithRawResponse: + def __init__(self, completions: AsyncCompletions) -> None: + self._completions = completions + + self.parse = _legacy_response.async_to_raw_response_wrapper( + completions.parse, + ) + + +class CompletionsWithStreamingResponse: + def __init__(self, completions: Completions) -> None: + self._completions = completions + + self.parse = to_streamed_response_wrapper( + completions.parse, + ) + + +class AsyncCompletionsWithStreamingResponse: + def __init__(self, completions: AsyncCompletions) -> None: + self._completions = completions + + self.parse = async_to_streamed_response_wrapper( + completions.parse, + ) diff --git a/tests/lib/chat/test_completions.py b/tests/lib/chat/test_completions.py index d66630fa3a..7702a98d49 100644 --- a/tests/lib/chat/test_completions.py +++ b/tests/lib/chat/test_completions.py @@ -3,7 +3,7 @@ import os import json from enum import Enum -from typing import Any, List, Callable, Optional +from typing import Any, List, Callable, Optional, Awaitable from typing_extensions import Literal, TypeVar import httpx @@ -773,6 +773,139 @@ def test_parse_non_strict_tools(client: OpenAI) -> None: ) +@pytest.mark.respx(base_url=base_url) +def test_parse_pydantic_raw_response(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None: + class Location(BaseModel): + city: str + temperature: float + units: Literal["c", "f"] + + response = _make_snapshot_request( + lambda c: c.beta.chat.completions.with_raw_response.parse( + model="gpt-4o-2024-08-06", + messages=[ + { + "role": "user", + "content": "What's the weather like in SF?", + }, + ], + response_format=Location, + ), + content_snapshot=snapshot( + '{"id": "chatcmpl-ABrDYCa8W1w66eUxKDO8TQF1m6trT", "object": "chat.completion", "created": 1727389540, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": "{\\"city\\":\\"San Francisco\\",\\"temperature\\":58,\\"units\\":\\"f\\"}", "refusal": null}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 79, "completion_tokens": 14, "total_tokens": 93, "completion_tokens_details": {"reasoning_tokens": 0}}, "system_fingerprint": "fp_5050236cbd"}' + ), + mock_client=client, + respx_mock=respx_mock, + ) + assert response.http_request.headers.get("x-stainless-helper-method") == "beta.chat.completions.parse" + + completion = response.parse() + message = completion.choices[0].message + assert message.parsed is not None + assert isinstance(message.parsed.city, str) + assert print_obj(completion, monkeypatch) == snapshot( + """\ +ParsedChatCompletion[Location]( + choices=[ + ParsedChoice[Location]( + finish_reason='stop', + index=0, + logprobs=None, + message=ParsedChatCompletionMessage[Location]( + content='{"city":"San Francisco","temperature":58,"units":"f"}', + function_call=None, + parsed=Location(city='San Francisco', temperature=58.0, units='f'), + refusal=None, + role='assistant', + tool_calls=[] + ) + ) + ], + created=1727389540, + id='chatcmpl-ABrDYCa8W1w66eUxKDO8TQF1m6trT', + model='gpt-4o-2024-08-06', + object='chat.completion', + service_tier=None, + system_fingerprint='fp_5050236cbd', + usage=CompletionUsage( + completion_tokens=14, + completion_tokens_details=CompletionTokensDetails(reasoning_tokens=0), + prompt_tokens=79, + total_tokens=93 + ) +) +""" + ) + + +@pytest.mark.respx(base_url=base_url) +@pytest.mark.asyncio +async def test_async_parse_pydantic_raw_response( + async_client: AsyncOpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch +) -> None: + class Location(BaseModel): + city: str + temperature: float + units: Literal["c", "f"] + + response = await _make_async_snapshot_request( + lambda c: c.beta.chat.completions.with_raw_response.parse( + model="gpt-4o-2024-08-06", + messages=[ + { + "role": "user", + "content": "What's the weather like in SF?", + }, + ], + response_format=Location, + ), + content_snapshot=snapshot( + '{"id": "chatcmpl-ABrDQWOiw0PK5JOsxl1D9ooeQgznq", "object": "chat.completion", "created": 1727389532, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": "{\\"city\\":\\"San Francisco\\",\\"temperature\\":65,\\"units\\":\\"f\\"}", "refusal": null}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 79, "completion_tokens": 14, "total_tokens": 93, "completion_tokens_details": {"reasoning_tokens": 0}}, "system_fingerprint": "fp_5050236cbd"}' + ), + mock_client=async_client, + respx_mock=respx_mock, + ) + assert response.http_request.headers.get("x-stainless-helper-method") == "beta.chat.completions.parse" + + completion = response.parse() + message = completion.choices[0].message + assert message.parsed is not None + assert isinstance(message.parsed.city, str) + assert print_obj(completion, monkeypatch) == snapshot( + """\ +ParsedChatCompletion[Location]( + choices=[ + ParsedChoice[Location]( + finish_reason='stop', + index=0, + logprobs=None, + message=ParsedChatCompletionMessage[Location]( + content='{"city":"San Francisco","temperature":65,"units":"f"}', + function_call=None, + parsed=Location(city='San Francisco', temperature=65.0, units='f'), + refusal=None, + role='assistant', + tool_calls=[] + ) + ) + ], + created=1727389532, + id='chatcmpl-ABrDQWOiw0PK5JOsxl1D9ooeQgznq', + model='gpt-4o-2024-08-06', + object='chat.completion', + service_tier=None, + system_fingerprint='fp_5050236cbd', + usage=CompletionUsage( + completion_tokens=14, + completion_tokens_details=CompletionTokensDetails(reasoning_tokens=0), + prompt_tokens=79, + total_tokens=93 + ) +) +""" + ) + + @pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) def test_parse_method_in_sync(sync: bool, client: OpenAI, async_client: AsyncOpenAI) -> None: checking_client: OpenAI | AsyncOpenAI = client if sync else async_client @@ -824,3 +957,45 @@ def _on_response(response: httpx.Response) -> None: client.close() return result + + +async def _make_async_snapshot_request( + func: Callable[[AsyncOpenAI], Awaitable[_T]], + *, + content_snapshot: Any, + respx_mock: MockRouter, + mock_client: AsyncOpenAI, +) -> _T: + live = os.environ.get("OPENAI_LIVE") == "1" + if live: + + async def _on_response(response: httpx.Response) -> None: + # update the content snapshot + assert json.dumps(json.loads(await response.aread())) == content_snapshot + + respx_mock.stop() + + client = AsyncOpenAI( + http_client=httpx.AsyncClient( + event_hooks={ + "response": [_on_response], + } + ) + ) + else: + respx_mock.post("/chat/completions").mock( + return_value=httpx.Response( + 200, + content=content_snapshot._old_value, + headers={"content-type": "application/json"}, + ) + ) + + client = mock_client + + result = await func(client) + + if live: + await client.close() + + return result From 37f5615da1f4360710f6f45920dbb81387d1a4c5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 26 Sep 2024 22:33:11 +0000 Subject: [PATCH 034/769] release: 1.50.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 5153ca9d4c..97e4d742db 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.49.0" + ".": "1.50.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a8156c611..20be5b530b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 1.50.0 (2024-09-26) + +Full Changelog: [v1.49.0...v1.50.0](https://github.com/openai/openai-python/compare/v1.49.0...v1.50.0) + +### Features + +* **structured outputs:** add support for accessing raw responses ([#1748](https://github.com/openai/openai-python/issues/1748)) ([0189e28](https://github.com/openai/openai-python/commit/0189e28b0b062a28b16343da0460a4f0f4e17a9a)) + + +### Chores + +* **pydantic v1:** exclude specific properties when rich printing ([#1751](https://github.com/openai/openai-python/issues/1751)) ([af535ce](https://github.com/openai/openai-python/commit/af535ce6a523eca39438f117a3e55f16064567a9)) + ## 1.49.0 (2024-09-26) Full Changelog: [v1.48.0...v1.49.0](https://github.com/openai/openai-python/compare/v1.48.0...v1.49.0) diff --git a/pyproject.toml b/pyproject.toml index aa4c7c1d76..f7061c5059 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.49.0" +version = "1.50.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 32d54fb9d0..e05b612a12 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.49.0" # x-release-please-version +__version__ = "1.50.0" # x-release-please-version From 73fc3b9ce2cc94959bd4efde8cdd4896e3953dee Mon Sep 17 00:00:00 2001 From: Sam El-Borai Date: Fri, 27 Sep 2024 14:20:58 +0200 Subject: [PATCH 035/769] docs(helpers): fix chat completion anchor (#1753) --- helpers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helpers.md b/helpers.md index 965dd6e23c..65515df973 100644 --- a/helpers.md +++ b/helpers.md @@ -128,7 +128,7 @@ The `beta.chat.completions.parse()` method imposes some additional restrictions # Streaming Helpers -OpenAI supports streaming responses when interacting with the [Chat Completion] & [Assistant](#assistant-streaming-api) APIs. +OpenAI supports streaming responses when interacting with the [Chat Completion](#chat-completions-api) & [Assistant](#assistant-streaming-api) APIs. ## Chat Completions API From 7a5632f6c9a64ce77083494ea7e2385e200373cc Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Sep 2024 12:21:24 +0000 Subject: [PATCH 036/769] release: 1.50.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 97e4d742db..43515db369 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.50.0" + ".": "1.50.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 20be5b530b..c51de0481b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.50.1 (2024-09-27) + +Full Changelog: [v1.50.0...v1.50.1](https://github.com/openai/openai-python/compare/v1.50.0...v1.50.1) + +### Documentation + +* **helpers:** fix chat completion anchor ([#1753](https://github.com/openai/openai-python/issues/1753)) ([956d4e8](https://github.com/openai/openai-python/commit/956d4e8e32507fbce399f4619e06daa9d37a0532)) + ## 1.50.0 (2024-09-26) Full Changelog: [v1.49.0...v1.50.0](https://github.com/openai/openai-python/compare/v1.49.0...v1.50.0) diff --git a/pyproject.toml b/pyproject.toml index f7061c5059..7ebf741165 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.50.0" +version = "1.50.1" 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 e05b612a12..2b0fd31d26 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.50.0" # x-release-please-version +__version__ = "1.50.1" # x-release-please-version From adb6da3aeebac792766bc4d11073e90116f55a47 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Fri, 27 Sep 2024 23:51:00 +0100 Subject: [PATCH 037/769] fix(audio): correct types for transcriptions / translations (#1755) fix --- .stats.yml | 2 +- api.md | 14 +- src/openai/_utils/_reflection.py | 5 +- src/openai/resources/audio/transcriptions.py | 155 +++++++++++++++++- src/openai/resources/audio/translations.py | 142 +++++++++++++++- src/openai/types/audio/__init__.py | 6 + .../audio/transcription_create_response.py | 11 ++ .../types/audio/transcription_segment.py | 49 ++++++ .../types/audio/transcription_verbose.py | 26 +++ src/openai/types/audio/transcription_word.py | 17 ++ .../audio/translation_create_response.py | 11 ++ src/openai/types/audio/translation_verbose.py | 22 +++ .../beta/static_file_chunking_strategy.py | 1 - .../audio/test_transcriptions.py | 18 +- .../api_resources/audio/test_translations.py | 18 +- tests/lib/test_audio.py | 83 ++++++++++ tests/utils.py | 6 +- 17 files changed, 543 insertions(+), 43 deletions(-) create mode 100644 src/openai/types/audio/transcription_create_response.py create mode 100644 src/openai/types/audio/transcription_segment.py create mode 100644 src/openai/types/audio/transcription_verbose.py create mode 100644 src/openai/types/audio/transcription_word.py create mode 100644 src/openai/types/audio/translation_create_response.py create mode 100644 src/openai/types/audio/translation_verbose.py create mode 100644 tests/lib/test_audio.py diff --git a/.stats.yml b/.stats.yml index 0998368a4c..68789976bf 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 68 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-17ddd746c775ca4d4fbe64e5621ac30756ef09c061ff6313190b6ec162222d4c.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-71e58a77027c67e003fdd1b1ac8ac11557d8bfabc7666d1a827c6b1ca8ab98b5.yml diff --git a/api.md b/api.md index 29db54f0fd..813c5cb615 100644 --- a/api.md +++ b/api.md @@ -122,24 +122,30 @@ from openai.types import AudioModel, AudioResponseFormat Types: ```python -from openai.types.audio import Transcription +from openai.types.audio import ( + Transcription, + TranscriptionSegment, + TranscriptionVerbose, + TranscriptionWord, + TranscriptionCreateResponse, +) ``` Methods: -- client.audio.transcriptions.create(\*\*params) -> Transcription +- client.audio.transcriptions.create(\*\*params) -> TranscriptionCreateResponse ## Translations Types: ```python -from openai.types.audio import Translation +from openai.types.audio import Translation, TranslationVerbose, TranslationCreateResponse ``` Methods: -- client.audio.translations.create(\*\*params) -> Translation +- client.audio.translations.create(\*\*params) -> TranslationCreateResponse ## Speech diff --git a/src/openai/_utils/_reflection.py b/src/openai/_utils/_reflection.py index 89aa712ac4..bdaca29e4a 100644 --- a/src/openai/_utils/_reflection.py +++ b/src/openai/_utils/_reflection.py @@ -15,6 +15,7 @@ def assert_signatures_in_sync( check_func: Callable[..., Any], *, exclude_params: set[str] = set(), + description: str = "", ) -> None: """Ensure that the signature of the second function matches the first.""" @@ -39,4 +40,6 @@ def assert_signatures_in_sync( continue if errors: - raise AssertionError(f"{len(errors)} errors encountered when comparing signatures:\n\n" + "\n\n".join(errors)) + raise AssertionError( + f"{len(errors)} errors encountered when comparing signatures{description}:\n\n" + "\n\n".join(errors) + ) diff --git a/src/openai/resources/audio/transcriptions.py b/src/openai/resources/audio/transcriptions.py index fd042d1ac3..e6596a480e 100644 --- a/src/openai/resources/audio/transcriptions.py +++ b/src/openai/resources/audio/transcriptions.py @@ -2,8 +2,9 @@ from __future__ import annotations -from typing import List, Union, Mapping, cast -from typing_extensions import Literal +import logging +from typing import TYPE_CHECKING, List, Union, Mapping, cast +from typing_extensions import Literal, overload, assert_never import httpx @@ -24,9 +25,12 @@ from ...types.audio_model import AudioModel from ...types.audio.transcription import Transcription from ...types.audio_response_format import AudioResponseFormat +from ...types.audio.transcription_verbose import TranscriptionVerbose __all__ = ["Transcriptions", "AsyncTranscriptions"] +log: logging.Logger = logging.getLogger("openai.audio.transcriptions") + class Transcriptions(SyncAPIResource): @cached_property @@ -48,14 +52,53 @@ def with_streaming_response(self) -> TranscriptionsWithStreamingResponse: """ return TranscriptionsWithStreamingResponse(self) + @overload + def create( + self, + *, + file: FileTypes, + model: Union[str, AudioModel], + response_format: Union[Literal["json"], NotGiven] = NOT_GIVEN, + language: str | NotGiven = NOT_GIVEN, + prompt: str | NotGiven = NOT_GIVEN, + temperature: float | NotGiven = NOT_GIVEN, + timestamp_granularities: List[Literal["word", "segment"]] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Transcription: ... + + @overload + def create( + self, + *, + file: FileTypes, + model: Union[str, AudioModel], + response_format: Literal["verbose_json"], + language: str | NotGiven = NOT_GIVEN, + prompt: str | NotGiven = NOT_GIVEN, + temperature: float | NotGiven = NOT_GIVEN, + timestamp_granularities: List[Literal["word", "segment"]] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> TranscriptionVerbose: ... + + @overload def create( self, *, file: FileTypes, model: Union[str, AudioModel], + response_format: Literal["text", "srt", "vtt"], language: str | NotGiven = NOT_GIVEN, prompt: str | NotGiven = NOT_GIVEN, - response_format: AudioResponseFormat | NotGiven = NOT_GIVEN, temperature: float | NotGiven = NOT_GIVEN, timestamp_granularities: List[Literal["word", "segment"]] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -64,7 +107,25 @@ def create( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Transcription: + ) -> str: ... + + def create( + self, + *, + file: FileTypes, + model: Union[str, AudioModel], + language: str | NotGiven = NOT_GIVEN, + prompt: str | NotGiven = NOT_GIVEN, + response_format: Union[AudioResponseFormat, NotGiven] = NOT_GIVEN, + temperature: float | NotGiven = NOT_GIVEN, + timestamp_granularities: List[Literal["word", "segment"]] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Transcription | TranscriptionVerbose | str: """ Transcribes audio into the input language. @@ -124,14 +185,14 @@ def create( # sent to the server will contain a `boundary` parameter, e.g. # multipart/form-data; boundary=---abc-- extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} - return self._post( + return self._post( # type: ignore[return-value] "/audio/transcriptions", body=maybe_transform(body, transcription_create_params.TranscriptionCreateParams), files=files, options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=Transcription, + cast_to=_get_response_format_type(response_format), ) @@ -155,14 +216,15 @@ def with_streaming_response(self) -> AsyncTranscriptionsWithStreamingResponse: """ return AsyncTranscriptionsWithStreamingResponse(self) + @overload async def create( self, *, file: FileTypes, model: Union[str, AudioModel], + response_format: Union[Literal["json"], NotGiven] = NOT_GIVEN, language: str | NotGiven = NOT_GIVEN, prompt: str | NotGiven = NOT_GIVEN, - response_format: AudioResponseFormat | NotGiven = NOT_GIVEN, temperature: float | NotGiven = NOT_GIVEN, timestamp_granularities: List[Literal["word", "segment"]] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -171,7 +233,63 @@ async def create( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Transcription: + ) -> Transcription: ... + + @overload + async def create( + self, + *, + file: FileTypes, + model: Union[str, AudioModel], + response_format: Literal["verbose_json"], + language: str | NotGiven = NOT_GIVEN, + prompt: str | NotGiven = NOT_GIVEN, + temperature: float | NotGiven = NOT_GIVEN, + timestamp_granularities: List[Literal["word", "segment"]] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> TranscriptionVerbose: ... + + @overload + async def create( + self, + *, + file: FileTypes, + model: Union[str, AudioModel], + response_format: Literal["text", "srt", "vtt"], + language: str | NotGiven = NOT_GIVEN, + prompt: str | NotGiven = NOT_GIVEN, + temperature: float | NotGiven = NOT_GIVEN, + timestamp_granularities: List[Literal["word", "segment"]] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> str: ... + + async def create( + self, + *, + file: FileTypes, + model: Union[str, AudioModel], + language: str | NotGiven = NOT_GIVEN, + prompt: str | NotGiven = NOT_GIVEN, + response_format: Union[AudioResponseFormat, NotGiven] = NOT_GIVEN, + temperature: float | NotGiven = NOT_GIVEN, + timestamp_granularities: List[Literal["word", "segment"]] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Transcription | TranscriptionVerbose | str: """ Transcribes audio into the input language. @@ -238,7 +356,7 @@ async def create( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=Transcription, + cast_to=_get_response_format_type(response_format), ) @@ -276,3 +394,22 @@ def __init__(self, transcriptions: AsyncTranscriptions) -> None: self.create = async_to_streamed_response_wrapper( transcriptions.create, ) + + +def _get_response_format_type( + response_format: Literal["json", "text", "srt", "verbose_json", "vtt"] | NotGiven, +) -> type[Transcription | TranscriptionVerbose | str]: + if isinstance(response_format, NotGiven) or response_format is None: # pyright: ignore[reportUnnecessaryComparison] + return Transcription + + if response_format == "json": + return Transcription + elif response_format == "verbose_json": + return TranscriptionVerbose + elif response_format == "srt" or response_format == "text" or response_format == "vtt": + return str + elif TYPE_CHECKING: # type: ignore[unreachable] + assert_never(response_format) + else: + log.warn("Unexpected audio response format: %s", response_format) + return Transcription diff --git a/src/openai/resources/audio/translations.py b/src/openai/resources/audio/translations.py index fe08dd550e..53ab625873 100644 --- a/src/openai/resources/audio/translations.py +++ b/src/openai/resources/audio/translations.py @@ -2,7 +2,9 @@ from __future__ import annotations -from typing import Union, Mapping, cast +import logging +from typing import TYPE_CHECKING, Union, Mapping, cast +from typing_extensions import Literal, overload, assert_never import httpx @@ -23,9 +25,12 @@ from ...types.audio_model import AudioModel from ...types.audio.translation import Translation from ...types.audio_response_format import AudioResponseFormat +from ...types.audio.translation_verbose import TranslationVerbose __all__ = ["Translations", "AsyncTranslations"] +log: logging.Logger = logging.getLogger("openai.audio.transcriptions") + class Translations(SyncAPIResource): @cached_property @@ -47,13 +52,64 @@ def with_streaming_response(self) -> TranslationsWithStreamingResponse: """ return TranslationsWithStreamingResponse(self) + @overload + def create( + self, + *, + file: FileTypes, + model: Union[str, AudioModel], + response_format: Union[Literal["json"], NotGiven] = NOT_GIVEN, + prompt: str | NotGiven = NOT_GIVEN, + temperature: float | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Translation: ... + + @overload + def create( + self, + *, + file: FileTypes, + model: Union[str, AudioModel], + response_format: Literal["verbose_json"], + prompt: str | NotGiven = NOT_GIVEN, + temperature: float | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> TranslationVerbose: ... + + @overload + def create( + self, + *, + file: FileTypes, + model: Union[str, AudioModel], + response_format: Literal["text", "srt", "vtt"], + prompt: str | NotGiven = NOT_GIVEN, + temperature: float | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> str: ... + def create( self, *, file: FileTypes, model: Union[str, AudioModel], prompt: str | NotGiven = NOT_GIVEN, - response_format: AudioResponseFormat | NotGiven = NOT_GIVEN, + response_format: Union[AudioResponseFormat, NotGiven] = NOT_GIVEN, temperature: float | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -61,7 +117,7 @@ def create( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Translation: + ) -> Translation | TranslationVerbose | str: """ Translates audio into English. @@ -108,14 +164,14 @@ def create( # sent to the server will contain a `boundary` parameter, e.g. # multipart/form-data; boundary=---abc-- extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} - return self._post( + return self._post( # type: ignore[return-value] "/audio/translations", body=maybe_transform(body, translation_create_params.TranslationCreateParams), files=files, options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=Translation, + cast_to=_get_response_format_type(response_format), ) @@ -139,13 +195,14 @@ def with_streaming_response(self) -> AsyncTranslationsWithStreamingResponse: """ return AsyncTranslationsWithStreamingResponse(self) + @overload async def create( self, *, file: FileTypes, model: Union[str, AudioModel], + response_format: Union[Literal["json"], NotGiven] = NOT_GIVEN, prompt: str | NotGiven = NOT_GIVEN, - response_format: AudioResponseFormat | NotGiven = NOT_GIVEN, temperature: float | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -153,7 +210,57 @@ async def create( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Translation: + ) -> Translation: ... + + @overload + async def create( + self, + *, + file: FileTypes, + model: Union[str, AudioModel], + response_format: Literal["verbose_json"], + prompt: str | NotGiven = NOT_GIVEN, + temperature: float | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> TranslationVerbose: ... + + @overload + async def create( + self, + *, + file: FileTypes, + model: Union[str, AudioModel], + response_format: Literal["text", "srt", "vtt"], + prompt: str | NotGiven = NOT_GIVEN, + temperature: float | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> str: ... + + async def create( + self, + *, + file: FileTypes, + model: Union[str, AudioModel], + prompt: str | NotGiven = NOT_GIVEN, + response_format: Union[AudioResponseFormat, NotGiven] = NOT_GIVEN, + temperature: float | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Translation | TranslationVerbose | str: """ Translates audio into English. @@ -207,7 +314,7 @@ async def create( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=Translation, + cast_to=_get_response_format_type(response_format), ) @@ -245,3 +352,22 @@ def __init__(self, translations: AsyncTranslations) -> None: self.create = async_to_streamed_response_wrapper( translations.create, ) + + +def _get_response_format_type( + response_format: Literal["json", "text", "srt", "verbose_json", "vtt"] | NotGiven, +) -> type[Translation | TranslationVerbose | str]: + if isinstance(response_format, NotGiven) or response_format is None: # pyright: ignore[reportUnnecessaryComparison] + return Translation + + if response_format == "json": + return Translation + elif response_format == "verbose_json": + return TranslationVerbose + elif response_format == "srt" or response_format == "text" or response_format == "vtt": + return str + elif TYPE_CHECKING: # type: ignore[unreachable] + assert_never(response_format) + else: + log.warn("Unexpected audio response format: %s", response_format) + return Transcription diff --git a/src/openai/types/audio/__init__.py b/src/openai/types/audio/__init__.py index 1de5c0ff82..822e0f3a8d 100644 --- a/src/openai/types/audio/__init__.py +++ b/src/openai/types/audio/__init__.py @@ -5,6 +5,12 @@ from .translation import Translation as Translation from .speech_model import SpeechModel as SpeechModel from .transcription import Transcription as Transcription +from .transcription_word import TranscriptionWord as TranscriptionWord +from .translation_verbose import TranslationVerbose as TranslationVerbose from .speech_create_params import SpeechCreateParams as SpeechCreateParams +from .transcription_segment import TranscriptionSegment as TranscriptionSegment +from .transcription_verbose import TranscriptionVerbose as TranscriptionVerbose from .translation_create_params import TranslationCreateParams as TranslationCreateParams from .transcription_create_params import TranscriptionCreateParams as TranscriptionCreateParams +from .translation_create_response import TranslationCreateResponse as TranslationCreateResponse +from .transcription_create_response import TranscriptionCreateResponse as TranscriptionCreateResponse diff --git a/src/openai/types/audio/transcription_create_response.py b/src/openai/types/audio/transcription_create_response.py new file mode 100644 index 0000000000..2f7bed8114 --- /dev/null +++ b/src/openai/types/audio/transcription_create_response.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from typing_extensions import TypeAlias + +from .transcription import Transcription +from .transcription_verbose import TranscriptionVerbose + +__all__ = ["TranscriptionCreateResponse"] + +TranscriptionCreateResponse: TypeAlias = Union[Transcription, TranscriptionVerbose] diff --git a/src/openai/types/audio/transcription_segment.py b/src/openai/types/audio/transcription_segment.py new file mode 100644 index 0000000000..522c401ebb --- /dev/null +++ b/src/openai/types/audio/transcription_segment.py @@ -0,0 +1,49 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel + +__all__ = ["TranscriptionSegment"] + + +class TranscriptionSegment(BaseModel): + id: int + """Unique identifier of the segment.""" + + avg_logprob: float + """Average logprob of the segment. + + If the value is lower than -1, consider the logprobs failed. + """ + + compression_ratio: float + """Compression ratio of the segment. + + If the value is greater than 2.4, consider the compression failed. + """ + + end: float + """End time of the segment in seconds.""" + + no_speech_prob: float + """Probability of no speech in the segment. + + If the value is higher than 1.0 and the `avg_logprob` is below -1, consider this + segment silent. + """ + + seek: int + """Seek offset of the segment.""" + + start: float + """Start time of the segment in seconds.""" + + temperature: float + """Temperature parameter used for generating the segment.""" + + text: str + """Text content of the segment.""" + + tokens: List[int] + """Array of token IDs for the text content.""" diff --git a/src/openai/types/audio/transcription_verbose.py b/src/openai/types/audio/transcription_verbose.py new file mode 100644 index 0000000000..3b18fa4871 --- /dev/null +++ b/src/openai/types/audio/transcription_verbose.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel +from .transcription_word import TranscriptionWord +from .transcription_segment import TranscriptionSegment + +__all__ = ["TranscriptionVerbose"] + + +class TranscriptionVerbose(BaseModel): + duration: str + """The duration of the input audio.""" + + language: str + """The language of the input audio.""" + + text: str + """The transcribed text.""" + + segments: Optional[List[TranscriptionSegment]] = None + """Segments of the transcribed text and their corresponding details.""" + + words: Optional[List[TranscriptionWord]] = None + """Extracted words and their corresponding timestamps.""" diff --git a/src/openai/types/audio/transcription_word.py b/src/openai/types/audio/transcription_word.py new file mode 100644 index 0000000000..969da32509 --- /dev/null +++ b/src/openai/types/audio/transcription_word.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + + +from ..._models import BaseModel + +__all__ = ["TranscriptionWord"] + + +class TranscriptionWord(BaseModel): + end: float + """End time of the word in seconds.""" + + start: float + """Start time of the word in seconds.""" + + word: str + """The text content of the word.""" diff --git a/src/openai/types/audio/translation_create_response.py b/src/openai/types/audio/translation_create_response.py new file mode 100644 index 0000000000..9953813c08 --- /dev/null +++ b/src/openai/types/audio/translation_create_response.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from typing_extensions import TypeAlias + +from .translation import Translation +from .translation_verbose import TranslationVerbose + +__all__ = ["TranslationCreateResponse"] + +TranslationCreateResponse: TypeAlias = Union[Translation, TranslationVerbose] diff --git a/src/openai/types/audio/translation_verbose.py b/src/openai/types/audio/translation_verbose.py new file mode 100644 index 0000000000..5901ae7535 --- /dev/null +++ b/src/openai/types/audio/translation_verbose.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel +from .transcription_segment import TranscriptionSegment + +__all__ = ["TranslationVerbose"] + + +class TranslationVerbose(BaseModel): + duration: str + """The duration of the input audio.""" + + language: str + """The language of the output translation (always `english`).""" + + text: str + """The translated text.""" + + segments: Optional[List[TranscriptionSegment]] = None + """Segments of the translated text and their corresponding details.""" diff --git a/src/openai/types/beta/static_file_chunking_strategy.py b/src/openai/types/beta/static_file_chunking_strategy.py index ba80e1a2b9..6080093517 100644 --- a/src/openai/types/beta/static_file_chunking_strategy.py +++ b/src/openai/types/beta/static_file_chunking_strategy.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from ..._models import BaseModel __all__ = ["StaticFileChunkingStrategy"] diff --git a/tests/api_resources/audio/test_transcriptions.py b/tests/api_resources/audio/test_transcriptions.py index ba8e9e4099..0fa91eb152 100644 --- a/tests/api_resources/audio/test_transcriptions.py +++ b/tests/api_resources/audio/test_transcriptions.py @@ -9,7 +9,7 @@ from openai import OpenAI, AsyncOpenAI from tests.utils import assert_matches_type -from openai.types.audio import Transcription +from openai.types.audio import TranscriptionCreateResponse base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -23,7 +23,7 @@ def test_method_create(self, client: OpenAI) -> None: file=b"raw file contents", model="whisper-1", ) - assert_matches_type(Transcription, transcription, path=["response"]) + assert_matches_type(TranscriptionCreateResponse, transcription, path=["response"]) @parametrize def test_method_create_with_all_params(self, client: OpenAI) -> None: @@ -36,7 +36,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: temperature=0, timestamp_granularities=["word", "segment"], ) - assert_matches_type(Transcription, transcription, path=["response"]) + assert_matches_type(TranscriptionCreateResponse, transcription, path=["response"]) @parametrize def test_raw_response_create(self, client: OpenAI) -> None: @@ -48,7 +48,7 @@ def test_raw_response_create(self, client: OpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" transcription = response.parse() - assert_matches_type(Transcription, transcription, path=["response"]) + assert_matches_type(TranscriptionCreateResponse, transcription, path=["response"]) @parametrize def test_streaming_response_create(self, client: OpenAI) -> None: @@ -60,7 +60,7 @@ def test_streaming_response_create(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" transcription = response.parse() - assert_matches_type(Transcription, transcription, path=["response"]) + assert_matches_type(TranscriptionCreateResponse, transcription, path=["response"]) assert cast(Any, response.is_closed) is True @@ -74,7 +74,7 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None: file=b"raw file contents", model="whisper-1", ) - assert_matches_type(Transcription, transcription, path=["response"]) + assert_matches_type(TranscriptionCreateResponse, transcription, path=["response"]) @parametrize async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: @@ -87,7 +87,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> temperature=0, timestamp_granularities=["word", "segment"], ) - assert_matches_type(Transcription, transcription, path=["response"]) + assert_matches_type(TranscriptionCreateResponse, transcription, path=["response"]) @parametrize async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: @@ -99,7 +99,7 @@ async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" transcription = response.parse() - assert_matches_type(Transcription, transcription, path=["response"]) + assert_matches_type(TranscriptionCreateResponse, transcription, path=["response"]) @parametrize async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: @@ -111,6 +111,6 @@ async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> Non assert response.http_request.headers.get("X-Stainless-Lang") == "python" transcription = await response.parse() - assert_matches_type(Transcription, transcription, path=["response"]) + assert_matches_type(TranscriptionCreateResponse, transcription, path=["response"]) assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/audio/test_translations.py b/tests/api_resources/audio/test_translations.py index b048a1af12..e12ab7e6c0 100644 --- a/tests/api_resources/audio/test_translations.py +++ b/tests/api_resources/audio/test_translations.py @@ -9,7 +9,7 @@ from openai import OpenAI, AsyncOpenAI from tests.utils import assert_matches_type -from openai.types.audio import Translation +from openai.types.audio import TranslationCreateResponse base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -23,7 +23,7 @@ def test_method_create(self, client: OpenAI) -> None: file=b"raw file contents", model="whisper-1", ) - assert_matches_type(Translation, translation, path=["response"]) + assert_matches_type(TranslationCreateResponse, translation, path=["response"]) @parametrize def test_method_create_with_all_params(self, client: OpenAI) -> None: @@ -34,7 +34,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: response_format="json", temperature=0, ) - assert_matches_type(Translation, translation, path=["response"]) + assert_matches_type(TranslationCreateResponse, translation, path=["response"]) @parametrize def test_raw_response_create(self, client: OpenAI) -> None: @@ -46,7 +46,7 @@ def test_raw_response_create(self, client: OpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" translation = response.parse() - assert_matches_type(Translation, translation, path=["response"]) + assert_matches_type(TranslationCreateResponse, translation, path=["response"]) @parametrize def test_streaming_response_create(self, client: OpenAI) -> None: @@ -58,7 +58,7 @@ def test_streaming_response_create(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" translation = response.parse() - assert_matches_type(Translation, translation, path=["response"]) + assert_matches_type(TranslationCreateResponse, translation, path=["response"]) assert cast(Any, response.is_closed) is True @@ -72,7 +72,7 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None: file=b"raw file contents", model="whisper-1", ) - assert_matches_type(Translation, translation, path=["response"]) + assert_matches_type(TranslationCreateResponse, translation, path=["response"]) @parametrize async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: @@ -83,7 +83,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> response_format="json", temperature=0, ) - assert_matches_type(Translation, translation, path=["response"]) + assert_matches_type(TranslationCreateResponse, translation, path=["response"]) @parametrize async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: @@ -95,7 +95,7 @@ async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" translation = response.parse() - assert_matches_type(Translation, translation, path=["response"]) + assert_matches_type(TranslationCreateResponse, translation, path=["response"]) @parametrize async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: @@ -107,6 +107,6 @@ async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> Non assert response.http_request.headers.get("X-Stainless-Lang") == "python" translation = await response.parse() - assert_matches_type(Translation, translation, path=["response"]) + assert_matches_type(TranslationCreateResponse, translation, path=["response"]) assert cast(Any, response.is_closed) is True diff --git a/tests/lib/test_audio.py b/tests/lib/test_audio.py new file mode 100644 index 0000000000..0f53b316ba --- /dev/null +++ b/tests/lib/test_audio.py @@ -0,0 +1,83 @@ +from __future__ import annotations + +import sys +import inspect +import typing_extensions +from typing import get_args + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import evaluate_forwardref +from openai._utils import assert_signatures_in_sync +from openai._compat import is_literal_type +from openai._utils._typing import is_union_type +from openai.types.audio_response_format import AudioResponseFormat + + +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +def test_translation_create_overloads_in_sync(sync: bool, client: OpenAI, async_client: AsyncOpenAI) -> None: + checking_client: OpenAI | AsyncOpenAI = client if sync else async_client + + fn = checking_client.audio.translations.create + overload_response_formats: set[str] = set() + + for i, overload in enumerate(typing_extensions.get_overloads(fn)): + assert_signatures_in_sync( + fn, + overload, + exclude_params={"response_format"}, + description=f" for overload {i}", + ) + + sig = inspect.signature(overload) + typ = evaluate_forwardref( + sig.parameters["response_format"].annotation, + globalns=sys.modules[fn.__module__].__dict__, + ) + if is_union_type(typ): + for arg in get_args(typ): + if not is_literal_type(arg): + continue + + overload_response_formats.update(get_args(arg)) + elif is_literal_type(typ): + overload_response_formats.update(get_args(typ)) + + src_response_formats: set[str] = set(get_args(AudioResponseFormat)) + diff = src_response_formats.difference(overload_response_formats) + assert len(diff) == 0, f"some response format options don't have overloads" + + +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +def test_transcription_create_overloads_in_sync(sync: bool, client: OpenAI, async_client: AsyncOpenAI) -> None: + checking_client: OpenAI | AsyncOpenAI = client if sync else async_client + + fn = checking_client.audio.transcriptions.create + overload_response_formats: set[str] = set() + + for i, overload in enumerate(typing_extensions.get_overloads(fn)): + assert_signatures_in_sync( + fn, + overload, + exclude_params={"response_format"}, + description=f" for overload {i}", + ) + + sig = inspect.signature(overload) + typ = evaluate_forwardref( + sig.parameters["response_format"].annotation, + globalns=sys.modules[fn.__module__].__dict__, + ) + if is_union_type(typ): + for arg in get_args(typ): + if not is_literal_type(arg): + continue + + overload_response_formats.update(get_args(arg)) + elif is_literal_type(typ): + overload_response_formats.update(get_args(typ)) + + src_response_formats: set[str] = set(get_args(AudioResponseFormat)) + diff = src_response_formats.difference(overload_response_formats) + assert len(diff) == 0, f"some response format options don't have overloads" diff --git a/tests/utils.py b/tests/utils.py index 8d5397f28e..16948a66f2 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -5,7 +5,7 @@ import inspect import traceback import contextlib -from typing import Any, TypeVar, Iterator, cast +from typing import Any, TypeVar, Iterator, ForwardRef, cast from datetime import date, datetime from typing_extensions import Literal, get_args, get_origin, assert_type @@ -26,6 +26,10 @@ BaseModelT = TypeVar("BaseModelT", bound=BaseModel) +def evaluate_forwardref(forwardref: ForwardRef, globalns: dict[str, Any]) -> type: + return eval(str(forwardref), globalns) # type: ignore[no-any-return] + + def assert_matches_model(model: type[BaseModelT], value: BaseModelT, *, path: list[str]) -> bool: for name, field in get_model_fields(model).items(): field_value = getattr(value, name) From aeaed488352274a9ca86c834eeb618d732989518 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Sep 2024 23:04:57 +0000 Subject: [PATCH 038/769] release: 1.50.2 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 43515db369..b11d9e721d 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.50.1" + ".": "1.50.2" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index c51de0481b..37571051de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.50.2 (2024-09-27) + +Full Changelog: [v1.50.1...v1.50.2](https://github.com/openai/openai-python/compare/v1.50.1...v1.50.2) + +### Bug Fixes + +* **audio:** correct types for transcriptions / translations ([#1755](https://github.com/openai/openai-python/issues/1755)) ([76c1f3f](https://github.com/openai/openai-python/commit/76c1f3f318b68003aae124c02efc4547a398a864)) + ## 1.50.1 (2024-09-27) Full Changelog: [v1.50.0...v1.50.1](https://github.com/openai/openai-python/compare/v1.50.0...v1.50.1) diff --git a/pyproject.toml b/pyproject.toml index 7ebf741165..90b8c8518c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.50.1" +version = "1.50.2" 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 2b0fd31d26..641dd21648 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.50.1" # x-release-please-version +__version__ = "1.50.2" # x-release-please-version From 3b4821ff79433ba268ef66190747c14e1f1aeb71 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Mon, 30 Sep 2024 10:19:21 -0400 Subject: [PATCH 039/769] chore(internal): remove ds store --- .DS_Store | Bin 6148 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index c88a062b05be4fd1d362b3e4c6a7481e718b69d0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeH~O$x$5422WzLU7Zi%h`AUZ!n0Spcima5J4*Vx1OW>k_m#k8KJGkN^pg011%5 z4-v3?8#bF)Wh4O-Ab}?V`#vPNX$~z_{nLTqBLK8P*$r!-C7{U)&>UK-q5{*H9yD6j z#}KP~J2b_)99pW@cF`C;crrWIXQgOGwy`I%~QMGk}L;X0y%TE9jyNVZZH|!@{KyzrRiVBQB0*--!1inh( E0rZ6u#{d8T From 4bd80b9f70773ae3a24874f2a82043db0ae7ef77 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 30 Sep 2024 14:51:54 +0000 Subject: [PATCH 040/769] chore(docs): fix maxium typo (#1762) --- .stats.yml | 2 +- src/openai/resources/beta/assistants.py | 8 ++++---- src/openai/resources/beta/threads/messages.py | 8 ++++---- .../resources/beta/threads/runs/runs.py | 16 +++++++-------- src/openai/resources/beta/threads/threads.py | 20 +++++++++---------- .../beta/vector_stores/vector_stores.py | 8 ++++---- src/openai/types/batch.py | 2 +- src/openai/types/beta/assistant.py | 2 +- .../types/beta/assistant_create_params.py | 4 ++-- .../types/beta/assistant_update_params.py | 2 +- src/openai/types/beta/thread.py | 2 +- .../beta/thread_create_and_run_params.py | 8 ++++---- src/openai/types/beta/thread_create_params.py | 6 +++--- src/openai/types/beta/thread_update_params.py | 2 +- src/openai/types/beta/threads/message.py | 2 +- .../beta/threads/message_create_params.py | 2 +- .../beta/threads/message_update_params.py | 2 +- src/openai/types/beta/threads/run.py | 2 +- .../types/beta/threads/run_create_params.py | 4 ++-- .../types/beta/threads/run_update_params.py | 2 +- .../types/beta/threads/runs/run_step.py | 2 +- src/openai/types/beta/vector_store.py | 2 +- .../types/beta/vector_store_create_params.py | 2 +- .../types/beta/vector_store_update_params.py | 2 +- 24 files changed, 56 insertions(+), 56 deletions(-) diff --git a/.stats.yml b/.stats.yml index 68789976bf..67778eef99 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 68 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-71e58a77027c67e003fdd1b1ac8ac11557d8bfabc7666d1a827c6b1ca8ab98b5.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-8ad878332083dd506a478a293db78dc9e7b1b2124f2682e1d991225bc5bbcc3b.yml diff --git a/src/openai/resources/beta/assistants.py b/src/openai/resources/beta/assistants.py index 5d8c6ec331..2ebef183b6 100644 --- a/src/openai/resources/beta/assistants.py +++ b/src/openai/resources/beta/assistants.py @@ -89,7 +89,7 @@ def create( metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maxium of 512 + can be a maximum of 64 characters long and values can be a maximum of 512 characters long. name: The name of the assistant. The maximum length is 256 characters. @@ -233,7 +233,7 @@ def update( metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maxium of 512 + can be a maximum of 64 characters long and values can be a maximum of 512 characters long. model: ID of the model to use. You can use the @@ -475,7 +475,7 @@ async def create( metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maxium of 512 + can be a maximum of 64 characters long and values can be a maximum of 512 characters long. name: The name of the assistant. The maximum length is 256 characters. @@ -619,7 +619,7 @@ async def update( metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maxium of 512 + can be a maximum of 64 characters long and values can be a maximum of 512 characters long. model: ID of the model to use. You can use the diff --git a/src/openai/resources/beta/threads/messages.py b/src/openai/resources/beta/threads/messages.py index 4901174329..de7ebcaf4d 100644 --- a/src/openai/resources/beta/threads/messages.py +++ b/src/openai/resources/beta/threads/messages.py @@ -82,7 +82,7 @@ def create( metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maxium of 512 + can be a maximum of 64 characters long and values can be a maximum of 512 characters long. extra_headers: Send extra headers @@ -169,7 +169,7 @@ def update( Args: metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maxium of 512 + can be a maximum of 64 characters long and values can be a maximum of 512 characters long. extra_headers: Send extra headers @@ -356,7 +356,7 @@ async def create( metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maxium of 512 + can be a maximum of 64 characters long and values can be a maximum of 512 characters long. extra_headers: Send extra headers @@ -443,7 +443,7 @@ async def update( Args: metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maxium of 512 + can be a maximum of 64 characters long and values can be a maximum of 512 characters long. extra_headers: Send extra headers diff --git a/src/openai/resources/beta/threads/runs/runs.py b/src/openai/resources/beta/threads/runs/runs.py index a4cbcc57e4..287c0ecf24 100644 --- a/src/openai/resources/beta/threads/runs/runs.py +++ b/src/openai/resources/beta/threads/runs/runs.py @@ -149,7 +149,7 @@ def create( metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maxium of 512 + can be a maximum of 64 characters long and values can be a maximum of 512 characters long. model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to @@ -293,7 +293,7 @@ def create( metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maxium of 512 + can be a maximum of 64 characters long and values can be a maximum of 512 characters long. model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to @@ -433,7 +433,7 @@ def create( metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maxium of 512 + can be a maximum of 64 characters long and values can be a maximum of 512 characters long. model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to @@ -623,7 +623,7 @@ def update( Args: metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maxium of 512 + can be a maximum of 64 characters long and values can be a maximum of 512 characters long. extra_headers: Send extra headers @@ -1511,7 +1511,7 @@ async def create( metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maxium of 512 + can be a maximum of 64 characters long and values can be a maximum of 512 characters long. model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to @@ -1655,7 +1655,7 @@ async def create( metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maxium of 512 + can be a maximum of 64 characters long and values can be a maximum of 512 characters long. model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to @@ -1795,7 +1795,7 @@ async def create( metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maxium of 512 + can be a maximum of 64 characters long and values can be a maximum of 512 characters long. model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to @@ -1986,7 +1986,7 @@ async def update( Args: metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maxium of 512 + can be a maximum of 64 characters long and values can be a maximum of 512 characters long. extra_headers: Send extra headers diff --git a/src/openai/resources/beta/threads/threads.py b/src/openai/resources/beta/threads/threads.py index acc0fe9bda..3b8851c03b 100644 --- a/src/openai/resources/beta/threads/threads.py +++ b/src/openai/resources/beta/threads/threads.py @@ -111,7 +111,7 @@ def create( metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maxium of 512 + can be a maximum of 64 characters long and values can be a maximum of 512 characters long. tool_resources: A set of resources that are made available to the assistant's tools in this @@ -197,7 +197,7 @@ def update( Args: metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maxium of 512 + can be a maximum of 64 characters long and values can be a maximum of 512 characters long. tool_resources: A set of resources that are made available to the assistant's tools in this @@ -317,7 +317,7 @@ def create_and_run( metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maxium of 512 + can be a maximum of 64 characters long and values can be a maximum of 512 characters long. model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to @@ -451,7 +451,7 @@ def create_and_run( metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maxium of 512 + can be a maximum of 64 characters long and values can be a maximum of 512 characters long. model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to @@ -581,7 +581,7 @@ def create_and_run( metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maxium of 512 + can be a maximum of 64 characters long and values can be a maximum of 512 characters long. model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to @@ -945,7 +945,7 @@ async def create( metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maxium of 512 + can be a maximum of 64 characters long and values can be a maximum of 512 characters long. tool_resources: A set of resources that are made available to the assistant's tools in this @@ -1031,7 +1031,7 @@ async def update( Args: metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maxium of 512 + can be a maximum of 64 characters long and values can be a maximum of 512 characters long. tool_resources: A set of resources that are made available to the assistant's tools in this @@ -1151,7 +1151,7 @@ async def create_and_run( metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maxium of 512 + can be a maximum of 64 characters long and values can be a maximum of 512 characters long. model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to @@ -1285,7 +1285,7 @@ async def create_and_run( metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maxium of 512 + can be a maximum of 64 characters long and values can be a maximum of 512 characters long. model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to @@ -1415,7 +1415,7 @@ async def create_and_run( metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maxium of 512 + can be a maximum of 64 characters long and values can be a maximum of 512 characters long. model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to diff --git a/src/openai/resources/beta/vector_stores/vector_stores.py b/src/openai/resources/beta/vector_stores/vector_stores.py index 06e26852b4..d69add7b26 100644 --- a/src/openai/resources/beta/vector_stores/vector_stores.py +++ b/src/openai/resources/beta/vector_stores/vector_stores.py @@ -105,7 +105,7 @@ def create( metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maxium of 512 + can be a maximum of 64 characters long and values can be a maximum of 512 characters long. name: The name of the vector store. @@ -193,7 +193,7 @@ def update( metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maxium of 512 + can be a maximum of 64 characters long and values can be a maximum of 512 characters long. name: The name of the vector store. @@ -383,7 +383,7 @@ async def create( metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maxium of 512 + can be a maximum of 64 characters long and values can be a maximum of 512 characters long. name: The name of the vector store. @@ -471,7 +471,7 @@ async def update( metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maxium of 512 + can be a maximum of 64 characters long and values can be a maximum of 512 characters long. name: The name of the vector store. diff --git a/src/openai/types/batch.py b/src/openai/types/batch.py index 90f6d79572..ac3d7ea119 100644 --- a/src/openai/types/batch.py +++ b/src/openai/types/batch.py @@ -75,7 +75,7 @@ class Batch(BaseModel): This can be useful for storing additional information about the object in a structured format. Keys can be a maximum of 64 characters long and values can be - a maxium of 512 characters long. + a maximum of 512 characters long. """ output_file_id: Optional[str] = None diff --git a/src/openai/types/beta/assistant.py b/src/openai/types/beta/assistant.py index b4da08745d..ea97de440f 100644 --- a/src/openai/types/beta/assistant.py +++ b/src/openai/types/beta/assistant.py @@ -56,7 +56,7 @@ class Assistant(BaseModel): This can be useful for storing additional information about the object in a structured format. Keys can be a maximum of 64 characters long and values can be - a maxium of 512 characters long. + a maximum of 512 characters long. """ model: str diff --git a/src/openai/types/beta/assistant_create_params.py b/src/openai/types/beta/assistant_create_params.py index eca4da0a2b..e11f842f05 100644 --- a/src/openai/types/beta/assistant_create_params.py +++ b/src/openai/types/beta/assistant_create_params.py @@ -44,7 +44,7 @@ class AssistantCreateParams(TypedDict, total=False): This can be useful for storing additional information about the object in a structured format. Keys can be a maximum of 64 characters long and values can be - a maxium of 512 characters long. + a maximum of 512 characters long. """ name: Optional[str] @@ -135,7 +135,7 @@ class ToolResourcesFileSearchVectorStore(TypedDict, total=False): This can be useful for storing additional information about the vector store in a structured format. Keys can be a maximum of 64 characters long and values can - be a maxium of 512 characters long. + be a maximum of 512 characters long. """ diff --git a/src/openai/types/beta/assistant_update_params.py b/src/openai/types/beta/assistant_update_params.py index 5396233937..c4598df507 100644 --- a/src/openai/types/beta/assistant_update_params.py +++ b/src/openai/types/beta/assistant_update_params.py @@ -26,7 +26,7 @@ class AssistantUpdateParams(TypedDict, total=False): This can be useful for storing additional information about the object in a structured format. Keys can be a maximum of 64 characters long and values can be - a maxium of 512 characters long. + a maximum of 512 characters long. """ model: str diff --git a/src/openai/types/beta/thread.py b/src/openai/types/beta/thread.py index 6f7a6c7d0c..37d50ccb93 100644 --- a/src/openai/types/beta/thread.py +++ b/src/openai/types/beta/thread.py @@ -45,7 +45,7 @@ class Thread(BaseModel): This can be useful for storing additional information about the object in a structured format. Keys can be a maximum of 64 characters long and values can be - a maxium of 512 characters long. + a maximum of 512 characters long. """ object: Literal["thread"] diff --git a/src/openai/types/beta/thread_create_and_run_params.py b/src/openai/types/beta/thread_create_and_run_params.py index 20d525fa1a..64ee6a8710 100644 --- a/src/openai/types/beta/thread_create_and_run_params.py +++ b/src/openai/types/beta/thread_create_and_run_params.py @@ -72,7 +72,7 @@ class ThreadCreateAndRunParamsBase(TypedDict, total=False): This can be useful for storing additional information about the object in a structured format. Keys can be a maximum of 64 characters long and values can be - a maxium of 512 characters long. + a maximum of 512 characters long. """ model: Union[str, ChatModel, None] @@ -202,7 +202,7 @@ class ThreadMessage(TypedDict, total=False): This can be useful for storing additional information about the object in a structured format. Keys can be a maximum of 64 characters long and values can be - a maxium of 512 characters long. + a maximum of 512 characters long. """ @@ -235,7 +235,7 @@ class ThreadToolResourcesFileSearchVectorStore(TypedDict, total=False): This can be useful for storing additional information about the vector store in a structured format. Keys can be a maximum of 64 characters long and values can - be a maxium of 512 characters long. + be a maximum of 512 characters long. """ @@ -275,7 +275,7 @@ class Thread(TypedDict, total=False): This can be useful for storing additional information about the object in a structured format. Keys can be a maximum of 64 characters long and values can be - a maxium of 512 characters long. + a maximum of 512 characters long. """ tool_resources: Optional[ThreadToolResources] diff --git a/src/openai/types/beta/thread_create_params.py b/src/openai/types/beta/thread_create_params.py index 729164b481..3ac6c7d69b 100644 --- a/src/openai/types/beta/thread_create_params.py +++ b/src/openai/types/beta/thread_create_params.py @@ -34,7 +34,7 @@ class ThreadCreateParams(TypedDict, total=False): This can be useful for storing additional information about the object in a structured format. Keys can be a maximum of 64 characters long and values can be - a maxium of 512 characters long. + a maximum of 512 characters long. """ tool_resources: Optional[ToolResources] @@ -83,7 +83,7 @@ class Message(TypedDict, total=False): This can be useful for storing additional information about the object in a structured format. Keys can be a maximum of 64 characters long and values can be - a maxium of 512 characters long. + a maximum of 512 characters long. """ @@ -116,7 +116,7 @@ class ToolResourcesFileSearchVectorStore(TypedDict, total=False): This can be useful for storing additional information about the vector store in a structured format. Keys can be a maximum of 64 characters long and values can - be a maxium of 512 characters long. + be a maximum of 512 characters long. """ diff --git a/src/openai/types/beta/thread_update_params.py b/src/openai/types/beta/thread_update_params.py index 7210ab77c9..78c5ec4f2e 100644 --- a/src/openai/types/beta/thread_update_params.py +++ b/src/openai/types/beta/thread_update_params.py @@ -14,7 +14,7 @@ class ThreadUpdateParams(TypedDict, total=False): This can be useful for storing additional information about the object in a structured format. Keys can be a maximum of 64 characters long and values can be - a maxium of 512 characters long. + a maximum of 512 characters long. """ tool_resources: Optional[ToolResources] diff --git a/src/openai/types/beta/threads/message.py b/src/openai/types/beta/threads/message.py index 298a1d4273..63c5c4800a 100644 --- a/src/openai/types/beta/threads/message.py +++ b/src/openai/types/beta/threads/message.py @@ -71,7 +71,7 @@ class Message(BaseModel): This can be useful for storing additional information about the object in a structured format. Keys can be a maximum of 64 characters long and values can be - a maxium of 512 characters long. + a maximum of 512 characters long. """ object: Literal["thread.message"] diff --git a/src/openai/types/beta/threads/message_create_params.py b/src/openai/types/beta/threads/message_create_params.py index 2b450deb5d..2c4edfdf71 100644 --- a/src/openai/types/beta/threads/message_create_params.py +++ b/src/openai/types/beta/threads/message_create_params.py @@ -32,7 +32,7 @@ class MessageCreateParams(TypedDict, total=False): This can be useful for storing additional information about the object in a structured format. Keys can be a maximum of 64 characters long and values can be - a maxium of 512 characters long. + a maximum of 512 characters long. """ diff --git a/src/openai/types/beta/threads/message_update_params.py b/src/openai/types/beta/threads/message_update_params.py index 7000f33122..e8f8cc910c 100644 --- a/src/openai/types/beta/threads/message_update_params.py +++ b/src/openai/types/beta/threads/message_update_params.py @@ -16,5 +16,5 @@ class MessageUpdateParams(TypedDict, total=False): This can be useful for storing additional information about the object in a structured format. Keys can be a maximum of 64 characters long and values can be - a maxium of 512 characters long. + a maximum of 512 characters long. """ diff --git a/src/openai/types/beta/threads/run.py b/src/openai/types/beta/threads/run.py index 5abc1de295..e8f2b74dee 100644 --- a/src/openai/types/beta/threads/run.py +++ b/src/openai/types/beta/threads/run.py @@ -138,7 +138,7 @@ class Run(BaseModel): This can be useful for storing additional information about the object in a structured format. Keys can be a maximum of 64 characters long and values can be - a maxium of 512 characters long. + a maximum of 512 characters long. """ model: str diff --git a/src/openai/types/beta/threads/run_create_params.py b/src/openai/types/beta/threads/run_create_params.py index 824cb1a041..9767b142e1 100644 --- a/src/openai/types/beta/threads/run_create_params.py +++ b/src/openai/types/beta/threads/run_create_params.py @@ -85,7 +85,7 @@ class RunCreateParamsBase(TypedDict, total=False): This can be useful for storing additional information about the object in a structured format. Keys can be a maximum of 64 characters long and values can be - a maxium of 512 characters long. + a maximum of 512 characters long. """ model: Union[str, ChatModel, None] @@ -204,7 +204,7 @@ class AdditionalMessage(TypedDict, total=False): This can be useful for storing additional information about the object in a structured format. Keys can be a maximum of 64 characters long and values can be - a maxium of 512 characters long. + a maximum of 512 characters long. """ diff --git a/src/openai/types/beta/threads/run_update_params.py b/src/openai/types/beta/threads/run_update_params.py index e595eac882..cb4f053645 100644 --- a/src/openai/types/beta/threads/run_update_params.py +++ b/src/openai/types/beta/threads/run_update_params.py @@ -16,5 +16,5 @@ class RunUpdateParams(TypedDict, total=False): This can be useful for storing additional information about the object in a structured format. Keys can be a maximum of 64 characters long and values can be - a maxium of 512 characters long. + a maximum of 512 characters long. """ diff --git a/src/openai/types/beta/threads/runs/run_step.py b/src/openai/types/beta/threads/runs/run_step.py index e3163c508b..0445ae360d 100644 --- a/src/openai/types/beta/threads/runs/run_step.py +++ b/src/openai/types/beta/threads/runs/run_step.py @@ -75,7 +75,7 @@ class RunStep(BaseModel): This can be useful for storing additional information about the object in a structured format. Keys can be a maximum of 64 characters long and values can be - a maxium of 512 characters long. + a maximum of 512 characters long. """ object: Literal["thread.run.step"] diff --git a/src/openai/types/beta/vector_store.py b/src/openai/types/beta/vector_store.py index 488961b444..2d3ceea80c 100644 --- a/src/openai/types/beta/vector_store.py +++ b/src/openai/types/beta/vector_store.py @@ -53,7 +53,7 @@ class VectorStore(BaseModel): This can be useful for storing additional information about the object in a structured format. Keys can be a maximum of 64 characters long and values can be - a maxium of 512 characters long. + a maximum of 512 characters long. """ name: str diff --git a/src/openai/types/beta/vector_store_create_params.py b/src/openai/types/beta/vector_store_create_params.py index a8f03a89b9..4fc7c38927 100644 --- a/src/openai/types/beta/vector_store_create_params.py +++ b/src/openai/types/beta/vector_store_create_params.py @@ -33,7 +33,7 @@ class VectorStoreCreateParams(TypedDict, total=False): This can be useful for storing additional information about the object in a structured format. Keys can be a maximum of 64 characters long and values can be - a maxium of 512 characters long. + a maximum of 512 characters long. """ name: str diff --git a/src/openai/types/beta/vector_store_update_params.py b/src/openai/types/beta/vector_store_update_params.py index 0f9593e476..ff6c068efb 100644 --- a/src/openai/types/beta/vector_store_update_params.py +++ b/src/openai/types/beta/vector_store_update_params.py @@ -17,7 +17,7 @@ class VectorStoreUpdateParams(TypedDict, total=False): This can be useful for storing additional information about the object in a structured format. Keys can be a maximum of 64 characters long and values can be - a maxium of 512 characters long. + a maximum of 512 characters long. """ name: Optional[str] From 94bfe19aaf5a96aed37e6405684743a39892092f Mon Sep 17 00:00:00 2001 From: Laziz Turakulov <4857092+LazaUK@users.noreply.github.com> Date: Mon, 30 Sep 2024 22:19:57 +0100 Subject: [PATCH 041/769] docs(helpers): fix method name typo (#1764) --- helpers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helpers.md b/helpers.md index 65515df973..3f3fafa45c 100644 --- a/helpers.md +++ b/helpers.md @@ -508,7 +508,7 @@ The polling methods are: ```python client.beta.threads.create_and_run_poll(...) client.beta.threads.runs.create_and_poll(...) -client.beta.threads.runs.submit_tool_ouptputs_and_poll(...) +client.beta.threads.runs.submit_tool_outputs_and_poll(...) client.beta.vector_stores.files.upload_and_poll(...) client.beta.vector_stores.files.create_and_poll(...) client.beta.vector_stores.file_batches.create_and_poll(...) From 7c8c11158c4e0b63fef495c32447d6e31870073f Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Tue, 1 Oct 2024 12:10:34 -0400 Subject: [PATCH 042/769] feat(api): support storing chat completions, enabling evals and model distillation in the dashboard Learn more at http://openai.com/devday2024 --- .stats.yml | 2 +- src/openai/resources/beta/chat/completions.py | 16 +++ src/openai/resources/chat/completions.py | 104 ++++++++++++++++-- .../types/chat/completion_create_params.py | 18 ++- src/openai/types/chat_model.py | 1 + src/openai/types/completion_usage.py | 16 ++- tests/api_resources/chat/test_completions.py | 8 ++ tests/lib/chat/test_completions.py | 18 ++- tests/lib/chat/test_completions_streaming.py | 3 +- 9 files changed, 164 insertions(+), 22 deletions(-) diff --git a/.stats.yml b/.stats.yml index 67778eef99..ece287351b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 68 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-8ad878332083dd506a478a293db78dc9e7b1b2124f2682e1d991225bc5bbcc3b.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-52b934aee6468039ec7f4ce046a282b5fbce114afc708e70f17121df654f71da.yml diff --git a/src/openai/resources/beta/chat/completions.py b/src/openai/resources/beta/chat/completions.py index da6f189929..c747464072 100644 --- a/src/openai/resources/beta/chat/completions.py +++ b/src/openai/resources/beta/chat/completions.py @@ -69,12 +69,14 @@ def parse( logprobs: Optional[bool] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | 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, + store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, @@ -158,6 +160,7 @@ def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseForma "logprobs": logprobs, "max_completion_tokens": max_completion_tokens, "max_tokens": max_tokens, + "metadata": metadata, "n": n, "parallel_tool_calls": parallel_tool_calls, "presence_penalty": presence_penalty, @@ -165,6 +168,7 @@ def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseForma "seed": seed, "service_tier": service_tier, "stop": stop, + "store": store, "stream": False, "stream_options": stream_options, "temperature": temperature, @@ -202,12 +206,14 @@ def stream( logprobs: Optional[bool] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | 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, + store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, @@ -262,11 +268,13 @@ def stream( logprobs=logprobs, max_completion_tokens=max_completion_tokens, max_tokens=max_tokens, + metadata=metadata, n=n, parallel_tool_calls=parallel_tool_calls, presence_penalty=presence_penalty, seed=seed, service_tier=service_tier, + store=store, stop=stop, stream_options=stream_options, temperature=temperature, @@ -320,12 +328,14 @@ async def parse( logprobs: Optional[bool] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | 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, + store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, @@ -409,12 +419,14 @@ def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseForma "logprobs": logprobs, "max_completion_tokens": max_completion_tokens, "max_tokens": max_tokens, + "metadata": metadata, "n": n, "parallel_tool_calls": parallel_tool_calls, "presence_penalty": presence_penalty, "response_format": _type_to_response_format(response_format), "seed": seed, "service_tier": service_tier, + "store": store, "stop": stop, "stream": False, "stream_options": stream_options, @@ -453,12 +465,14 @@ def stream( logprobs: Optional[bool] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | 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, + store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, @@ -514,12 +528,14 @@ def stream( logprobs=logprobs, max_completion_tokens=max_completion_tokens, max_tokens=max_tokens, + metadata=metadata, n=n, parallel_tool_calls=parallel_tool_calls, presence_penalty=presence_penalty, seed=seed, service_tier=service_tier, stop=stop, + store=store, stream_options=stream_options, temperature=temperature, tool_choice=tool_choice, diff --git a/src/openai/resources/chat/completions.py b/src/openai/resources/chat/completions.py index 05cfaacd83..c8080afaa1 100644 --- a/src/openai/resources/chat/completions.py +++ b/src/openai/resources/chat/completions.py @@ -66,6 +66,7 @@ def create( logprobs: Optional[bool] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, @@ -73,6 +74,7 @@ def create( seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str]] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -92,8 +94,12 @@ def create( Creates a model response for the given chat conversation. Args: - messages: A list of messages comprising the conversation so far. - [Example Python code](https://cookbook.openai.com/examples/how_to_format_inputs_to_chatgpt_models). + messages: A list of messages comprising the conversation so far. Depending on the + [model](https://platform.openai.com/docs/models) you use, different message + types (modalities) are supported, like + [text](https://platform.openai.com/docs/guides/text-generation), + [images](https://platform.openai.com/docs/guides/vision), and + [audio](https://platform.openai.com/docs/guides/audio). model: ID of the model to use. See the [model endpoint compatibility](https://platform.openai.com/docs/models/model-endpoint-compatibility) @@ -145,6 +151,9 @@ def create( compatible with [o1 series models](https://platform.openai.com/docs/guides/reasoning). + metadata: Developer-defined tags and values used for filtering completions in the + [dashboard](https://platform.openai.com/completions). + n: How many chat completion choices to generate for each input message. Note that you will be charged based on the number of generated tokens across all of the choices. Keep `n` as `1` to minimize costs. @@ -204,6 +213,9 @@ def create( stop: Up to 4 sequences where the API will stop generating further tokens. + store: Whether or not to store the output of this completion request for traffic + logging in the [dashboard](https://platform.openai.com/completions). + stream: If set, partial message deltas will be sent, like in ChatGPT. Tokens will be sent as data-only [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format) @@ -271,6 +283,7 @@ def create( logprobs: Optional[bool] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, @@ -278,6 +291,7 @@ def create( seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str]] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, @@ -296,8 +310,12 @@ def create( Creates a model response for the given chat conversation. Args: - messages: A list of messages comprising the conversation so far. - [Example Python code](https://cookbook.openai.com/examples/how_to_format_inputs_to_chatgpt_models). + messages: A list of messages comprising the conversation so far. Depending on the + [model](https://platform.openai.com/docs/models) you use, different message + types (modalities) are supported, like + [text](https://platform.openai.com/docs/guides/text-generation), + [images](https://platform.openai.com/docs/guides/vision), and + [audio](https://platform.openai.com/docs/guides/audio). model: ID of the model to use. See the [model endpoint compatibility](https://platform.openai.com/docs/models/model-endpoint-compatibility) @@ -356,6 +374,9 @@ def create( compatible with [o1 series models](https://platform.openai.com/docs/guides/reasoning). + metadata: Developer-defined tags and values used for filtering completions in the + [dashboard](https://platform.openai.com/completions). + n: How many chat completion choices to generate for each input message. Note that you will be charged based on the number of generated tokens across all of the choices. Keep `n` as `1` to minimize costs. @@ -415,6 +436,9 @@ def create( stop: Up to 4 sequences where the API will stop generating further tokens. + store: Whether or not to store the output of this completion request for traffic + logging in the [dashboard](https://platform.openai.com/completions). + stream_options: Options for streaming response. Only set this when you set `stream: true`. temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will @@ -475,6 +499,7 @@ def create( logprobs: Optional[bool] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, @@ -482,6 +507,7 @@ def create( seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str]] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, @@ -500,8 +526,12 @@ def create( Creates a model response for the given chat conversation. Args: - messages: A list of messages comprising the conversation so far. - [Example Python code](https://cookbook.openai.com/examples/how_to_format_inputs_to_chatgpt_models). + messages: A list of messages comprising the conversation so far. Depending on the + [model](https://platform.openai.com/docs/models) you use, different message + types (modalities) are supported, like + [text](https://platform.openai.com/docs/guides/text-generation), + [images](https://platform.openai.com/docs/guides/vision), and + [audio](https://platform.openai.com/docs/guides/audio). model: ID of the model to use. See the [model endpoint compatibility](https://platform.openai.com/docs/models/model-endpoint-compatibility) @@ -560,6 +590,9 @@ def create( compatible with [o1 series models](https://platform.openai.com/docs/guides/reasoning). + metadata: Developer-defined tags and values used for filtering completions in the + [dashboard](https://platform.openai.com/completions). + n: How many chat completion choices to generate for each input message. Note that you will be charged based on the number of generated tokens across all of the choices. Keep `n` as `1` to minimize costs. @@ -619,6 +652,9 @@ def create( stop: Up to 4 sequences where the API will stop generating further tokens. + store: Whether or not to store the output of this completion request for traffic + logging in the [dashboard](https://platform.openai.com/completions). + stream_options: Options for streaming response. Only set this when you set `stream: true`. temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will @@ -678,6 +714,7 @@ def create( logprobs: Optional[bool] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, @@ -685,6 +722,7 @@ def create( seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str]] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -714,6 +752,7 @@ def create( "logprobs": logprobs, "max_completion_tokens": max_completion_tokens, "max_tokens": max_tokens, + "metadata": metadata, "n": n, "parallel_tool_calls": parallel_tool_calls, "presence_penalty": presence_penalty, @@ -721,6 +760,7 @@ def create( "seed": seed, "service_tier": service_tier, "stop": stop, + "store": store, "stream": stream, "stream_options": stream_options, "temperature": temperature, @@ -774,6 +814,7 @@ async def create( logprobs: Optional[bool] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, @@ -781,6 +822,7 @@ async def create( seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str]] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -800,8 +842,12 @@ async def create( Creates a model response for the given chat conversation. Args: - messages: A list of messages comprising the conversation so far. - [Example Python code](https://cookbook.openai.com/examples/how_to_format_inputs_to_chatgpt_models). + messages: A list of messages comprising the conversation so far. Depending on the + [model](https://platform.openai.com/docs/models) you use, different message + types (modalities) are supported, like + [text](https://platform.openai.com/docs/guides/text-generation), + [images](https://platform.openai.com/docs/guides/vision), and + [audio](https://platform.openai.com/docs/guides/audio). model: ID of the model to use. See the [model endpoint compatibility](https://platform.openai.com/docs/models/model-endpoint-compatibility) @@ -853,6 +899,9 @@ async def create( compatible with [o1 series models](https://platform.openai.com/docs/guides/reasoning). + metadata: Developer-defined tags and values used for filtering completions in the + [dashboard](https://platform.openai.com/completions). + n: How many chat completion choices to generate for each input message. Note that you will be charged based on the number of generated tokens across all of the choices. Keep `n` as `1` to minimize costs. @@ -912,6 +961,9 @@ async def create( stop: Up to 4 sequences where the API will stop generating further tokens. + store: Whether or not to store the output of this completion request for traffic + logging in the [dashboard](https://platform.openai.com/completions). + stream: If set, partial message deltas will be sent, like in ChatGPT. Tokens will be sent as data-only [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format) @@ -979,6 +1031,7 @@ async def create( logprobs: Optional[bool] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, @@ -986,6 +1039,7 @@ async def create( seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str]] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, @@ -1004,8 +1058,12 @@ async def create( Creates a model response for the given chat conversation. Args: - messages: A list of messages comprising the conversation so far. - [Example Python code](https://cookbook.openai.com/examples/how_to_format_inputs_to_chatgpt_models). + messages: A list of messages comprising the conversation so far. Depending on the + [model](https://platform.openai.com/docs/models) you use, different message + types (modalities) are supported, like + [text](https://platform.openai.com/docs/guides/text-generation), + [images](https://platform.openai.com/docs/guides/vision), and + [audio](https://platform.openai.com/docs/guides/audio). model: ID of the model to use. See the [model endpoint compatibility](https://platform.openai.com/docs/models/model-endpoint-compatibility) @@ -1064,6 +1122,9 @@ async def create( compatible with [o1 series models](https://platform.openai.com/docs/guides/reasoning). + metadata: Developer-defined tags and values used for filtering completions in the + [dashboard](https://platform.openai.com/completions). + n: How many chat completion choices to generate for each input message. Note that you will be charged based on the number of generated tokens across all of the choices. Keep `n` as `1` to minimize costs. @@ -1123,6 +1184,9 @@ async def create( stop: Up to 4 sequences where the API will stop generating further tokens. + store: Whether or not to store the output of this completion request for traffic + logging in the [dashboard](https://platform.openai.com/completions). + stream_options: Options for streaming response. Only set this when you set `stream: true`. temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will @@ -1183,6 +1247,7 @@ async def create( logprobs: Optional[bool] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, @@ -1190,6 +1255,7 @@ async def create( seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str]] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, @@ -1208,8 +1274,12 @@ async def create( Creates a model response for the given chat conversation. Args: - messages: A list of messages comprising the conversation so far. - [Example Python code](https://cookbook.openai.com/examples/how_to_format_inputs_to_chatgpt_models). + messages: A list of messages comprising the conversation so far. Depending on the + [model](https://platform.openai.com/docs/models) you use, different message + types (modalities) are supported, like + [text](https://platform.openai.com/docs/guides/text-generation), + [images](https://platform.openai.com/docs/guides/vision), and + [audio](https://platform.openai.com/docs/guides/audio). model: ID of the model to use. See the [model endpoint compatibility](https://platform.openai.com/docs/models/model-endpoint-compatibility) @@ -1268,6 +1338,9 @@ async def create( compatible with [o1 series models](https://platform.openai.com/docs/guides/reasoning). + metadata: Developer-defined tags and values used for filtering completions in the + [dashboard](https://platform.openai.com/completions). + n: How many chat completion choices to generate for each input message. Note that you will be charged based on the number of generated tokens across all of the choices. Keep `n` as `1` to minimize costs. @@ -1327,6 +1400,9 @@ async def create( stop: Up to 4 sequences where the API will stop generating further tokens. + store: Whether or not to store the output of this completion request for traffic + logging in the [dashboard](https://platform.openai.com/completions). + stream_options: Options for streaming response. Only set this when you set `stream: true`. temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will @@ -1386,6 +1462,7 @@ async def create( logprobs: Optional[bool] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, @@ -1393,6 +1470,7 @@ async def create( seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str]] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -1422,6 +1500,7 @@ async def create( "logprobs": logprobs, "max_completion_tokens": max_completion_tokens, "max_tokens": max_tokens, + "metadata": metadata, "n": n, "parallel_tool_calls": parallel_tool_calls, "presence_penalty": presence_penalty, @@ -1429,6 +1508,7 @@ async def create( "seed": seed, "service_tier": service_tier, "stop": stop, + "store": store, "stream": stream, "stream_options": stream_options, "temperature": temperature, diff --git a/src/openai/types/chat/completion_create_params.py b/src/openai/types/chat/completion_create_params.py index 4ed89b00f5..3f55dfbe6e 100644 --- a/src/openai/types/chat/completion_create_params.py +++ b/src/openai/types/chat/completion_create_params.py @@ -30,7 +30,11 @@ class CompletionCreateParamsBase(TypedDict, total=False): messages: Required[Iterable[ChatCompletionMessageParam]] """A list of messages comprising the conversation so far. - [Example Python code](https://cookbook.openai.com/examples/how_to_format_inputs_to_chatgpt_models). + Depending on the [model](https://platform.openai.com/docs/models) you use, + different message types (modalities) are supported, like + [text](https://platform.openai.com/docs/guides/text-generation), + [images](https://platform.openai.com/docs/guides/vision), and + [audio](https://platform.openai.com/docs/guides/audio). """ model: Required[Union[str, ChatModel]] @@ -105,6 +109,12 @@ class CompletionCreateParamsBase(TypedDict, total=False): [o1 series models](https://platform.openai.com/docs/guides/reasoning). """ + metadata: Optional[Dict[str, str]] + """ + Developer-defined tags and values used for filtering completions in the + [dashboard](https://platform.openai.com/completions). + """ + n: Optional[int] """How many chat completion choices to generate for each input message. @@ -183,6 +193,12 @@ class CompletionCreateParamsBase(TypedDict, total=False): stop: Union[Optional[str], List[str]] """Up to 4 sequences where the API will stop generating further tokens.""" + store: Optional[bool] + """ + Whether or not to store the output of this completion request for traffic + logging in the [dashboard](https://platform.openai.com/completions). + """ + stream_options: Optional[ChatCompletionStreamOptionsParam] """Options for streaming response. Only set this when you set `stream: true`.""" diff --git a/src/openai/types/chat_model.py b/src/openai/types/chat_model.py index f8438c75c8..f2d5674786 100644 --- a/src/openai/types/chat_model.py +++ b/src/openai/types/chat_model.py @@ -12,6 +12,7 @@ "gpt-4o", "gpt-4o-2024-08-06", "gpt-4o-2024-05-13", + "gpt-4o-realtime-preview-2024-10-01", "chatgpt-4o-latest", "gpt-4o-mini", "gpt-4o-mini-2024-07-18", diff --git a/src/openai/types/completion_usage.py b/src/openai/types/completion_usage.py index a4b9116e35..fe112833e0 100644 --- a/src/openai/types/completion_usage.py +++ b/src/openai/types/completion_usage.py @@ -4,14 +4,25 @@ from .._models import BaseModel -__all__ = ["CompletionUsage", "CompletionTokensDetails"] +__all__ = ["CompletionUsage", "CompletionTokensDetails", "PromptTokensDetails"] class CompletionTokensDetails(BaseModel): + audio_tokens: Optional[int] = None + """Audio input tokens generated by the model.""" + reasoning_tokens: Optional[int] = None """Tokens generated by the model for reasoning.""" +class PromptTokensDetails(BaseModel): + audio_tokens: Optional[int] = None + """Audio input tokens present in the prompt.""" + + cached_tokens: Optional[int] = None + """Cached tokens present in the prompt.""" + + class CompletionUsage(BaseModel): completion_tokens: int """Number of tokens in the generated completion.""" @@ -24,3 +35,6 @@ class CompletionUsage(BaseModel): completion_tokens_details: Optional[CompletionTokensDetails] = None """Breakdown of tokens used in a completion.""" + + prompt_tokens_details: Optional[PromptTokensDetails] = None + """Breakdown of tokens used in the prompt.""" diff --git a/tests/api_resources/chat/test_completions.py b/tests/api_resources/chat/test_completions.py index c44703a434..8c1f263f54 100644 --- a/tests/api_resources/chat/test_completions.py +++ b/tests/api_resources/chat/test_completions.py @@ -57,6 +57,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: logprobs=True, max_completion_tokens=0, max_tokens=0, + metadata={"foo": "string"}, n=1, parallel_tool_calls=True, presence_penalty=-2, @@ -64,6 +65,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: seed=-9007199254740991, service_tier="auto", stop="string", + store=True, stream=False, stream_options={"include_usage": True}, temperature=1, @@ -178,6 +180,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: logprobs=True, max_completion_tokens=0, max_tokens=0, + metadata={"foo": "string"}, n=1, parallel_tool_calls=True, presence_penalty=-2, @@ -185,6 +188,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: seed=-9007199254740991, service_tier="auto", stop="string", + store=True, stream_options={"include_usage": True}, temperature=1, tool_choice="none", @@ -318,6 +322,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn logprobs=True, max_completion_tokens=0, max_tokens=0, + metadata={"foo": "string"}, n=1, parallel_tool_calls=True, presence_penalty=-2, @@ -325,6 +330,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn seed=-9007199254740991, service_tier="auto", stop="string", + store=True, stream=False, stream_options={"include_usage": True}, temperature=1, @@ -439,6 +445,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn logprobs=True, max_completion_tokens=0, max_tokens=0, + metadata={"foo": "string"}, n=1, parallel_tool_calls=True, presence_penalty=-2, @@ -446,6 +453,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn seed=-9007199254740991, service_tier="auto", stop="string", + store=True, stream_options={"include_usage": True}, temperature=1, tool_choice="none", diff --git a/tests/lib/chat/test_completions.py b/tests/lib/chat/test_completions.py index 7702a98d49..3cfea71f11 100644 --- a/tests/lib/chat/test_completions.py +++ b/tests/lib/chat/test_completions.py @@ -76,8 +76,9 @@ def test_parse_nothing(client: OpenAI, respx_mock: MockRouter, monkeypatch: pyte system_fingerprint='fp_b40fb1c6fb', usage=CompletionUsage( completion_tokens=37, - completion_tokens_details=CompletionTokensDetails(reasoning_tokens=0), + completion_tokens_details=CompletionTokensDetails(audio_tokens=None, reasoning_tokens=0), prompt_tokens=14, + prompt_tokens_details=None, total_tokens=51 ) ) @@ -136,8 +137,9 @@ class Location(BaseModel): system_fingerprint='fp_5050236cbd', usage=CompletionUsage( completion_tokens=14, - completion_tokens_details=CompletionTokensDetails(reasoning_tokens=0), + completion_tokens_details=CompletionTokensDetails(audio_tokens=None, reasoning_tokens=0), prompt_tokens=79, + prompt_tokens_details=None, total_tokens=93 ) ) @@ -198,8 +200,9 @@ class Location(BaseModel): system_fingerprint='fp_b40fb1c6fb', usage=CompletionUsage( completion_tokens=14, - completion_tokens_details=CompletionTokensDetails(reasoning_tokens=0), + completion_tokens_details=CompletionTokensDetails(audio_tokens=None, reasoning_tokens=0), prompt_tokens=88, + prompt_tokens_details=None, total_tokens=102 ) ) @@ -385,8 +388,9 @@ class CalendarEvent: system_fingerprint='fp_7568d46099', usage=CompletionUsage( completion_tokens=17, - completion_tokens_details=CompletionTokensDetails(reasoning_tokens=0), + completion_tokens_details=CompletionTokensDetails(audio_tokens=None, reasoning_tokens=0), prompt_tokens=92, + prompt_tokens_details=None, total_tokens=109 ) ) @@ -829,8 +833,9 @@ class Location(BaseModel): system_fingerprint='fp_5050236cbd', usage=CompletionUsage( completion_tokens=14, - completion_tokens_details=CompletionTokensDetails(reasoning_tokens=0), + completion_tokens_details=CompletionTokensDetails(audio_tokens=None, reasoning_tokens=0), prompt_tokens=79, + prompt_tokens_details=None, total_tokens=93 ) ) @@ -897,8 +902,9 @@ class Location(BaseModel): system_fingerprint='fp_5050236cbd', usage=CompletionUsage( completion_tokens=14, - completion_tokens_details=CompletionTokensDetails(reasoning_tokens=0), + completion_tokens_details=CompletionTokensDetails(audio_tokens=None, reasoning_tokens=0), prompt_tokens=79, + prompt_tokens_details=None, total_tokens=93 ) ) diff --git a/tests/lib/chat/test_completions_streaming.py b/tests/lib/chat/test_completions_streaming.py index ce402cd158..216fe9ddf5 100644 --- a/tests/lib/chat/test_completions_streaming.py +++ b/tests/lib/chat/test_completions_streaming.py @@ -155,8 +155,9 @@ def on_event(stream: ChatCompletionStream[Location], event: ChatCompletionStream system_fingerprint='fp_5050236cbd', usage=CompletionUsage( completion_tokens=14, - completion_tokens_details=CompletionTokensDetails(reasoning_tokens=0), + completion_tokens_details=CompletionTokensDetails(audio_tokens=None, reasoning_tokens=0), prompt_tokens=79, + prompt_tokens_details=None, total_tokens=93 ) ) From b7d9ce71669164a3864e170476b2846760f5e35f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 17:45:47 +0000 Subject: [PATCH 043/769] release: 1.51.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 19 +++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index b11d9e721d..3ff0a9eb32 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.50.2" + ".": "1.51.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 37571051de..8db39a51c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## 1.51.0 (2024-10-01) + +Full Changelog: [v1.50.2...v1.51.0](https://github.com/openai/openai-python/compare/v1.50.2...v1.51.0) + +### Features + +* **api:** support storing chat completions, enabling evals and model distillation in the dashboard ([2840c6d](https://github.com/openai/openai-python/commit/2840c6df94afb44cfd80efabe0405898331ee267)) + + +### Chores + +* **docs:** fix maxium typo ([#1762](https://github.com/openai/openai-python/issues/1762)) ([de94553](https://github.com/openai/openai-python/commit/de94553f93d71fc6c8187c8d3fbe924a71cc46dd)) +* **internal:** remove ds store ([47a3968](https://github.com/openai/openai-python/commit/47a3968f9b318eb02d5602f5b10e7d9e69c3ae84)) + + +### Documentation + +* **helpers:** fix method name typo ([#1764](https://github.com/openai/openai-python/issues/1764)) ([e1bcfe8](https://github.com/openai/openai-python/commit/e1bcfe86554017ac63055060153c4fd72e65c0cf)) + ## 1.50.2 (2024-09-27) Full Changelog: [v1.50.1...v1.50.2](https://github.com/openai/openai-python/compare/v1.50.1...v1.50.2) diff --git a/pyproject.toml b/pyproject.toml index 90b8c8518c..d1bffe39a9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.50.2" +version = "1.51.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 641dd21648..407f4cb969 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.50.2" # x-release-please-version +__version__ = "1.51.0" # x-release-please-version From a3001d8d91f9f991e2164671fd40cc16d495f006 Mon Sep 17 00:00:00 2001 From: Stainless Bot Date: Wed, 2 Oct 2024 19:16:58 +0000 Subject: [PATCH 044/769] docs: improve and reference contributing documentation (#1767) --- CONTRIBUTING.md | 44 ++++++++++++++++++++++++-------------------- README.md | 4 ++++ 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5a6639b8fc..37e060bdcf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,9 +2,13 @@ ### With Rye -We use [Rye](https://rye-up.com/) to manage dependencies so we highly recommend [installing it](https://rye-up.com/guide/installation/) as it will automatically provision a Python environment with the expected Python version. +We use [Rye](https://rye.astral.sh/) to manage dependencies because it will automatically provision a Python environment with the expected Python version. To set it up, run: -After installing Rye, you'll just have to run this command: +```sh +$ ./scripts/bootstrap +``` + +Or [install Rye manually](https://rye.astral.sh/guide/installation/) and run: ```sh $ rye sync --all-features @@ -39,17 +43,17 @@ modify the contents of the `src/openai/lib/` and `examples/` directories. All files in the `examples/` directory are not modified by the generator and can be freely edited or added to. -```bash +```ts # add an example to examples/.py #!/usr/bin/env -S rye run python … ``` -``` -chmod +x examples/.py +```sh +$ chmod +x examples/.py # run the example against your api -./examples/.py +$ ./examples/.py ``` ## Using the repository from source @@ -58,8 +62,8 @@ If you’d like to use the repository from source, you can either install from g To install via git: -```bash -pip install git+ssh://git@github.com/openai/openai-python.git +```sh +$ pip install git+ssh://git@github.com/openai/openai-python.git ``` Alternatively, you can build from source and install the wheel file: @@ -68,29 +72,29 @@ Building this package will create two files in the `dist/` directory, a `.tar.gz To create a distributable version of the library, all you have to do is run this command: -```bash -rye build +```sh +$ rye build # or -python -m build +$ python -m build ``` Then to install: ```sh -pip install ./path-to-wheel-file.whl +$ pip install ./path-to-wheel-file.whl ``` ## Running tests Most tests require you to [set up a mock server](https://github.com/stoplightio/prism) against the OpenAPI spec to run the tests. -```bash +```sh # you will need npm installed -npx prism mock path/to/your/openapi.yml +$ npx prism mock path/to/your/openapi.yml ``` -```bash -rye run pytest +```sh +$ ./scripts/test ``` ## Linting and formatting @@ -100,14 +104,14 @@ This repository uses [ruff](https://github.com/astral-sh/ruff) and To lint: -```bash -rye run lint +```sh +$ ./scripts/lint ``` To format and fix all ruff issues automatically: -```bash -rye run format +```sh +$ ./scripts/format ``` ## Publishing and releases diff --git a/README.md b/README.md index c47bdd54c5..dada1abfbb 100644 --- a/README.md +++ b/README.md @@ -713,3 +713,7 @@ print(openai.__version__) ## Requirements Python 3.7 or higher. + +## Contributing + +See [the contributing documentation](./CONTRIBUTING.md). From 50de514b910aced32104833acd892bebfb2cf123 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 20:04:38 +0000 Subject: [PATCH 045/769] docs: fix typo in fenced code block language (#1769) --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 37e060bdcf..52c2eb213a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -43,7 +43,7 @@ modify the contents of the `src/openai/lib/` and `examples/` directories. All files in the `examples/` directory are not modified by the generator and can be freely edited or added to. -```ts +```py # add an example to examples/.py #!/usr/bin/env -S rye run python From a7d9731bb1d79871ee4817faf0f3f558ce3d855c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 4 Oct 2024 14:39:22 +0000 Subject: [PATCH 046/769] chore(internal): add support for parsing bool response content (#1774) --- src/openai/_legacy_response.py | 3 ++ src/openai/_response.py | 3 ++ tests/test_legacy_response.py | 25 +++++++++++++++++ tests/test_response.py | 50 ++++++++++++++++++++++++++++++++++ 4 files changed, 81 insertions(+) diff --git a/src/openai/_legacy_response.py b/src/openai/_legacy_response.py index c7dbd54e23..5260e90bc1 100644 --- a/src/openai/_legacy_response.py +++ b/src/openai/_legacy_response.py @@ -258,6 +258,9 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: if cast_to == float: return cast(R, float(response.text)) + if cast_to == bool: + return cast(R, response.text.lower() == "true") + origin = get_origin(cast_to) or cast_to if inspect.isclass(origin) and issubclass(origin, HttpxBinaryResponseContent): diff --git a/src/openai/_response.py b/src/openai/_response.py index 20ce69ac8a..eac3fbae6c 100644 --- a/src/openai/_response.py +++ b/src/openai/_response.py @@ -192,6 +192,9 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: if cast_to == float: return cast(R, float(response.text)) + if cast_to == bool: + return cast(R, response.text.lower() == "true") + origin = get_origin(cast_to) or cast_to # handle the legacy binary response case diff --git a/tests/test_legacy_response.py b/tests/test_legacy_response.py index f50a77c24d..9da1a80659 100644 --- a/tests/test_legacy_response.py +++ b/tests/test_legacy_response.py @@ -34,6 +34,31 @@ def test_response_parse_mismatched_basemodel(client: OpenAI) -> None: response.parse(to=PydanticModel) +@pytest.mark.parametrize( + "content, expected", + [ + ("false", False), + ("true", True), + ("False", False), + ("True", True), + ("TrUe", True), + ("FalSe", False), + ], +) +def test_response_parse_bool(client: OpenAI, content: str, expected: bool) -> None: + response = LegacyAPIResponse( + raw=httpx.Response(200, content=content), + client=client, + stream=False, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + result = response.parse(to=bool) + assert result is expected + + def test_response_parse_custom_stream(client: OpenAI) -> None: response = LegacyAPIResponse( raw=httpx.Response(200, content=b"foo"), diff --git a/tests/test_response.py b/tests/test_response.py index e1fe332f2f..43f24c150d 100644 --- a/tests/test_response.py +++ b/tests/test_response.py @@ -237,6 +237,56 @@ async def test_async_response_parse_annotated_type(async_client: AsyncOpenAI) -> assert obj.bar == 2 +@pytest.mark.parametrize( + "content, expected", + [ + ("false", False), + ("true", True), + ("False", False), + ("True", True), + ("TrUe", True), + ("FalSe", False), + ], +) +def test_response_parse_bool(client: OpenAI, content: str, expected: bool) -> None: + response = APIResponse( + raw=httpx.Response(200, content=content), + client=client, + stream=False, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + result = response.parse(to=bool) + assert result is expected + + +@pytest.mark.parametrize( + "content, expected", + [ + ("false", False), + ("true", True), + ("False", False), + ("True", True), + ("TrUe", True), + ("FalSe", False), + ], +) +async def test_async_response_parse_bool(client: AsyncOpenAI, content: str, expected: bool) -> None: + response = AsyncAPIResponse( + raw=httpx.Response(200, content=content), + client=client, + stream=False, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + result = await response.parse(to=bool) + assert result is expected + + class OtherModel(BaseModel): a: str From 4d8fb73c8f1c0aa32364b0ab5000e1078f3a93c5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 13:52:45 +0000 Subject: [PATCH 047/769] fix(client): avoid OverflowError with very large retry counts (#1779) --- src/openai/_base_client.py | 3 ++- tests/test_client.py | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index c4c9803e74..931cbd8534 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -690,7 +690,8 @@ def _calculate_retry_timeout( if retry_after is not None and 0 < retry_after <= 60: return retry_after - nb_retries = max_retries - remaining_retries + # Also cap retry count to 1000 to avoid any potential overflows with `pow` + nb_retries = min(max_retries - remaining_retries, 1000) # Apply exponential backoff, but not more than the max. sleep_seconds = min(INITIAL_RETRY_DELAY * pow(2.0, nb_retries), MAX_RETRY_DELAY) diff --git a/tests/test_client.py b/tests/test_client.py index 463174465c..1da35ddd22 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -697,6 +697,7 @@ class Model(BaseModel): [3, "", 0.5], [2, "", 0.5 * 2.0], [1, "", 0.5 * 4.0], + [-1100, "", 7.8], # test large number potentially overflowing ], ) @mock.patch("time.time", mock.MagicMock(return_value=1696004797)) @@ -1553,6 +1554,7 @@ class Model(BaseModel): [3, "", 0.5], [2, "", 0.5 * 2.0], [1, "", 0.5 * 4.0], + [-1100, "", 7.8], # test large number potentially overflowing ], ) @mock.patch("time.time", mock.MagicMock(return_value=1696004797)) From 8467d41376c2b17eae1c78d56b39767e7807cb6f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 13:53:16 +0000 Subject: [PATCH 048/769] release: 1.51.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 19 +++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 3ff0a9eb32..3462272dee 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.51.0" + ".": "1.51.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 8db39a51c4..08b85350d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## 1.51.1 (2024-10-07) + +Full Changelog: [v1.51.0...v1.51.1](https://github.com/openai/openai-python/compare/v1.51.0...v1.51.1) + +### Bug Fixes + +* **client:** avoid OverflowError with very large retry counts ([#1779](https://github.com/openai/openai-python/issues/1779)) ([fb1dacf](https://github.com/openai/openai-python/commit/fb1dacfa4d9447d123c38ab3d3d433d900d32ec5)) + + +### Chores + +* **internal:** add support for parsing bool response content ([#1774](https://github.com/openai/openai-python/issues/1774)) ([aa2e25f](https://github.com/openai/openai-python/commit/aa2e25f9a4a632357051397ea34d269eafba026d)) + + +### Documentation + +* fix typo in fenced code block language ([#1769](https://github.com/openai/openai-python/issues/1769)) ([57bbc15](https://github.com/openai/openai-python/commit/57bbc155210cc439a36f4e5cbd082e94c3349d78)) +* improve and reference contributing documentation ([#1767](https://github.com/openai/openai-python/issues/1767)) ([a985a8b](https://github.com/openai/openai-python/commit/a985a8b8ab8d0b364bd3c26b6423a7c49ae7b1ce)) + ## 1.51.0 (2024-10-01) Full Changelog: [v1.50.2...v1.51.0](https://github.com/openai/openai-python/compare/v1.50.2...v1.51.0) diff --git a/pyproject.toml b/pyproject.toml index d1bffe39a9..41b3c18f01 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.51.0" +version = "1.51.1" 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 407f4cb969..ce7c45ab73 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.51.0" # x-release-please-version +__version__ = "1.51.1" # x-release-please-version From cfd99e7b0cb0a52769a09422dfbcbf39f3b56652 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 16:43:09 +0000 Subject: [PATCH 049/769] chore: add repr to PageInfo class (#1780) --- src/openai/_base_client.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index 931cbd8534..b2929df072 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -144,6 +144,12 @@ def __init__( self.url = url self.params = params + @override + def __repr__(self) -> str: + if self.url: + return f"{self.__class__.__name__}(url={self.url})" + return f"{self.__class__.__name__}(params={self.params})" + class BasePage(GenericModel, Generic[_T]): """ From af8e0ad8b7988e72e1d02478022d80eff4f55b91 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 8 Oct 2024 05:04:18 +0000 Subject: [PATCH 050/769] release: 1.51.2 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 3462272dee..395be07b55 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.51.1" + ".": "1.51.2" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 08b85350d7..8f583fe89f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.51.2 (2024-10-08) + +Full Changelog: [v1.51.1...v1.51.2](https://github.com/openai/openai-python/compare/v1.51.1...v1.51.2) + +### Chores + +* add repr to PageInfo class ([#1780](https://github.com/openai/openai-python/issues/1780)) ([63118ee](https://github.com/openai/openai-python/commit/63118ee3c2481d217682e8a31337bdcc16893127)) + ## 1.51.1 (2024-10-07) Full Changelog: [v1.51.0...v1.51.1](https://github.com/openai/openai-python/compare/v1.51.0...v1.51.1) diff --git a/pyproject.toml b/pyproject.toml index 41b3c18f01..8da5e0e2ce 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.51.1" +version = "1.51.2" 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 ce7c45ab73..cb98e08a8a 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.51.1" # x-release-please-version +__version__ = "1.51.2" # x-release-please-version From 550b855fe51dd3fad4e1c5c796d7c35b8e603d2f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 17 Oct 2024 16:49:46 +0000 Subject: [PATCH 051/769] feat(api): add gpt-4o-audio-preview model for chat completions (#1796) This enables audio inputs and outputs. https://platform.openai.com/docs/guides/audio --- .stats.yml | 2 +- api.md | 4 + src/openai/resources/beta/chat/completions.py | 18 ++ src/openai/resources/chat/completions.py | 207 +++++++++++++++--- .../types/beta/assistant_stream_event.py | 5 +- src/openai/types/chat/__init__.py | 6 + ...chat_completion_assistant_message_param.py | 14 +- .../types/chat/chat_completion_audio.py | 27 +++ .../types/chat/chat_completion_audio_param.py | 21 ++ ...mpletion_content_part_input_audio_param.py | 22 ++ .../chat_completion_content_part_param.py | 3 +- .../types/chat/chat_completion_message.py | 8 + .../types/chat/chat_completion_modality.py | 7 + .../types/chat/completion_create_params.py | 30 ++- src/openai/types/chat_model.py | 3 + tests/api_resources/chat/test_completions.py | 20 ++ tests/lib/chat/test_completions.py | 15 ++ tests/lib/chat/test_completions_streaming.py | 14 ++ 18 files changed, 388 insertions(+), 38 deletions(-) create mode 100644 src/openai/types/chat/chat_completion_audio.py create mode 100644 src/openai/types/chat/chat_completion_audio_param.py create mode 100644 src/openai/types/chat/chat_completion_content_part_input_audio_param.py create mode 100644 src/openai/types/chat/chat_completion_modality.py diff --git a/.stats.yml b/.stats.yml index ece287351b..984e8a8d5f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 68 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-52b934aee6468039ec7f4ce046a282b5fbce114afc708e70f17121df654f71da.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-8729aaa35436531ab453224af10e67f89677db8f350f0346bb3537489edea649.yml diff --git a/api.md b/api.md index 813c5cb615..f44169665d 100644 --- a/api.md +++ b/api.md @@ -39,9 +39,12 @@ Types: from openai.types.chat import ( ChatCompletion, ChatCompletionAssistantMessageParam, + ChatCompletionAudio, + ChatCompletionAudioParam, ChatCompletionChunk, ChatCompletionContentPart, ChatCompletionContentPartImage, + ChatCompletionContentPartInputAudio, ChatCompletionContentPartRefusal, ChatCompletionContentPartText, ChatCompletionFunctionCallOption, @@ -49,6 +52,7 @@ from openai.types.chat import ( ChatCompletionMessage, ChatCompletionMessageParam, ChatCompletionMessageToolCall, + ChatCompletionModality, ChatCompletionNamedToolChoice, ChatCompletionRole, ChatCompletionStreamOptions, diff --git a/src/openai/resources/beta/chat/completions.py b/src/openai/resources/beta/chat/completions.py index c747464072..47bcf42c16 100644 --- a/src/openai/resources/beta/chat/completions.py +++ b/src/openai/resources/beta/chat/completions.py @@ -28,7 +28,9 @@ from ....types.chat.chat_completion import ChatCompletion from ....types.chat.chat_completion_chunk import ChatCompletionChunk from ....types.chat.parsed_chat_completion import ParsedChatCompletion +from ....types.chat.chat_completion_modality import ChatCompletionModality from ....types.chat.chat_completion_tool_param import ChatCompletionToolParam +from ....types.chat.chat_completion_audio_param import ChatCompletionAudioParam from ....types.chat.chat_completion_message_param import ChatCompletionMessageParam from ....types.chat.chat_completion_stream_options_param import ChatCompletionStreamOptionsParam from ....types.chat.chat_completion_tool_choice_option_param import ChatCompletionToolChoiceOptionParam @@ -61,6 +63,7 @@ def parse( *, messages: Iterable[ChatCompletionMessageParam], model: Union[str, ChatModel], + audio: Optional[ChatCompletionAudioParam] | NotGiven = NOT_GIVEN, response_format: type[ResponseFormatT] | NotGiven = NOT_GIVEN, frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, function_call: completion_create_params.FunctionCall | NotGiven = NOT_GIVEN, @@ -70,6 +73,7 @@ def parse( max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, @@ -153,6 +157,7 @@ def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseForma { "messages": messages, "model": model, + "audio": audio, "frequency_penalty": frequency_penalty, "function_call": function_call, "functions": functions, @@ -161,6 +166,7 @@ def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseForma "max_completion_tokens": max_completion_tokens, "max_tokens": max_tokens, "metadata": metadata, + "modalities": modalities, "n": n, "parallel_tool_calls": parallel_tool_calls, "presence_penalty": presence_penalty, @@ -198,6 +204,7 @@ def stream( *, messages: Iterable[ChatCompletionMessageParam], model: Union[str, ChatModel], + audio: Optional[ChatCompletionAudioParam] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | type[ResponseFormatT] | NotGiven = NOT_GIVEN, frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, function_call: completion_create_params.FunctionCall | NotGiven = NOT_GIVEN, @@ -207,6 +214,7 @@ def stream( max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, @@ -259,6 +267,7 @@ def stream( self._client.chat.completions.create, messages=messages, model=model, + audio=audio, stream=True, response_format=_type_to_response_format(response_format), frequency_penalty=frequency_penalty, @@ -269,6 +278,7 @@ def stream( max_completion_tokens=max_completion_tokens, max_tokens=max_tokens, metadata=metadata, + modalities=modalities, n=n, parallel_tool_calls=parallel_tool_calls, presence_penalty=presence_penalty, @@ -320,6 +330,7 @@ async def parse( *, messages: Iterable[ChatCompletionMessageParam], model: Union[str, ChatModel], + audio: Optional[ChatCompletionAudioParam] | NotGiven = NOT_GIVEN, response_format: type[ResponseFormatT] | NotGiven = NOT_GIVEN, frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, function_call: completion_create_params.FunctionCall | NotGiven = NOT_GIVEN, @@ -329,6 +340,7 @@ async def parse( max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, @@ -412,6 +424,7 @@ def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseForma { "messages": messages, "model": model, + "audio": audio, "frequency_penalty": frequency_penalty, "function_call": function_call, "functions": functions, @@ -420,6 +433,7 @@ def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseForma "max_completion_tokens": max_completion_tokens, "max_tokens": max_tokens, "metadata": metadata, + "modalities": modalities, "n": n, "parallel_tool_calls": parallel_tool_calls, "presence_penalty": presence_penalty, @@ -457,6 +471,7 @@ def stream( *, messages: Iterable[ChatCompletionMessageParam], model: Union[str, ChatModel], + audio: Optional[ChatCompletionAudioParam] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | type[ResponseFormatT] | NotGiven = NOT_GIVEN, frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, function_call: completion_create_params.FunctionCall | NotGiven = NOT_GIVEN, @@ -466,6 +481,7 @@ def stream( max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, @@ -519,6 +535,7 @@ def stream( api_request = self._client.chat.completions.create( messages=messages, model=model, + audio=audio, stream=True, response_format=_type_to_response_format(response_format), frequency_penalty=frequency_penalty, @@ -529,6 +546,7 @@ def stream( max_completion_tokens=max_completion_tokens, max_tokens=max_tokens, metadata=metadata, + modalities=modalities, n=n, parallel_tool_calls=parallel_tool_calls, presence_penalty=presence_penalty, diff --git a/src/openai/resources/chat/completions.py b/src/openai/resources/chat/completions.py index c8080afaa1..ceaf3c2fec 100644 --- a/src/openai/resources/chat/completions.py +++ b/src/openai/resources/chat/completions.py @@ -20,12 +20,17 @@ from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper from ..._streaming import Stream, AsyncStream -from ...types.chat import completion_create_params +from ...types.chat import ( + ChatCompletionAudioParam, + completion_create_params, +) from ..._base_client import make_request_options from ...types.chat_model import ChatModel from ...types.chat.chat_completion import ChatCompletion from ...types.chat.chat_completion_chunk import ChatCompletionChunk +from ...types.chat.chat_completion_modality import ChatCompletionModality from ...types.chat.chat_completion_tool_param import ChatCompletionToolParam +from ...types.chat.chat_completion_audio_param import ChatCompletionAudioParam from ...types.chat.chat_completion_message_param import ChatCompletionMessageParam from ...types.chat.chat_completion_stream_options_param import ChatCompletionStreamOptionsParam from ...types.chat.chat_completion_tool_choice_option_param import ChatCompletionToolChoiceOptionParam @@ -59,6 +64,7 @@ def create( *, messages: Iterable[ChatCompletionMessageParam], model: Union[str, ChatModel], + audio: Optional[ChatCompletionAudioParam] | NotGiven = NOT_GIVEN, frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, function_call: completion_create_params.FunctionCall | NotGiven = NOT_GIVEN, functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, @@ -67,6 +73,7 @@ def create( max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, @@ -90,8 +97,12 @@ def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> ChatCompletion: - """ - Creates a model response for the given chat conversation. + """Creates a model response for the given chat conversation. + + Learn more in the + [text generation](https://platform.openai.com/docs/guides/text-generation), + [vision](https://platform.openai.com/docs/guides/vision), and + [audio](https://platform.openai.com/docs/guides/audio) guides. Args: messages: A list of messages comprising the conversation so far. Depending on the @@ -105,6 +116,10 @@ def create( [model endpoint compatibility](https://platform.openai.com/docs/models/model-endpoint-compatibility) table for details on which models work with the Chat API. + audio: Parameters for audio output. Required when audio output is requested with + `modalities: ["audio"]`. + [Learn more](https://platform.openai.com/docs/guides/audio). + frequency_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. @@ -152,7 +167,18 @@ def create( [o1 series models](https://platform.openai.com/docs/guides/reasoning). metadata: Developer-defined tags and values used for filtering completions in the - [dashboard](https://platform.openai.com/completions). + [dashboard](https://platform.openai.com/chat-completions). + + modalities: Output types that you would like the model to generate for this request. Most + models are capable of generating text, which is the default: + + `["text"]` + + The `gpt-4o-audio-preview` model can also be used to + [generate audio](https://platform.openai.com/docs/guides/audio). To request that + this model generate both text and audio responses, you can use: + + `["text", "audio"]` n: How many chat completion choices to generate for each input message. Note that you will be charged based on the number of generated tokens across all of the @@ -213,8 +239,9 @@ def create( stop: Up to 4 sequences where the API will stop generating further tokens. - store: Whether or not to store the output of this completion request for traffic - logging in the [dashboard](https://platform.openai.com/completions). + store: Whether or not to store the output of this chat completion request for use in + our [model distillation](https://platform.openai.com/docs/guides/distillation) + or [evals](https://platform.openai.com/docs/guides/evals) products. stream: If set, partial message deltas will be sent, like in ChatGPT. Tokens will be sent as data-only @@ -276,6 +303,7 @@ def create( messages: Iterable[ChatCompletionMessageParam], model: Union[str, ChatModel], stream: Literal[True], + audio: Optional[ChatCompletionAudioParam] | NotGiven = NOT_GIVEN, frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, function_call: completion_create_params.FunctionCall | NotGiven = NOT_GIVEN, functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, @@ -284,6 +312,7 @@ def create( max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, @@ -306,8 +335,12 @@ def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> Stream[ChatCompletionChunk]: - """ - Creates a model response for the given chat conversation. + """Creates a model response for the given chat conversation. + + Learn more in the + [text generation](https://platform.openai.com/docs/guides/text-generation), + [vision](https://platform.openai.com/docs/guides/vision), and + [audio](https://platform.openai.com/docs/guides/audio) guides. Args: messages: A list of messages comprising the conversation so far. Depending on the @@ -328,6 +361,10 @@ def create( message. [Example Python code](https://cookbook.openai.com/examples/how_to_stream_completions). + audio: Parameters for audio output. Required when audio output is requested with + `modalities: ["audio"]`. + [Learn more](https://platform.openai.com/docs/guides/audio). + frequency_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. @@ -375,7 +412,18 @@ def create( [o1 series models](https://platform.openai.com/docs/guides/reasoning). metadata: Developer-defined tags and values used for filtering completions in the - [dashboard](https://platform.openai.com/completions). + [dashboard](https://platform.openai.com/chat-completions). + + modalities: Output types that you would like the model to generate for this request. Most + models are capable of generating text, which is the default: + + `["text"]` + + The `gpt-4o-audio-preview` model can also be used to + [generate audio](https://platform.openai.com/docs/guides/audio). To request that + this model generate both text and audio responses, you can use: + + `["text", "audio"]` n: How many chat completion choices to generate for each input message. Note that you will be charged based on the number of generated tokens across all of the @@ -436,8 +484,9 @@ def create( stop: Up to 4 sequences where the API will stop generating further tokens. - store: Whether or not to store the output of this completion request for traffic - logging in the [dashboard](https://platform.openai.com/completions). + store: Whether or not to store the output of this chat completion request for use in + our [model distillation](https://platform.openai.com/docs/guides/distillation) + or [evals](https://platform.openai.com/docs/guides/evals) products. stream_options: Options for streaming response. Only set this when you set `stream: true`. @@ -492,6 +541,7 @@ def create( messages: Iterable[ChatCompletionMessageParam], model: Union[str, ChatModel], stream: bool, + audio: Optional[ChatCompletionAudioParam] | NotGiven = NOT_GIVEN, frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, function_call: completion_create_params.FunctionCall | NotGiven = NOT_GIVEN, functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, @@ -500,6 +550,7 @@ def create( max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, @@ -522,8 +573,12 @@ def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> ChatCompletion | Stream[ChatCompletionChunk]: - """ - Creates a model response for the given chat conversation. + """Creates a model response for the given chat conversation. + + Learn more in the + [text generation](https://platform.openai.com/docs/guides/text-generation), + [vision](https://platform.openai.com/docs/guides/vision), and + [audio](https://platform.openai.com/docs/guides/audio) guides. Args: messages: A list of messages comprising the conversation so far. Depending on the @@ -544,6 +599,10 @@ def create( message. [Example Python code](https://cookbook.openai.com/examples/how_to_stream_completions). + audio: Parameters for audio output. Required when audio output is requested with + `modalities: ["audio"]`. + [Learn more](https://platform.openai.com/docs/guides/audio). + frequency_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. @@ -591,7 +650,18 @@ def create( [o1 series models](https://platform.openai.com/docs/guides/reasoning). metadata: Developer-defined tags and values used for filtering completions in the - [dashboard](https://platform.openai.com/completions). + [dashboard](https://platform.openai.com/chat-completions). + + modalities: Output types that you would like the model to generate for this request. Most + models are capable of generating text, which is the default: + + `["text"]` + + The `gpt-4o-audio-preview` model can also be used to + [generate audio](https://platform.openai.com/docs/guides/audio). To request that + this model generate both text and audio responses, you can use: + + `["text", "audio"]` n: How many chat completion choices to generate for each input message. Note that you will be charged based on the number of generated tokens across all of the @@ -652,8 +722,9 @@ def create( stop: Up to 4 sequences where the API will stop generating further tokens. - store: Whether or not to store the output of this completion request for traffic - logging in the [dashboard](https://platform.openai.com/completions). + store: Whether or not to store the output of this chat completion request for use in + our [model distillation](https://platform.openai.com/docs/guides/distillation) + or [evals](https://platform.openai.com/docs/guides/evals) products. stream_options: Options for streaming response. Only set this when you set `stream: true`. @@ -707,6 +778,7 @@ def create( *, messages: Iterable[ChatCompletionMessageParam], model: Union[str, ChatModel], + audio: Optional[ChatCompletionAudioParam] | NotGiven = NOT_GIVEN, frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, function_call: completion_create_params.FunctionCall | NotGiven = NOT_GIVEN, functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, @@ -715,6 +787,7 @@ def create( max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, @@ -745,6 +818,7 @@ def create( { "messages": messages, "model": model, + "audio": audio, "frequency_penalty": frequency_penalty, "function_call": function_call, "functions": functions, @@ -753,6 +827,7 @@ def create( "max_completion_tokens": max_completion_tokens, "max_tokens": max_tokens, "metadata": metadata, + "modalities": modalities, "n": n, "parallel_tool_calls": parallel_tool_calls, "presence_penalty": presence_penalty, @@ -807,6 +882,7 @@ async def create( *, messages: Iterable[ChatCompletionMessageParam], model: Union[str, ChatModel], + audio: Optional[ChatCompletionAudioParam] | NotGiven = NOT_GIVEN, frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, function_call: completion_create_params.FunctionCall | NotGiven = NOT_GIVEN, functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, @@ -815,6 +891,7 @@ async def create( max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, @@ -838,8 +915,12 @@ async def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> ChatCompletion: - """ - Creates a model response for the given chat conversation. + """Creates a model response for the given chat conversation. + + Learn more in the + [text generation](https://platform.openai.com/docs/guides/text-generation), + [vision](https://platform.openai.com/docs/guides/vision), and + [audio](https://platform.openai.com/docs/guides/audio) guides. Args: messages: A list of messages comprising the conversation so far. Depending on the @@ -853,6 +934,10 @@ async def create( [model endpoint compatibility](https://platform.openai.com/docs/models/model-endpoint-compatibility) table for details on which models work with the Chat API. + audio: Parameters for audio output. Required when audio output is requested with + `modalities: ["audio"]`. + [Learn more](https://platform.openai.com/docs/guides/audio). + frequency_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. @@ -900,7 +985,18 @@ async def create( [o1 series models](https://platform.openai.com/docs/guides/reasoning). metadata: Developer-defined tags and values used for filtering completions in the - [dashboard](https://platform.openai.com/completions). + [dashboard](https://platform.openai.com/chat-completions). + + modalities: Output types that you would like the model to generate for this request. Most + models are capable of generating text, which is the default: + + `["text"]` + + The `gpt-4o-audio-preview` model can also be used to + [generate audio](https://platform.openai.com/docs/guides/audio). To request that + this model generate both text and audio responses, you can use: + + `["text", "audio"]` n: How many chat completion choices to generate for each input message. Note that you will be charged based on the number of generated tokens across all of the @@ -961,8 +1057,9 @@ async def create( stop: Up to 4 sequences where the API will stop generating further tokens. - store: Whether or not to store the output of this completion request for traffic - logging in the [dashboard](https://platform.openai.com/completions). + store: Whether or not to store the output of this chat completion request for use in + our [model distillation](https://platform.openai.com/docs/guides/distillation) + or [evals](https://platform.openai.com/docs/guides/evals) products. stream: If set, partial message deltas will be sent, like in ChatGPT. Tokens will be sent as data-only @@ -1024,6 +1121,7 @@ async def create( messages: Iterable[ChatCompletionMessageParam], model: Union[str, ChatModel], stream: Literal[True], + audio: Optional[ChatCompletionAudioParam] | NotGiven = NOT_GIVEN, frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, function_call: completion_create_params.FunctionCall | NotGiven = NOT_GIVEN, functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, @@ -1032,6 +1130,7 @@ async def create( max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, @@ -1054,8 +1153,12 @@ async def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> AsyncStream[ChatCompletionChunk]: - """ - Creates a model response for the given chat conversation. + """Creates a model response for the given chat conversation. + + Learn more in the + [text generation](https://platform.openai.com/docs/guides/text-generation), + [vision](https://platform.openai.com/docs/guides/vision), and + [audio](https://platform.openai.com/docs/guides/audio) guides. Args: messages: A list of messages comprising the conversation so far. Depending on the @@ -1076,6 +1179,10 @@ async def create( message. [Example Python code](https://cookbook.openai.com/examples/how_to_stream_completions). + audio: Parameters for audio output. Required when audio output is requested with + `modalities: ["audio"]`. + [Learn more](https://platform.openai.com/docs/guides/audio). + frequency_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. @@ -1123,7 +1230,18 @@ async def create( [o1 series models](https://platform.openai.com/docs/guides/reasoning). metadata: Developer-defined tags and values used for filtering completions in the - [dashboard](https://platform.openai.com/completions). + [dashboard](https://platform.openai.com/chat-completions). + + modalities: Output types that you would like the model to generate for this request. Most + models are capable of generating text, which is the default: + + `["text"]` + + The `gpt-4o-audio-preview` model can also be used to + [generate audio](https://platform.openai.com/docs/guides/audio). To request that + this model generate both text and audio responses, you can use: + + `["text", "audio"]` n: How many chat completion choices to generate for each input message. Note that you will be charged based on the number of generated tokens across all of the @@ -1184,8 +1302,9 @@ async def create( stop: Up to 4 sequences where the API will stop generating further tokens. - store: Whether or not to store the output of this completion request for traffic - logging in the [dashboard](https://platform.openai.com/completions). + store: Whether or not to store the output of this chat completion request for use in + our [model distillation](https://platform.openai.com/docs/guides/distillation) + or [evals](https://platform.openai.com/docs/guides/evals) products. stream_options: Options for streaming response. Only set this when you set `stream: true`. @@ -1240,6 +1359,7 @@ async def create( messages: Iterable[ChatCompletionMessageParam], model: Union[str, ChatModel], stream: bool, + audio: Optional[ChatCompletionAudioParam] | NotGiven = NOT_GIVEN, frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, function_call: completion_create_params.FunctionCall | NotGiven = NOT_GIVEN, functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, @@ -1248,6 +1368,7 @@ async def create( max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, @@ -1270,8 +1391,12 @@ async def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> ChatCompletion | AsyncStream[ChatCompletionChunk]: - """ - Creates a model response for the given chat conversation. + """Creates a model response for the given chat conversation. + + Learn more in the + [text generation](https://platform.openai.com/docs/guides/text-generation), + [vision](https://platform.openai.com/docs/guides/vision), and + [audio](https://platform.openai.com/docs/guides/audio) guides. Args: messages: A list of messages comprising the conversation so far. Depending on the @@ -1292,6 +1417,10 @@ async def create( message. [Example Python code](https://cookbook.openai.com/examples/how_to_stream_completions). + audio: Parameters for audio output. Required when audio output is requested with + `modalities: ["audio"]`. + [Learn more](https://platform.openai.com/docs/guides/audio). + frequency_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. @@ -1339,7 +1468,18 @@ async def create( [o1 series models](https://platform.openai.com/docs/guides/reasoning). metadata: Developer-defined tags and values used for filtering completions in the - [dashboard](https://platform.openai.com/completions). + [dashboard](https://platform.openai.com/chat-completions). + + modalities: Output types that you would like the model to generate for this request. Most + models are capable of generating text, which is the default: + + `["text"]` + + The `gpt-4o-audio-preview` model can also be used to + [generate audio](https://platform.openai.com/docs/guides/audio). To request that + this model generate both text and audio responses, you can use: + + `["text", "audio"]` n: How many chat completion choices to generate for each input message. Note that you will be charged based on the number of generated tokens across all of the @@ -1400,8 +1540,9 @@ async def create( stop: Up to 4 sequences where the API will stop generating further tokens. - store: Whether or not to store the output of this completion request for traffic - logging in the [dashboard](https://platform.openai.com/completions). + store: Whether or not to store the output of this chat completion request for use in + our [model distillation](https://platform.openai.com/docs/guides/distillation) + or [evals](https://platform.openai.com/docs/guides/evals) products. stream_options: Options for streaming response. Only set this when you set `stream: true`. @@ -1455,6 +1596,7 @@ async def create( *, messages: Iterable[ChatCompletionMessageParam], model: Union[str, ChatModel], + audio: Optional[ChatCompletionAudioParam] | NotGiven = NOT_GIVEN, frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, function_call: completion_create_params.FunctionCall | NotGiven = NOT_GIVEN, functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, @@ -1463,6 +1605,7 @@ async def create( max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, @@ -1493,6 +1636,7 @@ async def create( { "messages": messages, "model": model, + "audio": audio, "frequency_penalty": frequency_penalty, "function_call": function_call, "functions": functions, @@ -1501,6 +1645,7 @@ async def create( "max_completion_tokens": max_completion_tokens, "max_tokens": max_tokens, "metadata": metadata, + "modalities": modalities, "n": n, "parallel_tool_calls": parallel_tool_calls, "presence_penalty": presence_penalty, diff --git a/src/openai/types/beta/assistant_stream_event.py b/src/openai/types/beta/assistant_stream_event.py index f1d8898ff2..41d3a0c5ea 100644 --- a/src/openai/types/beta/assistant_stream_event.py +++ b/src/openai/types/beta/assistant_stream_event.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Union +from typing import Union, Optional from typing_extensions import Literal, Annotated, TypeAlias from .thread import Thread @@ -51,6 +51,9 @@ class ThreadCreated(BaseModel): event: Literal["thread.created"] + enabled: Optional[bool] = None + """Whether to enable input audio transcription.""" + class ThreadRunCreated(BaseModel): data: Run diff --git a/src/openai/types/chat/__init__.py b/src/openai/types/chat/__init__.py index a5cf3734b8..eb818a132e 100644 --- a/src/openai/types/chat/__init__.py +++ b/src/openai/types/chat/__init__.py @@ -4,6 +4,7 @@ from .chat_completion import ChatCompletion as ChatCompletion from .chat_completion_role import ChatCompletionRole as ChatCompletionRole +from .chat_completion_audio import ChatCompletionAudio as ChatCompletionAudio from .chat_completion_chunk import ChatCompletionChunk as ChatCompletionChunk from .parsed_chat_completion import ( ParsedChoice as ParsedChoice, @@ -11,12 +12,14 @@ ParsedChatCompletionMessage as ParsedChatCompletionMessage, ) from .chat_completion_message import ChatCompletionMessage as ChatCompletionMessage +from .chat_completion_modality import ChatCompletionModality as ChatCompletionModality from .completion_create_params import CompletionCreateParams as CompletionCreateParams from .parsed_function_tool_call import ( ParsedFunction as ParsedFunction, ParsedFunctionToolCall as ParsedFunctionToolCall, ) from .chat_completion_tool_param import ChatCompletionToolParam as ChatCompletionToolParam +from .chat_completion_audio_param import ChatCompletionAudioParam as ChatCompletionAudioParam from .chat_completion_message_param import ChatCompletionMessageParam as ChatCompletionMessageParam from .chat_completion_token_logprob import ChatCompletionTokenLogprob as ChatCompletionTokenLogprob from .chat_completion_message_tool_call import ChatCompletionMessageToolCall as ChatCompletionMessageToolCall @@ -52,3 +55,6 @@ from .chat_completion_function_call_option_param import ( ChatCompletionFunctionCallOptionParam as ChatCompletionFunctionCallOptionParam, ) +from .chat_completion_content_part_input_audio_param import ( + ChatCompletionContentPartInputAudioParam as ChatCompletionContentPartInputAudioParam, +) diff --git a/src/openai/types/chat/chat_completion_assistant_message_param.py b/src/openai/types/chat/chat_completion_assistant_message_param.py index 2429d41d33..35e3a3d784 100644 --- a/src/openai/types/chat/chat_completion_assistant_message_param.py +++ b/src/openai/types/chat/chat_completion_assistant_message_param.py @@ -9,7 +9,13 @@ from .chat_completion_message_tool_call_param import ChatCompletionMessageToolCallParam from .chat_completion_content_part_refusal_param import ChatCompletionContentPartRefusalParam -__all__ = ["ChatCompletionAssistantMessageParam", "ContentArrayOfContentPart", "FunctionCall"] +__all__ = ["ChatCompletionAssistantMessageParam", "Audio", "ContentArrayOfContentPart", "FunctionCall"] + + +class Audio(TypedDict, total=False): + id: Required[str] + """Unique identifier for a previous audio response from the model.""" + ContentArrayOfContentPart: TypeAlias = Union[ChatCompletionContentPartTextParam, ChatCompletionContentPartRefusalParam] @@ -31,6 +37,12 @@ class ChatCompletionAssistantMessageParam(TypedDict, total=False): role: Required[Literal["assistant"]] """The role of the messages author, in this case `assistant`.""" + audio: Optional[Audio] + """Data about a previous audio response from the model. + + [Learn more](https://platform.openai.com/docs/guides/audio). + """ + content: Union[str, Iterable[ContentArrayOfContentPart], None] """The contents of the assistant message. diff --git a/src/openai/types/chat/chat_completion_audio.py b/src/openai/types/chat/chat_completion_audio.py new file mode 100644 index 0000000000..135ee8845c --- /dev/null +++ b/src/openai/types/chat/chat_completion_audio.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + + + +from ..._models import BaseModel + +__all__ = ["ChatCompletionAudio"] + + +class ChatCompletionAudio(BaseModel): + id: str + """Unique identifier for this audio response.""" + + data: str + """ + Base64 encoded audio bytes generated by the model, in the format specified in + the request. + """ + + expires_at: int + """ + The Unix timestamp (in seconds) for when this audio response will no longer be + accessible on the server for use in multi-turn conversations. + """ + + transcript: str + """Transcript of the audio generated by the model.""" diff --git a/src/openai/types/chat/chat_completion_audio_param.py b/src/openai/types/chat/chat_completion_audio_param.py new file mode 100644 index 0000000000..6a4ce9ac1f --- /dev/null +++ b/src/openai/types/chat/chat_completion_audio_param.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ChatCompletionAudioParam"] + + +class ChatCompletionAudioParam(TypedDict, total=False): + format: Required[Literal["wav", "mp3", "flac", "opus", "pcm16"]] + """Specifies the output audio format. + + Must be one of `wav`, `mp3`, `flac`, `opus`, or `pcm16`. + """ + + voice: Required[Literal["alloy", "echo", "fable", "onyx", "nova", "shimmer"]] + """Specifies the voice type. + + Supported voices are `alloy`, `echo`, `fable`, `onyx`, `nova`, and `shimmer`. + """ diff --git a/src/openai/types/chat/chat_completion_content_part_input_audio_param.py b/src/openai/types/chat/chat_completion_content_part_input_audio_param.py new file mode 100644 index 0000000000..0b1b1a80b1 --- /dev/null +++ b/src/openai/types/chat/chat_completion_content_part_input_audio_param.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ChatCompletionContentPartInputAudioParam", "InputAudio"] + + +class InputAudio(TypedDict, total=False): + data: Required[str] + """Base64 encoded audio data.""" + + format: Required[Literal["wav", "mp3"]] + """The format of the encoded audio data. Currently supports "wav" and "mp3".""" + + +class ChatCompletionContentPartInputAudioParam(TypedDict, total=False): + input_audio: Required[InputAudio] + + type: Required[Literal["input_audio"]] + """The type of the content part. Always `input_audio`.""" diff --git a/src/openai/types/chat/chat_completion_content_part_param.py b/src/openai/types/chat/chat_completion_content_part_param.py index e0c6e480f2..682d11f4c7 100644 --- a/src/openai/types/chat/chat_completion_content_part_param.py +++ b/src/openai/types/chat/chat_completion_content_part_param.py @@ -7,9 +7,10 @@ from .chat_completion_content_part_text_param import ChatCompletionContentPartTextParam from .chat_completion_content_part_image_param import ChatCompletionContentPartImageParam +from .chat_completion_content_part_input_audio_param import ChatCompletionContentPartInputAudioParam __all__ = ["ChatCompletionContentPartParam"] ChatCompletionContentPartParam: TypeAlias = Union[ - ChatCompletionContentPartTextParam, ChatCompletionContentPartImageParam + ChatCompletionContentPartTextParam, ChatCompletionContentPartImageParam, ChatCompletionContentPartInputAudioParam ] diff --git a/src/openai/types/chat/chat_completion_message.py b/src/openai/types/chat/chat_completion_message.py index 492bb68c85..704fa5d5d1 100644 --- a/src/openai/types/chat/chat_completion_message.py +++ b/src/openai/types/chat/chat_completion_message.py @@ -4,6 +4,7 @@ from typing_extensions import Literal from ..._models import BaseModel +from .chat_completion_audio import ChatCompletionAudio from .chat_completion_message_tool_call import ChatCompletionMessageToolCall __all__ = ["ChatCompletionMessage", "FunctionCall"] @@ -32,6 +33,13 @@ class ChatCompletionMessage(BaseModel): role: Literal["assistant"] """The role of the author of this message.""" + audio: Optional[ChatCompletionAudio] = None + """ + If the audio output modality is requested, this object contains data about the + audio response from the model. + [Learn more](https://platform.openai.com/docs/guides/audio). + """ + function_call: Optional[FunctionCall] = None """Deprecated and replaced by `tool_calls`. diff --git a/src/openai/types/chat/chat_completion_modality.py b/src/openai/types/chat/chat_completion_modality.py new file mode 100644 index 0000000000..8e3c145979 --- /dev/null +++ b/src/openai/types/chat/chat_completion_modality.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["ChatCompletionModality"] + +ChatCompletionModality: TypeAlias = Literal["text", "audio"] diff --git a/src/openai/types/chat/completion_create_params.py b/src/openai/types/chat/completion_create_params.py index 3f55dfbe6e..af6a47c219 100644 --- a/src/openai/types/chat/completion_create_params.py +++ b/src/openai/types/chat/completion_create_params.py @@ -6,7 +6,9 @@ from typing_extensions import Literal, Required, TypeAlias, TypedDict from ..chat_model import ChatModel +from .chat_completion_modality import ChatCompletionModality from .chat_completion_tool_param import ChatCompletionToolParam +from .chat_completion_audio_param import ChatCompletionAudioParam from .chat_completion_message_param import ChatCompletionMessageParam from ..shared_params.function_parameters import FunctionParameters from ..shared_params.response_format_text import ResponseFormatText @@ -45,6 +47,13 @@ class CompletionCreateParamsBase(TypedDict, total=False): table for details on which models work with the Chat API. """ + audio: Optional[ChatCompletionAudioParam] + """Parameters for audio output. + + Required when audio output is requested with `modalities: ["audio"]`. + [Learn more](https://platform.openai.com/docs/guides/audio). + """ + frequency_penalty: Optional[float] """Number between -2.0 and 2.0. @@ -112,7 +121,21 @@ class CompletionCreateParamsBase(TypedDict, total=False): metadata: Optional[Dict[str, str]] """ Developer-defined tags and values used for filtering completions in the - [dashboard](https://platform.openai.com/completions). + [dashboard](https://platform.openai.com/chat-completions). + """ + + modalities: Optional[List[ChatCompletionModality]] + """ + Output types that you would like the model to generate for this request. Most + models are capable of generating text, which is the default: + + `["text"]` + + The `gpt-4o-audio-preview` model can also be used to + [generate audio](https://platform.openai.com/docs/guides/audio). To request that + this model generate both text and audio responses, you can use: + + `["text", "audio"]` """ n: Optional[int] @@ -195,8 +218,9 @@ class CompletionCreateParamsBase(TypedDict, total=False): store: Optional[bool] """ - Whether or not to store the output of this completion request for traffic - logging in the [dashboard](https://platform.openai.com/completions). + Whether or not to store the output of this chat completion request for use in + our [model distillation](https://platform.openai.com/docs/guides/distillation) + or [evals](https://platform.openai.com/docs/guides/evals) products. """ stream_options: Optional[ChatCompletionStreamOptionsParam] diff --git a/src/openai/types/chat_model.py b/src/openai/types/chat_model.py index f2d5674786..b801aa0914 100644 --- a/src/openai/types/chat_model.py +++ b/src/openai/types/chat_model.py @@ -12,7 +12,10 @@ "gpt-4o", "gpt-4o-2024-08-06", "gpt-4o-2024-05-13", + "gpt-4o-realtime-preview", "gpt-4o-realtime-preview-2024-10-01", + "gpt-4o-audio-preview", + "gpt-4o-audio-preview-2024-10-01", "chatgpt-4o-latest", "gpt-4o-mini", "gpt-4o-mini-2024-07-18", diff --git a/tests/api_resources/chat/test_completions.py b/tests/api_resources/chat/test_completions.py index 8c1f263f54..d7162dc7db 100644 --- a/tests/api_resources/chat/test_completions.py +++ b/tests/api_resources/chat/test_completions.py @@ -44,6 +44,10 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: } ], model="gpt-4o", + audio={ + "format": "wav", + "voice": "alloy", + }, frequency_penalty=-2, function_call="none", functions=[ @@ -58,6 +62,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: max_completion_tokens=0, max_tokens=0, metadata={"foo": "string"}, + modalities=["text", "audio"], n=1, parallel_tool_calls=True, presence_penalty=-2, @@ -167,6 +172,10 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: ], model="gpt-4o", stream=True, + audio={ + "format": "wav", + "voice": "alloy", + }, frequency_penalty=-2, function_call="none", functions=[ @@ -181,6 +190,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: max_completion_tokens=0, max_tokens=0, metadata={"foo": "string"}, + modalities=["text", "audio"], n=1, parallel_tool_calls=True, presence_penalty=-2, @@ -309,6 +319,10 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn } ], model="gpt-4o", + audio={ + "format": "wav", + "voice": "alloy", + }, frequency_penalty=-2, function_call="none", functions=[ @@ -323,6 +337,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn max_completion_tokens=0, max_tokens=0, metadata={"foo": "string"}, + modalities=["text", "audio"], n=1, parallel_tool_calls=True, presence_penalty=-2, @@ -432,6 +447,10 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn ], model="gpt-4o", stream=True, + audio={ + "format": "wav", + "voice": "alloy", + }, frequency_penalty=-2, function_call="none", functions=[ @@ -446,6 +465,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn max_completion_tokens=0, max_tokens=0, metadata={"foo": "string"}, + modalities=["text", "audio"], n=1, parallel_tool_calls=True, presence_penalty=-2, diff --git a/tests/lib/chat/test_completions.py b/tests/lib/chat/test_completions.py index 3cfea71f11..5cd7b1ee53 100644 --- a/tests/lib/chat/test_completions.py +++ b/tests/lib/chat/test_completions.py @@ -58,6 +58,7 @@ def test_parse_nothing(client: OpenAI, respx_mock: MockRouter, monkeypatch: pyte index=0, logprobs=None, message=ParsedChatCompletionMessage[NoneType]( + audio=None, content="I'm unable to provide real-time weather updates. To get the current weather in San Francisco, I recommend checking a reliable weather website or app like the Weather Channel or a local news station.", function_call=None, @@ -120,6 +121,7 @@ class Location(BaseModel): index=0, logprobs=None, message=ParsedChatCompletionMessage[Location]( + audio=None, content='{"city":"San Francisco","temperature":65,"units":"f"}', function_call=None, parsed=Location(city='San Francisco', temperature=65.0, units='f'), @@ -183,6 +185,7 @@ class Location(BaseModel): index=0, logprobs=None, message=ParsedChatCompletionMessage[Location]( + audio=None, content='{"city":"San Francisco","temperature":65,"units":"f"}', function_call=None, parsed=Location(city='San Francisco', temperature=65.0, units='f'), @@ -248,6 +251,7 @@ class ColorDetection(BaseModel): index=0, logprobs=None, message=ParsedChatCompletionMessage[ColorDetection]( + audio=None, content='{"color":"red","hex_color_code":"#FF0000"}', function_call=None, parsed=ColorDetection(color=, hex_color_code='#FF0000'), @@ -296,6 +300,7 @@ class Location(BaseModel): index=0, logprobs=None, message=ParsedChatCompletionMessage[Location]( + audio=None, content='{"city":"San Francisco","temperature":64,"units":"f"}', function_call=None, parsed=Location(city='San Francisco', temperature=64.0, units='f'), @@ -309,6 +314,7 @@ class Location(BaseModel): index=1, logprobs=None, message=ParsedChatCompletionMessage[Location]( + audio=None, content='{"city":"San Francisco","temperature":65,"units":"f"}', function_call=None, parsed=Location(city='San Francisco', temperature=65.0, units='f'), @@ -322,6 +328,7 @@ class Location(BaseModel): index=2, logprobs=None, message=ParsedChatCompletionMessage[Location]( + audio=None, content='{"city":"San Francisco","temperature":63.0,"units":"f"}', function_call=None, parsed=Location(city='San Francisco', temperature=63.0, units='f'), @@ -371,6 +378,7 @@ class CalendarEvent: index=0, logprobs=None, message=ParsedChatCompletionMessage[CalendarEvent]( + audio=None, content='{"name":"Science Fair","date":"Friday","participants":["Alice","Bob"]}', function_call=None, parsed=CalendarEvent(name='Science Fair', date='Friday', participants=['Alice', 'Bob']), @@ -426,6 +434,7 @@ def test_pydantic_tool_model_all_types(client: OpenAI, respx_mock: MockRouter, m index=0, logprobs=None, message=ParsedChatCompletionMessage[Query]( + audio=None, content=None, function_call=None, parsed=None, @@ -536,6 +545,7 @@ class Location(BaseModel): index=0, logprobs=None, message=ParsedChatCompletionMessage[Location]( + audio=None, content=None, function_call=None, parsed=None, @@ -584,6 +594,7 @@ class GetWeatherArgs(BaseModel): index=0, logprobs=None, message=ParsedChatCompletionMessage[NoneType]( + audio=None, content=None, function_call=None, parsed=None, @@ -655,6 +666,7 @@ class GetStockPrice(BaseModel): index=0, logprobs=None, message=ParsedChatCompletionMessage[NoneType]( + audio=None, content=None, function_call=None, parsed=None, @@ -735,6 +747,7 @@ def test_parse_strict_tools(client: OpenAI, respx_mock: MockRouter, monkeypatch: index=0, logprobs=None, message=ParsedChatCompletionMessage[NoneType]( + audio=None, content=None, function_call=None, parsed=None, @@ -816,6 +829,7 @@ class Location(BaseModel): index=0, logprobs=None, message=ParsedChatCompletionMessage[Location]( + audio=None, content='{"city":"San Francisco","temperature":58,"units":"f"}', function_call=None, parsed=Location(city='San Francisco', temperature=58.0, units='f'), @@ -885,6 +899,7 @@ class Location(BaseModel): index=0, logprobs=None, message=ParsedChatCompletionMessage[Location]( + audio=None, content='{"city":"San Francisco","temperature":65,"units":"f"}', function_call=None, parsed=Location(city='San Francisco', temperature=65.0, units='f'), diff --git a/tests/lib/chat/test_completions_streaming.py b/tests/lib/chat/test_completions_streaming.py index 216fe9ddf5..2846e6d2c3 100644 --- a/tests/lib/chat/test_completions_streaming.py +++ b/tests/lib/chat/test_completions_streaming.py @@ -61,6 +61,7 @@ def test_parse_nothing(client: OpenAI, respx_mock: MockRouter, monkeypatch: pyte index=0, logprobs=None, message=ParsedChatCompletionMessage[NoneType]( + audio=None, content="I'm unable to provide real-time weather updates. To get the current weather in San Francisco, I recommend checking a reliable weather website or a weather app.", function_call=None, @@ -138,6 +139,7 @@ def on_event(stream: ChatCompletionStream[Location], event: ChatCompletionStream index=0, logprobs=None, message=ParsedChatCompletionMessage[Location]( + audio=None, content='{"city":"San Francisco","temperature":61,"units":"f"}', function_call=None, parsed=Location(city='San Francisco', temperature=61.0, units='f'), @@ -309,6 +311,7 @@ class Location(BaseModel): index=0, logprobs=None, message=ParsedChatCompletionMessage[Location]( + audio=None, content='{"city":"San Francisco","temperature":65,"units":"f"}', function_call=None, parsed=Location(city='San Francisco', temperature=65.0, units='f'), @@ -322,6 +325,7 @@ class Location(BaseModel): index=1, logprobs=None, message=ParsedChatCompletionMessage[Location]( + audio=None, content='{"city":"San Francisco","temperature":61,"units":"f"}', function_call=None, parsed=Location(city='San Francisco', temperature=61.0, units='f'), @@ -335,6 +339,7 @@ class Location(BaseModel): index=2, logprobs=None, message=ParsedChatCompletionMessage[Location]( + audio=None, content='{"city":"San Francisco","temperature":59,"units":"f"}', function_call=None, parsed=Location(city='San Francisco', temperature=59.0, units='f'), @@ -409,6 +414,7 @@ class Location(BaseModel): index=0, logprobs=None, message=ParsedChatCompletionMessage[Location]( + audio=None, content=None, function_call=None, parsed=None, @@ -482,6 +488,7 @@ def test_content_logprobs_events(client: OpenAI, respx_mock: MockRouter, monkeyp refusal=None ), message=ParsedChatCompletionMessage[NoneType]( + audio=None, content='Foo!', function_call=None, parsed=None, @@ -592,6 +599,7 @@ class Location(BaseModel): ] ), message=ParsedChatCompletionMessage[Location]( + audio=None, content=None, function_call=None, parsed=None, @@ -637,6 +645,7 @@ class GetWeatherArgs(BaseModel): index=0, logprobs=None, message=ParsedChatCompletionMessage[object]( + audio=None, content=None, function_call=None, parsed=None, @@ -668,6 +677,7 @@ class GetWeatherArgs(BaseModel): index=0, logprobs=None, message=ParsedChatCompletionMessage[NoneType]( + audio=None, content=None, function_call=None, parsed=None, @@ -738,6 +748,7 @@ class GetStockPrice(BaseModel): index=0, logprobs=None, message=ParsedChatCompletionMessage[object]( + audio=None, content=None, function_call=None, parsed=None, @@ -845,6 +856,7 @@ def test_parse_strict_tools(client: OpenAI, respx_mock: MockRouter, monkeypatch: index=0, logprobs=None, message=ParsedChatCompletionMessage[object]( + audio=None, content=None, function_call=None, parsed=None, @@ -895,6 +907,7 @@ def test_non_pydantic_response_format(client: OpenAI, respx_mock: MockRouter, mo index=0, logprobs=None, message=ParsedChatCompletionMessage[NoneType]( + audio=None, content='\\n {\\n "location": "San Francisco, CA",\\n "weather": {\\n "temperature": "18°C",\\n "condition": "Partly Cloudy",\\n "humidity": "72%",\\n "windSpeed": "15 km/h",\\n "windDirection": "NW"\\n },\\n "forecast": [\\n {\\n "day": "Monday",\\n "high": "20°C",\\n "low": "14°C",\\n @@ -954,6 +967,7 @@ def test_allows_non_strict_tools_but_no_parsing( index=0, logprobs=None, message=ParsedChatCompletionMessage[NoneType]( + audio=None, content=None, function_call=None, parsed=None, From fc4fce30aff7620c32e57301d3c40b4883810825 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 17 Oct 2024 16:51:33 +0000 Subject: [PATCH 052/769] release: 1.52.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 395be07b55..37d774d68f 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.51.2" + ".": "1.52.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f583fe89f..55691f3fd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.52.0 (2024-10-17) + +Full Changelog: [v1.51.2...v1.52.0](https://github.com/openai/openai-python/compare/v1.51.2...v1.52.0) + +### Features + +* **api:** add gpt-4o-audio-preview model for chat completions ([#1796](https://github.com/openai/openai-python/issues/1796)) ([fbf1e0c](https://github.com/openai/openai-python/commit/fbf1e0c25c4d163f06b61a43d1a94ce001033a7b)) + ## 1.51.2 (2024-10-08) Full Changelog: [v1.51.1...v1.51.2](https://github.com/openai/openai-python/compare/v1.51.1...v1.51.2) diff --git a/pyproject.toml b/pyproject.toml index 8da5e0e2ce..490685d76d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.51.2" +version = "1.52.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 cb98e08a8a..cb5e5ffd0d 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.51.2" # x-release-please-version +__version__ = "1.52.0" # x-release-please-version From 8b5176139e93820d88f89e765685257f175bf77f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 17 Oct 2024 17:40:28 +0000 Subject: [PATCH 053/769] chore(internal): update test syntax (#1798) --- tests/test_models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_models.py b/tests/test_models.py index b703444248..117a90020e 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -245,7 +245,7 @@ class Model(BaseModel): assert m.foo is True m = Model.construct(foo="CARD_HOLDER") - assert m.foo is "CARD_HOLDER" + assert m.foo == "CARD_HOLDER" m = Model.construct(foo={"bar": False}) assert isinstance(m.foo, Submodel1) From 38d87a3d50b00d460401bb5c7ce023102f843d16 Mon Sep 17 00:00:00 2001 From: Stainless Bot Date: Fri, 18 Oct 2024 18:16:03 +0000 Subject: [PATCH 054/769] chore(internal): bump ruff dependency (#1801) --- pyproject.toml | 3 ++- requirements-dev.lock | 2 +- src/openai/types/chat/chat_completion_audio.py | 1 - 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 490685d76d..900fbdda8c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -74,11 +74,12 @@ format = { chain = [ "format:ruff", "format:docs", "fix:ruff", + # run formatting again to fix any inconsistencies when imports are stripped + "format:ruff", ]} "format:black" = "black ." "format:docs" = "python scripts/utils/ruffen-docs.py README.md api.md" "format:ruff" = "ruff format" -"format:isort" = "isort ." "lint" = { chain = [ "check:ruff", diff --git a/requirements-dev.lock b/requirements-dev.lock index a47de9656a..902a80c6ed 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -141,7 +141,7 @@ requests==2.31.0 respx==0.20.2 rich==13.7.1 # via inline-snapshot -ruff==0.6.5 +ruff==0.6.9 setuptools==68.2.2 # via nodeenv six==1.16.0 diff --git a/src/openai/types/chat/chat_completion_audio.py b/src/openai/types/chat/chat_completion_audio.py index 135ee8845c..dd15508ebb 100644 --- a/src/openai/types/chat/chat_completion_audio.py +++ b/src/openai/types/chat/chat_completion_audio.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from ..._models import BaseModel __all__ = ["ChatCompletionAudio"] From a366120a4ef9b0865a039230161a6f7ee0885ff5 Mon Sep 17 00:00:00 2001 From: fzyzcjy <5236035+fzyzcjy@users.noreply.github.com> Date: Mon, 21 Oct 2024 14:43:12 +0800 Subject: [PATCH 055/769] fix(client/async): correctly retry in all cases (#1803) --- src/openai/_base_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index b2929df072..e1d4849ae2 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -1591,7 +1591,7 @@ async def _request( except Exception as err: log.debug("Encountered Exception", exc_info=True) - if retries_taken > 0: + if remaining_retries > 0: return await self._retry_request( input_options, cast_to, From 6634f5250c98a2487a29458e997c6f9e9ee66e02 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 07:23:51 +0000 Subject: [PATCH 056/769] chore(tests): add more retry tests (#1806) --- tests/test_client.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/tests/test_client.py b/tests/test_client.py index 1da35ddd22..ff07ec393b 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -10,6 +10,7 @@ import tracemalloc from typing import Any, Union, cast from unittest import mock +from typing_extensions import Literal import httpx import pytest @@ -764,7 +765,14 @@ def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter) -> Non @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - def test_retries_taken(self, client: OpenAI, failures_before_success: int, respx_mock: MockRouter) -> None: + @pytest.mark.parametrize("failure_mode", ["status", "exception"]) + def test_retries_taken( + self, + client: OpenAI, + failures_before_success: int, + failure_mode: Literal["status", "exception"], + respx_mock: MockRouter, + ) -> None: client = client.with_options(max_retries=4) nb_retries = 0 @@ -773,6 +781,8 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: nonlocal nb_retries if nb_retries < failures_before_success: nb_retries += 1 + if failure_mode == "exception": + raise RuntimeError("oops") return httpx.Response(500) return httpx.Response(200) @@ -1623,8 +1633,13 @@ async def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter) @mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) @pytest.mark.asyncio + @pytest.mark.parametrize("failure_mode", ["status", "exception"]) async def test_retries_taken( - self, async_client: AsyncOpenAI, failures_before_success: int, respx_mock: MockRouter + self, + async_client: AsyncOpenAI, + failures_before_success: int, + failure_mode: Literal["status", "exception"], + respx_mock: MockRouter, ) -> None: client = async_client.with_options(max_retries=4) @@ -1634,6 +1649,8 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: nonlocal nb_retries if nb_retries < failures_before_success: nb_retries += 1 + if failure_mode == "exception": + raise RuntimeError("oops") return httpx.Response(500) return httpx.Response(200) From b186bc5786b75fb06260eadc32581438c0e61ea1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 11:54:15 +0000 Subject: [PATCH 057/769] chore(internal): remove unused black config (#1807) --- pyproject.toml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 900fbdda8c..4de8d3889b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -77,7 +77,6 @@ format = { chain = [ # run formatting again to fix any inconsistencies when imports are stripped "format:ruff", ]} -"format:black" = "black ." "format:docs" = "python scripts/utils/ruffen-docs.py README.md api.md" "format:ruff" = "ruff format" @@ -137,10 +136,6 @@ path = "README.md" pattern = '\[(.+?)\]\(((?!https?://)\S+?)\)' replacement = '[\1](https://github.com/openai/openai-python/tree/main/\g<2>)' -[tool.black] -line-length = 120 -target-version = ["py37"] - [tool.pytest.ini_options] testpaths = ["tests"] addopts = "--tb=short" From 73d20deb4792c13cbbf1861aef31c9a1123568d8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 22 Oct 2024 18:24:19 +0000 Subject: [PATCH 058/769] chore(internal): update spec version (#1810) --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 984e8a8d5f..e1a430e50a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 68 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-8729aaa35436531ab453224af10e67f89677db8f350f0346bb3537489edea649.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-f9320ebf347140052c7f8b0bc5c7db24f5e367c368c8cb34c3606af4e2b6591b.yml From 262f163cf19f22f45c493de0238a77c9e39f9e0a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 22 Oct 2024 18:24:50 +0000 Subject: [PATCH 059/769] release: 1.52.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 17 +++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 37d774d68f..89493ef540 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.52.0" + ".": "1.52.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 55691f3fd7..c00cc6e66d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # Changelog +## 1.52.1 (2024-10-22) + +Full Changelog: [v1.52.0...v1.52.1](https://github.com/openai/openai-python/compare/v1.52.0...v1.52.1) + +### Bug Fixes + +* **client/async:** correctly retry in all cases ([#1803](https://github.com/openai/openai-python/issues/1803)) ([9fe3f3f](https://github.com/openai/openai-python/commit/9fe3f3f925e06769b7ef6abbf1314a5e82749b4a)) + + +### Chores + +* **internal:** bump ruff dependency ([#1801](https://github.com/openai/openai-python/issues/1801)) ([859c672](https://github.com/openai/openai-python/commit/859c6725865f1b3285698f68693f9491d511f7ea)) +* **internal:** remove unused black config ([#1807](https://github.com/openai/openai-python/issues/1807)) ([112dab0](https://github.com/openai/openai-python/commit/112dab0290342654265db612c37d327d652251bb)) +* **internal:** update spec version ([#1810](https://github.com/openai/openai-python/issues/1810)) ([aa25b7b](https://github.com/openai/openai-python/commit/aa25b7b88823836b418a63da59491f5f3842773c)) +* **internal:** update test syntax ([#1798](https://github.com/openai/openai-python/issues/1798)) ([d3098dd](https://github.com/openai/openai-python/commit/d3098dd0b9fbe627c21a8ad39c119d125b7cdb54)) +* **tests:** add more retry tests ([#1806](https://github.com/openai/openai-python/issues/1806)) ([5525a1b](https://github.com/openai/openai-python/commit/5525a1ba536058ecc13411e1f98e88f7ec4bf8b9)) + ## 1.52.0 (2024-10-17) Full Changelog: [v1.51.2...v1.52.0](https://github.com/openai/openai-python/compare/v1.51.2...v1.52.0) diff --git a/pyproject.toml b/pyproject.toml index 4de8d3889b..3ebb38343e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.52.0" +version = "1.52.1" 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 cb5e5ffd0d..a027560c44 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.52.0" # x-release-please-version +__version__ = "1.52.1" # x-release-please-version From 865e390b537405ff16019ecac141eda9fd3a2a09 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 23 Oct 2024 21:57:02 +0000 Subject: [PATCH 060/769] chore(internal): update spec version (#1816) --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index e1a430e50a..0b08725565 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 68 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-f9320ebf347140052c7f8b0bc5c7db24f5e367c368c8cb34c3606af4e2b6591b.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-b60d5559d5150ecd3b49136064e5e251d832899770ff385b711378389afba370.yml From e1b2f8216cc69e802475a0d438e40e0e74510de4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 23 Oct 2024 21:57:32 +0000 Subject: [PATCH 061/769] release: 1.52.2 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 89493ef540..2f2a30a82e 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.52.1" + ".": "1.52.2" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index c00cc6e66d..21f6136744 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.52.2 (2024-10-23) + +Full Changelog: [v1.52.1...v1.52.2](https://github.com/openai/openai-python/compare/v1.52.1...v1.52.2) + +### Chores + +* **internal:** update spec version ([#1816](https://github.com/openai/openai-python/issues/1816)) ([c23282a](https://github.com/openai/openai-python/commit/c23282a328c48af90a88673ff5f6cc7a866f8758)) + ## 1.52.1 (2024-10-22) Full Changelog: [v1.52.0...v1.52.1](https://github.com/openai/openai-python/compare/v1.52.0...v1.52.1) diff --git a/pyproject.toml b/pyproject.toml index 3ebb38343e..3bd6246e43 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.52.1" +version = "1.52.2" 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 a027560c44..641d4f5b30 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.52.1" # x-release-please-version +__version__ = "1.52.2" # x-release-please-version From 44ac1cef62316cc6c4548eb2007a93de9ddb6825 Mon Sep 17 00:00:00 2001 From: Stainless Bot Date: Mon, 28 Oct 2024 12:28:17 +0000 Subject: [PATCH 062/769] chore(internal): bump pytest to v8 & pydantic (#1829) --- requirements-dev.lock | 43 +++++++++---------- requirements.lock | 18 ++++---- src/openai/_compat.py | 2 +- src/openai/_models.py | 10 ++--- src/openai/_types.py | 6 ++- src/openai/lib/streaming/chat/_completions.py | 18 +++++--- tests/conftest.py | 14 +++--- tests/lib/test_old_api.py | 2 +- 8 files changed, 60 insertions(+), 53 deletions(-) diff --git a/requirements-dev.lock b/requirements-dev.lock index 902a80c6ed..2df8a39c76 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -18,14 +18,13 @@ argcomplete==3.1.2 # via nox asttokens==2.4.1 # via inline-snapshot -attrs==23.1.0 +attrs==24.2.0 # via outcome - # via pytest # via trio -azure-core==1.30.1 +azure-core==1.31.0 # via azure-identity -azure-identity==1.15.0 -black==24.4.2 +azure-identity==1.19.0 +black==24.10.0 # via inline-snapshot certifi==2023.7.22 # via httpcore @@ -49,10 +48,11 @@ distlib==0.3.7 # via virtualenv distro==1.8.0 # via openai -exceptiongroup==1.1.3 +exceptiongroup==1.2.2 # via anyio + # via pytest # via trio -executing==2.0.1 +executing==2.1.0 # via inline-snapshot filelock==3.12.4 # via virtualenv @@ -78,7 +78,7 @@ markdown-it-py==3.0.0 # via rich mdurl==0.1.2 # via markdown-it-py -msal==1.29.0 +msal==1.31.0 # via azure-identity # via msal-extensions msal-extensions==1.2.0 @@ -109,26 +109,24 @@ pathspec==0.12.1 platformdirs==3.11.0 # via black # via virtualenv -pluggy==1.3.0 +pluggy==1.5.0 # via pytest -portalocker==2.8.2 +portalocker==2.10.1 # via msal-extensions -py==1.11.0 - # via pytest pycparser==2.22 # via cffi -pydantic==2.7.1 +pydantic==2.9.2 # via openai -pydantic-core==2.18.2 +pydantic-core==2.23.4 # via pydantic pygments==2.18.0 # via rich pyjwt==2.8.0 # via msal pyright==1.1.380 -pytest==7.1.1 +pytest==8.3.3 # via pytest-asyncio -pytest-asyncio==0.21.1 +pytest-asyncio==0.24.0 python-dateutil==2.8.2 # via pandas # via time-machine @@ -158,21 +156,22 @@ sortedcontainers==2.4.0 time-machine==2.9.0 toml==0.10.2 # via inline-snapshot -tomli==2.0.1 +tomli==2.0.2 # via black # via mypy # via pytest -tqdm==4.66.1 +tqdm==4.66.5 # via openai -trio==0.22.2 -types-pyaudio==0.2.16.20240106 -types-pytz==2024.1.0.20240417 +trio==0.27.0 +types-pyaudio==0.2.16.20240516 +types-pytz==2024.2.0.20241003 # via pandas-stubs types-toml==0.10.8.20240310 # via inline-snapshot -types-tqdm==4.66.0.2 +types-tqdm==4.66.0.20240417 typing-extensions==4.12.2 # via azure-core + # via azure-identity # via black # via mypy # via openai diff --git a/requirements.lock b/requirements.lock index de632aefbd..019dfcb4c5 100644 --- a/requirements.lock +++ b/requirements.lock @@ -19,7 +19,7 @@ certifi==2023.7.22 # via httpx distro==1.8.0 # via openai -exceptiongroup==1.1.3 +exceptiongroup==1.2.2 # via anyio h11==0.14.0 # via httpcore @@ -30,19 +30,19 @@ httpx==0.25.2 idna==3.4 # via anyio # via httpx -jiter==0.5.0 +jiter==0.6.1 # via openai -numpy==1.26.4 +numpy==2.0.2 # via openai # via pandas # via pandas-stubs -pandas==2.2.2 +pandas==2.2.3 # via openai -pandas-stubs==2.2.1.240316 +pandas-stubs==2.2.2.240807 # via openai -pydantic==2.7.1 +pydantic==2.9.2 # via openai -pydantic-core==2.18.2 +pydantic-core==2.23.4 # via pydantic python-dateutil==2.9.0.post0 # via pandas @@ -54,9 +54,9 @@ sniffio==1.3.0 # via anyio # via httpx # via openai -tqdm==4.66.1 +tqdm==4.66.5 # via openai -types-pytz==2024.1.0.20240417 +types-pytz==2024.2.0.20241003 # via pandas-stubs typing-extensions==4.12.2 # via openai diff --git a/src/openai/_compat.py b/src/openai/_compat.py index 78851277eb..4dfa23845d 100644 --- a/src/openai/_compat.py +++ b/src/openai/_compat.py @@ -133,7 +133,7 @@ def model_json(model: pydantic.BaseModel, *, indent: int | None = None) -> str: def model_dump( model: pydantic.BaseModel, *, - exclude: IncEx = None, + exclude: IncEx | None = None, exclude_unset: bool = False, exclude_defaults: bool = False, warnings: bool = True, diff --git a/src/openai/_models.py b/src/openai/_models.py index 710401defd..4100328c22 100644 --- a/src/openai/_models.py +++ b/src/openai/_models.py @@ -201,7 +201,7 @@ def __str__(self) -> str: # Based on https://github.com/samuelcolvin/pydantic/issues/1168#issuecomment-817742836. @classmethod @override - def construct( + def construct( # pyright: ignore[reportIncompatibleMethodOverride] cls: Type[ModelT], _fields_set: set[str] | None = None, **values: object, @@ -273,8 +273,8 @@ def model_dump( self, *, mode: Literal["json", "python"] | str = "python", - include: IncEx = None, - exclude: IncEx = None, + include: IncEx | None = None, + exclude: IncEx | None = None, by_alias: bool = False, exclude_unset: bool = False, exclude_defaults: bool = False, @@ -328,8 +328,8 @@ def model_dump_json( self, *, indent: int | None = None, - include: IncEx = None, - exclude: IncEx = None, + include: IncEx | None = None, + exclude: IncEx | None = None, by_alias: bool = False, exclude_unset: bool = False, exclude_defaults: bool = False, diff --git a/src/openai/_types.py b/src/openai/_types.py index 5611b2d38f..c8f4d5a922 100644 --- a/src/openai/_types.py +++ b/src/openai/_types.py @@ -16,7 +16,7 @@ Optional, Sequence, ) -from typing_extensions import Literal, Protocol, TypeAlias, TypedDict, override, runtime_checkable +from typing_extensions import Set, Literal, Protocol, TypeAlias, TypedDict, override, runtime_checkable import httpx import pydantic @@ -195,7 +195,9 @@ def get(self, __key: str) -> str | None: ... # Note: copied from Pydantic # https://github.com/pydantic/pydantic/blob/32ea570bf96e84234d2992e1ddf40ab8a565925a/pydantic/main.py#L49 -IncEx: TypeAlias = "set[int] | set[str] | dict[int, Any] | dict[str, Any] | None" +IncEx: TypeAlias = Union[ + Set[int], Set[str], Mapping[int, Union["IncEx", Literal[True]]], Mapping[str, Union["IncEx", Literal[True]]] +] PostParser = Callable[[Any], Any] diff --git a/src/openai/lib/streaming/chat/_completions.py b/src/openai/lib/streaming/chat/_completions.py index a4b0f856f7..8518de967f 100644 --- a/src/openai/lib/streaming/chat/_completions.py +++ b/src/openai/lib/streaming/chat/_completions.py @@ -23,7 +23,7 @@ FunctionToolCallArgumentsDeltaEvent, ) from .._deltas import accumulate_delta -from ...._types import NOT_GIVEN, NotGiven +from ...._types import NOT_GIVEN, IncEx, NotGiven from ...._utils import is_given, consume_sync_iterator, consume_async_iterator from ...._compat import model_dump from ...._models import build, construct_type @@ -352,13 +352,17 @@ def _accumulate_chunk(self, chunk: ChatCompletionChunk) -> ParsedChatCompletionS # we don't want to serialise / deserialise our custom properties # as they won't appear in the delta and we don't want to have to # continuosly reparse the content - exclude={ - "parsed": True, - "tool_calls": { - idx: {"function": {"parsed_arguments": True}} - for idx, _ in enumerate(choice_snapshot.message.tool_calls or []) + exclude=cast( + # cast required as mypy isn't smart enough to infer `True` here to `Literal[True]` + IncEx, + { + "parsed": True, + "tool_calls": { + idx: {"function": {"parsed_arguments": True}} + for idx, _ in enumerate(choice_snapshot.message.tool_calls or []) + }, }, - }, + ), ), ), cast("dict[object, object]", choice.delta.to_dict()), diff --git a/tests/conftest.py b/tests/conftest.py index 15af57e770..fa82d39d86 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,11 +1,11 @@ from __future__ import annotations import os -import asyncio import logging from typing import TYPE_CHECKING, Iterator, AsyncIterator import pytest +from pytest_asyncio import is_async_test from openai import OpenAI, AsyncOpenAI @@ -17,11 +17,13 @@ logging.getLogger("openai").setLevel(logging.DEBUG) -@pytest.fixture(scope="session") -def event_loop() -> Iterator[asyncio.AbstractEventLoop]: - loop = asyncio.new_event_loop() - yield loop - loop.close() +# automatically add `pytest.mark.asyncio()` to all of our async tests +# so we don't have to add that boilerplate everywhere +def pytest_collection_modifyitems(items: list[pytest.Function]) -> None: + pytest_asyncio_tests = (item for item in items if is_async_test(item)) + session_scope_marker = pytest.mark.asyncio(loop_scope="session") + for async_test in pytest_asyncio_tests: + async_test.add_marker(session_scope_marker, append=False) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") diff --git a/tests/lib/test_old_api.py b/tests/lib/test_old_api.py index 261b8acb94..bdb2a5398d 100644 --- a/tests/lib/test_old_api.py +++ b/tests/lib/test_old_api.py @@ -6,7 +6,7 @@ def test_basic_attribute_access_works() -> None: for attr in dir(openai): - dir(getattr(openai, attr)) + getattr(openai, attr) def test_helpful_error_is_raised() -> None: From c3ee00623709fcc67e9248af1c907cc7e863a5fd Mon Sep 17 00:00:00 2001 From: Stainless Bot Date: Wed, 30 Oct 2024 16:11:41 +0000 Subject: [PATCH 063/769] feat(api): add new, expressive voices for Realtime and Audio in Chat Completions https://platform.openai.com/docs/changelog --- .stats.yml | 2 +- src/openai/types/chat/chat_completion_audio_param.py | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.stats.yml b/.stats.yml index 0b08725565..39413df445 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 68 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-b60d5559d5150ecd3b49136064e5e251d832899770ff385b711378389afba370.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-7b0a5d715d94f75ac7795bd4d2175a0e3243af9b935a86c273f371e45583140f.yml diff --git a/src/openai/types/chat/chat_completion_audio_param.py b/src/openai/types/chat/chat_completion_audio_param.py index 6a4ce9ac1f..b92326d294 100644 --- a/src/openai/types/chat/chat_completion_audio_param.py +++ b/src/openai/types/chat/chat_completion_audio_param.py @@ -14,8 +14,9 @@ class ChatCompletionAudioParam(TypedDict, total=False): Must be one of `wav`, `mp3`, `flac`, `opus`, or `pcm16`. """ - voice: Required[Literal["alloy", "echo", "fable", "onyx", "nova", "shimmer"]] - """Specifies the voice type. + voice: Required[Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"]] + """The voice the model uses to respond. - Supported voices are `alloy`, `echo`, `fable`, `onyx`, `nova`, and `shimmer`. + Supported voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`, + `shimmer`, and `verse`. """ From 891e1c17b7fecbae34d1915ba90c15ddece807f9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 30 Oct 2024 16:27:56 +0000 Subject: [PATCH 064/769] release: 1.53.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 2f2a30a82e..0b97f7533e 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.52.2" + ".": "1.53.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 21f6136744..4f5a63ae72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 1.53.0 (2024-10-30) + +Full Changelog: [v1.52.2...v1.53.0](https://github.com/openai/openai-python/compare/v1.52.2...v1.53.0) + +### Features + +* **api:** add new, expressive voices for Realtime and Audio in Chat Completions ([7cf0a49](https://github.com/openai/openai-python/commit/7cf0a4958e4c985bef4d18bb919fa3948f389a82)) + + +### Chores + +* **internal:** bump pytest to v8 & pydantic ([#1829](https://github.com/openai/openai-python/issues/1829)) ([0e67a8a](https://github.com/openai/openai-python/commit/0e67a8af5daf9da029d2bd4bdf341cc8a494254a)) + ## 1.52.2 (2024-10-23) Full Changelog: [v1.52.1...v1.52.2](https://github.com/openai/openai-python/compare/v1.52.1...v1.52.2) diff --git a/pyproject.toml b/pyproject.toml index 3bd6246e43..46aced6fba 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.52.2" +version = "1.53.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 641d4f5b30..afda9b903f 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.52.2" # x-release-please-version +__version__ = "1.53.0" # x-release-please-version From c94ead1d0c865bb9a0c8b787149d1f34317ca935 Mon Sep 17 00:00:00 2001 From: Stainless Bot Date: Fri, 1 Nov 2024 12:34:07 +0000 Subject: [PATCH 065/769] chore(internal): bump mypy (#1839) --- requirements-dev.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.lock b/requirements-dev.lock index 2df8a39c76..5fe1ccad57 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -83,7 +83,7 @@ msal==1.31.0 # via msal-extensions msal-extensions==1.2.0 # via azure-identity -mypy==1.11.2 +mypy==1.13.0 mypy-extensions==1.0.0 # via black # via mypy From 643e500c52831f1966f16d7173651d06cb886a31 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 2 Nov 2024 02:46:36 +0000 Subject: [PATCH 066/769] fix: don't use dicts as iterables in transform (#1842) --- src/openai/_utils/_transform.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/openai/_utils/_transform.py b/src/openai/_utils/_transform.py index 47e262a515..7e9663d369 100644 --- a/src/openai/_utils/_transform.py +++ b/src/openai/_utils/_transform.py @@ -173,6 +173,11 @@ def _transform_recursive( # Iterable[T] or (is_iterable_type(stripped_type) and is_iterable(data) and not isinstance(data, str)) ): + # dicts are technically iterable, but it is an iterable on the keys of the dict and is not usually + # intended as an iterable, so we don't transform it. + if isinstance(data, dict): + return cast(object, data) + inner_type = extract_type_arg(stripped_type, 0) return [_transform_recursive(d, annotation=annotation, inner_type=inner_type) for d in data] From d21cd6c042e88629b81ae85c7d7023c973aa14f5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 14:59:58 +0000 Subject: [PATCH 067/769] fix: support json safe serialization for basemodel subclasses (#1844) --- src/openai/_compat.py | 6 ++++-- src/openai/_models.py | 9 ++++++--- src/openai/_utils/__init__.py | 1 + src/openai/_utils/_transform.py | 4 ++-- src/openai/_utils/_utils.py | 17 +++++++++++++++++ tests/test_models.py | 21 +++++++-------------- tests/test_transform.py | 15 +++++++++++++++ 7 files changed, 52 insertions(+), 21 deletions(-) diff --git a/src/openai/_compat.py b/src/openai/_compat.py index 4dfa23845d..7c3156a5eb 100644 --- a/src/openai/_compat.py +++ b/src/openai/_compat.py @@ -2,7 +2,7 @@ from typing import TYPE_CHECKING, Any, Union, Generic, TypeVar, Callable, cast, overload from datetime import date, datetime -from typing_extensions import Self +from typing_extensions import Self, Literal import pydantic from pydantic.fields import FieldInfo @@ -137,9 +137,11 @@ def model_dump( exclude_unset: bool = False, exclude_defaults: bool = False, warnings: bool = True, + mode: Literal["json", "python"] = "python", ) -> dict[str, Any]: - if PYDANTIC_V2: + if PYDANTIC_V2 or hasattr(model, "model_dump"): return model.model_dump( + mode=mode, exclude=exclude, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, diff --git a/src/openai/_models.py b/src/openai/_models.py index 4100328c22..20cd4c29bc 100644 --- a/src/openai/_models.py +++ b/src/openai/_models.py @@ -38,6 +38,7 @@ PropertyInfo, is_list, is_given, + json_safe, lru_cache, is_mapping, parse_date, @@ -304,8 +305,8 @@ def model_dump( Returns: A dictionary representation of the model. """ - if mode != "python": - raise ValueError("mode is only supported in Pydantic v2") + if mode not in {"json", "python"}: + raise ValueError("mode must be either 'json' or 'python'") if round_trip != False: raise ValueError("round_trip is only supported in Pydantic v2") if warnings != True: @@ -314,7 +315,7 @@ def model_dump( raise ValueError("context is only supported in Pydantic v2") if serialize_as_any != False: raise ValueError("serialize_as_any is only supported in Pydantic v2") - return super().dict( # pyright: ignore[reportDeprecated] + dumped = super().dict( # pyright: ignore[reportDeprecated] include=include, exclude=exclude, by_alias=by_alias, @@ -323,6 +324,8 @@ def model_dump( exclude_none=exclude_none, ) + return cast(dict[str, Any], json_safe(dumped)) if mode == "json" else dumped + @override def model_dump_json( self, diff --git a/src/openai/_utils/__init__.py b/src/openai/_utils/__init__.py index 3efe66c8e8..a7cff3c091 100644 --- a/src/openai/_utils/__init__.py +++ b/src/openai/_utils/__init__.py @@ -6,6 +6,7 @@ is_list as is_list, is_given as is_given, is_tuple as is_tuple, + json_safe as json_safe, lru_cache as lru_cache, is_mapping as is_mapping, is_tuple_t as is_tuple_t, diff --git a/src/openai/_utils/_transform.py b/src/openai/_utils/_transform.py index 7e9663d369..d7c05345d1 100644 --- a/src/openai/_utils/_transform.py +++ b/src/openai/_utils/_transform.py @@ -191,7 +191,7 @@ def _transform_recursive( return data if isinstance(data, pydantic.BaseModel): - return model_dump(data, exclude_unset=True) + return model_dump(data, exclude_unset=True, mode="json") annotated_type = _get_annotated_type(annotation) if annotated_type is None: @@ -329,7 +329,7 @@ async def _async_transform_recursive( return data if isinstance(data, pydantic.BaseModel): - return model_dump(data, exclude_unset=True) + return model_dump(data, exclude_unset=True, mode="json") annotated_type = _get_annotated_type(annotation) if annotated_type is None: diff --git a/src/openai/_utils/_utils.py b/src/openai/_utils/_utils.py index 0bba17caad..e5811bba42 100644 --- a/src/openai/_utils/_utils.py +++ b/src/openai/_utils/_utils.py @@ -16,6 +16,7 @@ overload, ) from pathlib import Path +from datetime import date, datetime from typing_extensions import TypeGuard import sniffio @@ -395,3 +396,19 @@ def lru_cache(*, maxsize: int | None = 128) -> Callable[[CallableT], CallableT]: maxsize=maxsize, ) return cast(Any, wrapper) # type: ignore[no-any-return] + + +def json_safe(data: object) -> object: + """Translates a mapping / sequence recursively in the same fashion + as `pydantic` v2's `model_dump(mode="json")`. + """ + if is_mapping(data): + return {json_safe(key): json_safe(value) for key, value in data.items()} + + if is_iterable(data) and not isinstance(data, (str, bytes, bytearray)): + return [json_safe(item) for item in data] + + if isinstance(data, (datetime, date)): + return data.isoformat() + + return data diff --git a/tests/test_models.py b/tests/test_models.py index 117a90020e..84dbce6914 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -520,19 +520,15 @@ class Model(BaseModel): assert m3.to_dict(exclude_none=True) == {} assert m3.to_dict(exclude_defaults=True) == {} - if PYDANTIC_V2: - - class Model2(BaseModel): - created_at: datetime + class Model2(BaseModel): + created_at: datetime - time_str = "2024-03-21T11:39:01.275859" - m4 = Model2.construct(created_at=time_str) - assert m4.to_dict(mode="python") == {"created_at": datetime.fromisoformat(time_str)} - assert m4.to_dict(mode="json") == {"created_at": time_str} - else: - with pytest.raises(ValueError, match="mode is only supported in Pydantic v2"): - m.to_dict(mode="json") + time_str = "2024-03-21T11:39:01.275859" + m4 = Model2.construct(created_at=time_str) + assert m4.to_dict(mode="python") == {"created_at": datetime.fromisoformat(time_str)} + assert m4.to_dict(mode="json") == {"created_at": time_str} + if not PYDANTIC_V2: with pytest.raises(ValueError, match="warnings is only supported in Pydantic v2"): m.to_dict(warnings=False) @@ -558,9 +554,6 @@ class Model(BaseModel): assert m3.model_dump(exclude_none=True) == {} if not PYDANTIC_V2: - with pytest.raises(ValueError, match="mode is only supported in Pydantic v2"): - m.model_dump(mode="json") - with pytest.raises(ValueError, match="round_trip is only supported in Pydantic v2"): m.model_dump(round_trip=True) diff --git a/tests/test_transform.py b/tests/test_transform.py index 1eb6cde9d6..8c6aba6448 100644 --- a/tests/test_transform.py +++ b/tests/test_transform.py @@ -177,17 +177,32 @@ class DateDict(TypedDict, total=False): foo: Annotated[date, PropertyInfo(format="iso8601")] +class DatetimeModel(BaseModel): + foo: datetime + + +class DateModel(BaseModel): + foo: Optional[date] + + @parametrize @pytest.mark.asyncio async def test_iso8601_format(use_async: bool) -> None: dt = datetime.fromisoformat("2023-02-23T14:16:36.337692+00:00") + tz = "Z" if PYDANTIC_V2 else "+00:00" assert await transform({"foo": dt}, DatetimeDict, use_async) == {"foo": "2023-02-23T14:16:36.337692+00:00"} # type: ignore[comparison-overlap] + assert await transform(DatetimeModel(foo=dt), Any, use_async) == {"foo": "2023-02-23T14:16:36.337692" + tz} # type: ignore[comparison-overlap] dt = dt.replace(tzinfo=None) assert await transform({"foo": dt}, DatetimeDict, use_async) == {"foo": "2023-02-23T14:16:36.337692"} # type: ignore[comparison-overlap] + assert await transform(DatetimeModel(foo=dt), Any, use_async) == {"foo": "2023-02-23T14:16:36.337692"} # type: ignore[comparison-overlap] assert await transform({"foo": None}, DateDict, use_async) == {"foo": None} # type: ignore[comparison-overlap] + assert await transform(DateModel(foo=None), Any, use_async) == {"foo": None} # type: ignore assert await transform({"foo": date.fromisoformat("2023-02-23")}, DateDict, use_async) == {"foo": "2023-02-23"} # type: ignore[comparison-overlap] + assert await transform(DateModel(foo=date.fromisoformat("2023-02-23")), DateDict, use_async) == { + "foo": "2023-02-23" + } # type: ignore[comparison-overlap] @parametrize From 6e42e7879a8e22db9268d1ef2f3b80428534e752 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 15:00:39 +0000 Subject: [PATCH 068/769] release: 1.53.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 14 ++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 0b97f7533e..5a86c0906c 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.53.0" + ".": "1.53.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f5a63ae72..c3a5a3cecb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## 1.53.1 (2024-11-04) + +Full Changelog: [v1.53.0...v1.53.1](https://github.com/openai/openai-python/compare/v1.53.0...v1.53.1) + +### Bug Fixes + +* don't use dicts as iterables in transform ([#1842](https://github.com/openai/openai-python/issues/1842)) ([258f265](https://github.com/openai/openai-python/commit/258f26535744ab3b2f0746991fd29eae72ebd667)) +* support json safe serialization for basemodel subclasses ([#1844](https://github.com/openai/openai-python/issues/1844)) ([2b80c90](https://github.com/openai/openai-python/commit/2b80c90c21d3b2468dfa3bf40c08c5b0e0eebffa)) + + +### Chores + +* **internal:** bump mypy ([#1839](https://github.com/openai/openai-python/issues/1839)) ([d92f959](https://github.com/openai/openai-python/commit/d92f959aa6f49be56574b4d1d1ac5ac48689dd46)) + ## 1.53.0 (2024-10-30) Full Changelog: [v1.52.2...v1.53.0](https://github.com/openai/openai-python/compare/v1.52.2...v1.53.0) diff --git a/pyproject.toml b/pyproject.toml index 46aced6fba..974e5fc740 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.53.0" +version = "1.53.1" 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 afda9b903f..9d221eb538 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.53.0" # x-release-please-version +__version__ = "1.53.1" # x-release-please-version From cb88c2f01dd02b10ece80974f0b6403ae5921298 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 18:00:25 +0000 Subject: [PATCH 069/769] feat(project): drop support for Python 3.7 (#1845) 3.7 has been EOL for over a year and accounts for a small number of downloads --- README.md | 4 ++-- pyproject.toml | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index dada1abfbb..bc334e7e07 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![PyPI version](https://img.shields.io/pypi/v/openai.svg)](https://pypi.org/project/openai/) -The OpenAI Python library provides convenient access to the OpenAI REST API from any Python 3.7+ +The OpenAI Python library provides convenient access to the OpenAI REST API from any Python 3.8+ application. The library includes type definitions for all request params and response fields, and offers both synchronous and asynchronous clients powered by [httpx](https://github.com/encode/httpx). @@ -712,7 +712,7 @@ print(openai.__version__) ## Requirements -Python 3.7 or higher. +Python 3.8 or higher. ## Contributing diff --git a/pyproject.toml b/pyproject.toml index 974e5fc740..20c0f3bb15 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,11 +18,10 @@ dependencies = [ "tqdm > 4", "jiter>=0.4.0, <1", ] -requires-python = ">= 3.7.1" +requires-python = ">= 3.8" classifiers = [ "Typing :: Typed", "Intended Audience :: Developers", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", @@ -150,7 +149,7 @@ filterwarnings = [ # there are a couple of flags that are still disabled by # default in strict mode as they are experimental and niche. typeCheckingMode = "strict" -pythonVersion = "3.7" +pythonVersion = "3.8" exclude = [ "_dev", From dfdcf571ced31f7859cd1871be39e2fb3af6bafa Mon Sep 17 00:00:00 2001 From: Stainless Bot Date: Mon, 4 Nov 2024 22:47:52 +0000 Subject: [PATCH 070/769] feat(api): add support for predicted outputs (#1847) --- .stats.yml | 2 +- api.md | 3 +- src/openai/resources/audio/speech.py | 8 +- src/openai/resources/audio/transcriptions.py | 4 +- src/openai/resources/audio/translations.py | 4 +- src/openai/resources/beta/assistants.py | 40 +++--- src/openai/resources/beta/threads/messages.py | 8 +- .../resources/beta/threads/runs/runs.py | 56 ++++---- .../resources/beta/threads/runs/steps.py | 16 +-- src/openai/resources/beta/threads/threads.py | 36 ++--- .../beta/vector_stores/file_batches.py | 8 +- .../resources/beta/vector_stores/files.py | 8 +- .../beta/vector_stores/vector_stores.py | 8 +- src/openai/resources/chat/completions.py | 125 +++++++++++------- src/openai/resources/completions.py | 60 ++++----- src/openai/resources/embeddings.py | 12 +- src/openai/resources/files.py | 74 ++++++++--- src/openai/resources/fine_tuning/jobs/jobs.py | 4 +- src/openai/resources/images.py | 12 +- src/openai/resources/moderations.py | 4 +- src/openai/resources/uploads/uploads.py | 4 +- .../types/audio/speech_create_params.py | 4 +- .../audio/transcription_create_params.py | 2 +- .../types/audio/translation_create_params.py | 2 +- src/openai/types/beta/assistant.py | 8 +- .../types/beta/assistant_create_params.py | 8 +- .../types/beta/assistant_list_params.py | 2 +- .../types/beta/assistant_update_params.py | 8 +- src/openai/types/beta/file_search_tool.py | 4 +- .../types/beta/file_search_tool_param.py | 4 +- .../beta/thread_create_and_run_params.py | 6 +- .../types/beta/threads/message_list_params.py | 2 +- src/openai/types/beta/threads/run.py | 6 +- .../types/beta/threads/run_create_params.py | 8 +- .../types/beta/threads/run_list_params.py | 2 +- .../beta/threads/runs/step_list_params.py | 4 +- .../beta/threads/runs/step_retrieve_params.py | 2 +- .../types/beta/vector_store_list_params.py | 2 +- .../file_batch_list_files_params.py | 2 +- .../beta/vector_stores/file_list_params.py | 2 +- src/openai/types/chat/__init__.py | 3 + ...hat_completion_content_part_image_param.py | 2 +- ...hat_completion_prediction_content_param.py | 25 ++++ .../types/chat/completion_create_params.py | 23 ++-- src/openai/types/completion_create_params.py | 10 +- src/openai/types/completion_usage.py | 14 ++ src/openai/types/embedding_create_params.py | 6 +- src/openai/types/file_list_params.py | 23 +++- .../types/fine_tuning/job_create_params.py | 2 +- .../types/image_create_variation_params.py | 2 +- src/openai/types/image_edit_params.py | 2 +- src/openai/types/image_generate_params.py | 2 +- src/openai/types/moderation_create_params.py | 2 +- tests/api_resources/chat/test_completions.py | 16 +++ tests/api_resources/test_files.py | 28 ++-- 55 files changed, 450 insertions(+), 284 deletions(-) create mode 100644 src/openai/types/chat/chat_completion_prediction_content_param.py diff --git a/.stats.yml b/.stats.yml index 39413df445..f368bc881d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 68 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-7b0a5d715d94f75ac7795bd4d2175a0e3243af9b935a86c273f371e45583140f.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-2f8ca92b9b1879fd535b685e4767338413fcd533d42f3baac13a9c41da3fce35.yml diff --git a/api.md b/api.md index f44169665d..7def07bb79 100644 --- a/api.md +++ b/api.md @@ -54,6 +54,7 @@ from openai.types.chat import ( ChatCompletionMessageToolCall, ChatCompletionModality, ChatCompletionNamedToolChoice, + ChatCompletionPredictionContent, ChatCompletionRole, ChatCompletionStreamOptions, ChatCompletionSystemMessageParam, @@ -93,7 +94,7 @@ Methods: - client.files.create(\*\*params) -> FileObject - client.files.retrieve(file_id) -> FileObject -- client.files.list(\*\*params) -> SyncPage[FileObject] +- client.files.list(\*\*params) -> SyncCursorPage[FileObject] - client.files.delete(file_id) -> FileDeleted - client.files.content(file_id) -> HttpxBinaryResponseContent - client.files.retrieve_content(file_id) -> str diff --git a/src/openai/resources/audio/speech.py b/src/openai/resources/audio/speech.py index 6085ae8afe..09faaddda6 100644 --- a/src/openai/resources/audio/speech.py +++ b/src/openai/resources/audio/speech.py @@ -70,13 +70,13 @@ def create( input: The text to generate audio for. The maximum length is 4096 characters. model: - One of the available [TTS models](https://platform.openai.com/docs/models/tts): + One of the available [TTS models](https://platform.openai.com/docs/models#tts): `tts-1` or `tts-1-hd` voice: The voice to use when generating the audio. Supported voices are `alloy`, `echo`, `fable`, `onyx`, `nova`, and `shimmer`. Previews of the voices are available in the - [Text to speech guide](https://platform.openai.com/docs/guides/text-to-speech/voice-options). + [Text to speech guide](https://platform.openai.com/docs/guides/text-to-speech#voice-options). response_format: The format to audio in. Supported formats are `mp3`, `opus`, `aac`, `flac`, `wav`, and `pcm`. @@ -154,13 +154,13 @@ async def create( input: The text to generate audio for. The maximum length is 4096 characters. model: - One of the available [TTS models](https://platform.openai.com/docs/models/tts): + One of the available [TTS models](https://platform.openai.com/docs/models#tts): `tts-1` or `tts-1-hd` voice: The voice to use when generating the audio. Supported voices are `alloy`, `echo`, `fable`, `onyx`, `nova`, and `shimmer`. Previews of the voices are available in the - [Text to speech guide](https://platform.openai.com/docs/guides/text-to-speech/voice-options). + [Text to speech guide](https://platform.openai.com/docs/guides/text-to-speech#voice-options). response_format: The format to audio in. Supported formats are `mp3`, `opus`, `aac`, `flac`, `wav`, and `pcm`. diff --git a/src/openai/resources/audio/transcriptions.py b/src/openai/resources/audio/transcriptions.py index e6596a480e..8b5f4404fc 100644 --- a/src/openai/resources/audio/transcriptions.py +++ b/src/openai/resources/audio/transcriptions.py @@ -143,7 +143,7 @@ def create( prompt: An optional text to guide the model's style or continue a previous audio segment. The - [prompt](https://platform.openai.com/docs/guides/speech-to-text/prompting) + [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) should match the audio language. response_format: The format of the output, in one of these options: `json`, `text`, `srt`, @@ -307,7 +307,7 @@ async def create( prompt: An optional text to guide the model's style or continue a previous audio segment. The - [prompt](https://platform.openai.com/docs/guides/speech-to-text/prompting) + [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) should match the audio language. response_format: The format of the output, in one of these options: `json`, `text`, `srt`, diff --git a/src/openai/resources/audio/translations.py b/src/openai/resources/audio/translations.py index 53ab625873..a2d28afa03 100644 --- a/src/openai/resources/audio/translations.py +++ b/src/openai/resources/audio/translations.py @@ -130,7 +130,7 @@ def create( prompt: An optional text to guide the model's style or continue a previous audio segment. The - [prompt](https://platform.openai.com/docs/guides/speech-to-text/prompting) + [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) should be in English. response_format: The format of the output, in one of these options: `json`, `text`, `srt`, @@ -273,7 +273,7 @@ async def create( prompt: An optional text to guide the model's style or continue a previous audio segment. The - [prompt](https://platform.openai.com/docs/guides/speech-to-text/prompting) + [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) should be in English. response_format: The format of the output, in one of these options: `json`, `text`, `srt`, diff --git a/src/openai/resources/beta/assistants.py b/src/openai/resources/beta/assistants.py index 2ebef183b6..7df212f155 100644 --- a/src/openai/resources/beta/assistants.py +++ b/src/openai/resources/beta/assistants.py @@ -79,8 +79,8 @@ def create( model: ID of the model to use. You can use the [List models](https://platform.openai.com/docs/api-reference/models/list) API to see all of your available models, or see our - [Model overview](https://platform.openai.com/docs/models/overview) for - descriptions of them. + [Model overview](https://platform.openai.com/docs/models) for descriptions of + them. description: The description of the assistant. The maximum length is 512 characters. @@ -95,8 +95,8 @@ def create( name: The name of the assistant. The maximum length is 256 characters. 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), + [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), and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured @@ -239,14 +239,14 @@ def update( model: ID of the model to use. You can use the [List models](https://platform.openai.com/docs/api-reference/models/list) API to see all of your available models, or see our - [Model overview](https://platform.openai.com/docs/models/overview) for - descriptions of them. + [Model overview](https://platform.openai.com/docs/models) for descriptions of + them. name: The name of the assistant. The maximum length is 256 characters. 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), + [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), and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured @@ -344,8 +344,8 @@ def list( before: A cursor for use in pagination. `before` is an object ID that defines your place in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include before=obj_foo in order to - fetch the previous page of the list. + starting with obj_foo, your subsequent call can include before=obj_foo in order + to fetch the previous page of the list. limit: A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 20. @@ -465,8 +465,8 @@ async def create( model: ID of the model to use. You can use the [List models](https://platform.openai.com/docs/api-reference/models/list) API to see all of your available models, or see our - [Model overview](https://platform.openai.com/docs/models/overview) for - descriptions of them. + [Model overview](https://platform.openai.com/docs/models) for descriptions of + them. description: The description of the assistant. The maximum length is 512 characters. @@ -481,8 +481,8 @@ async def create( name: The name of the assistant. The maximum length is 256 characters. 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), + [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), and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured @@ -625,14 +625,14 @@ async def update( model: ID of the model to use. You can use the [List models](https://platform.openai.com/docs/api-reference/models/list) API to see all of your available models, or see our - [Model overview](https://platform.openai.com/docs/models/overview) for - descriptions of them. + [Model overview](https://platform.openai.com/docs/models) for descriptions of + them. name: The name of the assistant. The maximum length is 256 characters. 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), + [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), and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured @@ -730,8 +730,8 @@ def list( before: A cursor for use in pagination. `before` is an object ID that defines your place in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include before=obj_foo in order to - fetch the previous page of the list. + starting with obj_foo, your subsequent call can include before=obj_foo in order + to fetch the previous page of the list. limit: A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 20. diff --git a/src/openai/resources/beta/threads/messages.py b/src/openai/resources/beta/threads/messages.py index de7ebcaf4d..e848507387 100644 --- a/src/openai/resources/beta/threads/messages.py +++ b/src/openai/resources/beta/threads/messages.py @@ -221,8 +221,8 @@ def list( before: A cursor for use in pagination. `before` is an object ID that defines your place in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include before=obj_foo in order to - fetch the previous page of the list. + starting with obj_foo, your subsequent call can include before=obj_foo in order + to fetch the previous page of the list. limit: A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 20. @@ -495,8 +495,8 @@ def list( before: A cursor for use in pagination. `before` is an object ID that defines your place in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include before=obj_foo in order to - fetch the previous page of the list. + starting with obj_foo, your subsequent call can include before=obj_foo in order + to fetch the previous page of the list. limit: A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 20. diff --git a/src/openai/resources/beta/threads/runs/runs.py b/src/openai/resources/beta/threads/runs/runs.py index 287c0ecf24..620cc270e5 100644 --- a/src/openai/resources/beta/threads/runs/runs.py +++ b/src/openai/resources/beta/threads/runs/runs.py @@ -122,7 +122,7 @@ def create( to fetch the file search result content. See the - [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search/customizing-file-search-settings) + [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) for more information. additional_instructions: Appends additional instructions at the end of the instructions for the run. This @@ -158,12 +158,12 @@ def create( assistant will be used. parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling/parallel-function-calling) + [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) during tool use. 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), + [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), and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured @@ -266,7 +266,7 @@ def create( to fetch the file search result content. See the - [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search/customizing-file-search-settings) + [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) for more information. additional_instructions: Appends additional instructions at the end of the instructions for the run. This @@ -302,12 +302,12 @@ def create( assistant will be used. parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling/parallel-function-calling) + [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) during tool use. 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), + [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), and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured @@ -406,7 +406,7 @@ def create( to fetch the file search result content. See the - [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search/customizing-file-search-settings) + [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) for more information. additional_instructions: Appends additional instructions at the end of the instructions for the run. This @@ -442,12 +442,12 @@ def create( assistant will be used. parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling/parallel-function-calling) + [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) during tool use. 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), + [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), and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured @@ -674,8 +674,8 @@ def list( before: A cursor for use in pagination. `before` is an object ID that defines your place in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include before=obj_foo in order to - fetch the previous page of the list. + starting with obj_foo, your subsequent call can include before=obj_foo in order + to fetch the previous page of the list. limit: A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 20. @@ -1484,7 +1484,7 @@ async def create( to fetch the file search result content. See the - [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search/customizing-file-search-settings) + [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) for more information. additional_instructions: Appends additional instructions at the end of the instructions for the run. This @@ -1520,12 +1520,12 @@ async def create( assistant will be used. parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling/parallel-function-calling) + [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) during tool use. 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), + [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), and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured @@ -1628,7 +1628,7 @@ async def create( to fetch the file search result content. See the - [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search/customizing-file-search-settings) + [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) for more information. additional_instructions: Appends additional instructions at the end of the instructions for the run. This @@ -1664,12 +1664,12 @@ async def create( assistant will be used. parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling/parallel-function-calling) + [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) during tool use. 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), + [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), and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured @@ -1768,7 +1768,7 @@ async def create( to fetch the file search result content. See the - [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search/customizing-file-search-settings) + [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) for more information. additional_instructions: Appends additional instructions at the end of the instructions for the run. This @@ -1804,12 +1804,12 @@ async def create( assistant will be used. parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling/parallel-function-calling) + [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) during tool use. 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), + [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), and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured @@ -2037,8 +2037,8 @@ def list( before: A cursor for use in pagination. `before` is an object ID that defines your place in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include before=obj_foo in order to - fetch the previous page of the list. + starting with obj_foo, your subsequent call can include before=obj_foo in order + to fetch the previous page of the list. limit: A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 20. diff --git a/src/openai/resources/beta/threads/runs/steps.py b/src/openai/resources/beta/threads/runs/steps.py index 5d6d55f9d9..9bd91e39e0 100644 --- a/src/openai/resources/beta/threads/runs/steps.py +++ b/src/openai/resources/beta/threads/runs/steps.py @@ -68,7 +68,7 @@ def retrieve( to fetch the file search result content. See the - [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search/customizing-file-search-settings) + [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) for more information. extra_headers: Send extra headers @@ -126,15 +126,15 @@ def list( before: A cursor for use in pagination. `before` is an object ID that defines your place in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include before=obj_foo in order to - fetch the previous page of the list. + starting with obj_foo, your subsequent call can include before=obj_foo in order + to fetch the previous page of the list. include: A list of additional fields to include in the response. Currently the only supported value is `step_details.tool_calls[*].file_search.results[*].content` to fetch the file search result content. See the - [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search/customizing-file-search-settings) + [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) for more information. limit: A limit on the number of objects to be returned. Limit can range between 1 and @@ -222,7 +222,7 @@ async def retrieve( to fetch the file search result content. See the - [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search/customizing-file-search-settings) + [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) for more information. extra_headers: Send extra headers @@ -280,15 +280,15 @@ def list( before: A cursor for use in pagination. `before` is an object ID that defines your place in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include before=obj_foo in order to - fetch the previous page of the list. + starting with obj_foo, your subsequent call can include before=obj_foo in order + to fetch the previous page of the list. include: A list of additional fields to include in the response. Currently the only supported value is `step_details.tool_calls[*].file_search.results[*].content` to fetch the file search result content. See the - [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search/customizing-file-search-settings) + [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) for more information. limit: A limit on the number of objects to be returned. Limit can range between 1 and diff --git a/src/openai/resources/beta/threads/threads.py b/src/openai/resources/beta/threads/threads.py index 3b8851c03b..058ba71a17 100644 --- a/src/openai/resources/beta/threads/threads.py +++ b/src/openai/resources/beta/threads/threads.py @@ -326,12 +326,12 @@ def create_and_run( assistant will be used. parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling/parallel-function-calling) + [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) during tool use. 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), + [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), and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured @@ -460,12 +460,12 @@ def create_and_run( assistant will be used. parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling/parallel-function-calling) + [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) during tool use. 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), + [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), and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured @@ -590,12 +590,12 @@ def create_and_run( assistant will be used. parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling/parallel-function-calling) + [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) during tool use. 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), + [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), and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured @@ -1160,12 +1160,12 @@ async def create_and_run( assistant will be used. parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling/parallel-function-calling) + [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) during tool use. 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), + [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), and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured @@ -1294,12 +1294,12 @@ async def create_and_run( assistant will be used. parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling/parallel-function-calling) + [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) during tool use. 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), + [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), and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured @@ -1424,12 +1424,12 @@ async def create_and_run( assistant will be used. parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling/parallel-function-calling) + [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) during tool use. 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), + [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), and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured diff --git a/src/openai/resources/beta/vector_stores/file_batches.py b/src/openai/resources/beta/vector_stores/file_batches.py index d1f9c872e4..9f9e643bd0 100644 --- a/src/openai/resources/beta/vector_stores/file_batches.py +++ b/src/openai/resources/beta/vector_stores/file_batches.py @@ -227,8 +227,8 @@ def list_files( before: A cursor for use in pagination. `before` is an object ID that defines your place in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include before=obj_foo in order to - fetch the previous page of the list. + starting with obj_foo, your subsequent call can include before=obj_foo in order + to fetch the previous page of the list. filter: Filter by file status. One of `in_progress`, `completed`, `failed`, `cancelled`. @@ -556,8 +556,8 @@ def list_files( before: A cursor for use in pagination. `before` is an object ID that defines your place in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include before=obj_foo in order to - fetch the previous page of the list. + starting with obj_foo, your subsequent call can include before=obj_foo in order + to fetch the previous page of the list. filter: Filter by file status. One of `in_progress`, `completed`, `failed`, `cancelled`. diff --git a/src/openai/resources/beta/vector_stores/files.py b/src/openai/resources/beta/vector_stores/files.py index fe43bb3488..7c155ac917 100644 --- a/src/openai/resources/beta/vector_stores/files.py +++ b/src/openai/resources/beta/vector_stores/files.py @@ -164,8 +164,8 @@ def list( before: A cursor for use in pagination. `before` is an object ID that defines your place in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include before=obj_foo in order to - fetch the previous page of the list. + starting with obj_foo, your subsequent call can include before=obj_foo in order + to fetch the previous page of the list. filter: Filter by file status. One of `in_progress`, `completed`, `failed`, `cancelled`. @@ -476,8 +476,8 @@ def list( before: A cursor for use in pagination. `before` is an object ID that defines your place in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include before=obj_foo in order to - fetch the previous page of the list. + starting with obj_foo, your subsequent call can include before=obj_foo in order + to fetch the previous page of the list. filter: Filter by file status. One of `in_progress`, `completed`, `failed`, `cancelled`. diff --git a/src/openai/resources/beta/vector_stores/vector_stores.py b/src/openai/resources/beta/vector_stores/vector_stores.py index d69add7b26..61a2eadc7b 100644 --- a/src/openai/resources/beta/vector_stores/vector_stores.py +++ b/src/openai/resources/beta/vector_stores/vector_stores.py @@ -251,8 +251,8 @@ def list( before: A cursor for use in pagination. `before` is an object ID that defines your place in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include before=obj_foo in order to - fetch the previous page of the list. + starting with obj_foo, your subsequent call can include before=obj_foo in order + to fetch the previous page of the list. limit: A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 20. @@ -529,8 +529,8 @@ def list( before: A cursor for use in pagination. `before` is an object ID that defines your place in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include before=obj_foo in order to - fetch the previous page of the list. + starting with obj_foo, your subsequent call can include before=obj_foo in order + to fetch the previous page of the list. limit: A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 20. diff --git a/src/openai/resources/chat/completions.py b/src/openai/resources/chat/completions.py index ceaf3c2fec..60ab5138ba 100644 --- a/src/openai/resources/chat/completions.py +++ b/src/openai/resources/chat/completions.py @@ -33,6 +33,7 @@ from ...types.chat.chat_completion_audio_param import ChatCompletionAudioParam from ...types.chat.chat_completion_message_param import ChatCompletionMessageParam from ...types.chat.chat_completion_stream_options_param import ChatCompletionStreamOptionsParam +from ...types.chat.chat_completion_prediction_content_param import ChatCompletionPredictionContentParam from ...types.chat.chat_completion_tool_choice_option_param import ChatCompletionToolChoiceOptionParam __all__ = ["Completions", "AsyncCompletions"] @@ -76,6 +77,7 @@ def create( modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, @@ -113,7 +115,7 @@ def create( [audio](https://platform.openai.com/docs/guides/audio). model: ID of the model to use. See the - [model endpoint compatibility](https://platform.openai.com/docs/models/model-endpoint-compatibility) + [model endpoint compatibility](https://platform.openai.com/docs/models#model-endpoint-compatibility) table for details on which models work with the Chat API. audio: Parameters for audio output. Required when audio output is requested with @@ -124,7 +126,7 @@ def create( existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation/parameter-details) + [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) function_call: Deprecated in favor of `tool_choice`. @@ -185,19 +187,22 @@ def create( choices. Keep `n` as `1` to minimize costs. parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling/parallel-function-calling) + [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) during tool use. + prediction: Static predicted output content, such as the content of a text file that is + being regenerated. + presence_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, increasing the model's likelihood to talk about new topics. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation/parameter-details) + [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) response_format: An object specifying the format that the model must output. Compatible with - [GPT-4o](https://platform.openai.com/docs/models/gpt-4o), - [GPT-4o mini](https://platform.openai.com/docs/models/gpt-4o-mini), - [GPT-4 Turbo](https://platform.openai.com/docs/models/gpt-4-and-gpt-4-turbo) and + [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), + [GPT-4o mini](https://platform.openai.com/docs/models#gpt-4o-mini), + [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4) and all GPT-3.5 Turbo models newer than `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured @@ -284,7 +289,7 @@ def create( user: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids). + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). extra_headers: Send extra headers @@ -315,6 +320,7 @@ def create( modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, @@ -351,7 +357,7 @@ def create( [audio](https://platform.openai.com/docs/guides/audio). model: ID of the model to use. See the - [model endpoint compatibility](https://platform.openai.com/docs/models/model-endpoint-compatibility) + [model endpoint compatibility](https://platform.openai.com/docs/models#model-endpoint-compatibility) table for details on which models work with the Chat API. stream: If set, partial message deltas will be sent, like in ChatGPT. Tokens will be @@ -369,7 +375,7 @@ def create( existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation/parameter-details) + [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) function_call: Deprecated in favor of `tool_choice`. @@ -430,19 +436,22 @@ def create( choices. Keep `n` as `1` to minimize costs. parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling/parallel-function-calling) + [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) during tool use. + prediction: Static predicted output content, such as the content of a text file that is + being regenerated. + presence_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, increasing the model's likelihood to talk about new topics. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation/parameter-details) + [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) response_format: An object specifying the format that the model must output. Compatible with - [GPT-4o](https://platform.openai.com/docs/models/gpt-4o), - [GPT-4o mini](https://platform.openai.com/docs/models/gpt-4o-mini), - [GPT-4 Turbo](https://platform.openai.com/docs/models/gpt-4-and-gpt-4-turbo) and + [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), + [GPT-4o mini](https://platform.openai.com/docs/models#gpt-4o-mini), + [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4) and all GPT-3.5 Turbo models newer than `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured @@ -522,7 +531,7 @@ def create( user: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids). + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). extra_headers: Send extra headers @@ -553,6 +562,7 @@ def create( modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, @@ -589,7 +599,7 @@ def create( [audio](https://platform.openai.com/docs/guides/audio). model: ID of the model to use. See the - [model endpoint compatibility](https://platform.openai.com/docs/models/model-endpoint-compatibility) + [model endpoint compatibility](https://platform.openai.com/docs/models#model-endpoint-compatibility) table for details on which models work with the Chat API. stream: If set, partial message deltas will be sent, like in ChatGPT. Tokens will be @@ -607,7 +617,7 @@ def create( existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation/parameter-details) + [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) function_call: Deprecated in favor of `tool_choice`. @@ -668,19 +678,22 @@ def create( choices. Keep `n` as `1` to minimize costs. parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling/parallel-function-calling) + [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) during tool use. + prediction: Static predicted output content, such as the content of a text file that is + being regenerated. + presence_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, increasing the model's likelihood to talk about new topics. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation/parameter-details) + [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) response_format: An object specifying the format that the model must output. Compatible with - [GPT-4o](https://platform.openai.com/docs/models/gpt-4o), - [GPT-4o mini](https://platform.openai.com/docs/models/gpt-4o-mini), - [GPT-4 Turbo](https://platform.openai.com/docs/models/gpt-4-and-gpt-4-turbo) and + [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), + [GPT-4o mini](https://platform.openai.com/docs/models#gpt-4o-mini), + [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4) and all GPT-3.5 Turbo models newer than `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured @@ -760,7 +773,7 @@ def create( user: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids). + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). extra_headers: Send extra headers @@ -790,6 +803,7 @@ def create( modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, @@ -830,6 +844,7 @@ def create( "modalities": modalities, "n": n, "parallel_tool_calls": parallel_tool_calls, + "prediction": prediction, "presence_penalty": presence_penalty, "response_format": response_format, "seed": seed, @@ -894,6 +909,7 @@ async def create( modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, @@ -931,7 +947,7 @@ async def create( [audio](https://platform.openai.com/docs/guides/audio). model: ID of the model to use. See the - [model endpoint compatibility](https://platform.openai.com/docs/models/model-endpoint-compatibility) + [model endpoint compatibility](https://platform.openai.com/docs/models#model-endpoint-compatibility) table for details on which models work with the Chat API. audio: Parameters for audio output. Required when audio output is requested with @@ -942,7 +958,7 @@ async def create( existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation/parameter-details) + [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) function_call: Deprecated in favor of `tool_choice`. @@ -1003,19 +1019,22 @@ async def create( choices. Keep `n` as `1` to minimize costs. parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling/parallel-function-calling) + [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) during tool use. + prediction: Static predicted output content, such as the content of a text file that is + being regenerated. + presence_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, increasing the model's likelihood to talk about new topics. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation/parameter-details) + [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) response_format: An object specifying the format that the model must output. Compatible with - [GPT-4o](https://platform.openai.com/docs/models/gpt-4o), - [GPT-4o mini](https://platform.openai.com/docs/models/gpt-4o-mini), - [GPT-4 Turbo](https://platform.openai.com/docs/models/gpt-4-and-gpt-4-turbo) and + [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), + [GPT-4o mini](https://platform.openai.com/docs/models#gpt-4o-mini), + [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4) and all GPT-3.5 Turbo models newer than `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured @@ -1102,7 +1121,7 @@ async def create( user: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids). + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). extra_headers: Send extra headers @@ -1133,6 +1152,7 @@ async def create( modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, @@ -1169,7 +1189,7 @@ async def create( [audio](https://platform.openai.com/docs/guides/audio). model: ID of the model to use. See the - [model endpoint compatibility](https://platform.openai.com/docs/models/model-endpoint-compatibility) + [model endpoint compatibility](https://platform.openai.com/docs/models#model-endpoint-compatibility) table for details on which models work with the Chat API. stream: If set, partial message deltas will be sent, like in ChatGPT. Tokens will be @@ -1187,7 +1207,7 @@ async def create( existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation/parameter-details) + [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) function_call: Deprecated in favor of `tool_choice`. @@ -1248,19 +1268,22 @@ async def create( choices. Keep `n` as `1` to minimize costs. parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling/parallel-function-calling) + [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) during tool use. + prediction: Static predicted output content, such as the content of a text file that is + being regenerated. + presence_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, increasing the model's likelihood to talk about new topics. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation/parameter-details) + [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) response_format: An object specifying the format that the model must output. Compatible with - [GPT-4o](https://platform.openai.com/docs/models/gpt-4o), - [GPT-4o mini](https://platform.openai.com/docs/models/gpt-4o-mini), - [GPT-4 Turbo](https://platform.openai.com/docs/models/gpt-4-and-gpt-4-turbo) and + [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), + [GPT-4o mini](https://platform.openai.com/docs/models#gpt-4o-mini), + [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4) and all GPT-3.5 Turbo models newer than `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured @@ -1340,7 +1363,7 @@ async def create( user: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids). + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). extra_headers: Send extra headers @@ -1371,6 +1394,7 @@ async def create( modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, @@ -1407,7 +1431,7 @@ async def create( [audio](https://platform.openai.com/docs/guides/audio). model: ID of the model to use. See the - [model endpoint compatibility](https://platform.openai.com/docs/models/model-endpoint-compatibility) + [model endpoint compatibility](https://platform.openai.com/docs/models#model-endpoint-compatibility) table for details on which models work with the Chat API. stream: If set, partial message deltas will be sent, like in ChatGPT. Tokens will be @@ -1425,7 +1449,7 @@ async def create( existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation/parameter-details) + [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) function_call: Deprecated in favor of `tool_choice`. @@ -1486,19 +1510,22 @@ async def create( choices. Keep `n` as `1` to minimize costs. parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling/parallel-function-calling) + [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) during tool use. + prediction: Static predicted output content, such as the content of a text file that is + being regenerated. + presence_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, increasing the model's likelihood to talk about new topics. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation/parameter-details) + [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) response_format: An object specifying the format that the model must output. Compatible with - [GPT-4o](https://platform.openai.com/docs/models/gpt-4o), - [GPT-4o mini](https://platform.openai.com/docs/models/gpt-4o-mini), - [GPT-4 Turbo](https://platform.openai.com/docs/models/gpt-4-and-gpt-4-turbo) and + [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), + [GPT-4o mini](https://platform.openai.com/docs/models#gpt-4o-mini), + [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4) and all GPT-3.5 Turbo models newer than `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured @@ -1578,7 +1605,7 @@ async def create( user: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids). + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). extra_headers: Send extra headers @@ -1608,6 +1635,7 @@ async def create( modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, @@ -1648,6 +1676,7 @@ async def create( "modalities": modalities, "n": n, "parallel_tool_calls": parallel_tool_calls, + "prediction": prediction, "presence_penalty": presence_penalty, "response_format": response_format, "seed": seed, diff --git a/src/openai/resources/completions.py b/src/openai/resources/completions.py index 49198d2687..1ac3575fd5 100644 --- a/src/openai/resources/completions.py +++ b/src/openai/resources/completions.py @@ -84,8 +84,8 @@ def create( model: ID of the model to use. You can use the [List models](https://platform.openai.com/docs/api-reference/models/list) API to see all of your available models, or see our - [Model overview](https://platform.openai.com/docs/models/overview) for - descriptions of them. + [Model overview](https://platform.openai.com/docs/models) for descriptions of + them. prompt: The prompt(s) to generate completions for, encoded as a string, array of strings, array of tokens, or array of token arrays. @@ -110,7 +110,7 @@ def create( existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation/parameter-details) + [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) logit_bias: Modify the likelihood of specified tokens appearing in the completion. @@ -150,7 +150,7 @@ def create( whether they appear in the text so far, increasing the model's likelihood to talk about new topics. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation/parameter-details) + [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) seed: If specified, our system will make a best effort to sample deterministically, such that repeated requests with the same `seed` and parameters should return @@ -189,7 +189,7 @@ def create( user: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids). + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). extra_headers: Send extra headers @@ -237,8 +237,8 @@ def create( model: ID of the model to use. You can use the [List models](https://platform.openai.com/docs/api-reference/models/list) API to see all of your available models, or see our - [Model overview](https://platform.openai.com/docs/models/overview) for - descriptions of them. + [Model overview](https://platform.openai.com/docs/models) for descriptions of + them. prompt: The prompt(s) to generate completions for, encoded as a string, array of strings, array of tokens, or array of token arrays. @@ -270,7 +270,7 @@ def create( existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation/parameter-details) + [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) logit_bias: Modify the likelihood of specified tokens appearing in the completion. @@ -310,7 +310,7 @@ def create( whether they appear in the text so far, increasing the model's likelihood to talk about new topics. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation/parameter-details) + [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) seed: If specified, our system will make a best effort to sample deterministically, such that repeated requests with the same `seed` and parameters should return @@ -342,7 +342,7 @@ def create( user: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids). + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). extra_headers: Send extra headers @@ -390,8 +390,8 @@ def create( model: ID of the model to use. You can use the [List models](https://platform.openai.com/docs/api-reference/models/list) API to see all of your available models, or see our - [Model overview](https://platform.openai.com/docs/models/overview) for - descriptions of them. + [Model overview](https://platform.openai.com/docs/models) for descriptions of + them. prompt: The prompt(s) to generate completions for, encoded as a string, array of strings, array of tokens, or array of token arrays. @@ -423,7 +423,7 @@ def create( existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation/parameter-details) + [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) logit_bias: Modify the likelihood of specified tokens appearing in the completion. @@ -463,7 +463,7 @@ def create( whether they appear in the text so far, increasing the model's likelihood to talk about new topics. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation/parameter-details) + [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) seed: If specified, our system will make a best effort to sample deterministically, such that repeated requests with the same `seed` and parameters should return @@ -495,7 +495,7 @@ def create( user: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids). + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). extra_headers: Send extra headers @@ -626,8 +626,8 @@ async def create( model: ID of the model to use. You can use the [List models](https://platform.openai.com/docs/api-reference/models/list) API to see all of your available models, or see our - [Model overview](https://platform.openai.com/docs/models/overview) for - descriptions of them. + [Model overview](https://platform.openai.com/docs/models) for descriptions of + them. prompt: The prompt(s) to generate completions for, encoded as a string, array of strings, array of tokens, or array of token arrays. @@ -652,7 +652,7 @@ async def create( existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation/parameter-details) + [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) logit_bias: Modify the likelihood of specified tokens appearing in the completion. @@ -692,7 +692,7 @@ async def create( whether they appear in the text so far, increasing the model's likelihood to talk about new topics. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation/parameter-details) + [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) seed: If specified, our system will make a best effort to sample deterministically, such that repeated requests with the same `seed` and parameters should return @@ -731,7 +731,7 @@ async def create( user: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids). + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). extra_headers: Send extra headers @@ -779,8 +779,8 @@ async def create( model: ID of the model to use. You can use the [List models](https://platform.openai.com/docs/api-reference/models/list) API to see all of your available models, or see our - [Model overview](https://platform.openai.com/docs/models/overview) for - descriptions of them. + [Model overview](https://platform.openai.com/docs/models) for descriptions of + them. prompt: The prompt(s) to generate completions for, encoded as a string, array of strings, array of tokens, or array of token arrays. @@ -812,7 +812,7 @@ async def create( existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation/parameter-details) + [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) logit_bias: Modify the likelihood of specified tokens appearing in the completion. @@ -852,7 +852,7 @@ async def create( whether they appear in the text so far, increasing the model's likelihood to talk about new topics. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation/parameter-details) + [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) seed: If specified, our system will make a best effort to sample deterministically, such that repeated requests with the same `seed` and parameters should return @@ -884,7 +884,7 @@ async def create( user: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids). + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). extra_headers: Send extra headers @@ -932,8 +932,8 @@ async def create( model: ID of the model to use. You can use the [List models](https://platform.openai.com/docs/api-reference/models/list) API to see all of your available models, or see our - [Model overview](https://platform.openai.com/docs/models/overview) for - descriptions of them. + [Model overview](https://platform.openai.com/docs/models) for descriptions of + them. prompt: The prompt(s) to generate completions for, encoded as a string, array of strings, array of tokens, or array of token arrays. @@ -965,7 +965,7 @@ async def create( existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation/parameter-details) + [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) logit_bias: Modify the likelihood of specified tokens appearing in the completion. @@ -1005,7 +1005,7 @@ async def create( whether they appear in the text so far, increasing the model's likelihood to talk about new topics. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation/parameter-details) + [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) seed: If specified, our system will make a best effort to sample deterministically, such that repeated requests with the same `seed` and parameters should return @@ -1037,7 +1037,7 @@ async def create( user: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids). + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). extra_headers: Send extra headers diff --git a/src/openai/resources/embeddings.py b/src/openai/resources/embeddings.py index c91e6cc13a..4ab2278e89 100644 --- a/src/openai/resources/embeddings.py +++ b/src/openai/resources/embeddings.py @@ -73,8 +73,8 @@ def create( model: ID of the model to use. You can use the [List models](https://platform.openai.com/docs/api-reference/models/list) API to see all of your available models, or see our - [Model overview](https://platform.openai.com/docs/models/overview) for - descriptions of them. + [Model overview](https://platform.openai.com/docs/models) for descriptions of + them. dimensions: The number of dimensions the resulting output embeddings should have. Only supported in `text-embedding-3` and later models. @@ -84,7 +84,7 @@ def create( user: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids). + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). extra_headers: Send extra headers @@ -185,8 +185,8 @@ async def create( model: ID of the model to use. You can use the [List models](https://platform.openai.com/docs/api-reference/models/list) API to see all of your available models, or see our - [Model overview](https://platform.openai.com/docs/models/overview) for - descriptions of them. + [Model overview](https://platform.openai.com/docs/models) for descriptions of + them. dimensions: The number of dimensions the resulting output embeddings should have. Only supported in `text-embedding-3` and later models. @@ -196,7 +196,7 @@ async def create( user: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids). + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). extra_headers: Send extra headers diff --git a/src/openai/resources/files.py b/src/openai/resources/files.py index e24eeec711..77706a7fd8 100644 --- a/src/openai/resources/files.py +++ b/src/openai/resources/files.py @@ -5,6 +5,7 @@ import time import typing_extensions from typing import Mapping, cast +from typing_extensions import Literal import httpx @@ -27,11 +28,8 @@ to_custom_streamed_response_wrapper, async_to_custom_streamed_response_wrapper, ) -from ..pagination import SyncPage, AsyncPage -from .._base_client import ( - AsyncPaginator, - make_request_options, -) +from ..pagination import SyncCursorPage, AsyncCursorPage +from .._base_client import AsyncPaginator, make_request_options from ..types.file_object import FileObject from ..types.file_deleted import FileDeleted from ..types.file_purpose import FilePurpose @@ -172,6 +170,9 @@ def retrieve( def list( self, *, + after: str | NotGiven = NOT_GIVEN, + limit: int | NotGiven = NOT_GIVEN, + order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, purpose: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -179,11 +180,23 @@ def list( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> SyncPage[FileObject]: - """ - Returns a list of files that belong to the user's organization. + ) -> SyncCursorPage[FileObject]: + """Returns a list of files. Args: + after: A cursor for use in pagination. + + `after` is an object ID that defines your place + in the list. For instance, if you make a list request and receive 100 objects, + ending with obj_foo, your subsequent call can include after=obj_foo in order to + fetch the next page of the list. + + limit: A limit on the number of objects to be returned. Limit can range between 1 and + 10,000, and the default is 10,000. + + order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending + order and `desc` for descending order. + purpose: Only return files with the given purpose. extra_headers: Send extra headers @@ -196,13 +209,21 @@ def list( """ return self._get_api_list( "/files", - page=SyncPage[FileObject], + page=SyncCursorPage[FileObject], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, - query=maybe_transform({"purpose": purpose}, file_list_params.FileListParams), + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + "purpose": purpose, + }, + file_list_params.FileListParams, + ), ), model=FileObject, ) @@ -465,6 +486,9 @@ async def retrieve( def list( self, *, + after: str | NotGiven = NOT_GIVEN, + limit: int | NotGiven = NOT_GIVEN, + order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, purpose: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -472,11 +496,23 @@ def list( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncPaginator[FileObject, AsyncPage[FileObject]]: - """ - Returns a list of files that belong to the user's organization. + ) -> AsyncPaginator[FileObject, AsyncCursorPage[FileObject]]: + """Returns a list of files. Args: + after: A cursor for use in pagination. + + `after` is an object ID that defines your place + in the list. For instance, if you make a list request and receive 100 objects, + ending with obj_foo, your subsequent call can include after=obj_foo in order to + fetch the next page of the list. + + limit: A limit on the number of objects to be returned. Limit can range between 1 and + 10,000, and the default is 10,000. + + order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending + order and `desc` for descending order. + purpose: Only return files with the given purpose. extra_headers: Send extra headers @@ -489,13 +525,21 @@ def list( """ return self._get_api_list( "/files", - page=AsyncPage[FileObject], + page=AsyncCursorPage[FileObject], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, - query=maybe_transform({"purpose": purpose}, file_list_params.FileListParams), + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + "purpose": purpose, + }, + file_list_params.FileListParams, + ), ), model=FileObject, ) diff --git a/src/openai/resources/fine_tuning/jobs/jobs.py b/src/openai/resources/fine_tuning/jobs/jobs.py index 44abf1cfe1..0ed5495b0e 100644 --- a/src/openai/resources/fine_tuning/jobs/jobs.py +++ b/src/openai/resources/fine_tuning/jobs/jobs.py @@ -88,7 +88,7 @@ def create( Args: model: The name of the model to fine-tune. You can select one of the - [supported models](https://platform.openai.com/docs/guides/fine-tuning/which-models-can-be-fine-tuned). + [supported models](https://platform.openai.com/docs/guides/fine-tuning#which-models-can-be-fine-tuned). training_file: The ID of an uploaded file that contains training data. @@ -379,7 +379,7 @@ async def create( Args: model: The name of the model to fine-tune. You can select one of the - [supported models](https://platform.openai.com/docs/guides/fine-tuning/which-models-can-be-fine-tuned). + [supported models](https://platform.openai.com/docs/guides/fine-tuning#which-models-can-be-fine-tuned). training_file: The ID of an uploaded file that contains training data. diff --git a/src/openai/resources/images.py b/src/openai/resources/images.py index e9629d48fd..2fbc077dd9 100644 --- a/src/openai/resources/images.py +++ b/src/openai/resources/images.py @@ -84,7 +84,7 @@ def create_variation( user: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids). + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). extra_headers: Send extra headers @@ -165,7 +165,7 @@ def edit( user: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids). + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). extra_headers: Send extra headers @@ -251,7 +251,7 @@ def generate( user: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids). + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). extra_headers: Send extra headers @@ -341,7 +341,7 @@ async def create_variation( user: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids). + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). extra_headers: Send extra headers @@ -422,7 +422,7 @@ async def edit( user: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids). + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). extra_headers: Send extra headers @@ -508,7 +508,7 @@ async def generate( user: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids). + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). extra_headers: Send extra headers diff --git a/src/openai/resources/moderations.py b/src/openai/resources/moderations.py index 8b73da57b2..ce80bb7d55 100644 --- a/src/openai/resources/moderations.py +++ b/src/openai/resources/moderations.py @@ -68,7 +68,7 @@ def create( model: The content moderation model you would like to use. Learn more in [the moderation guide](https://platform.openai.com/docs/guides/moderation), and learn about available models - [here](https://platform.openai.com/docs/models/moderation). + [here](https://platform.openai.com/docs/models#moderation). extra_headers: Send extra headers @@ -138,7 +138,7 @@ async def create( model: The content moderation model you would like to use. Learn more in [the moderation guide](https://platform.openai.com/docs/guides/moderation), and learn about available models - [here](https://platform.openai.com/docs/models/moderation). + [here](https://platform.openai.com/docs/models#moderation). extra_headers: Send extra headers diff --git a/src/openai/resources/uploads/uploads.py b/src/openai/resources/uploads/uploads.py index 96a531a8e4..cfb500b62c 100644 --- a/src/openai/resources/uploads/uploads.py +++ b/src/openai/resources/uploads/uploads.py @@ -196,7 +196,7 @@ def create( For certain `purpose`s, the correct `mime_type` must be specified. Please refer to documentation for the supported MIME types for your use case: - - [Assistants](https://platform.openai.com/docs/assistants/tools/file-search/supported-files) + - [Assistants](https://platform.openai.com/docs/assistants/tools/file-search#supported-files) For guidance on the proper filename extensions for each purpose, please follow the documentation on @@ -500,7 +500,7 @@ async def create( For certain `purpose`s, the correct `mime_type` must be specified. Please refer to documentation for the supported MIME types for your use case: - - [Assistants](https://platform.openai.com/docs/assistants/tools/file-search/supported-files) + - [Assistants](https://platform.openai.com/docs/assistants/tools/file-search#supported-files) For guidance on the proper filename extensions for each purpose, please follow the documentation on diff --git a/src/openai/types/audio/speech_create_params.py b/src/openai/types/audio/speech_create_params.py index dff66e49c7..a60d000708 100644 --- a/src/openai/types/audio/speech_create_params.py +++ b/src/openai/types/audio/speech_create_params.py @@ -16,7 +16,7 @@ class SpeechCreateParams(TypedDict, total=False): model: Required[Union[str, SpeechModel]] """ - One of the available [TTS models](https://platform.openai.com/docs/models/tts): + One of the available [TTS models](https://platform.openai.com/docs/models#tts): `tts-1` or `tts-1-hd` """ @@ -25,7 +25,7 @@ class SpeechCreateParams(TypedDict, total=False): Supported voices are `alloy`, `echo`, `fable`, `onyx`, `nova`, and `shimmer`. Previews of the voices are available in the - [Text to speech guide](https://platform.openai.com/docs/guides/text-to-speech/voice-options). + [Text to speech guide](https://platform.openai.com/docs/guides/text-to-speech#voice-options). """ response_format: Literal["mp3", "opus", "aac", "flac", "wav", "pcm"] diff --git a/src/openai/types/audio/transcription_create_params.py b/src/openai/types/audio/transcription_create_params.py index 5ac2bb91e5..88805affbd 100644 --- a/src/openai/types/audio/transcription_create_params.py +++ b/src/openai/types/audio/transcription_create_params.py @@ -38,7 +38,7 @@ class TranscriptionCreateParams(TypedDict, total=False): """An optional text to guide the model's style or continue a previous audio segment. - The [prompt](https://platform.openai.com/docs/guides/speech-to-text/prompting) + The [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) should match the audio language. """ diff --git a/src/openai/types/audio/translation_create_params.py b/src/openai/types/audio/translation_create_params.py index 6859ed9d30..62f85b8757 100644 --- a/src/openai/types/audio/translation_create_params.py +++ b/src/openai/types/audio/translation_create_params.py @@ -30,7 +30,7 @@ class TranslationCreateParams(TypedDict, total=False): """An optional text to guide the model's style or continue a previous audio segment. - The [prompt](https://platform.openai.com/docs/guides/speech-to-text/prompting) + The [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) should be in English. """ diff --git a/src/openai/types/beta/assistant.py b/src/openai/types/beta/assistant.py index ea97de440f..3c8b8e403b 100644 --- a/src/openai/types/beta/assistant.py +++ b/src/openai/types/beta/assistant.py @@ -65,8 +65,8 @@ class Assistant(BaseModel): You can use the [List models](https://platform.openai.com/docs/api-reference/models/list) API to see all of your available models, or see our - [Model overview](https://platform.openai.com/docs/models/overview) for - descriptions of them. + [Model overview](https://platform.openai.com/docs/models) for descriptions of + them. """ name: Optional[str] = None @@ -85,8 +85,8 @@ class Assistant(BaseModel): response_format: Optional[AssistantResponseFormatOption] = None """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), + 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), and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured diff --git a/src/openai/types/beta/assistant_create_params.py b/src/openai/types/beta/assistant_create_params.py index e11f842f05..568b223ce7 100644 --- a/src/openai/types/beta/assistant_create_params.py +++ b/src/openai/types/beta/assistant_create_params.py @@ -26,8 +26,8 @@ class AssistantCreateParams(TypedDict, total=False): You can use the [List models](https://platform.openai.com/docs/api-reference/models/list) API to see all of your available models, or see our - [Model overview](https://platform.openai.com/docs/models/overview) for - descriptions of them. + [Model overview](https://platform.openai.com/docs/models) for descriptions of + them. """ description: Optional[str] @@ -53,8 +53,8 @@ class AssistantCreateParams(TypedDict, total=False): response_format: Optional[AssistantResponseFormatOptionParam] """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), + 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), and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured diff --git a/src/openai/types/beta/assistant_list_params.py b/src/openai/types/beta/assistant_list_params.py index f54f63120b..834ffbcaf8 100644 --- a/src/openai/types/beta/assistant_list_params.py +++ b/src/openai/types/beta/assistant_list_params.py @@ -21,7 +21,7 @@ class AssistantListParams(TypedDict, total=False): """A cursor for use in pagination. `before` is an object ID that defines your place in the list. For instance, if - you make a list request and receive 100 objects, ending with obj_foo, your + you make a list request and receive 100 objects, starting with obj_foo, your subsequent call can include before=obj_foo in order to fetch the previous page of the list. """ diff --git a/src/openai/types/beta/assistant_update_params.py b/src/openai/types/beta/assistant_update_params.py index c4598df507..9a66e41ab3 100644 --- a/src/openai/types/beta/assistant_update_params.py +++ b/src/openai/types/beta/assistant_update_params.py @@ -35,8 +35,8 @@ class AssistantUpdateParams(TypedDict, total=False): You can use the [List models](https://platform.openai.com/docs/api-reference/models/list) API to see all of your available models, or see our - [Model overview](https://platform.openai.com/docs/models/overview) for - descriptions of them. + [Model overview](https://platform.openai.com/docs/models) for descriptions of + them. """ name: Optional[str] @@ -45,8 +45,8 @@ class AssistantUpdateParams(TypedDict, total=False): response_format: Optional[AssistantResponseFormatOptionParam] """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), + 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), and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured diff --git a/src/openai/types/beta/file_search_tool.py b/src/openai/types/beta/file_search_tool.py index aee6593e89..89fc16c04c 100644 --- a/src/openai/types/beta/file_search_tool.py +++ b/src/openai/types/beta/file_search_tool.py @@ -31,7 +31,7 @@ class FileSearch(BaseModel): Note that the file search tool may output fewer than `max_num_results` results. See the - [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search/customizing-file-search-settings) + [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) for more information. """ @@ -42,7 +42,7 @@ class FileSearch(BaseModel): score_threshold of 0. See the - [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search/customizing-file-search-settings) + [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) for more information. """ diff --git a/src/openai/types/beta/file_search_tool_param.py b/src/openai/types/beta/file_search_tool_param.py index 5ce91207ba..c73d0af79d 100644 --- a/src/openai/types/beta/file_search_tool_param.py +++ b/src/openai/types/beta/file_search_tool_param.py @@ -30,7 +30,7 @@ class FileSearch(TypedDict, total=False): Note that the file search tool may output fewer than `max_num_results` results. See the - [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search/customizing-file-search-settings) + [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) for more information. """ @@ -41,7 +41,7 @@ class FileSearch(TypedDict, total=False): score_threshold of 0. See the - [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search/customizing-file-search-settings) + [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) for more information. """ diff --git a/src/openai/types/beta/thread_create_and_run_params.py b/src/openai/types/beta/thread_create_and_run_params.py index 64ee6a8710..8310ba12f4 100644 --- a/src/openai/types/beta/thread_create_and_run_params.py +++ b/src/openai/types/beta/thread_create_and_run_params.py @@ -86,15 +86,15 @@ class ThreadCreateAndRunParamsBase(TypedDict, total=False): parallel_tool_calls: bool """ Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling/parallel-function-calling) + [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) during tool use. """ response_format: Optional[AssistantResponseFormatOptionParam] """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), + 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), and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured diff --git a/src/openai/types/beta/threads/message_list_params.py b/src/openai/types/beta/threads/message_list_params.py index 18c2442fb5..a7c22a66fb 100644 --- a/src/openai/types/beta/threads/message_list_params.py +++ b/src/openai/types/beta/threads/message_list_params.py @@ -21,7 +21,7 @@ class MessageListParams(TypedDict, total=False): """A cursor for use in pagination. `before` is an object ID that defines your place in the list. For instance, if - you make a list request and receive 100 objects, ending with obj_foo, your + you make a list request and receive 100 objects, starting with obj_foo, your subsequent call can include before=obj_foo in order to fetch the previous page of the list. """ diff --git a/src/openai/types/beta/threads/run.py b/src/openai/types/beta/threads/run.py index e8f2b74dee..ad32135b7d 100644 --- a/src/openai/types/beta/threads/run.py +++ b/src/openai/types/beta/threads/run.py @@ -154,7 +154,7 @@ class Run(BaseModel): parallel_tool_calls: bool """ Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling/parallel-function-calling) + [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) during tool use. """ @@ -167,8 +167,8 @@ class Run(BaseModel): response_format: Optional[AssistantResponseFormatOption] = None """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), + 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), and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured diff --git a/src/openai/types/beta/threads/run_create_params.py b/src/openai/types/beta/threads/run_create_params.py index 9767b142e1..88dc39645e 100644 --- a/src/openai/types/beta/threads/run_create_params.py +++ b/src/openai/types/beta/threads/run_create_params.py @@ -41,7 +41,7 @@ class RunCreateParamsBase(TypedDict, total=False): search result content. See the - [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search/customizing-file-search-settings) + [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) for more information. """ @@ -99,15 +99,15 @@ class RunCreateParamsBase(TypedDict, total=False): parallel_tool_calls: bool """ Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling/parallel-function-calling) + [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) during tool use. """ response_format: Optional[AssistantResponseFormatOptionParam] """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), + 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), and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured diff --git a/src/openai/types/beta/threads/run_list_params.py b/src/openai/types/beta/threads/run_list_params.py index 1e32bca4b4..fbea54f6f2 100644 --- a/src/openai/types/beta/threads/run_list_params.py +++ b/src/openai/types/beta/threads/run_list_params.py @@ -21,7 +21,7 @@ class RunListParams(TypedDict, total=False): """A cursor for use in pagination. `before` is an object ID that defines your place in the list. For instance, if - you make a list request and receive 100 objects, ending with obj_foo, your + you make a list request and receive 100 objects, starting with obj_foo, your subsequent call can include before=obj_foo in order to fetch the previous page of the list. """ diff --git a/src/openai/types/beta/threads/runs/step_list_params.py b/src/openai/types/beta/threads/runs/step_list_params.py index 3931bd7e0c..a6be771d9f 100644 --- a/src/openai/types/beta/threads/runs/step_list_params.py +++ b/src/openai/types/beta/threads/runs/step_list_params.py @@ -26,7 +26,7 @@ class StepListParams(TypedDict, total=False): """A cursor for use in pagination. `before` is an object ID that defines your place in the list. For instance, if - you make a list request and receive 100 objects, ending with obj_foo, your + you make a list request and receive 100 objects, starting with obj_foo, your subsequent call can include before=obj_foo in order to fetch the previous page of the list. """ @@ -39,7 +39,7 @@ class StepListParams(TypedDict, total=False): search result content. See the - [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search/customizing-file-search-settings) + [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) for more information. """ diff --git a/src/openai/types/beta/threads/runs/step_retrieve_params.py b/src/openai/types/beta/threads/runs/step_retrieve_params.py index 22c1c049f4..ecbb72edbd 100644 --- a/src/openai/types/beta/threads/runs/step_retrieve_params.py +++ b/src/openai/types/beta/threads/runs/step_retrieve_params.py @@ -23,6 +23,6 @@ class StepRetrieveParams(TypedDict, total=False): search result content. See the - [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search/customizing-file-search-settings) + [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) for more information. """ diff --git a/src/openai/types/beta/vector_store_list_params.py b/src/openai/types/beta/vector_store_list_params.py index f39f67266d..e26ff90a85 100644 --- a/src/openai/types/beta/vector_store_list_params.py +++ b/src/openai/types/beta/vector_store_list_params.py @@ -21,7 +21,7 @@ class VectorStoreListParams(TypedDict, total=False): """A cursor for use in pagination. `before` is an object ID that defines your place in the list. For instance, if - you make a list request and receive 100 objects, ending with obj_foo, your + you make a list request and receive 100 objects, starting with obj_foo, your subsequent call can include before=obj_foo in order to fetch the previous page of the list. """ diff --git a/src/openai/types/beta/vector_stores/file_batch_list_files_params.py b/src/openai/types/beta/vector_stores/file_batch_list_files_params.py index 24dee7d5a5..2a0a6c6aa7 100644 --- a/src/openai/types/beta/vector_stores/file_batch_list_files_params.py +++ b/src/openai/types/beta/vector_stores/file_batch_list_files_params.py @@ -23,7 +23,7 @@ class FileBatchListFilesParams(TypedDict, total=False): """A cursor for use in pagination. `before` is an object ID that defines your place in the list. For instance, if - you make a list request and receive 100 objects, ending with obj_foo, your + you make a list request and receive 100 objects, starting with obj_foo, your subsequent call can include before=obj_foo in order to fetch the previous page of the list. """ diff --git a/src/openai/types/beta/vector_stores/file_list_params.py b/src/openai/types/beta/vector_stores/file_list_params.py index 23dd7f0d94..867b5fb3bb 100644 --- a/src/openai/types/beta/vector_stores/file_list_params.py +++ b/src/openai/types/beta/vector_stores/file_list_params.py @@ -21,7 +21,7 @@ class FileListParams(TypedDict, total=False): """A cursor for use in pagination. `before` is an object ID that defines your place in the list. For instance, if - you make a list request and receive 100 objects, ending with obj_foo, your + you make a list request and receive 100 objects, starting with obj_foo, your subsequent call can include before=obj_foo in order to fetch the previous page of the list. """ diff --git a/src/openai/types/chat/__init__.py b/src/openai/types/chat/__init__.py index eb818a132e..d0a5403e79 100644 --- a/src/openai/types/chat/__init__.py +++ b/src/openai/types/chat/__init__.py @@ -46,6 +46,9 @@ from .chat_completion_content_part_image_param import ( ChatCompletionContentPartImageParam as ChatCompletionContentPartImageParam, ) +from .chat_completion_prediction_content_param import ( + ChatCompletionPredictionContentParam as ChatCompletionPredictionContentParam, +) from .chat_completion_tool_choice_option_param import ( ChatCompletionToolChoiceOptionParam as ChatCompletionToolChoiceOptionParam, ) diff --git a/src/openai/types/chat/chat_completion_content_part_image_param.py b/src/openai/types/chat/chat_completion_content_part_image_param.py index b1a186aa6d..9d407324d0 100644 --- a/src/openai/types/chat/chat_completion_content_part_image_param.py +++ b/src/openai/types/chat/chat_completion_content_part_image_param.py @@ -15,7 +15,7 @@ class ImageURL(TypedDict, total=False): """Specifies the detail level of the image. Learn more in the - [Vision guide](https://platform.openai.com/docs/guides/vision/low-or-high-fidelity-image-understanding). + [Vision guide](https://platform.openai.com/docs/guides/vision#low-or-high-fidelity-image-understanding). """ diff --git a/src/openai/types/chat/chat_completion_prediction_content_param.py b/src/openai/types/chat/chat_completion_prediction_content_param.py new file mode 100644 index 0000000000..c44e6e3653 --- /dev/null +++ b/src/openai/types/chat/chat_completion_prediction_content_param.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable +from typing_extensions import Literal, Required, TypedDict + +from .chat_completion_content_part_text_param import ChatCompletionContentPartTextParam + +__all__ = ["ChatCompletionPredictionContentParam"] + + +class ChatCompletionPredictionContentParam(TypedDict, total=False): + content: Required[Union[str, Iterable[ChatCompletionContentPartTextParam]]] + """ + The content that should be matched when generating a model response. If + generated tokens would match this content, the entire model response can be + returned much more quickly. + """ + + type: Required[Literal["content"]] + """The type of the predicted content you want to provide. + + This type is currently always `content`. + """ diff --git a/src/openai/types/chat/completion_create_params.py b/src/openai/types/chat/completion_create_params.py index af6a47c219..e838858314 100644 --- a/src/openai/types/chat/completion_create_params.py +++ b/src/openai/types/chat/completion_create_params.py @@ -13,6 +13,7 @@ from ..shared_params.function_parameters import FunctionParameters from ..shared_params.response_format_text import ResponseFormatText from .chat_completion_stream_options_param import ChatCompletionStreamOptionsParam +from .chat_completion_prediction_content_param import ChatCompletionPredictionContentParam from .chat_completion_tool_choice_option_param import ChatCompletionToolChoiceOptionParam from ..shared_params.response_format_json_object import ResponseFormatJSONObject from ..shared_params.response_format_json_schema import ResponseFormatJSONSchema @@ -43,7 +44,7 @@ class CompletionCreateParamsBase(TypedDict, total=False): """ID of the model to use. See the - [model endpoint compatibility](https://platform.openai.com/docs/models/model-endpoint-compatibility) + [model endpoint compatibility](https://platform.openai.com/docs/models#model-endpoint-compatibility) table for details on which models work with the Chat API. """ @@ -60,7 +61,7 @@ class CompletionCreateParamsBase(TypedDict, total=False): Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation/parameter-details) + [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) """ function_call: FunctionCall @@ -148,25 +149,31 @@ class CompletionCreateParamsBase(TypedDict, total=False): parallel_tool_calls: bool """ Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling/parallel-function-calling) + [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) during tool use. """ + prediction: Optional[ChatCompletionPredictionContentParam] + """ + Static predicted output content, such as the content of a text file that is + being regenerated. + """ + presence_penalty: Optional[float] """Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, increasing the model's likelihood to talk about new topics. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation/parameter-details) + [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) """ response_format: ResponseFormat """An object specifying the format that the model must output. - Compatible with [GPT-4o](https://platform.openai.com/docs/models/gpt-4o), - [GPT-4o mini](https://platform.openai.com/docs/models/gpt-4o-mini), - [GPT-4 Turbo](https://platform.openai.com/docs/models/gpt-4-and-gpt-4-turbo) and + Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), + [GPT-4o mini](https://platform.openai.com/docs/models#gpt-4o-mini), + [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4) and all GPT-3.5 Turbo models newer than `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured @@ -276,7 +283,7 @@ class CompletionCreateParamsBase(TypedDict, total=False): """ A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids). + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). """ diff --git a/src/openai/types/completion_create_params.py b/src/openai/types/completion_create_params.py index 6c112b3902..fdb1680d26 100644 --- a/src/openai/types/completion_create_params.py +++ b/src/openai/types/completion_create_params.py @@ -17,8 +17,8 @@ class CompletionCreateParamsBase(TypedDict, total=False): You can use the [List models](https://platform.openai.com/docs/api-reference/models/list) API to see all of your available models, or see our - [Model overview](https://platform.openai.com/docs/models/overview) for - descriptions of them. + [Model overview](https://platform.openai.com/docs/models) for descriptions of + them. """ prompt: Required[Union[str, List[str], Iterable[int], Iterable[Iterable[int]], None]] @@ -53,7 +53,7 @@ class CompletionCreateParamsBase(TypedDict, total=False): Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation/parameter-details) + [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) """ logit_bias: Optional[Dict[str, int]] @@ -106,7 +106,7 @@ class CompletionCreateParamsBase(TypedDict, total=False): Positive values penalize new tokens based on whether they appear in the text so far, increasing the model's likelihood to talk about new topics. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation/parameter-details) + [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) """ seed: Optional[int] @@ -156,7 +156,7 @@ class CompletionCreateParamsBase(TypedDict, total=False): """ A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids). + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). """ diff --git a/src/openai/types/completion_usage.py b/src/openai/types/completion_usage.py index fe112833e0..d8c4e84cf7 100644 --- a/src/openai/types/completion_usage.py +++ b/src/openai/types/completion_usage.py @@ -8,12 +8,26 @@ class CompletionTokensDetails(BaseModel): + accepted_prediction_tokens: Optional[int] = None + """ + When using Predicted Outputs, the number of tokens in the prediction that + appeared in the completion. + """ + audio_tokens: Optional[int] = None """Audio input tokens generated by the model.""" reasoning_tokens: Optional[int] = None """Tokens generated by the model for reasoning.""" + rejected_prediction_tokens: Optional[int] = None + """ + When using Predicted Outputs, the number of tokens in the prediction that did + not appear in the completion. However, like reasoning tokens, these tokens are + still counted in the total completion tokens for purposes of billing, output, + and context window limits. + """ + class PromptTokensDetails(BaseModel): audio_tokens: Optional[int] = None diff --git a/src/openai/types/embedding_create_params.py b/src/openai/types/embedding_create_params.py index 1548cdbd77..1385762885 100644 --- a/src/openai/types/embedding_create_params.py +++ b/src/openai/types/embedding_create_params.py @@ -28,8 +28,8 @@ class EmbeddingCreateParams(TypedDict, total=False): You can use the [List models](https://platform.openai.com/docs/api-reference/models/list) API to see all of your available models, or see our - [Model overview](https://platform.openai.com/docs/models/overview) for - descriptions of them. + [Model overview](https://platform.openai.com/docs/models) for descriptions of + them. """ dimensions: int @@ -48,5 +48,5 @@ class EmbeddingCreateParams(TypedDict, total=False): """ A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids). + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). """ diff --git a/src/openai/types/file_list_params.py b/src/openai/types/file_list_params.py index 212eca13c0..058d874c29 100644 --- a/src/openai/types/file_list_params.py +++ b/src/openai/types/file_list_params.py @@ -2,11 +2,32 @@ from __future__ import annotations -from typing_extensions import TypedDict +from typing_extensions import Literal, TypedDict __all__ = ["FileListParams"] class FileListParams(TypedDict, total=False): + after: str + """A cursor for use in pagination. + + `after` is an object ID that defines your place in the list. For instance, if + you make a list request and receive 100 objects, ending with obj_foo, your + subsequent call can include after=obj_foo in order to fetch the next page of the + list. + """ + + limit: int + """A limit on the number of objects to be returned. + + Limit can range between 1 and 10,000, and the default is 10,000. + """ + + order: Literal["asc", "desc"] + """Sort order by the `created_at` timestamp of the objects. + + `asc` for ascending order and `desc` for descending order. + """ + purpose: str """Only return files with the given purpose.""" diff --git a/src/openai/types/fine_tuning/job_create_params.py b/src/openai/types/fine_tuning/job_create_params.py index 8f5ea86274..8814229b2e 100644 --- a/src/openai/types/fine_tuning/job_create_params.py +++ b/src/openai/types/fine_tuning/job_create_params.py @@ -13,7 +13,7 @@ class JobCreateParams(TypedDict, total=False): """The name of the model to fine-tune. You can select one of the - [supported models](https://platform.openai.com/docs/guides/fine-tuning/which-models-can-be-fine-tuned). + [supported models](https://platform.openai.com/docs/guides/fine-tuning#which-models-can-be-fine-tuned). """ training_file: Required[str] diff --git a/src/openai/types/image_create_variation_params.py b/src/openai/types/image_create_variation_params.py index d6ecf0f1ae..d20f672912 100644 --- a/src/openai/types/image_create_variation_params.py +++ b/src/openai/types/image_create_variation_params.py @@ -47,5 +47,5 @@ class ImageCreateVariationParams(TypedDict, total=False): """ A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids). + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). """ diff --git a/src/openai/types/image_edit_params.py b/src/openai/types/image_edit_params.py index a596a8692b..1cb10611f3 100644 --- a/src/openai/types/image_edit_params.py +++ b/src/openai/types/image_edit_params.py @@ -58,5 +58,5 @@ class ImageEditParams(TypedDict, total=False): """ A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids). + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). """ diff --git a/src/openai/types/image_generate_params.py b/src/openai/types/image_generate_params.py index 307adeb3da..c88c45f518 100644 --- a/src/openai/types/image_generate_params.py +++ b/src/openai/types/image_generate_params.py @@ -61,5 +61,5 @@ class ImageGenerateParams(TypedDict, total=False): """ A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids). + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). """ diff --git a/src/openai/types/moderation_create_params.py b/src/openai/types/moderation_create_params.py index 3193fd9c2d..3ea2f3cd88 100644 --- a/src/openai/types/moderation_create_params.py +++ b/src/openai/types/moderation_create_params.py @@ -25,5 +25,5 @@ class ModerationCreateParams(TypedDict, total=False): Learn more in [the moderation guide](https://platform.openai.com/docs/guides/moderation), and learn about available models - [here](https://platform.openai.com/docs/models/moderation). + [here](https://platform.openai.com/docs/models#moderation). """ diff --git a/tests/api_resources/chat/test_completions.py b/tests/api_resources/chat/test_completions.py index d7162dc7db..dafedac9fb 100644 --- a/tests/api_resources/chat/test_completions.py +++ b/tests/api_resources/chat/test_completions.py @@ -65,6 +65,10 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: modalities=["text", "audio"], n=1, parallel_tool_calls=True, + prediction={ + "content": "string", + "type": "content", + }, presence_penalty=-2, response_format={"type": "text"}, seed=-9007199254740991, @@ -193,6 +197,10 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: modalities=["text", "audio"], n=1, parallel_tool_calls=True, + prediction={ + "content": "string", + "type": "content", + }, presence_penalty=-2, response_format={"type": "text"}, seed=-9007199254740991, @@ -340,6 +348,10 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn modalities=["text", "audio"], n=1, parallel_tool_calls=True, + prediction={ + "content": "string", + "type": "content", + }, presence_penalty=-2, response_format={"type": "text"}, seed=-9007199254740991, @@ -468,6 +480,10 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn modalities=["text", "audio"], n=1, parallel_tool_calls=True, + prediction={ + "content": "string", + "type": "content", + }, presence_penalty=-2, response_format={"type": "text"}, seed=-9007199254740991, diff --git a/tests/api_resources/test_files.py b/tests/api_resources/test_files.py index 882f0ddbe7..7402566d95 100644 --- a/tests/api_resources/test_files.py +++ b/tests/api_resources/test_files.py @@ -13,7 +13,7 @@ from openai import OpenAI, AsyncOpenAI from tests.utils import assert_matches_type from openai.types import FileObject, FileDeleted -from openai.pagination import SyncPage, AsyncPage +from openai.pagination import SyncCursorPage, AsyncCursorPage # pyright: reportDeprecated=false @@ -98,14 +98,17 @@ def test_path_params_retrieve(self, client: OpenAI) -> None: @parametrize def test_method_list(self, client: OpenAI) -> None: file = client.files.list() - assert_matches_type(SyncPage[FileObject], file, path=["response"]) + assert_matches_type(SyncCursorPage[FileObject], file, path=["response"]) @parametrize def test_method_list_with_all_params(self, client: OpenAI) -> None: file = client.files.list( - purpose="string", + after="after", + limit=0, + order="asc", + purpose="purpose", ) - assert_matches_type(SyncPage[FileObject], file, path=["response"]) + assert_matches_type(SyncCursorPage[FileObject], file, path=["response"]) @parametrize def test_raw_response_list(self, client: OpenAI) -> None: @@ -114,7 +117,7 @@ def test_raw_response_list(self, client: OpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" file = response.parse() - assert_matches_type(SyncPage[FileObject], file, path=["response"]) + assert_matches_type(SyncCursorPage[FileObject], file, path=["response"]) @parametrize def test_streaming_response_list(self, client: OpenAI) -> None: @@ -123,7 +126,7 @@ def test_streaming_response_list(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" file = response.parse() - assert_matches_type(SyncPage[FileObject], file, path=["response"]) + assert_matches_type(SyncCursorPage[FileObject], file, path=["response"]) assert cast(Any, response.is_closed) is True @@ -334,14 +337,17 @@ async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_method_list(self, async_client: AsyncOpenAI) -> None: file = await async_client.files.list() - assert_matches_type(AsyncPage[FileObject], file, path=["response"]) + assert_matches_type(AsyncCursorPage[FileObject], file, path=["response"]) @parametrize async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: file = await async_client.files.list( - purpose="string", + after="after", + limit=0, + order="asc", + purpose="purpose", ) - assert_matches_type(AsyncPage[FileObject], file, path=["response"]) + assert_matches_type(AsyncCursorPage[FileObject], file, path=["response"]) @parametrize async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: @@ -350,7 +356,7 @@ async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" file = response.parse() - assert_matches_type(AsyncPage[FileObject], file, path=["response"]) + assert_matches_type(AsyncCursorPage[FileObject], file, path=["response"]) @parametrize async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: @@ -359,7 +365,7 @@ async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" file = await response.parse() - assert_matches_type(AsyncPage[FileObject], file, path=["response"]) + assert_matches_type(AsyncCursorPage[FileObject], file, path=["response"]) assert cast(Any, response.is_closed) is True From b32507dd793b6b1dc218f76f7b485ae441db8841 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 22:48:18 +0000 Subject: [PATCH 071/769] release: 1.54.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 9 +++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 5a86c0906c..7e66027ecd 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.53.1" + ".": "1.54.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index c3a5a3cecb..a60cd5cd31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 1.54.0 (2024-11-04) + +Full Changelog: [v1.53.1...v1.54.0](https://github.com/openai/openai-python/compare/v1.53.1...v1.54.0) + +### Features + +* **api:** add support for predicted outputs ([#1847](https://github.com/openai/openai-python/issues/1847)) ([42a4103](https://github.com/openai/openai-python/commit/42a410379a1b5f72424cc2e96dc6ddff22fd00be)) +* **project:** drop support for Python 3.7 ([#1845](https://github.com/openai/openai-python/issues/1845)) ([0ed5b1a](https://github.com/openai/openai-python/commit/0ed5b1a9302ccf2f40c3c751cd777740a4749cda)) + ## 1.53.1 (2024-11-04) Full Changelog: [v1.53.0...v1.53.1](https://github.com/openai/openai-python/compare/v1.53.0...v1.53.1) diff --git a/pyproject.toml b/pyproject.toml index 20c0f3bb15..a88ce5608f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.53.1" +version = "1.54.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 9d221eb538..ef881a5f4c 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.53.1" # x-release-please-version +__version__ = "1.54.0" # x-release-please-version From 4ae58a7b80022504815c75929cf44be91ba18702 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Tue, 5 Nov 2024 09:31:27 +0000 Subject: [PATCH 072/769] fix: add new prediction param to all methods --- src/openai/resources/beta/chat/completions.py | 9 ++++ tests/lib/chat/test_completions.py | 42 ++++++++++++++++--- tests/lib/chat/test_completions_streaming.py | 7 +++- 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/src/openai/resources/beta/chat/completions.py b/src/openai/resources/beta/chat/completions.py index 47bcf42c16..38c09ce8dd 100644 --- a/src/openai/resources/beta/chat/completions.py +++ b/src/openai/resources/beta/chat/completions.py @@ -33,6 +33,7 @@ from ....types.chat.chat_completion_audio_param import ChatCompletionAudioParam from ....types.chat.chat_completion_message_param import ChatCompletionMessageParam from ....types.chat.chat_completion_stream_options_param import ChatCompletionStreamOptionsParam +from ....types.chat.chat_completion_prediction_content_param import ChatCompletionPredictionContentParam from ....types.chat.chat_completion_tool_choice_option_param import ChatCompletionToolChoiceOptionParam __all__ = ["Completions", "AsyncCompletions"] @@ -76,6 +77,7 @@ def parse( modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, @@ -169,6 +171,7 @@ def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseForma "modalities": modalities, "n": n, "parallel_tool_calls": parallel_tool_calls, + "prediction": prediction, "presence_penalty": presence_penalty, "response_format": _type_to_response_format(response_format), "seed": seed, @@ -217,6 +220,7 @@ def stream( modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, @@ -281,6 +285,7 @@ def stream( modalities=modalities, n=n, parallel_tool_calls=parallel_tool_calls, + prediction=prediction, presence_penalty=presence_penalty, seed=seed, service_tier=service_tier, @@ -343,6 +348,7 @@ async def parse( modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, @@ -436,6 +442,7 @@ def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseForma "modalities": modalities, "n": n, "parallel_tool_calls": parallel_tool_calls, + "prediction": prediction, "presence_penalty": presence_penalty, "response_format": _type_to_response_format(response_format), "seed": seed, @@ -484,6 +491,7 @@ def stream( modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, @@ -549,6 +557,7 @@ def stream( modalities=modalities, n=n, parallel_tool_calls=parallel_tool_calls, + prediction=prediction, presence_penalty=presence_penalty, seed=seed, service_tier=service_tier, diff --git a/tests/lib/chat/test_completions.py b/tests/lib/chat/test_completions.py index 5cd7b1ee53..48f41eb221 100644 --- a/tests/lib/chat/test_completions.py +++ b/tests/lib/chat/test_completions.py @@ -77,7 +77,12 @@ def test_parse_nothing(client: OpenAI, respx_mock: MockRouter, monkeypatch: pyte system_fingerprint='fp_b40fb1c6fb', usage=CompletionUsage( completion_tokens=37, - completion_tokens_details=CompletionTokensDetails(audio_tokens=None, reasoning_tokens=0), + completion_tokens_details=CompletionTokensDetails( + accepted_prediction_tokens=None, + audio_tokens=None, + reasoning_tokens=0, + rejected_prediction_tokens=None + ), prompt_tokens=14, prompt_tokens_details=None, total_tokens=51 @@ -139,7 +144,12 @@ class Location(BaseModel): system_fingerprint='fp_5050236cbd', usage=CompletionUsage( completion_tokens=14, - completion_tokens_details=CompletionTokensDetails(audio_tokens=None, reasoning_tokens=0), + completion_tokens_details=CompletionTokensDetails( + accepted_prediction_tokens=None, + audio_tokens=None, + reasoning_tokens=0, + rejected_prediction_tokens=None + ), prompt_tokens=79, prompt_tokens_details=None, total_tokens=93 @@ -203,7 +213,12 @@ class Location(BaseModel): system_fingerprint='fp_b40fb1c6fb', usage=CompletionUsage( completion_tokens=14, - completion_tokens_details=CompletionTokensDetails(audio_tokens=None, reasoning_tokens=0), + completion_tokens_details=CompletionTokensDetails( + accepted_prediction_tokens=None, + audio_tokens=None, + reasoning_tokens=0, + rejected_prediction_tokens=None + ), prompt_tokens=88, prompt_tokens_details=None, total_tokens=102 @@ -396,7 +411,12 @@ class CalendarEvent: system_fingerprint='fp_7568d46099', usage=CompletionUsage( completion_tokens=17, - completion_tokens_details=CompletionTokensDetails(audio_tokens=None, reasoning_tokens=0), + completion_tokens_details=CompletionTokensDetails( + accepted_prediction_tokens=None, + audio_tokens=None, + reasoning_tokens=0, + rejected_prediction_tokens=None + ), prompt_tokens=92, prompt_tokens_details=None, total_tokens=109 @@ -847,7 +867,12 @@ class Location(BaseModel): system_fingerprint='fp_5050236cbd', usage=CompletionUsage( completion_tokens=14, - completion_tokens_details=CompletionTokensDetails(audio_tokens=None, reasoning_tokens=0), + completion_tokens_details=CompletionTokensDetails( + accepted_prediction_tokens=None, + audio_tokens=None, + reasoning_tokens=0, + rejected_prediction_tokens=None + ), prompt_tokens=79, prompt_tokens_details=None, total_tokens=93 @@ -917,7 +942,12 @@ class Location(BaseModel): system_fingerprint='fp_5050236cbd', usage=CompletionUsage( completion_tokens=14, - completion_tokens_details=CompletionTokensDetails(audio_tokens=None, reasoning_tokens=0), + completion_tokens_details=CompletionTokensDetails( + accepted_prediction_tokens=None, + audio_tokens=None, + reasoning_tokens=0, + rejected_prediction_tokens=None + ), prompt_tokens=79, prompt_tokens_details=None, total_tokens=93 diff --git a/tests/lib/chat/test_completions_streaming.py b/tests/lib/chat/test_completions_streaming.py index 2846e6d2c3..ab12de44b3 100644 --- a/tests/lib/chat/test_completions_streaming.py +++ b/tests/lib/chat/test_completions_streaming.py @@ -157,7 +157,12 @@ def on_event(stream: ChatCompletionStream[Location], event: ChatCompletionStream system_fingerprint='fp_5050236cbd', usage=CompletionUsage( completion_tokens=14, - completion_tokens_details=CompletionTokensDetails(audio_tokens=None, reasoning_tokens=0), + completion_tokens_details=CompletionTokensDetails( + accepted_prediction_tokens=None, + audio_tokens=None, + reasoning_tokens=0, + rejected_prediction_tokens=None + ), prompt_tokens=79, prompt_tokens_details=None, total_tokens=93 From 22432e2d28a8503ea431b5c2599fd33e4a1cddb4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 09:32:01 +0000 Subject: [PATCH 073/769] release: 1.54.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 7e66027ecd..701df5bbab 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.54.0" + ".": "1.54.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index a60cd5cd31..511396ef95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.54.1 (2024-11-05) + +Full Changelog: [v1.54.0...v1.54.1](https://github.com/openai/openai-python/compare/v1.54.0...v1.54.1) + +### Bug Fixes + +* add new prediction param to all methods ([6aa424d](https://github.com/openai/openai-python/commit/6aa424d076098312801febd938bd4b5e8baf4851)) + ## 1.54.0 (2024-11-04) Full Changelog: [v1.53.1...v1.54.0](https://github.com/openai/openai-python/compare/v1.53.1...v1.54.0) diff --git a/pyproject.toml b/pyproject.toml index a88ce5608f..a4ea633fb6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.54.0" +version = "1.54.1" 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 ef881a5f4c..7d59fea6fe 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.54.0" # x-release-please-version +__version__ = "1.54.1" # x-release-please-version From 7f6a921c5951c4d464cd49a60db52a183cbf78f9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 6 Nov 2024 15:54:29 +0000 Subject: [PATCH 074/769] chore(tests): adjust retry timeout values (#1851) --- tests/test_client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_client.py b/tests/test_client.py index ff07ec393b..912ea1316c 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -698,7 +698,7 @@ class Model(BaseModel): [3, "", 0.5], [2, "", 0.5 * 2.0], [1, "", 0.5 * 4.0], - [-1100, "", 7.8], # test large number potentially overflowing + [-1100, "", 8], # test large number potentially overflowing ], ) @mock.patch("time.time", mock.MagicMock(return_value=1696004797)) @@ -1564,7 +1564,7 @@ class Model(BaseModel): [3, "", 0.5], [2, "", 0.5 * 2.0], [1, "", 0.5 * 4.0], - [-1100, "", 7.8], # test large number potentially overflowing + [-1100, "", 8], # test large number potentially overflowing ], ) @mock.patch("time.time", mock.MagicMock(return_value=1696004797)) From 74522adecf5d9919be8c797f3eb3da6e98b45229 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 6 Nov 2024 15:55:21 +0000 Subject: [PATCH 075/769] release: 1.54.2 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 701df5bbab..11adb14fb9 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.54.1" + ".": "1.54.2" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 511396ef95..61a18e3c8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.54.2 (2024-11-06) + +Full Changelog: [v1.54.1...v1.54.2](https://github.com/openai/openai-python/compare/v1.54.1...v1.54.2) + +### Chores + +* **tests:** adjust retry timeout values ([#1851](https://github.com/openai/openai-python/issues/1851)) ([cc8009c](https://github.com/openai/openai-python/commit/cc8009c9de56fe80f2689f69e7b891ff4ed297a3)) + ## 1.54.1 (2024-11-05) Full Changelog: [v1.54.0...v1.54.1](https://github.com/openai/openai-python/compare/v1.54.0...v1.54.1) diff --git a/pyproject.toml b/pyproject.toml index a4ea633fb6..13087f543f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.54.1" +version = "1.54.2" 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 7d59fea6fe..614d97d0f0 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.54.1" # x-release-please-version +__version__ = "1.54.2" # x-release-please-version From 1ca831cf60ead4151b061462f16d1894f02d025c Mon Sep 17 00:00:00 2001 From: Krista Pratico Date: Wed, 6 Nov 2024 13:18:00 -0800 Subject: [PATCH 076/769] fix(logs): redact sensitive headers (#1850) --- mypy.ini | 4 +- src/openai/_base_client.py | 3 +- src/openai/_utils/__init__.py | 1 + src/openai/_utils/_logs.py | 17 ++++++ tests/lib/test_azure.py | 101 +++++++++++++++++++++++++++++++ tests/test_utils/test_logging.py | 100 ++++++++++++++++++++++++++++++ 6 files changed, 223 insertions(+), 3 deletions(-) create mode 100644 tests/test_utils/test_logging.py diff --git a/mypy.ini b/mypy.ini index a4517a002d..97e5de4a60 100644 --- a/mypy.ini +++ b/mypy.ini @@ -2,10 +2,10 @@ pretty = True show_error_codes = True -# Exclude _files.py because mypy isn't smart enough to apply +# Exclude _files.py and _logs.py because mypy isn't smart enough to apply # the correct type narrowing and as this is an internal module # it's fine to just use Pyright. -exclude = ^(src/openai/_files\.py|_dev/.*\.py)$ +exclude = ^(src/openai/_files\.py|src/openai/_utils/_logs\.py|_dev/.*\.py)$ strict_equality = True implicit_reexport = True diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index e1d4849ae2..187518787a 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -62,7 +62,7 @@ HttpxRequestFiles, ModelBuilderProtocol, ) -from ._utils import is_dict, is_list, asyncify, is_given, lru_cache, is_mapping +from ._utils import SensitiveHeadersFilter, is_dict, is_list, asyncify, is_given, lru_cache, is_mapping from ._compat import model_copy, model_dump from ._models import GenericModel, FinalRequestOptions, validate_type, construct_type from ._response import ( @@ -90,6 +90,7 @@ from ._legacy_response import LegacyAPIResponse log: logging.Logger = logging.getLogger(__name__) +log.addFilter(SensitiveHeadersFilter()) # TODO: make base page type vars covariant SyncPageT = TypeVar("SyncPageT", bound="BaseSyncPage[Any]") diff --git a/src/openai/_utils/__init__.py b/src/openai/_utils/__init__.py index a7cff3c091..5abb34cde4 100644 --- a/src/openai/_utils/__init__.py +++ b/src/openai/_utils/__init__.py @@ -1,3 +1,4 @@ +from ._logs import SensitiveHeadersFilter as SensitiveHeadersFilter from ._sync import asyncify as asyncify from ._proxy import LazyProxy as LazyProxy from ._utils import ( diff --git a/src/openai/_utils/_logs.py b/src/openai/_utils/_logs.py index e5113fd8c0..376946933c 100644 --- a/src/openai/_utils/_logs.py +++ b/src/openai/_utils/_logs.py @@ -1,10 +1,16 @@ import os import logging +from typing_extensions import override + +from ._utils import is_dict logger: logging.Logger = logging.getLogger("openai") httpx_logger: logging.Logger = logging.getLogger("httpx") +SENSITIVE_HEADERS = {"api-key", "authorization"} + + def _basic_config() -> None: # e.g. [2023-10-05 14:12:26 - openai._base_client:818 - DEBUG] HTTP Request: POST http://127.0.0.1:4010/foo/bar "200 OK" logging.basicConfig( @@ -23,3 +29,14 @@ def setup_logging() -> None: _basic_config() logger.setLevel(logging.INFO) httpx_logger.setLevel(logging.INFO) + + +class SensitiveHeadersFilter(logging.Filter): + @override + def filter(self, record: logging.LogRecord) -> bool: + if is_dict(record.args) and "headers" in record.args and is_dict(record.args["headers"]): + headers = record.args["headers"] = {**record.args["headers"]} + for header in headers: + if str(header).lower() in SENSITIVE_HEADERS: + headers[header] = "" + return True diff --git a/tests/lib/test_azure.py b/tests/lib/test_azure.py index a9d3478350..626d7df311 100644 --- a/tests/lib/test_azure.py +++ b/tests/lib/test_azure.py @@ -1,3 +1,4 @@ +import logging from typing import Union, cast from typing_extensions import Literal, Protocol @@ -5,6 +6,7 @@ import pytest from respx import MockRouter +from openai._utils import SensitiveHeadersFilter, is_dict from openai._models import FinalRequestOptions from openai.lib.azure import AzureOpenAI, AsyncAzureOpenAI @@ -148,3 +150,102 @@ def token_provider() -> str: assert calls[0].request.headers.get("Authorization") == "Bearer first" assert calls[1].request.headers.get("Authorization") == "Bearer second" + + +class TestAzureLogging: + + @pytest.fixture(autouse=True) + def logger_with_filter(self) -> logging.Logger: + logger = logging.getLogger("openai") + logger.setLevel(logging.DEBUG) + logger.addFilter(SensitiveHeadersFilter()) + return logger + + @pytest.mark.respx() + def test_azure_api_key_redacted(self, respx_mock: MockRouter, caplog: pytest.LogCaptureFixture) -> None: + respx_mock.post( + "https://example-resource.azure.openai.com/openai/deployments/gpt-4/chat/completions?api-version=2024-06-01" + ).mock( + return_value=httpx.Response(200, json={"model": "gpt-4"}) + ) + + client = AzureOpenAI( + api_version="2024-06-01", + api_key="example_api_key", + azure_endpoint="https://example-resource.azure.openai.com", + ) + + with caplog.at_level(logging.DEBUG): + client.chat.completions.create(messages=[], model="gpt-4") + + for record in caplog.records: + if is_dict(record.args) and record.args.get("headers") and is_dict(record.args["headers"]): + assert record.args["headers"]["api-key"] == "" + + + @pytest.mark.respx() + def test_azure_bearer_token_redacted(self, respx_mock: MockRouter, caplog: pytest.LogCaptureFixture) -> None: + respx_mock.post( + "https://example-resource.azure.openai.com/openai/deployments/gpt-4/chat/completions?api-version=2024-06-01" + ).mock( + return_value=httpx.Response(200, json={"model": "gpt-4"}) + ) + + client = AzureOpenAI( + api_version="2024-06-01", + azure_ad_token="example_token", + azure_endpoint="https://example-resource.azure.openai.com", + ) + + with caplog.at_level(logging.DEBUG): + client.chat.completions.create(messages=[], model="gpt-4") + + for record in caplog.records: + if is_dict(record.args) and record.args.get("headers") and is_dict(record.args["headers"]): + assert record.args["headers"]["Authorization"] == "" + + + @pytest.mark.asyncio + @pytest.mark.respx() + async def test_azure_api_key_redacted_async(self, respx_mock: MockRouter, caplog: pytest.LogCaptureFixture) -> None: + respx_mock.post( + "https://example-resource.azure.openai.com/openai/deployments/gpt-4/chat/completions?api-version=2024-06-01" + ).mock( + return_value=httpx.Response(200, json={"model": "gpt-4"}) + ) + + client = AsyncAzureOpenAI( + api_version="2024-06-01", + api_key="example_api_key", + azure_endpoint="https://example-resource.azure.openai.com", + ) + + with caplog.at_level(logging.DEBUG): + await client.chat.completions.create(messages=[], model="gpt-4") + + for record in caplog.records: + if is_dict(record.args) and record.args.get("headers") and is_dict(record.args["headers"]): + assert record.args["headers"]["api-key"] == "" + + + @pytest.mark.asyncio + @pytest.mark.respx() + async def test_azure_bearer_token_redacted_async(self, respx_mock: MockRouter, caplog: pytest.LogCaptureFixture) -> None: + respx_mock.post( + "https://example-resource.azure.openai.com/openai/deployments/gpt-4/chat/completions?api-version=2024-06-01" + ).mock( + return_value=httpx.Response(200, json={"model": "gpt-4"}) + ) + + client = AsyncAzureOpenAI( + api_version="2024-06-01", + azure_ad_token="example_token", + azure_endpoint="https://example-resource.azure.openai.com", + ) + + with caplog.at_level(logging.DEBUG): + await client.chat.completions.create(messages=[], model="gpt-4") + + for record in caplog.records: + if is_dict(record.args) and record.args.get("headers") and is_dict(record.args["headers"]): + assert record.args["headers"]["Authorization"] == "" diff --git a/tests/test_utils/test_logging.py b/tests/test_utils/test_logging.py new file mode 100644 index 0000000000..cc018012e2 --- /dev/null +++ b/tests/test_utils/test_logging.py @@ -0,0 +1,100 @@ +import logging +from typing import Any, Dict, cast + +import pytest + +from openai._utils import SensitiveHeadersFilter + + +@pytest.fixture +def logger_with_filter() -> logging.Logger: + logger = logging.getLogger("test_logger") + logger.setLevel(logging.DEBUG) + logger.addFilter(SensitiveHeadersFilter()) + return logger + + +def test_keys_redacted(logger_with_filter: logging.Logger, caplog: pytest.LogCaptureFixture) -> None: + with caplog.at_level(logging.DEBUG): + logger_with_filter.debug( + "Request options: %s", + { + "method": "post", + "url": "chat/completions", + "headers": {"api-key": "12345", "Authorization": "Bearer token"}, + }, + ) + + log_record = cast(Dict[str, Any], caplog.records[0].args) + assert log_record["method"] == "post" + assert log_record["url"] == "chat/completions" + assert log_record["headers"]["api-key"] == "" + assert log_record["headers"]["Authorization"] == "" + assert ( + caplog.messages[0] + == "Request options: {'method': 'post', 'url': 'chat/completions', 'headers': {'api-key': '', 'Authorization': ''}}" + ) + + +def test_keys_redacted_case_insensitive(logger_with_filter: logging.Logger, caplog: pytest.LogCaptureFixture) -> None: + with caplog.at_level(logging.DEBUG): + logger_with_filter.debug( + "Request options: %s", + { + "method": "post", + "url": "chat/completions", + "headers": {"Api-key": "12345", "authorization": "Bearer token"}, + }, + ) + + log_record = cast(Dict[str, Any], caplog.records[0].args) + assert log_record["method"] == "post" + assert log_record["url"] == "chat/completions" + assert log_record["headers"]["Api-key"] == "" + assert log_record["headers"]["authorization"] == "" + assert ( + caplog.messages[0] + == "Request options: {'method': 'post', 'url': 'chat/completions', 'headers': {'Api-key': '', 'authorization': ''}}" + ) + + +def test_no_headers(logger_with_filter: logging.Logger, caplog: pytest.LogCaptureFixture) -> None: + with caplog.at_level(logging.DEBUG): + logger_with_filter.debug( + "Request options: %s", + {"method": "post", "url": "chat/completions"}, + ) + + log_record = cast(Dict[str, Any], caplog.records[0].args) + assert log_record["method"] == "post" + assert log_record["url"] == "chat/completions" + assert "api-key" not in log_record + assert "Authorization" not in log_record + assert caplog.messages[0] == "Request options: {'method': 'post', 'url': 'chat/completions'}" + + +def test_headers_without_sensitive_info(logger_with_filter: logging.Logger, caplog: pytest.LogCaptureFixture) -> None: + with caplog.at_level(logging.DEBUG): + logger_with_filter.debug( + "Request options: %s", + { + "method": "post", + "url": "chat/completions", + "headers": {"custom": "value"}, + }, + ) + + log_record = cast(Dict[str, Any], caplog.records[0].args) + assert log_record["method"] == "post" + assert log_record["url"] == "chat/completions" + assert log_record["headers"] == {"custom": "value"} + assert ( + caplog.messages[0] + == "Request options: {'method': 'post', 'url': 'chat/completions', 'headers': {'custom': 'value'}}" + ) + + +def test_standard_debug_msg(logger_with_filter: logging.Logger, caplog: pytest.LogCaptureFixture) -> None: + with caplog.at_level(logging.DEBUG): + logger_with_filter.debug("Sending HTTP Request: %s %s", "POST", "chat/completions") + assert caplog.messages[0] == "Sending HTTP Request: POST chat/completions" From 646a579cdb305a9d3fba6c5f9a96011c5e2c2882 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 6 Nov 2024 21:18:25 +0000 Subject: [PATCH 077/769] release: 1.54.3 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 11adb14fb9..2b6bc65c52 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.54.2" + ".": "1.54.3" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 61a18e3c8e..4addfb1025 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.54.3 (2024-11-06) + +Full Changelog: [v1.54.2...v1.54.3](https://github.com/openai/openai-python/compare/v1.54.2...v1.54.3) + +### Bug Fixes + +* **logs:** redact sensitive headers ([#1850](https://github.com/openai/openai-python/issues/1850)) ([466608f](https://github.com/openai/openai-python/commit/466608fa56b7a9939c08a4c78be2f6fe4a05111b)) + ## 1.54.2 (2024-11-06) Full Changelog: [v1.54.1...v1.54.2](https://github.com/openai/openai-python/compare/v1.54.1...v1.54.2) diff --git a/pyproject.toml b/pyproject.toml index 13087f543f..386f85e491 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.54.2" +version = "1.54.3" 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 614d97d0f0..848cd40935 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.54.2" # x-release-please-version +__version__ = "1.54.3" # x-release-please-version From db0aa22c4299606e6b6b86d6dd3e473e902d274a Mon Sep 17 00:00:00 2001 From: Adel Basli Date: Mon, 11 Nov 2024 11:17:26 +0100 Subject: [PATCH 078/769] docs(readme): add missing asyncio import (#1858) * fix missing import * reorder imports --------- Co-authored-by: Robert Craigie --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index bc334e7e07..47504b9137 100644 --- a/README.md +++ b/README.md @@ -196,6 +196,7 @@ for chunk in stream: The async client uses the exact same interface. ```python +import asyncio from openai import AsyncOpenAI client = AsyncOpenAI() From 6c6dfb19e49a604fb35e97b7f5adf654a5397ed6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 11 Nov 2024 22:39:39 +0000 Subject: [PATCH 079/769] docs: move comments in example snippets (#1860) --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 47504b9137..1051f10bf2 100644 --- a/README.md +++ b/README.md @@ -31,8 +31,7 @@ import os from openai import OpenAI client = OpenAI( - # This is the default and can be omitted - api_key=os.environ.get("OPENAI_API_KEY"), + api_key=os.environ.get("OPENAI_API_KEY"), # This is the default and can be omitted ) chat_completion = client.chat.completions.create( @@ -153,8 +152,7 @@ import asyncio from openai import AsyncOpenAI client = AsyncOpenAI( - # This is the default and can be omitted - api_key=os.environ.get("OPENAI_API_KEY"), + api_key=os.environ.get("OPENAI_API_KEY"), # This is the default and can be omitted ) From 23444ed92cc81b3b1a8f17432f29b4020b50f023 Mon Sep 17 00:00:00 2001 From: Stainless Bot Date: Tue, 12 Nov 2024 07:43:40 +0000 Subject: [PATCH 080/769] docs: bump models in example snippets to gpt-4o (#1861) --- README.md | 29 +++++++++++++++++------------ tests/test_client.py | 8 ++++---- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 1051f10bf2..f1cd97b96e 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ chat_completion = client.chat.completions.create( "content": "Say this is a test", } ], - model="gpt-3.5-turbo", + model="gpt-4o", ) ``` @@ -164,7 +164,7 @@ async def main() -> None: "content": "Say this is a test", } ], - model="gpt-3.5-turbo", + model="gpt-4o", ) @@ -183,8 +183,13 @@ from openai import OpenAI client = OpenAI() stream = client.chat.completions.create( - model="gpt-4", - messages=[{"role": "user", "content": "Say this is a test"}], + messages=[ + { + "role": "user", + "content": "Say this is a test", + } + ], + model="gpt-4o", stream=True, ) for chunk in stream: @@ -231,7 +236,7 @@ openai.base_url = "https://..." openai.default_headers = {"x-foo": "true"} completion = openai.chat.completions.create( - model="gpt-4", + model="gpt-4o", messages=[ { "role": "user", @@ -349,7 +354,7 @@ completion = client.chat.completions.create( "content": "Can you generate an example json object describing a fruit?", } ], - model="gpt-3.5-turbo-1106", + model="gpt-4o", response_format={"type": "json_object"}, ) ``` @@ -389,7 +394,7 @@ client = OpenAI() try: client.fine_tuning.jobs.create( - model="gpt-3.5-turbo", + model="gpt-4o", training_file="file-abc123", ) except openai.APIConnectionError as e: @@ -456,10 +461,10 @@ client.with_options(max_retries=5).chat.completions.create( messages=[ { "role": "user", - "content": "How can I get the name of the current day in Node.js?", + "content": "How can I get the name of the current day in JavaScript?", } ], - model="gpt-3.5-turbo", + model="gpt-4o", ) ``` @@ -490,7 +495,7 @@ client.with_options(timeout=5.0).chat.completions.create( "content": "How can I list all files in a directory using Python?", } ], - model="gpt-3.5-turbo", + model="gpt-4o", ) ``` @@ -535,7 +540,7 @@ response = client.chat.completions.with_raw_response.create( "role": "user", "content": "Say this is a test", }], - model="gpt-3.5-turbo", + model="gpt-4o", ) print(response.headers.get('X-My-Header')) @@ -568,7 +573,7 @@ with client.chat.completions.with_streaming_response.create( "content": "Say this is a test", } ], - model="gpt-3.5-turbo", + model="gpt-4o", ) as response: print(response.headers.get("X-My-Header")) diff --git a/tests/test_client.py b/tests/test_client.py index 912ea1316c..7ea2ab38d1 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -727,7 +727,7 @@ def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter) -> No "content": "Say this is a test", } ], - model="gpt-3.5-turbo", + model="gpt-4o", ), ), cast_to=httpx.Response, @@ -753,7 +753,7 @@ def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter) -> Non "content": "Say this is a test", } ], - model="gpt-3.5-turbo", + model="gpt-4o", ), ), cast_to=httpx.Response, @@ -1594,7 +1594,7 @@ async def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter) "content": "Say this is a test", } ], - model="gpt-3.5-turbo", + model="gpt-4o", ), ), cast_to=httpx.Response, @@ -1620,7 +1620,7 @@ async def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter) "content": "Say this is a test", } ], - model="gpt-3.5-turbo", + model="gpt-4o", ), ), cast_to=httpx.Response, From 9b28850fcd777a249e127ae4080d2720b4b76896 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 12 Nov 2024 12:11:55 +0000 Subject: [PATCH 081/769] fix: don't use dicts as iterables in transform (#1865) --- src/openai/_utils/_transform.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/openai/_utils/_transform.py b/src/openai/_utils/_transform.py index d7c05345d1..a6b62cad0c 100644 --- a/src/openai/_utils/_transform.py +++ b/src/openai/_utils/_transform.py @@ -316,6 +316,11 @@ async def _async_transform_recursive( # Iterable[T] or (is_iterable_type(stripped_type) and is_iterable(data) and not isinstance(data, str)) ): + # dicts are technically iterable, but it is an iterable on the keys of the dict and is not usually + # intended as an iterable, so we don't transform it. + if isinstance(data, dict): + return cast(object, data) + inner_type = extract_type_arg(stripped_type, 0) return [await _async_transform_recursive(d, annotation=annotation, inner_type=inner_type) for d in data] From 52357cff50bee57ef442e94d78a0de38b4173fc2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 12 Nov 2024 12:12:24 +0000 Subject: [PATCH 082/769] release: 1.54.4 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 15 +++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 2b6bc65c52..7bfe725d47 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.54.3" + ".": "1.54.4" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 4addfb1025..d82ac42553 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## 1.54.4 (2024-11-12) + +Full Changelog: [v1.54.3...v1.54.4](https://github.com/openai/openai-python/compare/v1.54.3...v1.54.4) + +### Bug Fixes + +* don't use dicts as iterables in transform ([#1865](https://github.com/openai/openai-python/issues/1865)) ([76a51b1](https://github.com/openai/openai-python/commit/76a51b11efae50659a562197b1e18c6343964b56)) + + +### Documentation + +* bump models in example snippets to gpt-4o ([#1861](https://github.com/openai/openai-python/issues/1861)) ([adafe08](https://github.com/openai/openai-python/commit/adafe0859178d406fa93b38f3547f3d262651331)) +* move comments in example snippets ([#1860](https://github.com/openai/openai-python/issues/1860)) ([362cf74](https://github.com/openai/openai-python/commit/362cf74d6c34506f98f6c4fb2304357be21f7691)) +* **readme:** add missing asyncio import ([#1858](https://github.com/openai/openai-python/issues/1858)) ([dec9d0c](https://github.com/openai/openai-python/commit/dec9d0c97b702b6bcf9c71f5bdd6172bb5718354)) + ## 1.54.3 (2024-11-06) Full Changelog: [v1.54.2...v1.54.3](https://github.com/openai/openai-python/compare/v1.54.2...v1.54.3) diff --git a/pyproject.toml b/pyproject.toml index 386f85e491..e0a20e8387 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.54.3" +version = "1.54.4" 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 848cd40935..5e531dd083 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.54.3" # x-release-please-version +__version__ = "1.54.4" # x-release-please-version From dd19d4f94a68ccecf38f23d10f5de2568345b79d Mon Sep 17 00:00:00 2001 From: Stainless Bot Date: Mon, 18 Nov 2024 10:35:41 +0000 Subject: [PATCH 083/769] chore(tests): limit array example length (#1870) --- .../audio/test_transcriptions.py | 4 +- tests/api_resources/beta/test_assistants.py | 20 +- tests/api_resources/beta/test_threads.py | 584 ++---------------- .../api_resources/beta/test_vector_stores.py | 4 +- .../beta/threads/test_messages.py | 28 +- tests/api_resources/beta/threads/test_runs.py | 460 ++------------ tests/api_resources/chat/test_completions.py | 88 +-- tests/api_resources/fine_tuning/test_jobs.py | 44 +- tests/api_resources/test_uploads.py | 20 +- 9 files changed, 146 insertions(+), 1106 deletions(-) diff --git a/tests/api_resources/audio/test_transcriptions.py b/tests/api_resources/audio/test_transcriptions.py index 0fa91eb152..bdb7e0dfb6 100644 --- a/tests/api_resources/audio/test_transcriptions.py +++ b/tests/api_resources/audio/test_transcriptions.py @@ -34,7 +34,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: prompt="string", response_format="json", temperature=0, - timestamp_granularities=["word", "segment"], + timestamp_granularities=["word"], ) assert_matches_type(TranscriptionCreateResponse, transcription, path=["response"]) @@ -85,7 +85,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> prompt="string", response_format="json", temperature=0, - timestamp_granularities=["word", "segment"], + timestamp_granularities=["word"], ) assert_matches_type(TranscriptionCreateResponse, transcription, path=["response"]) diff --git a/tests/api_resources/beta/test_assistants.py b/tests/api_resources/beta/test_assistants.py index 642935cdaf..d9944448b7 100644 --- a/tests/api_resources/beta/test_assistants.py +++ b/tests/api_resources/beta/test_assistants.py @@ -39,19 +39,19 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: response_format="auto", temperature=1, tool_resources={ - "code_interpreter": {"file_ids": ["string", "string", "string"]}, + "code_interpreter": {"file_ids": ["string"]}, "file_search": { "vector_store_ids": ["string"], "vector_stores": [ { "chunking_strategy": {"type": "auto"}, - "file_ids": ["string", "string", "string"], + "file_ids": ["string"], "metadata": {}, } ], }, }, - tools=[{"type": "code_interpreter"}, {"type": "code_interpreter"}, {"type": "code_interpreter"}], + tools=[{"type": "code_interpreter"}], top_p=1, ) assert_matches_type(Assistant, assistant, path=["response"]) @@ -137,10 +137,10 @@ def test_method_update_with_all_params(self, client: OpenAI) -> None: response_format="auto", temperature=1, tool_resources={ - "code_interpreter": {"file_ids": ["string", "string", "string"]}, + "code_interpreter": {"file_ids": ["string"]}, "file_search": {"vector_store_ids": ["string"]}, }, - tools=[{"type": "code_interpreter"}, {"type": "code_interpreter"}, {"type": "code_interpreter"}], + tools=[{"type": "code_interpreter"}], top_p=1, ) assert_matches_type(Assistant, assistant, path=["response"]) @@ -271,19 +271,19 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> response_format="auto", temperature=1, tool_resources={ - "code_interpreter": {"file_ids": ["string", "string", "string"]}, + "code_interpreter": {"file_ids": ["string"]}, "file_search": { "vector_store_ids": ["string"], "vector_stores": [ { "chunking_strategy": {"type": "auto"}, - "file_ids": ["string", "string", "string"], + "file_ids": ["string"], "metadata": {}, } ], }, }, - tools=[{"type": "code_interpreter"}, {"type": "code_interpreter"}, {"type": "code_interpreter"}], + tools=[{"type": "code_interpreter"}], top_p=1, ) assert_matches_type(Assistant, assistant, path=["response"]) @@ -369,10 +369,10 @@ async def test_method_update_with_all_params(self, async_client: AsyncOpenAI) -> response_format="auto", temperature=1, tool_resources={ - "code_interpreter": {"file_ids": ["string", "string", "string"]}, + "code_interpreter": {"file_ids": ["string"]}, "file_search": {"vector_store_ids": ["string"]}, }, - tools=[{"type": "code_interpreter"}, {"type": "code_interpreter"}, {"type": "code_interpreter"}], + tools=[{"type": "code_interpreter"}], top_p=1, ) assert_matches_type(Assistant, assistant, path=["response"]) diff --git a/tests/api_resources/beta/test_threads.py b/tests/api_resources/beta/test_threads.py index 95bebd84f5..789f870d6a 100644 --- a/tests/api_resources/beta/test_threads.py +++ b/tests/api_resources/beta/test_threads.py @@ -35,104 +35,22 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: "role": "user", "attachments": [ { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - ], - "metadata": {}, - }, - { - "content": "string", - "role": "user", - "attachments": [ - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - ], - "metadata": {}, - }, - { - "content": "string", - "role": "user", - "attachments": [ - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, + "file_id": "file_id", + "tools": [{"type": "code_interpreter"}], + } ], "metadata": {}, - }, + } ], metadata={}, tool_resources={ - "code_interpreter": {"file_ids": ["string", "string", "string"]}, + "code_interpreter": {"file_ids": ["string"]}, "file_search": { "vector_store_ids": ["string"], "vector_stores": [ { "chunking_strategy": {"type": "auto"}, - "file_ids": ["string", "string", "string"], + "file_ids": ["string"], "metadata": {}, } ], @@ -212,7 +130,7 @@ def test_method_update_with_all_params(self, client: OpenAI) -> None: "string", metadata={}, tool_resources={ - "code_interpreter": {"file_ids": ["string", "string", "string"]}, + "code_interpreter": {"file_ids": ["string"]}, "file_search": {"vector_store_ids": ["string"]}, }, ) @@ -314,104 +232,22 @@ def test_method_create_and_run_with_all_params_overload_1(self, client: OpenAI) "role": "user", "attachments": [ { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - ], - "metadata": {}, - }, - { - "content": "string", - "role": "user", - "attachments": [ - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - ], - "metadata": {}, - }, - { - "content": "string", - "role": "user", - "attachments": [ - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, + "file_id": "file_id", + "tools": [{"type": "code_interpreter"}], + } ], "metadata": {}, - }, + } ], "metadata": {}, "tool_resources": { - "code_interpreter": {"file_ids": ["string", "string", "string"]}, + "code_interpreter": {"file_ids": ["string"]}, "file_search": { "vector_store_ids": ["string"], "vector_stores": [ { "chunking_strategy": {"type": "auto"}, - "file_ids": ["string", "string", "string"], + "file_ids": ["string"], "metadata": {}, } ], @@ -420,10 +256,10 @@ def test_method_create_and_run_with_all_params_overload_1(self, client: OpenAI) }, tool_choice="none", tool_resources={ - "code_interpreter": {"file_ids": ["string", "string", "string"]}, + "code_interpreter": {"file_ids": ["string"]}, "file_search": {"vector_store_ids": ["string"]}, }, - tools=[{"type": "code_interpreter"}, {"type": "code_interpreter"}, {"type": "code_interpreter"}], + tools=[{"type": "code_interpreter"}], top_p=1, truncation_strategy={ "type": "auto", @@ -484,104 +320,22 @@ def test_method_create_and_run_with_all_params_overload_2(self, client: OpenAI) "role": "user", "attachments": [ { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - ], - "metadata": {}, - }, - { - "content": "string", - "role": "user", - "attachments": [ - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - ], - "metadata": {}, - }, - { - "content": "string", - "role": "user", - "attachments": [ - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, + "file_id": "file_id", + "tools": [{"type": "code_interpreter"}], + } ], "metadata": {}, - }, + } ], "metadata": {}, "tool_resources": { - "code_interpreter": {"file_ids": ["string", "string", "string"]}, + "code_interpreter": {"file_ids": ["string"]}, "file_search": { "vector_store_ids": ["string"], "vector_stores": [ { "chunking_strategy": {"type": "auto"}, - "file_ids": ["string", "string", "string"], + "file_ids": ["string"], "metadata": {}, } ], @@ -590,10 +344,10 @@ def test_method_create_and_run_with_all_params_overload_2(self, client: OpenAI) }, tool_choice="none", tool_resources={ - "code_interpreter": {"file_ids": ["string", "string", "string"]}, + "code_interpreter": {"file_ids": ["string"]}, "file_search": {"vector_store_ids": ["string"]}, }, - tools=[{"type": "code_interpreter"}, {"type": "code_interpreter"}, {"type": "code_interpreter"}], + tools=[{"type": "code_interpreter"}], top_p=1, truncation_strategy={ "type": "auto", @@ -645,104 +399,22 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> "role": "user", "attachments": [ { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - ], - "metadata": {}, - }, - { - "content": "string", - "role": "user", - "attachments": [ - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - ], - "metadata": {}, - }, - { - "content": "string", - "role": "user", - "attachments": [ - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, + "file_id": "file_id", + "tools": [{"type": "code_interpreter"}], + } ], "metadata": {}, - }, + } ], metadata={}, tool_resources={ - "code_interpreter": {"file_ids": ["string", "string", "string"]}, + "code_interpreter": {"file_ids": ["string"]}, "file_search": { "vector_store_ids": ["string"], "vector_stores": [ { "chunking_strategy": {"type": "auto"}, - "file_ids": ["string", "string", "string"], + "file_ids": ["string"], "metadata": {}, } ], @@ -822,7 +494,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncOpenAI) -> "string", metadata={}, tool_resources={ - "code_interpreter": {"file_ids": ["string", "string", "string"]}, + "code_interpreter": {"file_ids": ["string"]}, "file_search": {"vector_store_ids": ["string"]}, }, ) @@ -924,104 +596,22 @@ async def test_method_create_and_run_with_all_params_overload_1(self, async_clie "role": "user", "attachments": [ { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - ], - "metadata": {}, - }, - { - "content": "string", - "role": "user", - "attachments": [ - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - ], - "metadata": {}, - }, - { - "content": "string", - "role": "user", - "attachments": [ - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, + "file_id": "file_id", + "tools": [{"type": "code_interpreter"}], + } ], "metadata": {}, - }, + } ], "metadata": {}, "tool_resources": { - "code_interpreter": {"file_ids": ["string", "string", "string"]}, + "code_interpreter": {"file_ids": ["string"]}, "file_search": { "vector_store_ids": ["string"], "vector_stores": [ { "chunking_strategy": {"type": "auto"}, - "file_ids": ["string", "string", "string"], + "file_ids": ["string"], "metadata": {}, } ], @@ -1030,10 +620,10 @@ async def test_method_create_and_run_with_all_params_overload_1(self, async_clie }, tool_choice="none", tool_resources={ - "code_interpreter": {"file_ids": ["string", "string", "string"]}, + "code_interpreter": {"file_ids": ["string"]}, "file_search": {"vector_store_ids": ["string"]}, }, - tools=[{"type": "code_interpreter"}, {"type": "code_interpreter"}, {"type": "code_interpreter"}], + tools=[{"type": "code_interpreter"}], top_p=1, truncation_strategy={ "type": "auto", @@ -1094,104 +684,22 @@ async def test_method_create_and_run_with_all_params_overload_2(self, async_clie "role": "user", "attachments": [ { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - ], - "metadata": {}, - }, - { - "content": "string", - "role": "user", - "attachments": [ - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - ], - "metadata": {}, - }, - { - "content": "string", - "role": "user", - "attachments": [ - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, + "file_id": "file_id", + "tools": [{"type": "code_interpreter"}], + } ], "metadata": {}, - }, + } ], "metadata": {}, "tool_resources": { - "code_interpreter": {"file_ids": ["string", "string", "string"]}, + "code_interpreter": {"file_ids": ["string"]}, "file_search": { "vector_store_ids": ["string"], "vector_stores": [ { "chunking_strategy": {"type": "auto"}, - "file_ids": ["string", "string", "string"], + "file_ids": ["string"], "metadata": {}, } ], @@ -1200,10 +708,10 @@ async def test_method_create_and_run_with_all_params_overload_2(self, async_clie }, tool_choice="none", tool_resources={ - "code_interpreter": {"file_ids": ["string", "string", "string"]}, + "code_interpreter": {"file_ids": ["string"]}, "file_search": {"vector_store_ids": ["string"]}, }, - tools=[{"type": "code_interpreter"}, {"type": "code_interpreter"}, {"type": "code_interpreter"}], + tools=[{"type": "code_interpreter"}], top_p=1, truncation_strategy={ "type": "auto", diff --git a/tests/api_resources/beta/test_vector_stores.py b/tests/api_resources/beta/test_vector_stores.py index 39fdb9d1d4..99e1970c33 100644 --- a/tests/api_resources/beta/test_vector_stores.py +++ b/tests/api_resources/beta/test_vector_stores.py @@ -34,7 +34,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: "anchor": "last_active_at", "days": 1, }, - file_ids=["string", "string", "string"], + file_ids=["string"], metadata={}, name="string", ) @@ -239,7 +239,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> "anchor": "last_active_at", "days": 1, }, - file_ids=["string", "string", "string"], + file_ids=["string"], metadata={}, name="string", ) diff --git a/tests/api_resources/beta/threads/test_messages.py b/tests/api_resources/beta/threads/test_messages.py index b5be32a421..06c37e608a 100644 --- a/tests/api_resources/beta/threads/test_messages.py +++ b/tests/api_resources/beta/threads/test_messages.py @@ -38,17 +38,9 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: role="user", attachments=[ { - "file_id": "string", - "tools": [{"type": "code_interpreter"}, {"type": "code_interpreter"}, {"type": "code_interpreter"}], - }, - { - "file_id": "string", - "tools": [{"type": "code_interpreter"}, {"type": "code_interpreter"}, {"type": "code_interpreter"}], - }, - { - "file_id": "string", - "tools": [{"type": "code_interpreter"}, {"type": "code_interpreter"}, {"type": "code_interpreter"}], - }, + "file_id": "file_id", + "tools": [{"type": "code_interpreter"}], + } ], metadata={}, ) @@ -315,17 +307,9 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> role="user", attachments=[ { - "file_id": "string", - "tools": [{"type": "code_interpreter"}, {"type": "code_interpreter"}, {"type": "code_interpreter"}], - }, - { - "file_id": "string", - "tools": [{"type": "code_interpreter"}, {"type": "code_interpreter"}, {"type": "code_interpreter"}], - }, - { - "file_id": "string", - "tools": [{"type": "code_interpreter"}, {"type": "code_interpreter"}, {"type": "code_interpreter"}], - }, + "file_id": "file_id", + "tools": [{"type": "code_interpreter"}], + } ], metadata={}, ) diff --git a/tests/api_resources/beta/threads/test_runs.py b/tests/api_resources/beta/threads/test_runs.py index c8d70f5f89..c48cc6de43 100644 --- a/tests/api_resources/beta/threads/test_runs.py +++ b/tests/api_resources/beta/threads/test_runs.py @@ -43,94 +43,12 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: "role": "user", "attachments": [ { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, + "file_id": "file_id", + "tools": [{"type": "code_interpreter"}], + } ], "metadata": {}, - }, - { - "content": "string", - "role": "user", - "attachments": [ - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - ], - "metadata": {}, - }, - { - "content": "string", - "role": "user", - "attachments": [ - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - ], - "metadata": {}, - }, + } ], instructions="string", max_completion_tokens=256, @@ -142,7 +60,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: stream=False, temperature=1, tool_choice="none", - tools=[{"type": "code_interpreter"}, {"type": "code_interpreter"}, {"type": "code_interpreter"}], + tools=[{"type": "code_interpreter"}], top_p=1, truncation_strategy={ "type": "auto", @@ -208,94 +126,12 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: "role": "user", "attachments": [ { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, + "file_id": "file_id", + "tools": [{"type": "code_interpreter"}], + } ], "metadata": {}, - }, - { - "content": "string", - "role": "user", - "attachments": [ - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - ], - "metadata": {}, - }, - { - "content": "string", - "role": "user", - "attachments": [ - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - ], - "metadata": {}, - }, + } ], instructions="string", max_completion_tokens=256, @@ -306,7 +142,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: response_format="auto", temperature=1, tool_choice="none", - tools=[{"type": "code_interpreter"}, {"type": "code_interpreter"}, {"type": "code_interpreter"}], + tools=[{"type": "code_interpreter"}], top_p=1, truncation_strategy={ "type": "auto", @@ -556,9 +392,9 @@ def test_path_params_cancel(self, client: OpenAI) -> None: @parametrize def test_method_submit_tool_outputs_overload_1(self, client: OpenAI) -> None: run = client.beta.threads.runs.submit_tool_outputs( - "string", - thread_id="string", - tool_outputs=[{}, {}, {}], + run_id="run_id", + thread_id="thread_id", + tool_outputs=[{}], ) assert_matches_type(Run, run, path=["response"]) @@ -571,15 +407,7 @@ def test_method_submit_tool_outputs_with_all_params_overload_1(self, client: Ope { "output": "output", "tool_call_id": "tool_call_id", - }, - { - "output": "output", - "tool_call_id": "tool_call_id", - }, - { - "output": "output", - "tool_call_id": "tool_call_id", - }, + } ], stream=False, ) @@ -588,9 +416,9 @@ def test_method_submit_tool_outputs_with_all_params_overload_1(self, client: Ope @parametrize def test_raw_response_submit_tool_outputs_overload_1(self, client: OpenAI) -> None: response = client.beta.threads.runs.with_raw_response.submit_tool_outputs( - "string", - thread_id="string", - tool_outputs=[{}, {}, {}], + run_id="run_id", + thread_id="thread_id", + tool_outputs=[{}], ) assert response.is_closed is True @@ -601,9 +429,9 @@ def test_raw_response_submit_tool_outputs_overload_1(self, client: OpenAI) -> No @parametrize def test_streaming_response_submit_tool_outputs_overload_1(self, client: OpenAI) -> None: with client.beta.threads.runs.with_streaming_response.submit_tool_outputs( - "string", - thread_id="string", - tool_outputs=[{}, {}, {}], + run_id="run_id", + thread_id="thread_id", + tool_outputs=[{}], ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -619,14 +447,14 @@ def test_path_params_submit_tool_outputs_overload_1(self, client: OpenAI) -> Non client.beta.threads.runs.with_raw_response.submit_tool_outputs( "string", thread_id="", - tool_outputs=[{}, {}, {}], + tool_outputs=[{}], ) with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): client.beta.threads.runs.with_raw_response.submit_tool_outputs( - "", - thread_id="string", - tool_outputs=[{}, {}, {}], + run_id="", + thread_id="thread_id", + tool_outputs=[{}], ) @parametrize @@ -635,7 +463,7 @@ def test_method_submit_tool_outputs_overload_2(self, client: OpenAI) -> None: "string", thread_id="string", stream=True, - tool_outputs=[{}, {}, {}], + tool_outputs=[{}], ) run_stream.response.close() @@ -645,7 +473,7 @@ def test_raw_response_submit_tool_outputs_overload_2(self, client: OpenAI) -> No "string", thread_id="string", stream=True, - tool_outputs=[{}, {}, {}], + tool_outputs=[{}], ) assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -658,7 +486,7 @@ def test_streaming_response_submit_tool_outputs_overload_2(self, client: OpenAI) "string", thread_id="string", stream=True, - tool_outputs=[{}, {}, {}], + tool_outputs=[{}], ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -675,7 +503,7 @@ def test_path_params_submit_tool_outputs_overload_2(self, client: OpenAI) -> Non "string", thread_id="", stream=True, - tool_outputs=[{}, {}, {}], + tool_outputs=[{}], ) with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): @@ -683,7 +511,7 @@ def test_path_params_submit_tool_outputs_overload_2(self, client: OpenAI) -> Non "", thread_id="string", stream=True, - tool_outputs=[{}, {}, {}], + tool_outputs=[{}], ) @@ -711,94 +539,12 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn "role": "user", "attachments": [ { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, + "file_id": "file_id", + "tools": [{"type": "code_interpreter"}], + } ], "metadata": {}, - }, - { - "content": "string", - "role": "user", - "attachments": [ - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - ], - "metadata": {}, - }, - { - "content": "string", - "role": "user", - "attachments": [ - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - ], - "metadata": {}, - }, + } ], instructions="string", max_completion_tokens=256, @@ -810,7 +556,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn stream=False, temperature=1, tool_choice="none", - tools=[{"type": "code_interpreter"}, {"type": "code_interpreter"}, {"type": "code_interpreter"}], + tools=[{"type": "code_interpreter"}], top_p=1, truncation_strategy={ "type": "auto", @@ -876,94 +622,12 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn "role": "user", "attachments": [ { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, + "file_id": "file_id", + "tools": [{"type": "code_interpreter"}], + } ], "metadata": {}, - }, - { - "content": "string", - "role": "user", - "attachments": [ - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - ], - "metadata": {}, - }, - { - "content": "string", - "role": "user", - "attachments": [ - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - { - "file_id": "string", - "tools": [ - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - {"type": "code_interpreter"}, - ], - }, - ], - "metadata": {}, - }, + } ], instructions="string", max_completion_tokens=256, @@ -974,7 +638,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn response_format="auto", temperature=1, tool_choice="none", - tools=[{"type": "code_interpreter"}, {"type": "code_interpreter"}, {"type": "code_interpreter"}], + tools=[{"type": "code_interpreter"}], top_p=1, truncation_strategy={ "type": "auto", @@ -1224,9 +888,9 @@ async def test_path_params_cancel(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_method_submit_tool_outputs_overload_1(self, async_client: AsyncOpenAI) -> None: run = await async_client.beta.threads.runs.submit_tool_outputs( - "string", - thread_id="string", - tool_outputs=[{}, {}, {}], + run_id="run_id", + thread_id="thread_id", + tool_outputs=[{}], ) assert_matches_type(Run, run, path=["response"]) @@ -1239,15 +903,7 @@ async def test_method_submit_tool_outputs_with_all_params_overload_1(self, async { "output": "output", "tool_call_id": "tool_call_id", - }, - { - "output": "output", - "tool_call_id": "tool_call_id", - }, - { - "output": "output", - "tool_call_id": "tool_call_id", - }, + } ], stream=False, ) @@ -1256,9 +912,9 @@ async def test_method_submit_tool_outputs_with_all_params_overload_1(self, async @parametrize async def test_raw_response_submit_tool_outputs_overload_1(self, async_client: AsyncOpenAI) -> None: response = await async_client.beta.threads.runs.with_raw_response.submit_tool_outputs( - "string", - thread_id="string", - tool_outputs=[{}, {}, {}], + run_id="run_id", + thread_id="thread_id", + tool_outputs=[{}], ) assert response.is_closed is True @@ -1269,9 +925,9 @@ async def test_raw_response_submit_tool_outputs_overload_1(self, async_client: A @parametrize async def test_streaming_response_submit_tool_outputs_overload_1(self, async_client: AsyncOpenAI) -> None: async with async_client.beta.threads.runs.with_streaming_response.submit_tool_outputs( - "string", - thread_id="string", - tool_outputs=[{}, {}, {}], + run_id="run_id", + thread_id="thread_id", + tool_outputs=[{}], ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -1287,14 +943,14 @@ async def test_path_params_submit_tool_outputs_overload_1(self, async_client: As await async_client.beta.threads.runs.with_raw_response.submit_tool_outputs( "string", thread_id="", - tool_outputs=[{}, {}, {}], + tool_outputs=[{}], ) with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): await async_client.beta.threads.runs.with_raw_response.submit_tool_outputs( - "", - thread_id="string", - tool_outputs=[{}, {}, {}], + run_id="", + thread_id="thread_id", + tool_outputs=[{}], ) @parametrize @@ -1303,7 +959,7 @@ async def test_method_submit_tool_outputs_overload_2(self, async_client: AsyncOp "string", thread_id="string", stream=True, - tool_outputs=[{}, {}, {}], + tool_outputs=[{}], ) await run_stream.response.aclose() @@ -1313,7 +969,7 @@ async def test_raw_response_submit_tool_outputs_overload_2(self, async_client: A "string", thread_id="string", stream=True, - tool_outputs=[{}, {}, {}], + tool_outputs=[{}], ) assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -1326,7 +982,7 @@ async def test_streaming_response_submit_tool_outputs_overload_2(self, async_cli "string", thread_id="string", stream=True, - tool_outputs=[{}, {}, {}], + tool_outputs=[{}], ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -1343,7 +999,7 @@ async def test_path_params_submit_tool_outputs_overload_2(self, async_client: As "string", thread_id="", stream=True, - tool_outputs=[{}, {}, {}], + tool_outputs=[{}], ) with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): @@ -1351,5 +1007,5 @@ async def test_path_params_submit_tool_outputs_overload_2(self, async_client: As "", thread_id="string", stream=True, - tool_outputs=[{}, {}, {}], + tool_outputs=[{}], ) diff --git a/tests/api_resources/chat/test_completions.py b/tests/api_resources/chat/test_completions.py index dafedac9fb..1b52650b1d 100644 --- a/tests/api_resources/chat/test_completions.py +++ b/tests/api_resources/chat/test_completions.py @@ -62,7 +62,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: max_completion_tokens=0, max_tokens=0, metadata={"foo": "string"}, - modalities=["text", "audio"], + modalities=["text"], n=1, parallel_tool_calls=True, prediction={ @@ -88,25 +88,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: "strict": True, }, "type": "function", - }, - { - "function": { - "name": "name", - "description": "description", - "parameters": {"foo": "bar"}, - "strict": True, - }, - "type": "function", - }, - { - "function": { - "name": "name", - "description": "description", - "parameters": {"foo": "bar"}, - "strict": True, - }, - "type": "function", - }, + } ], top_logprobs=0, top_p=1, @@ -194,7 +176,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: max_completion_tokens=0, max_tokens=0, metadata={"foo": "string"}, - modalities=["text", "audio"], + modalities=["text"], n=1, parallel_tool_calls=True, prediction={ @@ -219,25 +201,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: "strict": True, }, "type": "function", - }, - { - "function": { - "name": "name", - "description": "description", - "parameters": {"foo": "bar"}, - "strict": True, - }, - "type": "function", - }, - { - "function": { - "name": "name", - "description": "description", - "parameters": {"foo": "bar"}, - "strict": True, - }, - "type": "function", - }, + } ], top_logprobs=0, top_p=1, @@ -345,7 +309,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn max_completion_tokens=0, max_tokens=0, metadata={"foo": "string"}, - modalities=["text", "audio"], + modalities=["text"], n=1, parallel_tool_calls=True, prediction={ @@ -371,25 +335,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn "strict": True, }, "type": "function", - }, - { - "function": { - "name": "name", - "description": "description", - "parameters": {"foo": "bar"}, - "strict": True, - }, - "type": "function", - }, - { - "function": { - "name": "name", - "description": "description", - "parameters": {"foo": "bar"}, - "strict": True, - }, - "type": "function", - }, + } ], top_logprobs=0, top_p=1, @@ -477,7 +423,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn max_completion_tokens=0, max_tokens=0, metadata={"foo": "string"}, - modalities=["text", "audio"], + modalities=["text"], n=1, parallel_tool_calls=True, prediction={ @@ -502,25 +448,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn "strict": True, }, "type": "function", - }, - { - "function": { - "name": "name", - "description": "description", - "parameters": {"foo": "bar"}, - "strict": True, - }, - "type": "function", - }, - { - "function": { - "name": "name", - "description": "description", - "parameters": {"foo": "bar"}, - "strict": True, - }, - "type": "function", - }, + } ], top_logprobs=0, top_p=1, diff --git a/tests/api_resources/fine_tuning/test_jobs.py b/tests/api_resources/fine_tuning/test_jobs.py index d1ad611219..aa2bf39528 100644 --- a/tests/api_resources/fine_tuning/test_jobs.py +++ b/tests/api_resources/fine_tuning/test_jobs.py @@ -46,27 +46,9 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: "project": "my-wandb-project", "entity": "entity", "name": "name", - "tags": ["custom-tag", "custom-tag", "custom-tag"], + "tags": ["custom-tag"], }, - }, - { - "type": "wandb", - "wandb": { - "project": "my-wandb-project", - "entity": "entity", - "name": "name", - "tags": ["custom-tag", "custom-tag", "custom-tag"], - }, - }, - { - "type": "wandb", - "wandb": { - "project": "my-wandb-project", - "entity": "entity", - "name": "name", - "tags": ["custom-tag", "custom-tag", "custom-tag"], - }, - }, + } ], seed=42, suffix="x", @@ -285,27 +267,9 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> "project": "my-wandb-project", "entity": "entity", "name": "name", - "tags": ["custom-tag", "custom-tag", "custom-tag"], - }, - }, - { - "type": "wandb", - "wandb": { - "project": "my-wandb-project", - "entity": "entity", - "name": "name", - "tags": ["custom-tag", "custom-tag", "custom-tag"], - }, - }, - { - "type": "wandb", - "wandb": { - "project": "my-wandb-project", - "entity": "entity", - "name": "name", - "tags": ["custom-tag", "custom-tag", "custom-tag"], + "tags": ["custom-tag"], }, - }, + } ], seed=42, suffix="x", diff --git a/tests/api_resources/test_uploads.py b/tests/api_resources/test_uploads.py index cb62df6b51..a14c4f8da2 100644 --- a/tests/api_resources/test_uploads.py +++ b/tests/api_resources/test_uploads.py @@ -99,7 +99,7 @@ def test_path_params_cancel(self, client: OpenAI) -> None: def test_method_complete(self, client: OpenAI) -> None: upload = client.uploads.complete( upload_id="upload_abc123", - part_ids=["string", "string", "string"], + part_ids=["string"], ) assert_matches_type(Upload, upload, path=["response"]) @@ -107,7 +107,7 @@ def test_method_complete(self, client: OpenAI) -> None: def test_method_complete_with_all_params(self, client: OpenAI) -> None: upload = client.uploads.complete( upload_id="upload_abc123", - part_ids=["string", "string", "string"], + part_ids=["string"], md5="md5", ) assert_matches_type(Upload, upload, path=["response"]) @@ -116,7 +116,7 @@ def test_method_complete_with_all_params(self, client: OpenAI) -> None: def test_raw_response_complete(self, client: OpenAI) -> None: response = client.uploads.with_raw_response.complete( upload_id="upload_abc123", - part_ids=["string", "string", "string"], + part_ids=["string"], ) assert response.is_closed is True @@ -128,7 +128,7 @@ def test_raw_response_complete(self, client: OpenAI) -> None: def test_streaming_response_complete(self, client: OpenAI) -> None: with client.uploads.with_streaming_response.complete( upload_id="upload_abc123", - part_ids=["string", "string", "string"], + part_ids=["string"], ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -143,7 +143,7 @@ def test_path_params_complete(self, client: OpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `upload_id` but received ''"): client.uploads.with_raw_response.complete( upload_id="", - part_ids=["string", "string", "string"], + part_ids=["string"], ) @@ -232,7 +232,7 @@ async def test_path_params_cancel(self, async_client: AsyncOpenAI) -> None: async def test_method_complete(self, async_client: AsyncOpenAI) -> None: upload = await async_client.uploads.complete( upload_id="upload_abc123", - part_ids=["string", "string", "string"], + part_ids=["string"], ) assert_matches_type(Upload, upload, path=["response"]) @@ -240,7 +240,7 @@ async def test_method_complete(self, async_client: AsyncOpenAI) -> None: async def test_method_complete_with_all_params(self, async_client: AsyncOpenAI) -> None: upload = await async_client.uploads.complete( upload_id="upload_abc123", - part_ids=["string", "string", "string"], + part_ids=["string"], md5="md5", ) assert_matches_type(Upload, upload, path=["response"]) @@ -249,7 +249,7 @@ async def test_method_complete_with_all_params(self, async_client: AsyncOpenAI) async def test_raw_response_complete(self, async_client: AsyncOpenAI) -> None: response = await async_client.uploads.with_raw_response.complete( upload_id="upload_abc123", - part_ids=["string", "string", "string"], + part_ids=["string"], ) assert response.is_closed is True @@ -261,7 +261,7 @@ async def test_raw_response_complete(self, async_client: AsyncOpenAI) -> None: async def test_streaming_response_complete(self, async_client: AsyncOpenAI) -> None: async with async_client.uploads.with_streaming_response.complete( upload_id="upload_abc123", - part_ids=["string", "string", "string"], + part_ids=["string"], ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -276,5 +276,5 @@ async def test_path_params_complete(self, async_client: AsyncOpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `upload_id` but received ''"): await async_client.uploads.with_raw_response.complete( upload_id="", - part_ids=["string", "string", "string"], + part_ids=["string"], ) From 0d6185edc2eb4155699a28415b8759653f91ef52 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 10:42:24 +0000 Subject: [PATCH 084/769] chore(internal): spec update (#1873) --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index f368bc881d..fdef8d2744 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 68 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-2f8ca92b9b1879fd535b685e4767338413fcd533d42f3baac13a9c41da3fce35.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-fb9db2d2c1f0d6b39d8ee042db5d5c59acba6ad1daf47c18792c1f5fb24b3401.yml From d8901d28587ad9db4f1435f1f00ad7b919c232f7 Mon Sep 17 00:00:00 2001 From: Seth Gilchrist Date: Mon, 18 Nov 2024 04:41:32 -0800 Subject: [PATCH 085/769] fix(asyncify): avoid hanging process under certain conditions (#1853) --- pyproject.toml | 4 +- requirements-dev.lock | 2 + requirements.lock | 1 + src/openai/_utils/_sync.py | 90 +++++++++++++++++--------------------- tests/test_client.py | 43 ++++++++++++++++++ 5 files changed, 88 insertions(+), 52 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e0a20e8387..b22ef1927d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -65,7 +65,9 @@ dev-dependencies = [ "azure-identity >=1.14.1", "types-tqdm > 4", "types-pyaudio > 0", - "trio >=0.22.2" + "trio >=0.22.2", + "nest_asyncio==1.6.0" + ] [tool.rye.scripts] diff --git a/requirements-dev.lock b/requirements-dev.lock index 5fe1ccad57..4d0ab191a4 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -7,6 +7,7 @@ # all-features: true # with-sources: false # generate-hashes: false +# universal: false -e file:. annotated-types==0.6.0 @@ -87,6 +88,7 @@ mypy==1.13.0 mypy-extensions==1.0.0 # via black # via mypy +nest-asyncio==1.6.0 nodeenv==1.8.0 # via pyright nox==2023.4.22 diff --git a/requirements.lock b/requirements.lock index 019dfcb4c5..aef8bc0a9a 100644 --- a/requirements.lock +++ b/requirements.lock @@ -7,6 +7,7 @@ # all-features: true # with-sources: false # generate-hashes: false +# universal: false -e file:. annotated-types==0.6.0 diff --git a/src/openai/_utils/_sync.py b/src/openai/_utils/_sync.py index d0d810337e..c0a0ae714c 100644 --- a/src/openai/_utils/_sync.py +++ b/src/openai/_utils/_sync.py @@ -1,56 +1,60 @@ from __future__ import annotations +import sys +import asyncio import functools -from typing import TypeVar, Callable, Awaitable +import contextvars +from typing import Any, TypeVar, Callable, Awaitable from typing_extensions import ParamSpec -import anyio -import anyio.to_thread - -from ._reflection import function_has_argument - T_Retval = TypeVar("T_Retval") T_ParamSpec = ParamSpec("T_ParamSpec") -# copied from `asyncer`, https://github.com/tiangolo/asyncer -def asyncify( - function: Callable[T_ParamSpec, T_Retval], - *, - cancellable: bool = False, - limiter: anyio.CapacityLimiter | None = None, -) -> Callable[T_ParamSpec, Awaitable[T_Retval]]: - """ - Take a blocking function and create an async one that receives the same - positional and keyword arguments, and that when called, calls the original function - in a worker thread using `anyio.to_thread.run_sync()`. Internally, - `asyncer.asyncify()` uses the same `anyio.to_thread.run_sync()`, but it supports - keyword arguments additional to positional arguments and it adds better support for - autocompletion and inline errors for the arguments of the function called and the - return value. +if sys.version_info >= (3, 9): + to_thread = asyncio.to_thread +else: + async def _to_thread( + func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs + ) -> Any: + """Asynchronously run function *func* in a separate thread. - If the `cancellable` option is enabled and the task waiting for its completion is - cancelled, the thread will still run its course but its return value (or any raised - exception) will be ignored. + Any *args and **kwargs supplied for this function are directly passed + to *func*. Also, the current :class:`contextvars.Context` is propagated, + allowing context variables from the main thread to be accessed in the + separate thread. - Use it like this: + Returns a coroutine that can be awaited to get the eventual result of *func*. + """ + loop = asyncio.events.get_running_loop() + ctx = contextvars.copy_context() + func_call = functools.partial(ctx.run, func, *args, **kwargs) + return await loop.run_in_executor(None, func_call) + + to_thread = _to_thread + +# inspired by `asyncer`, https://github.com/tiangolo/asyncer +def asyncify(function: Callable[T_ParamSpec, T_Retval]) -> Callable[T_ParamSpec, Awaitable[T_Retval]]: + """ + Take a blocking function and create an async one that receives the same + positional and keyword arguments. For python version 3.9 and above, it uses + asyncio.to_thread to run the function in a separate thread. For python version + 3.8, it uses locally defined copy of the asyncio.to_thread function which was + introduced in python 3.9. - ```Python - def do_work(arg1, arg2, kwarg1="", kwarg2="") -> str: - # Do work - return "Some result" + Usage: + ```python + def blocking_func(arg1, arg2, kwarg1=None): + # blocking code + return result - result = await to_thread.asyncify(do_work)("spam", "ham", kwarg1="a", kwarg2="b") - print(result) + result = asyncify(blocking_function)(arg1, arg2, kwarg1=value1) ``` ## Arguments `function`: a blocking regular callable (e.g. a function) - `cancellable`: `True` to allow cancellation of the operation - `limiter`: capacity limiter to use to limit the total amount of threads running - (if omitted, the default limiter is used) ## Return @@ -60,22 +64,6 @@ def do_work(arg1, arg2, kwarg1="", kwarg2="") -> str: """ async def wrapper(*args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs) -> T_Retval: - partial_f = functools.partial(function, *args, **kwargs) - - # In `v4.1.0` anyio added the `abandon_on_cancel` argument and deprecated the old - # `cancellable` argument, so we need to use the new `abandon_on_cancel` to avoid - # surfacing deprecation warnings. - if function_has_argument(anyio.to_thread.run_sync, "abandon_on_cancel"): - return await anyio.to_thread.run_sync( - partial_f, - abandon_on_cancel=cancellable, - limiter=limiter, - ) - - return await anyio.to_thread.run_sync( - partial_f, - cancellable=cancellable, - limiter=limiter, - ) + return await to_thread(function, *args, **kwargs) return wrapper diff --git a/tests/test_client.py b/tests/test_client.py index 7ea2ab38d1..08aff23f53 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -4,11 +4,14 @@ import gc import os +import sys import json import asyncio import inspect +import subprocess import tracemalloc from typing import Any, Union, cast +from textwrap import dedent from unittest import mock from typing_extensions import Literal @@ -1766,3 +1769,43 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: ) as response: assert response.retries_taken == failures_before_success assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success + + def test_get_platform(self) -> None: + # Issue https://github.com/openai/openai-python/issues/1827 was caused + # asyncify leaving threads unterminated when used with nest_asyncio. + # Since nest_asyncio.apply() is global and cannot be un-applied, this + # test is run in a separate process to avoid affecting other tests. + test_code = dedent("""\ + import asyncio + import nest_asyncio + + import threading + + from openai._base_client import get_platform + from openai._utils import asyncify + + async def test_main() -> None: + result = await asyncify(get_platform)() + print(result) + for thread in threading.enumerate(): + print(thread.name) + + nest_asyncio.apply() + asyncio.run(test_main()) + """) + with subprocess.Popen( + [sys.executable, "-c", test_code], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + ) as process: + try: + process.wait(2) + if process.returncode: + print(process.stdout) + print(process.stderr) + raise AssertionError("calling get_platform using asyncify resulted in a non-zero exit code") + except subprocess.TimeoutExpired as e: + process.kill() + raise AssertionError("calling get_platform using asyncify resulted in a hung process") from e + From 53ab046716631e5539304052162e5b374a2d6f15 Mon Sep 17 00:00:00 2001 From: Stainless Bot Date: Mon, 18 Nov 2024 12:58:39 +0000 Subject: [PATCH 086/769] chore(internal): minor test changes (#1874) --- src/openai/_utils/_sync.py | 5 +++-- tests/test_client.py | 15 +++++---------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/openai/_utils/_sync.py b/src/openai/_utils/_sync.py index c0a0ae714c..5d9e2c2ac9 100644 --- a/src/openai/_utils/_sync.py +++ b/src/openai/_utils/_sync.py @@ -14,7 +14,9 @@ if sys.version_info >= (3, 9): to_thread = asyncio.to_thread else: - async def _to_thread( + # backport of https://docs.python.org/3/library/asyncio-task.html#asyncio.to_thread + # for Python 3.8 support + async def to_thread( func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs ) -> Any: """Asynchronously run function *func* in a separate thread. @@ -31,7 +33,6 @@ async def _to_thread( func_call = functools.partial(ctx.run, func, *args, **kwargs) return await loop.run_in_executor(None, func_call) - to_thread = _to_thread # inspired by `asyncer`, https://github.com/tiangolo/asyncer def asyncify(function: Callable[T_ParamSpec, T_Retval]) -> Callable[T_ParamSpec, Awaitable[T_Retval]]: diff --git a/tests/test_client.py b/tests/test_client.py index 08aff23f53..7caa8cb319 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -1771,18 +1771,18 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success def test_get_platform(self) -> None: - # Issue https://github.com/openai/openai-python/issues/1827 was caused - # asyncify leaving threads unterminated when used with nest_asyncio. + # A previous implementation of asyncify could leave threads unterminated when + # used with nest_asyncio. + # # Since nest_asyncio.apply() is global and cannot be un-applied, this # test is run in a separate process to avoid affecting other tests. - test_code = dedent("""\ + test_code = dedent(""" import asyncio import nest_asyncio - import threading - from openai._base_client import get_platform from openai._utils import asyncify + from openai._base_client import get_platform async def test_main() -> None: result = await asyncify(get_platform)() @@ -1795,17 +1795,12 @@ async def test_main() -> None: """) with subprocess.Popen( [sys.executable, "-c", test_code], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, text=True, ) as process: try: process.wait(2) if process.returncode: - print(process.stdout) - print(process.stderr) raise AssertionError("calling get_platform using asyncify resulted in a non-zero exit code") except subprocess.TimeoutExpired as e: process.kill() raise AssertionError("calling get_platform using asyncify resulted in a hung process") from e - From 7cdc6ddbdd3c09e567c5582490aec9d7f99c468e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 19 Nov 2024 05:04:28 +0000 Subject: [PATCH 087/769] release: 1.54.5 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 15 +++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 7bfe725d47..68c5231faa 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.54.4" + ".": "1.54.5" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index d82ac42553..c646eca314 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## 1.54.5 (2024-11-19) + +Full Changelog: [v1.54.4...v1.54.5](https://github.com/openai/openai-python/compare/v1.54.4...v1.54.5) + +### Bug Fixes + +* **asyncify:** avoid hanging process under certain conditions ([#1853](https://github.com/openai/openai-python/issues/1853)) ([3d23437](https://github.com/openai/openai-python/commit/3d234377e7c9cd19db5186688612eb18e68cec8f)) + + +### Chores + +* **internal:** minor test changes ([#1874](https://github.com/openai/openai-python/issues/1874)) ([189339d](https://github.com/openai/openai-python/commit/189339d2a09d23ea1883286972f366e19b397f91)) +* **internal:** spec update ([#1873](https://github.com/openai/openai-python/issues/1873)) ([24c81f7](https://github.com/openai/openai-python/commit/24c81f729ae09ba3cec5542e5cc955c8b05b0f88)) +* **tests:** limit array example length ([#1870](https://github.com/openai/openai-python/issues/1870)) ([1e550df](https://github.com/openai/openai-python/commit/1e550df708fc3b5d903b7adfa2180058a216b676)) + ## 1.54.4 (2024-11-12) Full Changelog: [v1.54.3...v1.54.4](https://github.com/openai/openai-python/compare/v1.54.3...v1.54.4) diff --git a/pyproject.toml b/pyproject.toml index b22ef1927d..8138ffbaef 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.54.4" +version = "1.54.5" 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 5e531dd083..75ee06518f 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.54.4" # x-release-please-version +__version__ = "1.54.5" # x-release-please-version From 8eba381dc2b062ca41e909adef95540a6234be50 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 20 Nov 2024 18:17:44 +0000 Subject: [PATCH 088/769] feat(api): add gpt-4o-2024-11-20 model (#1877) --- .stats.yml | 2 +- src/openai/resources/batches.py | 4 ++-- src/openai/resources/files.py | 4 ++-- src/openai/types/batch_create_params.py | 2 +- src/openai/types/chat/chat_completion_audio_param.py | 5 +++-- src/openai/types/chat_model.py | 1 + 6 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.stats.yml b/.stats.yml index fdef8d2744..4827e5388f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 68 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-fb9db2d2c1f0d6b39d8ee042db5d5c59acba6ad1daf47c18792c1f5fb24b3401.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-aa9b01fc0c17eb0cbc200533fc20d6a49c5e764ceaf8049e08b294532be6e9ff.yml diff --git a/src/openai/resources/batches.py b/src/openai/resources/batches.py index a8a0ba4bbc..7cab75785d 100644 --- a/src/openai/resources/batches.py +++ b/src/openai/resources/batches.py @@ -81,7 +81,7 @@ def create( Your input file must be formatted as a [JSONL file](https://platform.openai.com/docs/api-reference/batch/request-input), and must be uploaded with the purpose `batch`. The file can contain up to 50,000 - requests, and can be up to 100 MB in size. + requests, and can be up to 200 MB in size. metadata: Optional custom metadata for the batch. @@ -286,7 +286,7 @@ async def create( Your input file must be formatted as a [JSONL file](https://platform.openai.com/docs/api-reference/batch/request-input), and must be uploaded with the purpose `batch`. The file can contain up to 50,000 - requests, and can be up to 100 MB in size. + requests, and can be up to 200 MB in size. metadata: Optional custom metadata for the batch. diff --git a/src/openai/resources/files.py b/src/openai/resources/files.py index 77706a7fd8..6eaea1b568 100644 --- a/src/openai/resources/files.py +++ b/src/openai/resources/files.py @@ -86,7 +86,7 @@ def create( [completions](https://platform.openai.com/docs/api-reference/fine-tuning/completions-input) models. - The Batch API only supports `.jsonl` files up to 100 MB in size. The input also + The Batch API only supports `.jsonl` files up to 200 MB in size. The input also has a specific required [format](https://platform.openai.com/docs/api-reference/batch/request-input). @@ -402,7 +402,7 @@ async def create( [completions](https://platform.openai.com/docs/api-reference/fine-tuning/completions-input) models. - The Batch API only supports `.jsonl` files up to 100 MB in size. The input also + The Batch API only supports `.jsonl` files up to 200 MB in size. The input also has a specific required [format](https://platform.openai.com/docs/api-reference/batch/request-input). diff --git a/src/openai/types/batch_create_params.py b/src/openai/types/batch_create_params.py index 55517d285b..b30c4d4658 100644 --- a/src/openai/types/batch_create_params.py +++ b/src/openai/types/batch_create_params.py @@ -32,7 +32,7 @@ class BatchCreateParams(TypedDict, total=False): Your input file must be formatted as a [JSONL file](https://platform.openai.com/docs/api-reference/batch/request-input), and must be uploaded with the purpose `batch`. The file can contain up to 50,000 - requests, and can be up to 100 MB in size. + requests, and can be up to 200 MB in size. """ metadata: Optional[Dict[str, str]] diff --git a/src/openai/types/chat/chat_completion_audio_param.py b/src/openai/types/chat/chat_completion_audio_param.py index b92326d294..1e20a52b41 100644 --- a/src/openai/types/chat/chat_completion_audio_param.py +++ b/src/openai/types/chat/chat_completion_audio_param.py @@ -17,6 +17,7 @@ class ChatCompletionAudioParam(TypedDict, total=False): voice: Required[Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"]] """The voice the model uses to respond. - Supported voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`, - `shimmer`, and `verse`. + Supported voices are `ash`, `ballad`, `coral`, `sage`, and `verse` (also + supported but not recommended are `alloy`, `echo`, and `shimmer`; these voices + are less expressive). """ diff --git a/src/openai/types/chat_model.py b/src/openai/types/chat_model.py index b801aa0914..3567a3ba65 100644 --- a/src/openai/types/chat_model.py +++ b/src/openai/types/chat_model.py @@ -10,6 +10,7 @@ "o1-mini", "o1-mini-2024-09-12", "gpt-4o", + "gpt-4o-2024-11-20", "gpt-4o-2024-08-06", "gpt-4o-2024-05-13", "gpt-4o-realtime-preview", From 83091e96cf43f344d22799c22eea301aeae36d51 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 20 Nov 2024 18:18:15 +0000 Subject: [PATCH 089/769] release: 1.55.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 68c5231faa..061f355bf3 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.54.5" + ".": "1.55.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index c646eca314..921f9b7bad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.55.0 (2024-11-20) + +Full Changelog: [v1.54.5...v1.55.0](https://github.com/openai/openai-python/compare/v1.54.5...v1.55.0) + +### Features + +* **api:** add gpt-4o-2024-11-20 model ([#1877](https://github.com/openai/openai-python/issues/1877)) ([ff64c2a](https://github.com/openai/openai-python/commit/ff64c2a0733854ed8cc1d7dd959a8287b2ec8120)) + ## 1.54.5 (2024-11-19) Full Changelog: [v1.54.4...v1.54.5](https://github.com/openai/openai-python/compare/v1.54.4...v1.54.5) diff --git a/pyproject.toml b/pyproject.toml index 8138ffbaef..02b3fbfb93 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.54.5" +version = "1.55.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 75ee06518f..093c3e3939 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.54.5" # x-release-please-version +__version__ = "1.55.0" # x-release-please-version From e9cbb256650a07c008e6529778e10cc66e9f7605 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 22 Nov 2024 11:22:30 +0000 Subject: [PATCH 090/769] fix(pydantic-v1): avoid runtime error for assistants streaming (#1885) --- src/openai/_compat.py | 3 ++- tests/test_models.py | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/openai/_compat.py b/src/openai/_compat.py index 7c3156a5eb..d7196c9193 100644 --- a/src/openai/_compat.py +++ b/src/openai/_compat.py @@ -145,7 +145,8 @@ def model_dump( exclude=exclude, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, - warnings=warnings, + # warnings are not supported in Pydantic v1 + warnings=warnings if PYDANTIC_V2 else True, ) return cast( "dict[str, Any]", diff --git a/tests/test_models.py b/tests/test_models.py index 84dbce6914..d2884bcbfa 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -561,6 +561,14 @@ class Model(BaseModel): m.model_dump(warnings=False) +def test_compat_method_no_error_for_warnings() -> None: + class Model(BaseModel): + foo: Optional[str] + + m = Model(foo="hello") + assert isinstance(model_dump(m, warnings=False), dict) + + def test_to_json() -> None: class Model(BaseModel): foo: Optional[str] = Field(alias="FOO", default=None) From f6199d60a0384bfb71c0ca2eb24c5765d760715e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 22 Nov 2024 16:06:42 +0000 Subject: [PATCH 091/769] docs: add info log level to readme (#1887) --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f1cd97b96e..5854e8d3ad 100644 --- a/README.md +++ b/README.md @@ -509,12 +509,14 @@ Note that requests that time out are [retried twice by default](#retries). We use the standard library [`logging`](https://docs.python.org/3/library/logging.html) module. -You can enable logging by setting the environment variable `OPENAI_LOG` to `debug`. +You can enable logging by setting the environment variable `OPENAI_LOG` to `info`. ```shell -$ export OPENAI_LOG=debug +$ export OPENAI_LOG=info ``` +Or to `debug` for more verbose logging. + ### How to tell whether `None` means `null` or missing In an API response, a field may be explicitly `null`, or missing entirely; in either case, its value is `None` in this library. You can differentiate the two cases with `.model_fields_set`: From 5dfb00886eb56db340a689380c6a481a7b7ea34f Mon Sep 17 00:00:00 2001 From: Harutaka Kawamura Date: Mon, 25 Nov 2024 21:17:54 +0900 Subject: [PATCH 092/769] chore: remove now unused `cached-property` dep (#1867) --- pyproject.toml | 1 - src/openai/_compat.py | 5 +---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 02b3fbfb93..4c41631edd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,7 +14,6 @@ dependencies = [ "anyio>=3.5.0, <5", "distro>=1.7.0, <2", "sniffio", - "cached-property; python_version < '3.8'", "tqdm > 4", "jiter>=0.4.0, <1", ] diff --git a/src/openai/_compat.py b/src/openai/_compat.py index d7196c9193..87fc370765 100644 --- a/src/openai/_compat.py +++ b/src/openai/_compat.py @@ -226,9 +226,6 @@ def __set_name__(self, owner: type[Any], name: str) -> None: ... # __set__ is not defined at runtime, but @cached_property is designed to be settable def __set__(self, instance: object, value: _T) -> None: ... else: - try: - from functools import cached_property as cached_property - except ImportError: - from cached_property import cached_property as cached_property + from functools import cached_property as cached_property typed_cached_property = cached_property From 83f4774156dc3e29c7fe6be9ffd681df68534509 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2024 12:25:56 +0000 Subject: [PATCH 093/769] release: 1.55.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 19 +++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 061f355bf3..af721f5395 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.55.0" + ".": "1.55.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 921f9b7bad..409d3c2df0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## 1.55.1 (2024-11-25) + +Full Changelog: [v1.55.0...v1.55.1](https://github.com/openai/openai-python/compare/v1.55.0...v1.55.1) + +### Bug Fixes + +* **pydantic-v1:** avoid runtime error for assistants streaming ([#1885](https://github.com/openai/openai-python/issues/1885)) ([197c94b](https://github.com/openai/openai-python/commit/197c94b9e2620da8902aeed6959d2f871bb70461)) + + +### Chores + +* remove now unused `cached-property` dep ([#1867](https://github.com/openai/openai-python/issues/1867)) ([df5fac1](https://github.com/openai/openai-python/commit/df5fac1e557f79ed8d0935c48ca7f3f0bf77fa98)) +* remove now unused `cached-property` dep ([#1891](https://github.com/openai/openai-python/issues/1891)) ([feebaae](https://github.com/openai/openai-python/commit/feebaae85d76960cb8f1c58dd9b5180136c47962)) + + +### Documentation + +* add info log level to readme ([#1887](https://github.com/openai/openai-python/issues/1887)) ([358255d](https://github.com/openai/openai-python/commit/358255d15ed220f8c80a3c0861b98e61e909a7ae)) + ## 1.55.0 (2024-11-20) Full Changelog: [v1.54.5...v1.55.0](https://github.com/openai/openai-python/compare/v1.54.5...v1.55.0) diff --git a/pyproject.toml b/pyproject.toml index 4c41631edd..fb48acf1f2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.55.0" +version = "1.55.1" 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 093c3e3939..f3c5f8db8b 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.55.0" # x-release-please-version +__version__ = "1.55.1" # x-release-please-version From 3ad59995e7475fa30007255d2a26bad09392b515 Mon Sep 17 00:00:00 2001 From: Vincent Josse Date: Wed, 27 Nov 2024 11:35:24 +0100 Subject: [PATCH 094/769] docs(assistants): correct on_text_delta example (#1896) --- src/openai/lib/streaming/_assistants.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openai/lib/streaming/_assistants.py b/src/openai/lib/streaming/_assistants.py index 103e4c40aa..6efb3ca3f1 100644 --- a/src/openai/lib/streaming/_assistants.py +++ b/src/openai/lib/streaming/_assistants.py @@ -243,7 +243,7 @@ def on_text_delta(self, delta: TextDelta, snapshot: Text) -> None: on_text_delta(TextDelta(value=" solution"), Text(value="The solution")), on_text_delta(TextDelta(value=" to"), Text(value="The solution to")), on_text_delta(TextDelta(value=" the"), Text(value="The solution to the")), - on_text_delta(TextDelta(value=" equation"), Text(value="The solution to the equivalent")), + on_text_delta(TextDelta(value=" equation"), Text(value="The solution to the equation")), """ def on_text_done(self, text: Text) -> None: From f2607f54b9f51a6f3fcb168834bd6351c1512ab9 Mon Sep 17 00:00:00 2001 From: Stainless Bot Date: Wed, 27 Nov 2024 14:04:44 +0000 Subject: [PATCH 095/769] chore(internal): exclude mypy from running on tests (#1899) --- mypy.ini | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mypy.ini b/mypy.ini index 97e5de4a60..50e5add04b 100644 --- a/mypy.ini +++ b/mypy.ini @@ -5,7 +5,10 @@ show_error_codes = True # Exclude _files.py and _logs.py because mypy isn't smart enough to apply # the correct type narrowing and as this is an internal module # it's fine to just use Pyright. -exclude = ^(src/openai/_files\.py|src/openai/_utils/_logs\.py|_dev/.*\.py)$ +# +# We also exclude our `tests` as mypy doesn't always infer +# types correctly and Pyright will still catch any type errors. +exclude = ^(src/openai/_files\.py|src/openai/_utils/_logs\.py|_dev/.*\.py|tests/.*)$ strict_equality = True implicit_reexport = True From 95bd2582a1e37bb35eac429925ffa0aea10078a5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 27 Nov 2024 14:05:13 +0000 Subject: [PATCH 096/769] release: 1.55.2 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index af721f5395..488f1adb5e 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.55.1" + ".": "1.55.2" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 409d3c2df0..8009aac671 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 1.55.2 (2024-11-27) + +Full Changelog: [v1.55.1...v1.55.2](https://github.com/openai/openai-python/compare/v1.55.1...v1.55.2) + +### Chores + +* **internal:** exclude mypy from running on tests ([#1899](https://github.com/openai/openai-python/issues/1899)) ([e2496f1](https://github.com/openai/openai-python/commit/e2496f1d274126bdaa46a8256b3dd384b4ae244b)) + + +### Documentation + +* **assistants:** correct on_text_delta example ([#1896](https://github.com/openai/openai-python/issues/1896)) ([460b663](https://github.com/openai/openai-python/commit/460b663567ed1031467a8d69eb13fd3b3da38827)) + ## 1.55.1 (2024-11-25) Full Changelog: [v1.55.0...v1.55.1](https://github.com/openai/openai-python/compare/v1.55.0...v1.55.1) diff --git a/pyproject.toml b/pyproject.toml index fb48acf1f2..4842cceea4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.55.1" +version = "1.55.2" 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 f3c5f8db8b..5b04f5cc00 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.55.1" # x-release-please-version +__version__ = "1.55.2" # x-release-please-version From bb9cf7a6acfd1729fa76247da041a4787a6bfc1a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 28 Nov 2024 16:16:48 +0000 Subject: [PATCH 097/769] fix(client): compat with new httpx 0.28.0 release (#1904) --- src/openai/_base_client.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index 187518787a..cceec903d9 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -794,6 +794,7 @@ def __init__( custom_query: Mapping[str, object] | None = None, _strict_response_validation: bool, ) -> None: + kwargs: dict[str, Any] = {} if limits is not None: warnings.warn( "The `connection_pool_limits` argument is deprecated. The `http_client` argument should be passed instead", @@ -806,6 +807,7 @@ def __init__( limits = DEFAULT_CONNECTION_LIMITS if transport is not None: + kwargs["transport"] = transport warnings.warn( "The `transport` argument is deprecated. The `http_client` argument should be passed instead", category=DeprecationWarning, @@ -815,6 +817,7 @@ def __init__( raise ValueError("The `http_client` argument is mutually exclusive with `transport`") if proxies is not None: + kwargs["proxies"] = proxies warnings.warn( "The `proxies` argument is deprecated. The `http_client` argument should be passed instead", category=DeprecationWarning, @@ -858,10 +861,9 @@ def __init__( base_url=base_url, # cast to a valid type because mypy doesn't understand our type narrowing timeout=cast(Timeout, timeout), - proxies=proxies, - transport=transport, limits=limits, follow_redirects=True, + **kwargs, # type: ignore ) def is_closed(self) -> bool: @@ -1375,6 +1377,7 @@ def __init__( custom_headers: Mapping[str, str] | None = None, custom_query: Mapping[str, object] | None = None, ) -> None: + kwargs: dict[str, Any] = {} if limits is not None: warnings.warn( "The `connection_pool_limits` argument is deprecated. The `http_client` argument should be passed instead", @@ -1387,6 +1390,7 @@ def __init__( limits = DEFAULT_CONNECTION_LIMITS if transport is not None: + kwargs["transport"] = transport warnings.warn( "The `transport` argument is deprecated. The `http_client` argument should be passed instead", category=DeprecationWarning, @@ -1396,6 +1400,7 @@ def __init__( raise ValueError("The `http_client` argument is mutually exclusive with `transport`") if proxies is not None: + kwargs["proxies"] = proxies warnings.warn( "The `proxies` argument is deprecated. The `http_client` argument should be passed instead", category=DeprecationWarning, @@ -1439,10 +1444,9 @@ def __init__( base_url=base_url, # cast to a valid type because mypy doesn't understand our type narrowing timeout=cast(Timeout, timeout), - proxies=proxies, - transport=transport, limits=limits, follow_redirects=True, + **kwargs, # type: ignore ) def is_closed(self) -> bool: From 6974a981aec1814b5abba429a8ea21be9ac58538 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 28 Nov 2024 16:17:16 +0000 Subject: [PATCH 098/769] release: 1.55.3 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 488f1adb5e..d23d0104a4 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.55.2" + ".": "1.55.3" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 8009aac671..866d34cb4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.55.3 (2024-11-28) + +Full Changelog: [v1.55.2...v1.55.3](https://github.com/openai/openai-python/compare/v1.55.2...v1.55.3) + +### Bug Fixes + +* **client:** compat with new httpx 0.28.0 release ([#1904](https://github.com/openai/openai-python/issues/1904)) ([72b6c63](https://github.com/openai/openai-python/commit/72b6c636c526885ef873580a07eff1c18e76bc10)) + ## 1.55.2 (2024-11-27) Full Changelog: [v1.55.1...v1.55.2](https://github.com/openai/openai-python/compare/v1.55.1...v1.55.2) diff --git a/pyproject.toml b/pyproject.toml index 4842cceea4..06c0e7fd73 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.55.2" +version = "1.55.3" 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 5b04f5cc00..c6d4c88a6d 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.55.2" # x-release-please-version +__version__ = "1.55.3" # x-release-please-version From 778e28e5658b4fcf2b11b51b5d7506bd1884e2d2 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Fri, 29 Nov 2024 16:05:14 -0500 Subject: [PATCH 099/769] feat(client): make ChatCompletionStreamState public (#1898) --- src/openai/lib/streaming/chat/__init__.py | 1 + src/openai/lib/streaming/chat/_completions.py | 33 ++++++- tests/lib/chat/test_completions_streaming.py | 94 ++++++++++++++++++- 3 files changed, 123 insertions(+), 5 deletions(-) diff --git a/src/openai/lib/streaming/chat/__init__.py b/src/openai/lib/streaming/chat/__init__.py index 5881c39b9a..dfa3f3f2e3 100644 --- a/src/openai/lib/streaming/chat/__init__.py +++ b/src/openai/lib/streaming/chat/__init__.py @@ -21,6 +21,7 @@ from ._completions import ( ChatCompletionStream as ChatCompletionStream, AsyncChatCompletionStream as AsyncChatCompletionStream, + ChatCompletionStreamState as ChatCompletionStreamState, ChatCompletionStreamManager as ChatCompletionStreamManager, AsyncChatCompletionStreamManager as AsyncChatCompletionStreamManager, ) diff --git a/src/openai/lib/streaming/chat/_completions.py b/src/openai/lib/streaming/chat/_completions.py index 8518de967f..2146091354 100644 --- a/src/openai/lib/streaming/chat/_completions.py +++ b/src/openai/lib/streaming/chat/_completions.py @@ -287,11 +287,31 @@ async def __aexit__( class ChatCompletionStreamState(Generic[ResponseFormatT]): + """Helper class for manually accumulating `ChatCompletionChunk`s into a final `ChatCompletion` object. + + This is useful in cases where you can't always use the `.stream()` method, e.g. + + ```py + from openai.lib.streaming.chat import ChatCompletionStreamState + + state = ChatCompletionStreamState() + + stream = client.chat.completions.create(..., stream=True) + for chunk in response: + state.handle_chunk(chunk) + + # can also access the accumulated `ChatCompletion` mid-stream + state.current_completion_snapshot + + print(state.get_final_completion()) + ``` + """ + def __init__( self, *, - input_tools: Iterable[ChatCompletionToolParam] | NotGiven, - response_format: type[ResponseFormatT] | ResponseFormatParam | NotGiven, + input_tools: Iterable[ChatCompletionToolParam] | NotGiven = NOT_GIVEN, + response_format: type[ResponseFormatT] | ResponseFormatParam | NotGiven = NOT_GIVEN, ) -> None: self.__current_completion_snapshot: ParsedChatCompletionSnapshot | None = None self.__choice_event_states: list[ChoiceEventState] = [] @@ -301,6 +321,11 @@ def __init__( self._rich_response_format: type | NotGiven = response_format if inspect.isclass(response_format) else NOT_GIVEN def get_final_completion(self) -> ParsedChatCompletion[ResponseFormatT]: + """Parse the final completion object. + + Note this does not provide any guarantees that the stream has actually finished, you must + only call this method when the stream is finished. + """ return parse_chat_completion( chat_completion=self.current_completion_snapshot, response_format=self._rich_response_format, @@ -312,8 +337,8 @@ def current_completion_snapshot(self) -> ParsedChatCompletionSnapshot: assert self.__current_completion_snapshot is not None return self.__current_completion_snapshot - def handle_chunk(self, chunk: ChatCompletionChunk) -> list[ChatCompletionStreamEvent[ResponseFormatT]]: - """Accumulate a new chunk into the snapshot and returns a list of events to yield.""" + def handle_chunk(self, chunk: ChatCompletionChunk) -> Iterable[ChatCompletionStreamEvent[ResponseFormatT]]: + """Accumulate a new chunk into the snapshot and returns an iterable of events to yield.""" self.__current_completion_snapshot = self._accumulate_chunk(chunk) return self._build_events( diff --git a/tests/lib/chat/test_completions_streaming.py b/tests/lib/chat/test_completions_streaming.py index ab12de44b3..1eed031af7 100644 --- a/tests/lib/chat/test_completions_streaming.py +++ b/tests/lib/chat/test_completions_streaming.py @@ -13,12 +13,14 @@ import openai from openai import OpenAI, AsyncOpenAI -from openai._utils import assert_signatures_in_sync +from openai._utils import consume_sync_iterator, assert_signatures_in_sync from openai._compat import model_copy +from openai.types.chat import ChatCompletionChunk from openai.lib.streaming.chat import ( ContentDoneEvent, ChatCompletionStream, ChatCompletionStreamEvent, + ChatCompletionStreamState, ChatCompletionStreamManager, ParsedChatCompletionSnapshot, ) @@ -997,6 +999,55 @@ def test_allows_non_strict_tools_but_no_parsing( ) +@pytest.mark.respx(base_url=base_url) +def test_chat_completion_state_helper(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None: + state = ChatCompletionStreamState() + + def streamer(client: OpenAI) -> Iterator[ChatCompletionChunk]: + stream = client.chat.completions.create( + model="gpt-4o-2024-08-06", + messages=[ + { + "role": "user", + "content": "What's the weather like in SF?", + }, + ], + stream=True, + ) + for chunk in stream: + state.handle_chunk(chunk) + yield chunk + + _make_raw_stream_snapshot_request( + streamer, + content_snapshot=snapshot(external("e2aad469b71d*.bin")), + mock_client=client, + respx_mock=respx_mock, + ) + + assert print_obj(state.get_final_completion().choices, monkeypatch) == snapshot( + """\ +[ + ParsedChoice[NoneType]( + finish_reason='stop', + index=0, + logprobs=None, + message=ParsedChatCompletionMessage[NoneType]( + audio=None, + content="I'm unable to provide real-time weather updates. To get the current weather in San Francisco, I +recommend checking a reliable weather website or a weather app.", + function_call=None, + parsed=None, + refusal=None, + role='assistant', + tool_calls=[] + ) + ) +] +""" + ) + + @pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) def test_stream_method_in_sync(sync: bool, client: OpenAI, async_client: AsyncOpenAI) -> None: checking_client: OpenAI | AsyncOpenAI = client if sync else async_client @@ -1075,3 +1126,44 @@ def _on_response(response: httpx.Response) -> None: client.close() return listener + + +def _make_raw_stream_snapshot_request( + func: Callable[[OpenAI], Iterator[ChatCompletionChunk]], + *, + content_snapshot: Any, + respx_mock: MockRouter, + mock_client: OpenAI, +) -> None: + live = os.environ.get("OPENAI_LIVE") == "1" + if live: + + def _on_response(response: httpx.Response) -> None: + # update the content snapshot + assert outsource(response.read()) == content_snapshot + + respx_mock.stop() + + client = OpenAI( + http_client=httpx.Client( + event_hooks={ + "response": [_on_response], + } + ) + ) + else: + respx_mock.post("/chat/completions").mock( + return_value=httpx.Response( + 200, + content=content_snapshot._old_value._load_value(), + headers={"content-type": "text/event-stream"}, + ) + ) + + client = mock_client + + stream = func(client) + consume_sync_iterator(stream) + + if live: + client.close() From 534d6c58f6c07d219ca74dd336eaca59d48d0ada Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 05:04:35 +0000 Subject: [PATCH 100/769] release: 1.56.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index d23d0104a4..24b1176fb1 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.55.3" + ".": "1.56.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 866d34cb4f..614dbb5795 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.56.0 (2024-12-02) + +Full Changelog: [v1.55.3...v1.56.0](https://github.com/openai/openai-python/compare/v1.55.3...v1.56.0) + +### Features + +* **client:** make ChatCompletionStreamState public ([#1898](https://github.com/openai/openai-python/issues/1898)) ([dc7f6cb](https://github.com/openai/openai-python/commit/dc7f6cb2618686ff04bfdca228913cda3d320884)) + ## 1.55.3 (2024-11-28) Full Changelog: [v1.55.2...v1.55.3](https://github.com/openai/openai-python/compare/v1.55.2...v1.55.3) diff --git a/pyproject.toml b/pyproject.toml index 06c0e7fd73..b5cf535fe5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.55.3" +version = "1.56.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 c6d4c88a6d..8561c9379b 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.55.3" # x-release-please-version +__version__ = "1.56.0" # x-release-please-version From 439ab56fe0933077a41290f588a6528f89e05c87 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Mon, 2 Dec 2024 15:21:20 -0500 Subject: [PATCH 101/769] fix(cli): remove usage of httpx proxies --- src/openai/cli/_cli.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/openai/cli/_cli.py b/src/openai/cli/_cli.py index 72e5c923bd..fd165f48ab 100644 --- a/src/openai/cli/_cli.py +++ b/src/openai/cli/_cli.py @@ -15,7 +15,6 @@ from .. import _ApiType, __version__ from ._api import register_commands from ._utils import can_use_http2 -from .._types import ProxiesDict from ._errors import CLIError, display_error from .._compat import PYDANTIC_V2, ConfigDict, model_parse from .._models import BaseModel @@ -167,17 +166,17 @@ def _main() -> None: if args.verbosity != 0: sys.stderr.write("Warning: --verbosity isn't supported yet\n") - proxies: ProxiesDict = {} + proxies: dict[str, httpx.BaseTransport] = {} if args.proxy is not None: for proxy in args.proxy: key = "https://" if proxy.startswith("https") else "http://" if key in proxies: raise CLIError(f"Multiple {key} proxies given - only the last one would be used") - proxies[key] = proxy + proxies[key] = httpx.HTTPTransport(proxy=httpx.Proxy(httpx.URL(proxy))) http_client = httpx.Client( - proxies=proxies or None, + mounts=proxies or None, http2=can_use_http2(), ) openai.http_client = http_client From 6a692ffb5e00e0e1ff9ae39633a62774c6fb5c31 Mon Sep 17 00:00:00 2001 From: Stainless Bot Date: Mon, 2 Dec 2024 20:47:19 +0000 Subject: [PATCH 102/769] chore(internal): bump pyright (#1917) --- requirements-dev.lock | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/requirements-dev.lock b/requirements-dev.lock index 4d0ab191a4..c8e74372aa 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -125,7 +125,7 @@ pygments==2.18.0 # via rich pyjwt==2.8.0 # via msal -pyright==1.1.380 +pyright==1.1.389 pytest==8.3.3 # via pytest-asyncio pytest-asyncio==0.24.0 @@ -179,6 +179,7 @@ typing-extensions==4.12.2 # via openai # via pydantic # via pydantic-core + # via pyright tzdata==2024.1 # via pandas urllib3==2.2.1 From 5e3e4d1b0f16ccc4469a90a5bff09cafe0de7a2e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 3 Dec 2024 05:04:28 +0000 Subject: [PATCH 103/769] release: 1.56.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 24b1176fb1..7e4064260b 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.56.0" + ".": "1.56.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 614dbb5795..ad4ea007e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 1.56.1 (2024-12-03) + +Full Changelog: [v1.56.0...v1.56.1](https://github.com/openai/openai-python/compare/v1.56.0...v1.56.1) + +### Bug Fixes + +* **cli:** remove usage of httpx proxies ([0e9fc3d](https://github.com/openai/openai-python/commit/0e9fc3dfbc7dec5b8c8f84dea9d87aad9f3d9cf6)) + + +### Chores + +* **internal:** bump pyright ([#1917](https://github.com/openai/openai-python/issues/1917)) ([0e87346](https://github.com/openai/openai-python/commit/0e8734637666ab22bc27fe4ec2cf7c39fddb5d08)) + ## 1.56.0 (2024-12-02) Full Changelog: [v1.55.3...v1.56.0](https://github.com/openai/openai-python/compare/v1.55.3...v1.56.0) diff --git a/pyproject.toml b/pyproject.toml index b5cf535fe5..93ababf9b7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.56.0" +version = "1.56.1" 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 8561c9379b..c879d22094 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.56.0" # x-release-please-version +__version__ = "1.56.1" # x-release-please-version From f3f2ae529a86b110f97a38977b20794284be1726 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 4 Dec 2024 02:15:40 +0000 Subject: [PATCH 104/769] chore: make the `Omit` type public (#1919) --- src/openai/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/openai/__init__.py b/src/openai/__init__.py index 3c1ebb573d..21c60f7e87 100644 --- a/src/openai/__init__.py +++ b/src/openai/__init__.py @@ -6,7 +6,7 @@ from typing_extensions import override from . import types -from ._types import NOT_GIVEN, NoneType, NotGiven, Transport, ProxiesTypes +from ._types import NOT_GIVEN, Omit, NoneType, NotGiven, Transport, ProxiesTypes from ._utils import file_from_path from ._client import Client, OpenAI, Stream, Timeout, Transport, AsyncClient, AsyncOpenAI, AsyncStream, RequestOptions from ._models import BaseModel @@ -43,6 +43,7 @@ "ProxiesTypes", "NotGiven", "NOT_GIVEN", + "Omit", "OpenAIError", "APIError", "APIStatusError", From bb9c2de913279acc89e79f6154173a422f31de45 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 4 Dec 2024 05:04:28 +0000 Subject: [PATCH 105/769] release: 1.56.2 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 7e4064260b..028ed90273 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.56.1" + ".": "1.56.2" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index ad4ea007e8..f91f69338b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.56.2 (2024-12-04) + +Full Changelog: [v1.56.1...v1.56.2](https://github.com/openai/openai-python/compare/v1.56.1...v1.56.2) + +### Chores + +* make the `Omit` type public ([#1919](https://github.com/openai/openai-python/issues/1919)) ([4fb8a1c](https://github.com/openai/openai-python/commit/4fb8a1cf1f8df37ce8c027bbaaac85a648bae02a)) + ## 1.56.1 (2024-12-03) Full Changelog: [v1.56.0...v1.56.1](https://github.com/openai/openai-python/compare/v1.56.0...v1.56.1) diff --git a/pyproject.toml b/pyproject.toml index 93ababf9b7..7ca731eb7d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.56.1" +version = "1.56.2" 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 c879d22094..190d3a5fe1 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.56.1" # x-release-please-version +__version__ = "1.56.2" # x-release-please-version From 52f3525276149fb2375d4af5e5903ffa77330cc3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 4 Dec 2024 20:20:39 +0000 Subject: [PATCH 106/769] chore: bump openapi url (#1922) --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 4827e5388f..19920c8be8 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 68 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-aa9b01fc0c17eb0cbc200533fc20d6a49c5e764ceaf8049e08b294532be6e9ff.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-d702cba829ceda336f44d0eb89ce61dba353849a40f0193e7007439345daf1bb.yml From afa2b1e089f9b43ff8db35ecb554c688aba5cf01 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 4 Dec 2024 20:53:44 +0000 Subject: [PATCH 107/769] feat(api): updates (#1924) --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 19920c8be8..3cc042fe0a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 68 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-d702cba829ceda336f44d0eb89ce61dba353849a40f0193e7007439345daf1bb.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-2e0e0678be19d1118fd796af291822075e40538dba326611e177e9f3dc245a53.yml From ea049cd0c42e115b90f1b9c7db80b2659a0bb92a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 5 Dec 2024 05:04:40 +0000 Subject: [PATCH 108/769] release: 1.57.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 028ed90273..3794816acd 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.56.2" + ".": "1.57.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index f91f69338b..c5baf5ab80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 1.57.0 (2024-12-05) + +Full Changelog: [v1.56.2...v1.57.0](https://github.com/openai/openai-python/compare/v1.56.2...v1.57.0) + +### Features + +* **api:** updates ([#1924](https://github.com/openai/openai-python/issues/1924)) ([82ba614](https://github.com/openai/openai-python/commit/82ba6144682b0a6b3a22d4f764231c0c6afdcf6e)) + + +### Chores + +* bump openapi url ([#1922](https://github.com/openai/openai-python/issues/1922)) ([a472a8f](https://github.com/openai/openai-python/commit/a472a8fd0ba36b6897dcd02b6005fcf23f98f056)) + ## 1.56.2 (2024-12-04) Full Changelog: [v1.56.1...v1.56.2](https://github.com/openai/openai-python/compare/v1.56.1...v1.56.2) diff --git a/pyproject.toml b/pyproject.toml index 7ca731eb7d..c488c40622 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.56.2" +version = "1.57.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 190d3a5fe1..58e2de3bd5 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.56.2" # x-release-please-version +__version__ = "1.57.0" # x-release-please-version From 64e3ec0f571cf9b43bbe5d26e6629a8f9d6049fb Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:40:47 +0000 Subject: [PATCH 109/769] chore(internal): bump pydantic dependency (#1929) --- requirements-dev.lock | 5 ++--- requirements.lock | 5 ++--- src/openai/_types.py | 6 ++---- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/requirements-dev.lock b/requirements-dev.lock index c8e74372aa..d7ecc4fcda 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -7,7 +7,6 @@ # all-features: true # with-sources: false # generate-hashes: false -# universal: false -e file:. annotated-types==0.6.0 @@ -117,9 +116,9 @@ portalocker==2.10.1 # via msal-extensions pycparser==2.22 # via cffi -pydantic==2.9.2 +pydantic==2.10.3 # via openai -pydantic-core==2.23.4 +pydantic-core==2.27.1 # via pydantic pygments==2.18.0 # via rich diff --git a/requirements.lock b/requirements.lock index aef8bc0a9a..826f0bc927 100644 --- a/requirements.lock +++ b/requirements.lock @@ -7,7 +7,6 @@ # all-features: true # with-sources: false # generate-hashes: false -# universal: false -e file:. annotated-types==0.6.0 @@ -41,9 +40,9 @@ pandas==2.2.3 # via openai pandas-stubs==2.2.2.240807 # via openai -pydantic==2.9.2 +pydantic==2.10.3 # via openai -pydantic-core==2.23.4 +pydantic-core==2.27.1 # via pydantic python-dateutil==2.9.0.post0 # via pandas diff --git a/src/openai/_types.py b/src/openai/_types.py index c8f4d5a922..a5cf207aa3 100644 --- a/src/openai/_types.py +++ b/src/openai/_types.py @@ -194,10 +194,8 @@ def get(self, __key: str) -> str | None: ... StrBytesIntFloat = Union[str, bytes, int, float] # Note: copied from Pydantic -# https://github.com/pydantic/pydantic/blob/32ea570bf96e84234d2992e1ddf40ab8a565925a/pydantic/main.py#L49 -IncEx: TypeAlias = Union[ - Set[int], Set[str], Mapping[int, Union["IncEx", Literal[True]]], Mapping[str, Union["IncEx", Literal[True]]] -] +# https://github.com/pydantic/pydantic/blob/6f31f8f68ef011f84357330186f603ff295312fd/pydantic/main.py#L79 +IncEx: TypeAlias = Union[Set[int], Set[str], Mapping[int, Union["IncEx", bool]], Mapping[str, Union["IncEx", bool]]] PostParser = Callable[[Any], Any] From 995cce048f9427bba4f7ac1e5fc60abbf1f8f0b7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:41:16 +0000 Subject: [PATCH 110/769] release: 1.57.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 3794816acd..4a5d7b25e2 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.57.0" + ".": "1.57.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index c5baf5ab80..b436c25abf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.57.1 (2024-12-09) + +Full Changelog: [v1.57.0...v1.57.1](https://github.com/openai/openai-python/compare/v1.57.0...v1.57.1) + +### Chores + +* **internal:** bump pydantic dependency ([#1929](https://github.com/openai/openai-python/issues/1929)) ([5227c95](https://github.com/openai/openai-python/commit/5227c95eff9c7b1395e6d8f14b94652a91ed2ee2)) + ## 1.57.0 (2024-12-05) Full Changelog: [v1.56.2...v1.57.0](https://github.com/openai/openai-python/compare/v1.56.2...v1.57.0) diff --git a/pyproject.toml b/pyproject.toml index c488c40622..9a92574c73 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.57.0" +version = "1.57.1" 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 58e2de3bd5..a59207d618 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.57.0" # x-release-please-version +__version__ = "1.57.1" # x-release-please-version From 6a1ab55104822b9e987e1227988c084cd415d294 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 9 Dec 2024 18:18:18 +0000 Subject: [PATCH 111/769] docs(readme): fix http client proxies example (#1932) --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5854e8d3ad..780ee261fe 100644 --- a/README.md +++ b/README.md @@ -624,18 +624,19 @@ can also get all the extra fields on the Pydantic model as a dict with You can directly override the [httpx client](https://www.python-httpx.org/api/#client) to customize it for your use case, including: -- Support for proxies -- Custom transports +- Support for [proxies](https://www.python-httpx.org/advanced/proxies/) +- Custom [transports](https://www.python-httpx.org/advanced/transports/) - Additional [advanced](https://www.python-httpx.org/advanced/clients/) functionality ```python +import httpx from openai import OpenAI, DefaultHttpxClient client = OpenAI( # Or use the `OPENAI_BASE_URL` env var base_url="http://my.test.server.example.com:8083/v1", http_client=DefaultHttpxClient( - proxies="http://my.test.proxy.example.com", + proxy="http://my.test.proxy.example.com", transport=httpx.HTTPTransport(local_address="0.0.0.0"), ), ) From 3cf3dd7b412414a6ca48a588ee4c7f0ef91c9e92 Mon Sep 17 00:00:00 2001 From: Kenji Hikmatullah <43457338+kenjihikmatullah@users.noreply.github.com> Date: Tue, 10 Dec 2024 18:52:45 +0700 Subject: [PATCH 112/769] fix(azure): handle trailing slash in `azure_endpoint` (#1935) --- src/openai/lib/azure.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/openai/lib/azure.py b/src/openai/lib/azure.py index 5d21f10b70..54122dbecb 100644 --- a/src/openai/lib/azure.py +++ b/src/openai/lib/azure.py @@ -193,9 +193,9 @@ def __init__( ) if azure_deployment is not None: - base_url = f"{azure_endpoint}/openai/deployments/{azure_deployment}" + base_url = f"{azure_endpoint.rstrip('/')}/openai/deployments/{azure_deployment}" else: - base_url = f"{azure_endpoint}/openai" + base_url = f"{azure_endpoint.rstrip('/')}/openai" else: if azure_endpoint is not None: raise ValueError("base_url and azure_endpoint are mutually exclusive") @@ -433,9 +433,9 @@ def __init__( ) if azure_deployment is not None: - base_url = f"{azure_endpoint}/openai/deployments/{azure_deployment}" + base_url = f"{azure_endpoint.rstrip('/')}/openai/deployments/{azure_deployment}" else: - base_url = f"{azure_endpoint}/openai" + base_url = f"{azure_endpoint.rstrip('/')}/openai" else: if azure_endpoint is not None: raise ValueError("base_url and azure_endpoint are mutually exclusive") From 6e1161bc3ed20eef070063ddd5ac52fd9a531e88 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 10 Dec 2024 11:53:14 +0000 Subject: [PATCH 113/769] release: 1.57.2 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 4a5d7b25e2..18d9ec48a9 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.57.1" + ".": "1.57.2" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index b436c25abf..7319ebd651 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 1.57.2 (2024-12-10) + +Full Changelog: [v1.57.1...v1.57.2](https://github.com/openai/openai-python/compare/v1.57.1...v1.57.2) + +### Bug Fixes + +* **azure:** handle trailing slash in `azure_endpoint` ([#1935](https://github.com/openai/openai-python/issues/1935)) ([69b73c5](https://github.com/openai/openai-python/commit/69b73c553b1982277c2f1b9d110ed951ddca689e)) + + +### Documentation + +* **readme:** fix http client proxies example ([#1932](https://github.com/openai/openai-python/issues/1932)) ([7a83e0f](https://github.com/openai/openai-python/commit/7a83e0fe4cc29e484ae417448b002c997745e4a3)) + ## 1.57.1 (2024-12-09) Full Changelog: [v1.57.0...v1.57.1](https://github.com/openai/openai-python/compare/v1.57.0...v1.57.1) diff --git a/pyproject.toml b/pyproject.toml index 9a92574c73..6df6f43789 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.57.1" +version = "1.57.2" 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 a59207d618..0757da4c78 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.57.1" # x-release-please-version +__version__ = "1.57.2" # x-release-please-version From f32d466b2d69b0ca8fa8a59f2b74ed84448f9459 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 12 Dec 2024 12:18:04 +0000 Subject: [PATCH 114/769] chore(internal): bump pyright (#1939) --- requirements-dev.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.lock b/requirements-dev.lock index d7ecc4fcda..2cf6ab5ea9 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -124,7 +124,7 @@ pygments==2.18.0 # via rich pyjwt==2.8.0 # via msal -pyright==1.1.389 +pyright==1.1.390 pytest==8.3.3 # via pytest-asyncio pytest-asyncio==0.24.0 From bed71312acd1658d6128f9142f2882162bb127ec Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 12 Dec 2024 12:44:38 +0000 Subject: [PATCH 115/769] chore(internal): add support for TypeAliasType (#1942) --- src/openai/_legacy_response.py | 20 ++++++++++---------- src/openai/_models.py | 3 +++ src/openai/_response.py | 20 ++++++++++---------- src/openai/_utils/__init__.py | 1 + src/openai/_utils/_typing.py | 31 ++++++++++++++++++++++++++++++- tests/test_models.py | 18 +++++++++++++++++- tests/utils.py | 4 ++++ 7 files changed, 75 insertions(+), 22 deletions(-) diff --git a/src/openai/_legacy_response.py b/src/openai/_legacy_response.py index 5260e90bc1..7a14f27adb 100644 --- a/src/openai/_legacy_response.py +++ b/src/openai/_legacy_response.py @@ -24,7 +24,7 @@ import pydantic from ._types import NoneType -from ._utils import is_given, extract_type_arg, is_annotated_type +from ._utils import is_given, extract_type_arg, is_annotated_type, is_type_alias_type from ._models import BaseModel, is_basemodel, add_request_id from ._constants import RAW_RESPONSE_HEADER from ._streaming import Stream, AsyncStream, is_stream_class_type, extract_stream_chunk_type @@ -195,9 +195,15 @@ def elapsed(self) -> datetime.timedelta: return self.http_response.elapsed def _parse(self, *, to: type[_T] | None = None) -> R | _T: + cast_to = to if to is not None else self._cast_to + + # unwrap `TypeAlias('Name', T)` -> `T` + if is_type_alias_type(cast_to): + cast_to = cast_to.__value__ # type: ignore[unreachable] + # unwrap `Annotated[T, ...]` -> `T` - if to and is_annotated_type(to): - to = extract_type_arg(to, 0) + if cast_to and is_annotated_type(cast_to): + cast_to = extract_type_arg(cast_to, 0) if self._stream: if to: @@ -233,18 +239,12 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: return cast( R, stream_cls( - cast_to=self._cast_to, + cast_to=cast_to, response=self.http_response, client=cast(Any, self._client), ), ) - cast_to = to if to is not None else self._cast_to - - # unwrap `Annotated[T, ...]` -> `T` - if is_annotated_type(cast_to): - cast_to = extract_type_arg(cast_to, 0) - if cast_to is NoneType: return cast(R, None) diff --git a/src/openai/_models.py b/src/openai/_models.py index 20cd4c29bc..2f67e5eb4d 100644 --- a/src/openai/_models.py +++ b/src/openai/_models.py @@ -47,6 +47,7 @@ strip_not_given, extract_type_arg, is_annotated_type, + is_type_alias_type, strip_annotated_type, ) from ._compat import ( @@ -453,6 +454,8 @@ def construct_type(*, value: object, type_: object) -> object: # 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_): + type_ = type_.__value__ # type: ignore[unreachable] # unwrap `Annotated[T, ...]` -> `T` if is_annotated_type(type_): diff --git a/src/openai/_response.py b/src/openai/_response.py index eac3fbae6c..1527446585 100644 --- a/src/openai/_response.py +++ b/src/openai/_response.py @@ -25,7 +25,7 @@ import pydantic from ._types import NoneType -from ._utils import is_given, extract_type_arg, is_annotated_type, extract_type_var_from_base +from ._utils import is_given, extract_type_arg, is_annotated_type, is_type_alias_type, extract_type_var_from_base from ._models import BaseModel, is_basemodel, add_request_id from ._constants import RAW_RESPONSE_HEADER, OVERRIDE_CAST_TO_HEADER from ._streaming import Stream, AsyncStream, is_stream_class_type, extract_stream_chunk_type @@ -126,9 +126,15 @@ def __repr__(self) -> str: ) def _parse(self, *, to: type[_T] | None = None) -> R | _T: + cast_to = to if to is not None else self._cast_to + + # unwrap `TypeAlias('Name', T)` -> `T` + if is_type_alias_type(cast_to): + cast_to = cast_to.__value__ # type: ignore[unreachable] + # unwrap `Annotated[T, ...]` -> `T` - if to and is_annotated_type(to): - to = extract_type_arg(to, 0) + if cast_to and is_annotated_type(cast_to): + cast_to = extract_type_arg(cast_to, 0) if self._is_sse_stream: if to: @@ -164,18 +170,12 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: return cast( R, stream_cls( - cast_to=self._cast_to, + cast_to=cast_to, response=self.http_response, client=cast(Any, self._client), ), ) - cast_to = to if to is not None else self._cast_to - - # unwrap `Annotated[T, ...]` -> `T` - if is_annotated_type(cast_to): - cast_to = extract_type_arg(cast_to, 0) - if cast_to is NoneType: return cast(R, None) diff --git a/src/openai/_utils/__init__.py b/src/openai/_utils/__init__.py index 5abb34cde4..af2c9bb77e 100644 --- a/src/openai/_utils/__init__.py +++ b/src/openai/_utils/__init__.py @@ -40,6 +40,7 @@ is_iterable_type as is_iterable_type, is_required_type as is_required_type, is_annotated_type as is_annotated_type, + is_type_alias_type as is_type_alias_type, strip_annotated_type as strip_annotated_type, extract_type_var_from_base as extract_type_var_from_base, ) diff --git a/src/openai/_utils/_typing.py b/src/openai/_utils/_typing.py index c036991f04..278749b147 100644 --- a/src/openai/_utils/_typing.py +++ b/src/openai/_utils/_typing.py @@ -1,8 +1,17 @@ from __future__ import annotations +import sys +import typing +import typing_extensions from typing import Any, TypeVar, Iterable, cast from collections import abc as _c_abc -from typing_extensions import Required, Annotated, get_args, get_origin +from typing_extensions import ( + TypeIs, + Required, + Annotated, + get_args, + get_origin, +) from .._types import InheritsGeneric from .._compat import is_union as _is_union @@ -36,6 +45,26 @@ def is_typevar(typ: type) -> bool: return type(typ) == TypeVar # type: ignore +_TYPE_ALIAS_TYPES: tuple[type[typing_extensions.TypeAliasType], ...] = (typing_extensions.TypeAliasType,) +if sys.version_info >= (3, 12): + _TYPE_ALIAS_TYPES = (*_TYPE_ALIAS_TYPES, typing.TypeAliasType) + + +def is_type_alias_type(tp: Any, /) -> TypeIs[typing_extensions.TypeAliasType]: + """Return whether the provided argument is an instance of `TypeAliasType`. + + ```python + type Int = int + is_type_alias_type(Int) + # > True + Str = TypeAliasType("Str", str) + is_type_alias_type(Str) + # > True + ``` + """ + return isinstance(tp, _TYPE_ALIAS_TYPES) + + # Extracts T from Annotated[T, ...] or from Required[Annotated[T, ...]] def strip_annotated_type(typ: type) -> type: if is_required_type(typ) or is_annotated_type(typ): diff --git a/tests/test_models.py b/tests/test_models.py index d2884bcbfa..19a71f13ba 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -1,7 +1,7 @@ import json from typing import Any, Dict, List, Union, Optional, cast from datetime import datetime, timezone -from typing_extensions import Literal, Annotated +from typing_extensions import Literal, Annotated, TypeAliasType import pytest import pydantic @@ -828,3 +828,19 @@ class B(BaseModel): # if the discriminator details object stays the same between invocations then # we hit the cache assert UnionType.__discriminator__ is discriminator + + +@pytest.mark.skipif(not PYDANTIC_V2, reason="TypeAliasType is not supported in Pydantic v1") +def test_type_alias_type() -> None: + Alias = TypeAliasType("Alias", str) + + class Model(BaseModel): + alias: Alias + union: Union[int, Alias] + + m = construct_type(value={"alias": "foo", "union": "bar"}, type_=Model) + assert isinstance(m, Model) + assert isinstance(m.alias, str) + assert m.alias == "foo" + assert isinstance(m.union, str) + assert m.union == "bar" diff --git a/tests/utils.py b/tests/utils.py index 16948a66f2..4cf5ce171b 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -19,6 +19,7 @@ is_union_type, extract_type_arg, is_annotated_type, + is_type_alias_type, ) from openai._compat import PYDANTIC_V2, field_outer_type, get_model_fields from openai._models import BaseModel @@ -58,6 +59,9 @@ def assert_matches_type( path: list[str], allow_none: bool = False, ) -> None: + if is_type_alias_type(type_): + type_ = type_.__value__ + # unwrap `Annotated[T, ...]` -> `T` if is_annotated_type(type_): type_ = extract_type_arg(type_, 0) From 0ae6f6b0ce55b6a9dd7e5caa684dfae2780c0088 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 12 Dec 2024 12:45:06 +0000 Subject: [PATCH 116/769] release: 1.57.3 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 9 +++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 18d9ec48a9..58e64c502c 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.57.2" + ".": "1.57.3" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 7319ebd651..80ed457618 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 1.57.3 (2024-12-12) + +Full Changelog: [v1.57.2...v1.57.3](https://github.com/openai/openai-python/compare/v1.57.2...v1.57.3) + +### Chores + +* **internal:** add support for TypeAliasType ([#1942](https://github.com/openai/openai-python/issues/1942)) ([d3442ff](https://github.com/openai/openai-python/commit/d3442ff28f2394200e14122f683d1f94686e8231)) +* **internal:** bump pyright ([#1939](https://github.com/openai/openai-python/issues/1939)) ([190d1a8](https://github.com/openai/openai-python/commit/190d1a805dee7c37fb8f9dcb93b1715caa06cf95)) + ## 1.57.2 (2024-12-10) Full Changelog: [v1.57.1...v1.57.2](https://github.com/openai/openai-python/compare/v1.57.1...v1.57.2) diff --git a/pyproject.toml b/pyproject.toml index 6df6f43789..a6a0868405 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.57.2" +version = "1.57.3" 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 0757da4c78..94ba432279 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.57.2" # x-release-please-version +__version__ = "1.57.3" # x-release-please-version From e93e3bd45fcef320c4fa70eed3987d852e9c96e5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 13 Dec 2024 11:17:39 +0000 Subject: [PATCH 117/769] chore(internal): remove some duplicated imports (#1946) --- src/openai/resources/beta/beta.py | 20 +++++++++---------- src/openai/resources/beta/threads/threads.py | 17 ++++++++-------- .../resources/fine_tuning/fine_tuning.py | 5 ++--- 3 files changed, 19 insertions(+), 23 deletions(-) diff --git a/src/openai/resources/beta/beta.py b/src/openai/resources/beta/beta.py index a7d3e707c8..5079c989a5 100644 --- a/src/openai/resources/beta/beta.py +++ b/src/openai/resources/beta/beta.py @@ -2,14 +2,6 @@ from __future__ import annotations -from .threads import ( - Threads, - AsyncThreads, - ThreadsWithRawResponse, - AsyncThreadsWithRawResponse, - ThreadsWithStreamingResponse, - AsyncThreadsWithStreamingResponse, -) from ..._compat import cached_property from .chat.chat import Chat, AsyncChat from .assistants import ( @@ -21,7 +13,15 @@ AsyncAssistantsWithStreamingResponse, ) from ..._resource import SyncAPIResource, AsyncAPIResource -from .vector_stores import ( +from .threads.threads import ( + Threads, + AsyncThreads, + ThreadsWithRawResponse, + AsyncThreadsWithRawResponse, + ThreadsWithStreamingResponse, + AsyncThreadsWithStreamingResponse, +) +from .vector_stores.vector_stores import ( VectorStores, AsyncVectorStores, VectorStoresWithRawResponse, @@ -29,8 +29,6 @@ VectorStoresWithStreamingResponse, AsyncVectorStoresWithStreamingResponse, ) -from .threads.threads import Threads, AsyncThreads -from .vector_stores.vector_stores import VectorStores, AsyncVectorStores __all__ = ["Beta", "AsyncBeta"] diff --git a/src/openai/resources/beta/threads/threads.py b/src/openai/resources/beta/threads/threads.py index 058ba71a17..e45090abb0 100644 --- a/src/openai/resources/beta/threads/threads.py +++ b/src/openai/resources/beta/threads/threads.py @@ -9,14 +9,6 @@ import httpx from .... import _legacy_response -from .runs import ( - Runs, - AsyncRuns, - RunsWithRawResponse, - AsyncRunsWithRawResponse, - RunsWithStreamingResponse, - AsyncRunsWithStreamingResponse, -) from .messages import ( Messages, AsyncMessages, @@ -31,7 +23,14 @@ maybe_transform, async_maybe_transform, ) -from .runs.runs import Runs, AsyncRuns +from .runs.runs import ( + Runs, + AsyncRuns, + RunsWithRawResponse, + AsyncRunsWithRawResponse, + RunsWithStreamingResponse, + AsyncRunsWithStreamingResponse, +) from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper diff --git a/src/openai/resources/fine_tuning/fine_tuning.py b/src/openai/resources/fine_tuning/fine_tuning.py index c386de3c2a..d2bce87c48 100644 --- a/src/openai/resources/fine_tuning/fine_tuning.py +++ b/src/openai/resources/fine_tuning/fine_tuning.py @@ -2,7 +2,8 @@ from __future__ import annotations -from .jobs import ( +from ..._compat import cached_property +from .jobs.jobs import ( Jobs, AsyncJobs, JobsWithRawResponse, @@ -10,8 +11,6 @@ JobsWithStreamingResponse, AsyncJobsWithStreamingResponse, ) -from ..._compat import cached_property -from .jobs.jobs import Jobs, AsyncJobs from ..._resource import SyncAPIResource, AsyncAPIResource __all__ = ["FineTuning", "AsyncFineTuning"] From 2e2531d944a0c4ff748f9fb0b1c9a015f029dd2f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 13 Dec 2024 14:01:59 +0000 Subject: [PATCH 118/769] chore(internal): updated imports (#1948) --- src/openai/_client.py | 212 +++++++++++++++++++++--------------------- 1 file changed, 104 insertions(+), 108 deletions(-) diff --git a/src/openai/_client.py b/src/openai/_client.py index d3ee6cf0f1..5419e88f06 100644 --- a/src/openai/_client.py +++ b/src/openai/_client.py @@ -8,7 +8,7 @@ import httpx -from . import resources, _exceptions +from . import _exceptions from ._qs import Querystring from ._types import ( NOT_GIVEN, @@ -25,6 +25,7 @@ get_async_library, ) from ._version import __version__ +from .resources import files, images, models, batches, embeddings, completions, moderations from ._streaming import Stream as Stream, AsyncStream as AsyncStream from ._exceptions import OpenAIError, APIStatusError from ._base_client import ( @@ -32,33 +33,28 @@ SyncAPIClient, AsyncAPIClient, ) +from .resources.beta import beta +from .resources.chat import chat +from .resources.audio import audio +from .resources.uploads import uploads +from .resources.fine_tuning import fine_tuning -__all__ = [ - "Timeout", - "Transport", - "ProxiesTypes", - "RequestOptions", - "resources", - "OpenAI", - "AsyncOpenAI", - "Client", - "AsyncClient", -] +__all__ = ["Timeout", "Transport", "ProxiesTypes", "RequestOptions", "OpenAI", "AsyncOpenAI", "Client", "AsyncClient"] class OpenAI(SyncAPIClient): - completions: resources.Completions - chat: resources.Chat - embeddings: resources.Embeddings - files: resources.Files - images: resources.Images - audio: resources.Audio - moderations: resources.Moderations - models: resources.Models - fine_tuning: resources.FineTuning - beta: resources.Beta - batches: resources.Batches - uploads: resources.Uploads + completions: completions.Completions + chat: chat.Chat + embeddings: embeddings.Embeddings + files: files.Files + images: images.Images + audio: audio.Audio + moderations: moderations.Moderations + models: models.Models + fine_tuning: fine_tuning.FineTuning + beta: beta.Beta + batches: batches.Batches + uploads: uploads.Uploads with_raw_response: OpenAIWithRawResponse with_streaming_response: OpenAIWithStreamedResponse @@ -133,18 +129,18 @@ def __init__( self._default_stream_cls = Stream - self.completions = resources.Completions(self) - self.chat = resources.Chat(self) - self.embeddings = resources.Embeddings(self) - self.files = resources.Files(self) - self.images = resources.Images(self) - self.audio = resources.Audio(self) - self.moderations = resources.Moderations(self) - self.models = resources.Models(self) - self.fine_tuning = resources.FineTuning(self) - self.beta = resources.Beta(self) - self.batches = resources.Batches(self) - self.uploads = resources.Uploads(self) + self.completions = completions.Completions(self) + self.chat = chat.Chat(self) + self.embeddings = embeddings.Embeddings(self) + self.files = files.Files(self) + self.images = images.Images(self) + self.audio = audio.Audio(self) + self.moderations = moderations.Moderations(self) + self.models = models.Models(self) + self.fine_tuning = fine_tuning.FineTuning(self) + self.beta = beta.Beta(self) + self.batches = batches.Batches(self) + self.uploads = uploads.Uploads(self) self.with_raw_response = OpenAIWithRawResponse(self) self.with_streaming_response = OpenAIWithStreamedResponse(self) @@ -261,18 +257,18 @@ def _make_status_error( class AsyncOpenAI(AsyncAPIClient): - completions: resources.AsyncCompletions - chat: resources.AsyncChat - embeddings: resources.AsyncEmbeddings - files: resources.AsyncFiles - images: resources.AsyncImages - audio: resources.AsyncAudio - moderations: resources.AsyncModerations - models: resources.AsyncModels - fine_tuning: resources.AsyncFineTuning - beta: resources.AsyncBeta - batches: resources.AsyncBatches - uploads: resources.AsyncUploads + completions: completions.AsyncCompletions + chat: chat.AsyncChat + embeddings: embeddings.AsyncEmbeddings + files: files.AsyncFiles + images: images.AsyncImages + audio: audio.AsyncAudio + moderations: moderations.AsyncModerations + models: models.AsyncModels + fine_tuning: fine_tuning.AsyncFineTuning + beta: beta.AsyncBeta + batches: batches.AsyncBatches + uploads: uploads.AsyncUploads with_raw_response: AsyncOpenAIWithRawResponse with_streaming_response: AsyncOpenAIWithStreamedResponse @@ -347,18 +343,18 @@ def __init__( self._default_stream_cls = AsyncStream - self.completions = resources.AsyncCompletions(self) - self.chat = resources.AsyncChat(self) - self.embeddings = resources.AsyncEmbeddings(self) - self.files = resources.AsyncFiles(self) - self.images = resources.AsyncImages(self) - self.audio = resources.AsyncAudio(self) - self.moderations = resources.AsyncModerations(self) - self.models = resources.AsyncModels(self) - self.fine_tuning = resources.AsyncFineTuning(self) - self.beta = resources.AsyncBeta(self) - self.batches = resources.AsyncBatches(self) - self.uploads = resources.AsyncUploads(self) + self.completions = completions.AsyncCompletions(self) + self.chat = chat.AsyncChat(self) + self.embeddings = embeddings.AsyncEmbeddings(self) + self.files = files.AsyncFiles(self) + self.images = images.AsyncImages(self) + self.audio = audio.AsyncAudio(self) + self.moderations = moderations.AsyncModerations(self) + self.models = models.AsyncModels(self) + self.fine_tuning = fine_tuning.AsyncFineTuning(self) + self.beta = beta.AsyncBeta(self) + self.batches = batches.AsyncBatches(self) + self.uploads = uploads.AsyncUploads(self) self.with_raw_response = AsyncOpenAIWithRawResponse(self) self.with_streaming_response = AsyncOpenAIWithStreamedResponse(self) @@ -476,66 +472,66 @@ def _make_status_error( class OpenAIWithRawResponse: def __init__(self, client: OpenAI) -> None: - self.completions = resources.CompletionsWithRawResponse(client.completions) - self.chat = resources.ChatWithRawResponse(client.chat) - self.embeddings = resources.EmbeddingsWithRawResponse(client.embeddings) - self.files = resources.FilesWithRawResponse(client.files) - self.images = resources.ImagesWithRawResponse(client.images) - self.audio = resources.AudioWithRawResponse(client.audio) - self.moderations = resources.ModerationsWithRawResponse(client.moderations) - self.models = resources.ModelsWithRawResponse(client.models) - self.fine_tuning = resources.FineTuningWithRawResponse(client.fine_tuning) - self.beta = resources.BetaWithRawResponse(client.beta) - self.batches = resources.BatchesWithRawResponse(client.batches) - self.uploads = resources.UploadsWithRawResponse(client.uploads) + self.completions = completions.CompletionsWithRawResponse(client.completions) + self.chat = chat.ChatWithRawResponse(client.chat) + self.embeddings = embeddings.EmbeddingsWithRawResponse(client.embeddings) + self.files = files.FilesWithRawResponse(client.files) + self.images = images.ImagesWithRawResponse(client.images) + self.audio = audio.AudioWithRawResponse(client.audio) + self.moderations = moderations.ModerationsWithRawResponse(client.moderations) + self.models = models.ModelsWithRawResponse(client.models) + self.fine_tuning = fine_tuning.FineTuningWithRawResponse(client.fine_tuning) + self.beta = beta.BetaWithRawResponse(client.beta) + self.batches = batches.BatchesWithRawResponse(client.batches) + self.uploads = uploads.UploadsWithRawResponse(client.uploads) class AsyncOpenAIWithRawResponse: def __init__(self, client: AsyncOpenAI) -> None: - self.completions = resources.AsyncCompletionsWithRawResponse(client.completions) - self.chat = resources.AsyncChatWithRawResponse(client.chat) - self.embeddings = resources.AsyncEmbeddingsWithRawResponse(client.embeddings) - self.files = resources.AsyncFilesWithRawResponse(client.files) - self.images = resources.AsyncImagesWithRawResponse(client.images) - self.audio = resources.AsyncAudioWithRawResponse(client.audio) - self.moderations = resources.AsyncModerationsWithRawResponse(client.moderations) - self.models = resources.AsyncModelsWithRawResponse(client.models) - self.fine_tuning = resources.AsyncFineTuningWithRawResponse(client.fine_tuning) - self.beta = resources.AsyncBetaWithRawResponse(client.beta) - self.batches = resources.AsyncBatchesWithRawResponse(client.batches) - self.uploads = resources.AsyncUploadsWithRawResponse(client.uploads) + self.completions = completions.AsyncCompletionsWithRawResponse(client.completions) + self.chat = chat.AsyncChatWithRawResponse(client.chat) + self.embeddings = embeddings.AsyncEmbeddingsWithRawResponse(client.embeddings) + self.files = files.AsyncFilesWithRawResponse(client.files) + self.images = images.AsyncImagesWithRawResponse(client.images) + self.audio = audio.AsyncAudioWithRawResponse(client.audio) + self.moderations = moderations.AsyncModerationsWithRawResponse(client.moderations) + self.models = models.AsyncModelsWithRawResponse(client.models) + self.fine_tuning = fine_tuning.AsyncFineTuningWithRawResponse(client.fine_tuning) + self.beta = beta.AsyncBetaWithRawResponse(client.beta) + self.batches = batches.AsyncBatchesWithRawResponse(client.batches) + self.uploads = uploads.AsyncUploadsWithRawResponse(client.uploads) class OpenAIWithStreamedResponse: def __init__(self, client: OpenAI) -> None: - self.completions = resources.CompletionsWithStreamingResponse(client.completions) - self.chat = resources.ChatWithStreamingResponse(client.chat) - self.embeddings = resources.EmbeddingsWithStreamingResponse(client.embeddings) - self.files = resources.FilesWithStreamingResponse(client.files) - self.images = resources.ImagesWithStreamingResponse(client.images) - self.audio = resources.AudioWithStreamingResponse(client.audio) - self.moderations = resources.ModerationsWithStreamingResponse(client.moderations) - self.models = resources.ModelsWithStreamingResponse(client.models) - self.fine_tuning = resources.FineTuningWithStreamingResponse(client.fine_tuning) - self.beta = resources.BetaWithStreamingResponse(client.beta) - self.batches = resources.BatchesWithStreamingResponse(client.batches) - self.uploads = resources.UploadsWithStreamingResponse(client.uploads) + self.completions = completions.CompletionsWithStreamingResponse(client.completions) + self.chat = chat.ChatWithStreamingResponse(client.chat) + self.embeddings = embeddings.EmbeddingsWithStreamingResponse(client.embeddings) + self.files = files.FilesWithStreamingResponse(client.files) + self.images = images.ImagesWithStreamingResponse(client.images) + self.audio = audio.AudioWithStreamingResponse(client.audio) + self.moderations = moderations.ModerationsWithStreamingResponse(client.moderations) + self.models = models.ModelsWithStreamingResponse(client.models) + self.fine_tuning = fine_tuning.FineTuningWithStreamingResponse(client.fine_tuning) + self.beta = beta.BetaWithStreamingResponse(client.beta) + self.batches = batches.BatchesWithStreamingResponse(client.batches) + self.uploads = uploads.UploadsWithStreamingResponse(client.uploads) class AsyncOpenAIWithStreamedResponse: def __init__(self, client: AsyncOpenAI) -> None: - self.completions = resources.AsyncCompletionsWithStreamingResponse(client.completions) - self.chat = resources.AsyncChatWithStreamingResponse(client.chat) - self.embeddings = resources.AsyncEmbeddingsWithStreamingResponse(client.embeddings) - self.files = resources.AsyncFilesWithStreamingResponse(client.files) - self.images = resources.AsyncImagesWithStreamingResponse(client.images) - self.audio = resources.AsyncAudioWithStreamingResponse(client.audio) - self.moderations = resources.AsyncModerationsWithStreamingResponse(client.moderations) - self.models = resources.AsyncModelsWithStreamingResponse(client.models) - self.fine_tuning = resources.AsyncFineTuningWithStreamingResponse(client.fine_tuning) - self.beta = resources.AsyncBetaWithStreamingResponse(client.beta) - self.batches = resources.AsyncBatchesWithStreamingResponse(client.batches) - self.uploads = resources.AsyncUploadsWithStreamingResponse(client.uploads) + self.completions = completions.AsyncCompletionsWithStreamingResponse(client.completions) + self.chat = chat.AsyncChatWithStreamingResponse(client.chat) + self.embeddings = embeddings.AsyncEmbeddingsWithStreamingResponse(client.embeddings) + self.files = files.AsyncFilesWithStreamingResponse(client.files) + self.images = images.AsyncImagesWithStreamingResponse(client.images) + self.audio = audio.AsyncAudioWithStreamingResponse(client.audio) + self.moderations = moderations.AsyncModerationsWithStreamingResponse(client.moderations) + self.models = models.AsyncModelsWithStreamingResponse(client.models) + self.fine_tuning = fine_tuning.AsyncFineTuningWithStreamingResponse(client.fine_tuning) + self.beta = beta.AsyncBetaWithStreamingResponse(client.beta) + self.batches = batches.AsyncBatchesWithStreamingResponse(client.batches) + self.uploads = uploads.AsyncUploadsWithStreamingResponse(client.uploads) Client = OpenAI From e94d98e9bf97a5d2d02d79d58f2abdbab26ff2bd Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 13 Dec 2024 14:02:30 +0000 Subject: [PATCH 119/769] release: 1.57.4 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 9 +++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 58e64c502c..f9ae229e1a 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.57.3" + ".": "1.57.4" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 80ed457618..02b7d0271d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 1.57.4 (2024-12-13) + +Full Changelog: [v1.57.3...v1.57.4](https://github.com/openai/openai-python/compare/v1.57.3...v1.57.4) + +### Chores + +* **internal:** remove some duplicated imports ([#1946](https://github.com/openai/openai-python/issues/1946)) ([f94fddd](https://github.com/openai/openai-python/commit/f94fddd377015764b3c82919fdf956f619447b77)) +* **internal:** updated imports ([#1948](https://github.com/openai/openai-python/issues/1948)) ([13971fc](https://github.com/openai/openai-python/commit/13971fc450106746c0ae02ab931e68b770ee105e)) + ## 1.57.3 (2024-12-12) Full Changelog: [v1.57.2...v1.57.3](https://github.com/openai/openai-python/compare/v1.57.2...v1.57.3) diff --git a/pyproject.toml b/pyproject.toml index a6a0868405..e03d4e798f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.57.3" +version = "1.57.4" 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 94ba432279..5b82015017 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.57.3" # x-release-please-version +__version__ = "1.57.4" # x-release-please-version From af791d5188cc142c6ec82fc0f0be90fa3036a85f Mon Sep 17 00:00:00 2001 From: Vincent Date: Mon, 16 Dec 2024 13:12:53 +0100 Subject: [PATCH 120/769] fix(cli/migrate): change grit binaries prefix (#1951) --- src/openai/cli/_tools/migrate.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/openai/cli/_tools/migrate.py b/src/openai/cli/_tools/migrate.py index 7a0b0f90f6..841b777528 100644 --- a/src/openai/cli/_tools/migrate.py +++ b/src/openai/cli/_tools/migrate.py @@ -92,8 +92,8 @@ def install() -> Path: install_dir = dir_name / ".install" target_dir = install_dir / "bin" - target_path = target_dir / "marzano" - temp_file = target_dir / "marzano.tmp" + target_path = target_dir / "grit" + temp_file = target_dir / "grit.tmp" if target_path.exists(): _debug(f"{target_path} already exists") @@ -110,7 +110,7 @@ def install() -> Path: arch = _get_arch() _debug(f"Using architecture {arch}") - file_name = f"marzano-{arch}-{platform}" + file_name = f"grit-{arch}-{platform}" download_url = f"https://github.com/getgrit/gritql/releases/latest/download/{file_name}.tar.gz" sys.stdout.write(f"Downloading Grit CLI from {download_url}\n") From 0bfd8c4d2c7377cd14d7be84ee4f4c1d1ed8a40c Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Mon, 16 Dec 2024 12:22:00 +0000 Subject: [PATCH 121/769] fix(assistants): correctly send `include` query param --- src/openai/resources/beta/threads/runs/runs.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/openai/resources/beta/threads/runs/runs.py b/src/openai/resources/beta/threads/runs/runs.py index 620cc270e5..0418d570ba 100644 --- a/src/openai/resources/beta/threads/runs/runs.py +++ b/src/openai/resources/beta/threads/runs/runs.py @@ -1106,7 +1106,6 @@ def stream( body=maybe_transform( { "assistant_id": assistant_id, - "include": include, "additional_instructions": additional_instructions, "additional_messages": additional_messages, "instructions": instructions, @@ -1126,7 +1125,11 @@ def stream( run_create_params.RunCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"include": include}, run_create_params.RunCreateParams), ), cast_to=Run, stream=True, @@ -1899,7 +1902,6 @@ async def create( body=await async_maybe_transform( { "assistant_id": assistant_id, - "include": include, "additional_instructions": additional_instructions, "additional_messages": additional_messages, "instructions": instructions, @@ -2472,7 +2474,6 @@ def stream( body=maybe_transform( { "assistant_id": assistant_id, - "include": include, "additional_instructions": additional_instructions, "additional_messages": additional_messages, "instructions": instructions, @@ -2492,7 +2493,11 @@ def stream( run_create_params.RunCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"include": include}, run_create_params.RunCreateParams), ), cast_to=Run, stream=True, From 588935e273fc934efddad15c702b3d11987bb44e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 16:04:05 +0000 Subject: [PATCH 122/769] docs(readme): example snippet for client context manager (#1953) --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 780ee261fe..cbcfdb4447 100644 --- a/README.md +++ b/README.md @@ -652,6 +652,16 @@ client.with_options(http_client=DefaultHttpxClient(...)) By default the library closes underlying HTTP connections whenever the client is [garbage collected](https://docs.python.org/3/reference/datamodel.html#object.__del__). You can manually close the client using the `.close()` method if desired, or with a context manager that closes when exiting. +```py +from openai import OpenAI + +with OpenAI() as client: + # make requests here + ... + +# HTTP client is now closed +``` + ## Microsoft Azure OpenAI To use this library with [Azure OpenAI](https://learn.microsoft.com/azure/ai-services/openai/overview), use the `AzureOpenAI` From eba67815fd3ae4ab068d244464dcbb389efa9f0b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Dec 2024 17:26:44 +0000 Subject: [PATCH 123/769] chore(internal): fix some typos (#1955) --- tests/test_client.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_client.py b/tests/test_client.py index 7caa8cb319..7751e7d463 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -349,11 +349,11 @@ def test_default_query_option(self) -> None: FinalRequestOptions( method="get", url="/foo", - params={"foo": "baz", "query_param": "overriden"}, + params={"foo": "baz", "query_param": "overridden"}, ) ) url = httpx.URL(request.url) - assert dict(url.params) == {"foo": "baz", "query_param": "overriden"} + assert dict(url.params) == {"foo": "baz", "query_param": "overridden"} def test_request_extra_json(self) -> None: request = self.client._build_request( @@ -1201,11 +1201,11 @@ def test_default_query_option(self) -> None: FinalRequestOptions( method="get", url="/foo", - params={"foo": "baz", "query_param": "overriden"}, + params={"foo": "baz", "query_param": "overridden"}, ) ) url = httpx.URL(request.url) - assert dict(url.params) == {"foo": "baz", "query_param": "overriden"} + assert dict(url.params) == {"foo": "baz", "query_param": "overridden"} def test_request_extra_json(self) -> None: request = self.client._build_request( From 575ff6078fcf84fba1c4478073969cbfd00ae4b4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Dec 2024 17:59:13 +0000 Subject: [PATCH 124/769] feat(api): new o1 and GPT-4o models + preference fine-tuning (#1956) learn more here: https://platform.openai.com/docs/changelog --- .stats.yml | 4 +- api.md | 16 + src/openai/resources/beta/beta.py | 32 ++ .../resources/beta/realtime/__init__.py | 33 ++ .../resources/beta/realtime/realtime.py | 102 ++++++ .../resources/beta/realtime/sessions.py | 337 ++++++++++++++++++ src/openai/resources/chat/completions.py | 240 ++++++++----- src/openai/resources/fine_tuning/jobs/jobs.py | 22 +- src/openai/types/beta/realtime/__init__.py | 6 + .../beta/realtime/session_create_params.py | 149 ++++++++ .../beta/realtime/session_create_response.py | 150 ++++++++ src/openai/types/chat/__init__.py | 4 + ...chat_completion_developer_message_param.py | 25 ++ .../chat/chat_completion_message_param.py | 2 + .../chat/chat_completion_reasoning_effort.py | 7 + .../types/chat/completion_create_params.py | 34 +- src/openai/types/chat_model.py | 7 +- .../types/fine_tuning/fine_tuning_job.py | 106 +++++- .../fine_tuning/fine_tuning_job_event.py | 13 + .../types/fine_tuning/job_create_params.py | 94 ++++- tests/api_resources/beta/realtime/__init__.py | 1 + .../beta/realtime/test_sessions.py | 146 ++++++++ tests/api_resources/chat/test_completions.py | 44 +-- tests/api_resources/fine_tuning/test_jobs.py | 36 ++ tests/test_client.py | 16 +- 25 files changed, 1475 insertions(+), 151 deletions(-) create mode 100644 src/openai/resources/beta/realtime/__init__.py create mode 100644 src/openai/resources/beta/realtime/realtime.py create mode 100644 src/openai/resources/beta/realtime/sessions.py create mode 100644 src/openai/types/beta/realtime/__init__.py create mode 100644 src/openai/types/beta/realtime/session_create_params.py create mode 100644 src/openai/types/beta/realtime/session_create_response.py create mode 100644 src/openai/types/chat/chat_completion_developer_message_param.py create mode 100644 src/openai/types/chat/chat_completion_reasoning_effort.py create mode 100644 tests/api_resources/beta/realtime/__init__.py create mode 100644 tests/api_resources/beta/realtime/test_sessions.py diff --git a/.stats.yml b/.stats.yml index 3cc042fe0a..e3a0040a5a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ -configured_endpoints: 68 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-2e0e0678be19d1118fd796af291822075e40538dba326611e177e9f3dc245a53.yml +configured_endpoints: 69 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-779ea2754025daf5e18eb8ceb203ec321692636bc3a999338556a479178efa6c.yml diff --git a/api.md b/api.md index 7def07bb79..91b2a9c2fd 100644 --- a/api.md +++ b/api.md @@ -47,6 +47,7 @@ from openai.types.chat import ( ChatCompletionContentPartInputAudio, ChatCompletionContentPartRefusal, ChatCompletionContentPartText, + ChatCompletionDeveloperMessageParam, ChatCompletionFunctionCallOption, ChatCompletionFunctionMessageParam, ChatCompletionMessage, @@ -55,6 +56,7 @@ from openai.types.chat import ( ChatCompletionModality, ChatCompletionNamedToolChoice, ChatCompletionPredictionContent, + ChatCompletionReasoningEffort, ChatCompletionRole, ChatCompletionStreamOptions, ChatCompletionSystemMessageParam, @@ -235,6 +237,20 @@ Methods: # Beta +## Realtime + +### Sessions + +Types: + +```python +from openai.types.beta.realtime import Session, SessionCreateResponse +``` + +Methods: + +- client.beta.realtime.sessions.create(\*\*params) -> SessionCreateResponse + ## VectorStores Types: diff --git a/src/openai/resources/beta/beta.py b/src/openai/resources/beta/beta.py index 5079c989a5..1ffa6c8e79 100644 --- a/src/openai/resources/beta/beta.py +++ b/src/openai/resources/beta/beta.py @@ -21,6 +21,14 @@ ThreadsWithStreamingResponse, AsyncThreadsWithStreamingResponse, ) +from .realtime.realtime import ( + Realtime, + AsyncRealtime, + RealtimeWithRawResponse, + AsyncRealtimeWithRawResponse, + RealtimeWithStreamingResponse, + AsyncRealtimeWithStreamingResponse, +) from .vector_stores.vector_stores import ( VectorStores, AsyncVectorStores, @@ -38,6 +46,10 @@ class Beta(SyncAPIResource): def chat(self) -> Chat: return Chat(self._client) + @cached_property + def realtime(self) -> Realtime: + return Realtime(self._client) + @cached_property def vector_stores(self) -> VectorStores: return VectorStores(self._client) @@ -75,6 +87,10 @@ class AsyncBeta(AsyncAPIResource): def chat(self) -> AsyncChat: return AsyncChat(self._client) + @cached_property + def realtime(self) -> AsyncRealtime: + return AsyncRealtime(self._client) + @cached_property def vector_stores(self) -> AsyncVectorStores: return AsyncVectorStores(self._client) @@ -111,6 +127,10 @@ class BetaWithRawResponse: def __init__(self, beta: Beta) -> None: self._beta = beta + @cached_property + def realtime(self) -> RealtimeWithRawResponse: + return RealtimeWithRawResponse(self._beta.realtime) + @cached_property def vector_stores(self) -> VectorStoresWithRawResponse: return VectorStoresWithRawResponse(self._beta.vector_stores) @@ -128,6 +148,10 @@ class AsyncBetaWithRawResponse: def __init__(self, beta: AsyncBeta) -> None: self._beta = beta + @cached_property + def realtime(self) -> AsyncRealtimeWithRawResponse: + return AsyncRealtimeWithRawResponse(self._beta.realtime) + @cached_property def vector_stores(self) -> AsyncVectorStoresWithRawResponse: return AsyncVectorStoresWithRawResponse(self._beta.vector_stores) @@ -145,6 +169,10 @@ class BetaWithStreamingResponse: def __init__(self, beta: Beta) -> None: self._beta = beta + @cached_property + def realtime(self) -> RealtimeWithStreamingResponse: + return RealtimeWithStreamingResponse(self._beta.realtime) + @cached_property def vector_stores(self) -> VectorStoresWithStreamingResponse: return VectorStoresWithStreamingResponse(self._beta.vector_stores) @@ -162,6 +190,10 @@ class AsyncBetaWithStreamingResponse: def __init__(self, beta: AsyncBeta) -> None: self._beta = beta + @cached_property + def realtime(self) -> AsyncRealtimeWithStreamingResponse: + return AsyncRealtimeWithStreamingResponse(self._beta.realtime) + @cached_property def vector_stores(self) -> AsyncVectorStoresWithStreamingResponse: return AsyncVectorStoresWithStreamingResponse(self._beta.vector_stores) diff --git a/src/openai/resources/beta/realtime/__init__.py b/src/openai/resources/beta/realtime/__init__.py new file mode 100644 index 0000000000..474434e6e1 --- /dev/null +++ b/src/openai/resources/beta/realtime/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .realtime import ( + Realtime, + AsyncRealtime, + RealtimeWithRawResponse, + AsyncRealtimeWithRawResponse, + RealtimeWithStreamingResponse, + AsyncRealtimeWithStreamingResponse, +) +from .sessions import ( + Sessions, + AsyncSessions, + SessionsWithRawResponse, + AsyncSessionsWithRawResponse, + SessionsWithStreamingResponse, + AsyncSessionsWithStreamingResponse, +) + +__all__ = [ + "Sessions", + "AsyncSessions", + "SessionsWithRawResponse", + "AsyncSessionsWithRawResponse", + "SessionsWithStreamingResponse", + "AsyncSessionsWithStreamingResponse", + "Realtime", + "AsyncRealtime", + "RealtimeWithRawResponse", + "AsyncRealtimeWithRawResponse", + "RealtimeWithStreamingResponse", + "AsyncRealtimeWithStreamingResponse", +] diff --git a/src/openai/resources/beta/realtime/realtime.py b/src/openai/resources/beta/realtime/realtime.py new file mode 100644 index 0000000000..e57e0be503 --- /dev/null +++ b/src/openai/resources/beta/realtime/realtime.py @@ -0,0 +1,102 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .sessions import ( + Sessions, + AsyncSessions, + SessionsWithRawResponse, + AsyncSessionsWithRawResponse, + SessionsWithStreamingResponse, + AsyncSessionsWithStreamingResponse, +) +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource + +__all__ = ["Realtime", "AsyncRealtime"] + + +class Realtime(SyncAPIResource): + @cached_property + def sessions(self) -> Sessions: + return Sessions(self._client) + + @cached_property + def with_raw_response(self) -> RealtimeWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return RealtimeWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> RealtimeWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return RealtimeWithStreamingResponse(self) + + +class AsyncRealtime(AsyncAPIResource): + @cached_property + def sessions(self) -> AsyncSessions: + return AsyncSessions(self._client) + + @cached_property + def with_raw_response(self) -> AsyncRealtimeWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncRealtimeWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncRealtimeWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncRealtimeWithStreamingResponse(self) + + +class RealtimeWithRawResponse: + def __init__(self, realtime: Realtime) -> None: + self._realtime = realtime + + @cached_property + def sessions(self) -> SessionsWithRawResponse: + return SessionsWithRawResponse(self._realtime.sessions) + + +class AsyncRealtimeWithRawResponse: + def __init__(self, realtime: AsyncRealtime) -> None: + self._realtime = realtime + + @cached_property + def sessions(self) -> AsyncSessionsWithRawResponse: + return AsyncSessionsWithRawResponse(self._realtime.sessions) + + +class RealtimeWithStreamingResponse: + def __init__(self, realtime: Realtime) -> None: + self._realtime = realtime + + @cached_property + def sessions(self) -> SessionsWithStreamingResponse: + return SessionsWithStreamingResponse(self._realtime.sessions) + + +class AsyncRealtimeWithStreamingResponse: + def __init__(self, realtime: AsyncRealtime) -> None: + self._realtime = realtime + + @cached_property + def sessions(self) -> AsyncSessionsWithStreamingResponse: + return AsyncSessionsWithStreamingResponse(self._realtime.sessions) diff --git a/src/openai/resources/beta/realtime/sessions.py b/src/openai/resources/beta/realtime/sessions.py new file mode 100644 index 0000000000..1d1ee701e5 --- /dev/null +++ b/src/openai/resources/beta/realtime/sessions.py @@ -0,0 +1,337 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union, Iterable +from typing_extensions import Literal + +import httpx + +from .... import _legacy_response +from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._utils import ( + maybe_transform, + async_maybe_transform, +) +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ...._base_client import make_request_options +from ....types.beta.realtime import session_create_params +from ....types.beta.realtime.session_create_response import SessionCreateResponse + +__all__ = ["Sessions", "AsyncSessions"] + + +class Sessions(SyncAPIResource): + @cached_property + def with_raw_response(self) -> SessionsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return SessionsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> SessionsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return SessionsWithStreamingResponse(self) + + def create( + self, + *, + model: Literal[ + "gpt-4o-realtime-preview", + "gpt-4o-realtime-preview-2024-10-01", + "gpt-4o-realtime-preview-2024-12-17", + "gpt-4o-mini-realtime-preview", + "gpt-4o-mini-realtime-preview-2024-12-17", + ], + input_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] | NotGiven = NOT_GIVEN, + input_audio_transcription: session_create_params.InputAudioTranscription | NotGiven = NOT_GIVEN, + instructions: str | NotGiven = NOT_GIVEN, + max_response_output_tokens: Union[int, Literal["inf"]] | NotGiven = NOT_GIVEN, + modalities: List[Literal["text", "audio"]] | NotGiven = NOT_GIVEN, + output_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] | NotGiven = NOT_GIVEN, + temperature: float | NotGiven = NOT_GIVEN, + tool_choice: str | NotGiven = NOT_GIVEN, + tools: Iterable[session_create_params.Tool] | NotGiven = NOT_GIVEN, + turn_detection: session_create_params.TurnDetection | NotGiven = NOT_GIVEN, + voice: Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> SessionCreateResponse: + """ + Create an ephemeral API token for use in client-side applications with the + Realtime API. Can be configured with the same session parameters as the + `session.update` client event. + + It responds with a session object, plus a `client_secret` key which contains a + usable ephemeral API token that can be used to authenticate browser clients for + the Realtime API. + + Args: + model: The Realtime model used for this session. + + input_audio_format: The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. + + input_audio_transcription: Configuration for input audio transcription, defaults to off and can be set to + `null` to turn off once on. Input audio transcription is not native to the + model, since the model consumes audio directly. Transcription runs + asynchronously through Whisper and should be treated as rough guidance rather + than the representation understood by the model. + + instructions: The default system instructions (i.e. system message) prepended to model calls. + This field allows the client to guide the model on desired responses. The model + can be instructed on response content and format, (e.g. "be extremely succinct", + "act friendly", "here are examples of good responses") and on audio behavior + (e.g. "talk quickly", "inject emotion into your voice", "laugh frequently"). The + instructions are not guaranteed to be followed by the model, but they provide + guidance to the model on the desired behavior. + + Note that the server sets default instructions which will be used if this field + is not set and are visible in the `session.created` event at the start of the + session. + + max_response_output_tokens: Maximum number of output tokens for a single assistant response, inclusive of + tool calls. Provide an integer between 1 and 4096 to limit output tokens, or + `inf` for the maximum available tokens for a given model. Defaults to `inf`. + + modalities: The set of modalities the model can respond with. To disable audio, set this to + ["text"]. + + output_audio_format: The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. + + temperature: Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8. + + tool_choice: How the model chooses tools. Options are `auto`, `none`, `required`, or specify + a function. + + tools: Tools (functions) available to the model. + + turn_detection: Configuration for turn detection. Can be set to `null` to turn off. Server VAD + means that the model will detect the start and end of speech based on audio + volume and respond at the end of user speech. + + voice: The voice the model uses to respond. Voice cannot be changed during the session + once the model has responded with audio at least once. Current voice options are + `alloy`, `ash`, `ballad`, `coral`, `echo` `sage`, `shimmer` and `verse`. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} + return self._post( + "/realtime/sessions", + body=maybe_transform( + { + "model": model, + "input_audio_format": input_audio_format, + "input_audio_transcription": input_audio_transcription, + "instructions": instructions, + "max_response_output_tokens": max_response_output_tokens, + "modalities": modalities, + "output_audio_format": output_audio_format, + "temperature": temperature, + "tool_choice": tool_choice, + "tools": tools, + "turn_detection": turn_detection, + "voice": voice, + }, + session_create_params.SessionCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SessionCreateResponse, + ) + + +class AsyncSessions(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncSessionsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncSessionsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncSessionsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncSessionsWithStreamingResponse(self) + + async def create( + self, + *, + model: Literal[ + "gpt-4o-realtime-preview", + "gpt-4o-realtime-preview-2024-10-01", + "gpt-4o-realtime-preview-2024-12-17", + "gpt-4o-mini-realtime-preview", + "gpt-4o-mini-realtime-preview-2024-12-17", + ], + input_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] | NotGiven = NOT_GIVEN, + input_audio_transcription: session_create_params.InputAudioTranscription | NotGiven = NOT_GIVEN, + instructions: str | NotGiven = NOT_GIVEN, + max_response_output_tokens: Union[int, Literal["inf"]] | NotGiven = NOT_GIVEN, + modalities: List[Literal["text", "audio"]] | NotGiven = NOT_GIVEN, + output_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] | NotGiven = NOT_GIVEN, + temperature: float | NotGiven = NOT_GIVEN, + tool_choice: str | NotGiven = NOT_GIVEN, + tools: Iterable[session_create_params.Tool] | NotGiven = NOT_GIVEN, + turn_detection: session_create_params.TurnDetection | NotGiven = NOT_GIVEN, + voice: Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> SessionCreateResponse: + """ + Create an ephemeral API token for use in client-side applications with the + Realtime API. Can be configured with the same session parameters as the + `session.update` client event. + + It responds with a session object, plus a `client_secret` key which contains a + usable ephemeral API token that can be used to authenticate browser clients for + the Realtime API. + + Args: + model: The Realtime model used for this session. + + input_audio_format: The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. + + input_audio_transcription: Configuration for input audio transcription, defaults to off and can be set to + `null` to turn off once on. Input audio transcription is not native to the + model, since the model consumes audio directly. Transcription runs + asynchronously through Whisper and should be treated as rough guidance rather + than the representation understood by the model. + + instructions: The default system instructions (i.e. system message) prepended to model calls. + This field allows the client to guide the model on desired responses. The model + can be instructed on response content and format, (e.g. "be extremely succinct", + "act friendly", "here are examples of good responses") and on audio behavior + (e.g. "talk quickly", "inject emotion into your voice", "laugh frequently"). The + instructions are not guaranteed to be followed by the model, but they provide + guidance to the model on the desired behavior. + + Note that the server sets default instructions which will be used if this field + is not set and are visible in the `session.created` event at the start of the + session. + + max_response_output_tokens: Maximum number of output tokens for a single assistant response, inclusive of + tool calls. Provide an integer between 1 and 4096 to limit output tokens, or + `inf` for the maximum available tokens for a given model. Defaults to `inf`. + + modalities: The set of modalities the model can respond with. To disable audio, set this to + ["text"]. + + output_audio_format: The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. + + temperature: Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8. + + tool_choice: How the model chooses tools. Options are `auto`, `none`, `required`, or specify + a function. + + tools: Tools (functions) available to the model. + + turn_detection: Configuration for turn detection. Can be set to `null` to turn off. Server VAD + means that the model will detect the start and end of speech based on audio + volume and respond at the end of user speech. + + voice: The voice the model uses to respond. Voice cannot be changed during the session + once the model has responded with audio at least once. Current voice options are + `alloy`, `ash`, `ballad`, `coral`, `echo` `sage`, `shimmer` and `verse`. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} + return await self._post( + "/realtime/sessions", + body=await async_maybe_transform( + { + "model": model, + "input_audio_format": input_audio_format, + "input_audio_transcription": input_audio_transcription, + "instructions": instructions, + "max_response_output_tokens": max_response_output_tokens, + "modalities": modalities, + "output_audio_format": output_audio_format, + "temperature": temperature, + "tool_choice": tool_choice, + "tools": tools, + "turn_detection": turn_detection, + "voice": voice, + }, + session_create_params.SessionCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SessionCreateResponse, + ) + + +class SessionsWithRawResponse: + def __init__(self, sessions: Sessions) -> None: + self._sessions = sessions + + self.create = _legacy_response.to_raw_response_wrapper( + sessions.create, + ) + + +class AsyncSessionsWithRawResponse: + def __init__(self, sessions: AsyncSessions) -> None: + self._sessions = sessions + + self.create = _legacy_response.async_to_raw_response_wrapper( + sessions.create, + ) + + +class SessionsWithStreamingResponse: + def __init__(self, sessions: Sessions) -> None: + self._sessions = sessions + + self.create = to_streamed_response_wrapper( + sessions.create, + ) + + +class AsyncSessionsWithStreamingResponse: + def __init__(self, sessions: AsyncSessions) -> None: + self._sessions = sessions + + self.create = async_to_streamed_response_wrapper( + sessions.create, + ) diff --git a/src/openai/resources/chat/completions.py b/src/openai/resources/chat/completions.py index 60ab5138ba..728c744327 100644 --- a/src/openai/resources/chat/completions.py +++ b/src/openai/resources/chat/completions.py @@ -22,6 +22,7 @@ from ..._streaming import Stream, AsyncStream from ...types.chat import ( ChatCompletionAudioParam, + ChatCompletionReasoningEffort, completion_create_params, ) from ..._base_client import make_request_options @@ -32,6 +33,7 @@ from ...types.chat.chat_completion_tool_param import ChatCompletionToolParam from ...types.chat.chat_completion_audio_param import ChatCompletionAudioParam from ...types.chat.chat_completion_message_param import ChatCompletionMessageParam +from ...types.chat.chat_completion_reasoning_effort import ChatCompletionReasoningEffort from ...types.chat.chat_completion_stream_options_param import ChatCompletionStreamOptionsParam from ...types.chat.chat_completion_prediction_content_param import ChatCompletionPredictionContentParam from ...types.chat.chat_completion_tool_choice_option_param import ChatCompletionToolChoiceOptionParam @@ -79,6 +81,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, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, @@ -106,6 +109,12 @@ def create( [vision](https://platform.openai.com/docs/guides/vision), and [audio](https://platform.openai.com/docs/guides/audio) guides. + Parameter support can differ depending on the model used to generate the + response, particularly for newer reasoning models. Parameters that are only + supported for reasoning models are noted below. For the current state of + unsupported parameters in reasoning models, + [refer to the reasoning guide](https://platform.openai.com/docs/guides/reasoning). + Args: messages: A list of messages comprising the conversation so far. Depending on the [model](https://platform.openai.com/docs/models) you use, different message @@ -126,16 +135,18 @@ def create( existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) - function_call: Deprecated in favor of `tool_choice`. - Controls which (if any) function is called by the model. `none` means the model - will not call a function and instead generates a message. `auto` means the model - can pick between generating a message or calling a function. Specifying a - particular function via `{"name": "my_function"}` forces the model to call that + Controls which (if any) function is called by the model. + + `none` means the model will not call a function and instead generates a message. + + `auto` means the model can pick between generating a message or calling a function. + Specifying a particular function via `{"name": "my_function"}` forces the model + to call that function. + `none` is the default when no functions are present. `auto` is the default if functions are present. @@ -197,13 +208,14 @@ def create( whether they appear in the text so far, increasing the model's likelihood to talk about new topics. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) + reasoning_effort: **o1 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: An object specifying the format that the model must output. Compatible with - [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), - [GPT-4o mini](https://platform.openai.com/docs/models#gpt-4o-mini), - [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4) and - all GPT-3.5 Turbo models newer than `gpt-3.5-turbo-1106`. + response_format: An object specifying the format that the model must output. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured Outputs which ensures the model will match your supplied JSON schema. Learn more @@ -259,9 +271,8 @@ def create( temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more - focused and deterministic. - - We generally recommend altering this or `top_p` but not both. + focused and deterministic. We generally recommend altering this or `top_p` but + not both. tool_choice: Controls which (if any) tool is called by the model. `none` means the model will not call any tool and instead generates a message. `auto` means the model can @@ -322,6 +333,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, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, @@ -348,6 +360,12 @@ def create( [vision](https://platform.openai.com/docs/guides/vision), and [audio](https://platform.openai.com/docs/guides/audio) guides. + Parameter support can differ depending on the model used to generate the + response, particularly for newer reasoning models. Parameters that are only + supported for reasoning models are noted below. For the current state of + unsupported parameters in reasoning models, + [refer to the reasoning guide](https://platform.openai.com/docs/guides/reasoning). + Args: messages: A list of messages comprising the conversation so far. Depending on the [model](https://platform.openai.com/docs/models) you use, different message @@ -375,16 +393,18 @@ def create( existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) - function_call: Deprecated in favor of `tool_choice`. - Controls which (if any) function is called by the model. `none` means the model - will not call a function and instead generates a message. `auto` means the model - can pick between generating a message or calling a function. Specifying a - particular function via `{"name": "my_function"}` forces the model to call that + Controls which (if any) function is called by the model. + + `none` means the model will not call a function and instead generates a message. + + `auto` means the model can pick between generating a message or calling a function. + Specifying a particular function via `{"name": "my_function"}` forces the model + to call that function. + `none` is the default when no functions are present. `auto` is the default if functions are present. @@ -446,13 +466,14 @@ def create( whether they appear in the text so far, increasing the model's likelihood to talk about new topics. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) + reasoning_effort: **o1 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: An object specifying the format that the model must output. Compatible with - [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), - [GPT-4o mini](https://platform.openai.com/docs/models#gpt-4o-mini), - [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4) and - all GPT-3.5 Turbo models newer than `gpt-3.5-turbo-1106`. + response_format: An object specifying the format that the model must output. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured Outputs which ensures the model will match your supplied JSON schema. Learn more @@ -501,9 +522,8 @@ def create( temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more - focused and deterministic. - - We generally recommend altering this or `top_p` but not both. + focused and deterministic. We generally recommend altering this or `top_p` but + not both. tool_choice: Controls which (if any) tool is called by the model. `none` means the model will not call any tool and instead generates a message. `auto` means the model can @@ -564,6 +584,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, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, @@ -590,6 +611,12 @@ def create( [vision](https://platform.openai.com/docs/guides/vision), and [audio](https://platform.openai.com/docs/guides/audio) guides. + Parameter support can differ depending on the model used to generate the + response, particularly for newer reasoning models. Parameters that are only + supported for reasoning models are noted below. For the current state of + unsupported parameters in reasoning models, + [refer to the reasoning guide](https://platform.openai.com/docs/guides/reasoning). + Args: messages: A list of messages comprising the conversation so far. Depending on the [model](https://platform.openai.com/docs/models) you use, different message @@ -617,16 +644,18 @@ def create( existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) - function_call: Deprecated in favor of `tool_choice`. - Controls which (if any) function is called by the model. `none` means the model - will not call a function and instead generates a message. `auto` means the model - can pick between generating a message or calling a function. Specifying a - particular function via `{"name": "my_function"}` forces the model to call that + Controls which (if any) function is called by the model. + + `none` means the model will not call a function and instead generates a message. + + `auto` means the model can pick between generating a message or calling a function. + Specifying a particular function via `{"name": "my_function"}` forces the model + to call that function. + `none` is the default when no functions are present. `auto` is the default if functions are present. @@ -688,13 +717,14 @@ def create( whether they appear in the text so far, increasing the model's likelihood to talk about new topics. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) + reasoning_effort: **o1 models only** - response_format: An object specifying the format that the model must output. Compatible with - [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), - [GPT-4o mini](https://platform.openai.com/docs/models#gpt-4o-mini), - [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4) and - all GPT-3.5 Turbo models newer than `gpt-3.5-turbo-1106`. + 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: An object specifying the format that the model must output. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured Outputs which ensures the model will match your supplied JSON schema. Learn more @@ -743,9 +773,8 @@ def create( temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more - focused and deterministic. - - We generally recommend altering this or `top_p` but not both. + focused and deterministic. We generally recommend altering this or `top_p` but + not both. tool_choice: Controls which (if any) tool is called by the model. `none` means the model will not call any tool and instead generates a message. `auto` means the model can @@ -805,6 +834,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, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, @@ -846,6 +876,7 @@ def create( "parallel_tool_calls": parallel_tool_calls, "prediction": prediction, "presence_penalty": presence_penalty, + "reasoning_effort": reasoning_effort, "response_format": response_format, "seed": seed, "service_tier": service_tier, @@ -911,6 +942,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, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, @@ -938,6 +970,12 @@ async def create( [vision](https://platform.openai.com/docs/guides/vision), and [audio](https://platform.openai.com/docs/guides/audio) guides. + Parameter support can differ depending on the model used to generate the + response, particularly for newer reasoning models. Parameters that are only + supported for reasoning models are noted below. For the current state of + unsupported parameters in reasoning models, + [refer to the reasoning guide](https://platform.openai.com/docs/guides/reasoning). + Args: messages: A list of messages comprising the conversation so far. Depending on the [model](https://platform.openai.com/docs/models) you use, different message @@ -958,16 +996,18 @@ async def create( existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) - function_call: Deprecated in favor of `tool_choice`. - Controls which (if any) function is called by the model. `none` means the model - will not call a function and instead generates a message. `auto` means the model - can pick between generating a message or calling a function. Specifying a - particular function via `{"name": "my_function"}` forces the model to call that + Controls which (if any) function is called by the model. + + `none` means the model will not call a function and instead generates a message. + + `auto` means the model can pick between generating a message or calling a function. + Specifying a particular function via `{"name": "my_function"}` forces the model + to call that function. + `none` is the default when no functions are present. `auto` is the default if functions are present. @@ -1029,13 +1069,14 @@ async def create( whether they appear in the text so far, increasing the model's likelihood to talk about new topics. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) + reasoning_effort: **o1 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: An object specifying the format that the model must output. Compatible with - [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), - [GPT-4o mini](https://platform.openai.com/docs/models#gpt-4o-mini), - [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4) and - all GPT-3.5 Turbo models newer than `gpt-3.5-turbo-1106`. + response_format: An object specifying the format that the model must output. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured Outputs which ensures the model will match your supplied JSON schema. Learn more @@ -1091,9 +1132,8 @@ async def create( temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more - focused and deterministic. - - We generally recommend altering this or `top_p` but not both. + focused and deterministic. We generally recommend altering this or `top_p` but + not both. tool_choice: Controls which (if any) tool is called by the model. `none` means the model will not call any tool and instead generates a message. `auto` means the model can @@ -1154,6 +1194,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, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, @@ -1180,6 +1221,12 @@ async def create( [vision](https://platform.openai.com/docs/guides/vision), and [audio](https://platform.openai.com/docs/guides/audio) guides. + Parameter support can differ depending on the model used to generate the + response, particularly for newer reasoning models. Parameters that are only + supported for reasoning models are noted below. For the current state of + unsupported parameters in reasoning models, + [refer to the reasoning guide](https://platform.openai.com/docs/guides/reasoning). + Args: messages: A list of messages comprising the conversation so far. Depending on the [model](https://platform.openai.com/docs/models) you use, different message @@ -1207,16 +1254,18 @@ async def create( existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) - function_call: Deprecated in favor of `tool_choice`. - Controls which (if any) function is called by the model. `none` means the model - will not call a function and instead generates a message. `auto` means the model - can pick between generating a message or calling a function. Specifying a - particular function via `{"name": "my_function"}` forces the model to call that + Controls which (if any) function is called by the model. + + `none` means the model will not call a function and instead generates a message. + + `auto` means the model can pick between generating a message or calling a function. + Specifying a particular function via `{"name": "my_function"}` forces the model + to call that function. + `none` is the default when no functions are present. `auto` is the default if functions are present. @@ -1278,13 +1327,14 @@ async def create( whether they appear in the text so far, increasing the model's likelihood to talk about new topics. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) + reasoning_effort: **o1 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: An object specifying the format that the model must output. Compatible with - [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), - [GPT-4o mini](https://platform.openai.com/docs/models#gpt-4o-mini), - [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4) and - all GPT-3.5 Turbo models newer than `gpt-3.5-turbo-1106`. + response_format: An object specifying the format that the model must output. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured Outputs which ensures the model will match your supplied JSON schema. Learn more @@ -1333,9 +1383,8 @@ async def create( temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more - focused and deterministic. - - We generally recommend altering this or `top_p` but not both. + focused and deterministic. We generally recommend altering this or `top_p` but + not both. tool_choice: Controls which (if any) tool is called by the model. `none` means the model will not call any tool and instead generates a message. `auto` means the model can @@ -1396,6 +1445,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, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, @@ -1422,6 +1472,12 @@ async def create( [vision](https://platform.openai.com/docs/guides/vision), and [audio](https://platform.openai.com/docs/guides/audio) guides. + Parameter support can differ depending on the model used to generate the + response, particularly for newer reasoning models. Parameters that are only + supported for reasoning models are noted below. For the current state of + unsupported parameters in reasoning models, + [refer to the reasoning guide](https://platform.openai.com/docs/guides/reasoning). + Args: messages: A list of messages comprising the conversation so far. Depending on the [model](https://platform.openai.com/docs/models) you use, different message @@ -1449,16 +1505,18 @@ async def create( existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) - function_call: Deprecated in favor of `tool_choice`. - Controls which (if any) function is called by the model. `none` means the model - will not call a function and instead generates a message. `auto` means the model - can pick between generating a message or calling a function. Specifying a - particular function via `{"name": "my_function"}` forces the model to call that + Controls which (if any) function is called by the model. + + `none` means the model will not call a function and instead generates a message. + + `auto` means the model can pick between generating a message or calling a function. + Specifying a particular function via `{"name": "my_function"}` forces the model + to call that function. + `none` is the default when no functions are present. `auto` is the default if functions are present. @@ -1520,13 +1578,14 @@ async def create( whether they appear in the text so far, increasing the model's likelihood to talk about new topics. - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) + reasoning_effort: **o1 models only** - response_format: An object specifying the format that the model must output. Compatible with - [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), - [GPT-4o mini](https://platform.openai.com/docs/models#gpt-4o-mini), - [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4) and - all GPT-3.5 Turbo models newer than `gpt-3.5-turbo-1106`. + 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: An object specifying the format that the model must output. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured Outputs which ensures the model will match your supplied JSON schema. Learn more @@ -1575,9 +1634,8 @@ async def create( temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more - focused and deterministic. - - We generally recommend altering this or `top_p` but not both. + focused and deterministic. We generally recommend altering this or `top_p` but + not both. tool_choice: Controls which (if any) tool is called by the model. `none` means the model will not call any tool and instead generates a message. `auto` means the model can @@ -1637,6 +1695,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, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, @@ -1678,6 +1737,7 @@ async def create( "parallel_tool_calls": parallel_tool_calls, "prediction": prediction, "presence_penalty": presence_penalty, + "reasoning_effort": reasoning_effort, "response_format": response_format, "seed": seed, "service_tier": service_tier, diff --git a/src/openai/resources/fine_tuning/jobs/jobs.py b/src/openai/resources/fine_tuning/jobs/jobs.py index 0ed5495b0e..78eefc253c 100644 --- a/src/openai/resources/fine_tuning/jobs/jobs.py +++ b/src/openai/resources/fine_tuning/jobs/jobs.py @@ -67,6 +67,7 @@ def create( training_file: str, hyperparameters: job_create_params.Hyperparameters | NotGiven = NOT_GIVEN, integrations: Optional[Iterable[job_create_params.Integration]] | NotGiven = NOT_GIVEN, + method: job_create_params.Method | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, suffix: Optional[str] | NotGiven = NOT_GIVEN, validation_file: Optional[str] | NotGiven = NOT_GIVEN, @@ -99,17 +100,22 @@ def create( your file with the purpose `fine-tune`. The contents of the file should differ depending on if the model uses the - [chat](https://platform.openai.com/docs/api-reference/fine-tuning/chat-input) or + [chat](https://platform.openai.com/docs/api-reference/fine-tuning/chat-input), [completions](https://platform.openai.com/docs/api-reference/fine-tuning/completions-input) + format, or if the fine-tuning method uses the + [preference](https://platform.openai.com/docs/api-reference/fine-tuning/preference-input) format. See the [fine-tuning guide](https://platform.openai.com/docs/guides/fine-tuning) for more details. - hyperparameters: The hyperparameters used for the fine-tuning job. + hyperparameters: The hyperparameters used for the fine-tuning job. This value is now deprecated + in favor of `method`, and should be passed in under the `method` parameter. integrations: A list of integrations to enable for your fine-tuning job. + method: The method used for fine-tuning. + seed: The seed controls the reproducibility of the job. Passing in the same seed and job parameters should produce the same results, but may differ in rare cases. If a seed is not specified, one will be generated for you. @@ -149,6 +155,7 @@ def create( "training_file": training_file, "hyperparameters": hyperparameters, "integrations": integrations, + "method": method, "seed": seed, "suffix": suffix, "validation_file": validation_file, @@ -358,6 +365,7 @@ async def create( training_file: str, hyperparameters: job_create_params.Hyperparameters | NotGiven = NOT_GIVEN, integrations: Optional[Iterable[job_create_params.Integration]] | NotGiven = NOT_GIVEN, + method: job_create_params.Method | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, suffix: Optional[str] | NotGiven = NOT_GIVEN, validation_file: Optional[str] | NotGiven = NOT_GIVEN, @@ -390,17 +398,22 @@ async def create( your file with the purpose `fine-tune`. The contents of the file should differ depending on if the model uses the - [chat](https://platform.openai.com/docs/api-reference/fine-tuning/chat-input) or + [chat](https://platform.openai.com/docs/api-reference/fine-tuning/chat-input), [completions](https://platform.openai.com/docs/api-reference/fine-tuning/completions-input) + format, or if the fine-tuning method uses the + [preference](https://platform.openai.com/docs/api-reference/fine-tuning/preference-input) format. See the [fine-tuning guide](https://platform.openai.com/docs/guides/fine-tuning) for more details. - hyperparameters: The hyperparameters used for the fine-tuning job. + hyperparameters: The hyperparameters used for the fine-tuning job. This value is now deprecated + in favor of `method`, and should be passed in under the `method` parameter. integrations: A list of integrations to enable for your fine-tuning job. + method: The method used for fine-tuning. + seed: The seed controls the reproducibility of the job. Passing in the same seed and job parameters should produce the same results, but may differ in rare cases. If a seed is not specified, one will be generated for you. @@ -440,6 +453,7 @@ async def create( "training_file": training_file, "hyperparameters": hyperparameters, "integrations": integrations, + "method": method, "seed": seed, "suffix": suffix, "validation_file": validation_file, diff --git a/src/openai/types/beta/realtime/__init__.py b/src/openai/types/beta/realtime/__init__.py new file mode 100644 index 0000000000..1c5246db7a --- /dev/null +++ b/src/openai/types/beta/realtime/__init__.py @@ -0,0 +1,6 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .session_create_params import SessionCreateParams as SessionCreateParams +from .session_create_response import SessionCreateResponse as SessionCreateResponse diff --git a/src/openai/types/beta/realtime/session_create_params.py b/src/openai/types/beta/realtime/session_create_params.py new file mode 100644 index 0000000000..f56f2c5c22 --- /dev/null +++ b/src/openai/types/beta/realtime/session_create_params.py @@ -0,0 +1,149 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union, Iterable +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["SessionCreateParams", "InputAudioTranscription", "Tool", "TurnDetection"] + + +class SessionCreateParams(TypedDict, total=False): + model: Required[ + Literal[ + "gpt-4o-realtime-preview", + "gpt-4o-realtime-preview-2024-10-01", + "gpt-4o-realtime-preview-2024-12-17", + "gpt-4o-mini-realtime-preview", + "gpt-4o-mini-realtime-preview-2024-12-17", + ] + ] + """The Realtime model used for this session.""" + + input_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] + """The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + + input_audio_transcription: InputAudioTranscription + """ + Configuration for input audio transcription, defaults to off and can be set to + `null` to turn off once on. Input audio transcription is not native to the + model, since the model consumes audio directly. Transcription runs + asynchronously through Whisper and should be treated as rough guidance rather + than the representation understood by the model. + """ + + instructions: str + """The default system instructions (i.e. + + system message) prepended to model calls. This field allows the client to guide + the model on desired responses. The model can be instructed on response content + and format, (e.g. "be extremely succinct", "act friendly", "here are examples of + good responses") and on audio behavior (e.g. "talk quickly", "inject emotion + into your voice", "laugh frequently"). The instructions are not guaranteed to be + followed by the model, but they provide guidance to the model on the desired + behavior. + + Note that the server sets default instructions which will be used if this field + is not set and are visible in the `session.created` event at the start of the + session. + """ + + max_response_output_tokens: Union[int, Literal["inf"]] + """ + Maximum number of output tokens for a single assistant response, inclusive of + tool calls. Provide an integer between 1 and 4096 to limit output tokens, or + `inf` for the maximum available tokens for a given model. Defaults to `inf`. + """ + + modalities: List[Literal["text", "audio"]] + """The set of modalities the model can respond with. + + To disable audio, set this to ["text"]. + """ + + output_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] + """The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + + temperature: float + """Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8.""" + + tool_choice: str + """How the model chooses tools. + + Options are `auto`, `none`, `required`, or specify a function. + """ + + tools: Iterable[Tool] + """Tools (functions) available to the model.""" + + turn_detection: TurnDetection + """Configuration for turn detection. + + Can be set to `null` to turn off. Server VAD means that the model will detect + the start and end of speech based on audio volume and respond at the end of user + speech. + """ + + voice: Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"] + """The voice the model uses to respond. + + Voice cannot be changed during the session once the model has responded with + audio at least once. Current voice options are `alloy`, `ash`, `ballad`, + `coral`, `echo` `sage`, `shimmer` and `verse`. + """ + + +class InputAudioTranscription(TypedDict, total=False): + model: str + """ + The model to use for transcription, `whisper-1` is the only currently supported + model. + """ + + +class Tool(TypedDict, total=False): + description: str + """ + The description of the function, including guidance on when and how to call it, + and guidance about what to tell the user when calling (if anything). + """ + + name: str + """The name of the function.""" + + parameters: object + """Parameters of the function in JSON Schema.""" + + type: Literal["function"] + """The type of the tool, i.e. `function`.""" + + +class TurnDetection(TypedDict, total=False): + create_response: bool + """Whether or not to automatically generate a response when VAD is enabled. + + `true` by default. + """ + + prefix_padding_ms: int + """Amount of audio to include before the VAD detected speech (in milliseconds). + + Defaults to 300ms. + """ + + silence_duration_ms: int + """Duration of silence to detect speech stop (in milliseconds). + + Defaults to 500ms. With shorter values the model will respond more quickly, but + may jump in on short pauses from the user. + """ + + threshold: float + """Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. + + A higher threshold will require louder audio to activate the model, and thus + might perform better in noisy environments. + """ + + type: str + """Type of turn detection, only `server_vad` is currently supported.""" diff --git a/src/openai/types/beta/realtime/session_create_response.py b/src/openai/types/beta/realtime/session_create_response.py new file mode 100644 index 0000000000..31f591b261 --- /dev/null +++ b/src/openai/types/beta/realtime/session_create_response.py @@ -0,0 +1,150 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["SessionCreateResponse", "ClientSecret", "InputAudioTranscription", "Tool", "TurnDetection"] + + +class ClientSecret(BaseModel): + expires_at: Optional[int] = None + """Timestamp for when the token expires. + + Currently, all tokens expire after one minute. + """ + + value: Optional[str] = None + """ + Ephemeral key usable in client environments to authenticate connections to the + Realtime API. Use this in client-side environments rather than a standard API + token, which should only be used server-side. + """ + + +class InputAudioTranscription(BaseModel): + model: Optional[str] = None + """ + The model to use for transcription, `whisper-1` is the only currently supported + model. + """ + + +class Tool(BaseModel): + description: Optional[str] = None + """ + The description of the function, including guidance on when and how to call it, + and guidance about what to tell the user when calling (if anything). + """ + + name: Optional[str] = None + """The name of the function.""" + + parameters: Optional[object] = None + """Parameters of the function in JSON Schema.""" + + type: Optional[Literal["function"]] = None + """The type of the tool, i.e. `function`.""" + + +class TurnDetection(BaseModel): + prefix_padding_ms: Optional[int] = None + """Amount of audio to include before the VAD detected speech (in milliseconds). + + Defaults to 300ms. + """ + + silence_duration_ms: Optional[int] = None + """Duration of silence to detect speech stop (in milliseconds). + + Defaults to 500ms. With shorter values the model will respond more quickly, but + may jump in on short pauses from the user. + """ + + threshold: Optional[float] = None + """Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. + + A higher threshold will require louder audio to activate the model, and thus + might perform better in noisy environments. + """ + + type: Optional[str] = None + """Type of turn detection, only `server_vad` is currently supported.""" + + +class SessionCreateResponse(BaseModel): + client_secret: Optional[ClientSecret] = None + """Ephemeral key returned by the API.""" + + input_audio_format: Optional[str] = None + """The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + + input_audio_transcription: Optional[InputAudioTranscription] = None + """ + Configuration for input audio transcription, defaults to off and can be set to + `null` to turn off once on. Input audio transcription is not native to the + model, since the model consumes audio directly. Transcription runs + asynchronously through Whisper and should be treated as rough guidance rather + than the representation understood by the model. + """ + + instructions: Optional[str] = None + """The default system instructions (i.e. + + system message) prepended to model calls. This field allows the client to guide + the model on desired responses. The model can be instructed on response content + and format, (e.g. "be extremely succinct", "act friendly", "here are examples of + good responses") and on audio behavior (e.g. "talk quickly", "inject emotion + into your voice", "laugh frequently"). The instructions are not guaranteed to be + followed by the model, but they provide guidance to the model on the desired + behavior. + + Note that the server sets default instructions which will be used if this field + is not set and are visible in the `session.created` event at the start of the + session. + """ + + max_response_output_tokens: Union[int, Literal["inf"], None] = None + """ + Maximum number of output tokens for a single assistant response, inclusive of + tool calls. Provide an integer between 1 and 4096 to limit output tokens, or + `inf` for the maximum available tokens for a given model. Defaults to `inf`. + """ + + modalities: Optional[List[Literal["text", "audio"]]] = None + """The set of modalities the model can respond with. + + To disable audio, set this to ["text"]. + """ + + output_audio_format: Optional[str] = None + """The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + + temperature: Optional[float] = None + """Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8.""" + + tool_choice: Optional[str] = None + """How the model chooses tools. + + Options are `auto`, `none`, `required`, or specify a function. + """ + + tools: Optional[List[Tool]] = None + """Tools (functions) available to the model.""" + + turn_detection: Optional[TurnDetection] = None + """Configuration for turn detection. + + Can be set to `null` to turn off. Server VAD means that the model will detect + the start and end of speech based on audio volume and respond at the end of user + speech. + """ + + voice: Optional[Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"]] = None + """The voice the model uses to respond. + + Voice cannot be changed during the session once the model has responded with + audio at least once. Current voice options are `alloy`, `ash`, `ballad`, + `coral`, `echo` `sage`, `shimmer` and `verse`. + """ diff --git a/src/openai/types/chat/__init__.py b/src/openai/types/chat/__init__.py index d0a5403e79..c623a982af 100644 --- a/src/openai/types/chat/__init__.py +++ b/src/openai/types/chat/__init__.py @@ -22,6 +22,7 @@ from .chat_completion_audio_param import ChatCompletionAudioParam as ChatCompletionAudioParam from .chat_completion_message_param import ChatCompletionMessageParam as ChatCompletionMessageParam from .chat_completion_token_logprob import ChatCompletionTokenLogprob as ChatCompletionTokenLogprob +from .chat_completion_reasoning_effort import ChatCompletionReasoningEffort as ChatCompletionReasoningEffort from .chat_completion_message_tool_call import ChatCompletionMessageToolCall as ChatCompletionMessageToolCall from .chat_completion_content_part_param import ChatCompletionContentPartParam as ChatCompletionContentPartParam from .chat_completion_tool_message_param import ChatCompletionToolMessageParam as ChatCompletionToolMessageParam @@ -37,6 +38,9 @@ from .chat_completion_content_part_text_param import ( ChatCompletionContentPartTextParam as ChatCompletionContentPartTextParam, ) +from .chat_completion_developer_message_param import ( + ChatCompletionDeveloperMessageParam as ChatCompletionDeveloperMessageParam, +) from .chat_completion_message_tool_call_param import ( ChatCompletionMessageToolCallParam as ChatCompletionMessageToolCallParam, ) diff --git a/src/openai/types/chat/chat_completion_developer_message_param.py b/src/openai/types/chat/chat_completion_developer_message_param.py new file mode 100644 index 0000000000..01e4fdb654 --- /dev/null +++ b/src/openai/types/chat/chat_completion_developer_message_param.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable +from typing_extensions import Literal, Required, TypedDict + +from .chat_completion_content_part_text_param import ChatCompletionContentPartTextParam + +__all__ = ["ChatCompletionDeveloperMessageParam"] + + +class ChatCompletionDeveloperMessageParam(TypedDict, total=False): + content: Required[Union[str, Iterable[ChatCompletionContentPartTextParam]]] + """The contents of the developer message.""" + + role: Required[Literal["developer"]] + """The role of the messages author, in this case `developer`.""" + + name: str + """An optional name for the participant. + + Provides the model information to differentiate between participants of the same + role. + """ diff --git a/src/openai/types/chat/chat_completion_message_param.py b/src/openai/types/chat/chat_completion_message_param.py index ec65d94cae..942da24304 100644 --- a/src/openai/types/chat/chat_completion_message_param.py +++ b/src/openai/types/chat/chat_completion_message_param.py @@ -10,10 +10,12 @@ from .chat_completion_system_message_param import ChatCompletionSystemMessageParam from .chat_completion_function_message_param import ChatCompletionFunctionMessageParam from .chat_completion_assistant_message_param import ChatCompletionAssistantMessageParam +from .chat_completion_developer_message_param import ChatCompletionDeveloperMessageParam __all__ = ["ChatCompletionMessageParam"] ChatCompletionMessageParam: TypeAlias = Union[ + ChatCompletionDeveloperMessageParam, ChatCompletionSystemMessageParam, ChatCompletionUserMessageParam, ChatCompletionAssistantMessageParam, diff --git a/src/openai/types/chat/chat_completion_reasoning_effort.py b/src/openai/types/chat/chat_completion_reasoning_effort.py new file mode 100644 index 0000000000..9e7946974a --- /dev/null +++ b/src/openai/types/chat/chat_completion_reasoning_effort.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["ChatCompletionReasoningEffort"] + +ChatCompletionReasoningEffort: TypeAlias = 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 e838858314..f168ddea6e 100644 --- a/src/openai/types/chat/completion_create_params.py +++ b/src/openai/types/chat/completion_create_params.py @@ -10,6 +10,7 @@ from .chat_completion_tool_param import ChatCompletionToolParam from .chat_completion_audio_param import ChatCompletionAudioParam from .chat_completion_message_param import ChatCompletionMessageParam +from .chat_completion_reasoning_effort import ChatCompletionReasoningEffort from ..shared_params.function_parameters import FunctionParameters from ..shared_params.response_format_text import ResponseFormatText from .chat_completion_stream_options_param import ChatCompletionStreamOptionsParam @@ -60,19 +61,21 @@ class CompletionCreateParamsBase(TypedDict, total=False): Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. - - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) """ function_call: FunctionCall """Deprecated in favor of `tool_choice`. - Controls which (if any) function is called by the model. `none` means the model - will not call a function and instead generates a message. `auto` means the model - can pick between generating a message or calling a function. Specifying a - particular function via `{"name": "my_function"}` forces the model to call that + Controls which (if any) function is called by the model. + + `none` means the model will not call a function and instead generates a message. + + `auto` means the model can pick between generating a message or calling a function. + Specifying a particular function via `{"name": "my_function"}` forces the model + to call that function. + `none` is the default when no functions are present. `auto` is the default if functions are present. """ @@ -164,18 +167,20 @@ class CompletionCreateParamsBase(TypedDict, total=False): Positive values penalize new tokens based on whether they appear in the text so far, increasing the model's likelihood to talk about new topics. + """ + + reasoning_effort: ChatCompletionReasoningEffort + """**o1 models only** - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) + 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: ResponseFormat """An object specifying the format that the model must output. - Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), - [GPT-4o mini](https://platform.openai.com/docs/models#gpt-4o-mini), - [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4) and - all GPT-3.5 Turbo models newer than `gpt-3.5-turbo-1106`. - Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured Outputs which ensures the model will match your supplied JSON schema. Learn more in the @@ -237,9 +242,8 @@ class CompletionCreateParamsBase(TypedDict, total=False): """What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like - 0.2 will make it more focused and deterministic. - - We generally recommend altering this or `top_p` but not both. + 0.2 will make it more focused and deterministic. We generally recommend altering + this or `top_p` but not both. """ tool_choice: ChatCompletionToolChoiceOptionParam diff --git a/src/openai/types/chat_model.py b/src/openai/types/chat_model.py index 3567a3ba65..e1ac464320 100644 --- a/src/openai/types/chat_model.py +++ b/src/openai/types/chat_model.py @@ -5,6 +5,8 @@ __all__ = ["ChatModel"] ChatModel: TypeAlias = Literal[ + "o1", + "o1-2024-12-17", "o1-preview", "o1-preview-2024-09-12", "o1-mini", @@ -13,10 +15,11 @@ "gpt-4o-2024-11-20", "gpt-4o-2024-08-06", "gpt-4o-2024-05-13", - "gpt-4o-realtime-preview", - "gpt-4o-realtime-preview-2024-10-01", "gpt-4o-audio-preview", "gpt-4o-audio-preview-2024-10-01", + "gpt-4o-audio-preview-2024-12-17", + "gpt-4o-mini-audio-preview", + "gpt-4o-mini-audio-preview-2024-12-17", "chatgpt-4o-latest", "gpt-4o-mini", "gpt-4o-mini-2024-07-18", diff --git a/src/openai/types/fine_tuning/fine_tuning_job.py b/src/openai/types/fine_tuning/fine_tuning_job.py index 7ac8792787..f5a11c2107 100644 --- a/src/openai/types/fine_tuning/fine_tuning_job.py +++ b/src/openai/types/fine_tuning/fine_tuning_job.py @@ -6,7 +6,16 @@ from ..._models import BaseModel from .fine_tuning_job_wandb_integration_object import FineTuningJobWandbIntegrationObject -__all__ = ["FineTuningJob", "Error", "Hyperparameters"] +__all__ = [ + "FineTuningJob", + "Error", + "Hyperparameters", + "Method", + "MethodDpo", + "MethodDpoHyperparameters", + "MethodSupervised", + "MethodSupervisedHyperparameters", +] class Error(BaseModel): @@ -24,15 +33,96 @@ class Error(BaseModel): class Hyperparameters(BaseModel): - n_epochs: Union[Literal["auto"], int] + batch_size: Union[Literal["auto"], int, None] = None + """Number of examples in each batch. + + A larger batch size means that model parameters are updated less frequently, but + with lower variance. + """ + + learning_rate_multiplier: Union[Literal["auto"], float, None] = None + """Scaling factor for the learning rate. + + A smaller learning rate may be useful to avoid overfitting. + """ + + n_epochs: Union[Literal["auto"], int, None] = None + """The number of epochs to train the model for. + + An epoch refers to one full cycle through the training dataset. + """ + + +class MethodDpoHyperparameters(BaseModel): + batch_size: Union[Literal["auto"], int, None] = None + """Number of examples in each batch. + + A larger batch size means that model parameters are updated less frequently, but + with lower variance. + """ + + beta: Union[Literal["auto"], float, None] = None + """The beta value for the DPO method. + + A higher beta value will increase the weight of the penalty between the policy + and reference model. + """ + + learning_rate_multiplier: Union[Literal["auto"], float, None] = None + """Scaling factor for the learning rate. + + A smaller learning rate may be useful to avoid overfitting. + """ + + n_epochs: Union[Literal["auto"], int, None] = None """The number of epochs to train the model for. - An epoch refers to one full cycle through the training dataset. "auto" decides - the optimal number of epochs based on the size of the dataset. If setting the - number manually, we support any number between 1 and 50 epochs. + An epoch refers to one full cycle through the training dataset. """ +class MethodDpo(BaseModel): + hyperparameters: Optional[MethodDpoHyperparameters] = None + """The hyperparameters used for the fine-tuning job.""" + + +class MethodSupervisedHyperparameters(BaseModel): + batch_size: Union[Literal["auto"], int, None] = None + """Number of examples in each batch. + + A larger batch size means that model parameters are updated less frequently, but + with lower variance. + """ + + learning_rate_multiplier: Union[Literal["auto"], float, None] = None + """Scaling factor for the learning rate. + + A smaller learning rate may be useful to avoid overfitting. + """ + + n_epochs: Union[Literal["auto"], int, None] = None + """The number of epochs to train the model for. + + An epoch refers to one full cycle through the training dataset. + """ + + +class MethodSupervised(BaseModel): + hyperparameters: Optional[MethodSupervisedHyperparameters] = None + """The hyperparameters used for the fine-tuning job.""" + + +class Method(BaseModel): + dpo: Optional[MethodDpo] = None + """Configuration for the DPO fine-tuning method.""" + + supervised: Optional[MethodSupervised] = None + """Configuration for the supervised fine-tuning method.""" + + type: Optional[Literal["supervised", "dpo"]] = None + """The type of method. Is either `supervised` or `dpo`.""" + + class FineTuningJob(BaseModel): id: str """The object identifier, which can be referenced in the API endpoints.""" @@ -61,8 +151,7 @@ class FineTuningJob(BaseModel): hyperparameters: Hyperparameters """The hyperparameters used for the fine-tuning job. - See the [fine-tuning guide](https://platform.openai.com/docs/guides/fine-tuning) - for more details. + This value will only be returned when running `supervised` jobs. """ model: str @@ -118,3 +207,6 @@ class FineTuningJob(BaseModel): integrations: Optional[List[FineTuningJobWandbIntegrationObject]] = None """A list of integrations to enable for this fine-tuning job.""" + + method: Optional[Method] = None + """The method used for fine-tuning.""" diff --git a/src/openai/types/fine_tuning/fine_tuning_job_event.py b/src/openai/types/fine_tuning/fine_tuning_job_event.py index 2d204bb980..1d728bd765 100644 --- a/src/openai/types/fine_tuning/fine_tuning_job_event.py +++ b/src/openai/types/fine_tuning/fine_tuning_job_event.py @@ -1,5 +1,7 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +import builtins +from typing import Optional from typing_extensions import Literal from ..._models import BaseModel @@ -9,11 +11,22 @@ class FineTuningJobEvent(BaseModel): id: str + """The object identifier.""" created_at: int + """The Unix timestamp (in seconds) for when the fine-tuning job was created.""" level: Literal["info", "warn", "error"] + """The log level of the event.""" message: str + """The message of the event.""" object: Literal["fine_tuning.job.event"] + """The object type, which is always "fine_tuning.job.event".""" + + data: Optional[builtins.object] = None + """The data associated with the event.""" + + type: Optional[Literal["message", "metrics"]] = None + """The type of event.""" diff --git a/src/openai/types/fine_tuning/job_create_params.py b/src/openai/types/fine_tuning/job_create_params.py index 8814229b2e..09c3f8571c 100644 --- a/src/openai/types/fine_tuning/job_create_params.py +++ b/src/openai/types/fine_tuning/job_create_params.py @@ -5,7 +5,17 @@ from typing import List, Union, Iterable, Optional from typing_extensions import Literal, Required, TypedDict -__all__ = ["JobCreateParams", "Hyperparameters", "Integration", "IntegrationWandb"] +__all__ = [ + "JobCreateParams", + "Hyperparameters", + "Integration", + "IntegrationWandb", + "Method", + "MethodDpo", + "MethodDpoHyperparameters", + "MethodSupervised", + "MethodSupervisedHyperparameters", +] class JobCreateParams(TypedDict, total=False): @@ -26,8 +36,10 @@ class JobCreateParams(TypedDict, total=False): your file with the purpose `fine-tune`. The contents of the file should differ depending on if the model uses the - [chat](https://platform.openai.com/docs/api-reference/fine-tuning/chat-input) or + [chat](https://platform.openai.com/docs/api-reference/fine-tuning/chat-input), [completions](https://platform.openai.com/docs/api-reference/fine-tuning/completions-input) + format, or if the fine-tuning method uses the + [preference](https://platform.openai.com/docs/api-reference/fine-tuning/preference-input) format. See the [fine-tuning guide](https://platform.openai.com/docs/guides/fine-tuning) @@ -35,11 +47,17 @@ class JobCreateParams(TypedDict, total=False): """ hyperparameters: Hyperparameters - """The hyperparameters used for the fine-tuning job.""" + """ + The hyperparameters used for the fine-tuning job. This value is now deprecated + in favor of `method`, and should be passed in under the `method` parameter. + """ integrations: Optional[Iterable[Integration]] """A list of integrations to enable for your fine-tuning job.""" + method: Method + """The method used for fine-tuning.""" + seed: Optional[int] """The seed controls the reproducibility of the job. @@ -134,3 +152,73 @@ class Integration(TypedDict, total=False): can set an explicit display name for your run, add tags to your run, and set a default entity (team, username, etc) to be associated with your run. """ + + +class MethodDpoHyperparameters(TypedDict, total=False): + batch_size: Union[Literal["auto"], int] + """Number of examples in each batch. + + A larger batch size means that model parameters are updated less frequently, but + with lower variance. + """ + + beta: Union[Literal["auto"], float] + """The beta value for the DPO method. + + A higher beta value will increase the weight of the penalty between the policy + and reference model. + """ + + learning_rate_multiplier: Union[Literal["auto"], float] + """Scaling factor for the learning rate. + + A smaller learning rate may be useful to avoid overfitting. + """ + + n_epochs: Union[Literal["auto"], int] + """The number of epochs to train the model for. + + An epoch refers to one full cycle through the training dataset. + """ + + +class MethodDpo(TypedDict, total=False): + hyperparameters: MethodDpoHyperparameters + """The hyperparameters used for the fine-tuning job.""" + + +class MethodSupervisedHyperparameters(TypedDict, total=False): + batch_size: Union[Literal["auto"], int] + """Number of examples in each batch. + + A larger batch size means that model parameters are updated less frequently, but + with lower variance. + """ + + learning_rate_multiplier: Union[Literal["auto"], float] + """Scaling factor for the learning rate. + + A smaller learning rate may be useful to avoid overfitting. + """ + + n_epochs: Union[Literal["auto"], int] + """The number of epochs to train the model for. + + An epoch refers to one full cycle through the training dataset. + """ + + +class MethodSupervised(TypedDict, total=False): + hyperparameters: MethodSupervisedHyperparameters + """The hyperparameters used for the fine-tuning job.""" + + +class Method(TypedDict, total=False): + dpo: MethodDpo + """Configuration for the DPO fine-tuning method.""" + + supervised: MethodSupervised + """Configuration for the supervised fine-tuning method.""" + + type: Literal["supervised", "dpo"] + """The type of method. Is either `supervised` or `dpo`.""" diff --git a/tests/api_resources/beta/realtime/__init__.py b/tests/api_resources/beta/realtime/__init__.py new file mode 100644 index 0000000000..fd8019a9a1 --- /dev/null +++ b/tests/api_resources/beta/realtime/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/beta/realtime/test_sessions.py b/tests/api_resources/beta/realtime/test_sessions.py new file mode 100644 index 0000000000..65bfa27572 --- /dev/null +++ b/tests/api_resources/beta/realtime/test_sessions.py @@ -0,0 +1,146 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.types.beta.realtime import SessionCreateResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestSessions: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: OpenAI) -> None: + session = client.beta.realtime.sessions.create( + model="gpt-4o-realtime-preview", + ) + assert_matches_type(SessionCreateResponse, session, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: OpenAI) -> None: + session = client.beta.realtime.sessions.create( + model="gpt-4o-realtime-preview", + input_audio_format="pcm16", + input_audio_transcription={"model": "model"}, + instructions="instructions", + max_response_output_tokens=0, + modalities=["text"], + output_audio_format="pcm16", + temperature=0, + tool_choice="tool_choice", + tools=[ + { + "description": "description", + "name": "name", + "parameters": {}, + "type": "function", + } + ], + turn_detection={ + "create_response": True, + "prefix_padding_ms": 0, + "silence_duration_ms": 0, + "threshold": 0, + "type": "type", + }, + voice="alloy", + ) + assert_matches_type(SessionCreateResponse, session, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: OpenAI) -> None: + response = client.beta.realtime.sessions.with_raw_response.create( + model="gpt-4o-realtime-preview", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + session = response.parse() + assert_matches_type(SessionCreateResponse, session, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: OpenAI) -> None: + with client.beta.realtime.sessions.with_streaming_response.create( + model="gpt-4o-realtime-preview", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + session = response.parse() + assert_matches_type(SessionCreateResponse, session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncSessions: + parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + async def test_method_create(self, async_client: AsyncOpenAI) -> None: + session = await async_client.beta.realtime.sessions.create( + model="gpt-4o-realtime-preview", + ) + assert_matches_type(SessionCreateResponse, session, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: + session = await async_client.beta.realtime.sessions.create( + model="gpt-4o-realtime-preview", + input_audio_format="pcm16", + input_audio_transcription={"model": "model"}, + instructions="instructions", + max_response_output_tokens=0, + modalities=["text"], + output_audio_format="pcm16", + temperature=0, + tool_choice="tool_choice", + tools=[ + { + "description": "description", + "name": "name", + "parameters": {}, + "type": "function", + } + ], + turn_detection={ + "create_response": True, + "prefix_padding_ms": 0, + "silence_duration_ms": 0, + "threshold": 0, + "type": "type", + }, + voice="alloy", + ) + assert_matches_type(SessionCreateResponse, session, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: + response = await async_client.beta.realtime.sessions.with_raw_response.create( + model="gpt-4o-realtime-preview", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + session = response.parse() + assert_matches_type(SessionCreateResponse, session, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: + async with async_client.beta.realtime.sessions.with_streaming_response.create( + model="gpt-4o-realtime-preview", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + session = await response.parse() + assert_matches_type(SessionCreateResponse, session, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/chat/test_completions.py b/tests/api_resources/chat/test_completions.py index 1b52650b1d..393a790549 100644 --- a/tests/api_resources/chat/test_completions.py +++ b/tests/api_resources/chat/test_completions.py @@ -26,7 +26,7 @@ def test_method_create_overload_1(self, client: OpenAI) -> None: messages=[ { "content": "string", - "role": "system", + "role": "developer", } ], model="gpt-4o", @@ -39,8 +39,8 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: messages=[ { "content": "string", - "role": "system", - "name": "string", + "role": "developer", + "name": "name", } ], model="gpt-4o", @@ -70,6 +70,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: "type": "content", }, presence_penalty=-2, + reasoning_effort="low", response_format={"type": "text"}, seed=-9007199254740991, service_tier="auto", @@ -102,7 +103,7 @@ def test_raw_response_create_overload_1(self, client: OpenAI) -> None: messages=[ { "content": "string", - "role": "system", + "role": "developer", } ], model="gpt-4o", @@ -119,7 +120,7 @@ def test_streaming_response_create_overload_1(self, client: OpenAI) -> None: messages=[ { "content": "string", - "role": "system", + "role": "developer", } ], model="gpt-4o", @@ -138,7 +139,7 @@ def test_method_create_overload_2(self, client: OpenAI) -> None: messages=[ { "content": "string", - "role": "system", + "role": "developer", } ], model="gpt-4o", @@ -152,8 +153,8 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: messages=[ { "content": "string", - "role": "system", - "name": "string", + "role": "developer", + "name": "name", } ], model="gpt-4o", @@ -184,6 +185,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: "type": "content", }, presence_penalty=-2, + reasoning_effort="low", response_format={"type": "text"}, seed=-9007199254740991, service_tier="auto", @@ -215,7 +217,7 @@ def test_raw_response_create_overload_2(self, client: OpenAI) -> None: messages=[ { "content": "string", - "role": "system", + "role": "developer", } ], model="gpt-4o", @@ -232,7 +234,7 @@ def test_streaming_response_create_overload_2(self, client: OpenAI) -> None: messages=[ { "content": "string", - "role": "system", + "role": "developer", } ], model="gpt-4o", @@ -273,7 +275,7 @@ async def test_method_create_overload_1(self, async_client: AsyncOpenAI) -> None messages=[ { "content": "string", - "role": "system", + "role": "developer", } ], model="gpt-4o", @@ -286,8 +288,8 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn messages=[ { "content": "string", - "role": "system", - "name": "string", + "role": "developer", + "name": "name", } ], model="gpt-4o", @@ -317,6 +319,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn "type": "content", }, presence_penalty=-2, + reasoning_effort="low", response_format={"type": "text"}, seed=-9007199254740991, service_tier="auto", @@ -349,7 +352,7 @@ async def test_raw_response_create_overload_1(self, async_client: AsyncOpenAI) - messages=[ { "content": "string", - "role": "system", + "role": "developer", } ], model="gpt-4o", @@ -366,7 +369,7 @@ async def test_streaming_response_create_overload_1(self, async_client: AsyncOpe messages=[ { "content": "string", - "role": "system", + "role": "developer", } ], model="gpt-4o", @@ -385,7 +388,7 @@ async def test_method_create_overload_2(self, async_client: AsyncOpenAI) -> None messages=[ { "content": "string", - "role": "system", + "role": "developer", } ], model="gpt-4o", @@ -399,8 +402,8 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn messages=[ { "content": "string", - "role": "system", - "name": "string", + "role": "developer", + "name": "name", } ], model="gpt-4o", @@ -431,6 +434,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn "type": "content", }, presence_penalty=-2, + reasoning_effort="low", response_format={"type": "text"}, seed=-9007199254740991, service_tier="auto", @@ -462,7 +466,7 @@ async def test_raw_response_create_overload_2(self, async_client: AsyncOpenAI) - messages=[ { "content": "string", - "role": "system", + "role": "developer", } ], model="gpt-4o", @@ -479,7 +483,7 @@ async def test_streaming_response_create_overload_2(self, async_client: AsyncOpe messages=[ { "content": "string", - "role": "system", + "role": "developer", } ], model="gpt-4o", diff --git a/tests/api_resources/fine_tuning/test_jobs.py b/tests/api_resources/fine_tuning/test_jobs.py index aa2bf39528..1e421c30c0 100644 --- a/tests/api_resources/fine_tuning/test_jobs.py +++ b/tests/api_resources/fine_tuning/test_jobs.py @@ -50,6 +50,24 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: }, } ], + method={ + "dpo": { + "hyperparameters": { + "batch_size": "auto", + "beta": "auto", + "learning_rate_multiplier": "auto", + "n_epochs": "auto", + } + }, + "supervised": { + "hyperparameters": { + "batch_size": "auto", + "learning_rate_multiplier": "auto", + "n_epochs": "auto", + } + }, + "type": "supervised", + }, seed=42, suffix="x", validation_file="file-abc123", @@ -271,6 +289,24 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> }, } ], + method={ + "dpo": { + "hyperparameters": { + "batch_size": "auto", + "beta": "auto", + "learning_rate_multiplier": "auto", + "n_epochs": "auto", + } + }, + "supervised": { + "hyperparameters": { + "batch_size": "auto", + "learning_rate_multiplier": "auto", + "n_epochs": "auto", + } + }, + "type": "supervised", + }, seed=42, suffix="x", validation_file="file-abc123", diff --git a/tests/test_client.py b/tests/test_client.py index 7751e7d463..e0d23403b1 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -795,7 +795,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: messages=[ { "content": "string", - "role": "system", + "role": "developer", } ], model="gpt-4o", @@ -827,7 +827,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: messages=[ { "content": "string", - "role": "system", + "role": "developer", } ], model="gpt-4o", @@ -859,7 +859,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: messages=[ { "content": "string", - "role": "system", + "role": "developer", } ], model="gpt-4o", @@ -891,7 +891,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: messages=[ { "content": "string", - "role": "system", + "role": "developer", } ], model="gpt-4o", @@ -1663,7 +1663,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: messages=[ { "content": "string", - "role": "system", + "role": "developer", } ], model="gpt-4o", @@ -1696,7 +1696,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: messages=[ { "content": "string", - "role": "system", + "role": "developer", } ], model="gpt-4o", @@ -1729,7 +1729,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: messages=[ { "content": "string", - "role": "system", + "role": "developer", } ], model="gpt-4o", @@ -1762,7 +1762,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: messages=[ { "content": "string", - "role": "system", + "role": "developer", } ], model="gpt-4o", From 5fdba4864b5a9dc00f50a939fcf40b992a550db9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Dec 2024 18:09:06 +0000 Subject: [PATCH 125/769] feat: add Realtime API support (#1958) More information on the Realtime API can be found here: https://platform.openai.com/docs/guides/realtime --- .stats.yml | 2 +- api.md | 51 ++ pyproject.toml | 7 +- requirements-dev.lock | 2 + requirements.lock | 2 + src/openai/_client.py | 26 + src/openai/lib/azure.py | 14 + .../resources/beta/realtime/realtime.py | 852 ++++++++++++++++++ src/openai/types/__init__.py | 1 + src/openai/types/beta/realtime/__init__.py | 74 ++ .../realtime/conversation_created_event.py | 27 + .../types/beta/realtime/conversation_item.py | 61 ++ .../realtime/conversation_item_content.py | 28 + .../conversation_item_content_param.py | 27 + .../conversation_item_create_event.py | 28 + .../conversation_item_create_event_param.py | 28 + .../conversation_item_created_event.py | 25 + .../conversation_item_delete_event.py | 19 + .../conversation_item_delete_event_param.py | 18 + .../conversation_item_deleted_event.py | 18 + ...put_audio_transcription_completed_event.py | 26 + ..._input_audio_transcription_failed_event.py | 39 + .../beta/realtime/conversation_item_param.py | 62 ++ .../conversation_item_truncate_event.py | 32 + .../conversation_item_truncate_event_param.py | 31 + .../conversation_item_truncated_event.py | 24 + src/openai/types/beta/realtime/error_event.py | 36 + .../input_audio_buffer_append_event.py | 23 + .../input_audio_buffer_append_event_param.py | 22 + .../input_audio_buffer_clear_event.py | 16 + .../input_audio_buffer_clear_event_param.py | 15 + .../input_audio_buffer_cleared_event.py | 15 + .../input_audio_buffer_commit_event.py | 16 + .../input_audio_buffer_commit_event_param.py | 15 + .../input_audio_buffer_committed_event.py | 21 + ...input_audio_buffer_speech_started_event.py | 26 + ...input_audio_buffer_speech_stopped_event.py | 25 + .../realtime/rate_limits_updated_event.py | 33 + .../beta/realtime/realtime_client_event.py | 32 + .../realtime/realtime_client_event_param.py | 30 + .../beta/realtime/realtime_connect_params.py | 11 + .../types/beta/realtime/realtime_response.py | 42 + .../beta/realtime/realtime_response_status.py | 39 + .../beta/realtime/realtime_response_usage.py | 52 ++ .../beta/realtime/realtime_server_event.py | 72 ++ .../realtime/response_audio_delta_event.py | 30 + .../realtime/response_audio_done_event.py | 27 + .../response_audio_transcript_delta_event.py | 30 + .../response_audio_transcript_done_event.py | 30 + .../beta/realtime/response_cancel_event.py | 22 + .../realtime/response_cancel_event_param.py | 21 + .../response_content_part_added_event.py | 45 + .../response_content_part_done_event.py | 45 + .../beta/realtime/response_create_event.py | 115 +++ .../realtime/response_create_event_param.py | 116 +++ .../beta/realtime/response_created_event.py | 19 + .../beta/realtime/response_done_event.py | 19 + ...nse_function_call_arguments_delta_event.py | 30 + ...onse_function_call_arguments_done_event.py | 30 + .../response_output_item_added_event.py | 25 + .../response_output_item_done_event.py | 25 + .../realtime/response_text_delta_event.py | 30 + .../beta/realtime/response_text_done_event.py | 30 + src/openai/types/beta/realtime/session.py | 148 +++ .../beta/realtime/session_created_event.py | 19 + .../beta/realtime/session_update_event.py | 158 ++++ .../realtime/session_update_event_param.py | 166 ++++ .../beta/realtime/session_updated_event.py | 19 + .../types/websocket_connection_options.py | 36 + tests/api_resources/beta/test_realtime.py | 17 + 70 files changed, 3313 insertions(+), 4 deletions(-) create mode 100644 src/openai/types/beta/realtime/conversation_created_event.py create mode 100644 src/openai/types/beta/realtime/conversation_item.py create mode 100644 src/openai/types/beta/realtime/conversation_item_content.py create mode 100644 src/openai/types/beta/realtime/conversation_item_content_param.py create mode 100644 src/openai/types/beta/realtime/conversation_item_create_event.py create mode 100644 src/openai/types/beta/realtime/conversation_item_create_event_param.py create mode 100644 src/openai/types/beta/realtime/conversation_item_created_event.py create mode 100644 src/openai/types/beta/realtime/conversation_item_delete_event.py create mode 100644 src/openai/types/beta/realtime/conversation_item_delete_event_param.py create mode 100644 src/openai/types/beta/realtime/conversation_item_deleted_event.py create mode 100644 src/openai/types/beta/realtime/conversation_item_input_audio_transcription_completed_event.py create mode 100644 src/openai/types/beta/realtime/conversation_item_input_audio_transcription_failed_event.py create mode 100644 src/openai/types/beta/realtime/conversation_item_param.py create mode 100644 src/openai/types/beta/realtime/conversation_item_truncate_event.py create mode 100644 src/openai/types/beta/realtime/conversation_item_truncate_event_param.py create mode 100644 src/openai/types/beta/realtime/conversation_item_truncated_event.py create mode 100644 src/openai/types/beta/realtime/error_event.py create mode 100644 src/openai/types/beta/realtime/input_audio_buffer_append_event.py create mode 100644 src/openai/types/beta/realtime/input_audio_buffer_append_event_param.py create mode 100644 src/openai/types/beta/realtime/input_audio_buffer_clear_event.py create mode 100644 src/openai/types/beta/realtime/input_audio_buffer_clear_event_param.py create mode 100644 src/openai/types/beta/realtime/input_audio_buffer_cleared_event.py create mode 100644 src/openai/types/beta/realtime/input_audio_buffer_commit_event.py create mode 100644 src/openai/types/beta/realtime/input_audio_buffer_commit_event_param.py create mode 100644 src/openai/types/beta/realtime/input_audio_buffer_committed_event.py create mode 100644 src/openai/types/beta/realtime/input_audio_buffer_speech_started_event.py create mode 100644 src/openai/types/beta/realtime/input_audio_buffer_speech_stopped_event.py create mode 100644 src/openai/types/beta/realtime/rate_limits_updated_event.py create mode 100644 src/openai/types/beta/realtime/realtime_client_event.py create mode 100644 src/openai/types/beta/realtime/realtime_client_event_param.py create mode 100644 src/openai/types/beta/realtime/realtime_connect_params.py create mode 100644 src/openai/types/beta/realtime/realtime_response.py create mode 100644 src/openai/types/beta/realtime/realtime_response_status.py create mode 100644 src/openai/types/beta/realtime/realtime_response_usage.py create mode 100644 src/openai/types/beta/realtime/realtime_server_event.py create mode 100644 src/openai/types/beta/realtime/response_audio_delta_event.py create mode 100644 src/openai/types/beta/realtime/response_audio_done_event.py create mode 100644 src/openai/types/beta/realtime/response_audio_transcript_delta_event.py create mode 100644 src/openai/types/beta/realtime/response_audio_transcript_done_event.py create mode 100644 src/openai/types/beta/realtime/response_cancel_event.py create mode 100644 src/openai/types/beta/realtime/response_cancel_event_param.py create mode 100644 src/openai/types/beta/realtime/response_content_part_added_event.py create mode 100644 src/openai/types/beta/realtime/response_content_part_done_event.py create mode 100644 src/openai/types/beta/realtime/response_create_event.py create mode 100644 src/openai/types/beta/realtime/response_create_event_param.py create mode 100644 src/openai/types/beta/realtime/response_created_event.py create mode 100644 src/openai/types/beta/realtime/response_done_event.py create mode 100644 src/openai/types/beta/realtime/response_function_call_arguments_delta_event.py create mode 100644 src/openai/types/beta/realtime/response_function_call_arguments_done_event.py create mode 100644 src/openai/types/beta/realtime/response_output_item_added_event.py create mode 100644 src/openai/types/beta/realtime/response_output_item_done_event.py create mode 100644 src/openai/types/beta/realtime/response_text_delta_event.py create mode 100644 src/openai/types/beta/realtime/response_text_done_event.py create mode 100644 src/openai/types/beta/realtime/session.py create mode 100644 src/openai/types/beta/realtime/session_created_event.py create mode 100644 src/openai/types/beta/realtime/session_update_event.py create mode 100644 src/openai/types/beta/realtime/session_update_event_param.py create mode 100644 src/openai/types/beta/realtime/session_updated_event.py create mode 100644 src/openai/types/websocket_connection_options.py create mode 100644 tests/api_resources/beta/test_realtime.py diff --git a/.stats.yml b/.stats.yml index e3a0040a5a..12219ccaa1 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-779ea2754025daf5e18eb8ceb203ec321692636bc3a999338556a479178efa6c.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-0d64ca9e45f51b4279f87b205eeb3a3576df98407698ce053f2e2302c1c08df1.yml diff --git a/api.md b/api.md index 91b2a9c2fd..ace93e0559 100644 --- a/api.md +++ b/api.md @@ -239,6 +239,57 @@ Methods: ## Realtime +Types: + +```python +from openai.types.beta.realtime import ( + ConversationCreatedEvent, + ConversationItem, + ConversationItemContent, + ConversationItemCreateEvent, + ConversationItemCreatedEvent, + ConversationItemDeleteEvent, + ConversationItemDeletedEvent, + ConversationItemInputAudioTranscriptionCompletedEvent, + ConversationItemInputAudioTranscriptionFailedEvent, + ConversationItemTruncateEvent, + ConversationItemTruncatedEvent, + ErrorEvent, + InputAudioBufferAppendEvent, + InputAudioBufferClearEvent, + InputAudioBufferClearedEvent, + InputAudioBufferCommitEvent, + InputAudioBufferCommittedEvent, + InputAudioBufferSpeechStartedEvent, + InputAudioBufferSpeechStoppedEvent, + RateLimitsUpdatedEvent, + RealtimeClientEvent, + RealtimeResponse, + RealtimeResponseStatus, + RealtimeResponseUsage, + RealtimeServerEvent, + ResponseAudioDeltaEvent, + ResponseAudioDoneEvent, + ResponseAudioTranscriptDeltaEvent, + ResponseAudioTranscriptDoneEvent, + ResponseCancelEvent, + ResponseContentPartAddedEvent, + ResponseContentPartDoneEvent, + ResponseCreateEvent, + ResponseCreatedEvent, + ResponseDoneEvent, + ResponseFunctionCallArgumentsDeltaEvent, + ResponseFunctionCallArgumentsDoneEvent, + ResponseOutputItemAddedEvent, + ResponseOutputItemDoneEvent, + ResponseTextDeltaEvent, + ResponseTextDoneEvent, + SessionCreatedEvent, + SessionUpdateEvent, + SessionUpdatedEvent, +) +``` + ### Sessions Types: diff --git a/pyproject.toml b/pyproject.toml index e03d4e798f..f83aff6fee 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,9 +35,6 @@ classifiers = [ "License :: OSI Approved :: Apache Software License" ] -[project.optional-dependencies] -datalib = ["numpy >= 1", "pandas >= 1.2.3", "pandas-stubs >= 1.1.0.11"] - [project.urls] Homepage = "https://github.com/openai/openai-python" Repository = "https://github.com/openai/openai-python" @@ -45,6 +42,10 @@ Repository = "https://github.com/openai/openai-python" [project.scripts] openai = "openai.cli:main" +[project.optional-dependencies] +realtime = ["websockets >= 13, < 15"] +datalib = ["numpy >= 1", "pandas >= 1.2.3", "pandas-stubs >= 1.1.0.11"] + [tool.rye] managed = true # version pins are in requirements-dev.lock diff --git a/requirements-dev.lock b/requirements-dev.lock index 2cf6ab5ea9..94cf6aca07 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -185,5 +185,7 @@ urllib3==2.2.1 # via requests virtualenv==20.24.5 # via nox +websockets==14.1 + # via openai zipp==3.17.0 # via importlib-metadata diff --git a/requirements.lock b/requirements.lock index 826f0bc927..c10449ac20 100644 --- a/requirements.lock +++ b/requirements.lock @@ -64,3 +64,5 @@ typing-extensions==4.12.2 # via pydantic-core tzdata==2024.1 # via pandas +websockets==14.1 + # via openai diff --git a/src/openai/_client.py b/src/openai/_client.py index 5419e88f06..c784694f20 100644 --- a/src/openai/_client.py +++ b/src/openai/_client.py @@ -63,6 +63,14 @@ class OpenAI(SyncAPIClient): organization: str | None project: str | None + websocket_base_url: str | httpx.URL | None + """Base URL for WebSocket connections. + + If not specified, the default base URL will be used, with 'wss://' replacing the + 'http://' or 'https://' scheme. For example: 'http://example.com' becomes + 'wss://example.com' + """ + def __init__( self, *, @@ -70,6 +78,7 @@ def __init__( organization: str | None = None, project: str | None = None, base_url: str | httpx.URL | None = None, + websocket_base_url: str | httpx.URL | None = None, timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN, max_retries: int = DEFAULT_MAX_RETRIES, default_headers: Mapping[str, str] | None = None, @@ -111,6 +120,8 @@ def __init__( project = os.environ.get("OPENAI_PROJECT_ID") self.project = project + self.websocket_base_url = websocket_base_url + if base_url is None: base_url = os.environ.get("OPENAI_BASE_URL") if base_url is None: @@ -172,6 +183,7 @@ def copy( api_key: str | None = None, organization: str | None = None, project: str | None = None, + websocket_base_url: str | httpx.URL | None = None, base_url: str | httpx.URL | None = None, timeout: float | Timeout | None | NotGiven = NOT_GIVEN, http_client: httpx.Client | None = None, @@ -208,6 +220,7 @@ def copy( api_key=api_key or self.api_key, organization=organization or self.organization, project=project or self.project, + websocket_base_url=websocket_base_url or self.websocket_base_url, base_url=base_url or self.base_url, timeout=self.timeout if isinstance(timeout, NotGiven) else timeout, http_client=http_client, @@ -277,6 +290,14 @@ class AsyncOpenAI(AsyncAPIClient): organization: str | None project: str | None + websocket_base_url: str | httpx.URL | None + """Base URL for WebSocket connections. + + If not specified, the default base URL will be used, with 'wss://' replacing the + 'http://' or 'https://' scheme. For example: 'http://example.com' becomes + 'wss://example.com' + """ + def __init__( self, *, @@ -284,6 +305,7 @@ def __init__( organization: str | None = None, project: str | None = None, base_url: str | httpx.URL | None = None, + websocket_base_url: str | httpx.URL | None = None, timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN, max_retries: int = DEFAULT_MAX_RETRIES, default_headers: Mapping[str, str] | None = None, @@ -325,6 +347,8 @@ def __init__( project = os.environ.get("OPENAI_PROJECT_ID") self.project = project + self.websocket_base_url = websocket_base_url + if base_url is None: base_url = os.environ.get("OPENAI_BASE_URL") if base_url is None: @@ -386,6 +410,7 @@ def copy( api_key: str | None = None, organization: str | None = None, project: str | None = None, + websocket_base_url: str | httpx.URL | None = None, base_url: str | httpx.URL | None = None, timeout: float | Timeout | None | NotGiven = NOT_GIVEN, http_client: httpx.AsyncClient | None = None, @@ -422,6 +447,7 @@ def copy( api_key=api_key or self.api_key, organization=organization or self.organization, project=project or self.project, + websocket_base_url=websocket_base_url or self.websocket_base_url, base_url=base_url or self.base_url, timeout=self.timeout if isinstance(timeout, NotGiven) else timeout, http_client=http_client, diff --git a/src/openai/lib/azure.py b/src/openai/lib/azure.py index 54122dbecb..13d9f31838 100644 --- a/src/openai/lib/azure.py +++ b/src/openai/lib/azure.py @@ -76,6 +76,7 @@ def __init__( azure_ad_token: str | None = None, azure_ad_token_provider: AzureADTokenProvider | None = None, organization: str | None = None, + websocket_base_url: str | httpx.URL | None = None, timeout: float | Timeout | None | NotGiven = NOT_GIVEN, max_retries: int = DEFAULT_MAX_RETRIES, default_headers: Mapping[str, str] | None = None, @@ -94,6 +95,7 @@ def __init__( azure_ad_token: str | None = None, azure_ad_token_provider: AzureADTokenProvider | None = None, organization: str | None = None, + websocket_base_url: str | httpx.URL | None = None, timeout: float | Timeout | None | NotGiven = NOT_GIVEN, max_retries: int = DEFAULT_MAX_RETRIES, default_headers: Mapping[str, str] | None = None, @@ -112,6 +114,7 @@ def __init__( azure_ad_token: str | None = None, azure_ad_token_provider: AzureADTokenProvider | None = None, organization: str | None = None, + websocket_base_url: str | httpx.URL | None = None, timeout: float | Timeout | None | NotGiven = NOT_GIVEN, max_retries: int = DEFAULT_MAX_RETRIES, default_headers: Mapping[str, str] | None = None, @@ -131,6 +134,7 @@ def __init__( azure_ad_token_provider: AzureADTokenProvider | None = None, organization: str | None = None, project: str | None = None, + websocket_base_url: str | httpx.URL | None = None, base_url: str | None = None, timeout: float | Timeout | None | NotGiven = NOT_GIVEN, max_retries: int = DEFAULT_MAX_RETRIES, @@ -214,6 +218,7 @@ def __init__( default_headers=default_headers, default_query=default_query, http_client=http_client, + websocket_base_url=websocket_base_url, _strict_response_validation=_strict_response_validation, ) self._api_version = api_version @@ -227,6 +232,7 @@ def copy( api_key: str | None = None, organization: str | None = None, project: str | None = None, + websocket_base_url: str | httpx.URL | None = None, api_version: str | None = None, azure_ad_token: str | None = None, azure_ad_token_provider: AzureADTokenProvider | None = None, @@ -247,6 +253,7 @@ def copy( api_key=api_key, organization=organization, project=project, + websocket_base_url=websocket_base_url, base_url=base_url, timeout=timeout, http_client=http_client, @@ -314,6 +321,7 @@ def __init__( azure_ad_token_provider: AsyncAzureADTokenProvider | None = None, organization: str | None = None, project: str | None = None, + websocket_base_url: str | httpx.URL | None = None, timeout: float | Timeout | None | NotGiven = NOT_GIVEN, max_retries: int = DEFAULT_MAX_RETRIES, default_headers: Mapping[str, str] | None = None, @@ -333,6 +341,7 @@ def __init__( azure_ad_token_provider: AsyncAzureADTokenProvider | None = None, organization: str | None = None, project: str | None = None, + websocket_base_url: str | httpx.URL | None = None, timeout: float | Timeout | None | NotGiven = NOT_GIVEN, max_retries: int = DEFAULT_MAX_RETRIES, default_headers: Mapping[str, str] | None = None, @@ -352,6 +361,7 @@ def __init__( azure_ad_token_provider: AsyncAzureADTokenProvider | None = None, organization: str | None = None, project: str | None = None, + websocket_base_url: str | httpx.URL | None = None, timeout: float | Timeout | None | NotGiven = NOT_GIVEN, max_retries: int = DEFAULT_MAX_RETRIES, default_headers: Mapping[str, str] | None = None, @@ -372,6 +382,7 @@ def __init__( organization: str | None = None, project: str | None = None, base_url: str | None = None, + websocket_base_url: str | httpx.URL | None = None, timeout: float | Timeout | None | NotGiven = NOT_GIVEN, max_retries: int = DEFAULT_MAX_RETRIES, default_headers: Mapping[str, str] | None = None, @@ -454,6 +465,7 @@ def __init__( default_headers=default_headers, default_query=default_query, http_client=http_client, + websocket_base_url=websocket_base_url, _strict_response_validation=_strict_response_validation, ) self._api_version = api_version @@ -467,6 +479,7 @@ def copy( api_key: str | None = None, organization: str | None = None, project: str | None = None, + websocket_base_url: str | httpx.URL | None = None, api_version: str | None = None, azure_ad_token: str | None = None, azure_ad_token_provider: AsyncAzureADTokenProvider | None = None, @@ -487,6 +500,7 @@ def copy( api_key=api_key, organization=organization, project=project, + websocket_base_url=websocket_base_url, base_url=base_url, timeout=timeout, http_client=http_client, diff --git a/src/openai/resources/beta/realtime/realtime.py b/src/openai/resources/beta/realtime/realtime.py index e57e0be503..c79fd46217 100644 --- a/src/openai/resources/beta/realtime/realtime.py +++ b/src/openai/resources/beta/realtime/realtime.py @@ -2,6 +2,15 @@ from __future__ import annotations +import json +import logging +from types import TracebackType +from typing import TYPE_CHECKING, Any, Iterator, cast +from typing_extensions import AsyncIterator + +import httpx +from pydantic import BaseModel + from .sessions import ( Sessions, AsyncSessions, @@ -10,11 +19,34 @@ SessionsWithStreamingResponse, AsyncSessionsWithStreamingResponse, ) +from ...._types import NOT_GIVEN, Query, Headers, NotGiven +from ...._utils import ( + maybe_transform, + strip_not_given, + async_maybe_transform, +) from ...._compat import cached_property +from ...._models import construct_type_unchecked from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._exceptions import OpenAIError +from ...._base_client import _merge_mappings +from ....types.beta.realtime import session_update_event_param, response_create_event_param +from ....types.websocket_connection_options import WebsocketConnectionOptions +from ....types.beta.realtime.realtime_client_event import RealtimeClientEvent +from ....types.beta.realtime.realtime_server_event import RealtimeServerEvent +from ....types.beta.realtime.conversation_item_param import ConversationItemParam +from ....types.beta.realtime.realtime_client_event_param import RealtimeClientEventParam + +if TYPE_CHECKING: + from websockets.sync.client import ClientConnection as WebsocketConnection + from websockets.asyncio.client import ClientConnection as AsyncWebsocketConnection + + from ...._client import OpenAI, AsyncOpenAI __all__ = ["Realtime", "AsyncRealtime"] +log: logging.Logger = logging.getLogger(__name__) + class Realtime(SyncAPIResource): @cached_property @@ -40,6 +72,33 @@ def with_streaming_response(self) -> RealtimeWithStreamingResponse: """ return RealtimeWithStreamingResponse(self) + def connect( + self, + *, + model: str, + extra_query: Query = {}, + extra_headers: Headers = {}, + websocket_connection_options: WebsocketConnectionOptions = {}, + ) -> RealtimeConnectionManager: + """ + The Realtime API enables you to build low-latency, multi-modal conversational experiences. It currently supports text and audio as both input and output, as well as function calling. + + Some notable benefits of the API include: + + - Native speech-to-speech: Skipping an intermediate text format means low latency and nuanced output. + - Natural, steerable voices: The models have natural inflection and can laugh, whisper, and adhere to tone direction. + - Simultaneous multimodal output: Text is useful for moderation; faster-than-realtime audio ensures stable playback. + + The Realtime API is a stateful, event-based API that communicates over a WebSocket. + """ + return RealtimeConnectionManager( + client=self._client, + extra_query=extra_query, + extra_headers=extra_headers, + websocket_connection_options=websocket_connection_options, + model=model, + ) + class AsyncRealtime(AsyncAPIResource): @cached_property @@ -65,6 +124,33 @@ def with_streaming_response(self) -> AsyncRealtimeWithStreamingResponse: """ return AsyncRealtimeWithStreamingResponse(self) + def connect( + self, + *, + model: str, + extra_query: Query = {}, + extra_headers: Headers = {}, + websocket_connection_options: WebsocketConnectionOptions = {}, + ) -> AsyncRealtimeConnectionManager: + """ + The Realtime API enables you to build low-latency, multi-modal conversational experiences. It currently supports text and audio as both input and output, as well as function calling. + + Some notable benefits of the API include: + + - Native speech-to-speech: Skipping an intermediate text format means low latency and nuanced output. + - Natural, steerable voices: The models have natural inflection and can laugh, whisper, and adhere to tone direction. + - Simultaneous multimodal output: Text is useful for moderation; faster-than-realtime audio ensures stable playback. + + The Realtime API is a stateful, event-based API that communicates over a WebSocket. + """ + return AsyncRealtimeConnectionManager( + client=self._client, + extra_query=extra_query, + extra_headers=extra_headers, + websocket_connection_options=websocket_connection_options, + model=model, + ) + class RealtimeWithRawResponse: def __init__(self, realtime: Realtime) -> None: @@ -100,3 +186,769 @@ def __init__(self, realtime: AsyncRealtime) -> None: @cached_property def sessions(self) -> AsyncSessionsWithStreamingResponse: return AsyncSessionsWithStreamingResponse(self._realtime.sessions) + + +class AsyncRealtimeConnection: + """Represents a live websocket connection to the Realtime API""" + + session: AsyncRealtimeSessionResource + response: AsyncRealtimeResponseResource + conversation: AsyncRealtimeConversationResource + input_audio_buffer: AsyncRealtimeInputAudioBufferResource + + _connection: AsyncWebsocketConnection + + def __init__(self, connection: AsyncWebsocketConnection) -> None: + self._connection = connection + + self.session = AsyncRealtimeSessionResource(self) + self.response = AsyncRealtimeResponseResource(self) + self.conversation = AsyncRealtimeConversationResource(self) + self.input_audio_buffer = AsyncRealtimeInputAudioBufferResource(self) + + async def __aiter__(self) -> AsyncIterator[RealtimeServerEvent]: + """ + An infinite-iterator that will continue to yield events until + the connection is closed. + """ + from websockets.exceptions import ConnectionClosedOK + + try: + while True: + yield await self.recv() + except ConnectionClosedOK: + return + + async def recv(self) -> RealtimeServerEvent: + """ + Receive the next message from the connection and parses it into a `RealtimeServerEvent` object. + + Canceling this method is safe. There's no risk of losing data. + """ + return self.parse_event(await self.recv_bytes()) + + async def recv_bytes(self) -> bytes: + """Receive the next message from the connection as raw bytes. + + Canceling this method is safe. There's no risk of losing data. + + If you want to parse the message into a `RealtimeServerEvent` object like `.recv()` does, + then you can call `.parse_event(data)`. + """ + message = await self._connection.recv(decode=False) + log.debug(f"Received websocket message: %s", message) + if not isinstance(message, bytes): + # passing `decode=False` should always result in us getting `bytes` back + raise TypeError(f"Expected `.recv(decode=False)` to return `bytes` but got {type(message)}") + + return message + + async def send(self, event: RealtimeClientEvent | RealtimeClientEventParam) -> None: + data = ( + event.to_json(use_api_names=True, exclude_defaults=True, exclude_unset=True) + if isinstance(event, BaseModel) + else json.dumps(await async_maybe_transform(event, RealtimeClientEventParam)) + ) + await self._connection.send(data) + + async def close(self, *, code: int = 1000, reason: str = "") -> None: + await self._connection.close(code=code, reason=reason) + + def parse_event(self, data: str | bytes) -> RealtimeServerEvent: + """ + Converts a raw `str` or `bytes` message into a `RealtimeServerEvent` object. + + This is helpful if you're using `.recv_bytes()`. + """ + return cast( + RealtimeServerEvent, construct_type_unchecked(value=json.loads(data), type_=cast(Any, RealtimeServerEvent)) + ) + + +class AsyncRealtimeConnectionManager: + """ + Context manager over a `AsyncRealtimeConnection` that is returned by `beta.realtime.connect()` + + This context manager ensures that the connection will be closed when it exits. + + --- + + Note that if your application doesn't work well with the context manager approach then you + can call the `.enter()` method directly to initiate a connection. + + **Warning**: You must remember to close the connection with `.close()`. + + ```py + connection = await client.beta.realtime.connect(...).enter() + # ... + await connection.close() + ``` + """ + + def __init__( + self, + *, + client: AsyncOpenAI, + model: str, + extra_query: Query, + extra_headers: Headers, + websocket_connection_options: WebsocketConnectionOptions, + ) -> None: + self.__client = client + self.__model = model + self.__connection: AsyncRealtimeConnection | None = None + self.__extra_query = extra_query + self.__extra_headers = extra_headers + self.__websocket_connection_options = websocket_connection_options + + async def __aenter__(self) -> AsyncRealtimeConnection: + """ + 👋 If your application doesn't work well with the context manager approach then you + can call this method directly to initiate a connection. + + **Warning**: You must remember to close the connection with `.close()`. + + ```py + connection = await client.beta.realtime.connect(...).enter() + # ... + await connection.close() + ``` + """ + try: + from websockets.asyncio.client import connect + except ImportError as exc: + raise OpenAIError("You need to install `openai[realtime]` to use this method") from exc + + url = self._prepare_url().copy_with( + params={ + **self.__client.base_url.params, + "model": self.__model, + **self.__extra_query, + }, + ) + log.debug("Connecting to %s", url) + if self.__websocket_connection_options: + log.debug("Connection options: %s", self.__websocket_connection_options) + + self.__connection = AsyncRealtimeConnection( + await connect( + str(url), + user_agent_header=self.__client.user_agent, + additional_headers=_merge_mappings( + { + **self.__client.auth_headers, + "OpenAI-Beta": "realtime=v1", + }, + self.__extra_headers, + ), + **self.__websocket_connection_options, + ) + ) + + return self.__connection + + enter = __aenter__ + + def _prepare_url(self) -> httpx.URL: + if self.__client.websocket_base_url is not None: + base_url = httpx.URL(self.__client.websocket_base_url) + else: + base_url = self.__client._base_url.copy_with(scheme="wss") + + merge_raw_path = base_url.raw_path.rstrip(b"/") + b"/realtime" + return base_url.copy_with(raw_path=merge_raw_path) + + async def __aexit__( + self, exc_type: type[BaseException] | None, exc: BaseException | None, exc_tb: TracebackType | None + ) -> None: + if self.__connection is not None: + await self.__connection.close() + + +class RealtimeConnection: + """Represents a live websocket connection to the Realtime API""" + + session: RealtimeSessionResource + response: RealtimeResponseResource + conversation: RealtimeConversationResource + input_audio_buffer: RealtimeInputAudioBufferResource + + _connection: WebsocketConnection + + def __init__(self, connection: WebsocketConnection) -> None: + self._connection = connection + + self.session = RealtimeSessionResource(self) + self.response = RealtimeResponseResource(self) + self.conversation = RealtimeConversationResource(self) + self.input_audio_buffer = RealtimeInputAudioBufferResource(self) + + def __iter__(self) -> Iterator[RealtimeServerEvent]: + """ + An infinite-iterator that will continue to yield events until + the connection is closed. + """ + from websockets.exceptions import ConnectionClosedOK + + try: + while True: + yield self.recv() + except ConnectionClosedOK: + return + + def recv(self) -> RealtimeServerEvent: + """ + Receive the next message from the connection and parses it into a `RealtimeServerEvent` object. + + Canceling this method is safe. There's no risk of losing data. + """ + return self.parse_event(self.recv_bytes()) + + def recv_bytes(self) -> bytes: + """Receive the next message from the connection as raw bytes. + + Canceling this method is safe. There's no risk of losing data. + + If you want to parse the message into a `RealtimeServerEvent` object like `.recv()` does, + then you can call `.parse_event(data)`. + """ + message = self._connection.recv(decode=False) + log.debug(f"Received websocket message: %s", message) + if not isinstance(message, bytes): + # passing `decode=False` should always result in us getting `bytes` back + raise TypeError(f"Expected `.recv(decode=False)` to return `bytes` but got {type(message)}") + + return message + + def send(self, event: RealtimeClientEvent | RealtimeClientEventParam) -> None: + data = ( + event.to_json(use_api_names=True, exclude_defaults=True, exclude_unset=True) + if isinstance(event, BaseModel) + else json.dumps(maybe_transform(event, RealtimeClientEventParam)) + ) + self._connection.send(data) + + def close(self, *, code: int = 1000, reason: str = "") -> None: + self._connection.close(code=code, reason=reason) + + def parse_event(self, data: str | bytes) -> RealtimeServerEvent: + """ + Converts a raw `str` or `bytes` message into a `RealtimeServerEvent` object. + + This is helpful if you're using `.recv_bytes()`. + """ + return cast( + RealtimeServerEvent, construct_type_unchecked(value=json.loads(data), type_=cast(Any, RealtimeServerEvent)) + ) + + +class RealtimeConnectionManager: + """ + Context manager over a `RealtimeConnection` that is returned by `beta.realtime.connect()` + + This context manager ensures that the connection will be closed when it exits. + + --- + + Note that if your application doesn't work well with the context manager approach then you + can call the `.enter()` method directly to initiate a connection. + + **Warning**: You must remember to close the connection with `.close()`. + + ```py + connection = client.beta.realtime.connect(...).enter() + # ... + connection.close() + ``` + """ + + def __init__( + self, + *, + client: OpenAI, + model: str, + extra_query: Query, + extra_headers: Headers, + websocket_connection_options: WebsocketConnectionOptions, + ) -> None: + self.__client = client + self.__model = model + self.__connection: RealtimeConnection | None = None + self.__extra_query = extra_query + self.__extra_headers = extra_headers + self.__websocket_connection_options = websocket_connection_options + + def __enter__(self) -> RealtimeConnection: + """ + 👋 If your application doesn't work well with the context manager approach then you + can call this method directly to initiate a connection. + + **Warning**: You must remember to close the connection with `.close()`. + + ```py + connection = client.beta.realtime.connect(...).enter() + # ... + connection.close() + ``` + """ + try: + from websockets.sync.client import connect + except ImportError as exc: + raise OpenAIError("You need to install `openai[realtime]` to use this method") from exc + + url = self._prepare_url().copy_with( + params={ + **self.__client.base_url.params, + "model": self.__model, + **self.__extra_query, + }, + ) + log.debug("Connecting to %s", url) + if self.__websocket_connection_options: + log.debug("Connection options: %s", self.__websocket_connection_options) + + self.__connection = RealtimeConnection( + connect( + str(url), + user_agent_header=self.__client.user_agent, + additional_headers=_merge_mappings( + { + **self.__client.auth_headers, + "OpenAI-Beta": "realtime=v1", + }, + self.__extra_headers, + ), + **self.__websocket_connection_options, + ) + ) + + return self.__connection + + enter = __enter__ + + def _prepare_url(self) -> httpx.URL: + if self.__client.websocket_base_url is not None: + base_url = httpx.URL(self.__client.websocket_base_url) + else: + base_url = self.__client._base_url.copy_with(scheme="wss") + + merge_raw_path = base_url.raw_path.rstrip(b"/") + b"/realtime" + return base_url.copy_with(raw_path=merge_raw_path) + + def __exit__( + self, exc_type: type[BaseException] | None, exc: BaseException | None, exc_tb: TracebackType | None + ) -> None: + if self.__connection is not None: + self.__connection.close() + + +class BaseRealtimeConnectionResource: + def __init__(self, connection: RealtimeConnection) -> None: + self._connection = connection + + +class RealtimeSessionResource(BaseRealtimeConnectionResource): + def update(self, *, session: session_update_event_param.Session, event_id: str | NotGiven = NOT_GIVEN) -> None: + """Send this event to update the session’s default configuration. + + The client may + send this event at any time to update the session configuration, and any + field may be updated at any time, except for "voice". The server will respond + with a `session.updated` event that shows the full effective configuration. + Only fields that are present are updated, thus the correct way to clear a + field like "instructions" is to pass an empty string. + """ + self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given({"type": "session.update", "session": session, "event_id": event_id}), + ) + ) + + +class RealtimeResponseResource(BaseRealtimeConnectionResource): + def cancel(self, *, event_id: str | NotGiven = NOT_GIVEN, response_id: str | NotGiven = NOT_GIVEN) -> None: + """Send this event to cancel an in-progress response. + + The server will respond + with a `response.cancelled` event or an error if there is no response to + cancel. + """ + self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given({"type": "response.cancel", "event_id": event_id, "response_id": response_id}), + ) + ) + + def create( + self, + *, + event_id: str | NotGiven = NOT_GIVEN, + response: response_create_event_param.Response | NotGiven = NOT_GIVEN, + ) -> None: + """ + This event instructs the server to create a Response, which means triggering + model inference. When in Server VAD mode, the server will create Responses + automatically. + + A Response will include at least one Item, and may have two, in which case + the second will be a function call. These Items will be appended to the + conversation history. + + The server will respond with a `response.created` event, events for Items + and content created, and finally a `response.done` event to indicate the + Response is complete. + + The `response.create` event includes inference configuration like + `instructions`, and `temperature`. These fields will override the Session's + configuration for this Response only. + """ + self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given({"type": "response.create", "event_id": event_id, "response": response}), + ) + ) + + +class RealtimeConversationResource(BaseRealtimeConnectionResource): + @cached_property + def item(self) -> RealtimeConversationItemResource: + return RealtimeConversationItemResource(self._connection) + + +class RealtimeConversationItemResource(BaseRealtimeConnectionResource): + def delete(self, *, item_id: str, event_id: str | NotGiven = NOT_GIVEN) -> None: + """Send this event when you want to remove any item from the conversation + history. + + The server will respond with a `conversation.item.deleted` event, + unless the item does not exist in the conversation history, in which case the + server will respond with an error. + """ + self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given({"type": "conversation.item.delete", "item_id": item_id, "event_id": event_id}), + ) + ) + + def create( + self, + *, + item: ConversationItemParam, + event_id: str | NotGiven = NOT_GIVEN, + previous_item_id: str | NotGiven = NOT_GIVEN, + ) -> None: + """ + Add a new Item to the Conversation's context, including messages, function + calls, and function call responses. This event can be used both to populate a + "history" of the conversation and to add new items mid-stream, but has the + current limitation that it cannot populate assistant audio messages. + + If successful, the server will respond with a `conversation.item.created` + event, otherwise an `error` event will be sent. + """ + self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given( + { + "type": "conversation.item.create", + "item": item, + "event_id": event_id, + "previous_item_id": previous_item_id, + } + ), + ) + ) + + def truncate( + self, *, audio_end_ms: int, content_index: int, item_id: str, event_id: str | NotGiven = NOT_GIVEN + ) -> None: + """Send this event to truncate a previous assistant message’s audio. + + The server + will produce audio faster than realtime, so this event is useful when the user + interrupts to truncate audio that has already been sent to the client but not + yet played. This will synchronize the server's understanding of the audio with + the client's playback. + + Truncating audio will delete the server-side text transcript to ensure there + is not text in the context that hasn't been heard by the user. + + If successful, the server will respond with a `conversation.item.truncated` + event. + """ + self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given( + { + "type": "conversation.item.truncate", + "audio_end_ms": audio_end_ms, + "content_index": content_index, + "item_id": item_id, + "event_id": event_id, + } + ), + ) + ) + + +class RealtimeInputAudioBufferResource(BaseRealtimeConnectionResource): + def clear(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: + """Send this event to clear the audio bytes in the buffer. + + The server will + respond with an `input_audio_buffer.cleared` event. + """ + self._connection.send( + cast(RealtimeClientEventParam, strip_not_given({"type": "input_audio_buffer.clear", "event_id": event_id})) + ) + + def commit(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: + """ + Send this event to commit the user input audio buffer, which will create a + new user message item in the conversation. This event will produce an error + if the input audio buffer is empty. When in Server VAD mode, the client does + not need to send this event, the server will commit the audio buffer + automatically. + + Committing the input audio buffer will trigger input audio transcription + (if enabled in session configuration), but it will not create a response + from the model. The server will respond with an `input_audio_buffer.committed` + event. + """ + self._connection.send( + cast(RealtimeClientEventParam, strip_not_given({"type": "input_audio_buffer.commit", "event_id": event_id})) + ) + + def append(self, *, audio: str, event_id: str | NotGiven = NOT_GIVEN) -> None: + """Send this event to append audio bytes to the input audio buffer. + + The audio + buffer is temporary storage you can write to and later commit. In Server VAD + mode, the audio buffer is used to detect speech and the server will decide + when to commit. When Server VAD is disabled, you must commit the audio buffer + manually. + + The client may choose how much audio to place in each event up to a maximum + of 15 MiB, for example streaming smaller chunks from the client may allow the + VAD to be more responsive. Unlike made other client events, the server will + not send a confirmation response to this event. + """ + self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given({"type": "input_audio_buffer.append", "audio": audio, "event_id": event_id}), + ) + ) + + +class BaseAsyncRealtimeConnectionResource: + def __init__(self, connection: AsyncRealtimeConnection) -> None: + self._connection = connection + + +class AsyncRealtimeSessionResource(BaseAsyncRealtimeConnectionResource): + async def update( + self, *, session: session_update_event_param.Session, event_id: str | NotGiven = NOT_GIVEN + ) -> None: + """Send this event to update the session’s default configuration. + + The client may + send this event at any time to update the session configuration, and any + field may be updated at any time, except for "voice". The server will respond + with a `session.updated` event that shows the full effective configuration. + Only fields that are present are updated, thus the correct way to clear a + field like "instructions" is to pass an empty string. + """ + await self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given({"type": "session.update", "session": session, "event_id": event_id}), + ) + ) + + +class AsyncRealtimeResponseResource(BaseAsyncRealtimeConnectionResource): + async def cancel(self, *, event_id: str | NotGiven = NOT_GIVEN, response_id: str | NotGiven = NOT_GIVEN) -> None: + """Send this event to cancel an in-progress response. + + The server will respond + with a `response.cancelled` event or an error if there is no response to + cancel. + """ + await self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given({"type": "response.cancel", "event_id": event_id, "response_id": response_id}), + ) + ) + + async def create( + self, + *, + event_id: str | NotGiven = NOT_GIVEN, + response: response_create_event_param.Response | NotGiven = NOT_GIVEN, + ) -> None: + """ + This event instructs the server to create a Response, which means triggering + model inference. When in Server VAD mode, the server will create Responses + automatically. + + A Response will include at least one Item, and may have two, in which case + the second will be a function call. These Items will be appended to the + conversation history. + + The server will respond with a `response.created` event, events for Items + and content created, and finally a `response.done` event to indicate the + Response is complete. + + The `response.create` event includes inference configuration like + `instructions`, and `temperature`. These fields will override the Session's + configuration for this Response only. + """ + await self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given({"type": "response.create", "event_id": event_id, "response": response}), + ) + ) + + +class AsyncRealtimeConversationResource(BaseAsyncRealtimeConnectionResource): + @cached_property + def item(self) -> AsyncRealtimeConversationItemResource: + return AsyncRealtimeConversationItemResource(self._connection) + + +class AsyncRealtimeConversationItemResource(BaseAsyncRealtimeConnectionResource): + async def delete(self, *, item_id: str, event_id: str | NotGiven = NOT_GIVEN) -> None: + """Send this event when you want to remove any item from the conversation + history. + + The server will respond with a `conversation.item.deleted` event, + unless the item does not exist in the conversation history, in which case the + server will respond with an error. + """ + await self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given({"type": "conversation.item.delete", "item_id": item_id, "event_id": event_id}), + ) + ) + + async def create( + self, + *, + item: ConversationItemParam, + event_id: str | NotGiven = NOT_GIVEN, + previous_item_id: str | NotGiven = NOT_GIVEN, + ) -> None: + """ + Add a new Item to the Conversation's context, including messages, function + calls, and function call responses. This event can be used both to populate a + "history" of the conversation and to add new items mid-stream, but has the + current limitation that it cannot populate assistant audio messages. + + If successful, the server will respond with a `conversation.item.created` + event, otherwise an `error` event will be sent. + """ + await self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given( + { + "type": "conversation.item.create", + "item": item, + "event_id": event_id, + "previous_item_id": previous_item_id, + } + ), + ) + ) + + async def truncate( + self, *, audio_end_ms: int, content_index: int, item_id: str, event_id: str | NotGiven = NOT_GIVEN + ) -> None: + """Send this event to truncate a previous assistant message’s audio. + + The server + will produce audio faster than realtime, so this event is useful when the user + interrupts to truncate audio that has already been sent to the client but not + yet played. This will synchronize the server's understanding of the audio with + the client's playback. + + Truncating audio will delete the server-side text transcript to ensure there + is not text in the context that hasn't been heard by the user. + + If successful, the server will respond with a `conversation.item.truncated` + event. + """ + await self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given( + { + "type": "conversation.item.truncate", + "audio_end_ms": audio_end_ms, + "content_index": content_index, + "item_id": item_id, + "event_id": event_id, + } + ), + ) + ) + + +class AsyncRealtimeInputAudioBufferResource(BaseAsyncRealtimeConnectionResource): + async def clear(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: + """Send this event to clear the audio bytes in the buffer. + + The server will + respond with an `input_audio_buffer.cleared` event. + """ + await self._connection.send( + cast(RealtimeClientEventParam, strip_not_given({"type": "input_audio_buffer.clear", "event_id": event_id})) + ) + + async def commit(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: + """ + Send this event to commit the user input audio buffer, which will create a + new user message item in the conversation. This event will produce an error + if the input audio buffer is empty. When in Server VAD mode, the client does + not need to send this event, the server will commit the audio buffer + automatically. + + Committing the input audio buffer will trigger input audio transcription + (if enabled in session configuration), but it will not create a response + from the model. The server will respond with an `input_audio_buffer.committed` + event. + """ + await self._connection.send( + cast(RealtimeClientEventParam, strip_not_given({"type": "input_audio_buffer.commit", "event_id": event_id})) + ) + + async def append(self, *, audio: str, event_id: str | NotGiven = NOT_GIVEN) -> None: + """Send this event to append audio bytes to the input audio buffer. + + The audio + buffer is temporary storage you can write to and later commit. In Server VAD + mode, the audio buffer is used to detect speech and the server will decide + when to commit. When Server VAD is disabled, you must commit the audio buffer + manually. + + The client may choose how much audio to place in each event up to a maximum + of 15 MiB, for example streaming smaller chunks from the client may allow the + VAD to be more responsive. Unlike made other client events, the server will + not send a confirmation response to this event. + """ + await self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given({"type": "input_audio_buffer.append", "audio": audio, "event_id": event_id}), + ) + ) diff --git a/src/openai/types/__init__.py b/src/openai/types/__init__.py index 7677be01b2..72950f2491 100644 --- a/src/openai/types/__init__.py +++ b/src/openai/types/__init__.py @@ -47,6 +47,7 @@ from .create_embedding_response import CreateEmbeddingResponse as CreateEmbeddingResponse from .moderation_create_response import ModerationCreateResponse as ModerationCreateResponse from .moderation_text_input_param import ModerationTextInputParam as ModerationTextInputParam +from .websocket_connection_options import WebsocketConnectionOptions as WebsocketConnectionOptions from .image_create_variation_params import ImageCreateVariationParams as ImageCreateVariationParams from .moderation_image_url_input_param import ModerationImageURLInputParam as ModerationImageURLInputParam from .moderation_multi_modal_input_param import ModerationMultiModalInputParam as ModerationMultiModalInputParam diff --git a/src/openai/types/beta/realtime/__init__.py b/src/openai/types/beta/realtime/__init__.py index 1c5246db7a..372d4ec19d 100644 --- a/src/openai/types/beta/realtime/__init__.py +++ b/src/openai/types/beta/realtime/__init__.py @@ -2,5 +2,79 @@ from __future__ import annotations +from .session import Session as Session +from .error_event import ErrorEvent as ErrorEvent +from .conversation_item import ConversationItem as ConversationItem +from .realtime_response import RealtimeResponse as RealtimeResponse +from .response_done_event import ResponseDoneEvent as ResponseDoneEvent +from .session_update_event import SessionUpdateEvent as SessionUpdateEvent +from .realtime_client_event import RealtimeClientEvent as RealtimeClientEvent +from .realtime_server_event import RealtimeServerEvent as RealtimeServerEvent +from .response_cancel_event import ResponseCancelEvent as ResponseCancelEvent +from .response_create_event import ResponseCreateEvent as ResponseCreateEvent from .session_create_params import SessionCreateParams as SessionCreateParams +from .session_created_event import SessionCreatedEvent as SessionCreatedEvent +from .session_updated_event import SessionUpdatedEvent as SessionUpdatedEvent +from .response_created_event import ResponseCreatedEvent as ResponseCreatedEvent +from .conversation_item_param import ConversationItemParam as ConversationItemParam +from .realtime_connect_params import RealtimeConnectParams as RealtimeConnectParams +from .realtime_response_usage import RealtimeResponseUsage as RealtimeResponseUsage from .session_create_response import SessionCreateResponse as SessionCreateResponse +from .realtime_response_status import RealtimeResponseStatus as RealtimeResponseStatus +from .response_text_done_event import ResponseTextDoneEvent as ResponseTextDoneEvent +from .conversation_item_content import ConversationItemContent as ConversationItemContent +from .rate_limits_updated_event import RateLimitsUpdatedEvent as RateLimitsUpdatedEvent +from .response_audio_done_event import ResponseAudioDoneEvent as ResponseAudioDoneEvent +from .response_text_delta_event import ResponseTextDeltaEvent as ResponseTextDeltaEvent +from .conversation_created_event import ConversationCreatedEvent as ConversationCreatedEvent +from .response_audio_delta_event import ResponseAudioDeltaEvent as ResponseAudioDeltaEvent +from .session_update_event_param import SessionUpdateEventParam as SessionUpdateEventParam +from .realtime_client_event_param import RealtimeClientEventParam as RealtimeClientEventParam +from .response_cancel_event_param import ResponseCancelEventParam as ResponseCancelEventParam +from .response_create_event_param import ResponseCreateEventParam as ResponseCreateEventParam +from .conversation_item_create_event import ConversationItemCreateEvent as ConversationItemCreateEvent +from .conversation_item_delete_event import ConversationItemDeleteEvent as ConversationItemDeleteEvent +from .input_audio_buffer_clear_event import InputAudioBufferClearEvent as InputAudioBufferClearEvent +from .conversation_item_content_param import ConversationItemContentParam as ConversationItemContentParam +from .conversation_item_created_event import ConversationItemCreatedEvent as ConversationItemCreatedEvent +from .conversation_item_deleted_event import ConversationItemDeletedEvent as ConversationItemDeletedEvent +from .input_audio_buffer_append_event import InputAudioBufferAppendEvent as InputAudioBufferAppendEvent +from .input_audio_buffer_commit_event import InputAudioBufferCommitEvent as InputAudioBufferCommitEvent +from .response_output_item_done_event import ResponseOutputItemDoneEvent as ResponseOutputItemDoneEvent +from .conversation_item_truncate_event import ConversationItemTruncateEvent as ConversationItemTruncateEvent +from .input_audio_buffer_cleared_event import InputAudioBufferClearedEvent as InputAudioBufferClearedEvent +from .response_content_part_done_event import ResponseContentPartDoneEvent as ResponseContentPartDoneEvent +from .response_output_item_added_event import ResponseOutputItemAddedEvent as ResponseOutputItemAddedEvent +from .conversation_item_truncated_event import ConversationItemTruncatedEvent as ConversationItemTruncatedEvent +from .response_content_part_added_event import ResponseContentPartAddedEvent as ResponseContentPartAddedEvent +from .input_audio_buffer_committed_event import InputAudioBufferCommittedEvent as InputAudioBufferCommittedEvent +from .conversation_item_create_event_param import ConversationItemCreateEventParam as ConversationItemCreateEventParam +from .conversation_item_delete_event_param import ConversationItemDeleteEventParam as ConversationItemDeleteEventParam +from .input_audio_buffer_clear_event_param import InputAudioBufferClearEventParam as InputAudioBufferClearEventParam +from .response_audio_transcript_done_event import ResponseAudioTranscriptDoneEvent as ResponseAudioTranscriptDoneEvent +from .input_audio_buffer_append_event_param import InputAudioBufferAppendEventParam as InputAudioBufferAppendEventParam +from .input_audio_buffer_commit_event_param import InputAudioBufferCommitEventParam as InputAudioBufferCommitEventParam +from .response_audio_transcript_delta_event import ( + ResponseAudioTranscriptDeltaEvent as ResponseAudioTranscriptDeltaEvent, +) +from .conversation_item_truncate_event_param import ( + ConversationItemTruncateEventParam as ConversationItemTruncateEventParam, +) +from .input_audio_buffer_speech_started_event import ( + InputAudioBufferSpeechStartedEvent as InputAudioBufferSpeechStartedEvent, +) +from .input_audio_buffer_speech_stopped_event import ( + InputAudioBufferSpeechStoppedEvent as InputAudioBufferSpeechStoppedEvent, +) +from .response_function_call_arguments_done_event import ( + ResponseFunctionCallArgumentsDoneEvent as ResponseFunctionCallArgumentsDoneEvent, +) +from .response_function_call_arguments_delta_event import ( + ResponseFunctionCallArgumentsDeltaEvent as ResponseFunctionCallArgumentsDeltaEvent, +) +from .conversation_item_input_audio_transcription_failed_event import ( + ConversationItemInputAudioTranscriptionFailedEvent as ConversationItemInputAudioTranscriptionFailedEvent, +) +from .conversation_item_input_audio_transcription_completed_event import ( + ConversationItemInputAudioTranscriptionCompletedEvent as ConversationItemInputAudioTranscriptionCompletedEvent, +) diff --git a/src/openai/types/beta/realtime/conversation_created_event.py b/src/openai/types/beta/realtime/conversation_created_event.py new file mode 100644 index 0000000000..4ba0540867 --- /dev/null +++ b/src/openai/types/beta/realtime/conversation_created_event.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["ConversationCreatedEvent", "Conversation"] + + +class Conversation(BaseModel): + id: Optional[str] = None + """The unique ID of the conversation.""" + + object: Optional[Literal["realtime.conversation"]] = None + """The object type, must be `realtime.conversation`.""" + + +class ConversationCreatedEvent(BaseModel): + conversation: Conversation + """The conversation resource.""" + + event_id: str + """The unique ID of the server event.""" + + type: Literal["conversation.created"] + """The event type, must be `conversation.created`.""" diff --git a/src/openai/types/beta/realtime/conversation_item.py b/src/openai/types/beta/realtime/conversation_item.py new file mode 100644 index 0000000000..4edf6c4d5f --- /dev/null +++ b/src/openai/types/beta/realtime/conversation_item.py @@ -0,0 +1,61 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ...._models import BaseModel +from .conversation_item_content import ConversationItemContent + +__all__ = ["ConversationItem"] + + +class ConversationItem(BaseModel): + id: Optional[str] = None + """ + The unique ID of the item, this can be generated by the client to help manage + server-side context, but is not required because the server will generate one if + not provided. + """ + + arguments: Optional[str] = None + """The arguments of the function call (for `function_call` items).""" + + call_id: Optional[str] = None + """ + The ID of the function call (for `function_call` and `function_call_output` + items). If passed on a `function_call_output` item, the server will check that a + `function_call` item with the same ID exists in the conversation history. + """ + + content: Optional[List[ConversationItemContent]] = None + """The content of the message, applicable for `message` items. + + - Message items of role `system` support only `input_text` content + - Message items of role `user` support `input_text` and `input_audio` content + - Message items of role `assistant` support `text` content. + """ + + name: Optional[str] = None + """The name of the function being called (for `function_call` items).""" + + object: Optional[Literal["realtime.item"]] = None + """Identifier for the API object being returned - always `realtime.item`.""" + + output: Optional[str] = None + """The output of the function call (for `function_call_output` items).""" + + role: Optional[Literal["user", "assistant", "system"]] = None + """ + The role of the message sender (`user`, `assistant`, `system`), only applicable + for `message` items. + """ + + status: Optional[Literal["completed", "incomplete"]] = None + """The status of the item (`completed`, `incomplete`). + + These have no effect on the conversation, but are accepted for consistency with + the `conversation.item.created` event. + """ + + type: Optional[Literal["message", "function_call", "function_call_output"]] = None + """The type of the item (`message`, `function_call`, `function_call_output`).""" diff --git a/src/openai/types/beta/realtime/conversation_item_content.py b/src/openai/types/beta/realtime/conversation_item_content.py new file mode 100644 index 0000000000..b854aa0e0f --- /dev/null +++ b/src/openai/types/beta/realtime/conversation_item_content.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["ConversationItemContent"] + + +class ConversationItemContent(BaseModel): + id: Optional[str] = None + """ + ID of a previous conversation item (like a model response), used for + `item_reference` content types. + """ + + audio: Optional[str] = None + """Base64-encoded audio bytes, used for `input_audio` content type.""" + + text: Optional[str] = None + """The text content, used for `input_text` and `text` content types.""" + + transcript: Optional[str] = None + """The transcript of the audio, used for `input_audio` content type.""" + + type: Optional[Literal["input_text", "input_audio", "item_reference", "text"]] = None + """The content type (`input_text`, `input_audio`, `item_reference`, `text`).""" diff --git a/src/openai/types/beta/realtime/conversation_item_content_param.py b/src/openai/types/beta/realtime/conversation_item_content_param.py new file mode 100644 index 0000000000..b354d78971 --- /dev/null +++ b/src/openai/types/beta/realtime/conversation_item_content_param.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["ConversationItemContentParam"] + + +class ConversationItemContentParam(TypedDict, total=False): + id: str + """ + ID of a previous conversation item (like a model response), used for + `item_reference` content types. + """ + + audio: str + """Base64-encoded audio bytes, used for `input_audio` content type.""" + + text: str + """The text content, used for `input_text` and `text` content types.""" + + transcript: str + """The transcript of the audio, used for `input_audio` content type.""" + + type: Literal["input_text", "input_audio", "item_reference", "text"] + """The content type (`input_text`, `input_audio`, `item_reference`, `text`).""" diff --git a/src/openai/types/beta/realtime/conversation_item_create_event.py b/src/openai/types/beta/realtime/conversation_item_create_event.py new file mode 100644 index 0000000000..50d309675b --- /dev/null +++ b/src/openai/types/beta/realtime/conversation_item_create_event.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ...._models import BaseModel +from .conversation_item import ConversationItem + +__all__ = ["ConversationItemCreateEvent"] + + +class ConversationItemCreateEvent(BaseModel): + item: ConversationItem + """The item to add to the conversation.""" + + type: Literal["conversation.item.create"] + """The event type, must be `conversation.item.create`.""" + + event_id: Optional[str] = None + """Optional client-generated ID used to identify this event.""" + + previous_item_id: Optional[str] = None + """The ID of the preceding item after which the new item will be inserted. + + If not set, the new item will be appended to the end of the conversation. If + set, it allows an item to be inserted mid-conversation. If the ID cannot be + found, an error will be returned and the item will not be added. + """ diff --git a/src/openai/types/beta/realtime/conversation_item_create_event_param.py b/src/openai/types/beta/realtime/conversation_item_create_event_param.py new file mode 100644 index 0000000000..b8c8bbc251 --- /dev/null +++ b/src/openai/types/beta/realtime/conversation_item_create_event_param.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +from .conversation_item_param import ConversationItemParam + +__all__ = ["ConversationItemCreateEventParam"] + + +class ConversationItemCreateEventParam(TypedDict, total=False): + item: Required[ConversationItemParam] + """The item to add to the conversation.""" + + type: Required[Literal["conversation.item.create"]] + """The event type, must be `conversation.item.create`.""" + + event_id: str + """Optional client-generated ID used to identify this event.""" + + previous_item_id: str + """The ID of the preceding item after which the new item will be inserted. + + If not set, the new item will be appended to the end of the conversation. If + set, it allows an item to be inserted mid-conversation. If the ID cannot be + found, an error will be returned and the item will not be added. + """ diff --git a/src/openai/types/beta/realtime/conversation_item_created_event.py b/src/openai/types/beta/realtime/conversation_item_created_event.py new file mode 100644 index 0000000000..2f20388246 --- /dev/null +++ b/src/openai/types/beta/realtime/conversation_item_created_event.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel +from .conversation_item import ConversationItem + +__all__ = ["ConversationItemCreatedEvent"] + + +class ConversationItemCreatedEvent(BaseModel): + event_id: str + """The unique ID of the server event.""" + + item: ConversationItem + """The item to add to the conversation.""" + + previous_item_id: str + """ + The ID of the preceding item in the Conversation context, allows the client to + understand the order of the conversation. + """ + + type: Literal["conversation.item.created"] + """The event type, must be `conversation.item.created`.""" diff --git a/src/openai/types/beta/realtime/conversation_item_delete_event.py b/src/openai/types/beta/realtime/conversation_item_delete_event.py new file mode 100644 index 0000000000..02ca8250ce --- /dev/null +++ b/src/openai/types/beta/realtime/conversation_item_delete_event.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["ConversationItemDeleteEvent"] + + +class ConversationItemDeleteEvent(BaseModel): + item_id: str + """The ID of the item to delete.""" + + type: Literal["conversation.item.delete"] + """The event type, must be `conversation.item.delete`.""" + + event_id: Optional[str] = None + """Optional client-generated ID used to identify this event.""" diff --git a/src/openai/types/beta/realtime/conversation_item_delete_event_param.py b/src/openai/types/beta/realtime/conversation_item_delete_event_param.py new file mode 100644 index 0000000000..c3f88d6627 --- /dev/null +++ b/src/openai/types/beta/realtime/conversation_item_delete_event_param.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ConversationItemDeleteEventParam"] + + +class ConversationItemDeleteEventParam(TypedDict, total=False): + item_id: Required[str] + """The ID of the item to delete.""" + + type: Required[Literal["conversation.item.delete"]] + """The event type, must be `conversation.item.delete`.""" + + event_id: str + """Optional client-generated ID used to identify this event.""" diff --git a/src/openai/types/beta/realtime/conversation_item_deleted_event.py b/src/openai/types/beta/realtime/conversation_item_deleted_event.py new file mode 100644 index 0000000000..a35a97817a --- /dev/null +++ b/src/openai/types/beta/realtime/conversation_item_deleted_event.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["ConversationItemDeletedEvent"] + + +class ConversationItemDeletedEvent(BaseModel): + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the item that was deleted.""" + + type: Literal["conversation.item.deleted"] + """The event type, must be `conversation.item.deleted`.""" diff --git a/src/openai/types/beta/realtime/conversation_item_input_audio_transcription_completed_event.py b/src/openai/types/beta/realtime/conversation_item_input_audio_transcription_completed_event.py new file mode 100644 index 0000000000..ded79cc0f7 --- /dev/null +++ b/src/openai/types/beta/realtime/conversation_item_input_audio_transcription_completed_event.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["ConversationItemInputAudioTranscriptionCompletedEvent"] + + +class ConversationItemInputAudioTranscriptionCompletedEvent(BaseModel): + content_index: int + """The index of the content part containing the audio.""" + + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the user message item containing the audio.""" + + transcript: str + """The transcribed text.""" + + type: Literal["conversation.item.input_audio_transcription.completed"] + """ + The event type, must be `conversation.item.input_audio_transcription.completed`. + """ diff --git a/src/openai/types/beta/realtime/conversation_item_input_audio_transcription_failed_event.py b/src/openai/types/beta/realtime/conversation_item_input_audio_transcription_failed_event.py new file mode 100644 index 0000000000..cecac93e64 --- /dev/null +++ b/src/openai/types/beta/realtime/conversation_item_input_audio_transcription_failed_event.py @@ -0,0 +1,39 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["ConversationItemInputAudioTranscriptionFailedEvent", "Error"] + + +class Error(BaseModel): + code: Optional[str] = None + """Error code, if any.""" + + message: Optional[str] = None + """A human-readable error message.""" + + param: Optional[str] = None + """Parameter related to the error, if any.""" + + type: Optional[str] = None + """The type of error.""" + + +class ConversationItemInputAudioTranscriptionFailedEvent(BaseModel): + content_index: int + """The index of the content part containing the audio.""" + + error: Error + """Details of the transcription error.""" + + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the user message item.""" + + type: Literal["conversation.item.input_audio_transcription.failed"] + """The event type, must be `conversation.item.input_audio_transcription.failed`.""" diff --git a/src/openai/types/beta/realtime/conversation_item_param.py b/src/openai/types/beta/realtime/conversation_item_param.py new file mode 100644 index 0000000000..ac0f8431e5 --- /dev/null +++ b/src/openai/types/beta/realtime/conversation_item_param.py @@ -0,0 +1,62 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Literal, TypedDict + +from .conversation_item_content_param import ConversationItemContentParam + +__all__ = ["ConversationItemParam"] + + +class ConversationItemParam(TypedDict, total=False): + id: str + """ + The unique ID of the item, this can be generated by the client to help manage + server-side context, but is not required because the server will generate one if + not provided. + """ + + arguments: str + """The arguments of the function call (for `function_call` items).""" + + call_id: str + """ + The ID of the function call (for `function_call` and `function_call_output` + items). If passed on a `function_call_output` item, the server will check that a + `function_call` item with the same ID exists in the conversation history. + """ + + content: Iterable[ConversationItemContentParam] + """The content of the message, applicable for `message` items. + + - Message items of role `system` support only `input_text` content + - Message items of role `user` support `input_text` and `input_audio` content + - Message items of role `assistant` support `text` content. + """ + + name: str + """The name of the function being called (for `function_call` items).""" + + object: Literal["realtime.item"] + """Identifier for the API object being returned - always `realtime.item`.""" + + output: str + """The output of the function call (for `function_call_output` items).""" + + role: Literal["user", "assistant", "system"] + """ + The role of the message sender (`user`, `assistant`, `system`), only applicable + for `message` items. + """ + + status: Literal["completed", "incomplete"] + """The status of the item (`completed`, `incomplete`). + + These have no effect on the conversation, but are accepted for consistency with + the `conversation.item.created` event. + """ + + type: Literal["message", "function_call", "function_call_output"] + """The type of the item (`message`, `function_call`, `function_call_output`).""" diff --git a/src/openai/types/beta/realtime/conversation_item_truncate_event.py b/src/openai/types/beta/realtime/conversation_item_truncate_event.py new file mode 100644 index 0000000000..cb336bba2c --- /dev/null +++ b/src/openai/types/beta/realtime/conversation_item_truncate_event.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["ConversationItemTruncateEvent"] + + +class ConversationItemTruncateEvent(BaseModel): + audio_end_ms: int + """Inclusive duration up to which audio is truncated, in milliseconds. + + If the audio_end_ms is greater than the actual audio duration, the server will + respond with an error. + """ + + content_index: int + """The index of the content part to truncate. Set this to 0.""" + + item_id: str + """The ID of the assistant message item to truncate. + + Only assistant message items can be truncated. + """ + + type: Literal["conversation.item.truncate"] + """The event type, must be `conversation.item.truncate`.""" + + event_id: Optional[str] = None + """Optional client-generated ID used to identify this event.""" diff --git a/src/openai/types/beta/realtime/conversation_item_truncate_event_param.py b/src/openai/types/beta/realtime/conversation_item_truncate_event_param.py new file mode 100644 index 0000000000..d3ad1e1e25 --- /dev/null +++ b/src/openai/types/beta/realtime/conversation_item_truncate_event_param.py @@ -0,0 +1,31 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ConversationItemTruncateEventParam"] + + +class ConversationItemTruncateEventParam(TypedDict, total=False): + audio_end_ms: Required[int] + """Inclusive duration up to which audio is truncated, in milliseconds. + + If the audio_end_ms is greater than the actual audio duration, the server will + respond with an error. + """ + + content_index: Required[int] + """The index of the content part to truncate. Set this to 0.""" + + item_id: Required[str] + """The ID of the assistant message item to truncate. + + Only assistant message items can be truncated. + """ + + type: Required[Literal["conversation.item.truncate"]] + """The event type, must be `conversation.item.truncate`.""" + + event_id: str + """Optional client-generated ID used to identify this event.""" diff --git a/src/openai/types/beta/realtime/conversation_item_truncated_event.py b/src/openai/types/beta/realtime/conversation_item_truncated_event.py new file mode 100644 index 0000000000..36368fa28f --- /dev/null +++ b/src/openai/types/beta/realtime/conversation_item_truncated_event.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["ConversationItemTruncatedEvent"] + + +class ConversationItemTruncatedEvent(BaseModel): + audio_end_ms: int + """The duration up to which the audio was truncated, in milliseconds.""" + + content_index: int + """The index of the content part that was truncated.""" + + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the assistant message item that was truncated.""" + + type: Literal["conversation.item.truncated"] + """The event type, must be `conversation.item.truncated`.""" diff --git a/src/openai/types/beta/realtime/error_event.py b/src/openai/types/beta/realtime/error_event.py new file mode 100644 index 0000000000..e020fc3848 --- /dev/null +++ b/src/openai/types/beta/realtime/error_event.py @@ -0,0 +1,36 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["ErrorEvent", "Error"] + + +class Error(BaseModel): + message: str + """A human-readable error message.""" + + type: str + """The type of error (e.g., "invalid_request_error", "server_error").""" + + code: Optional[str] = None + """Error code, if any.""" + + event_id: Optional[str] = None + """The event_id of the client event that caused the error, if applicable.""" + + param: Optional[str] = None + """Parameter related to the error, if any.""" + + +class ErrorEvent(BaseModel): + error: Error + """Details of the error.""" + + event_id: str + """The unique ID of the server event.""" + + type: Literal["error"] + """The event type, must be `error`.""" diff --git a/src/openai/types/beta/realtime/input_audio_buffer_append_event.py b/src/openai/types/beta/realtime/input_audio_buffer_append_event.py new file mode 100644 index 0000000000..a253a6488c --- /dev/null +++ b/src/openai/types/beta/realtime/input_audio_buffer_append_event.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["InputAudioBufferAppendEvent"] + + +class InputAudioBufferAppendEvent(BaseModel): + audio: str + """Base64-encoded audio bytes. + + This must be in the format specified by the `input_audio_format` field in the + session configuration. + """ + + type: Literal["input_audio_buffer.append"] + """The event type, must be `input_audio_buffer.append`.""" + + event_id: Optional[str] = None + """Optional client-generated ID used to identify this event.""" diff --git a/src/openai/types/beta/realtime/input_audio_buffer_append_event_param.py b/src/openai/types/beta/realtime/input_audio_buffer_append_event_param.py new file mode 100644 index 0000000000..3ad0bc737d --- /dev/null +++ b/src/openai/types/beta/realtime/input_audio_buffer_append_event_param.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["InputAudioBufferAppendEventParam"] + + +class InputAudioBufferAppendEventParam(TypedDict, total=False): + audio: Required[str] + """Base64-encoded audio bytes. + + This must be in the format specified by the `input_audio_format` field in the + session configuration. + """ + + type: Required[Literal["input_audio_buffer.append"]] + """The event type, must be `input_audio_buffer.append`.""" + + event_id: str + """Optional client-generated ID used to identify this event.""" diff --git a/src/openai/types/beta/realtime/input_audio_buffer_clear_event.py b/src/openai/types/beta/realtime/input_audio_buffer_clear_event.py new file mode 100644 index 0000000000..b0624d34df --- /dev/null +++ b/src/openai/types/beta/realtime/input_audio_buffer_clear_event.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["InputAudioBufferClearEvent"] + + +class InputAudioBufferClearEvent(BaseModel): + type: Literal["input_audio_buffer.clear"] + """The event type, must be `input_audio_buffer.clear`.""" + + event_id: Optional[str] = None + """Optional client-generated ID used to identify this event.""" diff --git a/src/openai/types/beta/realtime/input_audio_buffer_clear_event_param.py b/src/openai/types/beta/realtime/input_audio_buffer_clear_event_param.py new file mode 100644 index 0000000000..2bd6bc5a02 --- /dev/null +++ b/src/openai/types/beta/realtime/input_audio_buffer_clear_event_param.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["InputAudioBufferClearEventParam"] + + +class InputAudioBufferClearEventParam(TypedDict, total=False): + type: Required[Literal["input_audio_buffer.clear"]] + """The event type, must be `input_audio_buffer.clear`.""" + + event_id: str + """Optional client-generated ID used to identify this event.""" diff --git a/src/openai/types/beta/realtime/input_audio_buffer_cleared_event.py b/src/openai/types/beta/realtime/input_audio_buffer_cleared_event.py new file mode 100644 index 0000000000..632e1b94bc --- /dev/null +++ b/src/openai/types/beta/realtime/input_audio_buffer_cleared_event.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["InputAudioBufferClearedEvent"] + + +class InputAudioBufferClearedEvent(BaseModel): + event_id: str + """The unique ID of the server event.""" + + type: Literal["input_audio_buffer.cleared"] + """The event type, must be `input_audio_buffer.cleared`.""" diff --git a/src/openai/types/beta/realtime/input_audio_buffer_commit_event.py b/src/openai/types/beta/realtime/input_audio_buffer_commit_event.py new file mode 100644 index 0000000000..7b6f5e46b7 --- /dev/null +++ b/src/openai/types/beta/realtime/input_audio_buffer_commit_event.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["InputAudioBufferCommitEvent"] + + +class InputAudioBufferCommitEvent(BaseModel): + type: Literal["input_audio_buffer.commit"] + """The event type, must be `input_audio_buffer.commit`.""" + + event_id: Optional[str] = None + """Optional client-generated ID used to identify this event.""" diff --git a/src/openai/types/beta/realtime/input_audio_buffer_commit_event_param.py b/src/openai/types/beta/realtime/input_audio_buffer_commit_event_param.py new file mode 100644 index 0000000000..c9c927ab98 --- /dev/null +++ b/src/openai/types/beta/realtime/input_audio_buffer_commit_event_param.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["InputAudioBufferCommitEventParam"] + + +class InputAudioBufferCommitEventParam(TypedDict, total=False): + type: Required[Literal["input_audio_buffer.commit"]] + """The event type, must be `input_audio_buffer.commit`.""" + + event_id: str + """Optional client-generated ID used to identify this event.""" diff --git a/src/openai/types/beta/realtime/input_audio_buffer_committed_event.py b/src/openai/types/beta/realtime/input_audio_buffer_committed_event.py new file mode 100644 index 0000000000..3071eff357 --- /dev/null +++ b/src/openai/types/beta/realtime/input_audio_buffer_committed_event.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["InputAudioBufferCommittedEvent"] + + +class InputAudioBufferCommittedEvent(BaseModel): + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the user message item that will be created.""" + + previous_item_id: str + """The ID of the preceding item after which the new item will be inserted.""" + + type: Literal["input_audio_buffer.committed"] + """The event type, must be `input_audio_buffer.committed`.""" diff --git a/src/openai/types/beta/realtime/input_audio_buffer_speech_started_event.py b/src/openai/types/beta/realtime/input_audio_buffer_speech_started_event.py new file mode 100644 index 0000000000..4f3ab082c4 --- /dev/null +++ b/src/openai/types/beta/realtime/input_audio_buffer_speech_started_event.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["InputAudioBufferSpeechStartedEvent"] + + +class InputAudioBufferSpeechStartedEvent(BaseModel): + audio_start_ms: int + """ + Milliseconds from the start of all audio written to the buffer during the + session when speech was first detected. This will correspond to the beginning of + audio sent to the model, and thus includes the `prefix_padding_ms` configured in + the Session. + """ + + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the user message item that will be created when speech stops.""" + + type: Literal["input_audio_buffer.speech_started"] + """The event type, must be `input_audio_buffer.speech_started`.""" diff --git a/src/openai/types/beta/realtime/input_audio_buffer_speech_stopped_event.py b/src/openai/types/beta/realtime/input_audio_buffer_speech_stopped_event.py new file mode 100644 index 0000000000..40568170f2 --- /dev/null +++ b/src/openai/types/beta/realtime/input_audio_buffer_speech_stopped_event.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["InputAudioBufferSpeechStoppedEvent"] + + +class InputAudioBufferSpeechStoppedEvent(BaseModel): + audio_end_ms: int + """Milliseconds since the session started when speech stopped. + + This will correspond to the end of audio sent to the model, and thus includes + the `min_silence_duration_ms` configured in the Session. + """ + + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the user message item that will be created.""" + + type: Literal["input_audio_buffer.speech_stopped"] + """The event type, must be `input_audio_buffer.speech_stopped`.""" diff --git a/src/openai/types/beta/realtime/rate_limits_updated_event.py b/src/openai/types/beta/realtime/rate_limits_updated_event.py new file mode 100644 index 0000000000..7e12283c46 --- /dev/null +++ b/src/openai/types/beta/realtime/rate_limits_updated_event.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["RateLimitsUpdatedEvent", "RateLimit"] + + +class RateLimit(BaseModel): + limit: Optional[int] = None + """The maximum allowed value for the rate limit.""" + + name: Optional[Literal["requests", "tokens"]] = None + """The name of the rate limit (`requests`, `tokens`).""" + + remaining: Optional[int] = None + """The remaining value before the limit is reached.""" + + reset_seconds: Optional[float] = None + """Seconds until the rate limit resets.""" + + +class RateLimitsUpdatedEvent(BaseModel): + event_id: str + """The unique ID of the server event.""" + + rate_limits: List[RateLimit] + """List of rate limit information.""" + + type: Literal["rate_limits.updated"] + """The event type, must be `rate_limits.updated`.""" diff --git a/src/openai/types/beta/realtime/realtime_client_event.py b/src/openai/types/beta/realtime/realtime_client_event.py new file mode 100644 index 0000000000..0769184cd0 --- /dev/null +++ b/src/openai/types/beta/realtime/realtime_client_event.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from typing_extensions import Annotated, TypeAlias + +from ...._utils import PropertyInfo +from .session_update_event import SessionUpdateEvent +from .response_cancel_event import ResponseCancelEvent +from .response_create_event import ResponseCreateEvent +from .conversation_item_create_event import ConversationItemCreateEvent +from .conversation_item_delete_event import ConversationItemDeleteEvent +from .input_audio_buffer_clear_event import InputAudioBufferClearEvent +from .input_audio_buffer_append_event import InputAudioBufferAppendEvent +from .input_audio_buffer_commit_event import InputAudioBufferCommitEvent +from .conversation_item_truncate_event import ConversationItemTruncateEvent + +__all__ = ["RealtimeClientEvent"] + +RealtimeClientEvent: TypeAlias = Annotated[ + Union[ + SessionUpdateEvent, + InputAudioBufferAppendEvent, + InputAudioBufferCommitEvent, + InputAudioBufferClearEvent, + ConversationItemCreateEvent, + ConversationItemTruncateEvent, + ConversationItemDeleteEvent, + ResponseCreateEvent, + ResponseCancelEvent, + ], + PropertyInfo(discriminator="type"), +] diff --git a/src/openai/types/beta/realtime/realtime_client_event_param.py b/src/openai/types/beta/realtime/realtime_client_event_param.py new file mode 100644 index 0000000000..4020892c33 --- /dev/null +++ b/src/openai/types/beta/realtime/realtime_client_event_param.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import TypeAlias + +from .session_update_event_param import SessionUpdateEventParam +from .response_cancel_event_param import ResponseCancelEventParam +from .response_create_event_param import ResponseCreateEventParam +from .conversation_item_create_event_param import ConversationItemCreateEventParam +from .conversation_item_delete_event_param import ConversationItemDeleteEventParam +from .input_audio_buffer_clear_event_param import InputAudioBufferClearEventParam +from .input_audio_buffer_append_event_param import InputAudioBufferAppendEventParam +from .input_audio_buffer_commit_event_param import InputAudioBufferCommitEventParam +from .conversation_item_truncate_event_param import ConversationItemTruncateEventParam + +__all__ = ["RealtimeClientEventParam"] + +RealtimeClientEventParam: TypeAlias = Union[ + SessionUpdateEventParam, + InputAudioBufferAppendEventParam, + InputAudioBufferCommitEventParam, + InputAudioBufferClearEventParam, + ConversationItemCreateEventParam, + ConversationItemTruncateEventParam, + ConversationItemDeleteEventParam, + ResponseCreateEventParam, + ResponseCancelEventParam, +] diff --git a/src/openai/types/beta/realtime/realtime_connect_params.py b/src/openai/types/beta/realtime/realtime_connect_params.py new file mode 100644 index 0000000000..76474f3de4 --- /dev/null +++ b/src/openai/types/beta/realtime/realtime_connect_params.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["RealtimeConnectParams"] + + +class RealtimeConnectParams(TypedDict, total=False): + model: Required[str] diff --git a/src/openai/types/beta/realtime/realtime_response.py b/src/openai/types/beta/realtime/realtime_response.py new file mode 100644 index 0000000000..3e1b1406c0 --- /dev/null +++ b/src/openai/types/beta/realtime/realtime_response.py @@ -0,0 +1,42 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ...._models import BaseModel +from .conversation_item import ConversationItem +from .realtime_response_usage import RealtimeResponseUsage +from .realtime_response_status import RealtimeResponseStatus + +__all__ = ["RealtimeResponse"] + + +class RealtimeResponse(BaseModel): + id: Optional[str] = None + """The unique ID of the response.""" + + metadata: Optional[object] = None + """Developer-provided string key-value pairs associated with this response.""" + + object: Optional[Literal["realtime.response"]] = None + """The object type, must be `realtime.response`.""" + + output: Optional[List[ConversationItem]] = None + """The list of output items generated by the response.""" + + status: Optional[Literal["completed", "cancelled", "failed", "incomplete"]] = None + """ + The final status of the response (`completed`, `cancelled`, `failed`, or + `incomplete`). + """ + + status_details: Optional[RealtimeResponseStatus] = None + """Additional details about the status.""" + + usage: Optional[RealtimeResponseUsage] = None + """Usage statistics for the Response, this will correspond to billing. + + A Realtime API session will maintain a conversation context and append new Items + to the Conversation, thus output from previous turns (text and audio tokens) + will become the input for later turns. + """ diff --git a/src/openai/types/beta/realtime/realtime_response_status.py b/src/openai/types/beta/realtime/realtime_response_status.py new file mode 100644 index 0000000000..7189cd58a1 --- /dev/null +++ b/src/openai/types/beta/realtime/realtime_response_status.py @@ -0,0 +1,39 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["RealtimeResponseStatus", "Error"] + + +class Error(BaseModel): + code: Optional[str] = None + """Error code, if any.""" + + type: Optional[str] = None + """The type of error.""" + + +class RealtimeResponseStatus(BaseModel): + error: Optional[Error] = None + """ + A description of the error that caused the response to fail, populated when the + `status` is `failed`. + """ + + reason: Optional[Literal["turn_detected", "client_cancelled", "max_output_tokens", "content_filter"]] = None + """The reason the Response did not complete. + + For a `cancelled` Response, one of `turn_detected` (the server VAD detected a + new start of speech) or `client_cancelled` (the client sent a cancel event). For + an `incomplete` Response, one of `max_output_tokens` or `content_filter` (the + server-side safety filter activated and cut off the response). + """ + + type: Optional[Literal["completed", "cancelled", "incomplete", "failed"]] = None + """ + The type of error that caused the response to fail, corresponding with the + `status` field (`completed`, `cancelled`, `incomplete`, `failed`). + """ diff --git a/src/openai/types/beta/realtime/realtime_response_usage.py b/src/openai/types/beta/realtime/realtime_response_usage.py new file mode 100644 index 0000000000..7ca822e25e --- /dev/null +++ b/src/openai/types/beta/realtime/realtime_response_usage.py @@ -0,0 +1,52 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ...._models import BaseModel + +__all__ = ["RealtimeResponseUsage", "InputTokenDetails", "OutputTokenDetails"] + + +class InputTokenDetails(BaseModel): + audio_tokens: Optional[int] = None + """The number of audio tokens used in the Response.""" + + cached_tokens: Optional[int] = None + """The number of cached tokens used in the Response.""" + + text_tokens: Optional[int] = None + """The number of text tokens used in the Response.""" + + +class OutputTokenDetails(BaseModel): + audio_tokens: Optional[int] = None + """The number of audio tokens used in the Response.""" + + text_tokens: Optional[int] = None + """The number of text tokens used in the Response.""" + + +class RealtimeResponseUsage(BaseModel): + input_token_details: Optional[InputTokenDetails] = None + """Details about the input tokens used in the Response.""" + + input_tokens: Optional[int] = None + """ + The number of input tokens used in the Response, including text and audio + tokens. + """ + + output_token_details: Optional[OutputTokenDetails] = None + """Details about the output tokens used in the Response.""" + + output_tokens: Optional[int] = None + """ + The number of output tokens sent in the Response, including text and audio + tokens. + """ + + total_tokens: Optional[int] = None + """ + The total number of tokens in the Response including input and output text and + audio tokens. + """ diff --git a/src/openai/types/beta/realtime/realtime_server_event.py b/src/openai/types/beta/realtime/realtime_server_event.py new file mode 100644 index 0000000000..5f8ed55b13 --- /dev/null +++ b/src/openai/types/beta/realtime/realtime_server_event.py @@ -0,0 +1,72 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from typing_extensions import Annotated, TypeAlias + +from ...._utils import PropertyInfo +from .error_event import ErrorEvent +from .response_done_event import ResponseDoneEvent +from .session_created_event import SessionCreatedEvent +from .session_updated_event import SessionUpdatedEvent +from .response_created_event import ResponseCreatedEvent +from .response_text_done_event import ResponseTextDoneEvent +from .rate_limits_updated_event import RateLimitsUpdatedEvent +from .response_audio_done_event import ResponseAudioDoneEvent +from .response_text_delta_event import ResponseTextDeltaEvent +from .conversation_created_event import ConversationCreatedEvent +from .response_audio_delta_event import ResponseAudioDeltaEvent +from .conversation_item_created_event import ConversationItemCreatedEvent +from .conversation_item_deleted_event import ConversationItemDeletedEvent +from .response_output_item_done_event import ResponseOutputItemDoneEvent +from .input_audio_buffer_cleared_event import InputAudioBufferClearedEvent +from .response_content_part_done_event import ResponseContentPartDoneEvent +from .response_output_item_added_event import ResponseOutputItemAddedEvent +from .conversation_item_truncated_event import ConversationItemTruncatedEvent +from .response_content_part_added_event import ResponseContentPartAddedEvent +from .input_audio_buffer_committed_event import InputAudioBufferCommittedEvent +from .response_audio_transcript_done_event import ResponseAudioTranscriptDoneEvent +from .response_audio_transcript_delta_event import ResponseAudioTranscriptDeltaEvent +from .input_audio_buffer_speech_started_event import InputAudioBufferSpeechStartedEvent +from .input_audio_buffer_speech_stopped_event import InputAudioBufferSpeechStoppedEvent +from .response_function_call_arguments_done_event import ResponseFunctionCallArgumentsDoneEvent +from .response_function_call_arguments_delta_event import ResponseFunctionCallArgumentsDeltaEvent +from .conversation_item_input_audio_transcription_failed_event import ConversationItemInputAudioTranscriptionFailedEvent +from .conversation_item_input_audio_transcription_completed_event import ( + ConversationItemInputAudioTranscriptionCompletedEvent, +) + +__all__ = ["RealtimeServerEvent"] + +RealtimeServerEvent: TypeAlias = Annotated[ + Union[ + ErrorEvent, + SessionCreatedEvent, + SessionUpdatedEvent, + ConversationCreatedEvent, + InputAudioBufferCommittedEvent, + InputAudioBufferClearedEvent, + InputAudioBufferSpeechStartedEvent, + InputAudioBufferSpeechStoppedEvent, + ConversationItemCreatedEvent, + ConversationItemInputAudioTranscriptionCompletedEvent, + ConversationItemInputAudioTranscriptionFailedEvent, + ConversationItemTruncatedEvent, + ConversationItemDeletedEvent, + ResponseCreatedEvent, + ResponseDoneEvent, + ResponseOutputItemAddedEvent, + ResponseOutputItemDoneEvent, + ResponseContentPartAddedEvent, + ResponseContentPartDoneEvent, + ResponseTextDeltaEvent, + ResponseTextDoneEvent, + ResponseAudioTranscriptDeltaEvent, + ResponseAudioTranscriptDoneEvent, + ResponseAudioDeltaEvent, + ResponseAudioDoneEvent, + ResponseFunctionCallArgumentsDeltaEvent, + ResponseFunctionCallArgumentsDoneEvent, + RateLimitsUpdatedEvent, + ], + PropertyInfo(discriminator="type"), +] diff --git a/src/openai/types/beta/realtime/response_audio_delta_event.py b/src/openai/types/beta/realtime/response_audio_delta_event.py new file mode 100644 index 0000000000..8e0128d942 --- /dev/null +++ b/src/openai/types/beta/realtime/response_audio_delta_event.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["ResponseAudioDeltaEvent"] + + +class ResponseAudioDeltaEvent(BaseModel): + content_index: int + """The index of the content part in the item's content array.""" + + delta: str + """Base64-encoded audio data delta.""" + + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the item.""" + + output_index: int + """The index of the output item in the response.""" + + response_id: str + """The ID of the response.""" + + type: Literal["response.audio.delta"] + """The event type, must be `response.audio.delta`.""" diff --git a/src/openai/types/beta/realtime/response_audio_done_event.py b/src/openai/types/beta/realtime/response_audio_done_event.py new file mode 100644 index 0000000000..68e78bc778 --- /dev/null +++ b/src/openai/types/beta/realtime/response_audio_done_event.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["ResponseAudioDoneEvent"] + + +class ResponseAudioDoneEvent(BaseModel): + content_index: int + """The index of the content part in the item's content array.""" + + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the item.""" + + output_index: int + """The index of the output item in the response.""" + + response_id: str + """The ID of the response.""" + + type: Literal["response.audio.done"] + """The event type, must be `response.audio.done`.""" diff --git a/src/openai/types/beta/realtime/response_audio_transcript_delta_event.py b/src/openai/types/beta/realtime/response_audio_transcript_delta_event.py new file mode 100644 index 0000000000..3609948d10 --- /dev/null +++ b/src/openai/types/beta/realtime/response_audio_transcript_delta_event.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["ResponseAudioTranscriptDeltaEvent"] + + +class ResponseAudioTranscriptDeltaEvent(BaseModel): + content_index: int + """The index of the content part in the item's content array.""" + + delta: str + """The transcript delta.""" + + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the item.""" + + output_index: int + """The index of the output item in the response.""" + + response_id: str + """The ID of the response.""" + + type: Literal["response.audio_transcript.delta"] + """The event type, must be `response.audio_transcript.delta`.""" diff --git a/src/openai/types/beta/realtime/response_audio_transcript_done_event.py b/src/openai/types/beta/realtime/response_audio_transcript_done_event.py new file mode 100644 index 0000000000..4e4436a95f --- /dev/null +++ b/src/openai/types/beta/realtime/response_audio_transcript_done_event.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["ResponseAudioTranscriptDoneEvent"] + + +class ResponseAudioTranscriptDoneEvent(BaseModel): + content_index: int + """The index of the content part in the item's content array.""" + + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the item.""" + + output_index: int + """The index of the output item in the response.""" + + response_id: str + """The ID of the response.""" + + transcript: str + """The final transcript of the audio.""" + + type: Literal["response.audio_transcript.done"] + """The event type, must be `response.audio_transcript.done`.""" diff --git a/src/openai/types/beta/realtime/response_cancel_event.py b/src/openai/types/beta/realtime/response_cancel_event.py new file mode 100644 index 0000000000..c5ff991e9a --- /dev/null +++ b/src/openai/types/beta/realtime/response_cancel_event.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["ResponseCancelEvent"] + + +class ResponseCancelEvent(BaseModel): + type: Literal["response.cancel"] + """The event type, must be `response.cancel`.""" + + event_id: Optional[str] = None + """Optional client-generated ID used to identify this event.""" + + response_id: Optional[str] = None + """ + A specific response ID to cancel - if not provided, will cancel an in-progress + response in the default conversation. + """ diff --git a/src/openai/types/beta/realtime/response_cancel_event_param.py b/src/openai/types/beta/realtime/response_cancel_event_param.py new file mode 100644 index 0000000000..f33740730a --- /dev/null +++ b/src/openai/types/beta/realtime/response_cancel_event_param.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ResponseCancelEventParam"] + + +class ResponseCancelEventParam(TypedDict, total=False): + type: Required[Literal["response.cancel"]] + """The event type, must be `response.cancel`.""" + + event_id: str + """Optional client-generated ID used to identify this event.""" + + response_id: str + """ + A specific response ID to cancel - if not provided, will cancel an in-progress + response in the default conversation. + """ diff --git a/src/openai/types/beta/realtime/response_content_part_added_event.py b/src/openai/types/beta/realtime/response_content_part_added_event.py new file mode 100644 index 0000000000..45c8f20f97 --- /dev/null +++ b/src/openai/types/beta/realtime/response_content_part_added_event.py @@ -0,0 +1,45 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["ResponseContentPartAddedEvent", "Part"] + + +class Part(BaseModel): + audio: Optional[str] = None + """Base64-encoded audio data (if type is "audio").""" + + text: Optional[str] = None + """The text content (if type is "text").""" + + transcript: Optional[str] = None + """The transcript of the audio (if type is "audio").""" + + type: Optional[Literal["text", "audio"]] = None + """The content type ("text", "audio").""" + + +class ResponseContentPartAddedEvent(BaseModel): + content_index: int + """The index of the content part in the item's content array.""" + + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the item to which the content part was added.""" + + output_index: int + """The index of the output item in the response.""" + + part: Part + """The content part that was added.""" + + response_id: str + """The ID of the response.""" + + type: Literal["response.content_part.added"] + """The event type, must be `response.content_part.added`.""" diff --git a/src/openai/types/beta/realtime/response_content_part_done_event.py b/src/openai/types/beta/realtime/response_content_part_done_event.py new file mode 100644 index 0000000000..3d16116106 --- /dev/null +++ b/src/openai/types/beta/realtime/response_content_part_done_event.py @@ -0,0 +1,45 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["ResponseContentPartDoneEvent", "Part"] + + +class Part(BaseModel): + audio: Optional[str] = None + """Base64-encoded audio data (if type is "audio").""" + + text: Optional[str] = None + """The text content (if type is "text").""" + + transcript: Optional[str] = None + """The transcript of the audio (if type is "audio").""" + + type: Optional[Literal["text", "audio"]] = None + """The content type ("text", "audio").""" + + +class ResponseContentPartDoneEvent(BaseModel): + content_index: int + """The index of the content part in the item's content array.""" + + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the item.""" + + output_index: int + """The index of the output item in the response.""" + + part: Part + """The content part that is done.""" + + response_id: str + """The ID of the response.""" + + type: Literal["response.content_part.done"] + """The event type, must be `response.content_part.done`.""" diff --git a/src/openai/types/beta/realtime/response_create_event.py b/src/openai/types/beta/realtime/response_create_event.py new file mode 100644 index 0000000000..00ba1e5dad --- /dev/null +++ b/src/openai/types/beta/realtime/response_create_event.py @@ -0,0 +1,115 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal + +from ...._models import BaseModel +from .conversation_item import ConversationItem + +__all__ = ["ResponseCreateEvent", "Response", "ResponseTool"] + + +class ResponseTool(BaseModel): + description: Optional[str] = None + """ + The description of the function, including guidance on when and how to call it, + and guidance about what to tell the user when calling (if anything). + """ + + name: Optional[str] = None + """The name of the function.""" + + parameters: Optional[object] = None + """Parameters of the function in JSON Schema.""" + + type: Optional[Literal["function"]] = None + """The type of the tool, i.e. `function`.""" + + +class Response(BaseModel): + conversation: Union[str, Literal["auto", "none"], None] = None + """Controls which conversation the response is added to. + + Currently supports `auto` and `none`, with `auto` as the default value. The + `auto` value means that the contents of the response will be added to the + default conversation. Set this to `none` to create an out-of-band response which + will not add items to default conversation. + """ + + input: Optional[List[ConversationItem]] = None + """Input items to include in the prompt for the model. + + Creates a new context for this response, without including the default + conversation. Can include references to items from the default conversation. + """ + + instructions: Optional[str] = None + """The default system instructions (i.e. + + system message) prepended to model calls. This field allows the client to guide + the model on desired responses. The model can be instructed on response content + and format, (e.g. "be extremely succinct", "act friendly", "here are examples of + good responses") and on audio behavior (e.g. "talk quickly", "inject emotion + into your voice", "laugh frequently"). The instructions are not guaranteed to be + followed by the model, but they provide guidance to the model on the desired + behavior. + + Note that the server sets default instructions which will be used if this field + is not set and are visible in the `session.created` event at the start of the + session. + """ + + max_response_output_tokens: Union[int, Literal["inf"], None] = None + """ + Maximum number of output tokens for a single assistant response, inclusive of + tool calls. Provide an integer between 1 and 4096 to limit output tokens, or + `inf` for the maximum available tokens for a given model. Defaults to `inf`. + """ + + metadata: Optional[object] = None + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format. Keys can be a maximum of 64 characters long and values can be + a maximum of 512 characters long. + """ + + modalities: Optional[List[Literal["text", "audio"]]] = None + """The set of modalities the model can respond with. + + To disable audio, set this to ["text"]. + """ + + output_audio_format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None + """The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + + temperature: Optional[float] = None + """Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8.""" + + tool_choice: Optional[str] = None + """How the model chooses tools. + + Options are `auto`, `none`, `required`, or specify a function. + """ + + tools: Optional[List[ResponseTool]] = None + """Tools (functions) available to the model.""" + + voice: Optional[Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"]] = None + """The voice the model uses to respond. + + Voice cannot be changed during the session once the model has responded with + audio at least once. Current voice options are `alloy`, `ash`, `ballad`, + `coral`, `echo` `sage`, `shimmer` and `verse`. + """ + + +class ResponseCreateEvent(BaseModel): + type: Literal["response.create"] + """The event type, must be `response.create`.""" + + event_id: Optional[str] = None + """Optional client-generated ID used to identify this event.""" + + response: Optional[Response] = None + """Create a new Realtime response with these parameters""" diff --git a/src/openai/types/beta/realtime/response_create_event_param.py b/src/openai/types/beta/realtime/response_create_event_param.py new file mode 100644 index 0000000000..7c92b32df1 --- /dev/null +++ b/src/openai/types/beta/realtime/response_create_event_param.py @@ -0,0 +1,116 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypedDict + +from .conversation_item_param import ConversationItemParam + +__all__ = ["ResponseCreateEventParam", "Response", "ResponseTool"] + + +class ResponseTool(TypedDict, total=False): + description: str + """ + The description of the function, including guidance on when and how to call it, + and guidance about what to tell the user when calling (if anything). + """ + + name: str + """The name of the function.""" + + parameters: object + """Parameters of the function in JSON Schema.""" + + type: Literal["function"] + """The type of the tool, i.e. `function`.""" + + +class Response(TypedDict, total=False): + conversation: Union[str, Literal["auto", "none"]] + """Controls which conversation the response is added to. + + Currently supports `auto` and `none`, with `auto` as the default value. The + `auto` value means that the contents of the response will be added to the + default conversation. Set this to `none` to create an out-of-band response which + will not add items to default conversation. + """ + + input: Iterable[ConversationItemParam] + """Input items to include in the prompt for the model. + + Creates a new context for this response, without including the default + conversation. Can include references to items from the default conversation. + """ + + instructions: str + """The default system instructions (i.e. + + system message) prepended to model calls. This field allows the client to guide + the model on desired responses. The model can be instructed on response content + and format, (e.g. "be extremely succinct", "act friendly", "here are examples of + good responses") and on audio behavior (e.g. "talk quickly", "inject emotion + into your voice", "laugh frequently"). The instructions are not guaranteed to be + followed by the model, but they provide guidance to the model on the desired + behavior. + + Note that the server sets default instructions which will be used if this field + is not set and are visible in the `session.created` event at the start of the + session. + """ + + max_response_output_tokens: Union[int, Literal["inf"]] + """ + Maximum number of output tokens for a single assistant response, inclusive of + tool calls. Provide an integer between 1 and 4096 to limit output tokens, or + `inf` for the maximum available tokens for a given model. Defaults to `inf`. + """ + + metadata: Optional[object] + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format. Keys can be a maximum of 64 characters long and values can be + a maximum of 512 characters long. + """ + + modalities: List[Literal["text", "audio"]] + """The set of modalities the model can respond with. + + To disable audio, set this to ["text"]. + """ + + output_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] + """The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + + temperature: float + """Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8.""" + + tool_choice: str + """How the model chooses tools. + + Options are `auto`, `none`, `required`, or specify a function. + """ + + tools: Iterable[ResponseTool] + """Tools (functions) available to the model.""" + + voice: Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"] + """The voice the model uses to respond. + + Voice cannot be changed during the session once the model has responded with + audio at least once. Current voice options are `alloy`, `ash`, `ballad`, + `coral`, `echo` `sage`, `shimmer` and `verse`. + """ + + +class ResponseCreateEventParam(TypedDict, total=False): + type: Required[Literal["response.create"]] + """The event type, must be `response.create`.""" + + event_id: str + """Optional client-generated ID used to identify this event.""" + + response: Response + """Create a new Realtime response with these parameters""" diff --git a/src/openai/types/beta/realtime/response_created_event.py b/src/openai/types/beta/realtime/response_created_event.py new file mode 100644 index 0000000000..a4990cf095 --- /dev/null +++ b/src/openai/types/beta/realtime/response_created_event.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel +from .realtime_response import RealtimeResponse + +__all__ = ["ResponseCreatedEvent"] + + +class ResponseCreatedEvent(BaseModel): + event_id: str + """The unique ID of the server event.""" + + response: RealtimeResponse + """The response resource.""" + + type: Literal["response.created"] + """The event type, must be `response.created`.""" diff --git a/src/openai/types/beta/realtime/response_done_event.py b/src/openai/types/beta/realtime/response_done_event.py new file mode 100644 index 0000000000..9e655184b6 --- /dev/null +++ b/src/openai/types/beta/realtime/response_done_event.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel +from .realtime_response import RealtimeResponse + +__all__ = ["ResponseDoneEvent"] + + +class ResponseDoneEvent(BaseModel): + event_id: str + """The unique ID of the server event.""" + + response: RealtimeResponse + """The response resource.""" + + type: Literal["response.done"] + """The event type, must be `response.done`.""" diff --git a/src/openai/types/beta/realtime/response_function_call_arguments_delta_event.py b/src/openai/types/beta/realtime/response_function_call_arguments_delta_event.py new file mode 100644 index 0000000000..cdbb64e658 --- /dev/null +++ b/src/openai/types/beta/realtime/response_function_call_arguments_delta_event.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["ResponseFunctionCallArgumentsDeltaEvent"] + + +class ResponseFunctionCallArgumentsDeltaEvent(BaseModel): + call_id: str + """The ID of the function call.""" + + delta: str + """The arguments delta as a JSON string.""" + + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the function call item.""" + + output_index: int + """The index of the output item in the response.""" + + response_id: str + """The ID of the response.""" + + type: Literal["response.function_call_arguments.delta"] + """The event type, must be `response.function_call_arguments.delta`.""" diff --git a/src/openai/types/beta/realtime/response_function_call_arguments_done_event.py b/src/openai/types/beta/realtime/response_function_call_arguments_done_event.py new file mode 100644 index 0000000000..0a5db53323 --- /dev/null +++ b/src/openai/types/beta/realtime/response_function_call_arguments_done_event.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["ResponseFunctionCallArgumentsDoneEvent"] + + +class ResponseFunctionCallArgumentsDoneEvent(BaseModel): + arguments: str + """The final arguments as a JSON string.""" + + call_id: str + """The ID of the function call.""" + + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the function call item.""" + + output_index: int + """The index of the output item in the response.""" + + response_id: str + """The ID of the response.""" + + type: Literal["response.function_call_arguments.done"] + """The event type, must be `response.function_call_arguments.done`.""" diff --git a/src/openai/types/beta/realtime/response_output_item_added_event.py b/src/openai/types/beta/realtime/response_output_item_added_event.py new file mode 100644 index 0000000000..c89bfdc3be --- /dev/null +++ b/src/openai/types/beta/realtime/response_output_item_added_event.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel +from .conversation_item import ConversationItem + +__all__ = ["ResponseOutputItemAddedEvent"] + + +class ResponseOutputItemAddedEvent(BaseModel): + event_id: str + """The unique ID of the server event.""" + + item: ConversationItem + """The item to add to the conversation.""" + + output_index: int + """The index of the output item in the Response.""" + + response_id: str + """The ID of the Response to which the item belongs.""" + + type: Literal["response.output_item.added"] + """The event type, must be `response.output_item.added`.""" diff --git a/src/openai/types/beta/realtime/response_output_item_done_event.py b/src/openai/types/beta/realtime/response_output_item_done_event.py new file mode 100644 index 0000000000..b5910e22aa --- /dev/null +++ b/src/openai/types/beta/realtime/response_output_item_done_event.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel +from .conversation_item import ConversationItem + +__all__ = ["ResponseOutputItemDoneEvent"] + + +class ResponseOutputItemDoneEvent(BaseModel): + event_id: str + """The unique ID of the server event.""" + + item: ConversationItem + """The item to add to the conversation.""" + + output_index: int + """The index of the output item in the Response.""" + + response_id: str + """The ID of the Response to which the item belongs.""" + + type: Literal["response.output_item.done"] + """The event type, must be `response.output_item.done`.""" diff --git a/src/openai/types/beta/realtime/response_text_delta_event.py b/src/openai/types/beta/realtime/response_text_delta_event.py new file mode 100644 index 0000000000..c463b3c3d0 --- /dev/null +++ b/src/openai/types/beta/realtime/response_text_delta_event.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["ResponseTextDeltaEvent"] + + +class ResponseTextDeltaEvent(BaseModel): + content_index: int + """The index of the content part in the item's content array.""" + + delta: str + """The text delta.""" + + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the item.""" + + output_index: int + """The index of the output item in the response.""" + + response_id: str + """The ID of the response.""" + + type: Literal["response.text.delta"] + """The event type, must be `response.text.delta`.""" diff --git a/src/openai/types/beta/realtime/response_text_done_event.py b/src/openai/types/beta/realtime/response_text_done_event.py new file mode 100644 index 0000000000..020ff41d58 --- /dev/null +++ b/src/openai/types/beta/realtime/response_text_done_event.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["ResponseTextDoneEvent"] + + +class ResponseTextDoneEvent(BaseModel): + content_index: int + """The index of the content part in the item's content array.""" + + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the item.""" + + output_index: int + """The index of the output item in the response.""" + + response_id: str + """The ID of the response.""" + + text: str + """The final text content.""" + + type: Literal["response.text.done"] + """The event type, must be `response.text.done`.""" diff --git a/src/openai/types/beta/realtime/session.py b/src/openai/types/beta/realtime/session.py new file mode 100644 index 0000000000..09cdbb02bc --- /dev/null +++ b/src/openai/types/beta/realtime/session.py @@ -0,0 +1,148 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["Session", "InputAudioTranscription", "Tool", "TurnDetection"] + + +class InputAudioTranscription(BaseModel): + model: Optional[str] = None + """ + The model to use for transcription, `whisper-1` is the only currently supported + model. + """ + + +class Tool(BaseModel): + description: Optional[str] = None + """ + The description of the function, including guidance on when and how to call it, + and guidance about what to tell the user when calling (if anything). + """ + + name: Optional[str] = None + """The name of the function.""" + + parameters: Optional[object] = None + """Parameters of the function in JSON Schema.""" + + type: Optional[Literal["function"]] = None + """The type of the tool, i.e. `function`.""" + + +class TurnDetection(BaseModel): + prefix_padding_ms: Optional[int] = None + """Amount of audio to include before the VAD detected speech (in milliseconds). + + Defaults to 300ms. + """ + + silence_duration_ms: Optional[int] = None + """Duration of silence to detect speech stop (in milliseconds). + + Defaults to 500ms. With shorter values the model will respond more quickly, but + may jump in on short pauses from the user. + """ + + threshold: Optional[float] = None + """Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. + + A higher threshold will require louder audio to activate the model, and thus + might perform better in noisy environments. + """ + + type: Optional[Literal["server_vad"]] = None + """Type of turn detection, only `server_vad` is currently supported.""" + + +class Session(BaseModel): + id: Optional[str] = None + """Unique identifier for the session object.""" + + input_audio_format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None + """The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + + input_audio_transcription: Optional[InputAudioTranscription] = None + """ + Configuration for input audio transcription, defaults to off and can be set to + `null` to turn off once on. Input audio transcription is not native to the + model, since the model consumes audio directly. Transcription runs + asynchronously through Whisper and should be treated as rough guidance rather + than the representation understood by the model. + """ + + instructions: Optional[str] = None + """The default system instructions (i.e. + + system message) prepended to model calls. This field allows the client to guide + the model on desired responses. The model can be instructed on response content + and format, (e.g. "be extremely succinct", "act friendly", "here are examples of + good responses") and on audio behavior (e.g. "talk quickly", "inject emotion + into your voice", "laugh frequently"). The instructions are not guaranteed to be + followed by the model, but they provide guidance to the model on the desired + behavior. + + Note that the server sets default instructions which will be used if this field + is not set and are visible in the `session.created` event at the start of the + session. + """ + + max_response_output_tokens: Union[int, Literal["inf"], None] = None + """ + Maximum number of output tokens for a single assistant response, inclusive of + tool calls. Provide an integer between 1 and 4096 to limit output tokens, or + `inf` for the maximum available tokens for a given model. Defaults to `inf`. + """ + + modalities: Optional[List[Literal["text", "audio"]]] = None + """The set of modalities the model can respond with. + + To disable audio, set this to ["text"]. + """ + + model: Union[ + str, + Literal[ + "gpt-4o-realtime-preview", + "gpt-4o-realtime-preview-2024-10-01", + "gpt-4o-realtime-preview-2024-12-17", + "gpt-4o-mini-realtime-preview", + "gpt-4o-mini-realtime-preview-2024-12-17", + ], + None, + ] = None + """The Realtime model used for this session.""" + + output_audio_format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None + """The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + + temperature: Optional[float] = None + """Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8.""" + + tool_choice: Optional[str] = None + """How the model chooses tools. + + Options are `auto`, `none`, `required`, or specify a function. + """ + + tools: Optional[List[Tool]] = None + """Tools (functions) available to the model.""" + + turn_detection: Optional[TurnDetection] = None + """Configuration for turn detection. + + Can be set to `null` to turn off. Server VAD means that the model will detect + the start and end of speech based on audio volume and respond at the end of user + speech. + """ + + voice: Optional[Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"]] = None + """The voice the model uses to respond. + + Voice cannot be changed during the session once the model has responded with + audio at least once. Current voice options are `alloy`, `ash`, `ballad`, + `coral`, `echo` `sage`, `shimmer` and `verse`. + """ diff --git a/src/openai/types/beta/realtime/session_created_event.py b/src/openai/types/beta/realtime/session_created_event.py new file mode 100644 index 0000000000..baf6af388b --- /dev/null +++ b/src/openai/types/beta/realtime/session_created_event.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from .session import Session +from ...._models import BaseModel + +__all__ = ["SessionCreatedEvent"] + + +class SessionCreatedEvent(BaseModel): + event_id: str + """The unique ID of the server event.""" + + session: Session + """Realtime session object configuration.""" + + type: Literal["session.created"] + """The event type, must be `session.created`.""" diff --git a/src/openai/types/beta/realtime/session_update_event.py b/src/openai/types/beta/realtime/session_update_event.py new file mode 100644 index 0000000000..c04220aa25 --- /dev/null +++ b/src/openai/types/beta/realtime/session_update_event.py @@ -0,0 +1,158 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["SessionUpdateEvent", "Session", "SessionInputAudioTranscription", "SessionTool", "SessionTurnDetection"] + + +class SessionInputAudioTranscription(BaseModel): + model: Optional[str] = None + """ + The model to use for transcription, `whisper-1` is the only currently supported + model. + """ + + +class SessionTool(BaseModel): + description: Optional[str] = None + """ + The description of the function, including guidance on when and how to call it, + and guidance about what to tell the user when calling (if anything). + """ + + name: Optional[str] = None + """The name of the function.""" + + parameters: Optional[object] = None + """Parameters of the function in JSON Schema.""" + + type: Optional[Literal["function"]] = None + """The type of the tool, i.e. `function`.""" + + +class SessionTurnDetection(BaseModel): + create_response: Optional[bool] = None + """Whether or not to automatically generate a response when VAD is enabled. + + `true` by default. + """ + + prefix_padding_ms: Optional[int] = None + """Amount of audio to include before the VAD detected speech (in milliseconds). + + Defaults to 300ms. + """ + + silence_duration_ms: Optional[int] = None + """Duration of silence to detect speech stop (in milliseconds). + + Defaults to 500ms. With shorter values the model will respond more quickly, but + may jump in on short pauses from the user. + """ + + threshold: Optional[float] = None + """Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. + + A higher threshold will require louder audio to activate the model, and thus + might perform better in noisy environments. + """ + + type: Optional[str] = None + """Type of turn detection, only `server_vad` is currently supported.""" + + +class Session(BaseModel): + model: Literal[ + "gpt-4o-realtime-preview", + "gpt-4o-realtime-preview-2024-10-01", + "gpt-4o-realtime-preview-2024-12-17", + "gpt-4o-mini-realtime-preview", + "gpt-4o-mini-realtime-preview-2024-12-17", + ] + """The Realtime model used for this session.""" + + input_audio_format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None + """The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + + input_audio_transcription: Optional[SessionInputAudioTranscription] = None + """ + Configuration for input audio transcription, defaults to off and can be set to + `null` to turn off once on. Input audio transcription is not native to the + model, since the model consumes audio directly. Transcription runs + asynchronously through Whisper and should be treated as rough guidance rather + than the representation understood by the model. + """ + + instructions: Optional[str] = None + """The default system instructions (i.e. + + system message) prepended to model calls. This field allows the client to guide + the model on desired responses. The model can be instructed on response content + and format, (e.g. "be extremely succinct", "act friendly", "here are examples of + good responses") and on audio behavior (e.g. "talk quickly", "inject emotion + into your voice", "laugh frequently"). The instructions are not guaranteed to be + followed by the model, but they provide guidance to the model on the desired + behavior. + + Note that the server sets default instructions which will be used if this field + is not set and are visible in the `session.created` event at the start of the + session. + """ + + max_response_output_tokens: Union[int, Literal["inf"], None] = None + """ + Maximum number of output tokens for a single assistant response, inclusive of + tool calls. Provide an integer between 1 and 4096 to limit output tokens, or + `inf` for the maximum available tokens for a given model. Defaults to `inf`. + """ + + modalities: Optional[List[Literal["text", "audio"]]] = None + """The set of modalities the model can respond with. + + To disable audio, set this to ["text"]. + """ + + output_audio_format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None + """The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + + temperature: Optional[float] = None + """Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8.""" + + tool_choice: Optional[str] = None + """How the model chooses tools. + + Options are `auto`, `none`, `required`, or specify a function. + """ + + tools: Optional[List[SessionTool]] = None + """Tools (functions) available to the model.""" + + turn_detection: Optional[SessionTurnDetection] = None + """Configuration for turn detection. + + Can be set to `null` to turn off. Server VAD means that the model will detect + the start and end of speech based on audio volume and respond at the end of user + speech. + """ + + voice: Optional[Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"]] = None + """The voice the model uses to respond. + + Voice cannot be changed during the session once the model has responded with + audio at least once. Current voice options are `alloy`, `ash`, `ballad`, + `coral`, `echo` `sage`, `shimmer` and `verse`. + """ + + +class SessionUpdateEvent(BaseModel): + session: Session + """Realtime session object configuration.""" + + type: Literal["session.update"] + """The event type, must be `session.update`.""" + + event_id: Optional[str] = None + """Optional client-generated ID used to identify this event.""" diff --git a/src/openai/types/beta/realtime/session_update_event_param.py b/src/openai/types/beta/realtime/session_update_event_param.py new file mode 100644 index 0000000000..aa06069b04 --- /dev/null +++ b/src/openai/types/beta/realtime/session_update_event_param.py @@ -0,0 +1,166 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union, Iterable +from typing_extensions import Literal, Required, TypedDict + +__all__ = [ + "SessionUpdateEventParam", + "Session", + "SessionInputAudioTranscription", + "SessionTool", + "SessionTurnDetection", +] + + +class SessionInputAudioTranscription(TypedDict, total=False): + model: str + """ + The model to use for transcription, `whisper-1` is the only currently supported + model. + """ + + +class SessionTool(TypedDict, total=False): + description: str + """ + The description of the function, including guidance on when and how to call it, + and guidance about what to tell the user when calling (if anything). + """ + + name: str + """The name of the function.""" + + parameters: object + """Parameters of the function in JSON Schema.""" + + type: Literal["function"] + """The type of the tool, i.e. `function`.""" + + +class SessionTurnDetection(TypedDict, total=False): + create_response: bool + """Whether or not to automatically generate a response when VAD is enabled. + + `true` by default. + """ + + prefix_padding_ms: int + """Amount of audio to include before the VAD detected speech (in milliseconds). + + Defaults to 300ms. + """ + + silence_duration_ms: int + """Duration of silence to detect speech stop (in milliseconds). + + Defaults to 500ms. With shorter values the model will respond more quickly, but + may jump in on short pauses from the user. + """ + + threshold: float + """Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. + + A higher threshold will require louder audio to activate the model, and thus + might perform better in noisy environments. + """ + + type: str + """Type of turn detection, only `server_vad` is currently supported.""" + + +class Session(TypedDict, total=False): + model: Required[ + Literal[ + "gpt-4o-realtime-preview", + "gpt-4o-realtime-preview-2024-10-01", + "gpt-4o-realtime-preview-2024-12-17", + "gpt-4o-mini-realtime-preview", + "gpt-4o-mini-realtime-preview-2024-12-17", + ] + ] + """The Realtime model used for this session.""" + + input_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] + """The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + + input_audio_transcription: SessionInputAudioTranscription + """ + Configuration for input audio transcription, defaults to off and can be set to + `null` to turn off once on. Input audio transcription is not native to the + model, since the model consumes audio directly. Transcription runs + asynchronously through Whisper and should be treated as rough guidance rather + than the representation understood by the model. + """ + + instructions: str + """The default system instructions (i.e. + + system message) prepended to model calls. This field allows the client to guide + the model on desired responses. The model can be instructed on response content + and format, (e.g. "be extremely succinct", "act friendly", "here are examples of + good responses") and on audio behavior (e.g. "talk quickly", "inject emotion + into your voice", "laugh frequently"). The instructions are not guaranteed to be + followed by the model, but they provide guidance to the model on the desired + behavior. + + Note that the server sets default instructions which will be used if this field + is not set and are visible in the `session.created` event at the start of the + session. + """ + + max_response_output_tokens: Union[int, Literal["inf"]] + """ + Maximum number of output tokens for a single assistant response, inclusive of + tool calls. Provide an integer between 1 and 4096 to limit output tokens, or + `inf` for the maximum available tokens for a given model. Defaults to `inf`. + """ + + modalities: List[Literal["text", "audio"]] + """The set of modalities the model can respond with. + + To disable audio, set this to ["text"]. + """ + + output_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] + """The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + + temperature: float + """Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8.""" + + tool_choice: str + """How the model chooses tools. + + Options are `auto`, `none`, `required`, or specify a function. + """ + + tools: Iterable[SessionTool] + """Tools (functions) available to the model.""" + + turn_detection: SessionTurnDetection + """Configuration for turn detection. + + Can be set to `null` to turn off. Server VAD means that the model will detect + the start and end of speech based on audio volume and respond at the end of user + speech. + """ + + voice: Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"] + """The voice the model uses to respond. + + Voice cannot be changed during the session once the model has responded with + audio at least once. Current voice options are `alloy`, `ash`, `ballad`, + `coral`, `echo` `sage`, `shimmer` and `verse`. + """ + + +class SessionUpdateEventParam(TypedDict, total=False): + session: Required[Session] + """Realtime session object configuration.""" + + type: Required[Literal["session.update"]] + """The event type, must be `session.update`.""" + + event_id: str + """Optional client-generated ID used to identify this event.""" diff --git a/src/openai/types/beta/realtime/session_updated_event.py b/src/openai/types/beta/realtime/session_updated_event.py new file mode 100644 index 0000000000..b9b6488eb3 --- /dev/null +++ b/src/openai/types/beta/realtime/session_updated_event.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from .session import Session +from ...._models import BaseModel + +__all__ = ["SessionUpdatedEvent"] + + +class SessionUpdatedEvent(BaseModel): + event_id: str + """The unique ID of the server event.""" + + session: Session + """Realtime session object configuration.""" + + type: Literal["session.updated"] + """The event type, must be `session.updated`.""" diff --git a/src/openai/types/websocket_connection_options.py b/src/openai/types/websocket_connection_options.py new file mode 100644 index 0000000000..40fd24ab03 --- /dev/null +++ b/src/openai/types/websocket_connection_options.py @@ -0,0 +1,36 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import TYPE_CHECKING +from typing_extensions import Sequence, TypedDict + +if TYPE_CHECKING: + from websockets import Subprotocol + from websockets.extensions import ClientExtensionFactory + + +class WebsocketConnectionOptions(TypedDict, total=False): + """Websocket connection options copied from `websockets`. + + For example: https://websockets.readthedocs.io/en/stable/reference/asyncio/client.html#websockets.asyncio.client.connect + """ + + extensions: Sequence[ClientExtensionFactory] | None + """List of supported extensions, in order in which they should be negotiated and run.""" + + subprotocols: Sequence[Subprotocol] | None + """List of supported subprotocols, in order of decreasing preference.""" + + compression: str | None + """The “permessage-deflate” extension is enabled by default. Set compression to None to disable it. See the [compression guide](https://websockets.readthedocs.io/en/stable/topics/compression.html) for details.""" + + # limits + max_size: int | None + """Maximum size of incoming messages in bytes. None disables the limit.""" + + max_queue: int | None | tuple[int | None, int | None] + """High-water mark of the buffer where frames are received. It defaults to 16 frames. The low-water mark defaults to max_queue // 4. You may pass a (high, low) tuple to set the high-water and low-water marks. If you want to disable flow control entirely, you may set it to None, although that’s a bad idea.""" + + write_limit: int | tuple[int, int | None] + """High-water mark of write buffer in bytes. It is passed to set_write_buffer_limits(). It defaults to 32 KiB. You may pass a (high, low) tuple to set the high-water and low-water marks.""" diff --git a/tests/api_resources/beta/test_realtime.py b/tests/api_resources/beta/test_realtime.py new file mode 100644 index 0000000000..537017ffd3 --- /dev/null +++ b/tests/api_resources/beta/test_realtime.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os + +import pytest + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestRealtime: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + +class TestAsyncRealtime: + parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) From a6a94e08741acdfc9b371dc4c47cbc7b8613cd88 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Tue, 17 Dec 2024 18:06:18 +0000 Subject: [PATCH 126/769] fix: add reasoning_effort to all methods --- src/openai/resources/beta/chat/completions.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/openai/resources/beta/chat/completions.py b/src/openai/resources/beta/chat/completions.py index 38c09ce8dd..48cb13f7a6 100644 --- a/src/openai/resources/beta/chat/completions.py +++ b/src/openai/resources/beta/chat/completions.py @@ -15,7 +15,10 @@ from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper from ...._streaming import Stream -from ....types.chat import completion_create_params +from ....types.chat import ( + ChatCompletionReasoningEffort, + completion_create_params, +) from ...._base_client import make_request_options from ....lib._parsing import ( ResponseFormatT, @@ -79,6 +82,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, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str]] | NotGiven = NOT_GIVEN, @@ -173,6 +177,7 @@ def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseForma "parallel_tool_calls": parallel_tool_calls, "prediction": prediction, "presence_penalty": presence_penalty, + "reasoning_effort": reasoning_effort, "response_format": _type_to_response_format(response_format), "seed": seed, "service_tier": service_tier, @@ -222,6 +227,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, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str]] | NotGiven = NOT_GIVEN, @@ -287,6 +293,7 @@ def stream( parallel_tool_calls=parallel_tool_calls, prediction=prediction, presence_penalty=presence_penalty, + reasoning_effort=reasoning_effort, seed=seed, service_tier=service_tier, store=store, @@ -350,6 +357,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, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str]] | NotGiven = NOT_GIVEN, @@ -444,6 +452,7 @@ def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseForma "parallel_tool_calls": parallel_tool_calls, "prediction": prediction, "presence_penalty": presence_penalty, + "reasoning_effort": reasoning_effort, "response_format": _type_to_response_format(response_format), "seed": seed, "service_tier": service_tier, @@ -493,6 +502,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, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str]] | NotGiven = NOT_GIVEN, @@ -559,6 +569,7 @@ def stream( parallel_tool_calls=parallel_tool_calls, prediction=prediction, presence_penalty=presence_penalty, + reasoning_effort=reasoning_effort, seed=seed, service_tier=service_tier, stop=stop, From 488ec04b7b79d3a5597c910fd585df18e922665f Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Mon, 16 Dec 2024 19:16:25 +0000 Subject: [PATCH 127/769] docs: add examples + guidance on Realtime API support --- README.md | 61 ++++++ examples/realtime/audio_util.py | 142 +++++++++++++ examples/realtime/push_to_talk_app.py | 281 ++++++++++++++++++++++++++ mypy.ini | 5 +- pyproject.toml | 5 + 5 files changed, 493 insertions(+), 1 deletion(-) create mode 100644 examples/realtime/audio_util.py create mode 100755 examples/realtime/push_to_talk_app.py diff --git a/README.md b/README.md index cbcfdb4447..4c3ba87c97 100644 --- a/README.md +++ b/README.md @@ -258,6 +258,67 @@ We recommend that you always instantiate a client (e.g., with `client = OpenAI() - It's harder to mock for testing purposes - It's not possible to control cleanup of network connections +## Realtime API beta + +The Realtime API enables you to build low-latency, multi-modal conversational experiences. It currently supports text and audio as both input and output, as well as [function calling](https://platform.openai.com/docs/guides/function-calling) through a WebSocket connection. + +Under the hood the SDK uses the [`websockets`](https://websockets.readthedocs.io/en/stable/) library to manage connections. + +The Realtime API works through a combination of client-sent events and server-sent events. Clients can send events to do things like update session configuration or send text and audio inputs. Server events confirm when audio responses have completed, or when a text response from the model has been received. A full event reference can be found [here](platform.openai.com/docs/api-reference/realtime-client-events) and a guide can be found [here](https://platform.openai.com/docs/guides/realtime). + +Basic text based example: + +```py +import asyncio +from openai import AsyncOpenAI + +async def main(): + client = AsyncOpenAI() + + async with client.beta.realtime.connect(model="gpt-4o-realtime-preview-2024-10-01") as connection: + await connection.session.update(session={'modalities': ['text']}) + + await connection.conversation.item.create( + item={ + "type": "message", + "role": "user", + "content": [{"type": "input_text", "text": "Say hello!"}], + } + ) + await connection.response.create() + + async for event in connection: + if event.type == 'response.text.delta': + print(event.delta, flush=True, end="") + + elif event.type == 'response.text.done': + print() + + elif event.type == "response.done": + break + +asyncio.run(main()) +``` + +However the real magic of the Realtime API is handling audio inputs / outputs, see this example [TUI script](https://github.com/stainless-sdks/openai-python/blob/robert/realtime-docs-preview/examples/realtime/push_to_talk_app.py) for a fully fledged example. + +### Realtime error handling + +Whenever an error occurs, the Realtime API will send an [`error` event](https://platform.openai.com/docs/guides/realtime/realtime-api-beta#handling-errors) and the connection will stay open and remain usable. This means you need to handle it yourself, as *no errors are raised directly* by the SDK when an `error` event comes in. + +```py +client = AsyncOpenAI() + +async with client.beta.realtime.connect(model="gpt-4o-realtime-preview-2024-10-01") as connection: + ... + async for event in connection: + if event.type == 'error': + print(event.error.type) + print(event.error.code) + print(event.error.event_id) + print(event.error.message) +``` + ## Using types Nested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev) which also provide helper methods for things like: diff --git a/examples/realtime/audio_util.py b/examples/realtime/audio_util.py new file mode 100644 index 0000000000..b073cc45be --- /dev/null +++ b/examples/realtime/audio_util.py @@ -0,0 +1,142 @@ +from __future__ import annotations + +import io +import base64 +import asyncio +import threading +from typing import Callable, Awaitable + +import numpy as np +import pyaudio +import sounddevice as sd +from pydub import AudioSegment + +from openai.resources.beta.realtime.realtime import AsyncRealtimeConnection + +CHUNK_LENGTH_S = 0.05 # 100ms +SAMPLE_RATE = 24000 +FORMAT = pyaudio.paInt16 +CHANNELS = 1 + +# pyright: reportUnknownMemberType=false, reportUnknownVariableType=false, reportUnknownArgumentType=false + + +def audio_to_pcm16_base64(audio_bytes: bytes) -> bytes: + # load the audio file from the byte stream + audio = AudioSegment.from_file(io.BytesIO(audio_bytes)) + print(f"Loaded audio: {audio.frame_rate=} {audio.channels=} {audio.sample_width=} {audio.frame_width=}") + # resample to 24kHz mono pcm16 + pcm_audio = audio.set_frame_rate(SAMPLE_RATE).set_channels(CHANNELS).set_sample_width(2).raw_data + return pcm_audio + + +class AudioPlayerAsync: + def __init__(self): + self.queue = [] + self.lock = threading.Lock() + self.stream = sd.OutputStream( + callback=self.callback, + samplerate=SAMPLE_RATE, + channels=CHANNELS, + dtype=np.int16, + blocksize=int(CHUNK_LENGTH_S * SAMPLE_RATE), + ) + self.playing = False + self._frame_count = 0 + + def callback(self, outdata, frames, time, status): # noqa + with self.lock: + data = np.empty(0, dtype=np.int16) + + # get next item from queue if there is still space in the buffer + while len(data) < frames and len(self.queue) > 0: + item = self.queue.pop(0) + frames_needed = frames - len(data) + data = np.concatenate((data, item[:frames_needed])) + if len(item) > frames_needed: + self.queue.insert(0, item[frames_needed:]) + + self._frame_count += len(data) + + # fill the rest of the frames with zeros if there is no more data + if len(data) < frames: + data = np.concatenate((data, np.zeros(frames - len(data), dtype=np.int16))) + + outdata[:] = data.reshape(-1, 1) + + def reset_frame_count(self): + self._frame_count = 0 + + def get_frame_count(self): + return self._frame_count + + def add_data(self, data: bytes): + with self.lock: + # bytes is pcm16 single channel audio data, convert to numpy array + np_data = np.frombuffer(data, dtype=np.int16) + self.queue.append(np_data) + if not self.playing: + self.start() + + def start(self): + self.playing = True + self.stream.start() + + def stop(self): + self.playing = False + self.stream.stop() + with self.lock: + self.queue = [] + + def terminate(self): + self.stream.close() + + +async def send_audio_worker_sounddevice( + connection: AsyncRealtimeConnection, + should_send: Callable[[], bool] | None = None, + start_send: Callable[[], Awaitable[None]] | None = None, +): + sent_audio = False + + device_info = sd.query_devices() + print(device_info) + + read_size = int(SAMPLE_RATE * 0.02) + + stream = sd.InputStream( + channels=CHANNELS, + samplerate=SAMPLE_RATE, + dtype="int16", + ) + stream.start() + + try: + while True: + if stream.read_available < read_size: + await asyncio.sleep(0) + continue + + data, _ = stream.read(read_size) + + if should_send() if should_send else True: + if not sent_audio and start_send: + await start_send() + await connection.send( + {"type": "input_audio_buffer.append", "audio": base64.b64encode(data).decode("utf-8")} + ) + sent_audio = True + + elif sent_audio: + print("Done, triggering inference") + await connection.send({"type": "input_audio_buffer.commit"}) + await connection.send({"type": "response.create", "response": {}}) + sent_audio = False + + await asyncio.sleep(0) + + except KeyboardInterrupt: + pass + finally: + stream.stop() + stream.close() diff --git a/examples/realtime/push_to_talk_app.py b/examples/realtime/push_to_talk_app.py new file mode 100755 index 0000000000..d46945a8ed --- /dev/null +++ b/examples/realtime/push_to_talk_app.py @@ -0,0 +1,281 @@ +#!/usr/bin/env uv run +#################################################################### +# Sample TUI app with a push to talk interface to the Realtime API # +# If you have `uv` installed and the `OPENAI_API_KEY` # +# environment variable set, you can run this example with just # +# # +# `./examples/realtime/push_to_talk_app.py` # +#################################################################### +# +# /// script +# requires-python = ">=3.9" +# dependencies = [ +# "textual", +# "numpy", +# "pyaudio", +# "pydub", +# "sounddevice", +# "openai[realtime]", +# ] +# +# [tool.uv.sources] +# openai = { path = "../../", editable = true } +# /// +from __future__ import annotations + +import base64 +import asyncio +from typing import Any, cast +from typing_extensions import override + +from textual import events +from audio_util import CHANNELS, SAMPLE_RATE, AudioPlayerAsync +from textual.app import App, ComposeResult +from textual.widgets import Button, Static, RichLog +from textual.reactive import reactive +from textual.containers import Container + +from openai import AsyncOpenAI +from openai.types.beta.realtime.session import Session +from openai.resources.beta.realtime.realtime import AsyncRealtimeConnection + + +class SessionDisplay(Static): + """A widget that shows the current session ID.""" + + session_id = reactive("") + + @override + def render(self) -> str: + return f"Session ID: {self.session_id}" if self.session_id else "Connecting..." + + +class AudioStatusIndicator(Static): + """A widget that shows the current audio recording status.""" + + is_recording = reactive(False) + + @override + def render(self) -> str: + status = ( + "🔴 Recording... (Press K to stop)" if self.is_recording else "⚪ Press K to start recording (Q to quit)" + ) + return status + + +class RealtimeApp(App[None]): + CSS = """ + Screen { + background: #1a1b26; /* Dark blue-grey background */ + } + + Container { + border: double rgb(91, 164, 91); + } + + Horizontal { + width: 100%; + } + + #input-container { + height: 5; /* Explicit height for input container */ + margin: 1 1; + padding: 1 2; + } + + Input { + width: 80%; + height: 3; /* Explicit height for input */ + } + + Button { + width: 20%; + height: 3; /* Explicit height for button */ + } + + #bottom-pane { + width: 100%; + height: 82%; /* Reduced to make room for session display */ + border: round rgb(205, 133, 63); + content-align: center middle; + } + + #status-indicator { + height: 3; + content-align: center middle; + background: #2a2b36; + border: solid rgb(91, 164, 91); + margin: 1 1; + } + + #session-display { + height: 3; + content-align: center middle; + background: #2a2b36; + border: solid rgb(91, 164, 91); + margin: 1 1; + } + + Static { + color: white; + } + """ + + client: AsyncOpenAI + should_send_audio: asyncio.Event + audio_player: AudioPlayerAsync + last_audio_item_id: str | None + connection: AsyncRealtimeConnection | None + session: Session | None + connected: asyncio.Event + + def __init__(self) -> None: + super().__init__() + self.connection = None + self.session = None + self.client = AsyncOpenAI() + self.audio_player = AudioPlayerAsync() + self.last_audio_item_id = None + self.should_send_audio = asyncio.Event() + self.connected = asyncio.Event() + + @override + def compose(self) -> ComposeResult: + """Create child widgets for the app.""" + with Container(): + yield SessionDisplay(id="session-display") + yield AudioStatusIndicator(id="status-indicator") + yield RichLog(id="bottom-pane", wrap=True, highlight=True, markup=True) + + async def on_mount(self) -> None: + self.run_worker(self.handle_realtime_connection()) + self.run_worker(self.send_mic_audio()) + + async def handle_realtime_connection(self) -> None: + async with self.client.beta.realtime.connect(model="gpt-4o-realtime-preview-2024-10-01") as conn: + self.connection = conn + self.connected.set() + + # note: this is the default and can be omitted + # if you want to manually handle VAD yourself, then set `'turn_detection': None` + await conn.session.update(session={"turn_detection": {"type": "server_vad"}}) + + acc_items: dict[str, Any] = {} + + async for event in conn: + if event.type == "session.created": + self.session = event.session + session_display = self.query_one(SessionDisplay) + assert event.session.id is not None + session_display.session_id = event.session.id + continue + + if event.type == "session.updated": + self.session = event.session + continue + + if event.type == "response.audio.delta": + if event.item_id != self.last_audio_item_id: + self.audio_player.reset_frame_count() + self.last_audio_item_id = event.item_id + + bytes_data = base64.b64decode(event.delta) + self.audio_player.add_data(bytes_data) + continue + + if event.type == "response.audio_transcript.delta": + try: + text = acc_items[event.item_id] + except KeyError: + acc_items[event.item_id] = event.delta + else: + acc_items[event.item_id] = text + event.delta + + # Clear and update the entire content because RichLog otherwise treats each delta as a new line + bottom_pane = self.query_one("#bottom-pane", RichLog) + bottom_pane.clear() + bottom_pane.write(acc_items[event.item_id]) + continue + + async def _get_connection(self) -> AsyncRealtimeConnection: + await self.connected.wait() + assert self.connection is not None + return self.connection + + async def send_mic_audio(self) -> None: + import sounddevice as sd # type: ignore + + sent_audio = False + + device_info = sd.query_devices() + print(device_info) + + read_size = int(SAMPLE_RATE * 0.02) + + stream = sd.InputStream( + channels=CHANNELS, + samplerate=SAMPLE_RATE, + dtype="int16", + ) + stream.start() + + status_indicator = self.query_one(AudioStatusIndicator) + + try: + while True: + if stream.read_available < read_size: + await asyncio.sleep(0) + continue + + await self.should_send_audio.wait() + status_indicator.is_recording = True + + data, _ = stream.read(read_size) + + connection = await self._get_connection() + if not sent_audio: + asyncio.create_task(connection.send({"type": "response.cancel"})) + sent_audio = True + + await connection.input_audio_buffer.append(audio=base64.b64encode(cast(Any, data)).decode("utf-8")) + + await asyncio.sleep(0) + except KeyboardInterrupt: + pass + finally: + stream.stop() + stream.close() + + async def on_key(self, event: events.Key) -> None: + """Handle key press events.""" + if event.key == "enter": + self.query_one(Button).press() + return + + if event.key == "q": + self.exit() + return + + if event.key == "k": + status_indicator = self.query_one(AudioStatusIndicator) + if status_indicator.is_recording: + self.should_send_audio.clear() + status_indicator.is_recording = False + + if self.session and self.session.turn_detection is None: + # The default in the API is that the model will automatically detect when the user has + # stopped talking and then start responding itself. + # + # However if we're in manual `turn_detection` mode then we need to + # manually tell the model to commit the audio buffer and start responding. + conn = await self._get_connection() + await conn.input_audio_buffer.commit() + await conn.response.create() + else: + self.should_send_audio.set() + status_indicator.is_recording = True + + +if __name__ == "__main__": + app = RealtimeApp() + app.run() diff --git a/mypy.ini b/mypy.ini index 50e5add04b..1ea1fe909d 100644 --- a/mypy.ini +++ b/mypy.ini @@ -8,7 +8,10 @@ show_error_codes = True # # We also exclude our `tests` as mypy doesn't always infer # types correctly and Pyright will still catch any type errors. -exclude = ^(src/openai/_files\.py|src/openai/_utils/_logs\.py|_dev/.*\.py|tests/.*)$ + +# realtime examples use inline `uv` script dependencies +# which means it can't be type checked +exclude = ^(src/openai/_files\.py|_dev/.*\.py|tests/.*|src/openai/_utils/_logs\.py|examples/realtime/audio_util\.py|examples/realtime/push_to_talk_app\.py)$ strict_equality = True implicit_reexport = True diff --git a/pyproject.toml b/pyproject.toml index f83aff6fee..8e78257e67 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -157,6 +157,11 @@ exclude = [ "_dev", ".venv", ".nox", + + # uses inline `uv` script dependencies + # which means it can't be type checked + "examples/realtime/audio_util.py", + "examples/realtime/push_to_talk_app.py" ] reportImplicitOverride = true From 1b78f22ddf4b64542b39804882fca388a62355fb Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Dec 2024 18:19:24 +0000 Subject: [PATCH 128/769] release: 1.58.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 27 +++++++++++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index f9ae229e1a..452fa092bd 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.57.4" + ".": "1.58.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 02b7d0271d..5699c0cec2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,32 @@ # Changelog +## 1.58.0 (2024-12-17) + +Full Changelog: [v1.57.4...v1.58.0](https://github.com/openai/openai-python/compare/v1.57.4...v1.58.0) + +### Features + +* add Realtime API support ([#1958](https://github.com/openai/openai-python/issues/1958)) ([97d73cf](https://github.com/openai/openai-python/commit/97d73cf89935ca6098bb889a92f0ec2cdff16989)) +* **api:** new o1 and GPT-4o models + preference fine-tuning ([#1956](https://github.com/openai/openai-python/issues/1956)) ([ec22ffb](https://github.com/openai/openai-python/commit/ec22ffb129c524525caa33b088405d27c271e631)) + + +### Bug Fixes + +* add reasoning_effort to all methods ([8829c32](https://github.com/openai/openai-python/commit/8829c3202dbe790ca3646476c802ec55ed47d864)) +* **assistants:** correctly send `include` query param ([9a4c69c](https://github.com/openai/openai-python/commit/9a4c69c383bc6719b6521a485f2c7e62a9c036a9)) +* **cli/migrate:** change grit binaries prefix ([#1951](https://github.com/openai/openai-python/issues/1951)) ([1c396c9](https://github.com/openai/openai-python/commit/1c396c95b040fb3d1a2523b09eaad4ff62d96846)) + + +### Chores + +* **internal:** fix some typos ([#1955](https://github.com/openai/openai-python/issues/1955)) ([628dead](https://github.com/openai/openai-python/commit/628dead660c00435bf46e09081c7b90b7bbe4a8a)) + + +### Documentation + +* add examples + guidance on Realtime API support ([1cb00f8](https://github.com/openai/openai-python/commit/1cb00f8fed78052aacbb9e0fac997b6ba0d44d2a)) +* **readme:** example snippet for client context manager ([#1953](https://github.com/openai/openai-python/issues/1953)) ([ad80255](https://github.com/openai/openai-python/commit/ad802551d8aaf4e6eff711118676ec4e64392638)) + ## 1.57.4 (2024-12-13) Full Changelog: [v1.57.3...v1.57.4](https://github.com/openai/openai-python/compare/v1.57.3...v1.57.4) diff --git a/pyproject.toml b/pyproject.toml index 8e78257e67..1f2c9fe6c4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.57.4" +version = "1.58.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 5b82015017..7f2f4cafb8 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.57.4" # x-release-please-version +__version__ = "1.58.0" # x-release-please-version From 6935dfdcce9195a26e9ea83597d0c4f5c7631254 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Tue, 17 Dec 2024 19:54:33 +0000 Subject: [PATCH 129/769] docs(readme): fix example script link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4c3ba87c97..87837db175 100644 --- a/README.md +++ b/README.md @@ -300,7 +300,7 @@ async def main(): asyncio.run(main()) ``` -However the real magic of the Realtime API is handling audio inputs / outputs, see this example [TUI script](https://github.com/stainless-sdks/openai-python/blob/robert/realtime-docs-preview/examples/realtime/push_to_talk_app.py) for a fully fledged example. +However the real magic of the Realtime API is handling audio inputs / outputs, see this example [TUI script](https://github.com/openai/openai-python/blob/main/examples/realtime/push_to_talk_app.py) for a fully fledged example. ### Realtime error handling From 19ecaafeda91480d0dfd7ce44e7317220b9d48b6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Dec 2024 19:55:01 +0000 Subject: [PATCH 130/769] release: 1.58.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 452fa092bd..73a4167d2d 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.58.0" + ".": "1.58.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 5699c0cec2..6519747179 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.58.1 (2024-12-17) + +Full Changelog: [v1.58.0...v1.58.1](https://github.com/openai/openai-python/compare/v1.58.0...v1.58.1) + +### Documentation + +* **readme:** fix example script link ([23ba877](https://github.com/openai/openai-python/commit/23ba8778fd55e0f54f36685e9c5950b452d8e10c)) + ## 1.58.0 (2024-12-17) Full Changelog: [v1.57.4...v1.58.0](https://github.com/openai/openai-python/compare/v1.57.4...v1.58.0) diff --git a/pyproject.toml b/pyproject.toml index 1f2c9fe6c4..fd55cf2b5d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.58.0" +version = "1.58.1" 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 7f2f4cafb8..c08e68e11b 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.58.0" # x-release-please-version +__version__ = "1.58.1" # x-release-please-version From cacd374b850407b211d1f1e7740da0cf4e4d68d1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 18 Dec 2024 22:17:00 +0000 Subject: [PATCH 131/769] chore(realtime): update docstrings (#1964) --- .stats.yml | 2 +- src/openai/types/beta/realtime/conversation_item_content.py | 5 +++-- .../types/beta/realtime/conversation_item_content_param.py | 5 +++-- src/openai/types/beta/realtime/response_create_event.py | 3 ++- .../types/beta/realtime/response_create_event_param.py | 3 ++- 5 files changed, 11 insertions(+), 7 deletions(-) diff --git a/.stats.yml b/.stats.yml index 12219ccaa1..1a7a7a5269 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-0d64ca9e45f51b4279f87b205eeb3a3576df98407698ce053f2e2302c1c08df1.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-a39aca84ed97ebafb707ebd5221e2787c5a42ff3d98f2ffaea8a0dcd84cbcbcb.yml diff --git a/src/openai/types/beta/realtime/conversation_item_content.py b/src/openai/types/beta/realtime/conversation_item_content.py index b854aa0e0f..ab40a4a1a7 100644 --- a/src/openai/types/beta/realtime/conversation_item_content.py +++ b/src/openai/types/beta/realtime/conversation_item_content.py @@ -11,8 +11,9 @@ class ConversationItemContent(BaseModel): id: Optional[str] = None """ - ID of a previous conversation item (like a model response), used for - `item_reference` content types. + ID of a previous conversation item to reference (for `item_reference` content + types in `response.create` events). These can reference both client and server + created items. """ audio: Optional[str] = None diff --git a/src/openai/types/beta/realtime/conversation_item_content_param.py b/src/openai/types/beta/realtime/conversation_item_content_param.py index b354d78971..7a3a92a39d 100644 --- a/src/openai/types/beta/realtime/conversation_item_content_param.py +++ b/src/openai/types/beta/realtime/conversation_item_content_param.py @@ -10,8 +10,9 @@ class ConversationItemContentParam(TypedDict, total=False): id: str """ - ID of a previous conversation item (like a model response), used for - `item_reference` content types. + ID of a previous conversation item to reference (for `item_reference` content + types in `response.create` events). These can reference both client and server + created items. """ audio: str diff --git a/src/openai/types/beta/realtime/response_create_event.py b/src/openai/types/beta/realtime/response_create_event.py index 00ba1e5dad..e4e5e7c68f 100644 --- a/src/openai/types/beta/realtime/response_create_event.py +++ b/src/openai/types/beta/realtime/response_create_event.py @@ -89,7 +89,8 @@ class Response(BaseModel): tool_choice: Optional[str] = None """How the model chooses tools. - Options are `auto`, `none`, `required`, or specify a function. + Options are `auto`, `none`, `required`, or specify a function, like + `{"type": "function", "function": {"name": "my_function"}}`. """ tools: Optional[List[ResponseTool]] = None diff --git a/src/openai/types/beta/realtime/response_create_event_param.py b/src/openai/types/beta/realtime/response_create_event_param.py index 7c92b32df1..7a4b5f086a 100644 --- a/src/openai/types/beta/realtime/response_create_event_param.py +++ b/src/openai/types/beta/realtime/response_create_event_param.py @@ -90,7 +90,8 @@ class Response(TypedDict, total=False): tool_choice: str """How the model chooses tools. - Options are `auto`, `none`, `required`, or specify a function. + Options are `auto`, `none`, `required`, or specify a function, like + `{"type": "function", "function": {"name": "my_function"}}`. """ tools: Iterable[ResponseTool] From 5481c2ecd44044eeddbda479abb19ba9f9766fc2 Mon Sep 17 00:00:00 2001 From: Krista Pratico Date: Thu, 19 Dec 2024 09:28:52 -0800 Subject: [PATCH 132/769] feat(azure): support for the Realtime API (#1963) --- src/openai/_utils/__init__.py | 2 ++ src/openai/_utils/_utils.py | 16 ++++++++++ src/openai/lib/azure.py | 32 ++++++++++++++++++- .../resources/beta/realtime/realtime.py | 20 +++++++++--- 4 files changed, 65 insertions(+), 5 deletions(-) diff --git a/src/openai/_utils/__init__.py b/src/openai/_utils/__init__.py index af2c9bb77e..bd01c088dc 100644 --- a/src/openai/_utils/__init__.py +++ b/src/openai/_utils/__init__.py @@ -25,6 +25,7 @@ coerce_integer as coerce_integer, file_from_path as file_from_path, parse_datetime as parse_datetime, + is_azure_client as is_azure_client, strip_not_given as strip_not_given, deepcopy_minimal as deepcopy_minimal, get_async_library as get_async_library, @@ -32,6 +33,7 @@ get_required_header as get_required_header, maybe_coerce_boolean as maybe_coerce_boolean, maybe_coerce_integer as maybe_coerce_integer, + is_async_azure_client as is_async_azure_client, ) from ._typing import ( is_list_type as is_list_type, diff --git a/src/openai/_utils/_utils.py b/src/openai/_utils/_utils.py index e5811bba42..d6734e6b8f 100644 --- a/src/openai/_utils/_utils.py +++ b/src/openai/_utils/_utils.py @@ -5,6 +5,7 @@ import inspect import functools from typing import ( + TYPE_CHECKING, Any, Tuple, Mapping, @@ -30,6 +31,9 @@ _SequenceT = TypeVar("_SequenceT", bound=Sequence[object]) CallableT = TypeVar("CallableT", bound=Callable[..., Any]) +if TYPE_CHECKING: + from ..lib.azure import AzureOpenAI, AsyncAzureOpenAI + def flatten(t: Iterable[Iterable[_T]]) -> list[_T]: return [item for sublist in t for item in sublist] @@ -412,3 +416,15 @@ def json_safe(data: object) -> object: return data.isoformat() return data + + +def is_azure_client(client: object) -> TypeGuard[AzureOpenAI]: + from ..lib.azure import AzureOpenAI + + return isinstance(client, AzureOpenAI) + + +def is_async_azure_client(client: object) -> TypeGuard[AsyncAzureOpenAI]: + from ..lib.azure import AsyncAzureOpenAI + + return isinstance(client, AsyncAzureOpenAI) diff --git a/src/openai/lib/azure.py b/src/openai/lib/azure.py index 13d9f31838..f857d76e51 100644 --- a/src/openai/lib/azure.py +++ b/src/openai/lib/azure.py @@ -7,7 +7,7 @@ import httpx -from .._types import NOT_GIVEN, Omit, Timeout, NotGiven +from .._types import NOT_GIVEN, Omit, Query, Timeout, NotGiven from .._utils import is_given, is_mapping from .._client import OpenAI, AsyncOpenAI from .._compat import model_copy @@ -307,6 +307,21 @@ def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOptions: return options + def _configure_realtime(self, model: str, extra_query: Query) -> tuple[Query, dict[str, str]]: + auth_headers = {} + query = { + **extra_query, + "api-version": self._api_version, + "deployment": model, + } + if self.api_key != "": + auth_headers = {"api-key": self.api_key} + else: + token = self._get_azure_ad_token() + if token: + auth_headers = {"Authorization": f"Bearer {token}"} + return query, auth_headers + class AsyncAzureOpenAI(BaseAzureClient[httpx.AsyncClient, AsyncStream[Any]], AsyncOpenAI): @overload @@ -555,3 +570,18 @@ async def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOp raise ValueError("Unable to handle auth") return options + + async def _configure_realtime(self, model: str, extra_query: Query) -> tuple[Query, dict[str, str]]: + auth_headers = {} + query = { + **extra_query, + "api-version": self._api_version, + "deployment": model, + } + if self.api_key != "": + auth_headers = {"api-key": self.api_key} + else: + token = await self._get_azure_ad_token() + if token: + auth_headers = {"Authorization": f"Bearer {token}"} + return query, auth_headers diff --git a/src/openai/resources/beta/realtime/realtime.py b/src/openai/resources/beta/realtime/realtime.py index c79fd46217..b39b410ecf 100644 --- a/src/openai/resources/beta/realtime/realtime.py +++ b/src/openai/resources/beta/realtime/realtime.py @@ -21,9 +21,11 @@ ) from ...._types import NOT_GIVEN, Query, Headers, NotGiven from ...._utils import ( + is_azure_client, maybe_transform, strip_not_given, async_maybe_transform, + is_async_azure_client, ) from ...._compat import cached_property from ...._models import construct_type_unchecked @@ -319,11 +321,16 @@ async def __aenter__(self) -> AsyncRealtimeConnection: except ImportError as exc: raise OpenAIError("You need to install `openai[realtime]` to use this method") from exc + extra_query = self.__extra_query + auth_headers = self.__client.auth_headers + if is_async_azure_client(self.__client): + extra_query, auth_headers = await self.__client._configure_realtime(self.__model, extra_query) + url = self._prepare_url().copy_with( params={ **self.__client.base_url.params, "model": self.__model, - **self.__extra_query, + **extra_query, }, ) log.debug("Connecting to %s", url) @@ -336,7 +343,7 @@ async def __aenter__(self) -> AsyncRealtimeConnection: user_agent_header=self.__client.user_agent, additional_headers=_merge_mappings( { - **self.__client.auth_headers, + **auth_headers, "OpenAI-Beta": "realtime=v1", }, self.__extra_headers, @@ -496,11 +503,16 @@ def __enter__(self) -> RealtimeConnection: except ImportError as exc: raise OpenAIError("You need to install `openai[realtime]` to use this method") from exc + extra_query = self.__extra_query + auth_headers = self.__client.auth_headers + if is_azure_client(self.__client): + extra_query, auth_headers = self.__client._configure_realtime(self.__model, extra_query) + url = self._prepare_url().copy_with( params={ **self.__client.base_url.params, "model": self.__model, - **self.__extra_query, + **extra_query, }, ) log.debug("Connecting to %s", url) @@ -513,7 +525,7 @@ def __enter__(self) -> RealtimeConnection: user_agent_header=self.__client.user_agent, additional_headers=_merge_mappings( { - **self.__client.auth_headers, + **auth_headers, "OpenAI-Beta": "realtime=v1", }, self.__extra_headers, From 89d49335a02ac231925e5a514659c93322f29526 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 21 Dec 2024 05:03:53 +0000 Subject: [PATCH 133/769] release: 1.59.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 73a4167d2d..451b00c101 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.58.1" + ".": "1.59.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 6519747179..1f411fc397 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 1.59.0 (2024-12-21) + +Full Changelog: [v1.58.1...v1.59.0](https://github.com/openai/openai-python/compare/v1.58.1...v1.59.0) + +### Features + +* **azure:** support for the Realtime API ([#1963](https://github.com/openai/openai-python/issues/1963)) ([9fda141](https://github.com/openai/openai-python/commit/9fda14172abdb66fe240aa7b4dc7cfae4faf1d73)) + + +### Chores + +* **realtime:** update docstrings ([#1964](https://github.com/openai/openai-python/issues/1964)) ([3dee863](https://github.com/openai/openai-python/commit/3dee863554d28272103e90a6a199ac196e92ff05)) + ## 1.58.1 (2024-12-17) Full Changelog: [v1.58.0...v1.58.1](https://github.com/openai/openai-python/compare/v1.58.0...v1.58.1) diff --git a/pyproject.toml b/pyproject.toml index fd55cf2b5d..127213c372 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.58.1" +version = "1.59.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 c08e68e11b..7719866b19 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.58.1" # x-release-please-version +__version__ = "1.59.0" # x-release-please-version From 99861632e9bdb1a480d92913d621bded574bf797 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 2 Jan 2025 01:44:32 +0000 Subject: [PATCH 134/769] chore: bump license year (#1981) --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 621a6becfb..f011417af6 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2024 OpenAI + Copyright 2025 OpenAI Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. From 44d6210f101abedeb2dd68507fcffcb329df70ea Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 2 Jan 2025 05:04:23 +0000 Subject: [PATCH 135/769] release: 1.59.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 451b00c101..8dcb014faf 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.59.0" + ".": "1.59.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f411fc397..4f029bf1f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.59.1 (2025-01-02) + +Full Changelog: [v1.59.0...v1.59.1](https://github.com/openai/openai-python/compare/v1.59.0...v1.59.1) + +### Chores + +* bump license year ([#1981](https://github.com/openai/openai-python/issues/1981)) ([f29011a](https://github.com/openai/openai-python/commit/f29011a6426d3fa4844ecd723ee20561ee60c665)) + ## 1.59.0 (2024-12-21) Full Changelog: [v1.58.1...v1.59.0](https://github.com/openai/openai-python/compare/v1.58.1...v1.59.0) diff --git a/pyproject.toml b/pyproject.toml index 127213c372..51166e5eca 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.59.0" +version = "1.59.1" 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 7719866b19..98a34f1356 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.59.0" # x-release-please-version +__version__ = "1.59.1" # x-release-please-version From ccf5753ae01ddee52f102544d992b51e333cb669 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Fri, 3 Jan 2025 16:01:50 +0000 Subject: [PATCH 136/769] chore(ci): fix publish workflow --- .github/workflows/publish-pypi.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml index 44027a3c4c..76d0efca80 100644 --- a/.github/workflows/publish-pypi.yml +++ b/.github/workflows/publish-pypi.yml @@ -8,6 +8,7 @@ jobs: publish: name: publish runs-on: ubuntu-latest + environment: publish steps: - uses: actions/checkout@v4 From b3fc5b39594d30e7dc73813ce88c64796b0e8b96 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 3 Jan 2025 16:02:21 +0000 Subject: [PATCH 137/769] release: 1.59.2 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 9 +++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 8dcb014faf..7676e15413 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.59.1" + ".": "1.59.2" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f029bf1f2..2b410e0a5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 1.59.2 (2025-01-03) + +Full Changelog: [v1.59.1...v1.59.2](https://github.com/openai/openai-python/compare/v1.59.1...v1.59.2) + +### Chores + +* **ci:** fix publish workflow ([0be1f5d](https://github.com/openai/openai-python/commit/0be1f5de0daf807cece564abf061c8bb188bb9aa)) +* **internal:** empty commit ([fe8dc2e](https://github.com/openai/openai-python/commit/fe8dc2e97fc430ea2433ed28cfaa79425af223ec)) + ## 1.59.1 (2025-01-02) Full Changelog: [v1.59.0...v1.59.1](https://github.com/openai/openai-python/compare/v1.59.0...v1.59.1) diff --git a/pyproject.toml b/pyproject.toml index 51166e5eca..7d7c59fa0b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.59.1" +version = "1.59.2" 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 98a34f1356..866a882fc2 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.59.1" # x-release-please-version +__version__ = "1.59.2" # x-release-please-version From 0189770e1d5ba0db18d7a923e1d562df0ff4fe6d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 3 Jan 2025 22:57:16 +0000 Subject: [PATCH 138/769] chore(api): bump spec version (#1985) --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 1a7a7a5269..1ac7a94471 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-a39aca84ed97ebafb707ebd5221e2787c5a42ff3d98f2ffaea8a0dcd84cbcbcb.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-02200a58ed631064b6419711da99fefd6e97bdbbeb577a80a1a6e0c8dbcb18f5.yml From 1e07c9d839e7e96f02d0a4b745f379a43086334c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 3 Jan 2025 22:57:52 +0000 Subject: [PATCH 139/769] release: 1.59.3 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 7676e15413..f701c8396e 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.59.2" + ".": "1.59.3" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b410e0a5f..75d144cca6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.59.3 (2025-01-03) + +Full Changelog: [v1.59.2...v1.59.3](https://github.com/openai/openai-python/compare/v1.59.2...v1.59.3) + +### Chores + +* **api:** bump spec version ([#1985](https://github.com/openai/openai-python/issues/1985)) ([c6f1b35](https://github.com/openai/openai-python/commit/c6f1b357fcf669065f4ed6819d47a528b0787128)) + ## 1.59.2 (2025-01-03) Full Changelog: [v1.59.1...v1.59.2](https://github.com/openai/openai-python/compare/v1.59.1...v1.59.2) diff --git a/pyproject.toml b/pyproject.toml index 7d7c59fa0b..b9d4abf59a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.59.2" +version = "1.59.3" 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 866a882fc2..342d208d2b 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.59.2" # x-release-please-version +__version__ = "1.59.3" # x-release-please-version From 7117a18f4f25c5d07db8d96dd2930f0381f2309f Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Mon, 6 Jan 2025 16:50:25 +0000 Subject: [PATCH 140/769] chore: add missing isclass check for structured outputs --- src/openai/lib/_pydantic.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/openai/lib/_pydantic.py b/src/openai/lib/_pydantic.py index 22c7a1f3cd..4e8bc772be 100644 --- a/src/openai/lib/_pydantic.py +++ b/src/openai/lib/_pydantic.py @@ -127,6 +127,8 @@ def resolve_ref(*, root: dict[str, object], ref: str) -> object: def is_basemodel_type(typ: type) -> TypeGuard[type[pydantic.BaseModel]]: + if not inspect.isclass(typ): + return False return issubclass(typ, pydantic.BaseModel) From f5436b147421296c22269e2fe4081c917d7b1658 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 6 Jan 2025 17:15:50 +0000 Subject: [PATCH 141/769] chore: add missing isclass check (#1988) --- src/openai/_models.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/openai/_models.py b/src/openai/_models.py index 2f67e5eb4d..1bbc5fa4cc 100644 --- a/src/openai/_models.py +++ b/src/openai/_models.py @@ -513,7 +513,11 @@ def construct_type(*, value: object, type_: object) -> object: _, items_type = get_args(type_) # Dict[_, items_type] return {key: construct_type(value=item, type_=items_type) for key, item in value.items()} - if not is_literal_type(type_) and (issubclass(origin, BaseModel) or issubclass(origin, GenericModel)): + if ( + not is_literal_type(type_) + and inspect.isclass(origin) + and (issubclass(origin, BaseModel) or issubclass(origin, GenericModel)) + ): if is_list(value): return [cast(Any, type_).construct(**entry) if is_mapping(entry) else entry for entry in value] From 255677d7091313d2ef32316c6c64983673e077d0 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Mon, 6 Jan 2025 17:41:56 +0000 Subject: [PATCH 142/769] docs(realtime): fix event reference link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 87837db175..cc1eb1a4f7 100644 --- a/README.md +++ b/README.md @@ -264,7 +264,7 @@ The Realtime API enables you to build low-latency, multi-modal conversational ex Under the hood the SDK uses the [`websockets`](https://websockets.readthedocs.io/en/stable/) library to manage connections. -The Realtime API works through a combination of client-sent events and server-sent events. Clients can send events to do things like update session configuration or send text and audio inputs. Server events confirm when audio responses have completed, or when a text response from the model has been received. A full event reference can be found [here](platform.openai.com/docs/api-reference/realtime-client-events) and a guide can be found [here](https://platform.openai.com/docs/guides/realtime). +The Realtime API works through a combination of client-sent events and server-sent events. Clients can send events to do things like update session configuration or send text and audio inputs. Server events confirm when audio responses have completed, or when a text response from the model has been received. A full event reference can be found [here](https://platform.openai.com/docs/api-reference/realtime-client-events) and a guide can be found [here](https://platform.openai.com/docs/guides/realtime). Basic text based example: From 1fb671ea97b51918fdcdbac8bc9abb68fc6b7506 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 7 Jan 2025 09:49:30 +0000 Subject: [PATCH 143/769] chore(internal): bump httpx dependency (#1990) --- pyproject.toml | 3 +-- requirements-dev.lock | 5 ++--- requirements.lock | 3 +-- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index b9d4abf59a..3a683b0eef 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -66,8 +66,7 @@ dev-dependencies = [ "types-tqdm > 4", "types-pyaudio > 0", "trio >=0.22.2", - "nest_asyncio==1.6.0" - + "nest_asyncio==1.6.0", ] [tool.rye.scripts] diff --git a/requirements-dev.lock b/requirements-dev.lock index 94cf6aca07..15ecbf081a 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -60,7 +60,7 @@ h11==0.14.0 # via httpcore httpcore==1.0.2 # via httpx -httpx==0.25.2 +httpx==0.28.1 # via openai # via respx idna==3.4 @@ -137,7 +137,7 @@ pytz==2023.3.post1 requests==2.31.0 # via azure-core # via msal -respx==0.20.2 +respx==0.22.0 rich==13.7.1 # via inline-snapshot ruff==0.6.9 @@ -149,7 +149,6 @@ six==1.16.0 # via python-dateutil sniffio==1.3.0 # via anyio - # via httpx # via openai # via trio sortedcontainers==2.4.0 diff --git a/requirements.lock b/requirements.lock index c10449ac20..a3e3602abe 100644 --- a/requirements.lock +++ b/requirements.lock @@ -25,7 +25,7 @@ h11==0.14.0 # via httpcore httpcore==1.0.2 # via httpx -httpx==0.25.2 +httpx==0.28.1 # via openai idna==3.4 # via anyio @@ -52,7 +52,6 @@ six==1.16.0 # via python-dateutil sniffio==1.3.0 # via anyio - # via httpx # via openai tqdm==4.66.5 # via openai From 728100cf7a7aff90bbe274e593bc726030e392ec Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 7 Jan 2025 09:50:04 +0000 Subject: [PATCH 144/769] release: 1.59.4 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 15 +++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index f701c8396e..b58729ff4e 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.59.3" + ".": "1.59.4" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 75d144cca6..78a1f2a1cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## 1.59.4 (2025-01-07) + +Full Changelog: [v1.59.3...v1.59.4](https://github.com/openai/openai-python/compare/v1.59.3...v1.59.4) + +### Chores + +* add missing isclass check ([#1988](https://github.com/openai/openai-python/issues/1988)) ([61d9072](https://github.com/openai/openai-python/commit/61d9072fbace58d64910ec7378c3686ac555972e)) +* add missing isclass check for structured outputs ([bcbf013](https://github.com/openai/openai-python/commit/bcbf013e8d825b8b5f88172313dfb6e0313ca34c)) +* **internal:** bump httpx dependency ([#1990](https://github.com/openai/openai-python/issues/1990)) ([288c2c3](https://github.com/openai/openai-python/commit/288c2c30dc405cbaa89924f9243442300e95e100)) + + +### Documentation + +* **realtime:** fix event reference link ([9b6885d](https://github.com/openai/openai-python/commit/9b6885d50f8d65ba5009642046727d291e0f14fa)) + ## 1.59.3 (2025-01-03) Full Changelog: [v1.59.2...v1.59.3](https://github.com/openai/openai-python/compare/v1.59.2...v1.59.3) diff --git a/pyproject.toml b/pyproject.toml index 3a683b0eef..f5309b299a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.59.3" +version = "1.59.4" 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 342d208d2b..86545ed82a 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.59.3" # x-release-please-version +__version__ = "1.59.4" # x-release-please-version From bd49dd156f2654a14fea2a26fc39b33a068d7900 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 7 Jan 2025 20:09:36 +0000 Subject: [PATCH 145/769] fix(client): only call .close() when needed (#1992) --- src/openai/_base_client.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index cceec903d9..1fa039c0b1 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -769,6 +769,9 @@ def __init__(self, **kwargs: Any) -> None: class SyncHttpxClientWrapper(DefaultHttpxClient): def __del__(self) -> None: + if self.is_closed: + return + try: self.close() except Exception: @@ -1351,6 +1354,9 @@ def __init__(self, **kwargs: Any) -> None: class AsyncHttpxClientWrapper(DefaultAsyncHttpxClient): def __del__(self) -> None: + if self.is_closed: + return + try: # TODO(someday): support non asyncio runtimes here asyncio.get_running_loop().create_task(self.aclose()) From eb02a2c2a7bcd81cc00836c36f178b028df96c33 Mon Sep 17 00:00:00 2001 From: Mustafa <66224841+mustafa-nom@users.noreply.github.com> Date: Wed, 8 Jan 2025 05:22:24 -0800 Subject: [PATCH 146/769] docs: fix typos (#1995) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cc1eb1a4f7..3ab509ce42 100644 --- a/README.md +++ b/README.md @@ -655,7 +655,7 @@ If you need to access undocumented endpoints, params, or response properties, th #### Undocumented endpoints To make requests to undocumented endpoints, you can make requests using `client.get`, `client.post`, and other -http verbs. Options on the client will be respected (such as retries) will be respected when making this +http verbs. Options on the client (such as retries) will be respected when making this request. ```py From fee9c81bece28f2e145c7abf357a93f52983e119 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 8 Jan 2025 13:50:20 +0000 Subject: [PATCH 147/769] docs: fix typos (#1996) --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 3ab509ce42..32095a22d2 100644 --- a/README.md +++ b/README.md @@ -469,7 +469,7 @@ except openai.APIStatusError as e: print(e.response) ``` -Error codes are as followed: +Error codes are as follows: | Status Code | Error Type | | ----------- | -------------------------- | @@ -611,7 +611,7 @@ completion = response.parse() # get the object that `chat.completions.create()` print(completion) ``` -These methods return an [`LegacyAPIResponse`](https://github.com/openai/openai-python/tree/main/src/openai/_legacy_response.py) object. This is a legacy class as we're changing it slightly in the next major version. +These methods return a [`LegagcyAPIResponse`](https://github.com/openai/openai-python/tree/main/src/openai/_legacy_response.py) object. This is a legacy class as we're changing it slightly in the next major version. For the sync client this will mostly be the same with the exception of `content` & `text` will be methods instead of properties. In the @@ -655,8 +655,7 @@ If you need to access undocumented endpoints, params, or response properties, th #### Undocumented endpoints To make requests to undocumented endpoints, you can make requests using `client.get`, `client.post`, and other -http verbs. Options on the client (such as retries) will be respected when making this -request. +http verbs. Options on the client will be respected (such as retries) when making this request. ```py import httpx From 16315f22b459f96d4785ff5800712e8349811d57 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 8 Jan 2025 14:08:24 +0000 Subject: [PATCH 148/769] docs: more typo fixes (#1998) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 32095a22d2..42f69f5401 100644 --- a/README.md +++ b/README.md @@ -611,7 +611,7 @@ completion = response.parse() # get the object that `chat.completions.create()` print(completion) ``` -These methods return a [`LegagcyAPIResponse`](https://github.com/openai/openai-python/tree/main/src/openai/_legacy_response.py) object. This is a legacy class as we're changing it slightly in the next major version. +These methods return a [`LegacyAPIResponse`](https://github.com/openai/openai-python/tree/main/src/openai/_legacy_response.py) object. This is a legacy class as we're changing it slightly in the next major version. For the sync client this will mostly be the same with the exception of `content` & `text` will be methods instead of properties. In the From e502d3014d8520ce3b29c59abf0fe4a27d447163 Mon Sep 17 00:00:00 2001 From: Josiah Altschuler Date: Wed, 8 Jan 2025 09:00:17 -0600 Subject: [PATCH 149/769] docs(readme): moved period to inside parentheses (#1980) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 42f69f5401..ad1c9afd10 100644 --- a/README.md +++ b/README.md @@ -769,7 +769,7 @@ An example of using the client with Microsoft Entra ID (formerly known as Azure This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions: 1. Changes that only affect static types, without breaking runtime behavior. -2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals)_. +2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_ 3. Changes that we do not expect to impact the vast majority of users in practice. We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience. From 52f49794b6ea7c243372870d09a23deae8d019cf Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 8 Jan 2025 15:00:53 +0000 Subject: [PATCH 150/769] release: 1.59.5 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 16 ++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index b58729ff4e..802e19924e 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.59.4" + ".": "1.59.5" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 78a1f2a1cb..e3a67b7ac9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # Changelog +## 1.59.5 (2025-01-08) + +Full Changelog: [v1.59.4...v1.59.5](https://github.com/openai/openai-python/compare/v1.59.4...v1.59.5) + +### Bug Fixes + +* **client:** only call .close() when needed ([#1992](https://github.com/openai/openai-python/issues/1992)) ([bdfd699](https://github.com/openai/openai-python/commit/bdfd699b99522e83f7610b5f98e36fe43ddf8338)) + + +### Documentation + +* fix typos ([#1995](https://github.com/openai/openai-python/issues/1995)) ([be694a0](https://github.com/openai/openai-python/commit/be694a097d6cf2668f08ecf94c882773b2ee1f84)) +* fix typos ([#1996](https://github.com/openai/openai-python/issues/1996)) ([714aed9](https://github.com/openai/openai-python/commit/714aed9d7eb74a19f6e502fb6d4fe83399f82851)) +* more typo fixes ([#1998](https://github.com/openai/openai-python/issues/1998)) ([7bd92f0](https://github.com/openai/openai-python/commit/7bd92f06a75f11f6afc2d1223d2426e186cc74cb)) +* **readme:** moved period to inside parentheses ([#1980](https://github.com/openai/openai-python/issues/1980)) ([e7fae94](https://github.com/openai/openai-python/commit/e7fae948f2ba8db23461e4374308417570196847)) + ## 1.59.4 (2025-01-07) Full Changelog: [v1.59.3...v1.59.4](https://github.com/openai/openai-python/compare/v1.59.3...v1.59.4) diff --git a/pyproject.toml b/pyproject.toml index f5309b299a..7529b69960 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.59.4" +version = "1.59.5" 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 86545ed82a..f8a67d7937 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.59.4" # x-release-please-version +__version__ = "1.59.5" # x-release-please-version From 020385c075aa04e4adc284efabb14e38c23d16d5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 8 Jan 2025 16:41:34 +0000 Subject: [PATCH 151/769] chore(internal): spec update (#2000) --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 1ac7a94471..9600edae3b 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-02200a58ed631064b6419711da99fefd6e97bdbbeb577a80a1a6e0c8dbcb18f5.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-b5b0e2c794b012919701c3fd43286af10fa25d33ceb8a881bec2636028f446e0.yml From 5ca7876e6a99c0d47bffc2c4167a5faf58673384 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 9 Jan 2025 10:56:47 +0000 Subject: [PATCH 152/769] fix: correctly handle deserialising `cls` fields (#2002) --- src/openai/_models.py | 8 ++++---- tests/test_models.py | 10 ++++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/openai/_models.py b/src/openai/_models.py index 1bbc5fa4cc..23456d9f80 100644 --- a/src/openai/_models.py +++ b/src/openai/_models.py @@ -204,14 +204,14 @@ def __str__(self) -> str: @classmethod @override def construct( # pyright: ignore[reportIncompatibleMethodOverride] - cls: Type[ModelT], + __cls: Type[ModelT], _fields_set: set[str] | None = None, **values: object, ) -> ModelT: - m = cls.__new__(cls) + m = __cls.__new__(__cls) fields_values: dict[str, object] = {} - config = get_model_config(cls) + config = get_model_config(__cls) populate_by_name = ( config.allow_population_by_field_name if isinstance(config, _ConfigProtocol) @@ -221,7 +221,7 @@ def construct( # pyright: ignore[reportIncompatibleMethodOverride] if _fields_set is None: _fields_set = set() - model_fields = get_model_fields(cls) + model_fields = get_model_fields(__cls) for name, field in model_fields.items(): key = field.alias if key is None or (key not in values and populate_by_name): diff --git a/tests/test_models.py b/tests/test_models.py index 19a71f13ba..30b17e3ac0 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -844,3 +844,13 @@ class Model(BaseModel): assert m.alias == "foo" assert isinstance(m.union, str) assert m.union == "bar" + + +@pytest.mark.skipif(not PYDANTIC_V2, reason="TypeAliasType is not supported in Pydantic v1") +def test_field_named_cls() -> None: + class Model(BaseModel): + cls: str + + m = construct_type(value={"cls": "foo"}, type_=Model) + assert isinstance(m, Model) + assert isinstance(m.cls, str) From 33e40854beef0cb18c0790bea953678c30b6fb5c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 9 Jan 2025 10:57:26 +0000 Subject: [PATCH 153/769] release: 1.59.6 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 802e19924e..fc624851e9 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.59.5" + ".": "1.59.6" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index e3a67b7ac9..e65def028e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 1.59.6 (2025-01-09) + +Full Changelog: [v1.59.5...v1.59.6](https://github.com/openai/openai-python/compare/v1.59.5...v1.59.6) + +### Bug Fixes + +* correctly handle deserialising `cls` fields ([#2002](https://github.com/openai/openai-python/issues/2002)) ([089c820](https://github.com/openai/openai-python/commit/089c820c8a5d20e9db6a171f0a4f11b481fe8465)) + + +### Chores + +* **internal:** spec update ([#2000](https://github.com/openai/openai-python/issues/2000)) ([36548f8](https://github.com/openai/openai-python/commit/36548f871763fdd7b5ce44903d186bc916331549)) + ## 1.59.5 (2025-01-08) Full Changelog: [v1.59.4...v1.59.5](https://github.com/openai/openai-python/compare/v1.59.4...v1.59.5) diff --git a/pyproject.toml b/pyproject.toml index 7529b69960..4131e9c1fd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.59.5" +version = "1.59.6" 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 f8a67d7937..fa93e603a6 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.59.5" # x-release-please-version +__version__ = "1.59.6" # x-release-please-version From b2dd5e04d6136856c4c00e4ce9af10e45af5f7aa Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Mon, 13 Jan 2025 13:29:41 +0000 Subject: [PATCH 154/769] chore: export HttpxBinaryResponseContent class --- src/openai/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/openai/__init__.py b/src/openai/__init__.py index 21c60f7e87..fe85956a4a 100644 --- a/src/openai/__init__.py +++ b/src/openai/__init__.py @@ -33,6 +33,7 @@ ) from ._base_client import DefaultHttpxClient, DefaultAsyncHttpxClient from ._utils._logs import setup_logging as _setup_logging +from ._legacy_response import HttpxBinaryResponseContent as HttpxBinaryResponseContent __all__ = [ "types", From d9c966dea77fa3493114865a7f785f3134f1cc1e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 13 Jan 2025 13:30:18 +0000 Subject: [PATCH 155/769] release: 1.59.7 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index fc624851e9..7da3bd4caf 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.59.6" + ".": "1.59.7" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index e65def028e..08674b4a36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.59.7 (2025-01-13) + +Full Changelog: [v1.59.6...v1.59.7](https://github.com/openai/openai-python/compare/v1.59.6...v1.59.7) + +### Chores + +* export HttpxBinaryResponseContent class ([7191b71](https://github.com/openai/openai-python/commit/7191b71f3dcbbfcb2f2bec855c3bba93c956384e)) + ## 1.59.6 (2025-01-09) Full Changelog: [v1.59.5...v1.59.6](https://github.com/openai/openai-python/compare/v1.59.5...v1.59.6) diff --git a/pyproject.toml b/pyproject.toml index 4131e9c1fd..e769f4a95f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.59.6" +version = "1.59.7" 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 fa93e603a6..656d17ff63 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.59.6" # x-release-please-version +__version__ = "1.59.7" # x-release-please-version From babe65f92c8a71efdc8adb7e68205d5906f571cf Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 13 Jan 2025 16:20:02 +0000 Subject: [PATCH 156/769] chore(internal): streaming refactors (#2012) --- src/openai/_streaming.py | 66 +++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 34 deletions(-) diff --git a/src/openai/_streaming.py b/src/openai/_streaming.py index 0fda992cff..b275986a46 100644 --- a/src/openai/_streaming.py +++ b/src/openai/_streaming.py @@ -59,23 +59,22 @@ def __stream__(self) -> Iterator[_T]: if sse.data.startswith("[DONE]"): break - if sse.event is None: - data = sse.json() - if is_mapping(data) and data.get("error"): - message = None - error = data.get("error") - if is_mapping(error): - message = error.get("message") - if not message or not isinstance(message, str): - message = "An error occurred during streaming" - - raise APIError( - message=message, - request=self.response.request, - body=data["error"], - ) - - yield process_data(data=data, cast_to=cast_to, response=response) + data = sse.json() + if is_mapping(data) and data.get("error"): + message = None + error = data.get("error") + if is_mapping(error): + message = error.get("message") + if not message or not isinstance(message, str): + message = "An error occurred during streaming" + + raise APIError( + message=message, + request=self.response.request, + body=data["error"], + ) + + yield process_data(data=data, cast_to=cast_to, response=response) else: data = sse.json() @@ -161,23 +160,22 @@ async def __stream__(self) -> AsyncIterator[_T]: if sse.data.startswith("[DONE]"): break - if sse.event is None: - data = sse.json() - if is_mapping(data) and data.get("error"): - message = None - error = data.get("error") - if is_mapping(error): - message = error.get("message") - if not message or not isinstance(message, str): - message = "An error occurred during streaming" - - raise APIError( - message=message, - request=self.response.request, - body=data["error"], - ) - - yield process_data(data=data, cast_to=cast_to, response=response) + data = sse.json() + if is_mapping(data) and data.get("error"): + message = None + error = data.get("error") + if is_mapping(error): + message = error.get("message") + if not message or not isinstance(message, str): + message = "An error occurred during streaming" + + raise APIError( + message=message, + request=self.response.request, + body=data["error"], + ) + + yield process_data(data=data, cast_to=cast_to, response=response) else: data = sse.json() From 7e88d42289f1327540c3d3f9210fae3c61474053 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Mon, 13 Jan 2025 16:59:43 +0000 Subject: [PATCH 157/769] fix: streaming --- src/openai/_streaming.py | 38 -------------------------------------- 1 file changed, 38 deletions(-) diff --git a/src/openai/_streaming.py b/src/openai/_streaming.py index b275986a46..7aa7b62f6b 100644 --- a/src/openai/_streaming.py +++ b/src/openai/_streaming.py @@ -76,25 +76,6 @@ def __stream__(self) -> Iterator[_T]: yield process_data(data=data, cast_to=cast_to, response=response) - else: - data = sse.json() - - if sse.event == "error" and is_mapping(data) and data.get("error"): - message = None - error = data.get("error") - if is_mapping(error): - message = error.get("message") - if not message or not isinstance(message, str): - message = "An error occurred during streaming" - - raise APIError( - message=message, - request=self.response.request, - body=data["error"], - ) - - yield process_data(data={"data": data, "event": sse.event}, cast_to=cast_to, response=response) - # Ensure the entire stream is consumed for _sse in iterator: ... @@ -177,25 +158,6 @@ async def __stream__(self) -> AsyncIterator[_T]: yield process_data(data=data, cast_to=cast_to, response=response) - else: - data = sse.json() - - if sse.event == "error" and is_mapping(data) and data.get("error"): - message = None - error = data.get("error") - if is_mapping(error): - message = error.get("message") - if not message or not isinstance(message, str): - message = "An error occurred during streaming" - - raise APIError( - message=message, - request=self.response.request, - body=data["error"], - ) - - yield process_data(data={"data": data, "event": sse.event}, cast_to=cast_to, response=response) - # Ensure the entire stream is consumed async for _sse in iterator: ... From 82ccc9858ac0de22ac874dcf796c17a333ce7b00 Mon Sep 17 00:00:00 2001 From: Krista Pratico Date: Mon, 13 Jan 2025 10:08:10 -0800 Subject: [PATCH 158/769] docs(examples/azure): example script with realtime API (#1967) --- examples/realtime/azure_realtime.py | 57 +++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 examples/realtime/azure_realtime.py diff --git a/examples/realtime/azure_realtime.py b/examples/realtime/azure_realtime.py new file mode 100644 index 0000000000..de88d47052 --- /dev/null +++ b/examples/realtime/azure_realtime.py @@ -0,0 +1,57 @@ +import os +import asyncio + +from azure.identity.aio import DefaultAzureCredential, get_bearer_token_provider + +from openai import AsyncAzureOpenAI + +# Azure OpenAI Realtime Docs + +# How-to: https://learn.microsoft.com/azure/ai-services/openai/how-to/realtime-audio +# Supported models and API versions: https://learn.microsoft.com/azure/ai-services/openai/how-to/realtime-audio#supported-models +# Entra ID auth: https://learn.microsoft.com/azure/ai-services/openai/how-to/managed-identity + + +async def main() -> None: + """The following example demonstrates how to configure Azure OpenAI to use the Realtime API. + For an audio example, see push_to_talk_app.py and update the client and model parameter accordingly. + + When prompted for user input, type a message and hit enter to send it to the model. + Enter "q" to quit the conversation. + """ + + credential = DefaultAzureCredential() + client = AsyncAzureOpenAI( + azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"], + azure_ad_token_provider=get_bearer_token_provider(credential, "https://cognitiveservices.azure.com/.default"), + api_version="2024-10-01-preview", + ) + async with client.beta.realtime.connect( + model="gpt-4o-realtime-preview", # deployment name for your model + ) as connection: + await connection.session.update(session={"modalities": ["text"]}) # type: ignore + while True: + user_input = input("Enter a message: ") + if user_input == "q": + break + + await connection.conversation.item.create( + item={ + "type": "message", + "role": "user", + "content": [{"type": "input_text", "text": user_input}], + } + ) + await connection.response.create() + async for event in connection: + if event.type == "response.text.delta": + print(event.delta, flush=True, end="") + elif event.type == "response.text.done": + print() + elif event.type == "response.done": + break + + await credential.close() + + +asyncio.run(main()) From e081d99e16835a038ef0dbb68500e562e021291f Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Mon, 13 Jan 2025 20:23:17 +0000 Subject: [PATCH 159/769] Revert "chore(internal): streaming refactors (#2012)" This reverts commit d76a748f606743407f94dfc26758095560e2082a. --- src/openai/_streaming.py | 104 +++++++++++++++++++++++++++------------ 1 file changed, 72 insertions(+), 32 deletions(-) diff --git a/src/openai/_streaming.py b/src/openai/_streaming.py index 7aa7b62f6b..0fda992cff 100644 --- a/src/openai/_streaming.py +++ b/src/openai/_streaming.py @@ -59,22 +59,42 @@ def __stream__(self) -> Iterator[_T]: if sse.data.startswith("[DONE]"): break - data = sse.json() - if is_mapping(data) and data.get("error"): - message = None - error = data.get("error") - if is_mapping(error): - message = error.get("message") - if not message or not isinstance(message, str): - message = "An error occurred during streaming" - - raise APIError( - message=message, - request=self.response.request, - body=data["error"], - ) - - yield process_data(data=data, cast_to=cast_to, response=response) + if sse.event is None: + data = sse.json() + if is_mapping(data) and data.get("error"): + message = None + error = data.get("error") + if is_mapping(error): + message = error.get("message") + if not message or not isinstance(message, str): + message = "An error occurred during streaming" + + raise APIError( + message=message, + request=self.response.request, + body=data["error"], + ) + + yield process_data(data=data, cast_to=cast_to, response=response) + + else: + data = sse.json() + + if sse.event == "error" and is_mapping(data) and data.get("error"): + message = None + error = data.get("error") + if is_mapping(error): + message = error.get("message") + if not message or not isinstance(message, str): + message = "An error occurred during streaming" + + raise APIError( + message=message, + request=self.response.request, + body=data["error"], + ) + + yield process_data(data={"data": data, "event": sse.event}, cast_to=cast_to, response=response) # Ensure the entire stream is consumed for _sse in iterator: @@ -141,22 +161,42 @@ async def __stream__(self) -> AsyncIterator[_T]: if sse.data.startswith("[DONE]"): break - data = sse.json() - if is_mapping(data) and data.get("error"): - message = None - error = data.get("error") - if is_mapping(error): - message = error.get("message") - if not message or not isinstance(message, str): - message = "An error occurred during streaming" - - raise APIError( - message=message, - request=self.response.request, - body=data["error"], - ) - - yield process_data(data=data, cast_to=cast_to, response=response) + if sse.event is None: + data = sse.json() + if is_mapping(data) and data.get("error"): + message = None + error = data.get("error") + if is_mapping(error): + message = error.get("message") + if not message or not isinstance(message, str): + message = "An error occurred during streaming" + + raise APIError( + message=message, + request=self.response.request, + body=data["error"], + ) + + yield process_data(data=data, cast_to=cast_to, response=response) + + else: + data = sse.json() + + if sse.event == "error" and is_mapping(data) and data.get("error"): + message = None + error = data.get("error") + if is_mapping(error): + message = error.get("message") + if not message or not isinstance(message, str): + message = "An error occurred during streaming" + + raise APIError( + message=message, + request=self.response.request, + body=data["error"], + ) + + yield process_data(data={"data": data, "event": sse.event}, cast_to=cast_to, response=response) # Ensure the entire stream is consumed async for _sse in iterator: From 83f11490fa291f9814f3dae6a65b1f62d0177675 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 14 Jan 2025 11:56:21 +0000 Subject: [PATCH 160/769] chore(internal): update deps (#2015) --- mypy.ini | 2 +- requirements-dev.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mypy.ini b/mypy.ini index 1ea1fe909d..660f1a086e 100644 --- a/mypy.ini +++ b/mypy.ini @@ -44,7 +44,7 @@ cache_fine_grained = True # ``` # Changing this codegen to make mypy happy would increase complexity # and would not be worth it. -disable_error_code = func-returns-value +disable_error_code = func-returns-value,overload-cannot-match # https://github.com/python/mypy/issues/12162 [mypy.overrides] diff --git a/requirements-dev.lock b/requirements-dev.lock index 15ecbf081a..8799e10b06 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -83,7 +83,7 @@ msal==1.31.0 # via msal-extensions msal-extensions==1.2.0 # via azure-identity -mypy==1.13.0 +mypy==1.14.1 mypy-extensions==1.0.0 # via black # via mypy @@ -124,7 +124,7 @@ pygments==2.18.0 # via rich pyjwt==2.8.0 # via msal -pyright==1.1.390 +pyright==1.1.391 pytest==8.3.3 # via pytest-asyncio pytest-asyncio==0.24.0 From d256d83589261e3bb2d2778a4f5bd4dda3248ac9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 14 Jan 2025 11:59:51 +0000 Subject: [PATCH 161/769] fix(types): correct type for vector store chunking strategy (#2017) --- api.md | 2 +- src/openai/types/beta/__init__.py | 3 +++ .../types/beta/file_chunking_strategy_param.py | 4 ++-- ...static_file_chunking_strategy_object_param.py | 16 ++++++++++++++++ 4 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 src/openai/types/beta/static_file_chunking_strategy_object_param.py diff --git a/api.md b/api.md index ace93e0559..1edd3f6589 100644 --- a/api.md +++ b/api.md @@ -314,7 +314,7 @@ from openai.types.beta import ( OtherFileChunkingStrategyObject, StaticFileChunkingStrategy, StaticFileChunkingStrategyObject, - StaticFileChunkingStrategyParam, + StaticFileChunkingStrategyObjectParam, VectorStore, VectorStoreDeleted, ) diff --git a/src/openai/types/beta/__init__.py b/src/openai/types/beta/__init__.py index 7f76fed0cd..b9ea792bfa 100644 --- a/src/openai/types/beta/__init__.py +++ b/src/openai/types/beta/__init__.py @@ -43,3 +43,6 @@ from .assistant_response_format_option_param import ( AssistantResponseFormatOptionParam as AssistantResponseFormatOptionParam, ) +from .static_file_chunking_strategy_object_param import ( + StaticFileChunkingStrategyObjectParam as StaticFileChunkingStrategyObjectParam, +) diff --git a/src/openai/types/beta/file_chunking_strategy_param.py b/src/openai/types/beta/file_chunking_strategy_param.py index 46383358e5..25d94286d8 100644 --- a/src/openai/types/beta/file_chunking_strategy_param.py +++ b/src/openai/types/beta/file_chunking_strategy_param.py @@ -6,8 +6,8 @@ from typing_extensions import TypeAlias from .auto_file_chunking_strategy_param import AutoFileChunkingStrategyParam -from .static_file_chunking_strategy_param import StaticFileChunkingStrategyParam +from .static_file_chunking_strategy_object_param import StaticFileChunkingStrategyObjectParam __all__ = ["FileChunkingStrategyParam"] -FileChunkingStrategyParam: TypeAlias = Union[AutoFileChunkingStrategyParam, StaticFileChunkingStrategyParam] +FileChunkingStrategyParam: TypeAlias = Union[AutoFileChunkingStrategyParam, StaticFileChunkingStrategyObjectParam] diff --git a/src/openai/types/beta/static_file_chunking_strategy_object_param.py b/src/openai/types/beta/static_file_chunking_strategy_object_param.py new file mode 100644 index 0000000000..0cdf35c0df --- /dev/null +++ b/src/openai/types/beta/static_file_chunking_strategy_object_param.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +from .static_file_chunking_strategy_param import StaticFileChunkingStrategyParam + +__all__ = ["StaticFileChunkingStrategyObjectParam"] + + +class StaticFileChunkingStrategyObjectParam(TypedDict, total=False): + static: Required[StaticFileChunkingStrategyParam] + + type: Required[Literal["static"]] + """Always `static`.""" From fd76342499f061bb157e4d5501a1e55f867cbc2c Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Wed, 15 Jan 2025 14:06:06 +0000 Subject: [PATCH 162/769] chore(examples): update realtime model closes #2020 --- README.md | 4 ++-- examples/realtime/push_to_talk_app.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ad1c9afd10..ec556bd27a 100644 --- a/README.md +++ b/README.md @@ -275,7 +275,7 @@ from openai import AsyncOpenAI async def main(): client = AsyncOpenAI() - async with client.beta.realtime.connect(model="gpt-4o-realtime-preview-2024-10-01") as connection: + async with client.beta.realtime.connect(model="gpt-4o-realtime-preview") as connection: await connection.session.update(session={'modalities': ['text']}) await connection.conversation.item.create( @@ -309,7 +309,7 @@ Whenever an error occurs, the Realtime API will send an [`error` event](https:// ```py client = AsyncOpenAI() -async with client.beta.realtime.connect(model="gpt-4o-realtime-preview-2024-10-01") as connection: +async with client.beta.realtime.connect(model="gpt-4o-realtime-preview") as connection: ... async for event in connection: if event.type == 'error': diff --git a/examples/realtime/push_to_talk_app.py b/examples/realtime/push_to_talk_app.py index d46945a8ed..8dc303a83a 100755 --- a/examples/realtime/push_to_talk_app.py +++ b/examples/realtime/push_to_talk_app.py @@ -152,7 +152,7 @@ async def on_mount(self) -> None: self.run_worker(self.send_mic_audio()) async def handle_realtime_connection(self) -> None: - async with self.client.beta.realtime.connect(model="gpt-4o-realtime-preview-2024-10-01") as conn: + async with self.client.beta.realtime.connect(model="gpt-4o-realtime-preview") as conn: self.connection = conn self.connected.set() From bf5bebb57d74266d3010a72267298c0c832510a9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 15 Jan 2025 17:51:10 +0000 Subject: [PATCH 163/769] chore(internal): bump pyright dependency (#2021) --- requirements-dev.lock | 2 +- src/openai/_legacy_response.py | 12 ++++++++++-- src/openai/_response.py | 8 +++++++- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/requirements-dev.lock b/requirements-dev.lock index 8799e10b06..ef26591f12 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -124,7 +124,7 @@ pygments==2.18.0 # via rich pyjwt==2.8.0 # via msal -pyright==1.1.391 +pyright==1.1.392.post0 pytest==8.3.3 # via pytest-asyncio pytest-asyncio==0.24.0 diff --git a/src/openai/_legacy_response.py b/src/openai/_legacy_response.py index 7a14f27adb..25680049dc 100644 --- a/src/openai/_legacy_response.py +++ b/src/openai/_legacy_response.py @@ -269,7 +269,9 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: if origin == LegacyAPIResponse: raise RuntimeError("Unexpected state - cast_to is `APIResponse`") - if inspect.isclass(origin) and issubclass(origin, httpx.Response): + if inspect.isclass( + origin # pyright: ignore[reportUnknownArgumentType] + ) and issubclass(origin, httpx.Response): # Because of the invariance of our ResponseT TypeVar, users can subclass httpx.Response # and pass that class to our request functions. We cannot change the variance to be either # covariant or contravariant as that makes our usage of ResponseT illegal. We could construct @@ -279,7 +281,13 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: raise ValueError(f"Subclasses of httpx.Response cannot be passed to `cast_to`") return cast(R, response) - if inspect.isclass(origin) and not issubclass(origin, BaseModel) and issubclass(origin, pydantic.BaseModel): + if ( + inspect.isclass( + origin # pyright: ignore[reportUnknownArgumentType] + ) + and not issubclass(origin, BaseModel) + and issubclass(origin, pydantic.BaseModel) + ): raise TypeError("Pydantic models must subclass our base model type, e.g. `from openai import BaseModel`") if ( diff --git a/src/openai/_response.py b/src/openai/_response.py index 1527446585..36c7ea1281 100644 --- a/src/openai/_response.py +++ b/src/openai/_response.py @@ -214,7 +214,13 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: raise ValueError(f"Subclasses of httpx.Response cannot be passed to `cast_to`") return cast(R, response) - if inspect.isclass(origin) and not issubclass(origin, BaseModel) and issubclass(origin, pydantic.BaseModel): + if ( + inspect.isclass( + origin # pyright: ignore[reportUnknownArgumentType] + ) + and not issubclass(origin, BaseModel) + and issubclass(origin, pydantic.BaseModel) + ): raise TypeError("Pydantic models must subclass our base model type, e.g. `from openai import BaseModel`") if ( From 08ab62b93a0c7690f00e760172cfefcb81b8e150 Mon Sep 17 00:00:00 2001 From: Rohit Joshi <891456+rjoshi@users.noreply.github.com> Date: Thu, 16 Jan 2025 04:46:22 -0800 Subject: [PATCH 164/769] fix(structured outputs): avoid parsing empty empty content (#2023) Fixing https://github.com/openai/openai-python/issues/1763 where parsing often fails when content is empty string instead of None. --- src/openai/lib/_parsing/_completions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openai/lib/_parsing/_completions.py b/src/openai/lib/_parsing/_completions.py index f1fa9f2b55..33c4ccb946 100644 --- a/src/openai/lib/_parsing/_completions.py +++ b/src/openai/lib/_parsing/_completions.py @@ -157,7 +157,7 @@ def maybe_parse_content( response_format: type[ResponseFormatT] | ResponseFormatParam | NotGiven, message: ChatCompletionMessage | ParsedChatCompletionMessage[object], ) -> ResponseFormatT | None: - if has_rich_response_format(response_format) and message.content is not None and not message.refusal: + if has_rich_response_format(response_format) and message.content and not message.refusal: return _parse_content(response_format, message.content) return None From 1bdabb489a86bd721a3e237d8556583ed0d8dfa1 Mon Sep 17 00:00:00 2001 From: kanchi <17161397+KanchiShimono@users.noreply.github.com> Date: Fri, 17 Jan 2025 20:40:26 +0900 Subject: [PATCH 165/769] fix(structured outputs): correct schema coercion for inline ref expansion (#2025) --- src/openai/lib/_pydantic.py | 3 + tests/lib/test_pydantic.py | 174 ++++++++++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+) diff --git a/src/openai/lib/_pydantic.py b/src/openai/lib/_pydantic.py index 4e8bc772be..c2d73e5fc6 100644 --- a/src/openai/lib/_pydantic.py +++ b/src/openai/lib/_pydantic.py @@ -108,6 +108,9 @@ def _ensure_strict_json_schema( # properties from the json schema take priority over the ones on the `$ref` json_schema.update({**resolved, **json_schema}) json_schema.pop("$ref") + # Since the schema expanded from `$ref` might not have `additionalProperties: false` applied, + # we call `_ensure_strict_json_schema` again to fix the inlined schema and ensure it's valid. + return _ensure_strict_json_schema(json_schema, path=path, root=root) return json_schema diff --git a/tests/lib/test_pydantic.py b/tests/lib/test_pydantic.py index 99b9e96d21..7e128b70c0 100644 --- a/tests/lib/test_pydantic.py +++ b/tests/lib/test_pydantic.py @@ -7,6 +7,7 @@ import openai from openai._compat import PYDANTIC_V2 +from openai.lib._pydantic import to_strict_json_schema from .schema_types.query import Query @@ -235,3 +236,176 @@ def test_enums() -> None: }, } ) + + +class Star(BaseModel): + name: str = Field(description="The name of the star.") + + +class Galaxy(BaseModel): + name: str = Field(description="The name of the galaxy.") + largest_star: Star = Field(description="The largest star in the galaxy.") + + +class Universe(BaseModel): + name: str = Field(description="The name of the universe.") + galaxy: Galaxy = Field(description="A galaxy in the universe.") + + +def test_nested_inline_ref_expansion() -> None: + if PYDANTIC_V2: + assert to_strict_json_schema(Universe) == snapshot( + { + "title": "Universe", + "type": "object", + "$defs": { + "Star": { + "title": "Star", + "type": "object", + "properties": { + "name": { + "type": "string", + "title": "Name", + "description": "The name of the star.", + } + }, + "required": ["name"], + "additionalProperties": False, + }, + "Galaxy": { + "title": "Galaxy", + "type": "object", + "properties": { + "name": { + "type": "string", + "title": "Name", + "description": "The name of the galaxy.", + }, + "largest_star": { + "title": "Star", + "type": "object", + "properties": { + "name": { + "type": "string", + "title": "Name", + "description": "The name of the star.", + } + }, + "required": ["name"], + "description": "The largest star in the galaxy.", + "additionalProperties": False, + }, + }, + "required": ["name", "largest_star"], + "additionalProperties": False, + }, + }, + "properties": { + "name": { + "type": "string", + "title": "Name", + "description": "The name of the universe.", + }, + "galaxy": { + "title": "Galaxy", + "type": "object", + "properties": { + "name": { + "type": "string", + "title": "Name", + "description": "The name of the galaxy.", + }, + "largest_star": { + "title": "Star", + "type": "object", + "properties": { + "name": { + "type": "string", + "title": "Name", + "description": "The name of the star.", + } + }, + "required": ["name"], + "description": "The largest star in the galaxy.", + "additionalProperties": False, + }, + }, + "required": ["name", "largest_star"], + "description": "A galaxy in the universe.", + "additionalProperties": False, + }, + }, + "required": ["name", "galaxy"], + "additionalProperties": False, + } + ) + else: + assert to_strict_json_schema(Universe) == snapshot( + { + "title": "Universe", + "type": "object", + "definitions": { + "Star": { + "title": "Star", + "type": "object", + "properties": { + "name": {"title": "Name", "description": "The name of the star.", "type": "string"} + }, + "required": ["name"], + "additionalProperties": False, + }, + "Galaxy": { + "title": "Galaxy", + "type": "object", + "properties": { + "name": {"title": "Name", "description": "The name of the galaxy.", "type": "string"}, + "largest_star": { + "title": "Largest Star", + "description": "The largest star in the galaxy.", + "type": "object", + "properties": { + "name": {"title": "Name", "description": "The name of the star.", "type": "string"} + }, + "required": ["name"], + "additionalProperties": False, + }, + }, + "required": ["name", "largest_star"], + "additionalProperties": False, + }, + }, + "properties": { + "name": { + "title": "Name", + "description": "The name of the universe.", + "type": "string", + }, + "galaxy": { + "title": "Galaxy", + "description": "A galaxy in the universe.", + "type": "object", + "properties": { + "name": { + "title": "Name", + "description": "The name of the galaxy.", + "type": "string", + }, + "largest_star": { + "title": "Largest Star", + "description": "The largest star in the galaxy.", + "type": "object", + "properties": { + "name": {"title": "Name", "description": "The name of the star.", "type": "string"} + }, + "required": ["name"], + "additionalProperties": False, + }, + }, + "required": ["name", "largest_star"], + "additionalProperties": False, + }, + }, + "required": ["name", "galaxy"], + "additionalProperties": False, + } + ) From 4dd5cf25fa58076307a5baed0a87f6d765f20100 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 17 Jan 2025 11:40:58 +0000 Subject: [PATCH 166/769] release: 1.59.8 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 24 ++++++++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 27 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 7da3bd4caf..58f8a4601d 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.59.7" + ".": "1.59.8" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 08674b4a36..9f301cedff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,29 @@ # Changelog +## 1.59.8 (2025-01-17) + +Full Changelog: [v1.59.7...v1.59.8](https://github.com/openai/openai-python/compare/v1.59.7...v1.59.8) + +### Bug Fixes + +* streaming ([c16f58e](https://github.com/openai/openai-python/commit/c16f58ead0bc85055b164182689ba74b7e939dfa)) +* **structured outputs:** avoid parsing empty empty content ([#2023](https://github.com/openai/openai-python/issues/2023)) ([6d3513c](https://github.com/openai/openai-python/commit/6d3513c86f6e5800f8f73a45e089b7a205327121)) +* **structured outputs:** correct schema coercion for inline ref expansion ([#2025](https://github.com/openai/openai-python/issues/2025)) ([2f4f0b3](https://github.com/openai/openai-python/commit/2f4f0b374207f162060c328b71ec995049dc42e8)) +* **types:** correct type for vector store chunking strategy ([#2017](https://github.com/openai/openai-python/issues/2017)) ([e389279](https://github.com/openai/openai-python/commit/e38927950a5cdad99065853fe7b72aad6bb322e9)) + + +### Chores + +* **examples:** update realtime model ([f26746c](https://github.com/openai/openai-python/commit/f26746cbcd893d66cf8a3fd68a7c3779dc8c833c)), closes [#2020](https://github.com/openai/openai-python/issues/2020) +* **internal:** bump pyright dependency ([#2021](https://github.com/openai/openai-python/issues/2021)) ([0a9a0f5](https://github.com/openai/openai-python/commit/0a9a0f5d8b9d5457643798287f893305006dd518)) +* **internal:** streaming refactors ([#2012](https://github.com/openai/openai-python/issues/2012)) ([d76a748](https://github.com/openai/openai-python/commit/d76a748f606743407f94dfc26758095560e2082a)) +* **internal:** update deps ([#2015](https://github.com/openai/openai-python/issues/2015)) ([514e0e4](https://github.com/openai/openai-python/commit/514e0e415f87ab4510262d29ed6125384e017b84)) + + +### Documentation + +* **examples/azure:** example script with realtime API ([#1967](https://github.com/openai/openai-python/issues/1967)) ([84f2f9c](https://github.com/openai/openai-python/commit/84f2f9c0439229a7db7136fe78419292d34d1f81)) + ## 1.59.7 (2025-01-13) Full Changelog: [v1.59.6...v1.59.7](https://github.com/openai/openai-python/compare/v1.59.6...v1.59.7) diff --git a/pyproject.toml b/pyproject.toml index e769f4a95f..a75d24e1eb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.59.7" +version = "1.59.8" 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 656d17ff63..d6f55997e7 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.59.7" # x-release-please-version +__version__ = "1.59.8" # x-release-please-version From 1e5e19976a02f4f3423cf7e32ad5fa020c857b82 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 20 Jan 2025 09:38:30 +0000 Subject: [PATCH 167/769] chore(internal): update websockets dep (#2036) --- requirements-dev.lock | 2 +- requirements.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements-dev.lock b/requirements-dev.lock index ef26591f12..38cc6e1cf2 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -184,7 +184,7 @@ urllib3==2.2.1 # via requests virtualenv==20.24.5 # via nox -websockets==14.1 +websockets==14.2 # via openai zipp==3.17.0 # via importlib-metadata diff --git a/requirements.lock b/requirements.lock index a3e3602abe..cbdff94fa3 100644 --- a/requirements.lock +++ b/requirements.lock @@ -63,5 +63,5 @@ typing-extensions==4.12.2 # via pydantic-core tzdata==2024.1 # via pandas -websockets==14.1 +websockets==14.2 # via openai From fbc88b6206338761019cb6a4258d7de46f578fcb Mon Sep 17 00:00:00 2001 From: Nino Risteski <95188570+NinoRisteski@users.noreply.github.com> Date: Mon, 20 Jan 2025 10:53:29 +0100 Subject: [PATCH 168/769] docs: fix typo (#2031) removed duplicate 'the' twice --- src/openai/resources/chat/chat.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/openai/resources/chat/chat.py b/src/openai/resources/chat/chat.py index dc23a15a8e..9c4aacc953 100644 --- a/src/openai/resources/chat/chat.py +++ b/src/openai/resources/chat/chat.py @@ -24,7 +24,7 @@ def completions(self) -> Completions: @cached_property def with_raw_response(self) -> ChatWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers @@ -49,7 +49,7 @@ def completions(self) -> AsyncCompletions: @cached_property def with_raw_response(self) -> AsyncChatWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers From de0550420763b918ffe49d2fffd7b76b2dd00ba8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 20 Jan 2025 10:13:38 +0000 Subject: [PATCH 169/769] docs(raw responses): fix duplicate `the` (#2039) --- src/openai/resources/audio/audio.py | 4 ++-- src/openai/resources/audio/speech.py | 4 ++-- src/openai/resources/audio/transcriptions.py | 4 ++-- src/openai/resources/audio/translations.py | 4 ++-- src/openai/resources/batches.py | 4 ++-- src/openai/resources/beta/assistants.py | 4 ++-- src/openai/resources/beta/beta.py | 4 ++-- src/openai/resources/beta/realtime/realtime.py | 4 ++-- src/openai/resources/beta/realtime/sessions.py | 4 ++-- src/openai/resources/beta/threads/messages.py | 4 ++-- src/openai/resources/beta/threads/runs/runs.py | 4 ++-- src/openai/resources/beta/threads/runs/steps.py | 4 ++-- src/openai/resources/beta/threads/threads.py | 4 ++-- src/openai/resources/beta/vector_stores/file_batches.py | 4 ++-- src/openai/resources/beta/vector_stores/files.py | 4 ++-- src/openai/resources/beta/vector_stores/vector_stores.py | 4 ++-- src/openai/resources/chat/completions.py | 4 ++-- src/openai/resources/completions.py | 4 ++-- src/openai/resources/embeddings.py | 4 ++-- src/openai/resources/files.py | 4 ++-- src/openai/resources/fine_tuning/fine_tuning.py | 4 ++-- src/openai/resources/fine_tuning/jobs/checkpoints.py | 4 ++-- src/openai/resources/fine_tuning/jobs/jobs.py | 4 ++-- src/openai/resources/images.py | 4 ++-- src/openai/resources/models.py | 4 ++-- src/openai/resources/moderations.py | 4 ++-- src/openai/resources/uploads/parts.py | 4 ++-- src/openai/resources/uploads/uploads.py | 4 ++-- 28 files changed, 56 insertions(+), 56 deletions(-) diff --git a/src/openai/resources/audio/audio.py b/src/openai/resources/audio/audio.py index 18bd7b812c..383b7073bf 100644 --- a/src/openai/resources/audio/audio.py +++ b/src/openai/resources/audio/audio.py @@ -48,7 +48,7 @@ def speech(self) -> Speech: @cached_property def with_raw_response(self) -> AudioWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers @@ -81,7 +81,7 @@ def speech(self) -> AsyncSpeech: @cached_property def with_raw_response(self) -> AsyncAudioWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers diff --git a/src/openai/resources/audio/speech.py b/src/openai/resources/audio/speech.py index 09faaddda6..805a8c19c9 100644 --- a/src/openai/resources/audio/speech.py +++ b/src/openai/resources/audio/speech.py @@ -32,7 +32,7 @@ class Speech(SyncAPIResource): @cached_property def with_raw_response(self) -> SpeechWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers @@ -116,7 +116,7 @@ class AsyncSpeech(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncSpeechWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers diff --git a/src/openai/resources/audio/transcriptions.py b/src/openai/resources/audio/transcriptions.py index 8b5f4404fc..341446c43a 100644 --- a/src/openai/resources/audio/transcriptions.py +++ b/src/openai/resources/audio/transcriptions.py @@ -36,7 +36,7 @@ class Transcriptions(SyncAPIResource): @cached_property def with_raw_response(self) -> TranscriptionsWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers @@ -200,7 +200,7 @@ class AsyncTranscriptions(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncTranscriptionsWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers diff --git a/src/openai/resources/audio/translations.py b/src/openai/resources/audio/translations.py index a2d28afa03..cd3132dc57 100644 --- a/src/openai/resources/audio/translations.py +++ b/src/openai/resources/audio/translations.py @@ -36,7 +36,7 @@ class Translations(SyncAPIResource): @cached_property def with_raw_response(self) -> TranslationsWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers @@ -179,7 +179,7 @@ class AsyncTranslations(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncTranslationsWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers diff --git a/src/openai/resources/batches.py b/src/openai/resources/batches.py index 7cab75785d..4a887642e9 100644 --- a/src/openai/resources/batches.py +++ b/src/openai/resources/batches.py @@ -31,7 +31,7 @@ class Batches(SyncAPIResource): @cached_property def with_raw_response(self) -> BatchesWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers @@ -236,7 +236,7 @@ class AsyncBatches(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncBatchesWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers diff --git a/src/openai/resources/beta/assistants.py b/src/openai/resources/beta/assistants.py index 7df212f155..2f2482b648 100644 --- a/src/openai/resources/beta/assistants.py +++ b/src/openai/resources/beta/assistants.py @@ -36,7 +36,7 @@ class Assistants(SyncAPIResource): @cached_property def with_raw_response(self) -> AssistantsWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers @@ -422,7 +422,7 @@ class AsyncAssistants(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncAssistantsWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers diff --git a/src/openai/resources/beta/beta.py b/src/openai/resources/beta/beta.py index 1ffa6c8e79..5d71cff3f1 100644 --- a/src/openai/resources/beta/beta.py +++ b/src/openai/resources/beta/beta.py @@ -65,7 +65,7 @@ def threads(self) -> Threads: @cached_property def with_raw_response(self) -> BetaWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers @@ -106,7 +106,7 @@ def threads(self) -> AsyncThreads: @cached_property def with_raw_response(self) -> AsyncBetaWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers diff --git a/src/openai/resources/beta/realtime/realtime.py b/src/openai/resources/beta/realtime/realtime.py index b39b410ecf..235790a9f5 100644 --- a/src/openai/resources/beta/realtime/realtime.py +++ b/src/openai/resources/beta/realtime/realtime.py @@ -58,7 +58,7 @@ def sessions(self) -> Sessions: @cached_property def with_raw_response(self) -> RealtimeWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers @@ -110,7 +110,7 @@ def sessions(self) -> AsyncSessions: @cached_property def with_raw_response(self) -> AsyncRealtimeWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers diff --git a/src/openai/resources/beta/realtime/sessions.py b/src/openai/resources/beta/realtime/sessions.py index 1d1ee701e5..8d2df30753 100644 --- a/src/openai/resources/beta/realtime/sessions.py +++ b/src/openai/resources/beta/realtime/sessions.py @@ -27,7 +27,7 @@ class Sessions(SyncAPIResource): @cached_property def with_raw_response(self) -> SessionsWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers @@ -166,7 +166,7 @@ class AsyncSessions(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncSessionsWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers diff --git a/src/openai/resources/beta/threads/messages.py b/src/openai/resources/beta/threads/messages.py index e848507387..f780f6f558 100644 --- a/src/openai/resources/beta/threads/messages.py +++ b/src/openai/resources/beta/threads/messages.py @@ -33,7 +33,7 @@ class Messages(SyncAPIResource): @cached_property def with_raw_response(self) -> MessagesWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers @@ -307,7 +307,7 @@ class AsyncMessages(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncMessagesWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers diff --git a/src/openai/resources/beta/threads/runs/runs.py b/src/openai/resources/beta/threads/runs/runs.py index 0418d570ba..f32a08f235 100644 --- a/src/openai/resources/beta/threads/runs/runs.py +++ b/src/openai/resources/beta/threads/runs/runs.py @@ -64,7 +64,7 @@ def steps(self) -> Steps: @cached_property def with_raw_response(self) -> RunsWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers @@ -1429,7 +1429,7 @@ def steps(self) -> AsyncSteps: @cached_property def with_raw_response(self) -> AsyncRunsWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers diff --git a/src/openai/resources/beta/threads/runs/steps.py b/src/openai/resources/beta/threads/runs/steps.py index 9bd91e39e0..709c729d45 100644 --- a/src/openai/resources/beta/threads/runs/steps.py +++ b/src/openai/resources/beta/threads/runs/steps.py @@ -29,7 +29,7 @@ class Steps(SyncAPIResource): @cached_property def with_raw_response(self) -> StepsWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers @@ -183,7 +183,7 @@ class AsyncSteps(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncStepsWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers diff --git a/src/openai/resources/beta/threads/threads.py b/src/openai/resources/beta/threads/threads.py index e45090abb0..186b6f63e2 100644 --- a/src/openai/resources/beta/threads/threads.py +++ b/src/openai/resources/beta/threads/threads.py @@ -72,7 +72,7 @@ def messages(self) -> Messages: @cached_property def with_raw_response(self) -> ThreadsWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers @@ -906,7 +906,7 @@ def messages(self) -> AsyncMessages: @cached_property def with_raw_response(self) -> AsyncThreadsWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers diff --git a/src/openai/resources/beta/vector_stores/file_batches.py b/src/openai/resources/beta/vector_stores/file_batches.py index 9f9e643bd0..6d61e92c7f 100644 --- a/src/openai/resources/beta/vector_stores/file_batches.py +++ b/src/openai/resources/beta/vector_stores/file_batches.py @@ -36,7 +36,7 @@ class FileBatches(SyncAPIResource): @cached_property def with_raw_response(self) -> FileBatchesWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers @@ -365,7 +365,7 @@ class AsyncFileBatches(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncFileBatchesWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers diff --git a/src/openai/resources/beta/vector_stores/files.py b/src/openai/resources/beta/vector_stores/files.py index 7c155ac917..febf27a753 100644 --- a/src/openai/resources/beta/vector_stores/files.py +++ b/src/openai/resources/beta/vector_stores/files.py @@ -32,7 +32,7 @@ class Files(SyncAPIResource): @cached_property def with_raw_response(self) -> FilesWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers @@ -344,7 +344,7 @@ class AsyncFiles(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncFilesWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers diff --git a/src/openai/resources/beta/vector_stores/vector_stores.py b/src/openai/resources/beta/vector_stores/vector_stores.py index 61a2eadc7b..6b44c602f1 100644 --- a/src/openai/resources/beta/vector_stores/vector_stores.py +++ b/src/openai/resources/beta/vector_stores/vector_stores.py @@ -59,7 +59,7 @@ def file_batches(self) -> FileBatches: @cached_property def with_raw_response(self) -> VectorStoresWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers @@ -337,7 +337,7 @@ def file_batches(self) -> AsyncFileBatches: @cached_property def with_raw_response(self) -> AsyncVectorStoresWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers diff --git a/src/openai/resources/chat/completions.py b/src/openai/resources/chat/completions.py index 728c744327..201ae3f4c6 100644 --- a/src/openai/resources/chat/completions.py +++ b/src/openai/resources/chat/completions.py @@ -45,7 +45,7 @@ class Completions(SyncAPIResource): @cached_property def with_raw_response(self) -> CompletionsWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers @@ -906,7 +906,7 @@ class AsyncCompletions(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncCompletionsWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers diff --git a/src/openai/resources/completions.py b/src/openai/resources/completions.py index 1ac3575fd5..171f509352 100644 --- a/src/openai/resources/completions.py +++ b/src/openai/resources/completions.py @@ -32,7 +32,7 @@ class Completions(SyncAPIResource): @cached_property def with_raw_response(self) -> CompletionsWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers @@ -574,7 +574,7 @@ class AsyncCompletions(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncCompletionsWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers diff --git a/src/openai/resources/embeddings.py b/src/openai/resources/embeddings.py index 4ab2278e89..81a3e354e6 100644 --- a/src/openai/resources/embeddings.py +++ b/src/openai/resources/embeddings.py @@ -27,7 +27,7 @@ class Embeddings(SyncAPIResource): @cached_property def with_raw_response(self) -> EmbeddingsWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers @@ -139,7 +139,7 @@ class AsyncEmbeddings(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncEmbeddingsWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers diff --git a/src/openai/resources/files.py b/src/openai/resources/files.py index 6eaea1b568..af453e1e21 100644 --- a/src/openai/resources/files.py +++ b/src/openai/resources/files.py @@ -41,7 +41,7 @@ class Files(SyncAPIResource): @cached_property def with_raw_response(self) -> FilesWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers @@ -357,7 +357,7 @@ class AsyncFiles(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncFilesWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers diff --git a/src/openai/resources/fine_tuning/fine_tuning.py b/src/openai/resources/fine_tuning/fine_tuning.py index d2bce87c48..eebde07d81 100644 --- a/src/openai/resources/fine_tuning/fine_tuning.py +++ b/src/openai/resources/fine_tuning/fine_tuning.py @@ -24,7 +24,7 @@ def jobs(self) -> Jobs: @cached_property def with_raw_response(self) -> FineTuningWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers @@ -49,7 +49,7 @@ def jobs(self) -> AsyncJobs: @cached_property def with_raw_response(self) -> AsyncFineTuningWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers diff --git a/src/openai/resources/fine_tuning/jobs/checkpoints.py b/src/openai/resources/fine_tuning/jobs/checkpoints.py index 8b5e905ea5..f86462e513 100644 --- a/src/openai/resources/fine_tuning/jobs/checkpoints.py +++ b/src/openai/resources/fine_tuning/jobs/checkpoints.py @@ -25,7 +25,7 @@ class Checkpoints(SyncAPIResource): @cached_property def with_raw_response(self) -> CheckpointsWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers @@ -96,7 +96,7 @@ class AsyncCheckpoints(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncCheckpointsWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers diff --git a/src/openai/resources/fine_tuning/jobs/jobs.py b/src/openai/resources/fine_tuning/jobs/jobs.py index 78eefc253c..e023d28fea 100644 --- a/src/openai/resources/fine_tuning/jobs/jobs.py +++ b/src/openai/resources/fine_tuning/jobs/jobs.py @@ -44,7 +44,7 @@ def checkpoints(self) -> Checkpoints: @cached_property def with_raw_response(self) -> JobsWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers @@ -342,7 +342,7 @@ def checkpoints(self) -> AsyncCheckpoints: @cached_property def with_raw_response(self) -> AsyncJobsWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers diff --git a/src/openai/resources/images.py b/src/openai/resources/images.py index 2fbc077dd9..30473c14f7 100644 --- a/src/openai/resources/images.py +++ b/src/openai/resources/images.py @@ -30,7 +30,7 @@ class Images(SyncAPIResource): @cached_property def with_raw_response(self) -> ImagesWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers @@ -287,7 +287,7 @@ class AsyncImages(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncImagesWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers diff --git a/src/openai/resources/models.py b/src/openai/resources/models.py index d6062de230..a9693a6b0a 100644 --- a/src/openai/resources/models.py +++ b/src/openai/resources/models.py @@ -24,7 +24,7 @@ class Models(SyncAPIResource): @cached_property def with_raw_response(self) -> ModelsWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers @@ -137,7 +137,7 @@ class AsyncModels(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncModelsWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers diff --git a/src/openai/resources/moderations.py b/src/openai/resources/moderations.py index ce80bb7d55..a8f03142bc 100644 --- a/src/openai/resources/moderations.py +++ b/src/openai/resources/moderations.py @@ -28,7 +28,7 @@ class Moderations(SyncAPIResource): @cached_property def with_raw_response(self) -> ModerationsWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers @@ -98,7 +98,7 @@ class AsyncModerations(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncModerationsWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers diff --git a/src/openai/resources/uploads/parts.py b/src/openai/resources/uploads/parts.py index d46e5ea1bb..777469ac8e 100644 --- a/src/openai/resources/uploads/parts.py +++ b/src/openai/resources/uploads/parts.py @@ -28,7 +28,7 @@ class Parts(SyncAPIResource): @cached_property def with_raw_response(self) -> PartsWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers @@ -103,7 +103,7 @@ class AsyncParts(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncPartsWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers diff --git a/src/openai/resources/uploads/uploads.py b/src/openai/resources/uploads/uploads.py index cfb500b62c..2028decef5 100644 --- a/src/openai/resources/uploads/uploads.py +++ b/src/openai/resources/uploads/uploads.py @@ -51,7 +51,7 @@ def parts(self) -> Parts: @cached_property def with_raw_response(self) -> UploadsWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers @@ -344,7 +344,7 @@ def parts(self) -> AsyncParts: @cached_property def with_raw_response(self) -> AsyncUploadsWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers From 14543c59df4f56d2004530dfed411154ffc2f632 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 20 Jan 2025 10:22:16 +0000 Subject: [PATCH 170/769] fix(tests): make test_get_platform less flaky (#2040) --- tests/test_client.py | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/tests/test_client.py b/tests/test_client.py index e0d23403b1..41da2d5d04 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -6,6 +6,7 @@ import os import sys import json +import time import asyncio import inspect import subprocess @@ -1797,10 +1798,20 @@ async def test_main() -> None: [sys.executable, "-c", test_code], text=True, ) as process: - try: - process.wait(2) - if process.returncode: - raise AssertionError("calling get_platform using asyncify resulted in a non-zero exit code") - except subprocess.TimeoutExpired as e: - process.kill() - raise AssertionError("calling get_platform using asyncify resulted in a hung process") from e + timeout = 10 # seconds + + start_time = time.monotonic() + while True: + return_code = process.poll() + if return_code is not None: + if return_code != 0: + raise AssertionError("calling get_platform using asyncify resulted in a non-zero exit code") + + # success + break + + if time.monotonic() - start_time > timeout: + process.kill() + raise AssertionError("calling get_platform using asyncify resulted in a hung process") + + time.sleep(0.1) From 7989b045d2b974e03792e3010d5247b5bbe387fe Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 20 Jan 2025 12:11:31 +0000 Subject: [PATCH 171/769] chore(internal): avoid pytest-asyncio deprecation warning (#2041) --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index a75d24e1eb..e5beb93ec5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -141,6 +141,7 @@ testpaths = ["tests"] addopts = "--tb=short" xfail_strict = true asyncio_mode = "auto" +asyncio_default_fixture_loop_scope = "session" filterwarnings = [ "error" ] From 348a783523e36a88e24b92faee693db125efc5bf Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 20 Jan 2025 12:12:04 +0000 Subject: [PATCH 172/769] release: 1.59.9 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 20 ++++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 58f8a4601d..32b4e18516 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.59.8" + ".": "1.59.9" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f301cedff..86951242c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,25 @@ # Changelog +## 1.59.9 (2025-01-20) + +Full Changelog: [v1.59.8...v1.59.9](https://github.com/openai/openai-python/compare/v1.59.8...v1.59.9) + +### Bug Fixes + +* **tests:** make test_get_platform less flaky ([#2040](https://github.com/openai/openai-python/issues/2040)) ([72ea05c](https://github.com/openai/openai-python/commit/72ea05cf18caaa7a5e6fe7e2251ab93fa0ba3140)) + + +### Chores + +* **internal:** avoid pytest-asyncio deprecation warning ([#2041](https://github.com/openai/openai-python/issues/2041)) ([b901046](https://github.com/openai/openai-python/commit/b901046ddda9c79b7f019e2263c02d126a3b2ee2)) +* **internal:** update websockets dep ([#2036](https://github.com/openai/openai-python/issues/2036)) ([642cd11](https://github.com/openai/openai-python/commit/642cd119482c6fbca925ba702ad2579f9dc47bf9)) + + +### Documentation + +* fix typo ([#2031](https://github.com/openai/openai-python/issues/2031)) ([02fcf15](https://github.com/openai/openai-python/commit/02fcf15611953089826a74725cb96201d94658bb)) +* **raw responses:** fix duplicate `the` ([#2039](https://github.com/openai/openai-python/issues/2039)) ([9b8eab9](https://github.com/openai/openai-python/commit/9b8eab99fdc6a581a1f5cc421c6f74b0e2b30415)) + ## 1.59.8 (2025-01-17) Full Changelog: [v1.59.7...v1.59.8](https://github.com/openai/openai-python/compare/v1.59.7...v1.59.8) diff --git a/pyproject.toml b/pyproject.toml index e5beb93ec5..0b142a6bd8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.59.8" +version = "1.59.9" 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 d6f55997e7..7c92c3adf3 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.59.8" # x-release-please-version +__version__ = "1.59.9" # x-release-please-version From a05e8799f9bb5734b46b19d774d808457c737e31 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 21 Jan 2025 16:08:31 +0000 Subject: [PATCH 173/769] chore(internal): minor style changes (#2043) --- src/openai/_legacy_response.py | 4 ++-- src/openai/_response.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/openai/_legacy_response.py b/src/openai/_legacy_response.py index 25680049dc..8880e5f104 100644 --- a/src/openai/_legacy_response.py +++ b/src/openai/_legacy_response.py @@ -205,6 +205,8 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: if cast_to and is_annotated_type(cast_to): cast_to = extract_type_arg(cast_to, 0) + origin = get_origin(cast_to) or cast_to + if self._stream: if to: if not is_stream_class_type(to): @@ -261,8 +263,6 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: if cast_to == bool: return cast(R, response.text.lower() == "true") - origin = get_origin(cast_to) or cast_to - if inspect.isclass(origin) and issubclass(origin, HttpxBinaryResponseContent): return cast(R, cast_to(response)) # type: ignore diff --git a/src/openai/_response.py b/src/openai/_response.py index 36c7ea1281..95e94e6537 100644 --- a/src/openai/_response.py +++ b/src/openai/_response.py @@ -136,6 +136,8 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: if cast_to and is_annotated_type(cast_to): cast_to = extract_type_arg(cast_to, 0) + origin = get_origin(cast_to) or cast_to + if self._is_sse_stream: if to: if not is_stream_class_type(to): @@ -195,8 +197,6 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: if cast_to == bool: return cast(R, response.text.lower() == "true") - origin = get_origin(cast_to) or cast_to - # handle the legacy binary response case if inspect.isclass(cast_to) and cast_to.__name__ == "HttpxBinaryResponseContent": return cast(R, cast_to(response)) # type: ignore From 709926fff8761659761c3efb96c1e21a02fc1f5d Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Wed, 22 Jan 2025 10:43:52 +0000 Subject: [PATCH 174/769] docs(readme): mention failed requests in request IDs --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index ec556bd27a..5f7d477cc8 100644 --- a/README.md +++ b/README.md @@ -499,6 +499,21 @@ Note that unlike other properties that use an `_` prefix, the `_request_id` prop *is* public. Unless documented otherwise, *all* other `_` prefix properties, methods and modules are *private*. +> [!IMPORTANT] +> If you need to access request IDs for failed requests you must catch the `APIStatusError` exception + +```python +import openai + +try: + completion = await client.chat.completions.create( + messages=[{"role": "user", "content": "Say this is a test"}], model="gpt-4" + ) +except openai.APIStatusError as exc: + print(exc.request_id) # req_123 + raise exc +``` + ### Retries From 339d3151c5b972af690ab45f1055763c52af0e58 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 22 Jan 2025 13:20:56 +0000 Subject: [PATCH 175/769] feat(api): update enum values, comments, and examples (#2045) --- .stats.yml | 2 +- src/openai/resources/audio/speech.py | 16 +++---- .../resources/beta/realtime/sessions.py | 48 +++++++++++-------- src/openai/resources/chat/completions.py | 18 ------- src/openai/resources/embeddings.py | 6 ++- .../types/audio/speech_create_params.py | 6 +-- .../conversation_item_create_event.py | 11 +++-- .../conversation_item_create_event_param.py | 11 +++-- src/openai/types/beta/realtime/session.py | 13 ++++- .../beta/realtime/session_create_params.py | 35 ++++++++------ .../beta/realtime/session_update_event.py | 33 ++++++++----- .../realtime/session_update_event_param.py | 33 ++++++++----- src/openai/types/chat/chat_completion.py | 6 +-- ...chat_completion_assistant_message_param.py | 4 +- .../types/chat/chat_completion_chunk.py | 6 +-- .../types/chat/completion_create_params.py | 3 -- src/openai/types/embedding_create_params.py | 3 +- .../beta/realtime/test_sessions.py | 28 ++++------- tests/api_resources/chat/test_completions.py | 8 ++-- tests/api_resources/test_completions.py | 8 ++-- 20 files changed, 152 insertions(+), 146 deletions(-) diff --git a/.stats.yml b/.stats.yml index 9600edae3b..d518bac586 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-b5b0e2c794b012919701c3fd43286af10fa25d33ceb8a881bec2636028f446e0.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-3904ef6b29a89c98f93a9b7da19879695f3c440564be6384db7af1b734611ede.yml diff --git a/src/openai/resources/audio/speech.py b/src/openai/resources/audio/speech.py index 805a8c19c9..ad01118161 100644 --- a/src/openai/resources/audio/speech.py +++ b/src/openai/resources/audio/speech.py @@ -53,7 +53,7 @@ def create( *, input: str, model: Union[str, SpeechModel], - voice: Literal["alloy", "echo", "fable", "onyx", "nova", "shimmer"], + voice: Literal["alloy", "ash", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer"], response_format: Literal["mp3", "opus", "aac", "flac", "wav", "pcm"] | NotGiven = NOT_GIVEN, speed: float | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -73,9 +73,9 @@ def create( One of the available [TTS models](https://platform.openai.com/docs/models#tts): `tts-1` or `tts-1-hd` - voice: The voice to use when generating the audio. Supported voices are `alloy`, - `echo`, `fable`, `onyx`, `nova`, and `shimmer`. Previews of the voices are - available in the + voice: The voice to use when generating the audio. Supported voices are `alloy`, `ash`, + `coral`, `echo`, `fable`, `onyx`, `nova`, `sage` and `shimmer`. Previews of the + voices are available in the [Text to speech guide](https://platform.openai.com/docs/guides/text-to-speech#voice-options). response_format: The format to audio in. Supported formats are `mp3`, `opus`, `aac`, `flac`, @@ -137,7 +137,7 @@ async def create( *, input: str, model: Union[str, SpeechModel], - voice: Literal["alloy", "echo", "fable", "onyx", "nova", "shimmer"], + voice: Literal["alloy", "ash", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer"], response_format: Literal["mp3", "opus", "aac", "flac", "wav", "pcm"] | NotGiven = NOT_GIVEN, speed: float | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -157,9 +157,9 @@ async def create( One of the available [TTS models](https://platform.openai.com/docs/models#tts): `tts-1` or `tts-1-hd` - voice: The voice to use when generating the audio. Supported voices are `alloy`, - `echo`, `fable`, `onyx`, `nova`, and `shimmer`. Previews of the voices are - available in the + voice: The voice to use when generating the audio. Supported voices are `alloy`, `ash`, + `coral`, `echo`, `fable`, `onyx`, `nova`, `sage` and `shimmer`. Previews of the + voices are available in the [Text to speech guide](https://platform.openai.com/docs/guides/text-to-speech#voice-options). response_format: The format to audio in. Supported formats are `mp3`, `opus`, `aac`, `flac`, diff --git a/src/openai/resources/beta/realtime/sessions.py b/src/openai/resources/beta/realtime/sessions.py index 8d2df30753..b920c89207 100644 --- a/src/openai/resources/beta/realtime/sessions.py +++ b/src/openai/resources/beta/realtime/sessions.py @@ -46,18 +46,19 @@ def with_streaming_response(self) -> SessionsWithStreamingResponse: def create( self, *, + input_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] | NotGiven = NOT_GIVEN, + input_audio_transcription: session_create_params.InputAudioTranscription | NotGiven = NOT_GIVEN, + instructions: str | NotGiven = NOT_GIVEN, + max_response_output_tokens: Union[int, Literal["inf"]] | NotGiven = NOT_GIVEN, + modalities: List[Literal["text", "audio"]] | NotGiven = NOT_GIVEN, model: Literal[ "gpt-4o-realtime-preview", "gpt-4o-realtime-preview-2024-10-01", "gpt-4o-realtime-preview-2024-12-17", "gpt-4o-mini-realtime-preview", "gpt-4o-mini-realtime-preview-2024-12-17", - ], - input_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] | NotGiven = NOT_GIVEN, - input_audio_transcription: session_create_params.InputAudioTranscription | NotGiven = NOT_GIVEN, - instructions: str | NotGiven = NOT_GIVEN, - max_response_output_tokens: Union[int, Literal["inf"]] | NotGiven = NOT_GIVEN, - modalities: List[Literal["text", "audio"]] | NotGiven = NOT_GIVEN, + ] + | NotGiven = NOT_GIVEN, output_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] | NotGiven = NOT_GIVEN, temperature: float | NotGiven = NOT_GIVEN, tool_choice: str | NotGiven = NOT_GIVEN, @@ -81,9 +82,9 @@ def create( the Realtime API. Args: - model: The Realtime model used for this session. - - input_audio_format: The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. + input_audio_format: The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For + `pcm16`, input audio must be 16-bit PCM at a 24kHz sample rate, single channel + (mono), and little-endian byte order. input_audio_transcription: Configuration for input audio transcription, defaults to off and can be set to `null` to turn off once on. Input audio transcription is not native to the @@ -110,7 +111,10 @@ def create( modalities: The set of modalities the model can respond with. To disable audio, set this to ["text"]. + model: The Realtime model used for this session. + output_audio_format: The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. + For `pcm16`, output audio is sampled at a rate of 24kHz. temperature: Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8. @@ -140,12 +144,12 @@ def create( "/realtime/sessions", body=maybe_transform( { - "model": model, "input_audio_format": input_audio_format, "input_audio_transcription": input_audio_transcription, "instructions": instructions, "max_response_output_tokens": max_response_output_tokens, "modalities": modalities, + "model": model, "output_audio_format": output_audio_format, "temperature": temperature, "tool_choice": tool_choice, @@ -185,18 +189,19 @@ def with_streaming_response(self) -> AsyncSessionsWithStreamingResponse: async def create( self, *, + input_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] | NotGiven = NOT_GIVEN, + input_audio_transcription: session_create_params.InputAudioTranscription | NotGiven = NOT_GIVEN, + instructions: str | NotGiven = NOT_GIVEN, + max_response_output_tokens: Union[int, Literal["inf"]] | NotGiven = NOT_GIVEN, + modalities: List[Literal["text", "audio"]] | NotGiven = NOT_GIVEN, model: Literal[ "gpt-4o-realtime-preview", "gpt-4o-realtime-preview-2024-10-01", "gpt-4o-realtime-preview-2024-12-17", "gpt-4o-mini-realtime-preview", "gpt-4o-mini-realtime-preview-2024-12-17", - ], - input_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] | NotGiven = NOT_GIVEN, - input_audio_transcription: session_create_params.InputAudioTranscription | NotGiven = NOT_GIVEN, - instructions: str | NotGiven = NOT_GIVEN, - max_response_output_tokens: Union[int, Literal["inf"]] | NotGiven = NOT_GIVEN, - modalities: List[Literal["text", "audio"]] | NotGiven = NOT_GIVEN, + ] + | NotGiven = NOT_GIVEN, output_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] | NotGiven = NOT_GIVEN, temperature: float | NotGiven = NOT_GIVEN, tool_choice: str | NotGiven = NOT_GIVEN, @@ -220,9 +225,9 @@ async def create( the Realtime API. Args: - model: The Realtime model used for this session. - - input_audio_format: The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. + input_audio_format: The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For + `pcm16`, input audio must be 16-bit PCM at a 24kHz sample rate, single channel + (mono), and little-endian byte order. input_audio_transcription: Configuration for input audio transcription, defaults to off and can be set to `null` to turn off once on. Input audio transcription is not native to the @@ -249,7 +254,10 @@ async def create( modalities: The set of modalities the model can respond with. To disable audio, set this to ["text"]. + model: The Realtime model used for this session. + output_audio_format: The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. + For `pcm16`, output audio is sampled at a rate of 24kHz. temperature: Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8. @@ -279,12 +287,12 @@ async def create( "/realtime/sessions", body=await async_maybe_transform( { - "model": model, "input_audio_format": input_audio_format, "input_audio_transcription": input_audio_transcription, "instructions": instructions, "max_response_output_tokens": max_response_output_tokens, "modalities": modalities, + "model": model, "output_audio_format": output_audio_format, "temperature": temperature, "tool_choice": tool_choice, diff --git a/src/openai/resources/chat/completions.py b/src/openai/resources/chat/completions.py index 201ae3f4c6..a9685c507a 100644 --- a/src/openai/resources/chat/completions.py +++ b/src/openai/resources/chat/completions.py @@ -251,9 +251,6 @@ def create( tier with a lower uptime SLA and no latency guarentee. - When not set, the default behavior is 'auto'. - When this parameter is set, the response body will include the `service_tier` - utilized. - stop: Up to 4 sequences where the API will stop generating further tokens. store: Whether or not to store the output of this chat completion request for use in @@ -509,9 +506,6 @@ def create( tier with a lower uptime SLA and no latency guarentee. - When not set, the default behavior is 'auto'. - When this parameter is set, the response body will include the `service_tier` - utilized. - stop: Up to 4 sequences where the API will stop generating further tokens. store: Whether or not to store the output of this chat completion request for use in @@ -760,9 +754,6 @@ def create( tier with a lower uptime SLA and no latency guarentee. - When not set, the default behavior is 'auto'. - When this parameter is set, the response body will include the `service_tier` - utilized. - stop: Up to 4 sequences where the API will stop generating further tokens. store: Whether or not to store the output of this chat completion request for use in @@ -1112,9 +1103,6 @@ async def create( tier with a lower uptime SLA and no latency guarentee. - When not set, the default behavior is 'auto'. - When this parameter is set, the response body will include the `service_tier` - utilized. - stop: Up to 4 sequences where the API will stop generating further tokens. store: Whether or not to store the output of this chat completion request for use in @@ -1370,9 +1358,6 @@ async def create( tier with a lower uptime SLA and no latency guarentee. - When not set, the default behavior is 'auto'. - When this parameter is set, the response body will include the `service_tier` - utilized. - stop: Up to 4 sequences where the API will stop generating further tokens. store: Whether or not to store the output of this chat completion request for use in @@ -1621,9 +1606,6 @@ async def create( tier with a lower uptime SLA and no latency guarentee. - When not set, the default behavior is 'auto'. - When this parameter is set, the response body will include the `service_tier` - utilized. - stop: Up to 4 sequences where the API will stop generating further tokens. store: Whether or not to store the output of this chat completion request for use in diff --git a/src/openai/resources/embeddings.py b/src/openai/resources/embeddings.py index 81a3e354e6..382a42340e 100644 --- a/src/openai/resources/embeddings.py +++ b/src/openai/resources/embeddings.py @@ -68,7 +68,8 @@ def create( `text-embedding-ada-002`), cannot be an empty string, and any array must be 2048 dimensions or less. [Example Python code](https://cookbook.openai.com/examples/how_to_count_tokens_with_tiktoken) - for counting tokens. + for counting tokens. Some models may also impose a limit on total number of + tokens summed across inputs. model: ID of the model to use. You can use the [List models](https://platform.openai.com/docs/api-reference/models/list) API to @@ -180,7 +181,8 @@ async def create( `text-embedding-ada-002`), cannot be an empty string, and any array must be 2048 dimensions or less. [Example Python code](https://cookbook.openai.com/examples/how_to_count_tokens_with_tiktoken) - for counting tokens. + for counting tokens. Some models may also impose a limit on total number of + tokens summed across inputs. model: ID of the model to use. You can use the [List models](https://platform.openai.com/docs/api-reference/models/list) API to diff --git a/src/openai/types/audio/speech_create_params.py b/src/openai/types/audio/speech_create_params.py index a60d000708..ed1a1ce748 100644 --- a/src/openai/types/audio/speech_create_params.py +++ b/src/openai/types/audio/speech_create_params.py @@ -20,11 +20,11 @@ class SpeechCreateParams(TypedDict, total=False): `tts-1` or `tts-1-hd` """ - voice: Required[Literal["alloy", "echo", "fable", "onyx", "nova", "shimmer"]] + voice: Required[Literal["alloy", "ash", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer"]] """The voice to use when generating the audio. - Supported voices are `alloy`, `echo`, `fable`, `onyx`, `nova`, and `shimmer`. - Previews of the voices are available in the + Supported voices are `alloy`, `ash`, `coral`, `echo`, `fable`, `onyx`, `nova`, + `sage` and `shimmer`. Previews of the voices are available in the [Text to speech guide](https://platform.openai.com/docs/guides/text-to-speech#voice-options). """ diff --git a/src/openai/types/beta/realtime/conversation_item_create_event.py b/src/openai/types/beta/realtime/conversation_item_create_event.py index 50d309675b..c4f72b9aff 100644 --- a/src/openai/types/beta/realtime/conversation_item_create_event.py +++ b/src/openai/types/beta/realtime/conversation_item_create_event.py @@ -20,9 +20,10 @@ class ConversationItemCreateEvent(BaseModel): """Optional client-generated ID used to identify this event.""" previous_item_id: Optional[str] = None - """The ID of the preceding item after which the new item will be inserted. - - If not set, the new item will be appended to the end of the conversation. If - set, it allows an item to be inserted mid-conversation. If the ID cannot be - found, an error will be returned and the item will not be added. + """ + The ID of the preceding item after which the new item will be inserted. If not + set, the new item will be appended to the end of the conversation. If set to + `root`, the new item will be added to the beginning of the conversation. If set + to an existing ID, it allows an item to be inserted mid-conversation. If the ID + cannot be found, an error will be returned and the item will not be added. """ diff --git a/src/openai/types/beta/realtime/conversation_item_create_event_param.py b/src/openai/types/beta/realtime/conversation_item_create_event_param.py index b8c8bbc251..6da5a63a9d 100644 --- a/src/openai/types/beta/realtime/conversation_item_create_event_param.py +++ b/src/openai/types/beta/realtime/conversation_item_create_event_param.py @@ -20,9 +20,10 @@ class ConversationItemCreateEventParam(TypedDict, total=False): """Optional client-generated ID used to identify this event.""" previous_item_id: str - """The ID of the preceding item after which the new item will be inserted. - - If not set, the new item will be appended to the end of the conversation. If - set, it allows an item to be inserted mid-conversation. If the ID cannot be - found, an error will be returned and the item will not be added. + """ + The ID of the preceding item after which the new item will be inserted. If not + set, the new item will be appended to the end of the conversation. If set to + `root`, the new item will be added to the beginning of the conversation. If set + to an existing ID, it allows an item to be inserted mid-conversation. If the ID + cannot be found, an error will be returned and the item will not be added. """ diff --git a/src/openai/types/beta/realtime/session.py b/src/openai/types/beta/realtime/session.py index 09cdbb02bc..2d028f817c 100644 --- a/src/openai/types/beta/realtime/session.py +++ b/src/openai/types/beta/realtime/session.py @@ -63,7 +63,12 @@ class Session(BaseModel): """Unique identifier for the session object.""" input_audio_format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None - """The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + """The format of input audio. + + Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, input audio must + be 16-bit PCM at a 24kHz sample rate, single channel (mono), and little-endian + byte order. + """ input_audio_transcription: Optional[InputAudioTranscription] = None """ @@ -117,7 +122,11 @@ class Session(BaseModel): """The Realtime model used for this session.""" output_audio_format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None - """The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + """The format of output audio. + + Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, output audio is + sampled at a rate of 24kHz. + """ temperature: Optional[float] = None """Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8.""" diff --git a/src/openai/types/beta/realtime/session_create_params.py b/src/openai/types/beta/realtime/session_create_params.py index f56f2c5c22..3708efeecd 100644 --- a/src/openai/types/beta/realtime/session_create_params.py +++ b/src/openai/types/beta/realtime/session_create_params.py @@ -3,25 +3,19 @@ from __future__ import annotations from typing import List, Union, Iterable -from typing_extensions import Literal, Required, TypedDict +from typing_extensions import Literal, TypedDict __all__ = ["SessionCreateParams", "InputAudioTranscription", "Tool", "TurnDetection"] class SessionCreateParams(TypedDict, total=False): - model: Required[ - Literal[ - "gpt-4o-realtime-preview", - "gpt-4o-realtime-preview-2024-10-01", - "gpt-4o-realtime-preview-2024-12-17", - "gpt-4o-mini-realtime-preview", - "gpt-4o-mini-realtime-preview-2024-12-17", - ] - ] - """The Realtime model used for this session.""" - input_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] - """The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + """The format of input audio. + + Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, input audio must + be 16-bit PCM at a 24kHz sample rate, single channel (mono), and little-endian + byte order. + """ input_audio_transcription: InputAudioTranscription """ @@ -61,8 +55,21 @@ class SessionCreateParams(TypedDict, total=False): To disable audio, set this to ["text"]. """ + model: Literal[ + "gpt-4o-realtime-preview", + "gpt-4o-realtime-preview-2024-10-01", + "gpt-4o-realtime-preview-2024-12-17", + "gpt-4o-mini-realtime-preview", + "gpt-4o-mini-realtime-preview-2024-12-17", + ] + """The Realtime model used for this session.""" + output_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] - """The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + """The format of output audio. + + Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, output audio is + sampled at a rate of 24kHz. + """ temperature: float """Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8.""" diff --git a/src/openai/types/beta/realtime/session_update_event.py b/src/openai/types/beta/realtime/session_update_event.py index c04220aa25..322e588a4e 100644 --- a/src/openai/types/beta/realtime/session_update_event.py +++ b/src/openai/types/beta/realtime/session_update_event.py @@ -65,17 +65,13 @@ class SessionTurnDetection(BaseModel): class Session(BaseModel): - model: Literal[ - "gpt-4o-realtime-preview", - "gpt-4o-realtime-preview-2024-10-01", - "gpt-4o-realtime-preview-2024-12-17", - "gpt-4o-mini-realtime-preview", - "gpt-4o-mini-realtime-preview-2024-12-17", - ] - """The Realtime model used for this session.""" - input_audio_format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None - """The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + """The format of input audio. + + Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, input audio must + be 16-bit PCM at a 24kHz sample rate, single channel (mono), and little-endian + byte order. + """ input_audio_transcription: Optional[SessionInputAudioTranscription] = None """ @@ -115,8 +111,23 @@ class Session(BaseModel): To disable audio, set this to ["text"]. """ + model: Optional[ + Literal[ + "gpt-4o-realtime-preview", + "gpt-4o-realtime-preview-2024-10-01", + "gpt-4o-realtime-preview-2024-12-17", + "gpt-4o-mini-realtime-preview", + "gpt-4o-mini-realtime-preview-2024-12-17", + ] + ] = None + """The Realtime model used for this session.""" + output_audio_format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None - """The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + """The format of output audio. + + Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, output audio is + sampled at a rate of 24kHz. + """ temperature: Optional[float] = None """Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8.""" diff --git a/src/openai/types/beta/realtime/session_update_event_param.py b/src/openai/types/beta/realtime/session_update_event_param.py index aa06069b04..c01d9b6887 100644 --- a/src/openai/types/beta/realtime/session_update_event_param.py +++ b/src/openai/types/beta/realtime/session_update_event_param.py @@ -71,19 +71,13 @@ class SessionTurnDetection(TypedDict, total=False): class Session(TypedDict, total=False): - model: Required[ - Literal[ - "gpt-4o-realtime-preview", - "gpt-4o-realtime-preview-2024-10-01", - "gpt-4o-realtime-preview-2024-12-17", - "gpt-4o-mini-realtime-preview", - "gpt-4o-mini-realtime-preview-2024-12-17", - ] - ] - """The Realtime model used for this session.""" - input_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] - """The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + """The format of input audio. + + Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, input audio must + be 16-bit PCM at a 24kHz sample rate, single channel (mono), and little-endian + byte order. + """ input_audio_transcription: SessionInputAudioTranscription """ @@ -123,8 +117,21 @@ class Session(TypedDict, total=False): To disable audio, set this to ["text"]. """ + model: Literal[ + "gpt-4o-realtime-preview", + "gpt-4o-realtime-preview-2024-10-01", + "gpt-4o-realtime-preview-2024-12-17", + "gpt-4o-mini-realtime-preview", + "gpt-4o-mini-realtime-preview-2024-12-17", + ] + """The Realtime model used for this session.""" + output_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] - """The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + """The format of output audio. + + Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, output audio is + sampled at a rate of 24kHz. + """ temperature: float """Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8.""" diff --git a/src/openai/types/chat/chat_completion.py b/src/openai/types/chat/chat_completion.py index 4b53e70890..cb812a2702 100644 --- a/src/openai/types/chat/chat_completion.py +++ b/src/openai/types/chat/chat_completion.py @@ -60,11 +60,7 @@ class ChatCompletion(BaseModel): """The object type, which is always `chat.completion`.""" service_tier: Optional[Literal["scale", "default"]] = None - """The service tier used for processing the request. - - This field is only included if the `service_tier` parameter is specified in the - request. - """ + """The service tier used for processing the request.""" system_fingerprint: Optional[str] = None """This fingerprint represents the backend configuration that the model runs with. diff --git a/src/openai/types/chat/chat_completion_assistant_message_param.py b/src/openai/types/chat/chat_completion_assistant_message_param.py index 35e3a3d784..229fb822f4 100644 --- a/src/openai/types/chat/chat_completion_assistant_message_param.py +++ b/src/openai/types/chat/chat_completion_assistant_message_param.py @@ -38,8 +38,8 @@ class ChatCompletionAssistantMessageParam(TypedDict, total=False): """The role of the messages author, in this case `assistant`.""" audio: Optional[Audio] - """Data about a previous audio response from the model. - + """ + Data about a previous audio response from the model. [Learn more](https://platform.openai.com/docs/guides/audio). """ diff --git a/src/openai/types/chat/chat_completion_chunk.py b/src/openai/types/chat/chat_completion_chunk.py index 9ec6dc4bdb..7b0ae2e121 100644 --- a/src/openai/types/chat/chat_completion_chunk.py +++ b/src/openai/types/chat/chat_completion_chunk.py @@ -129,11 +129,7 @@ class ChatCompletionChunk(BaseModel): """The object type, which is always `chat.completion.chunk`.""" service_tier: Optional[Literal["scale", "default"]] = None - """The service tier used for processing the request. - - This field is only included if the `service_tier` parameter is specified in the - request. - """ + """The service tier used for processing the request.""" system_fingerprint: Optional[str] = None """ diff --git a/src/openai/types/chat/completion_create_params.py b/src/openai/types/chat/completion_create_params.py index f168ddea6e..30d930b120 100644 --- a/src/openai/types/chat/completion_create_params.py +++ b/src/openai/types/chat/completion_create_params.py @@ -220,9 +220,6 @@ class CompletionCreateParamsBase(TypedDict, total=False): - If set to 'default', the request will be processed using the default service tier with a lower uptime SLA and no latency guarentee. - When not set, the default behavior is 'auto'. - - When this parameter is set, the response body will include the `service_tier` - utilized. """ stop: Union[Optional[str], List[str]] diff --git a/src/openai/types/embedding_create_params.py b/src/openai/types/embedding_create_params.py index 1385762885..a90566449b 100644 --- a/src/openai/types/embedding_create_params.py +++ b/src/openai/types/embedding_create_params.py @@ -19,7 +19,8 @@ class EmbeddingCreateParams(TypedDict, total=False): (8192 tokens for `text-embedding-ada-002`), cannot be an empty string, and any array must be 2048 dimensions or less. [Example Python code](https://cookbook.openai.com/examples/how_to_count_tokens_with_tiktoken) - for counting tokens. + for counting tokens. Some models may also impose a limit on total number of + tokens summed across inputs. """ model: Required[Union[str, EmbeddingModel]] diff --git a/tests/api_resources/beta/realtime/test_sessions.py b/tests/api_resources/beta/realtime/test_sessions.py index 65bfa27572..908aa983be 100644 --- a/tests/api_resources/beta/realtime/test_sessions.py +++ b/tests/api_resources/beta/realtime/test_sessions.py @@ -19,20 +19,18 @@ class TestSessions: @parametrize def test_method_create(self, client: OpenAI) -> None: - session = client.beta.realtime.sessions.create( - model="gpt-4o-realtime-preview", - ) + session = client.beta.realtime.sessions.create() assert_matches_type(SessionCreateResponse, session, path=["response"]) @parametrize def test_method_create_with_all_params(self, client: OpenAI) -> None: session = client.beta.realtime.sessions.create( - model="gpt-4o-realtime-preview", input_audio_format="pcm16", input_audio_transcription={"model": "model"}, instructions="instructions", max_response_output_tokens=0, modalities=["text"], + model="gpt-4o-realtime-preview", output_audio_format="pcm16", temperature=0, tool_choice="tool_choice", @@ -57,9 +55,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: @parametrize def test_raw_response_create(self, client: OpenAI) -> None: - response = client.beta.realtime.sessions.with_raw_response.create( - model="gpt-4o-realtime-preview", - ) + response = client.beta.realtime.sessions.with_raw_response.create() assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -68,9 +64,7 @@ def test_raw_response_create(self, client: OpenAI) -> None: @parametrize def test_streaming_response_create(self, client: OpenAI) -> None: - with client.beta.realtime.sessions.with_streaming_response.create( - model="gpt-4o-realtime-preview", - ) as response: + with client.beta.realtime.sessions.with_streaming_response.create() as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -85,20 +79,18 @@ class TestAsyncSessions: @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: - session = await async_client.beta.realtime.sessions.create( - model="gpt-4o-realtime-preview", - ) + session = await async_client.beta.realtime.sessions.create() assert_matches_type(SessionCreateResponse, session, path=["response"]) @parametrize async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: session = await async_client.beta.realtime.sessions.create( - model="gpt-4o-realtime-preview", input_audio_format="pcm16", input_audio_transcription={"model": "model"}, instructions="instructions", max_response_output_tokens=0, modalities=["text"], + model="gpt-4o-realtime-preview", output_audio_format="pcm16", temperature=0, tool_choice="tool_choice", @@ -123,9 +115,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> @parametrize async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.realtime.sessions.with_raw_response.create( - model="gpt-4o-realtime-preview", - ) + response = await async_client.beta.realtime.sessions.with_raw_response.create() assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -134,9 +124,7 @@ async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.realtime.sessions.with_streaming_response.create( - model="gpt-4o-realtime-preview", - ) as response: + async with async_client.beta.realtime.sessions.with_streaming_response.create() as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" diff --git a/tests/api_resources/chat/test_completions.py b/tests/api_resources/chat/test_completions.py index 393a790549..25c9a36164 100644 --- a/tests/api_resources/chat/test_completions.py +++ b/tests/api_resources/chat/test_completions.py @@ -72,7 +72,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: presence_penalty=-2, reasoning_effort="low", response_format={"type": "text"}, - seed=-9007199254740991, + seed=0, service_tier="auto", stop="string", store=True, @@ -187,7 +187,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: presence_penalty=-2, reasoning_effort="low", response_format={"type": "text"}, - seed=-9007199254740991, + seed=0, service_tier="auto", stop="string", store=True, @@ -321,7 +321,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn presence_penalty=-2, reasoning_effort="low", response_format={"type": "text"}, - seed=-9007199254740991, + seed=0, service_tier="auto", stop="string", store=True, @@ -436,7 +436,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn presence_penalty=-2, reasoning_effort="low", response_format={"type": "text"}, - seed=-9007199254740991, + seed=0, service_tier="auto", stop="string", store=True, diff --git a/tests/api_resources/test_completions.py b/tests/api_resources/test_completions.py index ad2679cabe..9ec503c1e3 100644 --- a/tests/api_resources/test_completions.py +++ b/tests/api_resources/test_completions.py @@ -38,7 +38,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: max_tokens=16, n=1, presence_penalty=-2, - seed=-9007199254740991, + seed=0, stop="\n", stream=False, stream_options={"include_usage": True}, @@ -98,7 +98,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: max_tokens=16, n=1, presence_penalty=-2, - seed=-9007199254740991, + seed=0, stop="\n", stream_options={"include_usage": True}, suffix="test.", @@ -160,7 +160,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn max_tokens=16, n=1, presence_penalty=-2, - seed=-9007199254740991, + seed=0, stop="\n", stream=False, stream_options={"include_usage": True}, @@ -220,7 +220,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn max_tokens=16, n=1, presence_penalty=-2, - seed=-9007199254740991, + seed=0, stop="\n", stream_options={"include_usage": True}, suffix="test.", From c111dab6af1bb40e1f8768c9941dc7c292293e59 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 22 Jan 2025 13:22:04 +0000 Subject: [PATCH 176/769] release: 1.60.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 18 ++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 32b4e18516..88c2f64985 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.59.9" + ".": "1.60.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 86951242c5..9f90d3dd22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ # Changelog +## 1.60.0 (2025-01-22) + +Full Changelog: [v1.59.9...v1.60.0](https://github.com/openai/openai-python/compare/v1.59.9...v1.60.0) + +### Features + +* **api:** update enum values, comments, and examples ([#2045](https://github.com/openai/openai-python/issues/2045)) ([e8205fd](https://github.com/openai/openai-python/commit/e8205fd58f0d677f476c577a8d9afb90f5710506)) + + +### Chores + +* **internal:** minor style changes ([#2043](https://github.com/openai/openai-python/issues/2043)) ([89a9dd8](https://github.com/openai/openai-python/commit/89a9dd821eaf5300ad11b0270b61fdfa4fd6e9b6)) + + +### Documentation + +* **readme:** mention failed requests in request IDs ([5f7c30b](https://github.com/openai/openai-python/commit/5f7c30bc006ffb666c324011a68aae357cb33e35)) + ## 1.59.9 (2025-01-20) Full Changelog: [v1.59.8...v1.59.9](https://github.com/openai/openai-python/compare/v1.59.8...v1.59.9) diff --git a/pyproject.toml b/pyproject.toml index 0b142a6bd8..80c79ff585 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.59.9" +version = "1.60.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 7c92c3adf3..ef0ddcfc5c 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.59.9" # x-release-please-version +__version__ = "1.60.0" # x-release-please-version From abc5459c7504eec25a67b35104e2e09e7d8f232c Mon Sep 17 00:00:00 2001 From: Fernando de Oliveira <5161098+fedeoliv@users.noreply.github.com> Date: Wed, 22 Jan 2025 16:44:26 -0500 Subject: [PATCH 177/769] docs(examples/azure): add async snippet (#1787) --- examples/azure_ad.py | 79 ++++++++++++++++++++++++++++++++------------ 1 file changed, 58 insertions(+), 21 deletions(-) diff --git a/examples/azure_ad.py b/examples/azure_ad.py index 1b0d81863d..67e2f23713 100755 --- a/examples/azure_ad.py +++ b/examples/azure_ad.py @@ -1,30 +1,67 @@ -from azure.identity import DefaultAzureCredential, get_bearer_token_provider +import asyncio -from openai import AzureOpenAI +from openai.lib.azure import AzureOpenAI, AsyncAzureOpenAI, AzureADTokenProvider, AsyncAzureADTokenProvider -token_provider = get_bearer_token_provider(DefaultAzureCredential(), "https://cognitiveservices.azure.com/.default") +scopes = "https://cognitiveservices.azure.com/.default" - -# may change in the future +# May change in the future # https://learn.microsoft.com/en-us/azure/ai-services/openai/reference#rest-api-versioning api_version = "2023-07-01-preview" # https://learn.microsoft.com/en-us/azure/cognitive-services/openai/how-to/create-resource?pivots=web-portal#create-a-resource endpoint = "https://my-resource.openai.azure.com" -client = AzureOpenAI( - api_version=api_version, - azure_endpoint=endpoint, - azure_ad_token_provider=token_provider, -) - -completion = client.chat.completions.create( - model="deployment-name", # e.g. gpt-35-instant - messages=[ - { - "role": "user", - "content": "How do I output all files in a directory using Python?", - }, - ], -) -print(completion.to_json()) +deployment_name = "deployment-name" # e.g. gpt-35-instant + + +def sync_main() -> None: + from azure.identity import DefaultAzureCredential, get_bearer_token_provider + + token_provider: AzureADTokenProvider = get_bearer_token_provider(DefaultAzureCredential(), scopes) + + client = AzureOpenAI( + api_version=api_version, + azure_endpoint=endpoint, + azure_ad_token_provider=token_provider, + ) + + completion = client.chat.completions.create( + model=deployment_name, + messages=[ + { + "role": "user", + "content": "How do I output all files in a directory using Python?", + } + ], + ) + + print(completion.to_json()) + + +async def async_main() -> None: + from azure.identity.aio import DefaultAzureCredential, get_bearer_token_provider + + token_provider: AsyncAzureADTokenProvider = get_bearer_token_provider(DefaultAzureCredential(), scopes) + + client = AsyncAzureOpenAI( + api_version=api_version, + azure_endpoint=endpoint, + azure_ad_token_provider=token_provider, + ) + + completion = await client.chat.completions.create( + model=deployment_name, + messages=[ + { + "role": "user", + "content": "How do I output all files in a directory using Python?", + } + ], + ) + + print(completion.to_json()) + + +sync_main() + +asyncio.run(async_main()) From 27d0e67b1d121ccc5b48c95e1f0bc3f6e93e9bd3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 23 Jan 2025 12:39:04 +0000 Subject: [PATCH 178/769] chore(internal): minor formatting changes (#2050) --- .github/workflows/ci.yml | 1 + scripts/bootstrap | 2 +- scripts/lint | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index de70348b9c..26f497db1f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,6 +29,7 @@ jobs: - name: Run lints run: ./scripts/lint + test: name: test runs-on: ubuntu-latest diff --git a/scripts/bootstrap b/scripts/bootstrap index 29df07e77b..9910ec05fc 100755 --- a/scripts/bootstrap +++ b/scripts/bootstrap @@ -4,7 +4,7 @@ set -e cd "$(dirname "$0")/.." -if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ]; then +if ! command -v rye >/dev/null 2>&1 && [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ]; then brew bundle check >/dev/null 2>&1 || { echo "==> Installing Homebrew dependencies…" brew bundle diff --git a/scripts/lint b/scripts/lint index 64495ee345..55bc1dd711 100755 --- a/scripts/lint +++ b/scripts/lint @@ -9,4 +9,3 @@ rye run lint echo "==> Making sure it imports" rye run python -c 'import openai' - From b95be16e7c8a76c3d63335df13ab0d55ba3d5c35 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 24 Jan 2025 05:04:08 +0000 Subject: [PATCH 179/769] release: 1.60.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 88c2f64985..0b39405429 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.60.0" + ".": "1.60.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f90d3dd22..873a6a254d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 1.60.1 (2025-01-24) + +Full Changelog: [v1.60.0...v1.60.1](https://github.com/openai/openai-python/compare/v1.60.0...v1.60.1) + +### Chores + +* **internal:** minor formatting changes ([#2050](https://github.com/openai/openai-python/issues/2050)) ([9c44192](https://github.com/openai/openai-python/commit/9c44192be5776d9252d36dc027a33c60b33d81b2)) + + +### Documentation + +* **examples/azure:** add async snippet ([#1787](https://github.com/openai/openai-python/issues/1787)) ([f60eda1](https://github.com/openai/openai-python/commit/f60eda1c1e8caf0ec2274b18b3fb2252304196db)) + ## 1.60.0 (2025-01-22) Full Changelog: [v1.59.9...v1.60.0](https://github.com/openai/openai-python/compare/v1.59.9...v1.60.0) diff --git a/pyproject.toml b/pyproject.toml index 80c79ff585..fdfc9c73e3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.60.0" +version = "1.60.1" 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 ef0ddcfc5c..b87aa8abd4 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.60.0" # x-release-please-version +__version__ = "1.60.1" # x-release-please-version From 257d79e8a00144a7317d511401da2432a4201c7b Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Mon, 27 Jan 2025 19:20:32 +0000 Subject: [PATCH 180/769] fix(parsing): don't validate input tools in the asynchronous `.parse()` method --- src/openai/resources/beta/chat/completions.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/openai/resources/beta/chat/completions.py b/src/openai/resources/beta/chat/completions.py index 48cb13f7a6..7771d2ff50 100644 --- a/src/openai/resources/beta/chat/completions.py +++ b/src/openai/resources/beta/chat/completions.py @@ -268,6 +268,8 @@ def stream( When the context manager exits, the response will be closed, however the `stream` instance is still available outside the context manager. """ + _validate_input_tools(tools) + extra_headers = { "X-Stainless-Helper-Method": "beta.chat.completions.stream", **(extra_headers or {}), From d16e6edde5a155626910b5758a0b939bfedb9ced Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 27 Jan 2025 19:26:48 +0000 Subject: [PATCH 181/769] release: 1.60.2 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 0b39405429..73f712c242 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.60.1" + ".": "1.60.2" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 873a6a254d..168d98e5cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.60.2 (2025-01-27) + +Full Changelog: [v1.60.1...v1.60.2](https://github.com/openai/openai-python/compare/v1.60.1...v1.60.2) + +### Bug Fixes + +* **parsing:** don't validate input tools in the asynchronous `.parse()` method ([6fcfe73](https://github.com/openai/openai-python/commit/6fcfe73cd335853c7dd2cd3151a0d5d1785cfc9c)) + ## 1.60.1 (2025-01-24) Full Changelog: [v1.60.0...v1.60.1](https://github.com/openai/openai-python/compare/v1.60.0...v1.60.1) diff --git a/pyproject.toml b/pyproject.toml index fdfc9c73e3..9657bdc0ce 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.60.1" +version = "1.60.2" 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 b87aa8abd4..c8f825db34 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.60.1" # x-release-please-version +__version__ = "1.60.2" # x-release-please-version From 90e3d39655548c935002dee7ef6f617c846c123c Mon Sep 17 00:00:00 2001 From: Guspan Tanadi <36249910+guspan-tanadi@users.noreply.github.com> Date: Wed, 29 Jan 2025 04:58:34 +0700 Subject: [PATCH 182/769] docs(readme): current section links (#2055) chore(helpers): section links --- README.md | 4 ++-- helpers.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5f7d477cc8..3c103f036c 100644 --- a/README.md +++ b/README.md @@ -304,7 +304,7 @@ However the real magic of the Realtime API is handling audio inputs / outputs, s ### Realtime error handling -Whenever an error occurs, the Realtime API will send an [`error` event](https://platform.openai.com/docs/guides/realtime/realtime-api-beta#handling-errors) and the connection will stay open and remain usable. This means you need to handle it yourself, as *no errors are raised directly* by the SDK when an `error` event comes in. +Whenever an error occurs, the Realtime API will send an [`error` event](https://platform.openai.com/docs/guides/realtime-model-capabilities#error-handling) and the connection will stay open and remain usable. This means you need to handle it yourself, as *no errors are raised directly* by the SDK when an `error` event comes in. ```py client = AsyncOpenAI() @@ -547,7 +547,7 @@ client.with_options(max_retries=5).chat.completions.create( ### Timeouts By default requests time out after 10 minutes. You can configure this with a `timeout` option, -which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/#fine-tuning-the-configuration) object: +which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object: ```python from openai import OpenAI diff --git a/helpers.md b/helpers.md index 3f3fafa45c..77823fa750 100644 --- a/helpers.md +++ b/helpers.md @@ -134,7 +134,7 @@ OpenAI supports streaming responses when interacting with the [Chat Completion]( The SDK provides a `.beta.chat.completions.stream()` method that wraps the `.chat.completions.create(stream=True)` stream providing a more granular event API & automatic accumulation of each delta. -It also supports all aforementioned [parsing helpers](#parsing-helpers). +It also supports all aforementioned [parsing helpers](#structured-outputs-parsing-helpers). Unlike `.create(stream=True)`, the `.stream()` method requires usage within a context manager to prevent accidental leakage of the response: From d779e40bc960c1d5fcf1b23b804af9b9ccf43c58 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 31 Jan 2025 10:09:46 +0000 Subject: [PATCH 183/769] chore: update api.md (#2063) --- api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api.md b/api.md index 1edd3f6589..f1e0d023bd 100644 --- a/api.md +++ b/api.md @@ -99,7 +99,7 @@ Methods: - client.files.list(\*\*params) -> SyncCursorPage[FileObject] - client.files.delete(file_id) -> FileDeleted - client.files.content(file_id) -> HttpxBinaryResponseContent -- client.files.retrieve_content(file_id) -> str +- client.files.retrieve_content(file_id) -> str - client.files.wait_for_processing(\*args) -> FileObject # Images From a99096823a878f0725ef1433226b3bc725c4c618 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Fri, 31 Jan 2025 11:47:20 +0000 Subject: [PATCH 184/769] Revert "fix(parsing): don't validate input tools in the asynchronous `.parse()` method" This reverts commit 257d79e8a00144a7317d511401da2432a4201c7b. --- src/openai/resources/beta/chat/completions.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/openai/resources/beta/chat/completions.py b/src/openai/resources/beta/chat/completions.py index 7771d2ff50..48cb13f7a6 100644 --- a/src/openai/resources/beta/chat/completions.py +++ b/src/openai/resources/beta/chat/completions.py @@ -268,8 +268,6 @@ def stream( When the context manager exits, the response will be closed, however the `stream` instance is still available outside the context manager. """ - _validate_input_tools(tools) - extra_headers = { "X-Stainless-Helper-Method": "beta.chat.completions.stream", **(extra_headers or {}), From fdd52476b56cbd57d0cbc27d06f9d2907b537e82 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 31 Jan 2025 19:09:53 +0000 Subject: [PATCH 185/769] feat(api): add o3-mini (#2067) fix(types): correct metadata type + other fixes --- .stats.yml | 2 +- api.md | 1 + src/openai/resources/audio/transcriptions.py | 8 +- src/openai/resources/batches.py | 26 ++-- src/openai/resources/beta/assistants.py | 41 +++--- .../resources/beta/realtime/sessions.py | 14 +- src/openai/resources/beta/threads/messages.py | 41 +++--- .../resources/beta/threads/runs/runs.py | 85 +++++++----- src/openai/resources/beta/threads/threads.py | 123 +++++++++++------- .../beta/vector_stores/vector_stores.py | 41 +++--- src/openai/resources/chat/completions.py | 89 ++++++++----- src/openai/types/__init__.py | 1 + .../audio/transcription_create_params.py | 4 +- src/openai/types/batch.py | 10 +- src/openai/types/batch_create_params.py | 15 ++- src/openai/types/beta/assistant.py | 9 +- .../types/beta/assistant_create_params.py | 21 +-- .../types/beta/assistant_update_params.py | 9 +- .../conversation_item_create_event.py | 12 +- .../conversation_item_create_event_param.py | 12 +- .../types/beta/realtime/realtime_response.py | 51 +++++++- .../beta/realtime/response_create_event.py | 9 +- .../realtime/response_create_event_param.py | 9 +- .../beta/realtime/session_create_params.py | 23 +++- .../beta/realtime/session_create_response.py | 6 +- .../beta/realtime/session_update_event.py | 23 +++- .../realtime/session_update_event_param.py | 23 +++- src/openai/types/beta/thread.py | 9 +- .../beta/thread_create_and_run_params.py | 43 +++--- src/openai/types/beta/thread_create_params.py | 29 +++-- src/openai/types/beta/thread_update_params.py | 10 +- src/openai/types/beta/threads/message.py | 9 +- .../beta/threads/message_create_params.py | 9 +- .../beta/threads/message_update_params.py | 10 +- src/openai/types/beta/threads/run.py | 9 +- .../types/beta/threads/run_create_params.py | 17 ++- .../types/beta/threads/run_update_params.py | 10 +- .../types/beta/threads/runs/run_step.py | 9 +- src/openai/types/beta/vector_store.py | 9 +- .../types/beta/vector_store_create_params.py | 9 +- .../types/beta/vector_store_update_params.py | 10 +- ...chat_completion_assistant_message_param.py | 4 +- .../types/chat/completion_create_params.py | 17 ++- src/openai/types/chat_model.py | 2 + src/openai/types/shared/__init__.py | 1 + src/openai/types/shared/metadata.py | 8 ++ src/openai/types/shared_params/__init__.py | 1 + src/openai/types/shared_params/metadata.py | 10 ++ src/openai/types/upload.py | 2 +- .../beta/realtime/test_sessions.py | 12 +- tests/api_resources/beta/test_assistants.py | 12 +- tests/api_resources/beta/test_threads.py | 52 ++++---- .../api_resources/beta/test_vector_stores.py | 16 +-- .../beta/threads/test_messages.py | 16 +-- tests/api_resources/beta/threads/test_runs.py | 28 ++-- 55 files changed, 710 insertions(+), 371 deletions(-) create mode 100644 src/openai/types/shared/metadata.py create mode 100644 src/openai/types/shared_params/metadata.py diff --git a/.stats.yml b/.stats.yml index d518bac586..e49b5c56e8 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-3904ef6b29a89c98f93a9b7da19879695f3c440564be6384db7af1b734611ede.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-6204952a29973265b9c0d66fc67ffaf53c6a90ae4d75cdacf9d147676f5274c9.yml diff --git a/api.md b/api.md index f1e0d023bd..c1262fd2c5 100644 --- a/api.md +++ b/api.md @@ -5,6 +5,7 @@ from openai.types import ( ErrorObject, FunctionDefinition, FunctionParameters, + Metadata, ResponseFormatJSONObject, ResponseFormatJSONSchema, ResponseFormatText, diff --git a/src/openai/resources/audio/transcriptions.py b/src/openai/resources/audio/transcriptions.py index 341446c43a..f338ad067d 100644 --- a/src/openai/resources/audio/transcriptions.py +++ b/src/openai/resources/audio/transcriptions.py @@ -138,8 +138,8 @@ def create( Whisper V2 model) is currently available. language: The language of the input audio. Supplying the input language in - [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) format will - improve accuracy and latency. + [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) + format will improve accuracy and latency. prompt: An optional text to guide the model's style or continue a previous audio segment. The @@ -302,8 +302,8 @@ async def create( Whisper V2 model) is currently available. language: The language of the input audio. Supplying the input language in - [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) format will - improve accuracy and latency. + [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) + format will improve accuracy and latency. prompt: An optional text to guide the model's style or continue a previous audio segment. The diff --git a/src/openai/resources/batches.py b/src/openai/resources/batches.py index 4a887642e9..7e7ec19ec2 100644 --- a/src/openai/resources/batches.py +++ b/src/openai/resources/batches.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict, Optional +from typing import Optional from typing_extensions import Literal import httpx @@ -19,10 +19,8 @@ from .._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper from ..pagination import SyncCursorPage, AsyncCursorPage from ..types.batch import Batch -from .._base_client import ( - AsyncPaginator, - make_request_options, -) +from .._base_client import AsyncPaginator, make_request_options +from ..types.shared_params.metadata import Metadata __all__ = ["Batches", "AsyncBatches"] @@ -53,7 +51,7 @@ def create( completion_window: Literal["24h"], endpoint: Literal["/v1/chat/completions", "/v1/embeddings", "/v1/completions"], input_file_id: str, - metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -83,7 +81,12 @@ def create( and must be uploaded with the purpose `batch`. The file can contain up to 50,000 requests, and can be up to 200 MB in size. - metadata: Optional custom metadata for the batch. + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. extra_headers: Send extra headers @@ -258,7 +261,7 @@ async def create( completion_window: Literal["24h"], endpoint: Literal["/v1/chat/completions", "/v1/embeddings", "/v1/completions"], input_file_id: str, - metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -288,7 +291,12 @@ async def create( and must be uploaded with the purpose `batch`. The file can contain up to 50,000 requests, and can be up to 200 MB in size. - metadata: Optional custom metadata for the batch. + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. extra_headers: Send extra headers diff --git a/src/openai/resources/beta/assistants.py b/src/openai/resources/beta/assistants.py index 2f2482b648..65b7c9cfc2 100644 --- a/src/openai/resources/beta/assistants.py +++ b/src/openai/resources/beta/assistants.py @@ -26,6 +26,7 @@ from ...types.chat_model import ChatModel from ...types.beta.assistant import Assistant from ...types.beta.assistant_deleted import AssistantDeleted +from ...types.shared_params.metadata import Metadata from ...types.beta.assistant_tool_param import AssistantToolParam from ...types.beta.assistant_response_format_option_param import AssistantResponseFormatOptionParam @@ -58,7 +59,7 @@ def create( model: Union[str, ChatModel], description: Optional[str] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, name: Optional[str] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -88,9 +89,11 @@ def create( characters. metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maximum of 512 - characters long. + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. name: The name of the assistant. The maximum length is 256 characters. @@ -206,7 +209,7 @@ def update( *, description: Optional[str] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: str | NotGiven = NOT_GIVEN, name: Optional[str] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -232,9 +235,11 @@ def update( characters. metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maximum of 512 - characters long. + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. model: ID of the model to use. You can use the [List models](https://platform.openai.com/docs/api-reference/models/list) API to @@ -444,7 +449,7 @@ async def create( model: Union[str, ChatModel], description: Optional[str] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, name: Optional[str] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -474,9 +479,11 @@ async def create( characters. metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maximum of 512 - characters long. + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. name: The name of the assistant. The maximum length is 256 characters. @@ -592,7 +599,7 @@ async def update( *, description: Optional[str] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: str | NotGiven = NOT_GIVEN, name: Optional[str] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -618,9 +625,11 @@ async def update( characters. metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maximum of 512 - characters long. + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. model: ID of the model to use. You can use the [List models](https://platform.openai.com/docs/api-reference/models/list) API to diff --git a/src/openai/resources/beta/realtime/sessions.py b/src/openai/resources/beta/realtime/sessions.py index b920c89207..4b337b7c19 100644 --- a/src/openai/resources/beta/realtime/sessions.py +++ b/src/openai/resources/beta/realtime/sessions.py @@ -89,8 +89,11 @@ def create( input_audio_transcription: Configuration for input audio transcription, defaults to off and can be set to `null` to turn off once on. Input audio transcription is not native to the model, since the model consumes audio directly. Transcription runs - asynchronously through Whisper and should be treated as rough guidance rather - than the representation understood by the model. + asynchronously through + [OpenAI Whisper transcription](https://platform.openai.com/docs/api-reference/audio/createTranscription) + and should be treated as rough guidance rather than the representation + understood by the model. The client can optionally set the language and prompt + for transcription, these fields will be passed to the Whisper API. instructions: The default system instructions (i.e. system message) prepended to model calls. This field allows the client to guide the model on desired responses. The model @@ -232,8 +235,11 @@ async def create( input_audio_transcription: Configuration for input audio transcription, defaults to off and can be set to `null` to turn off once on. Input audio transcription is not native to the model, since the model consumes audio directly. Transcription runs - asynchronously through Whisper and should be treated as rough guidance rather - than the representation understood by the model. + asynchronously through + [OpenAI Whisper transcription](https://platform.openai.com/docs/api-reference/audio/createTranscription) + and should be treated as rough guidance rather than the representation + understood by the model. The client can optionally set the language and prompt + for transcription, these fields will be passed to the Whisper API. instructions: The default system instructions (i.e. system message) prepended to model calls. This field allows the client to guide the model on desired responses. The model diff --git a/src/openai/resources/beta/threads/messages.py b/src/openai/resources/beta/threads/messages.py index f780f6f558..e3374aba37 100644 --- a/src/openai/resources/beta/threads/messages.py +++ b/src/openai/resources/beta/threads/messages.py @@ -23,6 +23,7 @@ ) from ....types.beta.threads import message_list_params, message_create_params, message_update_params from ....types.beta.threads.message import Message +from ....types.shared_params.metadata import Metadata from ....types.beta.threads.message_deleted import MessageDeleted from ....types.beta.threads.message_content_part_param import MessageContentPartParam @@ -56,7 +57,7 @@ def create( content: Union[str, Iterable[MessageContentPartParam]], role: Literal["user", "assistant"], attachments: Optional[Iterable[message_create_params.Attachment]] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -81,9 +82,11 @@ def create( attachments: A list of files attached to the message, and the tools they should be added to. metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maximum of 512 - characters long. + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. extra_headers: Send extra headers @@ -155,7 +158,7 @@ def update( message_id: str, *, thread_id: str, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -168,9 +171,11 @@ def update( Args: metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maximum of 512 - characters long. + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. extra_headers: Send extra headers @@ -330,7 +335,7 @@ async def create( content: Union[str, Iterable[MessageContentPartParam]], role: Literal["user", "assistant"], attachments: Optional[Iterable[message_create_params.Attachment]] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -355,9 +360,11 @@ async def create( attachments: A list of files attached to the message, and the tools they should be added to. metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maximum of 512 - characters long. + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. extra_headers: Send extra headers @@ -429,7 +436,7 @@ async def update( message_id: str, *, thread_id: str, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -442,9 +449,11 @@ async def update( Args: metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maximum of 512 - characters long. + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. extra_headers: Send extra headers diff --git a/src/openai/resources/beta/threads/runs/runs.py b/src/openai/resources/beta/threads/runs/runs.py index f32a08f235..9cb202a1a2 100644 --- a/src/openai/resources/beta/threads/runs/runs.py +++ b/src/openai/resources/beta/threads/runs/runs.py @@ -47,6 +47,7 @@ run_submit_tool_outputs_params, ) from .....types.beta.threads.run import Run +from .....types.shared_params.metadata import Metadata from .....types.beta.assistant_tool_param import AssistantToolParam from .....types.beta.assistant_stream_event import AssistantStreamEvent from .....types.beta.threads.runs.run_step_include import RunStepInclude @@ -92,7 +93,7 @@ def create( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -148,9 +149,11 @@ def create( `incomplete_details` for more info. metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maximum of 512 - characters long. + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to be used to execute this run. If a value is provided here, it will override the @@ -233,7 +236,7 @@ def create( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -292,9 +295,11 @@ def create( `incomplete_details` for more info. metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maximum of 512 - characters long. + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to be used to execute this run. If a value is provided here, it will override the @@ -373,7 +378,7 @@ def create( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -432,9 +437,11 @@ def create( `incomplete_details` for more info. metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maximum of 512 - characters long. + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to be used to execute this run. If a value is provided here, it will override the @@ -512,7 +519,7 @@ def create( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -609,7 +616,7 @@ def update( run_id: str, *, thread_id: str, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -622,9 +629,11 @@ def update( Args: metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maximum of 512 - characters long. + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. extra_headers: Send extra headers @@ -1457,7 +1466,7 @@ async def create( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -1513,9 +1522,11 @@ async def create( `incomplete_details` for more info. metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maximum of 512 - characters long. + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to be used to execute this run. If a value is provided here, it will override the @@ -1598,7 +1609,7 @@ async def create( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -1657,9 +1668,11 @@ async def create( `incomplete_details` for more info. metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maximum of 512 - characters long. + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to be used to execute this run. If a value is provided here, it will override the @@ -1738,7 +1751,7 @@ async def create( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -1797,9 +1810,11 @@ async def create( `incomplete_details` for more info. metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maximum of 512 - characters long. + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to be used to execute this run. If a value is provided here, it will override the @@ -1877,7 +1892,7 @@ async def create( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -1974,7 +1989,7 @@ async def update( run_id: str, *, thread_id: str, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1987,9 +2002,11 @@ async def update( Args: metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maximum of 512 - characters long. + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. extra_headers: Send extra headers diff --git a/src/openai/resources/beta/threads/threads.py b/src/openai/resources/beta/threads/threads.py index 186b6f63e2..0ec59aca55 100644 --- a/src/openai/resources/beta/threads/threads.py +++ b/src/openai/resources/beta/threads/threads.py @@ -53,6 +53,7 @@ from ....types.beta.thread import Thread from ....types.beta.threads.run import Run from ....types.beta.thread_deleted import ThreadDeleted +from ....types.shared_params.metadata import Metadata from ....types.beta.assistant_stream_event import AssistantStreamEvent from ....types.beta.assistant_tool_choice_option_param import AssistantToolChoiceOptionParam from ....types.beta.assistant_response_format_option_param import AssistantResponseFormatOptionParam @@ -92,7 +93,7 @@ def create( self, *, messages: Iterable[thread_create_params.Message] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, tool_resources: Optional[thread_create_params.ToolResources] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -109,9 +110,11 @@ def create( start the thread with. metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maximum of 512 - characters long. + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. tool_resources: A set of resources that are made available to the assistant's tools in this thread. The resources are specific to the type of tool. For example, the @@ -181,7 +184,7 @@ def update( self, thread_id: str, *, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, tool_resources: Optional[thread_update_params.ToolResources] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -195,9 +198,11 @@ def update( Args: metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maximum of 512 - characters long. + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. tool_resources: A set of resources that are made available to the assistant's tools in this thread. The resources are specific to the type of tool. For example, the @@ -272,7 +277,7 @@ def create_and_run( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -315,9 +320,11 @@ def create_and_run( `incomplete_details` for more info. metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maximum of 512 - characters long. + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to be used to execute this run. If a value is provided here, it will override the @@ -357,7 +364,8 @@ def create_and_run( make the output more random, while lower values like 0.2 will make it more focused and deterministic. - thread: If no thread is provided, an empty thread will be created. + thread: Options to create a new thread. If no thread is provided when running a request, + an empty thread will be created. tool_choice: Controls which (if any) tool is called by the model. `none` means the model will not call any tools and instead generates a message. `auto` is the default value @@ -403,7 +411,7 @@ def create_and_run( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -449,9 +457,11 @@ def create_and_run( `incomplete_details` for more info. metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maximum of 512 - characters long. + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to be used to execute this run. If a value is provided here, it will override the @@ -487,7 +497,8 @@ def create_and_run( make the output more random, while lower values like 0.2 will make it more focused and deterministic. - thread: If no thread is provided, an empty thread will be created. + thread: Options to create a new thread. If no thread is provided when running a request, + an empty thread will be created. tool_choice: Controls which (if any) tool is called by the model. `none` means the model will not call any tools and instead generates a message. `auto` is the default value @@ -533,7 +544,7 @@ def create_and_run( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -579,9 +590,11 @@ def create_and_run( `incomplete_details` for more info. metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maximum of 512 - characters long. + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to be used to execute this run. If a value is provided here, it will override the @@ -617,7 +630,8 @@ def create_and_run( make the output more random, while lower values like 0.2 will make it more focused and deterministic. - thread: If no thread is provided, an empty thread will be created. + thread: Options to create a new thread. If no thread is provided when running a request, + an empty thread will be created. tool_choice: Controls which (if any) tool is called by the model. `none` means the model will not call any tools and instead generates a message. `auto` is the default value @@ -662,7 +676,7 @@ def create_and_run( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -926,7 +940,7 @@ async def create( self, *, messages: Iterable[thread_create_params.Message] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, tool_resources: Optional[thread_create_params.ToolResources] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -943,9 +957,11 @@ async def create( start the thread with. metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maximum of 512 - characters long. + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. tool_resources: A set of resources that are made available to the assistant's tools in this thread. The resources are specific to the type of tool. For example, the @@ -1015,7 +1031,7 @@ async def update( self, thread_id: str, *, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, tool_resources: Optional[thread_update_params.ToolResources] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -1029,9 +1045,11 @@ async def update( Args: metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maximum of 512 - characters long. + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. tool_resources: A set of resources that are made available to the assistant's tools in this thread. The resources are specific to the type of tool. For example, the @@ -1106,7 +1124,7 @@ async def create_and_run( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -1149,9 +1167,11 @@ async def create_and_run( `incomplete_details` for more info. metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maximum of 512 - characters long. + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to be used to execute this run. If a value is provided here, it will override the @@ -1191,7 +1211,8 @@ async def create_and_run( make the output more random, while lower values like 0.2 will make it more focused and deterministic. - thread: If no thread is provided, an empty thread will be created. + thread: Options to create a new thread. If no thread is provided when running a request, + an empty thread will be created. tool_choice: Controls which (if any) tool is called by the model. `none` means the model will not call any tools and instead generates a message. `auto` is the default value @@ -1237,7 +1258,7 @@ async def create_and_run( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -1283,9 +1304,11 @@ async def create_and_run( `incomplete_details` for more info. metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maximum of 512 - characters long. + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to be used to execute this run. If a value is provided here, it will override the @@ -1321,7 +1344,8 @@ async def create_and_run( make the output more random, while lower values like 0.2 will make it more focused and deterministic. - thread: If no thread is provided, an empty thread will be created. + thread: Options to create a new thread. If no thread is provided when running a request, + an empty thread will be created. tool_choice: Controls which (if any) tool is called by the model. `none` means the model will not call any tools and instead generates a message. `auto` is the default value @@ -1367,7 +1391,7 @@ async def create_and_run( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -1413,9 +1437,11 @@ async def create_and_run( `incomplete_details` for more info. metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maximum of 512 - characters long. + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to be used to execute this run. If a value is provided here, it will override the @@ -1451,7 +1477,8 @@ async def create_and_run( make the output more random, while lower values like 0.2 will make it more focused and deterministic. - thread: If no thread is provided, an empty thread will be created. + thread: Options to create a new thread. If no thread is provided when running a request, + an empty thread will be created. tool_choice: Controls which (if any) tool is called by the model. `none` means the model will not call any tools and instead generates a message. `auto` is the default value @@ -1496,7 +1523,7 @@ async def create_and_run( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, diff --git a/src/openai/resources/beta/vector_stores/vector_stores.py b/src/openai/resources/beta/vector_stores/vector_stores.py index 6b44c602f1..1da52fb3c7 100644 --- a/src/openai/resources/beta/vector_stores/vector_stores.py +++ b/src/openai/resources/beta/vector_stores/vector_stores.py @@ -41,6 +41,7 @@ ) from ...._base_client import AsyncPaginator, make_request_options from ....types.beta.vector_store import VectorStore +from ....types.shared_params.metadata import Metadata from ....types.beta.vector_store_deleted import VectorStoreDeleted from ....types.beta.file_chunking_strategy_param import FileChunkingStrategyParam @@ -81,7 +82,7 @@ def create( chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, expires_after: vector_store_create_params.ExpiresAfter | NotGiven = NOT_GIVEN, file_ids: List[str] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, name: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -104,9 +105,11 @@ def create( files. metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maximum of 512 - characters long. + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. name: The name of the vector store. @@ -176,7 +179,7 @@ def update( vector_store_id: str, *, expires_after: Optional[vector_store_update_params.ExpiresAfter] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, name: Optional[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -192,9 +195,11 @@ def update( expires_after: The expiration policy for a vector store. metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maximum of 512 - characters long. + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. name: The name of the vector store. @@ -359,7 +364,7 @@ async def create( chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, expires_after: vector_store_create_params.ExpiresAfter | NotGiven = NOT_GIVEN, file_ids: List[str] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, name: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -382,9 +387,11 @@ async def create( files. metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maximum of 512 - characters long. + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. name: The name of the vector store. @@ -454,7 +461,7 @@ async def update( vector_store_id: str, *, expires_after: Optional[vector_store_update_params.ExpiresAfter] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, name: Optional[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -470,9 +477,11 @@ async def update( expires_after: The expiration policy for a vector store. metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format. Keys - can be a maximum of 64 characters long and values can be a maximum of 512 - characters long. + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. name: The name of the vector store. diff --git a/src/openai/resources/chat/completions.py b/src/openai/resources/chat/completions.py index a9685c507a..34f6b50301 100644 --- a/src/openai/resources/chat/completions.py +++ b/src/openai/resources/chat/completions.py @@ -28,6 +28,7 @@ from ..._base_client import make_request_options from ...types.chat_model import ChatModel from ...types.chat.chat_completion import ChatCompletion +from ...types.shared_params.metadata import Metadata from ...types.chat.chat_completion_chunk import ChatCompletionChunk from ...types.chat.chat_completion_modality import ChatCompletionModality from ...types.chat.chat_completion_tool_param import ChatCompletionToolParam @@ -75,7 +76,7 @@ def create( logprobs: Optional[bool] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, @@ -179,8 +180,12 @@ def create( compatible with [o1 series models](https://platform.openai.com/docs/guides/reasoning). - metadata: Developer-defined tags and values used for filtering completions in the - [dashboard](https://platform.openai.com/chat-completions). + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. modalities: Output types that you would like the model to generate for this request. Most models are capable of generating text, which is the default: @@ -246,9 +251,9 @@ def create( utilize scale tier credits until they are exhausted. - If set to 'auto', and the Project is not Scale tier enabled, the request will be processed using the default service tier with a lower uptime SLA and no - latency guarentee. + latency guarantee. - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarentee. + tier with a lower uptime SLA and no latency guarantee. - When not set, the default behavior is 'auto'. stop: Up to 4 sequences where the API will stop generating further tokens. @@ -324,7 +329,7 @@ def create( logprobs: Optional[bool] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, @@ -434,8 +439,12 @@ def create( compatible with [o1 series models](https://platform.openai.com/docs/guides/reasoning). - metadata: Developer-defined tags and values used for filtering completions in the - [dashboard](https://platform.openai.com/chat-completions). + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. modalities: Output types that you would like the model to generate for this request. Most models are capable of generating text, which is the default: @@ -501,9 +510,9 @@ def create( utilize scale tier credits until they are exhausted. - If set to 'auto', and the Project is not Scale tier enabled, the request will be processed using the default service tier with a lower uptime SLA and no - latency guarentee. + latency guarantee. - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarentee. + tier with a lower uptime SLA and no latency guarantee. - When not set, the default behavior is 'auto'. stop: Up to 4 sequences where the API will stop generating further tokens. @@ -572,7 +581,7 @@ def create( logprobs: Optional[bool] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, @@ -682,8 +691,12 @@ def create( compatible with [o1 series models](https://platform.openai.com/docs/guides/reasoning). - metadata: Developer-defined tags and values used for filtering completions in the - [dashboard](https://platform.openai.com/chat-completions). + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. modalities: Output types that you would like the model to generate for this request. Most models are capable of generating text, which is the default: @@ -749,9 +762,9 @@ def create( utilize scale tier credits until they are exhausted. - If set to 'auto', and the Project is not Scale tier enabled, the request will be processed using the default service tier with a lower uptime SLA and no - latency guarentee. + latency guarantee. - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarentee. + tier with a lower uptime SLA and no latency guarantee. - When not set, the default behavior is 'auto'. stop: Up to 4 sequences where the API will stop generating further tokens. @@ -819,7 +832,7 @@ def create( logprobs: Optional[bool] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, @@ -927,7 +940,7 @@ async def create( logprobs: Optional[bool] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, @@ -1031,8 +1044,12 @@ async def create( compatible with [o1 series models](https://platform.openai.com/docs/guides/reasoning). - metadata: Developer-defined tags and values used for filtering completions in the - [dashboard](https://platform.openai.com/chat-completions). + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. modalities: Output types that you would like the model to generate for this request. Most models are capable of generating text, which is the default: @@ -1098,9 +1115,9 @@ async def create( utilize scale tier credits until they are exhausted. - If set to 'auto', and the Project is not Scale tier enabled, the request will be processed using the default service tier with a lower uptime SLA and no - latency guarentee. + latency guarantee. - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarentee. + tier with a lower uptime SLA and no latency guarantee. - When not set, the default behavior is 'auto'. stop: Up to 4 sequences where the API will stop generating further tokens. @@ -1176,7 +1193,7 @@ async def create( logprobs: Optional[bool] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, @@ -1286,8 +1303,12 @@ async def create( compatible with [o1 series models](https://platform.openai.com/docs/guides/reasoning). - metadata: Developer-defined tags and values used for filtering completions in the - [dashboard](https://platform.openai.com/chat-completions). + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. modalities: Output types that you would like the model to generate for this request. Most models are capable of generating text, which is the default: @@ -1353,9 +1374,9 @@ async def create( utilize scale tier credits until they are exhausted. - If set to 'auto', and the Project is not Scale tier enabled, the request will be processed using the default service tier with a lower uptime SLA and no - latency guarentee. + latency guarantee. - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarentee. + tier with a lower uptime SLA and no latency guarantee. - When not set, the default behavior is 'auto'. stop: Up to 4 sequences where the API will stop generating further tokens. @@ -1424,7 +1445,7 @@ async def create( logprobs: Optional[bool] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, @@ -1534,8 +1555,12 @@ async def create( compatible with [o1 series models](https://platform.openai.com/docs/guides/reasoning). - metadata: Developer-defined tags and values used for filtering completions in the - [dashboard](https://platform.openai.com/chat-completions). + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. modalities: Output types that you would like the model to generate for this request. Most models are capable of generating text, which is the default: @@ -1601,9 +1626,9 @@ async def create( utilize scale tier credits until they are exhausted. - If set to 'auto', and the Project is not Scale tier enabled, the request will be processed using the default service tier with a lower uptime SLA and no - latency guarentee. + latency guarantee. - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarentee. + tier with a lower uptime SLA and no latency guarantee. - When not set, the default behavior is 'auto'. stop: Up to 4 sequences where the API will stop generating further tokens. @@ -1671,7 +1696,7 @@ async def create( logprobs: Optional[bool] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, diff --git a/src/openai/types/__init__.py b/src/openai/types/__init__.py index 72950f2491..7abb22f239 100644 --- a/src/openai/types/__init__.py +++ b/src/openai/types/__init__.py @@ -6,6 +6,7 @@ from .image import Image as Image from .model import Model as Model from .shared import ( + Metadata as Metadata, ErrorObject as ErrorObject, FunctionDefinition as FunctionDefinition, FunctionParameters as FunctionParameters, diff --git a/src/openai/types/audio/transcription_create_params.py b/src/openai/types/audio/transcription_create_params.py index 88805affbd..f1779c35e6 100644 --- a/src/openai/types/audio/transcription_create_params.py +++ b/src/openai/types/audio/transcription_create_params.py @@ -30,8 +30,8 @@ class TranscriptionCreateParams(TypedDict, total=False): """The language of the input audio. Supplying the input language in - [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) format will - improve accuracy and latency. + [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) + format will improve accuracy and latency. """ prompt: str diff --git a/src/openai/types/batch.py b/src/openai/types/batch.py index ac3d7ea119..35de90ac85 100644 --- a/src/openai/types/batch.py +++ b/src/openai/types/batch.py @@ -1,11 +1,11 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import builtins from typing import List, Optional from typing_extensions import Literal from .._models import BaseModel from .batch_error import BatchError +from .shared.metadata import Metadata from .batch_request_counts import BatchRequestCounts __all__ = ["Batch", "Errors"] @@ -70,12 +70,14 @@ class Batch(BaseModel): in_progress_at: Optional[int] = None """The Unix timestamp (in seconds) for when the batch started processing.""" - metadata: Optional[builtins.object] = None + metadata: Optional[Metadata] = None """Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a - structured format. Keys can be a maximum of 64 characters long and values can be - a maximum of 512 characters long. + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. """ output_file_id: Optional[str] = None diff --git a/src/openai/types/batch_create_params.py b/src/openai/types/batch_create_params.py index b30c4d4658..e5be1d2bac 100644 --- a/src/openai/types/batch_create_params.py +++ b/src/openai/types/batch_create_params.py @@ -2,9 +2,11 @@ from __future__ import annotations -from typing import Dict, Optional +from typing import Optional from typing_extensions import Literal, Required, TypedDict +from .shared_params.metadata import Metadata + __all__ = ["BatchCreateParams"] @@ -35,5 +37,12 @@ class BatchCreateParams(TypedDict, total=False): requests, and can be up to 200 MB in size. """ - metadata: Optional[Dict[str, str]] - """Optional custom metadata for the batch.""" + metadata: Optional[Metadata] + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + """ diff --git a/src/openai/types/beta/assistant.py b/src/openai/types/beta/assistant.py index 3c8b8e403b..58421e0f66 100644 --- a/src/openai/types/beta/assistant.py +++ b/src/openai/types/beta/assistant.py @@ -5,6 +5,7 @@ from ..._models import BaseModel from .assistant_tool import AssistantTool +from ..shared.metadata import Metadata from .assistant_response_format_option import AssistantResponseFormatOption __all__ = ["Assistant", "ToolResources", "ToolResourcesCodeInterpreter", "ToolResourcesFileSearch"] @@ -51,12 +52,14 @@ class Assistant(BaseModel): The maximum length is 256,000 characters. """ - metadata: Optional[object] = None + metadata: Optional[Metadata] = None """Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a - structured format. Keys can be a maximum of 64 characters long and values can be - a maximum of 512 characters long. + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. """ model: str diff --git a/src/openai/types/beta/assistant_create_params.py b/src/openai/types/beta/assistant_create_params.py index 568b223ce7..e205856395 100644 --- a/src/openai/types/beta/assistant_create_params.py +++ b/src/openai/types/beta/assistant_create_params.py @@ -7,6 +7,7 @@ from ..chat_model import ChatModel from .assistant_tool_param import AssistantToolParam +from ..shared_params.metadata import Metadata from .file_chunking_strategy_param import FileChunkingStrategyParam from .assistant_response_format_option_param import AssistantResponseFormatOptionParam @@ -39,12 +40,14 @@ class AssistantCreateParams(TypedDict, total=False): The maximum length is 256,000 characters. """ - metadata: Optional[object] + metadata: Optional[Metadata] """Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a - structured format. Keys can be a maximum of 64 characters long and values can be - a maximum of 512 characters long. + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. """ name: Optional[str] @@ -130,12 +133,14 @@ class ToolResourcesFileSearchVectorStore(TypedDict, total=False): store. """ - metadata: object - """Set of 16 key-value pairs that can be attached to a vector store. + metadata: Optional[Metadata] + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. - This can be useful for storing additional information about the vector store in - a structured format. Keys can be a maximum of 64 characters long and values can - be a maximum of 512 characters long. + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. """ diff --git a/src/openai/types/beta/assistant_update_params.py b/src/openai/types/beta/assistant_update_params.py index 9a66e41ab3..35065ef61b 100644 --- a/src/openai/types/beta/assistant_update_params.py +++ b/src/openai/types/beta/assistant_update_params.py @@ -6,6 +6,7 @@ from typing_extensions import TypedDict from .assistant_tool_param import AssistantToolParam +from ..shared_params.metadata import Metadata from .assistant_response_format_option_param import AssistantResponseFormatOptionParam __all__ = ["AssistantUpdateParams", "ToolResources", "ToolResourcesCodeInterpreter", "ToolResourcesFileSearch"] @@ -21,12 +22,14 @@ class AssistantUpdateParams(TypedDict, total=False): The maximum length is 256,000 characters. """ - metadata: Optional[object] + metadata: Optional[Metadata] """Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a - structured format. Keys can be a maximum of 64 characters long and values can be - a maximum of 512 characters long. + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. """ model: str diff --git a/src/openai/types/beta/realtime/conversation_item_create_event.py b/src/openai/types/beta/realtime/conversation_item_create_event.py index c4f72b9aff..f19d552a92 100644 --- a/src/openai/types/beta/realtime/conversation_item_create_event.py +++ b/src/openai/types/beta/realtime/conversation_item_create_event.py @@ -20,10 +20,10 @@ class ConversationItemCreateEvent(BaseModel): """Optional client-generated ID used to identify this event.""" previous_item_id: Optional[str] = None - """ - The ID of the preceding item after which the new item will be inserted. If not - set, the new item will be appended to the end of the conversation. If set to - `root`, the new item will be added to the beginning of the conversation. If set - to an existing ID, it allows an item to be inserted mid-conversation. If the ID - cannot be found, an error will be returned and the item will not be added. + """The ID of the preceding item after which the new item will be inserted. + + If not set, the new item will be appended to the end of the conversation. If set + to `root`, the new item will be added to the beginning of the conversation. If + set to an existing ID, it allows an item to be inserted mid-conversation. If the + ID cannot be found, an error will be returned and the item will not be added. """ diff --git a/src/openai/types/beta/realtime/conversation_item_create_event_param.py b/src/openai/types/beta/realtime/conversation_item_create_event_param.py index 6da5a63a9d..693d0fd54d 100644 --- a/src/openai/types/beta/realtime/conversation_item_create_event_param.py +++ b/src/openai/types/beta/realtime/conversation_item_create_event_param.py @@ -20,10 +20,10 @@ class ConversationItemCreateEventParam(TypedDict, total=False): """Optional client-generated ID used to identify this event.""" previous_item_id: str - """ - The ID of the preceding item after which the new item will be inserted. If not - set, the new item will be appended to the end of the conversation. If set to - `root`, the new item will be added to the beginning of the conversation. If set - to an existing ID, it allows an item to be inserted mid-conversation. If the ID - cannot be found, an error will be returned and the item will not be added. + """The ID of the preceding item after which the new item will be inserted. + + If not set, the new item will be appended to the end of the conversation. If set + to `root`, the new item will be added to the beginning of the conversation. If + set to an existing ID, it allows an item to be inserted mid-conversation. If the + ID cannot be found, an error will be returned and the item will not be added. """ diff --git a/src/openai/types/beta/realtime/realtime_response.py b/src/openai/types/beta/realtime/realtime_response.py index 3e1b1406c0..4c3c83d666 100644 --- a/src/openai/types/beta/realtime/realtime_response.py +++ b/src/openai/types/beta/realtime/realtime_response.py @@ -1,9 +1,10 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Optional +from typing import List, Union, Optional from typing_extensions import Literal from ...._models import BaseModel +from ...shared.metadata import Metadata from .conversation_item import ConversationItem from .realtime_response_usage import RealtimeResponseUsage from .realtime_response_status import RealtimeResponseStatus @@ -15,8 +16,40 @@ class RealtimeResponse(BaseModel): id: Optional[str] = None """The unique ID of the response.""" - metadata: Optional[object] = None - """Developer-provided string key-value pairs associated with this response.""" + conversation_id: Optional[str] = None + """ + Which conversation the response is added to, determined by the `conversation` + field in the `response.create` event. If `auto`, the response will be added to + the default conversation and the value of `conversation_id` will be an id like + `conv_1234`. If `none`, the response will not be added to any conversation and + the value of `conversation_id` will be `null`. If responses are being triggered + by server VAD, the response will be added to the default conversation, thus the + `conversation_id` will be an id like `conv_1234`. + """ + + max_output_tokens: Union[int, Literal["inf"], None] = None + """ + Maximum number of output tokens for a single assistant response, inclusive of + tool calls, that was used in this response. + """ + + metadata: Optional[Metadata] = None + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + """ + + modalities: Optional[List[Literal["text", "audio"]]] = None + """The set of modalities the model used to respond. + + If there are multiple modalities, the model will pick one, for example if + `modalities` is `["text", "audio"]`, the model could be responding in either + text or audio. + """ object: Optional[Literal["realtime.response"]] = None """The object type, must be `realtime.response`.""" @@ -24,6 +57,9 @@ class RealtimeResponse(BaseModel): output: Optional[List[ConversationItem]] = None """The list of output items generated by the response.""" + output_audio_format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None + """The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + status: Optional[Literal["completed", "cancelled", "failed", "incomplete"]] = None """ The final status of the response (`completed`, `cancelled`, `failed`, or @@ -33,6 +69,9 @@ class RealtimeResponse(BaseModel): status_details: Optional[RealtimeResponseStatus] = None """Additional details about the status.""" + temperature: Optional[float] = None + """Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8.""" + usage: Optional[RealtimeResponseUsage] = None """Usage statistics for the Response, this will correspond to billing. @@ -40,3 +79,9 @@ class RealtimeResponse(BaseModel): to the Conversation, thus output from previous turns (text and audio tokens) will become the input for later turns. """ + + voice: Optional[Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"]] = None + """ + The voice the model used to respond. Current voice options are `alloy`, `ash`, + `ballad`, `coral`, `echo` `sage`, `shimmer` and `verse`. + """ diff --git a/src/openai/types/beta/realtime/response_create_event.py b/src/openai/types/beta/realtime/response_create_event.py index e4e5e7c68f..0801654bd8 100644 --- a/src/openai/types/beta/realtime/response_create_event.py +++ b/src/openai/types/beta/realtime/response_create_event.py @@ -4,6 +4,7 @@ from typing_extensions import Literal from ...._models import BaseModel +from ...shared.metadata import Metadata from .conversation_item import ConversationItem __all__ = ["ResponseCreateEvent", "Response", "ResponseTool"] @@ -66,12 +67,14 @@ class Response(BaseModel): `inf` for the maximum available tokens for a given model. Defaults to `inf`. """ - metadata: Optional[object] = None + metadata: Optional[Metadata] = None """Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a - structured format. Keys can be a maximum of 64 characters long and values can be - a maximum of 512 characters long. + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. """ modalities: Optional[List[Literal["text", "audio"]]] = None diff --git a/src/openai/types/beta/realtime/response_create_event_param.py b/src/openai/types/beta/realtime/response_create_event_param.py index 7a4b5f086a..a87ef955e8 100644 --- a/src/openai/types/beta/realtime/response_create_event_param.py +++ b/src/openai/types/beta/realtime/response_create_event_param.py @@ -6,6 +6,7 @@ from typing_extensions import Literal, Required, TypedDict from .conversation_item_param import ConversationItemParam +from ...shared_params.metadata import Metadata __all__ = ["ResponseCreateEventParam", "Response", "ResponseTool"] @@ -67,12 +68,14 @@ class Response(TypedDict, total=False): `inf` for the maximum available tokens for a given model. Defaults to `inf`. """ - metadata: Optional[object] + metadata: Optional[Metadata] """Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a - structured format. Keys can be a maximum of 64 characters long and values can be - a maximum of 512 characters long. + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. """ modalities: List[Literal["text", "audio"]] diff --git a/src/openai/types/beta/realtime/session_create_params.py b/src/openai/types/beta/realtime/session_create_params.py index 3708efeecd..1502d83d39 100644 --- a/src/openai/types/beta/realtime/session_create_params.py +++ b/src/openai/types/beta/realtime/session_create_params.py @@ -22,8 +22,11 @@ class SessionCreateParams(TypedDict, total=False): Configuration for input audio transcription, defaults to off and can be set to `null` to turn off once on. Input audio transcription is not native to the model, since the model consumes audio directly. Transcription runs - asynchronously through Whisper and should be treated as rough guidance rather - than the representation understood by the model. + asynchronously through + [OpenAI Whisper transcription](https://platform.openai.com/docs/api-reference/audio/createTranscription) + and should be treated as rough guidance rather than the representation + understood by the model. The client can optionally set the language and prompt + for transcription, these fields will be passed to the Whisper API. """ instructions: str @@ -101,12 +104,28 @@ class SessionCreateParams(TypedDict, total=False): class InputAudioTranscription(TypedDict, total=False): + language: str + """The language of the input audio. + + Supplying the input language in + [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) + format will improve accuracy and latency. + """ + model: str """ The model to use for transcription, `whisper-1` is the only currently supported model. """ + prompt: str + """An optional text to guide the model's style or continue a previous audio + segment. + + The [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) + should match the audio language. + """ + class Tool(TypedDict, total=False): description: str diff --git a/src/openai/types/beta/realtime/session_create_response.py b/src/openai/types/beta/realtime/session_create_response.py index 31f591b261..c26e62bef1 100644 --- a/src/openai/types/beta/realtime/session_create_response.py +++ b/src/openai/types/beta/realtime/session_create_response.py @@ -9,13 +9,13 @@ class ClientSecret(BaseModel): - expires_at: Optional[int] = None + expires_at: int """Timestamp for when the token expires. Currently, all tokens expire after one minute. """ - value: Optional[str] = None + value: str """ Ephemeral key usable in client environments to authenticate connections to the Realtime API. Use this in client-side environments rather than a standard API @@ -74,7 +74,7 @@ class TurnDetection(BaseModel): class SessionCreateResponse(BaseModel): - client_secret: Optional[ClientSecret] = None + client_secret: ClientSecret """Ephemeral key returned by the API.""" input_audio_format: Optional[str] = None diff --git a/src/openai/types/beta/realtime/session_update_event.py b/src/openai/types/beta/realtime/session_update_event.py index 322e588a4e..62fb0a3998 100644 --- a/src/openai/types/beta/realtime/session_update_event.py +++ b/src/openai/types/beta/realtime/session_update_event.py @@ -9,12 +9,28 @@ class SessionInputAudioTranscription(BaseModel): + language: Optional[str] = None + """The language of the input audio. + + Supplying the input language in + [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) + format will improve accuracy and latency. + """ + model: Optional[str] = None """ The model to use for transcription, `whisper-1` is the only currently supported model. """ + prompt: Optional[str] = None + """An optional text to guide the model's style or continue a previous audio + segment. + + The [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) + should match the audio language. + """ + class SessionTool(BaseModel): description: Optional[str] = None @@ -78,8 +94,11 @@ class Session(BaseModel): Configuration for input audio transcription, defaults to off and can be set to `null` to turn off once on. Input audio transcription is not native to the model, since the model consumes audio directly. Transcription runs - asynchronously through Whisper and should be treated as rough guidance rather - than the representation understood by the model. + asynchronously through + [OpenAI Whisper transcription](https://platform.openai.com/docs/api-reference/audio/createTranscription) + and should be treated as rough guidance rather than the representation + understood by the model. The client can optionally set the language and prompt + for transcription, these fields will be passed to the Whisper API. """ instructions: Optional[str] = None diff --git a/src/openai/types/beta/realtime/session_update_event_param.py b/src/openai/types/beta/realtime/session_update_event_param.py index c01d9b6887..133cdd91a1 100644 --- a/src/openai/types/beta/realtime/session_update_event_param.py +++ b/src/openai/types/beta/realtime/session_update_event_param.py @@ -15,12 +15,28 @@ class SessionInputAudioTranscription(TypedDict, total=False): + language: str + """The language of the input audio. + + Supplying the input language in + [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) + format will improve accuracy and latency. + """ + model: str """ The model to use for transcription, `whisper-1` is the only currently supported model. """ + prompt: str + """An optional text to guide the model's style or continue a previous audio + segment. + + The [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) + should match the audio language. + """ + class SessionTool(TypedDict, total=False): description: str @@ -84,8 +100,11 @@ class Session(TypedDict, total=False): Configuration for input audio transcription, defaults to off and can be set to `null` to turn off once on. Input audio transcription is not native to the model, since the model consumes audio directly. Transcription runs - asynchronously through Whisper and should be treated as rough guidance rather - than the representation understood by the model. + asynchronously through + [OpenAI Whisper transcription](https://platform.openai.com/docs/api-reference/audio/createTranscription) + and should be treated as rough guidance rather than the representation + understood by the model. The client can optionally set the language and prompt + for transcription, these fields will be passed to the Whisper API. """ instructions: str diff --git a/src/openai/types/beta/thread.py b/src/openai/types/beta/thread.py index 37d50ccb93..789f66e48b 100644 --- a/src/openai/types/beta/thread.py +++ b/src/openai/types/beta/thread.py @@ -4,6 +4,7 @@ from typing_extensions import Literal from ..._models import BaseModel +from ..shared.metadata import Metadata __all__ = ["Thread", "ToolResources", "ToolResourcesCodeInterpreter", "ToolResourcesFileSearch"] @@ -40,12 +41,14 @@ class Thread(BaseModel): created_at: int """The Unix timestamp (in seconds) for when the thread was created.""" - metadata: Optional[object] = None + metadata: Optional[Metadata] = None """Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a - structured format. Keys can be a maximum of 64 characters long and values can be - a maximum of 512 characters long. + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. """ object: Literal["thread"] diff --git a/src/openai/types/beta/thread_create_and_run_params.py b/src/openai/types/beta/thread_create_and_run_params.py index 8310ba12f4..08f044c1be 100644 --- a/src/openai/types/beta/thread_create_and_run_params.py +++ b/src/openai/types/beta/thread_create_and_run_params.py @@ -8,6 +8,7 @@ from ..chat_model import ChatModel from .function_tool_param import FunctionToolParam from .file_search_tool_param import FileSearchToolParam +from ..shared_params.metadata import Metadata from .code_interpreter_tool_param import CodeInterpreterToolParam from .file_chunking_strategy_param import FileChunkingStrategyParam from .assistant_tool_choice_option_param import AssistantToolChoiceOptionParam @@ -67,12 +68,14 @@ class ThreadCreateAndRunParamsBase(TypedDict, total=False): `incomplete_details` for more info. """ - metadata: Optional[object] + metadata: Optional[Metadata] """Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a - structured format. Keys can be a maximum of 64 characters long and values can be - a maximum of 512 characters long. + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. """ model: Union[str, ChatModel, None] @@ -122,7 +125,11 @@ class ThreadCreateAndRunParamsBase(TypedDict, total=False): """ thread: Thread - """If no thread is provided, an empty thread will be created.""" + """Options to create a new thread. + + If no thread is provided when running a request, an empty thread will be + created. + """ tool_choice: Optional[AssistantToolChoiceOptionParam] """ @@ -197,12 +204,14 @@ class ThreadMessage(TypedDict, total=False): attachments: Optional[Iterable[ThreadMessageAttachment]] """A list of files attached to the message, and the tools they should be added to.""" - metadata: Optional[object] + metadata: Optional[Metadata] """Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a - structured format. Keys can be a maximum of 64 characters long and values can be - a maximum of 512 characters long. + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. """ @@ -230,12 +239,14 @@ class ThreadToolResourcesFileSearchVectorStore(TypedDict, total=False): store. """ - metadata: object - """Set of 16 key-value pairs that can be attached to a vector store. + metadata: Optional[Metadata] + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. - This can be useful for storing additional information about the vector store in - a structured format. Keys can be a maximum of 64 characters long and values can - be a maximum of 512 characters long. + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. """ @@ -270,12 +281,14 @@ class Thread(TypedDict, total=False): start the thread with. """ - metadata: Optional[object] + metadata: Optional[Metadata] """Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a - structured format. Keys can be a maximum of 64 characters long and values can be - a maximum of 512 characters long. + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. """ tool_resources: Optional[ThreadToolResources] diff --git a/src/openai/types/beta/thread_create_params.py b/src/openai/types/beta/thread_create_params.py index 3ac6c7d69b..127202753c 100644 --- a/src/openai/types/beta/thread_create_params.py +++ b/src/openai/types/beta/thread_create_params.py @@ -5,6 +5,7 @@ from typing import List, Union, Iterable, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict +from ..shared_params.metadata import Metadata from .code_interpreter_tool_param import CodeInterpreterToolParam from .file_chunking_strategy_param import FileChunkingStrategyParam from .threads.message_content_part_param import MessageContentPartParam @@ -29,12 +30,14 @@ class ThreadCreateParams(TypedDict, total=False): start the thread with. """ - metadata: Optional[object] + metadata: Optional[Metadata] """Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a - structured format. Keys can be a maximum of 64 characters long and values can be - a maximum of 512 characters long. + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. """ tool_resources: Optional[ToolResources] @@ -78,12 +81,14 @@ class Message(TypedDict, total=False): attachments: Optional[Iterable[MessageAttachment]] """A list of files attached to the message, and the tools they should be added to.""" - metadata: Optional[object] + metadata: Optional[Metadata] """Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a - structured format. Keys can be a maximum of 64 characters long and values can be - a maximum of 512 characters long. + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. """ @@ -111,12 +116,14 @@ class ToolResourcesFileSearchVectorStore(TypedDict, total=False): store. """ - metadata: object - """Set of 16 key-value pairs that can be attached to a vector store. + metadata: Optional[Metadata] + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. - This can be useful for storing additional information about the vector store in - a structured format. Keys can be a maximum of 64 characters long and values can - be a maximum of 512 characters long. + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. """ diff --git a/src/openai/types/beta/thread_update_params.py b/src/openai/types/beta/thread_update_params.py index 78c5ec4f2e..b47ea8f3b0 100644 --- a/src/openai/types/beta/thread_update_params.py +++ b/src/openai/types/beta/thread_update_params.py @@ -5,16 +5,20 @@ from typing import List, Optional from typing_extensions import TypedDict +from ..shared_params.metadata import Metadata + __all__ = ["ThreadUpdateParams", "ToolResources", "ToolResourcesCodeInterpreter", "ToolResourcesFileSearch"] class ThreadUpdateParams(TypedDict, total=False): - metadata: Optional[object] + metadata: Optional[Metadata] """Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a - structured format. Keys can be a maximum of 64 characters long and values can be - a maximum of 512 characters long. + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. """ tool_resources: Optional[ToolResources] diff --git a/src/openai/types/beta/threads/message.py b/src/openai/types/beta/threads/message.py index 63c5c4800a..4a05a128eb 100644 --- a/src/openai/types/beta/threads/message.py +++ b/src/openai/types/beta/threads/message.py @@ -5,6 +5,7 @@ from ...._models import BaseModel from .message_content import MessageContent +from ...shared.metadata import Metadata from ..code_interpreter_tool import CodeInterpreterTool __all__ = [ @@ -66,12 +67,14 @@ class Message(BaseModel): incomplete_details: Optional[IncompleteDetails] = None """On an incomplete message, details about why the message is incomplete.""" - metadata: Optional[object] = None + metadata: Optional[Metadata] = None """Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a - structured format. Keys can be a maximum of 64 characters long and values can be - a maximum of 512 characters long. + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. """ object: Literal["thread.message"] diff --git a/src/openai/types/beta/threads/message_create_params.py b/src/openai/types/beta/threads/message_create_params.py index 2c4edfdf71..b52386824a 100644 --- a/src/openai/types/beta/threads/message_create_params.py +++ b/src/openai/types/beta/threads/message_create_params.py @@ -5,6 +5,7 @@ from typing import Union, Iterable, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict +from ...shared_params.metadata import Metadata from .message_content_part_param import MessageContentPartParam from ..code_interpreter_tool_param import CodeInterpreterToolParam @@ -27,12 +28,14 @@ class MessageCreateParams(TypedDict, total=False): attachments: Optional[Iterable[Attachment]] """A list of files attached to the message, and the tools they should be added to.""" - metadata: Optional[object] + metadata: Optional[Metadata] """Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a - structured format. Keys can be a maximum of 64 characters long and values can be - a maximum of 512 characters long. + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. """ diff --git a/src/openai/types/beta/threads/message_update_params.py b/src/openai/types/beta/threads/message_update_params.py index e8f8cc910c..bb078281e6 100644 --- a/src/openai/types/beta/threads/message_update_params.py +++ b/src/openai/types/beta/threads/message_update_params.py @@ -5,16 +5,20 @@ from typing import Optional from typing_extensions import Required, TypedDict +from ...shared_params.metadata import Metadata + __all__ = ["MessageUpdateParams"] class MessageUpdateParams(TypedDict, total=False): thread_id: Required[str] - metadata: Optional[object] + metadata: Optional[Metadata] """Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a - structured format. Keys can be a maximum of 64 characters long and values can be - a maximum of 512 characters long. + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. """ diff --git a/src/openai/types/beta/threads/run.py b/src/openai/types/beta/threads/run.py index ad32135b7d..da9418d6f9 100644 --- a/src/openai/types/beta/threads/run.py +++ b/src/openai/types/beta/threads/run.py @@ -6,6 +6,7 @@ from ...._models import BaseModel from .run_status import RunStatus from ..assistant_tool import AssistantTool +from ...shared.metadata import Metadata from ..assistant_tool_choice_option import AssistantToolChoiceOption from ..assistant_response_format_option import AssistantResponseFormatOption from .required_action_function_tool_call import RequiredActionFunctionToolCall @@ -133,12 +134,14 @@ class Run(BaseModel): of the run. """ - metadata: Optional[object] = None + metadata: Optional[Metadata] = None """Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a - structured format. Keys can be a maximum of 64 characters long and values can be - a maximum of 512 characters long. + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. """ model: str diff --git a/src/openai/types/beta/threads/run_create_params.py b/src/openai/types/beta/threads/run_create_params.py index 88dc39645e..091dd3da66 100644 --- a/src/openai/types/beta/threads/run_create_params.py +++ b/src/openai/types/beta/threads/run_create_params.py @@ -8,6 +8,7 @@ from ...chat_model import ChatModel from ..assistant_tool_param import AssistantToolParam from .runs.run_step_include import RunStepInclude +from ...shared_params.metadata import Metadata from .message_content_part_param import MessageContentPartParam from ..code_interpreter_tool_param import CodeInterpreterToolParam from ..assistant_tool_choice_option_param import AssistantToolChoiceOptionParam @@ -80,12 +81,14 @@ class RunCreateParamsBase(TypedDict, total=False): `incomplete_details` for more info. """ - metadata: Optional[object] + metadata: Optional[Metadata] """Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a - structured format. Keys can be a maximum of 64 characters long and values can be - a maximum of 512 characters long. + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. """ model: Union[str, ChatModel, None] @@ -199,12 +202,14 @@ class AdditionalMessage(TypedDict, total=False): attachments: Optional[Iterable[AdditionalMessageAttachment]] """A list of files attached to the message, and the tools they should be added to.""" - metadata: Optional[object] + metadata: Optional[Metadata] """Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a - structured format. Keys can be a maximum of 64 characters long and values can be - a maximum of 512 characters long. + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. """ diff --git a/src/openai/types/beta/threads/run_update_params.py b/src/openai/types/beta/threads/run_update_params.py index cb4f053645..fbcbd3fb14 100644 --- a/src/openai/types/beta/threads/run_update_params.py +++ b/src/openai/types/beta/threads/run_update_params.py @@ -5,16 +5,20 @@ from typing import Optional from typing_extensions import Required, TypedDict +from ...shared_params.metadata import Metadata + __all__ = ["RunUpdateParams"] class RunUpdateParams(TypedDict, total=False): thread_id: Required[str] - metadata: Optional[object] + metadata: Optional[Metadata] """Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a - structured format. Keys can be a maximum of 64 characters long and values can be - a maximum of 512 characters long. + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. """ diff --git a/src/openai/types/beta/threads/runs/run_step.py b/src/openai/types/beta/threads/runs/run_step.py index 0445ae360d..b5f380c7b1 100644 --- a/src/openai/types/beta/threads/runs/run_step.py +++ b/src/openai/types/beta/threads/runs/run_step.py @@ -5,6 +5,7 @@ from ....._utils import PropertyInfo from ....._models import BaseModel +from ....shared.metadata import Metadata from .tool_calls_step_details import ToolCallsStepDetails from .message_creation_step_details import MessageCreationStepDetails @@ -70,12 +71,14 @@ class RunStep(BaseModel): Will be `null` if there are no errors. """ - metadata: Optional[object] = None + metadata: Optional[Metadata] = None """Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a - structured format. Keys can be a maximum of 64 characters long and values can be - a maximum of 512 characters long. + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. """ object: Literal["thread.run.step"] diff --git a/src/openai/types/beta/vector_store.py b/src/openai/types/beta/vector_store.py index 2d3ceea80c..b947dfb79d 100644 --- a/src/openai/types/beta/vector_store.py +++ b/src/openai/types/beta/vector_store.py @@ -4,6 +4,7 @@ from typing_extensions import Literal from ..._models import BaseModel +from ..shared.metadata import Metadata __all__ = ["VectorStore", "FileCounts", "ExpiresAfter"] @@ -48,12 +49,14 @@ class VectorStore(BaseModel): last_active_at: Optional[int] = None """The Unix timestamp (in seconds) for when the vector store was last active.""" - metadata: Optional[object] = None + metadata: Optional[Metadata] = None """Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a - structured format. Keys can be a maximum of 64 characters long and values can be - a maximum of 512 characters long. + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. """ name: str diff --git a/src/openai/types/beta/vector_store_create_params.py b/src/openai/types/beta/vector_store_create_params.py index 4fc7c38927..faca6d9000 100644 --- a/src/openai/types/beta/vector_store_create_params.py +++ b/src/openai/types/beta/vector_store_create_params.py @@ -5,6 +5,7 @@ from typing import List, Optional from typing_extensions import Literal, Required, TypedDict +from ..shared_params.metadata import Metadata from .file_chunking_strategy_param import FileChunkingStrategyParam __all__ = ["VectorStoreCreateParams", "ExpiresAfter"] @@ -28,12 +29,14 @@ class VectorStoreCreateParams(TypedDict, total=False): files. """ - metadata: Optional[object] + metadata: Optional[Metadata] """Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a - structured format. Keys can be a maximum of 64 characters long and values can be - a maximum of 512 characters long. + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. """ name: str diff --git a/src/openai/types/beta/vector_store_update_params.py b/src/openai/types/beta/vector_store_update_params.py index ff6c068efb..e91b3ba5ad 100644 --- a/src/openai/types/beta/vector_store_update_params.py +++ b/src/openai/types/beta/vector_store_update_params.py @@ -5,6 +5,8 @@ from typing import Optional from typing_extensions import Literal, Required, TypedDict +from ..shared_params.metadata import Metadata + __all__ = ["VectorStoreUpdateParams", "ExpiresAfter"] @@ -12,12 +14,14 @@ class VectorStoreUpdateParams(TypedDict, total=False): expires_after: Optional[ExpiresAfter] """The expiration policy for a vector store.""" - metadata: Optional[object] + metadata: Optional[Metadata] """Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a - structured format. Keys can be a maximum of 64 characters long and values can be - a maximum of 512 characters long. + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. """ name: Optional[str] diff --git a/src/openai/types/chat/chat_completion_assistant_message_param.py b/src/openai/types/chat/chat_completion_assistant_message_param.py index 229fb822f4..35e3a3d784 100644 --- a/src/openai/types/chat/chat_completion_assistant_message_param.py +++ b/src/openai/types/chat/chat_completion_assistant_message_param.py @@ -38,8 +38,8 @@ class ChatCompletionAssistantMessageParam(TypedDict, total=False): """The role of the messages author, in this case `assistant`.""" audio: Optional[Audio] - """ - Data about a previous audio response from the model. + """Data about a previous audio response from the model. + [Learn more](https://platform.openai.com/docs/guides/audio). """ diff --git a/src/openai/types/chat/completion_create_params.py b/src/openai/types/chat/completion_create_params.py index 30d930b120..ec88ea1fb0 100644 --- a/src/openai/types/chat/completion_create_params.py +++ b/src/openai/types/chat/completion_create_params.py @@ -6,6 +6,7 @@ from typing_extensions import Literal, Required, TypeAlias, TypedDict from ..chat_model import ChatModel +from ..shared_params.metadata import Metadata from .chat_completion_modality import ChatCompletionModality from .chat_completion_tool_param import ChatCompletionToolParam from .chat_completion_audio_param import ChatCompletionAudioParam @@ -122,10 +123,14 @@ class CompletionCreateParamsBase(TypedDict, total=False): [o1 series models](https://platform.openai.com/docs/guides/reasoning). """ - metadata: Optional[Dict[str, str]] - """ - Developer-defined tags and values used for filtering completions in the - [dashboard](https://platform.openai.com/chat-completions). + metadata: Optional[Metadata] + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. """ modalities: Optional[List[ChatCompletionModality]] @@ -216,9 +221,9 @@ class CompletionCreateParamsBase(TypedDict, total=False): utilize scale tier credits until they are exhausted. - If set to 'auto', and the Project is not Scale tier enabled, the request will be processed using the default service tier with a lower uptime SLA and no - latency guarentee. + latency guarantee. - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarentee. + tier with a lower uptime SLA and no latency guarantee. - When not set, the default behavior is 'auto'. """ diff --git a/src/openai/types/chat_model.py b/src/openai/types/chat_model.py index e1ac464320..c191cb9734 100644 --- a/src/openai/types/chat_model.py +++ b/src/openai/types/chat_model.py @@ -5,6 +5,8 @@ __all__ = ["ChatModel"] ChatModel: TypeAlias = Literal[ + "o3-mini", + "o3-mini-2025-01-31", "o1", "o1-2024-12-17", "o1-preview", diff --git a/src/openai/types/shared/__init__.py b/src/openai/types/shared/__init__.py index c8776bca0e..74bf304904 100644 --- a/src/openai/types/shared/__init__.py +++ b/src/openai/types/shared/__init__.py @@ -1,5 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from .metadata import Metadata as Metadata from .error_object import ErrorObject as ErrorObject from .function_definition import FunctionDefinition as FunctionDefinition from .function_parameters import FunctionParameters as FunctionParameters diff --git a/src/openai/types/shared/metadata.py b/src/openai/types/shared/metadata.py new file mode 100644 index 0000000000..0da88c679c --- /dev/null +++ b/src/openai/types/shared/metadata.py @@ -0,0 +1,8 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict +from typing_extensions import TypeAlias + +__all__ = ["Metadata"] + +Metadata: TypeAlias = Dict[str, str] diff --git a/src/openai/types/shared_params/__init__.py b/src/openai/types/shared_params/__init__.py index ab4057d59f..68a8db75fe 100644 --- a/src/openai/types/shared_params/__init__.py +++ b/src/openai/types/shared_params/__init__.py @@ -1,5 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from .metadata import Metadata as Metadata from .function_definition import FunctionDefinition as FunctionDefinition from .function_parameters import FunctionParameters as FunctionParameters from .response_format_text import ResponseFormatText as ResponseFormatText diff --git a/src/openai/types/shared_params/metadata.py b/src/openai/types/shared_params/metadata.py new file mode 100644 index 0000000000..821650b48b --- /dev/null +++ b/src/openai/types/shared_params/metadata.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict +from typing_extensions import TypeAlias + +__all__ = ["Metadata"] + +Metadata: TypeAlias = Dict[str, str] diff --git a/src/openai/types/upload.py b/src/openai/types/upload.py index 1cf8ee97f8..d8108c62f9 100644 --- a/src/openai/types/upload.py +++ b/src/openai/types/upload.py @@ -39,4 +39,4 @@ class Upload(BaseModel): """The status of the Upload.""" file: Optional[FileObject] = None - """The ready File object after the Upload is completed.""" + """The `File` object represents a document that has been uploaded to OpenAI.""" diff --git a/tests/api_resources/beta/realtime/test_sessions.py b/tests/api_resources/beta/realtime/test_sessions.py index 908aa983be..5a17088ce6 100644 --- a/tests/api_resources/beta/realtime/test_sessions.py +++ b/tests/api_resources/beta/realtime/test_sessions.py @@ -26,7 +26,11 @@ def test_method_create(self, client: OpenAI) -> None: def test_method_create_with_all_params(self, client: OpenAI) -> None: session = client.beta.realtime.sessions.create( input_audio_format="pcm16", - input_audio_transcription={"model": "model"}, + input_audio_transcription={ + "language": "language", + "model": "model", + "prompt": "prompt", + }, instructions="instructions", max_response_output_tokens=0, modalities=["text"], @@ -86,7 +90,11 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None: async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: session = await async_client.beta.realtime.sessions.create( input_audio_format="pcm16", - input_audio_transcription={"model": "model"}, + input_audio_transcription={ + "language": "language", + "model": "model", + "prompt": "prompt", + }, instructions="instructions", max_response_output_tokens=0, modalities=["text"], diff --git a/tests/api_resources/beta/test_assistants.py b/tests/api_resources/beta/test_assistants.py index d9944448b7..458e3f5e90 100644 --- a/tests/api_resources/beta/test_assistants.py +++ b/tests/api_resources/beta/test_assistants.py @@ -34,7 +34,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: model="gpt-4o", description="description", instructions="instructions", - metadata={}, + metadata={"foo": "string"}, name="name", response_format="auto", temperature=1, @@ -46,7 +46,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: { "chunking_strategy": {"type": "auto"}, "file_ids": ["string"], - "metadata": {}, + "metadata": {"foo": "string"}, } ], }, @@ -131,7 +131,7 @@ def test_method_update_with_all_params(self, client: OpenAI) -> None: assistant_id="assistant_id", description="description", instructions="instructions", - metadata={}, + metadata={"foo": "string"}, model="model", name="name", response_format="auto", @@ -266,7 +266,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> model="gpt-4o", description="description", instructions="instructions", - metadata={}, + metadata={"foo": "string"}, name="name", response_format="auto", temperature=1, @@ -278,7 +278,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> { "chunking_strategy": {"type": "auto"}, "file_ids": ["string"], - "metadata": {}, + "metadata": {"foo": "string"}, } ], }, @@ -363,7 +363,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncOpenAI) -> assistant_id="assistant_id", description="description", instructions="instructions", - metadata={}, + metadata={"foo": "string"}, model="model", name="name", response_format="auto", diff --git a/tests/api_resources/beta/test_threads.py b/tests/api_resources/beta/test_threads.py index 789f870d6a..ecf5b11102 100644 --- a/tests/api_resources/beta/test_threads.py +++ b/tests/api_resources/beta/test_threads.py @@ -39,10 +39,10 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: "tools": [{"type": "code_interpreter"}], } ], - "metadata": {}, + "metadata": {"foo": "string"}, } ], - metadata={}, + metadata={"foo": "string"}, tool_resources={ "code_interpreter": {"file_ids": ["string"]}, "file_search": { @@ -51,7 +51,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: { "chunking_strategy": {"type": "auto"}, "file_ids": ["string"], - "metadata": {}, + "metadata": {"foo": "string"}, } ], }, @@ -127,8 +127,8 @@ def test_method_update(self, client: OpenAI) -> None: @parametrize def test_method_update_with_all_params(self, client: OpenAI) -> None: thread = client.beta.threads.update( - "string", - metadata={}, + thread_id="thread_id", + metadata={"foo": "string"}, tool_resources={ "code_interpreter": {"file_ids": ["string"]}, "file_search": {"vector_store_ids": ["string"]}, @@ -219,7 +219,7 @@ def test_method_create_and_run_with_all_params_overload_1(self, client: OpenAI) instructions="string", max_completion_tokens=256, max_prompt_tokens=256, - metadata={}, + metadata={"foo": "string"}, model="gpt-4o", parallel_tool_calls=True, response_format="auto", @@ -236,10 +236,10 @@ def test_method_create_and_run_with_all_params_overload_1(self, client: OpenAI) "tools": [{"type": "code_interpreter"}], } ], - "metadata": {}, + "metadata": {"foo": "string"}, } ], - "metadata": {}, + "metadata": {"foo": "string"}, "tool_resources": { "code_interpreter": {"file_ids": ["string"]}, "file_search": { @@ -248,7 +248,7 @@ def test_method_create_and_run_with_all_params_overload_1(self, client: OpenAI) { "chunking_strategy": {"type": "auto"}, "file_ids": ["string"], - "metadata": {}, + "metadata": {"foo": "string"}, } ], }, @@ -308,7 +308,7 @@ def test_method_create_and_run_with_all_params_overload_2(self, client: OpenAI) instructions="string", max_completion_tokens=256, max_prompt_tokens=256, - metadata={}, + metadata={"foo": "string"}, model="gpt-4o", parallel_tool_calls=True, response_format="auto", @@ -324,10 +324,10 @@ def test_method_create_and_run_with_all_params_overload_2(self, client: OpenAI) "tools": [{"type": "code_interpreter"}], } ], - "metadata": {}, + "metadata": {"foo": "string"}, } ], - "metadata": {}, + "metadata": {"foo": "string"}, "tool_resources": { "code_interpreter": {"file_ids": ["string"]}, "file_search": { @@ -336,7 +336,7 @@ def test_method_create_and_run_with_all_params_overload_2(self, client: OpenAI) { "chunking_strategy": {"type": "auto"}, "file_ids": ["string"], - "metadata": {}, + "metadata": {"foo": "string"}, } ], }, @@ -403,10 +403,10 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> "tools": [{"type": "code_interpreter"}], } ], - "metadata": {}, + "metadata": {"foo": "string"}, } ], - metadata={}, + metadata={"foo": "string"}, tool_resources={ "code_interpreter": {"file_ids": ["string"]}, "file_search": { @@ -415,7 +415,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> { "chunking_strategy": {"type": "auto"}, "file_ids": ["string"], - "metadata": {}, + "metadata": {"foo": "string"}, } ], }, @@ -491,8 +491,8 @@ async def test_method_update(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_method_update_with_all_params(self, async_client: AsyncOpenAI) -> None: thread = await async_client.beta.threads.update( - "string", - metadata={}, + thread_id="thread_id", + metadata={"foo": "string"}, tool_resources={ "code_interpreter": {"file_ids": ["string"]}, "file_search": {"vector_store_ids": ["string"]}, @@ -583,7 +583,7 @@ async def test_method_create_and_run_with_all_params_overload_1(self, async_clie instructions="string", max_completion_tokens=256, max_prompt_tokens=256, - metadata={}, + metadata={"foo": "string"}, model="gpt-4o", parallel_tool_calls=True, response_format="auto", @@ -600,10 +600,10 @@ async def test_method_create_and_run_with_all_params_overload_1(self, async_clie "tools": [{"type": "code_interpreter"}], } ], - "metadata": {}, + "metadata": {"foo": "string"}, } ], - "metadata": {}, + "metadata": {"foo": "string"}, "tool_resources": { "code_interpreter": {"file_ids": ["string"]}, "file_search": { @@ -612,7 +612,7 @@ async def test_method_create_and_run_with_all_params_overload_1(self, async_clie { "chunking_strategy": {"type": "auto"}, "file_ids": ["string"], - "metadata": {}, + "metadata": {"foo": "string"}, } ], }, @@ -672,7 +672,7 @@ async def test_method_create_and_run_with_all_params_overload_2(self, async_clie instructions="string", max_completion_tokens=256, max_prompt_tokens=256, - metadata={}, + metadata={"foo": "string"}, model="gpt-4o", parallel_tool_calls=True, response_format="auto", @@ -688,10 +688,10 @@ async def test_method_create_and_run_with_all_params_overload_2(self, async_clie "tools": [{"type": "code_interpreter"}], } ], - "metadata": {}, + "metadata": {"foo": "string"}, } ], - "metadata": {}, + "metadata": {"foo": "string"}, "tool_resources": { "code_interpreter": {"file_ids": ["string"]}, "file_search": { @@ -700,7 +700,7 @@ async def test_method_create_and_run_with_all_params_overload_2(self, async_clie { "chunking_strategy": {"type": "auto"}, "file_ids": ["string"], - "metadata": {}, + "metadata": {"foo": "string"}, } ], }, diff --git a/tests/api_resources/beta/test_vector_stores.py b/tests/api_resources/beta/test_vector_stores.py index 99e1970c33..e13b8c7613 100644 --- a/tests/api_resources/beta/test_vector_stores.py +++ b/tests/api_resources/beta/test_vector_stores.py @@ -35,8 +35,8 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: "days": 1, }, file_ids=["string"], - metadata={}, - name="string", + metadata={"foo": "string"}, + name="name", ) assert_matches_type(VectorStore, vector_store, path=["response"]) @@ -113,8 +113,8 @@ def test_method_update_with_all_params(self, client: OpenAI) -> None: "anchor": "last_active_at", "days": 1, }, - metadata={}, - name="string", + metadata={"foo": "string"}, + name="name", ) assert_matches_type(VectorStore, vector_store, path=["response"]) @@ -240,8 +240,8 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> "days": 1, }, file_ids=["string"], - metadata={}, - name="string", + metadata={"foo": "string"}, + name="name", ) assert_matches_type(VectorStore, vector_store, path=["response"]) @@ -318,8 +318,8 @@ async def test_method_update_with_all_params(self, async_client: AsyncOpenAI) -> "anchor": "last_active_at", "days": 1, }, - metadata={}, - name="string", + metadata={"foo": "string"}, + name="name", ) assert_matches_type(VectorStore, vector_store, path=["response"]) diff --git a/tests/api_resources/beta/threads/test_messages.py b/tests/api_resources/beta/threads/test_messages.py index 06c37e608a..9189a2f29e 100644 --- a/tests/api_resources/beta/threads/test_messages.py +++ b/tests/api_resources/beta/threads/test_messages.py @@ -42,7 +42,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: "tools": [{"type": "code_interpreter"}], } ], - metadata={}, + metadata={"foo": "string"}, ) assert_matches_type(Message, message, path=["response"]) @@ -142,9 +142,9 @@ def test_method_update(self, client: OpenAI) -> None: @parametrize def test_method_update_with_all_params(self, client: OpenAI) -> None: message = client.beta.threads.messages.update( - "string", - thread_id="string", - metadata={}, + message_id="message_id", + thread_id="thread_id", + metadata={"foo": "string"}, ) assert_matches_type(Message, message, path=["response"]) @@ -311,7 +311,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> "tools": [{"type": "code_interpreter"}], } ], - metadata={}, + metadata={"foo": "string"}, ) assert_matches_type(Message, message, path=["response"]) @@ -411,9 +411,9 @@ async def test_method_update(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_method_update_with_all_params(self, async_client: AsyncOpenAI) -> None: message = await async_client.beta.threads.messages.update( - "string", - thread_id="string", - metadata={}, + message_id="message_id", + thread_id="thread_id", + metadata={"foo": "string"}, ) assert_matches_type(Message, message, path=["response"]) diff --git a/tests/api_resources/beta/threads/test_runs.py b/tests/api_resources/beta/threads/test_runs.py index c48cc6de43..48b39cfe5b 100644 --- a/tests/api_resources/beta/threads/test_runs.py +++ b/tests/api_resources/beta/threads/test_runs.py @@ -47,13 +47,13 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: "tools": [{"type": "code_interpreter"}], } ], - "metadata": {}, + "metadata": {"foo": "string"}, } ], instructions="string", max_completion_tokens=256, max_prompt_tokens=256, - metadata={}, + metadata={"foo": "string"}, model="gpt-4o", parallel_tool_calls=True, response_format="auto", @@ -130,13 +130,13 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: "tools": [{"type": "code_interpreter"}], } ], - "metadata": {}, + "metadata": {"foo": "string"}, } ], instructions="string", max_completion_tokens=256, max_prompt_tokens=256, - metadata={}, + metadata={"foo": "string"}, model="gpt-4o", parallel_tool_calls=True, response_format="auto", @@ -246,9 +246,9 @@ def test_method_update(self, client: OpenAI) -> None: @parametrize def test_method_update_with_all_params(self, client: OpenAI) -> None: run = client.beta.threads.runs.update( - "string", - thread_id="string", - metadata={}, + run_id="run_id", + thread_id="thread_id", + metadata={"foo": "string"}, ) assert_matches_type(Run, run, path=["response"]) @@ -543,13 +543,13 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn "tools": [{"type": "code_interpreter"}], } ], - "metadata": {}, + "metadata": {"foo": "string"}, } ], instructions="string", max_completion_tokens=256, max_prompt_tokens=256, - metadata={}, + metadata={"foo": "string"}, model="gpt-4o", parallel_tool_calls=True, response_format="auto", @@ -626,13 +626,13 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn "tools": [{"type": "code_interpreter"}], } ], - "metadata": {}, + "metadata": {"foo": "string"}, } ], instructions="string", max_completion_tokens=256, max_prompt_tokens=256, - metadata={}, + metadata={"foo": "string"}, model="gpt-4o", parallel_tool_calls=True, response_format="auto", @@ -742,9 +742,9 @@ async def test_method_update(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_method_update_with_all_params(self, async_client: AsyncOpenAI) -> None: run = await async_client.beta.threads.runs.update( - "string", - thread_id="string", - metadata={}, + run_id="run_id", + thread_id="thread_id", + metadata={"foo": "string"}, ) assert_matches_type(Run, run, path=["response"]) From b56b357e60b9bccdb1ad5ab56a86614cfd4d402d Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Fri, 31 Jan 2025 19:14:32 +0000 Subject: [PATCH 186/769] chore(types): fix Metadata types --- src/openai/resources/beta/chat/completions.py | 9 +++--- .../resources/beta/threads/runs/runs.py | 28 +++++++++---------- src/openai/resources/beta/threads/threads.py | 16 +++++------ 3 files changed, 27 insertions(+), 26 deletions(-) diff --git a/src/openai/resources/beta/chat/completions.py b/src/openai/resources/beta/chat/completions.py index 48cb13f7a6..8a3a20d9e0 100644 --- a/src/openai/resources/beta/chat/completions.py +++ b/src/openai/resources/beta/chat/completions.py @@ -28,6 +28,7 @@ ) from ....types.chat_model import ChatModel from ....lib.streaming.chat import ChatCompletionStreamManager, AsyncChatCompletionStreamManager +from ....types.shared_params import Metadata from ....types.chat.chat_completion import ChatCompletion from ....types.chat.chat_completion_chunk import ChatCompletionChunk from ....types.chat.parsed_chat_completion import ParsedChatCompletion @@ -76,7 +77,7 @@ def parse( logprobs: Optional[bool] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, @@ -221,7 +222,7 @@ def stream( logprobs: Optional[bool] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, @@ -351,7 +352,7 @@ async def parse( logprobs: Optional[bool] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, @@ -496,7 +497,7 @@ def stream( logprobs: Optional[bool] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, diff --git a/src/openai/resources/beta/threads/runs/runs.py b/src/openai/resources/beta/threads/runs/runs.py index 9cb202a1a2..13301ad507 100644 --- a/src/openai/resources/beta/threads/runs/runs.py +++ b/src/openai/resources/beta/threads/runs/runs.py @@ -771,7 +771,7 @@ def create_and_poll( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -840,7 +840,7 @@ def create_and_stream( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -871,7 +871,7 @@ def create_and_stream( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -902,7 +902,7 @@ def create_and_stream( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -1019,7 +1019,7 @@ def stream( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -1050,7 +1050,7 @@ def stream( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -1081,7 +1081,7 @@ def stream( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -2144,7 +2144,7 @@ async def create_and_poll( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -2213,7 +2213,7 @@ def create_and_stream( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -2244,7 +2244,7 @@ def create_and_stream( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -2275,7 +2275,7 @@ def create_and_stream( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -2393,7 +2393,7 @@ def stream( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -2424,7 +2424,7 @@ def stream( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -2455,7 +2455,7 @@ def stream( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, diff --git a/src/openai/resources/beta/threads/threads.py b/src/openai/resources/beta/threads/threads.py index 0ec59aca55..6ff8539501 100644 --- a/src/openai/resources/beta/threads/threads.py +++ b/src/openai/resources/beta/threads/threads.py @@ -734,7 +734,7 @@ def create_and_run_poll( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -790,7 +790,7 @@ def create_and_run_stream( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -819,7 +819,7 @@ def create_and_run_stream( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -848,7 +848,7 @@ def create_and_run_stream( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -1581,7 +1581,7 @@ async def create_and_run_poll( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -1639,7 +1639,7 @@ def create_and_run_stream( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -1668,7 +1668,7 @@ def create_and_run_stream( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, @@ -1697,7 +1697,7 @@ def create_and_run_stream( instructions: Optional[str] | NotGiven = NOT_GIVEN, max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[object] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, From 7a6517d81e4ae9e9e9527cd401bb76937983dfef Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 31 Jan 2025 19:18:58 +0000 Subject: [PATCH 187/769] release: 1.61.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 25 +++++++++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 73f712c242..68804e4da0 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.60.2" + ".": "1.61.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 168d98e5cd..dcd1c06333 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,30 @@ # Changelog +## 1.61.0 (2025-01-31) + +Full Changelog: [v1.60.2...v1.61.0](https://github.com/openai/openai-python/compare/v1.60.2...v1.61.0) + +### Features + +* **api:** add o3-mini ([#2067](https://github.com/openai/openai-python/issues/2067)) ([12b87a4](https://github.com/openai/openai-python/commit/12b87a4a1e6cb071a6b063d089585dec56a5d534)) + + +### Bug Fixes + +* **types:** correct metadata type + other fixes ([12b87a4](https://github.com/openai/openai-python/commit/12b87a4a1e6cb071a6b063d089585dec56a5d534)) + + +### Chores + +* **helpers:** section links ([ef8d3cc](https://github.com/openai/openai-python/commit/ef8d3cce40022d3482d341455be604e5f1afbd70)) +* **types:** fix Metadata types ([82d3156](https://github.com/openai/openai-python/commit/82d3156e74ed2f95edd10cd7ebea53d2b5562794)) +* update api.md ([#2063](https://github.com/openai/openai-python/issues/2063)) ([21964f0](https://github.com/openai/openai-python/commit/21964f00fb104011c4c357544114702052b74548)) + + +### Documentation + +* **readme:** current section links ([#2055](https://github.com/openai/openai-python/issues/2055)) ([ef8d3cc](https://github.com/openai/openai-python/commit/ef8d3cce40022d3482d341455be604e5f1afbd70)) + ## 1.60.2 (2025-01-27) Full Changelog: [v1.60.1...v1.60.2](https://github.com/openai/openai-python/compare/v1.60.1...v1.60.2) diff --git a/pyproject.toml b/pyproject.toml index 9657bdc0ce..07913fcbd2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.60.2" +version = "1.61.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 c8f825db34..e9ab8be65e 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.60.2" # x-release-please-version +__version__ = "1.61.0" # x-release-please-version From c27e8cc997212b895743941966530980cd56d9da Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Mon, 3 Feb 2025 11:54:55 +0000 Subject: [PATCH 188/769] fix(cli/chat): only send params when set (#2077) --- src/openai/cli/_api/chat/completions.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/openai/cli/_api/chat/completions.py b/src/openai/cli/_api/chat/completions.py index c299741fe0..feedb5ccab 100644 --- a/src/openai/cli/_api/chat/completions.py +++ b/src/openai/cli/_api/chat/completions.py @@ -100,13 +100,17 @@ def create(args: CLIChatCompletionCreateArgs) -> None: "messages": [ {"role": cast(Literal["user"], message.role), "content": message.content} for message in args.message ], - "n": args.n, - "temperature": args.temperature, - "top_p": args.top_p, - "stop": args.stop, # type checkers are not good at inferring union types so we have to set stream afterwards "stream": False, } + if args.temperature is not None: + params['temperature'] = args.temperature + if args.stop is not None: + params['stop'] = args.stop + if args.top_p is not None: + params['top_p'] = args.top_p + if args.n is not None: + params['n'] = args.n if args.stream: params["stream"] = args.stream # type: ignore if args.max_tokens is not None: From 5a1a412b77c4233ca3b147738f63956f09a65fb1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 3 Feb 2025 14:43:52 +0000 Subject: [PATCH 189/769] chore(internal): change default timeout to an int (#2079) --- src/openai/_constants.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openai/_constants.py b/src/openai/_constants.py index 3f82bed037..7029dc72b0 100644 --- a/src/openai/_constants.py +++ b/src/openai/_constants.py @@ -6,7 +6,7 @@ OVERRIDE_CAST_TO_HEADER = "____stainless_override_cast_to" # default timeout is 10 minutes -DEFAULT_TIMEOUT = httpx.Timeout(timeout=600.0, connect=5.0) +DEFAULT_TIMEOUT = httpx.Timeout(timeout=600, connect=5.0) DEFAULT_MAX_RETRIES = 2 DEFAULT_CONNECTION_LIMITS = httpx.Limits(max_connections=1000, max_keepalive_connections=100) From 6afde0dc8512a16ff2eca781fee0395cab254f8c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 3 Feb 2025 15:27:06 +0000 Subject: [PATCH 190/769] chore(internal): bummp ruff dependency (#2080) --- pyproject.toml | 2 +- requirements-dev.lock | 2 +- scripts/utils/ruffen-docs.py | 4 ++-- src/openai/_models.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 07913fcbd2..dc78d95d3f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -194,7 +194,7 @@ select = [ "T201", "T203", # misuse of typing.TYPE_CHECKING - "TCH004", + "TC004", # import rules "TID251", ] diff --git a/requirements-dev.lock b/requirements-dev.lock index 38cc6e1cf2..5599057b66 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -140,7 +140,7 @@ requests==2.31.0 respx==0.22.0 rich==13.7.1 # via inline-snapshot -ruff==0.6.9 +ruff==0.9.4 setuptools==68.2.2 # via nodeenv six==1.16.0 diff --git a/scripts/utils/ruffen-docs.py b/scripts/utils/ruffen-docs.py index 37b3d94f0f..0cf2bd2fd9 100644 --- a/scripts/utils/ruffen-docs.py +++ b/scripts/utils/ruffen-docs.py @@ -47,7 +47,7 @@ def _md_match(match: Match[str]) -> str: with _collect_error(match): code = format_code_block(code) code = textwrap.indent(code, match["indent"]) - return f'{match["before"]}{code}{match["after"]}' + return f"{match['before']}{code}{match['after']}" def _pycon_match(match: Match[str]) -> str: code = "" @@ -97,7 +97,7 @@ def finish_fragment() -> None: def _md_pycon_match(match: Match[str]) -> str: code = _pycon_match(match) code = textwrap.indent(code, match["indent"]) - return f'{match["before"]}{code}{match["after"]}' + return f"{match['before']}{code}{match['after']}" src = MD_RE.sub(_md_match, src) src = MD_PYCON_RE.sub(_md_pycon_match, src) diff --git a/src/openai/_models.py b/src/openai/_models.py index 23456d9f80..c6e1305087 100644 --- a/src/openai/_models.py +++ b/src/openai/_models.py @@ -197,7 +197,7 @@ def to_json( @override def __str__(self) -> str: # mypy complains about an invalid self arg - return f'{self.__repr_name__()}({self.__repr_str__(", ")})' # type: ignore[misc] + return f"{self.__repr_name__()}({self.__repr_str__(', ')})" # type: ignore[misc] # Override the 'construct' method in a way that supports recursive parsing without validation. # Based on https://github.com/samuelcolvin/pydantic/issues/1168#issuecomment-817742836. From f344db250ac3a1f5cb1bb36b6719a2bf4e002d87 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 5 Feb 2025 11:26:48 +0000 Subject: [PATCH 191/769] fix(api/types): correct audio duration & role types (#2091) --- .stats.yml | 2 +- api.md | 1 + .../types/audio/transcription_verbose.py | 2 +- src/openai/types/audio/translation_verbose.py | 2 +- src/openai/types/beta/realtime/__init__.py | 4 ++ .../conversation_item_with_reference.py | 67 ++++++++++++++++++ .../conversation_item_with_reference_param.py | 68 +++++++++++++++++++ .../beta/realtime/response_create_event.py | 10 +-- .../realtime/response_create_event_param.py | 10 +-- .../types/chat/chat_completion_chunk.py | 2 +- src/openai/types/chat/chat_completion_role.py | 2 +- 11 files changed, 157 insertions(+), 13 deletions(-) create mode 100644 src/openai/types/beta/realtime/conversation_item_with_reference.py create mode 100644 src/openai/types/beta/realtime/conversation_item_with_reference_param.py diff --git a/.stats.yml b/.stats.yml index e49b5c56e8..df7877dfd0 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-6204952a29973265b9c0d66fc67ffaf53c6a90ae4d75cdacf9d147676f5274c9.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-fc5dbc19505b0035f9e7f88868619f4fb519b048bde011f6154f3132d4be71fb.yml diff --git a/api.md b/api.md index c1262fd2c5..efbfeaa68f 100644 --- a/api.md +++ b/api.md @@ -255,6 +255,7 @@ from openai.types.beta.realtime import ( ConversationItemInputAudioTranscriptionFailedEvent, ConversationItemTruncateEvent, ConversationItemTruncatedEvent, + ConversationItemWithReference, ErrorEvent, InputAudioBufferAppendEvent, InputAudioBufferClearEvent, diff --git a/src/openai/types/audio/transcription_verbose.py b/src/openai/types/audio/transcription_verbose.py index 3b18fa4871..2a670189e0 100644 --- a/src/openai/types/audio/transcription_verbose.py +++ b/src/openai/types/audio/transcription_verbose.py @@ -10,7 +10,7 @@ class TranscriptionVerbose(BaseModel): - duration: str + duration: float """The duration of the input audio.""" language: str diff --git a/src/openai/types/audio/translation_verbose.py b/src/openai/types/audio/translation_verbose.py index 5901ae7535..27cb02d64f 100644 --- a/src/openai/types/audio/translation_verbose.py +++ b/src/openai/types/audio/translation_verbose.py @@ -9,7 +9,7 @@ class TranslationVerbose(BaseModel): - duration: str + duration: float """The duration of the input audio.""" language: str diff --git a/src/openai/types/beta/realtime/__init__.py b/src/openai/types/beta/realtime/__init__.py index 372d4ec19d..cd0616dcfa 100644 --- a/src/openai/types/beta/realtime/__init__.py +++ b/src/openai/types/beta/realtime/__init__.py @@ -42,6 +42,7 @@ from .input_audio_buffer_commit_event import InputAudioBufferCommitEvent as InputAudioBufferCommitEvent from .response_output_item_done_event import ResponseOutputItemDoneEvent as ResponseOutputItemDoneEvent from .conversation_item_truncate_event import ConversationItemTruncateEvent as ConversationItemTruncateEvent +from .conversation_item_with_reference import ConversationItemWithReference as ConversationItemWithReference from .input_audio_buffer_cleared_event import InputAudioBufferClearedEvent as InputAudioBufferClearedEvent from .response_content_part_done_event import ResponseContentPartDoneEvent as ResponseContentPartDoneEvent from .response_output_item_added_event import ResponseOutputItemAddedEvent as ResponseOutputItemAddedEvent @@ -60,6 +61,9 @@ from .conversation_item_truncate_event_param import ( ConversationItemTruncateEventParam as ConversationItemTruncateEventParam, ) +from .conversation_item_with_reference_param import ( + ConversationItemWithReferenceParam as ConversationItemWithReferenceParam, +) from .input_audio_buffer_speech_started_event import ( InputAudioBufferSpeechStartedEvent as InputAudioBufferSpeechStartedEvent, ) diff --git a/src/openai/types/beta/realtime/conversation_item_with_reference.py b/src/openai/types/beta/realtime/conversation_item_with_reference.py new file mode 100644 index 0000000000..31806afc33 --- /dev/null +++ b/src/openai/types/beta/realtime/conversation_item_with_reference.py @@ -0,0 +1,67 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ...._models import BaseModel +from .conversation_item_content import ConversationItemContent + +__all__ = ["ConversationItemWithReference"] + + +class ConversationItemWithReference(BaseModel): + id: Optional[str] = None + """ + For an item of type (`message` | `function_call` | `function_call_output`) this + field allows the client to assign the unique ID of the item. It is not required + because the server will generate one if not provided. + + For an item of type `item_reference`, this field is required and is a reference + to any item that has previously existed in the conversation. + """ + + arguments: Optional[str] = None + """The arguments of the function call (for `function_call` items).""" + + call_id: Optional[str] = None + """ + The ID of the function call (for `function_call` and `function_call_output` + items). If passed on a `function_call_output` item, the server will check that a + `function_call` item with the same ID exists in the conversation history. + """ + + content: Optional[List[ConversationItemContent]] = None + """The content of the message, applicable for `message` items. + + - Message items of role `system` support only `input_text` content + - Message items of role `user` support `input_text` and `input_audio` content + - Message items of role `assistant` support `text` content. + """ + + name: Optional[str] = None + """The name of the function being called (for `function_call` items).""" + + object: Optional[Literal["realtime.item"]] = None + """Identifier for the API object being returned - always `realtime.item`.""" + + output: Optional[str] = None + """The output of the function call (for `function_call_output` items).""" + + role: Optional[Literal["user", "assistant", "system"]] = None + """ + The role of the message sender (`user`, `assistant`, `system`), only applicable + for `message` items. + """ + + status: Optional[Literal["completed", "incomplete"]] = None + """The status of the item (`completed`, `incomplete`). + + These have no effect on the conversation, but are accepted for consistency with + the `conversation.item.created` event. + """ + + type: Optional[Literal["message", "function_call", "function_call_output", "item_reference"]] = None + """ + The type of the item (`message`, `function_call`, `function_call_output`, + `item_reference`). + """ diff --git a/src/openai/types/beta/realtime/conversation_item_with_reference_param.py b/src/openai/types/beta/realtime/conversation_item_with_reference_param.py new file mode 100644 index 0000000000..e266cdce32 --- /dev/null +++ b/src/openai/types/beta/realtime/conversation_item_with_reference_param.py @@ -0,0 +1,68 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Literal, TypedDict + +from .conversation_item_content_param import ConversationItemContentParam + +__all__ = ["ConversationItemWithReferenceParam"] + + +class ConversationItemWithReferenceParam(TypedDict, total=False): + id: str + """ + For an item of type (`message` | `function_call` | `function_call_output`) this + field allows the client to assign the unique ID of the item. It is not required + because the server will generate one if not provided. + + For an item of type `item_reference`, this field is required and is a reference + to any item that has previously existed in the conversation. + """ + + arguments: str + """The arguments of the function call (for `function_call` items).""" + + call_id: str + """ + The ID of the function call (for `function_call` and `function_call_output` + items). If passed on a `function_call_output` item, the server will check that a + `function_call` item with the same ID exists in the conversation history. + """ + + content: Iterable[ConversationItemContentParam] + """The content of the message, applicable for `message` items. + + - Message items of role `system` support only `input_text` content + - Message items of role `user` support `input_text` and `input_audio` content + - Message items of role `assistant` support `text` content. + """ + + name: str + """The name of the function being called (for `function_call` items).""" + + object: Literal["realtime.item"] + """Identifier for the API object being returned - always `realtime.item`.""" + + output: str + """The output of the function call (for `function_call_output` items).""" + + role: Literal["user", "assistant", "system"] + """ + The role of the message sender (`user`, `assistant`, `system`), only applicable + for `message` items. + """ + + status: Literal["completed", "incomplete"] + """The status of the item (`completed`, `incomplete`). + + These have no effect on the conversation, but are accepted for consistency with + the `conversation.item.created` event. + """ + + type: Literal["message", "function_call", "function_call_output", "item_reference"] + """ + The type of the item (`message`, `function_call`, `function_call_output`, + `item_reference`). + """ diff --git a/src/openai/types/beta/realtime/response_create_event.py b/src/openai/types/beta/realtime/response_create_event.py index 0801654bd8..d6c5fda926 100644 --- a/src/openai/types/beta/realtime/response_create_event.py +++ b/src/openai/types/beta/realtime/response_create_event.py @@ -5,7 +5,7 @@ from ...._models import BaseModel from ...shared.metadata import Metadata -from .conversation_item import ConversationItem +from .conversation_item_with_reference import ConversationItemWithReference __all__ = ["ResponseCreateEvent", "Response", "ResponseTool"] @@ -37,11 +37,13 @@ class Response(BaseModel): will not add items to default conversation. """ - input: Optional[List[ConversationItem]] = None + input: Optional[List[ConversationItemWithReference]] = None """Input items to include in the prompt for the model. - Creates a new context for this response, without including the default - conversation. Can include references to items from the default conversation. + Using this field creates a new context for this Response instead of using the + default conversation. An empty array `[]` will clear the context for this + Response. Note that this can include references to items from the default + conversation. """ instructions: Optional[str] = None diff --git a/src/openai/types/beta/realtime/response_create_event_param.py b/src/openai/types/beta/realtime/response_create_event_param.py index a87ef955e8..c02fe1b34e 100644 --- a/src/openai/types/beta/realtime/response_create_event_param.py +++ b/src/openai/types/beta/realtime/response_create_event_param.py @@ -5,8 +5,8 @@ from typing import List, Union, Iterable, Optional from typing_extensions import Literal, Required, TypedDict -from .conversation_item_param import ConversationItemParam from ...shared_params.metadata import Metadata +from .conversation_item_with_reference_param import ConversationItemWithReferenceParam __all__ = ["ResponseCreateEventParam", "Response", "ResponseTool"] @@ -38,11 +38,13 @@ class Response(TypedDict, total=False): will not add items to default conversation. """ - input: Iterable[ConversationItemParam] + input: Iterable[ConversationItemWithReferenceParam] """Input items to include in the prompt for the model. - Creates a new context for this response, without including the default - conversation. Can include references to items from the default conversation. + Using this field creates a new context for this Response instead of using the + default conversation. An empty array `[]` will clear the context for this + Response. Note that this can include references to items from the default + conversation. """ instructions: str diff --git a/src/openai/types/chat/chat_completion_chunk.py b/src/openai/types/chat/chat_completion_chunk.py index 7b0ae2e121..dede513f1e 100644 --- a/src/openai/types/chat/chat_completion_chunk.py +++ b/src/openai/types/chat/chat_completion_chunk.py @@ -70,7 +70,7 @@ class ChoiceDelta(BaseModel): refusal: Optional[str] = None """The refusal message generated by the model.""" - role: Optional[Literal["system", "user", "assistant", "tool"]] = None + role: Optional[Literal["developer", "system", "user", "assistant", "tool"]] = None """The role of the author of this message.""" tool_calls: Optional[List[ChoiceDeltaToolCall]] = None diff --git a/src/openai/types/chat/chat_completion_role.py b/src/openai/types/chat/chat_completion_role.py index c2ebef74c8..3ec5e9ad87 100644 --- a/src/openai/types/chat/chat_completion_role.py +++ b/src/openai/types/chat/chat_completion_role.py @@ -4,4 +4,4 @@ __all__ = ["ChatCompletionRole"] -ChatCompletionRole: TypeAlias = Literal["system", "user", "assistant", "tool", "function"] +ChatCompletionRole: TypeAlias = Literal["developer", "system", "user", "assistant", "tool", "function"] From 7193688e364bd726594fe369032e813ced1bdfe2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 5 Feb 2025 11:27:26 +0000 Subject: [PATCH 192/769] release: 1.61.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 15 +++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 68804e4da0..285741ee32 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.61.0" + ".": "1.61.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index dcd1c06333..101e7480b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## 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) + +### Bug Fixes + +* **api/types:** correct audio duration & role types ([#2091](https://github.com/openai/openai-python/issues/2091)) ([afcea48](https://github.com/openai/openai-python/commit/afcea4891ff85de165ccc2b5497ccf9a90520e9e)) +* **cli/chat:** only send params when set ([#2077](https://github.com/openai/openai-python/issues/2077)) ([688b223](https://github.com/openai/openai-python/commit/688b223d9a733d241d50e5d7df62f346592c537c)) + + +### Chores + +* **internal:** bummp ruff dependency ([#2080](https://github.com/openai/openai-python/issues/2080)) ([b7a80b1](https://github.com/openai/openai-python/commit/b7a80b1994ab86e81485b88531e4aea63b3da594)) +* **internal:** change default timeout to an int ([#2079](https://github.com/openai/openai-python/issues/2079)) ([d3df1c6](https://github.com/openai/openai-python/commit/d3df1c6ca090598701e38fd376a9796aadba88f1)) + ## 1.61.0 (2025-01-31) Full Changelog: [v1.60.2...v1.61.0](https://github.com/openai/openai-python/compare/v1.60.2...v1.61.0) diff --git a/pyproject.toml b/pyproject.toml index dc78d95d3f..6f1a6eb28a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.61.0" +version = "1.61.1" 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 e9ab8be65e..7ffe16b95d 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.0" # x-release-please-version +__version__ = "1.61.1" # x-release-please-version From b99c35c62f3773980ee77179cdad9d8afd46f13b 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 193/769] 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 8640fd837f371e6c6e235bbdc3a6ff395ba632b7 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 194/769] 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 2c20ea7af7bcd531d04122624789402778370c52 Mon Sep 17 00:00:00 2001 From: Anthony Shaw Date: Thu, 6 Feb 2025 21:15:14 +1100 Subject: [PATCH 195/769] 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 af6a9437128fc64643178a12d3e700a962f08977 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 196/769] 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 e2f2db8a1c237997a699a28b4192a054a040fc61 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 197/769] 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 b5f6dc78feafbd3e34457dbf11b00978502823c0 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 198/769] 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 b45168e26f9fbbfcd7c1d1bd28f46a267ffcd3f9 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Mon, 10 Feb 2025 18:08:55 +0000 Subject: [PATCH 199/769] 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 3f8d8205ae41c389541e125336b0ae0c5e437661 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 200/769] 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 From 300f58bbbde749e023dd1cf39de8f5339780a33d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 13 Feb 2025 19:45:16 +0000 Subject: [PATCH 201/769] feat(api): add support for storing chat completions (#2117) --- .stats.yml | 4 +- api.md | 14 +- src/openai/_utils/_sync.py | 20 +- src/openai/cli/_api/chat/completions.py | 8 +- src/openai/lib/_parsing/_completions.py | 4 +- src/openai/resources/chat/chat.py | 2 +- .../resources/chat/completions/__init__.py | 33 ++ .../chat/{ => completions}/completions.py | 486 +++++++++++++++++- .../resources/chat/completions/messages.py | 212 ++++++++ src/openai/types/chat/__init__.py | 4 + .../types/chat/chat_completion_deleted.py | 18 + .../chat/chat_completion_store_message.py | 11 + .../types/chat/completion_list_params.py | 33 ++ .../types/chat/completion_update_params.py | 22 + src/openai/types/chat/completions/__init__.py | 5 + .../chat/completions/message_list_params.py | 21 + src/openai/types/moderation.py | 6 +- .../chat/completions/__init__.py | 1 + .../chat/completions/test_messages.py | 119 +++++ tests/api_resources/chat/test_completions.py | 310 +++++++++++ tests/lib/test_azure.py | 24 +- tests/test_client.py | 78 +-- 22 files changed, 1350 insertions(+), 85 deletions(-) create mode 100644 src/openai/resources/chat/completions/__init__.py rename src/openai/resources/chat/{ => completions}/completions.py (83%) create mode 100644 src/openai/resources/chat/completions/messages.py create mode 100644 src/openai/types/chat/chat_completion_deleted.py create mode 100644 src/openai/types/chat/chat_completion_store_message.py create mode 100644 src/openai/types/chat/completion_list_params.py create mode 100644 src/openai/types/chat/completion_update_params.py create mode 100644 src/openai/types/chat/completions/__init__.py create mode 100644 src/openai/types/chat/completions/message_list_params.py create mode 100644 tests/api_resources/chat/completions/__init__.py create mode 100644 tests/api_resources/chat/completions/test_messages.py diff --git a/.stats.yml b/.stats.yml index d59a86d22e..658877d3b0 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-dfb00c627f58e5180af7a9b29ed2f2aa0764a3b9daa6a32a1cc45bc8e48dfe15.yml +configured_endpoints: 74 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-4aa6ee65ba9efc789e05e6a5ef0883b2cadf06def8efd863dbf75e9e233067e1.yml diff --git a/api.md b/api.md index efbfeaa68f..2db9d1157e 100644 --- a/api.md +++ b/api.md @@ -48,6 +48,7 @@ from openai.types.chat import ( ChatCompletionContentPartInputAudio, ChatCompletionContentPartRefusal, ChatCompletionContentPartText, + ChatCompletionDeleted, ChatCompletionDeveloperMessageParam, ChatCompletionFunctionCallOption, ChatCompletionFunctionMessageParam, @@ -59,6 +60,7 @@ from openai.types.chat import ( ChatCompletionPredictionContent, ChatCompletionReasoningEffort, ChatCompletionRole, + ChatCompletionStoreMessage, ChatCompletionStreamOptions, ChatCompletionSystemMessageParam, ChatCompletionTokenLogprob, @@ -71,7 +73,17 @@ from openai.types.chat import ( Methods: -- client.chat.completions.create(\*\*params) -> ChatCompletion +- client.chat.completions.create(\*\*params) -> ChatCompletion +- client.chat.completions.retrieve(completion_id) -> ChatCompletion +- client.chat.completions.update(completion_id, \*\*params) -> ChatCompletion +- client.chat.completions.list(\*\*params) -> SyncCursorPage[ChatCompletion] +- client.chat.completions.delete(completion_id) -> ChatCompletionDeleted + +### Messages + +Methods: + +- client.chat.completions.messages.list(completion_id, \*\*params) -> SyncCursorPage[ChatCompletionStoreMessage] # Embeddings diff --git a/src/openai/_utils/_sync.py b/src/openai/_utils/_sync.py index 5d9e2c2ac9..ad7ec71b76 100644 --- a/src/openai/_utils/_sync.py +++ b/src/openai/_utils/_sync.py @@ -7,16 +7,20 @@ from typing import Any, TypeVar, Callable, Awaitable from typing_extensions import ParamSpec +import anyio +import sniffio +import anyio.to_thread + T_Retval = TypeVar("T_Retval") T_ParamSpec = ParamSpec("T_ParamSpec") if sys.version_info >= (3, 9): - to_thread = asyncio.to_thread + _asyncio_to_thread = asyncio.to_thread else: # backport of https://docs.python.org/3/library/asyncio-task.html#asyncio.to_thread # for Python 3.8 support - async def to_thread( + async def _asyncio_to_thread( func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs ) -> Any: """Asynchronously run function *func* in a separate thread. @@ -34,6 +38,17 @@ async def to_thread( return await loop.run_in_executor(None, func_call) +async def to_thread( + func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs +) -> T_Retval: + if sniffio.current_async_library() == "asyncio": + return await _asyncio_to_thread(func, *args, **kwargs) + + return await anyio.to_thread.run_sync( + functools.partial(func, *args, **kwargs), + ) + + # inspired by `asyncer`, https://github.com/tiangolo/asyncer def asyncify(function: Callable[T_ParamSpec, T_Retval]) -> Callable[T_ParamSpec, Awaitable[T_Retval]]: """ @@ -50,6 +65,7 @@ def blocking_func(arg1, arg2, kwarg1=None): # blocking code return result + result = asyncify(blocking_function)(arg1, arg2, kwarg1=value1) ``` diff --git a/src/openai/cli/_api/chat/completions.py b/src/openai/cli/_api/chat/completions.py index feedb5ccab..344eeff37c 100644 --- a/src/openai/cli/_api/chat/completions.py +++ b/src/openai/cli/_api/chat/completions.py @@ -104,13 +104,13 @@ def create(args: CLIChatCompletionCreateArgs) -> None: "stream": False, } if args.temperature is not None: - params['temperature'] = args.temperature + params["temperature"] = args.temperature if args.stop is not None: - params['stop'] = args.stop + params["stop"] = args.stop if args.top_p is not None: - params['top_p'] = args.top_p + params["top_p"] = args.top_p if args.n is not None: - params['n'] = args.n + params["n"] = args.n if args.stream: params["stream"] = args.stream # type: ignore if args.max_tokens is not None: diff --git a/src/openai/lib/_parsing/_completions.py b/src/openai/lib/_parsing/_completions.py index 14b1745d3d..c160070b66 100644 --- a/src/openai/lib/_parsing/_completions.py +++ b/src/openai/lib/_parsing/_completions.py @@ -45,13 +45,13 @@ def validate_input_tools( for tool in tools: if tool["type"] != "function": raise ValueError( - f'Currently only `function` tool types support auto-parsing; Received `{tool["type"]}`', + f"Currently only `function` tool types support auto-parsing; Received `{tool['type']}`", ) strict = tool["function"].get("strict") if strict is not True: raise ValueError( - f'`{tool["function"]["name"]}` is not strict. Only `strict` function tools can be auto-parsed' + f"`{tool['function']['name']}` is not strict. Only `strict` function tools can be auto-parsed" ) diff --git a/src/openai/resources/chat/chat.py b/src/openai/resources/chat/chat.py index 9c4aacc953..14f9224b41 100644 --- a/src/openai/resources/chat/chat.py +++ b/src/openai/resources/chat/chat.py @@ -4,7 +4,7 @@ from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource -from .completions import ( +from .completions.completions import ( Completions, AsyncCompletions, CompletionsWithRawResponse, diff --git a/src/openai/resources/chat/completions/__init__.py b/src/openai/resources/chat/completions/__init__.py new file mode 100644 index 0000000000..12d3b3aa28 --- /dev/null +++ b/src/openai/resources/chat/completions/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .messages import ( + Messages, + AsyncMessages, + MessagesWithRawResponse, + AsyncMessagesWithRawResponse, + MessagesWithStreamingResponse, + AsyncMessagesWithStreamingResponse, +) +from .completions import ( + Completions, + AsyncCompletions, + CompletionsWithRawResponse, + AsyncCompletionsWithRawResponse, + CompletionsWithStreamingResponse, + AsyncCompletionsWithStreamingResponse, +) + +__all__ = [ + "Messages", + "AsyncMessages", + "MessagesWithRawResponse", + "AsyncMessagesWithRawResponse", + "MessagesWithStreamingResponse", + "AsyncMessagesWithStreamingResponse", + "Completions", + "AsyncCompletions", + "CompletionsWithRawResponse", + "AsyncCompletionsWithRawResponse", + "CompletionsWithStreamingResponse", + "AsyncCompletionsWithStreamingResponse", +] diff --git a/src/openai/resources/chat/completions.py b/src/openai/resources/chat/completions/completions.py similarity index 83% rename from src/openai/resources/chat/completions.py rename to src/openai/resources/chat/completions/completions.py index cc839103a0..1753f6c990 100644 --- a/src/openai/resources/chat/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -9,40 +9,56 @@ import httpx import pydantic -from ... import _legacy_response -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ..._utils import ( +from .... import _legacy_response +from .messages import ( + Messages, + AsyncMessages, + MessagesWithRawResponse, + AsyncMessagesWithRawResponse, + MessagesWithStreamingResponse, + AsyncMessagesWithStreamingResponse, +) +from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._utils import ( required_args, maybe_transform, async_maybe_transform, ) -from ..._compat import cached_property -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ..._streaming import Stream, AsyncStream -from ...types.chat import ( +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ...._streaming import Stream, AsyncStream +from ....pagination import SyncCursorPage, AsyncCursorPage +from ....types.chat import ( ChatCompletionAudioParam, ChatCompletionReasoningEffort, + completion_list_params, completion_create_params, + completion_update_params, ) -from ..._base_client import make_request_options -from ...types.chat_model import ChatModel -from ...types.chat.chat_completion import ChatCompletion -from ...types.shared_params.metadata import Metadata -from ...types.chat.chat_completion_chunk import ChatCompletionChunk -from ...types.chat.chat_completion_modality import ChatCompletionModality -from ...types.chat.chat_completion_tool_param import ChatCompletionToolParam -from ...types.chat.chat_completion_audio_param import ChatCompletionAudioParam -from ...types.chat.chat_completion_message_param import ChatCompletionMessageParam -from ...types.chat.chat_completion_reasoning_effort import ChatCompletionReasoningEffort -from ...types.chat.chat_completion_stream_options_param import ChatCompletionStreamOptionsParam -from ...types.chat.chat_completion_prediction_content_param import ChatCompletionPredictionContentParam -from ...types.chat.chat_completion_tool_choice_option_param import ChatCompletionToolChoiceOptionParam +from ...._base_client import AsyncPaginator, make_request_options +from ....types.chat_model import ChatModel +from ....types.chat.chat_completion import ChatCompletion +from ....types.shared_params.metadata import Metadata +from ....types.chat.chat_completion_chunk import ChatCompletionChunk +from ....types.chat.chat_completion_deleted import ChatCompletionDeleted +from ....types.chat.chat_completion_modality import ChatCompletionModality +from ....types.chat.chat_completion_tool_param import ChatCompletionToolParam +from ....types.chat.chat_completion_audio_param import ChatCompletionAudioParam +from ....types.chat.chat_completion_message_param import ChatCompletionMessageParam +from ....types.chat.chat_completion_reasoning_effort import ChatCompletionReasoningEffort +from ....types.chat.chat_completion_stream_options_param import ChatCompletionStreamOptionsParam +from ....types.chat.chat_completion_prediction_content_param import ChatCompletionPredictionContentParam +from ....types.chat.chat_completion_tool_choice_option_param import ChatCompletionToolChoiceOptionParam __all__ = ["Completions", "AsyncCompletions"] class Completions(SyncAPIResource): + @cached_property + def messages(self) -> Messages: + return Messages(self._client) + @cached_property def with_raw_response(self) -> CompletionsWithRawResponse: """ @@ -905,8 +921,192 @@ def create( stream_cls=Stream[ChatCompletionChunk], ) + def retrieve( + self, + completion_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ChatCompletion: + """Get a stored chat completion. + + Only chat completions that have been created with + the `store` parameter set to `true` will be returned. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not completion_id: + raise ValueError(f"Expected a non-empty value for `completion_id` but received {completion_id!r}") + return self._get( + f"/chat/completions/{completion_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ChatCompletion, + ) + + def update( + self, + completion_id: str, + *, + metadata: Optional[Metadata], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ChatCompletion: + """Modify a stored chat completion. + + Only chat completions that have been created + with the `store` parameter set to `true` can be modified. Currently, the only + supported modification is to update the `metadata` field. + + Args: + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not completion_id: + raise ValueError(f"Expected a non-empty value for `completion_id` but received {completion_id!r}") + return self._post( + f"/chat/completions/{completion_id}", + body=maybe_transform({"metadata": metadata}, completion_update_params.CompletionUpdateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ChatCompletion, + ) + + def list( + self, + *, + after: str | NotGiven = NOT_GIVEN, + limit: int | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + model: str | NotGiven = NOT_GIVEN, + order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> SyncCursorPage[ChatCompletion]: + """List stored chat completions. + + Only chat completions that have been stored with + the `store` parameter set to `true` will be returned. + + Args: + after: Identifier for the last chat completion from the previous pagination request. + + limit: Number of chat completions to retrieve. + + metadata: + A list of metadata keys to filter the chat completions by. Example: + + `metadata[key1]=value1&metadata[key2]=value2` + + model: The model used to generate the chat completions. + + order: Sort order for chat completions by timestamp. Use `asc` for ascending order or + `desc` for descending order. Defaults to `asc`. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/chat/completions", + page=SyncCursorPage[ChatCompletion], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "metadata": metadata, + "model": model, + "order": order, + }, + completion_list_params.CompletionListParams, + ), + ), + model=ChatCompletion, + ) + + def delete( + self, + completion_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ChatCompletionDeleted: + """Delete a stored chat completion. + + Only chat completions that have been created + with the `store` parameter set to `true` can be deleted. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not completion_id: + raise ValueError(f"Expected a non-empty value for `completion_id` but received {completion_id!r}") + return self._delete( + f"/chat/completions/{completion_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ChatCompletionDeleted, + ) + class AsyncCompletions(AsyncAPIResource): + @cached_property + def messages(self) -> AsyncMessages: + return AsyncMessages(self._client) + @cached_property def with_raw_response(self) -> AsyncCompletionsWithRawResponse: """ @@ -1769,6 +1969,186 @@ async def create( stream_cls=AsyncStream[ChatCompletionChunk], ) + async def retrieve( + self, + completion_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ChatCompletion: + """Get a stored chat completion. + + Only chat completions that have been created with + the `store` parameter set to `true` will be returned. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not completion_id: + raise ValueError(f"Expected a non-empty value for `completion_id` but received {completion_id!r}") + return await self._get( + f"/chat/completions/{completion_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ChatCompletion, + ) + + async def update( + self, + completion_id: str, + *, + metadata: Optional[Metadata], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ChatCompletion: + """Modify a stored chat completion. + + Only chat completions that have been created + with the `store` parameter set to `true` can be modified. Currently, the only + supported modification is to update the `metadata` field. + + Args: + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not completion_id: + raise ValueError(f"Expected a non-empty value for `completion_id` but received {completion_id!r}") + return await self._post( + f"/chat/completions/{completion_id}", + body=await async_maybe_transform({"metadata": metadata}, completion_update_params.CompletionUpdateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ChatCompletion, + ) + + def list( + self, + *, + after: str | NotGiven = NOT_GIVEN, + limit: int | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + model: str | NotGiven = NOT_GIVEN, + order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> AsyncPaginator[ChatCompletion, AsyncCursorPage[ChatCompletion]]: + """List stored chat completions. + + Only chat completions that have been stored with + the `store` parameter set to `true` will be returned. + + Args: + after: Identifier for the last chat completion from the previous pagination request. + + limit: Number of chat completions to retrieve. + + metadata: + A list of metadata keys to filter the chat completions by. Example: + + `metadata[key1]=value1&metadata[key2]=value2` + + model: The model used to generate the chat completions. + + order: Sort order for chat completions by timestamp. Use `asc` for ascending order or + `desc` for descending order. Defaults to `asc`. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/chat/completions", + page=AsyncCursorPage[ChatCompletion], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "metadata": metadata, + "model": model, + "order": order, + }, + completion_list_params.CompletionListParams, + ), + ), + model=ChatCompletion, + ) + + async def delete( + self, + completion_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ChatCompletionDeleted: + """Delete a stored chat completion. + + Only chat completions that have been created + with the `store` parameter set to `true` can be deleted. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not completion_id: + raise ValueError(f"Expected a non-empty value for `completion_id` but received {completion_id!r}") + return await self._delete( + f"/chat/completions/{completion_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ChatCompletionDeleted, + ) + class CompletionsWithRawResponse: def __init__(self, completions: Completions) -> None: @@ -1777,6 +2157,22 @@ def __init__(self, completions: Completions) -> None: self.create = _legacy_response.to_raw_response_wrapper( completions.create, ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + completions.retrieve, + ) + self.update = _legacy_response.to_raw_response_wrapper( + completions.update, + ) + self.list = _legacy_response.to_raw_response_wrapper( + completions.list, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + completions.delete, + ) + + @cached_property + def messages(self) -> MessagesWithRawResponse: + return MessagesWithRawResponse(self._completions.messages) class AsyncCompletionsWithRawResponse: @@ -1786,6 +2182,22 @@ def __init__(self, completions: AsyncCompletions) -> None: self.create = _legacy_response.async_to_raw_response_wrapper( completions.create, ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + completions.retrieve, + ) + self.update = _legacy_response.async_to_raw_response_wrapper( + completions.update, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + completions.list, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + completions.delete, + ) + + @cached_property + def messages(self) -> AsyncMessagesWithRawResponse: + return AsyncMessagesWithRawResponse(self._completions.messages) class CompletionsWithStreamingResponse: @@ -1795,6 +2207,22 @@ def __init__(self, completions: Completions) -> None: self.create = to_streamed_response_wrapper( completions.create, ) + self.retrieve = to_streamed_response_wrapper( + completions.retrieve, + ) + self.update = to_streamed_response_wrapper( + completions.update, + ) + self.list = to_streamed_response_wrapper( + completions.list, + ) + self.delete = to_streamed_response_wrapper( + completions.delete, + ) + + @cached_property + def messages(self) -> MessagesWithStreamingResponse: + return MessagesWithStreamingResponse(self._completions.messages) class AsyncCompletionsWithStreamingResponse: @@ -1804,6 +2232,22 @@ def __init__(self, completions: AsyncCompletions) -> None: self.create = async_to_streamed_response_wrapper( completions.create, ) + self.retrieve = async_to_streamed_response_wrapper( + completions.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + completions.update, + ) + self.list = async_to_streamed_response_wrapper( + completions.list, + ) + self.delete = async_to_streamed_response_wrapper( + completions.delete, + ) + + @cached_property + def messages(self) -> AsyncMessagesWithStreamingResponse: + return AsyncMessagesWithStreamingResponse(self._completions.messages) def validate_response_format(response_format: object) -> None: diff --git a/src/openai/resources/chat/completions/messages.py b/src/openai/resources/chat/completions/messages.py new file mode 100644 index 0000000000..b71d670927 --- /dev/null +++ b/src/openai/resources/chat/completions/messages.py @@ -0,0 +1,212 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from .... import _legacy_response +from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._utils import maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ....pagination import SyncCursorPage, AsyncCursorPage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.chat.completions import message_list_params +from ....types.chat.chat_completion_store_message import ChatCompletionStoreMessage + +__all__ = ["Messages", "AsyncMessages"] + + +class Messages(SyncAPIResource): + @cached_property + def with_raw_response(self) -> MessagesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return MessagesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> MessagesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return MessagesWithStreamingResponse(self) + + def list( + self, + completion_id: str, + *, + after: str | NotGiven = NOT_GIVEN, + limit: int | NotGiven = NOT_GIVEN, + order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> SyncCursorPage[ChatCompletionStoreMessage]: + """Get the messages in a stored chat completion. + + Only chat completions that have + been created with the `store` parameter set to `true` will be returned. + + Args: + after: Identifier for the last message from the previous pagination request. + + limit: Number of messages to retrieve. + + order: Sort order for messages by timestamp. Use `asc` for ascending order or `desc` + for descending order. Defaults to `asc`. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not completion_id: + raise ValueError(f"Expected a non-empty value for `completion_id` but received {completion_id!r}") + return self._get_api_list( + f"/chat/completions/{completion_id}/messages", + page=SyncCursorPage[ChatCompletionStoreMessage], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + message_list_params.MessageListParams, + ), + ), + model=ChatCompletionStoreMessage, + ) + + +class AsyncMessages(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncMessagesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncMessagesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncMessagesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncMessagesWithStreamingResponse(self) + + def list( + self, + completion_id: str, + *, + after: str | NotGiven = NOT_GIVEN, + limit: int | NotGiven = NOT_GIVEN, + order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> AsyncPaginator[ChatCompletionStoreMessage, AsyncCursorPage[ChatCompletionStoreMessage]]: + """Get the messages in a stored chat completion. + + Only chat completions that have + been created with the `store` parameter set to `true` will be returned. + + Args: + after: Identifier for the last message from the previous pagination request. + + limit: Number of messages to retrieve. + + order: Sort order for messages by timestamp. Use `asc` for ascending order or `desc` + for descending order. Defaults to `asc`. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not completion_id: + raise ValueError(f"Expected a non-empty value for `completion_id` but received {completion_id!r}") + return self._get_api_list( + f"/chat/completions/{completion_id}/messages", + page=AsyncCursorPage[ChatCompletionStoreMessage], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + message_list_params.MessageListParams, + ), + ), + model=ChatCompletionStoreMessage, + ) + + +class MessagesWithRawResponse: + def __init__(self, messages: Messages) -> None: + self._messages = messages + + self.list = _legacy_response.to_raw_response_wrapper( + messages.list, + ) + + +class AsyncMessagesWithRawResponse: + def __init__(self, messages: AsyncMessages) -> None: + self._messages = messages + + self.list = _legacy_response.async_to_raw_response_wrapper( + messages.list, + ) + + +class MessagesWithStreamingResponse: + def __init__(self, messages: Messages) -> None: + self._messages = messages + + self.list = to_streamed_response_wrapper( + messages.list, + ) + + +class AsyncMessagesWithStreamingResponse: + def __init__(self, messages: AsyncMessages) -> None: + self._messages = messages + + self.list = async_to_streamed_response_wrapper( + messages.list, + ) diff --git a/src/openai/types/chat/__init__.py b/src/openai/types/chat/__init__.py index c623a982af..b4f43b298f 100644 --- a/src/openai/types/chat/__init__.py +++ b/src/openai/types/chat/__init__.py @@ -6,14 +6,17 @@ from .chat_completion_role import ChatCompletionRole as ChatCompletionRole from .chat_completion_audio import ChatCompletionAudio as ChatCompletionAudio from .chat_completion_chunk import ChatCompletionChunk as ChatCompletionChunk +from .completion_list_params import CompletionListParams as CompletionListParams from .parsed_chat_completion import ( ParsedChoice as ParsedChoice, ParsedChatCompletion as ParsedChatCompletion, ParsedChatCompletionMessage as ParsedChatCompletionMessage, ) +from .chat_completion_deleted import ChatCompletionDeleted as ChatCompletionDeleted from .chat_completion_message import ChatCompletionMessage as ChatCompletionMessage from .chat_completion_modality import ChatCompletionModality as ChatCompletionModality from .completion_create_params import CompletionCreateParams as CompletionCreateParams +from .completion_update_params import CompletionUpdateParams as CompletionUpdateParams from .parsed_function_tool_call import ( ParsedFunction as ParsedFunction, ParsedFunctionToolCall as ParsedFunctionToolCall, @@ -21,6 +24,7 @@ from .chat_completion_tool_param import ChatCompletionToolParam as ChatCompletionToolParam from .chat_completion_audio_param import ChatCompletionAudioParam as ChatCompletionAudioParam from .chat_completion_message_param import ChatCompletionMessageParam as ChatCompletionMessageParam +from .chat_completion_store_message import ChatCompletionStoreMessage as ChatCompletionStoreMessage from .chat_completion_token_logprob import ChatCompletionTokenLogprob as ChatCompletionTokenLogprob from .chat_completion_reasoning_effort import ChatCompletionReasoningEffort as ChatCompletionReasoningEffort from .chat_completion_message_tool_call import ChatCompletionMessageToolCall as ChatCompletionMessageToolCall diff --git a/src/openai/types/chat/chat_completion_deleted.py b/src/openai/types/chat/chat_completion_deleted.py new file mode 100644 index 0000000000..0a541cb23d --- /dev/null +++ b/src/openai/types/chat/chat_completion_deleted.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ChatCompletionDeleted"] + + +class ChatCompletionDeleted(BaseModel): + id: str + """The ID of the chat completion that was deleted.""" + + deleted: bool + """Whether the chat completion was deleted.""" + + object: Literal["chat.completion.deleted"] + """The type of object being deleted.""" diff --git a/src/openai/types/chat/chat_completion_store_message.py b/src/openai/types/chat/chat_completion_store_message.py new file mode 100644 index 0000000000..95adc08af8 --- /dev/null +++ b/src/openai/types/chat/chat_completion_store_message.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + + +from .chat_completion_message import ChatCompletionMessage + +__all__ = ["ChatCompletionStoreMessage"] + + +class ChatCompletionStoreMessage(ChatCompletionMessage): + id: str + """The identifier of the chat message.""" diff --git a/src/openai/types/chat/completion_list_params.py b/src/openai/types/chat/completion_list_params.py new file mode 100644 index 0000000000..a8fce900ce --- /dev/null +++ b/src/openai/types/chat/completion_list_params.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, TypedDict + +from ..shared_params.metadata import Metadata + +__all__ = ["CompletionListParams"] + + +class CompletionListParams(TypedDict, total=False): + after: str + """Identifier for the last chat completion from the previous pagination request.""" + + limit: int + """Number of chat completions to retrieve.""" + + metadata: Optional[Metadata] + """A list of metadata keys to filter the chat completions by. Example: + + `metadata[key1]=value1&metadata[key2]=value2` + """ + + model: str + """The model used to generate the chat completions.""" + + order: Literal["asc", "desc"] + """Sort order for chat completions by timestamp. + + Use `asc` for ascending order or `desc` for descending order. Defaults to `asc`. + """ diff --git a/src/openai/types/chat/completion_update_params.py b/src/openai/types/chat/completion_update_params.py new file mode 100644 index 0000000000..fc71733f07 --- /dev/null +++ b/src/openai/types/chat/completion_update_params.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Required, TypedDict + +from ..shared_params.metadata import Metadata + +__all__ = ["CompletionUpdateParams"] + + +class CompletionUpdateParams(TypedDict, total=False): + metadata: Required[Optional[Metadata]] + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + """ diff --git a/src/openai/types/chat/completions/__init__.py b/src/openai/types/chat/completions/__init__.py new file mode 100644 index 0000000000..b8e62d6a64 --- /dev/null +++ b/src/openai/types/chat/completions/__init__.py @@ -0,0 +1,5 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .message_list_params import MessageListParams as MessageListParams diff --git a/src/openai/types/chat/completions/message_list_params.py b/src/openai/types/chat/completions/message_list_params.py new file mode 100644 index 0000000000..4e694e83ea --- /dev/null +++ b/src/openai/types/chat/completions/message_list_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["MessageListParams"] + + +class MessageListParams(TypedDict, total=False): + after: str + """Identifier for the last message from the previous pagination request.""" + + limit: int + """Number of messages to retrieve.""" + + order: Literal["asc", "desc"] + """Sort order for messages by timestamp. + + Use `asc` for ascending order or `desc` for descending order. Defaults to `asc`. + """ diff --git a/src/openai/types/moderation.py b/src/openai/types/moderation.py index e4ec182ce2..608f562218 100644 --- a/src/openai/types/moderation.py +++ b/src/openai/types/moderation.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List +from typing import List, Optional from typing_extensions import Literal from pydantic import Field as FieldInfo @@ -38,14 +38,14 @@ class Categories(BaseModel): orientation, disability status, or caste. """ - illicit: bool + illicit: Optional[bool] = None """ Content that includes instructions or advice that facilitate the planning or execution of wrongdoing, or that gives advice or instruction on how to commit illicit acts. For example, "how to shoplift" would fit this category. """ - illicit_violent: bool = FieldInfo(alias="illicit/violent") + illicit_violent: Optional[bool] = FieldInfo(alias="illicit/violent", default=None) """ Content that includes instructions or advice that facilitate the planning or execution of wrongdoing that also includes violence, or that gives advice or diff --git a/tests/api_resources/chat/completions/__init__.py b/tests/api_resources/chat/completions/__init__.py new file mode 100644 index 0000000000..fd8019a9a1 --- /dev/null +++ b/tests/api_resources/chat/completions/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/chat/completions/test_messages.py b/tests/api_resources/chat/completions/test_messages.py new file mode 100644 index 0000000000..5caac9ec6c --- /dev/null +++ b/tests/api_resources/chat/completions/test_messages.py @@ -0,0 +1,119 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.pagination import SyncCursorPage, AsyncCursorPage +from openai.types.chat import ChatCompletionStoreMessage + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestMessages: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + message = client.chat.completions.messages.list( + completion_id="completion_id", + ) + assert_matches_type(SyncCursorPage[ChatCompletionStoreMessage], message, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + message = client.chat.completions.messages.list( + completion_id="completion_id", + after="after", + limit=0, + order="asc", + ) + assert_matches_type(SyncCursorPage[ChatCompletionStoreMessage], message, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.chat.completions.messages.with_raw_response.list( + completion_id="completion_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + message = response.parse() + assert_matches_type(SyncCursorPage[ChatCompletionStoreMessage], message, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.chat.completions.messages.with_streaming_response.list( + completion_id="completion_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + message = response.parse() + assert_matches_type(SyncCursorPage[ChatCompletionStoreMessage], message, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `completion_id` but received ''"): + client.chat.completions.messages.with_raw_response.list( + completion_id="", + ) + + +class TestAsyncMessages: + parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + message = await async_client.chat.completions.messages.list( + completion_id="completion_id", + ) + assert_matches_type(AsyncCursorPage[ChatCompletionStoreMessage], message, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + message = await async_client.chat.completions.messages.list( + completion_id="completion_id", + after="after", + limit=0, + order="asc", + ) + assert_matches_type(AsyncCursorPage[ChatCompletionStoreMessage], message, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.chat.completions.messages.with_raw_response.list( + completion_id="completion_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + message = response.parse() + assert_matches_type(AsyncCursorPage[ChatCompletionStoreMessage], message, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.chat.completions.messages.with_streaming_response.list( + completion_id="completion_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + message = await response.parse() + assert_matches_type(AsyncCursorPage[ChatCompletionStoreMessage], message, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `completion_id` but received ''"): + await async_client.chat.completions.messages.with_raw_response.list( + completion_id="", + ) diff --git a/tests/api_resources/chat/test_completions.py b/tests/api_resources/chat/test_completions.py index 25c9a36164..48b687a70e 100644 --- a/tests/api_resources/chat/test_completions.py +++ b/tests/api_resources/chat/test_completions.py @@ -10,8 +10,10 @@ from openai import OpenAI, AsyncOpenAI from tests.utils import assert_matches_type +from openai.pagination import SyncCursorPage, AsyncCursorPage from openai.types.chat import ( ChatCompletion, + ChatCompletionDeleted, ) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -248,6 +250,160 @@ def test_streaming_response_create_overload_2(self, client: OpenAI) -> None: assert cast(Any, response.is_closed) is True + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + completion = client.chat.completions.retrieve( + "completion_id", + ) + assert_matches_type(ChatCompletion, completion, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.chat.completions.with_raw_response.retrieve( + "completion_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + completion = response.parse() + assert_matches_type(ChatCompletion, completion, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.chat.completions.with_streaming_response.retrieve( + "completion_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + completion = response.parse() + assert_matches_type(ChatCompletion, completion, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `completion_id` but received ''"): + client.chat.completions.with_raw_response.retrieve( + "", + ) + + @parametrize + def test_method_update(self, client: OpenAI) -> None: + completion = client.chat.completions.update( + completion_id="completion_id", + metadata={"foo": "string"}, + ) + assert_matches_type(ChatCompletion, completion, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: OpenAI) -> None: + response = client.chat.completions.with_raw_response.update( + completion_id="completion_id", + metadata={"foo": "string"}, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + completion = response.parse() + assert_matches_type(ChatCompletion, completion, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: OpenAI) -> None: + with client.chat.completions.with_streaming_response.update( + completion_id="completion_id", + metadata={"foo": "string"}, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + completion = response.parse() + assert_matches_type(ChatCompletion, completion, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `completion_id` but received ''"): + client.chat.completions.with_raw_response.update( + completion_id="", + metadata={"foo": "string"}, + ) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + completion = client.chat.completions.list() + assert_matches_type(SyncCursorPage[ChatCompletion], completion, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + completion = client.chat.completions.list( + after="after", + limit=0, + metadata={"foo": "string"}, + model="model", + order="asc", + ) + assert_matches_type(SyncCursorPage[ChatCompletion], completion, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.chat.completions.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + completion = response.parse() + assert_matches_type(SyncCursorPage[ChatCompletion], completion, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.chat.completions.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + completion = response.parse() + assert_matches_type(SyncCursorPage[ChatCompletion], completion, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: OpenAI) -> None: + completion = client.chat.completions.delete( + "completion_id", + ) + assert_matches_type(ChatCompletionDeleted, completion, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: OpenAI) -> None: + response = client.chat.completions.with_raw_response.delete( + "completion_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + completion = response.parse() + assert_matches_type(ChatCompletionDeleted, completion, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: OpenAI) -> None: + with client.chat.completions.with_streaming_response.delete( + "completion_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + completion = response.parse() + assert_matches_type(ChatCompletionDeleted, completion, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `completion_id` but received ''"): + client.chat.completions.with_raw_response.delete( + "", + ) + @parametrize def test_method_create_disallows_pydantic(self, client: OpenAI) -> None: class MyModel(pydantic.BaseModel): @@ -497,6 +653,160 @@ async def test_streaming_response_create_overload_2(self, async_client: AsyncOpe assert cast(Any, response.is_closed) is True + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + completion = await async_client.chat.completions.retrieve( + "completion_id", + ) + assert_matches_type(ChatCompletion, completion, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.chat.completions.with_raw_response.retrieve( + "completion_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + completion = response.parse() + assert_matches_type(ChatCompletion, completion, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.chat.completions.with_streaming_response.retrieve( + "completion_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + completion = await response.parse() + assert_matches_type(ChatCompletion, completion, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `completion_id` but received ''"): + await async_client.chat.completions.with_raw_response.retrieve( + "", + ) + + @parametrize + async def test_method_update(self, async_client: AsyncOpenAI) -> None: + completion = await async_client.chat.completions.update( + completion_id="completion_id", + metadata={"foo": "string"}, + ) + assert_matches_type(ChatCompletion, completion, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: + response = await async_client.chat.completions.with_raw_response.update( + completion_id="completion_id", + metadata={"foo": "string"}, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + completion = response.parse() + assert_matches_type(ChatCompletion, completion, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncOpenAI) -> None: + async with async_client.chat.completions.with_streaming_response.update( + completion_id="completion_id", + metadata={"foo": "string"}, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + completion = await response.parse() + assert_matches_type(ChatCompletion, completion, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `completion_id` but received ''"): + await async_client.chat.completions.with_raw_response.update( + completion_id="", + metadata={"foo": "string"}, + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + completion = await async_client.chat.completions.list() + assert_matches_type(AsyncCursorPage[ChatCompletion], completion, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + completion = await async_client.chat.completions.list( + after="after", + limit=0, + metadata={"foo": "string"}, + model="model", + order="asc", + ) + assert_matches_type(AsyncCursorPage[ChatCompletion], completion, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.chat.completions.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + completion = response.parse() + assert_matches_type(AsyncCursorPage[ChatCompletion], completion, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.chat.completions.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + completion = await response.parse() + assert_matches_type(AsyncCursorPage[ChatCompletion], completion, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncOpenAI) -> None: + completion = await async_client.chat.completions.delete( + "completion_id", + ) + assert_matches_type(ChatCompletionDeleted, completion, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: + response = await async_client.chat.completions.with_raw_response.delete( + "completion_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + completion = response.parse() + assert_matches_type(ChatCompletionDeleted, completion, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: + async with async_client.chat.completions.with_streaming_response.delete( + "completion_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + completion = await response.parse() + assert_matches_type(ChatCompletionDeleted, completion, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `completion_id` but received ''"): + await async_client.chat.completions.with_raw_response.delete( + "", + ) + @parametrize async def test_method_create_disallows_pydantic(self, async_client: AsyncOpenAI) -> None: class MyModel(pydantic.BaseModel): diff --git a/tests/lib/test_azure.py b/tests/lib/test_azure.py index 626d7df311..a28aa8c2f6 100644 --- a/tests/lib/test_azure.py +++ b/tests/lib/test_azure.py @@ -153,7 +153,6 @@ def token_provider() -> str: class TestAzureLogging: - @pytest.fixture(autouse=True) def logger_with_filter(self) -> logging.Logger: logger = logging.getLogger("openai") @@ -165,9 +164,7 @@ def logger_with_filter(self) -> logging.Logger: def test_azure_api_key_redacted(self, respx_mock: MockRouter, caplog: pytest.LogCaptureFixture) -> None: respx_mock.post( "https://example-resource.azure.openai.com/openai/deployments/gpt-4/chat/completions?api-version=2024-06-01" - ).mock( - return_value=httpx.Response(200, json={"model": "gpt-4"}) - ) + ).mock(return_value=httpx.Response(200, json={"model": "gpt-4"})) client = AzureOpenAI( api_version="2024-06-01", @@ -182,14 +179,11 @@ def test_azure_api_key_redacted(self, respx_mock: MockRouter, caplog: pytest.Log if is_dict(record.args) and record.args.get("headers") and is_dict(record.args["headers"]): assert record.args["headers"]["api-key"] == "" - @pytest.mark.respx() def test_azure_bearer_token_redacted(self, respx_mock: MockRouter, caplog: pytest.LogCaptureFixture) -> None: respx_mock.post( "https://example-resource.azure.openai.com/openai/deployments/gpt-4/chat/completions?api-version=2024-06-01" - ).mock( - return_value=httpx.Response(200, json={"model": "gpt-4"}) - ) + ).mock(return_value=httpx.Response(200, json={"model": "gpt-4"})) client = AzureOpenAI( api_version="2024-06-01", @@ -204,15 +198,12 @@ def test_azure_bearer_token_redacted(self, respx_mock: MockRouter, caplog: pytes if is_dict(record.args) and record.args.get("headers") and is_dict(record.args["headers"]): assert record.args["headers"]["Authorization"] == "" - @pytest.mark.asyncio @pytest.mark.respx() async def test_azure_api_key_redacted_async(self, respx_mock: MockRouter, caplog: pytest.LogCaptureFixture) -> None: respx_mock.post( "https://example-resource.azure.openai.com/openai/deployments/gpt-4/chat/completions?api-version=2024-06-01" - ).mock( - return_value=httpx.Response(200, json={"model": "gpt-4"}) - ) + ).mock(return_value=httpx.Response(200, json={"model": "gpt-4"})) client = AsyncAzureOpenAI( api_version="2024-06-01", @@ -227,15 +218,14 @@ async def test_azure_api_key_redacted_async(self, respx_mock: MockRouter, caplog if is_dict(record.args) and record.args.get("headers") and is_dict(record.args["headers"]): assert record.args["headers"]["api-key"] == "" - @pytest.mark.asyncio @pytest.mark.respx() - async def test_azure_bearer_token_redacted_async(self, respx_mock: MockRouter, caplog: pytest.LogCaptureFixture) -> None: + async def test_azure_bearer_token_redacted_async( + self, respx_mock: MockRouter, caplog: pytest.LogCaptureFixture + ) -> None: respx_mock.post( "https://example-resource.azure.openai.com/openai/deployments/gpt-4/chat/completions?api-version=2024-06-01" - ).mock( - return_value=httpx.Response(200, json={"model": "gpt-4"}) - ) + ).mock(return_value=httpx.Response(200, json={"model": "gpt-4"})) client = AsyncAzureOpenAI( api_version="2024-06-01", diff --git a/tests/test_client.py b/tests/test_client.py index 41da2d5d04..62654afe1e 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -23,11 +23,13 @@ from openai import OpenAI, AsyncOpenAI, APIResponseValidationError from openai._types import Omit +from openai._utils import maybe_transform from openai._models import BaseModel, FinalRequestOptions from openai._constants import RAW_RESPONSE_HEADER from openai._streaming import Stream, AsyncStream from openai._exceptions import OpenAIError, APIStatusError, APITimeoutError, APIResponseValidationError from openai._base_client import DEFAULT_TIMEOUT, HTTPX_DEFAULT_TIMEOUT, BaseClient, make_request_options +from openai.types.chat.completion_create_params import CompletionCreateParamsNonStreaming from .utils import update_env @@ -724,14 +726,17 @@ def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter) -> No "/chat/completions", body=cast( object, - dict( - messages=[ - { - "role": "user", - "content": "Say this is a test", - } - ], - model="gpt-4o", + maybe_transform( + dict( + messages=[ + { + "role": "user", + "content": "Say this is a test", + } + ], + model="gpt-4o", + ), + CompletionCreateParamsNonStreaming, ), ), cast_to=httpx.Response, @@ -750,14 +755,17 @@ def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter) -> Non "/chat/completions", body=cast( object, - dict( - messages=[ - { - "role": "user", - "content": "Say this is a test", - } - ], - model="gpt-4o", + maybe_transform( + dict( + messages=[ + { + "role": "user", + "content": "Say this is a test", + } + ], + model="gpt-4o", + ), + CompletionCreateParamsNonStreaming, ), ), cast_to=httpx.Response, @@ -1591,14 +1599,17 @@ async def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter) "/chat/completions", body=cast( object, - dict( - messages=[ - { - "role": "user", - "content": "Say this is a test", - } - ], - model="gpt-4o", + maybe_transform( + dict( + messages=[ + { + "role": "user", + "content": "Say this is a test", + } + ], + model="gpt-4o", + ), + CompletionCreateParamsNonStreaming, ), ), cast_to=httpx.Response, @@ -1617,14 +1628,17 @@ async def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter) "/chat/completions", body=cast( object, - dict( - messages=[ - { - "role": "user", - "content": "Say this is a test", - } - ], - model="gpt-4o", + maybe_transform( + dict( + messages=[ + { + "role": "user", + "content": "Say this is a test", + } + ], + model="gpt-4o", + ), + CompletionCreateParamsNonStreaming, ), ), cast_to=httpx.Response, From 720ae54414f392202289578c9cc3b84cccc7432c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 13 Feb 2025 19:45:55 +0000 Subject: [PATCH 202/769] release: 1.63.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index ccd8ea8be5..7b243c5918 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.62.0" + ".": "1.63.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 583fbd9add..361effb558 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.63.0 (2025-02-13) + +Full Changelog: [v1.62.0...v1.63.0](https://github.com/openai/openai-python/compare/v1.62.0...v1.63.0) + +### Features + +* **api:** add support for storing chat completions ([#2117](https://github.com/openai/openai-python/issues/2117)) ([2357a8f](https://github.com/openai/openai-python/commit/2357a8f97246a3fe17c6ac1fb0d7a67d6f1ffc1d)) + ## 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) diff --git a/pyproject.toml b/pyproject.toml index 85cb145673..fed9f20ab3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.62.0" +version = "1.63.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 7dd5163b53..f58a5a5da8 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.62.0" # x-release-please-version +__version__ = "1.63.0" # x-release-please-version From a942394481e58a6f8b4a21f1b75af1ca6fcfd809 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 14 Feb 2025 11:11:51 +0000 Subject: [PATCH 203/769] chore(internal): temporary commit (#2121) --- .github/ISSUE_TEMPLATE/bug_report.yml | 64 ---------------------- .github/ISSUE_TEMPLATE/config.yml | 7 --- .github/ISSUE_TEMPLATE/feature_request.yml | 28 ---------- .github/pull_request_template.md | 10 ---- 4 files changed, 109 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml delete mode 100644 .github/ISSUE_TEMPLATE/config.yml delete mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml delete mode 100644 .github/pull_request_template.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml deleted file mode 100644 index fa09dbe5b0..0000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ /dev/null @@ -1,64 +0,0 @@ -name: Bug report -description: Report an issue or bug with this library -labels: ['bug'] -body: - - type: markdown - attributes: - value: | - Thanks for taking the time to fill out this bug report! - - type: checkboxes - id: non_api - attributes: - label: Confirm this is an issue with the Python library and not an underlying OpenAI API - description: Issues with the underlying OpenAI API should be reported on our [Developer Community](https://community.openai.com/c/api/7) - options: - - label: This is an issue with the Python library - required: true - - type: textarea - id: what-happened - attributes: - label: Describe the bug - description: A clear and concise description of what the bug is, and any additional context. - placeholder: Tell us what you see! - validations: - required: true - - type: textarea - id: repro-steps - attributes: - label: To Reproduce - description: Steps to reproduce the behavior. - placeholder: | - 1. Fetch a '...' - 2. Update the '....' - 3. See error - validations: - required: true - - type: textarea - id: code-snippets - attributes: - label: Code snippets - description: If applicable, add code snippets to help explain your problem. - render: Python - validations: - required: false - - type: input - id: os - attributes: - label: OS - placeholder: macOS - validations: - required: true - - type: input - id: language-version - attributes: - label: Python version - placeholder: Python v3.11.4 - validations: - required: true - - type: input - id: lib-version - attributes: - label: Library version - placeholder: openai v1.0.1 - validations: - required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index 0498cf7f6f..0000000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,7 +0,0 @@ -blank_issues_enabled: false -contact_links: - - name: OpenAI support - url: https://help.openai.com/ - about: | - Please only file issues here that you believe represent actual bugs or feature requests for the OpenAI Python library. - If you're having general trouble with the OpenAI API, please visit our help center to get support. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml deleted file mode 100644 index b529547d08..0000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: Feature request -description: Suggest an idea for this library -labels: ['feature-request'] -body: - - type: markdown - attributes: - value: | - Thanks for taking the time to fill out this feature request! - - type: checkboxes - id: non_api - attributes: - label: Confirm this is a feature request for the Python library and not the underlying OpenAI API. - description: Feature requests for the underlying OpenAI API should be reported on our [Developer Community](https://community.openai.com/c/api/7) - options: - - label: This is a feature request for the Python library - required: true - - type: textarea - id: feature - attributes: - label: Describe the feature or improvement you're requesting - description: A clear and concise description of what you want to happen. - validations: - required: true - - type: textarea - id: context - attributes: - label: Additional context - description: Add any other context about the feature request here. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md deleted file mode 100644 index 4416b1e547..0000000000 --- a/.github/pull_request_template.md +++ /dev/null @@ -1,10 +0,0 @@ - - - - - -- [ ] I understand that this repository is auto-generated and my pull request may not be merged - -## Changes being requested - -## Additional context & links From fea5e6b0dbc4353fcd35d5fcf11273347c4ee110 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 17 Feb 2025 05:04:23 +0000 Subject: [PATCH 204/769] release: 1.63.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 7b243c5918..d9c83dfafb 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.63.0" + ".": "1.63.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 361effb558..1bcb96c22c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.63.1 (2025-02-17) + +Full Changelog: [v1.63.0...v1.63.1](https://github.com/openai/openai-python/compare/v1.63.0...v1.63.1) + +### Chores + +* **internal:** temporary commit ([#2121](https://github.com/openai/openai-python/issues/2121)) ([f7f8361](https://github.com/openai/openai-python/commit/f7f83614c8da84c6725d60936f08f9f1a65f0a9e)) + ## 1.63.0 (2025-02-13) Full Changelog: [v1.62.0...v1.63.0](https://github.com/openai/openai-python/compare/v1.62.0...v1.63.0) diff --git a/pyproject.toml b/pyproject.toml index fed9f20ab3..0e90c2cad7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.63.0" +version = "1.63.1" 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 f58a5a5da8..1d08feda0d 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.63.0" # x-release-please-version +__version__ = "1.63.1" # x-release-please-version From 7319e6e3f139d68173e03033f077732c4c4bdfa5 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Mon, 17 Feb 2025 13:08:59 +0000 Subject: [PATCH 205/769] chore(internal): revert temporary commit (#2121) --- .github/ISSUE_TEMPLATE/bug_report.yml | 64 ++++++++++++++++++++++ .github/ISSUE_TEMPLATE/config.yml | 7 +++ .github/ISSUE_TEMPLATE/feature_request.yml | 28 ++++++++++ .github/pull_request_template.md | 10 ++++ 4 files changed, 109 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml create mode 100644 .github/pull_request_template.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000000..fa09dbe5b0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,64 @@ +name: Bug report +description: Report an issue or bug with this library +labels: ['bug'] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! + - type: checkboxes + id: non_api + attributes: + label: Confirm this is an issue with the Python library and not an underlying OpenAI API + description: Issues with the underlying OpenAI API should be reported on our [Developer Community](https://community.openai.com/c/api/7) + options: + - label: This is an issue with the Python library + required: true + - type: textarea + id: what-happened + attributes: + label: Describe the bug + description: A clear and concise description of what the bug is, and any additional context. + placeholder: Tell us what you see! + validations: + required: true + - type: textarea + id: repro-steps + attributes: + label: To Reproduce + description: Steps to reproduce the behavior. + placeholder: | + 1. Fetch a '...' + 2. Update the '....' + 3. See error + validations: + required: true + - type: textarea + id: code-snippets + attributes: + label: Code snippets + description: If applicable, add code snippets to help explain your problem. + render: Python + validations: + required: false + - type: input + id: os + attributes: + label: OS + placeholder: macOS + validations: + required: true + - type: input + id: language-version + attributes: + label: Python version + placeholder: Python v3.11.4 + validations: + required: true + - type: input + id: lib-version + attributes: + label: Library version + placeholder: openai v1.0.1 + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000..0498cf7f6f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,7 @@ +blank_issues_enabled: false +contact_links: + - name: OpenAI support + url: https://help.openai.com/ + about: | + Please only file issues here that you believe represent actual bugs or feature requests for the OpenAI Python library. + If you're having general trouble with the OpenAI API, please visit our help center to get support. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000000..b529547d08 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,28 @@ +name: Feature request +description: Suggest an idea for this library +labels: ['feature-request'] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this feature request! + - type: checkboxes + id: non_api + attributes: + label: Confirm this is a feature request for the Python library and not the underlying OpenAI API. + description: Feature requests for the underlying OpenAI API should be reported on our [Developer Community](https://community.openai.com/c/api/7) + options: + - label: This is a feature request for the Python library + required: true + - type: textarea + id: feature + attributes: + label: Describe the feature or improvement you're requesting + description: A clear and concise description of what you want to happen. + validations: + required: true + - type: textarea + id: context + attributes: + label: Additional context + description: Add any other context about the feature request here. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000000..4416b1e547 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,10 @@ + + + + + +- [ ] I understand that this repository is auto-generated and my pull request may not be merged + +## Changes being requested + +## Additional context & links From 2e56c8da6f163db00a4ca362020148bb391edca9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 17 Feb 2025 13:09:50 +0000 Subject: [PATCH 206/769] release: 1.63.2 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index d9c83dfafb..a9866d99a2 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.63.1" + ".": "1.63.2" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bcb96c22c..7ed87c5875 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.63.2 (2025-02-17) + +Full Changelog: [v1.63.1...v1.63.2](https://github.com/openai/openai-python/compare/v1.63.1...v1.63.2) + +### Chores + +* **internal:** revert temporary commit ([#2121](https://github.com/openai/openai-python/issues/2121)) ([72458ab](https://github.com/openai/openai-python/commit/72458abeed3dd95db8aabed94a33bb12a916f8b7)) + ## 1.63.1 (2025-02-17) Full Changelog: [v1.63.0...v1.63.1](https://github.com/openai/openai-python/compare/v1.63.0...v1.63.1) diff --git a/pyproject.toml b/pyproject.toml index 0e90c2cad7..453b3cea33 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.63.1" +version = "1.63.2" 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 1d08feda0d..1f57a6db7e 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.63.1" # x-release-please-version +__version__ = "1.63.2" # x-release-please-version From 7cc9c9e95511e9d94f3e5ba913bf79623477e10d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 20 Feb 2025 22:37:49 +0000 Subject: [PATCH 207/769] feat(client): allow passing `NotGiven` for body (#2135) fix(client): mark some request bodies as optional --- src/openai/_base_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index 8a408d8e58..94a5edd010 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -520,7 +520,7 @@ def _build_request( # so that passing a `TypedDict` doesn't cause an error. # https://github.com/microsoft/pyright/issues/3526#event-6715453066 params=self.qs.stringify(cast(Mapping[str, Any], params)) if params else None, - json=json_data, + json=json_data if is_given(json_data) else None, files=files, **kwargs, ) From fe9eb8d1d4c2232aab342e7ae068319e255bf685 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 21 Feb 2025 15:08:25 +0000 Subject: [PATCH 208/769] chore(internal): fix devcontainers setup (#2137) --- .devcontainer/Dockerfile | 2 +- .devcontainer/devcontainer.json | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index ac9a2e7521..55d20255c9 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -6,4 +6,4 @@ USER vscode RUN curl -sSf https://rye.astral.sh/get | RYE_VERSION="0.35.0" RYE_INSTALL_OPTION="--yes" bash ENV PATH=/home/vscode/.rye/shims:$PATH -RUN echo "[[ -d .venv ]] && source .venv/bin/activate" >> /home/vscode/.bashrc +RUN echo "[[ -d .venv ]] && source .venv/bin/activate || export PATH=\$PATH" >> /home/vscode/.bashrc diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index bbeb30b148..c17fdc169f 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -24,6 +24,9 @@ } } } + }, + "features": { + "ghcr.io/devcontainers/features/node:1": {} } // Features to add to the dev container. More info: https://containers.dev/features. From 3e69750d47df4f0759d4a28ddc68e4b38756d9ca Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 22 Feb 2025 05:03:56 +0000 Subject: [PATCH 209/769] release: 1.64.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 18 ++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index a9866d99a2..7ef7bb772e 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.63.2" + ".": "1.64.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ed87c5875..1aa32a14bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ # Changelog +## 1.64.0 (2025-02-22) + +Full Changelog: [v1.63.2...v1.64.0](https://github.com/openai/openai-python/compare/v1.63.2...v1.64.0) + +### Features + +* **client:** allow passing `NotGiven` for body ([#2135](https://github.com/openai/openai-python/issues/2135)) ([4451f56](https://github.com/openai/openai-python/commit/4451f5677f9eaad9b8fee74f71c2e5fe6785c420)) + + +### Bug Fixes + +* **client:** mark some request bodies as optional ([4451f56](https://github.com/openai/openai-python/commit/4451f5677f9eaad9b8fee74f71c2e5fe6785c420)) + + +### Chores + +* **internal:** fix devcontainers setup ([#2137](https://github.com/openai/openai-python/issues/2137)) ([4d88402](https://github.com/openai/openai-python/commit/4d884020cbeb1ca6093dd5317e3e5812551f7a46)) + ## 1.63.2 (2025-02-17) Full Changelog: [v1.63.1...v1.63.2](https://github.com/openai/openai-python/compare/v1.63.1...v1.63.2) diff --git a/pyproject.toml b/pyproject.toml index 453b3cea33..7cd583da3f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.63.2" +version = "1.64.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 1f57a6db7e..0a898ceeb8 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.63.2" # x-release-please-version +__version__ = "1.64.0" # x-release-please-version From 5bde5722f18e778abb896f9434fd52f0c4284e0a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 25 Feb 2025 11:04:28 +0000 Subject: [PATCH 210/769] chore(internal): properly set __pydantic_private__ (#2144) --- src/openai/_base_client.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index 94a5edd010..43dc9ab2a4 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -63,7 +63,7 @@ ModelBuilderProtocol, ) from ._utils import SensitiveHeadersFilter, is_dict, is_list, asyncify, is_given, lru_cache, is_mapping -from ._compat import model_copy, model_dump +from ._compat import PYDANTIC_V2, model_copy, model_dump from ._models import GenericModel, FinalRequestOptions, validate_type, construct_type from ._response import ( APIResponse, @@ -209,6 +209,9 @@ def _set_private_attributes( model: Type[_T], options: FinalRequestOptions, ) -> None: + if PYDANTIC_V2 and getattr(self, "__pydantic_private__", None) is None: + self.__pydantic_private__ = {} + self._model = model self._client = client self._options = options @@ -294,6 +297,9 @@ def _set_private_attributes( client: AsyncAPIClient, options: FinalRequestOptions, ) -> None: + if PYDANTIC_V2 and getattr(self, "__pydantic_private__", None) is None: + self.__pydantic_private__ = {} + self._model = model self._client = client self._options = options From 0c62bebe59c93921035459c77719d3d8ae23d0f5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 27 Feb 2025 20:05:36 +0000 Subject: [PATCH 211/769] feat(api): add gpt-4.5-preview (#2149) --- .stats.yml | 2 +- src/openai/resources/beta/assistants.py | 4 +++ .../resources/beta/realtime/realtime.py | 36 +++++++++++-------- .../types/beta/assistant_update_params.py | 2 ++ src/openai/types/beta/realtime/session.py | 14 ++++++++ .../beta/realtime/session_create_params.py | 10 +++++- .../beta/realtime/session_update_event.py | 10 +++++- .../realtime/session_update_event_param.py | 10 +++++- src/openai/types/chat_model.py | 2 ++ src/openai/types/file_object.py | 3 ++ src/openai/types/upload.py | 2 +- .../beta/realtime/test_sessions.py | 2 ++ 12 files changed, 77 insertions(+), 20 deletions(-) diff --git a/.stats.yml b/.stats.yml index 658877d3b0..163146e38d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 74 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-4aa6ee65ba9efc789e05e6a5ef0883b2cadf06def8efd863dbf75e9e233067e1.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-5d30684c3118d049682ea30cdb4dbef39b97d51667da484689193dc40162af32.yml diff --git a/src/openai/resources/beta/assistants.py b/src/openai/resources/beta/assistants.py index 462086f74b..d2bb8d7b92 100644 --- a/src/openai/resources/beta/assistants.py +++ b/src/openai/resources/beta/assistants.py @@ -232,6 +232,8 @@ def update( "gpt-4o-2024-05-13", "gpt-4o-mini", "gpt-4o-mini-2024-07-18", + "gpt-4.5-preview", + "gpt-4.5-preview-2025-02-27", "gpt-4-turbo", "gpt-4-turbo-2024-04-09", "gpt-4-0125-preview", @@ -673,6 +675,8 @@ async def update( "gpt-4o-2024-05-13", "gpt-4o-mini", "gpt-4o-mini-2024-07-18", + "gpt-4.5-preview", + "gpt-4.5-preview-2025-02-27", "gpt-4-turbo", "gpt-4-turbo-2024-04-09", "gpt-4-0125-preview", diff --git a/src/openai/resources/beta/realtime/realtime.py b/src/openai/resources/beta/realtime/realtime.py index 235790a9f5..0cf7c85799 100644 --- a/src/openai/resources/beta/realtime/realtime.py +++ b/src/openai/resources/beta/realtime/realtime.py @@ -561,14 +561,17 @@ def __init__(self, connection: RealtimeConnection) -> None: class RealtimeSessionResource(BaseRealtimeConnectionResource): def update(self, *, session: session_update_event_param.Session, event_id: str | NotGiven = NOT_GIVEN) -> None: - """Send this event to update the session’s default configuration. + """ + Send this event to update the session’s default configuration. + The client may send this event at any time to update any field, + except for `voice`. However, note that once a session has been + initialized with a particular `model`, it can’t be changed to + another model using `session.update`. - The client may - send this event at any time to update the session configuration, and any - field may be updated at any time, except for "voice". The server will respond - with a `session.updated` event that shows the full effective configuration. - Only fields that are present are updated, thus the correct way to clear a - field like "instructions" is to pass an empty string. + When the server receives a `session.update`, it will respond + with a `session.updated` event showing the full, effective configuration. + Only the fields that are present are updated. To clear a field like + `instructions`, pass an empty string. """ self._connection.send( cast( @@ -768,14 +771,17 @@ class AsyncRealtimeSessionResource(BaseAsyncRealtimeConnectionResource): async def update( self, *, session: session_update_event_param.Session, event_id: str | NotGiven = NOT_GIVEN ) -> None: - """Send this event to update the session’s default configuration. - - The client may - send this event at any time to update the session configuration, and any - field may be updated at any time, except for "voice". The server will respond - with a `session.updated` event that shows the full effective configuration. - Only fields that are present are updated, thus the correct way to clear a - field like "instructions" is to pass an empty string. + """ + Send this event to update the session’s default configuration. + The client may send this event at any time to update any field, + except for `voice`. However, note that once a session has been + initialized with a particular `model`, it can’t be changed to + another model using `session.update`. + + When the server receives a `session.update`, it will respond + with a `session.updated` event showing the full, effective configuration. + Only the fields that are present are updated. To clear a field like + `instructions`, pass an empty string. """ await self._connection.send( cast( diff --git a/src/openai/types/beta/assistant_update_params.py b/src/openai/types/beta/assistant_update_params.py index 80fec110cd..12a57a4063 100644 --- a/src/openai/types/beta/assistant_update_params.py +++ b/src/openai/types/beta/assistant_update_params.py @@ -45,6 +45,8 @@ class AssistantUpdateParams(TypedDict, total=False): "gpt-4o-2024-05-13", "gpt-4o-mini", "gpt-4o-mini-2024-07-18", + "gpt-4.5-preview", + "gpt-4.5-preview-2025-02-27", "gpt-4-turbo", "gpt-4-turbo-2024-04-09", "gpt-4-0125-preview", diff --git a/src/openai/types/beta/realtime/session.py b/src/openai/types/beta/realtime/session.py index 2d028f817c..aee20fa906 100644 --- a/src/openai/types/beta/realtime/session.py +++ b/src/openai/types/beta/realtime/session.py @@ -34,6 +34,20 @@ class Tool(BaseModel): class TurnDetection(BaseModel): + create_response: Optional[bool] = None + """Whether or not to automatically generate a response when a VAD stop event + occurs. + + `true` by default. + """ + + interrupt_response: Optional[bool] = None + """ + Whether or not to automatically interrupt any ongoing response with output to + the default conversation (i.e. `conversation` of `auto`) when a VAD start event + occurs. `true` by default. + """ + prefix_padding_ms: Optional[int] = None """Amount of audio to include before the VAD detected speech (in milliseconds). diff --git a/src/openai/types/beta/realtime/session_create_params.py b/src/openai/types/beta/realtime/session_create_params.py index 1502d83d39..bbc86d7c7d 100644 --- a/src/openai/types/beta/realtime/session_create_params.py +++ b/src/openai/types/beta/realtime/session_create_params.py @@ -146,11 +146,19 @@ class Tool(TypedDict, total=False): class TurnDetection(TypedDict, total=False): create_response: bool - """Whether or not to automatically generate a response when VAD is enabled. + """Whether or not to automatically generate a response when a VAD stop event + occurs. `true` by default. """ + interrupt_response: bool + """ + Whether or not to automatically interrupt any ongoing response with output to + the default conversation (i.e. `conversation` of `auto`) when a VAD start event + occurs. `true` by default. + """ + prefix_padding_ms: int """Amount of audio to include before the VAD detected speech (in milliseconds). diff --git a/src/openai/types/beta/realtime/session_update_event.py b/src/openai/types/beta/realtime/session_update_event.py index 62fb0a3998..999cd8d660 100644 --- a/src/openai/types/beta/realtime/session_update_event.py +++ b/src/openai/types/beta/realtime/session_update_event.py @@ -51,11 +51,19 @@ class SessionTool(BaseModel): class SessionTurnDetection(BaseModel): create_response: Optional[bool] = None - """Whether or not to automatically generate a response when VAD is enabled. + """Whether or not to automatically generate a response when a VAD stop event + occurs. `true` by default. """ + interrupt_response: Optional[bool] = None + """ + Whether or not to automatically interrupt any ongoing response with output to + the default conversation (i.e. `conversation` of `auto`) when a VAD start event + occurs. `true` by default. + """ + prefix_padding_ms: Optional[int] = None """Amount of audio to include before the VAD detected speech (in milliseconds). diff --git a/src/openai/types/beta/realtime/session_update_event_param.py b/src/openai/types/beta/realtime/session_update_event_param.py index 133cdd91a1..07fdba9d85 100644 --- a/src/openai/types/beta/realtime/session_update_event_param.py +++ b/src/openai/types/beta/realtime/session_update_event_param.py @@ -57,11 +57,19 @@ class SessionTool(TypedDict, total=False): class SessionTurnDetection(TypedDict, total=False): create_response: bool - """Whether or not to automatically generate a response when VAD is enabled. + """Whether or not to automatically generate a response when a VAD stop event + occurs. `true` by default. """ + interrupt_response: bool + """ + Whether or not to automatically interrupt any ongoing response with output to + the default conversation (i.e. `conversation` of `auto`) when a VAD start event + occurs. `true` by default. + """ + prefix_padding_ms: int """Amount of audio to include before the VAD detected speech (in milliseconds). diff --git a/src/openai/types/chat_model.py b/src/openai/types/chat_model.py index c191cb9734..6fe705a0b4 100644 --- a/src/openai/types/chat_model.py +++ b/src/openai/types/chat_model.py @@ -13,6 +13,8 @@ "o1-preview-2024-09-12", "o1-mini", "o1-mini-2024-09-12", + "gpt-4.5-preview", + "gpt-4.5-preview-2025-02-27", "gpt-4o", "gpt-4o-2024-11-20", "gpt-4o-2024-08-06", diff --git a/src/openai/types/file_object.py b/src/openai/types/file_object.py index 6e2bf310a4..1d65e6987d 100644 --- a/src/openai/types/file_object.py +++ b/src/openai/types/file_object.py @@ -40,6 +40,9 @@ class FileObject(BaseModel): `error`. """ + expires_at: Optional[int] = None + """The Unix timestamp (in seconds) for when the file will expire.""" + status_details: Optional[str] = None """Deprecated. diff --git a/src/openai/types/upload.py b/src/openai/types/upload.py index d8108c62f9..914b69a863 100644 --- a/src/openai/types/upload.py +++ b/src/openai/types/upload.py @@ -20,7 +20,7 @@ class Upload(BaseModel): """The Unix timestamp (in seconds) for when the Upload was created.""" expires_at: int - """The Unix timestamp (in seconds) for when the Upload was created.""" + """The Unix timestamp (in seconds) for when the Upload will expire.""" filename: str """The name of the file to be uploaded.""" diff --git a/tests/api_resources/beta/realtime/test_sessions.py b/tests/api_resources/beta/realtime/test_sessions.py index 5a17088ce6..5ea308ca0d 100644 --- a/tests/api_resources/beta/realtime/test_sessions.py +++ b/tests/api_resources/beta/realtime/test_sessions.py @@ -48,6 +48,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: ], turn_detection={ "create_response": True, + "interrupt_response": True, "prefix_padding_ms": 0, "silence_duration_ms": 0, "threshold": 0, @@ -112,6 +113,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> ], turn_detection={ "create_response": True, + "interrupt_response": True, "prefix_padding_ms": 0, "silence_duration_ms": 0, "threshold": 0, From 939c861263b2b6ed2d086b794261766ddf5b5f65 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 27 Feb 2025 20:07:02 +0000 Subject: [PATCH 212/769] release: 1.65.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 7ef7bb772e..045e3819b6 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.64.0" + ".": "1.65.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 1aa32a14bd..f6190ab04e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 1.65.0 (2025-02-27) + +Full Changelog: [v1.64.0...v1.65.0](https://github.com/openai/openai-python/compare/v1.64.0...v1.65.0) + +### Features + +* **api:** add gpt-4.5-preview ([#2149](https://github.com/openai/openai-python/issues/2149)) ([4cee52e](https://github.com/openai/openai-python/commit/4cee52e8d191b0532f28d86446da79b43a58b907)) + + +### Chores + +* **internal:** properly set __pydantic_private__ ([#2144](https://github.com/openai/openai-python/issues/2144)) ([2b1bd16](https://github.com/openai/openai-python/commit/2b1bd1604a038ded67367742a0b1c9d92e29dfc8)) + ## 1.64.0 (2025-02-22) Full Changelog: [v1.63.2...v1.64.0](https://github.com/openai/openai-python/compare/v1.63.2...v1.64.0) diff --git a/pyproject.toml b/pyproject.toml index 7cd583da3f..511da522a7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.64.0" +version = "1.65.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 0a898ceeb8..31af749758 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.64.0" # x-release-please-version +__version__ = "1.65.0" # x-release-please-version From 06d79fd2cc1edea9af81c8ba4304eefdd1195fc7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 27 Feb 2025 22:01:07 +0000 Subject: [PATCH 213/769] docs: update URLs from stainlessapi.com to stainless.com (#2150) More details at https://www.stainless.com/changelog/stainless-com --- SECURITY.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index c54acaf331..3b3bd8a662 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,9 +2,9 @@ ## Reporting Security Issues -This SDK is generated by [Stainless Software Inc](http://stainlessapi.com). Stainless takes security seriously, and encourages you to report any security vulnerability promptly so that appropriate action can be taken. +This SDK is generated by [Stainless Software Inc](http://stainless.com). Stainless takes security seriously, and encourages you to report any security vulnerability promptly so that appropriate action can be taken. -To report a security issue, please contact the Stainless team at security@stainlessapi.com. +To report a security issue, please contact the Stainless team at security@stainless.com. ## Responsible Disclosure From 724f56c56487578692bec45fca79474e57516308 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 27 Feb 2025 22:01:57 +0000 Subject: [PATCH 214/769] release: 1.65.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 045e3819b6..57b589ea9e 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.65.0" + ".": "1.65.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index f6190ab04e..ac6f54aa21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.65.1 (2025-02-27) + +Full Changelog: [v1.65.0...v1.65.1](https://github.com/openai/openai-python/compare/v1.65.0...v1.65.1) + +### Documentation + +* update URLs from stainlessapi.com to stainless.com ([#2150](https://github.com/openai/openai-python/issues/2150)) ([dee4298](https://github.com/openai/openai-python/commit/dee42986eff46dd23ba25b3e2a5bb7357aca39d9)) + ## 1.65.0 (2025-02-27) Full Changelog: [v1.64.0...v1.65.0](https://github.com/openai/openai-python/compare/v1.64.0...v1.65.0) diff --git a/pyproject.toml b/pyproject.toml index 511da522a7..13bd84e4f4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.65.0" +version = "1.65.1" 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 31af749758..422c9a283d 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.65.0" # x-release-please-version +__version__ = "1.65.1" # x-release-please-version From ba2a8a0953c41dc1364221a2009f2a942e4d6f35 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 27 Feb 2025 22:51:14 +0000 Subject: [PATCH 215/769] chore(docs): update client docstring (#2152) --- src/openai/_client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/openai/_client.py b/src/openai/_client.py index c784694f20..2464c6504c 100644 --- a/src/openai/_client.py +++ b/src/openai/_client.py @@ -97,7 +97,7 @@ def __init__( # part of our public interface in the future. _strict_response_validation: bool = False, ) -> None: - """Construct a new synchronous openai client instance. + """Construct a new synchronous OpenAI client instance. This automatically infers the following arguments from their corresponding environment variables if they are not provided: - `api_key` from `OPENAI_API_KEY` @@ -324,7 +324,7 @@ def __init__( # part of our public interface in the future. _strict_response_validation: bool = False, ) -> None: - """Construct a new async openai client instance. + """Construct a new async AsyncOpenAI client instance. This automatically infers the following arguments from their corresponding environment variables if they are not provided: - `api_key` from `OPENAI_API_KEY` From c98d7400785011e0f5de2e33c9bf4dec95332847 Mon Sep 17 00:00:00 2001 From: Krista Pratico Date: Fri, 28 Feb 2025 06:36:08 -0800 Subject: [PATCH 216/769] fix(azure): azure_deployment use with realtime + non-deployment-based APIs (#2154) * support realtime with azure_deployment * lint * use rsplit * switch approach: save copy of the original url * save azure_endpoint as it was given * docstring * format * remove unnecessary check + add test * fix for websocket_base_url * add another test --- src/openai/lib/azure.py | 67 ++- .../resources/beta/realtime/realtime.py | 36 +- tests/lib/test_azure.py | 563 ++++++++++++++++++ 3 files changed, 637 insertions(+), 29 deletions(-) diff --git a/src/openai/lib/azure.py b/src/openai/lib/azure.py index f857d76e51..ea7bd20d99 100644 --- a/src/openai/lib/azure.py +++ b/src/openai/lib/azure.py @@ -49,6 +49,9 @@ def __init__(self) -> None: class BaseAzureClient(BaseClient[_HttpxClientT, _DefaultStreamT]): + _azure_endpoint: httpx.URL | None + _azure_deployment: str | None + @override def _build_request( self, @@ -58,11 +61,29 @@ def _build_request( ) -> httpx.Request: if options.url in _deployments_endpoints and is_mapping(options.json_data): model = options.json_data.get("model") - if model is not None and not "/deployments" in str(self.base_url): + if model is not None and "/deployments" not in str(self.base_url.path): options.url = f"/deployments/{model}{options.url}" return super()._build_request(options, retries_taken=retries_taken) + @override + def _prepare_url(self, url: str) -> httpx.URL: + """Adjust the URL if the client was configured with an Azure endpoint + deployment + and the API feature being called is **not** a deployments-based endpoint + (i.e. requires /deployments/deployment-name in the URL path). + """ + if self._azure_deployment and self._azure_endpoint and url not in _deployments_endpoints: + merge_url = httpx.URL(url) + if merge_url.is_relative_url: + merge_raw_path = ( + self._azure_endpoint.raw_path.rstrip(b"/") + b"/openai/" + merge_url.raw_path.lstrip(b"/") + ) + return self._azure_endpoint.copy_with(raw_path=merge_raw_path) + + return merge_url + + return super()._prepare_url(url) + class AzureOpenAI(BaseAzureClient[httpx.Client, Stream[Any]], OpenAI): @overload @@ -160,8 +181,8 @@ def __init__( azure_ad_token_provider: A function that returns an Azure Active Directory token, will be invoked on every request. - azure_deployment: A model deployment, if given sets the base client URL to include `/deployments/{azure_deployment}`. - Note: this means you won't be able to use non-deployment endpoints. Not supported with Assistants APIs. + azure_deployment: A model deployment, if given with `azure_endpoint`, sets the base client URL to include `/deployments/{azure_deployment}`. + Not supported with Assistants APIs. """ if api_key is None: api_key = os.environ.get("AZURE_OPENAI_API_KEY") @@ -224,6 +245,8 @@ def __init__( self._api_version = api_version self._azure_ad_token = azure_ad_token self._azure_ad_token_provider = azure_ad_token_provider + self._azure_deployment = azure_deployment if azure_endpoint else None + self._azure_endpoint = httpx.URL(azure_endpoint) if azure_endpoint else None @override def copy( @@ -307,12 +330,12 @@ def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOptions: return options - def _configure_realtime(self, model: str, extra_query: Query) -> tuple[Query, dict[str, str]]: + def _configure_realtime(self, model: str, extra_query: Query) -> tuple[httpx.URL, dict[str, str]]: auth_headers = {} query = { **extra_query, "api-version": self._api_version, - "deployment": model, + "deployment": self._azure_deployment or model, } if self.api_key != "": auth_headers = {"api-key": self.api_key} @@ -320,7 +343,17 @@ def _configure_realtime(self, model: str, extra_query: Query) -> tuple[Query, di token = self._get_azure_ad_token() if token: auth_headers = {"Authorization": f"Bearer {token}"} - return query, auth_headers + + if self.websocket_base_url is not None: + base_url = httpx.URL(self.websocket_base_url) + merge_raw_path = base_url.raw_path.rstrip(b"/") + b"/realtime" + realtime_url = base_url.copy_with(raw_path=merge_raw_path) + else: + base_url = self._prepare_url("/realtime") + realtime_url = base_url.copy_with(scheme="wss") + + url = realtime_url.copy_with(params={**query}) + return url, auth_headers class AsyncAzureOpenAI(BaseAzureClient[httpx.AsyncClient, AsyncStream[Any]], AsyncOpenAI): @@ -422,8 +455,8 @@ def __init__( azure_ad_token_provider: A function that returns an Azure Active Directory token, will be invoked on every request. - azure_deployment: A model deployment, if given sets the base client URL to include `/deployments/{azure_deployment}`. - Note: this means you won't be able to use non-deployment endpoints. Not supported with Assistants APIs. + azure_deployment: A model deployment, if given with `azure_endpoint`, sets the base client URL to include `/deployments/{azure_deployment}`. + Not supported with Assistants APIs. """ if api_key is None: api_key = os.environ.get("AZURE_OPENAI_API_KEY") @@ -486,6 +519,8 @@ def __init__( self._api_version = api_version self._azure_ad_token = azure_ad_token self._azure_ad_token_provider = azure_ad_token_provider + self._azure_deployment = azure_deployment if azure_endpoint else None + self._azure_endpoint = httpx.URL(azure_endpoint) if azure_endpoint else None @override def copy( @@ -571,12 +606,12 @@ async def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOp return options - async def _configure_realtime(self, model: str, extra_query: Query) -> tuple[Query, dict[str, str]]: + async def _configure_realtime(self, model: str, extra_query: Query) -> tuple[httpx.URL, dict[str, str]]: auth_headers = {} query = { **extra_query, "api-version": self._api_version, - "deployment": model, + "deployment": self._azure_deployment or model, } if self.api_key != "": auth_headers = {"api-key": self.api_key} @@ -584,4 +619,14 @@ async def _configure_realtime(self, model: str, extra_query: Query) -> tuple[Que token = await self._get_azure_ad_token() if token: auth_headers = {"Authorization": f"Bearer {token}"} - return query, auth_headers + + if self.websocket_base_url is not None: + base_url = httpx.URL(self.websocket_base_url) + merge_raw_path = base_url.raw_path.rstrip(b"/") + b"/realtime" + realtime_url = base_url.copy_with(raw_path=merge_raw_path) + else: + base_url = self._prepare_url("/realtime") + realtime_url = base_url.copy_with(scheme="wss") + + url = realtime_url.copy_with(params={**query}) + return url, auth_headers diff --git a/src/openai/resources/beta/realtime/realtime.py b/src/openai/resources/beta/realtime/realtime.py index 0cf7c85799..cd610d9089 100644 --- a/src/openai/resources/beta/realtime/realtime.py +++ b/src/openai/resources/beta/realtime/realtime.py @@ -324,15 +324,15 @@ async def __aenter__(self) -> AsyncRealtimeConnection: extra_query = self.__extra_query auth_headers = self.__client.auth_headers if is_async_azure_client(self.__client): - extra_query, auth_headers = await self.__client._configure_realtime(self.__model, extra_query) - - url = self._prepare_url().copy_with( - params={ - **self.__client.base_url.params, - "model": self.__model, - **extra_query, - }, - ) + url, auth_headers = await self.__client._configure_realtime(self.__model, extra_query) + else: + url = self._prepare_url().copy_with( + params={ + **self.__client.base_url.params, + "model": self.__model, + **extra_query, + }, + ) log.debug("Connecting to %s", url) if self.__websocket_connection_options: log.debug("Connection options: %s", self.__websocket_connection_options) @@ -506,15 +506,15 @@ def __enter__(self) -> RealtimeConnection: extra_query = self.__extra_query auth_headers = self.__client.auth_headers if is_azure_client(self.__client): - extra_query, auth_headers = self.__client._configure_realtime(self.__model, extra_query) - - url = self._prepare_url().copy_with( - params={ - **self.__client.base_url.params, - "model": self.__model, - **extra_query, - }, - ) + url, auth_headers = self.__client._configure_realtime(self.__model, extra_query) + else: + url = self._prepare_url().copy_with( + params={ + **self.__client.base_url.params, + "model": self.__model, + **extra_query, + }, + ) log.debug("Connecting to %s", url) if self.__websocket_connection_options: log.debug("Connection options: %s", self.__websocket_connection_options) diff --git a/tests/lib/test_azure.py b/tests/lib/test_azure.py index a28aa8c2f6..52c24eba27 100644 --- a/tests/lib/test_azure.py +++ b/tests/lib/test_azure.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import logging from typing import Union, cast from typing_extensions import Literal, Protocol @@ -239,3 +241,564 @@ async def test_azure_bearer_token_redacted_async( for record in caplog.records: if is_dict(record.args) and record.args.get("headers") and is_dict(record.args["headers"]): assert record.args["headers"]["Authorization"] == "" + + +@pytest.mark.parametrize( + "client,base_url,api,json_data,expected", + [ + # Deployment-based endpoints + # AzureOpenAI: No deployment specified + ( + AzureOpenAI( + api_version="2024-02-01", + api_key="example API key", + azure_endpoint="https://example-resource.azure.openai.com", + ), + "https://example-resource.azure.openai.com/openai/", + "/chat/completions", + {"model": "deployment-body"}, + "https://example-resource.azure.openai.com/openai/deployments/deployment-body/chat/completions?api-version=2024-02-01", + ), + # AzureOpenAI: Deployment specified + ( + AzureOpenAI( + api_version="2024-02-01", + api_key="example API key", + azure_endpoint="https://example-resource.azure.openai.com", + azure_deployment="deployment-client", + ), + "https://example-resource.azure.openai.com/openai/deployments/deployment-client/", + "/chat/completions", + {"model": "deployment-body"}, + "https://example-resource.azure.openai.com/openai/deployments/deployment-client/chat/completions?api-version=2024-02-01", + ), + # AzureOpenAI: "deployments" in the DNS name + ( + AzureOpenAI( + api_version="2024-02-01", + api_key="example API key", + azure_endpoint="https://deployments.example-resource.azure.openai.com", + ), + "https://deployments.example-resource.azure.openai.com/openai/", + "/chat/completions", + {"model": "deployment-body"}, + "https://deployments.example-resource.azure.openai.com/openai/deployments/deployment-body/chat/completions?api-version=2024-02-01", + ), + # AzureOpenAI: Deployment called deployments + ( + AzureOpenAI( + api_version="2024-02-01", + api_key="example API key", + azure_endpoint="https://example-resource.azure.openai.com", + azure_deployment="deployments", + ), + "https://example-resource.azure.openai.com/openai/deployments/deployments/", + "/chat/completions", + {"model": "deployment-body"}, + "https://example-resource.azure.openai.com/openai/deployments/deployments/chat/completions?api-version=2024-02-01", + ), + # AzureOpenAI: base_url and azure_deployment specified; ignored b/c not supported + ( + AzureOpenAI( # type: ignore + api_version="2024-02-01", + api_key="example API key", + base_url="https://example.azure-api.net/PTU/", + azure_deployment="deployment-client", + ), + "https://example.azure-api.net/PTU/", + "/chat/completions", + {"model": "deployment-body"}, + "https://example.azure-api.net/PTU/deployments/deployment-body/chat/completions?api-version=2024-02-01", + ), + # AsyncAzureOpenAI: No deployment specified + ( + AsyncAzureOpenAI( + api_version="2024-02-01", + api_key="example API key", + azure_endpoint="https://example-resource.azure.openai.com", + ), + "https://example-resource.azure.openai.com/openai/", + "/chat/completions", + {"model": "deployment-body"}, + "https://example-resource.azure.openai.com/openai/deployments/deployment-body/chat/completions?api-version=2024-02-01", + ), + # AsyncAzureOpenAI: Deployment specified + ( + AsyncAzureOpenAI( + api_version="2024-02-01", + api_key="example API key", + azure_endpoint="https://example-resource.azure.openai.com", + azure_deployment="deployment-client", + ), + "https://example-resource.azure.openai.com/openai/deployments/deployment-client/", + "/chat/completions", + {"model": "deployment-body"}, + "https://example-resource.azure.openai.com/openai/deployments/deployment-client/chat/completions?api-version=2024-02-01", + ), + # AsyncAzureOpenAI: "deployments" in the DNS name + ( + AsyncAzureOpenAI( + api_version="2024-02-01", + api_key="example API key", + azure_endpoint="https://deployments.example-resource.azure.openai.com", + ), + "https://deployments.example-resource.azure.openai.com/openai/", + "/chat/completions", + {"model": "deployment-body"}, + "https://deployments.example-resource.azure.openai.com/openai/deployments/deployment-body/chat/completions?api-version=2024-02-01", + ), + # AsyncAzureOpenAI: Deployment called deployments + ( + AsyncAzureOpenAI( + api_version="2024-02-01", + api_key="example API key", + azure_endpoint="https://example-resource.azure.openai.com", + azure_deployment="deployments", + ), + "https://example-resource.azure.openai.com/openai/deployments/deployments/", + "/chat/completions", + {"model": "deployment-body"}, + "https://example-resource.azure.openai.com/openai/deployments/deployments/chat/completions?api-version=2024-02-01", + ), + # AsyncAzureOpenAI: base_url and azure_deployment specified; azure_deployment ignored b/c not supported + ( + AsyncAzureOpenAI( # type: ignore + api_version="2024-02-01", + api_key="example API key", + base_url="https://example.azure-api.net/PTU/", + azure_deployment="deployment-client", + ), + "https://example.azure-api.net/PTU/", + "/chat/completions", + {"model": "deployment-body"}, + "https://example.azure-api.net/PTU/deployments/deployment-body/chat/completions?api-version=2024-02-01", + ), + ], +) +def test_prepare_url_deployment_endpoint( + client: Client, base_url: str, api: str, json_data: dict[str, str], expected: str +) -> None: + req = client._build_request( + FinalRequestOptions.construct( + method="post", + url=api, + json_data=json_data, + ) + ) + assert req.url == expected + assert client.base_url == base_url + + +@pytest.mark.parametrize( + "client,base_url,api,json_data,expected", + [ + # Non-deployment endpoints + # AzureOpenAI: No deployment specified + ( + AzureOpenAI( + api_version="2024-02-01", + api_key="example API key", + azure_endpoint="https://example-resource.azure.openai.com", + ), + "https://example-resource.azure.openai.com/openai/", + "/models", + {}, + "https://example-resource.azure.openai.com/openai/models?api-version=2024-02-01", + ), + # AzureOpenAI: No deployment specified + ( + AzureOpenAI( + api_version="2024-02-01", + api_key="example API key", + azure_endpoint="https://example-resource.azure.openai.com", + ), + "https://example-resource.azure.openai.com/openai/", + "/assistants", + {"model": "deployment-body"}, + "https://example-resource.azure.openai.com/openai/assistants?api-version=2024-02-01", + ), + # AzureOpenAI: Deployment specified + ( + AzureOpenAI( + api_version="2024-02-01", + api_key="example API key", + azure_endpoint="https://example-resource.azure.openai.com", + azure_deployment="deployment-client", + ), + "https://example-resource.azure.openai.com/openai/deployments/deployment-client/", + "/models", + {}, + "https://example-resource.azure.openai.com/openai/models?api-version=2024-02-01", + ), + # AzureOpenAI: Deployment specified + ( + AzureOpenAI( + api_version="2024-02-01", + api_key="example API key", + azure_endpoint="https://example-resource.azure.openai.com", + azure_deployment="deployment-client", + ), + "https://example-resource.azure.openai.com/openai/deployments/deployment-client/", + "/assistants", + {"model": "deployment-body"}, + "https://example-resource.azure.openai.com/openai/assistants?api-version=2024-02-01", + ), + # AzureOpenAI: "deployments" in the DNS name + ( + AzureOpenAI( + api_version="2024-02-01", + api_key="example API key", + azure_endpoint="https://deployments.example-resource.azure.openai.com", + ), + "https://deployments.example-resource.azure.openai.com/openai/", + "/models", + {}, + "https://deployments.example-resource.azure.openai.com/openai/models?api-version=2024-02-01", + ), + # AzureOpenAI: Deployment called "deployments" + ( + AzureOpenAI( + api_version="2024-02-01", + api_key="example API key", + azure_endpoint="https://example-resource.azure.openai.com", + azure_deployment="deployments", + ), + "https://example-resource.azure.openai.com/openai/deployments/deployments/", + "/models", + {}, + "https://example-resource.azure.openai.com/openai/models?api-version=2024-02-01", + ), + # AzureOpenAI: base_url and azure_deployment specified; azure_deployment ignored b/c not supported + ( + AzureOpenAI( # type: ignore + api_version="2024-02-01", + api_key="example API key", + base_url="https://example.azure-api.net/PTU/", + azure_deployment="deployment-client", + ), + "https://example.azure-api.net/PTU/", + "/models", + {}, + "https://example.azure-api.net/PTU/models?api-version=2024-02-01", + ), + # AsyncAzureOpenAI: No deployment specified + ( + AsyncAzureOpenAI( + api_version="2024-02-01", + api_key="example API key", + azure_endpoint="https://example-resource.azure.openai.com", + ), + "https://example-resource.azure.openai.com/openai/", + "/models", + {}, + "https://example-resource.azure.openai.com/openai/models?api-version=2024-02-01", + ), + # AsyncAzureOpenAI: No deployment specified + ( + AsyncAzureOpenAI( + api_version="2024-02-01", + api_key="example API key", + azure_endpoint="https://example-resource.azure.openai.com", + ), + "https://example-resource.azure.openai.com/openai/", + "/assistants", + {"model": "deployment-body"}, + "https://example-resource.azure.openai.com/openai/assistants?api-version=2024-02-01", + ), + # AsyncAzureOpenAI: Deployment specified + ( + AsyncAzureOpenAI( + api_version="2024-02-01", + api_key="example API key", + azure_endpoint="https://example-resource.azure.openai.com", + azure_deployment="deployment-client", + ), + "https://example-resource.azure.openai.com/openai/deployments/deployment-client/", + "/models", + {}, + "https://example-resource.azure.openai.com/openai/models?api-version=2024-02-01", + ), + # AsyncAzureOpenAI: Deployment specified + ( + AsyncAzureOpenAI( + api_version="2024-02-01", + api_key="example API key", + azure_endpoint="https://example-resource.azure.openai.com", + azure_deployment="deployment-client", + ), + "https://example-resource.azure.openai.com/openai/deployments/deployment-client/", + "/assistants", + {"model": "deployment-body"}, + "https://example-resource.azure.openai.com/openai/assistants?api-version=2024-02-01", + ), + # AsyncAzureOpenAI: "deployments" in the DNS name + ( + AsyncAzureOpenAI( + api_version="2024-02-01", + api_key="example API key", + azure_endpoint="https://deployments.example-resource.azure.openai.com", + ), + "https://deployments.example-resource.azure.openai.com/openai/", + "/models", + {}, + "https://deployments.example-resource.azure.openai.com/openai/models?api-version=2024-02-01", + ), + # AsyncAzureOpenAI: Deployment called "deployments" + ( + AsyncAzureOpenAI( + api_version="2024-02-01", + api_key="example API key", + azure_endpoint="https://example-resource.azure.openai.com", + azure_deployment="deployments", + ), + "https://example-resource.azure.openai.com/openai/deployments/deployments/", + "/models", + {}, + "https://example-resource.azure.openai.com/openai/models?api-version=2024-02-01", + ), + # AsyncAzureOpenAI: base_url and azure_deployment specified; azure_deployment ignored b/c not supported + ( + AsyncAzureOpenAI( # type: ignore + api_version="2024-02-01", + api_key="example API key", + base_url="https://example.azure-api.net/PTU/", + azure_deployment="deployment-client", + ), + "https://example.azure-api.net/PTU/", + "/models", + {}, + "https://example.azure-api.net/PTU/models?api-version=2024-02-01", + ), + ], +) +def test_prepare_url_nondeployment_endpoint( + client: Client, base_url: str, api: str, json_data: dict[str, str], expected: str +) -> None: + req = client._build_request( + FinalRequestOptions.construct( + method="post", + url=api, + json_data=json_data, + ) + ) + assert req.url == expected + assert client.base_url == base_url + + +@pytest.mark.parametrize( + "client,base_url,json_data,expected", + [ + # Realtime endpoint + # AzureOpenAI: No deployment specified + ( + AzureOpenAI( + api_version="2024-02-01", + api_key="example API key", + azure_endpoint="https://example-resource.azure.openai.com", + ), + "https://example-resource.azure.openai.com/openai/", + {"model": "deployment-body"}, + "wss://example-resource.azure.openai.com/openai/realtime?api-version=2024-02-01&deployment=deployment-body", + ), + # AzureOpenAI: Deployment specified + ( + AzureOpenAI( + api_version="2024-02-01", + api_key="example API key", + azure_endpoint="https://example-resource.azure.openai.com", + azure_deployment="deployment-client", + ), + "https://example-resource.azure.openai.com/openai/deployments/deployment-client/", + {"model": "deployment-body"}, + "wss://example-resource.azure.openai.com/openai/realtime?api-version=2024-02-01&deployment=deployment-client", + ), + # AzureOpenAI: "deployments" in the DNS name + ( + AzureOpenAI( + api_version="2024-02-01", + api_key="example API key", + azure_endpoint="https://deployments.azure.openai.com", + ), + "https://deployments.azure.openai.com/openai/", + {"model": "deployment-body"}, + "wss://deployments.azure.openai.com/openai/realtime?api-version=2024-02-01&deployment=deployment-body", + ), + # AzureOpenAI: Deployment called "deployments" + ( + AzureOpenAI( + api_version="2024-02-01", + api_key="example API key", + azure_endpoint="https://example-resource.azure.openai.com", + azure_deployment="deployments", + ), + "https://example-resource.azure.openai.com/openai/deployments/deployments/", + {"model": "deployment-body"}, + "wss://example-resource.azure.openai.com/openai/realtime?api-version=2024-02-01&deployment=deployments", + ), + # AzureOpenAI: base_url and azure_deployment specified; azure_deployment ignored b/c not supported + ( + AzureOpenAI( # type: ignore + api_version="2024-02-01", + api_key="example API key", + base_url="https://example.azure-api.net/PTU/", + azure_deployment="my-deployment", + ), + "https://example.azure-api.net/PTU/", + {"model": "deployment-body"}, + "wss://example.azure-api.net/PTU/realtime?api-version=2024-02-01&deployment=deployment-body", + ), + # AzureOpenAI: websocket_base_url specified + ( + AzureOpenAI( + api_version="2024-02-01", + api_key="example API key", + azure_endpoint="https://example-resource.azure.openai.com", + websocket_base_url="wss://example-resource.azure.openai.com/base", + ), + "https://example-resource.azure.openai.com/openai/", + {"model": "deployment-body"}, + "wss://example-resource.azure.openai.com/base/realtime?api-version=2024-02-01&deployment=deployment-body", + ), + ], +) +def test_prepare_url_realtime(client: AzureOpenAI, base_url: str, json_data: dict[str, str], expected: str) -> None: + url, _ = client._configure_realtime(json_data["model"], {}) + assert str(url) == expected + assert client.base_url == base_url + + +@pytest.mark.parametrize( + "client,base_url,json_data,expected", + [ + # AsyncAzureOpenAI: No deployment specified + ( + AsyncAzureOpenAI( + api_version="2024-02-01", + api_key="example API key", + azure_endpoint="https://example-resource.azure.openai.com", + ), + "https://example-resource.azure.openai.com/openai/", + {"model": "deployment-body"}, + "wss://example-resource.azure.openai.com/openai/realtime?api-version=2024-02-01&deployment=deployment-body", + ), + # AsyncAzureOpenAI: Deployment specified + ( + AsyncAzureOpenAI( + api_version="2024-02-01", + api_key="example API key", + azure_endpoint="https://example-resource.azure.openai.com", + azure_deployment="deployment-client", + ), + "https://example-resource.azure.openai.com/openai/deployments/deployment-client/", + {"model": "deployment-body"}, + "wss://example-resource.azure.openai.com/openai/realtime?api-version=2024-02-01&deployment=deployment-client", + ), + # AsyncAzureOpenAI: "deployments" in the DNS name + ( + AsyncAzureOpenAI( + api_version="2024-02-01", + api_key="example API key", + azure_endpoint="https://deployments.azure.openai.com", + ), + "https://deployments.azure.openai.com/openai/", + {"model": "deployment-body"}, + "wss://deployments.azure.openai.com/openai/realtime?api-version=2024-02-01&deployment=deployment-body", + ), + # AsyncAzureOpenAI: Deployment called "deployments" + ( + AsyncAzureOpenAI( + api_version="2024-02-01", + api_key="example API key", + azure_endpoint="https://example-resource.azure.openai.com", + azure_deployment="deployments", + ), + "https://example-resource.azure.openai.com/openai/deployments/deployments/", + {"model": "deployment-body"}, + "wss://example-resource.azure.openai.com/openai/realtime?api-version=2024-02-01&deployment=deployments", + ), + # AsyncAzureOpenAI: base_url and azure_deployment specified; azure_deployment ignored b/c not supported + ( + AsyncAzureOpenAI( # type: ignore + api_version="2024-02-01", + api_key="example API key", + base_url="https://example.azure-api.net/PTU/", + azure_deployment="deployment-client", + ), + "https://example.azure-api.net/PTU/", + {"model": "deployment-body"}, + "wss://example.azure-api.net/PTU/realtime?api-version=2024-02-01&deployment=deployment-body", + ), + # AsyncAzureOpenAI: websocket_base_url specified + ( + AsyncAzureOpenAI( + api_version="2024-02-01", + api_key="example API key", + azure_endpoint="https://example-resource.azure.openai.com", + websocket_base_url="wss://example-resource.azure.openai.com/base", + ), + "https://example-resource.azure.openai.com/openai/", + {"model": "deployment-body"}, + "wss://example-resource.azure.openai.com/base/realtime?api-version=2024-02-01&deployment=deployment-body", + ), + ], +) +async def test_prepare_url_realtime_async( + client: AsyncAzureOpenAI, base_url: str, json_data: dict[str, str], expected: str +) -> None: + url, _ = await client._configure_realtime(json_data["model"], {}) + assert str(url) == expected + assert client.base_url == base_url + + +def test_client_sets_base_url(client: Client) -> None: + client = AzureOpenAI( + api_version="2024-02-01", + api_key="example API key", + azure_endpoint="https://example-resource.azure.openai.com", + azure_deployment="my-deployment", + ) + assert client.base_url == "https://example-resource.azure.openai.com/openai/deployments/my-deployment/" + + # (not recommended) user sets base_url to target different deployment + client.base_url = "https://example-resource.azure.openai.com/openai/deployments/different-deployment/" + req = client._build_request( + FinalRequestOptions.construct( + method="post", + url="/chat/completions", + json_data={"model": "placeholder"}, + ) + ) + assert ( + req.url + == "https://example-resource.azure.openai.com/openai/deployments/different-deployment/chat/completions?api-version=2024-02-01" + ) + req = client._build_request( + FinalRequestOptions.construct( + method="post", + url="/models", + json_data={}, + ) + ) + assert req.url == "https://example-resource.azure.openai.com/openai/models?api-version=2024-02-01" + + # (not recommended) user sets base_url to remove deployment + client.base_url = "https://example-resource.azure.openai.com/openai/" + req = client._build_request( + FinalRequestOptions.construct( + method="post", + url="/chat/completions", + json_data={"model": "deployment"}, + ) + ) + assert ( + req.url + == "https://example-resource.azure.openai.com/openai/deployments/deployment/chat/completions?api-version=2024-02-01" + ) + req = client._build_request( + FinalRequestOptions.construct( + method="post", + url="/models", + json_data={}, + ) + ) + assert req.url == "https://example-resource.azure.openai.com/openai/models?api-version=2024-02-01" From 64af9e8f06be4bfe02e0e5e9cb0aa7889a5db6d7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 1 Mar 2025 05:04:12 +0000 Subject: [PATCH 217/769] release: 1.65.2 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 57b589ea9e..ae5a2791b1 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.65.1" + ".": "1.65.2" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index ac6f54aa21..8f7edb2cae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 1.65.2 (2025-03-01) + +Full Changelog: [v1.65.1...v1.65.2](https://github.com/openai/openai-python/compare/v1.65.1...v1.65.2) + +### Bug Fixes + +* **azure:** azure_deployment use with realtime + non-deployment-based APIs ([#2154](https://github.com/openai/openai-python/issues/2154)) ([5846b55](https://github.com/openai/openai-python/commit/5846b552877f3d278689c521f9a26ce31167e1ea)) + + +### Chores + +* **docs:** update client docstring ([#2152](https://github.com/openai/openai-python/issues/2152)) ([0518c34](https://github.com/openai/openai-python/commit/0518c341ee0e19941c6b1d9d60e2552e1aa17f26)) + ## 1.65.1 (2025-02-27) Full Changelog: [v1.65.0...v1.65.1](https://github.com/openai/openai-python/compare/v1.65.0...v1.65.1) diff --git a/pyproject.toml b/pyproject.toml index 13bd84e4f4..d9a2417194 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.65.1" +version = "1.65.2" 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 422c9a283d..d48f48f4e1 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.65.1" # x-release-please-version +__version__ = "1.65.2" # x-release-please-version From 65f2c5cee943d5c2a57f087c7bcc8204449cec51 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 3 Mar 2025 20:43:26 +0000 Subject: [PATCH 218/769] chore(internal): remove unused http client options forwarding (#2158) --- src/openai/_base_client.py | 97 +------------------------------------- 1 file changed, 1 insertion(+), 96 deletions(-) diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index 43dc9ab2a4..f31e5af54b 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -9,7 +9,6 @@ import inspect import logging import platform -import warnings import email.utils from types import TracebackType from random import random @@ -36,7 +35,7 @@ import httpx import distro import pydantic -from httpx import URL, Limits +from httpx import URL from pydantic import PrivateAttr from . import _exceptions @@ -51,13 +50,10 @@ Timeout, NotGiven, ResponseT, - Transport, AnyMapping, PostParser, - ProxiesTypes, RequestFiles, HttpxSendArgs, - AsyncTransport, RequestOptions, HttpxRequestFiles, ModelBuilderProtocol, @@ -339,9 +335,6 @@ class BaseClient(Generic[_HttpxClientT, _DefaultStreamT]): _base_url: URL max_retries: int timeout: Union[float, Timeout, None] - _limits: httpx.Limits - _proxies: ProxiesTypes | None - _transport: Transport | AsyncTransport | None _strict_response_validation: bool _idempotency_header: str | None _default_stream_cls: type[_DefaultStreamT] | None = None @@ -354,9 +347,6 @@ def __init__( _strict_response_validation: bool, max_retries: int = DEFAULT_MAX_RETRIES, timeout: float | Timeout | None = DEFAULT_TIMEOUT, - limits: httpx.Limits, - transport: Transport | AsyncTransport | None, - proxies: ProxiesTypes | None, custom_headers: Mapping[str, str] | None = None, custom_query: Mapping[str, object] | None = None, ) -> None: @@ -364,9 +354,6 @@ def __init__( self._base_url = self._enforce_trailing_slash(URL(base_url)) self.max_retries = max_retries self.timeout = timeout - self._limits = limits - self._proxies = proxies - self._transport = transport self._custom_headers = custom_headers or {} self._custom_query = custom_query or {} self._strict_response_validation = _strict_response_validation @@ -802,46 +789,11 @@ def __init__( base_url: str | URL, max_retries: int = DEFAULT_MAX_RETRIES, timeout: float | Timeout | None | NotGiven = NOT_GIVEN, - transport: Transport | None = None, - proxies: ProxiesTypes | None = None, - limits: Limits | None = None, http_client: httpx.Client | None = None, custom_headers: Mapping[str, str] | None = None, custom_query: Mapping[str, object] | None = None, _strict_response_validation: bool, ) -> None: - kwargs: dict[str, Any] = {} - if limits is not None: - warnings.warn( - "The `connection_pool_limits` argument is deprecated. The `http_client` argument should be passed instead", - category=DeprecationWarning, - stacklevel=3, - ) - if http_client is not None: - raise ValueError("The `http_client` argument is mutually exclusive with `connection_pool_limits`") - else: - limits = DEFAULT_CONNECTION_LIMITS - - if transport is not None: - kwargs["transport"] = transport - warnings.warn( - "The `transport` argument is deprecated. The `http_client` argument should be passed instead", - category=DeprecationWarning, - stacklevel=3, - ) - if http_client is not None: - raise ValueError("The `http_client` argument is mutually exclusive with `transport`") - - if proxies is not None: - kwargs["proxies"] = proxies - warnings.warn( - "The `proxies` argument is deprecated. The `http_client` argument should be passed instead", - category=DeprecationWarning, - stacklevel=3, - ) - if http_client is not None: - raise ValueError("The `http_client` argument is mutually exclusive with `proxies`") - if not is_given(timeout): # if the user passed in a custom http client with a non-default # timeout set then we use that timeout. @@ -862,12 +814,9 @@ def __init__( super().__init__( version=version, - limits=limits, # cast to a valid type because mypy doesn't understand our type narrowing timeout=cast(Timeout, timeout), - proxies=proxies, base_url=base_url, - transport=transport, max_retries=max_retries, custom_query=custom_query, custom_headers=custom_headers, @@ -877,9 +826,6 @@ def __init__( base_url=base_url, # cast to a valid type because mypy doesn't understand our type narrowing timeout=cast(Timeout, timeout), - limits=limits, - follow_redirects=True, - **kwargs, # type: ignore ) def is_closed(self) -> bool: @@ -1389,45 +1335,10 @@ def __init__( _strict_response_validation: bool, max_retries: int = DEFAULT_MAX_RETRIES, timeout: float | Timeout | None | NotGiven = NOT_GIVEN, - transport: AsyncTransport | None = None, - proxies: ProxiesTypes | None = None, - limits: Limits | None = None, http_client: httpx.AsyncClient | None = None, custom_headers: Mapping[str, str] | None = None, custom_query: Mapping[str, object] | None = None, ) -> None: - kwargs: dict[str, Any] = {} - if limits is not None: - warnings.warn( - "The `connection_pool_limits` argument is deprecated. The `http_client` argument should be passed instead", - category=DeprecationWarning, - stacklevel=3, - ) - if http_client is not None: - raise ValueError("The `http_client` argument is mutually exclusive with `connection_pool_limits`") - else: - limits = DEFAULT_CONNECTION_LIMITS - - if transport is not None: - kwargs["transport"] = transport - warnings.warn( - "The `transport` argument is deprecated. The `http_client` argument should be passed instead", - category=DeprecationWarning, - stacklevel=3, - ) - if http_client is not None: - raise ValueError("The `http_client` argument is mutually exclusive with `transport`") - - if proxies is not None: - kwargs["proxies"] = proxies - warnings.warn( - "The `proxies` argument is deprecated. The `http_client` argument should be passed instead", - category=DeprecationWarning, - stacklevel=3, - ) - if http_client is not None: - raise ValueError("The `http_client` argument is mutually exclusive with `proxies`") - if not is_given(timeout): # if the user passed in a custom http client with a non-default # timeout set then we use that timeout. @@ -1449,11 +1360,8 @@ def __init__( super().__init__( version=version, base_url=base_url, - limits=limits, # cast to a valid type because mypy doesn't understand our type narrowing timeout=cast(Timeout, timeout), - proxies=proxies, - transport=transport, max_retries=max_retries, custom_query=custom_query, custom_headers=custom_headers, @@ -1463,9 +1371,6 @@ def __init__( base_url=base_url, # cast to a valid type because mypy doesn't understand our type narrowing timeout=cast(Timeout, timeout), - limits=limits, - follow_redirects=True, - **kwargs, # type: ignore ) def is_closed(self) -> bool: From b31f4d4c61cbeecf44b7ea6e0773eeec0748d91f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 4 Mar 2025 21:09:25 +0000 Subject: [PATCH 219/769] chore(internal): run example files in CI (#2160) --- .github/workflows/ci.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 26f497db1f..d0e0ffe2f3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,3 +51,30 @@ jobs: - name: Run tests run: ./scripts/test + + examples: + name: examples + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Install Rye + run: | + curl -sSf https://rye.astral.sh/get | bash + echo "$HOME/.rye/shims" >> $GITHUB_PATH + env: + RYE_VERSION: '0.35.0' + RYE_INSTALL_OPTION: '--yes' + - name: Install dependencies + run: | + rye sync --all-features + + - env: + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + run: | + rye run python examples/demo.py + - env: + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + run: | + rye run python examples/async_demo.py From d6bb8c14e66605ad2b7ed7bd62951014cd21b576 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 4 Mar 2025 21:10:03 +0000 Subject: [PATCH 220/769] release: 1.65.3 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 9 +++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index ae5a2791b1..352e389697 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.65.2" + ".": "1.65.3" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f7edb2cae..95093fb510 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 1.65.3 (2025-03-04) + +Full Changelog: [v1.65.2...v1.65.3](https://github.com/openai/openai-python/compare/v1.65.2...v1.65.3) + +### Chores + +* **internal:** remove unused http client options forwarding ([#2158](https://github.com/openai/openai-python/issues/2158)) ([76ec464](https://github.com/openai/openai-python/commit/76ec464cfe3db3fa59a766259d6d6ee5bb889f86)) +* **internal:** run example files in CI ([#2160](https://github.com/openai/openai-python/issues/2160)) ([9979345](https://github.com/openai/openai-python/commit/9979345038594440eec2f500c0c7cc5417cc7c08)) + ## 1.65.2 (2025-03-01) Full Changelog: [v1.65.1...v1.65.2](https://github.com/openai/openai-python/compare/v1.65.1...v1.65.2) diff --git a/pyproject.toml b/pyproject.toml index d9a2417194..c9e2afbf0c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.65.2" +version = "1.65.3" 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 d48f48f4e1..5e54102501 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.65.2" # x-release-please-version +__version__ = "1.65.3" # x-release-please-version From 5608d64bb832dc7f8305a4dfb6b8e76f7087c944 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 5 Mar 2025 21:22:02 +0000 Subject: [PATCH 221/769] fix(api): add missing file rank enum + more metadata (#2164) --- .stats.yml | 2 +- src/openai/resources/fine_tuning/jobs/jobs.py | 31 ++++++++++++++++++- .../threads/runs/file_search_tool_call.py | 7 +++-- .../types/fine_tuning/fine_tuning_job.py | 11 +++++++ .../types/fine_tuning/job_create_params.py | 12 +++++++ .../types/fine_tuning/job_list_params.py | 8 +++++ tests/api_resources/fine_tuning/test_jobs.py | 4 +++ 7 files changed, 71 insertions(+), 4 deletions(-) diff --git a/.stats.yml b/.stats.yml index 163146e38d..0d7e83be4f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 74 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-5d30684c3118d049682ea30cdb4dbef39b97d51667da484689193dc40162af32.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-b524aed1c2c5c928aa4e2c546f5dbb364e7b4d5027daf05e42e210b05a97c3c6.yml diff --git a/src/openai/resources/fine_tuning/jobs/jobs.py b/src/openai/resources/fine_tuning/jobs/jobs.py index e023d28fea..bbeff60bc6 100644 --- a/src/openai/resources/fine_tuning/jobs/jobs.py +++ b/src/openai/resources/fine_tuning/jobs/jobs.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Union, Iterable, Optional +from typing import Dict, Union, Iterable, Optional from typing_extensions import Literal import httpx @@ -30,6 +30,7 @@ make_request_options, ) from ....types.fine_tuning import job_list_params, job_create_params, job_list_events_params +from ....types.shared_params.metadata import Metadata from ....types.fine_tuning.fine_tuning_job import FineTuningJob from ....types.fine_tuning.fine_tuning_job_event import FineTuningJobEvent @@ -67,6 +68,7 @@ def create( training_file: str, hyperparameters: job_create_params.Hyperparameters | NotGiven = NOT_GIVEN, integrations: Optional[Iterable[job_create_params.Integration]] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, method: job_create_params.Method | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, suffix: Optional[str] | NotGiven = NOT_GIVEN, @@ -114,6 +116,13 @@ def create( integrations: A list of integrations to enable for your fine-tuning job. + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + method: The method used for fine-tuning. seed: The seed controls the reproducibility of the job. Passing in the same seed and @@ -155,6 +164,7 @@ def create( "training_file": training_file, "hyperparameters": hyperparameters, "integrations": integrations, + "metadata": metadata, "method": method, "seed": seed, "suffix": suffix, @@ -208,6 +218,7 @@ def list( *, after: str | NotGiven = NOT_GIVEN, limit: int | NotGiven = NOT_GIVEN, + metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -223,6 +234,9 @@ def list( limit: Number of fine-tuning jobs to retrieve. + metadata: Optional metadata filter. To filter, use the syntax `metadata[k]=v`. + Alternatively, set `metadata=null` to indicate no metadata. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -243,6 +257,7 @@ def list( { "after": after, "limit": limit, + "metadata": metadata, }, job_list_params.JobListParams, ), @@ -365,6 +380,7 @@ async def create( training_file: str, hyperparameters: job_create_params.Hyperparameters | NotGiven = NOT_GIVEN, integrations: Optional[Iterable[job_create_params.Integration]] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, method: job_create_params.Method | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, suffix: Optional[str] | NotGiven = NOT_GIVEN, @@ -412,6 +428,13 @@ async def create( integrations: A list of integrations to enable for your fine-tuning job. + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + method: The method used for fine-tuning. seed: The seed controls the reproducibility of the job. Passing in the same seed and @@ -453,6 +476,7 @@ async def create( "training_file": training_file, "hyperparameters": hyperparameters, "integrations": integrations, + "metadata": metadata, "method": method, "seed": seed, "suffix": suffix, @@ -506,6 +530,7 @@ def list( *, after: str | NotGiven = NOT_GIVEN, limit: int | NotGiven = NOT_GIVEN, + metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -521,6 +546,9 @@ def list( limit: Number of fine-tuning jobs to retrieve. + metadata: Optional metadata filter. To filter, use the syntax `metadata[k]=v`. + Alternatively, set `metadata=null` to indicate no metadata. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -541,6 +569,7 @@ def list( { "after": after, "limit": limit, + "metadata": metadata, }, job_list_params.JobListParams, ), diff --git a/src/openai/types/beta/threads/runs/file_search_tool_call.py b/src/openai/types/beta/threads/runs/file_search_tool_call.py index da4d58dc37..a2068daad1 100644 --- a/src/openai/types/beta/threads/runs/file_search_tool_call.py +++ b/src/openai/types/beta/threads/runs/file_search_tool_call.py @@ -15,8 +15,11 @@ class FileSearchRankingOptions(BaseModel): - ranker: Literal["default_2024_08_21"] - """The ranker used for the file search.""" + ranker: Literal["auto", "default_2024_08_21"] + """The ranker to use for the file search. + + If not specified will use the `auto` ranker. + """ score_threshold: float """The score threshold for the file search. diff --git a/src/openai/types/fine_tuning/fine_tuning_job.py b/src/openai/types/fine_tuning/fine_tuning_job.py index f5a11c2107..c7fff2b7b1 100644 --- a/src/openai/types/fine_tuning/fine_tuning_job.py +++ b/src/openai/types/fine_tuning/fine_tuning_job.py @@ -4,6 +4,7 @@ from typing_extensions import Literal from ..._models import BaseModel +from ..shared.metadata import Metadata from .fine_tuning_job_wandb_integration_object import FineTuningJobWandbIntegrationObject __all__ = [ @@ -208,5 +209,15 @@ class FineTuningJob(BaseModel): integrations: Optional[List[FineTuningJobWandbIntegrationObject]] = None """A list of integrations to enable for this fine-tuning job.""" + metadata: Optional[Metadata] = None + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + """ + method: Optional[Method] = None """The method used for fine-tuning.""" diff --git a/src/openai/types/fine_tuning/job_create_params.py b/src/openai/types/fine_tuning/job_create_params.py index 09c3f8571c..f4cf980b08 100644 --- a/src/openai/types/fine_tuning/job_create_params.py +++ b/src/openai/types/fine_tuning/job_create_params.py @@ -5,6 +5,8 @@ from typing import List, Union, Iterable, Optional from typing_extensions import Literal, Required, TypedDict +from ..shared_params.metadata import Metadata + __all__ = [ "JobCreateParams", "Hyperparameters", @@ -55,6 +57,16 @@ class JobCreateParams(TypedDict, total=False): integrations: Optional[Iterable[Integration]] """A list of integrations to enable for your fine-tuning job.""" + metadata: Optional[Metadata] + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + """ + method: Method """The method used for fine-tuning.""" diff --git a/src/openai/types/fine_tuning/job_list_params.py b/src/openai/types/fine_tuning/job_list_params.py index 5c075ca33f..b79f3ce86a 100644 --- a/src/openai/types/fine_tuning/job_list_params.py +++ b/src/openai/types/fine_tuning/job_list_params.py @@ -2,6 +2,7 @@ from __future__ import annotations +from typing import Dict, Optional from typing_extensions import TypedDict __all__ = ["JobListParams"] @@ -13,3 +14,10 @@ class JobListParams(TypedDict, total=False): limit: int """Number of fine-tuning jobs to retrieve.""" + + metadata: Optional[Dict[str, str]] + """Optional metadata filter. + + To filter, use the syntax `metadata[k]=v`. Alternatively, set `metadata=null` to + indicate no metadata. + """ diff --git a/tests/api_resources/fine_tuning/test_jobs.py b/tests/api_resources/fine_tuning/test_jobs.py index 1e421c30c0..75f72f9d09 100644 --- a/tests/api_resources/fine_tuning/test_jobs.py +++ b/tests/api_resources/fine_tuning/test_jobs.py @@ -50,6 +50,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: }, } ], + metadata={"foo": "string"}, method={ "dpo": { "hyperparameters": { @@ -148,6 +149,7 @@ def test_method_list_with_all_params(self, client: OpenAI) -> None: job = client.fine_tuning.jobs.list( after="string", limit=0, + metadata={"foo": "string"}, ) assert_matches_type(SyncCursorPage[FineTuningJob], job, path=["response"]) @@ -289,6 +291,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> }, } ], + metadata={"foo": "string"}, method={ "dpo": { "hyperparameters": { @@ -387,6 +390,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> N job = await async_client.fine_tuning.jobs.list( after="string", limit=0, + metadata={"foo": "string"}, ) assert_matches_type(AsyncCursorPage[FineTuningJob], job, path=["response"]) From dfc4cfabfab3db89c0668c9bfd5f3f6f49093935 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 5 Mar 2025 21:22:42 +0000 Subject: [PATCH 222/769] release: 1.65.4 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 352e389697..b31d1b2102 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.65.3" + ".": "1.65.4" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 95093fb510..759edd60a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.65.4 (2025-03-05) + +Full Changelog: [v1.65.3...v1.65.4](https://github.com/openai/openai-python/compare/v1.65.3...v1.65.4) + +### Bug Fixes + +* **api:** add missing file rank enum + more metadata ([#2164](https://github.com/openai/openai-python/issues/2164)) ([0387e48](https://github.com/openai/openai-python/commit/0387e48e0880e496eb74b60eec9ed76a3171f14d)) + ## 1.65.3 (2025-03-04) Full Changelog: [v1.65.2...v1.65.3](https://github.com/openai/openai-python/compare/v1.65.2...v1.65.3) diff --git a/pyproject.toml b/pyproject.toml index c9e2afbf0c..a44991907d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.65.3" +version = "1.65.4" 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 5e54102501..13991c8059 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.65.3" # x-release-please-version +__version__ = "1.65.4" # x-release-please-version From 530f9b80c7c21b1290a6749f6c2c82d72c047585 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 6 Mar 2025 20:10:48 +0000 Subject: [PATCH 223/769] chore: move ChatModel type to shared (#2167) --- api.md | 3 +- src/openai/resources/beta/assistants.py | 2 +- .../resources/beta/threads/runs/runs.py | 2 +- src/openai/resources/beta/threads/threads.py | 2 +- .../resources/chat/completions/completions.py | 2 +- src/openai/types/__init__.py | 2 +- .../types/beta/assistant_create_params.py | 2 +- .../beta/thread_create_and_run_params.py | 2 +- .../types/beta/threads/run_create_params.py | 2 +- .../types/chat/completion_create_params.py | 2 +- src/openai/types/chat_model.py | 47 ++--------------- src/openai/types/shared/__init__.py | 1 + src/openai/types/shared/chat_model.py | 49 ++++++++++++++++++ src/openai/types/shared_params/__init__.py | 1 + src/openai/types/shared_params/chat_model.py | 51 +++++++++++++++++++ 15 files changed, 116 insertions(+), 54 deletions(-) create mode 100644 src/openai/types/shared/chat_model.py create mode 100644 src/openai/types/shared_params/chat_model.py diff --git a/api.md b/api.md index 2db9d1157e..20e776289e 100644 --- a/api.md +++ b/api.md @@ -2,6 +2,7 @@ ```python from openai.types import ( + ChatModel, ErrorObject, FunctionDefinition, FunctionParameters, @@ -222,9 +223,9 @@ Types: from openai.types.fine_tuning import ( FineTuningJob, FineTuningJobEvent, - FineTuningJobIntegration, FineTuningJobWandbIntegration, FineTuningJobWandbIntegrationObject, + FineTuningJobIntegration, ) ``` diff --git a/src/openai/resources/beta/assistants.py b/src/openai/resources/beta/assistants.py index d2bb8d7b92..ffecd8f9e9 100644 --- a/src/openai/resources/beta/assistants.py +++ b/src/openai/resources/beta/assistants.py @@ -23,8 +23,8 @@ assistant_update_params, ) from ..._base_client import AsyncPaginator, make_request_options -from ...types.chat_model import ChatModel from ...types.beta.assistant import Assistant +from ...types.shared.chat_model import ChatModel from ...types.beta.assistant_deleted import AssistantDeleted from ...types.shared_params.metadata import Metadata from ...types.beta.assistant_tool_param import AssistantToolParam diff --git a/src/openai/resources/beta/threads/runs/runs.py b/src/openai/resources/beta/threads/runs/runs.py index dc364b4e31..b819678be6 100644 --- a/src/openai/resources/beta/threads/runs/runs.py +++ b/src/openai/resources/beta/threads/runs/runs.py @@ -39,7 +39,6 @@ AsyncAssistantEventHandlerT, AsyncAssistantStreamManager, ) -from .....types.chat_model import ChatModel from .....types.beta.threads import ( run_list_params, run_create_params, @@ -47,6 +46,7 @@ run_submit_tool_outputs_params, ) from .....types.beta.threads.run import Run +from .....types.shared.chat_model import ChatModel from .....types.shared_params.metadata import Metadata from .....types.beta.assistant_tool_param import AssistantToolParam from .....types.beta.assistant_stream_event import AssistantStreamEvent diff --git a/src/openai/resources/beta/threads/threads.py b/src/openai/resources/beta/threads/threads.py index 6ff8539501..d88559bdeb 100644 --- a/src/openai/resources/beta/threads/threads.py +++ b/src/openai/resources/beta/threads/threads.py @@ -49,9 +49,9 @@ AsyncAssistantEventHandlerT, AsyncAssistantStreamManager, ) -from ....types.chat_model import ChatModel from ....types.beta.thread import Thread from ....types.beta.threads.run import Run +from ....types.shared.chat_model import ChatModel from ....types.beta.thread_deleted import ThreadDeleted from ....types.shared_params.metadata import Metadata from ....types.beta.assistant_stream_event import AssistantStreamEvent diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index 1753f6c990..708b1ff166 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -37,7 +37,7 @@ completion_update_params, ) from ...._base_client import AsyncPaginator, make_request_options -from ....types.chat_model import ChatModel +from ....types.shared.chat_model import ChatModel from ....types.chat.chat_completion import ChatCompletion from ....types.shared_params.metadata import Metadata from ....types.chat.chat_completion_chunk import ChatCompletionChunk diff --git a/src/openai/types/__init__.py b/src/openai/types/__init__.py index 7abb22f239..5785877c8a 100644 --- a/src/openai/types/__init__.py +++ b/src/openai/types/__init__.py @@ -7,6 +7,7 @@ from .model import Model as Model from .shared import ( Metadata as Metadata, + ChatModel as ChatModel, ErrorObject as ErrorObject, FunctionDefinition as FunctionDefinition, FunctionParameters as FunctionParameters, @@ -16,7 +17,6 @@ ) from .upload import Upload as Upload from .embedding import Embedding as Embedding -from .chat_model import ChatModel as ChatModel from .completion import Completion as Completion from .moderation import Moderation as Moderation from .audio_model import AudioModel as AudioModel diff --git a/src/openai/types/beta/assistant_create_params.py b/src/openai/types/beta/assistant_create_params.py index 66bef02ced..e90aabfd3f 100644 --- a/src/openai/types/beta/assistant_create_params.py +++ b/src/openai/types/beta/assistant_create_params.py @@ -5,7 +5,7 @@ from typing import List, Union, Iterable, Optional from typing_extensions import Literal, Required, TypedDict -from ..chat_model import ChatModel +from ..shared.chat_model import ChatModel from .assistant_tool_param import AssistantToolParam from ..shared_params.metadata import Metadata from .file_chunking_strategy_param import FileChunkingStrategyParam diff --git a/src/openai/types/beta/thread_create_and_run_params.py b/src/openai/types/beta/thread_create_and_run_params.py index 08f044c1be..d888fb3eee 100644 --- a/src/openai/types/beta/thread_create_and_run_params.py +++ b/src/openai/types/beta/thread_create_and_run_params.py @@ -5,7 +5,7 @@ from typing import List, Union, Iterable, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict -from ..chat_model import ChatModel +from ..shared.chat_model import ChatModel from .function_tool_param import FunctionToolParam from .file_search_tool_param import FileSearchToolParam from ..shared_params.metadata import Metadata diff --git a/src/openai/types/beta/threads/run_create_params.py b/src/openai/types/beta/threads/run_create_params.py index 093b4ce321..098e50a1d9 100644 --- a/src/openai/types/beta/threads/run_create_params.py +++ b/src/openai/types/beta/threads/run_create_params.py @@ -5,7 +5,7 @@ from typing import List, Union, Iterable, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict -from ...chat_model import ChatModel +from ...shared.chat_model import ChatModel from ..assistant_tool_param import AssistantToolParam from .runs.run_step_include import RunStepInclude from ...shared_params.metadata import Metadata diff --git a/src/openai/types/chat/completion_create_params.py b/src/openai/types/chat/completion_create_params.py index c761cbe07b..4dd2812aba 100644 --- a/src/openai/types/chat/completion_create_params.py +++ b/src/openai/types/chat/completion_create_params.py @@ -5,7 +5,7 @@ from typing import Dict, List, Union, Iterable, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict -from ..chat_model import ChatModel +from ..shared.chat_model import ChatModel from ..shared_params.metadata import Metadata from .chat_completion_modality import ChatCompletionModality from .chat_completion_tool_param import ChatCompletionToolParam diff --git a/src/openai/types/chat_model.py b/src/openai/types/chat_model.py index 6fe705a0b4..9304d195d6 100644 --- a/src/openai/types/chat_model.py +++ b/src/openai/types/chat_model.py @@ -1,49 +1,8 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing_extensions import Literal, TypeAlias + +from .shared import chat_model __all__ = ["ChatModel"] -ChatModel: TypeAlias = Literal[ - "o3-mini", - "o3-mini-2025-01-31", - "o1", - "o1-2024-12-17", - "o1-preview", - "o1-preview-2024-09-12", - "o1-mini", - "o1-mini-2024-09-12", - "gpt-4.5-preview", - "gpt-4.5-preview-2025-02-27", - "gpt-4o", - "gpt-4o-2024-11-20", - "gpt-4o-2024-08-06", - "gpt-4o-2024-05-13", - "gpt-4o-audio-preview", - "gpt-4o-audio-preview-2024-10-01", - "gpt-4o-audio-preview-2024-12-17", - "gpt-4o-mini-audio-preview", - "gpt-4o-mini-audio-preview-2024-12-17", - "chatgpt-4o-latest", - "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-0301", - "gpt-3.5-turbo-0613", - "gpt-3.5-turbo-1106", - "gpt-3.5-turbo-0125", - "gpt-3.5-turbo-16k-0613", -] +ChatModel = chat_model.ChatModel diff --git a/src/openai/types/shared/__init__.py b/src/openai/types/shared/__init__.py index 74bf304904..4cf367b1cc 100644 --- a/src/openai/types/shared/__init__.py +++ b/src/openai/types/shared/__init__.py @@ -1,6 +1,7 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from .metadata import Metadata as Metadata +from .chat_model import ChatModel as ChatModel from .error_object import ErrorObject as ErrorObject from .function_definition import FunctionDefinition as FunctionDefinition from .function_parameters import FunctionParameters as FunctionParameters diff --git a/src/openai/types/shared/chat_model.py b/src/openai/types/shared/chat_model.py new file mode 100644 index 0000000000..6fe705a0b4 --- /dev/null +++ b/src/openai/types/shared/chat_model.py @@ -0,0 +1,49 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["ChatModel"] + +ChatModel: TypeAlias = Literal[ + "o3-mini", + "o3-mini-2025-01-31", + "o1", + "o1-2024-12-17", + "o1-preview", + "o1-preview-2024-09-12", + "o1-mini", + "o1-mini-2024-09-12", + "gpt-4.5-preview", + "gpt-4.5-preview-2025-02-27", + "gpt-4o", + "gpt-4o-2024-11-20", + "gpt-4o-2024-08-06", + "gpt-4o-2024-05-13", + "gpt-4o-audio-preview", + "gpt-4o-audio-preview-2024-10-01", + "gpt-4o-audio-preview-2024-12-17", + "gpt-4o-mini-audio-preview", + "gpt-4o-mini-audio-preview-2024-12-17", + "chatgpt-4o-latest", + "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-0301", + "gpt-3.5-turbo-0613", + "gpt-3.5-turbo-1106", + "gpt-3.5-turbo-0125", + "gpt-3.5-turbo-16k-0613", +] diff --git a/src/openai/types/shared_params/__init__.py b/src/openai/types/shared_params/__init__.py index 68a8db75fe..47a747b2d4 100644 --- a/src/openai/types/shared_params/__init__.py +++ b/src/openai/types/shared_params/__init__.py @@ -1,6 +1,7 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from .metadata import Metadata as Metadata +from .chat_model import ChatModel as ChatModel from .function_definition import FunctionDefinition as FunctionDefinition from .function_parameters import FunctionParameters as FunctionParameters from .response_format_text import ResponseFormatText as ResponseFormatText diff --git a/src/openai/types/shared_params/chat_model.py b/src/openai/types/shared_params/chat_model.py new file mode 100644 index 0000000000..0ac3f31611 --- /dev/null +++ b/src/openai/types/shared_params/chat_model.py @@ -0,0 +1,51 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypeAlias + +__all__ = ["ChatModel"] + +ChatModel: TypeAlias = Literal[ + "o3-mini", + "o3-mini-2025-01-31", + "o1", + "o1-2024-12-17", + "o1-preview", + "o1-preview-2024-09-12", + "o1-mini", + "o1-mini-2024-09-12", + "gpt-4.5-preview", + "gpt-4.5-preview-2025-02-27", + "gpt-4o", + "gpt-4o-2024-11-20", + "gpt-4o-2024-08-06", + "gpt-4o-2024-05-13", + "gpt-4o-audio-preview", + "gpt-4o-audio-preview-2024-10-01", + "gpt-4o-audio-preview-2024-12-17", + "gpt-4o-mini-audio-preview", + "gpt-4o-mini-audio-preview-2024-12-17", + "chatgpt-4o-latest", + "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-0301", + "gpt-3.5-turbo-0613", + "gpt-3.5-turbo-1106", + "gpt-3.5-turbo-0125", + "gpt-3.5-turbo-16k-0613", +] From a6b493071b843bec3db807637e441c1768b695f8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sun, 9 Mar 2025 05:03:47 +0000 Subject: [PATCH 224/769] release: 1.65.5 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index b31d1b2102..b8446e8608 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.65.4" + ".": "1.65.5" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 759edd60a8..e2bf62a4df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.65.5 (2025-03-09) + +Full Changelog: [v1.65.4...v1.65.5](https://github.com/openai/openai-python/compare/v1.65.4...v1.65.5) + +### Chores + +* move ChatModel type to shared ([#2167](https://github.com/openai/openai-python/issues/2167)) ([104f02a](https://github.com/openai/openai-python/commit/104f02af371076d5d2498e48ae14d2eacc7df8bd)) + ## 1.65.4 (2025-03-05) Full Changelog: [v1.65.3...v1.65.4](https://github.com/openai/openai-python/compare/v1.65.3...v1.65.4) diff --git a/pyproject.toml b/pyproject.toml index a44991907d..09e79f5592 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.65.4" +version = "1.65.5" 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 13991c8059..859b56580d 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.65.4" # x-release-please-version +__version__ = "1.65.5" # x-release-please-version From bf4a7e67d71a10a2644f18aeb110fda1dcba0023 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 11 Mar 2025 01:09:36 +0000 Subject: [PATCH 225/769] test: add DEFER_PYDANTIC_BUILD=false flag to tests (#2174) --- scripts/test | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/test b/scripts/test index 4fa5698b8f..2b87845670 100755 --- a/scripts/test +++ b/scripts/test @@ -52,6 +52,8 @@ else echo fi +export DEFER_PYDANTIC_BUILD=false + echo "==> Running tests" rye run pytest "$@" From 71f73540d4f0cb21887bedf2cc43516a0ebbe7c9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 11 Mar 2025 13:17:10 +0000 Subject: [PATCH 226/769] chore: export more types (#2176) --- src/openai/types/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/openai/types/__init__.py b/src/openai/types/__init__.py index 5785877c8a..eb71ac6ccc 100644 --- a/src/openai/types/__init__.py +++ b/src/openai/types/__init__.py @@ -17,6 +17,7 @@ ) from .upload import Upload as Upload from .embedding import Embedding as Embedding +from .chat_model import ChatModel as ChatModel from .completion import Completion as Completion from .moderation import Moderation as Moderation from .audio_model import AudioModel as AudioModel From 2954945ecc185259cfd7cd33c8cbc818a88e4e1b Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Tue, 11 Mar 2025 12:22:03 -0400 Subject: [PATCH 227/769] feat(api): add /v1/responses and built-in tools [platform.openai.com/docs/changelog](http://platform.openai.com/docs/changelog) --- .stats.yml | 4 +- README.md | 229 +-- api.md | 232 ++- examples/responses/__init__.py | 0 examples/responses/streaming.py | 30 + examples/responses/streaming_tools.py | 68 + examples/responses/structured_outputs.py | 55 + .../responses/structured_outputs_tools.py | 73 + src/openai/_client.py | 18 + src/openai/_streaming.py | 4 +- src/openai/lib/_parsing/_responses.py | 168 ++ src/openai/lib/_tools.py | 12 + .../lib/streaming/responses/__init__.py | 13 + src/openai/lib/streaming/responses/_events.py | 106 + .../lib/streaming/responses/_responses.py | 354 ++++ src/openai/lib/streaming/responses/_types.py | 10 + src/openai/resources/__init__.py | 28 + src/openai/resources/beta/__init__.py | 14 - src/openai/resources/beta/assistants.py | 17 +- src/openai/resources/beta/beta.py | 32 - src/openai/resources/beta/chat/completions.py | 40 +- .../resources/beta/threads/runs/runs.py | 51 +- .../resources/chat/completions/completions.py | 496 +++-- .../resources/chat/completions/messages.py | 4 +- src/openai/resources/files.py | 24 +- src/openai/resources/responses/__init__.py | 33 + src/openai/resources/responses/input_items.py | 223 ++ src/openai/resources/responses/responses.py | 1790 +++++++++++++++++ src/openai/resources/uploads/uploads.py | 14 +- .../{beta => }/vector_stores/__init__.py | 0 .../{beta => }/vector_stores/file_batches.py | 48 +- .../{beta => }/vector_stores/files.py | 235 ++- .../{beta => }/vector_stores/vector_stores.py | 178 +- src/openai/types/__init__.py | 21 + .../auto_file_chunking_strategy_param.py | 0 src/openai/types/beta/__init__.py | 15 - .../types/beta/assistant_create_params.py | 49 +- .../types/beta/assistant_update_params.py | 5 +- .../beta/thread_create_and_run_params.py | 43 +- src/openai/types/beta/thread_create_params.py | 42 +- .../types/beta/threads/run_create_params.py | 5 +- .../types/chat/chat_completion_audio_param.py | 5 +- .../chat_completion_content_part_param.py | 31 +- .../types/chat/chat_completion_message.py | 30 +- .../chat/chat_completion_reasoning_effort.py | 6 +- .../types/chat/completion_create_params.py | 132 +- .../types/chat/completion_list_params.py | 8 +- .../{beta => }/file_chunking_strategy.py | 2 +- .../file_chunking_strategy_param.py | 0 src/openai/types/file_create_params.py | 10 +- src/openai/types/file_purpose.py | 2 +- .../other_file_chunking_strategy_object.py | 2 +- src/openai/types/responses/__init__.py | 138 ++ src/openai/types/responses/computer_tool.py | 21 + .../types/responses/computer_tool_param.py | 21 + .../responses/easy_input_message_param.py | 27 + .../types/responses/file_search_tool.py | 44 + .../types/responses/file_search_tool_param.py | 45 + src/openai/types/responses/function_tool.py | 28 + .../types/responses/function_tool_param.py | 28 + .../types/responses/input_item_list_params.py | 28 + src/openai/types/responses/parsed_response.py | 77 + src/openai/types/responses/response.py | 204 ++ .../responses/response_audio_delta_event.py | 15 + .../responses/response_audio_done_event.py | 12 + .../response_audio_transcript_delta_event.py | 15 + .../response_audio_transcript_done_event.py | 12 + ..._code_interpreter_call_code_delta_event.py | 18 + ...e_code_interpreter_call_code_done_event.py | 18 + ...e_code_interpreter_call_completed_event.py | 19 + ...code_interpreter_call_in_progress_event.py | 19 + ...ode_interpreter_call_interpreting_event.py | 19 + .../response_code_interpreter_tool_call.py | 52 + .../responses/response_completed_event.py | 16 + .../responses/response_computer_tool_call.py | 212 ++ .../response_computer_tool_call_param.py | 208 ++ .../response_content_part_added_event.py | 30 + .../response_content_part_done_event.py | 30 + .../types/responses/response_create_params.py | 204 ++ .../types/responses/response_created_event.py | 16 + src/openai/types/responses/response_error.py | 34 + .../types/responses/response_error_event.py | 22 + .../types/responses/response_failed_event.py | 16 + ...sponse_file_search_call_completed_event.py | 18 + ...onse_file_search_call_in_progress_event.py | 18 + ...sponse_file_search_call_searching_event.py | 18 + .../response_file_search_tool_call.py | 51 + .../response_file_search_tool_call_param.py | 51 + .../responses/response_format_text_config.py | 16 + .../response_format_text_config_param.py | 16 + ...response_format_text_json_schema_config.py | 43 + ...se_format_text_json_schema_config_param.py | 41 + ...nse_function_call_arguments_delta_event.py | 23 + ...onse_function_call_arguments_done_event.py | 20 + .../responses/response_function_tool_call.py | 32 + .../response_function_tool_call_param.py | 31 + .../responses/response_function_web_search.py | 18 + .../response_function_web_search_param.py | 18 + .../responses/response_in_progress_event.py | 16 + .../types/responses/response_includable.py | 9 + .../responses/response_incomplete_event.py | 16 + .../types/responses/response_input_content.py | 15 + .../responses/response_input_content_param.py | 14 + .../types/responses/response_input_file.py | 22 + .../responses/response_input_file_param.py | 21 + .../types/responses/response_input_image.py | 28 + .../responses/response_input_image_param.py | 28 + .../responses/response_input_item_param.py | 174 ++ .../response_input_message_content_list.py | 10 + ...sponse_input_message_content_list_param.py | 16 + .../types/responses/response_input_param.py | 177 ++ .../types/responses/response_input_text.py | 15 + .../responses/response_input_text_param.py | 15 + .../types/responses/response_item_list.py | 152 ++ .../types/responses/response_output_item.py | 55 + .../response_output_item_added_event.py | 19 + .../response_output_item_done_event.py | 19 + .../responses/response_output_message.py | 34 + .../response_output_message_param.py | 34 + .../responses/response_output_refusal.py | 15 + .../response_output_refusal_param.py | 15 + .../types/responses/response_output_text.py | 64 + .../responses/response_output_text_param.py | 67 + .../responses/response_refusal_delta_event.py | 24 + .../responses/response_refusal_done_event.py | 24 + .../responses/response_retrieve_params.py | 18 + src/openai/types/responses/response_status.py | 7 + .../types/responses/response_stream_event.py | 78 + .../response_text_annotation_delta_event.py | 79 + .../types/responses/response_text_config.py | 26 + .../responses/response_text_config_param.py | 27 + .../responses/response_text_delta_event.py | 24 + .../responses/response_text_done_event.py | 24 + src/openai/types/responses/response_usage.py | 25 + ...esponse_web_search_call_completed_event.py | 18 + ...ponse_web_search_call_in_progress_event.py | 18 + ...esponse_web_search_call_searching_event.py | 18 + src/openai/types/responses/tool.py | 16 + .../types/responses/tool_choice_function.py | 15 + .../responses/tool_choice_function_param.py | 15 + .../types/responses/tool_choice_options.py | 7 + .../types/responses/tool_choice_types.py | 22 + .../responses/tool_choice_types_param.py | 24 + src/openai/types/responses/tool_param.py | 18 + src/openai/types/responses/web_search_tool.py | 48 + .../types/responses/web_search_tool_param.py | 48 + src/openai/types/shared/__init__.py | 4 + src/openai/types/shared/chat_model.py | 3 + src/openai/types/shared/comparison_filter.py | 30 + src/openai/types/shared/compound_filter.py | 22 + src/openai/types/shared/reasoning.py | 28 + src/openai/types/shared/reasoning_effort.py | 8 + .../shared/response_format_json_object.py | 2 +- .../shared/response_format_json_schema.py | 18 +- .../types/shared/response_format_text.py | 2 +- src/openai/types/shared_params/__init__.py | 4 + src/openai/types/shared_params/chat_model.py | 3 + .../types/shared_params/comparison_filter.py | 30 + .../types/shared_params/compound_filter.py | 23 + src/openai/types/shared_params/reasoning.py | 29 + .../types/shared_params/reasoning_effort.py | 10 + .../response_format_json_object.py | 2 +- .../response_format_json_schema.py | 18 +- .../shared_params/response_format_text.py | 2 +- .../static_file_chunking_strategy.py | 2 +- .../static_file_chunking_strategy_object.py | 2 +- ...tic_file_chunking_strategy_object_param.py | 0 .../static_file_chunking_strategy_param.py | 0 src/openai/types/{beta => }/vector_store.py | 4 +- .../{beta => }/vector_store_create_params.py | 2 +- .../types/{beta => }/vector_store_deleted.py | 2 +- .../{beta => }/vector_store_list_params.py | 0 .../types/vector_store_search_params.py | 40 + .../types/vector_store_search_response.py | 39 + .../{beta => }/vector_store_update_params.py | 2 +- .../{beta => }/vector_stores/__init__.py | 2 + .../vector_stores/file_batch_create_params.py | 11 +- .../file_batch_list_files_params.py | 0 .../vector_stores/file_content_response.py | 15 + .../vector_stores/file_create_params.py | 10 + .../vector_stores/file_list_params.py | 0 .../types/vector_stores/file_update_params.py | 21 + .../vector_stores/vector_store_file.py | 13 +- .../vector_stores/vector_store_file_batch.py | 2 +- .../vector_store_file_deleted.py | 2 +- .../beta/vector_stores/test_files.py | 420 ---- tests/api_resources/chat/test_completions.py | 64 +- .../vector_stores => responses}/__init__.py | 0 .../responses/test_input_items.py | 121 ++ tests/api_resources/test_responses.py | 498 +++++ .../{beta => }/test_vector_stores.py | 263 ++- tests/api_resources/vector_stores/__init__.py | 1 + .../vector_stores/test_file_batches.py | 216 +- .../api_resources/vector_stores/test_files.py | 625 ++++++ tests/lib/chat/test_completions.py | 15 + tests/lib/chat/test_completions_streaming.py | 15 + 196 files changed, 10058 insertions(+), 1333 deletions(-) create mode 100644 examples/responses/__init__.py create mode 100644 examples/responses/streaming.py create mode 100644 examples/responses/streaming_tools.py create mode 100644 examples/responses/structured_outputs.py create mode 100644 examples/responses/structured_outputs_tools.py create mode 100644 src/openai/lib/_parsing/_responses.py create mode 100644 src/openai/lib/streaming/responses/__init__.py create mode 100644 src/openai/lib/streaming/responses/_events.py create mode 100644 src/openai/lib/streaming/responses/_responses.py create mode 100644 src/openai/lib/streaming/responses/_types.py create mode 100644 src/openai/resources/responses/__init__.py create mode 100644 src/openai/resources/responses/input_items.py create mode 100644 src/openai/resources/responses/responses.py rename src/openai/resources/{beta => }/vector_stores/__init__.py (100%) rename src/openai/resources/{beta => }/vector_stores/file_batches.py (93%) rename src/openai/resources/{beta => }/vector_stores/files.py (73%) rename src/openai/resources/{beta => }/vector_stores/vector_stores.py (80%) rename src/openai/types/{beta => }/auto_file_chunking_strategy_param.py (100%) rename src/openai/types/{beta => }/file_chunking_strategy.py (93%) rename src/openai/types/{beta => }/file_chunking_strategy_param.py (100%) rename src/openai/types/{beta => }/other_file_chunking_strategy_object.py (89%) create mode 100644 src/openai/types/responses/__init__.py create mode 100644 src/openai/types/responses/computer_tool.py create mode 100644 src/openai/types/responses/computer_tool_param.py create mode 100644 src/openai/types/responses/easy_input_message_param.py create mode 100644 src/openai/types/responses/file_search_tool.py create mode 100644 src/openai/types/responses/file_search_tool_param.py create mode 100644 src/openai/types/responses/function_tool.py create mode 100644 src/openai/types/responses/function_tool_param.py create mode 100644 src/openai/types/responses/input_item_list_params.py create mode 100644 src/openai/types/responses/parsed_response.py create mode 100644 src/openai/types/responses/response.py create mode 100644 src/openai/types/responses/response_audio_delta_event.py create mode 100644 src/openai/types/responses/response_audio_done_event.py create mode 100644 src/openai/types/responses/response_audio_transcript_delta_event.py create mode 100644 src/openai/types/responses/response_audio_transcript_done_event.py create mode 100644 src/openai/types/responses/response_code_interpreter_call_code_delta_event.py create mode 100644 src/openai/types/responses/response_code_interpreter_call_code_done_event.py create mode 100644 src/openai/types/responses/response_code_interpreter_call_completed_event.py create mode 100644 src/openai/types/responses/response_code_interpreter_call_in_progress_event.py create mode 100644 src/openai/types/responses/response_code_interpreter_call_interpreting_event.py create mode 100644 src/openai/types/responses/response_code_interpreter_tool_call.py create mode 100644 src/openai/types/responses/response_completed_event.py create mode 100644 src/openai/types/responses/response_computer_tool_call.py create mode 100644 src/openai/types/responses/response_computer_tool_call_param.py create mode 100644 src/openai/types/responses/response_content_part_added_event.py create mode 100644 src/openai/types/responses/response_content_part_done_event.py create mode 100644 src/openai/types/responses/response_create_params.py create mode 100644 src/openai/types/responses/response_created_event.py create mode 100644 src/openai/types/responses/response_error.py create mode 100644 src/openai/types/responses/response_error_event.py create mode 100644 src/openai/types/responses/response_failed_event.py create mode 100644 src/openai/types/responses/response_file_search_call_completed_event.py create mode 100644 src/openai/types/responses/response_file_search_call_in_progress_event.py create mode 100644 src/openai/types/responses/response_file_search_call_searching_event.py create mode 100644 src/openai/types/responses/response_file_search_tool_call.py create mode 100644 src/openai/types/responses/response_file_search_tool_call_param.py create mode 100644 src/openai/types/responses/response_format_text_config.py create mode 100644 src/openai/types/responses/response_format_text_config_param.py create mode 100644 src/openai/types/responses/response_format_text_json_schema_config.py create mode 100644 src/openai/types/responses/response_format_text_json_schema_config_param.py create mode 100644 src/openai/types/responses/response_function_call_arguments_delta_event.py create mode 100644 src/openai/types/responses/response_function_call_arguments_done_event.py create mode 100644 src/openai/types/responses/response_function_tool_call.py create mode 100644 src/openai/types/responses/response_function_tool_call_param.py create mode 100644 src/openai/types/responses/response_function_web_search.py create mode 100644 src/openai/types/responses/response_function_web_search_param.py create mode 100644 src/openai/types/responses/response_in_progress_event.py create mode 100644 src/openai/types/responses/response_includable.py create mode 100644 src/openai/types/responses/response_incomplete_event.py create mode 100644 src/openai/types/responses/response_input_content.py create mode 100644 src/openai/types/responses/response_input_content_param.py create mode 100644 src/openai/types/responses/response_input_file.py create mode 100644 src/openai/types/responses/response_input_file_param.py create mode 100644 src/openai/types/responses/response_input_image.py create mode 100644 src/openai/types/responses/response_input_image_param.py create mode 100644 src/openai/types/responses/response_input_item_param.py create mode 100644 src/openai/types/responses/response_input_message_content_list.py create mode 100644 src/openai/types/responses/response_input_message_content_list_param.py create mode 100644 src/openai/types/responses/response_input_param.py create mode 100644 src/openai/types/responses/response_input_text.py create mode 100644 src/openai/types/responses/response_input_text_param.py create mode 100644 src/openai/types/responses/response_item_list.py create mode 100644 src/openai/types/responses/response_output_item.py create mode 100644 src/openai/types/responses/response_output_item_added_event.py create mode 100644 src/openai/types/responses/response_output_item_done_event.py create mode 100644 src/openai/types/responses/response_output_message.py create mode 100644 src/openai/types/responses/response_output_message_param.py create mode 100644 src/openai/types/responses/response_output_refusal.py create mode 100644 src/openai/types/responses/response_output_refusal_param.py create mode 100644 src/openai/types/responses/response_output_text.py create mode 100644 src/openai/types/responses/response_output_text_param.py create mode 100644 src/openai/types/responses/response_refusal_delta_event.py create mode 100644 src/openai/types/responses/response_refusal_done_event.py create mode 100644 src/openai/types/responses/response_retrieve_params.py create mode 100644 src/openai/types/responses/response_status.py create mode 100644 src/openai/types/responses/response_stream_event.py create mode 100644 src/openai/types/responses/response_text_annotation_delta_event.py create mode 100644 src/openai/types/responses/response_text_config.py create mode 100644 src/openai/types/responses/response_text_config_param.py create mode 100644 src/openai/types/responses/response_text_delta_event.py create mode 100644 src/openai/types/responses/response_text_done_event.py create mode 100644 src/openai/types/responses/response_usage.py create mode 100644 src/openai/types/responses/response_web_search_call_completed_event.py create mode 100644 src/openai/types/responses/response_web_search_call_in_progress_event.py create mode 100644 src/openai/types/responses/response_web_search_call_searching_event.py create mode 100644 src/openai/types/responses/tool.py create mode 100644 src/openai/types/responses/tool_choice_function.py create mode 100644 src/openai/types/responses/tool_choice_function_param.py create mode 100644 src/openai/types/responses/tool_choice_options.py create mode 100644 src/openai/types/responses/tool_choice_types.py create mode 100644 src/openai/types/responses/tool_choice_types_param.py create mode 100644 src/openai/types/responses/tool_param.py create mode 100644 src/openai/types/responses/web_search_tool.py create mode 100644 src/openai/types/responses/web_search_tool_param.py create mode 100644 src/openai/types/shared/comparison_filter.py create mode 100644 src/openai/types/shared/compound_filter.py create mode 100644 src/openai/types/shared/reasoning.py create mode 100644 src/openai/types/shared/reasoning_effort.py create mode 100644 src/openai/types/shared_params/comparison_filter.py create mode 100644 src/openai/types/shared_params/compound_filter.py create mode 100644 src/openai/types/shared_params/reasoning.py create mode 100644 src/openai/types/shared_params/reasoning_effort.py rename src/openai/types/{beta => }/static_file_chunking_strategy.py (94%) rename src/openai/types/{beta => }/static_file_chunking_strategy_object.py (92%) rename src/openai/types/{beta => }/static_file_chunking_strategy_object_param.py (100%) rename src/openai/types/{beta => }/static_file_chunking_strategy_param.py (100%) rename src/openai/types/{beta => }/vector_store.py (97%) rename src/openai/types/{beta => }/vector_store_create_params.py (97%) rename src/openai/types/{beta => }/vector_store_deleted.py (89%) rename src/openai/types/{beta => }/vector_store_list_params.py (100%) create mode 100644 src/openai/types/vector_store_search_params.py create mode 100644 src/openai/types/vector_store_search_response.py rename src/openai/types/{beta => }/vector_store_update_params.py (96%) rename src/openai/types/{beta => }/vector_stores/__init__.py (82%) rename src/openai/types/{beta => }/vector_stores/file_batch_create_params.py (61%) rename src/openai/types/{beta => }/vector_stores/file_batch_list_files_params.py (100%) create mode 100644 src/openai/types/vector_stores/file_content_response.py rename src/openai/types/{beta => }/vector_stores/file_create_params.py (60%) rename src/openai/types/{beta => }/vector_stores/file_list_params.py (100%) create mode 100644 src/openai/types/vector_stores/file_update_params.py rename src/openai/types/{beta => }/vector_stores/vector_store_file.py (76%) rename src/openai/types/{beta => }/vector_stores/vector_store_file_batch.py (97%) rename src/openai/types/{beta => }/vector_stores/vector_store_file_deleted.py (89%) delete mode 100644 tests/api_resources/beta/vector_stores/test_files.py rename tests/api_resources/{beta/vector_stores => responses}/__init__.py (100%) create mode 100644 tests/api_resources/responses/test_input_items.py create mode 100644 tests/api_resources/test_responses.py rename tests/api_resources/{beta => }/test_vector_stores.py (60%) create mode 100644 tests/api_resources/vector_stores/__init__.py rename tests/api_resources/{beta => }/vector_stores/test_file_batches.py (68%) create mode 100644 tests/api_resources/vector_stores/test_files.py diff --git a/.stats.yml b/.stats.yml index 0d7e83be4f..455874212c 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ -configured_endpoints: 74 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-b524aed1c2c5c928aa4e2c546f5dbb364e7b4d5027daf05e42e210b05a97c3c6.yml +configured_endpoints: 81 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-be834d63e326a82494e819085137f5eb15866f3fc787db1f3afe7168d419e18a.yml diff --git a/README.md b/README.md index 3c103f036c..c52bffbb5f 100644 --- a/README.md +++ b/README.md @@ -10,13 +10,10 @@ It is generated from our [OpenAPI specification](https://github.com/openai/opena ## Documentation -The REST API documentation can be found on [platform.openai.com](https://platform.openai.com/docs). The full API of this library can be found in [api.md](api.md). +The REST API documentation can be found on [platform.openai.com](https://platform.openai.com/docs/api-reference). The full API of this library can be found in [api.md](api.md). ## Installation -> [!IMPORTANT] -> The SDK was rewritten in v1, which was released November 6th 2023. See the [v1 migration guide](https://github.com/openai/openai-python/discussions/742), which includes scripts to automatically update your code. - ```sh # install from PyPI pip install openai @@ -26,46 +23,69 @@ pip install openai The full API of this library can be found in [api.md](api.md). +The primary API for interacting with OpenAI models is the [Responses API](https://platform.openai.com/docs/api-reference/responses). You can generate text from the model with the code below. + ```python import os from openai import OpenAI client = OpenAI( - api_key=os.environ.get("OPENAI_API_KEY"), # This is the default and can be omitted + # This is the default and can be omitted + api_key=os.environ.get("OPENAI_API_KEY"), +) + +response = client.responses.create( + model="gpt-4o", + instructions="You are a coding assistant that talks like a pirate.", + input="How do I check if a Python object is an instance of a class?", ) -chat_completion = client.chat.completions.create( +print(response.output_text) +``` + +The previous standard (supported indefinitely) for generating text is the [Chat Completions API](https://platform.openai.com/docs/api-reference/chat). You can use that API to generate text from the model with the code below. + +```python +from openai import OpenAI + +client = OpenAI() + +completion = client.chat.completions.create( + model="gpt-4o", messages=[ + {"role": "developer", "content": "Talk like a pirate."}, { "role": "user", - "content": "Say this is a test", - } + "content": "How do I check if a Python object is an instance of a class?", + }, ], - model="gpt-4o", ) + +print(completion.choices[0].message.content) ``` While you can provide an `api_key` keyword argument, we recommend using [python-dotenv](https://pypi.org/project/python-dotenv/) to add `OPENAI_API_KEY="My API Key"` to your `.env` file -so that your API Key is not stored in source control. +so that your API key is not stored in source control. +[Get an API key here](https://platform.openai.com/settings/organization/api-keys). ### Vision -With a hosted image: +With an image URL: ```python -response = client.chat.completions.create( +prompt = "What is in this image?" +img_url = "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d5/2023_06_08_Raccoon1.jpg/1599px-2023_06_08_Raccoon1.jpg" + +response = client.responses.create( model="gpt-4o-mini", - messages=[ + input=[ { "role": "user", "content": [ - {"type": "text", "text": prompt}, - { - "type": "image_url", - "image_url": {"url": f"{img_url}"}, - }, + {"type": "input_text", "text": prompt}, + {"type": "input_image", "image_url": f"{img_url}"}, ], } ], @@ -75,73 +95,29 @@ response = client.chat.completions.create( With the image as a base64 encoded string: ```python -response = client.chat.completions.create( +import base64 +from openai import OpenAI + +client = OpenAI() + +prompt = "What is in this image?" +with open("path/to/image.png", "rb") as image_file: + b64_image = base64.b64encode(image_file.read()).decode("utf-8") + +response = client.responses.create( model="gpt-4o-mini", - messages=[ + input=[ { "role": "user", "content": [ - {"type": "text", "text": prompt}, - { - "type": "image_url", - "image_url": {"url": f"data:{img_type};base64,{img_b64_str}"}, - }, + {"type": "input_text", "text": prompt}, + {"type": "input_image", "image_url": f"data:image/png;base64,{b64_image}"}, ], } ], ) ``` -### Polling Helpers - -When interacting with the API some actions such as starting a Run and adding files to vector stores are asynchronous and take time to complete. The SDK includes -helper functions which will poll the status until it reaches a terminal state and then return the resulting object. -If an API method results in an action that could benefit from polling there will be a corresponding version of the -method ending in '\_and_poll'. - -For instance to create a Run and poll until it reaches a terminal state you can run: - -```python -run = client.beta.threads.runs.create_and_poll( - thread_id=thread.id, - assistant_id=assistant.id, -) -``` - -More information on the lifecycle of a Run can be found in the [Run Lifecycle Documentation](https://platform.openai.com/docs/assistants/how-it-works/run-lifecycle) - -### Bulk Upload Helpers - -When creating and interacting with vector stores, you can use polling helpers to monitor the status of operations. -For convenience, we also provide a bulk upload helper to allow you to simultaneously upload several files at once. - -```python -sample_files = [Path("sample-paper.pdf"), ...] - -batch = await client.vector_stores.file_batches.upload_and_poll( - store.id, - files=sample_files, -) -``` - -### Streaming Helpers - -The SDK also includes helpers to process streams and handle incoming events. - -```python -with client.beta.threads.runs.stream( - thread_id=thread.id, - assistant_id=assistant.id, - instructions="Please address the user as Jane Doe. The user has a premium account.", -) as stream: - for event in stream: - # Print the text from text delta events - if event.type == "thread.message.delta" and event.data.delta.content: - print(event.data.delta.content[0].text) -``` - -More information on streaming helpers can be found in the dedicated documentation: [helpers.md](helpers.md) - ## Async usage Simply import `AsyncOpenAI` instead of `OpenAI` and use `await` with each API call: @@ -152,20 +128,16 @@ import asyncio from openai import AsyncOpenAI client = AsyncOpenAI( - api_key=os.environ.get("OPENAI_API_KEY"), # This is the default and can be omitted + # This is the default and can be omitted + api_key=os.environ.get("OPENAI_API_KEY"), ) async def main() -> None: - chat_completion = await client.chat.completions.create( - messages=[ - { - "role": "user", - "content": "Say this is a test", - } - ], - model="gpt-4o", + response = await client.responses.create( + model="gpt-4o", input="Explain disestablishmentarianism to a smart five year old." ) + print(response.output_text) asyncio.run(main()) @@ -182,18 +154,14 @@ from openai import OpenAI client = OpenAI() -stream = client.chat.completions.create( - messages=[ - { - "role": "user", - "content": "Say this is a test", - } - ], +stream = client.responses.create( model="gpt-4o", + input="Write a one-sentence bedtime story about a unicorn.", stream=True, ) -for chunk in stream: - print(chunk.choices[0].delta.content or "", end="") + +for event in stream: + print(event) ``` The async client uses the exact same interface. @@ -206,58 +174,19 @@ client = AsyncOpenAI() async def main(): - stream = await client.chat.completions.create( - model="gpt-4", - messages=[{"role": "user", "content": "Say this is a test"}], + stream = client.responses.create( + model="gpt-4o", + input="Write a one-sentence bedtime story about a unicorn.", stream=True, ) - async for chunk in stream: - print(chunk.choices[0].delta.content or "", end="") - - -asyncio.run(main()) -``` - -## Module-level client - -> [!IMPORTANT] -> We highly recommend instantiating client instances instead of relying on the global client. -We also expose a global client instance that is accessible in a similar fashion to versions prior to v1. - -```py -import openai - -# optional; defaults to `os.environ['OPENAI_API_KEY']` -openai.api_key = '...' + for event in stream: + print(event) -# all client options can be configured just like the `OpenAI` instantiation counterpart -openai.base_url = "https://..." -openai.default_headers = {"x-foo": "true"} -completion = openai.chat.completions.create( - model="gpt-4o", - messages=[ - { - "role": "user", - "content": "How do I output all files in a directory using Python?", - }, - ], -) -print(completion.choices[0].message.content) +asyncio.run(main()) ``` -The API is the exact same as the standard client instance-based API. - -This is intended to be used within REPLs or notebooks for faster iteration, **not** in application code. - -We recommend that you always instantiate a client (e.g., with `client = OpenAI()`) in application code because: - -- It can be difficult to reason about where client options are configured -- It's not possible to change certain client options without potentially causing race conditions -- It's harder to mock for testing purposes -- It's not possible to control cleanup of network connections - ## Realtime API beta The Realtime API enables you to build low-latency, multi-modal conversational experiences. It currently supports text and audio as both input and output, as well as [function calling](https://platform.openai.com/docs/guides/function-calling) through a WebSocket connection. @@ -304,7 +233,7 @@ However the real magic of the Realtime API is handling audio inputs / outputs, s ### Realtime error handling -Whenever an error occurs, the Realtime API will send an [`error` event](https://platform.openai.com/docs/guides/realtime-model-capabilities#error-handling) and the connection will stay open and remain usable. This means you need to handle it yourself, as *no errors are raised directly* by the SDK when an `error` event comes in. +Whenever an error occurs, the Realtime API will send an [`error` event](https://platform.openai.com/docs/guides/realtime-model-capabilities#error-handling) and the connection will stay open and remain usable. This means you need to handle it yourself, as _no errors are raised directly_ by the SDK when an `error` event comes in. ```py client = AsyncOpenAI() @@ -408,11 +337,11 @@ from openai import OpenAI client = OpenAI() -completion = client.chat.completions.create( - messages=[ +response = client.chat.responses.create( + input=[ { "role": "user", - "content": "Can you generate an example json object describing a fruit?", + "content": "How much ?", } ], model="gpt-4o", @@ -489,15 +418,16 @@ Error codes are as follows: All object responses in the SDK provide a `_request_id` property which is added from the `x-request-id` response header so that you can quickly log failing requests and report them back to OpenAI. ```python -completion = await client.chat.completions.create( - messages=[{"role": "user", "content": "Say this is a test"}], model="gpt-4" +response = await client.responses.create( + model="gpt-4o-mini", + input="Say 'this is a test'.", ) -print(completion._request_id) # req_123 +print(response._request_id) # req_123 ``` Note that unlike other properties that use an `_` prefix, the `_request_id` property -*is* public. Unless documented otherwise, *all* other `_` prefix properties, -methods and modules are *private*. +_is_ public. Unless documented otherwise, _all_ other `_` prefix properties, +methods and modules are _private_. > [!IMPORTANT] > If you need to access request IDs for failed requests you must catch the `APIStatusError` exception @@ -514,8 +444,7 @@ except openai.APIStatusError as exc: raise exc ``` - -### Retries +## Retries Certain errors are automatically retried 2 times by default, with a short exponential backoff. Connection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict, @@ -544,7 +473,7 @@ client.with_options(max_retries=5).chat.completions.create( ) ``` -### Timeouts +## Timeouts By default requests time out after 10 minutes. You can configure this with a `timeout` option, which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object: diff --git a/api.md b/api.md index 20e776289e..6827b88f0b 100644 --- a/api.md +++ b/api.md @@ -3,10 +3,14 @@ ```python from openai.types import ( ChatModel, + ComparisonFilter, + CompoundFilter, ErrorObject, FunctionDefinition, FunctionParameters, Metadata, + Reasoning, + ReasoningEffort, ResponseFormatJSONObject, ResponseFormatJSONSchema, ResponseFormatText, @@ -59,7 +63,6 @@ from openai.types.chat import ( ChatCompletionModality, ChatCompletionNamedToolChoice, ChatCompletionPredictionContent, - ChatCompletionReasoningEffort, ChatCompletionRole, ChatCompletionStoreMessage, ChatCompletionStreamOptions, @@ -69,6 +72,7 @@ from openai.types.chat import ( ChatCompletionToolChoiceOption, ChatCompletionToolMessageParam, ChatCompletionUserMessageParam, + ChatCompletionReasoningEffort, ) ``` @@ -249,6 +253,73 @@ Methods: - client.fine_tuning.jobs.checkpoints.list(fine_tuning_job_id, \*\*params) -> SyncCursorPage[FineTuningJobCheckpoint] +# VectorStores + +Types: + +```python +from openai.types import ( + AutoFileChunkingStrategyParam, + FileChunkingStrategy, + FileChunkingStrategyParam, + OtherFileChunkingStrategyObject, + StaticFileChunkingStrategy, + StaticFileChunkingStrategyObject, + StaticFileChunkingStrategyObjectParam, + VectorStore, + VectorStoreDeleted, + VectorStoreSearchResponse, +) +``` + +Methods: + +- client.vector_stores.create(\*\*params) -> VectorStore +- client.vector_stores.retrieve(vector_store_id) -> VectorStore +- client.vector_stores.update(vector_store_id, \*\*params) -> VectorStore +- client.vector_stores.list(\*\*params) -> SyncCursorPage[VectorStore] +- client.vector_stores.delete(vector_store_id) -> VectorStoreDeleted +- client.vector_stores.search(vector_store_id, \*\*params) -> SyncPage[VectorStoreSearchResponse] + +## Files + +Types: + +```python +from openai.types.vector_stores import VectorStoreFile, VectorStoreFileDeleted, FileContentResponse +``` + +Methods: + +- client.vector_stores.files.create(vector_store_id, \*\*params) -> VectorStoreFile +- client.vector_stores.files.retrieve(file_id, \*, vector_store_id) -> VectorStoreFile +- client.vector_stores.files.update(file_id, \*, vector_store_id, \*\*params) -> VectorStoreFile +- client.vector_stores.files.list(vector_store_id, \*\*params) -> SyncCursorPage[VectorStoreFile] +- client.vector_stores.files.delete(file_id, \*, vector_store_id) -> VectorStoreFileDeleted +- client.vector_stores.files.content(file_id, \*, vector_store_id) -> SyncPage[FileContentResponse] +- client.vector_stores.files.create_and_poll(\*args) -> VectorStoreFile +- client.vector_stores.files.poll(\*args) -> VectorStoreFile +- client.vector_stores.files.upload(\*args) -> VectorStoreFile +- client.vector_stores.files.upload_and_poll(\*args) -> VectorStoreFile + +## FileBatches + +Types: + +```python +from openai.types.vector_stores import VectorStoreFileBatch +``` + +Methods: + +- client.vector_stores.file_batches.create(vector_store_id, \*\*params) -> VectorStoreFileBatch +- client.vector_stores.file_batches.retrieve(batch_id, \*, vector_store_id) -> VectorStoreFileBatch +- client.vector_stores.file_batches.cancel(batch_id, \*, vector_store_id) -> VectorStoreFileBatch +- client.vector_stores.file_batches.list_files(batch_id, \*, vector_store_id, \*\*params) -> SyncCursorPage[VectorStoreFile] +- client.vector_stores.file_batches.create_and_poll(\*args) -> VectorStoreFileBatch +- client.vector_stores.file_batches.poll(\*args) -> VectorStoreFileBatch +- client.vector_stores.file_batches.upload_and_poll(\*args) -> VectorStoreFileBatch + # Beta ## Realtime @@ -317,69 +388,6 @@ Methods: - client.beta.realtime.sessions.create(\*\*params) -> SessionCreateResponse -## VectorStores - -Types: - -```python -from openai.types.beta import ( - AutoFileChunkingStrategyParam, - FileChunkingStrategy, - FileChunkingStrategyParam, - OtherFileChunkingStrategyObject, - StaticFileChunkingStrategy, - StaticFileChunkingStrategyObject, - StaticFileChunkingStrategyObjectParam, - VectorStore, - VectorStoreDeleted, -) -``` - -Methods: - -- client.beta.vector_stores.create(\*\*params) -> VectorStore -- client.beta.vector_stores.retrieve(vector_store_id) -> VectorStore -- client.beta.vector_stores.update(vector_store_id, \*\*params) -> VectorStore -- client.beta.vector_stores.list(\*\*params) -> SyncCursorPage[VectorStore] -- client.beta.vector_stores.delete(vector_store_id) -> VectorStoreDeleted - -### Files - -Types: - -```python -from openai.types.beta.vector_stores import VectorStoreFile, VectorStoreFileDeleted -``` - -Methods: - -- client.beta.vector_stores.files.create(vector_store_id, \*\*params) -> VectorStoreFile -- client.beta.vector_stores.files.retrieve(file_id, \*, vector_store_id) -> VectorStoreFile -- client.beta.vector_stores.files.list(vector_store_id, \*\*params) -> SyncCursorPage[VectorStoreFile] -- client.beta.vector_stores.files.delete(file_id, \*, vector_store_id) -> VectorStoreFileDeleted -- client.beta.vector_stores.files.create_and_poll(\*args) -> VectorStoreFile -- client.beta.vector_stores.files.poll(\*args) -> VectorStoreFile -- client.beta.vector_stores.files.upload(\*args) -> VectorStoreFile -- client.beta.vector_stores.files.upload_and_poll(\*args) -> VectorStoreFile - -### FileBatches - -Types: - -```python -from openai.types.beta.vector_stores import VectorStoreFileBatch -``` - -Methods: - -- client.beta.vector_stores.file_batches.create(vector_store_id, \*\*params) -> VectorStoreFileBatch -- client.beta.vector_stores.file_batches.retrieve(batch_id, \*, vector_store_id) -> VectorStoreFileBatch -- client.beta.vector_stores.file_batches.cancel(batch_id, \*, vector_store_id) -> VectorStoreFileBatch -- client.beta.vector_stores.file_batches.list_files(batch_id, \*, vector_store_id, \*\*params) -> SyncCursorPage[VectorStoreFile] -- client.beta.vector_stores.file_batches.create_and_poll(\*args) -> VectorStoreFileBatch -- client.beta.vector_stores.file_batches.poll(\*args) -> VectorStoreFileBatch -- client.beta.vector_stores.file_batches.upload_and_poll(\*args) -> VectorStoreFileBatch - ## Assistants Types: @@ -573,3 +581,99 @@ from openai.types.uploads import UploadPart Methods: - client.uploads.parts.create(upload_id, \*\*params) -> UploadPart + +# Responses + +Types: + +```python +from openai.types.responses import ( + ComputerTool, + EasyInputMessage, + FileSearchTool, + FunctionTool, + Response, + ResponseAudioDeltaEvent, + ResponseAudioDoneEvent, + ResponseAudioTranscriptDeltaEvent, + ResponseAudioTranscriptDoneEvent, + ResponseCodeInterpreterCallCodeDeltaEvent, + ResponseCodeInterpreterCallCodeDoneEvent, + ResponseCodeInterpreterCallCompletedEvent, + ResponseCodeInterpreterCallInProgressEvent, + ResponseCodeInterpreterCallInterpretingEvent, + ResponseCodeInterpreterToolCall, + ResponseCompletedEvent, + ResponseComputerToolCall, + ResponseContent, + ResponseContentPartAddedEvent, + ResponseContentPartDoneEvent, + ResponseCreatedEvent, + ResponseError, + ResponseErrorEvent, + ResponseFailedEvent, + ResponseFileSearchCallCompletedEvent, + ResponseFileSearchCallInProgressEvent, + ResponseFileSearchCallSearchingEvent, + ResponseFileSearchToolCall, + ResponseFormatTextConfig, + ResponseFormatTextJSONSchemaConfig, + ResponseFunctionCallArgumentsDeltaEvent, + ResponseFunctionCallArgumentsDoneEvent, + ResponseFunctionToolCall, + ResponseFunctionWebSearch, + ResponseInProgressEvent, + ResponseIncludable, + ResponseIncompleteEvent, + ResponseInput, + ResponseInputAudio, + ResponseInputContent, + ResponseInputFile, + ResponseInputImage, + ResponseInputItem, + ResponseInputMessageContentList, + ResponseInputText, + ResponseOutputAudio, + ResponseOutputItem, + ResponseOutputItemAddedEvent, + ResponseOutputItemDoneEvent, + ResponseOutputMessage, + ResponseOutputRefusal, + ResponseOutputText, + ResponseRefusalDeltaEvent, + ResponseRefusalDoneEvent, + ResponseStatus, + ResponseStreamEvent, + ResponseTextAnnotationDeltaEvent, + ResponseTextConfig, + ResponseTextDeltaEvent, + ResponseTextDoneEvent, + ResponseUsage, + ResponseWebSearchCallCompletedEvent, + ResponseWebSearchCallInProgressEvent, + ResponseWebSearchCallSearchingEvent, + Tool, + ToolChoiceFunction, + ToolChoiceOptions, + ToolChoiceTypes, + WebSearchTool, +) +``` + +Methods: + +- client.responses.create(\*\*params) -> Response +- client.responses.retrieve(response_id, \*\*params) -> Response +- client.responses.delete(response_id) -> None + +## InputItems + +Types: + +```python +from openai.types.responses import ResponseItemList +``` + +Methods: + +- client.responses.input_items.list(response_id, \*\*params) -> SyncCursorPage[Data] diff --git a/examples/responses/__init__.py b/examples/responses/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/responses/streaming.py b/examples/responses/streaming.py new file mode 100644 index 0000000000..39787968d6 --- /dev/null +++ b/examples/responses/streaming.py @@ -0,0 +1,30 @@ +from typing import List + +import rich +from pydantic import BaseModel + +from openai import OpenAI + + +class Step(BaseModel): + explanation: str + output: str + + +class MathResponse(BaseModel): + steps: List[Step] + final_answer: str + + +client = OpenAI() + +with client.responses.stream( + input="solve 8x + 31 = 2", + model="gpt-4o-2024-08-06", + text_format=MathResponse, +) as stream: + for event in stream: + if "output_text" in event.type: + rich.print(event) + +rich.print(stream.get_final_response()) diff --git a/examples/responses/streaming_tools.py b/examples/responses/streaming_tools.py new file mode 100644 index 0000000000..f40cd9356d --- /dev/null +++ b/examples/responses/streaming_tools.py @@ -0,0 +1,68 @@ +from enum import Enum +from typing import List, Union + +import rich +from pydantic import BaseModel + +import openai +from openai import OpenAI + + +class Table(str, Enum): + orders = "orders" + customers = "customers" + products = "products" + + +class Column(str, Enum): + id = "id" + status = "status" + expected_delivery_date = "expected_delivery_date" + delivered_at = "delivered_at" + shipped_at = "shipped_at" + ordered_at = "ordered_at" + canceled_at = "canceled_at" + + +class Operator(str, Enum): + eq = "=" + gt = ">" + lt = "<" + le = "<=" + ge = ">=" + ne = "!=" + + +class OrderBy(str, Enum): + asc = "asc" + desc = "desc" + + +class DynamicValue(BaseModel): + column_name: str + + +class Condition(BaseModel): + column: str + operator: Operator + value: Union[str, int, DynamicValue] + + +class Query(BaseModel): + table_name: Table + columns: List[Column] + conditions: List[Condition] + order_by: OrderBy + + +client = OpenAI() + +with client.responses.stream( + model="gpt-4o-2024-08-06", + input="look up all my orders in november of last year that were fulfilled but not delivered on time", + tools=[ + openai.pydantic_function_tool(Query), + ], +) as stream: + for event in stream: + rich.print(event) diff --git a/examples/responses/structured_outputs.py b/examples/responses/structured_outputs.py new file mode 100644 index 0000000000..0b146bc0bc --- /dev/null +++ b/examples/responses/structured_outputs.py @@ -0,0 +1,55 @@ +from typing import List + +import rich +from pydantic import BaseModel + +from openai import OpenAI + + +class Step(BaseModel): + explanation: str + output: str + + +class MathResponse(BaseModel): + steps: List[Step] + final_answer: str + + +client = OpenAI() + +rsp = client.responses.parse( + input="solve 8x + 31 = 2", + model="gpt-4o-2024-08-06", + text_format=MathResponse, +) + +for output in rsp.output: + if output.type != "message": + raise Exception("Unexpected non message") + + for item in output.content: + if item.type != "output_text": + raise Exception("unexpected output type") + + if not item.parsed: + raise Exception("Could not parse response") + + rich.print(item.parsed) + + print("answer: ", item.parsed.final_answer) + +# or + +message = rsp.output[0] +assert message.type == "message" + +text = message.content[0] +assert text.type == "output_text" + +if not text.parsed: + raise Exception("Could not parse response") + +rich.print(text.parsed) + +print("answer: ", text.parsed.final_answer) diff --git a/examples/responses/structured_outputs_tools.py b/examples/responses/structured_outputs_tools.py new file mode 100644 index 0000000000..918348207d --- /dev/null +++ b/examples/responses/structured_outputs_tools.py @@ -0,0 +1,73 @@ +from enum import Enum +from typing import List, Union + +import rich +from pydantic import BaseModel + +import openai +from openai import OpenAI + + +class Table(str, Enum): + orders = "orders" + customers = "customers" + products = "products" + + +class Column(str, Enum): + id = "id" + status = "status" + expected_delivery_date = "expected_delivery_date" + delivered_at = "delivered_at" + shipped_at = "shipped_at" + ordered_at = "ordered_at" + canceled_at = "canceled_at" + + +class Operator(str, Enum): + eq = "=" + gt = ">" + lt = "<" + le = "<=" + ge = ">=" + ne = "!=" + + +class OrderBy(str, Enum): + asc = "asc" + desc = "desc" + + +class DynamicValue(BaseModel): + column_name: str + + +class Condition(BaseModel): + column: str + operator: Operator + value: Union[str, int, DynamicValue] + + +class Query(BaseModel): + table_name: Table + columns: List[Column] + conditions: List[Condition] + order_by: OrderBy + + +client = OpenAI() + +response = client.responses.parse( + model="gpt-4o-2024-08-06", + input="look up all my orders in november of last year that were fulfilled but not delivered on time", + tools=[ + openai.pydantic_function_tool(Query), + ], +) + +rich.print(response) + +function_call = response.output[0] +assert function_call.type == "function_call" +assert isinstance(function_call.parsed_arguments, Query) +print("table name:", function_call.parsed_arguments.table_name) diff --git a/src/openai/_client.py b/src/openai/_client.py index 2464c6504c..18d96da9a3 100644 --- a/src/openai/_client.py +++ b/src/openai/_client.py @@ -37,7 +37,9 @@ from .resources.chat import chat from .resources.audio import audio from .resources.uploads import uploads +from .resources.responses import responses from .resources.fine_tuning import fine_tuning +from .resources.vector_stores import vector_stores __all__ = ["Timeout", "Transport", "ProxiesTypes", "RequestOptions", "OpenAI", "AsyncOpenAI", "Client", "AsyncClient"] @@ -52,9 +54,11 @@ class OpenAI(SyncAPIClient): moderations: moderations.Moderations models: models.Models fine_tuning: fine_tuning.FineTuning + vector_stores: vector_stores.VectorStores beta: beta.Beta batches: batches.Batches uploads: uploads.Uploads + responses: responses.Responses with_raw_response: OpenAIWithRawResponse with_streaming_response: OpenAIWithStreamedResponse @@ -149,9 +153,11 @@ def __init__( self.moderations = moderations.Moderations(self) self.models = models.Models(self) self.fine_tuning = fine_tuning.FineTuning(self) + self.vector_stores = vector_stores.VectorStores(self) self.beta = beta.Beta(self) self.batches = batches.Batches(self) self.uploads = uploads.Uploads(self) + self.responses = responses.Responses(self) self.with_raw_response = OpenAIWithRawResponse(self) self.with_streaming_response = OpenAIWithStreamedResponse(self) @@ -279,9 +285,11 @@ class AsyncOpenAI(AsyncAPIClient): moderations: moderations.AsyncModerations models: models.AsyncModels fine_tuning: fine_tuning.AsyncFineTuning + vector_stores: vector_stores.AsyncVectorStores beta: beta.AsyncBeta batches: batches.AsyncBatches uploads: uploads.AsyncUploads + responses: responses.AsyncResponses with_raw_response: AsyncOpenAIWithRawResponse with_streaming_response: AsyncOpenAIWithStreamedResponse @@ -376,9 +384,11 @@ def __init__( self.moderations = moderations.AsyncModerations(self) self.models = models.AsyncModels(self) self.fine_tuning = fine_tuning.AsyncFineTuning(self) + self.vector_stores = vector_stores.AsyncVectorStores(self) self.beta = beta.AsyncBeta(self) self.batches = batches.AsyncBatches(self) self.uploads = uploads.AsyncUploads(self) + self.responses = responses.AsyncResponses(self) self.with_raw_response = AsyncOpenAIWithRawResponse(self) self.with_streaming_response = AsyncOpenAIWithStreamedResponse(self) @@ -507,9 +517,11 @@ def __init__(self, client: OpenAI) -> None: self.moderations = moderations.ModerationsWithRawResponse(client.moderations) self.models = models.ModelsWithRawResponse(client.models) self.fine_tuning = fine_tuning.FineTuningWithRawResponse(client.fine_tuning) + self.vector_stores = vector_stores.VectorStoresWithRawResponse(client.vector_stores) self.beta = beta.BetaWithRawResponse(client.beta) self.batches = batches.BatchesWithRawResponse(client.batches) self.uploads = uploads.UploadsWithRawResponse(client.uploads) + self.responses = responses.ResponsesWithRawResponse(client.responses) class AsyncOpenAIWithRawResponse: @@ -523,9 +535,11 @@ def __init__(self, client: AsyncOpenAI) -> None: self.moderations = moderations.AsyncModerationsWithRawResponse(client.moderations) self.models = models.AsyncModelsWithRawResponse(client.models) self.fine_tuning = fine_tuning.AsyncFineTuningWithRawResponse(client.fine_tuning) + self.vector_stores = vector_stores.AsyncVectorStoresWithRawResponse(client.vector_stores) self.beta = beta.AsyncBetaWithRawResponse(client.beta) self.batches = batches.AsyncBatchesWithRawResponse(client.batches) self.uploads = uploads.AsyncUploadsWithRawResponse(client.uploads) + self.responses = responses.AsyncResponsesWithRawResponse(client.responses) class OpenAIWithStreamedResponse: @@ -539,9 +553,11 @@ def __init__(self, client: OpenAI) -> None: self.moderations = moderations.ModerationsWithStreamingResponse(client.moderations) self.models = models.ModelsWithStreamingResponse(client.models) self.fine_tuning = fine_tuning.FineTuningWithStreamingResponse(client.fine_tuning) + self.vector_stores = vector_stores.VectorStoresWithStreamingResponse(client.vector_stores) self.beta = beta.BetaWithStreamingResponse(client.beta) self.batches = batches.BatchesWithStreamingResponse(client.batches) self.uploads = uploads.UploadsWithStreamingResponse(client.uploads) + self.responses = responses.ResponsesWithStreamingResponse(client.responses) class AsyncOpenAIWithStreamedResponse: @@ -555,9 +571,11 @@ def __init__(self, client: AsyncOpenAI) -> None: self.moderations = moderations.AsyncModerationsWithStreamingResponse(client.moderations) self.models = models.AsyncModelsWithStreamingResponse(client.models) self.fine_tuning = fine_tuning.AsyncFineTuningWithStreamingResponse(client.fine_tuning) + self.vector_stores = vector_stores.AsyncVectorStoresWithStreamingResponse(client.vector_stores) self.beta = beta.AsyncBetaWithStreamingResponse(client.beta) self.batches = batches.AsyncBatchesWithStreamingResponse(client.batches) self.uploads = uploads.AsyncUploadsWithStreamingResponse(client.uploads) + self.responses = responses.AsyncResponsesWithStreamingResponse(client.responses) Client = OpenAI diff --git a/src/openai/_streaming.py b/src/openai/_streaming.py index 0fda992cff..9cb72ffe17 100644 --- a/src/openai/_streaming.py +++ b/src/openai/_streaming.py @@ -59,7 +59,7 @@ def __stream__(self) -> Iterator[_T]: if sse.data.startswith("[DONE]"): break - if sse.event is None: + if sse.event is None or sse.event.startswith("response."): data = sse.json() if is_mapping(data) and data.get("error"): message = None @@ -161,7 +161,7 @@ async def __stream__(self) -> AsyncIterator[_T]: if sse.data.startswith("[DONE]"): break - if sse.event is None: + if sse.event is None or sse.event.startswith("response."): data = sse.json() if is_mapping(data) and data.get("error"): message = None diff --git a/src/openai/lib/_parsing/_responses.py b/src/openai/lib/_parsing/_responses.py new file mode 100644 index 0000000000..a189dcf937 --- /dev/null +++ b/src/openai/lib/_parsing/_responses.py @@ -0,0 +1,168 @@ +from __future__ import annotations + +import json +from typing import TYPE_CHECKING, Any, List, Iterable, cast +from typing_extensions import TypeVar, assert_never + +import pydantic + +from .._tools import ResponsesPydanticFunctionTool +from ..._types import NotGiven +from ..._utils import is_given +from ..._compat import PYDANTIC_V2, model_parse_json +from ..._models import construct_type_unchecked +from .._pydantic import is_basemodel_type, is_dataclass_like_type +from ._completions import solve_response_format_t, type_to_response_format_param +from ...types.responses import ( + Response, + ToolParam, + ParsedContent, + ParsedResponse, + FunctionToolParam, + ParsedResponseOutputItem, + ParsedResponseOutputText, + ResponseFunctionToolCall, + ParsedResponseOutputMessage, + ResponseFormatTextConfigParam, + ParsedResponseFunctionToolCall, +) +from ...types.chat.completion_create_params import ResponseFormat + +TextFormatT = TypeVar( + "TextFormatT", + # if it isn't given then we don't do any parsing + default=None, +) + + +def type_to_text_format_param(type_: type) -> ResponseFormatTextConfigParam: + response_format_dict = type_to_response_format_param(type_) + assert is_given(response_format_dict) + response_format_dict = cast(ResponseFormat, response_format_dict) # pyright: ignore[reportUnnecessaryCast] + assert response_format_dict["type"] == "json_schema" + assert "schema" in response_format_dict["json_schema"] + + return { + "type": "json_schema", + "strict": True, + "name": response_format_dict["json_schema"]["name"], + "schema": response_format_dict["json_schema"]["schema"], + } + + +def parse_response( + *, + text_format: type[TextFormatT] | NotGiven, + input_tools: Iterable[ToolParam] | NotGiven | None, + response: Response | ParsedResponse[object], +) -> ParsedResponse[TextFormatT]: + solved_t = solve_response_format_t(text_format) + output_list: List[ParsedResponseOutputItem[TextFormatT]] = [] + + for output in response.output: + if output.type == "message": + content_list: List[ParsedContent[TextFormatT]] = [] + for item in output.content: + if item.type != "output_text": + content_list.append(item) + continue + + content_list.append( + construct_type_unchecked( + type_=cast(Any, ParsedResponseOutputText)[solved_t], + value={ + **item.to_dict(), + "parsed": parse_text(item.text, text_format=text_format), + }, + ) + ) + + output_list.append( + construct_type_unchecked( + type_=cast(Any, ParsedResponseOutputMessage)[solved_t], + value={ + **output.to_dict(), + "content": content_list, + }, + ) + ) + elif output.type == "function_call": + output_list.append( + construct_type_unchecked( + type_=ParsedResponseFunctionToolCall, + value={ + **output.to_dict(), + "parsed_arguments": parse_function_tool_arguments( + input_tools=input_tools, function_call=output + ), + }, + ) + ) + elif ( + output.type == "computer_call" + or output.type == "file_search_call" + or output.type == "web_search_call" + or output.type == "reasoning" + ): + output_list.append(output) + elif TYPE_CHECKING: # type: ignore + assert_never(output) + else: + output_list.append(output) + + return cast( + ParsedResponse[TextFormatT], + construct_type_unchecked( + type_=cast(Any, ParsedResponse)[solved_t], + value={ + **response.to_dict(), + "output": output_list, + }, + ), + ) + + +def parse_text(text: str, text_format: type[TextFormatT] | NotGiven) -> TextFormatT | None: + if not is_given(text_format): + return None + + if is_basemodel_type(text_format): + return cast(TextFormatT, model_parse_json(text_format, text)) + + if is_dataclass_like_type(text_format): + if not PYDANTIC_V2: + raise TypeError(f"Non BaseModel types are only supported with Pydantic v2 - {text_format}") + + return pydantic.TypeAdapter(text_format).validate_json(text) + + raise TypeError(f"Unable to automatically parse response format type {text_format}") + + +def get_input_tool_by_name(*, input_tools: Iterable[ToolParam], name: str) -> FunctionToolParam | None: + for tool in input_tools: + if tool["type"] == "function" and tool.get("name") == name: + return tool + + return None + + +def parse_function_tool_arguments( + *, + input_tools: Iterable[ToolParam] | NotGiven | None, + function_call: ParsedResponseFunctionToolCall | ResponseFunctionToolCall, +) -> object: + if input_tools is None or not is_given(input_tools): + return None + + input_tool = get_input_tool_by_name(input_tools=input_tools, name=function_call.name) + if not input_tool: + return None + + tool = cast(object, input_tool) + if isinstance(tool, ResponsesPydanticFunctionTool): + return model_parse_json(tool.model, function_call.arguments) + + if not input_tool.get("strict"): + return None + + return json.loads(function_call.arguments) diff --git a/src/openai/lib/_tools.py b/src/openai/lib/_tools.py index 8478ed676c..415d750074 100644 --- a/src/openai/lib/_tools.py +++ b/src/openai/lib/_tools.py @@ -7,6 +7,7 @@ from ._pydantic import to_strict_json_schema from ..types.chat import ChatCompletionToolParam from ..types.shared_params import FunctionDefinition +from ..types.responses.function_tool_param import FunctionToolParam as ResponsesFunctionToolParam class PydanticFunctionTool(Dict[str, Any]): @@ -25,6 +26,17 @@ def cast(self) -> FunctionDefinition: return cast(FunctionDefinition, self) +class ResponsesPydanticFunctionTool(Dict[str, Any]): + model: type[pydantic.BaseModel] + + def __init__(self, tool: ResponsesFunctionToolParam, model: type[pydantic.BaseModel]) -> None: + super().__init__(tool) + self.model = model + + def cast(self) -> ResponsesFunctionToolParam: + return cast(ResponsesFunctionToolParam, self) + + def pydantic_function_tool( model: type[pydantic.BaseModel], *, diff --git a/src/openai/lib/streaming/responses/__init__.py b/src/openai/lib/streaming/responses/__init__.py new file mode 100644 index 0000000000..ff073633bf --- /dev/null +++ b/src/openai/lib/streaming/responses/__init__.py @@ -0,0 +1,13 @@ +from ._events import ( + ResponseTextDoneEvent as ResponseTextDoneEvent, + ResponseTextDeltaEvent as ResponseTextDeltaEvent, + ResponseFunctionCallArgumentsDeltaEvent as ResponseFunctionCallArgumentsDeltaEvent, +) +from ._responses import ( + ResponseStream as ResponseStream, + AsyncResponseStream as AsyncResponseStream, + ResponseStreamEvent as ResponseStreamEvent, + ResponseStreamState as ResponseStreamState, + ResponseStreamManager as ResponseStreamManager, + AsyncResponseStreamManager as AsyncResponseStreamManager, +) diff --git a/src/openai/lib/streaming/responses/_events.py b/src/openai/lib/streaming/responses/_events.py new file mode 100644 index 0000000000..fe17edf649 --- /dev/null +++ b/src/openai/lib/streaming/responses/_events.py @@ -0,0 +1,106 @@ +from __future__ import annotations + +from typing import Optional +from typing_extensions import Union, Generic, TypeVar, Annotated, TypeAlias + +from ...._utils import PropertyInfo +from ...._compat import GenericModel +from ....types.responses import ( + ParsedResponse, + ResponseErrorEvent, + ResponseFailedEvent, + ResponseCreatedEvent, + ResponseTextDoneEvent as RawResponseTextDoneEvent, + ResponseAudioDoneEvent, + ResponseCompletedEvent as RawResponseCompletedEvent, + ResponseTextDeltaEvent as RawResponseTextDeltaEvent, + ResponseAudioDeltaEvent, + ResponseIncompleteEvent, + ResponseInProgressEvent, + ResponseRefusalDoneEvent, + ResponseRefusalDeltaEvent, + ResponseOutputItemDoneEvent, + ResponseContentPartDoneEvent, + ResponseOutputItemAddedEvent, + ResponseContentPartAddedEvent, + ResponseAudioTranscriptDoneEvent, + ResponseTextAnnotationDeltaEvent, + ResponseAudioTranscriptDeltaEvent, + ResponseWebSearchCallCompletedEvent, + ResponseWebSearchCallSearchingEvent, + ResponseFileSearchCallCompletedEvent, + ResponseFileSearchCallSearchingEvent, + ResponseWebSearchCallInProgressEvent, + ResponseFileSearchCallInProgressEvent, + ResponseFunctionCallArgumentsDoneEvent, + ResponseFunctionCallArgumentsDeltaEvent as RawResponseFunctionCallArgumentsDeltaEvent, + ResponseCodeInterpreterCallCodeDoneEvent, + ResponseCodeInterpreterCallCodeDeltaEvent, + ResponseCodeInterpreterCallCompletedEvent, + ResponseCodeInterpreterCallInProgressEvent, + ResponseCodeInterpreterCallInterpretingEvent, +) + +TextFormatT = TypeVar( + "TextFormatT", + # if it isn't given then we don't do any parsing + default=None, +) + + +class ResponseTextDeltaEvent(RawResponseTextDeltaEvent): + snapshot: str + + +class ResponseTextDoneEvent(RawResponseTextDoneEvent, GenericModel, Generic[TextFormatT]): + parsed: Optional[TextFormatT] = None + + +class ResponseFunctionCallArgumentsDeltaEvent(RawResponseFunctionCallArgumentsDeltaEvent): + snapshot: str + + +class ResponseCompletedEvent(RawResponseCompletedEvent, GenericModel, Generic[TextFormatT]): + response: ParsedResponse[TextFormatT] # type: ignore[assignment] + + +ResponseStreamEvent: TypeAlias = Annotated[ + Union[ + # wrappers with snapshots added on + ResponseTextDeltaEvent, + ResponseTextDoneEvent[TextFormatT], + ResponseFunctionCallArgumentsDeltaEvent, + ResponseCompletedEvent[TextFormatT], + # the same as the non-accumulated API + ResponseAudioDeltaEvent, + ResponseAudioDoneEvent, + ResponseAudioTranscriptDeltaEvent, + ResponseAudioTranscriptDoneEvent, + ResponseCodeInterpreterCallCodeDeltaEvent, + ResponseCodeInterpreterCallCodeDoneEvent, + ResponseCodeInterpreterCallCompletedEvent, + ResponseCodeInterpreterCallInProgressEvent, + ResponseCodeInterpreterCallInterpretingEvent, + ResponseContentPartAddedEvent, + ResponseContentPartDoneEvent, + ResponseCreatedEvent, + ResponseErrorEvent, + ResponseFileSearchCallCompletedEvent, + ResponseFileSearchCallInProgressEvent, + ResponseFileSearchCallSearchingEvent, + ResponseFunctionCallArgumentsDoneEvent, + ResponseInProgressEvent, + ResponseFailedEvent, + ResponseIncompleteEvent, + ResponseOutputItemAddedEvent, + ResponseOutputItemDoneEvent, + ResponseRefusalDeltaEvent, + ResponseRefusalDoneEvent, + ResponseTextAnnotationDeltaEvent, + ResponseTextDoneEvent, + ResponseWebSearchCallCompletedEvent, + ResponseWebSearchCallInProgressEvent, + ResponseWebSearchCallSearchingEvent, + ], + PropertyInfo(discriminator="type"), +] diff --git a/src/openai/lib/streaming/responses/_responses.py b/src/openai/lib/streaming/responses/_responses.py new file mode 100644 index 0000000000..f8f4b64174 --- /dev/null +++ b/src/openai/lib/streaming/responses/_responses.py @@ -0,0 +1,354 @@ +from __future__ import annotations + +import inspect +from types import TracebackType +from typing import Any, List, Generic, Iterable, Awaitable, cast +from typing_extensions import Self, Callable, Iterator, AsyncIterator + +from ._types import ParsedResponseSnapshot +from ._events import ( + ResponseStreamEvent, + ResponseTextDoneEvent, + ResponseCompletedEvent, + ResponseTextDeltaEvent, + ResponseFunctionCallArgumentsDeltaEvent, +) +from ...._types import NOT_GIVEN, NotGiven +from ...._utils import is_given, consume_sync_iterator, consume_async_iterator +from ...._models import build, construct_type_unchecked +from ...._streaming import Stream, AsyncStream +from ....types.responses import ParsedResponse, ResponseStreamEvent as RawResponseStreamEvent +from ..._parsing._responses import TextFormatT, parse_text, parse_response +from ....types.responses.tool_param import ToolParam +from ....types.responses.parsed_response import ( + ParsedContent, + ParsedResponseOutputMessage, + ParsedResponseFunctionToolCall, +) + + +class ResponseStream(Generic[TextFormatT]): + def __init__( + self, + *, + raw_stream: Stream[RawResponseStreamEvent], + text_format: type[TextFormatT] | NotGiven, + input_tools: Iterable[ToolParam] | NotGiven, + ) -> None: + self._raw_stream = raw_stream + self._response = raw_stream.response + self._iterator = self.__stream__() + self._state = ResponseStreamState(text_format=text_format, input_tools=input_tools) + + def __next__(self) -> ResponseStreamEvent[TextFormatT]: + return self._iterator.__next__() + + def __iter__(self) -> Iterator[ResponseStreamEvent[TextFormatT]]: + for item in self._iterator: + yield item + + def __enter__(self) -> Self: + return self + + def __stream__(self) -> Iterator[ResponseStreamEvent[TextFormatT]]: + for sse_event in self._raw_stream: + events_to_fire = self._state.handle_event(sse_event) + for event in events_to_fire: + yield event + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + self.close() + + def close(self) -> None: + """ + Close the response and release the connection. + + Automatically called if the response body is read to completion. + """ + self._response.close() + + def get_final_response(self) -> ParsedResponse[TextFormatT]: + """Waits until the stream has been read to completion and returns + the accumulated `ParsedResponse` object. + """ + self.until_done() + response = self._state._completed_response + if not response: + raise RuntimeError("Didn't receive a `response.completed` event.") + + return response + + def until_done(self) -> Self: + """Blocks until the stream has been consumed.""" + consume_sync_iterator(self) + return self + + +class ResponseStreamManager(Generic[TextFormatT]): + def __init__( + self, + api_request: Callable[[], Stream[RawResponseStreamEvent]], + *, + text_format: type[TextFormatT] | NotGiven, + input_tools: Iterable[ToolParam] | NotGiven, + ) -> None: + self.__stream: ResponseStream[TextFormatT] | None = None + self.__api_request = api_request + self.__text_format = text_format + self.__input_tools = input_tools + + def __enter__(self) -> ResponseStream[TextFormatT]: + raw_stream = self.__api_request() + + self.__stream = ResponseStream( + raw_stream=raw_stream, + text_format=self.__text_format, + input_tools=self.__input_tools, + ) + + return self.__stream + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + if self.__stream is not None: + self.__stream.close() + + +class AsyncResponseStream(Generic[TextFormatT]): + def __init__( + self, + *, + raw_stream: AsyncStream[RawResponseStreamEvent], + text_format: type[TextFormatT] | NotGiven, + input_tools: Iterable[ToolParam] | NotGiven, + ) -> None: + self._raw_stream = raw_stream + self._response = raw_stream.response + self._iterator = self.__stream__() + self._state = ResponseStreamState(text_format=text_format, input_tools=input_tools) + + async def __anext__(self) -> ResponseStreamEvent[TextFormatT]: + return await self._iterator.__anext__() + + async def __aiter__(self) -> AsyncIterator[ResponseStreamEvent[TextFormatT]]: + async for item in self._iterator: + yield item + + async def __stream__(self) -> AsyncIterator[ResponseStreamEvent[TextFormatT]]: + async for sse_event in self._raw_stream: + events_to_fire = self._state.handle_event(sse_event) + for event in events_to_fire: + yield event + + async def __aenter__(self) -> Self: + return self + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + await self.close() + + async def close(self) -> None: + """ + Close the response and release the connection. + + Automatically called if the response body is read to completion. + """ + await self._response.aclose() + + async def get_final_response(self) -> ParsedResponse[TextFormatT]: + """Waits until the stream has been read to completion and returns + the accumulated `ParsedResponse` object. + """ + await self.until_done() + response = self._state._completed_response + if not response: + raise RuntimeError("Didn't receive a `response.completed` event.") + + return response + + async def until_done(self) -> Self: + """Blocks until the stream has been consumed.""" + await consume_async_iterator(self) + return self + + +class AsyncResponseStreamManager(Generic[TextFormatT]): + def __init__( + self, + api_request: Awaitable[AsyncStream[RawResponseStreamEvent]], + *, + text_format: type[TextFormatT] | NotGiven, + input_tools: Iterable[ToolParam] | NotGiven, + ) -> None: + self.__stream: AsyncResponseStream[TextFormatT] | None = None + self.__api_request = api_request + self.__text_format = text_format + self.__input_tools = input_tools + + async def __aenter__(self) -> AsyncResponseStream[TextFormatT]: + raw_stream = await self.__api_request + + self.__stream = AsyncResponseStream( + raw_stream=raw_stream, + text_format=self.__text_format, + input_tools=self.__input_tools, + ) + + return self.__stream + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + if self.__stream is not None: + await self.__stream.close() + + +class ResponseStreamState(Generic[TextFormatT]): + def __init__( + self, + *, + input_tools: Iterable[ToolParam] | NotGiven, + text_format: type[TextFormatT] | NotGiven, + ) -> None: + self.__current_snapshot: ParsedResponseSnapshot | None = None + self._completed_response: ParsedResponse[TextFormatT] | None = None + self._input_tools = [tool for tool in input_tools] if is_given(input_tools) else [] + self._text_format = text_format + self._rich_text_format: type | NotGiven = text_format if inspect.isclass(text_format) else NOT_GIVEN + + def handle_event(self, event: RawResponseStreamEvent) -> List[ResponseStreamEvent[TextFormatT]]: + self.__current_snapshot = snapshot = self.accumulate_event(event) + + events: List[ResponseStreamEvent[TextFormatT]] = [] + + if event.type == "response.output_text.delta": + output = snapshot.output[event.output_index] + assert output.type == "message" + + content = output.content[event.content_index] + assert content.type == "output_text" + + events.append( + build( + ResponseTextDeltaEvent, + content_index=event.content_index, + delta=event.delta, + item_id=event.item_id, + output_index=event.output_index, + type="response.output_text.delta", + snapshot=content.text, + ) + ) + elif event.type == "response.output_text.done": + output = snapshot.output[event.output_index] + assert output.type == "message" + + content = output.content[event.content_index] + assert content.type == "output_text" + + events.append( + build( + ResponseTextDoneEvent[TextFormatT], + content_index=event.content_index, + item_id=event.item_id, + output_index=event.output_index, + type="response.output_text.done", + text=event.text, + parsed=parse_text(event.text, text_format=self._text_format), + ) + ) + elif event.type == "response.function_call_arguments.delta": + output = snapshot.output[event.output_index] + assert output.type == "function_call" + + events.append( + build( + ResponseFunctionCallArgumentsDeltaEvent, + delta=event.delta, + item_id=event.item_id, + output_index=event.output_index, + type="response.function_call_arguments.delta", + snapshot=output.arguments, + ) + ) + + elif event.type == "response.completed": + response = self._completed_response + assert response is not None + + events.append( + build( + ResponseCompletedEvent, + type="response.completed", + response=response, + ) + ) + else: + events.append(event) + + return events + + def accumulate_event(self, event: RawResponseStreamEvent) -> ParsedResponseSnapshot: + snapshot = self.__current_snapshot + if snapshot is None: + return self._create_initial_response(event) + + if event.type == "response.output_item.added": + if event.item.type == "function_call": + snapshot.output.append( + construct_type_unchecked( + type_=cast(Any, ParsedResponseFunctionToolCall), value=event.item.to_dict() + ) + ) + elif event.item.type == "message": + snapshot.output.append( + construct_type_unchecked(type_=cast(Any, ParsedResponseOutputMessage), value=event.item.to_dict()) + ) + else: + snapshot.output.append(event.item) + elif event.type == "response.content_part.added": + output = snapshot.output[event.output_index] + if output.type == "message": + output.content.append( + construct_type_unchecked(type_=cast(Any, ParsedContent), value=event.part.to_dict()) + ) + elif event.type == "response.output_text.delta": + output = snapshot.output[event.output_index] + if output.type == "message": + content = output.content[event.content_index] + assert content.type == "output_text" + content.text += event.delta + elif event.type == "response.function_call_arguments.delta": + output = snapshot.output[event.output_index] + if output.type == "function_call": + output.arguments += event.delta + elif event.type == "response.completed": + self._completed_response = parse_response( + text_format=self._text_format, + response=event.response, + input_tools=self._input_tools, + ) + + return snapshot + + def _create_initial_response(self, event: RawResponseStreamEvent) -> ParsedResponseSnapshot: + if event.type != "response.created": + raise RuntimeError(f"Expected to have received `response.created` before `{event.type}`") + + return construct_type_unchecked(type_=ParsedResponseSnapshot, value=event.response.to_dict()) diff --git a/src/openai/lib/streaming/responses/_types.py b/src/openai/lib/streaming/responses/_types.py new file mode 100644 index 0000000000..6d3fd90e40 --- /dev/null +++ b/src/openai/lib/streaming/responses/_types.py @@ -0,0 +1,10 @@ +from __future__ import annotations + +from typing_extensions import TypeAlias + +from ....types.responses import ParsedResponse + +ParsedResponseSnapshot: TypeAlias = ParsedResponse[object] +"""Snapshot type representing an in-progress accumulation of +a `ParsedResponse` object. +""" diff --git a/src/openai/resources/__init__.py b/src/openai/resources/__init__.py index e2cc1c4b0c..d3457cf319 100644 --- a/src/openai/resources/__init__.py +++ b/src/openai/resources/__init__.py @@ -64,6 +64,14 @@ UploadsWithStreamingResponse, AsyncUploadsWithStreamingResponse, ) +from .responses import ( + Responses, + AsyncResponses, + ResponsesWithRawResponse, + AsyncResponsesWithRawResponse, + ResponsesWithStreamingResponse, + AsyncResponsesWithStreamingResponse, +) from .embeddings import ( Embeddings, AsyncEmbeddings, @@ -96,6 +104,14 @@ ModerationsWithStreamingResponse, AsyncModerationsWithStreamingResponse, ) +from .vector_stores import ( + VectorStores, + AsyncVectorStores, + VectorStoresWithRawResponse, + AsyncVectorStoresWithRawResponse, + VectorStoresWithStreamingResponse, + AsyncVectorStoresWithStreamingResponse, +) __all__ = [ "Completions", @@ -152,6 +168,12 @@ "AsyncFineTuningWithRawResponse", "FineTuningWithStreamingResponse", "AsyncFineTuningWithStreamingResponse", + "VectorStores", + "AsyncVectorStores", + "VectorStoresWithRawResponse", + "AsyncVectorStoresWithRawResponse", + "VectorStoresWithStreamingResponse", + "AsyncVectorStoresWithStreamingResponse", "Beta", "AsyncBeta", "BetaWithRawResponse", @@ -170,4 +192,10 @@ "AsyncUploadsWithRawResponse", "UploadsWithStreamingResponse", "AsyncUploadsWithStreamingResponse", + "Responses", + "AsyncResponses", + "ResponsesWithRawResponse", + "AsyncResponsesWithRawResponse", + "ResponsesWithStreamingResponse", + "AsyncResponsesWithStreamingResponse", ] diff --git a/src/openai/resources/beta/__init__.py b/src/openai/resources/beta/__init__.py index 01f5338757..87fea25267 100644 --- a/src/openai/resources/beta/__init__.py +++ b/src/openai/resources/beta/__init__.py @@ -24,22 +24,8 @@ AssistantsWithStreamingResponse, AsyncAssistantsWithStreamingResponse, ) -from .vector_stores import ( - VectorStores, - AsyncVectorStores, - VectorStoresWithRawResponse, - AsyncVectorStoresWithRawResponse, - VectorStoresWithStreamingResponse, - AsyncVectorStoresWithStreamingResponse, -) __all__ = [ - "VectorStores", - "AsyncVectorStores", - "VectorStoresWithRawResponse", - "AsyncVectorStoresWithRawResponse", - "VectorStoresWithStreamingResponse", - "AsyncVectorStoresWithStreamingResponse", "Assistants", "AsyncAssistants", "AssistantsWithRawResponse", diff --git a/src/openai/resources/beta/assistants.py b/src/openai/resources/beta/assistants.py index ffecd8f9e9..1c7cbf3737 100644 --- a/src/openai/resources/beta/assistants.py +++ b/src/openai/resources/beta/assistants.py @@ -27,6 +27,7 @@ from ...types.shared.chat_model import ChatModel from ...types.beta.assistant_deleted import AssistantDeleted from ...types.shared_params.metadata import Metadata +from ...types.shared.reasoning_effort import ReasoningEffort from ...types.beta.assistant_tool_param import AssistantToolParam from ...types.beta.assistant_response_format_option_param import AssistantResponseFormatOptionParam @@ -61,7 +62,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, + reasoning_effort: Optional[ReasoningEffort] | 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, @@ -98,7 +99,7 @@ def create( name: The name of the assistant. The maximum length is 256 characters. - reasoning_effort: **o1 and o3-mini models only** + reasoning_effort: **o-series models only** Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently @@ -256,7 +257,7 @@ def update( ] | NotGiven = NOT_GIVEN, name: Optional[str] | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[ReasoningEffort] | 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, @@ -294,7 +295,7 @@ def update( name: The name of the assistant. The maximum length is 256 characters. - reasoning_effort: **o1 and o3-mini models only** + reasoning_effort: **o-series models only** Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently @@ -504,7 +505,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, + reasoning_effort: Optional[ReasoningEffort] | 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, @@ -541,7 +542,7 @@ async def create( name: The name of the assistant. The maximum length is 256 characters. - reasoning_effort: **o1 and o3-mini models only** + reasoning_effort: **o-series models only** Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently @@ -699,7 +700,7 @@ async def update( ] | NotGiven = NOT_GIVEN, name: Optional[str] | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[ReasoningEffort] | 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, @@ -737,7 +738,7 @@ async def update( name: The name of the assistant. The maximum length is 256 characters. - reasoning_effort: **o1 and o3-mini models only** + reasoning_effort: **o-series models only** Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently diff --git a/src/openai/resources/beta/beta.py b/src/openai/resources/beta/beta.py index 5d71cff3f1..62fc8258b9 100644 --- a/src/openai/resources/beta/beta.py +++ b/src/openai/resources/beta/beta.py @@ -29,14 +29,6 @@ RealtimeWithStreamingResponse, AsyncRealtimeWithStreamingResponse, ) -from .vector_stores.vector_stores import ( - VectorStores, - AsyncVectorStores, - VectorStoresWithRawResponse, - AsyncVectorStoresWithRawResponse, - VectorStoresWithStreamingResponse, - AsyncVectorStoresWithStreamingResponse, -) __all__ = ["Beta", "AsyncBeta"] @@ -50,10 +42,6 @@ def chat(self) -> Chat: def realtime(self) -> Realtime: return Realtime(self._client) - @cached_property - def vector_stores(self) -> VectorStores: - return VectorStores(self._client) - @cached_property def assistants(self) -> Assistants: return Assistants(self._client) @@ -91,10 +79,6 @@ def chat(self) -> AsyncChat: def realtime(self) -> AsyncRealtime: return AsyncRealtime(self._client) - @cached_property - def vector_stores(self) -> AsyncVectorStores: - return AsyncVectorStores(self._client) - @cached_property def assistants(self) -> AsyncAssistants: return AsyncAssistants(self._client) @@ -131,10 +115,6 @@ def __init__(self, beta: Beta) -> None: def realtime(self) -> RealtimeWithRawResponse: return RealtimeWithRawResponse(self._beta.realtime) - @cached_property - def vector_stores(self) -> VectorStoresWithRawResponse: - return VectorStoresWithRawResponse(self._beta.vector_stores) - @cached_property def assistants(self) -> AssistantsWithRawResponse: return AssistantsWithRawResponse(self._beta.assistants) @@ -152,10 +132,6 @@ def __init__(self, beta: AsyncBeta) -> None: def realtime(self) -> AsyncRealtimeWithRawResponse: return AsyncRealtimeWithRawResponse(self._beta.realtime) - @cached_property - def vector_stores(self) -> AsyncVectorStoresWithRawResponse: - return AsyncVectorStoresWithRawResponse(self._beta.vector_stores) - @cached_property def assistants(self) -> AsyncAssistantsWithRawResponse: return AsyncAssistantsWithRawResponse(self._beta.assistants) @@ -173,10 +149,6 @@ def __init__(self, beta: Beta) -> None: def realtime(self) -> RealtimeWithStreamingResponse: return RealtimeWithStreamingResponse(self._beta.realtime) - @cached_property - def vector_stores(self) -> VectorStoresWithStreamingResponse: - return VectorStoresWithStreamingResponse(self._beta.vector_stores) - @cached_property def assistants(self) -> AssistantsWithStreamingResponse: return AssistantsWithStreamingResponse(self._beta.assistants) @@ -194,10 +166,6 @@ def __init__(self, beta: AsyncBeta) -> None: def realtime(self) -> AsyncRealtimeWithStreamingResponse: return AsyncRealtimeWithStreamingResponse(self._beta.realtime) - @cached_property - def vector_stores(self) -> AsyncVectorStoresWithStreamingResponse: - return AsyncVectorStoresWithStreamingResponse(self._beta.vector_stores) - @cached_property def assistants(self) -> AsyncAssistantsWithStreamingResponse: return AsyncAssistantsWithStreamingResponse(self._beta.assistants) diff --git a/src/openai/resources/beta/chat/completions.py b/src/openai/resources/beta/chat/completions.py index 0c631b9821..545a3f4087 100644 --- a/src/openai/resources/beta/chat/completions.py +++ b/src/openai/resources/beta/chat/completions.py @@ -15,10 +15,7 @@ from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper from ...._streaming import Stream -from ....types.chat import ( - ChatCompletionReasoningEffort, - completion_create_params, -) +from ....types.chat import completion_create_params from ...._base_client import make_request_options from ....lib._parsing import ( ResponseFormatT, @@ -28,11 +25,10 @@ ) from ....types.chat_model import ChatModel from ....lib.streaming.chat import ChatCompletionStreamManager, AsyncChatCompletionStreamManager -from ....types.shared_params import Metadata +from ....types.shared_params import Metadata, ReasoningEffort from ....types.chat.chat_completion import ChatCompletion from ....types.chat.chat_completion_chunk import ChatCompletionChunk from ....types.chat.parsed_chat_completion import ParsedChatCompletion -from ....types.chat.chat_completion_modality import ChatCompletionModality from ....types.chat.chat_completion_tool_param import ChatCompletionToolParam from ....types.chat.chat_completion_audio_param import ChatCompletionAudioParam from ....types.chat.chat_completion_message_param import ChatCompletionMessageParam @@ -78,15 +74,15 @@ def parse( max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, + modalities: Optional[List[Literal["text", "audio"]]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ChatCompletionReasoningEffort] | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[ReasoningEffort] | 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, + stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -95,6 +91,7 @@ def parse( top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, + web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -192,6 +189,7 @@ def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseForma "top_logprobs": top_logprobs, "top_p": top_p, "user": user, + "web_search_options": web_search_options, }, completion_create_params.CompletionCreateParams, ), @@ -223,15 +221,15 @@ def stream( max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, + modalities: Optional[List[Literal["text", "audio"]]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ChatCompletionReasoningEffort] | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[ReasoningEffort] | 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, + stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -240,6 +238,7 @@ def stream( top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, + web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -306,6 +305,7 @@ def stream( top_logprobs=top_logprobs, top_p=top_p, user=user, + web_search_options=web_search_options, extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, @@ -353,15 +353,15 @@ async def parse( max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, + modalities: Optional[List[Literal["text", "audio"]]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ChatCompletionReasoningEffort] | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[ReasoningEffort] | 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, + stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -370,6 +370,7 @@ async def parse( top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, + web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -467,6 +468,7 @@ def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseForma "top_logprobs": top_logprobs, "top_p": top_p, "user": user, + "web_search_options": web_search_options, }, completion_create_params.CompletionCreateParams, ), @@ -498,15 +500,15 @@ def stream( max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, + modalities: Optional[List[Literal["text", "audio"]]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ChatCompletionReasoningEffort] | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[ReasoningEffort] | 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, + stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -515,6 +517,7 @@ def stream( top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, + web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -586,6 +589,7 @@ def stream( extra_query=extra_query, extra_body=extra_body, timeout=timeout, + web_search_options=web_search_options, ) return AsyncChatCompletionStreamManager( api_request, diff --git a/src/openai/resources/beta/threads/runs/runs.py b/src/openai/resources/beta/threads/runs/runs.py index b819678be6..acb1c9b261 100644 --- a/src/openai/resources/beta/threads/runs/runs.py +++ b/src/openai/resources/beta/threads/runs/runs.py @@ -48,6 +48,7 @@ from .....types.beta.threads.run import Run from .....types.shared.chat_model import ChatModel from .....types.shared_params.metadata import Metadata +from .....types.shared.reasoning_effort import ReasoningEffort from .....types.beta.assistant_tool_param import AssistantToolParam from .....types.beta.assistant_stream_event import AssistantStreamEvent from .....types.beta.threads.runs.run_step_include import RunStepInclude @@ -96,7 +97,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, + reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -165,7 +166,7 @@ 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** + reasoning_effort: **o-series models only** Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently @@ -247,7 +248,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, + reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, @@ -319,7 +320,7 @@ 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** + reasoning_effort: **o-series models only** Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently @@ -397,7 +398,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, + reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, @@ -469,7 +470,7 @@ 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** + reasoning_effort: **o-series models only** Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently @@ -546,7 +547,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, + reasoning_effort: Optional[ReasoningEffort] | 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, @@ -800,7 +801,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, + reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, @@ -871,7 +872,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, + reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, @@ -903,7 +904,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, + reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, @@ -935,7 +936,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, + reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, @@ -1054,7 +1055,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, + reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, @@ -1086,7 +1087,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, + reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, @@ -1118,7 +1119,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, + reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, @@ -1505,7 +1506,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, + reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -1574,7 +1575,7 @@ 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** + reasoning_effort: **o-series models only** Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently @@ -1656,7 +1657,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, + reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, @@ -1728,7 +1729,7 @@ 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** + reasoning_effort: **o-series models only** Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently @@ -1806,7 +1807,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, + reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, @@ -1878,7 +1879,7 @@ 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** + reasoning_effort: **o-series models only** Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently @@ -1955,7 +1956,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, + reasoning_effort: Optional[ReasoningEffort] | 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, @@ -2209,7 +2210,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, + reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, @@ -2460,7 +2461,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, + reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, @@ -2492,7 +2493,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, + reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, @@ -2524,7 +2525,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, + reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index 708b1ff166..d28be012c9 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -31,7 +31,6 @@ from ....pagination import SyncCursorPage, AsyncCursorPage from ....types.chat import ( ChatCompletionAudioParam, - ChatCompletionReasoningEffort, completion_list_params, completion_create_params, completion_update_params, @@ -40,13 +39,12 @@ from ....types.shared.chat_model import ChatModel from ....types.chat.chat_completion import ChatCompletion from ....types.shared_params.metadata import Metadata +from ....types.shared.reasoning_effort import ReasoningEffort from ....types.chat.chat_completion_chunk import ChatCompletionChunk from ....types.chat.chat_completion_deleted import ChatCompletionDeleted -from ....types.chat.chat_completion_modality import ChatCompletionModality from ....types.chat.chat_completion_tool_param import ChatCompletionToolParam from ....types.chat.chat_completion_audio_param import ChatCompletionAudioParam from ....types.chat.chat_completion_message_param import ChatCompletionMessageParam -from ....types.chat.chat_completion_reasoning_effort import ChatCompletionReasoningEffort from ....types.chat.chat_completion_stream_options_param import ChatCompletionStreamOptionsParam from ....types.chat.chat_completion_prediction_content_param import ChatCompletionPredictionContentParam from ....types.chat.chat_completion_tool_choice_option_param import ChatCompletionToolChoiceOptionParam @@ -93,16 +91,16 @@ def create( max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, + modalities: Optional[List[Literal["text", "audio"]]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ChatCompletionReasoningEffort] | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[ReasoningEffort] | 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, - stop: Union[Optional[str], List[str]] | NotGiven = NOT_GIVEN, + stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, @@ -112,6 +110,7 @@ def create( top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, + web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -119,9 +118,15 @@ def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> ChatCompletion: - """Creates a model response for the given chat conversation. + """ + **Starting a new project?** We recommend trying + [Responses](https://platform.openai.com/docs/api-reference/responses) to take + advantage of the latest OpenAI platform features. Compare + [Chat Completions with Responses](https://platform.openai.com/docs/guides/responses-vs-chat-completions?api-mode=responses). + + --- - Learn more in the + Creates a model response for the given chat conversation. Learn more in the [text generation](https://platform.openai.com/docs/guides/text-generation), [vision](https://platform.openai.com/docs/guides/vision), and [audio](https://platform.openai.com/docs/guides/audio) guides. @@ -140,9 +145,11 @@ def create( [images](https://platform.openai.com/docs/guides/vision), and [audio](https://platform.openai.com/docs/guides/audio). - model: ID of the model to use. See the - [model endpoint compatibility](https://platform.openai.com/docs/models#model-endpoint-compatibility) - table for details on which models work with the Chat API. + model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a + wide range of models with different capabilities, performance characteristics, + and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. audio: Parameters for audio output. Required when audio output is requested with `modalities: ["audio"]`. @@ -203,8 +210,8 @@ def create( Keys are strings with a maximum length of 64 characters. Values are strings with a maximum length of 512 characters. - modalities: Output types that you would like the model to generate for this request. Most - models are capable of generating text, which is the default: + modalities: Output types that you would like the model to generate. Most models are capable + of generating text, which is the default: `["text"]` @@ -229,7 +236,7 @@ def create( whether they appear in the text so far, increasing the model's likelihood to talk about new topics. - reasoning_effort: **o1 and o3-mini models only** + reasoning_effort: **o-series models only** Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently @@ -243,16 +250,9 @@ def create( in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the - message the model generates is valid JSON. - - **Important:** when using JSON mode, you **must** also instruct the model to - produce JSON yourself via a system or user message. Without this, the model may - generate an unending stream of whitespace until the generation reaches the token - limit, resulting in a long-running and seemingly "stuck" request. Also note that - the message content may be partially cut off if `finish_reason="length"`, which - indicates the generation exceeded `max_tokens` or the conversation exceeded the - max context length. + Setting to `{ "type": "json_object" }` enables the older JSON mode, which + ensures the message the model generates is valid JSON. Using `json_schema` is + preferred for models that support it. seed: This feature is in Beta. If specified, our system will make a best effort to sample deterministically, such that repeated requests with the same `seed` and @@ -267,23 +267,29 @@ def create( utilize scale tier credits until they are exhausted. - If set to 'auto', and the Project is not Scale tier enabled, the request will be processed using the default service tier with a lower uptime SLA and no - latency guarantee. + latency guarentee. - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarantee. + tier with a lower uptime SLA and no latency guarentee. - When not set, the default behavior is 'auto'. - stop: Up to 4 sequences where the API will stop generating further tokens. + When this parameter is set, the response body will include the `service_tier` + utilized. + + stop: Up to 4 sequences where the API will stop generating further tokens. The + returned text will not contain the stop sequence. store: Whether or not to store the output of this chat completion request for use in our [model distillation](https://platform.openai.com/docs/guides/distillation) or [evals](https://platform.openai.com/docs/guides/evals) products. - stream: If set, partial message deltas will be sent, like in ChatGPT. Tokens will be - sent as data-only - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format) - as they become available, with the stream terminated by a `data: [DONE]` - message. - [Example Python code](https://cookbook.openai.com/examples/how_to_stream_completions). + stream: If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section below](https://platform.openai.com/docs/api-reference/chat/streaming) + for more information, along with the + [streaming responses](https://platform.openai.com/docs/guides/streaming-responses) + guide for more information on how to handle the streaming events. stream_options: Options for streaming response. Only set this when you set `stream: true`. @@ -320,6 +326,10 @@ def create( and detect abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + web_search_options: This tool searches the web for relevant results to use in a response. Learn more + about the + [web search tool](https://platform.openai.com/docs/guides/tools-web-search?api-mode=chat). + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -346,16 +356,16 @@ def create( max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, + modalities: Optional[List[Literal["text", "audio"]]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ChatCompletionReasoningEffort] | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[ReasoningEffort] | 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, - stop: Union[Optional[str], List[str]] | NotGiven = NOT_GIVEN, + stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -364,6 +374,7 @@ def create( top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, + web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -371,9 +382,15 @@ def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> Stream[ChatCompletionChunk]: - """Creates a model response for the given chat conversation. + """ + **Starting a new project?** We recommend trying + [Responses](https://platform.openai.com/docs/api-reference/responses) to take + advantage of the latest OpenAI platform features. Compare + [Chat Completions with Responses](https://platform.openai.com/docs/guides/responses-vs-chat-completions?api-mode=responses). + + --- - Learn more in the + Creates a model response for the given chat conversation. Learn more in the [text generation](https://platform.openai.com/docs/guides/text-generation), [vision](https://platform.openai.com/docs/guides/vision), and [audio](https://platform.openai.com/docs/guides/audio) guides. @@ -392,16 +409,20 @@ def create( [images](https://platform.openai.com/docs/guides/vision), and [audio](https://platform.openai.com/docs/guides/audio). - model: ID of the model to use. See the - [model endpoint compatibility](https://platform.openai.com/docs/models#model-endpoint-compatibility) - table for details on which models work with the Chat API. - - stream: If set, partial message deltas will be sent, like in ChatGPT. Tokens will be - sent as data-only - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format) - as they become available, with the stream terminated by a `data: [DONE]` - message. - [Example Python code](https://cookbook.openai.com/examples/how_to_stream_completions). + model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a + wide range of models with different capabilities, performance characteristics, + and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + + stream: If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section below](https://platform.openai.com/docs/api-reference/chat/streaming) + for more information, along with the + [streaming responses](https://platform.openai.com/docs/guides/streaming-responses) + guide for more information on how to handle the streaming events. audio: Parameters for audio output. Required when audio output is requested with `modalities: ["audio"]`. @@ -462,8 +483,8 @@ def create( Keys are strings with a maximum length of 64 characters. Values are strings with a maximum length of 512 characters. - modalities: Output types that you would like the model to generate for this request. Most - models are capable of generating text, which is the default: + modalities: Output types that you would like the model to generate. Most models are capable + of generating text, which is the default: `["text"]` @@ -488,7 +509,7 @@ def create( whether they appear in the text so far, increasing the model's likelihood to talk about new topics. - reasoning_effort: **o1 and o3-mini models only** + reasoning_effort: **o-series models only** Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently @@ -502,16 +523,9 @@ def create( in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the - message the model generates is valid JSON. - - **Important:** when using JSON mode, you **must** also instruct the model to - produce JSON yourself via a system or user message. Without this, the model may - generate an unending stream of whitespace until the generation reaches the token - limit, resulting in a long-running and seemingly "stuck" request. Also note that - the message content may be partially cut off if `finish_reason="length"`, which - indicates the generation exceeded `max_tokens` or the conversation exceeded the - max context length. + Setting to `{ "type": "json_object" }` enables the older JSON mode, which + ensures the message the model generates is valid JSON. Using `json_schema` is + preferred for models that support it. seed: This feature is in Beta. If specified, our system will make a best effort to sample deterministically, such that repeated requests with the same `seed` and @@ -526,12 +540,16 @@ def create( utilize scale tier credits until they are exhausted. - If set to 'auto', and the Project is not Scale tier enabled, the request will be processed using the default service tier with a lower uptime SLA and no - latency guarantee. + latency guarentee. - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarantee. + tier with a lower uptime SLA and no latency guarentee. - When not set, the default behavior is 'auto'. - stop: Up to 4 sequences where the API will stop generating further tokens. + When this parameter is set, the response body will include the `service_tier` + utilized. + + stop: Up to 4 sequences where the API will stop generating further tokens. The + returned text will not contain the stop sequence. store: Whether or not to store the output of this chat completion request for use in our [model distillation](https://platform.openai.com/docs/guides/distillation) @@ -572,6 +590,10 @@ def create( and detect abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + web_search_options: This tool searches the web for relevant results to use in a response. Learn more + about the + [web search tool](https://platform.openai.com/docs/guides/tools-web-search?api-mode=chat). + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -598,16 +620,16 @@ def create( max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, + modalities: Optional[List[Literal["text", "audio"]]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ChatCompletionReasoningEffort] | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[ReasoningEffort] | 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, - stop: Union[Optional[str], List[str]] | NotGiven = NOT_GIVEN, + stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -616,6 +638,7 @@ def create( top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, + web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -623,9 +646,15 @@ def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> ChatCompletion | Stream[ChatCompletionChunk]: - """Creates a model response for the given chat conversation. + """ + **Starting a new project?** We recommend trying + [Responses](https://platform.openai.com/docs/api-reference/responses) to take + advantage of the latest OpenAI platform features. Compare + [Chat Completions with Responses](https://platform.openai.com/docs/guides/responses-vs-chat-completions?api-mode=responses). + + --- - Learn more in the + Creates a model response for the given chat conversation. Learn more in the [text generation](https://platform.openai.com/docs/guides/text-generation), [vision](https://platform.openai.com/docs/guides/vision), and [audio](https://platform.openai.com/docs/guides/audio) guides. @@ -644,16 +673,20 @@ def create( [images](https://platform.openai.com/docs/guides/vision), and [audio](https://platform.openai.com/docs/guides/audio). - model: ID of the model to use. See the - [model endpoint compatibility](https://platform.openai.com/docs/models#model-endpoint-compatibility) - table for details on which models work with the Chat API. - - stream: If set, partial message deltas will be sent, like in ChatGPT. Tokens will be - sent as data-only - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format) - as they become available, with the stream terminated by a `data: [DONE]` - message. - [Example Python code](https://cookbook.openai.com/examples/how_to_stream_completions). + model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a + wide range of models with different capabilities, performance characteristics, + and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + + stream: If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section below](https://platform.openai.com/docs/api-reference/chat/streaming) + for more information, along with the + [streaming responses](https://platform.openai.com/docs/guides/streaming-responses) + guide for more information on how to handle the streaming events. audio: Parameters for audio output. Required when audio output is requested with `modalities: ["audio"]`. @@ -714,8 +747,8 @@ def create( Keys are strings with a maximum length of 64 characters. Values are strings with a maximum length of 512 characters. - modalities: Output types that you would like the model to generate for this request. Most - models are capable of generating text, which is the default: + modalities: Output types that you would like the model to generate. Most models are capable + of generating text, which is the default: `["text"]` @@ -740,7 +773,7 @@ def create( whether they appear in the text so far, increasing the model's likelihood to talk about new topics. - reasoning_effort: **o1 and o3-mini models only** + reasoning_effort: **o-series models only** Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently @@ -754,16 +787,9 @@ def create( in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the - message the model generates is valid JSON. - - **Important:** when using JSON mode, you **must** also instruct the model to - produce JSON yourself via a system or user message. Without this, the model may - generate an unending stream of whitespace until the generation reaches the token - limit, resulting in a long-running and seemingly "stuck" request. Also note that - the message content may be partially cut off if `finish_reason="length"`, which - indicates the generation exceeded `max_tokens` or the conversation exceeded the - max context length. + Setting to `{ "type": "json_object" }` enables the older JSON mode, which + ensures the message the model generates is valid JSON. Using `json_schema` is + preferred for models that support it. seed: This feature is in Beta. If specified, our system will make a best effort to sample deterministically, such that repeated requests with the same `seed` and @@ -778,12 +804,16 @@ def create( utilize scale tier credits until they are exhausted. - If set to 'auto', and the Project is not Scale tier enabled, the request will be processed using the default service tier with a lower uptime SLA and no - latency guarantee. + latency guarentee. - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarantee. + tier with a lower uptime SLA and no latency guarentee. - When not set, the default behavior is 'auto'. - stop: Up to 4 sequences where the API will stop generating further tokens. + When this parameter is set, the response body will include the `service_tier` + utilized. + + stop: Up to 4 sequences where the API will stop generating further tokens. The + returned text will not contain the stop sequence. store: Whether or not to store the output of this chat completion request for use in our [model distillation](https://platform.openai.com/docs/guides/distillation) @@ -824,6 +854,10 @@ def create( and detect abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + web_search_options: This tool searches the web for relevant results to use in a response. Learn more + about the + [web search tool](https://platform.openai.com/docs/guides/tools-web-search?api-mode=chat). + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -849,16 +883,16 @@ def create( max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, + modalities: Optional[List[Literal["text", "audio"]]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ChatCompletionReasoningEffort] | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[ReasoningEffort] | 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, - stop: Union[Optional[str], List[str]] | NotGiven = NOT_GIVEN, + stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, @@ -868,6 +902,7 @@ def create( top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, + web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -910,6 +945,7 @@ def create( "top_logprobs": top_logprobs, "top_p": top_p, "user": user, + "web_search_options": web_search_options, }, completion_create_params.CompletionCreateParams, ), @@ -934,7 +970,7 @@ def retrieve( ) -> ChatCompletion: """Get a stored chat completion. - Only chat completions that have been created with + Only Chat Completions that have been created with the `store` parameter set to `true` will be returned. Args: @@ -970,7 +1006,7 @@ def update( ) -> ChatCompletion: """Modify a stored chat completion. - Only chat completions that have been created + Only Chat Completions that have been created with the `store` parameter set to `true` can be modified. Currently, the only supported modification is to update the `metadata` field. @@ -1016,24 +1052,24 @@ def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> SyncCursorPage[ChatCompletion]: - """List stored chat completions. + """List stored Chat Completions. - Only chat completions that have been stored with + Only Chat Completions that have been stored with the `store` parameter set to `true` will be returned. Args: after: Identifier for the last chat completion from the previous pagination request. - limit: Number of chat completions to retrieve. + limit: Number of Chat Completions to retrieve. metadata: - A list of metadata keys to filter the chat completions by. Example: + A list of metadata keys to filter the Chat Completions by. Example: `metadata[key1]=value1&metadata[key2]=value2` - model: The model used to generate the chat completions. + model: The model used to generate the Chat Completions. - order: Sort order for chat completions by timestamp. Use `asc` for ascending order or + order: Sort order for Chat Completions by timestamp. Use `asc` for ascending order or `desc` for descending order. Defaults to `asc`. extra_headers: Send extra headers @@ -1079,7 +1115,7 @@ def delete( ) -> ChatCompletionDeleted: """Delete a stored chat completion. - Only chat completions that have been created + Only Chat Completions that have been created with the `store` parameter set to `true` can be deleted. Args: @@ -1141,16 +1177,16 @@ async def create( max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, + modalities: Optional[List[Literal["text", "audio"]]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ChatCompletionReasoningEffort] | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[ReasoningEffort] | 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, - stop: Union[Optional[str], List[str]] | NotGiven = NOT_GIVEN, + stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, @@ -1160,6 +1196,7 @@ async def create( top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, + web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1167,9 +1204,15 @@ async def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> ChatCompletion: - """Creates a model response for the given chat conversation. + """ + **Starting a new project?** We recommend trying + [Responses](https://platform.openai.com/docs/api-reference/responses) to take + advantage of the latest OpenAI platform features. Compare + [Chat Completions with Responses](https://platform.openai.com/docs/guides/responses-vs-chat-completions?api-mode=responses). + + --- - Learn more in the + Creates a model response for the given chat conversation. Learn more in the [text generation](https://platform.openai.com/docs/guides/text-generation), [vision](https://platform.openai.com/docs/guides/vision), and [audio](https://platform.openai.com/docs/guides/audio) guides. @@ -1188,9 +1231,11 @@ async def create( [images](https://platform.openai.com/docs/guides/vision), and [audio](https://platform.openai.com/docs/guides/audio). - model: ID of the model to use. See the - [model endpoint compatibility](https://platform.openai.com/docs/models#model-endpoint-compatibility) - table for details on which models work with the Chat API. + model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a + wide range of models with different capabilities, performance characteristics, + and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. audio: Parameters for audio output. Required when audio output is requested with `modalities: ["audio"]`. @@ -1251,8 +1296,8 @@ async def create( Keys are strings with a maximum length of 64 characters. Values are strings with a maximum length of 512 characters. - modalities: Output types that you would like the model to generate for this request. Most - models are capable of generating text, which is the default: + modalities: Output types that you would like the model to generate. Most models are capable + of generating text, which is the default: `["text"]` @@ -1277,7 +1322,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 and o3-mini models only** + reasoning_effort: **o-series models only** Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently @@ -1291,16 +1336,9 @@ async def create( in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the - message the model generates is valid JSON. - - **Important:** when using JSON mode, you **must** also instruct the model to - produce JSON yourself via a system or user message. Without this, the model may - generate an unending stream of whitespace until the generation reaches the token - limit, resulting in a long-running and seemingly "stuck" request. Also note that - the message content may be partially cut off if `finish_reason="length"`, which - indicates the generation exceeded `max_tokens` or the conversation exceeded the - max context length. + Setting to `{ "type": "json_object" }` enables the older JSON mode, which + ensures the message the model generates is valid JSON. Using `json_schema` is + preferred for models that support it. seed: This feature is in Beta. If specified, our system will make a best effort to sample deterministically, such that repeated requests with the same `seed` and @@ -1315,23 +1353,29 @@ async def create( utilize scale tier credits until they are exhausted. - If set to 'auto', and the Project is not Scale tier enabled, the request will be processed using the default service tier with a lower uptime SLA and no - latency guarantee. + latency guarentee. - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarantee. + tier with a lower uptime SLA and no latency guarentee. - When not set, the default behavior is 'auto'. - stop: Up to 4 sequences where the API will stop generating further tokens. + When this parameter is set, the response body will include the `service_tier` + utilized. + + stop: Up to 4 sequences where the API will stop generating further tokens. The + returned text will not contain the stop sequence. store: Whether or not to store the output of this chat completion request for use in our [model distillation](https://platform.openai.com/docs/guides/distillation) or [evals](https://platform.openai.com/docs/guides/evals) products. - stream: If set, partial message deltas will be sent, like in ChatGPT. Tokens will be - sent as data-only - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format) - as they become available, with the stream terminated by a `data: [DONE]` - message. - [Example Python code](https://cookbook.openai.com/examples/how_to_stream_completions). + stream: If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section below](https://platform.openai.com/docs/api-reference/chat/streaming) + for more information, along with the + [streaming responses](https://platform.openai.com/docs/guides/streaming-responses) + guide for more information on how to handle the streaming events. stream_options: Options for streaming response. Only set this when you set `stream: true`. @@ -1368,6 +1412,10 @@ async def create( and detect abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + web_search_options: This tool searches the web for relevant results to use in a response. Learn more + about the + [web search tool](https://platform.openai.com/docs/guides/tools-web-search?api-mode=chat). + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -1394,16 +1442,16 @@ async def create( max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, + modalities: Optional[List[Literal["text", "audio"]]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ChatCompletionReasoningEffort] | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[ReasoningEffort] | 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, - stop: Union[Optional[str], List[str]] | NotGiven = NOT_GIVEN, + stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -1412,6 +1460,7 @@ async def create( top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, + web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1419,9 +1468,15 @@ async def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> AsyncStream[ChatCompletionChunk]: - """Creates a model response for the given chat conversation. + """ + **Starting a new project?** We recommend trying + [Responses](https://platform.openai.com/docs/api-reference/responses) to take + advantage of the latest OpenAI platform features. Compare + [Chat Completions with Responses](https://platform.openai.com/docs/guides/responses-vs-chat-completions?api-mode=responses). + + --- - Learn more in the + Creates a model response for the given chat conversation. Learn more in the [text generation](https://platform.openai.com/docs/guides/text-generation), [vision](https://platform.openai.com/docs/guides/vision), and [audio](https://platform.openai.com/docs/guides/audio) guides. @@ -1440,16 +1495,20 @@ async def create( [images](https://platform.openai.com/docs/guides/vision), and [audio](https://platform.openai.com/docs/guides/audio). - model: ID of the model to use. See the - [model endpoint compatibility](https://platform.openai.com/docs/models#model-endpoint-compatibility) - table for details on which models work with the Chat API. - - stream: If set, partial message deltas will be sent, like in ChatGPT. Tokens will be - sent as data-only - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format) - as they become available, with the stream terminated by a `data: [DONE]` - message. - [Example Python code](https://cookbook.openai.com/examples/how_to_stream_completions). + model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a + wide range of models with different capabilities, performance characteristics, + and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + + stream: If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section below](https://platform.openai.com/docs/api-reference/chat/streaming) + for more information, along with the + [streaming responses](https://platform.openai.com/docs/guides/streaming-responses) + guide for more information on how to handle the streaming events. audio: Parameters for audio output. Required when audio output is requested with `modalities: ["audio"]`. @@ -1510,8 +1569,8 @@ async def create( Keys are strings with a maximum length of 64 characters. Values are strings with a maximum length of 512 characters. - modalities: Output types that you would like the model to generate for this request. Most - models are capable of generating text, which is the default: + modalities: Output types that you would like the model to generate. Most models are capable + of generating text, which is the default: `["text"]` @@ -1536,7 +1595,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 and o3-mini models only** + reasoning_effort: **o-series models only** Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently @@ -1550,16 +1609,9 @@ async def create( in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the - message the model generates is valid JSON. - - **Important:** when using JSON mode, you **must** also instruct the model to - produce JSON yourself via a system or user message. Without this, the model may - generate an unending stream of whitespace until the generation reaches the token - limit, resulting in a long-running and seemingly "stuck" request. Also note that - the message content may be partially cut off if `finish_reason="length"`, which - indicates the generation exceeded `max_tokens` or the conversation exceeded the - max context length. + Setting to `{ "type": "json_object" }` enables the older JSON mode, which + ensures the message the model generates is valid JSON. Using `json_schema` is + preferred for models that support it. seed: This feature is in Beta. If specified, our system will make a best effort to sample deterministically, such that repeated requests with the same `seed` and @@ -1574,12 +1626,16 @@ async def create( utilize scale tier credits until they are exhausted. - If set to 'auto', and the Project is not Scale tier enabled, the request will be processed using the default service tier with a lower uptime SLA and no - latency guarantee. + latency guarentee. - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarantee. + tier with a lower uptime SLA and no latency guarentee. - When not set, the default behavior is 'auto'. - stop: Up to 4 sequences where the API will stop generating further tokens. + When this parameter is set, the response body will include the `service_tier` + utilized. + + stop: Up to 4 sequences where the API will stop generating further tokens. The + returned text will not contain the stop sequence. store: Whether or not to store the output of this chat completion request for use in our [model distillation](https://platform.openai.com/docs/guides/distillation) @@ -1620,6 +1676,10 @@ async def create( and detect abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + web_search_options: This tool searches the web for relevant results to use in a response. Learn more + about the + [web search tool](https://platform.openai.com/docs/guides/tools-web-search?api-mode=chat). + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -1646,16 +1706,16 @@ async def create( max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, + modalities: Optional[List[Literal["text", "audio"]]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ChatCompletionReasoningEffort] | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[ReasoningEffort] | 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, - stop: Union[Optional[str], List[str]] | NotGiven = NOT_GIVEN, + stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -1664,6 +1724,7 @@ async def create( top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, + web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1671,9 +1732,15 @@ async def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> ChatCompletion | AsyncStream[ChatCompletionChunk]: - """Creates a model response for the given chat conversation. + """ + **Starting a new project?** We recommend trying + [Responses](https://platform.openai.com/docs/api-reference/responses) to take + advantage of the latest OpenAI platform features. Compare + [Chat Completions with Responses](https://platform.openai.com/docs/guides/responses-vs-chat-completions?api-mode=responses). + + --- - Learn more in the + Creates a model response for the given chat conversation. Learn more in the [text generation](https://platform.openai.com/docs/guides/text-generation), [vision](https://platform.openai.com/docs/guides/vision), and [audio](https://platform.openai.com/docs/guides/audio) guides. @@ -1692,16 +1759,20 @@ async def create( [images](https://platform.openai.com/docs/guides/vision), and [audio](https://platform.openai.com/docs/guides/audio). - model: ID of the model to use. See the - [model endpoint compatibility](https://platform.openai.com/docs/models#model-endpoint-compatibility) - table for details on which models work with the Chat API. - - stream: If set, partial message deltas will be sent, like in ChatGPT. Tokens will be - sent as data-only - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format) - as they become available, with the stream terminated by a `data: [DONE]` - message. - [Example Python code](https://cookbook.openai.com/examples/how_to_stream_completions). + model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a + wide range of models with different capabilities, performance characteristics, + and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + + stream: If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section below](https://platform.openai.com/docs/api-reference/chat/streaming) + for more information, along with the + [streaming responses](https://platform.openai.com/docs/guides/streaming-responses) + guide for more information on how to handle the streaming events. audio: Parameters for audio output. Required when audio output is requested with `modalities: ["audio"]`. @@ -1762,8 +1833,8 @@ async def create( Keys are strings with a maximum length of 64 characters. Values are strings with a maximum length of 512 characters. - modalities: Output types that you would like the model to generate for this request. Most - models are capable of generating text, which is the default: + modalities: Output types that you would like the model to generate. Most models are capable + of generating text, which is the default: `["text"]` @@ -1788,7 +1859,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 and o3-mini models only** + reasoning_effort: **o-series models only** Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently @@ -1802,16 +1873,9 @@ async def create( in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the - message the model generates is valid JSON. - - **Important:** when using JSON mode, you **must** also instruct the model to - produce JSON yourself via a system or user message. Without this, the model may - generate an unending stream of whitespace until the generation reaches the token - limit, resulting in a long-running and seemingly "stuck" request. Also note that - the message content may be partially cut off if `finish_reason="length"`, which - indicates the generation exceeded `max_tokens` or the conversation exceeded the - max context length. + Setting to `{ "type": "json_object" }` enables the older JSON mode, which + ensures the message the model generates is valid JSON. Using `json_schema` is + preferred for models that support it. seed: This feature is in Beta. If specified, our system will make a best effort to sample deterministically, such that repeated requests with the same `seed` and @@ -1826,12 +1890,16 @@ async def create( utilize scale tier credits until they are exhausted. - If set to 'auto', and the Project is not Scale tier enabled, the request will be processed using the default service tier with a lower uptime SLA and no - latency guarantee. + latency guarentee. - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarantee. + tier with a lower uptime SLA and no latency guarentee. - When not set, the default behavior is 'auto'. - stop: Up to 4 sequences where the API will stop generating further tokens. + When this parameter is set, the response body will include the `service_tier` + utilized. + + stop: Up to 4 sequences where the API will stop generating further tokens. The + returned text will not contain the stop sequence. store: Whether or not to store the output of this chat completion request for use in our [model distillation](https://platform.openai.com/docs/guides/distillation) @@ -1872,6 +1940,10 @@ async def create( and detect abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + web_search_options: This tool searches the web for relevant results to use in a response. Learn more + about the + [web search tool](https://platform.openai.com/docs/guides/tools-web-search?api-mode=chat). + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -1897,16 +1969,16 @@ async def create( max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, max_tokens: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - modalities: Optional[List[ChatCompletionModality]] | NotGiven = NOT_GIVEN, + modalities: Optional[List[Literal["text", "audio"]]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ChatCompletionReasoningEffort] | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[ReasoningEffort] | 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, - stop: Union[Optional[str], List[str]] | NotGiven = NOT_GIVEN, + stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, @@ -1916,6 +1988,7 @@ async def create( top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, + web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1958,6 +2031,7 @@ async def create( "top_logprobs": top_logprobs, "top_p": top_p, "user": user, + "web_search_options": web_search_options, }, completion_create_params.CompletionCreateParams, ), @@ -1982,7 +2056,7 @@ async def retrieve( ) -> ChatCompletion: """Get a stored chat completion. - Only chat completions that have been created with + Only Chat Completions that have been created with the `store` parameter set to `true` will be returned. Args: @@ -2018,7 +2092,7 @@ async def update( ) -> ChatCompletion: """Modify a stored chat completion. - Only chat completions that have been created + Only Chat Completions that have been created with the `store` parameter set to `true` can be modified. Currently, the only supported modification is to update the `metadata` field. @@ -2064,24 +2138,24 @@ def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> AsyncPaginator[ChatCompletion, AsyncCursorPage[ChatCompletion]]: - """List stored chat completions. + """List stored Chat Completions. - Only chat completions that have been stored with + Only Chat Completions that have been stored with the `store` parameter set to `true` will be returned. Args: after: Identifier for the last chat completion from the previous pagination request. - limit: Number of chat completions to retrieve. + limit: Number of Chat Completions to retrieve. metadata: - A list of metadata keys to filter the chat completions by. Example: + A list of metadata keys to filter the Chat Completions by. Example: `metadata[key1]=value1&metadata[key2]=value2` - model: The model used to generate the chat completions. + model: The model used to generate the Chat Completions. - order: Sort order for chat completions by timestamp. Use `asc` for ascending order or + order: Sort order for Chat Completions by timestamp. Use `asc` for ascending order or `desc` for descending order. Defaults to `asc`. extra_headers: Send extra headers @@ -2127,7 +2201,7 @@ async def delete( ) -> ChatCompletionDeleted: """Delete a stored chat completion. - Only chat completions that have been created + Only Chat Completions that have been created with the `store` parameter set to `true` can be deleted. Args: diff --git a/src/openai/resources/chat/completions/messages.py b/src/openai/resources/chat/completions/messages.py index b71d670927..fac15fba8b 100644 --- a/src/openai/resources/chat/completions/messages.py +++ b/src/openai/resources/chat/completions/messages.py @@ -56,7 +56,7 @@ def list( ) -> SyncCursorPage[ChatCompletionStoreMessage]: """Get the messages in a stored chat completion. - Only chat completions that have + Only Chat Completions that have been created with the `store` parameter set to `true` will be returned. Args: @@ -134,7 +134,7 @@ def list( ) -> AsyncPaginator[ChatCompletionStoreMessage, AsyncCursorPage[ChatCompletionStoreMessage]]: """Get the messages in a stored chat completion. - Only chat completions that have + Only Chat Completions that have been created with the `store` parameter set to `true` will be returned. Args: diff --git a/src/openai/resources/files.py b/src/openai/resources/files.py index af453e1e21..2eaa4a6401 100644 --- a/src/openai/resources/files.py +++ b/src/openai/resources/files.py @@ -96,14 +96,10 @@ def create( Args: file: The File object (not file name) to be uploaded. - purpose: The intended purpose of the uploaded file. - - Use "assistants" for - [Assistants](https://platform.openai.com/docs/api-reference/assistants) and - [Message](https://platform.openai.com/docs/api-reference/messages) files, - "vision" for Assistants image file inputs, "batch" for - [Batch API](https://platform.openai.com/docs/guides/batch), and "fine-tune" for - [Fine-tuning](https://platform.openai.com/docs/api-reference/fine-tuning). + purpose: The intended purpose of the uploaded file. One of: - `assistants`: Used in the + Assistants API - `batch`: Used in the Batch API - `fine-tune`: Used for + fine-tuning - `vision`: Images used for vision fine-tuning - `user_data`: + Flexible file type for any purpose - `evals`: Used for eval data sets extra_headers: Send extra headers @@ -412,14 +408,10 @@ async def create( Args: file: The File object (not file name) to be uploaded. - purpose: The intended purpose of the uploaded file. - - Use "assistants" for - [Assistants](https://platform.openai.com/docs/api-reference/assistants) and - [Message](https://platform.openai.com/docs/api-reference/messages) files, - "vision" for Assistants image file inputs, "batch" for - [Batch API](https://platform.openai.com/docs/guides/batch), and "fine-tune" for - [Fine-tuning](https://platform.openai.com/docs/api-reference/fine-tuning). + purpose: The intended purpose of the uploaded file. One of: - `assistants`: Used in the + Assistants API - `batch`: Used in the Batch API - `fine-tune`: Used for + fine-tuning - `vision`: Images used for vision fine-tuning - `user_data`: + Flexible file type for any purpose - `evals`: Used for eval data sets extra_headers: Send extra headers diff --git a/src/openai/resources/responses/__init__.py b/src/openai/resources/responses/__init__.py new file mode 100644 index 0000000000..ad19218b01 --- /dev/null +++ b/src/openai/resources/responses/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .responses import ( + Responses, + AsyncResponses, + ResponsesWithRawResponse, + AsyncResponsesWithRawResponse, + ResponsesWithStreamingResponse, + AsyncResponsesWithStreamingResponse, +) +from .input_items import ( + InputItems, + AsyncInputItems, + InputItemsWithRawResponse, + AsyncInputItemsWithRawResponse, + InputItemsWithStreamingResponse, + AsyncInputItemsWithStreamingResponse, +) + +__all__ = [ + "InputItems", + "AsyncInputItems", + "InputItemsWithRawResponse", + "AsyncInputItemsWithRawResponse", + "InputItemsWithStreamingResponse", + "AsyncInputItemsWithStreamingResponse", + "Responses", + "AsyncResponses", + "ResponsesWithRawResponse", + "AsyncResponsesWithRawResponse", + "ResponsesWithStreamingResponse", + "AsyncResponsesWithStreamingResponse", +] diff --git a/src/openai/resources/responses/input_items.py b/src/openai/resources/responses/input_items.py new file mode 100644 index 0000000000..10e7d545dc --- /dev/null +++ b/src/openai/resources/responses/input_items.py @@ -0,0 +1,223 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Any, cast +from typing_extensions import Literal + +import httpx + +from ... import _legacy_response +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._utils import maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ...pagination import SyncCursorPage, AsyncCursorPage +from ..._base_client import AsyncPaginator, make_request_options +from ...types.responses import input_item_list_params +from ...types.responses.response_item_list import Data + +__all__ = ["InputItems", "AsyncInputItems"] + + +class InputItems(SyncAPIResource): + @cached_property + def with_raw_response(self) -> InputItemsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return InputItemsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> InputItemsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return InputItemsWithStreamingResponse(self) + + def list( + self, + response_id: str, + *, + after: str | NotGiven = NOT_GIVEN, + before: str | NotGiven = NOT_GIVEN, + limit: int | NotGiven = NOT_GIVEN, + order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> SyncCursorPage[Data]: + """ + Returns a list of input items for a given response. + + Args: + after: An item ID to list items after, used in pagination. + + before: An item ID to list items before, used in pagination. + + limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the default is 20. + + order: The order to return the input items in. Default is `asc`. + + - `asc`: Return the input items in ascending order. + - `desc`: Return the input items in descending order. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not response_id: + raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") + return self._get_api_list( + f"/responses/{response_id}/input_items", + page=SyncCursorPage[Data], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "before": before, + "limit": limit, + "order": order, + }, + input_item_list_params.InputItemListParams, + ), + ), + model=cast(Any, Data), # Union types cannot be passed in as arguments in the type system + ) + + +class AsyncInputItems(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncInputItemsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncInputItemsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncInputItemsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncInputItemsWithStreamingResponse(self) + + def list( + self, + response_id: str, + *, + after: str | NotGiven = NOT_GIVEN, + before: str | NotGiven = NOT_GIVEN, + limit: int | NotGiven = NOT_GIVEN, + order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> AsyncPaginator[Data, AsyncCursorPage[Data]]: + """ + Returns a list of input items for a given response. + + Args: + after: An item ID to list items after, used in pagination. + + before: An item ID to list items before, used in pagination. + + limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the default is 20. + + order: The order to return the input items in. Default is `asc`. + + - `asc`: Return the input items in ascending order. + - `desc`: Return the input items in descending order. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not response_id: + raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") + return self._get_api_list( + f"/responses/{response_id}/input_items", + page=AsyncCursorPage[Data], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "before": before, + "limit": limit, + "order": order, + }, + input_item_list_params.InputItemListParams, + ), + ), + model=cast(Any, Data), # Union types cannot be passed in as arguments in the type system + ) + + +class InputItemsWithRawResponse: + def __init__(self, input_items: InputItems) -> None: + self._input_items = input_items + + self.list = _legacy_response.to_raw_response_wrapper( + input_items.list, + ) + + +class AsyncInputItemsWithRawResponse: + def __init__(self, input_items: AsyncInputItems) -> None: + self._input_items = input_items + + self.list = _legacy_response.async_to_raw_response_wrapper( + input_items.list, + ) + + +class InputItemsWithStreamingResponse: + def __init__(self, input_items: InputItems) -> None: + self._input_items = input_items + + self.list = to_streamed_response_wrapper( + input_items.list, + ) + + +class AsyncInputItemsWithStreamingResponse: + def __init__(self, input_items: AsyncInputItems) -> None: + self._input_items = input_items + + self.list = async_to_streamed_response_wrapper( + input_items.list, + ) diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py new file mode 100644 index 0000000000..0c70a2ef22 --- /dev/null +++ b/src/openai/resources/responses/responses.py @@ -0,0 +1,1790 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Any, List, Type, Union, Iterable, Optional, cast +from functools import partial +from typing_extensions import Literal, overload + +import httpx + +from ... import _legacy_response +from ..._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven +from ..._utils import ( + is_given, + required_args, + maybe_transform, + async_maybe_transform, +) +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from .input_items import ( + InputItems, + AsyncInputItems, + InputItemsWithRawResponse, + AsyncInputItemsWithRawResponse, + InputItemsWithStreamingResponse, + AsyncInputItemsWithStreamingResponse, +) +from ..._streaming import Stream, AsyncStream +from ...lib._tools import PydanticFunctionTool, ResponsesPydanticFunctionTool +from ..._base_client import make_request_options +from ...types.responses import response_create_params, response_retrieve_params +from ...lib._parsing._responses import ( + TextFormatT, + parse_response, + type_to_text_format_param as _type_to_text_format_param, +) +from ...types.shared.chat_model import ChatModel +from ...types.responses.response import Response +from ...types.responses.tool_param import ToolParam, ParseableToolParam +from ...types.shared_params.metadata import Metadata +from ...types.shared_params.reasoning import Reasoning +from ...types.responses.parsed_response import ParsedResponse +from ...lib.streaming.responses._responses import ResponseStreamManager, AsyncResponseStreamManager +from ...types.responses.response_includable import ResponseIncludable +from ...types.responses.response_input_param import ResponseInputParam +from ...types.responses.response_stream_event import ResponseStreamEvent +from ...types.responses.response_text_config_param import ResponseTextConfigParam + +__all__ = ["Responses", "AsyncResponses"] + + +class Responses(SyncAPIResource): + @cached_property + def input_items(self) -> InputItems: + return InputItems(self._client) + + @cached_property + def with_raw_response(self) -> ResponsesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return ResponsesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ResponsesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return ResponsesWithStreamingResponse(self) + + @overload + def create( + self, + *, + input: Union[str, ResponseInputParam], + model: Union[str, ChatModel], + include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | NotGiven = NOT_GIVEN, + max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, + previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, + stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, + temperature: Optional[float] | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, + tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, + top_p: Optional[float] | NotGiven = NOT_GIVEN, + truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Response: + """Creates a model response. + + Provide + [text](https://platform.openai.com/docs/guides/text) or + [image](https://platform.openai.com/docs/guides/images) inputs to generate + [text](https://platform.openai.com/docs/guides/text) or + [JSON](https://platform.openai.com/docs/guides/structured-outputs) outputs. Have + the model call your own + [custom code](https://platform.openai.com/docs/guides/function-calling) or use + built-in [tools](https://platform.openai.com/docs/guides/tools) like + [web search](https://platform.openai.com/docs/guides/tools-web-search) or + [file search](https://platform.openai.com/docs/guides/tools-file-search) to use + your own data as input for the model's response. + + Args: + input: Text, image, or file inputs to the model, used to generate a response. + + Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Image inputs](https://platform.openai.com/docs/guides/images) + - [File inputs](https://platform.openai.com/docs/guides/pdf-files) + - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) + - [Function calling](https://platform.openai.com/docs/guides/function-calling) + + model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a + wide range of models with different capabilities, performance characteristics, + and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + + include: Specify additional output data to include in the model response. Currently + supported values are: + + - `file_search_call.results`: Include the search results of the file search tool + call. + - `message.input_image.image_url`: Include image urls from the input message. + - `computer_call_output.output.image_url`: Include image urls from the computer + call output. + + instructions: Inserts a system (or developer) message as the first item in the model's + context. + + When using along with `previous_response_id`, the instructions from a previous + response will be not be carried over to the next response. This makes it simple + to swap out system (or developer) messages in new responses. + + max_output_tokens: An upper bound for the number of tokens that can be generated for a response, + including visible output tokens and + [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). + + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + + parallel_tool_calls: Whether to allow the model to run tool calls in parallel. + + previous_response_id: The unique ID of the previous response to the model. Use this to create + multi-turn conversations. Learn more about + [conversation state](https://platform.openai.com/docs/guides/conversation-state). + + reasoning: **o-series models only** + + Configuration options for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). + + store: Whether to store the generated model response for later retrieval via API. + + stream: If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) + for more information. + + temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will + make the output more random, while lower values like 0.2 will make it more + focused and deterministic. We generally recommend altering this or `top_p` but + not both. + + text: Configuration options for a text response from the model. Can be plain text or + structured JSON data. Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + + tool_choice: How the model should select which tool (or tools) to use when generating a + response. See the `tools` parameter to see how to specify which tools the model + can call. + + tools: An array of tools the model may call while generating a response. You can + specify which tool to use by setting the `tool_choice` parameter. + + The two categories of tools you can provide the model are: + + - **Built-in tools**: Tools that are provided by OpenAI that extend the model's + capabilities, like + [web search](https://platform.openai.com/docs/guides/tools-web-search) or + [file search](https://platform.openai.com/docs/guides/tools-file-search). + Learn more about + [built-in tools](https://platform.openai.com/docs/guides/tools). + - **Function calls (custom tools)**: Functions that are defined by you, enabling + the model to call your own code. Learn more about + [function calling](https://platform.openai.com/docs/guides/function-calling). + + top_p: An alternative to sampling with temperature, called nucleus sampling, where the + model considers the results of the tokens with top_p probability mass. So 0.1 + means only the tokens comprising the top 10% probability mass are considered. + + We generally recommend altering this or `temperature` but not both. + + truncation: The truncation strategy to use for the model response. + + - `auto`: If the context of this response and previous ones exceeds the model's + context window size, the model will truncate the response to fit the context + window by dropping input items in the middle of the conversation. + - `disabled` (default): If a model response will exceed the context window size + for a model, the request will fail with a 400 error. + + user: A unique identifier representing your end-user, which can help OpenAI to monitor + and detect abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def create( + self, + *, + input: Union[str, ResponseInputParam], + model: Union[str, ChatModel], + stream: Literal[True], + include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | NotGiven = NOT_GIVEN, + max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, + previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, + temperature: Optional[float] | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, + tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, + top_p: Optional[float] | NotGiven = NOT_GIVEN, + truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Stream[ResponseStreamEvent]: + """Creates a model response. + + Provide + [text](https://platform.openai.com/docs/guides/text) or + [image](https://platform.openai.com/docs/guides/images) inputs to generate + [text](https://platform.openai.com/docs/guides/text) or + [JSON](https://platform.openai.com/docs/guides/structured-outputs) outputs. Have + the model call your own + [custom code](https://platform.openai.com/docs/guides/function-calling) or use + built-in [tools](https://platform.openai.com/docs/guides/tools) like + [web search](https://platform.openai.com/docs/guides/tools-web-search) or + [file search](https://platform.openai.com/docs/guides/tools-file-search) to use + your own data as input for the model's response. + + Args: + input: Text, image, or file inputs to the model, used to generate a response. + + Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Image inputs](https://platform.openai.com/docs/guides/images) + - [File inputs](https://platform.openai.com/docs/guides/pdf-files) + - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) + - [Function calling](https://platform.openai.com/docs/guides/function-calling) + + model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a + wide range of models with different capabilities, performance characteristics, + and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + + stream: If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) + for more information. + + include: Specify additional output data to include in the model response. Currently + supported values are: + + - `file_search_call.results`: Include the search results of the file search tool + call. + - `message.input_image.image_url`: Include image urls from the input message. + - `computer_call_output.output.image_url`: Include image urls from the computer + call output. + + instructions: Inserts a system (or developer) message as the first item in the model's + context. + + When using along with `previous_response_id`, the instructions from a previous + response will be not be carried over to the next response. This makes it simple + to swap out system (or developer) messages in new responses. + + max_output_tokens: An upper bound for the number of tokens that can be generated for a response, + including visible output tokens and + [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). + + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + + parallel_tool_calls: Whether to allow the model to run tool calls in parallel. + + previous_response_id: The unique ID of the previous response to the model. Use this to create + multi-turn conversations. Learn more about + [conversation state](https://platform.openai.com/docs/guides/conversation-state). + + reasoning: **o-series models only** + + Configuration options for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). + + store: Whether to store the generated model response for later retrieval via API. + + temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will + make the output more random, while lower values like 0.2 will make it more + focused and deterministic. We generally recommend altering this or `top_p` but + not both. + + text: Configuration options for a text response from the model. Can be plain text or + structured JSON data. Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + + tool_choice: How the model should select which tool (or tools) to use when generating a + response. See the `tools` parameter to see how to specify which tools the model + can call. + + tools: An array of tools the model may call while generating a response. You can + specify which tool to use by setting the `tool_choice` parameter. + + The two categories of tools you can provide the model are: + + - **Built-in tools**: Tools that are provided by OpenAI that extend the model's + capabilities, like + [web search](https://platform.openai.com/docs/guides/tools-web-search) or + [file search](https://platform.openai.com/docs/guides/tools-file-search). + Learn more about + [built-in tools](https://platform.openai.com/docs/guides/tools). + - **Function calls (custom tools)**: Functions that are defined by you, enabling + the model to call your own code. Learn more about + [function calling](https://platform.openai.com/docs/guides/function-calling). + + top_p: An alternative to sampling with temperature, called nucleus sampling, where the + model considers the results of the tokens with top_p probability mass. So 0.1 + means only the tokens comprising the top 10% probability mass are considered. + + We generally recommend altering this or `temperature` but not both. + + truncation: The truncation strategy to use for the model response. + + - `auto`: If the context of this response and previous ones exceeds the model's + context window size, the model will truncate the response to fit the context + window by dropping input items in the middle of the conversation. + - `disabled` (default): If a model response will exceed the context window size + for a model, the request will fail with a 400 error. + + user: A unique identifier representing your end-user, which can help OpenAI to monitor + and detect abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def create( + self, + *, + input: Union[str, ResponseInputParam], + model: Union[str, ChatModel], + stream: bool, + include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | NotGiven = NOT_GIVEN, + max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, + previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, + temperature: Optional[float] | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, + tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, + top_p: Optional[float] | NotGiven = NOT_GIVEN, + truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Response | Stream[ResponseStreamEvent]: + """Creates a model response. + + Provide + [text](https://platform.openai.com/docs/guides/text) or + [image](https://platform.openai.com/docs/guides/images) inputs to generate + [text](https://platform.openai.com/docs/guides/text) or + [JSON](https://platform.openai.com/docs/guides/structured-outputs) outputs. Have + the model call your own + [custom code](https://platform.openai.com/docs/guides/function-calling) or use + built-in [tools](https://platform.openai.com/docs/guides/tools) like + [web search](https://platform.openai.com/docs/guides/tools-web-search) or + [file search](https://platform.openai.com/docs/guides/tools-file-search) to use + your own data as input for the model's response. + + Args: + input: Text, image, or file inputs to the model, used to generate a response. + + Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Image inputs](https://platform.openai.com/docs/guides/images) + - [File inputs](https://platform.openai.com/docs/guides/pdf-files) + - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) + - [Function calling](https://platform.openai.com/docs/guides/function-calling) + + model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a + wide range of models with different capabilities, performance characteristics, + and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + + stream: If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) + for more information. + + include: Specify additional output data to include in the model response. Currently + supported values are: + + - `file_search_call.results`: Include the search results of the file search tool + call. + - `message.input_image.image_url`: Include image urls from the input message. + - `computer_call_output.output.image_url`: Include image urls from the computer + call output. + + instructions: Inserts a system (or developer) message as the first item in the model's + context. + + When using along with `previous_response_id`, the instructions from a previous + response will be not be carried over to the next response. This makes it simple + to swap out system (or developer) messages in new responses. + + max_output_tokens: An upper bound for the number of tokens that can be generated for a response, + including visible output tokens and + [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). + + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + + parallel_tool_calls: Whether to allow the model to run tool calls in parallel. + + previous_response_id: The unique ID of the previous response to the model. Use this to create + multi-turn conversations. Learn more about + [conversation state](https://platform.openai.com/docs/guides/conversation-state). + + reasoning: **o-series models only** + + Configuration options for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). + + store: Whether to store the generated model response for later retrieval via API. + + temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will + make the output more random, while lower values like 0.2 will make it more + focused and deterministic. We generally recommend altering this or `top_p` but + not both. + + text: Configuration options for a text response from the model. Can be plain text or + structured JSON data. Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + + tool_choice: How the model should select which tool (or tools) to use when generating a + response. See the `tools` parameter to see how to specify which tools the model + can call. + + tools: An array of tools the model may call while generating a response. You can + specify which tool to use by setting the `tool_choice` parameter. + + The two categories of tools you can provide the model are: + + - **Built-in tools**: Tools that are provided by OpenAI that extend the model's + capabilities, like + [web search](https://platform.openai.com/docs/guides/tools-web-search) or + [file search](https://platform.openai.com/docs/guides/tools-file-search). + Learn more about + [built-in tools](https://platform.openai.com/docs/guides/tools). + - **Function calls (custom tools)**: Functions that are defined by you, enabling + the model to call your own code. Learn more about + [function calling](https://platform.openai.com/docs/guides/function-calling). + + top_p: An alternative to sampling with temperature, called nucleus sampling, where the + model considers the results of the tokens with top_p probability mass. So 0.1 + means only the tokens comprising the top 10% probability mass are considered. + + We generally recommend altering this or `temperature` but not both. + + truncation: The truncation strategy to use for the model response. + + - `auto`: If the context of this response and previous ones exceeds the model's + context window size, the model will truncate the response to fit the context + window by dropping input items in the middle of the conversation. + - `disabled` (default): If a model response will exceed the context window size + for a model, the request will fail with a 400 error. + + user: A unique identifier representing your end-user, which can help OpenAI to monitor + and detect abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @required_args(["input", "model"], ["input", "model", "stream"]) + def create( + self, + *, + input: Union[str, ResponseInputParam], + model: Union[str, ChatModel], + include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | NotGiven = NOT_GIVEN, + max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, + previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, + stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, + temperature: Optional[float] | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, + tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, + top_p: Optional[float] | NotGiven = NOT_GIVEN, + truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Response | Stream[ResponseStreamEvent]: + return self._post( + "/responses", + body=maybe_transform( + { + "input": input, + "model": model, + "include": include, + "instructions": instructions, + "max_output_tokens": max_output_tokens, + "metadata": metadata, + "parallel_tool_calls": parallel_tool_calls, + "previous_response_id": previous_response_id, + "reasoning": reasoning, + "store": store, + "stream": stream, + "temperature": temperature, + "text": text, + "tool_choice": tool_choice, + "tools": tools, + "top_p": top_p, + "truncation": truncation, + "user": user, + }, + response_create_params.ResponseCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Response, + stream=stream or False, + stream_cls=Stream[ResponseStreamEvent], + ) + + def stream( + self, + *, + input: Union[str, ResponseInputParam], + model: Union[str, ChatModel], + text_format: type[TextFormatT] | NotGiven = NOT_GIVEN, + tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, + include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | NotGiven = NOT_GIVEN, + max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, + previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, + temperature: Optional[float] | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, + top_p: Optional[float] | NotGiven = NOT_GIVEN, + truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ResponseStreamManager[TextFormatT]: + if is_given(text_format): + if not text: + text = {} + + if "format" in text: + raise TypeError("Cannot mix and match text.format with text_format") + + text["format"] = _type_to_text_format_param(text_format) + + tools = _make_tools(tools) + + api_request: partial[Stream[ResponseStreamEvent]] = partial( + self.create, + input=input, + model=model, + tools=tools, + include=include, + instructions=instructions, + max_output_tokens=max_output_tokens, + metadata=metadata, + parallel_tool_calls=parallel_tool_calls, + previous_response_id=previous_response_id, + store=store, + stream=True, + temperature=temperature, + text=text, + tool_choice=tool_choice, + reasoning=reasoning, + top_p=top_p, + truncation=truncation, + user=user, + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + ) + + return ResponseStreamManager( + api_request, + text_format=text_format, + input_tools=tools, + ) + + def parse( + self, + *, + input: Union[str, ResponseInputParam], + model: Union[str, ChatModel], + text_format: type[TextFormatT] | NotGiven = NOT_GIVEN, + tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, + include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | NotGiven = NOT_GIVEN, + max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, + previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, + stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, + temperature: Optional[float] | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, + top_p: Optional[float] | NotGiven = NOT_GIVEN, + truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ParsedResponse[TextFormatT]: + if is_given(text_format): + if not text: + text = {} + + if "format" in text: + raise TypeError("Cannot mix and match text.format with text_format") + + text["format"] = _type_to_text_format_param(text_format) + + tools = _make_tools(tools) + + def parser(raw_response: Response) -> ParsedResponse[TextFormatT]: + return parse_response( + input_tools=tools, + text_format=text_format, + response=raw_response, + ) + + return self._post( + "/responses", + body=maybe_transform( + { + "input": input, + "model": model, + "include": include, + "instructions": instructions, + "max_output_tokens": max_output_tokens, + "metadata": metadata, + "parallel_tool_calls": parallel_tool_calls, + "previous_response_id": previous_response_id, + "reasoning": reasoning, + "store": store, + "stream": stream, + "temperature": temperature, + "text": text, + "tool_choice": tool_choice, + "tools": tools, + "top_p": top_p, + "truncation": truncation, + "user": user, + }, + response_create_params.ResponseCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=parser, + ), + # we turn the `Response` instance into a `ParsedResponse` + # in the `parser` function above + cast_to=cast(Type[ParsedResponse[TextFormatT]], Response), + ) + + def retrieve( + self, + response_id: str, + *, + include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Response: + """ + Retrieves a model response with the given ID. + + Args: + include: Additional fields to include in the response. See the `include` parameter for + Response creation above for more information. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not response_id: + raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") + return self._get( + f"/responses/{response_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"include": include}, response_retrieve_params.ResponseRetrieveParams), + ), + cast_to=Response, + ) + + def delete( + self, + response_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> None: + """ + Deletes a model response with the given ID. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not response_id: + raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/responses/{response_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncResponses(AsyncAPIResource): + @cached_property + def input_items(self) -> AsyncInputItems: + return AsyncInputItems(self._client) + + @cached_property + def with_raw_response(self) -> AsyncResponsesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncResponsesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncResponsesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncResponsesWithStreamingResponse(self) + + @overload + async def create( + self, + *, + input: Union[str, ResponseInputParam], + model: Union[str, ChatModel], + include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | NotGiven = NOT_GIVEN, + max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, + previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, + stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, + temperature: Optional[float] | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, + tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, + top_p: Optional[float] | NotGiven = NOT_GIVEN, + truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Response: + """Creates a model response. + + Provide + [text](https://platform.openai.com/docs/guides/text) or + [image](https://platform.openai.com/docs/guides/images) inputs to generate + [text](https://platform.openai.com/docs/guides/text) or + [JSON](https://platform.openai.com/docs/guides/structured-outputs) outputs. Have + the model call your own + [custom code](https://platform.openai.com/docs/guides/function-calling) or use + built-in [tools](https://platform.openai.com/docs/guides/tools) like + [web search](https://platform.openai.com/docs/guides/tools-web-search) or + [file search](https://platform.openai.com/docs/guides/tools-file-search) to use + your own data as input for the model's response. + + Args: + input: Text, image, or file inputs to the model, used to generate a response. + + Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Image inputs](https://platform.openai.com/docs/guides/images) + - [File inputs](https://platform.openai.com/docs/guides/pdf-files) + - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) + - [Function calling](https://platform.openai.com/docs/guides/function-calling) + + model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a + wide range of models with different capabilities, performance characteristics, + and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + + include: Specify additional output data to include in the model response. Currently + supported values are: + + - `file_search_call.results`: Include the search results of the file search tool + call. + - `message.input_image.image_url`: Include image urls from the input message. + - `computer_call_output.output.image_url`: Include image urls from the computer + call output. + + instructions: Inserts a system (or developer) message as the first item in the model's + context. + + When using along with `previous_response_id`, the instructions from a previous + response will be not be carried over to the next response. This makes it simple + to swap out system (or developer) messages in new responses. + + max_output_tokens: An upper bound for the number of tokens that can be generated for a response, + including visible output tokens and + [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). + + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + + parallel_tool_calls: Whether to allow the model to run tool calls in parallel. + + previous_response_id: The unique ID of the previous response to the model. Use this to create + multi-turn conversations. Learn more about + [conversation state](https://platform.openai.com/docs/guides/conversation-state). + + reasoning: **o-series models only** + + Configuration options for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). + + store: Whether to store the generated model response for later retrieval via API. + + stream: If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) + for more information. + + temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will + make the output more random, while lower values like 0.2 will make it more + focused and deterministic. We generally recommend altering this or `top_p` but + not both. + + text: Configuration options for a text response from the model. Can be plain text or + structured JSON data. Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + + tool_choice: How the model should select which tool (or tools) to use when generating a + response. See the `tools` parameter to see how to specify which tools the model + can call. + + tools: An array of tools the model may call while generating a response. You can + specify which tool to use by setting the `tool_choice` parameter. + + The two categories of tools you can provide the model are: + + - **Built-in tools**: Tools that are provided by OpenAI that extend the model's + capabilities, like + [web search](https://platform.openai.com/docs/guides/tools-web-search) or + [file search](https://platform.openai.com/docs/guides/tools-file-search). + Learn more about + [built-in tools](https://platform.openai.com/docs/guides/tools). + - **Function calls (custom tools)**: Functions that are defined by you, enabling + the model to call your own code. Learn more about + [function calling](https://platform.openai.com/docs/guides/function-calling). + + top_p: An alternative to sampling with temperature, called nucleus sampling, where the + model considers the results of the tokens with top_p probability mass. So 0.1 + means only the tokens comprising the top 10% probability mass are considered. + + We generally recommend altering this or `temperature` but not both. + + truncation: The truncation strategy to use for the model response. + + - `auto`: If the context of this response and previous ones exceeds the model's + context window size, the model will truncate the response to fit the context + window by dropping input items in the middle of the conversation. + - `disabled` (default): If a model response will exceed the context window size + for a model, the request will fail with a 400 error. + + user: A unique identifier representing your end-user, which can help OpenAI to monitor + and detect abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def create( + self, + *, + input: Union[str, ResponseInputParam], + model: Union[str, ChatModel], + stream: Literal[True], + include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | NotGiven = NOT_GIVEN, + max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, + previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, + temperature: Optional[float] | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, + tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, + top_p: Optional[float] | NotGiven = NOT_GIVEN, + truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> AsyncStream[ResponseStreamEvent]: + """Creates a model response. + + Provide + [text](https://platform.openai.com/docs/guides/text) or + [image](https://platform.openai.com/docs/guides/images) inputs to generate + [text](https://platform.openai.com/docs/guides/text) or + [JSON](https://platform.openai.com/docs/guides/structured-outputs) outputs. Have + the model call your own + [custom code](https://platform.openai.com/docs/guides/function-calling) or use + built-in [tools](https://platform.openai.com/docs/guides/tools) like + [web search](https://platform.openai.com/docs/guides/tools-web-search) or + [file search](https://platform.openai.com/docs/guides/tools-file-search) to use + your own data as input for the model's response. + + Args: + input: Text, image, or file inputs to the model, used to generate a response. + + Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Image inputs](https://platform.openai.com/docs/guides/images) + - [File inputs](https://platform.openai.com/docs/guides/pdf-files) + - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) + - [Function calling](https://platform.openai.com/docs/guides/function-calling) + + model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a + wide range of models with different capabilities, performance characteristics, + and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + + stream: If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) + for more information. + + include: Specify additional output data to include in the model response. Currently + supported values are: + + - `file_search_call.results`: Include the search results of the file search tool + call. + - `message.input_image.image_url`: Include image urls from the input message. + - `computer_call_output.output.image_url`: Include image urls from the computer + call output. + + instructions: Inserts a system (or developer) message as the first item in the model's + context. + + When using along with `previous_response_id`, the instructions from a previous + response will be not be carried over to the next response. This makes it simple + to swap out system (or developer) messages in new responses. + + max_output_tokens: An upper bound for the number of tokens that can be generated for a response, + including visible output tokens and + [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). + + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + + parallel_tool_calls: Whether to allow the model to run tool calls in parallel. + + previous_response_id: The unique ID of the previous response to the model. Use this to create + multi-turn conversations. Learn more about + [conversation state](https://platform.openai.com/docs/guides/conversation-state). + + reasoning: **o-series models only** + + Configuration options for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). + + store: Whether to store the generated model response for later retrieval via API. + + temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will + make the output more random, while lower values like 0.2 will make it more + focused and deterministic. We generally recommend altering this or `top_p` but + not both. + + text: Configuration options for a text response from the model. Can be plain text or + structured JSON data. Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + + tool_choice: How the model should select which tool (or tools) to use when generating a + response. See the `tools` parameter to see how to specify which tools the model + can call. + + tools: An array of tools the model may call while generating a response. You can + specify which tool to use by setting the `tool_choice` parameter. + + The two categories of tools you can provide the model are: + + - **Built-in tools**: Tools that are provided by OpenAI that extend the model's + capabilities, like + [web search](https://platform.openai.com/docs/guides/tools-web-search) or + [file search](https://platform.openai.com/docs/guides/tools-file-search). + Learn more about + [built-in tools](https://platform.openai.com/docs/guides/tools). + - **Function calls (custom tools)**: Functions that are defined by you, enabling + the model to call your own code. Learn more about + [function calling](https://platform.openai.com/docs/guides/function-calling). + + top_p: An alternative to sampling with temperature, called nucleus sampling, where the + model considers the results of the tokens with top_p probability mass. So 0.1 + means only the tokens comprising the top 10% probability mass are considered. + + We generally recommend altering this or `temperature` but not both. + + truncation: The truncation strategy to use for the model response. + + - `auto`: If the context of this response and previous ones exceeds the model's + context window size, the model will truncate the response to fit the context + window by dropping input items in the middle of the conversation. + - `disabled` (default): If a model response will exceed the context window size + for a model, the request will fail with a 400 error. + + user: A unique identifier representing your end-user, which can help OpenAI to monitor + and detect abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def create( + self, + *, + input: Union[str, ResponseInputParam], + model: Union[str, ChatModel], + stream: bool, + include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | NotGiven = NOT_GIVEN, + max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, + previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, + temperature: Optional[float] | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, + tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, + top_p: Optional[float] | NotGiven = NOT_GIVEN, + truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Response | AsyncStream[ResponseStreamEvent]: + """Creates a model response. + + Provide + [text](https://platform.openai.com/docs/guides/text) or + [image](https://platform.openai.com/docs/guides/images) inputs to generate + [text](https://platform.openai.com/docs/guides/text) or + [JSON](https://platform.openai.com/docs/guides/structured-outputs) outputs. Have + the model call your own + [custom code](https://platform.openai.com/docs/guides/function-calling) or use + built-in [tools](https://platform.openai.com/docs/guides/tools) like + [web search](https://platform.openai.com/docs/guides/tools-web-search) or + [file search](https://platform.openai.com/docs/guides/tools-file-search) to use + your own data as input for the model's response. + + Args: + input: Text, image, or file inputs to the model, used to generate a response. + + Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Image inputs](https://platform.openai.com/docs/guides/images) + - [File inputs](https://platform.openai.com/docs/guides/pdf-files) + - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) + - [Function calling](https://platform.openai.com/docs/guides/function-calling) + + model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a + wide range of models with different capabilities, performance characteristics, + and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + + stream: If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) + for more information. + + include: Specify additional output data to include in the model response. Currently + supported values are: + + - `file_search_call.results`: Include the search results of the file search tool + call. + - `message.input_image.image_url`: Include image urls from the input message. + - `computer_call_output.output.image_url`: Include image urls from the computer + call output. + + instructions: Inserts a system (or developer) message as the first item in the model's + context. + + When using along with `previous_response_id`, the instructions from a previous + response will be not be carried over to the next response. This makes it simple + to swap out system (or developer) messages in new responses. + + max_output_tokens: An upper bound for the number of tokens that can be generated for a response, + including visible output tokens and + [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). + + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + + parallel_tool_calls: Whether to allow the model to run tool calls in parallel. + + previous_response_id: The unique ID of the previous response to the model. Use this to create + multi-turn conversations. Learn more about + [conversation state](https://platform.openai.com/docs/guides/conversation-state). + + reasoning: **o-series models only** + + Configuration options for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). + + store: Whether to store the generated model response for later retrieval via API. + + temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will + make the output more random, while lower values like 0.2 will make it more + focused and deterministic. We generally recommend altering this or `top_p` but + not both. + + text: Configuration options for a text response from the model. Can be plain text or + structured JSON data. Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + + tool_choice: How the model should select which tool (or tools) to use when generating a + response. See the `tools` parameter to see how to specify which tools the model + can call. + + tools: An array of tools the model may call while generating a response. You can + specify which tool to use by setting the `tool_choice` parameter. + + The two categories of tools you can provide the model are: + + - **Built-in tools**: Tools that are provided by OpenAI that extend the model's + capabilities, like + [web search](https://platform.openai.com/docs/guides/tools-web-search) or + [file search](https://platform.openai.com/docs/guides/tools-file-search). + Learn more about + [built-in tools](https://platform.openai.com/docs/guides/tools). + - **Function calls (custom tools)**: Functions that are defined by you, enabling + the model to call your own code. Learn more about + [function calling](https://platform.openai.com/docs/guides/function-calling). + + top_p: An alternative to sampling with temperature, called nucleus sampling, where the + model considers the results of the tokens with top_p probability mass. So 0.1 + means only the tokens comprising the top 10% probability mass are considered. + + We generally recommend altering this or `temperature` but not both. + + truncation: The truncation strategy to use for the model response. + + - `auto`: If the context of this response and previous ones exceeds the model's + context window size, the model will truncate the response to fit the context + window by dropping input items in the middle of the conversation. + - `disabled` (default): If a model response will exceed the context window size + for a model, the request will fail with a 400 error. + + user: A unique identifier representing your end-user, which can help OpenAI to monitor + and detect abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @required_args(["input", "model"], ["input", "model", "stream"]) + async def create( + self, + *, + input: Union[str, ResponseInputParam], + model: Union[str, ChatModel], + include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | NotGiven = NOT_GIVEN, + max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, + previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, + stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, + temperature: Optional[float] | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, + tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, + top_p: Optional[float] | NotGiven = NOT_GIVEN, + truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Response | AsyncStream[ResponseStreamEvent]: + return await self._post( + "/responses", + body=await async_maybe_transform( + { + "input": input, + "model": model, + "include": include, + "instructions": instructions, + "max_output_tokens": max_output_tokens, + "metadata": metadata, + "parallel_tool_calls": parallel_tool_calls, + "previous_response_id": previous_response_id, + "reasoning": reasoning, + "store": store, + "stream": stream, + "temperature": temperature, + "text": text, + "tool_choice": tool_choice, + "tools": tools, + "top_p": top_p, + "truncation": truncation, + "user": user, + }, + response_create_params.ResponseCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Response, + stream=stream or False, + stream_cls=AsyncStream[ResponseStreamEvent], + ) + + def stream( + self, + *, + input: Union[str, ResponseInputParam], + model: Union[str, ChatModel], + text_format: type[TextFormatT] | NotGiven = NOT_GIVEN, + tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, + include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | NotGiven = NOT_GIVEN, + max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, + previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, + temperature: Optional[float] | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, + top_p: Optional[float] | NotGiven = NOT_GIVEN, + truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> AsyncResponseStreamManager[TextFormatT]: + if is_given(text_format): + if not text: + text = {} + + if "format" in text: + raise TypeError("Cannot mix and match text.format with text_format") + + text["format"] = _type_to_text_format_param(text_format) + + tools = _make_tools(tools) + + api_request = self.create( + input=input, + model=model, + tools=tools, + include=include, + instructions=instructions, + max_output_tokens=max_output_tokens, + metadata=metadata, + parallel_tool_calls=parallel_tool_calls, + previous_response_id=previous_response_id, + store=store, + stream=True, + temperature=temperature, + text=text, + tool_choice=tool_choice, + reasoning=reasoning, + top_p=top_p, + truncation=truncation, + user=user, + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + ) + + return AsyncResponseStreamManager( + api_request, + text_format=text_format, + input_tools=tools, + ) + + async def parse( + self, + *, + input: Union[str, ResponseInputParam], + model: Union[str, ChatModel], + text_format: type[TextFormatT] | NotGiven = NOT_GIVEN, + tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, + include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | NotGiven = NOT_GIVEN, + max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, + previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, + stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, + temperature: Optional[float] | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, + top_p: Optional[float] | NotGiven = NOT_GIVEN, + truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ParsedResponse[TextFormatT]: + if is_given(text_format): + if not text: + text = {} + + if "format" in text: + raise TypeError("Cannot mix and match text.format with text_format") + + text["format"] = _type_to_text_format_param(text_format) + + tools = _make_tools(tools) + + def parser(raw_response: Response) -> ParsedResponse[TextFormatT]: + return parse_response( + input_tools=tools, + text_format=text_format, + response=raw_response, + ) + + return await self._post( + "/responses", + body=maybe_transform( + { + "input": input, + "model": model, + "include": include, + "instructions": instructions, + "max_output_tokens": max_output_tokens, + "metadata": metadata, + "parallel_tool_calls": parallel_tool_calls, + "previous_response_id": previous_response_id, + "reasoning": reasoning, + "store": store, + "stream": stream, + "temperature": temperature, + "text": text, + "tool_choice": tool_choice, + "tools": tools, + "top_p": top_p, + "truncation": truncation, + "user": user, + }, + response_create_params.ResponseCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=parser, + ), + # we turn the `Response` instance into a `ParsedResponse` + # in the `parser` function above + cast_to=cast(Type[ParsedResponse[TextFormatT]], Response), + ) + + async def retrieve( + self, + response_id: str, + *, + include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Response: + """ + Retrieves a model response with the given ID. + + Args: + include: Additional fields to include in the response. See the `include` parameter for + Response creation above for more information. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not response_id: + raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") + return await self._get( + f"/responses/{response_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"include": include}, response_retrieve_params.ResponseRetrieveParams + ), + ), + cast_to=Response, + ) + + async def delete( + self, + response_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> None: + """ + Deletes a model response with the given ID. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not response_id: + raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/responses/{response_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class ResponsesWithRawResponse: + def __init__(self, responses: Responses) -> None: + self._responses = responses + + self.create = _legacy_response.to_raw_response_wrapper( + responses.create, + ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + responses.retrieve, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + responses.delete, + ) + + @cached_property + def input_items(self) -> InputItemsWithRawResponse: + return InputItemsWithRawResponse(self._responses.input_items) + + +class AsyncResponsesWithRawResponse: + def __init__(self, responses: AsyncResponses) -> None: + self._responses = responses + + self.create = _legacy_response.async_to_raw_response_wrapper( + responses.create, + ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + responses.retrieve, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + responses.delete, + ) + + @cached_property + def input_items(self) -> AsyncInputItemsWithRawResponse: + return AsyncInputItemsWithRawResponse(self._responses.input_items) + + +class ResponsesWithStreamingResponse: + def __init__(self, responses: Responses) -> None: + self._responses = responses + + self.create = to_streamed_response_wrapper( + responses.create, + ) + self.retrieve = to_streamed_response_wrapper( + responses.retrieve, + ) + self.delete = to_streamed_response_wrapper( + responses.delete, + ) + + @cached_property + def input_items(self) -> InputItemsWithStreamingResponse: + return InputItemsWithStreamingResponse(self._responses.input_items) + + +class AsyncResponsesWithStreamingResponse: + def __init__(self, responses: AsyncResponses) -> None: + self._responses = responses + + self.create = async_to_streamed_response_wrapper( + responses.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + responses.retrieve, + ) + self.delete = async_to_streamed_response_wrapper( + responses.delete, + ) + + @cached_property + def input_items(self) -> AsyncInputItemsWithStreamingResponse: + return AsyncInputItemsWithStreamingResponse(self._responses.input_items) + + +def _make_tools(tools: Iterable[ParseableToolParam] | NotGiven) -> List[ToolParam] | NotGiven: + if not is_given(tools): + return NOT_GIVEN + + converted_tools: List[ToolParam] = [] + for tool in tools: + if tool["type"] != "function": + converted_tools.append(tool) + continue + + if "function" not in tool: + # standard Responses API case + converted_tools.append(tool) + continue + + function = cast(Any, tool)["function"] # pyright: ignore[reportUnnecessaryCast] + if not isinstance(function, PydanticFunctionTool): + raise Exception( + "Expected Chat Completions function tool shape to be created using `openai.pydantic_function_tool()`" + ) + + assert "parameters" in function + new_tool = ResponsesPydanticFunctionTool( + { + "type": "function", + "name": function["name"], + "description": function.get("description"), + "parameters": function["parameters"], + "strict": function.get("strict") or False, + }, + function.model, + ) + + converted_tools.append(new_tool.cast()) + + return converted_tools diff --git a/src/openai/resources/uploads/uploads.py b/src/openai/resources/uploads/uploads.py index 2028decef5..9297dbc2c3 100644 --- a/src/openai/resources/uploads/uploads.py +++ b/src/openai/resources/uploads/uploads.py @@ -193,10 +193,9 @@ def create( contains all the parts you uploaded. This File is usable in the rest of our platform as a regular File object. - For certain `purpose`s, the correct `mime_type` must be specified. Please refer - to documentation for the supported MIME types for your use case: - - - [Assistants](https://platform.openai.com/docs/assistants/tools/file-search#supported-files) + For certain `purpose` values, the correct `mime_type` must be specified. Please + refer to documentation for the + [supported MIME types for your use case](https://platform.openai.com/docs/assistants/tools/file-search#supported-files). For guidance on the proper filename extensions for each purpose, please follow the documentation on @@ -497,10 +496,9 @@ async def create( contains all the parts you uploaded. This File is usable in the rest of our platform as a regular File object. - For certain `purpose`s, the correct `mime_type` must be specified. Please refer - to documentation for the supported MIME types for your use case: - - - [Assistants](https://platform.openai.com/docs/assistants/tools/file-search#supported-files) + For certain `purpose` values, the correct `mime_type` must be specified. Please + refer to documentation for the + [supported MIME types for your use case](https://platform.openai.com/docs/assistants/tools/file-search#supported-files). For guidance on the proper filename extensions for each purpose, please follow the documentation on diff --git a/src/openai/resources/beta/vector_stores/__init__.py b/src/openai/resources/vector_stores/__init__.py similarity index 100% rename from src/openai/resources/beta/vector_stores/__init__.py rename to src/openai/resources/vector_stores/__init__.py diff --git a/src/openai/resources/beta/vector_stores/file_batches.py b/src/openai/resources/vector_stores/file_batches.py similarity index 93% rename from src/openai/resources/beta/vector_stores/file_batches.py rename to src/openai/resources/vector_stores/file_batches.py index 6d61e92c7f..9b4b64d35e 100644 --- a/src/openai/resources/beta/vector_stores/file_batches.py +++ b/src/openai/resources/vector_stores/file_batches.py @@ -3,31 +3,31 @@ from __future__ import annotations import asyncio -from typing import List, Iterable -from typing_extensions import Literal +from typing import Dict, List, Iterable, Optional +from typing_extensions import Union, Literal from concurrent.futures import Future, ThreadPoolExecutor, as_completed import httpx import sniffio -from .... import _legacy_response -from ....types import FileObject -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven, FileTypes -from ...._utils import ( +from ... import _legacy_response +from ...types import FileChunkingStrategyParam +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven, FileTypes +from ..._utils import ( is_given, maybe_transform, async_maybe_transform, ) -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ....pagination import SyncCursorPage, AsyncCursorPage -from ....types.beta import FileChunkingStrategyParam -from ...._base_client import AsyncPaginator, make_request_options -from ....types.beta.vector_stores import file_batch_create_params, file_batch_list_files_params -from ....types.beta.file_chunking_strategy_param import FileChunkingStrategyParam -from ....types.beta.vector_stores.vector_store_file import VectorStoreFile -from ....types.beta.vector_stores.vector_store_file_batch import VectorStoreFileBatch +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ...pagination import SyncCursorPage, AsyncCursorPage +from ..._base_client import AsyncPaginator, make_request_options +from ...types.file_object import FileObject +from ...types.vector_stores import file_batch_create_params, file_batch_list_files_params +from ...types.file_chunking_strategy_param import FileChunkingStrategyParam +from ...types.vector_stores.vector_store_file import VectorStoreFile +from ...types.vector_stores.vector_store_file_batch import VectorStoreFileBatch __all__ = ["FileBatches", "AsyncFileBatches"] @@ -57,6 +57,7 @@ def create( vector_store_id: str, *, file_ids: List[str], + attributes: Optional[Dict[str, Union[str, float, bool]]] | NotGiven = NOT_GIVEN, chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -73,6 +74,12 @@ def create( the vector store should use. Useful for tools like `file_search` that can access files. + attributes: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. Keys are strings with a maximum + length of 64 characters. Values are strings with a maximum length of 512 + characters, booleans, or numbers. + chunking_strategy: The chunking strategy used to chunk the file(s). If not set, will use the `auto` strategy. Only applicable if `file_ids` is non-empty. @@ -92,6 +99,7 @@ def create( body=maybe_transform( { "file_ids": file_ids, + "attributes": attributes, "chunking_strategy": chunking_strategy, }, file_batch_create_params.FileBatchCreateParams, @@ -386,6 +394,7 @@ async def create( vector_store_id: str, *, file_ids: List[str], + attributes: Optional[Dict[str, Union[str, float, bool]]] | NotGiven = NOT_GIVEN, chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -402,6 +411,12 @@ async def create( the vector store should use. Useful for tools like `file_search` that can access files. + attributes: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. Keys are strings with a maximum + length of 64 characters. Values are strings with a maximum length of 512 + characters, booleans, or numbers. + chunking_strategy: The chunking strategy used to chunk the file(s). If not set, will use the `auto` strategy. Only applicable if `file_ids` is non-empty. @@ -421,6 +436,7 @@ async def create( body=await async_maybe_transform( { "file_ids": file_ids, + "attributes": attributes, "chunking_strategy": chunking_strategy, }, file_batch_create_params.FileBatchCreateParams, diff --git a/src/openai/resources/beta/vector_stores/files.py b/src/openai/resources/vector_stores/files.py similarity index 73% rename from src/openai/resources/beta/vector_stores/files.py rename to src/openai/resources/vector_stores/files.py index febf27a753..7d93798adf 100644 --- a/src/openai/resources/beta/vector_stores/files.py +++ b/src/openai/resources/vector_stores/files.py @@ -2,28 +2,29 @@ from __future__ import annotations -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Dict, Union, Optional from typing_extensions import Literal, assert_never import httpx -from .... import _legacy_response -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven, FileTypes -from ...._utils import ( +from ... import _legacy_response +from ...types import FileChunkingStrategyParam +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven, FileTypes +from ..._utils import ( is_given, maybe_transform, async_maybe_transform, ) -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ....pagination import SyncCursorPage, AsyncCursorPage -from ....types.beta import FileChunkingStrategyParam -from ...._base_client import AsyncPaginator, make_request_options -from ....types.beta.vector_stores import file_list_params, file_create_params -from ....types.beta.file_chunking_strategy_param import FileChunkingStrategyParam -from ....types.beta.vector_stores.vector_store_file import VectorStoreFile -from ....types.beta.vector_stores.vector_store_file_deleted import VectorStoreFileDeleted +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ...pagination import SyncPage, AsyncPage, SyncCursorPage, AsyncCursorPage +from ..._base_client import AsyncPaginator, make_request_options +from ...types.vector_stores import file_list_params, file_create_params, file_update_params +from ...types.file_chunking_strategy_param import FileChunkingStrategyParam +from ...types.vector_stores.vector_store_file import VectorStoreFile +from ...types.vector_stores.file_content_response import FileContentResponse +from ...types.vector_stores.vector_store_file_deleted import VectorStoreFileDeleted __all__ = ["Files", "AsyncFiles"] @@ -53,6 +54,7 @@ def create( vector_store_id: str, *, file_id: str, + attributes: Optional[Dict[str, Union[str, float, bool]]] | NotGiven = NOT_GIVEN, chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -71,6 +73,12 @@ def create( vector store should use. Useful for tools like `file_search` that can access files. + attributes: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. Keys are strings with a maximum + length of 64 characters. Values are strings with a maximum length of 512 + characters, booleans, or numbers. + chunking_strategy: The chunking strategy used to chunk the file(s). If not set, will use the `auto` strategy. Only applicable if `file_ids` is non-empty. @@ -90,6 +98,7 @@ def create( body=maybe_transform( { "file_id": file_id, + "attributes": attributes, "chunking_strategy": chunking_strategy, }, file_create_params.FileCreateParams, @@ -137,6 +146,51 @@ def retrieve( cast_to=VectorStoreFile, ) + def update( + self, + file_id: str, + *, + vector_store_id: str, + attributes: Optional[Dict[str, Union[str, float, bool]]], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> VectorStoreFile: + """ + Update attributes on a vector store file. + + Args: + attributes: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. Keys are strings with a maximum + length of 64 characters. Values are strings with a maximum length of 512 + characters, booleans, or numbers. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not vector_store_id: + raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") + if not file_id: + raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} + return self._post( + f"/vector_stores/{vector_store_id}/files/{file_id}", + body=maybe_transform({"attributes": attributes}, file_update_params.FileUpdateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=VectorStoreFile, + ) + def list( self, vector_store_id: str, @@ -339,6 +393,44 @@ def upload_and_poll( poll_interval_ms=poll_interval_ms, ) + def content( + self, + file_id: str, + *, + vector_store_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> SyncPage[FileContentResponse]: + """ + Retrieve the parsed contents of a vector store file. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not vector_store_id: + raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") + if not file_id: + raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} + return self._get_api_list( + f"/vector_stores/{vector_store_id}/files/{file_id}/content", + page=SyncPage[FileContentResponse], + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + model=FileContentResponse, + ) + class AsyncFiles(AsyncAPIResource): @cached_property @@ -365,6 +457,7 @@ async def create( vector_store_id: str, *, file_id: str, + attributes: Optional[Dict[str, Union[str, float, bool]]] | NotGiven = NOT_GIVEN, chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -383,6 +476,12 @@ async def create( vector store should use. Useful for tools like `file_search` that can access files. + attributes: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. Keys are strings with a maximum + length of 64 characters. Values are strings with a maximum length of 512 + characters, booleans, or numbers. + chunking_strategy: The chunking strategy used to chunk the file(s). If not set, will use the `auto` strategy. Only applicable if `file_ids` is non-empty. @@ -402,6 +501,7 @@ async def create( body=await async_maybe_transform( { "file_id": file_id, + "attributes": attributes, "chunking_strategy": chunking_strategy, }, file_create_params.FileCreateParams, @@ -449,6 +549,51 @@ async def retrieve( cast_to=VectorStoreFile, ) + async def update( + self, + file_id: str, + *, + vector_store_id: str, + attributes: Optional[Dict[str, Union[str, float, bool]]], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> VectorStoreFile: + """ + Update attributes on a vector store file. + + Args: + attributes: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. Keys are strings with a maximum + length of 64 characters. Values are strings with a maximum length of 512 + characters, booleans, or numbers. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not vector_store_id: + raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") + if not file_id: + raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} + return await self._post( + f"/vector_stores/{vector_store_id}/files/{file_id}", + body=await async_maybe_transform({"attributes": attributes}, file_update_params.FileUpdateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=VectorStoreFile, + ) + def list( self, vector_store_id: str, @@ -653,6 +798,44 @@ async def upload_and_poll( chunking_strategy=chunking_strategy, ) + def content( + self, + file_id: str, + *, + vector_store_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> AsyncPaginator[FileContentResponse, AsyncPage[FileContentResponse]]: + """ + Retrieve the parsed contents of a vector store file. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not vector_store_id: + raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") + if not file_id: + raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} + return self._get_api_list( + f"/vector_stores/{vector_store_id}/files/{file_id}/content", + page=AsyncPage[FileContentResponse], + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + model=FileContentResponse, + ) + class FilesWithRawResponse: def __init__(self, files: Files) -> None: @@ -664,12 +847,18 @@ def __init__(self, files: Files) -> None: self.retrieve = _legacy_response.to_raw_response_wrapper( files.retrieve, ) + self.update = _legacy_response.to_raw_response_wrapper( + files.update, + ) self.list = _legacy_response.to_raw_response_wrapper( files.list, ) self.delete = _legacy_response.to_raw_response_wrapper( files.delete, ) + self.content = _legacy_response.to_raw_response_wrapper( + files.content, + ) class AsyncFilesWithRawResponse: @@ -682,12 +871,18 @@ def __init__(self, files: AsyncFiles) -> None: self.retrieve = _legacy_response.async_to_raw_response_wrapper( files.retrieve, ) + self.update = _legacy_response.async_to_raw_response_wrapper( + files.update, + ) self.list = _legacy_response.async_to_raw_response_wrapper( files.list, ) self.delete = _legacy_response.async_to_raw_response_wrapper( files.delete, ) + self.content = _legacy_response.async_to_raw_response_wrapper( + files.content, + ) class FilesWithStreamingResponse: @@ -700,12 +895,18 @@ def __init__(self, files: Files) -> None: self.retrieve = to_streamed_response_wrapper( files.retrieve, ) + self.update = to_streamed_response_wrapper( + files.update, + ) self.list = to_streamed_response_wrapper( files.list, ) self.delete = to_streamed_response_wrapper( files.delete, ) + self.content = to_streamed_response_wrapper( + files.content, + ) class AsyncFilesWithStreamingResponse: @@ -718,9 +919,15 @@ def __init__(self, files: AsyncFiles) -> None: self.retrieve = async_to_streamed_response_wrapper( files.retrieve, ) + self.update = async_to_streamed_response_wrapper( + files.update, + ) self.list = async_to_streamed_response_wrapper( files.list, ) self.delete = async_to_streamed_response_wrapper( files.delete, ) + self.content = async_to_streamed_response_wrapper( + files.content, + ) diff --git a/src/openai/resources/beta/vector_stores/vector_stores.py b/src/openai/resources/vector_stores/vector_stores.py similarity index 80% rename from src/openai/resources/beta/vector_stores/vector_stores.py rename to src/openai/resources/vector_stores/vector_stores.py index 1da52fb3c7..aaa6ed2757 100644 --- a/src/openai/resources/beta/vector_stores/vector_stores.py +++ b/src/openai/resources/vector_stores/vector_stores.py @@ -2,12 +2,12 @@ from __future__ import annotations -from typing import List, Optional +from typing import List, Union, Optional from typing_extensions import Literal import httpx -from .... import _legacy_response +from ... import _legacy_response from .files import ( Files, AsyncFiles, @@ -16,14 +16,22 @@ FilesWithStreamingResponse, AsyncFilesWithStreamingResponse, ) -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ...._utils import ( +from ...types import ( + FileChunkingStrategyParam, + vector_store_list_params, + vector_store_create_params, + vector_store_search_params, + vector_store_update_params, +) +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._utils import ( maybe_transform, async_maybe_transform, ) -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ...pagination import SyncPage, AsyncPage, SyncCursorPage, AsyncCursorPage from .file_batches import ( FileBatches, AsyncFileBatches, @@ -32,18 +40,12 @@ FileBatchesWithStreamingResponse, AsyncFileBatchesWithStreamingResponse, ) -from ....pagination import SyncCursorPage, AsyncCursorPage -from ....types.beta import ( - FileChunkingStrategyParam, - vector_store_list_params, - vector_store_create_params, - vector_store_update_params, -) -from ...._base_client import AsyncPaginator, make_request_options -from ....types.beta.vector_store import VectorStore -from ....types.shared_params.metadata import Metadata -from ....types.beta.vector_store_deleted import VectorStoreDeleted -from ....types.beta.file_chunking_strategy_param import FileChunkingStrategyParam +from ..._base_client import AsyncPaginator, make_request_options +from ...types.vector_store import VectorStore +from ...types.vector_store_deleted import VectorStoreDeleted +from ...types.shared_params.metadata import Metadata +from ...types.file_chunking_strategy_param import FileChunkingStrategyParam +from ...types.vector_store_search_response import VectorStoreSearchResponse __all__ = ["VectorStores", "AsyncVectorStores"] @@ -329,6 +331,69 @@ def delete( cast_to=VectorStoreDeleted, ) + def search( + self, + vector_store_id: str, + *, + query: Union[str, List[str]], + filters: vector_store_search_params.Filters | NotGiven = NOT_GIVEN, + max_num_results: int | NotGiven = NOT_GIVEN, + ranking_options: vector_store_search_params.RankingOptions | NotGiven = NOT_GIVEN, + rewrite_query: bool | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> SyncPage[VectorStoreSearchResponse]: + """ + Search a vector store for relevant chunks based on a query and file attributes + filter. + + Args: + query: A query string for a search + + filters: A filter to apply based on file attributes. + + max_num_results: The maximum number of results to return. This number should be between 1 and 50 + inclusive. + + ranking_options: Ranking options for search. + + rewrite_query: Whether to rewrite the natural language query for vector search. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not vector_store_id: + raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} + return self._get_api_list( + f"/vector_stores/{vector_store_id}/search", + page=SyncPage[VectorStoreSearchResponse], + body=maybe_transform( + { + "query": query, + "filters": filters, + "max_num_results": max_num_results, + "ranking_options": ranking_options, + "rewrite_query": rewrite_query, + }, + vector_store_search_params.VectorStoreSearchParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + model=VectorStoreSearchResponse, + method="post", + ) + class AsyncVectorStores(AsyncAPIResource): @cached_property @@ -611,6 +676,69 @@ async def delete( cast_to=VectorStoreDeleted, ) + def search( + self, + vector_store_id: str, + *, + query: Union[str, List[str]], + filters: vector_store_search_params.Filters | NotGiven = NOT_GIVEN, + max_num_results: int | NotGiven = NOT_GIVEN, + ranking_options: vector_store_search_params.RankingOptions | NotGiven = NOT_GIVEN, + rewrite_query: bool | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> AsyncPaginator[VectorStoreSearchResponse, AsyncPage[VectorStoreSearchResponse]]: + """ + Search a vector store for relevant chunks based on a query and file attributes + filter. + + Args: + query: A query string for a search + + filters: A filter to apply based on file attributes. + + max_num_results: The maximum number of results to return. This number should be between 1 and 50 + inclusive. + + ranking_options: Ranking options for search. + + rewrite_query: Whether to rewrite the natural language query for vector search. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not vector_store_id: + raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} + return self._get_api_list( + f"/vector_stores/{vector_store_id}/search", + page=AsyncPage[VectorStoreSearchResponse], + body=maybe_transform( + { + "query": query, + "filters": filters, + "max_num_results": max_num_results, + "ranking_options": ranking_options, + "rewrite_query": rewrite_query, + }, + vector_store_search_params.VectorStoreSearchParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + model=VectorStoreSearchResponse, + method="post", + ) + class VectorStoresWithRawResponse: def __init__(self, vector_stores: VectorStores) -> None: @@ -631,6 +759,9 @@ def __init__(self, vector_stores: VectorStores) -> None: self.delete = _legacy_response.to_raw_response_wrapper( vector_stores.delete, ) + self.search = _legacy_response.to_raw_response_wrapper( + vector_stores.search, + ) @cached_property def files(self) -> FilesWithRawResponse: @@ -660,6 +791,9 @@ def __init__(self, vector_stores: AsyncVectorStores) -> None: self.delete = _legacy_response.async_to_raw_response_wrapper( vector_stores.delete, ) + self.search = _legacy_response.async_to_raw_response_wrapper( + vector_stores.search, + ) @cached_property def files(self) -> AsyncFilesWithRawResponse: @@ -689,6 +823,9 @@ def __init__(self, vector_stores: VectorStores) -> None: self.delete = to_streamed_response_wrapper( vector_stores.delete, ) + self.search = to_streamed_response_wrapper( + vector_stores.search, + ) @cached_property def files(self) -> FilesWithStreamingResponse: @@ -718,6 +855,9 @@ def __init__(self, vector_stores: AsyncVectorStores) -> None: self.delete = async_to_streamed_response_wrapper( vector_stores.delete, ) + self.search = async_to_streamed_response_wrapper( + vector_stores.search, + ) @cached_property def files(self) -> AsyncFilesWithStreamingResponse: diff --git a/src/openai/types/__init__.py b/src/openai/types/__init__.py index eb71ac6ccc..4c337d41c7 100644 --- a/src/openai/types/__init__.py +++ b/src/openai/types/__init__.py @@ -8,7 +8,11 @@ from .shared import ( Metadata as Metadata, ChatModel as ChatModel, + Reasoning as Reasoning, ErrorObject as ErrorObject, + CompoundFilter as CompoundFilter, + ReasoningEffort as ReasoningEffort, + ComparisonFilter as ComparisonFilter, FunctionDefinition as FunctionDefinition, FunctionParameters as FunctionParameters, ResponseFormatText as ResponseFormatText, @@ -27,6 +31,7 @@ from .file_content import FileContent as FileContent from .file_deleted import FileDeleted as FileDeleted from .file_purpose import FilePurpose as FilePurpose +from .vector_store import VectorStore as VectorStore from .model_deleted import ModelDeleted as ModelDeleted from .embedding_model import EmbeddingModel as EmbeddingModel from .images_response import ImagesResponse as ImagesResponse @@ -40,16 +45,32 @@ from .batch_create_params import BatchCreateParams as BatchCreateParams from .batch_request_counts import BatchRequestCounts as BatchRequestCounts from .upload_create_params import UploadCreateParams as UploadCreateParams +from .vector_store_deleted import VectorStoreDeleted as VectorStoreDeleted from .audio_response_format import AudioResponseFormat as AudioResponseFormat from .image_generate_params import ImageGenerateParams as ImageGenerateParams +from .file_chunking_strategy import FileChunkingStrategy as FileChunkingStrategy from .upload_complete_params import UploadCompleteParams as UploadCompleteParams from .embedding_create_params import EmbeddingCreateParams as EmbeddingCreateParams from .completion_create_params import CompletionCreateParams as CompletionCreateParams from .moderation_create_params import ModerationCreateParams as ModerationCreateParams +from .vector_store_list_params import VectorStoreListParams as VectorStoreListParams from .create_embedding_response import CreateEmbeddingResponse as CreateEmbeddingResponse from .moderation_create_response import ModerationCreateResponse as ModerationCreateResponse +from .vector_store_create_params import VectorStoreCreateParams as VectorStoreCreateParams +from .vector_store_search_params import VectorStoreSearchParams as VectorStoreSearchParams +from .vector_store_update_params import VectorStoreUpdateParams as VectorStoreUpdateParams from .moderation_text_input_param import ModerationTextInputParam as ModerationTextInputParam +from .file_chunking_strategy_param import FileChunkingStrategyParam as FileChunkingStrategyParam +from .vector_store_search_response import VectorStoreSearchResponse as VectorStoreSearchResponse from .websocket_connection_options import WebsocketConnectionOptions as WebsocketConnectionOptions from .image_create_variation_params import ImageCreateVariationParams as ImageCreateVariationParams +from .static_file_chunking_strategy import StaticFileChunkingStrategy as StaticFileChunkingStrategy from .moderation_image_url_input_param import ModerationImageURLInputParam as ModerationImageURLInputParam +from .auto_file_chunking_strategy_param import AutoFileChunkingStrategyParam as AutoFileChunkingStrategyParam from .moderation_multi_modal_input_param import ModerationMultiModalInputParam as ModerationMultiModalInputParam +from .other_file_chunking_strategy_object import OtherFileChunkingStrategyObject as OtherFileChunkingStrategyObject +from .static_file_chunking_strategy_param import StaticFileChunkingStrategyParam as StaticFileChunkingStrategyParam +from .static_file_chunking_strategy_object import StaticFileChunkingStrategyObject as StaticFileChunkingStrategyObject +from .static_file_chunking_strategy_object_param import ( + StaticFileChunkingStrategyObjectParam as StaticFileChunkingStrategyObjectParam, +) diff --git a/src/openai/types/beta/auto_file_chunking_strategy_param.py b/src/openai/types/auto_file_chunking_strategy_param.py similarity index 100% rename from src/openai/types/beta/auto_file_chunking_strategy_param.py rename to src/openai/types/auto_file_chunking_strategy_param.py diff --git a/src/openai/types/beta/__init__.py b/src/openai/types/beta/__init__.py index b9ea792bfa..5ba3eadf3c 100644 --- a/src/openai/types/beta/__init__.py +++ b/src/openai/types/beta/__init__.py @@ -4,7 +4,6 @@ from .thread import Thread as Thread from .assistant import Assistant as Assistant -from .vector_store import VectorStore as VectorStore from .function_tool import FunctionTool as FunctionTool from .assistant_tool import AssistantTool as AssistantTool from .thread_deleted import ThreadDeleted as ThreadDeleted @@ -14,35 +13,21 @@ from .assistant_tool_param import AssistantToolParam as AssistantToolParam from .thread_create_params import ThreadCreateParams as ThreadCreateParams from .thread_update_params import ThreadUpdateParams as ThreadUpdateParams -from .vector_store_deleted import VectorStoreDeleted as VectorStoreDeleted from .assistant_list_params import AssistantListParams as AssistantListParams from .assistant_tool_choice import AssistantToolChoice as AssistantToolChoice from .code_interpreter_tool import CodeInterpreterTool as CodeInterpreterTool from .assistant_stream_event import AssistantStreamEvent as AssistantStreamEvent -from .file_chunking_strategy import FileChunkingStrategy as FileChunkingStrategy from .file_search_tool_param import FileSearchToolParam as FileSearchToolParam from .assistant_create_params import AssistantCreateParams as AssistantCreateParams from .assistant_update_params import AssistantUpdateParams as AssistantUpdateParams -from .vector_store_list_params import VectorStoreListParams as VectorStoreListParams -from .vector_store_create_params import VectorStoreCreateParams as VectorStoreCreateParams -from .vector_store_update_params import VectorStoreUpdateParams as VectorStoreUpdateParams from .assistant_tool_choice_param import AssistantToolChoiceParam as AssistantToolChoiceParam from .code_interpreter_tool_param import CodeInterpreterToolParam as CodeInterpreterToolParam from .assistant_tool_choice_option import AssistantToolChoiceOption as AssistantToolChoiceOption -from .file_chunking_strategy_param import FileChunkingStrategyParam as FileChunkingStrategyParam from .thread_create_and_run_params import ThreadCreateAndRunParams as ThreadCreateAndRunParams -from .static_file_chunking_strategy import StaticFileChunkingStrategy as StaticFileChunkingStrategy from .assistant_tool_choice_function import AssistantToolChoiceFunction as AssistantToolChoiceFunction from .assistant_response_format_option import AssistantResponseFormatOption as AssistantResponseFormatOption -from .auto_file_chunking_strategy_param import AutoFileChunkingStrategyParam as AutoFileChunkingStrategyParam from .assistant_tool_choice_option_param import AssistantToolChoiceOptionParam as AssistantToolChoiceOptionParam -from .other_file_chunking_strategy_object import OtherFileChunkingStrategyObject as OtherFileChunkingStrategyObject -from .static_file_chunking_strategy_param import StaticFileChunkingStrategyParam as StaticFileChunkingStrategyParam from .assistant_tool_choice_function_param import AssistantToolChoiceFunctionParam as AssistantToolChoiceFunctionParam -from .static_file_chunking_strategy_object import StaticFileChunkingStrategyObject as StaticFileChunkingStrategyObject from .assistant_response_format_option_param import ( AssistantResponseFormatOptionParam as AssistantResponseFormatOptionParam, ) -from .static_file_chunking_strategy_object_param import ( - StaticFileChunkingStrategyObjectParam as StaticFileChunkingStrategyObjectParam, -) diff --git a/src/openai/types/beta/assistant_create_params.py b/src/openai/types/beta/assistant_create_params.py index e90aabfd3f..8b3c331850 100644 --- a/src/openai/types/beta/assistant_create_params.py +++ b/src/openai/types/beta/assistant_create_params.py @@ -3,12 +3,12 @@ from __future__ import annotations from typing import List, Union, Iterable, Optional -from typing_extensions import Literal, Required, TypedDict +from typing_extensions import Literal, Required, TypeAlias, TypedDict from ..shared.chat_model import ChatModel from .assistant_tool_param import AssistantToolParam from ..shared_params.metadata import Metadata -from .file_chunking_strategy_param import FileChunkingStrategyParam +from ..shared.reasoning_effort import ReasoningEffort from .assistant_response_format_option_param import AssistantResponseFormatOptionParam __all__ = [ @@ -17,6 +17,10 @@ "ToolResourcesCodeInterpreter", "ToolResourcesFileSearch", "ToolResourcesFileSearchVectorStore", + "ToolResourcesFileSearchVectorStoreChunkingStrategy", + "ToolResourcesFileSearchVectorStoreChunkingStrategyAuto", + "ToolResourcesFileSearchVectorStoreChunkingStrategyStatic", + "ToolResourcesFileSearchVectorStoreChunkingStrategyStaticStatic", ] @@ -53,8 +57,8 @@ 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** + reasoning_effort: Optional[ReasoningEffort] + """**o-series models only** Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently @@ -127,12 +131,43 @@ class ToolResourcesCodeInterpreter(TypedDict, total=False): """ +class ToolResourcesFileSearchVectorStoreChunkingStrategyAuto(TypedDict, total=False): + type: Required[Literal["auto"]] + """Always `auto`.""" + + +class ToolResourcesFileSearchVectorStoreChunkingStrategyStaticStatic(TypedDict, total=False): + chunk_overlap_tokens: Required[int] + """The number of tokens that overlap between chunks. The default value is `400`. + + Note that the overlap must not exceed half of `max_chunk_size_tokens`. + """ + + max_chunk_size_tokens: Required[int] + """The maximum number of tokens in each chunk. + + The default value is `800`. The minimum value is `100` and the maximum value is + `4096`. + """ + + +class ToolResourcesFileSearchVectorStoreChunkingStrategyStatic(TypedDict, total=False): + static: Required[ToolResourcesFileSearchVectorStoreChunkingStrategyStaticStatic] + + type: Required[Literal["static"]] + """Always `static`.""" + + +ToolResourcesFileSearchVectorStoreChunkingStrategy: TypeAlias = Union[ + ToolResourcesFileSearchVectorStoreChunkingStrategyAuto, ToolResourcesFileSearchVectorStoreChunkingStrategyStatic +] + + class ToolResourcesFileSearchVectorStore(TypedDict, total=False): - chunking_strategy: FileChunkingStrategyParam + chunking_strategy: ToolResourcesFileSearchVectorStoreChunkingStrategy """The chunking strategy used to chunk the file(s). - If not set, will use the `auto` strategy. Only applicable if `file_ids` is - non-empty. + If not set, will use the `auto` strategy. """ file_ids: List[str] diff --git a/src/openai/types/beta/assistant_update_params.py b/src/openai/types/beta/assistant_update_params.py index 12a57a4063..d3ec7614fd 100644 --- a/src/openai/types/beta/assistant_update_params.py +++ b/src/openai/types/beta/assistant_update_params.py @@ -7,6 +7,7 @@ from .assistant_tool_param import AssistantToolParam from ..shared_params.metadata import Metadata +from ..shared.reasoning_effort import ReasoningEffort from .assistant_response_format_option_param import AssistantResponseFormatOptionParam __all__ = ["AssistantUpdateParams", "ToolResources", "ToolResourcesCodeInterpreter", "ToolResourcesFileSearch"] @@ -79,8 +80,8 @@ 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** + reasoning_effort: Optional[ReasoningEffort] + """**o-series models only** Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently diff --git a/src/openai/types/beta/thread_create_and_run_params.py b/src/openai/types/beta/thread_create_and_run_params.py index d888fb3eee..065c390f4e 100644 --- a/src/openai/types/beta/thread_create_and_run_params.py +++ b/src/openai/types/beta/thread_create_and_run_params.py @@ -10,7 +10,6 @@ from .file_search_tool_param import FileSearchToolParam from ..shared_params.metadata import Metadata from .code_interpreter_tool_param import CodeInterpreterToolParam -from .file_chunking_strategy_param import FileChunkingStrategyParam from .assistant_tool_choice_option_param import AssistantToolChoiceOptionParam from .threads.message_content_part_param import MessageContentPartParam from .assistant_response_format_option_param import AssistantResponseFormatOptionParam @@ -26,6 +25,10 @@ "ThreadToolResourcesCodeInterpreter", "ThreadToolResourcesFileSearch", "ThreadToolResourcesFileSearchVectorStore", + "ThreadToolResourcesFileSearchVectorStoreChunkingStrategy", + "ThreadToolResourcesFileSearchVectorStoreChunkingStrategyAuto", + "ThreadToolResourcesFileSearchVectorStoreChunkingStrategyStatic", + "ThreadToolResourcesFileSearchVectorStoreChunkingStrategyStaticStatic", "ToolResources", "ToolResourcesCodeInterpreter", "ToolResourcesFileSearch", @@ -224,12 +227,44 @@ class ThreadToolResourcesCodeInterpreter(TypedDict, total=False): """ +class ThreadToolResourcesFileSearchVectorStoreChunkingStrategyAuto(TypedDict, total=False): + type: Required[Literal["auto"]] + """Always `auto`.""" + + +class ThreadToolResourcesFileSearchVectorStoreChunkingStrategyStaticStatic(TypedDict, total=False): + chunk_overlap_tokens: Required[int] + """The number of tokens that overlap between chunks. The default value is `400`. + + Note that the overlap must not exceed half of `max_chunk_size_tokens`. + """ + + max_chunk_size_tokens: Required[int] + """The maximum number of tokens in each chunk. + + The default value is `800`. The minimum value is `100` and the maximum value is + `4096`. + """ + + +class ThreadToolResourcesFileSearchVectorStoreChunkingStrategyStatic(TypedDict, total=False): + static: Required[ThreadToolResourcesFileSearchVectorStoreChunkingStrategyStaticStatic] + + type: Required[Literal["static"]] + """Always `static`.""" + + +ThreadToolResourcesFileSearchVectorStoreChunkingStrategy: TypeAlias = Union[ + ThreadToolResourcesFileSearchVectorStoreChunkingStrategyAuto, + ThreadToolResourcesFileSearchVectorStoreChunkingStrategyStatic, +] + + class ThreadToolResourcesFileSearchVectorStore(TypedDict, total=False): - chunking_strategy: FileChunkingStrategyParam + chunking_strategy: ThreadToolResourcesFileSearchVectorStoreChunkingStrategy """The chunking strategy used to chunk the file(s). - If not set, will use the `auto` strategy. Only applicable if `file_ids` is - non-empty. + If not set, will use the `auto` strategy. """ file_ids: List[str] diff --git a/src/openai/types/beta/thread_create_params.py b/src/openai/types/beta/thread_create_params.py index 127202753c..ec1ccf19a6 100644 --- a/src/openai/types/beta/thread_create_params.py +++ b/src/openai/types/beta/thread_create_params.py @@ -7,7 +7,6 @@ from ..shared_params.metadata import Metadata from .code_interpreter_tool_param import CodeInterpreterToolParam -from .file_chunking_strategy_param import FileChunkingStrategyParam from .threads.message_content_part_param import MessageContentPartParam __all__ = [ @@ -20,6 +19,10 @@ "ToolResourcesCodeInterpreter", "ToolResourcesFileSearch", "ToolResourcesFileSearchVectorStore", + "ToolResourcesFileSearchVectorStoreChunkingStrategy", + "ToolResourcesFileSearchVectorStoreChunkingStrategyAuto", + "ToolResourcesFileSearchVectorStoreChunkingStrategyStatic", + "ToolResourcesFileSearchVectorStoreChunkingStrategyStaticStatic", ] @@ -101,12 +104,43 @@ class ToolResourcesCodeInterpreter(TypedDict, total=False): """ +class ToolResourcesFileSearchVectorStoreChunkingStrategyAuto(TypedDict, total=False): + type: Required[Literal["auto"]] + """Always `auto`.""" + + +class ToolResourcesFileSearchVectorStoreChunkingStrategyStaticStatic(TypedDict, total=False): + chunk_overlap_tokens: Required[int] + """The number of tokens that overlap between chunks. The default value is `400`. + + Note that the overlap must not exceed half of `max_chunk_size_tokens`. + """ + + max_chunk_size_tokens: Required[int] + """The maximum number of tokens in each chunk. + + The default value is `800`. The minimum value is `100` and the maximum value is + `4096`. + """ + + +class ToolResourcesFileSearchVectorStoreChunkingStrategyStatic(TypedDict, total=False): + static: Required[ToolResourcesFileSearchVectorStoreChunkingStrategyStaticStatic] + + type: Required[Literal["static"]] + """Always `static`.""" + + +ToolResourcesFileSearchVectorStoreChunkingStrategy: TypeAlias = Union[ + ToolResourcesFileSearchVectorStoreChunkingStrategyAuto, ToolResourcesFileSearchVectorStoreChunkingStrategyStatic +] + + class ToolResourcesFileSearchVectorStore(TypedDict, total=False): - chunking_strategy: FileChunkingStrategyParam + chunking_strategy: ToolResourcesFileSearchVectorStoreChunkingStrategy """The chunking strategy used to chunk the file(s). - If not set, will use the `auto` strategy. Only applicable if `file_ids` is - non-empty. + If not set, will use the `auto` strategy. """ file_ids: List[str] diff --git a/src/openai/types/beta/threads/run_create_params.py b/src/openai/types/beta/threads/run_create_params.py index 098e50a1d9..fc70227862 100644 --- a/src/openai/types/beta/threads/run_create_params.py +++ b/src/openai/types/beta/threads/run_create_params.py @@ -9,6 +9,7 @@ from ..assistant_tool_param import AssistantToolParam from .runs.run_step_include import RunStepInclude from ...shared_params.metadata import Metadata +from ...shared.reasoning_effort import ReasoningEffort from .message_content_part_param import MessageContentPartParam from ..code_interpreter_tool_param import CodeInterpreterToolParam from ..assistant_tool_choice_option_param import AssistantToolChoiceOptionParam @@ -106,8 +107,8 @@ class RunCreateParamsBase(TypedDict, total=False): during tool use. """ - reasoning_effort: Optional[Literal["low", "medium", "high"]] - """**o1 and o3-mini models only** + reasoning_effort: Optional[ReasoningEffort] + """**o-series models only** Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently diff --git a/src/openai/types/chat/chat_completion_audio_param.py b/src/openai/types/chat/chat_completion_audio_param.py index 1e20a52b41..6321417826 100644 --- a/src/openai/types/chat/chat_completion_audio_param.py +++ b/src/openai/types/chat/chat_completion_audio_param.py @@ -17,7 +17,6 @@ class ChatCompletionAudioParam(TypedDict, total=False): voice: Required[Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"]] """The voice the model uses to respond. - Supported voices are `ash`, `ballad`, `coral`, `sage`, and `verse` (also - supported but not recommended are `alloy`, `echo`, and `shimmer`; these voices - are less expressive). + Supported voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`, and + `shimmer`. """ diff --git a/src/openai/types/chat/chat_completion_content_part_param.py b/src/openai/types/chat/chat_completion_content_part_param.py index 682d11f4c7..1293c54312 100644 --- a/src/openai/types/chat/chat_completion_content_part_param.py +++ b/src/openai/types/chat/chat_completion_content_part_param.py @@ -3,14 +3,39 @@ from __future__ import annotations from typing import Union -from typing_extensions import TypeAlias +from typing_extensions import Literal, Required, TypeAlias, TypedDict from .chat_completion_content_part_text_param import ChatCompletionContentPartTextParam from .chat_completion_content_part_image_param import ChatCompletionContentPartImageParam from .chat_completion_content_part_input_audio_param import ChatCompletionContentPartInputAudioParam -__all__ = ["ChatCompletionContentPartParam"] +__all__ = ["ChatCompletionContentPartParam", "File", "FileFile"] + + +class FileFile(TypedDict, total=False): + file_data: str + """ + The base64 encoded file data, used when passing the file to the model as a + string. + """ + + file_id: str + """The ID of an uploaded file to use as input.""" + + file_name: str + """The name of the file, used when passing the file to the model as a string.""" + + +class File(TypedDict, total=False): + file: Required[FileFile] + + type: Required[Literal["file"]] + """The type of the content part. Always `file`.""" + ChatCompletionContentPartParam: TypeAlias = Union[ - ChatCompletionContentPartTextParam, ChatCompletionContentPartImageParam, ChatCompletionContentPartInputAudioParam + ChatCompletionContentPartTextParam, + ChatCompletionContentPartImageParam, + ChatCompletionContentPartInputAudioParam, + File, ] diff --git a/src/openai/types/chat/chat_completion_message.py b/src/openai/types/chat/chat_completion_message.py index 704fa5d5d1..c659ac3da0 100644 --- a/src/openai/types/chat/chat_completion_message.py +++ b/src/openai/types/chat/chat_completion_message.py @@ -7,7 +7,29 @@ from .chat_completion_audio import ChatCompletionAudio from .chat_completion_message_tool_call import ChatCompletionMessageToolCall -__all__ = ["ChatCompletionMessage", "FunctionCall"] +__all__ = ["ChatCompletionMessage", "Annotation", "AnnotationURLCitation", "FunctionCall"] + + +class AnnotationURLCitation(BaseModel): + end_index: int + """The index of the last character of the URL citation in the message.""" + + start_index: int + """The index of the first character of the URL citation in the message.""" + + title: str + """The title of the web resource.""" + + url: str + """The URL of the web resource.""" + + +class Annotation(BaseModel): + type: Literal["url_citation"] + """The type of the URL citation. Always `url_citation`.""" + + url_citation: AnnotationURLCitation + """A URL citation when using web search.""" class FunctionCall(BaseModel): @@ -33,6 +55,12 @@ class ChatCompletionMessage(BaseModel): role: Literal["assistant"] """The role of the author of this message.""" + annotations: Optional[List[Annotation]] = None + """ + Annotations for the message, when applicable, as when using the + [web search tool](https://platform.openai.com/docs/guides/tools-web-search?api-mode=chat). + """ + audio: Optional[ChatCompletionAudio] = None """ If the audio output modality is requested, this object contains data about the diff --git a/src/openai/types/chat/chat_completion_reasoning_effort.py b/src/openai/types/chat/chat_completion_reasoning_effort.py index 85249c53b1..e4785c90bf 100644 --- a/src/openai/types/chat/chat_completion_reasoning_effort.py +++ b/src/openai/types/chat/chat_completion_reasoning_effort.py @@ -1,8 +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 + +from ..shared.reasoning_effort import ReasoningEffort __all__ = ["ChatCompletionReasoningEffort"] -ChatCompletionReasoningEffort: TypeAlias = Optional[Literal["low", "medium", "high"]] +ChatCompletionReasoningEffort = ReasoningEffort diff --git a/src/openai/types/chat/completion_create_params.py b/src/openai/types/chat/completion_create_params.py index 4dd2812aba..05103fba91 100644 --- a/src/openai/types/chat/completion_create_params.py +++ b/src/openai/types/chat/completion_create_params.py @@ -7,11 +7,10 @@ from ..shared.chat_model import ChatModel from ..shared_params.metadata import Metadata -from .chat_completion_modality import ChatCompletionModality +from ..shared.reasoning_effort import ReasoningEffort from .chat_completion_tool_param import ChatCompletionToolParam from .chat_completion_audio_param import ChatCompletionAudioParam from .chat_completion_message_param import ChatCompletionMessageParam -from .chat_completion_reasoning_effort import ChatCompletionReasoningEffort from ..shared_params.function_parameters import FunctionParameters from ..shared_params.response_format_text import ResponseFormatText from .chat_completion_stream_options_param import ChatCompletionStreamOptionsParam @@ -26,6 +25,9 @@ "FunctionCall", "Function", "ResponseFormat", + "WebSearchOptions", + "WebSearchOptionsUserLocation", + "WebSearchOptionsUserLocationApproximate", "CompletionCreateParamsNonStreaming", "CompletionCreateParamsStreaming", ] @@ -43,11 +45,12 @@ class CompletionCreateParamsBase(TypedDict, total=False): """ model: Required[Union[str, ChatModel]] - """ID of the model to use. + """Model ID used to generate the response, like `gpt-4o` or `o1`. - See the - [model endpoint compatibility](https://platform.openai.com/docs/models#model-endpoint-compatibility) - table for details on which models work with the Chat API. + OpenAI offers a wide range of models with different capabilities, performance + characteristics, and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. """ audio: Optional[ChatCompletionAudioParam] @@ -133,10 +136,10 @@ class CompletionCreateParamsBase(TypedDict, total=False): a maximum length of 512 characters. """ - modalities: Optional[List[ChatCompletionModality]] + modalities: Optional[List[Literal["text", "audio"]]] """ - Output types that you would like the model to generate for this request. Most - models are capable of generating text, which is the default: + Output types that you would like the model to generate. Most models are capable + of generating text, which is the default: `["text"]` @@ -174,8 +177,8 @@ class CompletionCreateParamsBase(TypedDict, total=False): far, increasing the model's likelihood to talk about new topics. """ - reasoning_effort: Optional[ChatCompletionReasoningEffort] - """**o1 and o3-mini models only** + reasoning_effort: Optional[ReasoningEffort] + """**o-series models only** Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently @@ -191,16 +194,9 @@ class CompletionCreateParamsBase(TypedDict, total=False): in the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the - message the model generates is valid JSON. - - **Important:** when using JSON mode, you **must** also instruct the model to - produce JSON yourself via a system or user message. Without this, the model may - generate an unending stream of whitespace until the generation reaches the token - limit, resulting in a long-running and seemingly "stuck" request. Also note that - the message content may be partially cut off if `finish_reason="length"`, which - indicates the generation exceeded `max_tokens` or the conversation exceeded the - max context length. + Setting to `{ "type": "json_object" }` enables the older JSON mode, which + ensures the message the model generates is valid JSON. Using `json_schema` is + preferred for models that support it. """ seed: Optional[int] @@ -221,14 +217,20 @@ class CompletionCreateParamsBase(TypedDict, total=False): utilize scale tier credits until they are exhausted. - If set to 'auto', and the Project is not Scale tier enabled, the request will be processed using the default service tier with a lower uptime SLA and no - latency guarantee. + latency guarentee. - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarantee. + tier with a lower uptime SLA and no latency guarentee. - When not set, the default behavior is 'auto'. + + When this parameter is set, the response body will include the `service_tier` + utilized. """ - stop: Union[Optional[str], List[str]] - """Up to 4 sequences where the API will stop generating further tokens.""" + stop: Union[Optional[str], List[str], None] + """Up to 4 sequences where the API will stop generating further tokens. + + The returned text will not contain the stop sequence. + """ store: Optional[bool] """ @@ -292,6 +294,13 @@ class CompletionCreateParamsBase(TypedDict, total=False): [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). """ + web_search_options: WebSearchOptions + """ + This tool searches the web for relevant results to use in a response. Learn more + about the + [web search tool](https://platform.openai.com/docs/guides/tools-web-search?api-mode=chat). + """ + FunctionCall: TypeAlias = Union[Literal["none", "auto"], ChatCompletionFunctionCallOptionParam] @@ -322,30 +331,73 @@ class Function(TypedDict, total=False): """ -ResponseFormat: TypeAlias = Union[ResponseFormatText, ResponseFormatJSONObject, ResponseFormatJSONSchema] +ResponseFormat: TypeAlias = Union[ResponseFormatText, ResponseFormatJSONSchema, ResponseFormatJSONObject] + + +class WebSearchOptionsUserLocationApproximate(TypedDict, total=False): + city: str + """Free text input for the city of the user, e.g. `San Francisco`.""" + + country: str + """ + The two-letter [ISO country code](https://en.wikipedia.org/wiki/ISO_3166-1) of + the user, e.g. `US`. + """ + + region: str + """Free text input for the region of the user, e.g. `California`.""" + + timezone: str + """ + The [IANA timezone](https://timeapi.io/documentation/iana-timezones) of the + user, e.g. `America/Los_Angeles`. + """ + + +class WebSearchOptionsUserLocation(TypedDict, total=False): + approximate: Required[WebSearchOptionsUserLocationApproximate] + """Approximate location parameters for the search.""" + + type: Required[Literal["approximate"]] + """The type of location approximation. Always `approximate`.""" + + +class WebSearchOptions(TypedDict, total=False): + search_context_size: Literal["low", "medium", "high"] + """ + High level guidance for the amount of context window space to use for the + search. One of `low`, `medium`, or `high`. `medium` is the default. + """ + + user_location: Optional[WebSearchOptionsUserLocation] + """Approximate location parameters for the search.""" class CompletionCreateParamsNonStreaming(CompletionCreateParamsBase, total=False): stream: Optional[Literal[False]] - """If set, partial message deltas will be sent, like in ChatGPT. - - Tokens will be sent as data-only - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format) - as they become available, with the stream terminated by a `data: [DONE]` - message. - [Example Python code](https://cookbook.openai.com/examples/how_to_stream_completions). + """ + If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section below](https://platform.openai.com/docs/api-reference/chat/streaming) + for more information, along with the + [streaming responses](https://platform.openai.com/docs/guides/streaming-responses) + guide for more information on how to handle the streaming events. """ class CompletionCreateParamsStreaming(CompletionCreateParamsBase): stream: Required[Literal[True]] - """If set, partial message deltas will be sent, like in ChatGPT. - - Tokens will be sent as data-only - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format) - as they become available, with the stream terminated by a `data: [DONE]` - message. - [Example Python code](https://cookbook.openai.com/examples/how_to_stream_completions). + """ + If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section below](https://platform.openai.com/docs/api-reference/chat/streaming) + for more information, along with the + [streaming responses](https://platform.openai.com/docs/guides/streaming-responses) + guide for more information on how to handle the streaming events. """ diff --git a/src/openai/types/chat/completion_list_params.py b/src/openai/types/chat/completion_list_params.py index a8fce900ce..d93da834a3 100644 --- a/src/openai/types/chat/completion_list_params.py +++ b/src/openai/types/chat/completion_list_params.py @@ -15,19 +15,19 @@ class CompletionListParams(TypedDict, total=False): """Identifier for the last chat completion from the previous pagination request.""" limit: int - """Number of chat completions to retrieve.""" + """Number of Chat Completions to retrieve.""" metadata: Optional[Metadata] - """A list of metadata keys to filter the chat completions by. Example: + """A list of metadata keys to filter the Chat Completions by. Example: `metadata[key1]=value1&metadata[key2]=value2` """ model: str - """The model used to generate the chat completions.""" + """The model used to generate the Chat Completions.""" order: Literal["asc", "desc"] - """Sort order for chat completions by timestamp. + """Sort order for Chat Completions by timestamp. Use `asc` for ascending order or `desc` for descending order. Defaults to `asc`. """ diff --git a/src/openai/types/beta/file_chunking_strategy.py b/src/openai/types/file_chunking_strategy.py similarity index 93% rename from src/openai/types/beta/file_chunking_strategy.py rename to src/openai/types/file_chunking_strategy.py index 406d69dd0e..ee96bd7884 100644 --- a/src/openai/types/beta/file_chunking_strategy.py +++ b/src/openai/types/file_chunking_strategy.py @@ -3,7 +3,7 @@ from typing import Union from typing_extensions import Annotated, TypeAlias -from ..._utils import PropertyInfo +from .._utils import PropertyInfo from .other_file_chunking_strategy_object import OtherFileChunkingStrategyObject from .static_file_chunking_strategy_object import StaticFileChunkingStrategyObject diff --git a/src/openai/types/beta/file_chunking_strategy_param.py b/src/openai/types/file_chunking_strategy_param.py similarity index 100% rename from src/openai/types/beta/file_chunking_strategy_param.py rename to src/openai/types/file_chunking_strategy_param.py diff --git a/src/openai/types/file_create_params.py b/src/openai/types/file_create_params.py index ecf7503358..728dfd350f 100644 --- a/src/openai/types/file_create_params.py +++ b/src/openai/types/file_create_params.py @@ -17,10 +17,8 @@ class FileCreateParams(TypedDict, total=False): purpose: Required[FilePurpose] """The intended purpose of the uploaded file. - Use "assistants" for - [Assistants](https://platform.openai.com/docs/api-reference/assistants) and - [Message](https://platform.openai.com/docs/api-reference/messages) files, - "vision" for Assistants image file inputs, "batch" for - [Batch API](https://platform.openai.com/docs/guides/batch), and "fine-tune" for - [Fine-tuning](https://platform.openai.com/docs/api-reference/fine-tuning). + One of: - `assistants`: Used in the Assistants API - `batch`: Used in the Batch + API - `fine-tune`: Used for fine-tuning - `vision`: Images used for vision + fine-tuning - `user_data`: Flexible file type for any purpose - `evals`: Used + for eval data sets """ diff --git a/src/openai/types/file_purpose.py b/src/openai/types/file_purpose.py index 32dc352c62..b2c2d5f9fc 100644 --- a/src/openai/types/file_purpose.py +++ b/src/openai/types/file_purpose.py @@ -4,4 +4,4 @@ __all__ = ["FilePurpose"] -FilePurpose: TypeAlias = Literal["assistants", "batch", "fine-tune", "vision"] +FilePurpose: TypeAlias = Literal["assistants", "batch", "fine-tune", "vision", "user_data", "evals"] diff --git a/src/openai/types/beta/other_file_chunking_strategy_object.py b/src/openai/types/other_file_chunking_strategy_object.py similarity index 89% rename from src/openai/types/beta/other_file_chunking_strategy_object.py rename to src/openai/types/other_file_chunking_strategy_object.py index 89da560be4..e4cd61a8fc 100644 --- a/src/openai/types/beta/other_file_chunking_strategy_object.py +++ b/src/openai/types/other_file_chunking_strategy_object.py @@ -2,7 +2,7 @@ from typing_extensions import Literal -from ..._models import BaseModel +from .._models import BaseModel __all__ = ["OtherFileChunkingStrategyObject"] diff --git a/src/openai/types/responses/__init__.py b/src/openai/types/responses/__init__.py new file mode 100644 index 0000000000..970a167d2c --- /dev/null +++ b/src/openai/types/responses/__init__.py @@ -0,0 +1,138 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .tool import Tool as Tool +from .response import Response as Response +from .tool_param import ToolParam as ToolParam +from .computer_tool import ComputerTool as ComputerTool +from .function_tool import FunctionTool as FunctionTool +from .response_error import ResponseError as ResponseError +from .response_usage import ResponseUsage as ResponseUsage +from .parsed_response import ( + ParsedContent as ParsedContent, + ParsedResponse as ParsedResponse, + ParsedResponseOutputItem as ParsedResponseOutputItem, + ParsedResponseOutputText as ParsedResponseOutputText, + ParsedResponseOutputMessage as ParsedResponseOutputMessage, + ParsedResponseFunctionToolCall as ParsedResponseFunctionToolCall, +) +from .response_status import ResponseStatus as ResponseStatus +from .web_search_tool import WebSearchTool as WebSearchTool +from .file_search_tool import FileSearchTool as FileSearchTool +from .tool_choice_types import ToolChoiceTypes as ToolChoiceTypes +from .response_item_list import ResponseItemList as ResponseItemList +from .computer_tool_param import ComputerToolParam as ComputerToolParam +from .function_tool_param import FunctionToolParam as FunctionToolParam +from .response_includable import ResponseIncludable as ResponseIncludable +from .response_input_file import ResponseInputFile as ResponseInputFile +from .response_input_text import ResponseInputText as ResponseInputText +from .tool_choice_options import ToolChoiceOptions as ToolChoiceOptions +from .response_error_event import ResponseErrorEvent as ResponseErrorEvent +from .response_input_image import ResponseInputImage as ResponseInputImage +from .response_input_param import ResponseInputParam as ResponseInputParam +from .response_output_item import ResponseOutputItem as ResponseOutputItem +from .response_output_text import ResponseOutputText as ResponseOutputText +from .response_text_config import ResponseTextConfig as ResponseTextConfig +from .tool_choice_function import ToolChoiceFunction as ToolChoiceFunction +from .response_failed_event import ResponseFailedEvent as ResponseFailedEvent +from .response_stream_event import ResponseStreamEvent as ResponseStreamEvent +from .web_search_tool_param import WebSearchToolParam as WebSearchToolParam +from .file_search_tool_param import FileSearchToolParam as FileSearchToolParam +from .input_item_list_params import InputItemListParams as InputItemListParams +from .response_create_params import ResponseCreateParams as ResponseCreateParams +from .response_created_event import ResponseCreatedEvent as ResponseCreatedEvent +from .response_input_content import ResponseInputContent as ResponseInputContent +from .response_output_message import ResponseOutputMessage as ResponseOutputMessage +from .response_output_refusal import ResponseOutputRefusal as ResponseOutputRefusal +from .tool_choice_types_param import ToolChoiceTypesParam as ToolChoiceTypesParam +from .easy_input_message_param import EasyInputMessageParam as EasyInputMessageParam +from .response_completed_event import ResponseCompletedEvent as ResponseCompletedEvent +from .response_retrieve_params import ResponseRetrieveParams as ResponseRetrieveParams +from .response_text_done_event import ResponseTextDoneEvent as ResponseTextDoneEvent +from .response_audio_done_event import ResponseAudioDoneEvent as ResponseAudioDoneEvent +from .response_incomplete_event import ResponseIncompleteEvent as ResponseIncompleteEvent +from .response_input_file_param import ResponseInputFileParam as ResponseInputFileParam +from .response_input_item_param import ResponseInputItemParam as ResponseInputItemParam +from .response_input_text_param import ResponseInputTextParam as ResponseInputTextParam +from .response_text_delta_event import ResponseTextDeltaEvent as ResponseTextDeltaEvent +from .response_audio_delta_event import ResponseAudioDeltaEvent as ResponseAudioDeltaEvent +from .response_in_progress_event import ResponseInProgressEvent as ResponseInProgressEvent +from .response_input_image_param import ResponseInputImageParam as ResponseInputImageParam +from .response_output_text_param import ResponseOutputTextParam as ResponseOutputTextParam +from .response_text_config_param import ResponseTextConfigParam as ResponseTextConfigParam +from .tool_choice_function_param import ToolChoiceFunctionParam as ToolChoiceFunctionParam +from .response_computer_tool_call import ResponseComputerToolCall as ResponseComputerToolCall +from .response_format_text_config import ResponseFormatTextConfig as ResponseFormatTextConfig +from .response_function_tool_call import ResponseFunctionToolCall as ResponseFunctionToolCall +from .response_refusal_done_event import ResponseRefusalDoneEvent as ResponseRefusalDoneEvent +from .response_function_web_search import ResponseFunctionWebSearch as ResponseFunctionWebSearch +from .response_input_content_param import ResponseInputContentParam as ResponseInputContentParam +from .response_refusal_delta_event import ResponseRefusalDeltaEvent as ResponseRefusalDeltaEvent +from .response_output_message_param import ResponseOutputMessageParam as ResponseOutputMessageParam +from .response_output_refusal_param import ResponseOutputRefusalParam as ResponseOutputRefusalParam +from .response_file_search_tool_call import ResponseFileSearchToolCall as ResponseFileSearchToolCall +from .response_output_item_done_event import ResponseOutputItemDoneEvent as ResponseOutputItemDoneEvent +from .response_content_part_done_event import ResponseContentPartDoneEvent as ResponseContentPartDoneEvent +from .response_output_item_added_event import ResponseOutputItemAddedEvent as ResponseOutputItemAddedEvent +from .response_computer_tool_call_param import ResponseComputerToolCallParam as ResponseComputerToolCallParam +from .response_content_part_added_event import ResponseContentPartAddedEvent as ResponseContentPartAddedEvent +from .response_format_text_config_param import ResponseFormatTextConfigParam as ResponseFormatTextConfigParam +from .response_function_tool_call_param import ResponseFunctionToolCallParam as ResponseFunctionToolCallParam +from .response_function_web_search_param import ResponseFunctionWebSearchParam as ResponseFunctionWebSearchParam +from .response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall as ResponseCodeInterpreterToolCall +from .response_input_message_content_list import ResponseInputMessageContentList as ResponseInputMessageContentList +from .response_audio_transcript_done_event import ResponseAudioTranscriptDoneEvent as ResponseAudioTranscriptDoneEvent +from .response_file_search_tool_call_param import ResponseFileSearchToolCallParam as ResponseFileSearchToolCallParam +from .response_text_annotation_delta_event import ResponseTextAnnotationDeltaEvent as ResponseTextAnnotationDeltaEvent +from .response_audio_transcript_delta_event import ( + ResponseAudioTranscriptDeltaEvent as ResponseAudioTranscriptDeltaEvent, +) +from .response_format_text_json_schema_config import ( + ResponseFormatTextJSONSchemaConfig as ResponseFormatTextJSONSchemaConfig, +) +from .response_web_search_call_completed_event import ( + ResponseWebSearchCallCompletedEvent as ResponseWebSearchCallCompletedEvent, +) +from .response_web_search_call_searching_event import ( + ResponseWebSearchCallSearchingEvent as ResponseWebSearchCallSearchingEvent, +) +from .response_file_search_call_completed_event import ( + ResponseFileSearchCallCompletedEvent as ResponseFileSearchCallCompletedEvent, +) +from .response_file_search_call_searching_event import ( + ResponseFileSearchCallSearchingEvent as ResponseFileSearchCallSearchingEvent, +) +from .response_input_message_content_list_param import ( + ResponseInputMessageContentListParam as ResponseInputMessageContentListParam, +) +from .response_web_search_call_in_progress_event import ( + ResponseWebSearchCallInProgressEvent as ResponseWebSearchCallInProgressEvent, +) +from .response_file_search_call_in_progress_event import ( + ResponseFileSearchCallInProgressEvent as ResponseFileSearchCallInProgressEvent, +) +from .response_function_call_arguments_done_event import ( + ResponseFunctionCallArgumentsDoneEvent as ResponseFunctionCallArgumentsDoneEvent, +) +from .response_function_call_arguments_delta_event import ( + ResponseFunctionCallArgumentsDeltaEvent as ResponseFunctionCallArgumentsDeltaEvent, +) +from .response_format_text_json_schema_config_param import ( + ResponseFormatTextJSONSchemaConfigParam as ResponseFormatTextJSONSchemaConfigParam, +) +from .response_code_interpreter_call_code_done_event import ( + ResponseCodeInterpreterCallCodeDoneEvent as ResponseCodeInterpreterCallCodeDoneEvent, +) +from .response_code_interpreter_call_completed_event import ( + ResponseCodeInterpreterCallCompletedEvent as ResponseCodeInterpreterCallCompletedEvent, +) +from .response_code_interpreter_call_code_delta_event import ( + ResponseCodeInterpreterCallCodeDeltaEvent as ResponseCodeInterpreterCallCodeDeltaEvent, +) +from .response_code_interpreter_call_in_progress_event import ( + ResponseCodeInterpreterCallInProgressEvent as ResponseCodeInterpreterCallInProgressEvent, +) +from .response_code_interpreter_call_interpreting_event import ( + ResponseCodeInterpreterCallInterpretingEvent as ResponseCodeInterpreterCallInterpretingEvent, +) diff --git a/src/openai/types/responses/computer_tool.py b/src/openai/types/responses/computer_tool.py new file mode 100644 index 0000000000..f0499cd950 --- /dev/null +++ b/src/openai/types/responses/computer_tool.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ComputerTool"] + + +class ComputerTool(BaseModel): + display_height: float + """The height of the computer display.""" + + display_width: float + """The width of the computer display.""" + + environment: Literal["mac", "windows", "ubuntu", "browser"] + """The type of computer environment to control.""" + + type: Literal["computer-preview"] + """The type of the computer use tool. Always `computer_use_preview`.""" diff --git a/src/openai/types/responses/computer_tool_param.py b/src/openai/types/responses/computer_tool_param.py new file mode 100644 index 0000000000..685b471378 --- /dev/null +++ b/src/openai/types/responses/computer_tool_param.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ComputerToolParam"] + + +class ComputerToolParam(TypedDict, total=False): + display_height: Required[float] + """The height of the computer display.""" + + display_width: Required[float] + """The width of the computer display.""" + + environment: Required[Literal["mac", "windows", "ubuntu", "browser"]] + """The type of computer environment to control.""" + + type: Required[Literal["computer-preview"]] + """The type of the computer use tool. Always `computer_use_preview`.""" diff --git a/src/openai/types/responses/easy_input_message_param.py b/src/openai/types/responses/easy_input_message_param.py new file mode 100644 index 0000000000..ef2f1c5f37 --- /dev/null +++ b/src/openai/types/responses/easy_input_message_param.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import Literal, Required, TypedDict + +from .response_input_message_content_list_param import ResponseInputMessageContentListParam + +__all__ = ["EasyInputMessageParam"] + + +class EasyInputMessageParam(TypedDict, total=False): + content: Required[Union[str, ResponseInputMessageContentListParam]] + """ + Text, image, or audio input to the model, used to generate a response. Can also + contain previous assistant responses. + """ + + role: Required[Literal["user", "assistant", "system", "developer"]] + """The role of the message input. + + One of `user`, `assistant`, `system`, or `developer`. + """ + + type: Literal["message"] + """The type of the message input. Always `message`.""" diff --git a/src/openai/types/responses/file_search_tool.py b/src/openai/types/responses/file_search_tool.py new file mode 100644 index 0000000000..683fc533fe --- /dev/null +++ b/src/openai/types/responses/file_search_tool.py @@ -0,0 +1,44 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, TypeAlias + +from ..._models import BaseModel +from ..shared.compound_filter import CompoundFilter +from ..shared.comparison_filter import ComparisonFilter + +__all__ = ["FileSearchTool", "Filters", "RankingOptions"] + +Filters: TypeAlias = Union[ComparisonFilter, CompoundFilter] + + +class RankingOptions(BaseModel): + ranker: Optional[Literal["auto", "default-2024-11-15"]] = None + """The ranker to use for the file search.""" + + score_threshold: Optional[float] = None + """ + The score threshold for the file search, a number between 0 and 1. Numbers + closer to 1 will attempt to return only the most relevant results, but may + return fewer results. + """ + + +class FileSearchTool(BaseModel): + type: Literal["file_search"] + """The type of the file search tool. Always `file_search`.""" + + vector_store_ids: List[str] + """The IDs of the vector stores to search.""" + + filters: Optional[Filters] = None + """A filter to apply based on file attributes.""" + + max_num_results: Optional[int] = None + """The maximum number of results to return. + + This number should be between 1 and 50 inclusive. + """ + + ranking_options: Optional[RankingOptions] = None + """Ranking options for search.""" diff --git a/src/openai/types/responses/file_search_tool_param.py b/src/openai/types/responses/file_search_tool_param.py new file mode 100644 index 0000000000..2d6af8536b --- /dev/null +++ b/src/openai/types/responses/file_search_tool_param.py @@ -0,0 +1,45 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from ..shared_params.compound_filter import CompoundFilter +from ..shared_params.comparison_filter import ComparisonFilter + +__all__ = ["FileSearchToolParam", "Filters", "RankingOptions"] + +Filters: TypeAlias = Union[ComparisonFilter, CompoundFilter] + + +class RankingOptions(TypedDict, total=False): + ranker: Literal["auto", "default-2024-11-15"] + """The ranker to use for the file search.""" + + score_threshold: float + """ + The score threshold for the file search, a number between 0 and 1. Numbers + closer to 1 will attempt to return only the most relevant results, but may + return fewer results. + """ + + +class FileSearchToolParam(TypedDict, total=False): + type: Required[Literal["file_search"]] + """The type of the file search tool. Always `file_search`.""" + + vector_store_ids: Required[List[str]] + """The IDs of the vector stores to search.""" + + filters: Filters + """A filter to apply based on file attributes.""" + + max_num_results: int + """The maximum number of results to return. + + This number should be between 1 and 50 inclusive. + """ + + ranking_options: RankingOptions + """Ranking options for search.""" diff --git a/src/openai/types/responses/function_tool.py b/src/openai/types/responses/function_tool.py new file mode 100644 index 0000000000..236a2c7c63 --- /dev/null +++ b/src/openai/types/responses/function_tool.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["FunctionTool"] + + +class FunctionTool(BaseModel): + name: str + """The name of the function to call.""" + + parameters: Dict[str, object] + """A JSON schema object describing the parameters of the function.""" + + strict: bool + """Whether to enforce strict parameter validation. Default `true`.""" + + type: Literal["function"] + """The type of the function tool. Always `function`.""" + + description: Optional[str] = None + """A description of the function. + + Used by the model to determine whether or not to call the function. + """ diff --git a/src/openai/types/responses/function_tool_param.py b/src/openai/types/responses/function_tool_param.py new file mode 100644 index 0000000000..774a22e336 --- /dev/null +++ b/src/openai/types/responses/function_tool_param.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["FunctionToolParam"] + + +class FunctionToolParam(TypedDict, total=False): + name: Required[str] + """The name of the function to call.""" + + parameters: Required[Dict[str, object]] + """A JSON schema object describing the parameters of the function.""" + + strict: Required[bool] + """Whether to enforce strict parameter validation. Default `true`.""" + + type: Required[Literal["function"]] + """The type of the function tool. Always `function`.""" + + description: Optional[str] + """A description of the function. + + Used by the model to determine whether or not to call the function. + """ diff --git a/src/openai/types/responses/input_item_list_params.py b/src/openai/types/responses/input_item_list_params.py new file mode 100644 index 0000000000..e0b71f1ac5 --- /dev/null +++ b/src/openai/types/responses/input_item_list_params.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["InputItemListParams"] + + +class InputItemListParams(TypedDict, total=False): + after: str + """An item ID to list items after, used in pagination.""" + + before: str + """An item ID to list items before, used in pagination.""" + + limit: int + """A limit on the number of objects to be returned. + + Limit can range between 1 and 100, and the default is 20. + """ + + order: Literal["asc", "desc"] + """The order to return the input items in. Default is `asc`. + + - `asc`: Return the input items in ascending order. + - `desc`: Return the input items in descending order. + """ diff --git a/src/openai/types/responses/parsed_response.py b/src/openai/types/responses/parsed_response.py new file mode 100644 index 0000000000..3216a71ba9 --- /dev/null +++ b/src/openai/types/responses/parsed_response.py @@ -0,0 +1,77 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import TYPE_CHECKING, List, Union, Generic, TypeVar, Optional +from typing_extensions import Annotated, TypeAlias + +from ..._utils import PropertyInfo +from .response import Response +from ..._models import GenericModel +from ..._utils._transform import PropertyInfo +from .response_output_item import Reasoning +from .response_output_text import ResponseOutputText +from .response_output_message import ResponseOutputMessage +from .response_output_refusal import ResponseOutputRefusal +from .response_computer_tool_call import ResponseComputerToolCall +from .response_function_tool_call import ResponseFunctionToolCall +from .response_function_web_search import ResponseFunctionWebSearch +from .response_file_search_tool_call import ResponseFileSearchToolCall + +__all__ = ["ParsedResponse", "ParsedResponseOutputMessage", "ParsedResponseOutputText"] + +ContentType = TypeVar("ContentType") + +# we need to disable this check because we're overriding properties +# with subclasses of their types which is technically unsound as +# properties can be mutated. +# pyright: reportIncompatibleVariableOverride=false + + +class ParsedResponseOutputText(ResponseOutputText, GenericModel, Generic[ContentType]): + parsed: Optional[ContentType] = None + + +ParsedContent: TypeAlias = Annotated[ + Union[ParsedResponseOutputText[ContentType], ResponseOutputRefusal], + PropertyInfo(discriminator="type"), +] + + +class ParsedResponseOutputMessage(ResponseOutputMessage, GenericModel, Generic[ContentType]): + if TYPE_CHECKING: + content: List[ParsedContent[ContentType]] # type: ignore[assignment] + else: + content: List[ParsedContent] + + +class ParsedResponseFunctionToolCall(ResponseFunctionToolCall): + parsed_arguments: object = None + + +ParsedResponseOutputItem: TypeAlias = Annotated[ + Union[ + ParsedResponseOutputMessage[ContentType], + ParsedResponseFunctionToolCall, + ResponseFileSearchToolCall, + ResponseFunctionWebSearch, + ResponseComputerToolCall, + Reasoning, + ], + PropertyInfo(discriminator="type"), +] + + +class ParsedResponse(Response, GenericModel, Generic[ContentType]): + if TYPE_CHECKING: + output: List[ParsedResponseOutputItem[ContentType]] # type: ignore[assignment] + else: + output: List[ParsedResponseOutputItem] + + @property + def output_parsed(self) -> Optional[ContentType]: + for output in self.output: + if output.type == "message": + for content in output.content: + if content.type == "output_text" and content.parsed: + return content.parsed + + return None diff --git a/src/openai/types/responses/response.py b/src/openai/types/responses/response.py new file mode 100644 index 0000000000..66887ae9b5 --- /dev/null +++ b/src/openai/types/responses/response.py @@ -0,0 +1,204 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, TypeAlias + +from .tool import Tool +from ..._models import BaseModel +from .response_error import ResponseError +from .response_usage import ResponseUsage +from .response_status import ResponseStatus +from ..shared.metadata import Metadata +from ..shared.reasoning import Reasoning +from .tool_choice_types import ToolChoiceTypes +from ..shared.chat_model import ChatModel +from .tool_choice_options import ToolChoiceOptions +from .response_output_item import ResponseOutputItem +from .response_text_config import ResponseTextConfig +from .tool_choice_function import ToolChoiceFunction + +__all__ = ["Response", "IncompleteDetails", "ToolChoice"] + + +class IncompleteDetails(BaseModel): + reason: Optional[Literal["max_output_tokens", "content_filter"]] = None + """The reason why the response is incomplete.""" + + +ToolChoice: TypeAlias = Union[ToolChoiceOptions, ToolChoiceTypes, ToolChoiceFunction] + + +class Response(BaseModel): + id: str + """Unique identifier for this Response.""" + + created_at: float + """Unix timestamp (in seconds) of when this Response was created.""" + + error: Optional[ResponseError] = None + """An error object returned when the model fails to generate a Response.""" + + incomplete_details: Optional[IncompleteDetails] = None + """Details about why the response is incomplete.""" + + instructions: Optional[str] = None + """ + Inserts a system (or developer) message as the first item in the model's + context. + + When using along with `previous_response_id`, the instructions from a previous + response will be not be carried over to the next response. This makes it simple + to swap out system (or developer) messages in new responses. + """ + + metadata: Optional[Metadata] = None + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + """ + + model: Union[str, ChatModel] + """Model ID used to generate the response, like `gpt-4o` or `o1`. + + OpenAI offers a wide range of models with different capabilities, performance + characteristics, and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + """ + + object: Literal["response"] + """The object type of this resource - always set to `response`.""" + + output: List[ResponseOutputItem] + """An array of content items generated by the model. + + - The length and order of items in the `output` array is dependent on the + model's response. + - Rather than accessing the first item in the `output` array and assuming it's + an `assistant` message with the content generated by the model, you might + consider using the `output_text` property where supported in SDKs. + """ + + parallel_tool_calls: bool + """Whether to allow the model to run tool calls in parallel.""" + + temperature: Optional[float] = None + """What sampling temperature to use, between 0 and 2. + + Higher values like 0.8 will make the output more random, while lower values like + 0.2 will make it more focused and deterministic. We generally recommend altering + this or `top_p` but not both. + """ + + tool_choice: ToolChoice + """ + How the model should select which tool (or tools) to use when generating a + response. See the `tools` parameter to see how to specify which tools the model + can call. + """ + + tools: List[Tool] + """An array of tools the model may call while generating a response. + + You can specify which tool to use by setting the `tool_choice` parameter. + + The two categories of tools you can provide the model are: + + - **Built-in tools**: Tools that are provided by OpenAI that extend the model's + capabilities, like + [web search](https://platform.openai.com/docs/guides/tools-web-search) or + [file search](https://platform.openai.com/docs/guides/tools-file-search). + Learn more about + [built-in tools](https://platform.openai.com/docs/guides/tools). + - **Function calls (custom tools)**: Functions that are defined by you, enabling + the model to call your own code. Learn more about + [function calling](https://platform.openai.com/docs/guides/function-calling). + """ + + top_p: Optional[float] = None + """ + An alternative to sampling with temperature, called nucleus sampling, where the + model considers the results of the tokens with top_p probability mass. So 0.1 + means only the tokens comprising the top 10% probability mass are considered. + + We generally recommend altering this or `temperature` but not both. + """ + + max_output_tokens: Optional[int] = None + """ + An upper bound for the number of tokens that can be generated for a response, + including visible output tokens and + [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). + """ + + previous_response_id: Optional[str] = None + """The unique ID of the previous response to the model. + + Use this to create multi-turn conversations. Learn more about + [conversation state](https://platform.openai.com/docs/guides/conversation-state). + """ + + reasoning: Optional[Reasoning] = None + """**o-series models only** + + Configuration options for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). + """ + + status: Optional[ResponseStatus] = None + """The status of the response generation. + + One of `completed`, `failed`, `in_progress`, or `incomplete`. + """ + + text: Optional[ResponseTextConfig] = None + """Configuration options for a text response from the model. + + Can be plain text or structured JSON data. Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + """ + + truncation: Optional[Literal["auto", "disabled"]] = None + """The truncation strategy to use for the model response. + + - `auto`: If the context of this response and previous ones exceeds the model's + context window size, the model will truncate the response to fit the context + window by dropping input items in the middle of the conversation. + - `disabled` (default): If a model response will exceed the context window size + for a model, the request will fail with a 400 error. + """ + + usage: Optional[ResponseUsage] = None + """ + Represents token usage details including input tokens, output tokens, a + breakdown of output tokens, and the total tokens used. + """ + + user: Optional[str] = None + """ + A unique identifier representing your end-user, which can help OpenAI to monitor + and detect abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + """ + + @property + def output_text(self) -> str: + """Convenience property that aggregates all `output_text` items from the `output` + list. + + If no `output_text` content blocks exist, then an empty string is returned. + """ + texts: List[str] = [] + for output in self.output: + if output.type == "message": + for content in output.content: + if content.type == "output_text": + texts.append(content.text) + + return "".join(texts) diff --git a/src/openai/types/responses/response_audio_delta_event.py b/src/openai/types/responses/response_audio_delta_event.py new file mode 100644 index 0000000000..f3d77fac52 --- /dev/null +++ b/src/openai/types/responses/response_audio_delta_event.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseAudioDeltaEvent"] + + +class ResponseAudioDeltaEvent(BaseModel): + delta: str + """A chunk of Base64 encoded response audio bytes.""" + + type: Literal["response.audio.delta"] + """The type of the event. Always `response.audio.delta`.""" diff --git a/src/openai/types/responses/response_audio_done_event.py b/src/openai/types/responses/response_audio_done_event.py new file mode 100644 index 0000000000..5654f8e398 --- /dev/null +++ b/src/openai/types/responses/response_audio_done_event.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseAudioDoneEvent"] + + +class ResponseAudioDoneEvent(BaseModel): + type: Literal["response.audio.done"] + """The type of the event. Always `response.audio.done`.""" diff --git a/src/openai/types/responses/response_audio_transcript_delta_event.py b/src/openai/types/responses/response_audio_transcript_delta_event.py new file mode 100644 index 0000000000..69b6660f3f --- /dev/null +++ b/src/openai/types/responses/response_audio_transcript_delta_event.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseAudioTranscriptDeltaEvent"] + + +class ResponseAudioTranscriptDeltaEvent(BaseModel): + delta: str + """The partial transcript of the audio response.""" + + type: Literal["response.audio.transcript.delta"] + """The type of the event. Always `response.audio.transcript.delta`.""" diff --git a/src/openai/types/responses/response_audio_transcript_done_event.py b/src/openai/types/responses/response_audio_transcript_done_event.py new file mode 100644 index 0000000000..1a20319f83 --- /dev/null +++ b/src/openai/types/responses/response_audio_transcript_done_event.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseAudioTranscriptDoneEvent"] + + +class ResponseAudioTranscriptDoneEvent(BaseModel): + type: Literal["response.audio.transcript.done"] + """The type of the event. Always `response.audio.transcript.done`.""" diff --git a/src/openai/types/responses/response_code_interpreter_call_code_delta_event.py b/src/openai/types/responses/response_code_interpreter_call_code_delta_event.py new file mode 100644 index 0000000000..7527238d06 --- /dev/null +++ b/src/openai/types/responses/response_code_interpreter_call_code_delta_event.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseCodeInterpreterCallCodeDeltaEvent"] + + +class ResponseCodeInterpreterCallCodeDeltaEvent(BaseModel): + delta: str + """The partial code snippet added by the code interpreter.""" + + output_index: int + """The index of the output item that the code interpreter call is in progress.""" + + type: Literal["response.code_interpreter_call.code.delta"] + """The type of the event. Always `response.code_interpreter_call.code.delta`.""" diff --git a/src/openai/types/responses/response_code_interpreter_call_code_done_event.py b/src/openai/types/responses/response_code_interpreter_call_code_done_event.py new file mode 100644 index 0000000000..f84d4cf3e8 --- /dev/null +++ b/src/openai/types/responses/response_code_interpreter_call_code_done_event.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseCodeInterpreterCallCodeDoneEvent"] + + +class ResponseCodeInterpreterCallCodeDoneEvent(BaseModel): + code: str + """The final code snippet output by the code interpreter.""" + + output_index: int + """The index of the output item that the code interpreter call is in progress.""" + + type: Literal["response.code_interpreter_call.code.done"] + """The type of the event. Always `response.code_interpreter_call.code.done`.""" diff --git a/src/openai/types/responses/response_code_interpreter_call_completed_event.py b/src/openai/types/responses/response_code_interpreter_call_completed_event.py new file mode 100644 index 0000000000..b0cb73fb72 --- /dev/null +++ b/src/openai/types/responses/response_code_interpreter_call_completed_event.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel +from .response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall + +__all__ = ["ResponseCodeInterpreterCallCompletedEvent"] + + +class ResponseCodeInterpreterCallCompletedEvent(BaseModel): + code_interpreter_call: ResponseCodeInterpreterToolCall + """A tool call to run code.""" + + output_index: int + """The index of the output item that the code interpreter call is in progress.""" + + type: Literal["response.code_interpreter_call.completed"] + """The type of the event. Always `response.code_interpreter_call.completed`.""" diff --git a/src/openai/types/responses/response_code_interpreter_call_in_progress_event.py b/src/openai/types/responses/response_code_interpreter_call_in_progress_event.py new file mode 100644 index 0000000000..64b739f308 --- /dev/null +++ b/src/openai/types/responses/response_code_interpreter_call_in_progress_event.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel +from .response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall + +__all__ = ["ResponseCodeInterpreterCallInProgressEvent"] + + +class ResponseCodeInterpreterCallInProgressEvent(BaseModel): + code_interpreter_call: ResponseCodeInterpreterToolCall + """A tool call to run code.""" + + output_index: int + """The index of the output item that the code interpreter call is in progress.""" + + type: Literal["response.code_interpreter_call.in_progress"] + """The type of the event. Always `response.code_interpreter_call.in_progress`.""" diff --git a/src/openai/types/responses/response_code_interpreter_call_interpreting_event.py b/src/openai/types/responses/response_code_interpreter_call_interpreting_event.py new file mode 100644 index 0000000000..3100eac175 --- /dev/null +++ b/src/openai/types/responses/response_code_interpreter_call_interpreting_event.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel +from .response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall + +__all__ = ["ResponseCodeInterpreterCallInterpretingEvent"] + + +class ResponseCodeInterpreterCallInterpretingEvent(BaseModel): + code_interpreter_call: ResponseCodeInterpreterToolCall + """A tool call to run code.""" + + output_index: int + """The index of the output item that the code interpreter call is in progress.""" + + type: Literal["response.code_interpreter_call.interpreting"] + """The type of the event. Always `response.code_interpreter_call.interpreting`.""" diff --git a/src/openai/types/responses/response_code_interpreter_tool_call.py b/src/openai/types/responses/response_code_interpreter_tool_call.py new file mode 100644 index 0000000000..d5a5057074 --- /dev/null +++ b/src/openai/types/responses/response_code_interpreter_tool_call.py @@ -0,0 +1,52 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel + +__all__ = ["ResponseCodeInterpreterToolCall", "Result", "ResultLogs", "ResultFiles", "ResultFilesFile"] + + +class ResultLogs(BaseModel): + logs: str + """The logs of the code interpreter tool call.""" + + type: Literal["logs"] + """The type of the code interpreter text output. Always `logs`.""" + + +class ResultFilesFile(BaseModel): + file_id: str + """The ID of the file.""" + + mime_type: str + """The MIME type of the file.""" + + +class ResultFiles(BaseModel): + files: List[ResultFilesFile] + + type: Literal["files"] + """The type of the code interpreter file output. Always `files`.""" + + +Result: TypeAlias = Annotated[Union[ResultLogs, ResultFiles], PropertyInfo(discriminator="type")] + + +class ResponseCodeInterpreterToolCall(BaseModel): + id: str + """The unique ID of the code interpreter tool call.""" + + code: str + """The code to run.""" + + results: List[Result] + """The results of the code interpreter tool call.""" + + status: Literal["in_progress", "interpreting", "completed"] + """The status of the code interpreter tool call.""" + + type: Literal["code_interpreter_call"] + """The type of the code interpreter tool call. Always `code_interpreter_call`.""" diff --git a/src/openai/types/responses/response_completed_event.py b/src/openai/types/responses/response_completed_event.py new file mode 100644 index 0000000000..a944f248ef --- /dev/null +++ b/src/openai/types/responses/response_completed_event.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from .response import Response +from ..._models import BaseModel + +__all__ = ["ResponseCompletedEvent"] + + +class ResponseCompletedEvent(BaseModel): + response: Response + """Properties of the completed response.""" + + type: Literal["response.completed"] + """The type of the event. Always `response.completed`.""" diff --git a/src/openai/types/responses/response_computer_tool_call.py b/src/openai/types/responses/response_computer_tool_call.py new file mode 100644 index 0000000000..994837567a --- /dev/null +++ b/src/openai/types/responses/response_computer_tool_call.py @@ -0,0 +1,212 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel + +__all__ = [ + "ResponseComputerToolCall", + "Action", + "ActionClick", + "ActionDoubleClick", + "ActionDrag", + "ActionDragPath", + "ActionKeypress", + "ActionMove", + "ActionScreenshot", + "ActionScroll", + "ActionType", + "ActionWait", + "PendingSafetyCheck", +] + + +class ActionClick(BaseModel): + button: Literal["left", "right", "wheel", "back", "forward"] + """Indicates which mouse button was pressed during the click. + + One of `left`, `right`, `wheel`, `back`, or `forward`. + """ + + type: Literal["click"] + """Specifies the event type. + + For a click action, this property is always set to `click`. + """ + + x: int + """The x-coordinate where the click occurred.""" + + y: int + """The y-coordinate where the click occurred.""" + + +class ActionDoubleClick(BaseModel): + type: Literal["double_click"] + """Specifies the event type. + + For a double click action, this property is always set to `double_click`. + """ + + x: int + """The x-coordinate where the double click occurred.""" + + y: int + """The y-coordinate where the double click occurred.""" + + +class ActionDragPath(BaseModel): + x: int + """The x-coordinate.""" + + y: int + """The y-coordinate.""" + + +class ActionDrag(BaseModel): + path: List[ActionDragPath] + """An array of coordinates representing the path of the drag action. + + Coordinates will appear as an array of objects, eg + + ``` + [ + { x: 100, y: 200 }, + { x: 200, y: 300 } + ] + ``` + """ + + type: Literal["drag"] + """Specifies the event type. + + For a drag action, this property is always set to `drag`. + """ + + +class ActionKeypress(BaseModel): + keys: List[str] + """The combination of keys the model is requesting to be pressed. + + This is an array of strings, each representing a key. + """ + + type: Literal["keypress"] + """Specifies the event type. + + For a keypress action, this property is always set to `keypress`. + """ + + +class ActionMove(BaseModel): + type: Literal["move"] + """Specifies the event type. + + For a move action, this property is always set to `move`. + """ + + x: int + """The x-coordinate to move to.""" + + y: int + """The y-coordinate to move to.""" + + +class ActionScreenshot(BaseModel): + type: Literal["screenshot"] + """Specifies the event type. + + For a screenshot action, this property is always set to `screenshot`. + """ + + +class ActionScroll(BaseModel): + scroll_x: int + """The horizontal scroll distance.""" + + scroll_y: int + """The vertical scroll distance.""" + + type: Literal["scroll"] + """Specifies the event type. + + For a scroll action, this property is always set to `scroll`. + """ + + x: int + """The x-coordinate where the scroll occurred.""" + + y: int + """The y-coordinate where the scroll occurred.""" + + +class ActionType(BaseModel): + text: str + """The text to type.""" + + type: Literal["type"] + """Specifies the event type. + + For a type action, this property is always set to `type`. + """ + + +class ActionWait(BaseModel): + type: Literal["wait"] + """Specifies the event type. + + For a wait action, this property is always set to `wait`. + """ + + +Action: TypeAlias = Annotated[ + Union[ + ActionClick, + ActionDoubleClick, + ActionDrag, + ActionKeypress, + ActionMove, + ActionScreenshot, + ActionScroll, + ActionType, + ActionWait, + ], + PropertyInfo(discriminator="type"), +] + + +class PendingSafetyCheck(BaseModel): + id: str + """The ID of the pending safety check.""" + + code: str + """The type of the pending safety check.""" + + message: str + """Details about the pending safety check.""" + + +class ResponseComputerToolCall(BaseModel): + id: str + """The unique ID of the computer call.""" + + action: Action + """A click action.""" + + call_id: str + """An identifier used when responding to the tool call with output.""" + + pending_safety_checks: List[PendingSafetyCheck] + """The pending safety checks for the computer call.""" + + status: Literal["in_progress", "completed", "incomplete"] + """The status of the item. + + One of `in_progress`, `completed`, or `incomplete`. Populated when items are + returned via API. + """ + + type: Literal["computer_call"] + """The type of the computer call. Always `computer_call`.""" diff --git a/src/openai/types/responses/response_computer_tool_call_param.py b/src/openai/types/responses/response_computer_tool_call_param.py new file mode 100644 index 0000000000..d4ef56ab5c --- /dev/null +++ b/src/openai/types/responses/response_computer_tool_call_param.py @@ -0,0 +1,208 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union, Iterable +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +__all__ = [ + "ResponseComputerToolCallParam", + "Action", + "ActionClick", + "ActionDoubleClick", + "ActionDrag", + "ActionDragPath", + "ActionKeypress", + "ActionMove", + "ActionScreenshot", + "ActionScroll", + "ActionType", + "ActionWait", + "PendingSafetyCheck", +] + + +class ActionClick(TypedDict, total=False): + button: Required[Literal["left", "right", "wheel", "back", "forward"]] + """Indicates which mouse button was pressed during the click. + + One of `left`, `right`, `wheel`, `back`, or `forward`. + """ + + type: Required[Literal["click"]] + """Specifies the event type. + + For a click action, this property is always set to `click`. + """ + + x: Required[int] + """The x-coordinate where the click occurred.""" + + y: Required[int] + """The y-coordinate where the click occurred.""" + + +class ActionDoubleClick(TypedDict, total=False): + type: Required[Literal["double_click"]] + """Specifies the event type. + + For a double click action, this property is always set to `double_click`. + """ + + x: Required[int] + """The x-coordinate where the double click occurred.""" + + y: Required[int] + """The y-coordinate where the double click occurred.""" + + +class ActionDragPath(TypedDict, total=False): + x: Required[int] + """The x-coordinate.""" + + y: Required[int] + """The y-coordinate.""" + + +class ActionDrag(TypedDict, total=False): + path: Required[Iterable[ActionDragPath]] + """An array of coordinates representing the path of the drag action. + + Coordinates will appear as an array of objects, eg + + ``` + [ + { x: 100, y: 200 }, + { x: 200, y: 300 } + ] + ``` + """ + + type: Required[Literal["drag"]] + """Specifies the event type. + + For a drag action, this property is always set to `drag`. + """ + + +class ActionKeypress(TypedDict, total=False): + keys: Required[List[str]] + """The combination of keys the model is requesting to be pressed. + + This is an array of strings, each representing a key. + """ + + type: Required[Literal["keypress"]] + """Specifies the event type. + + For a keypress action, this property is always set to `keypress`. + """ + + +class ActionMove(TypedDict, total=False): + type: Required[Literal["move"]] + """Specifies the event type. + + For a move action, this property is always set to `move`. + """ + + x: Required[int] + """The x-coordinate to move to.""" + + y: Required[int] + """The y-coordinate to move to.""" + + +class ActionScreenshot(TypedDict, total=False): + type: Required[Literal["screenshot"]] + """Specifies the event type. + + For a screenshot action, this property is always set to `screenshot`. + """ + + +class ActionScroll(TypedDict, total=False): + scroll_x: Required[int] + """The horizontal scroll distance.""" + + scroll_y: Required[int] + """The vertical scroll distance.""" + + type: Required[Literal["scroll"]] + """Specifies the event type. + + For a scroll action, this property is always set to `scroll`. + """ + + x: Required[int] + """The x-coordinate where the scroll occurred.""" + + y: Required[int] + """The y-coordinate where the scroll occurred.""" + + +class ActionType(TypedDict, total=False): + text: Required[str] + """The text to type.""" + + type: Required[Literal["type"]] + """Specifies the event type. + + For a type action, this property is always set to `type`. + """ + + +class ActionWait(TypedDict, total=False): + type: Required[Literal["wait"]] + """Specifies the event type. + + For a wait action, this property is always set to `wait`. + """ + + +Action: TypeAlias = Union[ + ActionClick, + ActionDoubleClick, + ActionDrag, + ActionKeypress, + ActionMove, + ActionScreenshot, + ActionScroll, + ActionType, + ActionWait, +] + + +class PendingSafetyCheck(TypedDict, total=False): + id: Required[str] + """The ID of the pending safety check.""" + + code: Required[str] + """The type of the pending safety check.""" + + message: Required[str] + """Details about the pending safety check.""" + + +class ResponseComputerToolCallParam(TypedDict, total=False): + id: Required[str] + """The unique ID of the computer call.""" + + action: Required[Action] + """A click action.""" + + call_id: Required[str] + """An identifier used when responding to the tool call with output.""" + + pending_safety_checks: Required[Iterable[PendingSafetyCheck]] + """The pending safety checks for the computer call.""" + + status: Required[Literal["in_progress", "completed", "incomplete"]] + """The status of the item. + + One of `in_progress`, `completed`, or `incomplete`. Populated when items are + returned via API. + """ + + type: Required[Literal["computer_call"]] + """The type of the computer call. Always `computer_call`.""" diff --git a/src/openai/types/responses/response_content_part_added_event.py b/src/openai/types/responses/response_content_part_added_event.py new file mode 100644 index 0000000000..93f5ec4b0c --- /dev/null +++ b/src/openai/types/responses/response_content_part_added_event.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .response_output_text import ResponseOutputText +from .response_output_refusal import ResponseOutputRefusal + +__all__ = ["ResponseContentPartAddedEvent", "Part"] + +Part: TypeAlias = Annotated[Union[ResponseOutputText, ResponseOutputRefusal], PropertyInfo(discriminator="type")] + + +class ResponseContentPartAddedEvent(BaseModel): + content_index: int + """The index of the content part that was added.""" + + item_id: str + """The ID of the output item that the content part was added to.""" + + output_index: int + """The index of the output item that the content part was added to.""" + + part: Part + """The content part that was added.""" + + type: Literal["response.content_part.added"] + """The type of the event. Always `response.content_part.added`.""" diff --git a/src/openai/types/responses/response_content_part_done_event.py b/src/openai/types/responses/response_content_part_done_event.py new file mode 100644 index 0000000000..4ec0739877 --- /dev/null +++ b/src/openai/types/responses/response_content_part_done_event.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .response_output_text import ResponseOutputText +from .response_output_refusal import ResponseOutputRefusal + +__all__ = ["ResponseContentPartDoneEvent", "Part"] + +Part: TypeAlias = Annotated[Union[ResponseOutputText, ResponseOutputRefusal], PropertyInfo(discriminator="type")] + + +class ResponseContentPartDoneEvent(BaseModel): + content_index: int + """The index of the content part that is done.""" + + item_id: str + """The ID of the output item that the content part was added to.""" + + output_index: int + """The index of the output item that the content part was added to.""" + + part: Part + """The content part that is done.""" + + type: Literal["response.content_part.done"] + """The type of the event. Always `response.content_part.done`.""" diff --git a/src/openai/types/responses/response_create_params.py b/src/openai/types/responses/response_create_params.py new file mode 100644 index 0000000000..d5b2fdeb1a --- /dev/null +++ b/src/openai/types/responses/response_create_params.py @@ -0,0 +1,204 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .tool_param import ToolParam +from ..shared.chat_model import ChatModel +from .response_includable import ResponseIncludable +from .tool_choice_options import ToolChoiceOptions +from .response_input_param import ResponseInputParam +from ..shared_params.metadata import Metadata +from .tool_choice_types_param import ToolChoiceTypesParam +from ..shared_params.reasoning import Reasoning +from .response_text_config_param import ResponseTextConfigParam +from .tool_choice_function_param import ToolChoiceFunctionParam + +__all__ = [ + "ResponseCreateParamsBase", + "ToolChoice", + "ResponseCreateParamsNonStreaming", + "ResponseCreateParamsStreaming", +] + + +class ResponseCreateParamsBase(TypedDict, total=False): + input: Required[Union[str, ResponseInputParam]] + """Text, image, or file inputs to the model, used to generate a response. + + Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Image inputs](https://platform.openai.com/docs/guides/images) + - [File inputs](https://platform.openai.com/docs/guides/pdf-files) + - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) + - [Function calling](https://platform.openai.com/docs/guides/function-calling) + """ + + model: Required[Union[str, ChatModel]] + """Model ID used to generate the response, like `gpt-4o` or `o1`. + + OpenAI offers a wide range of models with different capabilities, performance + characteristics, and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + """ + + include: Optional[List[ResponseIncludable]] + """Specify additional output data to include in the model response. + + Currently supported values are: + + - `file_search_call.results`: Include the search results of the file search tool + call. + - `message.input_image.image_url`: Include image urls from the input message. + - `computer_call_output.output.image_url`: Include image urls from the computer + call output. + """ + + instructions: Optional[str] + """ + Inserts a system (or developer) message as the first item in the model's + context. + + When using along with `previous_response_id`, the instructions from a previous + response will be not be carried over to the next response. This makes it simple + to swap out system (or developer) messages in new responses. + """ + + max_output_tokens: Optional[int] + """ + An upper bound for the number of tokens that can be generated for a response, + including visible output tokens and + [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). + """ + + metadata: Optional[Metadata] + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + """ + + parallel_tool_calls: Optional[bool] + """Whether to allow the model to run tool calls in parallel.""" + + previous_response_id: Optional[str] + """The unique ID of the previous response to the model. + + Use this to create multi-turn conversations. Learn more about + [conversation state](https://platform.openai.com/docs/guides/conversation-state). + """ + + reasoning: Optional[Reasoning] + """**o-series models only** + + Configuration options for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). + """ + + store: Optional[bool] + """Whether to store the generated model response for later retrieval via API.""" + + temperature: Optional[float] + """What sampling temperature to use, between 0 and 2. + + Higher values like 0.8 will make the output more random, while lower values like + 0.2 will make it more focused and deterministic. We generally recommend altering + this or `top_p` but not both. + """ + + text: ResponseTextConfigParam + """Configuration options for a text response from the model. + + Can be plain text or structured JSON data. Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + """ + + tool_choice: ToolChoice + """ + How the model should select which tool (or tools) to use when generating a + response. See the `tools` parameter to see how to specify which tools the model + can call. + """ + + tools: Iterable[ToolParam] + """An array of tools the model may call while generating a response. + + You can specify which tool to use by setting the `tool_choice` parameter. + + The two categories of tools you can provide the model are: + + - **Built-in tools**: Tools that are provided by OpenAI that extend the model's + capabilities, like + [web search](https://platform.openai.com/docs/guides/tools-web-search) or + [file search](https://platform.openai.com/docs/guides/tools-file-search). + Learn more about + [built-in tools](https://platform.openai.com/docs/guides/tools). + - **Function calls (custom tools)**: Functions that are defined by you, enabling + the model to call your own code. Learn more about + [function calling](https://platform.openai.com/docs/guides/function-calling). + """ + + top_p: Optional[float] + """ + An alternative to sampling with temperature, called nucleus sampling, where the + model considers the results of the tokens with top_p probability mass. So 0.1 + means only the tokens comprising the top 10% probability mass are considered. + + We generally recommend altering this or `temperature` but not both. + """ + + truncation: Optional[Literal["auto", "disabled"]] + """The truncation strategy to use for the model response. + + - `auto`: If the context of this response and previous ones exceeds the model's + context window size, the model will truncate the response to fit the context + window by dropping input items in the middle of the conversation. + - `disabled` (default): If a model response will exceed the context window size + for a model, the request will fail with a 400 error. + """ + + user: str + """ + A unique identifier representing your end-user, which can help OpenAI to monitor + and detect abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + """ + + +ToolChoice: TypeAlias = Union[ToolChoiceOptions, ToolChoiceTypesParam, ToolChoiceFunctionParam] + + +class ResponseCreateParamsNonStreaming(ResponseCreateParamsBase, total=False): + stream: Optional[Literal[False]] + """ + If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) + for more information. + """ + + +class ResponseCreateParamsStreaming(ResponseCreateParamsBase): + stream: Required[Literal[True]] + """ + If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) + for more information. + """ + + +ResponseCreateParams = Union[ResponseCreateParamsNonStreaming, ResponseCreateParamsStreaming] diff --git a/src/openai/types/responses/response_created_event.py b/src/openai/types/responses/response_created_event.py new file mode 100644 index 0000000000..7a524cec87 --- /dev/null +++ b/src/openai/types/responses/response_created_event.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from .response import Response +from ..._models import BaseModel + +__all__ = ["ResponseCreatedEvent"] + + +class ResponseCreatedEvent(BaseModel): + response: Response + """The response that was created.""" + + type: Literal["response.created"] + """The type of the event. Always `response.created`.""" diff --git a/src/openai/types/responses/response_error.py b/src/openai/types/responses/response_error.py new file mode 100644 index 0000000000..90f1fcf5da --- /dev/null +++ b/src/openai/types/responses/response_error.py @@ -0,0 +1,34 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseError"] + + +class ResponseError(BaseModel): + code: Literal[ + "server_error", + "rate_limit_exceeded", + "invalid_prompt", + "vector_store_timeout", + "invalid_image", + "invalid_image_format", + "invalid_base64_image", + "invalid_image_url", + "image_too_large", + "image_too_small", + "image_parse_error", + "image_content_policy_violation", + "invalid_image_mode", + "image_file_too_large", + "unsupported_image_media_type", + "empty_image_file", + "failed_to_download_image", + "image_file_not_found", + ] + """The error code for the response.""" + + message: str + """A human-readable description of the error.""" diff --git a/src/openai/types/responses/response_error_event.py b/src/openai/types/responses/response_error_event.py new file mode 100644 index 0000000000..1b7e605d02 --- /dev/null +++ b/src/openai/types/responses/response_error_event.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseErrorEvent"] + + +class ResponseErrorEvent(BaseModel): + code: Optional[str] = None + """The error code.""" + + message: str + """The error message.""" + + param: Optional[str] = None + """The error parameter.""" + + type: Literal["error"] + """The type of the event. Always `error`.""" diff --git a/src/openai/types/responses/response_failed_event.py b/src/openai/types/responses/response_failed_event.py new file mode 100644 index 0000000000..3e8f75d8c4 --- /dev/null +++ b/src/openai/types/responses/response_failed_event.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from .response import Response +from ..._models import BaseModel + +__all__ = ["ResponseFailedEvent"] + + +class ResponseFailedEvent(BaseModel): + response: Response + """The response that failed.""" + + type: Literal["response.failed"] + """The type of the event. Always `response.failed`.""" diff --git a/src/openai/types/responses/response_file_search_call_completed_event.py b/src/openai/types/responses/response_file_search_call_completed_event.py new file mode 100644 index 0000000000..4b86083369 --- /dev/null +++ b/src/openai/types/responses/response_file_search_call_completed_event.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseFileSearchCallCompletedEvent"] + + +class ResponseFileSearchCallCompletedEvent(BaseModel): + item_id: str + """The ID of the output item that the file search call is initiated.""" + + output_index: int + """The index of the output item that the file search call is initiated.""" + + type: Literal["response.file_search_call.completed"] + """The type of the event. Always `response.file_search_call.completed`.""" diff --git a/src/openai/types/responses/response_file_search_call_in_progress_event.py b/src/openai/types/responses/response_file_search_call_in_progress_event.py new file mode 100644 index 0000000000..eb42e3dad6 --- /dev/null +++ b/src/openai/types/responses/response_file_search_call_in_progress_event.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseFileSearchCallInProgressEvent"] + + +class ResponseFileSearchCallInProgressEvent(BaseModel): + item_id: str + """The ID of the output item that the file search call is initiated.""" + + output_index: int + """The index of the output item that the file search call is initiated.""" + + type: Literal["response.file_search_call.in_progress"] + """The type of the event. Always `response.file_search_call.in_progress`.""" diff --git a/src/openai/types/responses/response_file_search_call_searching_event.py b/src/openai/types/responses/response_file_search_call_searching_event.py new file mode 100644 index 0000000000..3cd8905de6 --- /dev/null +++ b/src/openai/types/responses/response_file_search_call_searching_event.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseFileSearchCallSearchingEvent"] + + +class ResponseFileSearchCallSearchingEvent(BaseModel): + item_id: str + """The ID of the output item that the file search call is initiated.""" + + output_index: int + """The index of the output item that the file search call is searching.""" + + type: Literal["response.file_search_call.searching"] + """The type of the event. Always `response.file_search_call.searching`.""" diff --git a/src/openai/types/responses/response_file_search_tool_call.py b/src/openai/types/responses/response_file_search_tool_call.py new file mode 100644 index 0000000000..ef1c6a5608 --- /dev/null +++ b/src/openai/types/responses/response_file_search_tool_call.py @@ -0,0 +1,51 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseFileSearchToolCall", "Result"] + + +class Result(BaseModel): + attributes: Optional[Dict[str, Union[str, float, bool]]] = None + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. Keys are + strings with a maximum length of 64 characters. Values are strings with a + maximum length of 512 characters, booleans, or numbers. + """ + + file_id: Optional[str] = None + """The unique ID of the file.""" + + filename: Optional[str] = None + """The name of the file.""" + + score: Optional[float] = None + """The relevance score of the file - a value between 0 and 1.""" + + text: Optional[str] = None + """The text that was retrieved from the file.""" + + +class ResponseFileSearchToolCall(BaseModel): + id: str + """The unique ID of the file search tool call.""" + + queries: List[str] + """The queries used to search for files.""" + + status: Literal["in_progress", "searching", "completed", "incomplete", "failed"] + """The status of the file search tool call. + + One of `in_progress`, `searching`, `incomplete` or `failed`, + """ + + type: Literal["file_search_call"] + """The type of the file search tool call. Always `file_search_call`.""" + + results: Optional[List[Result]] = None + """The results of the file search tool call.""" diff --git a/src/openai/types/responses/response_file_search_tool_call_param.py b/src/openai/types/responses/response_file_search_tool_call_param.py new file mode 100644 index 0000000000..9a4177cf81 --- /dev/null +++ b/src/openai/types/responses/response_file_search_tool_call_param.py @@ -0,0 +1,51 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, List, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ResponseFileSearchToolCallParam", "Result"] + + +class Result(TypedDict, total=False): + attributes: Optional[Dict[str, Union[str, float, bool]]] + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. Keys are + strings with a maximum length of 64 characters. Values are strings with a + maximum length of 512 characters, booleans, or numbers. + """ + + file_id: str + """The unique ID of the file.""" + + filename: str + """The name of the file.""" + + score: float + """The relevance score of the file - a value between 0 and 1.""" + + text: str + """The text that was retrieved from the file.""" + + +class ResponseFileSearchToolCallParam(TypedDict, total=False): + id: Required[str] + """The unique ID of the file search tool call.""" + + queries: Required[List[str]] + """The queries used to search for files.""" + + status: Required[Literal["in_progress", "searching", "completed", "incomplete", "failed"]] + """The status of the file search tool call. + + One of `in_progress`, `searching`, `incomplete` or `failed`, + """ + + type: Required[Literal["file_search_call"]] + """The type of the file search tool call. Always `file_search_call`.""" + + results: Optional[Iterable[Result]] + """The results of the file search tool call.""" diff --git a/src/openai/types/responses/response_format_text_config.py b/src/openai/types/responses/response_format_text_config.py new file mode 100644 index 0000000000..a4896bf9fe --- /dev/null +++ b/src/openai/types/responses/response_format_text_config.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from typing_extensions import Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..shared.response_format_text import ResponseFormatText +from ..shared.response_format_json_object import ResponseFormatJSONObject +from .response_format_text_json_schema_config import ResponseFormatTextJSONSchemaConfig + +__all__ = ["ResponseFormatTextConfig"] + +ResponseFormatTextConfig: TypeAlias = Annotated[ + Union[ResponseFormatText, ResponseFormatTextJSONSchemaConfig, ResponseFormatJSONObject], + PropertyInfo(discriminator="type"), +] diff --git a/src/openai/types/responses/response_format_text_config_param.py b/src/openai/types/responses/response_format_text_config_param.py new file mode 100644 index 0000000000..fcaf8f3fb6 --- /dev/null +++ b/src/openai/types/responses/response_format_text_config_param.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import TypeAlias + +from ..shared_params.response_format_text import ResponseFormatText +from ..shared_params.response_format_json_object import ResponseFormatJSONObject +from .response_format_text_json_schema_config_param import ResponseFormatTextJSONSchemaConfigParam + +__all__ = ["ResponseFormatTextConfigParam"] + +ResponseFormatTextConfigParam: TypeAlias = Union[ + ResponseFormatText, ResponseFormatTextJSONSchemaConfigParam, ResponseFormatJSONObject +] diff --git a/src/openai/types/responses/response_format_text_json_schema_config.py b/src/openai/types/responses/response_format_text_json_schema_config.py new file mode 100644 index 0000000000..3cf066370f --- /dev/null +++ b/src/openai/types/responses/response_format_text_json_schema_config.py @@ -0,0 +1,43 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = ["ResponseFormatTextJSONSchemaConfig"] + + +class ResponseFormatTextJSONSchemaConfig(BaseModel): + schema_: Dict[str, object] = FieldInfo(alias="schema") + """ + The schema for the response format, described as a JSON Schema object. Learn how + to build JSON schemas [here](https://json-schema.org/). + """ + + type: Literal["json_schema"] + """The type of response format being defined. Always `json_schema`.""" + + description: Optional[str] = None + """ + A description of what the response format is for, used by the model to determine + how to respond in the format. + """ + + name: Optional[str] = None + """The name of the response format. + + Must be a-z, A-Z, 0-9, or contain underscores and dashes, with a maximum length + of 64. + """ + + strict: Optional[bool] = None + """ + Whether to enable strict schema adherence when generating the output. If set to + true, the model will always follow the exact schema defined in the `schema` + field. Only a subset of JSON Schema is supported when `strict` is `true`. To + learn more, read the + [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). + """ diff --git a/src/openai/types/responses/response_format_text_json_schema_config_param.py b/src/openai/types/responses/response_format_text_json_schema_config_param.py new file mode 100644 index 0000000000..211c5d1eff --- /dev/null +++ b/src/openai/types/responses/response_format_text_json_schema_config_param.py @@ -0,0 +1,41 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ResponseFormatTextJSONSchemaConfigParam"] + + +class ResponseFormatTextJSONSchemaConfigParam(TypedDict, total=False): + schema: Required[Dict[str, object]] + """ + The schema for the response format, described as a JSON Schema object. Learn how + to build JSON schemas [here](https://json-schema.org/). + """ + + type: Required[Literal["json_schema"]] + """The type of response format being defined. Always `json_schema`.""" + + description: str + """ + A description of what the response format is for, used by the model to determine + how to respond in the format. + """ + + name: str + """The name of the response format. + + Must be a-z, A-Z, 0-9, or contain underscores and dashes, with a maximum length + of 64. + """ + + strict: Optional[bool] + """ + Whether to enable strict schema adherence when generating the output. If set to + true, the model will always follow the exact schema defined in the `schema` + field. Only a subset of JSON Schema is supported when `strict` is `true`. To + learn more, read the + [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). + """ diff --git a/src/openai/types/responses/response_function_call_arguments_delta_event.py b/src/openai/types/responses/response_function_call_arguments_delta_event.py new file mode 100644 index 0000000000..0989b7caeb --- /dev/null +++ b/src/openai/types/responses/response_function_call_arguments_delta_event.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseFunctionCallArgumentsDeltaEvent"] + + +class ResponseFunctionCallArgumentsDeltaEvent(BaseModel): + delta: str + """The function-call arguments delta that is added.""" + + item_id: str + """The ID of the output item that the function-call arguments delta is added to.""" + + output_index: int + """ + The index of the output item that the function-call arguments delta is added to. + """ + + type: Literal["response.function_call_arguments.delta"] + """The type of the event. Always `response.function_call_arguments.delta`.""" diff --git a/src/openai/types/responses/response_function_call_arguments_done_event.py b/src/openai/types/responses/response_function_call_arguments_done_event.py new file mode 100644 index 0000000000..1d805a57c6 --- /dev/null +++ b/src/openai/types/responses/response_function_call_arguments_done_event.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseFunctionCallArgumentsDoneEvent"] + + +class ResponseFunctionCallArgumentsDoneEvent(BaseModel): + arguments: str + """The function-call arguments.""" + + item_id: str + """The ID of the item.""" + + output_index: int + """The index of the output item.""" + + type: Literal["response.function_call_arguments.done"] diff --git a/src/openai/types/responses/response_function_tool_call.py b/src/openai/types/responses/response_function_tool_call.py new file mode 100644 index 0000000000..5d82906cb7 --- /dev/null +++ b/src/openai/types/responses/response_function_tool_call.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseFunctionToolCall"] + + +class ResponseFunctionToolCall(BaseModel): + id: str + """The unique ID of the function tool call.""" + + arguments: str + """A JSON string of the arguments to pass to the function.""" + + call_id: str + """The unique ID of the function tool call generated by the model.""" + + name: str + """The name of the function to run.""" + + type: Literal["function_call"] + """The type of the function tool call. Always `function_call`.""" + + status: Optional[Literal["in_progress", "completed", "incomplete"]] = None + """The status of the item. + + One of `in_progress`, `completed`, or `incomplete`. Populated when items are + returned via API. + """ diff --git a/src/openai/types/responses/response_function_tool_call_param.py b/src/openai/types/responses/response_function_tool_call_param.py new file mode 100644 index 0000000000..51b947a764 --- /dev/null +++ b/src/openai/types/responses/response_function_tool_call_param.py @@ -0,0 +1,31 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ResponseFunctionToolCallParam"] + + +class ResponseFunctionToolCallParam(TypedDict, total=False): + id: Required[str] + """The unique ID of the function tool call.""" + + arguments: Required[str] + """A JSON string of the arguments to pass to the function.""" + + call_id: Required[str] + """The unique ID of the function tool call generated by the model.""" + + name: Required[str] + """The name of the function to run.""" + + type: Required[Literal["function_call"]] + """The type of the function tool call. Always `function_call`.""" + + status: Literal["in_progress", "completed", "incomplete"] + """The status of the item. + + One of `in_progress`, `completed`, or `incomplete`. Populated when items are + returned via API. + """ diff --git a/src/openai/types/responses/response_function_web_search.py b/src/openai/types/responses/response_function_web_search.py new file mode 100644 index 0000000000..44734b681f --- /dev/null +++ b/src/openai/types/responses/response_function_web_search.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseFunctionWebSearch"] + + +class ResponseFunctionWebSearch(BaseModel): + id: str + """The unique ID of the web search tool call.""" + + status: Literal["in_progress", "searching", "completed", "failed"] + """The status of the web search tool call.""" + + type: Literal["web_search_call"] + """The type of the web search tool call. Always `web_search_call`.""" diff --git a/src/openai/types/responses/response_function_web_search_param.py b/src/openai/types/responses/response_function_web_search_param.py new file mode 100644 index 0000000000..d413e60b12 --- /dev/null +++ b/src/openai/types/responses/response_function_web_search_param.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ResponseFunctionWebSearchParam"] + + +class ResponseFunctionWebSearchParam(TypedDict, total=False): + id: Required[str] + """The unique ID of the web search tool call.""" + + status: Required[Literal["in_progress", "searching", "completed", "failed"]] + """The status of the web search tool call.""" + + type: Required[Literal["web_search_call"]] + """The type of the web search tool call. Always `web_search_call`.""" diff --git a/src/openai/types/responses/response_in_progress_event.py b/src/openai/types/responses/response_in_progress_event.py new file mode 100644 index 0000000000..7d96cbb8ad --- /dev/null +++ b/src/openai/types/responses/response_in_progress_event.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from .response import Response +from ..._models import BaseModel + +__all__ = ["ResponseInProgressEvent"] + + +class ResponseInProgressEvent(BaseModel): + response: Response + """The response that is in progress.""" + + type: Literal["response.in_progress"] + """The type of the event. Always `response.in_progress`.""" diff --git a/src/openai/types/responses/response_includable.py b/src/openai/types/responses/response_includable.py new file mode 100644 index 0000000000..83489fa7f1 --- /dev/null +++ b/src/openai/types/responses/response_includable.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["ResponseIncludable"] + +ResponseIncludable: TypeAlias = Literal[ + "file_search_call.results", "message.input_image.image_url", "computer_call_output.output.image_url" +] diff --git a/src/openai/types/responses/response_incomplete_event.py b/src/openai/types/responses/response_incomplete_event.py new file mode 100644 index 0000000000..742b789c7e --- /dev/null +++ b/src/openai/types/responses/response_incomplete_event.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from .response import Response +from ..._models import BaseModel + +__all__ = ["ResponseIncompleteEvent"] + + +class ResponseIncompleteEvent(BaseModel): + response: Response + """The response that was incomplete.""" + + type: Literal["response.incomplete"] + """The type of the event. Always `response.incomplete`.""" diff --git a/src/openai/types/responses/response_input_content.py b/src/openai/types/responses/response_input_content.py new file mode 100644 index 0000000000..1726909a17 --- /dev/null +++ b/src/openai/types/responses/response_input_content.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from typing_extensions import Annotated, TypeAlias + +from ..._utils import PropertyInfo +from .response_input_file import ResponseInputFile +from .response_input_text import ResponseInputText +from .response_input_image import ResponseInputImage + +__all__ = ["ResponseInputContent"] + +ResponseInputContent: TypeAlias = Annotated[ + Union[ResponseInputText, ResponseInputImage, ResponseInputFile], PropertyInfo(discriminator="type") +] diff --git a/src/openai/types/responses/response_input_content_param.py b/src/openai/types/responses/response_input_content_param.py new file mode 100644 index 0000000000..7791cdfd8e --- /dev/null +++ b/src/openai/types/responses/response_input_content_param.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import TypeAlias + +from .response_input_file_param import ResponseInputFileParam +from .response_input_text_param import ResponseInputTextParam +from .response_input_image_param import ResponseInputImageParam + +__all__ = ["ResponseInputContentParam"] + +ResponseInputContentParam: TypeAlias = Union[ResponseInputTextParam, ResponseInputImageParam, ResponseInputFileParam] diff --git a/src/openai/types/responses/response_input_file.py b/src/openai/types/responses/response_input_file.py new file mode 100644 index 0000000000..00b35dc844 --- /dev/null +++ b/src/openai/types/responses/response_input_file.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseInputFile"] + + +class ResponseInputFile(BaseModel): + type: Literal["input_file"] + """The type of the input item. Always `input_file`.""" + + file_data: Optional[str] = None + """The content of the file to be sent to the model.""" + + file_id: Optional[str] = None + """The ID of the file to be sent to the model.""" + + filename: Optional[str] = None + """The name of the file to be sent to the model.""" diff --git a/src/openai/types/responses/response_input_file_param.py b/src/openai/types/responses/response_input_file_param.py new file mode 100644 index 0000000000..dc06a4ea2d --- /dev/null +++ b/src/openai/types/responses/response_input_file_param.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ResponseInputFileParam"] + + +class ResponseInputFileParam(TypedDict, total=False): + type: Required[Literal["input_file"]] + """The type of the input item. Always `input_file`.""" + + file_data: str + """The content of the file to be sent to the model.""" + + file_id: str + """The ID of the file to be sent to the model.""" + + filename: str + """The name of the file to be sent to the model.""" diff --git a/src/openai/types/responses/response_input_image.py b/src/openai/types/responses/response_input_image.py new file mode 100644 index 0000000000..d719f44e9b --- /dev/null +++ b/src/openai/types/responses/response_input_image.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseInputImage"] + + +class ResponseInputImage(BaseModel): + detail: Literal["high", "low", "auto"] + """The detail level of the image to be sent to the model. + + One of `high`, `low`, or `auto`. Defaults to `auto`. + """ + + type: Literal["input_image"] + """The type of the input item. Always `input_image`.""" + + file_id: Optional[str] = None + """The ID of the file to be sent to the model.""" + + image_url: Optional[str] = None + """The URL of the image to be sent to the model. + + A fully qualified URL or base64 encoded image in a data URL. + """ diff --git a/src/openai/types/responses/response_input_image_param.py b/src/openai/types/responses/response_input_image_param.py new file mode 100644 index 0000000000..5dd4db2b5d --- /dev/null +++ b/src/openai/types/responses/response_input_image_param.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ResponseInputImageParam"] + + +class ResponseInputImageParam(TypedDict, total=False): + detail: Required[Literal["high", "low", "auto"]] + """The detail level of the image to be sent to the model. + + One of `high`, `low`, or `auto`. Defaults to `auto`. + """ + + type: Required[Literal["input_image"]] + """The type of the input item. Always `input_image`.""" + + file_id: Optional[str] + """The ID of the file to be sent to the model.""" + + image_url: Optional[str] + """The URL of the image to be sent to the model. + + A fully qualified URL or base64 encoded image in a data URL. + """ diff --git a/src/openai/types/responses/response_input_item_param.py b/src/openai/types/responses/response_input_item_param.py new file mode 100644 index 0000000000..c9daaa6a89 --- /dev/null +++ b/src/openai/types/responses/response_input_item_param.py @@ -0,0 +1,174 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .easy_input_message_param import EasyInputMessageParam +from .response_output_message_param import ResponseOutputMessageParam +from .response_computer_tool_call_param import ResponseComputerToolCallParam +from .response_function_tool_call_param import ResponseFunctionToolCallParam +from .response_function_web_search_param import ResponseFunctionWebSearchParam +from .response_file_search_tool_call_param import ResponseFileSearchToolCallParam +from .response_input_message_content_list_param import ResponseInputMessageContentListParam + +__all__ = [ + "ResponseInputItemParam", + "Message", + "ComputerCallOutput", + "ComputerCallOutputOutput", + "ComputerCallOutputAcknowledgedSafetyCheck", + "FunctionCallOutput", + "Reasoning", + "ReasoningContent", + "ItemReference", +] + + +class Message(TypedDict, total=False): + content: Required[ResponseInputMessageContentListParam] + """ + A list of one or many input items to the model, containing different content + types. + """ + + role: Required[Literal["user", "system", "developer"]] + """The role of the message input. One of `user`, `system`, or `developer`.""" + + status: Literal["in_progress", "completed", "incomplete"] + """The status of item. + + One of `in_progress`, `completed`, or `incomplete`. Populated when items are + returned via API. + """ + + type: Literal["message"] + """The type of the message input. Always set to `message`.""" + + +class ComputerCallOutputOutput(TypedDict, total=False): + type: Required[Literal["computer_screenshot"]] + """Specifies the event type. + + For a computer screenshot, this property is always set to `computer_screenshot`. + """ + + file_id: str + """The identifier of an uploaded file that contains the screenshot.""" + + image_url: str + """The URL of the screenshot image.""" + + +class ComputerCallOutputAcknowledgedSafetyCheck(TypedDict, total=False): + id: Required[str] + """The ID of the pending safety check.""" + + code: Required[str] + """The type of the pending safety check.""" + + message: Required[str] + """Details about the pending safety check.""" + + +class ComputerCallOutput(TypedDict, total=False): + call_id: Required[str] + """The ID of the computer tool call that produced the output.""" + + output: Required[ComputerCallOutputOutput] + """A computer screenshot image used with the computer use tool.""" + + type: Required[Literal["computer_call_output"]] + """The type of the computer tool call output. Always `computer_call_output`.""" + + id: str + """The ID of the computer tool call output.""" + + acknowledged_safety_checks: Iterable[ComputerCallOutputAcknowledgedSafetyCheck] + """ + The safety checks reported by the API that have been acknowledged by the + developer. + """ + + status: Literal["in_progress", "completed", "incomplete"] + """The status of the message input. + + One of `in_progress`, `completed`, or `incomplete`. Populated when input items + are returned via API. + """ + + +class FunctionCallOutput(TypedDict, total=False): + call_id: Required[str] + """The unique ID of the function tool call generated by the model.""" + + output: Required[str] + """A JSON string of the output of the function tool call.""" + + type: Required[Literal["function_call_output"]] + """The type of the function tool call output. Always `function_call_output`.""" + + id: str + """The unique ID of the function tool call output. + + Populated when this item is returned via API. + """ + + status: Literal["in_progress", "completed", "incomplete"] + """The status of the item. + + One of `in_progress`, `completed`, or `incomplete`. Populated when items are + returned via API. + """ + + +class ReasoningContent(TypedDict, total=False): + text: Required[str] + """ + A short summary of the reasoning used by the model when generating the response. + """ + + type: Required[Literal["reasoning_summary"]] + """The type of the object. Always `text`.""" + + +class Reasoning(TypedDict, total=False): + id: Required[str] + """The unique identifier of the reasoning content.""" + + content: Required[Iterable[ReasoningContent]] + """Reasoning text contents.""" + + type: Required[Literal["reasoning"]] + """The type of the object. Always `reasoning`.""" + + status: Literal["in_progress", "completed", "incomplete"] + """The status of the item. + + One of `in_progress`, `completed`, or `incomplete`. Populated when items are + returned via API. + """ + + +class ItemReference(TypedDict, total=False): + id: Required[str] + """The ID of the item to reference.""" + + type: Required[Literal["item_reference"]] + """The type of item to reference. Always `item_reference`.""" + + +ResponseInputItemParam: TypeAlias = Union[ + EasyInputMessageParam, + Message, + ResponseOutputMessageParam, + ResponseFileSearchToolCallParam, + ResponseComputerToolCallParam, + ComputerCallOutput, + ResponseFunctionWebSearchParam, + ResponseFunctionToolCallParam, + FunctionCallOutput, + Reasoning, + ItemReference, +] diff --git a/src/openai/types/responses/response_input_message_content_list.py b/src/openai/types/responses/response_input_message_content_list.py new file mode 100644 index 0000000000..99b7c10f12 --- /dev/null +++ b/src/openai/types/responses/response_input_message_content_list.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .response_input_content import ResponseInputContent + +__all__ = ["ResponseInputMessageContentList"] + +ResponseInputMessageContentList: TypeAlias = List[ResponseInputContent] diff --git a/src/openai/types/responses/response_input_message_content_list_param.py b/src/openai/types/responses/response_input_message_content_list_param.py new file mode 100644 index 0000000000..080613df0d --- /dev/null +++ b/src/openai/types/responses/response_input_message_content_list_param.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union +from typing_extensions import TypeAlias + +from .response_input_file_param import ResponseInputFileParam +from .response_input_text_param import ResponseInputTextParam +from .response_input_image_param import ResponseInputImageParam + +__all__ = ["ResponseInputMessageContentListParam", "ResponseInputContentParam"] + +ResponseInputContentParam: TypeAlias = Union[ResponseInputTextParam, ResponseInputImageParam, ResponseInputFileParam] + +ResponseInputMessageContentListParam: TypeAlias = List[ResponseInputContentParam] diff --git a/src/openai/types/responses/response_input_param.py b/src/openai/types/responses/response_input_param.py new file mode 100644 index 0000000000..c81308500d --- /dev/null +++ b/src/openai/types/responses/response_input_param.py @@ -0,0 +1,177 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union, Iterable +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .easy_input_message_param import EasyInputMessageParam +from .response_output_message_param import ResponseOutputMessageParam +from .response_computer_tool_call_param import ResponseComputerToolCallParam +from .response_function_tool_call_param import ResponseFunctionToolCallParam +from .response_function_web_search_param import ResponseFunctionWebSearchParam +from .response_file_search_tool_call_param import ResponseFileSearchToolCallParam +from .response_input_message_content_list_param import ResponseInputMessageContentListParam + +__all__ = [ + "ResponseInputParam", + "ResponseInputItemParam", + "Message", + "ComputerCallOutput", + "ComputerCallOutputOutput", + "ComputerCallOutputAcknowledgedSafetyCheck", + "FunctionCallOutput", + "Reasoning", + "ReasoningContent", + "ItemReference", +] + + +class Message(TypedDict, total=False): + content: Required[ResponseInputMessageContentListParam] + """ + A list of one or many input items to the model, containing different content + types. + """ + + role: Required[Literal["user", "system", "developer"]] + """The role of the message input. One of `user`, `system`, or `developer`.""" + + status: Literal["in_progress", "completed", "incomplete"] + """The status of item. + + One of `in_progress`, `completed`, or `incomplete`. Populated when items are + returned via API. + """ + + type: Literal["message"] + """The type of the message input. Always set to `message`.""" + + +class ComputerCallOutputOutput(TypedDict, total=False): + type: Required[Literal["computer_screenshot"]] + """Specifies the event type. + + For a computer screenshot, this property is always set to `computer_screenshot`. + """ + + file_id: str + """The identifier of an uploaded file that contains the screenshot.""" + + image_url: str + """The URL of the screenshot image.""" + + +class ComputerCallOutputAcknowledgedSafetyCheck(TypedDict, total=False): + id: Required[str] + """The ID of the pending safety check.""" + + code: Required[str] + """The type of the pending safety check.""" + + message: Required[str] + """Details about the pending safety check.""" + + +class ComputerCallOutput(TypedDict, total=False): + call_id: Required[str] + """The ID of the computer tool call that produced the output.""" + + output: Required[ComputerCallOutputOutput] + """A computer screenshot image used with the computer use tool.""" + + type: Required[Literal["computer_call_output"]] + """The type of the computer tool call output. Always `computer_call_output`.""" + + id: str + """The ID of the computer tool call output.""" + + acknowledged_safety_checks: Iterable[ComputerCallOutputAcknowledgedSafetyCheck] + """ + The safety checks reported by the API that have been acknowledged by the + developer. + """ + + status: Literal["in_progress", "completed", "incomplete"] + """The status of the message input. + + One of `in_progress`, `completed`, or `incomplete`. Populated when input items + are returned via API. + """ + + +class FunctionCallOutput(TypedDict, total=False): + call_id: Required[str] + """The unique ID of the function tool call generated by the model.""" + + output: Required[str] + """A JSON string of the output of the function tool call.""" + + type: Required[Literal["function_call_output"]] + """The type of the function tool call output. Always `function_call_output`.""" + + id: str + """The unique ID of the function tool call output. + + Populated when this item is returned via API. + """ + + status: Literal["in_progress", "completed", "incomplete"] + """The status of the item. + + One of `in_progress`, `completed`, or `incomplete`. Populated when items are + returned via API. + """ + + +class ReasoningContent(TypedDict, total=False): + text: Required[str] + """ + A short summary of the reasoning used by the model when generating the response. + """ + + type: Required[Literal["reasoning_summary"]] + """The type of the object. Always `text`.""" + + +class Reasoning(TypedDict, total=False): + id: Required[str] + """The unique identifier of the reasoning content.""" + + content: Required[Iterable[ReasoningContent]] + """Reasoning text contents.""" + + type: Required[Literal["reasoning"]] + """The type of the object. Always `reasoning`.""" + + status: Literal["in_progress", "completed", "incomplete"] + """The status of the item. + + One of `in_progress`, `completed`, or `incomplete`. Populated when items are + returned via API. + """ + + +class ItemReference(TypedDict, total=False): + id: Required[str] + """The ID of the item to reference.""" + + type: Required[Literal["item_reference"]] + """The type of item to reference. Always `item_reference`.""" + + +ResponseInputItemParam: TypeAlias = Union[ + EasyInputMessageParam, + Message, + ResponseOutputMessageParam, + ResponseFileSearchToolCallParam, + ResponseComputerToolCallParam, + ComputerCallOutput, + ResponseFunctionWebSearchParam, + ResponseFunctionToolCallParam, + FunctionCallOutput, + Reasoning, + ItemReference, +] + +ResponseInputParam: TypeAlias = List[ResponseInputItemParam] diff --git a/src/openai/types/responses/response_input_text.py b/src/openai/types/responses/response_input_text.py new file mode 100644 index 0000000000..ba8d1ea18b --- /dev/null +++ b/src/openai/types/responses/response_input_text.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseInputText"] + + +class ResponseInputText(BaseModel): + text: str + """The text input to the model.""" + + type: Literal["input_text"] + """The type of the input item. Always `input_text`.""" diff --git a/src/openai/types/responses/response_input_text_param.py b/src/openai/types/responses/response_input_text_param.py new file mode 100644 index 0000000000..f2ba834082 --- /dev/null +++ b/src/openai/types/responses/response_input_text_param.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ResponseInputTextParam"] + + +class ResponseInputTextParam(TypedDict, total=False): + text: Required[str] + """The text input to the model.""" + + type: Required[Literal["input_text"]] + """The type of the input item. Always `input_text`.""" diff --git a/src/openai/types/responses/response_item_list.py b/src/openai/types/responses/response_item_list.py new file mode 100644 index 0000000000..7c3e4d7f82 --- /dev/null +++ b/src/openai/types/responses/response_item_list.py @@ -0,0 +1,152 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .response_output_message import ResponseOutputMessage +from .response_computer_tool_call import ResponseComputerToolCall +from .response_function_tool_call import ResponseFunctionToolCall +from .response_function_web_search import ResponseFunctionWebSearch +from .response_file_search_tool_call import ResponseFileSearchToolCall +from .response_input_message_content_list import ResponseInputMessageContentList + +__all__ = [ + "ResponseItemList", + "Data", + "DataMessage", + "DataComputerCallOutput", + "DataComputerCallOutputOutput", + "DataComputerCallOutputAcknowledgedSafetyCheck", + "DataFunctionCallOutput", +] + + +class DataMessage(BaseModel): + id: str + """The unique ID of the message input.""" + + content: ResponseInputMessageContentList + """ + A list of one or many input items to the model, containing different content + types. + """ + + role: Literal["user", "system", "developer"] + """The role of the message input. One of `user`, `system`, or `developer`.""" + + status: Optional[Literal["in_progress", "completed", "incomplete"]] = None + """The status of item. + + One of `in_progress`, `completed`, or `incomplete`. Populated when items are + returned via API. + """ + + type: Optional[Literal["message"]] = None + """The type of the message input. Always set to `message`.""" + + +class DataComputerCallOutputOutput(BaseModel): + type: Literal["computer_screenshot"] + """Specifies the event type. + + For a computer screenshot, this property is always set to `computer_screenshot`. + """ + + file_id: Optional[str] = None + """The identifier of an uploaded file that contains the screenshot.""" + + image_url: Optional[str] = None + """The URL of the screenshot image.""" + + +class DataComputerCallOutputAcknowledgedSafetyCheck(BaseModel): + id: str + """The ID of the pending safety check.""" + + code: str + """The type of the pending safety check.""" + + message: str + """Details about the pending safety check.""" + + +class DataComputerCallOutput(BaseModel): + id: str + """The unique ID of the computer call tool output.""" + + call_id: str + """The ID of the computer tool call that produced the output.""" + + output: DataComputerCallOutputOutput + """A computer screenshot image used with the computer use tool.""" + + type: Literal["computer_call_output"] + """The type of the computer tool call output. Always `computer_call_output`.""" + + acknowledged_safety_checks: Optional[List[DataComputerCallOutputAcknowledgedSafetyCheck]] = None + """ + The safety checks reported by the API that have been acknowledged by the + developer. + """ + + status: Optional[Literal["in_progress", "completed", "incomplete"]] = None + """The status of the message input. + + One of `in_progress`, `completed`, or `incomplete`. Populated when input items + are returned via API. + """ + + +class DataFunctionCallOutput(BaseModel): + id: str + """The unique ID of the function call tool output.""" + + call_id: str + """The unique ID of the function tool call generated by the model.""" + + output: str + """A JSON string of the output of the function tool call.""" + + type: Literal["function_call_output"] + """The type of the function tool call output. Always `function_call_output`.""" + + status: Optional[Literal["in_progress", "completed", "incomplete"]] = None + """The status of the item. + + One of `in_progress`, `completed`, or `incomplete`. Populated when items are + returned via API. + """ + + +Data: TypeAlias = Annotated[ + Union[ + DataMessage, + ResponseOutputMessage, + ResponseFileSearchToolCall, + ResponseComputerToolCall, + DataComputerCallOutput, + ResponseFunctionWebSearch, + ResponseFunctionToolCall, + DataFunctionCallOutput, + ], + PropertyInfo(discriminator="type"), +] + + +class ResponseItemList(BaseModel): + data: List[Data] + """A list of items used to generate this response.""" + + first_id: str + """The ID of the first item in the list.""" + + has_more: bool + """Whether there are more items available.""" + + last_id: str + """The ID of the last item in the list.""" + + object: Literal["list"] + """The type of object returned, must be `list`.""" diff --git a/src/openai/types/responses/response_output_item.py b/src/openai/types/responses/response_output_item.py new file mode 100644 index 0000000000..45d5cc0094 --- /dev/null +++ b/src/openai/types/responses/response_output_item.py @@ -0,0 +1,55 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .response_output_message import ResponseOutputMessage +from .response_computer_tool_call import ResponseComputerToolCall +from .response_function_tool_call import ResponseFunctionToolCall +from .response_function_web_search import ResponseFunctionWebSearch +from .response_file_search_tool_call import ResponseFileSearchToolCall + +__all__ = ["ResponseOutputItem", "Reasoning", "ReasoningContent"] + + +class ReasoningContent(BaseModel): + text: str + """ + A short summary of the reasoning used by the model when generating the response. + """ + + type: Literal["reasoning_summary"] + """The type of the object. Always `text`.""" + + +class Reasoning(BaseModel): + id: str + """The unique identifier of the reasoning content.""" + + content: List[ReasoningContent] + """Reasoning text contents.""" + + type: Literal["reasoning"] + """The type of the object. Always `reasoning`.""" + + status: Optional[Literal["in_progress", "completed", "incomplete"]] = None + """The status of the item. + + One of `in_progress`, `completed`, or `incomplete`. Populated when items are + returned via API. + """ + + +ResponseOutputItem: TypeAlias = Annotated[ + Union[ + ResponseOutputMessage, + ResponseFileSearchToolCall, + ResponseFunctionToolCall, + ResponseFunctionWebSearch, + ResponseComputerToolCall, + Reasoning, + ], + PropertyInfo(discriminator="type"), +] diff --git a/src/openai/types/responses/response_output_item_added_event.py b/src/openai/types/responses/response_output_item_added_event.py new file mode 100644 index 0000000000..7344fb9a6c --- /dev/null +++ b/src/openai/types/responses/response_output_item_added_event.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel +from .response_output_item import ResponseOutputItem + +__all__ = ["ResponseOutputItemAddedEvent"] + + +class ResponseOutputItemAddedEvent(BaseModel): + item: ResponseOutputItem + """The output item that was added.""" + + output_index: int + """The index of the output item that was added.""" + + type: Literal["response.output_item.added"] + """The type of the event. Always `response.output_item.added`.""" diff --git a/src/openai/types/responses/response_output_item_done_event.py b/src/openai/types/responses/response_output_item_done_event.py new file mode 100644 index 0000000000..a0a871a019 --- /dev/null +++ b/src/openai/types/responses/response_output_item_done_event.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel +from .response_output_item import ResponseOutputItem + +__all__ = ["ResponseOutputItemDoneEvent"] + + +class ResponseOutputItemDoneEvent(BaseModel): + item: ResponseOutputItem + """The output item that was marked done.""" + + output_index: int + """The index of the output item that was marked done.""" + + type: Literal["response.output_item.done"] + """The type of the event. Always `response.output_item.done`.""" diff --git a/src/openai/types/responses/response_output_message.py b/src/openai/types/responses/response_output_message.py new file mode 100644 index 0000000000..3864aa2111 --- /dev/null +++ b/src/openai/types/responses/response_output_message.py @@ -0,0 +1,34 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .response_output_text import ResponseOutputText +from .response_output_refusal import ResponseOutputRefusal + +__all__ = ["ResponseOutputMessage", "Content"] + +Content: TypeAlias = Annotated[Union[ResponseOutputText, ResponseOutputRefusal], PropertyInfo(discriminator="type")] + + +class ResponseOutputMessage(BaseModel): + id: str + """The unique ID of the output message.""" + + content: List[Content] + """The content of the output message.""" + + role: Literal["assistant"] + """The role of the output message. Always `assistant`.""" + + status: Literal["in_progress", "completed", "incomplete"] + """The status of the message input. + + One of `in_progress`, `completed`, or `incomplete`. Populated when input items + are returned via API. + """ + + type: Literal["message"] + """The type of the output message. Always `message`.""" diff --git a/src/openai/types/responses/response_output_message_param.py b/src/openai/types/responses/response_output_message_param.py new file mode 100644 index 0000000000..46cbbd20de --- /dev/null +++ b/src/openai/types/responses/response_output_message_param.py @@ -0,0 +1,34 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .response_output_text_param import ResponseOutputTextParam +from .response_output_refusal_param import ResponseOutputRefusalParam + +__all__ = ["ResponseOutputMessageParam", "Content"] + +Content: TypeAlias = Union[ResponseOutputTextParam, ResponseOutputRefusalParam] + + +class ResponseOutputMessageParam(TypedDict, total=False): + id: Required[str] + """The unique ID of the output message.""" + + content: Required[Iterable[Content]] + """The content of the output message.""" + + role: Required[Literal["assistant"]] + """The role of the output message. Always `assistant`.""" + + status: Required[Literal["in_progress", "completed", "incomplete"]] + """The status of the message input. + + One of `in_progress`, `completed`, or `incomplete`. Populated when input items + are returned via API. + """ + + type: Required[Literal["message"]] + """The type of the output message. Always `message`.""" diff --git a/src/openai/types/responses/response_output_refusal.py b/src/openai/types/responses/response_output_refusal.py new file mode 100644 index 0000000000..eba581070d --- /dev/null +++ b/src/openai/types/responses/response_output_refusal.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseOutputRefusal"] + + +class ResponseOutputRefusal(BaseModel): + refusal: str + """The refusal explanationfrom the model.""" + + type: Literal["refusal"] + """The type of the refusal. Always `refusal`.""" diff --git a/src/openai/types/responses/response_output_refusal_param.py b/src/openai/types/responses/response_output_refusal_param.py new file mode 100644 index 0000000000..53140a6080 --- /dev/null +++ b/src/openai/types/responses/response_output_refusal_param.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ResponseOutputRefusalParam"] + + +class ResponseOutputRefusalParam(TypedDict, total=False): + refusal: Required[str] + """The refusal explanationfrom the model.""" + + type: Required[Literal["refusal"]] + """The type of the refusal. Always `refusal`.""" diff --git a/src/openai/types/responses/response_output_text.py b/src/openai/types/responses/response_output_text.py new file mode 100644 index 0000000000..fa653cd1af --- /dev/null +++ b/src/openai/types/responses/response_output_text.py @@ -0,0 +1,64 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel + +__all__ = ["ResponseOutputText", "Annotation", "AnnotationFileCitation", "AnnotationURLCitation", "AnnotationFilePath"] + + +class AnnotationFileCitation(BaseModel): + file_id: str + """The ID of the file.""" + + index: int + """The index of the file in the list of files.""" + + type: Literal["file_citation"] + """The type of the file citation. Always `file_citation`.""" + + +class AnnotationURLCitation(BaseModel): + end_index: int + """The index of the last character of the URL citation in the message.""" + + start_index: int + """The index of the first character of the URL citation in the message.""" + + title: str + """The title of the web resource.""" + + type: Literal["url_citation"] + """The type of the URL citation. Always `url_citation`.""" + + url: str + """The URL of the web resource.""" + + +class AnnotationFilePath(BaseModel): + file_id: str + """The ID of the file.""" + + index: int + """The index of the file in the list of files.""" + + type: Literal["file_path"] + """The type of the file path. Always `file_path`.""" + + +Annotation: TypeAlias = Annotated[ + Union[AnnotationFileCitation, AnnotationURLCitation, AnnotationFilePath], PropertyInfo(discriminator="type") +] + + +class ResponseOutputText(BaseModel): + annotations: List[Annotation] + """The annotations of the text output.""" + + text: str + """The text output from the model.""" + + type: Literal["output_text"] + """The type of the output text. Always `output_text`.""" diff --git a/src/openai/types/responses/response_output_text_param.py b/src/openai/types/responses/response_output_text_param.py new file mode 100644 index 0000000000..1f0967285f --- /dev/null +++ b/src/openai/types/responses/response_output_text_param.py @@ -0,0 +1,67 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +__all__ = [ + "ResponseOutputTextParam", + "Annotation", + "AnnotationFileCitation", + "AnnotationURLCitation", + "AnnotationFilePath", +] + + +class AnnotationFileCitation(TypedDict, total=False): + file_id: Required[str] + """The ID of the file.""" + + index: Required[int] + """The index of the file in the list of files.""" + + type: Required[Literal["file_citation"]] + """The type of the file citation. Always `file_citation`.""" + + +class AnnotationURLCitation(TypedDict, total=False): + end_index: Required[int] + """The index of the last character of the URL citation in the message.""" + + start_index: Required[int] + """The index of the first character of the URL citation in the message.""" + + title: Required[str] + """The title of the web resource.""" + + type: Required[Literal["url_citation"]] + """The type of the URL citation. Always `url_citation`.""" + + url: Required[str] + """The URL of the web resource.""" + + +class AnnotationFilePath(TypedDict, total=False): + file_id: Required[str] + """The ID of the file.""" + + index: Required[int] + """The index of the file in the list of files.""" + + type: Required[Literal["file_path"]] + """The type of the file path. Always `file_path`.""" + + +Annotation: TypeAlias = Union[AnnotationFileCitation, AnnotationURLCitation, AnnotationFilePath] + + +class ResponseOutputTextParam(TypedDict, total=False): + annotations: Required[Iterable[Annotation]] + """The annotations of the text output.""" + + text: Required[str] + """The text output from the model.""" + + type: Required[Literal["output_text"]] + """The type of the output text. Always `output_text`.""" diff --git a/src/openai/types/responses/response_refusal_delta_event.py b/src/openai/types/responses/response_refusal_delta_event.py new file mode 100644 index 0000000000..04dcdf1c8c --- /dev/null +++ b/src/openai/types/responses/response_refusal_delta_event.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseRefusalDeltaEvent"] + + +class ResponseRefusalDeltaEvent(BaseModel): + content_index: int + """The index of the content part that the refusal text is added to.""" + + delta: str + """The refusal text that is added.""" + + item_id: str + """The ID of the output item that the refusal text is added to.""" + + output_index: int + """The index of the output item that the refusal text is added to.""" + + type: Literal["response.refusal.delta"] + """The type of the event. Always `response.refusal.delta`.""" diff --git a/src/openai/types/responses/response_refusal_done_event.py b/src/openai/types/responses/response_refusal_done_event.py new file mode 100644 index 0000000000..a9b6f4b055 --- /dev/null +++ b/src/openai/types/responses/response_refusal_done_event.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseRefusalDoneEvent"] + + +class ResponseRefusalDoneEvent(BaseModel): + content_index: int + """The index of the content part that the refusal text is finalized.""" + + item_id: str + """The ID of the output item that the refusal text is finalized.""" + + output_index: int + """The index of the output item that the refusal text is finalized.""" + + refusal: str + """The refusal text that is finalized.""" + + type: Literal["response.refusal.done"] + """The type of the event. Always `response.refusal.done`.""" diff --git a/src/openai/types/responses/response_retrieve_params.py b/src/openai/types/responses/response_retrieve_params.py new file mode 100644 index 0000000000..137bf4dcee --- /dev/null +++ b/src/openai/types/responses/response_retrieve_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import TypedDict + +from .response_includable import ResponseIncludable + +__all__ = ["ResponseRetrieveParams"] + + +class ResponseRetrieveParams(TypedDict, total=False): + include: List[ResponseIncludable] + """Additional fields to include in the response. + + See the `include` parameter for Response creation above for more information. + """ diff --git a/src/openai/types/responses/response_status.py b/src/openai/types/responses/response_status.py new file mode 100644 index 0000000000..934d17cda3 --- /dev/null +++ b/src/openai/types/responses/response_status.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["ResponseStatus"] + +ResponseStatus: TypeAlias = Literal["completed", "failed", "in_progress", "incomplete"] diff --git a/src/openai/types/responses/response_stream_event.py b/src/openai/types/responses/response_stream_event.py new file mode 100644 index 0000000000..446863b175 --- /dev/null +++ b/src/openai/types/responses/response_stream_event.py @@ -0,0 +1,78 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from typing_extensions import Annotated, TypeAlias + +from ..._utils import PropertyInfo +from .response_error_event import ResponseErrorEvent +from .response_failed_event import ResponseFailedEvent +from .response_created_event import ResponseCreatedEvent +from .response_completed_event import ResponseCompletedEvent +from .response_text_done_event import ResponseTextDoneEvent +from .response_audio_done_event import ResponseAudioDoneEvent +from .response_incomplete_event import ResponseIncompleteEvent +from .response_text_delta_event import ResponseTextDeltaEvent +from .response_audio_delta_event import ResponseAudioDeltaEvent +from .response_in_progress_event import ResponseInProgressEvent +from .response_refusal_done_event import ResponseRefusalDoneEvent +from .response_refusal_delta_event import ResponseRefusalDeltaEvent +from .response_output_item_done_event import ResponseOutputItemDoneEvent +from .response_content_part_done_event import ResponseContentPartDoneEvent +from .response_output_item_added_event import ResponseOutputItemAddedEvent +from .response_content_part_added_event import ResponseContentPartAddedEvent +from .response_audio_transcript_done_event import ResponseAudioTranscriptDoneEvent +from .response_text_annotation_delta_event import ResponseTextAnnotationDeltaEvent +from .response_audio_transcript_delta_event import ResponseAudioTranscriptDeltaEvent +from .response_web_search_call_completed_event import ResponseWebSearchCallCompletedEvent +from .response_web_search_call_searching_event import ResponseWebSearchCallSearchingEvent +from .response_file_search_call_completed_event import ResponseFileSearchCallCompletedEvent +from .response_file_search_call_searching_event import ResponseFileSearchCallSearchingEvent +from .response_web_search_call_in_progress_event import ResponseWebSearchCallInProgressEvent +from .response_file_search_call_in_progress_event import ResponseFileSearchCallInProgressEvent +from .response_function_call_arguments_done_event import ResponseFunctionCallArgumentsDoneEvent +from .response_function_call_arguments_delta_event import ResponseFunctionCallArgumentsDeltaEvent +from .response_code_interpreter_call_code_done_event import ResponseCodeInterpreterCallCodeDoneEvent +from .response_code_interpreter_call_completed_event import ResponseCodeInterpreterCallCompletedEvent +from .response_code_interpreter_call_code_delta_event import ResponseCodeInterpreterCallCodeDeltaEvent +from .response_code_interpreter_call_in_progress_event import ResponseCodeInterpreterCallInProgressEvent +from .response_code_interpreter_call_interpreting_event import ResponseCodeInterpreterCallInterpretingEvent + +__all__ = ["ResponseStreamEvent"] + +ResponseStreamEvent: TypeAlias = Annotated[ + Union[ + ResponseAudioDeltaEvent, + ResponseAudioDoneEvent, + ResponseAudioTranscriptDeltaEvent, + ResponseAudioTranscriptDoneEvent, + ResponseCodeInterpreterCallCodeDeltaEvent, + ResponseCodeInterpreterCallCodeDoneEvent, + ResponseCodeInterpreterCallCompletedEvent, + ResponseCodeInterpreterCallInProgressEvent, + ResponseCodeInterpreterCallInterpretingEvent, + ResponseCompletedEvent, + ResponseContentPartAddedEvent, + ResponseContentPartDoneEvent, + ResponseCreatedEvent, + ResponseErrorEvent, + ResponseFileSearchCallCompletedEvent, + ResponseFileSearchCallInProgressEvent, + ResponseFileSearchCallSearchingEvent, + ResponseFunctionCallArgumentsDeltaEvent, + ResponseFunctionCallArgumentsDoneEvent, + ResponseInProgressEvent, + ResponseFailedEvent, + ResponseIncompleteEvent, + ResponseOutputItemAddedEvent, + ResponseOutputItemDoneEvent, + ResponseRefusalDeltaEvent, + ResponseRefusalDoneEvent, + ResponseTextAnnotationDeltaEvent, + ResponseTextDeltaEvent, + ResponseTextDoneEvent, + ResponseWebSearchCallCompletedEvent, + ResponseWebSearchCallInProgressEvent, + ResponseWebSearchCallSearchingEvent, + ], + PropertyInfo(discriminator="type"), +] diff --git a/src/openai/types/responses/response_text_annotation_delta_event.py b/src/openai/types/responses/response_text_annotation_delta_event.py new file mode 100644 index 0000000000..4f2582282a --- /dev/null +++ b/src/openai/types/responses/response_text_annotation_delta_event.py @@ -0,0 +1,79 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel + +__all__ = [ + "ResponseTextAnnotationDeltaEvent", + "Annotation", + "AnnotationFileCitation", + "AnnotationURLCitation", + "AnnotationFilePath", +] + + +class AnnotationFileCitation(BaseModel): + file_id: str + """The ID of the file.""" + + index: int + """The index of the file in the list of files.""" + + type: Literal["file_citation"] + """The type of the file citation. Always `file_citation`.""" + + +class AnnotationURLCitation(BaseModel): + end_index: int + """The index of the last character of the URL citation in the message.""" + + start_index: int + """The index of the first character of the URL citation in the message.""" + + title: str + """The title of the web resource.""" + + type: Literal["url_citation"] + """The type of the URL citation. Always `url_citation`.""" + + url: str + """The URL of the web resource.""" + + +class AnnotationFilePath(BaseModel): + file_id: str + """The ID of the file.""" + + index: int + """The index of the file in the list of files.""" + + type: Literal["file_path"] + """The type of the file path. Always `file_path`.""" + + +Annotation: TypeAlias = Annotated[ + Union[AnnotationFileCitation, AnnotationURLCitation, AnnotationFilePath], PropertyInfo(discriminator="type") +] + + +class ResponseTextAnnotationDeltaEvent(BaseModel): + annotation: Annotation + """A citation to a file.""" + + annotation_index: int + """The index of the annotation that was added.""" + + content_index: int + """The index of the content part that the text annotation was added to.""" + + item_id: str + """The ID of the output item that the text annotation was added to.""" + + output_index: int + """The index of the output item that the text annotation was added to.""" + + type: Literal["response.output_text.annotation.added"] + """The type of the event. Always `response.output_text.annotation.added`.""" diff --git a/src/openai/types/responses/response_text_config.py b/src/openai/types/responses/response_text_config.py new file mode 100644 index 0000000000..a1894a9176 --- /dev/null +++ b/src/openai/types/responses/response_text_config.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel +from .response_format_text_config import ResponseFormatTextConfig + +__all__ = ["ResponseTextConfig"] + + +class ResponseTextConfig(BaseModel): + format: Optional[ResponseFormatTextConfig] = None + """An object specifying the format that the model must output. + + Configuring `{ "type": "json_schema" }` enables Structured Outputs, which + ensures the model will match your supplied JSON schema. Learn more in the + [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). + + The default format is `{ "type": "text" }` with no additional options. + + **Not recommended for gpt-4o and newer models:** + + Setting to `{ "type": "json_object" }` enables the older JSON mode, which + ensures the message the model generates is valid JSON. Using `json_schema` is + preferred for models that support it. + """ diff --git a/src/openai/types/responses/response_text_config_param.py b/src/openai/types/responses/response_text_config_param.py new file mode 100644 index 0000000000..aec064bf89 --- /dev/null +++ b/src/openai/types/responses/response_text_config_param.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +from .response_format_text_config_param import ResponseFormatTextConfigParam + +__all__ = ["ResponseTextConfigParam"] + + +class ResponseTextConfigParam(TypedDict, total=False): + format: ResponseFormatTextConfigParam + """An object specifying the format that the model must output. + + Configuring `{ "type": "json_schema" }` enables Structured Outputs, which + ensures the model will match your supplied JSON schema. Learn more in the + [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). + + The default format is `{ "type": "text" }` with no additional options. + + **Not recommended for gpt-4o and newer models:** + + Setting to `{ "type": "json_object" }` enables the older JSON mode, which + ensures the message the model generates is valid JSON. Using `json_schema` is + preferred for models that support it. + """ diff --git a/src/openai/types/responses/response_text_delta_event.py b/src/openai/types/responses/response_text_delta_event.py new file mode 100644 index 0000000000..751a5e2a19 --- /dev/null +++ b/src/openai/types/responses/response_text_delta_event.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseTextDeltaEvent"] + + +class ResponseTextDeltaEvent(BaseModel): + content_index: int + """The index of the content part that the text delta was added to.""" + + delta: str + """The text delta that was added.""" + + item_id: str + """The ID of the output item that the text delta was added to.""" + + output_index: int + """The index of the output item that the text delta was added to.""" + + type: Literal["response.output_text.delta"] + """The type of the event. Always `response.output_text.delta`.""" diff --git a/src/openai/types/responses/response_text_done_event.py b/src/openai/types/responses/response_text_done_event.py new file mode 100644 index 0000000000..9b5c5e020c --- /dev/null +++ b/src/openai/types/responses/response_text_done_event.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseTextDoneEvent"] + + +class ResponseTextDoneEvent(BaseModel): + content_index: int + """The index of the content part that the text content is finalized.""" + + item_id: str + """The ID of the output item that the text content is finalized.""" + + output_index: int + """The index of the output item that the text content is finalized.""" + + text: str + """The text content that is finalized.""" + + type: Literal["response.output_text.done"] + """The type of the event. Always `response.output_text.done`.""" diff --git a/src/openai/types/responses/response_usage.py b/src/openai/types/responses/response_usage.py new file mode 100644 index 0000000000..ef631c5882 --- /dev/null +++ b/src/openai/types/responses/response_usage.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + + +from ..._models import BaseModel + +__all__ = ["ResponseUsage", "OutputTokensDetails"] + + +class OutputTokensDetails(BaseModel): + reasoning_tokens: int + """The number of reasoning tokens.""" + + +class ResponseUsage(BaseModel): + input_tokens: int + """The number of input tokens.""" + + output_tokens: int + """The number of output tokens.""" + + output_tokens_details: OutputTokensDetails + """A detailed breakdown of the output tokens.""" + + total_tokens: int + """The total number of tokens used.""" diff --git a/src/openai/types/responses/response_web_search_call_completed_event.py b/src/openai/types/responses/response_web_search_call_completed_event.py new file mode 100644 index 0000000000..76f26766a1 --- /dev/null +++ b/src/openai/types/responses/response_web_search_call_completed_event.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseWebSearchCallCompletedEvent"] + + +class ResponseWebSearchCallCompletedEvent(BaseModel): + item_id: str + """Unique ID for the output item associated with the web search call.""" + + output_index: int + """The index of the output item that the web search call is associated with.""" + + type: Literal["response.web_search_call.completed"] + """The type of the event. Always `response.web_search_call.completed`.""" diff --git a/src/openai/types/responses/response_web_search_call_in_progress_event.py b/src/openai/types/responses/response_web_search_call_in_progress_event.py new file mode 100644 index 0000000000..681ce6d94b --- /dev/null +++ b/src/openai/types/responses/response_web_search_call_in_progress_event.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseWebSearchCallInProgressEvent"] + + +class ResponseWebSearchCallInProgressEvent(BaseModel): + item_id: str + """Unique ID for the output item associated with the web search call.""" + + output_index: int + """The index of the output item that the web search call is associated with.""" + + type: Literal["response.web_search_call.in_progress"] + """The type of the event. Always `response.web_search_call.in_progress`.""" diff --git a/src/openai/types/responses/response_web_search_call_searching_event.py b/src/openai/types/responses/response_web_search_call_searching_event.py new file mode 100644 index 0000000000..c885d98918 --- /dev/null +++ b/src/openai/types/responses/response_web_search_call_searching_event.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseWebSearchCallSearchingEvent"] + + +class ResponseWebSearchCallSearchingEvent(BaseModel): + item_id: str + """Unique ID for the output item associated with the web search call.""" + + output_index: int + """The index of the output item that the web search call is associated with.""" + + type: Literal["response.web_search_call.searching"] + """The type of the event. Always `response.web_search_call.searching`.""" diff --git a/src/openai/types/responses/tool.py b/src/openai/types/responses/tool.py new file mode 100644 index 0000000000..de5d5524d4 --- /dev/null +++ b/src/openai/types/responses/tool.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from typing_extensions import Annotated, TypeAlias + +from ..._utils import PropertyInfo +from .computer_tool import ComputerTool +from .function_tool import FunctionTool +from .web_search_tool import WebSearchTool +from .file_search_tool import FileSearchTool + +__all__ = ["Tool"] + +Tool: TypeAlias = Annotated[ + Union[FileSearchTool, FunctionTool, ComputerTool, WebSearchTool], PropertyInfo(discriminator="type") +] diff --git a/src/openai/types/responses/tool_choice_function.py b/src/openai/types/responses/tool_choice_function.py new file mode 100644 index 0000000000..8d2a4f2822 --- /dev/null +++ b/src/openai/types/responses/tool_choice_function.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ToolChoiceFunction"] + + +class ToolChoiceFunction(BaseModel): + name: str + """The name of the function to call.""" + + type: Literal["function"] + """For function calling, the type is always `function`.""" diff --git a/src/openai/types/responses/tool_choice_function_param.py b/src/openai/types/responses/tool_choice_function_param.py new file mode 100644 index 0000000000..910537fd97 --- /dev/null +++ b/src/openai/types/responses/tool_choice_function_param.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ToolChoiceFunctionParam"] + + +class ToolChoiceFunctionParam(TypedDict, total=False): + name: Required[str] + """The name of the function to call.""" + + type: Required[Literal["function"]] + """For function calling, the type is always `function`.""" diff --git a/src/openai/types/responses/tool_choice_options.py b/src/openai/types/responses/tool_choice_options.py new file mode 100644 index 0000000000..c200db54e1 --- /dev/null +++ b/src/openai/types/responses/tool_choice_options.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["ToolChoiceOptions"] + +ToolChoiceOptions: TypeAlias = Literal["none", "auto", "required"] diff --git a/src/openai/types/responses/tool_choice_types.py b/src/openai/types/responses/tool_choice_types.py new file mode 100644 index 0000000000..4942808f14 --- /dev/null +++ b/src/openai/types/responses/tool_choice_types.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ToolChoiceTypes"] + + +class ToolChoiceTypes(BaseModel): + type: Literal["file_search", "web_search_preview", "computer_use_preview", "web_search_preview_2025_03_11"] + """The type of hosted tool the model should to use. + + Learn more about + [built-in tools](https://platform.openai.com/docs/guides/tools). + + Allowed values are: + + - `file_search` + - `web_search_preview` + - `computer_use_preview` + """ diff --git a/src/openai/types/responses/tool_choice_types_param.py b/src/openai/types/responses/tool_choice_types_param.py new file mode 100644 index 0000000000..b14f2a9eb0 --- /dev/null +++ b/src/openai/types/responses/tool_choice_types_param.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ToolChoiceTypesParam"] + + +class ToolChoiceTypesParam(TypedDict, total=False): + type: Required[ + Literal["file_search", "web_search_preview", "computer_use_preview", "web_search_preview_2025_03_11"] + ] + """The type of hosted tool the model should to use. + + Learn more about + [built-in tools](https://platform.openai.com/docs/guides/tools). + + Allowed values are: + + - `file_search` + - `web_search_preview` + - `computer_use_preview` + """ diff --git a/src/openai/types/responses/tool_param.py b/src/openai/types/responses/tool_param.py new file mode 100644 index 0000000000..be1cf82452 --- /dev/null +++ b/src/openai/types/responses/tool_param.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import TypeAlias + +from .computer_tool_param import ComputerToolParam +from .function_tool_param import FunctionToolParam +from .web_search_tool_param import WebSearchToolParam +from .file_search_tool_param import FileSearchToolParam +from ..chat.chat_completion_tool_param import ChatCompletionToolParam + +__all__ = ["ToolParam"] + +ToolParam: TypeAlias = Union[FileSearchToolParam, FunctionToolParam, ComputerToolParam, WebSearchToolParam] + +ParseableToolParam: TypeAlias = Union[ToolParam, ChatCompletionToolParam] diff --git a/src/openai/types/responses/web_search_tool.py b/src/openai/types/responses/web_search_tool.py new file mode 100644 index 0000000000..bee270bf85 --- /dev/null +++ b/src/openai/types/responses/web_search_tool.py @@ -0,0 +1,48 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["WebSearchTool", "UserLocation"] + + +class UserLocation(BaseModel): + type: Literal["approximate"] + """The type of location approximation. Always `approximate`.""" + + city: Optional[str] = None + """Free text input for the city of the user, e.g. `San Francisco`.""" + + country: Optional[str] = None + """ + The two-letter [ISO country code](https://en.wikipedia.org/wiki/ISO_3166-1) of + the user, e.g. `US`. + """ + + region: Optional[str] = None + """Free text input for the region of the user, e.g. `California`.""" + + timezone: Optional[str] = None + """ + The [IANA timezone](https://timeapi.io/documentation/iana-timezones) of the + user, e.g. `America/Los_Angeles`. + """ + + +class WebSearchTool(BaseModel): + type: Literal["web_search_preview", "web_search_preview_2025_03_11"] + """The type of the web search tool. One of: + + - `web_search_preview` + - `web_search_preview_2025_03_11` + """ + + search_context_size: Optional[Literal["low", "medium", "high"]] = None + """ + High level guidance for the amount of context window space to use for the + search. One of `low`, `medium`, or `high`. `medium` is the default. + """ + + user_location: Optional[UserLocation] = None diff --git a/src/openai/types/responses/web_search_tool_param.py b/src/openai/types/responses/web_search_tool_param.py new file mode 100644 index 0000000000..8ee36ffb47 --- /dev/null +++ b/src/openai/types/responses/web_search_tool_param.py @@ -0,0 +1,48 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["WebSearchToolParam", "UserLocation"] + + +class UserLocation(TypedDict, total=False): + type: Required[Literal["approximate"]] + """The type of location approximation. Always `approximate`.""" + + city: str + """Free text input for the city of the user, e.g. `San Francisco`.""" + + country: str + """ + The two-letter [ISO country code](https://en.wikipedia.org/wiki/ISO_3166-1) of + the user, e.g. `US`. + """ + + region: str + """Free text input for the region of the user, e.g. `California`.""" + + timezone: str + """ + The [IANA timezone](https://timeapi.io/documentation/iana-timezones) of the + user, e.g. `America/Los_Angeles`. + """ + + +class WebSearchToolParam(TypedDict, total=False): + type: Required[Literal["web_search_preview", "web_search_preview_2025_03_11"]] + """The type of the web search tool. One of: + + - `web_search_preview` + - `web_search_preview_2025_03_11` + """ + + search_context_size: Literal["low", "medium", "high"] + """ + High level guidance for the amount of context window space to use for the + search. One of `low`, `medium`, or `high`. `medium` is the default. + """ + + user_location: Optional[UserLocation] diff --git a/src/openai/types/shared/__init__.py b/src/openai/types/shared/__init__.py index 4cf367b1cc..6ccc2313cc 100644 --- a/src/openai/types/shared/__init__.py +++ b/src/openai/types/shared/__init__.py @@ -1,8 +1,12 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from .metadata import Metadata as Metadata +from .reasoning import Reasoning as Reasoning from .chat_model import ChatModel as ChatModel from .error_object import ErrorObject as ErrorObject +from .compound_filter import CompoundFilter as CompoundFilter +from .reasoning_effort import ReasoningEffort as ReasoningEffort +from .comparison_filter import ComparisonFilter as ComparisonFilter from .function_definition import FunctionDefinition as FunctionDefinition from .function_parameters import FunctionParameters as FunctionParameters from .response_format_text import ResponseFormatText as ResponseFormatText diff --git a/src/openai/types/shared/chat_model.py b/src/openai/types/shared/chat_model.py index 6fe705a0b4..31d7104e6e 100644 --- a/src/openai/types/shared/chat_model.py +++ b/src/openai/types/shared/chat_model.py @@ -13,6 +13,9 @@ "o1-preview-2024-09-12", "o1-mini", "o1-mini-2024-09-12", + "computer-use-preview", + "computer-use-preview-2025-02-04", + "computer-use-preview-2025-03-11", "gpt-4.5-preview", "gpt-4.5-preview-2025-02-27", "gpt-4o", diff --git a/src/openai/types/shared/comparison_filter.py b/src/openai/types/shared/comparison_filter.py new file mode 100644 index 0000000000..2ec2651ff2 --- /dev/null +++ b/src/openai/types/shared/comparison_filter.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ComparisonFilter"] + + +class ComparisonFilter(BaseModel): + key: str + """The key to compare against the value.""" + + type: Literal["eq", "ne", "gt", "gte", "lt", "lte"] + """Specifies the comparison operator: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`. + + - `eq`: equals + - `ne`: not equal + - `gt`: greater than + - `gte`: greater than or equal + - `lt`: less than + - `lte`: less than or equal + """ + + value: Union[str, float, bool] + """ + The value to compare against the attribute key; supports string, number, or + boolean types. + """ diff --git a/src/openai/types/shared/compound_filter.py b/src/openai/types/shared/compound_filter.py new file mode 100644 index 0000000000..3aefa43647 --- /dev/null +++ b/src/openai/types/shared/compound_filter.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union +from typing_extensions import Literal, TypeAlias + +from ..._models import BaseModel +from .comparison_filter import ComparisonFilter + +__all__ = ["CompoundFilter", "Filter"] + +Filter: TypeAlias = Union[ComparisonFilter, object] + + +class CompoundFilter(BaseModel): + filters: List[Filter] + """Array of filters to combine. + + Items can be `ComparisonFilter` or `CompoundFilter`. + """ + + type: Literal["and", "or"] + """Type of operation: `and` or `or`.""" diff --git a/src/openai/types/shared/reasoning.py b/src/openai/types/shared/reasoning.py new file mode 100644 index 0000000000..50821a1727 --- /dev/null +++ b/src/openai/types/shared/reasoning.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel +from .reasoning_effort import ReasoningEffort + +__all__ = ["Reasoning"] + + +class Reasoning(BaseModel): + effort: Optional[ReasoningEffort] = None + """**o-series 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. + """ + + generate_summary: Optional[Literal["concise", "detailed"]] = None + """**o-series models only** + + A summary of the reasoning performed by the model. This can be useful for + debugging and understanding the model's reasoning process. One of `concise` or + `detailed`. + """ diff --git a/src/openai/types/shared/reasoning_effort.py b/src/openai/types/shared/reasoning_effort.py new file mode 100644 index 0000000000..ace21b67e4 --- /dev/null +++ b/src/openai/types/shared/reasoning_effort.py @@ -0,0 +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__ = ["ReasoningEffort"] + +ReasoningEffort: TypeAlias = Optional[Literal["low", "medium", "high"]] diff --git a/src/openai/types/shared/response_format_json_object.py b/src/openai/types/shared/response_format_json_object.py index 107728dd2e..2aaa5dbdfe 100644 --- a/src/openai/types/shared/response_format_json_object.py +++ b/src/openai/types/shared/response_format_json_object.py @@ -9,4 +9,4 @@ class ResponseFormatJSONObject(BaseModel): type: Literal["json_object"] - """The type of response format being defined: `json_object`""" + """The type of response format being defined. Always `json_object`.""" diff --git a/src/openai/types/shared/response_format_json_schema.py b/src/openai/types/shared/response_format_json_schema.py index 3194a4fe91..c7924446f4 100644 --- a/src/openai/types/shared/response_format_json_schema.py +++ b/src/openai/types/shared/response_format_json_schema.py @@ -25,20 +25,24 @@ class JSONSchema(BaseModel): """ schema_: Optional[Dict[str, object]] = FieldInfo(alias="schema", default=None) - """The schema for the response format, described as a JSON Schema object.""" + """ + The schema for the response format, described as a JSON Schema object. Learn how + to build JSON schemas [here](https://json-schema.org/). + """ strict: Optional[bool] = None - """Whether to enable strict schema adherence when generating the output. - - If set to true, the model will always follow the exact schema defined in the - `schema` field. Only a subset of JSON Schema is supported when `strict` is - `true`. To learn more, read the + """ + Whether to enable strict schema adherence when generating the output. If set to + true, the model will always follow the exact schema defined in the `schema` + field. Only a subset of JSON Schema is supported when `strict` is `true`. To + learn more, read the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). """ class ResponseFormatJSONSchema(BaseModel): json_schema: JSONSchema + """Structured Outputs configuration options, including a JSON Schema.""" type: Literal["json_schema"] - """The type of response format being defined: `json_schema`""" + """The type of response format being defined. Always `json_schema`.""" diff --git a/src/openai/types/shared/response_format_text.py b/src/openai/types/shared/response_format_text.py index 6721fe0973..f0c8cfb700 100644 --- a/src/openai/types/shared/response_format_text.py +++ b/src/openai/types/shared/response_format_text.py @@ -9,4 +9,4 @@ class ResponseFormatText(BaseModel): type: Literal["text"] - """The type of response format being defined: `text`""" + """The type of response format being defined. Always `text`.""" diff --git a/src/openai/types/shared_params/__init__.py b/src/openai/types/shared_params/__init__.py index 47a747b2d4..4a4a8cdf1e 100644 --- a/src/openai/types/shared_params/__init__.py +++ b/src/openai/types/shared_params/__init__.py @@ -1,7 +1,11 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from .metadata import Metadata as Metadata +from .reasoning import Reasoning as Reasoning from .chat_model import ChatModel as ChatModel +from .compound_filter import CompoundFilter as CompoundFilter +from .reasoning_effort import ReasoningEffort as ReasoningEffort +from .comparison_filter import ComparisonFilter as ComparisonFilter from .function_definition import FunctionDefinition as FunctionDefinition from .function_parameters import FunctionParameters as FunctionParameters from .response_format_text import ResponseFormatText as ResponseFormatText diff --git a/src/openai/types/shared_params/chat_model.py b/src/openai/types/shared_params/chat_model.py index 0ac3f31611..55649876eb 100644 --- a/src/openai/types/shared_params/chat_model.py +++ b/src/openai/types/shared_params/chat_model.py @@ -15,6 +15,9 @@ "o1-preview-2024-09-12", "o1-mini", "o1-mini-2024-09-12", + "computer-use-preview", + "computer-use-preview-2025-02-04", + "computer-use-preview-2025-03-11", "gpt-4.5-preview", "gpt-4.5-preview-2025-02-27", "gpt-4o", diff --git a/src/openai/types/shared_params/comparison_filter.py b/src/openai/types/shared_params/comparison_filter.py new file mode 100644 index 0000000000..38edd315ed --- /dev/null +++ b/src/openai/types/shared_params/comparison_filter.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ComparisonFilter"] + + +class ComparisonFilter(TypedDict, total=False): + key: Required[str] + """The key to compare against the value.""" + + type: Required[Literal["eq", "ne", "gt", "gte", "lt", "lte"]] + """Specifies the comparison operator: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`. + + - `eq`: equals + - `ne`: not equal + - `gt`: greater than + - `gte`: greater than or equal + - `lt`: less than + - `lte`: less than or equal + """ + + value: Required[Union[str, float, bool]] + """ + The value to compare against the attribute key; supports string, number, or + boolean types. + """ diff --git a/src/openai/types/shared_params/compound_filter.py b/src/openai/types/shared_params/compound_filter.py new file mode 100644 index 0000000000..d12e9b1bda --- /dev/null +++ b/src/openai/types/shared_params/compound_filter.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .comparison_filter import ComparisonFilter + +__all__ = ["CompoundFilter", "Filter"] + +Filter: TypeAlias = Union[ComparisonFilter, object] + + +class CompoundFilter(TypedDict, total=False): + filters: Required[Iterable[Filter]] + """Array of filters to combine. + + Items can be `ComparisonFilter` or `CompoundFilter`. + """ + + type: Required[Literal["and", "or"]] + """Type of operation: `and` or `or`.""" diff --git a/src/openai/types/shared_params/reasoning.py b/src/openai/types/shared_params/reasoning.py new file mode 100644 index 0000000000..f2b5c5963a --- /dev/null +++ b/src/openai/types/shared_params/reasoning.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +from ..shared.reasoning_effort import ReasoningEffort + +__all__ = ["Reasoning"] + + +class Reasoning(TypedDict, total=False): + effort: Required[Optional[ReasoningEffort]] + """**o-series 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. + """ + + generate_summary: Optional[Literal["concise", "detailed"]] + """**o-series models only** + + A summary of the reasoning performed by the model. This can be useful for + debugging and understanding the model's reasoning process. One of `concise` or + `detailed`. + """ diff --git a/src/openai/types/shared_params/reasoning_effort.py b/src/openai/types/shared_params/reasoning_effort.py new file mode 100644 index 0000000000..6052c5ae15 --- /dev/null +++ b/src/openai/types/shared_params/reasoning_effort.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, TypeAlias + +__all__ = ["ReasoningEffort"] + +ReasoningEffort: TypeAlias = Optional[Literal["low", "medium", "high"]] diff --git a/src/openai/types/shared_params/response_format_json_object.py b/src/openai/types/shared_params/response_format_json_object.py index 8419c6cb56..d4d1deaae5 100644 --- a/src/openai/types/shared_params/response_format_json_object.py +++ b/src/openai/types/shared_params/response_format_json_object.py @@ -9,4 +9,4 @@ class ResponseFormatJSONObject(TypedDict, total=False): type: Required[Literal["json_object"]] - """The type of response format being defined: `json_object`""" + """The type of response format being defined. Always `json_object`.""" diff --git a/src/openai/types/shared_params/response_format_json_schema.py b/src/openai/types/shared_params/response_format_json_schema.py index 4b60fae8ee..5b0a13ee06 100644 --- a/src/openai/types/shared_params/response_format_json_schema.py +++ b/src/openai/types/shared_params/response_format_json_schema.py @@ -23,20 +23,24 @@ class JSONSchema(TypedDict, total=False): """ schema: Dict[str, object] - """The schema for the response format, described as a JSON Schema object.""" + """ + The schema for the response format, described as a JSON Schema object. Learn how + to build JSON schemas [here](https://json-schema.org/). + """ strict: Optional[bool] - """Whether to enable strict schema adherence when generating the output. - - If set to true, the model will always follow the exact schema defined in the - `schema` field. Only a subset of JSON Schema is supported when `strict` is - `true`. To learn more, read the + """ + Whether to enable strict schema adherence when generating the output. If set to + true, the model will always follow the exact schema defined in the `schema` + field. Only a subset of JSON Schema is supported when `strict` is `true`. To + learn more, read the [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). """ class ResponseFormatJSONSchema(TypedDict, total=False): json_schema: Required[JSONSchema] + """Structured Outputs configuration options, including a JSON Schema.""" type: Required[Literal["json_schema"]] - """The type of response format being defined: `json_schema`""" + """The type of response format being defined. Always `json_schema`.""" diff --git a/src/openai/types/shared_params/response_format_text.py b/src/openai/types/shared_params/response_format_text.py index 5bec7fc503..c3ef2b0816 100644 --- a/src/openai/types/shared_params/response_format_text.py +++ b/src/openai/types/shared_params/response_format_text.py @@ -9,4 +9,4 @@ class ResponseFormatText(TypedDict, total=False): type: Required[Literal["text"]] - """The type of response format being defined: `text`""" + """The type of response format being defined. Always `text`.""" diff --git a/src/openai/types/beta/static_file_chunking_strategy.py b/src/openai/types/static_file_chunking_strategy.py similarity index 94% rename from src/openai/types/beta/static_file_chunking_strategy.py rename to src/openai/types/static_file_chunking_strategy.py index 6080093517..2813bc6630 100644 --- a/src/openai/types/beta/static_file_chunking_strategy.py +++ b/src/openai/types/static_file_chunking_strategy.py @@ -1,7 +1,7 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from ..._models import BaseModel +from .._models import BaseModel __all__ = ["StaticFileChunkingStrategy"] diff --git a/src/openai/types/beta/static_file_chunking_strategy_object.py b/src/openai/types/static_file_chunking_strategy_object.py similarity index 92% rename from src/openai/types/beta/static_file_chunking_strategy_object.py rename to src/openai/types/static_file_chunking_strategy_object.py index 896c4b8320..2a95dce5b3 100644 --- a/src/openai/types/beta/static_file_chunking_strategy_object.py +++ b/src/openai/types/static_file_chunking_strategy_object.py @@ -2,7 +2,7 @@ from typing_extensions import Literal -from ..._models import BaseModel +from .._models import BaseModel from .static_file_chunking_strategy import StaticFileChunkingStrategy __all__ = ["StaticFileChunkingStrategyObject"] diff --git a/src/openai/types/beta/static_file_chunking_strategy_object_param.py b/src/openai/types/static_file_chunking_strategy_object_param.py similarity index 100% rename from src/openai/types/beta/static_file_chunking_strategy_object_param.py rename to src/openai/types/static_file_chunking_strategy_object_param.py diff --git a/src/openai/types/beta/static_file_chunking_strategy_param.py b/src/openai/types/static_file_chunking_strategy_param.py similarity index 100% rename from src/openai/types/beta/static_file_chunking_strategy_param.py rename to src/openai/types/static_file_chunking_strategy_param.py diff --git a/src/openai/types/beta/vector_store.py b/src/openai/types/vector_store.py similarity index 97% rename from src/openai/types/beta/vector_store.py rename to src/openai/types/vector_store.py index b947dfb79d..2473a442d2 100644 --- a/src/openai/types/beta/vector_store.py +++ b/src/openai/types/vector_store.py @@ -3,8 +3,8 @@ from typing import Optional from typing_extensions import Literal -from ..._models import BaseModel -from ..shared.metadata import Metadata +from .._models import BaseModel +from .shared.metadata import Metadata __all__ = ["VectorStore", "FileCounts", "ExpiresAfter"] diff --git a/src/openai/types/beta/vector_store_create_params.py b/src/openai/types/vector_store_create_params.py similarity index 97% rename from src/openai/types/beta/vector_store_create_params.py rename to src/openai/types/vector_store_create_params.py index faca6d9000..365d0936b1 100644 --- a/src/openai/types/beta/vector_store_create_params.py +++ b/src/openai/types/vector_store_create_params.py @@ -5,7 +5,7 @@ from typing import List, Optional from typing_extensions import Literal, Required, TypedDict -from ..shared_params.metadata import Metadata +from .shared_params.metadata import Metadata from .file_chunking_strategy_param import FileChunkingStrategyParam __all__ = ["VectorStoreCreateParams", "ExpiresAfter"] diff --git a/src/openai/types/beta/vector_store_deleted.py b/src/openai/types/vector_store_deleted.py similarity index 89% rename from src/openai/types/beta/vector_store_deleted.py rename to src/openai/types/vector_store_deleted.py index 21ccda1db5..dfac9ce8bd 100644 --- a/src/openai/types/beta/vector_store_deleted.py +++ b/src/openai/types/vector_store_deleted.py @@ -2,7 +2,7 @@ from typing_extensions import Literal -from ..._models import BaseModel +from .._models import BaseModel __all__ = ["VectorStoreDeleted"] diff --git a/src/openai/types/beta/vector_store_list_params.py b/src/openai/types/vector_store_list_params.py similarity index 100% rename from src/openai/types/beta/vector_store_list_params.py rename to src/openai/types/vector_store_list_params.py diff --git a/src/openai/types/vector_store_search_params.py b/src/openai/types/vector_store_search_params.py new file mode 100644 index 0000000000..17573d0f61 --- /dev/null +++ b/src/openai/types/vector_store_search_params.py @@ -0,0 +1,40 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .shared_params.compound_filter import CompoundFilter +from .shared_params.comparison_filter import ComparisonFilter + +__all__ = ["VectorStoreSearchParams", "Filters", "RankingOptions"] + + +class VectorStoreSearchParams(TypedDict, total=False): + query: Required[Union[str, List[str]]] + """A query string for a search""" + + filters: Filters + """A filter to apply based on file attributes.""" + + max_num_results: int + """The maximum number of results to return. + + This number should be between 1 and 50 inclusive. + """ + + ranking_options: RankingOptions + """Ranking options for search.""" + + rewrite_query: bool + """Whether to rewrite the natural language query for vector search.""" + + +Filters: TypeAlias = Union[ComparisonFilter, CompoundFilter] + + +class RankingOptions(TypedDict, total=False): + ranker: Literal["auto", "default-2024-11-15"] + + score_threshold: float diff --git a/src/openai/types/vector_store_search_response.py b/src/openai/types/vector_store_search_response.py new file mode 100644 index 0000000000..d78b71bfba --- /dev/null +++ b/src/openai/types/vector_store_search_response.py @@ -0,0 +1,39 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["VectorStoreSearchResponse", "Content"] + + +class Content(BaseModel): + text: str + """The text content returned from search.""" + + type: Literal["text"] + """The type of content.""" + + +class VectorStoreSearchResponse(BaseModel): + attributes: Optional[Dict[str, Union[str, float, bool]]] = None + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. Keys are + strings with a maximum length of 64 characters. Values are strings with a + maximum length of 512 characters, booleans, or numbers. + """ + + content: List[Content] + """Content chunks from the file.""" + + file_id: str + """The ID of the vector store file.""" + + filename: str + """The name of the vector store file.""" + + score: float + """The similarity score for the result.""" diff --git a/src/openai/types/beta/vector_store_update_params.py b/src/openai/types/vector_store_update_params.py similarity index 96% rename from src/openai/types/beta/vector_store_update_params.py rename to src/openai/types/vector_store_update_params.py index e91b3ba5ad..4f6ac63963 100644 --- a/src/openai/types/beta/vector_store_update_params.py +++ b/src/openai/types/vector_store_update_params.py @@ -5,7 +5,7 @@ from typing import Optional from typing_extensions import Literal, Required, TypedDict -from ..shared_params.metadata import Metadata +from .shared_params.metadata import Metadata __all__ = ["VectorStoreUpdateParams", "ExpiresAfter"] diff --git a/src/openai/types/beta/vector_stores/__init__.py b/src/openai/types/vector_stores/__init__.py similarity index 82% rename from src/openai/types/beta/vector_stores/__init__.py rename to src/openai/types/vector_stores/__init__.py index ff05dd63d8..96ce301481 100644 --- a/src/openai/types/beta/vector_stores/__init__.py +++ b/src/openai/types/vector_stores/__init__.py @@ -5,6 +5,8 @@ from .file_list_params import FileListParams as FileListParams from .vector_store_file import VectorStoreFile as VectorStoreFile from .file_create_params import FileCreateParams as FileCreateParams +from .file_update_params import FileUpdateParams as FileUpdateParams +from .file_content_response import FileContentResponse as FileContentResponse from .vector_store_file_batch import VectorStoreFileBatch as VectorStoreFileBatch from .file_batch_create_params import FileBatchCreateParams as FileBatchCreateParams from .vector_store_file_deleted import VectorStoreFileDeleted as VectorStoreFileDeleted diff --git a/src/openai/types/beta/vector_stores/file_batch_create_params.py b/src/openai/types/vector_stores/file_batch_create_params.py similarity index 61% rename from src/openai/types/beta/vector_stores/file_batch_create_params.py rename to src/openai/types/vector_stores/file_batch_create_params.py index e42ea99cd1..1a470f757a 100644 --- a/src/openai/types/beta/vector_stores/file_batch_create_params.py +++ b/src/openai/types/vector_stores/file_batch_create_params.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import List +from typing import Dict, List, Union, Optional from typing_extensions import Required, TypedDict from ..file_chunking_strategy_param import FileChunkingStrategyParam @@ -18,6 +18,15 @@ class FileBatchCreateParams(TypedDict, total=False): files. """ + attributes: Optional[Dict[str, Union[str, float, bool]]] + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. Keys are + strings with a maximum length of 64 characters. Values are strings with a + maximum length of 512 characters, booleans, or numbers. + """ + chunking_strategy: FileChunkingStrategyParam """The chunking strategy used to chunk the file(s). diff --git a/src/openai/types/beta/vector_stores/file_batch_list_files_params.py b/src/openai/types/vector_stores/file_batch_list_files_params.py similarity index 100% rename from src/openai/types/beta/vector_stores/file_batch_list_files_params.py rename to src/openai/types/vector_stores/file_batch_list_files_params.py diff --git a/src/openai/types/vector_stores/file_content_response.py b/src/openai/types/vector_stores/file_content_response.py new file mode 100644 index 0000000000..32db2f2ce9 --- /dev/null +++ b/src/openai/types/vector_stores/file_content_response.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["FileContentResponse"] + + +class FileContentResponse(BaseModel): + text: Optional[str] = None + """The text content""" + + type: Optional[str] = None + """The content type (currently only `"text"`)""" diff --git a/src/openai/types/beta/vector_stores/file_create_params.py b/src/openai/types/vector_stores/file_create_params.py similarity index 60% rename from src/openai/types/beta/vector_stores/file_create_params.py rename to src/openai/types/vector_stores/file_create_params.py index d074d766e6..5b8989251a 100644 --- a/src/openai/types/beta/vector_stores/file_create_params.py +++ b/src/openai/types/vector_stores/file_create_params.py @@ -2,6 +2,7 @@ from __future__ import annotations +from typing import Dict, Union, Optional from typing_extensions import Required, TypedDict from ..file_chunking_strategy_param import FileChunkingStrategyParam @@ -17,6 +18,15 @@ class FileCreateParams(TypedDict, total=False): files. """ + attributes: Optional[Dict[str, Union[str, float, bool]]] + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. Keys are + strings with a maximum length of 64 characters. Values are strings with a + maximum length of 512 characters, booleans, or numbers. + """ + chunking_strategy: FileChunkingStrategyParam """The chunking strategy used to chunk the file(s). diff --git a/src/openai/types/beta/vector_stores/file_list_params.py b/src/openai/types/vector_stores/file_list_params.py similarity index 100% rename from src/openai/types/beta/vector_stores/file_list_params.py rename to src/openai/types/vector_stores/file_list_params.py diff --git a/src/openai/types/vector_stores/file_update_params.py b/src/openai/types/vector_stores/file_update_params.py new file mode 100644 index 0000000000..ebf540d046 --- /dev/null +++ b/src/openai/types/vector_stores/file_update_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Required, TypedDict + +__all__ = ["FileUpdateParams"] + + +class FileUpdateParams(TypedDict, total=False): + vector_store_id: Required[str] + + attributes: Required[Optional[Dict[str, Union[str, float, bool]]]] + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. Keys are + strings with a maximum length of 64 characters. Values are strings with a + maximum length of 512 characters, booleans, or numbers. + """ diff --git a/src/openai/types/beta/vector_stores/vector_store_file.py b/src/openai/types/vector_stores/vector_store_file.py similarity index 76% rename from src/openai/types/beta/vector_stores/vector_store_file.py rename to src/openai/types/vector_stores/vector_store_file.py index e4608e159c..b59a61dfb0 100644 --- a/src/openai/types/beta/vector_stores/vector_store_file.py +++ b/src/openai/types/vector_stores/vector_store_file.py @@ -1,9 +1,9 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional +from typing import Dict, Union, Optional from typing_extensions import Literal -from ...._models import BaseModel +from ..._models import BaseModel from ..file_chunking_strategy import FileChunkingStrategy __all__ = ["VectorStoreFile", "LastError"] @@ -54,5 +54,14 @@ class VectorStoreFile(BaseModel): attached to. """ + attributes: Optional[Dict[str, Union[str, float, bool]]] = None + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. Keys are + strings with a maximum length of 64 characters. Values are strings with a + maximum length of 512 characters, booleans, or numbers. + """ + chunking_strategy: Optional[FileChunkingStrategy] = None """The strategy used to chunk the file.""" diff --git a/src/openai/types/beta/vector_stores/vector_store_file_batch.py b/src/openai/types/vector_stores/vector_store_file_batch.py similarity index 97% rename from src/openai/types/beta/vector_stores/vector_store_file_batch.py rename to src/openai/types/vector_stores/vector_store_file_batch.py index df130a58de..57dbfbd809 100644 --- a/src/openai/types/beta/vector_stores/vector_store_file_batch.py +++ b/src/openai/types/vector_stores/vector_store_file_batch.py @@ -2,7 +2,7 @@ from typing_extensions import Literal -from ...._models import BaseModel +from ..._models import BaseModel __all__ = ["VectorStoreFileBatch", "FileCounts"] diff --git a/src/openai/types/beta/vector_stores/vector_store_file_deleted.py b/src/openai/types/vector_stores/vector_store_file_deleted.py similarity index 89% rename from src/openai/types/beta/vector_stores/vector_store_file_deleted.py rename to src/openai/types/vector_stores/vector_store_file_deleted.py index ae37f84364..5c856f26cd 100644 --- a/src/openai/types/beta/vector_stores/vector_store_file_deleted.py +++ b/src/openai/types/vector_stores/vector_store_file_deleted.py @@ -2,7 +2,7 @@ from typing_extensions import Literal -from ...._models import BaseModel +from ..._models import BaseModel __all__ = ["VectorStoreFileDeleted"] diff --git a/tests/api_resources/beta/vector_stores/test_files.py b/tests/api_resources/beta/vector_stores/test_files.py deleted file mode 100644 index 36622e699b..0000000000 --- a/tests/api_resources/beta/vector_stores/test_files.py +++ /dev/null @@ -1,420 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from openai import OpenAI, AsyncOpenAI -from tests.utils import assert_matches_type -from openai.pagination import SyncCursorPage, AsyncCursorPage -from openai.types.beta.vector_stores import ( - VectorStoreFile, - VectorStoreFileDeleted, -) - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestFiles: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: OpenAI) -> None: - file = client.beta.vector_stores.files.create( - "vs_abc123", - file_id="string", - ) - assert_matches_type(VectorStoreFile, file, path=["response"]) - - @parametrize - def test_method_create_with_all_params(self, client: OpenAI) -> None: - file = client.beta.vector_stores.files.create( - "vs_abc123", - file_id="string", - chunking_strategy={"type": "auto"}, - ) - assert_matches_type(VectorStoreFile, file, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: OpenAI) -> None: - response = client.beta.vector_stores.files.with_raw_response.create( - "vs_abc123", - file_id="string", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - file = response.parse() - assert_matches_type(VectorStoreFile, file, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: OpenAI) -> None: - with client.beta.vector_stores.files.with_streaming_response.create( - "vs_abc123", - file_id="string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - file = response.parse() - assert_matches_type(VectorStoreFile, file, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_create(self, client: OpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): - client.beta.vector_stores.files.with_raw_response.create( - "", - file_id="string", - ) - - @parametrize - def test_method_retrieve(self, client: OpenAI) -> None: - file = client.beta.vector_stores.files.retrieve( - "file-abc123", - vector_store_id="vs_abc123", - ) - assert_matches_type(VectorStoreFile, file, path=["response"]) - - @parametrize - def test_raw_response_retrieve(self, client: OpenAI) -> None: - response = client.beta.vector_stores.files.with_raw_response.retrieve( - "file-abc123", - vector_store_id="vs_abc123", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - file = response.parse() - assert_matches_type(VectorStoreFile, file, path=["response"]) - - @parametrize - def test_streaming_response_retrieve(self, client: OpenAI) -> None: - with client.beta.vector_stores.files.with_streaming_response.retrieve( - "file-abc123", - vector_store_id="vs_abc123", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - file = response.parse() - assert_matches_type(VectorStoreFile, file, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_retrieve(self, client: OpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): - client.beta.vector_stores.files.with_raw_response.retrieve( - "file-abc123", - vector_store_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_id` but received ''"): - client.beta.vector_stores.files.with_raw_response.retrieve( - "", - vector_store_id="vs_abc123", - ) - - @parametrize - def test_method_list(self, client: OpenAI) -> None: - file = client.beta.vector_stores.files.list( - "string", - ) - assert_matches_type(SyncCursorPage[VectorStoreFile], file, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: OpenAI) -> None: - file = client.beta.vector_stores.files.list( - "string", - after="string", - before="string", - filter="in_progress", - limit=0, - order="asc", - ) - assert_matches_type(SyncCursorPage[VectorStoreFile], file, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: OpenAI) -> None: - response = client.beta.vector_stores.files.with_raw_response.list( - "string", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - file = response.parse() - assert_matches_type(SyncCursorPage[VectorStoreFile], file, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: OpenAI) -> None: - with client.beta.vector_stores.files.with_streaming_response.list( - "string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - file = response.parse() - assert_matches_type(SyncCursorPage[VectorStoreFile], file, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_list(self, client: OpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): - client.beta.vector_stores.files.with_raw_response.list( - "", - ) - - @parametrize - def test_method_delete(self, client: OpenAI) -> None: - file = client.beta.vector_stores.files.delete( - "string", - vector_store_id="string", - ) - assert_matches_type(VectorStoreFileDeleted, file, path=["response"]) - - @parametrize - def test_raw_response_delete(self, client: OpenAI) -> None: - response = client.beta.vector_stores.files.with_raw_response.delete( - "string", - vector_store_id="string", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - file = response.parse() - assert_matches_type(VectorStoreFileDeleted, file, path=["response"]) - - @parametrize - def test_streaming_response_delete(self, client: OpenAI) -> None: - with client.beta.vector_stores.files.with_streaming_response.delete( - "string", - vector_store_id="string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - file = response.parse() - assert_matches_type(VectorStoreFileDeleted, file, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_delete(self, client: OpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): - client.beta.vector_stores.files.with_raw_response.delete( - "string", - vector_store_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_id` but received ''"): - client.beta.vector_stores.files.with_raw_response.delete( - "", - vector_store_id="string", - ) - - -class TestAsyncFiles: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - async def test_method_create(self, async_client: AsyncOpenAI) -> None: - file = await async_client.beta.vector_stores.files.create( - "vs_abc123", - file_id="string", - ) - assert_matches_type(VectorStoreFile, file, path=["response"]) - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: - file = await async_client.beta.vector_stores.files.create( - "vs_abc123", - file_id="string", - chunking_strategy={"type": "auto"}, - ) - assert_matches_type(VectorStoreFile, file, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.vector_stores.files.with_raw_response.create( - "vs_abc123", - file_id="string", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - file = response.parse() - assert_matches_type(VectorStoreFile, file, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.vector_stores.files.with_streaming_response.create( - "vs_abc123", - file_id="string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - file = await response.parse() - assert_matches_type(VectorStoreFile, file, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_create(self, async_client: AsyncOpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): - await async_client.beta.vector_stores.files.with_raw_response.create( - "", - file_id="string", - ) - - @parametrize - async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: - file = await async_client.beta.vector_stores.files.retrieve( - "file-abc123", - vector_store_id="vs_abc123", - ) - assert_matches_type(VectorStoreFile, file, path=["response"]) - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.vector_stores.files.with_raw_response.retrieve( - "file-abc123", - vector_store_id="vs_abc123", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - file = response.parse() - assert_matches_type(VectorStoreFile, file, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.vector_stores.files.with_streaming_response.retrieve( - "file-abc123", - vector_store_id="vs_abc123", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - file = await response.parse() - assert_matches_type(VectorStoreFile, file, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): - await async_client.beta.vector_stores.files.with_raw_response.retrieve( - "file-abc123", - vector_store_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_id` but received ''"): - await async_client.beta.vector_stores.files.with_raw_response.retrieve( - "", - vector_store_id="vs_abc123", - ) - - @parametrize - async def test_method_list(self, async_client: AsyncOpenAI) -> None: - file = await async_client.beta.vector_stores.files.list( - "string", - ) - assert_matches_type(AsyncCursorPage[VectorStoreFile], file, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: - file = await async_client.beta.vector_stores.files.list( - "string", - after="string", - before="string", - filter="in_progress", - limit=0, - order="asc", - ) - assert_matches_type(AsyncCursorPage[VectorStoreFile], file, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.vector_stores.files.with_raw_response.list( - "string", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - file = response.parse() - assert_matches_type(AsyncCursorPage[VectorStoreFile], file, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.vector_stores.files.with_streaming_response.list( - "string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - file = await response.parse() - assert_matches_type(AsyncCursorPage[VectorStoreFile], file, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_list(self, async_client: AsyncOpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): - await async_client.beta.vector_stores.files.with_raw_response.list( - "", - ) - - @parametrize - async def test_method_delete(self, async_client: AsyncOpenAI) -> None: - file = await async_client.beta.vector_stores.files.delete( - "string", - vector_store_id="string", - ) - assert_matches_type(VectorStoreFileDeleted, file, path=["response"]) - - @parametrize - async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.vector_stores.files.with_raw_response.delete( - "string", - vector_store_id="string", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - file = response.parse() - assert_matches_type(VectorStoreFileDeleted, file, path=["response"]) - - @parametrize - async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.vector_stores.files.with_streaming_response.delete( - "string", - vector_store_id="string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - file = await response.parse() - assert_matches_type(VectorStoreFileDeleted, file, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): - await async_client.beta.vector_stores.files.with_raw_response.delete( - "string", - vector_store_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_id` but received ''"): - await async_client.beta.vector_stores.files.with_raw_response.delete( - "", - vector_store_id="string", - ) diff --git a/tests/api_resources/chat/test_completions.py b/tests/api_resources/chat/test_completions.py index 48b687a70e..d4ccc494dd 100644 --- a/tests/api_resources/chat/test_completions.py +++ b/tests/api_resources/chat/test_completions.py @@ -74,9 +74,9 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: presence_penalty=-2, reasoning_effort="low", response_format={"type": "text"}, - seed=0, + seed=-9007199254740991, service_tier="auto", - stop="string", + stop="\n", store=True, stream=False, stream_options={"include_usage": True}, @@ -96,6 +96,18 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: top_logprobs=0, top_p=1, user="user-1234", + web_search_options={ + "search_context_size": "low", + "user_location": { + "approximate": { + "city": "city", + "country": "country", + "region": "region", + "timezone": "timezone", + }, + "type": "approximate", + }, + }, ) assert_matches_type(ChatCompletion, completion, path=["response"]) @@ -189,9 +201,9 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: presence_penalty=-2, reasoning_effort="low", response_format={"type": "text"}, - seed=0, + seed=-9007199254740991, service_tier="auto", - stop="string", + stop="\n", store=True, stream_options={"include_usage": True}, temperature=1, @@ -210,6 +222,18 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: top_logprobs=0, top_p=1, user="user-1234", + web_search_options={ + "search_context_size": "low", + "user_location": { + "approximate": { + "city": "city", + "country": "country", + "region": "region", + "timezone": "timezone", + }, + "type": "approximate", + }, + }, ) completion_stream.response.close() @@ -477,9 +501,9 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn presence_penalty=-2, reasoning_effort="low", response_format={"type": "text"}, - seed=0, + seed=-9007199254740991, service_tier="auto", - stop="string", + stop="\n", store=True, stream=False, stream_options={"include_usage": True}, @@ -499,6 +523,18 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn top_logprobs=0, top_p=1, user="user-1234", + web_search_options={ + "search_context_size": "low", + "user_location": { + "approximate": { + "city": "city", + "country": "country", + "region": "region", + "timezone": "timezone", + }, + "type": "approximate", + }, + }, ) assert_matches_type(ChatCompletion, completion, path=["response"]) @@ -592,9 +628,9 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn presence_penalty=-2, reasoning_effort="low", response_format={"type": "text"}, - seed=0, + seed=-9007199254740991, service_tier="auto", - stop="string", + stop="\n", store=True, stream_options={"include_usage": True}, temperature=1, @@ -613,6 +649,18 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn top_logprobs=0, top_p=1, user="user-1234", + web_search_options={ + "search_context_size": "low", + "user_location": { + "approximate": { + "city": "city", + "country": "country", + "region": "region", + "timezone": "timezone", + }, + "type": "approximate", + }, + }, ) await completion_stream.response.aclose() diff --git a/tests/api_resources/beta/vector_stores/__init__.py b/tests/api_resources/responses/__init__.py similarity index 100% rename from tests/api_resources/beta/vector_stores/__init__.py rename to tests/api_resources/responses/__init__.py diff --git a/tests/api_resources/responses/test_input_items.py b/tests/api_resources/responses/test_input_items.py new file mode 100644 index 0000000000..28c5e8ca1f --- /dev/null +++ b/tests/api_resources/responses/test_input_items.py @@ -0,0 +1,121 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.pagination import SyncCursorPage, AsyncCursorPage +from openai.types.responses.response_item_list import Data + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestInputItems: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + input_item = client.responses.input_items.list( + response_id="response_id", + ) + assert_matches_type(SyncCursorPage[Data], input_item, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + input_item = client.responses.input_items.list( + response_id="response_id", + after="after", + before="before", + limit=0, + order="asc", + ) + assert_matches_type(SyncCursorPage[Data], input_item, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.responses.input_items.with_raw_response.list( + response_id="response_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + input_item = response.parse() + assert_matches_type(SyncCursorPage[Data], input_item, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.responses.input_items.with_streaming_response.list( + response_id="response_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + input_item = response.parse() + assert_matches_type(SyncCursorPage[Data], input_item, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `response_id` but received ''"): + client.responses.input_items.with_raw_response.list( + response_id="", + ) + + +class TestAsyncInputItems: + parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + input_item = await async_client.responses.input_items.list( + response_id="response_id", + ) + assert_matches_type(AsyncCursorPage[Data], input_item, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + input_item = await async_client.responses.input_items.list( + response_id="response_id", + after="after", + before="before", + limit=0, + order="asc", + ) + assert_matches_type(AsyncCursorPage[Data], input_item, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.responses.input_items.with_raw_response.list( + response_id="response_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + input_item = response.parse() + assert_matches_type(AsyncCursorPage[Data], input_item, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.responses.input_items.with_streaming_response.list( + response_id="response_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + input_item = await response.parse() + assert_matches_type(AsyncCursorPage[Data], input_item, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `response_id` but received ''"): + await async_client.responses.input_items.with_raw_response.list( + response_id="", + ) diff --git a/tests/api_resources/test_responses.py b/tests/api_resources/test_responses.py new file mode 100644 index 0000000000..e45a5becf3 --- /dev/null +++ b/tests/api_resources/test_responses.py @@ -0,0 +1,498 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.types.responses import Response + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestResponses: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create_overload_1(self, client: OpenAI) -> None: + response = client.responses.create( + input="string", + model="gpt-4o", + ) + assert_matches_type(Response, response, path=["response"]) + + @parametrize + def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: + response = client.responses.create( + input="string", + model="gpt-4o", + include=["file_search_call.results"], + instructions="instructions", + max_output_tokens=0, + metadata={"foo": "string"}, + parallel_tool_calls=True, + previous_response_id="previous_response_id", + reasoning={ + "effort": "low", + "generate_summary": "concise", + }, + store=True, + stream=False, + temperature=1, + text={"format": {"type": "text"}}, + tool_choice="none", + tools=[ + { + "type": "file_search", + "vector_store_ids": ["string"], + "filters": { + "key": "key", + "type": "eq", + "value": "string", + }, + "max_num_results": 0, + "ranking_options": { + "ranker": "auto", + "score_threshold": 0, + }, + } + ], + top_p=1, + truncation="auto", + user="user-1234", + ) + assert_matches_type(Response, response, path=["response"]) + + @parametrize + def test_raw_response_create_overload_1(self, client: OpenAI) -> None: + http_response = client.responses.with_raw_response.create( + input="string", + model="gpt-4o", + ) + + assert http_response.is_closed is True + assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" + response = http_response.parse() + assert_matches_type(Response, response, path=["response"]) + + @parametrize + def test_streaming_response_create_overload_1(self, client: OpenAI) -> None: + with client.responses.with_streaming_response.create( + input="string", + model="gpt-4o", + ) as http_response: + assert not http_response.is_closed + assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" + + response = http_response.parse() + assert_matches_type(Response, response, path=["response"]) + + assert cast(Any, http_response.is_closed) is True + + @parametrize + def test_method_create_overload_2(self, client: OpenAI) -> None: + response_stream = client.responses.create( + input="string", + model="gpt-4o", + stream=True, + ) + response_stream.response.close() + + @parametrize + def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: + response_stream = client.responses.create( + input="string", + model="gpt-4o", + stream=True, + include=["file_search_call.results"], + instructions="instructions", + max_output_tokens=0, + metadata={"foo": "string"}, + parallel_tool_calls=True, + previous_response_id="previous_response_id", + reasoning={ + "effort": "low", + "generate_summary": "concise", + }, + store=True, + temperature=1, + text={"format": {"type": "text"}}, + tool_choice="none", + tools=[ + { + "type": "file_search", + "vector_store_ids": ["string"], + "filters": { + "key": "key", + "type": "eq", + "value": "string", + }, + "max_num_results": 0, + "ranking_options": { + "ranker": "auto", + "score_threshold": 0, + }, + } + ], + top_p=1, + truncation="auto", + user="user-1234", + ) + response_stream.response.close() + + @parametrize + def test_raw_response_create_overload_2(self, client: OpenAI) -> None: + response = client.responses.with_raw_response.create( + input="string", + model="gpt-4o", + stream=True, + ) + + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = response.parse() + stream.close() + + @parametrize + def test_streaming_response_create_overload_2(self, client: OpenAI) -> None: + with client.responses.with_streaming_response.create( + input="string", + model="gpt-4o", + stream=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = response.parse() + stream.close() + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + response = client.responses.retrieve( + response_id="resp_677efb5139a88190b512bc3fef8e535d", + ) + assert_matches_type(Response, response, path=["response"]) + + @parametrize + def test_method_retrieve_with_all_params(self, client: OpenAI) -> None: + response = client.responses.retrieve( + response_id="resp_677efb5139a88190b512bc3fef8e535d", + include=["file_search_call.results"], + ) + assert_matches_type(Response, response, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + http_response = client.responses.with_raw_response.retrieve( + response_id="resp_677efb5139a88190b512bc3fef8e535d", + ) + + assert http_response.is_closed is True + assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" + response = http_response.parse() + assert_matches_type(Response, response, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.responses.with_streaming_response.retrieve( + response_id="resp_677efb5139a88190b512bc3fef8e535d", + ) as http_response: + assert not http_response.is_closed + assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" + + response = http_response.parse() + assert_matches_type(Response, response, path=["response"]) + + assert cast(Any, http_response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `response_id` but received ''"): + client.responses.with_raw_response.retrieve( + response_id="", + ) + + @parametrize + def test_method_delete(self, client: OpenAI) -> None: + response = client.responses.delete( + "resp_677efb5139a88190b512bc3fef8e535d", + ) + assert response is None + + @parametrize + def test_raw_response_delete(self, client: OpenAI) -> None: + http_response = client.responses.with_raw_response.delete( + "resp_677efb5139a88190b512bc3fef8e535d", + ) + + assert http_response.is_closed is True + assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" + response = http_response.parse() + assert response is None + + @parametrize + def test_streaming_response_delete(self, client: OpenAI) -> None: + with client.responses.with_streaming_response.delete( + "resp_677efb5139a88190b512bc3fef8e535d", + ) as http_response: + assert not http_response.is_closed + assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" + + response = http_response.parse() + assert response is None + + assert cast(Any, http_response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `response_id` but received ''"): + client.responses.with_raw_response.delete( + "", + ) + + +class TestAsyncResponses: + parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + async def test_method_create_overload_1(self, async_client: AsyncOpenAI) -> None: + response = await async_client.responses.create( + input="string", + model="gpt-4o", + ) + assert_matches_type(Response, response, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_1(self, async_client: AsyncOpenAI) -> None: + response = await async_client.responses.create( + input="string", + model="gpt-4o", + include=["file_search_call.results"], + instructions="instructions", + max_output_tokens=0, + metadata={"foo": "string"}, + parallel_tool_calls=True, + previous_response_id="previous_response_id", + reasoning={ + "effort": "low", + "generate_summary": "concise", + }, + store=True, + stream=False, + temperature=1, + text={"format": {"type": "text"}}, + tool_choice="none", + tools=[ + { + "type": "file_search", + "vector_store_ids": ["string"], + "filters": { + "key": "key", + "type": "eq", + "value": "string", + }, + "max_num_results": 0, + "ranking_options": { + "ranker": "auto", + "score_threshold": 0, + }, + } + ], + top_p=1, + truncation="auto", + user="user-1234", + ) + assert_matches_type(Response, response, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_1(self, async_client: AsyncOpenAI) -> None: + http_response = await async_client.responses.with_raw_response.create( + input="string", + model="gpt-4o", + ) + + assert http_response.is_closed is True + assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" + response = http_response.parse() + assert_matches_type(Response, response, path=["response"]) + + @parametrize + async def test_streaming_response_create_overload_1(self, async_client: AsyncOpenAI) -> None: + async with async_client.responses.with_streaming_response.create( + input="string", + model="gpt-4o", + ) as http_response: + assert not http_response.is_closed + assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" + + response = await http_response.parse() + assert_matches_type(Response, response, path=["response"]) + + assert cast(Any, http_response.is_closed) is True + + @parametrize + async def test_method_create_overload_2(self, async_client: AsyncOpenAI) -> None: + response_stream = await async_client.responses.create( + input="string", + model="gpt-4o", + stream=True, + ) + await response_stream.response.aclose() + + @parametrize + async def test_method_create_with_all_params_overload_2(self, async_client: AsyncOpenAI) -> None: + response_stream = await async_client.responses.create( + input="string", + model="gpt-4o", + stream=True, + include=["file_search_call.results"], + instructions="instructions", + max_output_tokens=0, + metadata={"foo": "string"}, + parallel_tool_calls=True, + previous_response_id="previous_response_id", + reasoning={ + "effort": "low", + "generate_summary": "concise", + }, + store=True, + temperature=1, + text={"format": {"type": "text"}}, + tool_choice="none", + tools=[ + { + "type": "file_search", + "vector_store_ids": ["string"], + "filters": { + "key": "key", + "type": "eq", + "value": "string", + }, + "max_num_results": 0, + "ranking_options": { + "ranker": "auto", + "score_threshold": 0, + }, + } + ], + top_p=1, + truncation="auto", + user="user-1234", + ) + await response_stream.response.aclose() + + @parametrize + async def test_raw_response_create_overload_2(self, async_client: AsyncOpenAI) -> None: + response = await async_client.responses.with_raw_response.create( + input="string", + model="gpt-4o", + stream=True, + ) + + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = response.parse() + await stream.close() + + @parametrize + async def test_streaming_response_create_overload_2(self, async_client: AsyncOpenAI) -> None: + async with async_client.responses.with_streaming_response.create( + input="string", + model="gpt-4o", + stream=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = await response.parse() + await stream.close() + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.responses.retrieve( + response_id="resp_677efb5139a88190b512bc3fef8e535d", + ) + assert_matches_type(Response, response, path=["response"]) + + @parametrize + async def test_method_retrieve_with_all_params(self, async_client: AsyncOpenAI) -> None: + response = await async_client.responses.retrieve( + response_id="resp_677efb5139a88190b512bc3fef8e535d", + include=["file_search_call.results"], + ) + assert_matches_type(Response, response, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + http_response = await async_client.responses.with_raw_response.retrieve( + response_id="resp_677efb5139a88190b512bc3fef8e535d", + ) + + assert http_response.is_closed is True + assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" + response = http_response.parse() + assert_matches_type(Response, response, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.responses.with_streaming_response.retrieve( + response_id="resp_677efb5139a88190b512bc3fef8e535d", + ) as http_response: + assert not http_response.is_closed + assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" + + response = await http_response.parse() + assert_matches_type(Response, response, path=["response"]) + + assert cast(Any, http_response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `response_id` but received ''"): + await async_client.responses.with_raw_response.retrieve( + response_id="", + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncOpenAI) -> None: + response = await async_client.responses.delete( + "resp_677efb5139a88190b512bc3fef8e535d", + ) + assert response is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: + http_response = await async_client.responses.with_raw_response.delete( + "resp_677efb5139a88190b512bc3fef8e535d", + ) + + assert http_response.is_closed is True + assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" + response = http_response.parse() + assert response is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: + async with async_client.responses.with_streaming_response.delete( + "resp_677efb5139a88190b512bc3fef8e535d", + ) as http_response: + assert not http_response.is_closed + assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" + + response = await http_response.parse() + assert response is None + + assert cast(Any, http_response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `response_id` but received ''"): + await async_client.responses.with_raw_response.delete( + "", + ) diff --git a/tests/api_resources/beta/test_vector_stores.py b/tests/api_resources/test_vector_stores.py similarity index 60% rename from tests/api_resources/beta/test_vector_stores.py rename to tests/api_resources/test_vector_stores.py index e13b8c7613..54bb75bc1d 100644 --- a/tests/api_resources/beta/test_vector_stores.py +++ b/tests/api_resources/test_vector_stores.py @@ -9,11 +9,12 @@ from openai import OpenAI, AsyncOpenAI from tests.utils import assert_matches_type -from openai.pagination import SyncCursorPage, AsyncCursorPage -from openai.types.beta import ( +from openai.types import ( VectorStore, VectorStoreDeleted, + VectorStoreSearchResponse, ) +from openai.pagination import SyncPage, AsyncPage, SyncCursorPage, AsyncCursorPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -23,12 +24,12 @@ class TestVectorStores: @parametrize def test_method_create(self, client: OpenAI) -> None: - vector_store = client.beta.vector_stores.create() + vector_store = client.vector_stores.create() assert_matches_type(VectorStore, vector_store, path=["response"]) @parametrize def test_method_create_with_all_params(self, client: OpenAI) -> None: - vector_store = client.beta.vector_stores.create( + vector_store = client.vector_stores.create( chunking_strategy={"type": "auto"}, expires_after={ "anchor": "last_active_at", @@ -42,7 +43,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: @parametrize def test_raw_response_create(self, client: OpenAI) -> None: - response = client.beta.vector_stores.with_raw_response.create() + response = client.vector_stores.with_raw_response.create() assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -51,7 +52,7 @@ def test_raw_response_create(self, client: OpenAI) -> None: @parametrize def test_streaming_response_create(self, client: OpenAI) -> None: - with client.beta.vector_stores.with_streaming_response.create() as response: + with client.vector_stores.with_streaming_response.create() as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -62,15 +63,15 @@ def test_streaming_response_create(self, client: OpenAI) -> None: @parametrize def test_method_retrieve(self, client: OpenAI) -> None: - vector_store = client.beta.vector_stores.retrieve( - "string", + vector_store = client.vector_stores.retrieve( + "vector_store_id", ) assert_matches_type(VectorStore, vector_store, path=["response"]) @parametrize def test_raw_response_retrieve(self, client: OpenAI) -> None: - response = client.beta.vector_stores.with_raw_response.retrieve( - "string", + response = client.vector_stores.with_raw_response.retrieve( + "vector_store_id", ) assert response.is_closed is True @@ -80,8 +81,8 @@ def test_raw_response_retrieve(self, client: OpenAI) -> None: @parametrize def test_streaming_response_retrieve(self, client: OpenAI) -> None: - with client.beta.vector_stores.with_streaming_response.retrieve( - "string", + with client.vector_stores.with_streaming_response.retrieve( + "vector_store_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -94,21 +95,21 @@ def test_streaming_response_retrieve(self, client: OpenAI) -> None: @parametrize def test_path_params_retrieve(self, client: OpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): - client.beta.vector_stores.with_raw_response.retrieve( + client.vector_stores.with_raw_response.retrieve( "", ) @parametrize def test_method_update(self, client: OpenAI) -> None: - vector_store = client.beta.vector_stores.update( - "string", + vector_store = client.vector_stores.update( + vector_store_id="vector_store_id", ) assert_matches_type(VectorStore, vector_store, path=["response"]) @parametrize def test_method_update_with_all_params(self, client: OpenAI) -> None: - vector_store = client.beta.vector_stores.update( - "string", + vector_store = client.vector_stores.update( + vector_store_id="vector_store_id", expires_after={ "anchor": "last_active_at", "days": 1, @@ -120,8 +121,8 @@ def test_method_update_with_all_params(self, client: OpenAI) -> None: @parametrize def test_raw_response_update(self, client: OpenAI) -> None: - response = client.beta.vector_stores.with_raw_response.update( - "string", + response = client.vector_stores.with_raw_response.update( + vector_store_id="vector_store_id", ) assert response.is_closed is True @@ -131,8 +132,8 @@ def test_raw_response_update(self, client: OpenAI) -> None: @parametrize def test_streaming_response_update(self, client: OpenAI) -> None: - with client.beta.vector_stores.with_streaming_response.update( - "string", + with client.vector_stores.with_streaming_response.update( + vector_store_id="vector_store_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -145,20 +146,20 @@ def test_streaming_response_update(self, client: OpenAI) -> None: @parametrize def test_path_params_update(self, client: OpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): - client.beta.vector_stores.with_raw_response.update( - "", + client.vector_stores.with_raw_response.update( + vector_store_id="", ) @parametrize def test_method_list(self, client: OpenAI) -> None: - vector_store = client.beta.vector_stores.list() + vector_store = client.vector_stores.list() assert_matches_type(SyncCursorPage[VectorStore], vector_store, path=["response"]) @parametrize def test_method_list_with_all_params(self, client: OpenAI) -> None: - vector_store = client.beta.vector_stores.list( - after="string", - before="string", + vector_store = client.vector_stores.list( + after="after", + before="before", limit=0, order="asc", ) @@ -166,7 +167,7 @@ def test_method_list_with_all_params(self, client: OpenAI) -> None: @parametrize def test_raw_response_list(self, client: OpenAI) -> None: - response = client.beta.vector_stores.with_raw_response.list() + response = client.vector_stores.with_raw_response.list() assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -175,7 +176,7 @@ def test_raw_response_list(self, client: OpenAI) -> None: @parametrize def test_streaming_response_list(self, client: OpenAI) -> None: - with client.beta.vector_stores.with_streaming_response.list() as response: + with client.vector_stores.with_streaming_response.list() as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -186,15 +187,15 @@ def test_streaming_response_list(self, client: OpenAI) -> None: @parametrize def test_method_delete(self, client: OpenAI) -> None: - vector_store = client.beta.vector_stores.delete( - "string", + vector_store = client.vector_stores.delete( + "vector_store_id", ) assert_matches_type(VectorStoreDeleted, vector_store, path=["response"]) @parametrize def test_raw_response_delete(self, client: OpenAI) -> None: - response = client.beta.vector_stores.with_raw_response.delete( - "string", + response = client.vector_stores.with_raw_response.delete( + "vector_store_id", ) assert response.is_closed is True @@ -204,8 +205,8 @@ def test_raw_response_delete(self, client: OpenAI) -> None: @parametrize def test_streaming_response_delete(self, client: OpenAI) -> None: - with client.beta.vector_stores.with_streaming_response.delete( - "string", + with client.vector_stores.with_streaming_response.delete( + "vector_store_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -218,22 +219,83 @@ def test_streaming_response_delete(self, client: OpenAI) -> None: @parametrize def test_path_params_delete(self, client: OpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): - client.beta.vector_stores.with_raw_response.delete( + client.vector_stores.with_raw_response.delete( "", ) + @parametrize + def test_method_search(self, client: OpenAI) -> None: + vector_store = client.vector_stores.search( + vector_store_id="vs_abc123", + query="string", + ) + assert_matches_type(SyncPage[VectorStoreSearchResponse], vector_store, path=["response"]) + + @parametrize + def test_method_search_with_all_params(self, client: OpenAI) -> None: + vector_store = client.vector_stores.search( + vector_store_id="vs_abc123", + query="string", + filters={ + "key": "key", + "type": "eq", + "value": "string", + }, + max_num_results=1, + ranking_options={ + "ranker": "auto", + "score_threshold": 0, + }, + rewrite_query=True, + ) + assert_matches_type(SyncPage[VectorStoreSearchResponse], vector_store, path=["response"]) + + @parametrize + def test_raw_response_search(self, client: OpenAI) -> None: + response = client.vector_stores.with_raw_response.search( + vector_store_id="vs_abc123", + query="string", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + vector_store = response.parse() + assert_matches_type(SyncPage[VectorStoreSearchResponse], vector_store, path=["response"]) + + @parametrize + def test_streaming_response_search(self, client: OpenAI) -> None: + with client.vector_stores.with_streaming_response.search( + vector_store_id="vs_abc123", + query="string", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + vector_store = response.parse() + assert_matches_type(SyncPage[VectorStoreSearchResponse], vector_store, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_search(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): + client.vector_stores.with_raw_response.search( + vector_store_id="", + query="string", + ) + class TestAsyncVectorStores: parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: - vector_store = await async_client.beta.vector_stores.create() + vector_store = await async_client.vector_stores.create() assert_matches_type(VectorStore, vector_store, path=["response"]) @parametrize async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: - vector_store = await async_client.beta.vector_stores.create( + vector_store = await async_client.vector_stores.create( chunking_strategy={"type": "auto"}, expires_after={ "anchor": "last_active_at", @@ -247,7 +309,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> @parametrize async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.vector_stores.with_raw_response.create() + response = await async_client.vector_stores.with_raw_response.create() assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -256,7 +318,7 @@ async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.vector_stores.with_streaming_response.create() as response: + async with async_client.vector_stores.with_streaming_response.create() as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -267,15 +329,15 @@ async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> Non @parametrize async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: - vector_store = await async_client.beta.vector_stores.retrieve( - "string", + vector_store = await async_client.vector_stores.retrieve( + "vector_store_id", ) assert_matches_type(VectorStore, vector_store, path=["response"]) @parametrize async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.vector_stores.with_raw_response.retrieve( - "string", + response = await async_client.vector_stores.with_raw_response.retrieve( + "vector_store_id", ) assert response.is_closed is True @@ -285,8 +347,8 @@ async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.vector_stores.with_streaming_response.retrieve( - "string", + async with async_client.vector_stores.with_streaming_response.retrieve( + "vector_store_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -299,21 +361,21 @@ async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> N @parametrize async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): - await async_client.beta.vector_stores.with_raw_response.retrieve( + await async_client.vector_stores.with_raw_response.retrieve( "", ) @parametrize async def test_method_update(self, async_client: AsyncOpenAI) -> None: - vector_store = await async_client.beta.vector_stores.update( - "string", + vector_store = await async_client.vector_stores.update( + vector_store_id="vector_store_id", ) assert_matches_type(VectorStore, vector_store, path=["response"]) @parametrize async def test_method_update_with_all_params(self, async_client: AsyncOpenAI) -> None: - vector_store = await async_client.beta.vector_stores.update( - "string", + vector_store = await async_client.vector_stores.update( + vector_store_id="vector_store_id", expires_after={ "anchor": "last_active_at", "days": 1, @@ -325,8 +387,8 @@ async def test_method_update_with_all_params(self, async_client: AsyncOpenAI) -> @parametrize async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.vector_stores.with_raw_response.update( - "string", + response = await async_client.vector_stores.with_raw_response.update( + vector_store_id="vector_store_id", ) assert response.is_closed is True @@ -336,8 +398,8 @@ async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_update(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.vector_stores.with_streaming_response.update( - "string", + async with async_client.vector_stores.with_streaming_response.update( + vector_store_id="vector_store_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -350,20 +412,20 @@ async def test_streaming_response_update(self, async_client: AsyncOpenAI) -> Non @parametrize async def test_path_params_update(self, async_client: AsyncOpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): - await async_client.beta.vector_stores.with_raw_response.update( - "", + await async_client.vector_stores.with_raw_response.update( + vector_store_id="", ) @parametrize async def test_method_list(self, async_client: AsyncOpenAI) -> None: - vector_store = await async_client.beta.vector_stores.list() + vector_store = await async_client.vector_stores.list() assert_matches_type(AsyncCursorPage[VectorStore], vector_store, path=["response"]) @parametrize async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: - vector_store = await async_client.beta.vector_stores.list( - after="string", - before="string", + vector_store = await async_client.vector_stores.list( + after="after", + before="before", limit=0, order="asc", ) @@ -371,7 +433,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> N @parametrize async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.vector_stores.with_raw_response.list() + response = await async_client.vector_stores.with_raw_response.list() assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -380,7 +442,7 @@ async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.vector_stores.with_streaming_response.list() as response: + async with async_client.vector_stores.with_streaming_response.list() as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -391,15 +453,15 @@ async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_method_delete(self, async_client: AsyncOpenAI) -> None: - vector_store = await async_client.beta.vector_stores.delete( - "string", + vector_store = await async_client.vector_stores.delete( + "vector_store_id", ) assert_matches_type(VectorStoreDeleted, vector_store, path=["response"]) @parametrize async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.vector_stores.with_raw_response.delete( - "string", + response = await async_client.vector_stores.with_raw_response.delete( + "vector_store_id", ) assert response.is_closed is True @@ -409,8 +471,8 @@ async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.vector_stores.with_streaming_response.delete( - "string", + async with async_client.vector_stores.with_streaming_response.delete( + "vector_store_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -423,6 +485,67 @@ async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> Non @parametrize async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): - await async_client.beta.vector_stores.with_raw_response.delete( + await async_client.vector_stores.with_raw_response.delete( "", ) + + @parametrize + async def test_method_search(self, async_client: AsyncOpenAI) -> None: + vector_store = await async_client.vector_stores.search( + vector_store_id="vs_abc123", + query="string", + ) + assert_matches_type(AsyncPage[VectorStoreSearchResponse], vector_store, path=["response"]) + + @parametrize + async def test_method_search_with_all_params(self, async_client: AsyncOpenAI) -> None: + vector_store = await async_client.vector_stores.search( + vector_store_id="vs_abc123", + query="string", + filters={ + "key": "key", + "type": "eq", + "value": "string", + }, + max_num_results=1, + ranking_options={ + "ranker": "auto", + "score_threshold": 0, + }, + rewrite_query=True, + ) + assert_matches_type(AsyncPage[VectorStoreSearchResponse], vector_store, path=["response"]) + + @parametrize + async def test_raw_response_search(self, async_client: AsyncOpenAI) -> None: + response = await async_client.vector_stores.with_raw_response.search( + vector_store_id="vs_abc123", + query="string", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + vector_store = response.parse() + assert_matches_type(AsyncPage[VectorStoreSearchResponse], vector_store, path=["response"]) + + @parametrize + async def test_streaming_response_search(self, async_client: AsyncOpenAI) -> None: + async with async_client.vector_stores.with_streaming_response.search( + vector_store_id="vs_abc123", + query="string", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + vector_store = await response.parse() + assert_matches_type(AsyncPage[VectorStoreSearchResponse], vector_store, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_search(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): + await async_client.vector_stores.with_raw_response.search( + vector_store_id="", + query="string", + ) diff --git a/tests/api_resources/vector_stores/__init__.py b/tests/api_resources/vector_stores/__init__.py new file mode 100644 index 0000000000..fd8019a9a1 --- /dev/null +++ b/tests/api_resources/vector_stores/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/beta/vector_stores/test_file_batches.py b/tests/api_resources/vector_stores/test_file_batches.py similarity index 68% rename from tests/api_resources/beta/vector_stores/test_file_batches.py rename to tests/api_resources/vector_stores/test_file_batches.py index 631f2669ad..0587cfc56a 100644 --- a/tests/api_resources/beta/vector_stores/test_file_batches.py +++ b/tests/api_resources/vector_stores/test_file_batches.py @@ -10,7 +10,7 @@ from openai import OpenAI, AsyncOpenAI from tests.utils import assert_matches_type from openai.pagination import SyncCursorPage, AsyncCursorPage -from openai.types.beta.vector_stores import ( +from openai.types.vector_stores import ( VectorStoreFile, VectorStoreFileBatch, ) @@ -23,25 +23,26 @@ class TestFileBatches: @parametrize def test_method_create(self, client: OpenAI) -> None: - file_batch = client.beta.vector_stores.file_batches.create( - "vs_abc123", + file_batch = client.vector_stores.file_batches.create( + vector_store_id="vs_abc123", file_ids=["string"], ) assert_matches_type(VectorStoreFileBatch, file_batch, path=["response"]) @parametrize def test_method_create_with_all_params(self, client: OpenAI) -> None: - file_batch = client.beta.vector_stores.file_batches.create( - "vs_abc123", + file_batch = client.vector_stores.file_batches.create( + vector_store_id="vs_abc123", file_ids=["string"], + attributes={"foo": "string"}, chunking_strategy={"type": "auto"}, ) assert_matches_type(VectorStoreFileBatch, file_batch, path=["response"]) @parametrize def test_raw_response_create(self, client: OpenAI) -> None: - response = client.beta.vector_stores.file_batches.with_raw_response.create( - "vs_abc123", + response = client.vector_stores.file_batches.with_raw_response.create( + vector_store_id="vs_abc123", file_ids=["string"], ) @@ -52,8 +53,8 @@ def test_raw_response_create(self, client: OpenAI) -> None: @parametrize def test_streaming_response_create(self, client: OpenAI) -> None: - with client.beta.vector_stores.file_batches.with_streaming_response.create( - "vs_abc123", + with client.vector_stores.file_batches.with_streaming_response.create( + vector_store_id="vs_abc123", file_ids=["string"], ) as response: assert not response.is_closed @@ -67,23 +68,23 @@ def test_streaming_response_create(self, client: OpenAI) -> None: @parametrize def test_path_params_create(self, client: OpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): - client.beta.vector_stores.file_batches.with_raw_response.create( - "", + client.vector_stores.file_batches.with_raw_response.create( + vector_store_id="", file_ids=["string"], ) @parametrize def test_method_retrieve(self, client: OpenAI) -> None: - file_batch = client.beta.vector_stores.file_batches.retrieve( - "vsfb_abc123", + file_batch = client.vector_stores.file_batches.retrieve( + batch_id="vsfb_abc123", vector_store_id="vs_abc123", ) assert_matches_type(VectorStoreFileBatch, file_batch, path=["response"]) @parametrize def test_raw_response_retrieve(self, client: OpenAI) -> None: - response = client.beta.vector_stores.file_batches.with_raw_response.retrieve( - "vsfb_abc123", + response = client.vector_stores.file_batches.with_raw_response.retrieve( + batch_id="vsfb_abc123", vector_store_id="vs_abc123", ) @@ -94,8 +95,8 @@ def test_raw_response_retrieve(self, client: OpenAI) -> None: @parametrize def test_streaming_response_retrieve(self, client: OpenAI) -> None: - with client.beta.vector_stores.file_batches.with_streaming_response.retrieve( - "vsfb_abc123", + with client.vector_stores.file_batches.with_streaming_response.retrieve( + batch_id="vsfb_abc123", vector_store_id="vs_abc123", ) as response: assert not response.is_closed @@ -109,30 +110,30 @@ def test_streaming_response_retrieve(self, client: OpenAI) -> None: @parametrize def test_path_params_retrieve(self, client: OpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): - client.beta.vector_stores.file_batches.with_raw_response.retrieve( - "vsfb_abc123", + client.vector_stores.file_batches.with_raw_response.retrieve( + batch_id="vsfb_abc123", vector_store_id="", ) with pytest.raises(ValueError, match=r"Expected a non-empty value for `batch_id` but received ''"): - client.beta.vector_stores.file_batches.with_raw_response.retrieve( - "", + client.vector_stores.file_batches.with_raw_response.retrieve( + batch_id="", vector_store_id="vs_abc123", ) @parametrize def test_method_cancel(self, client: OpenAI) -> None: - file_batch = client.beta.vector_stores.file_batches.cancel( - "string", - vector_store_id="string", + file_batch = client.vector_stores.file_batches.cancel( + batch_id="batch_id", + vector_store_id="vector_store_id", ) assert_matches_type(VectorStoreFileBatch, file_batch, path=["response"]) @parametrize def test_raw_response_cancel(self, client: OpenAI) -> None: - response = client.beta.vector_stores.file_batches.with_raw_response.cancel( - "string", - vector_store_id="string", + response = client.vector_stores.file_batches.with_raw_response.cancel( + batch_id="batch_id", + vector_store_id="vector_store_id", ) assert response.is_closed is True @@ -142,9 +143,9 @@ def test_raw_response_cancel(self, client: OpenAI) -> None: @parametrize def test_streaming_response_cancel(self, client: OpenAI) -> None: - with client.beta.vector_stores.file_batches.with_streaming_response.cancel( - "string", - vector_store_id="string", + with client.vector_stores.file_batches.with_streaming_response.cancel( + batch_id="batch_id", + vector_store_id="vector_store_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -157,32 +158,32 @@ def test_streaming_response_cancel(self, client: OpenAI) -> None: @parametrize def test_path_params_cancel(self, client: OpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): - client.beta.vector_stores.file_batches.with_raw_response.cancel( - "string", + client.vector_stores.file_batches.with_raw_response.cancel( + batch_id="batch_id", vector_store_id="", ) with pytest.raises(ValueError, match=r"Expected a non-empty value for `batch_id` but received ''"): - client.beta.vector_stores.file_batches.with_raw_response.cancel( - "", - vector_store_id="string", + client.vector_stores.file_batches.with_raw_response.cancel( + batch_id="", + vector_store_id="vector_store_id", ) @parametrize def test_method_list_files(self, client: OpenAI) -> None: - file_batch = client.beta.vector_stores.file_batches.list_files( - "string", - vector_store_id="string", + file_batch = client.vector_stores.file_batches.list_files( + batch_id="batch_id", + vector_store_id="vector_store_id", ) assert_matches_type(SyncCursorPage[VectorStoreFile], file_batch, path=["response"]) @parametrize def test_method_list_files_with_all_params(self, client: OpenAI) -> None: - file_batch = client.beta.vector_stores.file_batches.list_files( - "string", - vector_store_id="string", - after="string", - before="string", + file_batch = client.vector_stores.file_batches.list_files( + batch_id="batch_id", + vector_store_id="vector_store_id", + after="after", + before="before", filter="in_progress", limit=0, order="asc", @@ -191,9 +192,9 @@ def test_method_list_files_with_all_params(self, client: OpenAI) -> None: @parametrize def test_raw_response_list_files(self, client: OpenAI) -> None: - response = client.beta.vector_stores.file_batches.with_raw_response.list_files( - "string", - vector_store_id="string", + response = client.vector_stores.file_batches.with_raw_response.list_files( + batch_id="batch_id", + vector_store_id="vector_store_id", ) assert response.is_closed is True @@ -203,9 +204,9 @@ def test_raw_response_list_files(self, client: OpenAI) -> None: @parametrize def test_streaming_response_list_files(self, client: OpenAI) -> None: - with client.beta.vector_stores.file_batches.with_streaming_response.list_files( - "string", - vector_store_id="string", + with client.vector_stores.file_batches.with_streaming_response.list_files( + batch_id="batch_id", + vector_store_id="vector_store_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -218,15 +219,15 @@ def test_streaming_response_list_files(self, client: OpenAI) -> None: @parametrize def test_path_params_list_files(self, client: OpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): - client.beta.vector_stores.file_batches.with_raw_response.list_files( - "string", + client.vector_stores.file_batches.with_raw_response.list_files( + batch_id="batch_id", vector_store_id="", ) with pytest.raises(ValueError, match=r"Expected a non-empty value for `batch_id` but received ''"): - client.beta.vector_stores.file_batches.with_raw_response.list_files( - "", - vector_store_id="string", + client.vector_stores.file_batches.with_raw_response.list_files( + batch_id="", + vector_store_id="vector_store_id", ) @@ -235,25 +236,26 @@ class TestAsyncFileBatches: @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: - file_batch = await async_client.beta.vector_stores.file_batches.create( - "vs_abc123", + file_batch = await async_client.vector_stores.file_batches.create( + vector_store_id="vs_abc123", file_ids=["string"], ) assert_matches_type(VectorStoreFileBatch, file_batch, path=["response"]) @parametrize async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: - file_batch = await async_client.beta.vector_stores.file_batches.create( - "vs_abc123", + file_batch = await async_client.vector_stores.file_batches.create( + vector_store_id="vs_abc123", file_ids=["string"], + attributes={"foo": "string"}, chunking_strategy={"type": "auto"}, ) assert_matches_type(VectorStoreFileBatch, file_batch, path=["response"]) @parametrize async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.vector_stores.file_batches.with_raw_response.create( - "vs_abc123", + response = await async_client.vector_stores.file_batches.with_raw_response.create( + vector_store_id="vs_abc123", file_ids=["string"], ) @@ -264,8 +266,8 @@ async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.vector_stores.file_batches.with_streaming_response.create( - "vs_abc123", + async with async_client.vector_stores.file_batches.with_streaming_response.create( + vector_store_id="vs_abc123", file_ids=["string"], ) as response: assert not response.is_closed @@ -279,23 +281,23 @@ async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> Non @parametrize async def test_path_params_create(self, async_client: AsyncOpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): - await async_client.beta.vector_stores.file_batches.with_raw_response.create( - "", + await async_client.vector_stores.file_batches.with_raw_response.create( + vector_store_id="", file_ids=["string"], ) @parametrize async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: - file_batch = await async_client.beta.vector_stores.file_batches.retrieve( - "vsfb_abc123", + file_batch = await async_client.vector_stores.file_batches.retrieve( + batch_id="vsfb_abc123", vector_store_id="vs_abc123", ) assert_matches_type(VectorStoreFileBatch, file_batch, path=["response"]) @parametrize async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.vector_stores.file_batches.with_raw_response.retrieve( - "vsfb_abc123", + response = await async_client.vector_stores.file_batches.with_raw_response.retrieve( + batch_id="vsfb_abc123", vector_store_id="vs_abc123", ) @@ -306,8 +308,8 @@ async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.vector_stores.file_batches.with_streaming_response.retrieve( - "vsfb_abc123", + async with async_client.vector_stores.file_batches.with_streaming_response.retrieve( + batch_id="vsfb_abc123", vector_store_id="vs_abc123", ) as response: assert not response.is_closed @@ -321,30 +323,30 @@ async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> N @parametrize async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): - await async_client.beta.vector_stores.file_batches.with_raw_response.retrieve( - "vsfb_abc123", + await async_client.vector_stores.file_batches.with_raw_response.retrieve( + batch_id="vsfb_abc123", vector_store_id="", ) with pytest.raises(ValueError, match=r"Expected a non-empty value for `batch_id` but received ''"): - await async_client.beta.vector_stores.file_batches.with_raw_response.retrieve( - "", + await async_client.vector_stores.file_batches.with_raw_response.retrieve( + batch_id="", vector_store_id="vs_abc123", ) @parametrize async def test_method_cancel(self, async_client: AsyncOpenAI) -> None: - file_batch = await async_client.beta.vector_stores.file_batches.cancel( - "string", - vector_store_id="string", + file_batch = await async_client.vector_stores.file_batches.cancel( + batch_id="batch_id", + vector_store_id="vector_store_id", ) assert_matches_type(VectorStoreFileBatch, file_batch, path=["response"]) @parametrize async def test_raw_response_cancel(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.vector_stores.file_batches.with_raw_response.cancel( - "string", - vector_store_id="string", + response = await async_client.vector_stores.file_batches.with_raw_response.cancel( + batch_id="batch_id", + vector_store_id="vector_store_id", ) assert response.is_closed is True @@ -354,9 +356,9 @@ async def test_raw_response_cancel(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_cancel(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.vector_stores.file_batches.with_streaming_response.cancel( - "string", - vector_store_id="string", + async with async_client.vector_stores.file_batches.with_streaming_response.cancel( + batch_id="batch_id", + vector_store_id="vector_store_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -369,32 +371,32 @@ async def test_streaming_response_cancel(self, async_client: AsyncOpenAI) -> Non @parametrize async def test_path_params_cancel(self, async_client: AsyncOpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): - await async_client.beta.vector_stores.file_batches.with_raw_response.cancel( - "string", + await async_client.vector_stores.file_batches.with_raw_response.cancel( + batch_id="batch_id", vector_store_id="", ) with pytest.raises(ValueError, match=r"Expected a non-empty value for `batch_id` but received ''"): - await async_client.beta.vector_stores.file_batches.with_raw_response.cancel( - "", - vector_store_id="string", + await async_client.vector_stores.file_batches.with_raw_response.cancel( + batch_id="", + vector_store_id="vector_store_id", ) @parametrize async def test_method_list_files(self, async_client: AsyncOpenAI) -> None: - file_batch = await async_client.beta.vector_stores.file_batches.list_files( - "string", - vector_store_id="string", + file_batch = await async_client.vector_stores.file_batches.list_files( + batch_id="batch_id", + vector_store_id="vector_store_id", ) assert_matches_type(AsyncCursorPage[VectorStoreFile], file_batch, path=["response"]) @parametrize async def test_method_list_files_with_all_params(self, async_client: AsyncOpenAI) -> None: - file_batch = await async_client.beta.vector_stores.file_batches.list_files( - "string", - vector_store_id="string", - after="string", - before="string", + file_batch = await async_client.vector_stores.file_batches.list_files( + batch_id="batch_id", + vector_store_id="vector_store_id", + after="after", + before="before", filter="in_progress", limit=0, order="asc", @@ -403,9 +405,9 @@ async def test_method_list_files_with_all_params(self, async_client: AsyncOpenAI @parametrize async def test_raw_response_list_files(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.vector_stores.file_batches.with_raw_response.list_files( - "string", - vector_store_id="string", + response = await async_client.vector_stores.file_batches.with_raw_response.list_files( + batch_id="batch_id", + vector_store_id="vector_store_id", ) assert response.is_closed is True @@ -415,9 +417,9 @@ async def test_raw_response_list_files(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_list_files(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.vector_stores.file_batches.with_streaming_response.list_files( - "string", - vector_store_id="string", + async with async_client.vector_stores.file_batches.with_streaming_response.list_files( + batch_id="batch_id", + vector_store_id="vector_store_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -430,13 +432,13 @@ async def test_streaming_response_list_files(self, async_client: AsyncOpenAI) -> @parametrize async def test_path_params_list_files(self, async_client: AsyncOpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): - await async_client.beta.vector_stores.file_batches.with_raw_response.list_files( - "string", + await async_client.vector_stores.file_batches.with_raw_response.list_files( + batch_id="batch_id", vector_store_id="", ) with pytest.raises(ValueError, match=r"Expected a non-empty value for `batch_id` but received ''"): - await async_client.beta.vector_stores.file_batches.with_raw_response.list_files( - "", - vector_store_id="string", + await async_client.vector_stores.file_batches.with_raw_response.list_files( + batch_id="", + vector_store_id="vector_store_id", ) diff --git a/tests/api_resources/vector_stores/test_files.py b/tests/api_resources/vector_stores/test_files.py new file mode 100644 index 0000000000..c13442261e --- /dev/null +++ b/tests/api_resources/vector_stores/test_files.py @@ -0,0 +1,625 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.pagination import SyncPage, AsyncPage, SyncCursorPage, AsyncCursorPage +from openai.types.vector_stores import ( + VectorStoreFile, + FileContentResponse, + VectorStoreFileDeleted, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestFiles: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: OpenAI) -> None: + file = client.vector_stores.files.create( + vector_store_id="vs_abc123", + file_id="file_id", + ) + assert_matches_type(VectorStoreFile, file, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: OpenAI) -> None: + file = client.vector_stores.files.create( + vector_store_id="vs_abc123", + file_id="file_id", + attributes={"foo": "string"}, + chunking_strategy={"type": "auto"}, + ) + assert_matches_type(VectorStoreFile, file, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: OpenAI) -> None: + response = client.vector_stores.files.with_raw_response.create( + vector_store_id="vs_abc123", + file_id="file_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file = response.parse() + assert_matches_type(VectorStoreFile, file, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: OpenAI) -> None: + with client.vector_stores.files.with_streaming_response.create( + vector_store_id="vs_abc123", + file_id="file_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file = response.parse() + assert_matches_type(VectorStoreFile, file, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_create(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): + client.vector_stores.files.with_raw_response.create( + vector_store_id="", + file_id="file_id", + ) + + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + file = client.vector_stores.files.retrieve( + file_id="file-abc123", + vector_store_id="vs_abc123", + ) + assert_matches_type(VectorStoreFile, file, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.vector_stores.files.with_raw_response.retrieve( + file_id="file-abc123", + vector_store_id="vs_abc123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file = response.parse() + assert_matches_type(VectorStoreFile, file, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.vector_stores.files.with_streaming_response.retrieve( + file_id="file-abc123", + vector_store_id="vs_abc123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file = response.parse() + assert_matches_type(VectorStoreFile, file, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): + client.vector_stores.files.with_raw_response.retrieve( + file_id="file-abc123", + vector_store_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_id` but received ''"): + client.vector_stores.files.with_raw_response.retrieve( + file_id="", + vector_store_id="vs_abc123", + ) + + @parametrize + def test_method_update(self, client: OpenAI) -> None: + file = client.vector_stores.files.update( + file_id="file-abc123", + vector_store_id="vs_abc123", + attributes={"foo": "string"}, + ) + assert_matches_type(VectorStoreFile, file, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: OpenAI) -> None: + response = client.vector_stores.files.with_raw_response.update( + file_id="file-abc123", + vector_store_id="vs_abc123", + attributes={"foo": "string"}, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file = response.parse() + assert_matches_type(VectorStoreFile, file, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: OpenAI) -> None: + with client.vector_stores.files.with_streaming_response.update( + file_id="file-abc123", + vector_store_id="vs_abc123", + attributes={"foo": "string"}, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file = response.parse() + assert_matches_type(VectorStoreFile, file, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): + client.vector_stores.files.with_raw_response.update( + file_id="file-abc123", + vector_store_id="", + attributes={"foo": "string"}, + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_id` but received ''"): + client.vector_stores.files.with_raw_response.update( + file_id="", + vector_store_id="vs_abc123", + attributes={"foo": "string"}, + ) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + file = client.vector_stores.files.list( + vector_store_id="vector_store_id", + ) + assert_matches_type(SyncCursorPage[VectorStoreFile], file, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + file = client.vector_stores.files.list( + vector_store_id="vector_store_id", + after="after", + before="before", + filter="in_progress", + limit=0, + order="asc", + ) + assert_matches_type(SyncCursorPage[VectorStoreFile], file, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.vector_stores.files.with_raw_response.list( + vector_store_id="vector_store_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file = response.parse() + assert_matches_type(SyncCursorPage[VectorStoreFile], file, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.vector_stores.files.with_streaming_response.list( + vector_store_id="vector_store_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file = response.parse() + assert_matches_type(SyncCursorPage[VectorStoreFile], file, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): + client.vector_stores.files.with_raw_response.list( + vector_store_id="", + ) + + @parametrize + def test_method_delete(self, client: OpenAI) -> None: + file = client.vector_stores.files.delete( + file_id="file_id", + vector_store_id="vector_store_id", + ) + assert_matches_type(VectorStoreFileDeleted, file, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: OpenAI) -> None: + response = client.vector_stores.files.with_raw_response.delete( + file_id="file_id", + vector_store_id="vector_store_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file = response.parse() + assert_matches_type(VectorStoreFileDeleted, file, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: OpenAI) -> None: + with client.vector_stores.files.with_streaming_response.delete( + file_id="file_id", + vector_store_id="vector_store_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file = response.parse() + assert_matches_type(VectorStoreFileDeleted, file, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): + client.vector_stores.files.with_raw_response.delete( + file_id="file_id", + vector_store_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_id` but received ''"): + client.vector_stores.files.with_raw_response.delete( + file_id="", + vector_store_id="vector_store_id", + ) + + @parametrize + def test_method_content(self, client: OpenAI) -> None: + file = client.vector_stores.files.content( + file_id="file-abc123", + vector_store_id="vs_abc123", + ) + assert_matches_type(SyncPage[FileContentResponse], file, path=["response"]) + + @parametrize + def test_raw_response_content(self, client: OpenAI) -> None: + response = client.vector_stores.files.with_raw_response.content( + file_id="file-abc123", + vector_store_id="vs_abc123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file = response.parse() + assert_matches_type(SyncPage[FileContentResponse], file, path=["response"]) + + @parametrize + def test_streaming_response_content(self, client: OpenAI) -> None: + with client.vector_stores.files.with_streaming_response.content( + file_id="file-abc123", + vector_store_id="vs_abc123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file = response.parse() + assert_matches_type(SyncPage[FileContentResponse], file, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_content(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): + client.vector_stores.files.with_raw_response.content( + file_id="file-abc123", + vector_store_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_id` but received ''"): + client.vector_stores.files.with_raw_response.content( + file_id="", + vector_store_id="vs_abc123", + ) + + +class TestAsyncFiles: + parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + async def test_method_create(self, async_client: AsyncOpenAI) -> None: + file = await async_client.vector_stores.files.create( + vector_store_id="vs_abc123", + file_id="file_id", + ) + assert_matches_type(VectorStoreFile, file, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: + file = await async_client.vector_stores.files.create( + vector_store_id="vs_abc123", + file_id="file_id", + attributes={"foo": "string"}, + chunking_strategy={"type": "auto"}, + ) + assert_matches_type(VectorStoreFile, file, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: + response = await async_client.vector_stores.files.with_raw_response.create( + vector_store_id="vs_abc123", + file_id="file_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file = response.parse() + assert_matches_type(VectorStoreFile, file, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: + async with async_client.vector_stores.files.with_streaming_response.create( + vector_store_id="vs_abc123", + file_id="file_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file = await response.parse() + assert_matches_type(VectorStoreFile, file, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): + await async_client.vector_stores.files.with_raw_response.create( + vector_store_id="", + file_id="file_id", + ) + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + file = await async_client.vector_stores.files.retrieve( + file_id="file-abc123", + vector_store_id="vs_abc123", + ) + assert_matches_type(VectorStoreFile, file, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.vector_stores.files.with_raw_response.retrieve( + file_id="file-abc123", + vector_store_id="vs_abc123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file = response.parse() + assert_matches_type(VectorStoreFile, file, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.vector_stores.files.with_streaming_response.retrieve( + file_id="file-abc123", + vector_store_id="vs_abc123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file = await response.parse() + assert_matches_type(VectorStoreFile, file, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): + await async_client.vector_stores.files.with_raw_response.retrieve( + file_id="file-abc123", + vector_store_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_id` but received ''"): + await async_client.vector_stores.files.with_raw_response.retrieve( + file_id="", + vector_store_id="vs_abc123", + ) + + @parametrize + async def test_method_update(self, async_client: AsyncOpenAI) -> None: + file = await async_client.vector_stores.files.update( + file_id="file-abc123", + vector_store_id="vs_abc123", + attributes={"foo": "string"}, + ) + assert_matches_type(VectorStoreFile, file, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: + response = await async_client.vector_stores.files.with_raw_response.update( + file_id="file-abc123", + vector_store_id="vs_abc123", + attributes={"foo": "string"}, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file = response.parse() + assert_matches_type(VectorStoreFile, file, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncOpenAI) -> None: + async with async_client.vector_stores.files.with_streaming_response.update( + file_id="file-abc123", + vector_store_id="vs_abc123", + attributes={"foo": "string"}, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file = await response.parse() + assert_matches_type(VectorStoreFile, file, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): + await async_client.vector_stores.files.with_raw_response.update( + file_id="file-abc123", + vector_store_id="", + attributes={"foo": "string"}, + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_id` but received ''"): + await async_client.vector_stores.files.with_raw_response.update( + file_id="", + vector_store_id="vs_abc123", + attributes={"foo": "string"}, + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + file = await async_client.vector_stores.files.list( + vector_store_id="vector_store_id", + ) + assert_matches_type(AsyncCursorPage[VectorStoreFile], file, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + file = await async_client.vector_stores.files.list( + vector_store_id="vector_store_id", + after="after", + before="before", + filter="in_progress", + limit=0, + order="asc", + ) + assert_matches_type(AsyncCursorPage[VectorStoreFile], file, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.vector_stores.files.with_raw_response.list( + vector_store_id="vector_store_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file = response.parse() + assert_matches_type(AsyncCursorPage[VectorStoreFile], file, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.vector_stores.files.with_streaming_response.list( + vector_store_id="vector_store_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file = await response.parse() + assert_matches_type(AsyncCursorPage[VectorStoreFile], file, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): + await async_client.vector_stores.files.with_raw_response.list( + vector_store_id="", + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncOpenAI) -> None: + file = await async_client.vector_stores.files.delete( + file_id="file_id", + vector_store_id="vector_store_id", + ) + assert_matches_type(VectorStoreFileDeleted, file, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: + response = await async_client.vector_stores.files.with_raw_response.delete( + file_id="file_id", + vector_store_id="vector_store_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file = response.parse() + assert_matches_type(VectorStoreFileDeleted, file, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: + async with async_client.vector_stores.files.with_streaming_response.delete( + file_id="file_id", + vector_store_id="vector_store_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file = await response.parse() + assert_matches_type(VectorStoreFileDeleted, file, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): + await async_client.vector_stores.files.with_raw_response.delete( + file_id="file_id", + vector_store_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_id` but received ''"): + await async_client.vector_stores.files.with_raw_response.delete( + file_id="", + vector_store_id="vector_store_id", + ) + + @parametrize + async def test_method_content(self, async_client: AsyncOpenAI) -> None: + file = await async_client.vector_stores.files.content( + file_id="file-abc123", + vector_store_id="vs_abc123", + ) + assert_matches_type(AsyncPage[FileContentResponse], file, path=["response"]) + + @parametrize + async def test_raw_response_content(self, async_client: AsyncOpenAI) -> None: + response = await async_client.vector_stores.files.with_raw_response.content( + file_id="file-abc123", + vector_store_id="vs_abc123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file = response.parse() + assert_matches_type(AsyncPage[FileContentResponse], file, path=["response"]) + + @parametrize + async def test_streaming_response_content(self, async_client: AsyncOpenAI) -> None: + async with async_client.vector_stores.files.with_streaming_response.content( + file_id="file-abc123", + vector_store_id="vs_abc123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file = await response.parse() + assert_matches_type(AsyncPage[FileContentResponse], file, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_content(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): + await async_client.vector_stores.files.with_raw_response.content( + file_id="file-abc123", + vector_store_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_id` but received ''"): + await async_client.vector_stores.files.with_raw_response.content( + file_id="", + vector_store_id="vs_abc123", + ) diff --git a/tests/lib/chat/test_completions.py b/tests/lib/chat/test_completions.py index 74cee27b93..62fdd34c0a 100644 --- a/tests/lib/chat/test_completions.py +++ b/tests/lib/chat/test_completions.py @@ -58,6 +58,7 @@ def test_parse_nothing(client: OpenAI, respx_mock: MockRouter, monkeypatch: pyte index=0, logprobs=None, message=ParsedChatCompletionMessage[NoneType]( + annotations=None, audio=None, content="I'm unable to provide real-time weather updates. To get the current weather in San Francisco, I recommend checking a reliable weather website or app like the Weather Channel or a local news station.", @@ -126,6 +127,7 @@ class Location(BaseModel): index=0, logprobs=None, message=ParsedChatCompletionMessage[Location]( + annotations=None, audio=None, content='{"city":"San Francisco","temperature":65,"units":"f"}', function_call=None, @@ -195,6 +197,7 @@ class Location(BaseModel): index=0, logprobs=None, message=ParsedChatCompletionMessage[Location]( + annotations=None, audio=None, content='{"city":"San Francisco","temperature":65,"units":"f"}', function_call=None, @@ -266,6 +269,7 @@ class ColorDetection(BaseModel): index=0, logprobs=None, message=ParsedChatCompletionMessage[ColorDetection]( + annotations=None, audio=None, content='{"color":"red","hex_color_code":"#FF0000"}', function_call=None, @@ -315,6 +319,7 @@ class Location(BaseModel): index=0, logprobs=None, message=ParsedChatCompletionMessage[Location]( + annotations=None, audio=None, content='{"city":"San Francisco","temperature":64,"units":"f"}', function_call=None, @@ -329,6 +334,7 @@ class Location(BaseModel): index=1, logprobs=None, message=ParsedChatCompletionMessage[Location]( + annotations=None, audio=None, content='{"city":"San Francisco","temperature":65,"units":"f"}', function_call=None, @@ -343,6 +349,7 @@ class Location(BaseModel): index=2, logprobs=None, message=ParsedChatCompletionMessage[Location]( + annotations=None, audio=None, content='{"city":"San Francisco","temperature":63.0,"units":"f"}', function_call=None, @@ -393,6 +400,7 @@ class CalendarEvent: index=0, logprobs=None, message=ParsedChatCompletionMessage[CalendarEvent]( + annotations=None, audio=None, content='{"name":"Science Fair","date":"Friday","participants":["Alice","Bob"]}', function_call=None, @@ -454,6 +462,7 @@ def test_pydantic_tool_model_all_types(client: OpenAI, respx_mock: MockRouter, m index=0, logprobs=None, message=ParsedChatCompletionMessage[Query]( + annotations=None, audio=None, content=None, function_call=None, @@ -565,6 +574,7 @@ class Location(BaseModel): index=0, logprobs=None, message=ParsedChatCompletionMessage[Location]( + annotations=None, audio=None, content=None, function_call=None, @@ -614,6 +624,7 @@ class GetWeatherArgs(BaseModel): index=0, logprobs=None, message=ParsedChatCompletionMessage[NoneType]( + annotations=None, audio=None, content=None, function_call=None, @@ -686,6 +697,7 @@ class GetStockPrice(BaseModel): index=0, logprobs=None, message=ParsedChatCompletionMessage[NoneType]( + annotations=None, audio=None, content=None, function_call=None, @@ -767,6 +779,7 @@ def test_parse_strict_tools(client: OpenAI, respx_mock: MockRouter, monkeypatch: index=0, logprobs=None, message=ParsedChatCompletionMessage[NoneType]( + annotations=None, audio=None, content=None, function_call=None, @@ -849,6 +862,7 @@ class Location(BaseModel): index=0, logprobs=None, message=ParsedChatCompletionMessage[Location]( + annotations=None, audio=None, content='{"city":"San Francisco","temperature":58,"units":"f"}', function_call=None, @@ -924,6 +938,7 @@ class Location(BaseModel): index=0, logprobs=None, message=ParsedChatCompletionMessage[Location]( + annotations=None, audio=None, content='{"city":"San Francisco","temperature":65,"units":"f"}', function_call=None, diff --git a/tests/lib/chat/test_completions_streaming.py b/tests/lib/chat/test_completions_streaming.py index 71b4173738..5852c5a343 100644 --- a/tests/lib/chat/test_completions_streaming.py +++ b/tests/lib/chat/test_completions_streaming.py @@ -63,6 +63,7 @@ def test_parse_nothing(client: OpenAI, respx_mock: MockRouter, monkeypatch: pyte index=0, logprobs=None, message=ParsedChatCompletionMessage[NoneType]( + annotations=None, audio=None, content="I'm unable to provide real-time weather updates. To get the current weather in San Francisco, I recommend checking a reliable weather website or a weather app.", @@ -141,6 +142,7 @@ def on_event(stream: ChatCompletionStream[Location], event: ChatCompletionStream index=0, logprobs=None, message=ParsedChatCompletionMessage[Location]( + annotations=None, audio=None, content='{"city":"San Francisco","temperature":61,"units":"f"}', function_call=None, @@ -318,6 +320,7 @@ class Location(BaseModel): index=0, logprobs=None, message=ParsedChatCompletionMessage[Location]( + annotations=None, audio=None, content='{"city":"San Francisco","temperature":65,"units":"f"}', function_call=None, @@ -332,6 +335,7 @@ class Location(BaseModel): index=1, logprobs=None, message=ParsedChatCompletionMessage[Location]( + annotations=None, audio=None, content='{"city":"San Francisco","temperature":61,"units":"f"}', function_call=None, @@ -346,6 +350,7 @@ class Location(BaseModel): index=2, logprobs=None, message=ParsedChatCompletionMessage[Location]( + annotations=None, audio=None, content='{"city":"San Francisco","temperature":59,"units":"f"}', function_call=None, @@ -421,6 +426,7 @@ class Location(BaseModel): index=0, logprobs=None, message=ParsedChatCompletionMessage[Location]( + annotations=None, audio=None, content=None, function_call=None, @@ -495,6 +501,7 @@ def test_content_logprobs_events(client: OpenAI, respx_mock: MockRouter, monkeyp refusal=None ), message=ParsedChatCompletionMessage[NoneType]( + annotations=None, audio=None, content='Foo!', function_call=None, @@ -606,6 +613,7 @@ class Location(BaseModel): ] ), message=ParsedChatCompletionMessage[Location]( + annotations=None, audio=None, content=None, function_call=None, @@ -652,6 +660,7 @@ class GetWeatherArgs(BaseModel): index=0, logprobs=None, message=ParsedChatCompletionMessage[object]( + annotations=None, audio=None, content=None, function_call=None, @@ -684,6 +693,7 @@ class GetWeatherArgs(BaseModel): index=0, logprobs=None, message=ParsedChatCompletionMessage[NoneType]( + annotations=None, audio=None, content=None, function_call=None, @@ -755,6 +765,7 @@ class GetStockPrice(BaseModel): index=0, logprobs=None, message=ParsedChatCompletionMessage[object]( + annotations=None, audio=None, content=None, function_call=None, @@ -863,6 +874,7 @@ def test_parse_strict_tools(client: OpenAI, respx_mock: MockRouter, monkeypatch: index=0, logprobs=None, message=ParsedChatCompletionMessage[object]( + annotations=None, audio=None, content=None, function_call=None, @@ -914,6 +926,7 @@ def test_non_pydantic_response_format(client: OpenAI, respx_mock: MockRouter, mo index=0, logprobs=None, message=ParsedChatCompletionMessage[NoneType]( + annotations=None, audio=None, content='\\n {\\n "location": "San Francisco, CA",\\n "weather": {\\n "temperature": "18°C",\\n "condition": "Partly Cloudy",\\n "humidity": "72%",\\n "windSpeed": "15 km/h",\\n "windDirection": "NW"\\n @@ -974,6 +987,7 @@ def test_allows_non_strict_tools_but_no_parsing( index=0, logprobs=None, message=ParsedChatCompletionMessage[NoneType]( + annotations=None, audio=None, content=None, function_call=None, @@ -1033,6 +1047,7 @@ def streamer(client: OpenAI) -> Iterator[ChatCompletionChunk]: index=0, logprobs=None, message=ParsedChatCompletionMessage[NoneType]( + annotations=None, audio=None, content="I'm unable to provide real-time weather updates. To get the current weather in San Francisco, I recommend checking a reliable weather website or a weather app.", From 849ec26310dde6f7c8a6d0cc8a93a067d3facb89 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 11 Mar 2025 16:31:57 +0000 Subject: [PATCH 228/769] release: 1.66.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index b8446e8608..fa1c44bbb5 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.65.5" + ".": "1.66.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index e2bf62a4df..fb576487cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 1.66.0 (2025-03-11) + +Full Changelog: [v1.65.5...v1.66.0](https://github.com/openai/openai-python/compare/v1.65.5...v1.66.0) + +### Features + +* **api:** add /v1/responses and built-in tools ([854df97](https://github.com/openai/openai-python/commit/854df97884736244d46060fd3d5a92916826ec8f)) + + +### Chores + +* export more types ([#2176](https://github.com/openai/openai-python/issues/2176)) ([a730f0e](https://github.com/openai/openai-python/commit/a730f0efedd228f96a49467f17fb19b6a219246c)) + ## 1.65.5 (2025-03-09) Full Changelog: [v1.65.4...v1.65.5](https://github.com/openai/openai-python/compare/v1.65.4...v1.65.5) diff --git a/pyproject.toml b/pyproject.toml index 09e79f5592..f362b5e264 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.65.5" +version = "1.66.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 859b56580d..74f5619299 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.65.5" # x-release-please-version +__version__ = "1.66.0" # x-release-please-version From 5f548eaa2ca330f163f9d4fb035e81eb225633b6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 11 Mar 2025 19:52:46 +0000 Subject: [PATCH 229/769] fix(responses): correct computer use enum value (#2180) --- .stats.yml | 2 +- src/openai/types/responses/computer_tool.py | 2 +- src/openai/types/responses/computer_tool_param.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.stats.yml b/.stats.yml index 455874212c..9c4a2e5367 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 81 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-be834d63e326a82494e819085137f5eb15866f3fc787db1f3afe7168d419e18a.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-9ce5257763fb30c6e0e1ee2bef7e13baf661511e09572207e528d643da8e16b3.yml diff --git a/src/openai/types/responses/computer_tool.py b/src/openai/types/responses/computer_tool.py index f0499cd950..dffb7af7b7 100644 --- a/src/openai/types/responses/computer_tool.py +++ b/src/openai/types/responses/computer_tool.py @@ -17,5 +17,5 @@ class ComputerTool(BaseModel): environment: Literal["mac", "windows", "ubuntu", "browser"] """The type of computer environment to control.""" - type: Literal["computer-preview"] + type: Literal["computer_use_preview"] """The type of the computer use tool. Always `computer_use_preview`.""" diff --git a/src/openai/types/responses/computer_tool_param.py b/src/openai/types/responses/computer_tool_param.py index 685b471378..6b1072ffd2 100644 --- a/src/openai/types/responses/computer_tool_param.py +++ b/src/openai/types/responses/computer_tool_param.py @@ -17,5 +17,5 @@ class ComputerToolParam(TypedDict, total=False): environment: Required[Literal["mac", "windows", "ubuntu", "browser"]] """The type of computer environment to control.""" - type: Required[Literal["computer-preview"]] + type: Required[Literal["computer_use_preview"]] """The type of the computer use tool. Always `computer_use_preview`.""" From 5a1eded551ecd2e10d2508fc47ed1003e6675872 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 11 Mar 2025 19:53:21 +0000 Subject: [PATCH 230/769] release: 1.66.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index fa1c44bbb5..5d08177085 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.66.0" + ".": "1.66.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index fb576487cb..4068372dd6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 1.66.1 (2025-03-11) + +Full Changelog: [v1.66.0...v1.66.1](https://github.com/openai/openai-python/compare/v1.66.0...v1.66.1) + +### Bug Fixes + +* **responses:** correct computer use enum value ([#2180](https://github.com/openai/openai-python/issues/2180)) ([48f4628](https://github.com/openai/openai-python/commit/48f4628c5fb18ddd7d71e8730184f3ac50c4ffea)) + + +### Chores + +* **internal:** temporary commit ([afabec1](https://github.com/openai/openai-python/commit/afabec1b5b18b41ac870970d06e6c2f152ef7bbe)) + ## 1.66.0 (2025-03-11) Full Changelog: [v1.65.5...v1.66.0](https://github.com/openai/openai-python/compare/v1.65.5...v1.66.0) diff --git a/pyproject.toml b/pyproject.toml index f362b5e264..04ba80639b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.66.0" +version = "1.66.1" 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 74f5619299..473c6aba83 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.66.0" # x-release-please-version +__version__ = "1.66.1" # x-release-please-version From 27ef73fd301c0e49d43d62fe7fbd17badd0c986d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 11 Mar 2025 21:44:13 +0000 Subject: [PATCH 231/769] fix(responses): correct reasoning output type (#2181) --- .stats.yml | 2 +- api.md | 1 + src/openai/types/responses/__init__.py | 2 + src/openai/types/responses/parsed_response.py | 4 +- .../responses/response_input_item_param.py | 33 +--------------- .../types/responses/response_input_param.py | 33 +--------------- .../types/responses/response_output_item.py | 39 +++---------------- .../responses/response_reasoning_item.py | 36 +++++++++++++++++ .../response_reasoning_item_param.py | 36 +++++++++++++++++ 9 files changed, 87 insertions(+), 99 deletions(-) create mode 100644 src/openai/types/responses/response_reasoning_item.py create mode 100644 src/openai/types/responses/response_reasoning_item_param.py diff --git a/.stats.yml b/.stats.yml index 9c4a2e5367..edc2aaf89f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 81 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-9ce5257763fb30c6e0e1ee2bef7e13baf661511e09572207e528d643da8e16b3.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-c8579861bc21d4d2155a5b9e8e7d54faee8083730673c4d32cbbe573d7fb4116.yml diff --git a/api.md b/api.md index 6827b88f0b..e760fe69c1 100644 --- a/api.md +++ b/api.md @@ -640,6 +640,7 @@ from openai.types.responses import ( ResponseOutputMessage, ResponseOutputRefusal, ResponseOutputText, + ResponseReasoningItem, ResponseRefusalDeltaEvent, ResponseRefusalDoneEvent, ResponseStatus, diff --git a/src/openai/types/responses/__init__.py b/src/openai/types/responses/__init__.py index 970a167d2c..7c0cf9e3f2 100644 --- a/src/openai/types/responses/__init__.py +++ b/src/openai/types/responses/__init__.py @@ -45,6 +45,7 @@ from .response_input_content import ResponseInputContent as ResponseInputContent from .response_output_message import ResponseOutputMessage as ResponseOutputMessage from .response_output_refusal import ResponseOutputRefusal as ResponseOutputRefusal +from .response_reasoning_item import ResponseReasoningItem as ResponseReasoningItem from .tool_choice_types_param import ToolChoiceTypesParam as ToolChoiceTypesParam from .easy_input_message_param import EasyInputMessageParam as EasyInputMessageParam from .response_completed_event import ResponseCompletedEvent as ResponseCompletedEvent @@ -71,6 +72,7 @@ from .response_refusal_delta_event import ResponseRefusalDeltaEvent as ResponseRefusalDeltaEvent from .response_output_message_param import ResponseOutputMessageParam as ResponseOutputMessageParam from .response_output_refusal_param import ResponseOutputRefusalParam as ResponseOutputRefusalParam +from .response_reasoning_item_param import ResponseReasoningItemParam as ResponseReasoningItemParam from .response_file_search_tool_call import ResponseFileSearchToolCall as ResponseFileSearchToolCall from .response_output_item_done_event import ResponseOutputItemDoneEvent as ResponseOutputItemDoneEvent from .response_content_part_done_event import ResponseContentPartDoneEvent as ResponseContentPartDoneEvent diff --git a/src/openai/types/responses/parsed_response.py b/src/openai/types/responses/parsed_response.py index 3216a71ba9..1263dfd648 100644 --- a/src/openai/types/responses/parsed_response.py +++ b/src/openai/types/responses/parsed_response.py @@ -7,10 +7,10 @@ from .response import Response from ..._models import GenericModel from ..._utils._transform import PropertyInfo -from .response_output_item import Reasoning from .response_output_text import ResponseOutputText from .response_output_message import ResponseOutputMessage from .response_output_refusal import ResponseOutputRefusal +from .response_reasoning_item import ResponseReasoningItem from .response_computer_tool_call import ResponseComputerToolCall from .response_function_tool_call import ResponseFunctionToolCall from .response_function_web_search import ResponseFunctionWebSearch @@ -54,7 +54,7 @@ class ParsedResponseFunctionToolCall(ResponseFunctionToolCall): ResponseFileSearchToolCall, ResponseFunctionWebSearch, ResponseComputerToolCall, - Reasoning, + ResponseReasoningItem, ], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/responses/response_input_item_param.py b/src/openai/types/responses/response_input_item_param.py index c9daaa6a89..32ac13cabb 100644 --- a/src/openai/types/responses/response_input_item_param.py +++ b/src/openai/types/responses/response_input_item_param.py @@ -7,6 +7,7 @@ from .easy_input_message_param import EasyInputMessageParam from .response_output_message_param import ResponseOutputMessageParam +from .response_reasoning_item_param import ResponseReasoningItemParam from .response_computer_tool_call_param import ResponseComputerToolCallParam from .response_function_tool_call_param import ResponseFunctionToolCallParam from .response_function_web_search_param import ResponseFunctionWebSearchParam @@ -20,8 +21,6 @@ "ComputerCallOutputOutput", "ComputerCallOutputAcknowledgedSafetyCheck", "FunctionCallOutput", - "Reasoning", - "ReasoningContent", "ItemReference", ] @@ -123,34 +122,6 @@ class FunctionCallOutput(TypedDict, total=False): """ -class ReasoningContent(TypedDict, total=False): - text: Required[str] - """ - A short summary of the reasoning used by the model when generating the response. - """ - - type: Required[Literal["reasoning_summary"]] - """The type of the object. Always `text`.""" - - -class Reasoning(TypedDict, total=False): - id: Required[str] - """The unique identifier of the reasoning content.""" - - content: Required[Iterable[ReasoningContent]] - """Reasoning text contents.""" - - type: Required[Literal["reasoning"]] - """The type of the object. Always `reasoning`.""" - - status: Literal["in_progress", "completed", "incomplete"] - """The status of the item. - - One of `in_progress`, `completed`, or `incomplete`. Populated when items are - returned via API. - """ - - class ItemReference(TypedDict, total=False): id: Required[str] """The ID of the item to reference.""" @@ -169,6 +140,6 @@ class ItemReference(TypedDict, total=False): ResponseFunctionWebSearchParam, ResponseFunctionToolCallParam, FunctionCallOutput, - Reasoning, + ResponseReasoningItemParam, ItemReference, ] diff --git a/src/openai/types/responses/response_input_param.py b/src/openai/types/responses/response_input_param.py index c81308500d..b942f4868a 100644 --- a/src/openai/types/responses/response_input_param.py +++ b/src/openai/types/responses/response_input_param.py @@ -7,6 +7,7 @@ from .easy_input_message_param import EasyInputMessageParam from .response_output_message_param import ResponseOutputMessageParam +from .response_reasoning_item_param import ResponseReasoningItemParam from .response_computer_tool_call_param import ResponseComputerToolCallParam from .response_function_tool_call_param import ResponseFunctionToolCallParam from .response_function_web_search_param import ResponseFunctionWebSearchParam @@ -21,8 +22,6 @@ "ComputerCallOutputOutput", "ComputerCallOutputAcknowledgedSafetyCheck", "FunctionCallOutput", - "Reasoning", - "ReasoningContent", "ItemReference", ] @@ -124,34 +123,6 @@ class FunctionCallOutput(TypedDict, total=False): """ -class ReasoningContent(TypedDict, total=False): - text: Required[str] - """ - A short summary of the reasoning used by the model when generating the response. - """ - - type: Required[Literal["reasoning_summary"]] - """The type of the object. Always `text`.""" - - -class Reasoning(TypedDict, total=False): - id: Required[str] - """The unique identifier of the reasoning content.""" - - content: Required[Iterable[ReasoningContent]] - """Reasoning text contents.""" - - type: Required[Literal["reasoning"]] - """The type of the object. Always `reasoning`.""" - - status: Literal["in_progress", "completed", "incomplete"] - """The status of the item. - - One of `in_progress`, `completed`, or `incomplete`. Populated when items are - returned via API. - """ - - class ItemReference(TypedDict, total=False): id: Required[str] """The ID of the item to reference.""" @@ -170,7 +141,7 @@ class ItemReference(TypedDict, total=False): ResponseFunctionWebSearchParam, ResponseFunctionToolCallParam, FunctionCallOutput, - Reasoning, + ResponseReasoningItemParam, ItemReference, ] diff --git a/src/openai/types/responses/response_output_item.py b/src/openai/types/responses/response_output_item.py index 45d5cc0094..f1e9693195 100644 --- a/src/openai/types/responses/response_output_item.py +++ b/src/openai/types/responses/response_output_item.py @@ -1,46 +1,17 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias +from typing import Union +from typing_extensions import Annotated, TypeAlias from ..._utils import PropertyInfo -from ..._models import BaseModel from .response_output_message import ResponseOutputMessage +from .response_reasoning_item import ResponseReasoningItem from .response_computer_tool_call import ResponseComputerToolCall from .response_function_tool_call import ResponseFunctionToolCall from .response_function_web_search import ResponseFunctionWebSearch from .response_file_search_tool_call import ResponseFileSearchToolCall -__all__ = ["ResponseOutputItem", "Reasoning", "ReasoningContent"] - - -class ReasoningContent(BaseModel): - text: str - """ - A short summary of the reasoning used by the model when generating the response. - """ - - type: Literal["reasoning_summary"] - """The type of the object. Always `text`.""" - - -class Reasoning(BaseModel): - id: str - """The unique identifier of the reasoning content.""" - - content: List[ReasoningContent] - """Reasoning text contents.""" - - type: Literal["reasoning"] - """The type of the object. Always `reasoning`.""" - - status: Optional[Literal["in_progress", "completed", "incomplete"]] = None - """The status of the item. - - One of `in_progress`, `completed`, or `incomplete`. Populated when items are - returned via API. - """ - +__all__ = ["ResponseOutputItem"] ResponseOutputItem: TypeAlias = Annotated[ Union[ @@ -49,7 +20,7 @@ class Reasoning(BaseModel): ResponseFunctionToolCall, ResponseFunctionWebSearch, ResponseComputerToolCall, - Reasoning, + ResponseReasoningItem, ], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/responses/response_reasoning_item.py b/src/openai/types/responses/response_reasoning_item.py new file mode 100644 index 0000000000..57e5fbfe6d --- /dev/null +++ b/src/openai/types/responses/response_reasoning_item.py @@ -0,0 +1,36 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseReasoningItem", "Summary"] + + +class Summary(BaseModel): + text: str + """ + A short summary of the reasoning used by the model when generating the response. + """ + + type: Literal["summary_text"] + """The type of the object. Always `summary_text`.""" + + +class ResponseReasoningItem(BaseModel): + id: str + """The unique identifier of the reasoning content.""" + + summary: List[Summary] + """Reasoning text contents.""" + + type: Literal["reasoning"] + """The type of the object. Always `reasoning`.""" + + status: Optional[Literal["in_progress", "completed", "incomplete"]] = None + """The status of the item. + + One of `in_progress`, `completed`, or `incomplete`. Populated when items are + returned via API. + """ diff --git a/src/openai/types/responses/response_reasoning_item_param.py b/src/openai/types/responses/response_reasoning_item_param.py new file mode 100644 index 0000000000..adb49d6402 --- /dev/null +++ b/src/openai/types/responses/response_reasoning_item_param.py @@ -0,0 +1,36 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ResponseReasoningItemParam", "Summary"] + + +class Summary(TypedDict, total=False): + text: Required[str] + """ + A short summary of the reasoning used by the model when generating the response. + """ + + type: Required[Literal["summary_text"]] + """The type of the object. Always `summary_text`.""" + + +class ResponseReasoningItemParam(TypedDict, total=False): + id: Required[str] + """The unique identifier of the reasoning content.""" + + summary: Required[Iterable[Summary]] + """Reasoning text contents.""" + + type: Required[Literal["reasoning"]] + """The type of the object. Always `reasoning`.""" + + status: Literal["in_progress", "completed", "incomplete"] + """The status of the item. + + One of `in_progress`, `completed`, or `incomplete`. Populated when items are + returned via API. + """ From 16a10604fbd0d82c1382b84b417a1d6a2d33a7f1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 11 Mar 2025 21:47:29 +0000 Subject: [PATCH 232/769] release: 1.66.2 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 5d08177085..4e427aab32 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.66.1" + ".": "1.66.2" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 4068372dd6..460dbb287e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.66.2 (2025-03-11) + +Full Changelog: [v1.66.1...v1.66.2](https://github.com/openai/openai-python/compare/v1.66.1...v1.66.2) + +### Bug Fixes + +* **responses:** correct reasoning output type ([#2181](https://github.com/openai/openai-python/issues/2181)) ([8cb1129](https://github.com/openai/openai-python/commit/8cb11299acc40c80061af275691cd09a2bf30c65)) + ## 1.66.1 (2025-03-11) Full Changelog: [v1.66.0...v1.66.1](https://github.com/openai/openai-python/compare/v1.66.0...v1.66.1) diff --git a/pyproject.toml b/pyproject.toml index 04ba80639b..a9d46a72b4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.66.1" +version = "1.66.2" 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 473c6aba83..dc6a545c76 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.66.1" # x-release-please-version +__version__ = "1.66.2" # x-release-please-version From 4fb86f6a5efeac33309d87698d3dc397bec4da88 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 12 Mar 2025 19:36:15 +0000 Subject: [PATCH 233/769] fix: update module level client (#2185) --- src/openai/__init__.py | 3 +++ src/openai/_module_client.py | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/src/openai/__init__.py b/src/openai/__init__.py index fe85956a4a..7ce6df0817 100644 --- a/src/openai/__init__.py +++ b/src/openai/__init__.py @@ -356,8 +356,11 @@ def _reset_client() -> None: # type: ignore[reportUnusedFunction] images as images, models as models, batches as batches, + uploads as uploads, + responses as responses, embeddings as embeddings, completions as completions, fine_tuning as fine_tuning, moderations as moderations, + vector_stores as vector_stores, ) diff --git a/src/openai/_module_client.py b/src/openai/_module_client.py index 6f7356eb3c..e7d2657860 100644 --- a/src/openai/_module_client.py +++ b/src/openai/_module_client.py @@ -48,6 +48,18 @@ def __load__(self) -> resources.Batches: return _load_client().batches +class UploadsProxy(LazyProxy[resources.Uploads]): + @override + def __load__(self) -> resources.Uploads: + return _load_client().uploads + + +class ResponsesProxy(LazyProxy[resources.Responses]): + @override + def __load__(self) -> resources.Responses: + return _load_client().responses + + class EmbeddingsProxy(LazyProxy[resources.Embeddings]): @override def __load__(self) -> resources.Embeddings: @@ -72,6 +84,12 @@ def __load__(self) -> resources.FineTuning: return _load_client().fine_tuning +class VectorStoresProxy(LazyProxy[resources.VectorStores]): + @override + def __load__(self) -> resources.VectorStores: + return _load_client().vector_stores + + chat: resources.Chat = ChatProxy().__as_proxied__() beta: resources.Beta = BetaProxy().__as_proxied__() files: resources.Files = FilesProxy().__as_proxied__() @@ -79,7 +97,10 @@ def __load__(self) -> resources.FineTuning: images: resources.Images = ImagesProxy().__as_proxied__() models: resources.Models = ModelsProxy().__as_proxied__() batches: resources.Batches = BatchesProxy().__as_proxied__() +uploads: resources.Uploads = UploadsProxy().__as_proxied__() +responses: resources.Responses = ResponsesProxy().__as_proxied__() embeddings: resources.Embeddings = EmbeddingsProxy().__as_proxied__() completions: resources.Completions = CompletionsProxy().__as_proxied__() moderations: resources.Moderations = ModerationsProxy().__as_proxied__() fine_tuning: resources.FineTuning = FineTuningProxy().__as_proxied__() +vector_stores: resources.VectorStores = VectorStoresProxy().__as_proxied__() From 9dea82fb8cdd06683f9e8033b54cff219789af7f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 12 Mar 2025 19:40:02 +0000 Subject: [PATCH 234/769] release: 1.66.3 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 4e427aab32..6d3d57b7ab 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.66.2" + ".": "1.66.3" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 460dbb287e..e799f6d117 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.66.3 (2025-03-12) + +Full Changelog: [v1.66.2...v1.66.3](https://github.com/openai/openai-python/compare/v1.66.2...v1.66.3) + +### Bug Fixes + +* update module level client ([#2185](https://github.com/openai/openai-python/issues/2185)) ([456f324](https://github.com/openai/openai-python/commit/456f3240a0c33e71521c6b73c32e8adc1b8cd3bc)) + ## 1.66.2 (2025-03-11) Full Changelog: [v1.66.1...v1.66.2](https://github.com/openai/openai-python/compare/v1.66.1...v1.66.2) diff --git a/pyproject.toml b/pyproject.toml index a9d46a72b4..3088eb2fb2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.66.2" +version = "1.66.3" 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 dc6a545c76..6c4a192efc 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.66.2" # x-release-please-version +__version__ = "1.66.3" # x-release-please-version From 11eea35f9557c2e1f4126b722d3e274d8ef3ea7f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 13 Mar 2025 16:48:23 +0000 Subject: [PATCH 235/769] chore(internal): remove extra empty newlines (#2195) --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 3088eb2fb2..2608de2060 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -169,7 +169,6 @@ reportImplicitOverride = true reportImportCycles = false reportPrivateUsage = false - [tool.ruff] line-length = 120 output-format = "grouped" From d664ff22a9958efb7ccc297e280b6562dd14c6ca Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 14 Mar 2025 15:21:04 +0000 Subject: [PATCH 236/769] chore(internal): bump rye to 0.44.0 (#2200) --- .devcontainer/Dockerfile | 2 +- .github/workflows/ci.yml | 6 +++--- .github/workflows/create-releases.yml | 2 +- .github/workflows/publish-pypi.yml | 2 +- requirements-dev.lock | 1 + requirements.lock | 1 + 6 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 55d20255c9..ff261bad78 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -3,7 +3,7 @@ FROM mcr.microsoft.com/vscode/devcontainers/python:0-${VARIANT} USER vscode -RUN curl -sSf https://rye.astral.sh/get | RYE_VERSION="0.35.0" RYE_INSTALL_OPTION="--yes" bash +RUN curl -sSf https://rye.astral.sh/get | RYE_VERSION="0.44.0" RYE_INSTALL_OPTION="--yes" bash ENV PATH=/home/vscode/.rye/shims:$PATH RUN echo "[[ -d .venv ]] && source .venv/bin/activate || export PATH=\$PATH" >> /home/vscode/.bashrc diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d0e0ffe2f3..34dfde36fa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: curl -sSf https://rye.astral.sh/get | bash echo "$HOME/.rye/shims" >> $GITHUB_PATH env: - RYE_VERSION: '0.35.0' + RYE_VERSION: '0.44.0' RYE_INSTALL_OPTION: '--yes' - name: Install dependencies @@ -43,7 +43,7 @@ jobs: curl -sSf https://rye.astral.sh/get | bash echo "$HOME/.rye/shims" >> $GITHUB_PATH env: - RYE_VERSION: '0.35.0' + RYE_VERSION: '0.44.0' RYE_INSTALL_OPTION: '--yes' - name: Bootstrap @@ -64,7 +64,7 @@ jobs: curl -sSf https://rye.astral.sh/get | bash echo "$HOME/.rye/shims" >> $GITHUB_PATH env: - RYE_VERSION: '0.35.0' + RYE_VERSION: '0.44.0' RYE_INSTALL_OPTION: '--yes' - name: Install dependencies run: | diff --git a/.github/workflows/create-releases.yml b/.github/workflows/create-releases.yml index 2a97049033..b3e1c679d4 100644 --- a/.github/workflows/create-releases.yml +++ b/.github/workflows/create-releases.yml @@ -28,7 +28,7 @@ jobs: curl -sSf https://rye.astral.sh/get | bash echo "$HOME/.rye/shims" >> $GITHUB_PATH env: - RYE_VERSION: '0.35.0' + RYE_VERSION: '0.44.0' RYE_INSTALL_OPTION: '--yes' - name: Publish to PyPI diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml index 76d0efca80..32bd6929e2 100644 --- a/.github/workflows/publish-pypi.yml +++ b/.github/workflows/publish-pypi.yml @@ -18,7 +18,7 @@ jobs: curl -sSf https://rye.astral.sh/get | bash echo "$HOME/.rye/shims" >> $GITHUB_PATH env: - RYE_VERSION: '0.35.0' + RYE_VERSION: '0.44.0' RYE_INSTALL_OPTION: '--yes' - name: Publish to PyPI diff --git a/requirements-dev.lock b/requirements-dev.lock index 5599057b66..48e49f926c 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -7,6 +7,7 @@ # all-features: true # with-sources: false # generate-hashes: false +# universal: false -e file:. annotated-types==0.6.0 diff --git a/requirements.lock b/requirements.lock index cbdff94fa3..b935c0ee59 100644 --- a/requirements.lock +++ b/requirements.lock @@ -7,6 +7,7 @@ # all-features: true # with-sources: false # generate-hashes: false +# universal: false -e file:. annotated-types==0.6.0 From b6ba4876bb5004dbd79b00dcf8ea345e141e1674 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 14 Mar 2025 19:21:28 +0000 Subject: [PATCH 237/769] chore(internal): remove CI condition (#2203) --- .github/workflows/ci.yml | 2 -- .github/workflows/create-releases.yml | 39 --------------------------- .github/workflows/publish-pypi.yml | 8 ++++-- .github/workflows/release-doctor.yml | 1 - .stats.yml | 2 +- bin/check-release-environment | 4 --- 6 files changed, 7 insertions(+), 49 deletions(-) delete mode 100644 .github/workflows/create-releases.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 34dfde36fa..06eb10c5f0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,6 @@ jobs: lint: name: lint runs-on: ubuntu-latest - if: github.repository == 'openai/openai-python' steps: - uses: actions/checkout@v4 @@ -33,7 +32,6 @@ jobs: test: name: test runs-on: ubuntu-latest - if: github.repository == 'openai/openai-python' steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/create-releases.yml b/.github/workflows/create-releases.yml deleted file mode 100644 index b3e1c679d4..0000000000 --- a/.github/workflows/create-releases.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: Create releases -on: - schedule: - - cron: '0 5 * * *' # every day at 5am UTC - push: - branches: - - main - -jobs: - release: - name: release - if: github.ref == 'refs/heads/main' && github.repository == 'openai/openai-python' - runs-on: ubuntu-latest - environment: publish - - steps: - - uses: actions/checkout@v4 - - - uses: stainless-api/trigger-release-please@v1 - id: release - with: - repo: ${{ github.event.repository.full_name }} - stainless-api-key: ${{ secrets.STAINLESS_API_KEY }} - - - name: Install Rye - if: ${{ steps.release.outputs.releases_created }} - run: | - curl -sSf https://rye.astral.sh/get | bash - echo "$HOME/.rye/shims" >> $GITHUB_PATH - env: - RYE_VERSION: '0.44.0' - RYE_INSTALL_OPTION: '--yes' - - - name: Publish to PyPI - if: ${{ steps.release.outputs.releases_created }} - run: | - bash ./bin/publish-pypi - env: - PYPI_TOKEN: ${{ secrets.OPENAI_PYPI_TOKEN || secrets.PYPI_TOKEN }} diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml index 32bd6929e2..b395b2f545 100644 --- a/.github/workflows/publish-pypi.yml +++ b/.github/workflows/publish-pypi.yml @@ -1,9 +1,13 @@ -# workflow for re-running publishing to PyPI in case it fails for some reason -# you can run this workflow by navigating to https://www.github.com/openai/openai-python/actions/workflows/publish-pypi.yml +# This workflow is triggered when a GitHub release is created. +# It can also be run manually to re-publish to PyPI in case it failed for some reason. +# You can run this workflow by navigating to https://www.github.com/openai/openai-python/actions/workflows/publish-pypi.yml name: Publish PyPI on: workflow_dispatch: + release: + types: [published] + jobs: publish: name: publish diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml index e078964a6f..445f626d93 100644 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -19,5 +19,4 @@ jobs: run: | bash ./bin/check-release-environment env: - STAINLESS_API_KEY: ${{ secrets.STAINLESS_API_KEY }} PYPI_TOKEN: ${{ secrets.OPENAI_PYPI_TOKEN || secrets.PYPI_TOKEN }} diff --git a/.stats.yml b/.stats.yml index edc2aaf89f..53c73037d5 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 81 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-c8579861bc21d4d2155a5b9e8e7d54faee8083730673c4d32cbbe573d7fb4116.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-c8579861bc21d4d2155a5b9e8e7d54faee8083730673c4d32cbbe573d7fb4116.yml diff --git a/bin/check-release-environment b/bin/check-release-environment index 2cc5ad6352..5471b69edb 100644 --- a/bin/check-release-environment +++ b/bin/check-release-environment @@ -2,10 +2,6 @@ errors=() -if [ -z "${STAINLESS_API_KEY}" ]; then - errors+=("The STAINLESS_API_KEY secret has not been set. Please contact Stainless for an API key & set it in your organization secrets on GitHub.") -fi - if [ -z "${PYPI_TOKEN}" ]; then errors+=("The OPENAI_PYPI_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets.") fi From 1cb138b559fa937440388b5b160fc27561af29f7 Mon Sep 17 00:00:00 2001 From: meorphis Date: Fri, 14 Mar 2025 16:54:21 -0400 Subject: [PATCH 238/769] chore(internal): update release workflows --- .github/workflows/publish-pypi.yml | 8 ++------ .github/workflows/release-doctor.yml | 1 + 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml index b395b2f545..32bd6929e2 100644 --- a/.github/workflows/publish-pypi.yml +++ b/.github/workflows/publish-pypi.yml @@ -1,13 +1,9 @@ -# This workflow is triggered when a GitHub release is created. -# It can also be run manually to re-publish to PyPI in case it failed for some reason. -# You can run this workflow by navigating to https://www.github.com/openai/openai-python/actions/workflows/publish-pypi.yml +# workflow for re-running publishing to PyPI in case it fails for some reason +# you can run this workflow by navigating to https://www.github.com/openai/openai-python/actions/workflows/publish-pypi.yml name: Publish PyPI on: workflow_dispatch: - release: - types: [published] - jobs: publish: name: publish diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml index 445f626d93..e078964a6f 100644 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -19,4 +19,5 @@ jobs: run: | bash ./bin/check-release-environment env: + STAINLESS_API_KEY: ${{ secrets.STAINLESS_API_KEY }} PYPI_TOKEN: ${{ secrets.OPENAI_PYPI_TOKEN || secrets.PYPI_TOKEN }} From eb3d7ae36d2686645e15840ab369255157247dd9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 14 Mar 2025 22:11:11 +0000 Subject: [PATCH 239/769] fix(types): handle more discriminated union shapes (#2206) --- src/openai/_models.py | 7 +++++-- tests/test_models.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/openai/_models.py b/src/openai/_models.py index 92986bfdf5..ff7c1f3392 100644 --- a/src/openai/_models.py +++ b/src/openai/_models.py @@ -66,7 +66,7 @@ from ._constants import RAW_RESPONSE_HEADER if TYPE_CHECKING: - from pydantic_core.core_schema import ModelField, LiteralSchema, ModelFieldsSchema + from pydantic_core.core_schema import ModelField, ModelSchema, LiteralSchema, ModelFieldsSchema __all__ = ["BaseModel", "GenericModel"] @@ -671,15 +671,18 @@ def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, def _extract_field_schema_pv2(model: type[BaseModel], field_name: str) -> ModelField | None: schema = model.__pydantic_core_schema__ + if schema["type"] == "definitions": + schema = schema["schema"] + if schema["type"] != "model": return None + schema = cast("ModelSchema", schema) fields_schema = schema["schema"] if fields_schema["type"] != "model-fields": return None fields_schema = cast("ModelFieldsSchema", fields_schema) - field = fields_schema["fields"].get(field_name) if not field: return None diff --git a/tests/test_models.py b/tests/test_models.py index 30b17e3ac0..b9be1f3ea3 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -854,3 +854,35 @@ class Model(BaseModel): m = construct_type(value={"cls": "foo"}, type_=Model) assert isinstance(m, Model) assert isinstance(m.cls, str) + + +def test_discriminated_union_case() -> None: + class A(BaseModel): + type: Literal["a"] + + data: bool + + class B(BaseModel): + type: Literal["b"] + + data: List[Union[A, object]] + + class ModelA(BaseModel): + type: Literal["modelA"] + + data: int + + class ModelB(BaseModel): + type: Literal["modelB"] + + required: str + + data: Union[A, B] + + # when constructing ModelA | ModelB, value data doesn't match ModelB exactly - missing `required` + m = construct_type( + value={"type": "modelB", "data": {"type": "a", "data": True}}, + type_=cast(Any, Annotated[Union[ModelA, ModelB], PropertyInfo(discriminator="type")]), + ) + + assert isinstance(m, ModelB) From 5647865266af923b2e257ea0b5fc77e590542490 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 17 Mar 2025 13:04:17 +0000 Subject: [PATCH 240/769] fix(ci): ensure pip is always available (#2207) --- bin/publish-pypi | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/publish-pypi b/bin/publish-pypi index 05bfccbb71..ebebf91657 100644 --- a/bin/publish-pypi +++ b/bin/publish-pypi @@ -5,5 +5,6 @@ mkdir -p dist rye build --clean # Patching importlib-metadata version until upstream library version is updated # https://github.com/pypa/twine/issues/977#issuecomment-2189800841 +"$HOME/.rye/self/bin/python3" -m ensurepip "$HOME/.rye/self/bin/python3" -m pip install 'importlib-metadata==7.2.1' rye publish --yes --token=$PYPI_TOKEN From 69919665d26d32c2c729ac7f1dc8db4e0d14d1a4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 17 Mar 2025 15:52:16 +0000 Subject: [PATCH 241/769] fix(ci): remove publishing patch (#2208) --- bin/publish-pypi | 4 ---- pyproject.toml | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/bin/publish-pypi b/bin/publish-pypi index ebebf91657..826054e924 100644 --- a/bin/publish-pypi +++ b/bin/publish-pypi @@ -3,8 +3,4 @@ set -eux mkdir -p dist rye build --clean -# Patching importlib-metadata version until upstream library version is updated -# https://github.com/pypa/twine/issues/977#issuecomment-2189800841 -"$HOME/.rye/self/bin/python3" -m ensurepip -"$HOME/.rye/self/bin/python3" -m pip install 'importlib-metadata==7.2.1' rye publish --yes --token=$PYPI_TOKEN diff --git a/pyproject.toml b/pyproject.toml index 2608de2060..0a9a931f6f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -99,7 +99,7 @@ typecheck = { chain = [ "typecheck:mypy" = "mypy ." [build-system] -requires = ["hatchling", "hatch-fancy-pypi-readme"] +requires = ["hatchling==1.26.3", "hatch-fancy-pypi-readme"] build-backend = "hatchling.build" [tool.hatch.build] From 17d78674d17e74b344f3701eb4ca6f5aa5cf1fc5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 17 Mar 2025 15:52:49 +0000 Subject: [PATCH 242/769] release: 1.66.4 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 18 ++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 6d3d57b7ab..dac37ce406 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.66.3" + ".": "1.66.4" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index e799f6d117..1ed70082c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ # Changelog +## 1.66.4 (2025-03-17) + +Full Changelog: [v1.66.3...v1.66.4](https://github.com/openai/openai-python/compare/v1.66.3...v1.66.4) + +### Bug Fixes + +* **ci:** ensure pip is always available ([#2207](https://github.com/openai/openai-python/issues/2207)) ([3f08e56](https://github.com/openai/openai-python/commit/3f08e56a48a04c2b7f03a4ad63f38228e25810e6)) +* **ci:** remove publishing patch ([#2208](https://github.com/openai/openai-python/issues/2208)) ([dd2dab7](https://github.com/openai/openai-python/commit/dd2dab7faf2a003da3e6af66780bd250be6e7f3f)) +* **types:** handle more discriminated union shapes ([#2206](https://github.com/openai/openai-python/issues/2206)) ([f85a9c6](https://github.com/openai/openai-python/commit/f85a9c633dcb9b64c0eb47d20151894742bbef22)) + + +### Chores + +* **internal:** bump rye to 0.44.0 ([#2200](https://github.com/openai/openai-python/issues/2200)) ([2dd3139](https://github.com/openai/openai-python/commit/2dd3139df6e7fe6307f9847e6527073e355e5047)) +* **internal:** remove CI condition ([#2203](https://github.com/openai/openai-python/issues/2203)) ([9620fdc](https://github.com/openai/openai-python/commit/9620fdcf4f2d01b6753ecc0abc16e5239c2b41e1)) +* **internal:** remove extra empty newlines ([#2195](https://github.com/openai/openai-python/issues/2195)) ([a1016a7](https://github.com/openai/openai-python/commit/a1016a78fe551e0f0e2562a0e81d1cb724d195da)) +* **internal:** update release workflows ([e2def44](https://github.com/openai/openai-python/commit/e2def4453323aa1cf8077df447fd55eb4c626393)) + ## 1.66.3 (2025-03-12) Full Changelog: [v1.66.2...v1.66.3](https://github.com/openai/openai-python/compare/v1.66.2...v1.66.3) diff --git a/pyproject.toml b/pyproject.toml index 0a9a931f6f..8247861185 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.66.3" +version = "1.66.4" 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 6c4a192efc..df2f60a7dc 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.66.3" # x-release-please-version +__version__ = "1.66.4" # x-release-please-version From bff8da95ab1967426b92e0c0b899596a05606130 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 18 Mar 2025 21:50:14 +0000 Subject: [PATCH 243/769] release: 1.66.5 (#2223) * chore(internal): remove extra empty newlines (#2195) * chore(internal): bump rye to 0.44.0 (#2200) * chore(internal): remove CI condition (#2203) * chore(internal): update release workflows * fix(types): handle more discriminated union shapes (#2206) * fix(ci): ensure pip is always available (#2207) * fix(ci): remove publishing patch (#2208) * chore(internal): add back releases workflow * chore(internal): codegen related update (#2222) * fix(types): improve responses type names (#2224) * release: 1.66.5 --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> Co-authored-by: meorphis --- .github/workflows/create-releases.yml | 39 +++++ .release-please-manifest.json | 2 +- .stats.yml | 2 +- CHANGELOG.md | 14 ++ api.md | 8 +- pyproject.toml | 2 +- src/openai/_version.py | 2 +- src/openai/resources/batches.py | 16 +-- src/openai/resources/responses/input_items.py | 14 +- src/openai/types/batch_create_params.py | 9 +- .../types/chat/chat_completion_chunk.py | 7 +- .../chat_completion_content_part_param.py | 2 +- .../chat_completion_stream_options_param.py | 7 +- src/openai/types/responses/__init__.py | 15 ++ ...response_computer_tool_call_output_item.py | 47 ++++++ ...se_computer_tool_call_output_screenshot.py | 22 +++ ...puter_tool_call_output_screenshot_param.py | 21 +++ .../responses/response_function_tool_call.py | 6 +- .../response_function_tool_call_item.py | 11 ++ ...response_function_tool_call_output_item.py | 29 ++++ .../response_function_tool_call_param.py | 6 +- .../responses/response_input_item_param.py | 18 +-- .../responses/response_input_message_item.py | 33 +++++ .../types/responses/response_input_param.py | 18 +-- src/openai/types/responses/response_item.py | 30 ++++ .../types/responses/response_item_list.py | 136 +----------------- src/openai/types/responses/response_usage.py | 13 +- src/openai/types/shared/reasoning.py | 2 +- src/openai/types/shared_params/reasoning.py | 6 +- .../responses/test_input_items.py | 18 +-- tests/api_resources/test_batches.py | 16 +-- 31 files changed, 351 insertions(+), 220 deletions(-) create mode 100644 .github/workflows/create-releases.yml create mode 100644 src/openai/types/responses/response_computer_tool_call_output_item.py create mode 100644 src/openai/types/responses/response_computer_tool_call_output_screenshot.py create mode 100644 src/openai/types/responses/response_computer_tool_call_output_screenshot_param.py create mode 100644 src/openai/types/responses/response_function_tool_call_item.py create mode 100644 src/openai/types/responses/response_function_tool_call_output_item.py create mode 100644 src/openai/types/responses/response_input_message_item.py create mode 100644 src/openai/types/responses/response_item.py diff --git a/.github/workflows/create-releases.yml b/.github/workflows/create-releases.yml new file mode 100644 index 0000000000..b3e1c679d4 --- /dev/null +++ b/.github/workflows/create-releases.yml @@ -0,0 +1,39 @@ +name: Create releases +on: + schedule: + - cron: '0 5 * * *' # every day at 5am UTC + push: + branches: + - main + +jobs: + release: + name: release + if: github.ref == 'refs/heads/main' && github.repository == 'openai/openai-python' + runs-on: ubuntu-latest + environment: publish + + steps: + - uses: actions/checkout@v4 + + - uses: stainless-api/trigger-release-please@v1 + id: release + with: + repo: ${{ github.event.repository.full_name }} + stainless-api-key: ${{ secrets.STAINLESS_API_KEY }} + + - name: Install Rye + if: ${{ steps.release.outputs.releases_created }} + run: | + curl -sSf https://rye.astral.sh/get | bash + echo "$HOME/.rye/shims" >> $GITHUB_PATH + env: + RYE_VERSION: '0.44.0' + RYE_INSTALL_OPTION: '--yes' + + - name: Publish to PyPI + if: ${{ steps.release.outputs.releases_created }} + run: | + bash ./bin/publish-pypi + env: + PYPI_TOKEN: ${{ secrets.OPENAI_PYPI_TOKEN || secrets.PYPI_TOKEN }} diff --git a/.release-please-manifest.json b/.release-please-manifest.json index dac37ce406..e567f9cb13 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.66.4" + ".": "1.66.5" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 53c73037d5..b032562238 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 81 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-c8579861bc21d4d2155a5b9e8e7d54faee8083730673c4d32cbbe573d7fb4116.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-f3bce04386c4fcfd5037e0477fbaa39010003fd1558eb5185fe4a71dd6a05fdd.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ed70082c7..d8fb019fc8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## 1.66.5 (2025-03-18) + +Full Changelog: [v1.66.4...v1.66.5](https://github.com/openai/openai-python/compare/v1.66.4...v1.66.5) + +### Bug Fixes + +* **types:** improve responses type names ([#2224](https://github.com/openai/openai-python/issues/2224)) ([5f7beb8](https://github.com/openai/openai-python/commit/5f7beb873af5ccef2551f34ab3ef098e099ce9c6)) + + +### Chores + +* **internal:** add back releases workflow ([c71d4c9](https://github.com/openai/openai-python/commit/c71d4c918eab3532b36ea944b0c4069db6ac2d38)) +* **internal:** codegen related update ([#2222](https://github.com/openai/openai-python/issues/2222)) ([f570d91](https://github.com/openai/openai-python/commit/f570d914a16cb5092533e32dfd863027d378c0b5)) + ## 1.66.4 (2025-03-17) Full Changelog: [v1.66.3...v1.66.4](https://github.com/openai/openai-python/compare/v1.66.3...v1.66.4) diff --git a/api.md b/api.md index e760fe69c1..6e7f48a645 100644 --- a/api.md +++ b/api.md @@ -605,6 +605,8 @@ from openai.types.responses import ( ResponseCodeInterpreterToolCall, ResponseCompletedEvent, ResponseComputerToolCall, + ResponseComputerToolCallOutputItem, + ResponseComputerToolCallOutputScreenshot, ResponseContent, ResponseContentPartAddedEvent, ResponseContentPartDoneEvent, @@ -621,6 +623,8 @@ from openai.types.responses import ( ResponseFunctionCallArgumentsDeltaEvent, ResponseFunctionCallArgumentsDoneEvent, ResponseFunctionToolCall, + ResponseFunctionToolCallItem, + ResponseFunctionToolCallOutputItem, ResponseFunctionWebSearch, ResponseInProgressEvent, ResponseIncludable, @@ -632,7 +636,9 @@ from openai.types.responses import ( ResponseInputImage, ResponseInputItem, ResponseInputMessageContentList, + ResponseInputMessageItem, ResponseInputText, + ResponseItem, ResponseOutputAudio, ResponseOutputItem, ResponseOutputItemAddedEvent, @@ -677,4 +683,4 @@ from openai.types.responses import ResponseItemList Methods: -- client.responses.input_items.list(response_id, \*\*params) -> SyncCursorPage[Data] +- client.responses.input_items.list(response_id, \*\*params) -> SyncCursorPage[ResponseItem] diff --git a/pyproject.toml b/pyproject.toml index 8247861185..5fdf2a836d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.66.4" +version = "1.66.5" 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 df2f60a7dc..dbefc6ec32 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.66.4" # x-release-please-version +__version__ = "1.66.5" # x-release-please-version diff --git a/src/openai/resources/batches.py b/src/openai/resources/batches.py index 7e7ec19ec2..b7a299be12 100644 --- a/src/openai/resources/batches.py +++ b/src/openai/resources/batches.py @@ -49,7 +49,7 @@ def create( self, *, completion_window: Literal["24h"], - endpoint: Literal["/v1/chat/completions", "/v1/embeddings", "/v1/completions"], + endpoint: Literal["/v1/responses", "/v1/chat/completions", "/v1/embeddings", "/v1/completions"], input_file_id: str, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -67,9 +67,9 @@ def create( is supported. endpoint: The endpoint to be used for all requests in the batch. Currently - `/v1/chat/completions`, `/v1/embeddings`, and `/v1/completions` are supported. - Note that `/v1/embeddings` batches are also restricted to a maximum of 50,000 - embedding inputs across all requests in the batch. + `/v1/responses`, `/v1/chat/completions`, `/v1/embeddings`, and `/v1/completions` + are supported. Note that `/v1/embeddings` batches are also restricted to a + maximum of 50,000 embedding inputs across all requests in the batch. input_file_id: The ID of an uploaded file that contains requests for the new batch. @@ -259,7 +259,7 @@ async def create( self, *, completion_window: Literal["24h"], - endpoint: Literal["/v1/chat/completions", "/v1/embeddings", "/v1/completions"], + endpoint: Literal["/v1/responses", "/v1/chat/completions", "/v1/embeddings", "/v1/completions"], input_file_id: str, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -277,9 +277,9 @@ async def create( is supported. endpoint: The endpoint to be used for all requests in the batch. Currently - `/v1/chat/completions`, `/v1/embeddings`, and `/v1/completions` are supported. - Note that `/v1/embeddings` batches are also restricted to a maximum of 50,000 - embedding inputs across all requests in the batch. + `/v1/responses`, `/v1/chat/completions`, `/v1/embeddings`, and `/v1/completions` + are supported. Note that `/v1/embeddings` batches are also restricted to a + maximum of 50,000 embedding inputs across all requests in the batch. input_file_id: The ID of an uploaded file that contains requests for the new batch. diff --git a/src/openai/resources/responses/input_items.py b/src/openai/resources/responses/input_items.py index 10e7d545dc..e341393cd1 100644 --- a/src/openai/resources/responses/input_items.py +++ b/src/openai/resources/responses/input_items.py @@ -16,7 +16,7 @@ from ...pagination import SyncCursorPage, AsyncCursorPage from ..._base_client import AsyncPaginator, make_request_options from ...types.responses import input_item_list_params -from ...types.responses.response_item_list import Data +from ...types.responses.response_item import ResponseItem __all__ = ["InputItems", "AsyncInputItems"] @@ -55,7 +55,7 @@ def list( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> SyncCursorPage[Data]: + ) -> SyncCursorPage[ResponseItem]: """ Returns a list of input items for a given response. @@ -84,7 +84,7 @@ def list( raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") return self._get_api_list( f"/responses/{response_id}/input_items", - page=SyncCursorPage[Data], + page=SyncCursorPage[ResponseItem], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -100,7 +100,7 @@ def list( input_item_list_params.InputItemListParams, ), ), - model=cast(Any, Data), # Union types cannot be passed in as arguments in the type system + model=cast(Any, ResponseItem), # Union types cannot be passed in as arguments in the type system ) @@ -138,7 +138,7 @@ def list( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncPaginator[Data, AsyncCursorPage[Data]]: + ) -> AsyncPaginator[ResponseItem, AsyncCursorPage[ResponseItem]]: """ Returns a list of input items for a given response. @@ -167,7 +167,7 @@ def list( raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") return self._get_api_list( f"/responses/{response_id}/input_items", - page=AsyncCursorPage[Data], + page=AsyncCursorPage[ResponseItem], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -183,7 +183,7 @@ def list( input_item_list_params.InputItemListParams, ), ), - model=cast(Any, Data), # Union types cannot be passed in as arguments in the type system + model=cast(Any, ResponseItem), # Union types cannot be passed in as arguments in the type system ) diff --git a/src/openai/types/batch_create_params.py b/src/openai/types/batch_create_params.py index e5be1d2bac..cc95afd3ba 100644 --- a/src/openai/types/batch_create_params.py +++ b/src/openai/types/batch_create_params.py @@ -17,12 +17,13 @@ class BatchCreateParams(TypedDict, total=False): Currently only `24h` is supported. """ - endpoint: Required[Literal["/v1/chat/completions", "/v1/embeddings", "/v1/completions"]] + endpoint: Required[Literal["/v1/responses", "/v1/chat/completions", "/v1/embeddings", "/v1/completions"]] """The endpoint to be used for all requests in the batch. - Currently `/v1/chat/completions`, `/v1/embeddings`, and `/v1/completions` are - supported. Note that `/v1/embeddings` batches are also restricted to a maximum - of 50,000 embedding inputs across all requests in the batch. + Currently `/v1/responses`, `/v1/chat/completions`, `/v1/embeddings`, and + `/v1/completions` are supported. Note that `/v1/embeddings` batches are also + restricted to a maximum of 50,000 embedding inputs across all requests in the + batch. """ input_file_id: Required[str] diff --git a/src/openai/types/chat/chat_completion_chunk.py b/src/openai/types/chat/chat_completion_chunk.py index dede513f1e..31b9cb5456 100644 --- a/src/openai/types/chat/chat_completion_chunk.py +++ b/src/openai/types/chat/chat_completion_chunk.py @@ -142,6 +142,9 @@ class ChatCompletionChunk(BaseModel): """ An optional field that will only be present when you set `stream_options: {"include_usage": true}` in your request. When present, it - contains a null value except for the last chunk which contains the token usage - statistics for the entire request. + contains a null value **except for the last chunk** which contains the token + usage statistics for the entire request. + + **NOTE:** If the stream is interrupted or cancelled, you may not receive the + final usage chunk which contains the total token usage for the request. """ diff --git a/src/openai/types/chat/chat_completion_content_part_param.py b/src/openai/types/chat/chat_completion_content_part_param.py index 1293c54312..cbedc853ba 100644 --- a/src/openai/types/chat/chat_completion_content_part_param.py +++ b/src/openai/types/chat/chat_completion_content_part_param.py @@ -22,7 +22,7 @@ class FileFile(TypedDict, total=False): file_id: str """The ID of an uploaded file to use as input.""" - file_name: str + filename: str """The name of the file, used when passing the file to the model as a string.""" diff --git a/src/openai/types/chat/chat_completion_stream_options_param.py b/src/openai/types/chat/chat_completion_stream_options_param.py index fbf7291821..471e0eba98 100644 --- a/src/openai/types/chat/chat_completion_stream_options_param.py +++ b/src/openai/types/chat/chat_completion_stream_options_param.py @@ -12,6 +12,9 @@ class ChatCompletionStreamOptionsParam(TypedDict, total=False): """If set, an additional chunk will be streamed before the `data: [DONE]` message. The `usage` field on this chunk shows the token usage statistics for the entire - request, and the `choices` field will always be an empty array. All other chunks - will also include a `usage` field, but with a null value. + request, and the `choices` field will always be an empty array. + + All other chunks will also include a `usage` field, but with a null value. + **NOTE:** If the stream is interrupted, you may not receive the final usage + chunk which contains the total token usage for the request. """ diff --git a/src/openai/types/responses/__init__.py b/src/openai/types/responses/__init__.py index 7c0cf9e3f2..4f07a3d097 100644 --- a/src/openai/types/responses/__init__.py +++ b/src/openai/types/responses/__init__.py @@ -7,6 +7,7 @@ from .tool_param import ToolParam as ToolParam from .computer_tool import ComputerTool as ComputerTool from .function_tool import FunctionTool as FunctionTool +from .response_item import ResponseItem as ResponseItem from .response_error import ResponseError as ResponseError from .response_usage import ResponseUsage as ResponseUsage from .parsed_response import ( @@ -66,6 +67,7 @@ from .response_computer_tool_call import ResponseComputerToolCall as ResponseComputerToolCall from .response_format_text_config import ResponseFormatTextConfig as ResponseFormatTextConfig from .response_function_tool_call import ResponseFunctionToolCall as ResponseFunctionToolCall +from .response_input_message_item import ResponseInputMessageItem as ResponseInputMessageItem from .response_refusal_done_event import ResponseRefusalDoneEvent as ResponseRefusalDoneEvent from .response_function_web_search import ResponseFunctionWebSearch as ResponseFunctionWebSearch from .response_input_content_param import ResponseInputContentParam as ResponseInputContentParam @@ -76,6 +78,7 @@ from .response_file_search_tool_call import ResponseFileSearchToolCall as ResponseFileSearchToolCall from .response_output_item_done_event import ResponseOutputItemDoneEvent as ResponseOutputItemDoneEvent from .response_content_part_done_event import ResponseContentPartDoneEvent as ResponseContentPartDoneEvent +from .response_function_tool_call_item import ResponseFunctionToolCallItem as ResponseFunctionToolCallItem from .response_output_item_added_event import ResponseOutputItemAddedEvent as ResponseOutputItemAddedEvent from .response_computer_tool_call_param import ResponseComputerToolCallParam as ResponseComputerToolCallParam from .response_content_part_added_event import ResponseContentPartAddedEvent as ResponseContentPartAddedEvent @@ -90,9 +93,15 @@ from .response_audio_transcript_delta_event import ( ResponseAudioTranscriptDeltaEvent as ResponseAudioTranscriptDeltaEvent, ) +from .response_computer_tool_call_output_item import ( + ResponseComputerToolCallOutputItem as ResponseComputerToolCallOutputItem, +) from .response_format_text_json_schema_config import ( ResponseFormatTextJSONSchemaConfig as ResponseFormatTextJSONSchemaConfig, ) +from .response_function_tool_call_output_item import ( + ResponseFunctionToolCallOutputItem as ResponseFunctionToolCallOutputItem, +) from .response_web_search_call_completed_event import ( ResponseWebSearchCallCompletedEvent as ResponseWebSearchCallCompletedEvent, ) @@ -120,6 +129,9 @@ from .response_function_call_arguments_delta_event import ( ResponseFunctionCallArgumentsDeltaEvent as ResponseFunctionCallArgumentsDeltaEvent, ) +from .response_computer_tool_call_output_screenshot import ( + ResponseComputerToolCallOutputScreenshot as ResponseComputerToolCallOutputScreenshot, +) from .response_format_text_json_schema_config_param import ( ResponseFormatTextJSONSchemaConfigParam as ResponseFormatTextJSONSchemaConfigParam, ) @@ -138,3 +150,6 @@ from .response_code_interpreter_call_interpreting_event import ( ResponseCodeInterpreterCallInterpretingEvent as ResponseCodeInterpreterCallInterpretingEvent, ) +from .response_computer_tool_call_output_screenshot_param import ( + ResponseComputerToolCallOutputScreenshotParam as ResponseComputerToolCallOutputScreenshotParam, +) diff --git a/src/openai/types/responses/response_computer_tool_call_output_item.py b/src/openai/types/responses/response_computer_tool_call_output_item.py new file mode 100644 index 0000000000..a2dd68f579 --- /dev/null +++ b/src/openai/types/responses/response_computer_tool_call_output_item.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel +from .response_computer_tool_call_output_screenshot import ResponseComputerToolCallOutputScreenshot + +__all__ = ["ResponseComputerToolCallOutputItem", "AcknowledgedSafetyCheck"] + + +class AcknowledgedSafetyCheck(BaseModel): + id: str + """The ID of the pending safety check.""" + + code: str + """The type of the pending safety check.""" + + message: str + """Details about the pending safety check.""" + + +class ResponseComputerToolCallOutputItem(BaseModel): + id: str + """The unique ID of the computer call tool output.""" + + call_id: str + """The ID of the computer tool call that produced the output.""" + + output: ResponseComputerToolCallOutputScreenshot + """A computer screenshot image used with the computer use tool.""" + + type: Literal["computer_call_output"] + """The type of the computer tool call output. Always `computer_call_output`.""" + + acknowledged_safety_checks: Optional[List[AcknowledgedSafetyCheck]] = None + """ + The safety checks reported by the API that have been acknowledged by the + developer. + """ + + status: Optional[Literal["in_progress", "completed", "incomplete"]] = None + """The status of the message input. + + One of `in_progress`, `completed`, or `incomplete`. Populated when input items + are returned via API. + """ diff --git a/src/openai/types/responses/response_computer_tool_call_output_screenshot.py b/src/openai/types/responses/response_computer_tool_call_output_screenshot.py new file mode 100644 index 0000000000..a500da85c1 --- /dev/null +++ b/src/openai/types/responses/response_computer_tool_call_output_screenshot.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseComputerToolCallOutputScreenshot"] + + +class ResponseComputerToolCallOutputScreenshot(BaseModel): + type: Literal["computer_screenshot"] + """Specifies the event type. + + For a computer screenshot, this property is always set to `computer_screenshot`. + """ + + file_id: Optional[str] = None + """The identifier of an uploaded file that contains the screenshot.""" + + image_url: Optional[str] = None + """The URL of the screenshot image.""" diff --git a/src/openai/types/responses/response_computer_tool_call_output_screenshot_param.py b/src/openai/types/responses/response_computer_tool_call_output_screenshot_param.py new file mode 100644 index 0000000000..efc2028aa4 --- /dev/null +++ b/src/openai/types/responses/response_computer_tool_call_output_screenshot_param.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ResponseComputerToolCallOutputScreenshotParam"] + + +class ResponseComputerToolCallOutputScreenshotParam(TypedDict, total=False): + type: Required[Literal["computer_screenshot"]] + """Specifies the event type. + + For a computer screenshot, this property is always set to `computer_screenshot`. + """ + + file_id: str + """The identifier of an uploaded file that contains the screenshot.""" + + image_url: str + """The URL of the screenshot image.""" diff --git a/src/openai/types/responses/response_function_tool_call.py b/src/openai/types/responses/response_function_tool_call.py index 5d82906cb7..2a8482204e 100644 --- a/src/openai/types/responses/response_function_tool_call.py +++ b/src/openai/types/responses/response_function_tool_call.py @@ -9,9 +9,6 @@ class ResponseFunctionToolCall(BaseModel): - id: str - """The unique ID of the function tool call.""" - arguments: str """A JSON string of the arguments to pass to the function.""" @@ -24,6 +21,9 @@ class ResponseFunctionToolCall(BaseModel): type: Literal["function_call"] """The type of the function tool call. Always `function_call`.""" + id: Optional[str] = None + """The unique ID of the function tool call.""" + status: Optional[Literal["in_progress", "completed", "incomplete"]] = None """The status of the item. diff --git a/src/openai/types/responses/response_function_tool_call_item.py b/src/openai/types/responses/response_function_tool_call_item.py new file mode 100644 index 0000000000..477e9b70aa --- /dev/null +++ b/src/openai/types/responses/response_function_tool_call_item.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + + +from .response_function_tool_call import ResponseFunctionToolCall + +__all__ = ["ResponseFunctionToolCallItem"] + + +class ResponseFunctionToolCallItem(ResponseFunctionToolCall): + id: str # type: ignore + """The unique ID of the function call tool output.""" diff --git a/src/openai/types/responses/response_function_tool_call_output_item.py b/src/openai/types/responses/response_function_tool_call_output_item.py new file mode 100644 index 0000000000..4c8c41a6fe --- /dev/null +++ b/src/openai/types/responses/response_function_tool_call_output_item.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseFunctionToolCallOutputItem"] + + +class ResponseFunctionToolCallOutputItem(BaseModel): + id: str + """The unique ID of the function call tool output.""" + + call_id: str + """The unique ID of the function tool call generated by the model.""" + + output: str + """A JSON string of the output of the function tool call.""" + + type: Literal["function_call_output"] + """The type of the function tool call output. Always `function_call_output`.""" + + status: Optional[Literal["in_progress", "completed", "incomplete"]] = None + """The status of the item. + + One of `in_progress`, `completed`, or `incomplete`. Populated when items are + returned via API. + """ diff --git a/src/openai/types/responses/response_function_tool_call_param.py b/src/openai/types/responses/response_function_tool_call_param.py index 51b947a764..eaa263cf67 100644 --- a/src/openai/types/responses/response_function_tool_call_param.py +++ b/src/openai/types/responses/response_function_tool_call_param.py @@ -8,9 +8,6 @@ class ResponseFunctionToolCallParam(TypedDict, total=False): - id: Required[str] - """The unique ID of the function tool call.""" - arguments: Required[str] """A JSON string of the arguments to pass to the function.""" @@ -23,6 +20,9 @@ class ResponseFunctionToolCallParam(TypedDict, total=False): type: Required[Literal["function_call"]] """The type of the function tool call. Always `function_call`.""" + id: str + """The unique ID of the function tool call.""" + status: Literal["in_progress", "completed", "incomplete"] """The status of the item. diff --git a/src/openai/types/responses/response_input_item_param.py b/src/openai/types/responses/response_input_item_param.py index 32ac13cabb..2505f7c0b5 100644 --- a/src/openai/types/responses/response_input_item_param.py +++ b/src/openai/types/responses/response_input_item_param.py @@ -13,12 +13,12 @@ from .response_function_web_search_param import ResponseFunctionWebSearchParam from .response_file_search_tool_call_param import ResponseFileSearchToolCallParam from .response_input_message_content_list_param import ResponseInputMessageContentListParam +from .response_computer_tool_call_output_screenshot_param import ResponseComputerToolCallOutputScreenshotParam __all__ = [ "ResponseInputItemParam", "Message", "ComputerCallOutput", - "ComputerCallOutputOutput", "ComputerCallOutputAcknowledgedSafetyCheck", "FunctionCallOutput", "ItemReference", @@ -46,20 +46,6 @@ class Message(TypedDict, total=False): """The type of the message input. Always set to `message`.""" -class ComputerCallOutputOutput(TypedDict, total=False): - type: Required[Literal["computer_screenshot"]] - """Specifies the event type. - - For a computer screenshot, this property is always set to `computer_screenshot`. - """ - - file_id: str - """The identifier of an uploaded file that contains the screenshot.""" - - image_url: str - """The URL of the screenshot image.""" - - class ComputerCallOutputAcknowledgedSafetyCheck(TypedDict, total=False): id: Required[str] """The ID of the pending safety check.""" @@ -75,7 +61,7 @@ class ComputerCallOutput(TypedDict, total=False): call_id: Required[str] """The ID of the computer tool call that produced the output.""" - output: Required[ComputerCallOutputOutput] + output: Required[ResponseComputerToolCallOutputScreenshotParam] """A computer screenshot image used with the computer use tool.""" type: Required[Literal["computer_call_output"]] diff --git a/src/openai/types/responses/response_input_message_item.py b/src/openai/types/responses/response_input_message_item.py new file mode 100644 index 0000000000..6a788e7fa4 --- /dev/null +++ b/src/openai/types/responses/response_input_message_item.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel +from .response_input_message_content_list import ResponseInputMessageContentList + +__all__ = ["ResponseInputMessageItem"] + + +class ResponseInputMessageItem(BaseModel): + id: str + """The unique ID of the message input.""" + + content: ResponseInputMessageContentList + """ + A list of one or many input items to the model, containing different content + types. + """ + + role: Literal["user", "system", "developer"] + """The role of the message input. One of `user`, `system`, or `developer`.""" + + status: Optional[Literal["in_progress", "completed", "incomplete"]] = None + """The status of item. + + One of `in_progress`, `completed`, or `incomplete`. Populated when items are + returned via API. + """ + + type: Optional[Literal["message"]] = None + """The type of the message input. Always set to `message`.""" diff --git a/src/openai/types/responses/response_input_param.py b/src/openai/types/responses/response_input_param.py index b942f4868a..84a80eb7c2 100644 --- a/src/openai/types/responses/response_input_param.py +++ b/src/openai/types/responses/response_input_param.py @@ -13,13 +13,13 @@ from .response_function_web_search_param import ResponseFunctionWebSearchParam from .response_file_search_tool_call_param import ResponseFileSearchToolCallParam from .response_input_message_content_list_param import ResponseInputMessageContentListParam +from .response_computer_tool_call_output_screenshot_param import ResponseComputerToolCallOutputScreenshotParam __all__ = [ "ResponseInputParam", "ResponseInputItemParam", "Message", "ComputerCallOutput", - "ComputerCallOutputOutput", "ComputerCallOutputAcknowledgedSafetyCheck", "FunctionCallOutput", "ItemReference", @@ -47,20 +47,6 @@ class Message(TypedDict, total=False): """The type of the message input. Always set to `message`.""" -class ComputerCallOutputOutput(TypedDict, total=False): - type: Required[Literal["computer_screenshot"]] - """Specifies the event type. - - For a computer screenshot, this property is always set to `computer_screenshot`. - """ - - file_id: str - """The identifier of an uploaded file that contains the screenshot.""" - - image_url: str - """The URL of the screenshot image.""" - - class ComputerCallOutputAcknowledgedSafetyCheck(TypedDict, total=False): id: Required[str] """The ID of the pending safety check.""" @@ -76,7 +62,7 @@ class ComputerCallOutput(TypedDict, total=False): call_id: Required[str] """The ID of the computer tool call that produced the output.""" - output: Required[ComputerCallOutputOutput] + output: Required[ResponseComputerToolCallOutputScreenshotParam] """A computer screenshot image used with the computer use tool.""" type: Required[Literal["computer_call_output"]] diff --git a/src/openai/types/responses/response_item.py b/src/openai/types/responses/response_item.py new file mode 100644 index 0000000000..dc8d67d0f2 --- /dev/null +++ b/src/openai/types/responses/response_item.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from typing_extensions import Annotated, TypeAlias + +from ..._utils import PropertyInfo +from .response_output_message import ResponseOutputMessage +from .response_computer_tool_call import ResponseComputerToolCall +from .response_input_message_item import ResponseInputMessageItem +from .response_function_web_search import ResponseFunctionWebSearch +from .response_file_search_tool_call import ResponseFileSearchToolCall +from .response_function_tool_call_item import ResponseFunctionToolCallItem +from .response_computer_tool_call_output_item import ResponseComputerToolCallOutputItem +from .response_function_tool_call_output_item import ResponseFunctionToolCallOutputItem + +__all__ = ["ResponseItem"] + +ResponseItem: TypeAlias = Annotated[ + Union[ + ResponseInputMessageItem, + ResponseOutputMessage, + ResponseFileSearchToolCall, + ResponseComputerToolCall, + ResponseComputerToolCallOutputItem, + ResponseFunctionWebSearch, + ResponseFunctionToolCallItem, + ResponseFunctionToolCallOutputItem, + ], + PropertyInfo(discriminator="type"), +] diff --git a/src/openai/types/responses/response_item_list.py b/src/openai/types/responses/response_item_list.py index 7c3e4d7f82..b43eacdb51 100644 --- a/src/openai/types/responses/response_item_list.py +++ b/src/openai/types/responses/response_item_list.py @@ -1,142 +1,16 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias +from typing import List +from typing_extensions import Literal -from ..._utils import PropertyInfo from ..._models import BaseModel -from .response_output_message import ResponseOutputMessage -from .response_computer_tool_call import ResponseComputerToolCall -from .response_function_tool_call import ResponseFunctionToolCall -from .response_function_web_search import ResponseFunctionWebSearch -from .response_file_search_tool_call import ResponseFileSearchToolCall -from .response_input_message_content_list import ResponseInputMessageContentList +from .response_item import ResponseItem -__all__ = [ - "ResponseItemList", - "Data", - "DataMessage", - "DataComputerCallOutput", - "DataComputerCallOutputOutput", - "DataComputerCallOutputAcknowledgedSafetyCheck", - "DataFunctionCallOutput", -] - - -class DataMessage(BaseModel): - id: str - """The unique ID of the message input.""" - - content: ResponseInputMessageContentList - """ - A list of one or many input items to the model, containing different content - types. - """ - - role: Literal["user", "system", "developer"] - """The role of the message input. One of `user`, `system`, or `developer`.""" - - status: Optional[Literal["in_progress", "completed", "incomplete"]] = None - """The status of item. - - One of `in_progress`, `completed`, or `incomplete`. Populated when items are - returned via API. - """ - - type: Optional[Literal["message"]] = None - """The type of the message input. Always set to `message`.""" - - -class DataComputerCallOutputOutput(BaseModel): - type: Literal["computer_screenshot"] - """Specifies the event type. - - For a computer screenshot, this property is always set to `computer_screenshot`. - """ - - file_id: Optional[str] = None - """The identifier of an uploaded file that contains the screenshot.""" - - image_url: Optional[str] = None - """The URL of the screenshot image.""" - - -class DataComputerCallOutputAcknowledgedSafetyCheck(BaseModel): - id: str - """The ID of the pending safety check.""" - - code: str - """The type of the pending safety check.""" - - message: str - """Details about the pending safety check.""" - - -class DataComputerCallOutput(BaseModel): - id: str - """The unique ID of the computer call tool output.""" - - call_id: str - """The ID of the computer tool call that produced the output.""" - - output: DataComputerCallOutputOutput - """A computer screenshot image used with the computer use tool.""" - - type: Literal["computer_call_output"] - """The type of the computer tool call output. Always `computer_call_output`.""" - - acknowledged_safety_checks: Optional[List[DataComputerCallOutputAcknowledgedSafetyCheck]] = None - """ - The safety checks reported by the API that have been acknowledged by the - developer. - """ - - status: Optional[Literal["in_progress", "completed", "incomplete"]] = None - """The status of the message input. - - One of `in_progress`, `completed`, or `incomplete`. Populated when input items - are returned via API. - """ - - -class DataFunctionCallOutput(BaseModel): - id: str - """The unique ID of the function call tool output.""" - - call_id: str - """The unique ID of the function tool call generated by the model.""" - - output: str - """A JSON string of the output of the function tool call.""" - - type: Literal["function_call_output"] - """The type of the function tool call output. Always `function_call_output`.""" - - status: Optional[Literal["in_progress", "completed", "incomplete"]] = None - """The status of the item. - - One of `in_progress`, `completed`, or `incomplete`. Populated when items are - returned via API. - """ - - -Data: TypeAlias = Annotated[ - Union[ - DataMessage, - ResponseOutputMessage, - ResponseFileSearchToolCall, - ResponseComputerToolCall, - DataComputerCallOutput, - ResponseFunctionWebSearch, - ResponseFunctionToolCall, - DataFunctionCallOutput, - ], - PropertyInfo(discriminator="type"), -] +__all__ = ["ResponseItemList"] class ResponseItemList(BaseModel): - data: List[Data] + data: List[ResponseItem] """A list of items used to generate this response.""" first_id: str diff --git a/src/openai/types/responses/response_usage.py b/src/openai/types/responses/response_usage.py index ef631c5882..9ad36bd326 100644 --- a/src/openai/types/responses/response_usage.py +++ b/src/openai/types/responses/response_usage.py @@ -3,7 +3,15 @@ from ..._models import BaseModel -__all__ = ["ResponseUsage", "OutputTokensDetails"] +__all__ = ["ResponseUsage", "InputTokensDetails", "OutputTokensDetails"] + + +class InputTokensDetails(BaseModel): + cached_tokens: int + """The number of tokens that were retrieved from the cache. + + [More on prompt caching](https://platform.openai.com/docs/guides/prompt-caching). + """ class OutputTokensDetails(BaseModel): @@ -15,6 +23,9 @@ class ResponseUsage(BaseModel): input_tokens: int """The number of input tokens.""" + input_tokens_details: InputTokensDetails + """A detailed breakdown of the input tokens.""" + output_tokens: int """The number of output tokens.""" diff --git a/src/openai/types/shared/reasoning.py b/src/openai/types/shared/reasoning.py index 50821a1727..78a396d738 100644 --- a/src/openai/types/shared/reasoning.py +++ b/src/openai/types/shared/reasoning.py @@ -20,7 +20,7 @@ class Reasoning(BaseModel): """ generate_summary: Optional[Literal["concise", "detailed"]] = None - """**o-series models only** + """**computer_use_preview only** A summary of the reasoning performed by the model. This can be useful for debugging and understanding the model's reasoning process. One of `concise` or diff --git a/src/openai/types/shared_params/reasoning.py b/src/openai/types/shared_params/reasoning.py index f2b5c5963a..2953b895c4 100644 --- a/src/openai/types/shared_params/reasoning.py +++ b/src/openai/types/shared_params/reasoning.py @@ -3,7 +3,7 @@ from __future__ import annotations from typing import Optional -from typing_extensions import Literal, Required, TypedDict +from typing_extensions import Literal, TypedDict from ..shared.reasoning_effort import ReasoningEffort @@ -11,7 +11,7 @@ class Reasoning(TypedDict, total=False): - effort: Required[Optional[ReasoningEffort]] + effort: Optional[ReasoningEffort] """**o-series models only** Constrains effort on reasoning for @@ -21,7 +21,7 @@ class Reasoning(TypedDict, total=False): """ generate_summary: Optional[Literal["concise", "detailed"]] - """**o-series models only** + """**computer_use_preview only** A summary of the reasoning performed by the model. This can be useful for debugging and understanding the model's reasoning process. One of `concise` or diff --git a/tests/api_resources/responses/test_input_items.py b/tests/api_resources/responses/test_input_items.py index 28c5e8ca1f..77a156b5ac 100644 --- a/tests/api_resources/responses/test_input_items.py +++ b/tests/api_resources/responses/test_input_items.py @@ -10,7 +10,7 @@ from openai import OpenAI, AsyncOpenAI from tests.utils import assert_matches_type from openai.pagination import SyncCursorPage, AsyncCursorPage -from openai.types.responses.response_item_list import Data +from openai.types.responses import ResponseItem base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -23,7 +23,7 @@ def test_method_list(self, client: OpenAI) -> None: input_item = client.responses.input_items.list( response_id="response_id", ) - assert_matches_type(SyncCursorPage[Data], input_item, path=["response"]) + assert_matches_type(SyncCursorPage[ResponseItem], input_item, path=["response"]) @parametrize def test_method_list_with_all_params(self, client: OpenAI) -> None: @@ -34,7 +34,7 @@ def test_method_list_with_all_params(self, client: OpenAI) -> None: limit=0, order="asc", ) - assert_matches_type(SyncCursorPage[Data], input_item, path=["response"]) + assert_matches_type(SyncCursorPage[ResponseItem], input_item, path=["response"]) @parametrize def test_raw_response_list(self, client: OpenAI) -> None: @@ -45,7 +45,7 @@ def test_raw_response_list(self, client: OpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" input_item = response.parse() - assert_matches_type(SyncCursorPage[Data], input_item, path=["response"]) + assert_matches_type(SyncCursorPage[ResponseItem], input_item, path=["response"]) @parametrize def test_streaming_response_list(self, client: OpenAI) -> None: @@ -56,7 +56,7 @@ def test_streaming_response_list(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" input_item = response.parse() - assert_matches_type(SyncCursorPage[Data], input_item, path=["response"]) + assert_matches_type(SyncCursorPage[ResponseItem], input_item, path=["response"]) assert cast(Any, response.is_closed) is True @@ -76,7 +76,7 @@ async def test_method_list(self, async_client: AsyncOpenAI) -> None: input_item = await async_client.responses.input_items.list( response_id="response_id", ) - assert_matches_type(AsyncCursorPage[Data], input_item, path=["response"]) + assert_matches_type(AsyncCursorPage[ResponseItem], input_item, path=["response"]) @parametrize async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: @@ -87,7 +87,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> N limit=0, order="asc", ) - assert_matches_type(AsyncCursorPage[Data], input_item, path=["response"]) + assert_matches_type(AsyncCursorPage[ResponseItem], input_item, path=["response"]) @parametrize async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: @@ -98,7 +98,7 @@ async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" input_item = response.parse() - assert_matches_type(AsyncCursorPage[Data], input_item, path=["response"]) + assert_matches_type(AsyncCursorPage[ResponseItem], input_item, path=["response"]) @parametrize async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: @@ -109,7 +109,7 @@ async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" input_item = await response.parse() - assert_matches_type(AsyncCursorPage[Data], input_item, path=["response"]) + assert_matches_type(AsyncCursorPage[ResponseItem], input_item, path=["response"]) assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_batches.py b/tests/api_resources/test_batches.py index 6f9b598e61..a2f8fb48a3 100644 --- a/tests/api_resources/test_batches.py +++ b/tests/api_resources/test_batches.py @@ -22,7 +22,7 @@ class TestBatches: def test_method_create(self, client: OpenAI) -> None: batch = client.batches.create( completion_window="24h", - endpoint="/v1/chat/completions", + endpoint="/v1/responses", input_file_id="string", ) assert_matches_type(Batch, batch, path=["response"]) @@ -31,7 +31,7 @@ def test_method_create(self, client: OpenAI) -> None: def test_method_create_with_all_params(self, client: OpenAI) -> None: batch = client.batches.create( completion_window="24h", - endpoint="/v1/chat/completions", + endpoint="/v1/responses", input_file_id="string", metadata={"foo": "string"}, ) @@ -41,7 +41,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: def test_raw_response_create(self, client: OpenAI) -> None: response = client.batches.with_raw_response.create( completion_window="24h", - endpoint="/v1/chat/completions", + endpoint="/v1/responses", input_file_id="string", ) @@ -54,7 +54,7 @@ def test_raw_response_create(self, client: OpenAI) -> None: def test_streaming_response_create(self, client: OpenAI) -> None: with client.batches.with_streaming_response.create( completion_window="24h", - endpoint="/v1/chat/completions", + endpoint="/v1/responses", input_file_id="string", ) as response: assert not response.is_closed @@ -182,7 +182,7 @@ class TestAsyncBatches: async def test_method_create(self, async_client: AsyncOpenAI) -> None: batch = await async_client.batches.create( completion_window="24h", - endpoint="/v1/chat/completions", + endpoint="/v1/responses", input_file_id="string", ) assert_matches_type(Batch, batch, path=["response"]) @@ -191,7 +191,7 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None: async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: batch = await async_client.batches.create( completion_window="24h", - endpoint="/v1/chat/completions", + endpoint="/v1/responses", input_file_id="string", metadata={"foo": "string"}, ) @@ -201,7 +201,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: response = await async_client.batches.with_raw_response.create( completion_window="24h", - endpoint="/v1/chat/completions", + endpoint="/v1/responses", input_file_id="string", ) @@ -214,7 +214,7 @@ async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: async with async_client.batches.with_streaming_response.create( completion_window="24h", - endpoint="/v1/chat/completions", + endpoint="/v1/responses", input_file_id="string", ) as response: assert not response.is_closed From 653dfec4c0abf67c4f90f25044c57bc6acbae77a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 19 Mar 2025 20:39:23 +0000 Subject: [PATCH 244/769] feat(api): o1-pro now available through the API (#2228) --- .stats.yml | 2 +- api.md | 2 + src/openai/resources/responses/responses.py | 17 +- .../resources/responses/responses.py.orig | 1796 +++++++++++++++++ src/openai/types/__init__.py | 2 + src/openai/types/responses/response.py | 4 +- .../types/responses/response_create_params.py | 4 +- .../response_function_tool_call_item.py | 2 +- src/openai/types/shared/__init__.py | 2 + src/openai/types/shared/all_models.py | 16 + src/openai/types/shared/chat_model.py | 9 +- src/openai/types/shared/responses_model.py | 12 + src/openai/types/shared_params/__init__.py | 1 + src/openai/types/shared_params/chat_model.py | 9 +- .../types/shared_params/responses_model.py | 14 + 15 files changed, 1868 insertions(+), 24 deletions(-) create mode 100644 src/openai/resources/responses/responses.py.orig create mode 100644 src/openai/types/shared/all_models.py create mode 100644 src/openai/types/shared/responses_model.py create mode 100644 src/openai/types/shared_params/responses_model.py diff --git a/.stats.yml b/.stats.yml index b032562238..e0b06dc22a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 81 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-f3bce04386c4fcfd5037e0477fbaa39010003fd1558eb5185fe4a71dd6a05fdd.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-b26121d5df6eb5d3032a45a267473798b15fcfec76dd44a3256cf1238be05fa4.yml diff --git a/api.md b/api.md index 6e7f48a645..7f3a9392a2 100644 --- a/api.md +++ b/api.md @@ -2,6 +2,7 @@ ```python from openai.types import ( + AllModels, ChatModel, ComparisonFilter, CompoundFilter, @@ -14,6 +15,7 @@ from openai.types import ( ResponseFormatJSONObject, ResponseFormatJSONSchema, ResponseFormatText, + ResponsesModel, ) ``` diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 0c70a2ef22..668f4db80a 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -44,6 +44,7 @@ from ...types.responses.parsed_response import ParsedResponse from ...lib.streaming.responses._responses import ResponseStreamManager, AsyncResponseStreamManager from ...types.responses.response_includable import ResponseIncludable +from ...types.shared_params.responses_model import ResponsesModel from ...types.responses.response_input_param import ResponseInputParam from ...types.responses.response_stream_event import ResponseStreamEvent from ...types.responses.response_text_config_param import ResponseTextConfigParam @@ -80,7 +81,7 @@ def create( self, *, input: Union[str, ResponseInputParam], - model: Union[str, ChatModel], + model: ResponsesModel, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, @@ -245,7 +246,7 @@ def create( self, *, input: Union[str, ResponseInputParam], - model: Union[str, ChatModel], + model: ResponsesModel, stream: Literal[True], include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, @@ -410,7 +411,7 @@ def create( self, *, input: Union[str, ResponseInputParam], - model: Union[str, ChatModel], + model: ResponsesModel, stream: bool, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, @@ -575,7 +576,7 @@ def create( self, *, input: Union[str, ResponseInputParam], - model: Union[str, ChatModel], + model: ResponsesModel, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, @@ -892,7 +893,7 @@ async def create( self, *, input: Union[str, ResponseInputParam], - model: Union[str, ChatModel], + model: ResponsesModel, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, @@ -1057,7 +1058,7 @@ async def create( self, *, input: Union[str, ResponseInputParam], - model: Union[str, ChatModel], + model: ResponsesModel, stream: Literal[True], include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, @@ -1222,7 +1223,7 @@ async def create( self, *, input: Union[str, ResponseInputParam], - model: Union[str, ChatModel], + model: ResponsesModel, stream: bool, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, @@ -1387,7 +1388,7 @@ async def create( self, *, input: Union[str, ResponseInputParam], - model: Union[str, ChatModel], + model: ResponsesModel, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, diff --git a/src/openai/resources/responses/responses.py.orig b/src/openai/resources/responses/responses.py.orig new file mode 100644 index 0000000000..dec4c19367 --- /dev/null +++ b/src/openai/resources/responses/responses.py.orig @@ -0,0 +1,1796 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Any, List, Type, Union, Iterable, Optional, cast +from functools import partial +from typing_extensions import Literal, overload + +import httpx + +from ... import _legacy_response +from ..._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven +from ..._utils import ( + is_given, + required_args, + maybe_transform, + async_maybe_transform, +) +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from .input_items import ( + InputItems, + AsyncInputItems, + InputItemsWithRawResponse, + AsyncInputItemsWithRawResponse, + InputItemsWithStreamingResponse, + AsyncInputItemsWithStreamingResponse, +) +from ..._streaming import Stream, AsyncStream +from ...lib._tools import PydanticFunctionTool, ResponsesPydanticFunctionTool +from ..._base_client import make_request_options +from ...types.responses import response_create_params, response_retrieve_params +<<<<<<< HEAD +from ...lib._parsing._responses import ( + TextFormatT, + parse_response, + type_to_text_format_param as _type_to_text_format_param, +) +from ...types.shared.chat_model import ChatModel +||||||| parent of 001707b8 (feat(api): o1-pro now available through the API (#2228)) +from ...types.shared.chat_model import ChatModel +======= +>>>>>>> 001707b8 (feat(api): o1-pro now available through the API (#2228)) +from ...types.responses.response import Response +from ...types.responses.tool_param import ToolParam, ParseableToolParam +from ...types.shared_params.metadata import Metadata +from ...types.shared_params.reasoning import Reasoning +from ...types.responses.parsed_response import ParsedResponse +from ...lib.streaming.responses._responses import ResponseStreamManager, AsyncResponseStreamManager +from ...types.responses.response_includable import ResponseIncludable +from ...types.shared_params.responses_model import ResponsesModel +from ...types.responses.response_input_param import ResponseInputParam +from ...types.responses.response_stream_event import ResponseStreamEvent +from ...types.responses.response_text_config_param import ResponseTextConfigParam + +__all__ = ["Responses", "AsyncResponses"] + + +class Responses(SyncAPIResource): + @cached_property + def input_items(self) -> InputItems: + return InputItems(self._client) + + @cached_property + def with_raw_response(self) -> ResponsesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return ResponsesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ResponsesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return ResponsesWithStreamingResponse(self) + + @overload + def create( + self, + *, + input: Union[str, ResponseInputParam], + model: ResponsesModel, + include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | NotGiven = NOT_GIVEN, + max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, + previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, + stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, + temperature: Optional[float] | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, + tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, + top_p: Optional[float] | NotGiven = NOT_GIVEN, + truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Response: + """Creates a model response. + + Provide + [text](https://platform.openai.com/docs/guides/text) or + [image](https://platform.openai.com/docs/guides/images) inputs to generate + [text](https://platform.openai.com/docs/guides/text) or + [JSON](https://platform.openai.com/docs/guides/structured-outputs) outputs. Have + the model call your own + [custom code](https://platform.openai.com/docs/guides/function-calling) or use + built-in [tools](https://platform.openai.com/docs/guides/tools) like + [web search](https://platform.openai.com/docs/guides/tools-web-search) or + [file search](https://platform.openai.com/docs/guides/tools-file-search) to use + your own data as input for the model's response. + + Args: + input: Text, image, or file inputs to the model, used to generate a response. + + Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Image inputs](https://platform.openai.com/docs/guides/images) + - [File inputs](https://platform.openai.com/docs/guides/pdf-files) + - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) + - [Function calling](https://platform.openai.com/docs/guides/function-calling) + + model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a + wide range of models with different capabilities, performance characteristics, + and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + + include: Specify additional output data to include in the model response. Currently + supported values are: + + - `file_search_call.results`: Include the search results of the file search tool + call. + - `message.input_image.image_url`: Include image urls from the input message. + - `computer_call_output.output.image_url`: Include image urls from the computer + call output. + + instructions: Inserts a system (or developer) message as the first item in the model's + context. + + When using along with `previous_response_id`, the instructions from a previous + response will be not be carried over to the next response. This makes it simple + to swap out system (or developer) messages in new responses. + + max_output_tokens: An upper bound for the number of tokens that can be generated for a response, + including visible output tokens and + [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). + + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + + parallel_tool_calls: Whether to allow the model to run tool calls in parallel. + + previous_response_id: The unique ID of the previous response to the model. Use this to create + multi-turn conversations. Learn more about + [conversation state](https://platform.openai.com/docs/guides/conversation-state). + + reasoning: **o-series models only** + + Configuration options for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). + + store: Whether to store the generated model response for later retrieval via API. + + stream: If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) + for more information. + + temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will + make the output more random, while lower values like 0.2 will make it more + focused and deterministic. We generally recommend altering this or `top_p` but + not both. + + text: Configuration options for a text response from the model. Can be plain text or + structured JSON data. Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + + tool_choice: How the model should select which tool (or tools) to use when generating a + response. See the `tools` parameter to see how to specify which tools the model + can call. + + tools: An array of tools the model may call while generating a response. You can + specify which tool to use by setting the `tool_choice` parameter. + + The two categories of tools you can provide the model are: + + - **Built-in tools**: Tools that are provided by OpenAI that extend the model's + capabilities, like + [web search](https://platform.openai.com/docs/guides/tools-web-search) or + [file search](https://platform.openai.com/docs/guides/tools-file-search). + Learn more about + [built-in tools](https://platform.openai.com/docs/guides/tools). + - **Function calls (custom tools)**: Functions that are defined by you, enabling + the model to call your own code. Learn more about + [function calling](https://platform.openai.com/docs/guides/function-calling). + + top_p: An alternative to sampling with temperature, called nucleus sampling, where the + model considers the results of the tokens with top_p probability mass. So 0.1 + means only the tokens comprising the top 10% probability mass are considered. + + We generally recommend altering this or `temperature` but not both. + + truncation: The truncation strategy to use for the model response. + + - `auto`: If the context of this response and previous ones exceeds the model's + context window size, the model will truncate the response to fit the context + window by dropping input items in the middle of the conversation. + - `disabled` (default): If a model response will exceed the context window size + for a model, the request will fail with a 400 error. + + user: A unique identifier representing your end-user, which can help OpenAI to monitor + and detect abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def create( + self, + *, + input: Union[str, ResponseInputParam], + model: ResponsesModel, + stream: Literal[True], + include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | NotGiven = NOT_GIVEN, + max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, + previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, + temperature: Optional[float] | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, + tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, + top_p: Optional[float] | NotGiven = NOT_GIVEN, + truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Stream[ResponseStreamEvent]: + """Creates a model response. + + Provide + [text](https://platform.openai.com/docs/guides/text) or + [image](https://platform.openai.com/docs/guides/images) inputs to generate + [text](https://platform.openai.com/docs/guides/text) or + [JSON](https://platform.openai.com/docs/guides/structured-outputs) outputs. Have + the model call your own + [custom code](https://platform.openai.com/docs/guides/function-calling) or use + built-in [tools](https://platform.openai.com/docs/guides/tools) like + [web search](https://platform.openai.com/docs/guides/tools-web-search) or + [file search](https://platform.openai.com/docs/guides/tools-file-search) to use + your own data as input for the model's response. + + Args: + input: Text, image, or file inputs to the model, used to generate a response. + + Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Image inputs](https://platform.openai.com/docs/guides/images) + - [File inputs](https://platform.openai.com/docs/guides/pdf-files) + - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) + - [Function calling](https://platform.openai.com/docs/guides/function-calling) + + model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a + wide range of models with different capabilities, performance characteristics, + and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + + stream: If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) + for more information. + + include: Specify additional output data to include in the model response. Currently + supported values are: + + - `file_search_call.results`: Include the search results of the file search tool + call. + - `message.input_image.image_url`: Include image urls from the input message. + - `computer_call_output.output.image_url`: Include image urls from the computer + call output. + + instructions: Inserts a system (or developer) message as the first item in the model's + context. + + When using along with `previous_response_id`, the instructions from a previous + response will be not be carried over to the next response. This makes it simple + to swap out system (or developer) messages in new responses. + + max_output_tokens: An upper bound for the number of tokens that can be generated for a response, + including visible output tokens and + [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). + + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + + parallel_tool_calls: Whether to allow the model to run tool calls in parallel. + + previous_response_id: The unique ID of the previous response to the model. Use this to create + multi-turn conversations. Learn more about + [conversation state](https://platform.openai.com/docs/guides/conversation-state). + + reasoning: **o-series models only** + + Configuration options for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). + + store: Whether to store the generated model response for later retrieval via API. + + temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will + make the output more random, while lower values like 0.2 will make it more + focused and deterministic. We generally recommend altering this or `top_p` but + not both. + + text: Configuration options for a text response from the model. Can be plain text or + structured JSON data. Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + + tool_choice: How the model should select which tool (or tools) to use when generating a + response. See the `tools` parameter to see how to specify which tools the model + can call. + + tools: An array of tools the model may call while generating a response. You can + specify which tool to use by setting the `tool_choice` parameter. + + The two categories of tools you can provide the model are: + + - **Built-in tools**: Tools that are provided by OpenAI that extend the model's + capabilities, like + [web search](https://platform.openai.com/docs/guides/tools-web-search) or + [file search](https://platform.openai.com/docs/guides/tools-file-search). + Learn more about + [built-in tools](https://platform.openai.com/docs/guides/tools). + - **Function calls (custom tools)**: Functions that are defined by you, enabling + the model to call your own code. Learn more about + [function calling](https://platform.openai.com/docs/guides/function-calling). + + top_p: An alternative to sampling with temperature, called nucleus sampling, where the + model considers the results of the tokens with top_p probability mass. So 0.1 + means only the tokens comprising the top 10% probability mass are considered. + + We generally recommend altering this or `temperature` but not both. + + truncation: The truncation strategy to use for the model response. + + - `auto`: If the context of this response and previous ones exceeds the model's + context window size, the model will truncate the response to fit the context + window by dropping input items in the middle of the conversation. + - `disabled` (default): If a model response will exceed the context window size + for a model, the request will fail with a 400 error. + + user: A unique identifier representing your end-user, which can help OpenAI to monitor + and detect abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def create( + self, + *, + input: Union[str, ResponseInputParam], + model: ResponsesModel, + stream: bool, + include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | NotGiven = NOT_GIVEN, + max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, + previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, + temperature: Optional[float] | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, + tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, + top_p: Optional[float] | NotGiven = NOT_GIVEN, + truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Response | Stream[ResponseStreamEvent]: + """Creates a model response. + + Provide + [text](https://platform.openai.com/docs/guides/text) or + [image](https://platform.openai.com/docs/guides/images) inputs to generate + [text](https://platform.openai.com/docs/guides/text) or + [JSON](https://platform.openai.com/docs/guides/structured-outputs) outputs. Have + the model call your own + [custom code](https://platform.openai.com/docs/guides/function-calling) or use + built-in [tools](https://platform.openai.com/docs/guides/tools) like + [web search](https://platform.openai.com/docs/guides/tools-web-search) or + [file search](https://platform.openai.com/docs/guides/tools-file-search) to use + your own data as input for the model's response. + + Args: + input: Text, image, or file inputs to the model, used to generate a response. + + Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Image inputs](https://platform.openai.com/docs/guides/images) + - [File inputs](https://platform.openai.com/docs/guides/pdf-files) + - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) + - [Function calling](https://platform.openai.com/docs/guides/function-calling) + + model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a + wide range of models with different capabilities, performance characteristics, + and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + + stream: If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) + for more information. + + include: Specify additional output data to include in the model response. Currently + supported values are: + + - `file_search_call.results`: Include the search results of the file search tool + call. + - `message.input_image.image_url`: Include image urls from the input message. + - `computer_call_output.output.image_url`: Include image urls from the computer + call output. + + instructions: Inserts a system (or developer) message as the first item in the model's + context. + + When using along with `previous_response_id`, the instructions from a previous + response will be not be carried over to the next response. This makes it simple + to swap out system (or developer) messages in new responses. + + max_output_tokens: An upper bound for the number of tokens that can be generated for a response, + including visible output tokens and + [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). + + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + + parallel_tool_calls: Whether to allow the model to run tool calls in parallel. + + previous_response_id: The unique ID of the previous response to the model. Use this to create + multi-turn conversations. Learn more about + [conversation state](https://platform.openai.com/docs/guides/conversation-state). + + reasoning: **o-series models only** + + Configuration options for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). + + store: Whether to store the generated model response for later retrieval via API. + + temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will + make the output more random, while lower values like 0.2 will make it more + focused and deterministic. We generally recommend altering this or `top_p` but + not both. + + text: Configuration options for a text response from the model. Can be plain text or + structured JSON data. Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + + tool_choice: How the model should select which tool (or tools) to use when generating a + response. See the `tools` parameter to see how to specify which tools the model + can call. + + tools: An array of tools the model may call while generating a response. You can + specify which tool to use by setting the `tool_choice` parameter. + + The two categories of tools you can provide the model are: + + - **Built-in tools**: Tools that are provided by OpenAI that extend the model's + capabilities, like + [web search](https://platform.openai.com/docs/guides/tools-web-search) or + [file search](https://platform.openai.com/docs/guides/tools-file-search). + Learn more about + [built-in tools](https://platform.openai.com/docs/guides/tools). + - **Function calls (custom tools)**: Functions that are defined by you, enabling + the model to call your own code. Learn more about + [function calling](https://platform.openai.com/docs/guides/function-calling). + + top_p: An alternative to sampling with temperature, called nucleus sampling, where the + model considers the results of the tokens with top_p probability mass. So 0.1 + means only the tokens comprising the top 10% probability mass are considered. + + We generally recommend altering this or `temperature` but not both. + + truncation: The truncation strategy to use for the model response. + + - `auto`: If the context of this response and previous ones exceeds the model's + context window size, the model will truncate the response to fit the context + window by dropping input items in the middle of the conversation. + - `disabled` (default): If a model response will exceed the context window size + for a model, the request will fail with a 400 error. + + user: A unique identifier representing your end-user, which can help OpenAI to monitor + and detect abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @required_args(["input", "model"], ["input", "model", "stream"]) + def create( + self, + *, + input: Union[str, ResponseInputParam], + model: ResponsesModel, + include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | NotGiven = NOT_GIVEN, + max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, + previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, + stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, + temperature: Optional[float] | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, + tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, + top_p: Optional[float] | NotGiven = NOT_GIVEN, + truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Response | Stream[ResponseStreamEvent]: + return self._post( + "/responses", + body=maybe_transform( + { + "input": input, + "model": model, + "include": include, + "instructions": instructions, + "max_output_tokens": max_output_tokens, + "metadata": metadata, + "parallel_tool_calls": parallel_tool_calls, + "previous_response_id": previous_response_id, + "reasoning": reasoning, + "store": store, + "stream": stream, + "temperature": temperature, + "text": text, + "tool_choice": tool_choice, + "tools": tools, + "top_p": top_p, + "truncation": truncation, + "user": user, + }, + response_create_params.ResponseCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Response, + stream=stream or False, + stream_cls=Stream[ResponseStreamEvent], + ) + + def stream( + self, + *, + input: Union[str, ResponseInputParam], + model: Union[str, ChatModel], + text_format: type[TextFormatT] | NotGiven = NOT_GIVEN, + tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, + include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | NotGiven = NOT_GIVEN, + max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, + previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, + temperature: Optional[float] | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, + top_p: Optional[float] | NotGiven = NOT_GIVEN, + truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ResponseStreamManager[TextFormatT]: + if is_given(text_format): + if not text: + text = {} + + if "format" in text: + raise TypeError("Cannot mix and match text.format with text_format") + + text["format"] = _type_to_text_format_param(text_format) + + tools = _make_tools(tools) + + api_request: partial[Stream[ResponseStreamEvent]] = partial( + self.create, + input=input, + model=model, + tools=tools, + include=include, + instructions=instructions, + max_output_tokens=max_output_tokens, + metadata=metadata, + parallel_tool_calls=parallel_tool_calls, + previous_response_id=previous_response_id, + store=store, + stream=True, + temperature=temperature, + text=text, + tool_choice=tool_choice, + reasoning=reasoning, + top_p=top_p, + truncation=truncation, + user=user, + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + ) + + return ResponseStreamManager( + api_request, + text_format=text_format, + input_tools=tools, + ) + + def parse( + self, + *, + input: Union[str, ResponseInputParam], + model: Union[str, ChatModel], + text_format: type[TextFormatT] | NotGiven = NOT_GIVEN, + tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, + include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | NotGiven = NOT_GIVEN, + max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, + previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, + stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, + temperature: Optional[float] | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, + top_p: Optional[float] | NotGiven = NOT_GIVEN, + truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ParsedResponse[TextFormatT]: + if is_given(text_format): + if not text: + text = {} + + if "format" in text: + raise TypeError("Cannot mix and match text.format with text_format") + + text["format"] = _type_to_text_format_param(text_format) + + tools = _make_tools(tools) + + def parser(raw_response: Response) -> ParsedResponse[TextFormatT]: + return parse_response( + input_tools=tools, + text_format=text_format, + response=raw_response, + ) + + return self._post( + "/responses", + body=maybe_transform( + { + "input": input, + "model": model, + "include": include, + "instructions": instructions, + "max_output_tokens": max_output_tokens, + "metadata": metadata, + "parallel_tool_calls": parallel_tool_calls, + "previous_response_id": previous_response_id, + "reasoning": reasoning, + "store": store, + "stream": stream, + "temperature": temperature, + "text": text, + "tool_choice": tool_choice, + "tools": tools, + "top_p": top_p, + "truncation": truncation, + "user": user, + }, + response_create_params.ResponseCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=parser, + ), + # we turn the `Response` instance into a `ParsedResponse` + # in the `parser` function above + cast_to=cast(Type[ParsedResponse[TextFormatT]], Response), + ) + + def retrieve( + self, + response_id: str, + *, + include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Response: + """ + Retrieves a model response with the given ID. + + Args: + include: Additional fields to include in the response. See the `include` parameter for + Response creation above for more information. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not response_id: + raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") + return self._get( + f"/responses/{response_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"include": include}, response_retrieve_params.ResponseRetrieveParams), + ), + cast_to=Response, + ) + + def delete( + self, + response_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> None: + """ + Deletes a model response with the given ID. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not response_id: + raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/responses/{response_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncResponses(AsyncAPIResource): + @cached_property + def input_items(self) -> AsyncInputItems: + return AsyncInputItems(self._client) + + @cached_property + def with_raw_response(self) -> AsyncResponsesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncResponsesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncResponsesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncResponsesWithStreamingResponse(self) + + @overload + async def create( + self, + *, + input: Union[str, ResponseInputParam], + model: ResponsesModel, + include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | NotGiven = NOT_GIVEN, + max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, + previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, + stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, + temperature: Optional[float] | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, + tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, + top_p: Optional[float] | NotGiven = NOT_GIVEN, + truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Response: + """Creates a model response. + + Provide + [text](https://platform.openai.com/docs/guides/text) or + [image](https://platform.openai.com/docs/guides/images) inputs to generate + [text](https://platform.openai.com/docs/guides/text) or + [JSON](https://platform.openai.com/docs/guides/structured-outputs) outputs. Have + the model call your own + [custom code](https://platform.openai.com/docs/guides/function-calling) or use + built-in [tools](https://platform.openai.com/docs/guides/tools) like + [web search](https://platform.openai.com/docs/guides/tools-web-search) or + [file search](https://platform.openai.com/docs/guides/tools-file-search) to use + your own data as input for the model's response. + + Args: + input: Text, image, or file inputs to the model, used to generate a response. + + Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Image inputs](https://platform.openai.com/docs/guides/images) + - [File inputs](https://platform.openai.com/docs/guides/pdf-files) + - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) + - [Function calling](https://platform.openai.com/docs/guides/function-calling) + + model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a + wide range of models with different capabilities, performance characteristics, + and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + + include: Specify additional output data to include in the model response. Currently + supported values are: + + - `file_search_call.results`: Include the search results of the file search tool + call. + - `message.input_image.image_url`: Include image urls from the input message. + - `computer_call_output.output.image_url`: Include image urls from the computer + call output. + + instructions: Inserts a system (or developer) message as the first item in the model's + context. + + When using along with `previous_response_id`, the instructions from a previous + response will be not be carried over to the next response. This makes it simple + to swap out system (or developer) messages in new responses. + + max_output_tokens: An upper bound for the number of tokens that can be generated for a response, + including visible output tokens and + [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). + + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + + parallel_tool_calls: Whether to allow the model to run tool calls in parallel. + + previous_response_id: The unique ID of the previous response to the model. Use this to create + multi-turn conversations. Learn more about + [conversation state](https://platform.openai.com/docs/guides/conversation-state). + + reasoning: **o-series models only** + + Configuration options for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). + + store: Whether to store the generated model response for later retrieval via API. + + stream: If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) + for more information. + + temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will + make the output more random, while lower values like 0.2 will make it more + focused and deterministic. We generally recommend altering this or `top_p` but + not both. + + text: Configuration options for a text response from the model. Can be plain text or + structured JSON data. Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + + tool_choice: How the model should select which tool (or tools) to use when generating a + response. See the `tools` parameter to see how to specify which tools the model + can call. + + tools: An array of tools the model may call while generating a response. You can + specify which tool to use by setting the `tool_choice` parameter. + + The two categories of tools you can provide the model are: + + - **Built-in tools**: Tools that are provided by OpenAI that extend the model's + capabilities, like + [web search](https://platform.openai.com/docs/guides/tools-web-search) or + [file search](https://platform.openai.com/docs/guides/tools-file-search). + Learn more about + [built-in tools](https://platform.openai.com/docs/guides/tools). + - **Function calls (custom tools)**: Functions that are defined by you, enabling + the model to call your own code. Learn more about + [function calling](https://platform.openai.com/docs/guides/function-calling). + + top_p: An alternative to sampling with temperature, called nucleus sampling, where the + model considers the results of the tokens with top_p probability mass. So 0.1 + means only the tokens comprising the top 10% probability mass are considered. + + We generally recommend altering this or `temperature` but not both. + + truncation: The truncation strategy to use for the model response. + + - `auto`: If the context of this response and previous ones exceeds the model's + context window size, the model will truncate the response to fit the context + window by dropping input items in the middle of the conversation. + - `disabled` (default): If a model response will exceed the context window size + for a model, the request will fail with a 400 error. + + user: A unique identifier representing your end-user, which can help OpenAI to monitor + and detect abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def create( + self, + *, + input: Union[str, ResponseInputParam], + model: ResponsesModel, + stream: Literal[True], + include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | NotGiven = NOT_GIVEN, + max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, + previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, + temperature: Optional[float] | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, + tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, + top_p: Optional[float] | NotGiven = NOT_GIVEN, + truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> AsyncStream[ResponseStreamEvent]: + """Creates a model response. + + Provide + [text](https://platform.openai.com/docs/guides/text) or + [image](https://platform.openai.com/docs/guides/images) inputs to generate + [text](https://platform.openai.com/docs/guides/text) or + [JSON](https://platform.openai.com/docs/guides/structured-outputs) outputs. Have + the model call your own + [custom code](https://platform.openai.com/docs/guides/function-calling) or use + built-in [tools](https://platform.openai.com/docs/guides/tools) like + [web search](https://platform.openai.com/docs/guides/tools-web-search) or + [file search](https://platform.openai.com/docs/guides/tools-file-search) to use + your own data as input for the model's response. + + Args: + input: Text, image, or file inputs to the model, used to generate a response. + + Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Image inputs](https://platform.openai.com/docs/guides/images) + - [File inputs](https://platform.openai.com/docs/guides/pdf-files) + - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) + - [Function calling](https://platform.openai.com/docs/guides/function-calling) + + model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a + wide range of models with different capabilities, performance characteristics, + and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + + stream: If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) + for more information. + + include: Specify additional output data to include in the model response. Currently + supported values are: + + - `file_search_call.results`: Include the search results of the file search tool + call. + - `message.input_image.image_url`: Include image urls from the input message. + - `computer_call_output.output.image_url`: Include image urls from the computer + call output. + + instructions: Inserts a system (or developer) message as the first item in the model's + context. + + When using along with `previous_response_id`, the instructions from a previous + response will be not be carried over to the next response. This makes it simple + to swap out system (or developer) messages in new responses. + + max_output_tokens: An upper bound for the number of tokens that can be generated for a response, + including visible output tokens and + [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). + + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + + parallel_tool_calls: Whether to allow the model to run tool calls in parallel. + + previous_response_id: The unique ID of the previous response to the model. Use this to create + multi-turn conversations. Learn more about + [conversation state](https://platform.openai.com/docs/guides/conversation-state). + + reasoning: **o-series models only** + + Configuration options for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). + + store: Whether to store the generated model response for later retrieval via API. + + temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will + make the output more random, while lower values like 0.2 will make it more + focused and deterministic. We generally recommend altering this or `top_p` but + not both. + + text: Configuration options for a text response from the model. Can be plain text or + structured JSON data. Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + + tool_choice: How the model should select which tool (or tools) to use when generating a + response. See the `tools` parameter to see how to specify which tools the model + can call. + + tools: An array of tools the model may call while generating a response. You can + specify which tool to use by setting the `tool_choice` parameter. + + The two categories of tools you can provide the model are: + + - **Built-in tools**: Tools that are provided by OpenAI that extend the model's + capabilities, like + [web search](https://platform.openai.com/docs/guides/tools-web-search) or + [file search](https://platform.openai.com/docs/guides/tools-file-search). + Learn more about + [built-in tools](https://platform.openai.com/docs/guides/tools). + - **Function calls (custom tools)**: Functions that are defined by you, enabling + the model to call your own code. Learn more about + [function calling](https://platform.openai.com/docs/guides/function-calling). + + top_p: An alternative to sampling with temperature, called nucleus sampling, where the + model considers the results of the tokens with top_p probability mass. So 0.1 + means only the tokens comprising the top 10% probability mass are considered. + + We generally recommend altering this or `temperature` but not both. + + truncation: The truncation strategy to use for the model response. + + - `auto`: If the context of this response and previous ones exceeds the model's + context window size, the model will truncate the response to fit the context + window by dropping input items in the middle of the conversation. + - `disabled` (default): If a model response will exceed the context window size + for a model, the request will fail with a 400 error. + + user: A unique identifier representing your end-user, which can help OpenAI to monitor + and detect abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def create( + self, + *, + input: Union[str, ResponseInputParam], + model: ResponsesModel, + stream: bool, + include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | NotGiven = NOT_GIVEN, + max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, + previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, + temperature: Optional[float] | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, + tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, + top_p: Optional[float] | NotGiven = NOT_GIVEN, + truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Response | AsyncStream[ResponseStreamEvent]: + """Creates a model response. + + Provide + [text](https://platform.openai.com/docs/guides/text) or + [image](https://platform.openai.com/docs/guides/images) inputs to generate + [text](https://platform.openai.com/docs/guides/text) or + [JSON](https://platform.openai.com/docs/guides/structured-outputs) outputs. Have + the model call your own + [custom code](https://platform.openai.com/docs/guides/function-calling) or use + built-in [tools](https://platform.openai.com/docs/guides/tools) like + [web search](https://platform.openai.com/docs/guides/tools-web-search) or + [file search](https://platform.openai.com/docs/guides/tools-file-search) to use + your own data as input for the model's response. + + Args: + input: Text, image, or file inputs to the model, used to generate a response. + + Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Image inputs](https://platform.openai.com/docs/guides/images) + - [File inputs](https://platform.openai.com/docs/guides/pdf-files) + - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) + - [Function calling](https://platform.openai.com/docs/guides/function-calling) + + model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a + wide range of models with different capabilities, performance characteristics, + and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + + stream: If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) + for more information. + + include: Specify additional output data to include in the model response. Currently + supported values are: + + - `file_search_call.results`: Include the search results of the file search tool + call. + - `message.input_image.image_url`: Include image urls from the input message. + - `computer_call_output.output.image_url`: Include image urls from the computer + call output. + + instructions: Inserts a system (or developer) message as the first item in the model's + context. + + When using along with `previous_response_id`, the instructions from a previous + response will be not be carried over to the next response. This makes it simple + to swap out system (or developer) messages in new responses. + + max_output_tokens: An upper bound for the number of tokens that can be generated for a response, + including visible output tokens and + [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). + + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + + parallel_tool_calls: Whether to allow the model to run tool calls in parallel. + + previous_response_id: The unique ID of the previous response to the model. Use this to create + multi-turn conversations. Learn more about + [conversation state](https://platform.openai.com/docs/guides/conversation-state). + + reasoning: **o-series models only** + + Configuration options for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). + + store: Whether to store the generated model response for later retrieval via API. + + temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will + make the output more random, while lower values like 0.2 will make it more + focused and deterministic. We generally recommend altering this or `top_p` but + not both. + + text: Configuration options for a text response from the model. Can be plain text or + structured JSON data. Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + + tool_choice: How the model should select which tool (or tools) to use when generating a + response. See the `tools` parameter to see how to specify which tools the model + can call. + + tools: An array of tools the model may call while generating a response. You can + specify which tool to use by setting the `tool_choice` parameter. + + The two categories of tools you can provide the model are: + + - **Built-in tools**: Tools that are provided by OpenAI that extend the model's + capabilities, like + [web search](https://platform.openai.com/docs/guides/tools-web-search) or + [file search](https://platform.openai.com/docs/guides/tools-file-search). + Learn more about + [built-in tools](https://platform.openai.com/docs/guides/tools). + - **Function calls (custom tools)**: Functions that are defined by you, enabling + the model to call your own code. Learn more about + [function calling](https://platform.openai.com/docs/guides/function-calling). + + top_p: An alternative to sampling with temperature, called nucleus sampling, where the + model considers the results of the tokens with top_p probability mass. So 0.1 + means only the tokens comprising the top 10% probability mass are considered. + + We generally recommend altering this or `temperature` but not both. + + truncation: The truncation strategy to use for the model response. + + - `auto`: If the context of this response and previous ones exceeds the model's + context window size, the model will truncate the response to fit the context + window by dropping input items in the middle of the conversation. + - `disabled` (default): If a model response will exceed the context window size + for a model, the request will fail with a 400 error. + + user: A unique identifier representing your end-user, which can help OpenAI to monitor + and detect abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @required_args(["input", "model"], ["input", "model", "stream"]) + async def create( + self, + *, + input: Union[str, ResponseInputParam], + model: ResponsesModel, + include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | NotGiven = NOT_GIVEN, + max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, + previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, + stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, + temperature: Optional[float] | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, + tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, + top_p: Optional[float] | NotGiven = NOT_GIVEN, + truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Response | AsyncStream[ResponseStreamEvent]: + return await self._post( + "/responses", + body=await async_maybe_transform( + { + "input": input, + "model": model, + "include": include, + "instructions": instructions, + "max_output_tokens": max_output_tokens, + "metadata": metadata, + "parallel_tool_calls": parallel_tool_calls, + "previous_response_id": previous_response_id, + "reasoning": reasoning, + "store": store, + "stream": stream, + "temperature": temperature, + "text": text, + "tool_choice": tool_choice, + "tools": tools, + "top_p": top_p, + "truncation": truncation, + "user": user, + }, + response_create_params.ResponseCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Response, + stream=stream or False, + stream_cls=AsyncStream[ResponseStreamEvent], + ) + + def stream( + self, + *, + input: Union[str, ResponseInputParam], + model: Union[str, ChatModel], + text_format: type[TextFormatT] | NotGiven = NOT_GIVEN, + tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, + include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | NotGiven = NOT_GIVEN, + max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, + previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, + temperature: Optional[float] | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, + top_p: Optional[float] | NotGiven = NOT_GIVEN, + truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> AsyncResponseStreamManager[TextFormatT]: + if is_given(text_format): + if not text: + text = {} + + if "format" in text: + raise TypeError("Cannot mix and match text.format with text_format") + + text["format"] = _type_to_text_format_param(text_format) + + tools = _make_tools(tools) + + api_request = self.create( + input=input, + model=model, + tools=tools, + include=include, + instructions=instructions, + max_output_tokens=max_output_tokens, + metadata=metadata, + parallel_tool_calls=parallel_tool_calls, + previous_response_id=previous_response_id, + store=store, + stream=True, + temperature=temperature, + text=text, + tool_choice=tool_choice, + reasoning=reasoning, + top_p=top_p, + truncation=truncation, + user=user, + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + ) + + return AsyncResponseStreamManager( + api_request, + text_format=text_format, + input_tools=tools, + ) + + async def parse( + self, + *, + input: Union[str, ResponseInputParam], + model: Union[str, ChatModel], + text_format: type[TextFormatT] | NotGiven = NOT_GIVEN, + tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, + include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | NotGiven = NOT_GIVEN, + max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, + previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, + stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, + temperature: Optional[float] | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, + top_p: Optional[float] | NotGiven = NOT_GIVEN, + truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ParsedResponse[TextFormatT]: + if is_given(text_format): + if not text: + text = {} + + if "format" in text: + raise TypeError("Cannot mix and match text.format with text_format") + + text["format"] = _type_to_text_format_param(text_format) + + tools = _make_tools(tools) + + def parser(raw_response: Response) -> ParsedResponse[TextFormatT]: + return parse_response( + input_tools=tools, + text_format=text_format, + response=raw_response, + ) + + return await self._post( + "/responses", + body=maybe_transform( + { + "input": input, + "model": model, + "include": include, + "instructions": instructions, + "max_output_tokens": max_output_tokens, + "metadata": metadata, + "parallel_tool_calls": parallel_tool_calls, + "previous_response_id": previous_response_id, + "reasoning": reasoning, + "store": store, + "stream": stream, + "temperature": temperature, + "text": text, + "tool_choice": tool_choice, + "tools": tools, + "top_p": top_p, + "truncation": truncation, + "user": user, + }, + response_create_params.ResponseCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=parser, + ), + # we turn the `Response` instance into a `ParsedResponse` + # in the `parser` function above + cast_to=cast(Type[ParsedResponse[TextFormatT]], Response), + ) + + async def retrieve( + self, + response_id: str, + *, + include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Response: + """ + Retrieves a model response with the given ID. + + Args: + include: Additional fields to include in the response. See the `include` parameter for + Response creation above for more information. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not response_id: + raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") + return await self._get( + f"/responses/{response_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"include": include}, response_retrieve_params.ResponseRetrieveParams + ), + ), + cast_to=Response, + ) + + async def delete( + self, + response_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> None: + """ + Deletes a model response with the given ID. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not response_id: + raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/responses/{response_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class ResponsesWithRawResponse: + def __init__(self, responses: Responses) -> None: + self._responses = responses + + self.create = _legacy_response.to_raw_response_wrapper( + responses.create, + ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + responses.retrieve, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + responses.delete, + ) + + @cached_property + def input_items(self) -> InputItemsWithRawResponse: + return InputItemsWithRawResponse(self._responses.input_items) + + +class AsyncResponsesWithRawResponse: + def __init__(self, responses: AsyncResponses) -> None: + self._responses = responses + + self.create = _legacy_response.async_to_raw_response_wrapper( + responses.create, + ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + responses.retrieve, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + responses.delete, + ) + + @cached_property + def input_items(self) -> AsyncInputItemsWithRawResponse: + return AsyncInputItemsWithRawResponse(self._responses.input_items) + + +class ResponsesWithStreamingResponse: + def __init__(self, responses: Responses) -> None: + self._responses = responses + + self.create = to_streamed_response_wrapper( + responses.create, + ) + self.retrieve = to_streamed_response_wrapper( + responses.retrieve, + ) + self.delete = to_streamed_response_wrapper( + responses.delete, + ) + + @cached_property + def input_items(self) -> InputItemsWithStreamingResponse: + return InputItemsWithStreamingResponse(self._responses.input_items) + + +class AsyncResponsesWithStreamingResponse: + def __init__(self, responses: AsyncResponses) -> None: + self._responses = responses + + self.create = async_to_streamed_response_wrapper( + responses.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + responses.retrieve, + ) + self.delete = async_to_streamed_response_wrapper( + responses.delete, + ) + + @cached_property + def input_items(self) -> AsyncInputItemsWithStreamingResponse: + return AsyncInputItemsWithStreamingResponse(self._responses.input_items) + + +def _make_tools(tools: Iterable[ParseableToolParam] | NotGiven) -> List[ToolParam] | NotGiven: + if not is_given(tools): + return NOT_GIVEN + + converted_tools: List[ToolParam] = [] + for tool in tools: + if tool["type"] != "function": + converted_tools.append(tool) + continue + + if "function" not in tool: + # standard Responses API case + converted_tools.append(tool) + continue + + function = cast(Any, tool)["function"] # pyright: ignore[reportUnnecessaryCast] + if not isinstance(function, PydanticFunctionTool): + raise Exception( + "Expected Chat Completions function tool shape to be created using `openai.pydantic_function_tool()`" + ) + + assert "parameters" in function + new_tool = ResponsesPydanticFunctionTool( + { + "type": "function", + "name": function["name"], + "description": function.get("description"), + "parameters": function["parameters"], + "strict": function.get("strict") or False, + }, + function.model, + ) + + converted_tools.append(new_tool.cast()) + + return converted_tools diff --git a/src/openai/types/__init__.py b/src/openai/types/__init__.py index 4c337d41c7..11761534c9 100644 --- a/src/openai/types/__init__.py +++ b/src/openai/types/__init__.py @@ -7,10 +7,12 @@ from .model import Model as Model from .shared import ( Metadata as Metadata, + AllModels as AllModels, ChatModel as ChatModel, Reasoning as Reasoning, ErrorObject as ErrorObject, CompoundFilter as CompoundFilter, + ResponsesModel as ResponsesModel, ReasoningEffort as ReasoningEffort, ComparisonFilter as ComparisonFilter, FunctionDefinition as FunctionDefinition, diff --git a/src/openai/types/responses/response.py b/src/openai/types/responses/response.py index 66887ae9b5..1bedf80889 100644 --- a/src/openai/types/responses/response.py +++ b/src/openai/types/responses/response.py @@ -11,11 +11,11 @@ from ..shared.metadata import Metadata from ..shared.reasoning import Reasoning from .tool_choice_types import ToolChoiceTypes -from ..shared.chat_model import ChatModel from .tool_choice_options import ToolChoiceOptions from .response_output_item import ResponseOutputItem from .response_text_config import ResponseTextConfig from .tool_choice_function import ToolChoiceFunction +from ..shared.responses_model import ResponsesModel __all__ = ["Response", "IncompleteDetails", "ToolChoice"] @@ -61,7 +61,7 @@ class Response(BaseModel): a maximum length of 512 characters. """ - model: Union[str, ChatModel] + model: ResponsesModel """Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a wide range of models with different capabilities, performance diff --git a/src/openai/types/responses/response_create_params.py b/src/openai/types/responses/response_create_params.py index d5b2fdeb1a..651050c50d 100644 --- a/src/openai/types/responses/response_create_params.py +++ b/src/openai/types/responses/response_create_params.py @@ -6,7 +6,6 @@ from typing_extensions import Literal, Required, TypeAlias, TypedDict from .tool_param import ToolParam -from ..shared.chat_model import ChatModel from .response_includable import ResponseIncludable from .tool_choice_options import ToolChoiceOptions from .response_input_param import ResponseInputParam @@ -15,6 +14,7 @@ from ..shared_params.reasoning import Reasoning from .response_text_config_param import ResponseTextConfigParam from .tool_choice_function_param import ToolChoiceFunctionParam +from ..shared_params.responses_model import ResponsesModel __all__ = [ "ResponseCreateParamsBase", @@ -37,7 +37,7 @@ class ResponseCreateParamsBase(TypedDict, total=False): - [Function calling](https://platform.openai.com/docs/guides/function-calling) """ - model: Required[Union[str, ChatModel]] + model: Required[ResponsesModel] """Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a wide range of models with different capabilities, performance diff --git a/src/openai/types/responses/response_function_tool_call_item.py b/src/openai/types/responses/response_function_tool_call_item.py index 477e9b70aa..25984f9451 100644 --- a/src/openai/types/responses/response_function_tool_call_item.py +++ b/src/openai/types/responses/response_function_tool_call_item.py @@ -8,4 +8,4 @@ class ResponseFunctionToolCallItem(ResponseFunctionToolCall): id: str # type: ignore - """The unique ID of the function call tool output.""" + """The unique ID of the function tool call.""" diff --git a/src/openai/types/shared/__init__.py b/src/openai/types/shared/__init__.py index 6ccc2313cc..6ad0ed5e01 100644 --- a/src/openai/types/shared/__init__.py +++ b/src/openai/types/shared/__init__.py @@ -2,9 +2,11 @@ from .metadata import Metadata as Metadata from .reasoning import Reasoning as Reasoning +from .all_models import AllModels as AllModels from .chat_model import ChatModel as ChatModel from .error_object import ErrorObject as ErrorObject from .compound_filter import CompoundFilter as CompoundFilter +from .responses_model import ResponsesModel as ResponsesModel from .reasoning_effort import ReasoningEffort as ReasoningEffort from .comparison_filter import ComparisonFilter as ComparisonFilter from .function_definition import FunctionDefinition as FunctionDefinition diff --git a/src/openai/types/shared/all_models.py b/src/openai/types/shared/all_models.py new file mode 100644 index 0000000000..c4635e2140 --- /dev/null +++ b/src/openai/types/shared/all_models.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from typing_extensions import Literal, TypeAlias + +from .chat_model import ChatModel + +__all__ = ["AllModels"] + +AllModels: TypeAlias = Union[ + str, + ChatModel, + str, + ChatModel, + Literal["o1-pro", "o1-pro-2025-03-19", "computer-use-preview", "computer-use-preview-2025-03-11"], +] diff --git a/src/openai/types/shared/chat_model.py b/src/openai/types/shared/chat_model.py index 31d7104e6e..b19375725d 100644 --- a/src/openai/types/shared/chat_model.py +++ b/src/openai/types/shared/chat_model.py @@ -13,11 +13,6 @@ "o1-preview-2024-09-12", "o1-mini", "o1-mini-2024-09-12", - "computer-use-preview", - "computer-use-preview-2025-02-04", - "computer-use-preview-2025-03-11", - "gpt-4.5-preview", - "gpt-4.5-preview-2025-02-27", "gpt-4o", "gpt-4o-2024-11-20", "gpt-4o-2024-08-06", @@ -27,6 +22,10 @@ "gpt-4o-audio-preview-2024-12-17", "gpt-4o-mini-audio-preview", "gpt-4o-mini-audio-preview-2024-12-17", + "gpt-4o-search-preview", + "gpt-4o-mini-search-preview", + "gpt-4o-search-preview-2025-03-11", + "gpt-4o-mini-search-preview-2025-03-11", "chatgpt-4o-latest", "gpt-4o-mini", "gpt-4o-mini-2024-07-18", diff --git a/src/openai/types/shared/responses_model.py b/src/openai/types/shared/responses_model.py new file mode 100644 index 0000000000..85f154fd84 --- /dev/null +++ b/src/openai/types/shared/responses_model.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from typing_extensions import Literal, TypeAlias + +from .chat_model import ChatModel + +__all__ = ["ResponsesModel"] + +ResponsesModel: TypeAlias = Union[ + str, ChatModel, Literal["o1-pro", "o1-pro-2025-03-19", "computer-use-preview", "computer-use-preview-2025-03-11"] +] diff --git a/src/openai/types/shared_params/__init__.py b/src/openai/types/shared_params/__init__.py index 4a4a8cdf1e..8894710807 100644 --- a/src/openai/types/shared_params/__init__.py +++ b/src/openai/types/shared_params/__init__.py @@ -4,6 +4,7 @@ from .reasoning import Reasoning as Reasoning from .chat_model import ChatModel as ChatModel from .compound_filter import CompoundFilter as CompoundFilter +from .responses_model import ResponsesModel as ResponsesModel from .reasoning_effort import ReasoningEffort as ReasoningEffort from .comparison_filter import ComparisonFilter as ComparisonFilter from .function_definition import FunctionDefinition as FunctionDefinition diff --git a/src/openai/types/shared_params/chat_model.py b/src/openai/types/shared_params/chat_model.py index 55649876eb..ff81b07ac3 100644 --- a/src/openai/types/shared_params/chat_model.py +++ b/src/openai/types/shared_params/chat_model.py @@ -15,11 +15,6 @@ "o1-preview-2024-09-12", "o1-mini", "o1-mini-2024-09-12", - "computer-use-preview", - "computer-use-preview-2025-02-04", - "computer-use-preview-2025-03-11", - "gpt-4.5-preview", - "gpt-4.5-preview-2025-02-27", "gpt-4o", "gpt-4o-2024-11-20", "gpt-4o-2024-08-06", @@ -29,6 +24,10 @@ "gpt-4o-audio-preview-2024-12-17", "gpt-4o-mini-audio-preview", "gpt-4o-mini-audio-preview-2024-12-17", + "gpt-4o-search-preview", + "gpt-4o-mini-search-preview", + "gpt-4o-search-preview-2025-03-11", + "gpt-4o-mini-search-preview-2025-03-11", "chatgpt-4o-latest", "gpt-4o-mini", "gpt-4o-mini-2024-07-18", diff --git a/src/openai/types/shared_params/responses_model.py b/src/openai/types/shared_params/responses_model.py new file mode 100644 index 0000000000..3bf0e13731 --- /dev/null +++ b/src/openai/types/shared_params/responses_model.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import Literal, TypeAlias + +from ..shared.chat_model import ChatModel + +__all__ = ["ResponsesModel"] + +ResponsesModel: TypeAlias = Union[ + str, ChatModel, Literal["o1-pro", "o1-pro-2025-03-19", "computer-use-preview", "computer-use-preview-2025-03-11"] +] From e9f971a71f7820c624d53c4927590dba67b2f71b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 19 Mar 2025 21:02:54 +0000 Subject: [PATCH 245/769] release: 1.67.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index e567f9cb13..4556676715 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.66.5" + ".": "1.67.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index d8fb019fc8..ddd8b945c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.67.0 (2025-03-19) + +Full Changelog: [v1.66.5...v1.67.0](https://github.com/openai/openai-python/compare/v1.66.5...v1.67.0) + +### Features + +* **api:** o1-pro now available through the API ([#2228](https://github.com/openai/openai-python/issues/2228)) ([40a19d8](https://github.com/openai/openai-python/commit/40a19d8592c1767d6318230fc93e37c360d1bcd1)) + ## 1.66.5 (2025-03-18) Full Changelog: [v1.66.4...v1.66.5](https://github.com/openai/openai-python/compare/v1.66.4...v1.66.5) diff --git a/pyproject.toml b/pyproject.toml index 5fdf2a836d..a0a7eba2f5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.66.5" +version = "1.67.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 dbefc6ec32..b63e6ad189 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.66.5" # x-release-please-version +__version__ = "1.67.0" # x-release-please-version From 2b4bc759b49504580cabc5e90b9cd79be4267207 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 20 Mar 2025 16:25:10 +0000 Subject: [PATCH 246/769] feat(api): new models for TTS, STT, + new audio features for Realtime (#2232) --- .stats.yml | 4 +- api.md | 20 ++ src/openai/resources/audio/speech.py | 14 +- src/openai/resources/audio/transcriptions.py | 285 +++++++++++++++- src/openai/resources/audio/translations.py | 3 +- .../resources/beta/realtime/__init__.py | 14 + .../resources/beta/realtime/realtime.py | 312 ++++++++++++------ .../resources/beta/realtime/sessions.py | 64 +++- .../beta/realtime/transcription_sessions.py | 277 ++++++++++++++++ src/openai/types/audio/__init__.py | 4 + .../types/audio/speech_create_params.py | 8 +- src/openai/types/audio/speech_model.py | 2 +- src/openai/types/audio/transcription.py | 21 +- .../audio/transcription_create_params.py | 58 +++- .../types/audio/transcription_include.py | 7 + .../types/audio/transcription_stream_event.py | 14 + .../audio/transcription_text_delta_event.py | 35 ++ .../audio/transcription_text_done_event.py | 35 ++ .../types/audio/translation_create_params.py | 5 +- src/openai/types/audio_model.py | 2 +- src/openai/types/beta/realtime/__init__.py | 12 + ...put_audio_transcription_completed_event.py | 17 +- ...m_input_audio_transcription_delta_event.py | 39 +++ .../conversation_item_retrieve_event.py | 19 ++ .../conversation_item_retrieve_event_param.py | 18 + .../beta/realtime/realtime_client_event.py | 16 +- .../realtime/realtime_client_event_param.py | 16 +- .../beta/realtime/realtime_server_event.py | 57 ++-- src/openai/types/beta/realtime/session.py | 112 +++++-- .../beta/realtime/session_create_params.py | 97 ++++-- .../beta/realtime/session_update_event.py | 106 ++++-- .../realtime/session_update_event_param.py | 98 ++++-- .../beta/realtime/transcription_session.py | 100 ++++++ .../transcription_session_create_params.py | 143 ++++++++ .../realtime/transcription_session_update.py | 160 +++++++++ .../transcription_session_update_param.py | 160 +++++++++ .../transcription_session_updated_event.py | 24 ++ tests/api_resources/audio/test_speech.py | 2 + .../audio/test_transcriptions.py | 146 ++++++-- .../beta/realtime/test_sessions.py | 8 +- .../realtime/test_transcription_sessions.py | 120 +++++++ tests/lib/test_audio.py | 4 +- 42 files changed, 2333 insertions(+), 325 deletions(-) create mode 100644 src/openai/resources/beta/realtime/transcription_sessions.py create mode 100644 src/openai/types/audio/transcription_include.py create mode 100644 src/openai/types/audio/transcription_stream_event.py create mode 100644 src/openai/types/audio/transcription_text_delta_event.py create mode 100644 src/openai/types/audio/transcription_text_done_event.py create mode 100644 src/openai/types/beta/realtime/conversation_item_input_audio_transcription_delta_event.py create mode 100644 src/openai/types/beta/realtime/conversation_item_retrieve_event.py create mode 100644 src/openai/types/beta/realtime/conversation_item_retrieve_event_param.py create mode 100644 src/openai/types/beta/realtime/transcription_session.py create mode 100644 src/openai/types/beta/realtime/transcription_session_create_params.py create mode 100644 src/openai/types/beta/realtime/transcription_session_update.py create mode 100644 src/openai/types/beta/realtime/transcription_session_update_param.py create mode 100644 src/openai/types/beta/realtime/transcription_session_updated_event.py create mode 100644 tests/api_resources/beta/realtime/test_transcription_sessions.py diff --git a/.stats.yml b/.stats.yml index e0b06dc22a..abb9371314 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ -configured_endpoints: 81 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-b26121d5df6eb5d3032a45a267473798b15fcfec76dd44a3256cf1238be05fa4.yml +configured_endpoints: 82 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-c22f59c66aec7914b6ee653d3098d1c1c8c16c180d2a158e819c8ddbf476f74b.yml diff --git a/api.md b/api.md index 7f3a9392a2..a5f81c624c 100644 --- a/api.md +++ b/api.md @@ -151,7 +151,11 @@ Types: ```python from openai.types.audio import ( Transcription, + TranscriptionInclude, TranscriptionSegment, + TranscriptionStreamEvent, + TranscriptionTextDeltaEvent, + TranscriptionTextDoneEvent, TranscriptionVerbose, TranscriptionWord, TranscriptionCreateResponse, @@ -338,7 +342,9 @@ from openai.types.beta.realtime import ( ConversationItemDeleteEvent, ConversationItemDeletedEvent, ConversationItemInputAudioTranscriptionCompletedEvent, + ConversationItemInputAudioTranscriptionDeltaEvent, ConversationItemInputAudioTranscriptionFailedEvent, + ConversationItemRetrieveEvent, ConversationItemTruncateEvent, ConversationItemTruncatedEvent, ConversationItemWithReference, @@ -375,6 +381,8 @@ from openai.types.beta.realtime import ( SessionCreatedEvent, SessionUpdateEvent, SessionUpdatedEvent, + TranscriptionSessionUpdate, + TranscriptionSessionUpdatedEvent, ) ``` @@ -390,6 +398,18 @@ Methods: - client.beta.realtime.sessions.create(\*\*params) -> SessionCreateResponse +### TranscriptionSessions + +Types: + +```python +from openai.types.beta.realtime import TranscriptionSession +``` + +Methods: + +- client.beta.realtime.transcription_sessions.create(\*\*params) -> TranscriptionSession + ## Assistants Types: diff --git a/src/openai/resources/audio/speech.py b/src/openai/resources/audio/speech.py index ad01118161..529e3a47ea 100644 --- a/src/openai/resources/audio/speech.py +++ b/src/openai/resources/audio/speech.py @@ -54,6 +54,7 @@ def create( input: str, model: Union[str, SpeechModel], voice: Literal["alloy", "ash", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer"], + instructions: str | NotGiven = NOT_GIVEN, response_format: Literal["mp3", "opus", "aac", "flac", "wav", "pcm"] | NotGiven = NOT_GIVEN, speed: float | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -71,13 +72,16 @@ def create( model: One of the available [TTS models](https://platform.openai.com/docs/models#tts): - `tts-1` or `tts-1-hd` + `tts-1`, `tts-1-hd` or `gpt-4o-mini-tts`. voice: The voice to use when generating the audio. Supported voices are `alloy`, `ash`, `coral`, `echo`, `fable`, `onyx`, `nova`, `sage` and `shimmer`. Previews of the voices are available in the [Text to speech guide](https://platform.openai.com/docs/guides/text-to-speech#voice-options). + instructions: Control the voice of your generated audio with additional instructions. Does not + work with `tts-1` or `tts-1-hd`. + response_format: The format to audio in. Supported formats are `mp3`, `opus`, `aac`, `flac`, `wav`, and `pcm`. @@ -100,6 +104,7 @@ def create( "input": input, "model": model, "voice": voice, + "instructions": instructions, "response_format": response_format, "speed": speed, }, @@ -138,6 +143,7 @@ async def create( input: str, model: Union[str, SpeechModel], voice: Literal["alloy", "ash", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer"], + instructions: str | NotGiven = NOT_GIVEN, response_format: Literal["mp3", "opus", "aac", "flac", "wav", "pcm"] | NotGiven = NOT_GIVEN, speed: float | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -155,13 +161,16 @@ async def create( model: One of the available [TTS models](https://platform.openai.com/docs/models#tts): - `tts-1` or `tts-1-hd` + `tts-1`, `tts-1-hd` or `gpt-4o-mini-tts`. voice: The voice to use when generating the audio. Supported voices are `alloy`, `ash`, `coral`, `echo`, `fable`, `onyx`, `nova`, `sage` and `shimmer`. Previews of the voices are available in the [Text to speech guide](https://platform.openai.com/docs/guides/text-to-speech#voice-options). + instructions: Control the voice of your generated audio with additional instructions. Does not + work with `tts-1` or `tts-1-hd`. + response_format: The format to audio in. Supported formats are `mp3`, `opus`, `aac`, `flac`, `wav`, and `pcm`. @@ -184,6 +193,7 @@ async def create( "input": input, "model": model, "voice": voice, + "instructions": instructions, "response_format": response_format, "speed": speed, }, diff --git a/src/openai/resources/audio/transcriptions.py b/src/openai/resources/audio/transcriptions.py index f338ad067d..2a77f91d69 100644 --- a/src/openai/resources/audio/transcriptions.py +++ b/src/openai/resources/audio/transcriptions.py @@ -3,7 +3,7 @@ from __future__ import annotations import logging -from typing import TYPE_CHECKING, List, Union, Mapping, cast +from typing import TYPE_CHECKING, List, Union, Mapping, Optional, cast from typing_extensions import Literal, overload, assert_never import httpx @@ -13,6 +13,7 @@ from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven, FileTypes from ..._utils import ( extract_files, + required_args, maybe_transform, deepcopy_minimal, async_maybe_transform, @@ -20,12 +21,16 @@ from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ..._streaming import Stream, AsyncStream from ...types.audio import transcription_create_params from ..._base_client import make_request_options from ...types.audio_model import AudioModel from ...types.audio.transcription import Transcription from ...types.audio_response_format import AudioResponseFormat +from ...types.audio.transcription_include import TranscriptionInclude from ...types.audio.transcription_verbose import TranscriptionVerbose +from ...types.audio.transcription_stream_event import TranscriptionStreamEvent +from ...types.audio.transcription_create_response import TranscriptionCreateResponse __all__ = ["Transcriptions", "AsyncTranscriptions"] @@ -58,6 +63,7 @@ def create( *, file: FileTypes, model: Union[str, AudioModel], + include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, response_format: Union[Literal["json"], NotGiven] = NOT_GIVEN, language: str | NotGiven = NOT_GIVEN, prompt: str | NotGiven = NOT_GIVEN, @@ -77,6 +83,7 @@ def create( *, file: FileTypes, model: Union[str, AudioModel], + include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, response_format: Literal["verbose_json"], language: str | NotGiven = NOT_GIVEN, prompt: str | NotGiven = NOT_GIVEN, @@ -97,6 +104,7 @@ def create( file: FileTypes, model: Union[str, AudioModel], response_format: Literal["text", "srt", "vtt"], + include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, language: str | NotGiven = NOT_GIVEN, prompt: str | NotGiven = NOT_GIVEN, temperature: float | NotGiven = NOT_GIVEN, @@ -109,11 +117,96 @@ def create( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> str: ... + @overload + def create( + self, + *, + file: FileTypes, + model: Union[str, AudioModel], + stream: Literal[True], + include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, + language: str | NotGiven = NOT_GIVEN, + prompt: str | NotGiven = NOT_GIVEN, + response_format: Union[AudioResponseFormat, NotGiven] = NOT_GIVEN, + temperature: float | NotGiven = NOT_GIVEN, + timestamp_granularities: List[Literal["word", "segment"]] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Stream[TranscriptionStreamEvent]: + """ + Transcribes audio into the input language. + + Args: + file: + The audio file object (not file name) to transcribe, in one of these formats: + flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. + + model: ID of the model to use. The options are `gpt-4o-transcribe`, + `gpt-4o-mini-transcribe`, and `whisper-1` (which is powered by our open source + Whisper V2 model). + + stream: If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section of the Speech-to-Text guide](https://platform.openai.com/docs/guides/speech-to-text?lang=curl#streaming-transcriptions) + for more information. + + Note: Streaming is not supported for the `whisper-1` model and will be ignored. + + include: Additional information to include in the transcription response. `logprobs` will + return the log probabilities of the tokens in the response to understand the + model's confidence in the transcription. `logprobs` only works with + response_format set to `json` and only with the models `gpt-4o-transcribe` and + `gpt-4o-mini-transcribe`. + + language: The language of the input audio. Supplying the input language in + [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) + format will improve accuracy and latency. + + prompt: An optional text to guide the model's style or continue a previous audio + segment. The + [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) + should match the audio language. + + response_format: The format of the output, in one of these options: `json`, `text`, `srt`, + `verbose_json`, or `vtt`. For `gpt-4o-transcribe` and `gpt-4o-mini-transcribe`, + the only supported format is `json`. + + temperature: The sampling temperature, between 0 and 1. Higher values like 0.8 will make the + output more random, while lower values like 0.2 will make it more focused and + deterministic. If set to 0, the model will use + [log probability](https://en.wikipedia.org/wiki/Log_probability) to + automatically increase the temperature until certain thresholds are hit. + + timestamp_granularities: The timestamp granularities to populate for this transcription. + `response_format` must be set `verbose_json` to use timestamp granularities. + Either or both of these options are supported: `word`, or `segment`. Note: There + is no additional latency for segment timestamps, but generating word timestamps + incurs additional latency. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload def create( self, *, file: FileTypes, model: Union[str, AudioModel], + stream: bool, + include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, language: str | NotGiven = NOT_GIVEN, prompt: str | NotGiven = NOT_GIVEN, response_format: Union[AudioResponseFormat, NotGiven] = NOT_GIVEN, @@ -125,7 +218,7 @@ def create( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Transcription | TranscriptionVerbose | str: + ) -> TranscriptionCreateResponse | Stream[TranscriptionStreamEvent]: """ Transcribes audio into the input language. @@ -134,8 +227,24 @@ def create( The audio file object (not file name) to transcribe, in one of these formats: flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. - model: ID of the model to use. Only `whisper-1` (which is powered by our open source - Whisper V2 model) is currently available. + model: ID of the model to use. The options are `gpt-4o-transcribe`, + `gpt-4o-mini-transcribe`, and `whisper-1` (which is powered by our open source + Whisper V2 model). + + stream: If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section of the Speech-to-Text guide](https://platform.openai.com/docs/guides/speech-to-text?lang=curl#streaming-transcriptions) + for more information. + + Note: Streaming is not supported for the `whisper-1` model and will be ignored. + + include: Additional information to include in the transcription response. `logprobs` will + return the log probabilities of the tokens in the response to understand the + model's confidence in the transcription. `logprobs` only works with + response_format set to `json` and only with the models `gpt-4o-transcribe` and + `gpt-4o-mini-transcribe`. language: The language of the input audio. Supplying the input language in [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) @@ -147,7 +256,8 @@ def create( should match the audio language. response_format: The format of the output, in one of these options: `json`, `text`, `srt`, - `verbose_json`, or `vtt`. + `verbose_json`, or `vtt`. For `gpt-4o-transcribe` and `gpt-4o-mini-transcribe`, + the only supported format is `json`. temperature: The sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and @@ -169,13 +279,37 @@ def create( timeout: Override the client-level default timeout for this request, in seconds """ + ... + + @required_args(["file", "model"], ["file", "model", "stream"]) + def create( + self, + *, + file: FileTypes, + model: Union[str, AudioModel], + include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, + language: str | NotGiven = NOT_GIVEN, + prompt: str | NotGiven = NOT_GIVEN, + response_format: Union[AudioResponseFormat, NotGiven] = NOT_GIVEN, + stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, + temperature: float | NotGiven = NOT_GIVEN, + timestamp_granularities: List[Literal["word", "segment"]] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> str | Transcription | TranscriptionVerbose | Stream[TranscriptionStreamEvent]: body = deepcopy_minimal( { "file": file, "model": model, + "include": include, "language": language, "prompt": prompt, "response_format": response_format, + "stream": stream, "temperature": temperature, "timestamp_granularities": timestamp_granularities, } @@ -193,6 +327,8 @@ def create( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), cast_to=_get_response_format_type(response_format), + stream=stream or False, + stream_cls=Stream[TranscriptionStreamEvent], ) @@ -226,6 +362,7 @@ async def create( language: str | NotGiven = NOT_GIVEN, prompt: str | NotGiven = NOT_GIVEN, temperature: float | NotGiven = NOT_GIVEN, + include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, timestamp_granularities: List[Literal["word", "segment"]] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -241,6 +378,7 @@ async def create( *, file: FileTypes, model: Union[str, AudioModel], + include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, response_format: Literal["verbose_json"], language: str | NotGiven = NOT_GIVEN, prompt: str | NotGiven = NOT_GIVEN, @@ -260,6 +398,7 @@ async def create( *, file: FileTypes, model: Union[str, AudioModel], + include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, response_format: Literal["text", "srt", "vtt"], language: str | NotGiven = NOT_GIVEN, prompt: str | NotGiven = NOT_GIVEN, @@ -273,11 +412,96 @@ async def create( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> str: ... + @overload + async def create( + self, + *, + file: FileTypes, + model: Union[str, AudioModel], + stream: Literal[True], + include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, + language: str | NotGiven = NOT_GIVEN, + prompt: str | NotGiven = NOT_GIVEN, + response_format: Union[AudioResponseFormat, NotGiven] = NOT_GIVEN, + temperature: float | NotGiven = NOT_GIVEN, + timestamp_granularities: List[Literal["word", "segment"]] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> AsyncStream[TranscriptionStreamEvent]: + """ + Transcribes audio into the input language. + + Args: + file: + The audio file object (not file name) to transcribe, in one of these formats: + flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. + + model: ID of the model to use. The options are `gpt-4o-transcribe`, + `gpt-4o-mini-transcribe`, and `whisper-1` (which is powered by our open source + Whisper V2 model). + + stream: If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section of the Speech-to-Text guide](https://platform.openai.com/docs/guides/speech-to-text?lang=curl#streaming-transcriptions) + for more information. + + Note: Streaming is not supported for the `whisper-1` model and will be ignored. + + include: Additional information to include in the transcription response. `logprobs` will + return the log probabilities of the tokens in the response to understand the + model's confidence in the transcription. `logprobs` only works with + response_format set to `json` and only with the models `gpt-4o-transcribe` and + `gpt-4o-mini-transcribe`. + + language: The language of the input audio. Supplying the input language in + [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) + format will improve accuracy and latency. + + prompt: An optional text to guide the model's style or continue a previous audio + segment. The + [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) + should match the audio language. + + response_format: The format of the output, in one of these options: `json`, `text`, `srt`, + `verbose_json`, or `vtt`. For `gpt-4o-transcribe` and `gpt-4o-mini-transcribe`, + the only supported format is `json`. + + temperature: The sampling temperature, between 0 and 1. Higher values like 0.8 will make the + output more random, while lower values like 0.2 will make it more focused and + deterministic. If set to 0, the model will use + [log probability](https://en.wikipedia.org/wiki/Log_probability) to + automatically increase the temperature until certain thresholds are hit. + + timestamp_granularities: The timestamp granularities to populate for this transcription. + `response_format` must be set `verbose_json` to use timestamp granularities. + Either or both of these options are supported: `word`, or `segment`. Note: There + is no additional latency for segment timestamps, but generating word timestamps + incurs additional latency. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload async def create( self, *, file: FileTypes, model: Union[str, AudioModel], + stream: bool, + include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, language: str | NotGiven = NOT_GIVEN, prompt: str | NotGiven = NOT_GIVEN, response_format: Union[AudioResponseFormat, NotGiven] = NOT_GIVEN, @@ -289,7 +513,7 @@ async def create( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Transcription | TranscriptionVerbose | str: + ) -> TranscriptionCreateResponse | AsyncStream[TranscriptionStreamEvent]: """ Transcribes audio into the input language. @@ -298,8 +522,24 @@ async def create( The audio file object (not file name) to transcribe, in one of these formats: flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. - model: ID of the model to use. Only `whisper-1` (which is powered by our open source - Whisper V2 model) is currently available. + model: ID of the model to use. The options are `gpt-4o-transcribe`, + `gpt-4o-mini-transcribe`, and `whisper-1` (which is powered by our open source + Whisper V2 model). + + stream: If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section of the Speech-to-Text guide](https://platform.openai.com/docs/guides/speech-to-text?lang=curl#streaming-transcriptions) + for more information. + + Note: Streaming is not supported for the `whisper-1` model and will be ignored. + + include: Additional information to include in the transcription response. `logprobs` will + return the log probabilities of the tokens in the response to understand the + model's confidence in the transcription. `logprobs` only works with + response_format set to `json` and only with the models `gpt-4o-transcribe` and + `gpt-4o-mini-transcribe`. language: The language of the input audio. Supplying the input language in [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) @@ -311,7 +551,8 @@ async def create( should match the audio language. response_format: The format of the output, in one of these options: `json`, `text`, `srt`, - `verbose_json`, or `vtt`. + `verbose_json`, or `vtt`. For `gpt-4o-transcribe` and `gpt-4o-mini-transcribe`, + the only supported format is `json`. temperature: The sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and @@ -333,13 +574,37 @@ async def create( timeout: Override the client-level default timeout for this request, in seconds """ + ... + + @required_args(["file", "model"], ["file", "model", "stream"]) + async def create( + self, + *, + file: FileTypes, + model: Union[str, AudioModel], + include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, + language: str | NotGiven = NOT_GIVEN, + prompt: str | NotGiven = NOT_GIVEN, + response_format: Union[AudioResponseFormat, NotGiven] = NOT_GIVEN, + stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, + temperature: float | NotGiven = NOT_GIVEN, + timestamp_granularities: List[Literal["word", "segment"]] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Transcription | TranscriptionVerbose | str | AsyncStream[TranscriptionStreamEvent]: body = deepcopy_minimal( { "file": file, "model": model, + "include": include, "language": language, "prompt": prompt, "response_format": response_format, + "stream": stream, "temperature": temperature, "timestamp_granularities": timestamp_granularities, } @@ -357,6 +622,8 @@ async def create( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), cast_to=_get_response_format_type(response_format), + stream=stream or False, + stream_cls=AsyncStream[TranscriptionStreamEvent], ) diff --git a/src/openai/resources/audio/translations.py b/src/openai/resources/audio/translations.py index cd3132dc57..f55dbd0ee5 100644 --- a/src/openai/resources/audio/translations.py +++ b/src/openai/resources/audio/translations.py @@ -9,7 +9,6 @@ import httpx from ... import _legacy_response -from ...types import AudioResponseFormat from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven, FileTypes from ..._utils import ( extract_files, @@ -109,7 +108,7 @@ def create( file: FileTypes, model: Union[str, AudioModel], prompt: str | NotGiven = NOT_GIVEN, - response_format: Union[AudioResponseFormat, NotGiven] = NOT_GIVEN, + response_format: Union[Literal["json", "text", "srt", "verbose_json", "vtt"], NotGiven] = NOT_GIVEN, temperature: float | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. diff --git a/src/openai/resources/beta/realtime/__init__.py b/src/openai/resources/beta/realtime/__init__.py index 474434e6e1..7ab3d9931c 100644 --- a/src/openai/resources/beta/realtime/__init__.py +++ b/src/openai/resources/beta/realtime/__init__.py @@ -16,6 +16,14 @@ SessionsWithStreamingResponse, AsyncSessionsWithStreamingResponse, ) +from .transcription_sessions import ( + TranscriptionSessions, + AsyncTranscriptionSessions, + TranscriptionSessionsWithRawResponse, + AsyncTranscriptionSessionsWithRawResponse, + TranscriptionSessionsWithStreamingResponse, + AsyncTranscriptionSessionsWithStreamingResponse, +) __all__ = [ "Sessions", @@ -24,6 +32,12 @@ "AsyncSessionsWithRawResponse", "SessionsWithStreamingResponse", "AsyncSessionsWithStreamingResponse", + "TranscriptionSessions", + "AsyncTranscriptionSessions", + "TranscriptionSessionsWithRawResponse", + "AsyncTranscriptionSessionsWithRawResponse", + "TranscriptionSessionsWithStreamingResponse", + "AsyncTranscriptionSessionsWithStreamingResponse", "Realtime", "AsyncRealtime", "RealtimeWithRawResponse", diff --git a/src/openai/resources/beta/realtime/realtime.py b/src/openai/resources/beta/realtime/realtime.py index cd610d9089..76e57f8cb7 100644 --- a/src/openai/resources/beta/realtime/realtime.py +++ b/src/openai/resources/beta/realtime/realtime.py @@ -32,7 +32,19 @@ from ...._resource import SyncAPIResource, AsyncAPIResource from ...._exceptions import OpenAIError from ...._base_client import _merge_mappings -from ....types.beta.realtime import session_update_event_param, response_create_event_param +from ....types.beta.realtime import ( + session_update_event_param, + response_create_event_param, + transcription_session_update_param, +) +from .transcription_sessions import ( + TranscriptionSessions, + AsyncTranscriptionSessions, + TranscriptionSessionsWithRawResponse, + AsyncTranscriptionSessionsWithRawResponse, + TranscriptionSessionsWithStreamingResponse, + AsyncTranscriptionSessionsWithStreamingResponse, +) from ....types.websocket_connection_options import WebsocketConnectionOptions from ....types.beta.realtime.realtime_client_event import RealtimeClientEvent from ....types.beta.realtime.realtime_server_event import RealtimeServerEvent @@ -55,6 +67,10 @@ class Realtime(SyncAPIResource): def sessions(self) -> Sessions: return Sessions(self._client) + @cached_property + def transcription_sessions(self) -> TranscriptionSessions: + return TranscriptionSessions(self._client) + @cached_property def with_raw_response(self) -> RealtimeWithRawResponse: """ @@ -107,6 +123,10 @@ class AsyncRealtime(AsyncAPIResource): def sessions(self) -> AsyncSessions: return AsyncSessions(self._client) + @cached_property + def transcription_sessions(self) -> AsyncTranscriptionSessions: + return AsyncTranscriptionSessions(self._client) + @cached_property def with_raw_response(self) -> AsyncRealtimeWithRawResponse: """ @@ -162,6 +182,10 @@ def __init__(self, realtime: Realtime) -> None: def sessions(self) -> SessionsWithRawResponse: return SessionsWithRawResponse(self._realtime.sessions) + @cached_property + def transcription_sessions(self) -> TranscriptionSessionsWithRawResponse: + return TranscriptionSessionsWithRawResponse(self._realtime.transcription_sessions) + class AsyncRealtimeWithRawResponse: def __init__(self, realtime: AsyncRealtime) -> None: @@ -171,6 +195,10 @@ def __init__(self, realtime: AsyncRealtime) -> None: def sessions(self) -> AsyncSessionsWithRawResponse: return AsyncSessionsWithRawResponse(self._realtime.sessions) + @cached_property + def transcription_sessions(self) -> AsyncTranscriptionSessionsWithRawResponse: + return AsyncTranscriptionSessionsWithRawResponse(self._realtime.transcription_sessions) + class RealtimeWithStreamingResponse: def __init__(self, realtime: Realtime) -> None: @@ -180,6 +208,10 @@ def __init__(self, realtime: Realtime) -> None: def sessions(self) -> SessionsWithStreamingResponse: return SessionsWithStreamingResponse(self._realtime.sessions) + @cached_property + def transcription_sessions(self) -> TranscriptionSessionsWithStreamingResponse: + return TranscriptionSessionsWithStreamingResponse(self._realtime.transcription_sessions) + class AsyncRealtimeWithStreamingResponse: def __init__(self, realtime: AsyncRealtime) -> None: @@ -189,14 +221,19 @@ def __init__(self, realtime: AsyncRealtime) -> None: def sessions(self) -> AsyncSessionsWithStreamingResponse: return AsyncSessionsWithStreamingResponse(self._realtime.sessions) + @cached_property + def transcription_sessions(self) -> AsyncTranscriptionSessionsWithStreamingResponse: + return AsyncTranscriptionSessionsWithStreamingResponse(self._realtime.transcription_sessions) + class AsyncRealtimeConnection: """Represents a live websocket connection to the Realtime API""" session: AsyncRealtimeSessionResource response: AsyncRealtimeResponseResource - conversation: AsyncRealtimeConversationResource input_audio_buffer: AsyncRealtimeInputAudioBufferResource + conversation: AsyncRealtimeConversationResource + transcription_session: AsyncRealtimeTranscriptionSessionResource _connection: AsyncWebsocketConnection @@ -205,8 +242,9 @@ def __init__(self, connection: AsyncWebsocketConnection) -> None: self.session = AsyncRealtimeSessionResource(self) self.response = AsyncRealtimeResponseResource(self) - self.conversation = AsyncRealtimeConversationResource(self) self.input_audio_buffer = AsyncRealtimeInputAudioBufferResource(self) + self.conversation = AsyncRealtimeConversationResource(self) + self.transcription_session = AsyncRealtimeTranscriptionSessionResource(self) async def __aiter__(self) -> AsyncIterator[RealtimeServerEvent]: """ @@ -377,8 +415,9 @@ class RealtimeConnection: session: RealtimeSessionResource response: RealtimeResponseResource - conversation: RealtimeConversationResource input_audio_buffer: RealtimeInputAudioBufferResource + conversation: RealtimeConversationResource + transcription_session: RealtimeTranscriptionSessionResource _connection: WebsocketConnection @@ -387,8 +426,9 @@ def __init__(self, connection: WebsocketConnection) -> None: self.session = RealtimeSessionResource(self) self.response = RealtimeResponseResource(self) - self.conversation = RealtimeConversationResource(self) self.input_audio_buffer = RealtimeInputAudioBufferResource(self) + self.conversation = RealtimeConversationResource(self) + self.transcription_session = RealtimeTranscriptionSessionResource(self) def __iter__(self) -> Iterator[RealtimeServerEvent]: """ @@ -582,20 +622,6 @@ def update(self, *, session: session_update_event_param.Session, event_id: str | class RealtimeResponseResource(BaseRealtimeConnectionResource): - def cancel(self, *, event_id: str | NotGiven = NOT_GIVEN, response_id: str | NotGiven = NOT_GIVEN) -> None: - """Send this event to cancel an in-progress response. - - The server will respond - with a `response.cancelled` event or an error if there is no response to - cancel. - """ - self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given({"type": "response.cancel", "event_id": event_id, "response_id": response_id}), - ) - ) - def create( self, *, @@ -626,6 +652,70 @@ def create( ) ) + def cancel(self, *, event_id: str | NotGiven = NOT_GIVEN, response_id: str | NotGiven = NOT_GIVEN) -> None: + """Send this event to cancel an in-progress response. + + The server will respond + with a `response.cancelled` event or an error if there is no response to + cancel. + """ + self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given({"type": "response.cancel", "event_id": event_id, "response_id": response_id}), + ) + ) + + +class RealtimeInputAudioBufferResource(BaseRealtimeConnectionResource): + def clear(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: + """Send this event to clear the audio bytes in the buffer. + + The server will + respond with an `input_audio_buffer.cleared` event. + """ + self._connection.send( + cast(RealtimeClientEventParam, strip_not_given({"type": "input_audio_buffer.clear", "event_id": event_id})) + ) + + def commit(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: + """ + Send this event to commit the user input audio buffer, which will create a + new user message item in the conversation. This event will produce an error + if the input audio buffer is empty. When in Server VAD mode, the client does + not need to send this event, the server will commit the audio buffer + automatically. + + Committing the input audio buffer will trigger input audio transcription + (if enabled in session configuration), but it will not create a response + from the model. The server will respond with an `input_audio_buffer.committed` + event. + """ + self._connection.send( + cast(RealtimeClientEventParam, strip_not_given({"type": "input_audio_buffer.commit", "event_id": event_id})) + ) + + def append(self, *, audio: str, event_id: str | NotGiven = NOT_GIVEN) -> None: + """Send this event to append audio bytes to the input audio buffer. + + The audio + buffer is temporary storage you can write to and later commit. In Server VAD + mode, the audio buffer is used to detect speech and the server will decide + when to commit. When Server VAD is disabled, you must commit the audio buffer + manually. + + The client may choose how much audio to place in each event up to a maximum + of 15 MiB, for example streaming smaller chunks from the client may allow the + VAD to be more responsive. Unlike made other client events, the server will + not send a confirmation response to this event. + """ + self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given({"type": "input_audio_buffer.append", "audio": audio, "event_id": event_id}), + ) + ) + class RealtimeConversationResource(BaseRealtimeConnectionResource): @cached_property @@ -711,53 +801,30 @@ def truncate( ) ) - -class RealtimeInputAudioBufferResource(BaseRealtimeConnectionResource): - def clear(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: - """Send this event to clear the audio bytes in the buffer. - - The server will - respond with an `input_audio_buffer.cleared` event. + def retrieve(self, *, item_id: str, event_id: str | NotGiven = NOT_GIVEN) -> None: """ - self._connection.send( - cast(RealtimeClientEventParam, strip_not_given({"type": "input_audio_buffer.clear", "event_id": event_id})) - ) - - def commit(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: - """ - Send this event to commit the user input audio buffer, which will create a - new user message item in the conversation. This event will produce an error - if the input audio buffer is empty. When in Server VAD mode, the client does - not need to send this event, the server will commit the audio buffer - automatically. - - Committing the input audio buffer will trigger input audio transcription - (if enabled in session configuration), but it will not create a response - from the model. The server will respond with an `input_audio_buffer.committed` - event. + Send this event when you want to retrieve the server's representation of a specific item in the conversation history. This is useful, for example, to inspect user audio after noise cancellation and VAD. + The server will respond with a `conversation.item.retrieved` event, + unless the item does not exist in the conversation history, in which case the + server will respond with an error. """ self._connection.send( - cast(RealtimeClientEventParam, strip_not_given({"type": "input_audio_buffer.commit", "event_id": event_id})) + cast( + RealtimeClientEventParam, + strip_not_given({"type": "conversation.item.retrieve", "item_id": item_id, "event_id": event_id}), + ) ) - def append(self, *, audio: str, event_id: str | NotGiven = NOT_GIVEN) -> None: - """Send this event to append audio bytes to the input audio buffer. - The audio - buffer is temporary storage you can write to and later commit. In Server VAD - mode, the audio buffer is used to detect speech and the server will decide - when to commit. When Server VAD is disabled, you must commit the audio buffer - manually. - - The client may choose how much audio to place in each event up to a maximum - of 15 MiB, for example streaming smaller chunks from the client may allow the - VAD to be more responsive. Unlike made other client events, the server will - not send a confirmation response to this event. - """ +class RealtimeTranscriptionSessionResource(BaseRealtimeConnectionResource): + def update( + self, *, session: transcription_session_update_param.Session, event_id: str | NotGiven = NOT_GIVEN + ) -> None: + """Send this event to update a transcription session.""" self._connection.send( cast( RealtimeClientEventParam, - strip_not_given({"type": "input_audio_buffer.append", "audio": audio, "event_id": event_id}), + strip_not_given({"type": "transcription_session.update", "session": session, "event_id": event_id}), ) ) @@ -792,20 +859,6 @@ async def update( class AsyncRealtimeResponseResource(BaseAsyncRealtimeConnectionResource): - async def cancel(self, *, event_id: str | NotGiven = NOT_GIVEN, response_id: str | NotGiven = NOT_GIVEN) -> None: - """Send this event to cancel an in-progress response. - - The server will respond - with a `response.cancelled` event or an error if there is no response to - cancel. - """ - await self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given({"type": "response.cancel", "event_id": event_id, "response_id": response_id}), - ) - ) - async def create( self, *, @@ -836,6 +889,70 @@ async def create( ) ) + async def cancel(self, *, event_id: str | NotGiven = NOT_GIVEN, response_id: str | NotGiven = NOT_GIVEN) -> None: + """Send this event to cancel an in-progress response. + + The server will respond + with a `response.cancelled` event or an error if there is no response to + cancel. + """ + await self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given({"type": "response.cancel", "event_id": event_id, "response_id": response_id}), + ) + ) + + +class AsyncRealtimeInputAudioBufferResource(BaseAsyncRealtimeConnectionResource): + async def clear(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: + """Send this event to clear the audio bytes in the buffer. + + The server will + respond with an `input_audio_buffer.cleared` event. + """ + await self._connection.send( + cast(RealtimeClientEventParam, strip_not_given({"type": "input_audio_buffer.clear", "event_id": event_id})) + ) + + async def commit(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: + """ + Send this event to commit the user input audio buffer, which will create a + new user message item in the conversation. This event will produce an error + if the input audio buffer is empty. When in Server VAD mode, the client does + not need to send this event, the server will commit the audio buffer + automatically. + + Committing the input audio buffer will trigger input audio transcription + (if enabled in session configuration), but it will not create a response + from the model. The server will respond with an `input_audio_buffer.committed` + event. + """ + await self._connection.send( + cast(RealtimeClientEventParam, strip_not_given({"type": "input_audio_buffer.commit", "event_id": event_id})) + ) + + async def append(self, *, audio: str, event_id: str | NotGiven = NOT_GIVEN) -> None: + """Send this event to append audio bytes to the input audio buffer. + + The audio + buffer is temporary storage you can write to and later commit. In Server VAD + mode, the audio buffer is used to detect speech and the server will decide + when to commit. When Server VAD is disabled, you must commit the audio buffer + manually. + + The client may choose how much audio to place in each event up to a maximum + of 15 MiB, for example streaming smaller chunks from the client may allow the + VAD to be more responsive. Unlike made other client events, the server will + not send a confirmation response to this event. + """ + await self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given({"type": "input_audio_buffer.append", "audio": audio, "event_id": event_id}), + ) + ) + class AsyncRealtimeConversationResource(BaseAsyncRealtimeConnectionResource): @cached_property @@ -921,52 +1038,29 @@ async def truncate( ) ) - -class AsyncRealtimeInputAudioBufferResource(BaseAsyncRealtimeConnectionResource): - async def clear(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: - """Send this event to clear the audio bytes in the buffer. - - The server will - respond with an `input_audio_buffer.cleared` event. - """ - await self._connection.send( - cast(RealtimeClientEventParam, strip_not_given({"type": "input_audio_buffer.clear", "event_id": event_id})) - ) - - async def commit(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: + async def retrieve(self, *, item_id: str, event_id: str | NotGiven = NOT_GIVEN) -> None: """ - Send this event to commit the user input audio buffer, which will create a - new user message item in the conversation. This event will produce an error - if the input audio buffer is empty. When in Server VAD mode, the client does - not need to send this event, the server will commit the audio buffer - automatically. - - Committing the input audio buffer will trigger input audio transcription - (if enabled in session configuration), but it will not create a response - from the model. The server will respond with an `input_audio_buffer.committed` - event. + Send this event when you want to retrieve the server's representation of a specific item in the conversation history. This is useful, for example, to inspect user audio after noise cancellation and VAD. + The server will respond with a `conversation.item.retrieved` event, + unless the item does not exist in the conversation history, in which case the + server will respond with an error. """ await self._connection.send( - cast(RealtimeClientEventParam, strip_not_given({"type": "input_audio_buffer.commit", "event_id": event_id})) + cast( + RealtimeClientEventParam, + strip_not_given({"type": "conversation.item.retrieve", "item_id": item_id, "event_id": event_id}), + ) ) - async def append(self, *, audio: str, event_id: str | NotGiven = NOT_GIVEN) -> None: - """Send this event to append audio bytes to the input audio buffer. - - The audio - buffer is temporary storage you can write to and later commit. In Server VAD - mode, the audio buffer is used to detect speech and the server will decide - when to commit. When Server VAD is disabled, you must commit the audio buffer - manually. - The client may choose how much audio to place in each event up to a maximum - of 15 MiB, for example streaming smaller chunks from the client may allow the - VAD to be more responsive. Unlike made other client events, the server will - not send a confirmation response to this event. - """ +class AsyncRealtimeTranscriptionSessionResource(BaseAsyncRealtimeConnectionResource): + async def update( + self, *, session: transcription_session_update_param.Session, event_id: str | NotGiven = NOT_GIVEN + ) -> None: + """Send this event to update a transcription session.""" await self._connection.send( cast( RealtimeClientEventParam, - strip_not_given({"type": "input_audio_buffer.append", "audio": audio, "event_id": event_id}), + strip_not_given({"type": "transcription_session.update", "session": session, "event_id": event_id}), ) ) diff --git a/src/openai/resources/beta/realtime/sessions.py b/src/openai/resources/beta/realtime/sessions.py index 4b337b7c19..5884e54de2 100644 --- a/src/openai/resources/beta/realtime/sessions.py +++ b/src/openai/resources/beta/realtime/sessions.py @@ -47,6 +47,7 @@ def create( self, *, input_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] | NotGiven = NOT_GIVEN, + input_audio_noise_reduction: session_create_params.InputAudioNoiseReduction | NotGiven = NOT_GIVEN, input_audio_transcription: session_create_params.InputAudioTranscription | NotGiven = NOT_GIVEN, instructions: str | NotGiven = NOT_GIVEN, max_response_output_tokens: Union[int, Literal["inf"]] | NotGiven = NOT_GIVEN, @@ -86,14 +87,20 @@ def create( `pcm16`, input audio must be 16-bit PCM at a 24kHz sample rate, single channel (mono), and little-endian byte order. + input_audio_noise_reduction: Configuration for input audio noise reduction. This can be set to `null` to turn + off. Noise reduction filters audio added to the input audio buffer before it is + sent to VAD and the model. Filtering the audio can improve VAD and turn + detection accuracy (reducing false positives) and model performance by improving + perception of the input audio. + input_audio_transcription: Configuration for input audio transcription, defaults to off and can be set to `null` to turn off once on. Input audio transcription is not native to the model, since the model consumes audio directly. Transcription runs asynchronously through - [OpenAI Whisper transcription](https://platform.openai.com/docs/api-reference/audio/createTranscription) - and should be treated as rough guidance rather than the representation - understood by the model. The client can optionally set the language and prompt - for transcription, these fields will be passed to the Whisper API. + [the /audio/transcriptions endpoint](https://platform.openai.com/docs/api-reference/audio/createTranscription) + and should be treated as guidance of input audio content rather than precisely + what the model heard. The client can optionally set the language and prompt for + transcription, these offer additional guidance to the transcription service. instructions: The default system instructions (i.e. system message) prepended to model calls. This field allows the client to guide the model on desired responses. The model @@ -119,16 +126,24 @@ def create( output_audio_format: The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, output audio is sampled at a rate of 24kHz. - temperature: Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8. + temperature: Sampling temperature for the model, limited to [0.6, 1.2]. For audio models a + temperature of 0.8 is highly recommended for best performance. tool_choice: How the model chooses tools. Options are `auto`, `none`, `required`, or specify a function. tools: Tools (functions) available to the model. - turn_detection: Configuration for turn detection. Can be set to `null` to turn off. Server VAD - means that the model will detect the start and end of speech based on audio - volume and respond at the end of user speech. + turn_detection: Configuration for turn detection, ether Server VAD or Semantic VAD. This can be + set to `null` to turn off, in which case the client must manually trigger model + response. Server VAD means that the model will detect the start and end of + speech based on audio volume and respond at the end of user speech. Semantic VAD + is more advanced and uses a turn detection model (in conjuction with VAD) to + semantically estimate whether the user has finished speaking, then dynamically + sets a timeout based on this probability. For example, if user audio trails off + with "uhhm", the model will score a low probability of turn end and wait longer + for the user to continue speaking. This can be useful for more natural + conversations, but may have a higher latency. voice: The voice the model uses to respond. Voice cannot be changed during the session once the model has responded with audio at least once. Current voice options are @@ -148,6 +163,7 @@ def create( body=maybe_transform( { "input_audio_format": input_audio_format, + "input_audio_noise_reduction": input_audio_noise_reduction, "input_audio_transcription": input_audio_transcription, "instructions": instructions, "max_response_output_tokens": max_response_output_tokens, @@ -193,6 +209,7 @@ async def create( self, *, input_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] | NotGiven = NOT_GIVEN, + input_audio_noise_reduction: session_create_params.InputAudioNoiseReduction | NotGiven = NOT_GIVEN, input_audio_transcription: session_create_params.InputAudioTranscription | NotGiven = NOT_GIVEN, instructions: str | NotGiven = NOT_GIVEN, max_response_output_tokens: Union[int, Literal["inf"]] | NotGiven = NOT_GIVEN, @@ -232,14 +249,20 @@ async def create( `pcm16`, input audio must be 16-bit PCM at a 24kHz sample rate, single channel (mono), and little-endian byte order. + input_audio_noise_reduction: Configuration for input audio noise reduction. This can be set to `null` to turn + off. Noise reduction filters audio added to the input audio buffer before it is + sent to VAD and the model. Filtering the audio can improve VAD and turn + detection accuracy (reducing false positives) and model performance by improving + perception of the input audio. + input_audio_transcription: Configuration for input audio transcription, defaults to off and can be set to `null` to turn off once on. Input audio transcription is not native to the model, since the model consumes audio directly. Transcription runs asynchronously through - [OpenAI Whisper transcription](https://platform.openai.com/docs/api-reference/audio/createTranscription) - and should be treated as rough guidance rather than the representation - understood by the model. The client can optionally set the language and prompt - for transcription, these fields will be passed to the Whisper API. + [the /audio/transcriptions endpoint](https://platform.openai.com/docs/api-reference/audio/createTranscription) + and should be treated as guidance of input audio content rather than precisely + what the model heard. The client can optionally set the language and prompt for + transcription, these offer additional guidance to the transcription service. instructions: The default system instructions (i.e. system message) prepended to model calls. This field allows the client to guide the model on desired responses. The model @@ -265,16 +288,24 @@ async def create( output_audio_format: The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, output audio is sampled at a rate of 24kHz. - temperature: Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8. + temperature: Sampling temperature for the model, limited to [0.6, 1.2]. For audio models a + temperature of 0.8 is highly recommended for best performance. tool_choice: How the model chooses tools. Options are `auto`, `none`, `required`, or specify a function. tools: Tools (functions) available to the model. - turn_detection: Configuration for turn detection. Can be set to `null` to turn off. Server VAD - means that the model will detect the start and end of speech based on audio - volume and respond at the end of user speech. + turn_detection: Configuration for turn detection, ether Server VAD or Semantic VAD. This can be + set to `null` to turn off, in which case the client must manually trigger model + response. Server VAD means that the model will detect the start and end of + speech based on audio volume and respond at the end of user speech. Semantic VAD + is more advanced and uses a turn detection model (in conjuction with VAD) to + semantically estimate whether the user has finished speaking, then dynamically + sets a timeout based on this probability. For example, if user audio trails off + with "uhhm", the model will score a low probability of turn end and wait longer + for the user to continue speaking. This can be useful for more natural + conversations, but may have a higher latency. voice: The voice the model uses to respond. Voice cannot be changed during the session once the model has responded with audio at least once. Current voice options are @@ -294,6 +325,7 @@ async def create( body=await async_maybe_transform( { "input_audio_format": input_audio_format, + "input_audio_noise_reduction": input_audio_noise_reduction, "input_audio_transcription": input_audio_transcription, "instructions": instructions, "max_response_output_tokens": max_response_output_tokens, diff --git a/src/openai/resources/beta/realtime/transcription_sessions.py b/src/openai/resources/beta/realtime/transcription_sessions.py new file mode 100644 index 0000000000..0917da71fa --- /dev/null +++ b/src/openai/resources/beta/realtime/transcription_sessions.py @@ -0,0 +1,277 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Literal + +import httpx + +from .... import _legacy_response +from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._utils import ( + maybe_transform, + async_maybe_transform, +) +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ...._base_client import make_request_options +from ....types.beta.realtime import transcription_session_create_params +from ....types.beta.realtime.transcription_session import TranscriptionSession + +__all__ = ["TranscriptionSessions", "AsyncTranscriptionSessions"] + + +class TranscriptionSessions(SyncAPIResource): + @cached_property + def with_raw_response(self) -> TranscriptionSessionsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return TranscriptionSessionsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> TranscriptionSessionsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return TranscriptionSessionsWithStreamingResponse(self) + + def create( + self, + *, + include: List[str] | NotGiven = NOT_GIVEN, + input_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] | NotGiven = NOT_GIVEN, + input_audio_noise_reduction: transcription_session_create_params.InputAudioNoiseReduction + | NotGiven = NOT_GIVEN, + input_audio_transcription: transcription_session_create_params.InputAudioTranscription | NotGiven = NOT_GIVEN, + modalities: List[Literal["text", "audio"]] | NotGiven = NOT_GIVEN, + turn_detection: transcription_session_create_params.TurnDetection | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> TranscriptionSession: + """ + Create an ephemeral API token for use in client-side applications with the + Realtime API specifically for realtime transcriptions. Can be configured with + the same session parameters as the `transcription_session.update` client event. + + It responds with a session object, plus a `client_secret` key which contains a + usable ephemeral API token that can be used to authenticate browser clients for + the Realtime API. + + Args: + include: + The set of items to include in the transcription. Current available items are: + + - `item.input_audio_transcription.logprobs` + + input_audio_format: The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For + `pcm16`, input audio must be 16-bit PCM at a 24kHz sample rate, single channel + (mono), and little-endian byte order. + + input_audio_noise_reduction: Configuration for input audio noise reduction. This can be set to `null` to turn + off. Noise reduction filters audio added to the input audio buffer before it is + sent to VAD and the model. Filtering the audio can improve VAD and turn + detection accuracy (reducing false positives) and model performance by improving + perception of the input audio. + + input_audio_transcription: Configuration for input audio transcription. The client can optionally set the + language and prompt for transcription, these offer additional guidance to the + transcription service. + + modalities: The set of modalities the model can respond with. To disable audio, set this to + ["text"]. + + turn_detection: Configuration for turn detection, ether Server VAD or Semantic VAD. This can be + set to `null` to turn off, in which case the client must manually trigger model + response. Server VAD means that the model will detect the start and end of + speech based on audio volume and respond at the end of user speech. Semantic VAD + is more advanced and uses a turn detection model (in conjuction with VAD) to + semantically estimate whether the user has finished speaking, then dynamically + sets a timeout based on this probability. For example, if user audio trails off + with "uhhm", the model will score a low probability of turn end and wait longer + for the user to continue speaking. This can be useful for more natural + conversations, but may have a higher latency. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} + return self._post( + "/realtime/transcription_sessions", + body=maybe_transform( + { + "include": include, + "input_audio_format": input_audio_format, + "input_audio_noise_reduction": input_audio_noise_reduction, + "input_audio_transcription": input_audio_transcription, + "modalities": modalities, + "turn_detection": turn_detection, + }, + transcription_session_create_params.TranscriptionSessionCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TranscriptionSession, + ) + + +class AsyncTranscriptionSessions(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncTranscriptionSessionsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncTranscriptionSessionsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncTranscriptionSessionsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncTranscriptionSessionsWithStreamingResponse(self) + + async def create( + self, + *, + include: List[str] | NotGiven = NOT_GIVEN, + input_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] | NotGiven = NOT_GIVEN, + input_audio_noise_reduction: transcription_session_create_params.InputAudioNoiseReduction + | NotGiven = NOT_GIVEN, + input_audio_transcription: transcription_session_create_params.InputAudioTranscription | NotGiven = NOT_GIVEN, + modalities: List[Literal["text", "audio"]] | NotGiven = NOT_GIVEN, + turn_detection: transcription_session_create_params.TurnDetection | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> TranscriptionSession: + """ + Create an ephemeral API token for use in client-side applications with the + Realtime API specifically for realtime transcriptions. Can be configured with + the same session parameters as the `transcription_session.update` client event. + + It responds with a session object, plus a `client_secret` key which contains a + usable ephemeral API token that can be used to authenticate browser clients for + the Realtime API. + + Args: + include: + The set of items to include in the transcription. Current available items are: + + - `item.input_audio_transcription.logprobs` + + input_audio_format: The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For + `pcm16`, input audio must be 16-bit PCM at a 24kHz sample rate, single channel + (mono), and little-endian byte order. + + input_audio_noise_reduction: Configuration for input audio noise reduction. This can be set to `null` to turn + off. Noise reduction filters audio added to the input audio buffer before it is + sent to VAD and the model. Filtering the audio can improve VAD and turn + detection accuracy (reducing false positives) and model performance by improving + perception of the input audio. + + input_audio_transcription: Configuration for input audio transcription. The client can optionally set the + language and prompt for transcription, these offer additional guidance to the + transcription service. + + modalities: The set of modalities the model can respond with. To disable audio, set this to + ["text"]. + + turn_detection: Configuration for turn detection, ether Server VAD or Semantic VAD. This can be + set to `null` to turn off, in which case the client must manually trigger model + response. Server VAD means that the model will detect the start and end of + speech based on audio volume and respond at the end of user speech. Semantic VAD + is more advanced and uses a turn detection model (in conjuction with VAD) to + semantically estimate whether the user has finished speaking, then dynamically + sets a timeout based on this probability. For example, if user audio trails off + with "uhhm", the model will score a low probability of turn end and wait longer + for the user to continue speaking. This can be useful for more natural + conversations, but may have a higher latency. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} + return await self._post( + "/realtime/transcription_sessions", + body=await async_maybe_transform( + { + "include": include, + "input_audio_format": input_audio_format, + "input_audio_noise_reduction": input_audio_noise_reduction, + "input_audio_transcription": input_audio_transcription, + "modalities": modalities, + "turn_detection": turn_detection, + }, + transcription_session_create_params.TranscriptionSessionCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TranscriptionSession, + ) + + +class TranscriptionSessionsWithRawResponse: + def __init__(self, transcription_sessions: TranscriptionSessions) -> None: + self._transcription_sessions = transcription_sessions + + self.create = _legacy_response.to_raw_response_wrapper( + transcription_sessions.create, + ) + + +class AsyncTranscriptionSessionsWithRawResponse: + def __init__(self, transcription_sessions: AsyncTranscriptionSessions) -> None: + self._transcription_sessions = transcription_sessions + + self.create = _legacy_response.async_to_raw_response_wrapper( + transcription_sessions.create, + ) + + +class TranscriptionSessionsWithStreamingResponse: + def __init__(self, transcription_sessions: TranscriptionSessions) -> None: + self._transcription_sessions = transcription_sessions + + self.create = to_streamed_response_wrapper( + transcription_sessions.create, + ) + + +class AsyncTranscriptionSessionsWithStreamingResponse: + def __init__(self, transcription_sessions: AsyncTranscriptionSessions) -> None: + self._transcription_sessions = transcription_sessions + + self.create = async_to_streamed_response_wrapper( + transcription_sessions.create, + ) diff --git a/src/openai/types/audio/__init__.py b/src/openai/types/audio/__init__.py index 822e0f3a8d..396944ee47 100644 --- a/src/openai/types/audio/__init__.py +++ b/src/openai/types/audio/__init__.py @@ -8,9 +8,13 @@ from .transcription_word import TranscriptionWord as TranscriptionWord from .translation_verbose import TranslationVerbose as TranslationVerbose from .speech_create_params import SpeechCreateParams as SpeechCreateParams +from .transcription_include import TranscriptionInclude as TranscriptionInclude from .transcription_segment import TranscriptionSegment as TranscriptionSegment from .transcription_verbose import TranscriptionVerbose as TranscriptionVerbose from .translation_create_params import TranslationCreateParams as TranslationCreateParams +from .transcription_stream_event import TranscriptionStreamEvent as TranscriptionStreamEvent from .transcription_create_params import TranscriptionCreateParams as TranscriptionCreateParams from .translation_create_response import TranslationCreateResponse as TranslationCreateResponse from .transcription_create_response import TranscriptionCreateResponse as TranscriptionCreateResponse +from .transcription_text_done_event import TranscriptionTextDoneEvent as TranscriptionTextDoneEvent +from .transcription_text_delta_event import TranscriptionTextDeltaEvent as TranscriptionTextDeltaEvent diff --git a/src/openai/types/audio/speech_create_params.py b/src/openai/types/audio/speech_create_params.py index ed1a1ce748..958680710b 100644 --- a/src/openai/types/audio/speech_create_params.py +++ b/src/openai/types/audio/speech_create_params.py @@ -17,7 +17,7 @@ class SpeechCreateParams(TypedDict, total=False): model: Required[Union[str, SpeechModel]] """ One of the available [TTS models](https://platform.openai.com/docs/models#tts): - `tts-1` or `tts-1-hd` + `tts-1`, `tts-1-hd` or `gpt-4o-mini-tts`. """ voice: Required[Literal["alloy", "ash", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer"]] @@ -28,6 +28,12 @@ class SpeechCreateParams(TypedDict, total=False): [Text to speech guide](https://platform.openai.com/docs/guides/text-to-speech#voice-options). """ + instructions: str + """Control the voice of your generated audio with additional instructions. + + Does not work with `tts-1` or `tts-1-hd`. + """ + response_format: Literal["mp3", "opus", "aac", "flac", "wav", "pcm"] """The format to audio in. diff --git a/src/openai/types/audio/speech_model.py b/src/openai/types/audio/speech_model.py index bd685ab34d..f004f805da 100644 --- a/src/openai/types/audio/speech_model.py +++ b/src/openai/types/audio/speech_model.py @@ -4,4 +4,4 @@ __all__ = ["SpeechModel"] -SpeechModel: TypeAlias = Literal["tts-1", "tts-1-hd"] +SpeechModel: TypeAlias = Literal["tts-1", "tts-1-hd", "gpt-4o-mini-tts"] diff --git a/src/openai/types/audio/transcription.py b/src/openai/types/audio/transcription.py index edb5f227fc..1576385404 100644 --- a/src/openai/types/audio/transcription.py +++ b/src/openai/types/audio/transcription.py @@ -1,11 +1,30 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from typing import List, Optional from ..._models import BaseModel -__all__ = ["Transcription"] +__all__ = ["Transcription", "Logprob"] + + +class Logprob(BaseModel): + token: Optional[str] = None + """The token in the transcription.""" + + bytes: Optional[List[float]] = None + """The bytes of the token.""" + + logprob: Optional[float] = None + """The log probability of the token.""" class Transcription(BaseModel): text: str """The transcribed text.""" + + logprobs: Optional[List[Logprob]] = None + """The log probabilities of the tokens in the transcription. + + Only returned with the models `gpt-4o-transcribe` and `gpt-4o-mini-transcribe` + if `logprobs` is added to the `include` array. + """ diff --git a/src/openai/types/audio/transcription_create_params.py b/src/openai/types/audio/transcription_create_params.py index f1779c35e6..0cda4c7907 100644 --- a/src/openai/types/audio/transcription_create_params.py +++ b/src/openai/types/audio/transcription_create_params.py @@ -2,17 +2,22 @@ from __future__ import annotations -from typing import List, Union +from typing import List, Union, Optional from typing_extensions import Literal, Required, TypedDict from ..._types import FileTypes from ..audio_model import AudioModel +from .transcription_include import TranscriptionInclude from ..audio_response_format import AudioResponseFormat -__all__ = ["TranscriptionCreateParams"] +__all__ = [ + "TranscriptionCreateParamsBase", + "TranscriptionCreateParamsNonStreaming", + "TranscriptionCreateParamsStreaming", +] -class TranscriptionCreateParams(TypedDict, total=False): +class TranscriptionCreateParamsBase(TypedDict, total=False): file: Required[FileTypes] """ The audio file object (not file name) to transcribe, in one of these formats: @@ -22,8 +27,17 @@ class TranscriptionCreateParams(TypedDict, total=False): model: Required[Union[str, AudioModel]] """ID of the model to use. - Only `whisper-1` (which is powered by our open source Whisper V2 model) is - currently available. + The options are `gpt-4o-transcribe`, `gpt-4o-mini-transcribe`, and `whisper-1` + (which is powered by our open source Whisper V2 model). + """ + + include: List[TranscriptionInclude] + """Additional information to include in the transcription response. + + `logprobs` will return the log probabilities of the tokens in the response to + understand the model's confidence in the transcription. `logprobs` only works + with response_format set to `json` and only with the models `gpt-4o-transcribe` + and `gpt-4o-mini-transcribe`. """ language: str @@ -45,7 +59,8 @@ class TranscriptionCreateParams(TypedDict, total=False): response_format: AudioResponseFormat """ The format of the output, in one of these options: `json`, `text`, `srt`, - `verbose_json`, or `vtt`. + `verbose_json`, or `vtt`. For `gpt-4o-transcribe` and `gpt-4o-mini-transcribe`, + the only supported format is `json`. """ temperature: float @@ -65,3 +80,34 @@ class TranscriptionCreateParams(TypedDict, total=False): is no additional latency for segment timestamps, but generating word timestamps incurs additional latency. """ + + +class TranscriptionCreateParamsNonStreaming(TranscriptionCreateParamsBase, total=False): + stream: Optional[Literal[False]] + """ + If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section of the Speech-to-Text guide](https://platform.openai.com/docs/guides/speech-to-text?lang=curl#streaming-transcriptions) + for more information. + + Note: Streaming is not supported for the `whisper-1` model and will be ignored. + """ + + +class TranscriptionCreateParamsStreaming(TranscriptionCreateParamsBase): + stream: Required[Literal[True]] + """ + If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section of the Speech-to-Text guide](https://platform.openai.com/docs/guides/speech-to-text?lang=curl#streaming-transcriptions) + for more information. + + Note: Streaming is not supported for the `whisper-1` model and will be ignored. + """ + + +TranscriptionCreateParams = Union[TranscriptionCreateParamsNonStreaming, TranscriptionCreateParamsStreaming] diff --git a/src/openai/types/audio/transcription_include.py b/src/openai/types/audio/transcription_include.py new file mode 100644 index 0000000000..0e464ac934 --- /dev/null +++ b/src/openai/types/audio/transcription_include.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["TranscriptionInclude"] + +TranscriptionInclude: TypeAlias = Literal["logprobs"] diff --git a/src/openai/types/audio/transcription_stream_event.py b/src/openai/types/audio/transcription_stream_event.py new file mode 100644 index 0000000000..757077a280 --- /dev/null +++ b/src/openai/types/audio/transcription_stream_event.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from typing_extensions import Annotated, TypeAlias + +from ..._utils import PropertyInfo +from .transcription_text_done_event import TranscriptionTextDoneEvent +from .transcription_text_delta_event import TranscriptionTextDeltaEvent + +__all__ = ["TranscriptionStreamEvent"] + +TranscriptionStreamEvent: TypeAlias = Annotated[ + Union[TranscriptionTextDeltaEvent, TranscriptionTextDoneEvent], PropertyInfo(discriminator="type") +] diff --git a/src/openai/types/audio/transcription_text_delta_event.py b/src/openai/types/audio/transcription_text_delta_event.py new file mode 100644 index 0000000000..f8d5355491 --- /dev/null +++ b/src/openai/types/audio/transcription_text_delta_event.py @@ -0,0 +1,35 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["TranscriptionTextDeltaEvent", "Logprob"] + + +class Logprob(BaseModel): + token: Optional[str] = None + """The token that was used to generate the log probability.""" + + bytes: Optional[List[object]] = None + """The bytes that were used to generate the log probability.""" + + logprob: Optional[float] = None + """The log probability of the token.""" + + +class TranscriptionTextDeltaEvent(BaseModel): + delta: str + """The text delta that was additionally transcribed.""" + + type: Literal["transcript.text.delta"] + """The type of the event. Always `transcript.text.delta`.""" + + logprobs: Optional[List[Logprob]] = None + """The log probabilities of the delta. + + Only included if you + [create a transcription](https://platform.openai.com/docs/api-reference/audio/create-transcription) + with the `include[]` parameter set to `logprobs`. + """ diff --git a/src/openai/types/audio/transcription_text_done_event.py b/src/openai/types/audio/transcription_text_done_event.py new file mode 100644 index 0000000000..3f1a713a52 --- /dev/null +++ b/src/openai/types/audio/transcription_text_done_event.py @@ -0,0 +1,35 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["TranscriptionTextDoneEvent", "Logprob"] + + +class Logprob(BaseModel): + token: Optional[str] = None + """The token that was used to generate the log probability.""" + + bytes: Optional[List[object]] = None + """The bytes that were used to generate the log probability.""" + + logprob: Optional[float] = None + """The log probability of the token.""" + + +class TranscriptionTextDoneEvent(BaseModel): + text: str + """The text that was transcribed.""" + + type: Literal["transcript.text.done"] + """The type of the event. Always `transcript.text.done`.""" + + logprobs: Optional[List[Logprob]] = None + """The log probabilities of the individual tokens in the transcription. + + Only included if you + [create a transcription](https://platform.openai.com/docs/api-reference/audio/create-transcription) + with the `include[]` parameter set to `logprobs`. + """ diff --git a/src/openai/types/audio/translation_create_params.py b/src/openai/types/audio/translation_create_params.py index 62f85b8757..b23a185375 100644 --- a/src/openai/types/audio/translation_create_params.py +++ b/src/openai/types/audio/translation_create_params.py @@ -3,11 +3,10 @@ from __future__ import annotations from typing import Union -from typing_extensions import Required, TypedDict +from typing_extensions import Literal, Required, TypedDict from ..._types import FileTypes from ..audio_model import AudioModel -from ..audio_response_format import AudioResponseFormat __all__ = ["TranslationCreateParams"] @@ -34,7 +33,7 @@ class TranslationCreateParams(TypedDict, total=False): should be in English. """ - response_format: AudioResponseFormat + response_format: Literal["json", "text", "srt", "verbose_json", "vtt"] """ The format of the output, in one of these options: `json`, `text`, `srt`, `verbose_json`, or `vtt`. diff --git a/src/openai/types/audio_model.py b/src/openai/types/audio_model.py index 94ae84c015..4d14d60181 100644 --- a/src/openai/types/audio_model.py +++ b/src/openai/types/audio_model.py @@ -4,4 +4,4 @@ __all__ = ["AudioModel"] -AudioModel: TypeAlias = Literal["whisper-1"] +AudioModel: TypeAlias = Literal["whisper-1", "gpt-4o-transcribe", "gpt-4o-mini-transcribe"] diff --git a/src/openai/types/beta/realtime/__init__.py b/src/openai/types/beta/realtime/__init__.py index cd0616dcfa..0374b9b457 100644 --- a/src/openai/types/beta/realtime/__init__.py +++ b/src/openai/types/beta/realtime/__init__.py @@ -15,6 +15,7 @@ from .session_create_params import SessionCreateParams as SessionCreateParams from .session_created_event import SessionCreatedEvent as SessionCreatedEvent from .session_updated_event import SessionUpdatedEvent as SessionUpdatedEvent +from .transcription_session import TranscriptionSession as TranscriptionSession from .response_created_event import ResponseCreatedEvent as ResponseCreatedEvent from .conversation_item_param import ConversationItemParam as ConversationItemParam from .realtime_connect_params import RealtimeConnectParams as RealtimeConnectParams @@ -32,6 +33,7 @@ from .realtime_client_event_param import RealtimeClientEventParam as RealtimeClientEventParam from .response_cancel_event_param import ResponseCancelEventParam as ResponseCancelEventParam from .response_create_event_param import ResponseCreateEventParam as ResponseCreateEventParam +from .transcription_session_update import TranscriptionSessionUpdate as TranscriptionSessionUpdate from .conversation_item_create_event import ConversationItemCreateEvent as ConversationItemCreateEvent from .conversation_item_delete_event import ConversationItemDeleteEvent as ConversationItemDeleteEvent from .input_audio_buffer_clear_event import InputAudioBufferClearEvent as InputAudioBufferClearEvent @@ -41,6 +43,7 @@ from .input_audio_buffer_append_event import InputAudioBufferAppendEvent as InputAudioBufferAppendEvent from .input_audio_buffer_commit_event import InputAudioBufferCommitEvent as InputAudioBufferCommitEvent from .response_output_item_done_event import ResponseOutputItemDoneEvent as ResponseOutputItemDoneEvent +from .conversation_item_retrieve_event import ConversationItemRetrieveEvent as ConversationItemRetrieveEvent from .conversation_item_truncate_event import ConversationItemTruncateEvent as ConversationItemTruncateEvent from .conversation_item_with_reference import ConversationItemWithReference as ConversationItemWithReference from .input_audio_buffer_cleared_event import InputAudioBufferClearedEvent as InputAudioBufferClearedEvent @@ -49,6 +52,9 @@ from .conversation_item_truncated_event import ConversationItemTruncatedEvent as ConversationItemTruncatedEvent from .response_content_part_added_event import ResponseContentPartAddedEvent as ResponseContentPartAddedEvent from .input_audio_buffer_committed_event import InputAudioBufferCommittedEvent as InputAudioBufferCommittedEvent +from .transcription_session_update_param import TranscriptionSessionUpdateParam as TranscriptionSessionUpdateParam +from .transcription_session_create_params import TranscriptionSessionCreateParams as TranscriptionSessionCreateParams +from .transcription_session_updated_event import TranscriptionSessionUpdatedEvent as TranscriptionSessionUpdatedEvent from .conversation_item_create_event_param import ConversationItemCreateEventParam as ConversationItemCreateEventParam from .conversation_item_delete_event_param import ConversationItemDeleteEventParam as ConversationItemDeleteEventParam from .input_audio_buffer_clear_event_param import InputAudioBufferClearEventParam as InputAudioBufferClearEventParam @@ -58,6 +64,9 @@ from .response_audio_transcript_delta_event import ( ResponseAudioTranscriptDeltaEvent as ResponseAudioTranscriptDeltaEvent, ) +from .conversation_item_retrieve_event_param import ( + ConversationItemRetrieveEventParam as ConversationItemRetrieveEventParam, +) from .conversation_item_truncate_event_param import ( ConversationItemTruncateEventParam as ConversationItemTruncateEventParam, ) @@ -76,6 +85,9 @@ from .response_function_call_arguments_delta_event import ( ResponseFunctionCallArgumentsDeltaEvent as ResponseFunctionCallArgumentsDeltaEvent, ) +from .conversation_item_input_audio_transcription_delta_event import ( + ConversationItemInputAudioTranscriptionDeltaEvent as ConversationItemInputAudioTranscriptionDeltaEvent, +) from .conversation_item_input_audio_transcription_failed_event import ( ConversationItemInputAudioTranscriptionFailedEvent as ConversationItemInputAudioTranscriptionFailedEvent, ) diff --git a/src/openai/types/beta/realtime/conversation_item_input_audio_transcription_completed_event.py b/src/openai/types/beta/realtime/conversation_item_input_audio_transcription_completed_event.py index ded79cc0f7..469811693c 100644 --- a/src/openai/types/beta/realtime/conversation_item_input_audio_transcription_completed_event.py +++ b/src/openai/types/beta/realtime/conversation_item_input_audio_transcription_completed_event.py @@ -1,10 +1,22 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from typing import List, Optional from typing_extensions import Literal from ...._models import BaseModel -__all__ = ["ConversationItemInputAudioTranscriptionCompletedEvent"] +__all__ = ["ConversationItemInputAudioTranscriptionCompletedEvent", "Logprob"] + + +class Logprob(BaseModel): + token: str + """The token that was used to generate the log probability.""" + + bytes: List[int] + """The bytes that were used to generate the log probability.""" + + logprob: float + """The log probability of the token.""" class ConversationItemInputAudioTranscriptionCompletedEvent(BaseModel): @@ -24,3 +36,6 @@ class ConversationItemInputAudioTranscriptionCompletedEvent(BaseModel): """ The event type, must be `conversation.item.input_audio_transcription.completed`. """ + + logprobs: Optional[List[Logprob]] = None + """The log probabilities of the transcription.""" diff --git a/src/openai/types/beta/realtime/conversation_item_input_audio_transcription_delta_event.py b/src/openai/types/beta/realtime/conversation_item_input_audio_transcription_delta_event.py new file mode 100644 index 0000000000..924d06d98a --- /dev/null +++ b/src/openai/types/beta/realtime/conversation_item_input_audio_transcription_delta_event.py @@ -0,0 +1,39 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["ConversationItemInputAudioTranscriptionDeltaEvent", "Logprob"] + + +class Logprob(BaseModel): + token: str + """The token that was used to generate the log probability.""" + + bytes: List[int] + """The bytes that were used to generate the log probability.""" + + logprob: float + """The log probability of the token.""" + + +class ConversationItemInputAudioTranscriptionDeltaEvent(BaseModel): + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the item.""" + + type: Literal["conversation.item.input_audio_transcription.delta"] + """The event type, must be `conversation.item.input_audio_transcription.delta`.""" + + content_index: Optional[int] = None + """The index of the content part in the item's content array.""" + + delta: Optional[str] = None + """The text delta.""" + + logprobs: Optional[List[Logprob]] = None + """The log probabilities of the transcription.""" diff --git a/src/openai/types/beta/realtime/conversation_item_retrieve_event.py b/src/openai/types/beta/realtime/conversation_item_retrieve_event.py new file mode 100644 index 0000000000..822386055c --- /dev/null +++ b/src/openai/types/beta/realtime/conversation_item_retrieve_event.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["ConversationItemRetrieveEvent"] + + +class ConversationItemRetrieveEvent(BaseModel): + item_id: str + """The ID of the item to retrieve.""" + + type: Literal["conversation.item.retrieve"] + """The event type, must be `conversation.item.retrieve`.""" + + event_id: Optional[str] = None + """Optional client-generated ID used to identify this event.""" diff --git a/src/openai/types/beta/realtime/conversation_item_retrieve_event_param.py b/src/openai/types/beta/realtime/conversation_item_retrieve_event_param.py new file mode 100644 index 0000000000..71b3ffa499 --- /dev/null +++ b/src/openai/types/beta/realtime/conversation_item_retrieve_event_param.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ConversationItemRetrieveEventParam"] + + +class ConversationItemRetrieveEventParam(TypedDict, total=False): + item_id: Required[str] + """The ID of the item to retrieve.""" + + type: Required[Literal["conversation.item.retrieve"]] + """The event type, must be `conversation.item.retrieve`.""" + + event_id: str + """Optional client-generated ID used to identify this event.""" diff --git a/src/openai/types/beta/realtime/realtime_client_event.py b/src/openai/types/beta/realtime/realtime_client_event.py index 0769184cd0..f962a505cd 100644 --- a/src/openai/types/beta/realtime/realtime_client_event.py +++ b/src/openai/types/beta/realtime/realtime_client_event.py @@ -7,26 +7,30 @@ from .session_update_event import SessionUpdateEvent from .response_cancel_event import ResponseCancelEvent from .response_create_event import ResponseCreateEvent +from .transcription_session_update import TranscriptionSessionUpdate from .conversation_item_create_event import ConversationItemCreateEvent from .conversation_item_delete_event import ConversationItemDeleteEvent from .input_audio_buffer_clear_event import InputAudioBufferClearEvent from .input_audio_buffer_append_event import InputAudioBufferAppendEvent from .input_audio_buffer_commit_event import InputAudioBufferCommitEvent +from .conversation_item_retrieve_event import ConversationItemRetrieveEvent from .conversation_item_truncate_event import ConversationItemTruncateEvent __all__ = ["RealtimeClientEvent"] RealtimeClientEvent: TypeAlias = Annotated[ Union[ - SessionUpdateEvent, - InputAudioBufferAppendEvent, - InputAudioBufferCommitEvent, - InputAudioBufferClearEvent, ConversationItemCreateEvent, - ConversationItemTruncateEvent, ConversationItemDeleteEvent, - ResponseCreateEvent, + ConversationItemRetrieveEvent, + ConversationItemTruncateEvent, + InputAudioBufferAppendEvent, + InputAudioBufferClearEvent, + InputAudioBufferCommitEvent, ResponseCancelEvent, + ResponseCreateEvent, + SessionUpdateEvent, + TranscriptionSessionUpdate, ], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/beta/realtime/realtime_client_event_param.py b/src/openai/types/beta/realtime/realtime_client_event_param.py index 4020892c33..6fdba4b87c 100644 --- a/src/openai/types/beta/realtime/realtime_client_event_param.py +++ b/src/openai/types/beta/realtime/realtime_client_event_param.py @@ -8,23 +8,27 @@ from .session_update_event_param import SessionUpdateEventParam from .response_cancel_event_param import ResponseCancelEventParam from .response_create_event_param import ResponseCreateEventParam +from .transcription_session_update_param import TranscriptionSessionUpdateParam from .conversation_item_create_event_param import ConversationItemCreateEventParam from .conversation_item_delete_event_param import ConversationItemDeleteEventParam from .input_audio_buffer_clear_event_param import InputAudioBufferClearEventParam from .input_audio_buffer_append_event_param import InputAudioBufferAppendEventParam from .input_audio_buffer_commit_event_param import InputAudioBufferCommitEventParam +from .conversation_item_retrieve_event_param import ConversationItemRetrieveEventParam from .conversation_item_truncate_event_param import ConversationItemTruncateEventParam __all__ = ["RealtimeClientEventParam"] RealtimeClientEventParam: TypeAlias = Union[ - SessionUpdateEventParam, - InputAudioBufferAppendEventParam, - InputAudioBufferCommitEventParam, - InputAudioBufferClearEventParam, ConversationItemCreateEventParam, - ConversationItemTruncateEventParam, ConversationItemDeleteEventParam, - ResponseCreateEventParam, + ConversationItemRetrieveEventParam, + ConversationItemTruncateEventParam, + InputAudioBufferAppendEventParam, + InputAudioBufferClearEventParam, + InputAudioBufferCommitEventParam, ResponseCancelEventParam, + ResponseCreateEventParam, + SessionUpdateEventParam, + TranscriptionSessionUpdateParam, ] diff --git a/src/openai/types/beta/realtime/realtime_server_event.py b/src/openai/types/beta/realtime/realtime_server_event.py index 5f8ed55b13..ba1d324445 100644 --- a/src/openai/types/beta/realtime/realtime_server_event.py +++ b/src/openai/types/beta/realtime/realtime_server_event.py @@ -1,10 +1,12 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from typing import Union -from typing_extensions import Annotated, TypeAlias +from typing_extensions import Literal, Annotated, TypeAlias from ...._utils import PropertyInfo +from ...._models import BaseModel from .error_event import ErrorEvent +from .conversation_item import ConversationItem from .response_done_event import ResponseDoneEvent from .session_created_event import SessionCreatedEvent from .session_updated_event import SessionUpdatedEvent @@ -24,49 +26,66 @@ from .conversation_item_truncated_event import ConversationItemTruncatedEvent from .response_content_part_added_event import ResponseContentPartAddedEvent from .input_audio_buffer_committed_event import InputAudioBufferCommittedEvent +from .transcription_session_updated_event import TranscriptionSessionUpdatedEvent from .response_audio_transcript_done_event import ResponseAudioTranscriptDoneEvent from .response_audio_transcript_delta_event import ResponseAudioTranscriptDeltaEvent from .input_audio_buffer_speech_started_event import InputAudioBufferSpeechStartedEvent from .input_audio_buffer_speech_stopped_event import InputAudioBufferSpeechStoppedEvent from .response_function_call_arguments_done_event import ResponseFunctionCallArgumentsDoneEvent from .response_function_call_arguments_delta_event import ResponseFunctionCallArgumentsDeltaEvent +from .conversation_item_input_audio_transcription_delta_event import ConversationItemInputAudioTranscriptionDeltaEvent from .conversation_item_input_audio_transcription_failed_event import ConversationItemInputAudioTranscriptionFailedEvent from .conversation_item_input_audio_transcription_completed_event import ( ConversationItemInputAudioTranscriptionCompletedEvent, ) -__all__ = ["RealtimeServerEvent"] +__all__ = ["RealtimeServerEvent", "ConversationItemRetrieved"] + + +class ConversationItemRetrieved(BaseModel): + event_id: str + """The unique ID of the server event.""" + + item: ConversationItem + """The item to add to the conversation.""" + + type: Literal["conversation.item.retrieved"] + """The event type, must be `conversation.item.retrieved`.""" + RealtimeServerEvent: TypeAlias = Annotated[ Union[ - ErrorEvent, - SessionCreatedEvent, - SessionUpdatedEvent, ConversationCreatedEvent, - InputAudioBufferCommittedEvent, - InputAudioBufferClearedEvent, - InputAudioBufferSpeechStartedEvent, - InputAudioBufferSpeechStoppedEvent, ConversationItemCreatedEvent, + ConversationItemDeletedEvent, ConversationItemInputAudioTranscriptionCompletedEvent, + ConversationItemInputAudioTranscriptionDeltaEvent, ConversationItemInputAudioTranscriptionFailedEvent, + ConversationItemRetrieved, ConversationItemTruncatedEvent, - ConversationItemDeletedEvent, + ErrorEvent, + InputAudioBufferClearedEvent, + InputAudioBufferCommittedEvent, + InputAudioBufferSpeechStartedEvent, + InputAudioBufferSpeechStoppedEvent, + RateLimitsUpdatedEvent, + ResponseAudioDeltaEvent, + ResponseAudioDoneEvent, + ResponseAudioTranscriptDeltaEvent, + ResponseAudioTranscriptDoneEvent, + ResponseContentPartAddedEvent, + ResponseContentPartDoneEvent, ResponseCreatedEvent, ResponseDoneEvent, + ResponseFunctionCallArgumentsDeltaEvent, + ResponseFunctionCallArgumentsDoneEvent, ResponseOutputItemAddedEvent, ResponseOutputItemDoneEvent, - ResponseContentPartAddedEvent, - ResponseContentPartDoneEvent, ResponseTextDeltaEvent, ResponseTextDoneEvent, - ResponseAudioTranscriptDeltaEvent, - ResponseAudioTranscriptDoneEvent, - ResponseAudioDeltaEvent, - ResponseAudioDoneEvent, - ResponseFunctionCallArgumentsDeltaEvent, - ResponseFunctionCallArgumentsDoneEvent, - RateLimitsUpdatedEvent, + SessionCreatedEvent, + SessionUpdatedEvent, + TranscriptionSessionUpdatedEvent, ], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/beta/realtime/session.py b/src/openai/types/beta/realtime/session.py index aee20fa906..3ed53ff5f8 100644 --- a/src/openai/types/beta/realtime/session.py +++ b/src/openai/types/beta/realtime/session.py @@ -5,14 +5,40 @@ from ...._models import BaseModel -__all__ = ["Session", "InputAudioTranscription", "Tool", "TurnDetection"] +__all__ = ["Session", "InputAudioNoiseReduction", "InputAudioTranscription", "Tool", "TurnDetection"] + + +class InputAudioNoiseReduction(BaseModel): + type: Optional[Literal["near_field", "far_field"]] = None + """Type of noise reduction. + + `near_field` is for close-talking microphones such as headphones, `far_field` is + for far-field microphones such as laptop or conference room microphones. + """ class InputAudioTranscription(BaseModel): + language: Optional[str] = None + """The language of the input audio. + + Supplying the input language in + [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) + format will improve accuracy and latency. + """ + model: Optional[str] = None """ - The model to use for transcription, `whisper-1` is the only currently supported - model. + The model to use for transcription, current options are `gpt-4o-transcribe`, + `gpt-4o-mini-transcribe`, and `whisper-1`. + """ + + prompt: Optional[str] = None + """ + An optional text to guide the model's style or continue a previous audio + segment. For `whisper-1`, the + [prompt is a list of keywords](https://platform.openai.com/docs/guides/speech-to-text#prompting). + For `gpt-4o-transcribe` models, the prompt is a free text string, for example + "expect words related to technology". """ @@ -35,46 +61,56 @@ class Tool(BaseModel): class TurnDetection(BaseModel): create_response: Optional[bool] = None - """Whether or not to automatically generate a response when a VAD stop event + """ + Whether or not to automatically generate a response when a VAD stop event occurs. + """ + + eagerness: Optional[Literal["low", "medium", "high", "auto"]] = None + """Used only for `semantic_vad` mode. - `true` by default. + The eagerness of the model to respond. `low` will wait longer for the user to + continue speaking, `high` will respond more quickly. `auto` is the default and + is equivalent to `medium`. """ interrupt_response: Optional[bool] = None """ Whether or not to automatically interrupt any ongoing response with output to the default conversation (i.e. `conversation` of `auto`) when a VAD start event - occurs. `true` by default. + occurs. """ prefix_padding_ms: Optional[int] = None - """Amount of audio to include before the VAD detected speech (in milliseconds). + """Used only for `server_vad` mode. + Amount of audio to include before the VAD detected speech (in milliseconds). Defaults to 300ms. """ silence_duration_ms: Optional[int] = None - """Duration of silence to detect speech stop (in milliseconds). + """Used only for `server_vad` mode. - Defaults to 500ms. With shorter values the model will respond more quickly, but - may jump in on short pauses from the user. + Duration of silence to detect speech stop (in milliseconds). Defaults to 500ms. + With shorter values the model will respond more quickly, but may jump in on + short pauses from the user. """ threshold: Optional[float] = None - """Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. + """Used only for `server_vad` mode. - A higher threshold will require louder audio to activate the model, and thus - might perform better in noisy environments. + Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A higher + threshold will require louder audio to activate the model, and thus might + perform better in noisy environments. """ - type: Optional[Literal["server_vad"]] = None - """Type of turn detection, only `server_vad` is currently supported.""" + type: Optional[Literal["server_vad", "semantic_vad"]] = None + """Type of turn detection.""" class Session(BaseModel): id: Optional[str] = None - """Unique identifier for the session object.""" + """Unique identifier for the session that looks like `sess_1234567890abcdef`.""" input_audio_format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None """The format of input audio. @@ -84,13 +120,25 @@ class Session(BaseModel): byte order. """ + input_audio_noise_reduction: Optional[InputAudioNoiseReduction] = None + """Configuration for input audio noise reduction. + + This can be set to `null` to turn off. Noise reduction filters audio added to + the input audio buffer before it is sent to VAD and the model. Filtering the + audio can improve VAD and turn detection accuracy (reducing false positives) and + model performance by improving perception of the input audio. + """ + input_audio_transcription: Optional[InputAudioTranscription] = None """ Configuration for input audio transcription, defaults to off and can be set to `null` to turn off once on. Input audio transcription is not native to the model, since the model consumes audio directly. Transcription runs - asynchronously through Whisper and should be treated as rough guidance rather - than the representation understood by the model. + asynchronously through + [the /audio/transcriptions endpoint](https://platform.openai.com/docs/api-reference/audio/createTranscription) + and should be treated as guidance of input audio content rather than precisely + what the model heard. The client can optionally set the language and prompt for + transcription, these offer additional guidance to the transcription service. """ instructions: Optional[str] = None @@ -122,16 +170,14 @@ class Session(BaseModel): To disable audio, set this to ["text"]. """ - model: Union[ - str, + model: Optional[ Literal[ "gpt-4o-realtime-preview", "gpt-4o-realtime-preview-2024-10-01", "gpt-4o-realtime-preview-2024-12-17", "gpt-4o-mini-realtime-preview", "gpt-4o-mini-realtime-preview-2024-12-17", - ], - None, + ] ] = None """The Realtime model used for this session.""" @@ -143,7 +189,11 @@ class Session(BaseModel): """ temperature: Optional[float] = None - """Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8.""" + """Sampling temperature for the model, limited to [0.6, 1.2]. + + For audio models a temperature of 0.8 is highly recommended for best + performance. + """ tool_choice: Optional[str] = None """How the model chooses tools. @@ -155,11 +205,17 @@ class Session(BaseModel): """Tools (functions) available to the model.""" turn_detection: Optional[TurnDetection] = None - """Configuration for turn detection. - - Can be set to `null` to turn off. Server VAD means that the model will detect - the start and end of speech based on audio volume and respond at the end of user - speech. + """Configuration for turn detection, ether Server VAD or Semantic VAD. + + This can be set to `null` to turn off, in which case the client must manually + trigger model response. Server VAD means that the model will detect the start + and end of speech based on audio volume and respond at the end of user speech. + Semantic VAD is more advanced and uses a turn detection model (in conjuction + with VAD) to semantically estimate whether the user has finished speaking, then + dynamically sets a timeout based on this probability. For example, if user audio + trails off with "uhhm", the model will score a low probability of turn end and + wait longer for the user to continue speaking. This can be useful for more + natural conversations, but may have a higher latency. """ voice: Optional[Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"]] = None diff --git a/src/openai/types/beta/realtime/session_create_params.py b/src/openai/types/beta/realtime/session_create_params.py index bbc86d7c7d..fe4a1c8636 100644 --- a/src/openai/types/beta/realtime/session_create_params.py +++ b/src/openai/types/beta/realtime/session_create_params.py @@ -5,7 +5,7 @@ from typing import List, Union, Iterable from typing_extensions import Literal, TypedDict -__all__ = ["SessionCreateParams", "InputAudioTranscription", "Tool", "TurnDetection"] +__all__ = ["SessionCreateParams", "InputAudioNoiseReduction", "InputAudioTranscription", "Tool", "TurnDetection"] class SessionCreateParams(TypedDict, total=False): @@ -17,16 +17,25 @@ class SessionCreateParams(TypedDict, total=False): byte order. """ + input_audio_noise_reduction: InputAudioNoiseReduction + """Configuration for input audio noise reduction. + + This can be set to `null` to turn off. Noise reduction filters audio added to + the input audio buffer before it is sent to VAD and the model. Filtering the + audio can improve VAD and turn detection accuracy (reducing false positives) and + model performance by improving perception of the input audio. + """ + input_audio_transcription: InputAudioTranscription """ Configuration for input audio transcription, defaults to off and can be set to `null` to turn off once on. Input audio transcription is not native to the model, since the model consumes audio directly. Transcription runs asynchronously through - [OpenAI Whisper transcription](https://platform.openai.com/docs/api-reference/audio/createTranscription) - and should be treated as rough guidance rather than the representation - understood by the model. The client can optionally set the language and prompt - for transcription, these fields will be passed to the Whisper API. + [the /audio/transcriptions endpoint](https://platform.openai.com/docs/api-reference/audio/createTranscription) + and should be treated as guidance of input audio content rather than precisely + what the model heard. The client can optionally set the language and prompt for + transcription, these offer additional guidance to the transcription service. """ instructions: str @@ -75,7 +84,11 @@ class SessionCreateParams(TypedDict, total=False): """ temperature: float - """Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8.""" + """Sampling temperature for the model, limited to [0.6, 1.2]. + + For audio models a temperature of 0.8 is highly recommended for best + performance. + """ tool_choice: str """How the model chooses tools. @@ -87,11 +100,17 @@ class SessionCreateParams(TypedDict, total=False): """Tools (functions) available to the model.""" turn_detection: TurnDetection - """Configuration for turn detection. + """Configuration for turn detection, ether Server VAD or Semantic VAD. - Can be set to `null` to turn off. Server VAD means that the model will detect - the start and end of speech based on audio volume and respond at the end of user - speech. + This can be set to `null` to turn off, in which case the client must manually + trigger model response. Server VAD means that the model will detect the start + and end of speech based on audio volume and respond at the end of user speech. + Semantic VAD is more advanced and uses a turn detection model (in conjuction + with VAD) to semantically estimate whether the user has finished speaking, then + dynamically sets a timeout based on this probability. For example, if user audio + trails off with "uhhm", the model will score a low probability of turn end and + wait longer for the user to continue speaking. This can be useful for more + natural conversations, but may have a higher latency. """ voice: Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"] @@ -103,6 +122,15 @@ class SessionCreateParams(TypedDict, total=False): """ +class InputAudioNoiseReduction(TypedDict, total=False): + type: Literal["near_field", "far_field"] + """Type of noise reduction. + + `near_field` is for close-talking microphones such as headphones, `far_field` is + for far-field microphones such as laptop or conference room microphones. + """ + + class InputAudioTranscription(TypedDict, total=False): language: str """The language of the input audio. @@ -114,16 +142,17 @@ class InputAudioTranscription(TypedDict, total=False): model: str """ - The model to use for transcription, `whisper-1` is the only currently supported - model. + The model to use for transcription, current options are `gpt-4o-transcribe`, + `gpt-4o-mini-transcribe`, and `whisper-1`. """ prompt: str - """An optional text to guide the model's style or continue a previous audio - segment. - - The [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) - should match the audio language. + """ + An optional text to guide the model's style or continue a previous audio + segment. For `whisper-1`, the + [prompt is a list of keywords](https://platform.openai.com/docs/guides/speech-to-text#prompting). + For `gpt-4o-transcribe` models, the prompt is a free text string, for example + "expect words related to technology". """ @@ -146,38 +175,48 @@ class Tool(TypedDict, total=False): class TurnDetection(TypedDict, total=False): create_response: bool - """Whether or not to automatically generate a response when a VAD stop event + """ + Whether or not to automatically generate a response when a VAD stop event occurs. + """ + + eagerness: Literal["low", "medium", "high", "auto"] + """Used only for `semantic_vad` mode. - `true` by default. + The eagerness of the model to respond. `low` will wait longer for the user to + continue speaking, `high` will respond more quickly. `auto` is the default and + is equivalent to `medium`. """ interrupt_response: bool """ Whether or not to automatically interrupt any ongoing response with output to the default conversation (i.e. `conversation` of `auto`) when a VAD start event - occurs. `true` by default. + occurs. """ prefix_padding_ms: int - """Amount of audio to include before the VAD detected speech (in milliseconds). + """Used only for `server_vad` mode. + Amount of audio to include before the VAD detected speech (in milliseconds). Defaults to 300ms. """ silence_duration_ms: int - """Duration of silence to detect speech stop (in milliseconds). + """Used only for `server_vad` mode. - Defaults to 500ms. With shorter values the model will respond more quickly, but - may jump in on short pauses from the user. + Duration of silence to detect speech stop (in milliseconds). Defaults to 500ms. + With shorter values the model will respond more quickly, but may jump in on + short pauses from the user. """ threshold: float - """Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. + """Used only for `server_vad` mode. - A higher threshold will require louder audio to activate the model, and thus - might perform better in noisy environments. + Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A higher + threshold will require louder audio to activate the model, and thus might + perform better in noisy environments. """ - type: str - """Type of turn detection, only `server_vad` is currently supported.""" + type: Literal["server_vad", "semantic_vad"] + """Type of turn detection.""" diff --git a/src/openai/types/beta/realtime/session_update_event.py b/src/openai/types/beta/realtime/session_update_event.py index 999cd8d660..00180f593d 100644 --- a/src/openai/types/beta/realtime/session_update_event.py +++ b/src/openai/types/beta/realtime/session_update_event.py @@ -5,7 +5,23 @@ from ...._models import BaseModel -__all__ = ["SessionUpdateEvent", "Session", "SessionInputAudioTranscription", "SessionTool", "SessionTurnDetection"] +__all__ = [ + "SessionUpdateEvent", + "Session", + "SessionInputAudioNoiseReduction", + "SessionInputAudioTranscription", + "SessionTool", + "SessionTurnDetection", +] + + +class SessionInputAudioNoiseReduction(BaseModel): + type: Optional[Literal["near_field", "far_field"]] = None + """Type of noise reduction. + + `near_field` is for close-talking microphones such as headphones, `far_field` is + for far-field microphones such as laptop or conference room microphones. + """ class SessionInputAudioTranscription(BaseModel): @@ -19,16 +35,17 @@ class SessionInputAudioTranscription(BaseModel): model: Optional[str] = None """ - The model to use for transcription, `whisper-1` is the only currently supported - model. + The model to use for transcription, current options are `gpt-4o-transcribe`, + `gpt-4o-mini-transcribe`, and `whisper-1`. """ prompt: Optional[str] = None - """An optional text to guide the model's style or continue a previous audio - segment. - - The [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) - should match the audio language. + """ + An optional text to guide the model's style or continue a previous audio + segment. For `whisper-1`, the + [prompt is a list of keywords](https://platform.openai.com/docs/guides/speech-to-text#prompting). + For `gpt-4o-transcribe` models, the prompt is a free text string, for example + "expect words related to technology". """ @@ -51,41 +68,51 @@ class SessionTool(BaseModel): class SessionTurnDetection(BaseModel): create_response: Optional[bool] = None - """Whether or not to automatically generate a response when a VAD stop event + """ + Whether or not to automatically generate a response when a VAD stop event occurs. + """ - `true` by default. + eagerness: Optional[Literal["low", "medium", "high", "auto"]] = None + """Used only for `semantic_vad` mode. + + The eagerness of the model to respond. `low` will wait longer for the user to + continue speaking, `high` will respond more quickly. `auto` is the default and + is equivalent to `medium`. """ interrupt_response: Optional[bool] = None """ Whether or not to automatically interrupt any ongoing response with output to the default conversation (i.e. `conversation` of `auto`) when a VAD start event - occurs. `true` by default. + occurs. """ prefix_padding_ms: Optional[int] = None - """Amount of audio to include before the VAD detected speech (in milliseconds). + """Used only for `server_vad` mode. + Amount of audio to include before the VAD detected speech (in milliseconds). Defaults to 300ms. """ silence_duration_ms: Optional[int] = None - """Duration of silence to detect speech stop (in milliseconds). + """Used only for `server_vad` mode. - Defaults to 500ms. With shorter values the model will respond more quickly, but - may jump in on short pauses from the user. + Duration of silence to detect speech stop (in milliseconds). Defaults to 500ms. + With shorter values the model will respond more quickly, but may jump in on + short pauses from the user. """ threshold: Optional[float] = None - """Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. + """Used only for `server_vad` mode. - A higher threshold will require louder audio to activate the model, and thus - might perform better in noisy environments. + Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A higher + threshold will require louder audio to activate the model, and thus might + perform better in noisy environments. """ - type: Optional[str] = None - """Type of turn detection, only `server_vad` is currently supported.""" + type: Optional[Literal["server_vad", "semantic_vad"]] = None + """Type of turn detection.""" class Session(BaseModel): @@ -97,16 +124,25 @@ class Session(BaseModel): byte order. """ + input_audio_noise_reduction: Optional[SessionInputAudioNoiseReduction] = None + """Configuration for input audio noise reduction. + + This can be set to `null` to turn off. Noise reduction filters audio added to + the input audio buffer before it is sent to VAD and the model. Filtering the + audio can improve VAD and turn detection accuracy (reducing false positives) and + model performance by improving perception of the input audio. + """ + input_audio_transcription: Optional[SessionInputAudioTranscription] = None """ Configuration for input audio transcription, defaults to off and can be set to `null` to turn off once on. Input audio transcription is not native to the model, since the model consumes audio directly. Transcription runs asynchronously through - [OpenAI Whisper transcription](https://platform.openai.com/docs/api-reference/audio/createTranscription) - and should be treated as rough guidance rather than the representation - understood by the model. The client can optionally set the language and prompt - for transcription, these fields will be passed to the Whisper API. + [the /audio/transcriptions endpoint](https://platform.openai.com/docs/api-reference/audio/createTranscription) + and should be treated as guidance of input audio content rather than precisely + what the model heard. The client can optionally set the language and prompt for + transcription, these offer additional guidance to the transcription service. """ instructions: Optional[str] = None @@ -157,7 +193,11 @@ class Session(BaseModel): """ temperature: Optional[float] = None - """Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8.""" + """Sampling temperature for the model, limited to [0.6, 1.2]. + + For audio models a temperature of 0.8 is highly recommended for best + performance. + """ tool_choice: Optional[str] = None """How the model chooses tools. @@ -169,11 +209,17 @@ class Session(BaseModel): """Tools (functions) available to the model.""" turn_detection: Optional[SessionTurnDetection] = None - """Configuration for turn detection. - - Can be set to `null` to turn off. Server VAD means that the model will detect - the start and end of speech based on audio volume and respond at the end of user - speech. + """Configuration for turn detection, ether Server VAD or Semantic VAD. + + This can be set to `null` to turn off, in which case the client must manually + trigger model response. Server VAD means that the model will detect the start + and end of speech based on audio volume and respond at the end of user speech. + Semantic VAD is more advanced and uses a turn detection model (in conjuction + with VAD) to semantically estimate whether the user has finished speaking, then + dynamically sets a timeout based on this probability. For example, if user audio + trails off with "uhhm", the model will score a low probability of turn end and + wait longer for the user to continue speaking. This can be useful for more + natural conversations, but may have a higher latency. """ voice: Optional[Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"]] = None diff --git a/src/openai/types/beta/realtime/session_update_event_param.py b/src/openai/types/beta/realtime/session_update_event_param.py index 07fdba9d85..b8bce8fbd0 100644 --- a/src/openai/types/beta/realtime/session_update_event_param.py +++ b/src/openai/types/beta/realtime/session_update_event_param.py @@ -8,12 +8,22 @@ __all__ = [ "SessionUpdateEventParam", "Session", + "SessionInputAudioNoiseReduction", "SessionInputAudioTranscription", "SessionTool", "SessionTurnDetection", ] +class SessionInputAudioNoiseReduction(TypedDict, total=False): + type: Literal["near_field", "far_field"] + """Type of noise reduction. + + `near_field` is for close-talking microphones such as headphones, `far_field` is + for far-field microphones such as laptop or conference room microphones. + """ + + class SessionInputAudioTranscription(TypedDict, total=False): language: str """The language of the input audio. @@ -25,16 +35,17 @@ class SessionInputAudioTranscription(TypedDict, total=False): model: str """ - The model to use for transcription, `whisper-1` is the only currently supported - model. + The model to use for transcription, current options are `gpt-4o-transcribe`, + `gpt-4o-mini-transcribe`, and `whisper-1`. """ prompt: str - """An optional text to guide the model's style or continue a previous audio - segment. - - The [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) - should match the audio language. + """ + An optional text to guide the model's style or continue a previous audio + segment. For `whisper-1`, the + [prompt is a list of keywords](https://platform.openai.com/docs/guides/speech-to-text#prompting). + For `gpt-4o-transcribe` models, the prompt is a free text string, for example + "expect words related to technology". """ @@ -57,41 +68,51 @@ class SessionTool(TypedDict, total=False): class SessionTurnDetection(TypedDict, total=False): create_response: bool - """Whether or not to automatically generate a response when a VAD stop event + """ + Whether or not to automatically generate a response when a VAD stop event occurs. + """ - `true` by default. + eagerness: Literal["low", "medium", "high", "auto"] + """Used only for `semantic_vad` mode. + + The eagerness of the model to respond. `low` will wait longer for the user to + continue speaking, `high` will respond more quickly. `auto` is the default and + is equivalent to `medium`. """ interrupt_response: bool """ Whether or not to automatically interrupt any ongoing response with output to the default conversation (i.e. `conversation` of `auto`) when a VAD start event - occurs. `true` by default. + occurs. """ prefix_padding_ms: int - """Amount of audio to include before the VAD detected speech (in milliseconds). + """Used only for `server_vad` mode. + Amount of audio to include before the VAD detected speech (in milliseconds). Defaults to 300ms. """ silence_duration_ms: int - """Duration of silence to detect speech stop (in milliseconds). + """Used only for `server_vad` mode. - Defaults to 500ms. With shorter values the model will respond more quickly, but - may jump in on short pauses from the user. + Duration of silence to detect speech stop (in milliseconds). Defaults to 500ms. + With shorter values the model will respond more quickly, but may jump in on + short pauses from the user. """ threshold: float - """Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. + """Used only for `server_vad` mode. - A higher threshold will require louder audio to activate the model, and thus - might perform better in noisy environments. + Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A higher + threshold will require louder audio to activate the model, and thus might + perform better in noisy environments. """ - type: str - """Type of turn detection, only `server_vad` is currently supported.""" + type: Literal["server_vad", "semantic_vad"] + """Type of turn detection.""" class Session(TypedDict, total=False): @@ -103,16 +124,25 @@ class Session(TypedDict, total=False): byte order. """ + input_audio_noise_reduction: SessionInputAudioNoiseReduction + """Configuration for input audio noise reduction. + + This can be set to `null` to turn off. Noise reduction filters audio added to + the input audio buffer before it is sent to VAD and the model. Filtering the + audio can improve VAD and turn detection accuracy (reducing false positives) and + model performance by improving perception of the input audio. + """ + input_audio_transcription: SessionInputAudioTranscription """ Configuration for input audio transcription, defaults to off and can be set to `null` to turn off once on. Input audio transcription is not native to the model, since the model consumes audio directly. Transcription runs asynchronously through - [OpenAI Whisper transcription](https://platform.openai.com/docs/api-reference/audio/createTranscription) - and should be treated as rough guidance rather than the representation - understood by the model. The client can optionally set the language and prompt - for transcription, these fields will be passed to the Whisper API. + [the /audio/transcriptions endpoint](https://platform.openai.com/docs/api-reference/audio/createTranscription) + and should be treated as guidance of input audio content rather than precisely + what the model heard. The client can optionally set the language and prompt for + transcription, these offer additional guidance to the transcription service. """ instructions: str @@ -161,7 +191,11 @@ class Session(TypedDict, total=False): """ temperature: float - """Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8.""" + """Sampling temperature for the model, limited to [0.6, 1.2]. + + For audio models a temperature of 0.8 is highly recommended for best + performance. + """ tool_choice: str """How the model chooses tools. @@ -173,11 +207,17 @@ class Session(TypedDict, total=False): """Tools (functions) available to the model.""" turn_detection: SessionTurnDetection - """Configuration for turn detection. - - Can be set to `null` to turn off. Server VAD means that the model will detect - the start and end of speech based on audio volume and respond at the end of user - speech. + """Configuration for turn detection, ether Server VAD or Semantic VAD. + + This can be set to `null` to turn off, in which case the client must manually + trigger model response. Server VAD means that the model will detect the start + and end of speech based on audio volume and respond at the end of user speech. + Semantic VAD is more advanced and uses a turn detection model (in conjuction + with VAD) to semantically estimate whether the user has finished speaking, then + dynamically sets a timeout based on this probability. For example, if user audio + trails off with "uhhm", the model will score a low probability of turn end and + wait longer for the user to continue speaking. This can be useful for more + natural conversations, but may have a higher latency. """ voice: Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"] diff --git a/src/openai/types/beta/realtime/transcription_session.py b/src/openai/types/beta/realtime/transcription_session.py new file mode 100644 index 0000000000..7c7abf37b6 --- /dev/null +++ b/src/openai/types/beta/realtime/transcription_session.py @@ -0,0 +1,100 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["TranscriptionSession", "ClientSecret", "InputAudioTranscription", "TurnDetection"] + + +class ClientSecret(BaseModel): + expires_at: int + """Timestamp for when the token expires. + + Currently, all tokens expire after one minute. + """ + + value: str + """ + Ephemeral key usable in client environments to authenticate connections to the + Realtime API. Use this in client-side environments rather than a standard API + token, which should only be used server-side. + """ + + +class InputAudioTranscription(BaseModel): + language: Optional[str] = None + """The language of the input audio. + + Supplying the input language in + [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) + format will improve accuracy and latency. + """ + + model: Optional[Literal["gpt-4o-transcribe", "gpt-4o-mini-transcribe", "whisper-1"]] = None + """The model to use for transcription. + + Can be `gpt-4o-transcribe`, `gpt-4o-mini-transcribe`, or `whisper-1`. + """ + + prompt: Optional[str] = None + """An optional text to guide the model's style or continue a previous audio + segment. + + The [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) + should match the audio language. + """ + + +class TurnDetection(BaseModel): + prefix_padding_ms: Optional[int] = None + """Amount of audio to include before the VAD detected speech (in milliseconds). + + Defaults to 300ms. + """ + + silence_duration_ms: Optional[int] = None + """Duration of silence to detect speech stop (in milliseconds). + + Defaults to 500ms. With shorter values the model will respond more quickly, but + may jump in on short pauses from the user. + """ + + threshold: Optional[float] = None + """Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. + + A higher threshold will require louder audio to activate the model, and thus + might perform better in noisy environments. + """ + + type: Optional[str] = None + """Type of turn detection, only `server_vad` is currently supported.""" + + +class TranscriptionSession(BaseModel): + client_secret: ClientSecret + """Ephemeral key returned by the API. + + Only present when the session is created on the server via REST API. + """ + + input_audio_format: Optional[str] = None + """The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + + input_audio_transcription: Optional[InputAudioTranscription] = None + """Configuration of the transcription model.""" + + modalities: Optional[List[Literal["text", "audio"]]] = None + """The set of modalities the model can respond with. + + To disable audio, set this to ["text"]. + """ + + turn_detection: Optional[TurnDetection] = None + """Configuration for turn detection. + + Can be set to `null` to turn off. Server VAD means that the model will detect + the start and end of speech based on audio volume and respond at the end of user + speech. + """ diff --git a/src/openai/types/beta/realtime/transcription_session_create_params.py b/src/openai/types/beta/realtime/transcription_session_create_params.py new file mode 100644 index 0000000000..4066dc4c5d --- /dev/null +++ b/src/openai/types/beta/realtime/transcription_session_create_params.py @@ -0,0 +1,143 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Literal, TypedDict + +__all__ = ["TranscriptionSessionCreateParams", "InputAudioNoiseReduction", "InputAudioTranscription", "TurnDetection"] + + +class TranscriptionSessionCreateParams(TypedDict, total=False): + include: List[str] + """The set of items to include in the transcription. Current available items are: + + - `item.input_audio_transcription.logprobs` + """ + + input_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] + """The format of input audio. + + Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, input audio must + be 16-bit PCM at a 24kHz sample rate, single channel (mono), and little-endian + byte order. + """ + + input_audio_noise_reduction: InputAudioNoiseReduction + """Configuration for input audio noise reduction. + + This can be set to `null` to turn off. Noise reduction filters audio added to + the input audio buffer before it is sent to VAD and the model. Filtering the + audio can improve VAD and turn detection accuracy (reducing false positives) and + model performance by improving perception of the input audio. + """ + + input_audio_transcription: InputAudioTranscription + """Configuration for input audio transcription. + + The client can optionally set the language and prompt for transcription, these + offer additional guidance to the transcription service. + """ + + modalities: List[Literal["text", "audio"]] + """The set of modalities the model can respond with. + + To disable audio, set this to ["text"]. + """ + + turn_detection: TurnDetection + """Configuration for turn detection, ether Server VAD or Semantic VAD. + + This can be set to `null` to turn off, in which case the client must manually + trigger model response. Server VAD means that the model will detect the start + and end of speech based on audio volume and respond at the end of user speech. + Semantic VAD is more advanced and uses a turn detection model (in conjuction + with VAD) to semantically estimate whether the user has finished speaking, then + dynamically sets a timeout based on this probability. For example, if user audio + trails off with "uhhm", the model will score a low probability of turn end and + wait longer for the user to continue speaking. This can be useful for more + natural conversations, but may have a higher latency. + """ + + +class InputAudioNoiseReduction(TypedDict, total=False): + type: Literal["near_field", "far_field"] + """Type of noise reduction. + + `near_field` is for close-talking microphones such as headphones, `far_field` is + for far-field microphones such as laptop or conference room microphones. + """ + + +class InputAudioTranscription(TypedDict, total=False): + language: str + """The language of the input audio. + + Supplying the input language in + [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) + format will improve accuracy and latency. + """ + + model: Literal["gpt-4o-transcribe", "gpt-4o-mini-transcribe", "whisper-1"] + """ + The model to use for transcription, current options are `gpt-4o-transcribe`, + `gpt-4o-mini-transcribe`, and `whisper-1`. + """ + + prompt: str + """ + An optional text to guide the model's style or continue a previous audio + segment. For `whisper-1`, the + [prompt is a list of keywords](https://platform.openai.com/docs/guides/speech-to-text#prompting). + For `gpt-4o-transcribe` models, the prompt is a free text string, for example + "expect words related to technology". + """ + + +class TurnDetection(TypedDict, total=False): + create_response: bool + """ + Whether or not to automatically generate a response when a VAD stop event + occurs. + """ + + eagerness: Literal["low", "medium", "high", "auto"] + """Used only for `semantic_vad` mode. + + The eagerness of the model to respond. `low` will wait longer for the user to + continue speaking, `high` will respond more quickly. `auto` is the default and + is equivalent to `medium`. + """ + + interrupt_response: bool + """ + Whether or not to automatically interrupt any ongoing response with output to + the default conversation (i.e. `conversation` of `auto`) when a VAD start event + occurs. + """ + + prefix_padding_ms: int + """Used only for `server_vad` mode. + + Amount of audio to include before the VAD detected speech (in milliseconds). + Defaults to 300ms. + """ + + silence_duration_ms: int + """Used only for `server_vad` mode. + + Duration of silence to detect speech stop (in milliseconds). Defaults to 500ms. + With shorter values the model will respond more quickly, but may jump in on + short pauses from the user. + """ + + threshold: float + """Used only for `server_vad` mode. + + Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A higher + threshold will require louder audio to activate the model, and thus might + perform better in noisy environments. + """ + + type: Literal["server_vad", "semantic_vad"] + """Type of turn detection.""" diff --git a/src/openai/types/beta/realtime/transcription_session_update.py b/src/openai/types/beta/realtime/transcription_session_update.py new file mode 100644 index 0000000000..043ac02e07 --- /dev/null +++ b/src/openai/types/beta/realtime/transcription_session_update.py @@ -0,0 +1,160 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = [ + "TranscriptionSessionUpdate", + "Session", + "SessionInputAudioNoiseReduction", + "SessionInputAudioTranscription", + "SessionTurnDetection", +] + + +class SessionInputAudioNoiseReduction(BaseModel): + type: Optional[Literal["near_field", "far_field"]] = None + """Type of noise reduction. + + `near_field` is for close-talking microphones such as headphones, `far_field` is + for far-field microphones such as laptop or conference room microphones. + """ + + +class SessionInputAudioTranscription(BaseModel): + language: Optional[str] = None + """The language of the input audio. + + Supplying the input language in + [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) + format will improve accuracy and latency. + """ + + model: Optional[Literal["gpt-4o-transcribe", "gpt-4o-mini-transcribe", "whisper-1"]] = None + """ + The model to use for transcription, current options are `gpt-4o-transcribe`, + `gpt-4o-mini-transcribe`, and `whisper-1`. + """ + + prompt: Optional[str] = None + """ + An optional text to guide the model's style or continue a previous audio + segment. For `whisper-1`, the + [prompt is a list of keywords](https://platform.openai.com/docs/guides/speech-to-text#prompting). + For `gpt-4o-transcribe` models, the prompt is a free text string, for example + "expect words related to technology". + """ + + +class SessionTurnDetection(BaseModel): + create_response: Optional[bool] = None + """ + Whether or not to automatically generate a response when a VAD stop event + occurs. + """ + + eagerness: Optional[Literal["low", "medium", "high", "auto"]] = None + """Used only for `semantic_vad` mode. + + The eagerness of the model to respond. `low` will wait longer for the user to + continue speaking, `high` will respond more quickly. `auto` is the default and + is equivalent to `medium`. + """ + + interrupt_response: Optional[bool] = None + """ + Whether or not to automatically interrupt any ongoing response with output to + the default conversation (i.e. `conversation` of `auto`) when a VAD start event + occurs. + """ + + prefix_padding_ms: Optional[int] = None + """Used only for `server_vad` mode. + + Amount of audio to include before the VAD detected speech (in milliseconds). + Defaults to 300ms. + """ + + silence_duration_ms: Optional[int] = None + """Used only for `server_vad` mode. + + Duration of silence to detect speech stop (in milliseconds). Defaults to 500ms. + With shorter values the model will respond more quickly, but may jump in on + short pauses from the user. + """ + + threshold: Optional[float] = None + """Used only for `server_vad` mode. + + Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A higher + threshold will require louder audio to activate the model, and thus might + perform better in noisy environments. + """ + + type: Optional[Literal["server_vad", "semantic_vad"]] = None + """Type of turn detection.""" + + +class Session(BaseModel): + include: Optional[List[str]] = None + """The set of items to include in the transcription. Current available items are: + + - `item.input_audio_transcription.logprobs` + """ + + input_audio_format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None + """The format of input audio. + + Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, input audio must + be 16-bit PCM at a 24kHz sample rate, single channel (mono), and little-endian + byte order. + """ + + input_audio_noise_reduction: Optional[SessionInputAudioNoiseReduction] = None + """Configuration for input audio noise reduction. + + This can be set to `null` to turn off. Noise reduction filters audio added to + the input audio buffer before it is sent to VAD and the model. Filtering the + audio can improve VAD and turn detection accuracy (reducing false positives) and + model performance by improving perception of the input audio. + """ + + input_audio_transcription: Optional[SessionInputAudioTranscription] = None + """Configuration for input audio transcription. + + The client can optionally set the language and prompt for transcription, these + offer additional guidance to the transcription service. + """ + + modalities: Optional[List[Literal["text", "audio"]]] = None + """The set of modalities the model can respond with. + + To disable audio, set this to ["text"]. + """ + + turn_detection: Optional[SessionTurnDetection] = None + """Configuration for turn detection, ether Server VAD or Semantic VAD. + + This can be set to `null` to turn off, in which case the client must manually + trigger model response. Server VAD means that the model will detect the start + and end of speech based on audio volume and respond at the end of user speech. + Semantic VAD is more advanced and uses a turn detection model (in conjuction + with VAD) to semantically estimate whether the user has finished speaking, then + dynamically sets a timeout based on this probability. For example, if user audio + trails off with "uhhm", the model will score a low probability of turn end and + wait longer for the user to continue speaking. This can be useful for more + natural conversations, but may have a higher latency. + """ + + +class TranscriptionSessionUpdate(BaseModel): + session: Session + """Realtime transcription session object configuration.""" + + type: Literal["transcription_session.update"] + """The event type, must be `transcription_session.update`.""" + + event_id: Optional[str] = None + """Optional client-generated ID used to identify this event.""" diff --git a/src/openai/types/beta/realtime/transcription_session_update_param.py b/src/openai/types/beta/realtime/transcription_session_update_param.py new file mode 100644 index 0000000000..997a36d77b --- /dev/null +++ b/src/openai/types/beta/realtime/transcription_session_update_param.py @@ -0,0 +1,160 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Literal, Required, TypedDict + +__all__ = [ + "TranscriptionSessionUpdateParam", + "Session", + "SessionInputAudioNoiseReduction", + "SessionInputAudioTranscription", + "SessionTurnDetection", +] + + +class SessionInputAudioNoiseReduction(TypedDict, total=False): + type: Literal["near_field", "far_field"] + """Type of noise reduction. + + `near_field` is for close-talking microphones such as headphones, `far_field` is + for far-field microphones such as laptop or conference room microphones. + """ + + +class SessionInputAudioTranscription(TypedDict, total=False): + language: str + """The language of the input audio. + + Supplying the input language in + [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) + format will improve accuracy and latency. + """ + + model: Literal["gpt-4o-transcribe", "gpt-4o-mini-transcribe", "whisper-1"] + """ + The model to use for transcription, current options are `gpt-4o-transcribe`, + `gpt-4o-mini-transcribe`, and `whisper-1`. + """ + + prompt: str + """ + An optional text to guide the model's style or continue a previous audio + segment. For `whisper-1`, the + [prompt is a list of keywords](https://platform.openai.com/docs/guides/speech-to-text#prompting). + For `gpt-4o-transcribe` models, the prompt is a free text string, for example + "expect words related to technology". + """ + + +class SessionTurnDetection(TypedDict, total=False): + create_response: bool + """ + Whether or not to automatically generate a response when a VAD stop event + occurs. + """ + + eagerness: Literal["low", "medium", "high", "auto"] + """Used only for `semantic_vad` mode. + + The eagerness of the model to respond. `low` will wait longer for the user to + continue speaking, `high` will respond more quickly. `auto` is the default and + is equivalent to `medium`. + """ + + interrupt_response: bool + """ + Whether or not to automatically interrupt any ongoing response with output to + the default conversation (i.e. `conversation` of `auto`) when a VAD start event + occurs. + """ + + prefix_padding_ms: int + """Used only for `server_vad` mode. + + Amount of audio to include before the VAD detected speech (in milliseconds). + Defaults to 300ms. + """ + + silence_duration_ms: int + """Used only for `server_vad` mode. + + Duration of silence to detect speech stop (in milliseconds). Defaults to 500ms. + With shorter values the model will respond more quickly, but may jump in on + short pauses from the user. + """ + + threshold: float + """Used only for `server_vad` mode. + + Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A higher + threshold will require louder audio to activate the model, and thus might + perform better in noisy environments. + """ + + type: Literal["server_vad", "semantic_vad"] + """Type of turn detection.""" + + +class Session(TypedDict, total=False): + include: List[str] + """The set of items to include in the transcription. Current available items are: + + - `item.input_audio_transcription.logprobs` + """ + + input_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] + """The format of input audio. + + Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, input audio must + be 16-bit PCM at a 24kHz sample rate, single channel (mono), and little-endian + byte order. + """ + + input_audio_noise_reduction: SessionInputAudioNoiseReduction + """Configuration for input audio noise reduction. + + This can be set to `null` to turn off. Noise reduction filters audio added to + the input audio buffer before it is sent to VAD and the model. Filtering the + audio can improve VAD and turn detection accuracy (reducing false positives) and + model performance by improving perception of the input audio. + """ + + input_audio_transcription: SessionInputAudioTranscription + """Configuration for input audio transcription. + + The client can optionally set the language and prompt for transcription, these + offer additional guidance to the transcription service. + """ + + modalities: List[Literal["text", "audio"]] + """The set of modalities the model can respond with. + + To disable audio, set this to ["text"]. + """ + + turn_detection: SessionTurnDetection + """Configuration for turn detection, ether Server VAD or Semantic VAD. + + This can be set to `null` to turn off, in which case the client must manually + trigger model response. Server VAD means that the model will detect the start + and end of speech based on audio volume and respond at the end of user speech. + Semantic VAD is more advanced and uses a turn detection model (in conjuction + with VAD) to semantically estimate whether the user has finished speaking, then + dynamically sets a timeout based on this probability. For example, if user audio + trails off with "uhhm", the model will score a low probability of turn end and + wait longer for the user to continue speaking. This can be useful for more + natural conversations, but may have a higher latency. + """ + + +class TranscriptionSessionUpdateParam(TypedDict, total=False): + session: Required[Session] + """Realtime transcription session object configuration.""" + + type: Required[Literal["transcription_session.update"]] + """The event type, must be `transcription_session.update`.""" + + event_id: str + """Optional client-generated ID used to identify this event.""" diff --git a/src/openai/types/beta/realtime/transcription_session_updated_event.py b/src/openai/types/beta/realtime/transcription_session_updated_event.py new file mode 100644 index 0000000000..ffc100bcc2 --- /dev/null +++ b/src/openai/types/beta/realtime/transcription_session_updated_event.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel +from .transcription_session import TranscriptionSession + +__all__ = ["TranscriptionSessionUpdatedEvent"] + + +class TranscriptionSessionUpdatedEvent(BaseModel): + event_id: str + """The unique ID of the server event.""" + + session: TranscriptionSession + """A new Realtime transcription session configuration. + + When a session is created on the server via REST API, the session object also + contains an ephemeral key. Default TTL for keys is one minute. This property is + not present when a session is updated via the WebSocket API. + """ + + type: Literal["transcription_session.updated"] + """The event type, must be `transcription_session.updated`.""" diff --git a/tests/api_resources/audio/test_speech.py b/tests/api_resources/audio/test_speech.py index 781ebeceb9..808f6ef66c 100644 --- a/tests/api_resources/audio/test_speech.py +++ b/tests/api_resources/audio/test_speech.py @@ -41,6 +41,7 @@ def test_method_create_with_all_params(self, client: OpenAI, respx_mock: MockRou input="string", model="string", voice="alloy", + instructions="instructions", response_format="mp3", speed=0.25, ) @@ -104,6 +105,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI, re input="string", model="string", voice="alloy", + instructions="instructions", response_format="mp3", speed=0.25, ) diff --git a/tests/api_resources/audio/test_transcriptions.py b/tests/api_resources/audio/test_transcriptions.py index bdb7e0dfb6..19215e11df 100644 --- a/tests/api_resources/audio/test_transcriptions.py +++ b/tests/api_resources/audio/test_transcriptions.py @@ -18,31 +18,33 @@ class TestTranscriptions: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) @parametrize - def test_method_create(self, client: OpenAI) -> None: + def test_method_create_overload_1(self, client: OpenAI) -> None: transcription = client.audio.transcriptions.create( file=b"raw file contents", - model="whisper-1", + model="gpt-4o-transcribe", ) assert_matches_type(TranscriptionCreateResponse, transcription, path=["response"]) @parametrize - def test_method_create_with_all_params(self, client: OpenAI) -> None: + def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: transcription = client.audio.transcriptions.create( file=b"raw file contents", - model="whisper-1", - language="string", - prompt="string", + model="gpt-4o-transcribe", + include=["logprobs"], + language="language", + prompt="prompt", response_format="json", + stream=False, temperature=0, timestamp_granularities=["word"], ) assert_matches_type(TranscriptionCreateResponse, transcription, path=["response"]) @parametrize - def test_raw_response_create(self, client: OpenAI) -> None: + def test_raw_response_create_overload_1(self, client: OpenAI) -> None: response = client.audio.transcriptions.with_raw_response.create( file=b"raw file contents", - model="whisper-1", + model="gpt-4o-transcribe", ) assert response.is_closed is True @@ -51,10 +53,10 @@ def test_raw_response_create(self, client: OpenAI) -> None: assert_matches_type(TranscriptionCreateResponse, transcription, path=["response"]) @parametrize - def test_streaming_response_create(self, client: OpenAI) -> None: + def test_streaming_response_create_overload_1(self, client: OpenAI) -> None: with client.audio.transcriptions.with_streaming_response.create( file=b"raw file contents", - model="whisper-1", + model="gpt-4o-transcribe", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -64,36 +66,89 @@ def test_streaming_response_create(self, client: OpenAI) -> None: assert cast(Any, response.is_closed) is True + @parametrize + def test_method_create_overload_2(self, client: OpenAI) -> None: + transcription_stream = client.audio.transcriptions.create( + file=b"raw file contents", + model="gpt-4o-transcribe", + stream=True, + ) + transcription_stream.response.close() + + @parametrize + def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: + transcription_stream = client.audio.transcriptions.create( + file=b"raw file contents", + model="gpt-4o-transcribe", + stream=True, + include=["logprobs"], + language="language", + prompt="prompt", + response_format="json", + temperature=0, + timestamp_granularities=["word"], + ) + transcription_stream.response.close() + + @parametrize + def test_raw_response_create_overload_2(self, client: OpenAI) -> None: + response = client.audio.transcriptions.with_raw_response.create( + file=b"raw file contents", + model="gpt-4o-transcribe", + stream=True, + ) + + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = response.parse() + stream.close() + + @parametrize + def test_streaming_response_create_overload_2(self, client: OpenAI) -> None: + with client.audio.transcriptions.with_streaming_response.create( + file=b"raw file contents", + model="gpt-4o-transcribe", + stream=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = response.parse() + stream.close() + + assert cast(Any, response.is_closed) is True + class TestAsyncTranscriptions: parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) @parametrize - async def test_method_create(self, async_client: AsyncOpenAI) -> None: + async def test_method_create_overload_1(self, async_client: AsyncOpenAI) -> None: transcription = await async_client.audio.transcriptions.create( file=b"raw file contents", - model="whisper-1", + model="gpt-4o-transcribe", ) assert_matches_type(TranscriptionCreateResponse, transcription, path=["response"]) @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: + async def test_method_create_with_all_params_overload_1(self, async_client: AsyncOpenAI) -> None: transcription = await async_client.audio.transcriptions.create( file=b"raw file contents", - model="whisper-1", - language="string", - prompt="string", + model="gpt-4o-transcribe", + include=["logprobs"], + language="language", + prompt="prompt", response_format="json", + stream=False, temperature=0, timestamp_granularities=["word"], ) assert_matches_type(TranscriptionCreateResponse, transcription, path=["response"]) @parametrize - async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: + async def test_raw_response_create_overload_1(self, async_client: AsyncOpenAI) -> None: response = await async_client.audio.transcriptions.with_raw_response.create( file=b"raw file contents", - model="whisper-1", + model="gpt-4o-transcribe", ) assert response.is_closed is True @@ -102,10 +157,10 @@ async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: assert_matches_type(TranscriptionCreateResponse, transcription, path=["response"]) @parametrize - async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: + async def test_streaming_response_create_overload_1(self, async_client: AsyncOpenAI) -> None: async with async_client.audio.transcriptions.with_streaming_response.create( file=b"raw file contents", - model="whisper-1", + model="gpt-4o-transcribe", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -114,3 +169,54 @@ async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> Non assert_matches_type(TranscriptionCreateResponse, transcription, path=["response"]) assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_create_overload_2(self, async_client: AsyncOpenAI) -> None: + transcription_stream = await async_client.audio.transcriptions.create( + file=b"raw file contents", + model="gpt-4o-transcribe", + stream=True, + ) + await transcription_stream.response.aclose() + + @parametrize + async def test_method_create_with_all_params_overload_2(self, async_client: AsyncOpenAI) -> None: + transcription_stream = await async_client.audio.transcriptions.create( + file=b"raw file contents", + model="gpt-4o-transcribe", + stream=True, + include=["logprobs"], + language="language", + prompt="prompt", + response_format="json", + temperature=0, + timestamp_granularities=["word"], + ) + await transcription_stream.response.aclose() + + @parametrize + async def test_raw_response_create_overload_2(self, async_client: AsyncOpenAI) -> None: + response = await async_client.audio.transcriptions.with_raw_response.create( + file=b"raw file contents", + model="gpt-4o-transcribe", + stream=True, + ) + + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = response.parse() + await stream.close() + + @parametrize + async def test_streaming_response_create_overload_2(self, async_client: AsyncOpenAI) -> None: + async with async_client.audio.transcriptions.with_streaming_response.create( + file=b"raw file contents", + model="gpt-4o-transcribe", + stream=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = await response.parse() + await stream.close() + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/beta/realtime/test_sessions.py b/tests/api_resources/beta/realtime/test_sessions.py index 5ea308ca0d..c0a426a417 100644 --- a/tests/api_resources/beta/realtime/test_sessions.py +++ b/tests/api_resources/beta/realtime/test_sessions.py @@ -26,6 +26,7 @@ def test_method_create(self, client: OpenAI) -> None: def test_method_create_with_all_params(self, client: OpenAI) -> None: session = client.beta.realtime.sessions.create( input_audio_format="pcm16", + input_audio_noise_reduction={"type": "near_field"}, input_audio_transcription={ "language": "language", "model": "model", @@ -48,11 +49,12 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: ], turn_detection={ "create_response": True, + "eagerness": "low", "interrupt_response": True, "prefix_padding_ms": 0, "silence_duration_ms": 0, "threshold": 0, - "type": "type", + "type": "server_vad", }, voice="alloy", ) @@ -91,6 +93,7 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None: async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: session = await async_client.beta.realtime.sessions.create( input_audio_format="pcm16", + input_audio_noise_reduction={"type": "near_field"}, input_audio_transcription={ "language": "language", "model": "model", @@ -113,11 +116,12 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> ], turn_detection={ "create_response": True, + "eagerness": "low", "interrupt_response": True, "prefix_padding_ms": 0, "silence_duration_ms": 0, "threshold": 0, - "type": "type", + "type": "server_vad", }, voice="alloy", ) diff --git a/tests/api_resources/beta/realtime/test_transcription_sessions.py b/tests/api_resources/beta/realtime/test_transcription_sessions.py new file mode 100644 index 0000000000..4826185bea --- /dev/null +++ b/tests/api_resources/beta/realtime/test_transcription_sessions.py @@ -0,0 +1,120 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.types.beta.realtime import TranscriptionSession + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestTranscriptionSessions: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: OpenAI) -> None: + transcription_session = client.beta.realtime.transcription_sessions.create() + assert_matches_type(TranscriptionSession, transcription_session, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: OpenAI) -> None: + transcription_session = client.beta.realtime.transcription_sessions.create( + include=["string"], + input_audio_format="pcm16", + input_audio_noise_reduction={"type": "near_field"}, + input_audio_transcription={ + "language": "language", + "model": "gpt-4o-transcribe", + "prompt": "prompt", + }, + modalities=["text"], + turn_detection={ + "create_response": True, + "eagerness": "low", + "interrupt_response": True, + "prefix_padding_ms": 0, + "silence_duration_ms": 0, + "threshold": 0, + "type": "server_vad", + }, + ) + assert_matches_type(TranscriptionSession, transcription_session, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: OpenAI) -> None: + response = client.beta.realtime.transcription_sessions.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + transcription_session = response.parse() + assert_matches_type(TranscriptionSession, transcription_session, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: OpenAI) -> None: + with client.beta.realtime.transcription_sessions.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + transcription_session = response.parse() + assert_matches_type(TranscriptionSession, transcription_session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncTranscriptionSessions: + parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + async def test_method_create(self, async_client: AsyncOpenAI) -> None: + transcription_session = await async_client.beta.realtime.transcription_sessions.create() + assert_matches_type(TranscriptionSession, transcription_session, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: + transcription_session = await async_client.beta.realtime.transcription_sessions.create( + include=["string"], + input_audio_format="pcm16", + input_audio_noise_reduction={"type": "near_field"}, + input_audio_transcription={ + "language": "language", + "model": "gpt-4o-transcribe", + "prompt": "prompt", + }, + modalities=["text"], + turn_detection={ + "create_response": True, + "eagerness": "low", + "interrupt_response": True, + "prefix_padding_ms": 0, + "silence_duration_ms": 0, + "threshold": 0, + "type": "server_vad", + }, + ) + assert_matches_type(TranscriptionSession, transcription_session, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: + response = await async_client.beta.realtime.transcription_sessions.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + transcription_session = response.parse() + assert_matches_type(TranscriptionSession, transcription_session, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: + async with async_client.beta.realtime.transcription_sessions.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + transcription_session = await response.parse() + assert_matches_type(TranscriptionSession, transcription_session, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/lib/test_audio.py b/tests/lib/test_audio.py index 0f53b316ba..ff8dba4714 100644 --- a/tests/lib/test_audio.py +++ b/tests/lib/test_audio.py @@ -26,7 +26,7 @@ def test_translation_create_overloads_in_sync(sync: bool, client: OpenAI, async_ assert_signatures_in_sync( fn, overload, - exclude_params={"response_format"}, + exclude_params={"response_format", "stream"}, description=f" for overload {i}", ) @@ -60,7 +60,7 @@ def test_transcription_create_overloads_in_sync(sync: bool, client: OpenAI, asyn assert_signatures_in_sync( fn, overload, - exclude_params={"response_format"}, + exclude_params={"response_format", "stream"}, description=f" for overload {i}", ) From 8136a21637df5d79442efcb26459d2dd6154db77 Mon Sep 17 00:00:00 2001 From: Kevin Whinnery Date: Thu, 20 Mar 2025 11:31:58 -0500 Subject: [PATCH 247/769] feat: add audio helpers * add audio helpers * update ignore, lockfile, add execute * fix examples, lint errors * lint and export errors * temp: ignore type errors --- .gitignore | 4 + examples/audio.py | 26 ---- examples/speech_to_text.py | 25 ++++ examples/text_to_speech.py | 31 +++++ pyproject.toml | 2 + requirements-dev.lock | 7 +- requirements.lock | 6 + src/openai/helpers.py | 4 + src/openai/helpers/__init__.py | 4 + src/openai/helpers/local_audio_player.py | 162 +++++++++++++++++++++++ src/openai/helpers/microphone.py | 98 ++++++++++++++ 11 files changed, 341 insertions(+), 28 deletions(-) create mode 100755 examples/speech_to_text.py create mode 100755 examples/text_to_speech.py create mode 100644 src/openai/helpers.py create mode 100644 src/openai/helpers/__init__.py create mode 100644 src/openai/helpers/local_audio_player.py create mode 100644 src/openai/helpers/microphone.py diff --git a/.gitignore b/.gitignore index 8779740800..70815df7f6 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,7 @@ dist .envrc codegen.log Brewfile.lock.json + +.DS_Store + +examples/*.mp3 diff --git a/examples/audio.py b/examples/audio.py index 85f47bfb06..af41fe601b 100755 --- a/examples/audio.py +++ b/examples/audio.py @@ -1,6 +1,5 @@ #!/usr/bin/env rye run python -import time from pathlib import Path from openai import OpenAI @@ -12,8 +11,6 @@ def main() -> None: - stream_to_speakers() - # Create text-to-speech audio file with openai.audio.speech.with_streaming_response.create( model="tts-1", @@ -37,28 +34,5 @@ def main() -> None: print(translation.text) -def stream_to_speakers() -> None: - import pyaudio - - player_stream = pyaudio.PyAudio().open(format=pyaudio.paInt16, channels=1, rate=24000, output=True) - - start_time = time.time() - - with openai.audio.speech.with_streaming_response.create( - model="tts-1", - voice="alloy", - response_format="pcm", # similar to WAV, but without a header chunk at the start. - input="""I see skies of blue and clouds of white - The bright blessed days, the dark sacred nights - And I think to myself - What a wonderful world""", - ) as response: - print(f"Time to first byte: {int((time.time() - start_time) * 1000)}ms") - for chunk in response.iter_bytes(chunk_size=1024): - player_stream.write(chunk) - - print(f"Done in {int((time.time() - start_time) * 1000)}ms.") - - if __name__ == "__main__": main() diff --git a/examples/speech_to_text.py b/examples/speech_to_text.py new file mode 100755 index 0000000000..cc3f56b424 --- /dev/null +++ b/examples/speech_to_text.py @@ -0,0 +1,25 @@ +#!/usr/bin/env rye run python + +import asyncio + +from openai import AsyncOpenAI +from openai.helpers import Microphone + +# gets OPENAI_API_KEY from your environment variables +openai = AsyncOpenAI() + + +async def main() -> None: + print("Recording for the next 10 seconds...") + recording = await Microphone(timeout=10).record() + print("Recording complete") + transcription = await openai.audio.transcriptions.create( + model="whisper-1", + file=recording, + ) + + print(transcription.text) + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/examples/text_to_speech.py b/examples/text_to_speech.py new file mode 100755 index 0000000000..ac8b12b0ab --- /dev/null +++ b/examples/text_to_speech.py @@ -0,0 +1,31 @@ +#!/usr/bin/env rye run python + +import time +import asyncio + +from openai import AsyncOpenAI +from openai.helpers import LocalAudioPlayer + +# gets OPENAI_API_KEY from your environment variables +openai = AsyncOpenAI() + + +async def main() -> None: + start_time = time.time() + + async with openai.audio.speech.with_streaming_response.create( + model="tts-1", + voice="alloy", + response_format="pcm", # similar to WAV, but without a header chunk at the start. + input="""I see skies of blue and clouds of white + The bright blessed days, the dark sacred nights + And I think to myself + What a wonderful world""", + ) as response: + print(f"Time to first byte: {int((time.time() - start_time) * 1000)}ms") + await LocalAudioPlayer().play(response) + print(f"Time to play: {int((time.time() - start_time) * 1000)}ms") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/pyproject.toml b/pyproject.toml index a0a7eba2f5..dcec9ad3c4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,6 +16,8 @@ dependencies = [ "sniffio", "tqdm > 4", "jiter>=0.4.0, <1", + "sounddevice>=0.5.1", + "numpy>=2.0.2", ] requires-python = ">= 3.8" classifiers = [ diff --git a/requirements-dev.lock b/requirements-dev.lock index 48e49f926c..0755ddb3c5 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -33,6 +33,7 @@ certifi==2023.7.22 # via requests cffi==1.16.0 # via cryptography + # via sounddevice charset-normalizer==3.3.2 # via requests click==8.1.7 @@ -92,7 +93,7 @@ nest-asyncio==1.6.0 nodeenv==1.8.0 # via pyright nox==2023.4.22 -numpy==1.26.3 +numpy==2.0.2 # via openai # via pandas # via pandas-stubs @@ -102,7 +103,7 @@ packaging==23.2 # via black # via nox # via pytest -pandas==2.1.4 +pandas==2.2.3 # via openai pandas-stubs==2.1.4.231227 # via openai @@ -154,6 +155,8 @@ sniffio==1.3.0 # via trio sortedcontainers==2.4.0 # via trio +sounddevice==0.5.1 + # via openai time-machine==2.9.0 toml==0.10.2 # via inline-snapshot diff --git a/requirements.lock b/requirements.lock index b935c0ee59..fa88e26c0f 100644 --- a/requirements.lock +++ b/requirements.lock @@ -18,6 +18,8 @@ anyio==4.1.0 certifi==2023.7.22 # via httpcore # via httpx +cffi==1.17.1 + # via sounddevice distro==1.8.0 # via openai exceptiongroup==1.2.2 @@ -41,6 +43,8 @@ pandas==2.2.3 # via openai pandas-stubs==2.2.2.240807 # via openai +pycparser==2.22 + # via cffi pydantic==2.10.3 # via openai pydantic-core==2.27.1 @@ -54,6 +58,8 @@ six==1.16.0 sniffio==1.3.0 # via anyio # via openai +sounddevice==0.5.1 + # via openai tqdm==4.66.5 # via openai types-pytz==2024.2.0.20241003 diff --git a/src/openai/helpers.py b/src/openai/helpers.py new file mode 100644 index 0000000000..1a10168a96 --- /dev/null +++ b/src/openai/helpers.py @@ -0,0 +1,4 @@ +from .helpers.microphone import Microphone +from .helpers.local_audio_player import LocalAudioPlayer + +__all__ = ["LocalAudioPlayer", "Microphone"] diff --git a/src/openai/helpers/__init__.py b/src/openai/helpers/__init__.py new file mode 100644 index 0000000000..ab3044da59 --- /dev/null +++ b/src/openai/helpers/__init__.py @@ -0,0 +1,4 @@ +from .microphone import Microphone +from .local_audio_player import LocalAudioPlayer + +__all__ = ["Microphone", "LocalAudioPlayer"] diff --git a/src/openai/helpers/local_audio_player.py b/src/openai/helpers/local_audio_player.py new file mode 100644 index 0000000000..46a16ce6bb --- /dev/null +++ b/src/openai/helpers/local_audio_player.py @@ -0,0 +1,162 @@ +# mypy: ignore-errors +import queue +import asyncio +from typing import Any, Union, Callable, AsyncGenerator, cast + +import numpy as np +import sounddevice as sd # type: ignore +import numpy.typing as npt + +from .. import _legacy_response +from .._response import StreamedBinaryAPIResponse, AsyncStreamedBinaryAPIResponse + +SAMPLE_RATE = 24000 + + +class LocalAudioPlayer: + def __init__( + self, + should_stop: Union[Callable[[], bool], None] = None, + ): + self.channels = 1 + self.dtype = np.float32 + self.should_stop = should_stop + + async def _tts_response_to_buffer( + self, + response: Union[ + _legacy_response.HttpxBinaryResponseContent, + AsyncStreamedBinaryAPIResponse, + StreamedBinaryAPIResponse, + ], + ) -> npt.NDArray[np.float32]: + chunks: list[bytes] = [] + if isinstance(response, _legacy_response.HttpxBinaryResponseContent) or isinstance( + response, StreamedBinaryAPIResponse + ): + for chunk in response.iter_bytes(chunk_size=1024): + if chunk: + chunks.append(chunk) + else: + async for chunk in response.iter_bytes(chunk_size=1024): + if chunk: + chunks.append(chunk) + + audio_bytes = b"".join(chunks) + audio_np = np.frombuffer(audio_bytes, dtype=np.int16).astype(np.float32) / 32767.0 + audio_np = audio_np.reshape(-1, 1) + return audio_np + + async def play( + self, + input: Union[ + npt.NDArray[np.int16], + npt.NDArray[np.float32], + _legacy_response.HttpxBinaryResponseContent, + AsyncStreamedBinaryAPIResponse, + StreamedBinaryAPIResponse, + ], + ) -> None: + audio_content: npt.NDArray[np.float32] + if isinstance(input, np.ndarray): + if input.dtype == np.int16 and self.dtype == np.float32: + audio_content = (input.astype(np.float32) / 32767.0).reshape(-1, self.channels) + elif input.dtype == np.float32: + audio_content = cast(npt.NDArray[np.float32], input) + else: + raise ValueError(f"Unsupported dtype: {input.dtype}") + else: + audio_content = await self._tts_response_to_buffer(input) + + loop = asyncio.get_event_loop() + event = asyncio.Event() + idx = 0 + + def callback( + outdata: npt.NDArray[np.float32], + frame_count: int, + _time_info: Any, + _status: Any, + ): + nonlocal idx + + remainder = len(audio_content) - idx + if remainder == 0 or (callable(self.should_stop) and self.should_stop()): + loop.call_soon_threadsafe(event.set) + raise sd.CallbackStop + valid_frames = frame_count if remainder >= frame_count else remainder + outdata[:valid_frames] = audio_content[idx : idx + valid_frames] + outdata[valid_frames:] = 0 + idx += valid_frames + + stream = sd.OutputStream( + samplerate=SAMPLE_RATE, + callback=callback, + dtype=audio_content.dtype, + channels=audio_content.shape[1], + ) + with stream: + await event.wait() + + async def play_stream( + self, + buffer_stream: AsyncGenerator[Union[npt.NDArray[np.float32], npt.NDArray[np.int16], None], None], + ) -> None: + loop = asyncio.get_event_loop() + event = asyncio.Event() + buffer_queue: queue.Queue[Union[npt.NDArray[np.float32], npt.NDArray[np.int16], None]] = queue.Queue(maxsize=50) + + async def buffer_producer(): + async for buffer in buffer_stream: + if buffer is None: + break + await loop.run_in_executor(None, buffer_queue.put, buffer) + await loop.run_in_executor(None, buffer_queue.put, None) # Signal completion + + def callback( + outdata: npt.NDArray[np.float32], + frame_count: int, + _time_info: Any, + _status: Any, + ): + nonlocal current_buffer, buffer_pos + + frames_written = 0 + while frames_written < frame_count: + if current_buffer is None or buffer_pos >= len(current_buffer): + try: + current_buffer = buffer_queue.get(timeout=0.1) + if current_buffer is None: + loop.call_soon_threadsafe(event.set) + raise sd.CallbackStop + buffer_pos = 0 + + if current_buffer.dtype == np.int16 and self.dtype == np.float32: + current_buffer = (current_buffer.astype(np.float32) / 32767.0).reshape(-1, self.channels) + + except queue.Empty: + outdata[frames_written:] = 0 + return + + remaining_frames = len(current_buffer) - buffer_pos + frames_to_write = min(frame_count - frames_written, remaining_frames) + outdata[frames_written : frames_written + frames_to_write] = current_buffer[ + buffer_pos : buffer_pos + frames_to_write + ] + buffer_pos += frames_to_write + frames_written += frames_to_write + + current_buffer = None + buffer_pos = 0 + + producer_task = asyncio.create_task(buffer_producer()) + + with sd.OutputStream( + samplerate=SAMPLE_RATE, + channels=self.channels, + dtype=self.dtype, + callback=callback, + ): + await event.wait() + + await producer_task diff --git a/src/openai/helpers/microphone.py b/src/openai/helpers/microphone.py new file mode 100644 index 0000000000..18650909aa --- /dev/null +++ b/src/openai/helpers/microphone.py @@ -0,0 +1,98 @@ +# mypy: ignore-errors +import io +import time +import wave +import asyncio +from typing import Any, Type, Union, Generic, TypeVar, Callable, overload +from typing_extensions import Literal + +import numpy as np +import sounddevice as sd # type: ignore +import numpy.typing as npt + +from openai._types import FileTypes, FileContent + +SAMPLE_RATE = 24000 + +DType = TypeVar("DType", bound=np.generic) + + +class Microphone(Generic[DType]): + def __init__( + self, + channels: int = 1, + dtype: Type[DType] = np.int16, + should_record: Union[Callable[[], bool], None] = None, + timeout: Union[float, None] = None, + ): + self.channels = channels + self.dtype = dtype + self.should_record = should_record + self.buffer_chunks = [] + self.timeout = timeout + self.has_record_function = callable(should_record) + + def _ndarray_to_wav(self, audio_data: npt.NDArray[DType]) -> FileTypes: + buffer: FileContent = io.BytesIO() + with wave.open(buffer, "w") as wav_file: + wav_file.setnchannels(self.channels) + wav_file.setsampwidth(np.dtype(self.dtype).itemsize) + wav_file.setframerate(SAMPLE_RATE) + wav_file.writeframes(audio_data.tobytes()) + buffer.seek(0) + return ("audio.wav", buffer, "audio/wav") + + @overload + async def record(self, return_ndarray: Literal[True]) -> npt.NDArray[DType]: ... + + @overload + async def record(self, return_ndarray: Literal[False]) -> FileTypes: ... + + @overload + async def record(self, return_ndarray: None = ...) -> FileTypes: ... + + async def record(self, return_ndarray: Union[bool, None] = False) -> Union[npt.NDArray[DType], FileTypes]: + loop = asyncio.get_event_loop() + event = asyncio.Event() + self.buffer_chunks: list[npt.NDArray[DType]] = [] + start_time = time.perf_counter() + + def callback( + indata: npt.NDArray[DType], + _frame_count: int, + _time_info: Any, + _status: Any, + ): + execution_time = time.perf_counter() - start_time + reached_recording_timeout = execution_time > self.timeout if self.timeout is not None else False + if reached_recording_timeout: + loop.call_soon_threadsafe(event.set) + raise sd.CallbackStop + + should_be_recording = self.should_record() if callable(self.should_record) else True + if not should_be_recording: + loop.call_soon_threadsafe(event.set) + raise sd.CallbackStop + + self.buffer_chunks.append(indata.copy()) + + stream = sd.InputStream( + callback=callback, + dtype=self.dtype, + samplerate=SAMPLE_RATE, + channels=self.channels, + ) + with stream: + await event.wait() + + # Concatenate all chunks into a single buffer, handle empty case + concatenated_chunks: npt.NDArray[DType] = ( + np.concatenate(self.buffer_chunks, axis=0) + if len(self.buffer_chunks) > 0 + else np.array([], dtype=self.dtype) + ) + + if return_ndarray: + return concatenated_chunks + else: + return self._ndarray_to_wav(concatenated_chunks) From 6d0ecdd8ecbface903cf93c7571398b90b803b0b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 20 Mar 2025 16:32:31 +0000 Subject: [PATCH 248/769] release: 1.68.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 9 +++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 4556676715..42bc7e250e 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.67.0" + ".": "1.68.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index ddd8b945c6..78ae21f27f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 1.68.0 (2025-03-20) + +Full Changelog: [v1.67.0...v1.68.0](https://github.com/openai/openai-python/compare/v1.67.0...v1.68.0) + +### Features + +* add audio helpers ([423655c](https://github.com/openai/openai-python/commit/423655ca9077cfd258f1e52f6eb386fc8307fa5f)) +* **api:** new models for TTS, STT, + new audio features for Realtime ([#2232](https://github.com/openai/openai-python/issues/2232)) ([ab5192d](https://github.com/openai/openai-python/commit/ab5192d0a7b417ade622ec94dd48f86beb90692c)) + ## 1.67.0 (2025-03-19) Full Changelog: [v1.66.5...v1.67.0](https://github.com/openai/openai-python/compare/v1.66.5...v1.67.0) diff --git a/pyproject.toml b/pyproject.toml index dcec9ad3c4..5ee7157038 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.67.0" +version = "1.68.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 b63e6ad189..23e4e7ffb7 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.67.0" # x-release-please-version +__version__ = "1.68.0" # x-release-please-version From 916641e801d2b0bf0ec7a6ea1d171c2a1931fdef Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 20 Mar 2025 17:58:42 +0000 Subject: [PATCH 249/769] fix(client): remove duplicate types (#2235) --- src/openai/types/shared/all_models.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/openai/types/shared/all_models.py b/src/openai/types/shared/all_models.py index c4635e2140..db8410773e 100644 --- a/src/openai/types/shared/all_models.py +++ b/src/openai/types/shared/all_models.py @@ -8,9 +8,5 @@ __all__ = ["AllModels"] AllModels: TypeAlias = Union[ - str, - ChatModel, - str, - ChatModel, - Literal["o1-pro", "o1-pro-2025-03-19", "computer-use-preview", "computer-use-preview-2025-03-11"], + str, ChatModel, Literal["o1-pro", "o1-pro-2025-03-19", "computer-use-preview", "computer-use-preview-2025-03-11"] ] From 35e0e11d85038d7c5350afe534e8c7f0f46b4f05 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 20 Mar 2025 18:06:44 -0400 Subject: [PATCH 250/769] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index abb9371314..2df281d34f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 82 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-c22f59c66aec7914b6ee653d3098d1c1c8c16c180d2a158e819c8ddbf476f74b.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-5ad6884898c07591750dde560118baf7074a59aecd1f367f930c5e42b04e848a.yml From dbf975c84b02ffdd13de183f6af9a88890a367b3 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Fri, 21 Mar 2025 13:32:27 +0000 Subject: [PATCH 251/769] fix(package): make sounddevice and numpy optional dependencies --- pyproject.toml | 3 +-- src/openai/_extras/__init__.py | 1 + src/openai/_extras/numpy_proxy.py | 2 +- src/openai/_extras/sounddevice_proxy.py | 28 ++++++++++++++++++++++++ src/openai/helpers/local_audio_player.py | 13 ++++++----- src/openai/helpers/microphone.py | 12 +++++----- 6 files changed, 46 insertions(+), 13 deletions(-) create mode 100644 src/openai/_extras/sounddevice_proxy.py diff --git a/pyproject.toml b/pyproject.toml index 5ee7157038..f34bf6bfa3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,8 +16,6 @@ dependencies = [ "sniffio", "tqdm > 4", "jiter>=0.4.0, <1", - "sounddevice>=0.5.1", - "numpy>=2.0.2", ] requires-python = ">= 3.8" classifiers = [ @@ -47,6 +45,7 @@ openai = "openai.cli:main" [project.optional-dependencies] realtime = ["websockets >= 13, < 15"] datalib = ["numpy >= 1", "pandas >= 1.2.3", "pandas-stubs >= 1.1.0.11"] +audio = ["sounddevice>=0.5.1", "numpy>=2.0.2"] [tool.rye] managed = true diff --git a/src/openai/_extras/__init__.py b/src/openai/_extras/__init__.py index 864dac4171..692de248c0 100644 --- a/src/openai/_extras/__init__.py +++ b/src/openai/_extras/__init__.py @@ -1,2 +1,3 @@ from .numpy_proxy import numpy as numpy, has_numpy as has_numpy from .pandas_proxy import pandas as pandas +from .sounddevice_proxy import sounddevice as sounddevice diff --git a/src/openai/_extras/numpy_proxy.py b/src/openai/_extras/numpy_proxy.py index 27880bf132..8412965e44 100644 --- a/src/openai/_extras/numpy_proxy.py +++ b/src/openai/_extras/numpy_proxy.py @@ -10,7 +10,7 @@ import numpy as numpy -NUMPY_INSTRUCTIONS = format_instructions(library="numpy", extra="datalib") +NUMPY_INSTRUCTIONS = format_instructions(library="numpy", extra="audio") class NumpyProxy(LazyProxy[Any]): diff --git a/src/openai/_extras/sounddevice_proxy.py b/src/openai/_extras/sounddevice_proxy.py new file mode 100644 index 0000000000..0894782bd5 --- /dev/null +++ b/src/openai/_extras/sounddevice_proxy.py @@ -0,0 +1,28 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING, Any +from typing_extensions import override + +from .._utils import LazyProxy +from ._common import MissingDependencyError, format_instructions + +if TYPE_CHECKING: + import sounddevice as sounddevice # type: ignore + + +SOUNDDEVICE_INSTRUCTIONS = format_instructions(library="sounddevice", extra="audio") + + +class SounddeviceProxy(LazyProxy[Any]): + @override + def __load__(self) -> Any: + try: + import sounddevice # type: ignore + except ImportError as err: + raise MissingDependencyError(SOUNDDEVICE_INSTRUCTIONS) from err + + return sounddevice + + +if not TYPE_CHECKING: + sounddevice = SounddeviceProxy() diff --git a/src/openai/helpers/local_audio_player.py b/src/openai/helpers/local_audio_player.py index 46a16ce6bb..eed68aa21d 100644 --- a/src/openai/helpers/local_audio_player.py +++ b/src/openai/helpers/local_audio_player.py @@ -1,15 +1,18 @@ # mypy: ignore-errors +from __future__ import annotations + import queue import asyncio from typing import Any, Union, Callable, AsyncGenerator, cast - -import numpy as np -import sounddevice as sd # type: ignore -import numpy.typing as npt +from typing_extensions import TYPE_CHECKING from .. import _legacy_response +from .._extras import numpy as np, sounddevice as sd from .._response import StreamedBinaryAPIResponse, AsyncStreamedBinaryAPIResponse +if TYPE_CHECKING: + import numpy.typing as npt + SAMPLE_RATE = 24000 @@ -62,7 +65,7 @@ async def play( if input.dtype == np.int16 and self.dtype == np.float32: audio_content = (input.astype(np.float32) / 32767.0).reshape(-1, self.channels) elif input.dtype == np.float32: - audio_content = cast(npt.NDArray[np.float32], input) + audio_content = cast('npt.NDArray[np.float32]', input) else: raise ValueError(f"Unsupported dtype: {input.dtype}") else: diff --git a/src/openai/helpers/microphone.py b/src/openai/helpers/microphone.py index 18650909aa..62a6d8d8a9 100644 --- a/src/openai/helpers/microphone.py +++ b/src/openai/helpers/microphone.py @@ -1,16 +1,18 @@ # mypy: ignore-errors +from __future__ import annotations + import io import time import wave import asyncio from typing import Any, Type, Union, Generic, TypeVar, Callable, overload -from typing_extensions import Literal +from typing_extensions import TYPE_CHECKING, Literal -import numpy as np -import sounddevice as sd # type: ignore -import numpy.typing as npt +from .._types import FileTypes, FileContent +from .._extras import numpy as np, sounddevice as sd -from openai._types import FileTypes, FileContent +if TYPE_CHECKING: + import numpy.typing as npt SAMPLE_RATE = 24000 From 751d739eb3dd6c759537c809d61e789f57bef4bf Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Fri, 21 Mar 2025 13:33:45 +0000 Subject: [PATCH 252/769] chore(ci): run workflows on next too --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 06eb10c5f0..d86fc0ea53 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,7 @@ on: pull_request: branches: - main + - next jobs: lint: From 044f192e41831f4b01fe47944a2248a554cfdd34 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Fri, 21 Mar 2025 13:41:53 +0000 Subject: [PATCH 253/769] fix(helpers/audio): remove duplicative module --- src/openai/helpers.py | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 src/openai/helpers.py diff --git a/src/openai/helpers.py b/src/openai/helpers.py deleted file mode 100644 index 1a10168a96..0000000000 --- a/src/openai/helpers.py +++ /dev/null @@ -1,4 +0,0 @@ -from .helpers.microphone import Microphone -from .helpers.local_audio_player import LocalAudioPlayer - -__all__ = ["LocalAudioPlayer", "Microphone"] From d55062a3c474dfa2aa5964e997304aac080a4dd1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 21 Mar 2025 13:42:29 +0000 Subject: [PATCH 254/769] release: 1.68.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 15 +++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 42bc7e250e..2ec6ee54df 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.68.0" + ".": "1.68.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 78ae21f27f..d26a769784 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## 1.68.1 (2025-03-21) + +Full Changelog: [v1.68.0...v1.68.1](https://github.com/openai/openai-python/compare/v1.68.0...v1.68.1) + +### Bug Fixes + +* **client:** remove duplicate types ([#2235](https://github.com/openai/openai-python/issues/2235)) ([063f7d0](https://github.com/openai/openai-python/commit/063f7d0684c350ca9d766e2cb150233a22a623c8)) +* **helpers/audio:** remove duplicative module ([f253d04](https://github.com/openai/openai-python/commit/f253d0415145f2c4904ea2e7b389d31d94e45a54)) +* **package:** make sounddevice and numpy optional dependencies ([8b04453](https://github.com/openai/openai-python/commit/8b04453f0483736c13f0209a9f8f3618bc0e86c9)) + + +### Chores + +* **ci:** run workflows on next too ([67f89d4](https://github.com/openai/openai-python/commit/67f89d478aab780d1481c9bf6682c6633e431137)) + ## 1.68.0 (2025-03-20) Full Changelog: [v1.67.0...v1.68.0](https://github.com/openai/openai-python/compare/v1.67.0...v1.68.0) diff --git a/pyproject.toml b/pyproject.toml index f34bf6bfa3..57871a46fe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.68.0" +version = "1.68.1" 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 23e4e7ffb7..1f00359eb1 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.68.0" # x-release-please-version +__version__ = "1.68.1" # x-release-please-version From 257152bb1bbbce965ef37b9d349a0027742525f5 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Fri, 21 Mar 2025 14:41:50 +0000 Subject: [PATCH 255/769] refactor(package): rename audio extra to voice_helpers --- pyproject.toml | 2 +- src/openai/_extras/numpy_proxy.py | 2 +- src/openai/_extras/sounddevice_proxy.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 57871a46fe..e40060400a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,7 +45,7 @@ openai = "openai.cli:main" [project.optional-dependencies] realtime = ["websockets >= 13, < 15"] datalib = ["numpy >= 1", "pandas >= 1.2.3", "pandas-stubs >= 1.1.0.11"] -audio = ["sounddevice>=0.5.1", "numpy>=2.0.2"] +voice_helpers = ["sounddevice>=0.5.1", "numpy>=2.0.2"] [tool.rye] managed = true diff --git a/src/openai/_extras/numpy_proxy.py b/src/openai/_extras/numpy_proxy.py index 8412965e44..2b0669576e 100644 --- a/src/openai/_extras/numpy_proxy.py +++ b/src/openai/_extras/numpy_proxy.py @@ -10,7 +10,7 @@ import numpy as numpy -NUMPY_INSTRUCTIONS = format_instructions(library="numpy", extra="audio") +NUMPY_INSTRUCTIONS = format_instructions(library="numpy", extra="voice_helpers") class NumpyProxy(LazyProxy[Any]): diff --git a/src/openai/_extras/sounddevice_proxy.py b/src/openai/_extras/sounddevice_proxy.py index 0894782bd5..482d4c6874 100644 --- a/src/openai/_extras/sounddevice_proxy.py +++ b/src/openai/_extras/sounddevice_proxy.py @@ -10,7 +10,7 @@ import sounddevice as sounddevice # type: ignore -SOUNDDEVICE_INSTRUCTIONS = format_instructions(library="sounddevice", extra="audio") +SOUNDDEVICE_INSTRUCTIONS = format_instructions(library="sounddevice", extra="voice_helpers") class SounddeviceProxy(LazyProxy[Any]): From f66d2e6fdc51c4528c99bb25a8fbca6f9b9b872d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 21 Mar 2025 14:42:25 +0000 Subject: [PATCH 256/769] release: 1.68.2 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 2ec6ee54df..e280020f03 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.68.1" + ".": "1.68.2" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index d26a769784..ee22cfe7fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.68.2 (2025-03-21) + +Full Changelog: [v1.68.1...v1.68.2](https://github.com/openai/openai-python/compare/v1.68.1...v1.68.2) + +### Refactors + +* **package:** rename audio extra to voice_helpers ([2dd6cb8](https://github.com/openai/openai-python/commit/2dd6cb87489fe12c5e45128f44d985c3f49aba1d)) + ## 1.68.1 (2025-03-21) Full Changelog: [v1.68.0...v1.68.1](https://github.com/openai/openai-python/compare/v1.68.0...v1.68.1) diff --git a/pyproject.toml b/pyproject.toml index e40060400a..b1917922cd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.68.1" +version = "1.68.2" 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 1f00359eb1..a29ce4e818 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.68.1" # x-release-please-version +__version__ = "1.68.2" # x-release-please-version From 2706bdd779d3fca61b68ebd956ecd8eb1db421ae Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 26 Mar 2025 16:35:37 +0000 Subject: [PATCH 257/769] chore: fix typos (#2259) --- src/openai/_models.py | 2 +- src/openai/_utils/_transform.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/openai/_models.py b/src/openai/_models.py index ff7c1f3392..fc4f201e4e 100644 --- a/src/openai/_models.py +++ b/src/openai/_models.py @@ -721,7 +721,7 @@ def add_request_id(obj: BaseModel, request_id: str | None) -> None: cast(Any, obj).__exclude_fields__ = {*(exclude_fields or {}), "_request_id", "__exclude_fields__"} -# our use of subclasssing here causes weirdness for type checkers, +# our use of subclassing here causes weirdness for type checkers, # so we just pretend that we don't subclass if TYPE_CHECKING: GenericModel = BaseModel diff --git a/src/openai/_utils/_transform.py b/src/openai/_utils/_transform.py index 18afd9d8bd..7ac2e17fbb 100644 --- a/src/openai/_utils/_transform.py +++ b/src/openai/_utils/_transform.py @@ -126,7 +126,7 @@ def _get_annotated_type(type_: type) -> type | None: def _maybe_transform_key(key: str, type_: type) -> str: """Transform the given `data` based on the annotations provided in `type_`. - Note: this function only looks at `Annotated` types that contain `PropertInfo` metadata. + Note: this function only looks at `Annotated` types that contain `PropertyInfo` metadata. """ annotated_type = _get_annotated_type(type_) if annotated_type is None: From a4b9f4075ebcf54a97489bc55995e308ccb62a1b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 26 Mar 2025 17:32:51 +0000 Subject: [PATCH 258/769] chore: add hash of OpenAPI spec/config inputs to .stats.yml --- .stats.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.stats.yml b/.stats.yml index 2df281d34f..fe93204292 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,4 @@ configured_endpoints: 82 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-5ad6884898c07591750dde560118baf7074a59aecd1f367f930c5e42b04e848a.yml +openapi_spec_hash: 0c255269b89767eae26f4d4dc22d3cbd +config_hash: d36e491b0afc4f79e3afad4b3c9bec70 From 2e73b5291ba6256714daea346c935dd01dbb6bb2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 26 Mar 2025 20:32:36 +0000 Subject: [PATCH 259/769] chore(api): updates to supported Voice IDs (#2261) --- .stats.yml | 4 ++-- src/openai/resources/audio/speech.py | 16 ++++++++----- .../resources/beta/realtime/sessions.py | 16 +++++++++---- src/openai/resources/responses/input_items.py | 13 +++++++++- src/openai/resources/responses/responses.py | 24 +++++++++---------- .../types/audio/speech_create_params.py | 11 ++++++--- .../types/beta/realtime/realtime_response.py | 9 +++++-- .../beta/realtime/response_create_event.py | 8 +++++-- .../realtime/response_create_event_param.py | 6 +++-- src/openai/types/beta/realtime/session.py | 6 ++++- .../beta/realtime/session_create_params.py | 6 +++-- .../beta/realtime/session_create_response.py | 6 ++++- .../beta/realtime/session_update_event.py | 8 +++++-- .../realtime/session_update_event_param.py | 6 +++-- .../transcription_session_create_params.py | 7 +++--- .../realtime/transcription_session_update.py | 7 +++--- .../transcription_session_update_param.py | 7 +++--- .../types/chat/chat_completion_audio_param.py | 7 +++++- .../types/responses/input_item_list_params.py | 9 +++++++ src/openai/types/responses/response.py | 4 ++-- .../types/responses/response_create_params.py | 4 ++-- ...response_format_text_json_schema_config.py | 14 +++++------ ...se_format_text_json_schema_config_param.py | 14 +++++------ tests/api_resources/audio/test_speech.py | 16 ++++++------- .../beta/realtime/test_sessions.py | 4 ++-- tests/api_resources/chat/test_completions.py | 8 +++---- .../responses/test_input_items.py | 2 ++ 27 files changed, 158 insertions(+), 84 deletions(-) diff --git a/.stats.yml b/.stats.yml index fe93204292..4d1276a5e6 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 82 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-5ad6884898c07591750dde560118baf7074a59aecd1f367f930c5e42b04e848a.yml -openapi_spec_hash: 0c255269b89767eae26f4d4dc22d3cbd +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-6663c59193eb95b201e492de17dcbd5e126ba03d18ce66287a3e2c632ca56fe7.yml +openapi_spec_hash: 7996d2c34cc44fe2ce9ffe93c0ab774e config_hash: d36e491b0afc4f79e3afad4b3c9bec70 diff --git a/src/openai/resources/audio/speech.py b/src/openai/resources/audio/speech.py index 529e3a47ea..1ee53db9d5 100644 --- a/src/openai/resources/audio/speech.py +++ b/src/openai/resources/audio/speech.py @@ -53,7 +53,9 @@ def create( *, input: str, model: Union[str, SpeechModel], - voice: Literal["alloy", "ash", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer"], + voice: Union[ + str, Literal["alloy", "ash", "ballad", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer", "verse"] + ], instructions: str | NotGiven = NOT_GIVEN, response_format: Literal["mp3", "opus", "aac", "flac", "wav", "pcm"] | NotGiven = NOT_GIVEN, speed: float | NotGiven = NOT_GIVEN, @@ -75,8 +77,8 @@ def create( `tts-1`, `tts-1-hd` or `gpt-4o-mini-tts`. voice: The voice to use when generating the audio. Supported voices are `alloy`, `ash`, - `coral`, `echo`, `fable`, `onyx`, `nova`, `sage` and `shimmer`. Previews of the - voices are available in the + `ballad`, `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, `shimmer`, and + `verse`. Previews of the voices are available in the [Text to speech guide](https://platform.openai.com/docs/guides/text-to-speech#voice-options). instructions: Control the voice of your generated audio with additional instructions. Does not @@ -142,7 +144,9 @@ async def create( *, input: str, model: Union[str, SpeechModel], - voice: Literal["alloy", "ash", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer"], + voice: Union[ + str, Literal["alloy", "ash", "ballad", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer", "verse"] + ], instructions: str | NotGiven = NOT_GIVEN, response_format: Literal["mp3", "opus", "aac", "flac", "wav", "pcm"] | NotGiven = NOT_GIVEN, speed: float | NotGiven = NOT_GIVEN, @@ -164,8 +168,8 @@ async def create( `tts-1`, `tts-1-hd` or `gpt-4o-mini-tts`. voice: The voice to use when generating the audio. Supported voices are `alloy`, `ash`, - `coral`, `echo`, `fable`, `onyx`, `nova`, `sage` and `shimmer`. Previews of the - voices are available in the + `ballad`, `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, `shimmer`, and + `verse`. Previews of the voices are available in the [Text to speech guide](https://platform.openai.com/docs/guides/text-to-speech#voice-options). instructions: Control the voice of your generated audio with additional instructions. Does not diff --git a/src/openai/resources/beta/realtime/sessions.py b/src/openai/resources/beta/realtime/sessions.py index 5884e54de2..3e1c956fe4 100644 --- a/src/openai/resources/beta/realtime/sessions.py +++ b/src/openai/resources/beta/realtime/sessions.py @@ -65,7 +65,10 @@ def create( tool_choice: str | NotGiven = NOT_GIVEN, tools: Iterable[session_create_params.Tool] | NotGiven = NOT_GIVEN, turn_detection: session_create_params.TurnDetection | NotGiven = NOT_GIVEN, - voice: Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"] | NotGiven = NOT_GIVEN, + voice: Union[ + str, Literal["alloy", "ash", "ballad", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer", "verse"] + ] + | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -147,7 +150,8 @@ def create( voice: The voice the model uses to respond. Voice cannot be changed during the session once the model has responded with audio at least once. Current voice options are - `alloy`, `ash`, `ballad`, `coral`, `echo` `sage`, `shimmer` and `verse`. + `alloy`, `ash`, `ballad`, `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, + `shimmer`, and `verse`. extra_headers: Send extra headers @@ -227,7 +231,10 @@ async def create( tool_choice: str | NotGiven = NOT_GIVEN, tools: Iterable[session_create_params.Tool] | NotGiven = NOT_GIVEN, turn_detection: session_create_params.TurnDetection | NotGiven = NOT_GIVEN, - voice: Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"] | NotGiven = NOT_GIVEN, + voice: Union[ + str, Literal["alloy", "ash", "ballad", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer", "verse"] + ] + | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -309,7 +316,8 @@ async def create( voice: The voice the model uses to respond. Voice cannot be changed during the session once the model has responded with audio at least once. Current voice options are - `alloy`, `ash`, `ballad`, `coral`, `echo` `sage`, `shimmer` and `verse`. + `alloy`, `ash`, `ballad`, `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, + `shimmer`, and `verse`. extra_headers: Send extra headers diff --git a/src/openai/resources/responses/input_items.py b/src/openai/resources/responses/input_items.py index e341393cd1..ee0e628169 100644 --- a/src/openai/resources/responses/input_items.py +++ b/src/openai/resources/responses/input_items.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Any, cast +from typing import Any, List, cast from typing_extensions import Literal import httpx @@ -17,6 +17,7 @@ from ..._base_client import AsyncPaginator, make_request_options from ...types.responses import input_item_list_params from ...types.responses.response_item import ResponseItem +from ...types.responses.response_includable import ResponseIncludable __all__ = ["InputItems", "AsyncInputItems"] @@ -47,6 +48,7 @@ def list( *, after: str | NotGiven = NOT_GIVEN, before: str | NotGiven = NOT_GIVEN, + include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, limit: int | NotGiven = NOT_GIVEN, order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -64,6 +66,9 @@ def list( before: An item ID to list items before, used in pagination. + include: Additional fields to include in the response. See the `include` parameter for + Response creation above for more information. + limit: A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 20. @@ -94,6 +99,7 @@ def list( { "after": after, "before": before, + "include": include, "limit": limit, "order": order, }, @@ -130,6 +136,7 @@ def list( *, after: str | NotGiven = NOT_GIVEN, before: str | NotGiven = NOT_GIVEN, + include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, limit: int | NotGiven = NOT_GIVEN, order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -147,6 +154,9 @@ def list( before: An item ID to list items before, used in pagination. + include: Additional fields to include in the response. See the `include` parameter for + Response creation above for more information. + limit: A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 20. @@ -177,6 +187,7 @@ def list( { "after": after, "before": before, + "include": include, "limit": limit, "order": order, }, diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 668f4db80a..29ed3de42a 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -149,8 +149,8 @@ def create( context. When using along with `previous_response_id`, the instructions from a previous - response will be not be carried over to the next response. This makes it simple - to swap out system (or developer) messages in new responses. + response will not be carried over to the next response. This makes it simple to + swap out system (or developer) messages in new responses. max_output_tokens: An upper bound for the number of tokens that can be generated for a response, including visible output tokens and @@ -321,8 +321,8 @@ def create( context. When using along with `previous_response_id`, the instructions from a previous - response will be not be carried over to the next response. This makes it simple - to swap out system (or developer) messages in new responses. + response will not be carried over to the next response. This makes it simple to + swap out system (or developer) messages in new responses. max_output_tokens: An upper bound for the number of tokens that can be generated for a response, including visible output tokens and @@ -486,8 +486,8 @@ def create( context. When using along with `previous_response_id`, the instructions from a previous - response will be not be carried over to the next response. This makes it simple - to swap out system (or developer) messages in new responses. + response will not be carried over to the next response. This makes it simple to + swap out system (or developer) messages in new responses. max_output_tokens: An upper bound for the number of tokens that can be generated for a response, including visible output tokens and @@ -961,8 +961,8 @@ async def create( context. When using along with `previous_response_id`, the instructions from a previous - response will be not be carried over to the next response. This makes it simple - to swap out system (or developer) messages in new responses. + response will not be carried over to the next response. This makes it simple to + swap out system (or developer) messages in new responses. max_output_tokens: An upper bound for the number of tokens that can be generated for a response, including visible output tokens and @@ -1133,8 +1133,8 @@ async def create( context. When using along with `previous_response_id`, the instructions from a previous - response will be not be carried over to the next response. This makes it simple - to swap out system (or developer) messages in new responses. + response will not be carried over to the next response. This makes it simple to + swap out system (or developer) messages in new responses. max_output_tokens: An upper bound for the number of tokens that can be generated for a response, including visible output tokens and @@ -1298,8 +1298,8 @@ async def create( context. When using along with `previous_response_id`, the instructions from a previous - response will be not be carried over to the next response. This makes it simple - to swap out system (or developer) messages in new responses. + response will not be carried over to the next response. This makes it simple to + swap out system (or developer) messages in new responses. max_output_tokens: An upper bound for the number of tokens that can be generated for a response, including visible output tokens and diff --git a/src/openai/types/audio/speech_create_params.py b/src/openai/types/audio/speech_create_params.py index 958680710b..a4fc020532 100644 --- a/src/openai/types/audio/speech_create_params.py +++ b/src/openai/types/audio/speech_create_params.py @@ -20,11 +20,16 @@ class SpeechCreateParams(TypedDict, total=False): `tts-1`, `tts-1-hd` or `gpt-4o-mini-tts`. """ - voice: Required[Literal["alloy", "ash", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer"]] + voice: Required[ + Union[ + str, Literal["alloy", "ash", "ballad", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer", "verse"] + ] + ] """The voice to use when generating the audio. - Supported voices are `alloy`, `ash`, `coral`, `echo`, `fable`, `onyx`, `nova`, - `sage` and `shimmer`. Previews of the voices are available in the + Supported voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, `fable`, `onyx`, + `nova`, `sage`, `shimmer`, and `verse`. Previews of the voices are available in + the [Text to speech guide](https://platform.openai.com/docs/guides/text-to-speech#voice-options). """ diff --git a/src/openai/types/beta/realtime/realtime_response.py b/src/openai/types/beta/realtime/realtime_response.py index 4c3c83d666..8ecfb91c31 100644 --- a/src/openai/types/beta/realtime/realtime_response.py +++ b/src/openai/types/beta/realtime/realtime_response.py @@ -80,8 +80,13 @@ class RealtimeResponse(BaseModel): will become the input for later turns. """ - voice: Optional[Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"]] = None + voice: Union[ + str, + Literal["alloy", "ash", "ballad", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer", "verse"], + None, + ] = None """ The voice the model used to respond. Current voice options are `alloy`, `ash`, - `ballad`, `coral`, `echo` `sage`, `shimmer` and `verse`. + `ballad`, `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, `shimmer`, and + `verse`. """ diff --git a/src/openai/types/beta/realtime/response_create_event.py b/src/openai/types/beta/realtime/response_create_event.py index d6c5fda926..3b8a6de8df 100644 --- a/src/openai/types/beta/realtime/response_create_event.py +++ b/src/openai/types/beta/realtime/response_create_event.py @@ -101,12 +101,16 @@ class Response(BaseModel): tools: Optional[List[ResponseTool]] = None """Tools (functions) available to the model.""" - voice: Optional[Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"]] = None + voice: Union[ + str, + Literal["alloy", "ash", "ballad", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer", "verse"], + None, + ] = None """The voice the model uses to respond. Voice cannot be changed during the session once the model has responded with audio at least once. Current voice options are `alloy`, `ash`, `ballad`, - `coral`, `echo` `sage`, `shimmer` and `verse`. + `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, `shimmer`, and `verse`. """ diff --git a/src/openai/types/beta/realtime/response_create_event_param.py b/src/openai/types/beta/realtime/response_create_event_param.py index c02fe1b34e..c569d507a0 100644 --- a/src/openai/types/beta/realtime/response_create_event_param.py +++ b/src/openai/types/beta/realtime/response_create_event_param.py @@ -102,12 +102,14 @@ class Response(TypedDict, total=False): tools: Iterable[ResponseTool] """Tools (functions) available to the model.""" - voice: Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"] + voice: Union[ + str, Literal["alloy", "ash", "ballad", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer", "verse"] + ] """The voice the model uses to respond. Voice cannot be changed during the session once the model has responded with audio at least once. Current voice options are `alloy`, `ash`, `ballad`, - `coral`, `echo` `sage`, `shimmer` and `verse`. + `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, `shimmer`, and `verse`. """ diff --git a/src/openai/types/beta/realtime/session.py b/src/openai/types/beta/realtime/session.py index 3ed53ff5f8..6acde57f09 100644 --- a/src/openai/types/beta/realtime/session.py +++ b/src/openai/types/beta/realtime/session.py @@ -218,7 +218,11 @@ class Session(BaseModel): natural conversations, but may have a higher latency. """ - voice: Optional[Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"]] = None + voice: Union[ + str, + Literal["alloy", "ash", "ballad", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer", "verse"], + None, + ] = None """The voice the model uses to respond. Voice cannot be changed during the session once the model has responded with diff --git a/src/openai/types/beta/realtime/session_create_params.py b/src/openai/types/beta/realtime/session_create_params.py index fe4a1c8636..eadee29b28 100644 --- a/src/openai/types/beta/realtime/session_create_params.py +++ b/src/openai/types/beta/realtime/session_create_params.py @@ -113,12 +113,14 @@ class SessionCreateParams(TypedDict, total=False): natural conversations, but may have a higher latency. """ - voice: Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"] + voice: Union[ + str, Literal["alloy", "ash", "ballad", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer", "verse"] + ] """The voice the model uses to respond. Voice cannot be changed during the session once the model has responded with audio at least once. Current voice options are `alloy`, `ash`, `ballad`, - `coral`, `echo` `sage`, `shimmer` and `verse`. + `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, `shimmer`, and `verse`. """ diff --git a/src/openai/types/beta/realtime/session_create_response.py b/src/openai/types/beta/realtime/session_create_response.py index c26e62bef1..3cc8ca15ce 100644 --- a/src/openai/types/beta/realtime/session_create_response.py +++ b/src/openai/types/beta/realtime/session_create_response.py @@ -141,7 +141,11 @@ class SessionCreateResponse(BaseModel): speech. """ - voice: Optional[Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"]] = None + voice: Union[ + str, + Literal["alloy", "ash", "ballad", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer", "verse"], + None, + ] = None """The voice the model uses to respond. Voice cannot be changed during the session once the model has responded with diff --git a/src/openai/types/beta/realtime/session_update_event.py b/src/openai/types/beta/realtime/session_update_event.py index 00180f593d..ba34b0260b 100644 --- a/src/openai/types/beta/realtime/session_update_event.py +++ b/src/openai/types/beta/realtime/session_update_event.py @@ -222,12 +222,16 @@ class Session(BaseModel): natural conversations, but may have a higher latency. """ - voice: Optional[Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"]] = None + voice: Union[ + str, + Literal["alloy", "ash", "ballad", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer", "verse"], + None, + ] = None """The voice the model uses to respond. Voice cannot be changed during the session once the model has responded with audio at least once. Current voice options are `alloy`, `ash`, `ballad`, - `coral`, `echo` `sage`, `shimmer` and `verse`. + `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, `shimmer`, and `verse`. """ diff --git a/src/openai/types/beta/realtime/session_update_event_param.py b/src/openai/types/beta/realtime/session_update_event_param.py index b8bce8fbd0..0984d39e91 100644 --- a/src/openai/types/beta/realtime/session_update_event_param.py +++ b/src/openai/types/beta/realtime/session_update_event_param.py @@ -220,12 +220,14 @@ class Session(TypedDict, total=False): natural conversations, but may have a higher latency. """ - voice: Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"] + voice: Union[ + str, Literal["alloy", "ash", "ballad", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer", "verse"] + ] """The voice the model uses to respond. Voice cannot be changed during the session once the model has responded with audio at least once. Current voice options are `alloy`, `ash`, `ballad`, - `coral`, `echo` `sage`, `shimmer` and `verse`. + `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, `shimmer`, and `verse`. """ diff --git a/src/openai/types/beta/realtime/transcription_session_create_params.py b/src/openai/types/beta/realtime/transcription_session_create_params.py index 4066dc4c5d..1cf511f0b5 100644 --- a/src/openai/types/beta/realtime/transcription_session_create_params.py +++ b/src/openai/types/beta/realtime/transcription_session_create_params.py @@ -96,9 +96,10 @@ class InputAudioTranscription(TypedDict, total=False): class TurnDetection(TypedDict, total=False): create_response: bool - """ - Whether or not to automatically generate a response when a VAD stop event + """Whether or not to automatically generate a response when a VAD stop event occurs. + + Not available for transcription sessions. """ eagerness: Literal["low", "medium", "high", "auto"] @@ -113,7 +114,7 @@ class TurnDetection(TypedDict, total=False): """ Whether or not to automatically interrupt any ongoing response with output to the default conversation (i.e. `conversation` of `auto`) when a VAD start event - occurs. + occurs. Not available for transcription sessions. """ prefix_padding_ms: int diff --git a/src/openai/types/beta/realtime/transcription_session_update.py b/src/openai/types/beta/realtime/transcription_session_update.py index 043ac02e07..c3e8f011c8 100644 --- a/src/openai/types/beta/realtime/transcription_session_update.py +++ b/src/openai/types/beta/realtime/transcription_session_update.py @@ -50,9 +50,10 @@ class SessionInputAudioTranscription(BaseModel): class SessionTurnDetection(BaseModel): create_response: Optional[bool] = None - """ - Whether or not to automatically generate a response when a VAD stop event + """Whether or not to automatically generate a response when a VAD stop event occurs. + + Not available for transcription sessions. """ eagerness: Optional[Literal["low", "medium", "high", "auto"]] = None @@ -67,7 +68,7 @@ class SessionTurnDetection(BaseModel): """ Whether or not to automatically interrupt any ongoing response with output to the default conversation (i.e. `conversation` of `auto`) when a VAD start event - occurs. + occurs. Not available for transcription sessions. """ prefix_padding_ms: Optional[int] = None diff --git a/src/openai/types/beta/realtime/transcription_session_update_param.py b/src/openai/types/beta/realtime/transcription_session_update_param.py index 997a36d77b..549c49011b 100644 --- a/src/openai/types/beta/realtime/transcription_session_update_param.py +++ b/src/openai/types/beta/realtime/transcription_session_update_param.py @@ -50,9 +50,10 @@ class SessionInputAudioTranscription(TypedDict, total=False): class SessionTurnDetection(TypedDict, total=False): create_response: bool - """ - Whether or not to automatically generate a response when a VAD stop event + """Whether or not to automatically generate a response when a VAD stop event occurs. + + Not available for transcription sessions. """ eagerness: Literal["low", "medium", "high", "auto"] @@ -67,7 +68,7 @@ class SessionTurnDetection(TypedDict, total=False): """ Whether or not to automatically interrupt any ongoing response with output to the default conversation (i.e. `conversation` of `auto`) when a VAD start event - occurs. + occurs. Not available for transcription sessions. """ prefix_padding_ms: int diff --git a/src/openai/types/chat/chat_completion_audio_param.py b/src/openai/types/chat/chat_completion_audio_param.py index 6321417826..b902f2667f 100644 --- a/src/openai/types/chat/chat_completion_audio_param.py +++ b/src/openai/types/chat/chat_completion_audio_param.py @@ -2,6 +2,7 @@ from __future__ import annotations +from typing import Union from typing_extensions import Literal, Required, TypedDict __all__ = ["ChatCompletionAudioParam"] @@ -14,7 +15,11 @@ class ChatCompletionAudioParam(TypedDict, total=False): Must be one of `wav`, `mp3`, `flac`, `opus`, or `pcm16`. """ - voice: Required[Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"]] + voice: Required[ + Union[ + str, Literal["alloy", "ash", "ballad", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer", "verse"] + ] + ] """The voice the model uses to respond. Supported voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`, and diff --git a/src/openai/types/responses/input_item_list_params.py b/src/openai/types/responses/input_item_list_params.py index e0b71f1ac5..6555d26788 100644 --- a/src/openai/types/responses/input_item_list_params.py +++ b/src/openai/types/responses/input_item_list_params.py @@ -2,8 +2,11 @@ from __future__ import annotations +from typing import List from typing_extensions import Literal, TypedDict +from .response_includable import ResponseIncludable + __all__ = ["InputItemListParams"] @@ -14,6 +17,12 @@ class InputItemListParams(TypedDict, total=False): before: str """An item ID to list items before, used in pagination.""" + include: List[ResponseIncludable] + """Additional fields to include in the response. + + See the `include` parameter for Response creation above for more information. + """ + limit: int """A limit on the number of objects to be returned. diff --git a/src/openai/types/responses/response.py b/src/openai/types/responses/response.py index 1bedf80889..8cd1e01144 100644 --- a/src/openai/types/responses/response.py +++ b/src/openai/types/responses/response.py @@ -47,8 +47,8 @@ class Response(BaseModel): context. When using along with `previous_response_id`, the instructions from a previous - response will be not be carried over to the next response. This makes it simple - to swap out system (or developer) messages in new responses. + response will not be carried over to the next response. This makes it simple to + swap out system (or developer) messages in new responses. """ metadata: Optional[Metadata] = None diff --git a/src/openai/types/responses/response_create_params.py b/src/openai/types/responses/response_create_params.py index 651050c50d..ed82e678e5 100644 --- a/src/openai/types/responses/response_create_params.py +++ b/src/openai/types/responses/response_create_params.py @@ -64,8 +64,8 @@ class ResponseCreateParamsBase(TypedDict, total=False): context. When using along with `previous_response_id`, the instructions from a previous - response will be not be carried over to the next response. This makes it simple - to swap out system (or developer) messages in new responses. + response will not be carried over to the next response. This makes it simple to + swap out system (or developer) messages in new responses. """ max_output_tokens: Optional[int] diff --git a/src/openai/types/responses/response_format_text_json_schema_config.py b/src/openai/types/responses/response_format_text_json_schema_config.py index 3cf066370f..001fcf5bab 100644 --- a/src/openai/types/responses/response_format_text_json_schema_config.py +++ b/src/openai/types/responses/response_format_text_json_schema_config.py @@ -11,6 +11,13 @@ class ResponseFormatTextJSONSchemaConfig(BaseModel): + name: str + """The name of the response format. + + Must be a-z, A-Z, 0-9, or contain underscores and dashes, with a maximum length + of 64. + """ + schema_: Dict[str, object] = FieldInfo(alias="schema") """ The schema for the response format, described as a JSON Schema object. Learn how @@ -26,13 +33,6 @@ class ResponseFormatTextJSONSchemaConfig(BaseModel): how to respond in the format. """ - name: Optional[str] = None - """The name of the response format. - - Must be a-z, A-Z, 0-9, or contain underscores and dashes, with a maximum length - of 64. - """ - strict: Optional[bool] = None """ Whether to enable strict schema adherence when generating the output. If set to diff --git a/src/openai/types/responses/response_format_text_json_schema_config_param.py b/src/openai/types/responses/response_format_text_json_schema_config_param.py index 211c5d1eff..f293a80c5a 100644 --- a/src/openai/types/responses/response_format_text_json_schema_config_param.py +++ b/src/openai/types/responses/response_format_text_json_schema_config_param.py @@ -9,6 +9,13 @@ class ResponseFormatTextJSONSchemaConfigParam(TypedDict, total=False): + name: Required[str] + """The name of the response format. + + Must be a-z, A-Z, 0-9, or contain underscores and dashes, with a maximum length + of 64. + """ + schema: Required[Dict[str, object]] """ The schema for the response format, described as a JSON Schema object. Learn how @@ -24,13 +31,6 @@ class ResponseFormatTextJSONSchemaConfigParam(TypedDict, total=False): how to respond in the format. """ - name: str - """The name of the response format. - - Must be a-z, A-Z, 0-9, or contain underscores and dashes, with a maximum length - of 64. - """ - strict: Optional[bool] """ Whether to enable strict schema adherence when generating the output. If set to diff --git a/tests/api_resources/audio/test_speech.py b/tests/api_resources/audio/test_speech.py index 808f6ef66c..ce9ed59ce3 100644 --- a/tests/api_resources/audio/test_speech.py +++ b/tests/api_resources/audio/test_speech.py @@ -28,7 +28,7 @@ def test_method_create(self, client: OpenAI, respx_mock: MockRouter) -> None: speech = client.audio.speech.create( input="string", model="string", - voice="alloy", + voice="ash", ) assert isinstance(speech, _legacy_response.HttpxBinaryResponseContent) assert speech.json() == {"foo": "bar"} @@ -40,7 +40,7 @@ def test_method_create_with_all_params(self, client: OpenAI, respx_mock: MockRou speech = client.audio.speech.create( input="string", model="string", - voice="alloy", + voice="ash", instructions="instructions", response_format="mp3", speed=0.25, @@ -56,7 +56,7 @@ def test_raw_response_create(self, client: OpenAI, respx_mock: MockRouter) -> No response = client.audio.speech.with_raw_response.create( input="string", model="string", - voice="alloy", + voice="ash", ) assert response.is_closed is True @@ -71,7 +71,7 @@ def test_streaming_response_create(self, client: OpenAI, respx_mock: MockRouter) with client.audio.speech.with_streaming_response.create( input="string", model="string", - voice="alloy", + voice="ash", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -92,7 +92,7 @@ async def test_method_create(self, async_client: AsyncOpenAI, respx_mock: MockRo speech = await async_client.audio.speech.create( input="string", model="string", - voice="alloy", + voice="ash", ) assert isinstance(speech, _legacy_response.HttpxBinaryResponseContent) assert speech.json() == {"foo": "bar"} @@ -104,7 +104,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI, re speech = await async_client.audio.speech.create( input="string", model="string", - voice="alloy", + voice="ash", instructions="instructions", response_format="mp3", speed=0.25, @@ -120,7 +120,7 @@ async def test_raw_response_create(self, async_client: AsyncOpenAI, respx_mock: response = await async_client.audio.speech.with_raw_response.create( input="string", model="string", - voice="alloy", + voice="ash", ) assert response.is_closed is True @@ -135,7 +135,7 @@ async def test_streaming_response_create(self, async_client: AsyncOpenAI, respx_ async with async_client.audio.speech.with_streaming_response.create( input="string", model="string", - voice="alloy", + voice="ash", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" diff --git a/tests/api_resources/beta/realtime/test_sessions.py b/tests/api_resources/beta/realtime/test_sessions.py index c0a426a417..f432b7d277 100644 --- a/tests/api_resources/beta/realtime/test_sessions.py +++ b/tests/api_resources/beta/realtime/test_sessions.py @@ -56,7 +56,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: "threshold": 0, "type": "server_vad", }, - voice="alloy", + voice="ash", ) assert_matches_type(SessionCreateResponse, session, path=["response"]) @@ -123,7 +123,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> "threshold": 0, "type": "server_vad", }, - voice="alloy", + voice="ash", ) assert_matches_type(SessionCreateResponse, session, path=["response"]) diff --git a/tests/api_resources/chat/test_completions.py b/tests/api_resources/chat/test_completions.py index d4ccc494dd..aaef82e8c5 100644 --- a/tests/api_resources/chat/test_completions.py +++ b/tests/api_resources/chat/test_completions.py @@ -48,7 +48,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: model="gpt-4o", audio={ "format": "wav", - "voice": "alloy", + "voice": "ash", }, frequency_penalty=-2, function_call="none", @@ -175,7 +175,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: stream=True, audio={ "format": "wav", - "voice": "alloy", + "voice": "ash", }, frequency_penalty=-2, function_call="none", @@ -475,7 +475,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn model="gpt-4o", audio={ "format": "wav", - "voice": "alloy", + "voice": "ash", }, frequency_penalty=-2, function_call="none", @@ -602,7 +602,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn stream=True, audio={ "format": "wav", - "voice": "alloy", + "voice": "ash", }, frequency_penalty=-2, function_call="none", diff --git a/tests/api_resources/responses/test_input_items.py b/tests/api_resources/responses/test_input_items.py index 77a156b5ac..2528943c06 100644 --- a/tests/api_resources/responses/test_input_items.py +++ b/tests/api_resources/responses/test_input_items.py @@ -31,6 +31,7 @@ def test_method_list_with_all_params(self, client: OpenAI) -> None: response_id="response_id", after="after", before="before", + include=["file_search_call.results"], limit=0, order="asc", ) @@ -84,6 +85,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> N response_id="response_id", after="after", before="before", + include=["file_search_call.results"], limit=0, order="asc", ) From 8677d3ca5350c7ad07a66dcde78152bccb1655c0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 27 Mar 2025 16:07:22 +0000 Subject: [PATCH 260/769] feat(api): add `get /chat/completions` endpoint --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 4d1276a5e6..1e1104a062 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 82 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-6663c59193eb95b201e492de17dcbd5e126ba03d18ce66287a3e2c632ca56fe7.yml openapi_spec_hash: 7996d2c34cc44fe2ce9ffe93c0ab774e -config_hash: d36e491b0afc4f79e3afad4b3c9bec70 +config_hash: 9351ea829c2b41da3b48a38c934c92ee From a6393219a6d4bd1fbcafdabfe757de093a87e2af Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Thu, 27 Mar 2025 17:21:23 +0000 Subject: [PATCH 261/769] fix(audio): correctly parse transcription stream events --- src/openai/_streaming.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/openai/_streaming.py b/src/openai/_streaming.py index 9cb72ffe17..641c3a7a72 100644 --- a/src/openai/_streaming.py +++ b/src/openai/_streaming.py @@ -59,7 +59,7 @@ def __stream__(self) -> Iterator[_T]: if sse.data.startswith("[DONE]"): break - if sse.event is None or sse.event.startswith("response."): + if sse.event is None or sse.event.startswith("response.") or sse.event.startswith('transcript.'): data = sse.json() if is_mapping(data) and data.get("error"): message = None @@ -161,7 +161,7 @@ async def __stream__(self) -> AsyncIterator[_T]: if sse.data.startswith("[DONE]"): break - if sse.event is None or sse.event.startswith("response."): + if sse.event is None or sse.event.startswith("response.") or sse.event.startswith('transcript.'): data = sse.json() if is_mapping(data) and data.get("error"): message = None From 46ed48e793ff9f5a088918ce9b1ad7bef13b9b37 Mon Sep 17 00:00:00 2001 From: Lucas Grzegorczyk Date: Thu, 27 Mar 2025 18:30:19 +0100 Subject: [PATCH 262/769] Remove stray responses.py.orig file (#2258) --- .../resources/responses/responses.py.orig | 1796 ----------------- 1 file changed, 1796 deletions(-) delete mode 100644 src/openai/resources/responses/responses.py.orig diff --git a/src/openai/resources/responses/responses.py.orig b/src/openai/resources/responses/responses.py.orig deleted file mode 100644 index dec4c19367..0000000000 --- a/src/openai/resources/responses/responses.py.orig +++ /dev/null @@ -1,1796 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Any, List, Type, Union, Iterable, Optional, cast -from functools import partial -from typing_extensions import Literal, overload - -import httpx - -from ... import _legacy_response -from ..._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven -from ..._utils import ( - is_given, - required_args, - maybe_transform, - async_maybe_transform, -) -from ..._compat import cached_property -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from .input_items import ( - InputItems, - AsyncInputItems, - InputItemsWithRawResponse, - AsyncInputItemsWithRawResponse, - InputItemsWithStreamingResponse, - AsyncInputItemsWithStreamingResponse, -) -from ..._streaming import Stream, AsyncStream -from ...lib._tools import PydanticFunctionTool, ResponsesPydanticFunctionTool -from ..._base_client import make_request_options -from ...types.responses import response_create_params, response_retrieve_params -<<<<<<< HEAD -from ...lib._parsing._responses import ( - TextFormatT, - parse_response, - type_to_text_format_param as _type_to_text_format_param, -) -from ...types.shared.chat_model import ChatModel -||||||| parent of 001707b8 (feat(api): o1-pro now available through the API (#2228)) -from ...types.shared.chat_model import ChatModel -======= ->>>>>>> 001707b8 (feat(api): o1-pro now available through the API (#2228)) -from ...types.responses.response import Response -from ...types.responses.tool_param import ToolParam, ParseableToolParam -from ...types.shared_params.metadata import Metadata -from ...types.shared_params.reasoning import Reasoning -from ...types.responses.parsed_response import ParsedResponse -from ...lib.streaming.responses._responses import ResponseStreamManager, AsyncResponseStreamManager -from ...types.responses.response_includable import ResponseIncludable -from ...types.shared_params.responses_model import ResponsesModel -from ...types.responses.response_input_param import ResponseInputParam -from ...types.responses.response_stream_event import ResponseStreamEvent -from ...types.responses.response_text_config_param import ResponseTextConfigParam - -__all__ = ["Responses", "AsyncResponses"] - - -class Responses(SyncAPIResource): - @cached_property - def input_items(self) -> InputItems: - return InputItems(self._client) - - @cached_property - def with_raw_response(self) -> ResponsesWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return ResponsesWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> ResponsesWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return ResponsesWithStreamingResponse(self) - - @overload - def create( - self, - *, - input: Union[str, ResponseInputParam], - model: ResponsesModel, - include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, - previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, - reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, - tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, - tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Response: - """Creates a model response. - - Provide - [text](https://platform.openai.com/docs/guides/text) or - [image](https://platform.openai.com/docs/guides/images) inputs to generate - [text](https://platform.openai.com/docs/guides/text) or - [JSON](https://platform.openai.com/docs/guides/structured-outputs) outputs. Have - the model call your own - [custom code](https://platform.openai.com/docs/guides/function-calling) or use - built-in [tools](https://platform.openai.com/docs/guides/tools) like - [web search](https://platform.openai.com/docs/guides/tools-web-search) or - [file search](https://platform.openai.com/docs/guides/tools-file-search) to use - your own data as input for the model's response. - - Args: - input: Text, image, or file inputs to the model, used to generate a response. - - Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Image inputs](https://platform.openai.com/docs/guides/images) - - [File inputs](https://platform.openai.com/docs/guides/pdf-files) - - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) - - [Function calling](https://platform.openai.com/docs/guides/function-calling) - - model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a - wide range of models with different capabilities, performance characteristics, - and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - - include: Specify additional output data to include in the model response. Currently - supported values are: - - - `file_search_call.results`: Include the search results of the file search tool - call. - - `message.input_image.image_url`: Include image urls from the input message. - - `computer_call_output.output.image_url`: Include image urls from the computer - call output. - - instructions: Inserts a system (or developer) message as the first item in the model's - context. - - When using along with `previous_response_id`, the instructions from a previous - response will be not be carried over to the next response. This makes it simple - to swap out system (or developer) messages in new responses. - - max_output_tokens: An upper bound for the number of tokens that can be generated for a response, - including visible output tokens and - [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - parallel_tool_calls: Whether to allow the model to run tool calls in parallel. - - previous_response_id: The unique ID of the previous response to the model. Use this to create - multi-turn conversations. Learn more about - [conversation state](https://platform.openai.com/docs/guides/conversation-state). - - reasoning: **o-series models only** - - Configuration options for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). - - store: Whether to store the generated model response for later retrieval via API. - - stream: If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) - for more information. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. We generally recommend altering this or `top_p` but - not both. - - text: Configuration options for a text response from the model. Can be plain text or - structured JSON data. Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - - tool_choice: How the model should select which tool (or tools) to use when generating a - response. See the `tools` parameter to see how to specify which tools the model - can call. - - tools: An array of tools the model may call while generating a response. You can - specify which tool to use by setting the `tool_choice` parameter. - - The two categories of tools you can provide the model are: - - - **Built-in tools**: Tools that are provided by OpenAI that extend the model's - capabilities, like - [web search](https://platform.openai.com/docs/guides/tools-web-search) or - [file search](https://platform.openai.com/docs/guides/tools-file-search). - Learn more about - [built-in tools](https://platform.openai.com/docs/guides/tools). - - **Function calls (custom tools)**: Functions that are defined by you, enabling - the model to call your own code. Learn more about - [function calling](https://platform.openai.com/docs/guides/function-calling). - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or `temperature` but not both. - - truncation: The truncation strategy to use for the model response. - - - `auto`: If the context of this response and previous ones exceeds the model's - context window size, the model will truncate the response to fit the context - window by dropping input items in the middle of the conversation. - - `disabled` (default): If a model response will exceed the context window size - for a model, the request will fail with a 400 error. - - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - def create( - self, - *, - input: Union[str, ResponseInputParam], - model: ResponsesModel, - stream: Literal[True], - include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, - previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, - reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, - tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, - tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Stream[ResponseStreamEvent]: - """Creates a model response. - - Provide - [text](https://platform.openai.com/docs/guides/text) or - [image](https://platform.openai.com/docs/guides/images) inputs to generate - [text](https://platform.openai.com/docs/guides/text) or - [JSON](https://platform.openai.com/docs/guides/structured-outputs) outputs. Have - the model call your own - [custom code](https://platform.openai.com/docs/guides/function-calling) or use - built-in [tools](https://platform.openai.com/docs/guides/tools) like - [web search](https://platform.openai.com/docs/guides/tools-web-search) or - [file search](https://platform.openai.com/docs/guides/tools-file-search) to use - your own data as input for the model's response. - - Args: - input: Text, image, or file inputs to the model, used to generate a response. - - Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Image inputs](https://platform.openai.com/docs/guides/images) - - [File inputs](https://platform.openai.com/docs/guides/pdf-files) - - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) - - [Function calling](https://platform.openai.com/docs/guides/function-calling) - - model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a - wide range of models with different capabilities, performance characteristics, - and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - - stream: If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) - for more information. - - include: Specify additional output data to include in the model response. Currently - supported values are: - - - `file_search_call.results`: Include the search results of the file search tool - call. - - `message.input_image.image_url`: Include image urls from the input message. - - `computer_call_output.output.image_url`: Include image urls from the computer - call output. - - instructions: Inserts a system (or developer) message as the first item in the model's - context. - - When using along with `previous_response_id`, the instructions from a previous - response will be not be carried over to the next response. This makes it simple - to swap out system (or developer) messages in new responses. - - max_output_tokens: An upper bound for the number of tokens that can be generated for a response, - including visible output tokens and - [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - parallel_tool_calls: Whether to allow the model to run tool calls in parallel. - - previous_response_id: The unique ID of the previous response to the model. Use this to create - multi-turn conversations. Learn more about - [conversation state](https://platform.openai.com/docs/guides/conversation-state). - - reasoning: **o-series models only** - - Configuration options for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). - - store: Whether to store the generated model response for later retrieval via API. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. We generally recommend altering this or `top_p` but - not both. - - text: Configuration options for a text response from the model. Can be plain text or - structured JSON data. Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - - tool_choice: How the model should select which tool (or tools) to use when generating a - response. See the `tools` parameter to see how to specify which tools the model - can call. - - tools: An array of tools the model may call while generating a response. You can - specify which tool to use by setting the `tool_choice` parameter. - - The two categories of tools you can provide the model are: - - - **Built-in tools**: Tools that are provided by OpenAI that extend the model's - capabilities, like - [web search](https://platform.openai.com/docs/guides/tools-web-search) or - [file search](https://platform.openai.com/docs/guides/tools-file-search). - Learn more about - [built-in tools](https://platform.openai.com/docs/guides/tools). - - **Function calls (custom tools)**: Functions that are defined by you, enabling - the model to call your own code. Learn more about - [function calling](https://platform.openai.com/docs/guides/function-calling). - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or `temperature` but not both. - - truncation: The truncation strategy to use for the model response. - - - `auto`: If the context of this response and previous ones exceeds the model's - context window size, the model will truncate the response to fit the context - window by dropping input items in the middle of the conversation. - - `disabled` (default): If a model response will exceed the context window size - for a model, the request will fail with a 400 error. - - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - def create( - self, - *, - input: Union[str, ResponseInputParam], - model: ResponsesModel, - stream: bool, - include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, - previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, - reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, - tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, - tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Response | Stream[ResponseStreamEvent]: - """Creates a model response. - - Provide - [text](https://platform.openai.com/docs/guides/text) or - [image](https://platform.openai.com/docs/guides/images) inputs to generate - [text](https://platform.openai.com/docs/guides/text) or - [JSON](https://platform.openai.com/docs/guides/structured-outputs) outputs. Have - the model call your own - [custom code](https://platform.openai.com/docs/guides/function-calling) or use - built-in [tools](https://platform.openai.com/docs/guides/tools) like - [web search](https://platform.openai.com/docs/guides/tools-web-search) or - [file search](https://platform.openai.com/docs/guides/tools-file-search) to use - your own data as input for the model's response. - - Args: - input: Text, image, or file inputs to the model, used to generate a response. - - Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Image inputs](https://platform.openai.com/docs/guides/images) - - [File inputs](https://platform.openai.com/docs/guides/pdf-files) - - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) - - [Function calling](https://platform.openai.com/docs/guides/function-calling) - - model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a - wide range of models with different capabilities, performance characteristics, - and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - - stream: If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) - for more information. - - include: Specify additional output data to include in the model response. Currently - supported values are: - - - `file_search_call.results`: Include the search results of the file search tool - call. - - `message.input_image.image_url`: Include image urls from the input message. - - `computer_call_output.output.image_url`: Include image urls from the computer - call output. - - instructions: Inserts a system (or developer) message as the first item in the model's - context. - - When using along with `previous_response_id`, the instructions from a previous - response will be not be carried over to the next response. This makes it simple - to swap out system (or developer) messages in new responses. - - max_output_tokens: An upper bound for the number of tokens that can be generated for a response, - including visible output tokens and - [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - parallel_tool_calls: Whether to allow the model to run tool calls in parallel. - - previous_response_id: The unique ID of the previous response to the model. Use this to create - multi-turn conversations. Learn more about - [conversation state](https://platform.openai.com/docs/guides/conversation-state). - - reasoning: **o-series models only** - - Configuration options for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). - - store: Whether to store the generated model response for later retrieval via API. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. We generally recommend altering this or `top_p` but - not both. - - text: Configuration options for a text response from the model. Can be plain text or - structured JSON data. Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - - tool_choice: How the model should select which tool (or tools) to use when generating a - response. See the `tools` parameter to see how to specify which tools the model - can call. - - tools: An array of tools the model may call while generating a response. You can - specify which tool to use by setting the `tool_choice` parameter. - - The two categories of tools you can provide the model are: - - - **Built-in tools**: Tools that are provided by OpenAI that extend the model's - capabilities, like - [web search](https://platform.openai.com/docs/guides/tools-web-search) or - [file search](https://platform.openai.com/docs/guides/tools-file-search). - Learn more about - [built-in tools](https://platform.openai.com/docs/guides/tools). - - **Function calls (custom tools)**: Functions that are defined by you, enabling - the model to call your own code. Learn more about - [function calling](https://platform.openai.com/docs/guides/function-calling). - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or `temperature` but not both. - - truncation: The truncation strategy to use for the model response. - - - `auto`: If the context of this response and previous ones exceeds the model's - context window size, the model will truncate the response to fit the context - window by dropping input items in the middle of the conversation. - - `disabled` (default): If a model response will exceed the context window size - for a model, the request will fail with a 400 error. - - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @required_args(["input", "model"], ["input", "model", "stream"]) - def create( - self, - *, - input: Union[str, ResponseInputParam], - model: ResponsesModel, - include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, - previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, - reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, - tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, - tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Response | Stream[ResponseStreamEvent]: - return self._post( - "/responses", - body=maybe_transform( - { - "input": input, - "model": model, - "include": include, - "instructions": instructions, - "max_output_tokens": max_output_tokens, - "metadata": metadata, - "parallel_tool_calls": parallel_tool_calls, - "previous_response_id": previous_response_id, - "reasoning": reasoning, - "store": store, - "stream": stream, - "temperature": temperature, - "text": text, - "tool_choice": tool_choice, - "tools": tools, - "top_p": top_p, - "truncation": truncation, - "user": user, - }, - response_create_params.ResponseCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Response, - stream=stream or False, - stream_cls=Stream[ResponseStreamEvent], - ) - - def stream( - self, - *, - input: Union[str, ResponseInputParam], - model: Union[str, ChatModel], - text_format: type[TextFormatT] | NotGiven = NOT_GIVEN, - tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, - include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, - previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, - reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, - tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> ResponseStreamManager[TextFormatT]: - if is_given(text_format): - if not text: - text = {} - - if "format" in text: - raise TypeError("Cannot mix and match text.format with text_format") - - text["format"] = _type_to_text_format_param(text_format) - - tools = _make_tools(tools) - - api_request: partial[Stream[ResponseStreamEvent]] = partial( - self.create, - input=input, - model=model, - tools=tools, - include=include, - instructions=instructions, - max_output_tokens=max_output_tokens, - metadata=metadata, - parallel_tool_calls=parallel_tool_calls, - previous_response_id=previous_response_id, - store=store, - stream=True, - temperature=temperature, - text=text, - tool_choice=tool_choice, - reasoning=reasoning, - top_p=top_p, - truncation=truncation, - user=user, - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - ) - - return ResponseStreamManager( - api_request, - text_format=text_format, - input_tools=tools, - ) - - def parse( - self, - *, - input: Union[str, ResponseInputParam], - model: Union[str, ChatModel], - text_format: type[TextFormatT] | NotGiven = NOT_GIVEN, - tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, - include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, - previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, - reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, - tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> ParsedResponse[TextFormatT]: - if is_given(text_format): - if not text: - text = {} - - if "format" in text: - raise TypeError("Cannot mix and match text.format with text_format") - - text["format"] = _type_to_text_format_param(text_format) - - tools = _make_tools(tools) - - def parser(raw_response: Response) -> ParsedResponse[TextFormatT]: - return parse_response( - input_tools=tools, - text_format=text_format, - response=raw_response, - ) - - return self._post( - "/responses", - body=maybe_transform( - { - "input": input, - "model": model, - "include": include, - "instructions": instructions, - "max_output_tokens": max_output_tokens, - "metadata": metadata, - "parallel_tool_calls": parallel_tool_calls, - "previous_response_id": previous_response_id, - "reasoning": reasoning, - "store": store, - "stream": stream, - "temperature": temperature, - "text": text, - "tool_choice": tool_choice, - "tools": tools, - "top_p": top_p, - "truncation": truncation, - "user": user, - }, - response_create_params.ResponseCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - post_parser=parser, - ), - # we turn the `Response` instance into a `ParsedResponse` - # in the `parser` function above - cast_to=cast(Type[ParsedResponse[TextFormatT]], Response), - ) - - def retrieve( - self, - response_id: str, - *, - include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Response: - """ - Retrieves a model response with the given ID. - - Args: - include: Additional fields to include in the response. See the `include` parameter for - Response creation above for more information. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not response_id: - raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") - return self._get( - f"/responses/{response_id}", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform({"include": include}, response_retrieve_params.ResponseRetrieveParams), - ), - cast_to=Response, - ) - - def delete( - self, - response_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> None: - """ - Deletes a model response with the given ID. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not response_id: - raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._delete( - f"/responses/{response_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - -class AsyncResponses(AsyncAPIResource): - @cached_property - def input_items(self) -> AsyncInputItems: - return AsyncInputItems(self._client) - - @cached_property - def with_raw_response(self) -> AsyncResponsesWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncResponsesWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncResponsesWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncResponsesWithStreamingResponse(self) - - @overload - async def create( - self, - *, - input: Union[str, ResponseInputParam], - model: ResponsesModel, - include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, - previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, - reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, - tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, - tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Response: - """Creates a model response. - - Provide - [text](https://platform.openai.com/docs/guides/text) or - [image](https://platform.openai.com/docs/guides/images) inputs to generate - [text](https://platform.openai.com/docs/guides/text) or - [JSON](https://platform.openai.com/docs/guides/structured-outputs) outputs. Have - the model call your own - [custom code](https://platform.openai.com/docs/guides/function-calling) or use - built-in [tools](https://platform.openai.com/docs/guides/tools) like - [web search](https://platform.openai.com/docs/guides/tools-web-search) or - [file search](https://platform.openai.com/docs/guides/tools-file-search) to use - your own data as input for the model's response. - - Args: - input: Text, image, or file inputs to the model, used to generate a response. - - Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Image inputs](https://platform.openai.com/docs/guides/images) - - [File inputs](https://platform.openai.com/docs/guides/pdf-files) - - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) - - [Function calling](https://platform.openai.com/docs/guides/function-calling) - - model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a - wide range of models with different capabilities, performance characteristics, - and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - - include: Specify additional output data to include in the model response. Currently - supported values are: - - - `file_search_call.results`: Include the search results of the file search tool - call. - - `message.input_image.image_url`: Include image urls from the input message. - - `computer_call_output.output.image_url`: Include image urls from the computer - call output. - - instructions: Inserts a system (or developer) message as the first item in the model's - context. - - When using along with `previous_response_id`, the instructions from a previous - response will be not be carried over to the next response. This makes it simple - to swap out system (or developer) messages in new responses. - - max_output_tokens: An upper bound for the number of tokens that can be generated for a response, - including visible output tokens and - [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - parallel_tool_calls: Whether to allow the model to run tool calls in parallel. - - previous_response_id: The unique ID of the previous response to the model. Use this to create - multi-turn conversations. Learn more about - [conversation state](https://platform.openai.com/docs/guides/conversation-state). - - reasoning: **o-series models only** - - Configuration options for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). - - store: Whether to store the generated model response for later retrieval via API. - - stream: If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) - for more information. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. We generally recommend altering this or `top_p` but - not both. - - text: Configuration options for a text response from the model. Can be plain text or - structured JSON data. Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - - tool_choice: How the model should select which tool (or tools) to use when generating a - response. See the `tools` parameter to see how to specify which tools the model - can call. - - tools: An array of tools the model may call while generating a response. You can - specify which tool to use by setting the `tool_choice` parameter. - - The two categories of tools you can provide the model are: - - - **Built-in tools**: Tools that are provided by OpenAI that extend the model's - capabilities, like - [web search](https://platform.openai.com/docs/guides/tools-web-search) or - [file search](https://platform.openai.com/docs/guides/tools-file-search). - Learn more about - [built-in tools](https://platform.openai.com/docs/guides/tools). - - **Function calls (custom tools)**: Functions that are defined by you, enabling - the model to call your own code. Learn more about - [function calling](https://platform.openai.com/docs/guides/function-calling). - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or `temperature` but not both. - - truncation: The truncation strategy to use for the model response. - - - `auto`: If the context of this response and previous ones exceeds the model's - context window size, the model will truncate the response to fit the context - window by dropping input items in the middle of the conversation. - - `disabled` (default): If a model response will exceed the context window size - for a model, the request will fail with a 400 error. - - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - async def create( - self, - *, - input: Union[str, ResponseInputParam], - model: ResponsesModel, - stream: Literal[True], - include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, - previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, - reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, - tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, - tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncStream[ResponseStreamEvent]: - """Creates a model response. - - Provide - [text](https://platform.openai.com/docs/guides/text) or - [image](https://platform.openai.com/docs/guides/images) inputs to generate - [text](https://platform.openai.com/docs/guides/text) or - [JSON](https://platform.openai.com/docs/guides/structured-outputs) outputs. Have - the model call your own - [custom code](https://platform.openai.com/docs/guides/function-calling) or use - built-in [tools](https://platform.openai.com/docs/guides/tools) like - [web search](https://platform.openai.com/docs/guides/tools-web-search) or - [file search](https://platform.openai.com/docs/guides/tools-file-search) to use - your own data as input for the model's response. - - Args: - input: Text, image, or file inputs to the model, used to generate a response. - - Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Image inputs](https://platform.openai.com/docs/guides/images) - - [File inputs](https://platform.openai.com/docs/guides/pdf-files) - - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) - - [Function calling](https://platform.openai.com/docs/guides/function-calling) - - model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a - wide range of models with different capabilities, performance characteristics, - and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - - stream: If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) - for more information. - - include: Specify additional output data to include in the model response. Currently - supported values are: - - - `file_search_call.results`: Include the search results of the file search tool - call. - - `message.input_image.image_url`: Include image urls from the input message. - - `computer_call_output.output.image_url`: Include image urls from the computer - call output. - - instructions: Inserts a system (or developer) message as the first item in the model's - context. - - When using along with `previous_response_id`, the instructions from a previous - response will be not be carried over to the next response. This makes it simple - to swap out system (or developer) messages in new responses. - - max_output_tokens: An upper bound for the number of tokens that can be generated for a response, - including visible output tokens and - [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - parallel_tool_calls: Whether to allow the model to run tool calls in parallel. - - previous_response_id: The unique ID of the previous response to the model. Use this to create - multi-turn conversations. Learn more about - [conversation state](https://platform.openai.com/docs/guides/conversation-state). - - reasoning: **o-series models only** - - Configuration options for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). - - store: Whether to store the generated model response for later retrieval via API. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. We generally recommend altering this or `top_p` but - not both. - - text: Configuration options for a text response from the model. Can be plain text or - structured JSON data. Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - - tool_choice: How the model should select which tool (or tools) to use when generating a - response. See the `tools` parameter to see how to specify which tools the model - can call. - - tools: An array of tools the model may call while generating a response. You can - specify which tool to use by setting the `tool_choice` parameter. - - The two categories of tools you can provide the model are: - - - **Built-in tools**: Tools that are provided by OpenAI that extend the model's - capabilities, like - [web search](https://platform.openai.com/docs/guides/tools-web-search) or - [file search](https://platform.openai.com/docs/guides/tools-file-search). - Learn more about - [built-in tools](https://platform.openai.com/docs/guides/tools). - - **Function calls (custom tools)**: Functions that are defined by you, enabling - the model to call your own code. Learn more about - [function calling](https://platform.openai.com/docs/guides/function-calling). - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or `temperature` but not both. - - truncation: The truncation strategy to use for the model response. - - - `auto`: If the context of this response and previous ones exceeds the model's - context window size, the model will truncate the response to fit the context - window by dropping input items in the middle of the conversation. - - `disabled` (default): If a model response will exceed the context window size - for a model, the request will fail with a 400 error. - - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - async def create( - self, - *, - input: Union[str, ResponseInputParam], - model: ResponsesModel, - stream: bool, - include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, - previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, - reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, - tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, - tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Response | AsyncStream[ResponseStreamEvent]: - """Creates a model response. - - Provide - [text](https://platform.openai.com/docs/guides/text) or - [image](https://platform.openai.com/docs/guides/images) inputs to generate - [text](https://platform.openai.com/docs/guides/text) or - [JSON](https://platform.openai.com/docs/guides/structured-outputs) outputs. Have - the model call your own - [custom code](https://platform.openai.com/docs/guides/function-calling) or use - built-in [tools](https://platform.openai.com/docs/guides/tools) like - [web search](https://platform.openai.com/docs/guides/tools-web-search) or - [file search](https://platform.openai.com/docs/guides/tools-file-search) to use - your own data as input for the model's response. - - Args: - input: Text, image, or file inputs to the model, used to generate a response. - - Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Image inputs](https://platform.openai.com/docs/guides/images) - - [File inputs](https://platform.openai.com/docs/guides/pdf-files) - - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) - - [Function calling](https://platform.openai.com/docs/guides/function-calling) - - model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a - wide range of models with different capabilities, performance characteristics, - and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - - stream: If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) - for more information. - - include: Specify additional output data to include in the model response. Currently - supported values are: - - - `file_search_call.results`: Include the search results of the file search tool - call. - - `message.input_image.image_url`: Include image urls from the input message. - - `computer_call_output.output.image_url`: Include image urls from the computer - call output. - - instructions: Inserts a system (or developer) message as the first item in the model's - context. - - When using along with `previous_response_id`, the instructions from a previous - response will be not be carried over to the next response. This makes it simple - to swap out system (or developer) messages in new responses. - - max_output_tokens: An upper bound for the number of tokens that can be generated for a response, - including visible output tokens and - [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - parallel_tool_calls: Whether to allow the model to run tool calls in parallel. - - previous_response_id: The unique ID of the previous response to the model. Use this to create - multi-turn conversations. Learn more about - [conversation state](https://platform.openai.com/docs/guides/conversation-state). - - reasoning: **o-series models only** - - Configuration options for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). - - store: Whether to store the generated model response for later retrieval via API. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. We generally recommend altering this or `top_p` but - not both. - - text: Configuration options for a text response from the model. Can be plain text or - structured JSON data. Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - - tool_choice: How the model should select which tool (or tools) to use when generating a - response. See the `tools` parameter to see how to specify which tools the model - can call. - - tools: An array of tools the model may call while generating a response. You can - specify which tool to use by setting the `tool_choice` parameter. - - The two categories of tools you can provide the model are: - - - **Built-in tools**: Tools that are provided by OpenAI that extend the model's - capabilities, like - [web search](https://platform.openai.com/docs/guides/tools-web-search) or - [file search](https://platform.openai.com/docs/guides/tools-file-search). - Learn more about - [built-in tools](https://platform.openai.com/docs/guides/tools). - - **Function calls (custom tools)**: Functions that are defined by you, enabling - the model to call your own code. Learn more about - [function calling](https://platform.openai.com/docs/guides/function-calling). - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or `temperature` but not both. - - truncation: The truncation strategy to use for the model response. - - - `auto`: If the context of this response and previous ones exceeds the model's - context window size, the model will truncate the response to fit the context - window by dropping input items in the middle of the conversation. - - `disabled` (default): If a model response will exceed the context window size - for a model, the request will fail with a 400 error. - - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @required_args(["input", "model"], ["input", "model", "stream"]) - async def create( - self, - *, - input: Union[str, ResponseInputParam], - model: ResponsesModel, - include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, - previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, - reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, - tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, - tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Response | AsyncStream[ResponseStreamEvent]: - return await self._post( - "/responses", - body=await async_maybe_transform( - { - "input": input, - "model": model, - "include": include, - "instructions": instructions, - "max_output_tokens": max_output_tokens, - "metadata": metadata, - "parallel_tool_calls": parallel_tool_calls, - "previous_response_id": previous_response_id, - "reasoning": reasoning, - "store": store, - "stream": stream, - "temperature": temperature, - "text": text, - "tool_choice": tool_choice, - "tools": tools, - "top_p": top_p, - "truncation": truncation, - "user": user, - }, - response_create_params.ResponseCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Response, - stream=stream or False, - stream_cls=AsyncStream[ResponseStreamEvent], - ) - - def stream( - self, - *, - input: Union[str, ResponseInputParam], - model: Union[str, ChatModel], - text_format: type[TextFormatT] | NotGiven = NOT_GIVEN, - tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, - include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, - previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, - reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, - tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncResponseStreamManager[TextFormatT]: - if is_given(text_format): - if not text: - text = {} - - if "format" in text: - raise TypeError("Cannot mix and match text.format with text_format") - - text["format"] = _type_to_text_format_param(text_format) - - tools = _make_tools(tools) - - api_request = self.create( - input=input, - model=model, - tools=tools, - include=include, - instructions=instructions, - max_output_tokens=max_output_tokens, - metadata=metadata, - parallel_tool_calls=parallel_tool_calls, - previous_response_id=previous_response_id, - store=store, - stream=True, - temperature=temperature, - text=text, - tool_choice=tool_choice, - reasoning=reasoning, - top_p=top_p, - truncation=truncation, - user=user, - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - ) - - return AsyncResponseStreamManager( - api_request, - text_format=text_format, - input_tools=tools, - ) - - async def parse( - self, - *, - input: Union[str, ResponseInputParam], - model: Union[str, ChatModel], - text_format: type[TextFormatT] | NotGiven = NOT_GIVEN, - tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, - include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, - previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, - reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, - tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> ParsedResponse[TextFormatT]: - if is_given(text_format): - if not text: - text = {} - - if "format" in text: - raise TypeError("Cannot mix and match text.format with text_format") - - text["format"] = _type_to_text_format_param(text_format) - - tools = _make_tools(tools) - - def parser(raw_response: Response) -> ParsedResponse[TextFormatT]: - return parse_response( - input_tools=tools, - text_format=text_format, - response=raw_response, - ) - - return await self._post( - "/responses", - body=maybe_transform( - { - "input": input, - "model": model, - "include": include, - "instructions": instructions, - "max_output_tokens": max_output_tokens, - "metadata": metadata, - "parallel_tool_calls": parallel_tool_calls, - "previous_response_id": previous_response_id, - "reasoning": reasoning, - "store": store, - "stream": stream, - "temperature": temperature, - "text": text, - "tool_choice": tool_choice, - "tools": tools, - "top_p": top_p, - "truncation": truncation, - "user": user, - }, - response_create_params.ResponseCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - post_parser=parser, - ), - # we turn the `Response` instance into a `ParsedResponse` - # in the `parser` function above - cast_to=cast(Type[ParsedResponse[TextFormatT]], Response), - ) - - async def retrieve( - self, - response_id: str, - *, - include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Response: - """ - Retrieves a model response with the given ID. - - Args: - include: Additional fields to include in the response. See the `include` parameter for - Response creation above for more information. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not response_id: - raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") - return await self._get( - f"/responses/{response_id}", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform( - {"include": include}, response_retrieve_params.ResponseRetrieveParams - ), - ), - cast_to=Response, - ) - - async def delete( - self, - response_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> None: - """ - Deletes a model response with the given ID. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not response_id: - raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._delete( - f"/responses/{response_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - -class ResponsesWithRawResponse: - def __init__(self, responses: Responses) -> None: - self._responses = responses - - self.create = _legacy_response.to_raw_response_wrapper( - responses.create, - ) - self.retrieve = _legacy_response.to_raw_response_wrapper( - responses.retrieve, - ) - self.delete = _legacy_response.to_raw_response_wrapper( - responses.delete, - ) - - @cached_property - def input_items(self) -> InputItemsWithRawResponse: - return InputItemsWithRawResponse(self._responses.input_items) - - -class AsyncResponsesWithRawResponse: - def __init__(self, responses: AsyncResponses) -> None: - self._responses = responses - - self.create = _legacy_response.async_to_raw_response_wrapper( - responses.create, - ) - self.retrieve = _legacy_response.async_to_raw_response_wrapper( - responses.retrieve, - ) - self.delete = _legacy_response.async_to_raw_response_wrapper( - responses.delete, - ) - - @cached_property - def input_items(self) -> AsyncInputItemsWithRawResponse: - return AsyncInputItemsWithRawResponse(self._responses.input_items) - - -class ResponsesWithStreamingResponse: - def __init__(self, responses: Responses) -> None: - self._responses = responses - - self.create = to_streamed_response_wrapper( - responses.create, - ) - self.retrieve = to_streamed_response_wrapper( - responses.retrieve, - ) - self.delete = to_streamed_response_wrapper( - responses.delete, - ) - - @cached_property - def input_items(self) -> InputItemsWithStreamingResponse: - return InputItemsWithStreamingResponse(self._responses.input_items) - - -class AsyncResponsesWithStreamingResponse: - def __init__(self, responses: AsyncResponses) -> None: - self._responses = responses - - self.create = async_to_streamed_response_wrapper( - responses.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - responses.retrieve, - ) - self.delete = async_to_streamed_response_wrapper( - responses.delete, - ) - - @cached_property - def input_items(self) -> AsyncInputItemsWithStreamingResponse: - return AsyncInputItemsWithStreamingResponse(self._responses.input_items) - - -def _make_tools(tools: Iterable[ParseableToolParam] | NotGiven) -> List[ToolParam] | NotGiven: - if not is_given(tools): - return NOT_GIVEN - - converted_tools: List[ToolParam] = [] - for tool in tools: - if tool["type"] != "function": - converted_tools.append(tool) - continue - - if "function" not in tool: - # standard Responses API case - converted_tools.append(tool) - continue - - function = cast(Any, tool)["function"] # pyright: ignore[reportUnnecessaryCast] - if not isinstance(function, PydanticFunctionTool): - raise Exception( - "Expected Chat Completions function tool shape to be created using `openai.pydantic_function_tool()`" - ) - - assert "parameters" in function - new_tool = ResponsesPydanticFunctionTool( - { - "type": "function", - "name": function["name"], - "description": function.get("description"), - "parameters": function["parameters"], - "strict": function.get("strict") or False, - }, - function.model, - ) - - converted_tools.append(new_tool.cast()) - - return converted_tools From a8fa0def5cd999044dae39b6cdff7a54db25c627 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 27 Mar 2025 17:30:46 +0000 Subject: [PATCH 263/769] release: 1.69.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 20 ++++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index e280020f03..5df3c6496b 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.68.2" + ".": "1.69.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index ee22cfe7fb..773c20d2af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,25 @@ # Changelog +## 1.69.0 (2025-03-27) + +Full Changelog: [v1.68.2...v1.69.0](https://github.com/openai/openai-python/compare/v1.68.2...v1.69.0) + +### Features + +* **api:** add `get /chat/completions` endpoint ([e6b8a42](https://github.com/openai/openai-python/commit/e6b8a42fc4286656cc86c2acd83692b170e77b68)) + + +### Bug Fixes + +* **audio:** correctly parse transcription stream events ([16a3a19](https://github.com/openai/openai-python/commit/16a3a195ff31f099fbe46043a12d2380c2c01f83)) + + +### Chores + +* add hash of OpenAPI spec/config inputs to .stats.yml ([515e1cd](https://github.com/openai/openai-python/commit/515e1cdd4a3109e5b29618df813656e17f22b52a)) +* **api:** updates to supported Voice IDs ([#2261](https://github.com/openai/openai-python/issues/2261)) ([64956f9](https://github.com/openai/openai-python/commit/64956f9d9889b04380c7f5eb926509d1efd523e6)) +* fix typos ([#2259](https://github.com/openai/openai-python/issues/2259)) ([6160de3](https://github.com/openai/openai-python/commit/6160de3e099f09c2d6ee5eeee4cbcc55b67a8f87)) + ## 1.68.2 (2025-03-21) Full Changelog: [v1.68.1...v1.68.2](https://github.com/openai/openai-python/compare/v1.68.1...v1.68.2) diff --git a/pyproject.toml b/pyproject.toml index b1917922cd..e50c5d6c1f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.68.2" +version = "1.69.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 a29ce4e818..50c0e42d78 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.68.2" # x-release-please-version +__version__ = "1.69.0" # x-release-please-version From 972753a5d38f78149f33b9e768fb426e21456b9d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 27 Mar 2025 19:41:51 +0000 Subject: [PATCH 264/769] feat(api): add `get /responses/{response_id}/input_items` endpoint --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 1e1104a062..f6a90d2438 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 82 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-6663c59193eb95b201e492de17dcbd5e126ba03d18ce66287a3e2c632ca56fe7.yml openapi_spec_hash: 7996d2c34cc44fe2ce9ffe93c0ab774e -config_hash: 9351ea829c2b41da3b48a38c934c92ee +config_hash: e25e31d8446b6bc0e3ef7103b6993cce From 384e6b23ce0366d6b2f31cc98d35525da5b22c10 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 31 Mar 2025 05:03:58 +0000 Subject: [PATCH 265/769] release: 1.70.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 5df3c6496b..ba5cbfb627 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.69.0" + ".": "1.70.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 773c20d2af..8954d86571 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.70.0 (2025-03-31) + +Full Changelog: [v1.69.0...v1.70.0](https://github.com/openai/openai-python/compare/v1.69.0...v1.70.0) + +### Features + +* **api:** add `get /responses/{response_id}/input_items` endpoint ([4c6a35d](https://github.com/openai/openai-python/commit/4c6a35dec65362a6a738c3387dae57bf8cbfcbb2)) + ## 1.69.0 (2025-03-27) Full Changelog: [v1.68.2...v1.69.0](https://github.com/openai/openai-python/compare/v1.68.2...v1.69.0) diff --git a/pyproject.toml b/pyproject.toml index e50c5d6c1f..296d02e40b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.69.0" +version = "1.70.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 50c0e42d78..6b4385ec3c 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.69.0" # x-release-please-version +__version__ = "1.70.0" # x-release-please-version From a718999f751b2fb4574ebfdc1d66d6234334367c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 1 Apr 2025 00:26:24 +0000 Subject: [PATCH 266/769] chore: Remove deprecated/unused remote spec feature --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index f6a90d2438..2ccfd3411d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 82 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-6663c59193eb95b201e492de17dcbd5e126ba03d18ce66287a3e2c632ca56fe7.yml openapi_spec_hash: 7996d2c34cc44fe2ce9ffe93c0ab774e -config_hash: e25e31d8446b6bc0e3ef7103b6993cce +config_hash: 2daae06cc598821ccf87201de0861e40 From 7feb73e3ef2759d4c1dc9169b21fa3d51e694d00 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 1 Apr 2025 23:12:33 +0000 Subject: [PATCH 267/769] feat(api): manual updates --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 2ccfd3411d..71ac95541b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 82 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-6663c59193eb95b201e492de17dcbd5e126ba03d18ce66287a3e2c632ca56fe7.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-4bce8217a697c729ac98046d4caf2c9e826b54c427fb0ab4f98e549a2e0ce31c.yml openapi_spec_hash: 7996d2c34cc44fe2ce9ffe93c0ab774e -config_hash: 2daae06cc598821ccf87201de0861e40 +config_hash: 31a12443afeef2933b34e2de23c40954 From 6747d4276a994e02e9c09cf87f620aadc7182fc6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 1 Apr 2025 23:18:34 +0000 Subject: [PATCH 268/769] feat(api): manual updates --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 71ac95541b..baad2afc1b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 82 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-4bce8217a697c729ac98046d4caf2c9e826b54c427fb0ab4f98e549a2e0ce31c.yml openapi_spec_hash: 7996d2c34cc44fe2ce9ffe93c0ab774e -config_hash: 31a12443afeef2933b34e2de23c40954 +config_hash: 178ba1bfb1237bf6b94abb3408072aa7 From c87b46135f9351147d80b5a65e61108c26cd0405 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 2 Apr 2025 14:49:55 +0000 Subject: [PATCH 269/769] feat(api): manual updates --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index baad2afc1b..675edb075a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 82 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-4bce8217a697c729ac98046d4caf2c9e826b54c427fb0ab4f98e549a2e0ce31c.yml openapi_spec_hash: 7996d2c34cc44fe2ce9ffe93c0ab774e -config_hash: 178ba1bfb1237bf6b94abb3408072aa7 +config_hash: 578c5bff4208d560c0c280f13324409f From fb69e674f3caaf451ad55ad92d430d0a50e7c0a4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 3 Apr 2025 15:55:21 +0000 Subject: [PATCH 270/769] chore(internal): remove trailing character (#2277) --- tests/test_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_client.py b/tests/test_client.py index 62654afe1e..616255af3c 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -1797,7 +1797,7 @@ def test_get_platform(self) -> None: import threading from openai._utils import asyncify - from openai._base_client import get_platform + from openai._base_client import get_platform async def test_main() -> None: result = await asyncify(get_platform)() From 41e74d45396659b4883fee6353c7abc88870f1f5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 3 Apr 2025 18:37:53 +0000 Subject: [PATCH 271/769] feat(api): manual updates --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 675edb075a..aebb90c8cf 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 82 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-4bce8217a697c729ac98046d4caf2c9e826b54c427fb0ab4f98e549a2e0ce31c.yml openapi_spec_hash: 7996d2c34cc44fe2ce9ffe93c0ab774e -config_hash: 578c5bff4208d560c0c280f13324409f +config_hash: bcd2cacdcb9fae9938f273cd167f613c From f24c9820397bd5a42980986ac04706625bba78ce Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 7 Apr 2025 13:29:13 +0000 Subject: [PATCH 272/769] chore(deps): allow websockets v15 (#2281) --- pyproject.toml | 2 +- requirements-dev.lock | 2 +- requirements.lock | 2 +- src/openai/resources/beta/realtime/realtime.py | 8 -------- 4 files changed, 3 insertions(+), 11 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 296d02e40b..0b7d1d41b4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,7 +43,7 @@ Repository = "https://github.com/openai/openai-python" openai = "openai.cli:main" [project.optional-dependencies] -realtime = ["websockets >= 13, < 15"] +realtime = ["websockets >= 13, < 16"] datalib = ["numpy >= 1", "pandas >= 1.2.3", "pandas-stubs >= 1.1.0.11"] voice_helpers = ["sounddevice>=0.5.1", "numpy>=2.0.2"] diff --git a/requirements-dev.lock b/requirements-dev.lock index 0755ddb3c5..11bb5c1b30 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -188,7 +188,7 @@ urllib3==2.2.1 # via requests virtualenv==20.24.5 # via nox -websockets==14.2 +websockets==15.0.1 # via openai zipp==3.17.0 # via importlib-metadata diff --git a/requirements.lock b/requirements.lock index fa88e26c0f..467abc6e90 100644 --- a/requirements.lock +++ b/requirements.lock @@ -70,5 +70,5 @@ typing-extensions==4.12.2 # via pydantic-core tzdata==2024.1 # via pandas -websockets==14.2 +websockets==15.0.1 # via openai diff --git a/src/openai/resources/beta/realtime/realtime.py b/src/openai/resources/beta/realtime/realtime.py index 76e57f8cb7..5cafce1322 100644 --- a/src/openai/resources/beta/realtime/realtime.py +++ b/src/openai/resources/beta/realtime/realtime.py @@ -277,10 +277,6 @@ async def recv_bytes(self) -> bytes: """ message = await self._connection.recv(decode=False) log.debug(f"Received websocket message: %s", message) - if not isinstance(message, bytes): - # passing `decode=False` should always result in us getting `bytes` back - raise TypeError(f"Expected `.recv(decode=False)` to return `bytes` but got {type(message)}") - return message async def send(self, event: RealtimeClientEvent | RealtimeClientEventParam) -> None: @@ -461,10 +457,6 @@ def recv_bytes(self) -> bytes: """ message = self._connection.recv(decode=False) log.debug(f"Received websocket message: %s", message) - if not isinstance(message, bytes): - # passing `decode=False` should always result in us getting `bytes` back - raise TypeError(f"Expected `.recv(decode=False)` to return `bytes` but got {type(message)}") - return message def send(self, event: RealtimeClientEvent | RealtimeClientEventParam) -> None: From a764253788df8a57fd05759aafd42c3c722d361c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 7 Apr 2025 14:51:50 +0000 Subject: [PATCH 273/769] chore(internal): only run examples workflow in main repo (#2282) --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d86fc0ea53..6d2699cca8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,6 +54,7 @@ jobs: examples: name: examples runs-on: ubuntu-latest + if: github.repository == 'openai/openai-python' steps: - uses: actions/checkout@v4 From 692fd082b41047529b55a9c7e2047bdcbc2cccdd Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 7 Apr 2025 14:52:31 +0000 Subject: [PATCH 274/769] release: 1.71.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 19 +++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index ba5cbfb627..c7704ce953 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.70.0" + ".": "1.71.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 8954d86571..e8f2e22cb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## 1.71.0 (2025-04-07) + +Full Changelog: [v1.70.0...v1.71.0](https://github.com/openai/openai-python/compare/v1.70.0...v1.71.0) + +### Features + +* **api:** manual updates ([bf8b4b6](https://github.com/openai/openai-python/commit/bf8b4b69906bfaea622c9c644270e985d92e2df2)) +* **api:** manual updates ([3e37aa3](https://github.com/openai/openai-python/commit/3e37aa3e151d9738625a1daf75d6243d6fdbe8f2)) +* **api:** manual updates ([dba9b65](https://github.com/openai/openai-python/commit/dba9b656fa5955b6eba8f6910da836a34de8d59d)) +* **api:** manual updates ([f0c463b](https://github.com/openai/openai-python/commit/f0c463b47836666d091b5f616871f1b94646d346)) + + +### Chores + +* **deps:** allow websockets v15 ([#2281](https://github.com/openai/openai-python/issues/2281)) ([19c619e](https://github.com/openai/openai-python/commit/19c619ea95839129a86c19d5b60133e1ed9f2746)) +* **internal:** only run examples workflow in main repo ([#2282](https://github.com/openai/openai-python/issues/2282)) ([c3e0927](https://github.com/openai/openai-python/commit/c3e0927d3fbbb9f753ba12adfa682a4235ba530a)) +* **internal:** remove trailing character ([#2277](https://github.com/openai/openai-python/issues/2277)) ([5a21a2d](https://github.com/openai/openai-python/commit/5a21a2d7994e39bb0c86271eeb807983a9ae874a)) +* Remove deprecated/unused remote spec feature ([23f76eb](https://github.com/openai/openai-python/commit/23f76eb0b9ddf12bcb04a6ad3f3ec5e956d2863f)) + ## 1.70.0 (2025-03-31) Full Changelog: [v1.69.0...v1.70.0](https://github.com/openai/openai-python/compare/v1.69.0...v1.70.0) diff --git a/pyproject.toml b/pyproject.toml index 0b7d1d41b4..4583a5531f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.70.0" +version = "1.71.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 6b4385ec3c..12e9d20bb1 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.70.0" # x-release-please-version +__version__ = "1.71.0" # x-release-please-version From 039b1bf54a2fe34c2ff2d669ee23515dae52d743 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 8 Apr 2025 12:09:51 +0000 Subject: [PATCH 275/769] chore(internal): slight transform perf improvement (#2284) --- src/openai/_utils/_transform.py | 22 ++++++++++++++++++++++ tests/test_transform.py | 12 ++++++++++++ 2 files changed, 34 insertions(+) diff --git a/src/openai/_utils/_transform.py b/src/openai/_utils/_transform.py index 7ac2e17fbb..3ec620818c 100644 --- a/src/openai/_utils/_transform.py +++ b/src/openai/_utils/_transform.py @@ -142,6 +142,10 @@ def _maybe_transform_key(key: str, type_: type) -> str: return key +def _no_transform_needed(annotation: type) -> bool: + return annotation == float or annotation == int + + def _transform_recursive( data: object, *, @@ -184,6 +188,15 @@ def _transform_recursive( return cast(object, data) inner_type = extract_type_arg(stripped_type, 0) + if _no_transform_needed(inner_type): + # for some types there is no need to transform anything, so we can get a small + # perf boost from skipping that work. + # + # but we still need to convert to a list to ensure the data is json-serializable + if is_list(data): + return data + return list(data) + return [_transform_recursive(d, annotation=annotation, inner_type=inner_type) for d in data] if is_union_type(stripped_type): @@ -332,6 +345,15 @@ async def _async_transform_recursive( return cast(object, data) inner_type = extract_type_arg(stripped_type, 0) + if _no_transform_needed(inner_type): + # for some types there is no need to transform anything, so we can get a small + # perf boost from skipping that work. + # + # but we still need to convert to a list to ensure the data is json-serializable + if is_list(data): + return data + return list(data) + return [await _async_transform_recursive(d, annotation=annotation, inner_type=inner_type) for d in data] if is_union_type(stripped_type): diff --git a/tests/test_transform.py b/tests/test_transform.py index 385fbe2b2c..cd584756d7 100644 --- a/tests/test_transform.py +++ b/tests/test_transform.py @@ -432,3 +432,15 @@ async def test_base64_file_input(use_async: bool) -> None: assert await transform({"foo": io.BytesIO(b"Hello, world!")}, TypedDictBase64Input, use_async) == { "foo": "SGVsbG8sIHdvcmxkIQ==" } # type: ignore[comparison-overlap] + + +@parametrize +@pytest.mark.asyncio +async def test_transform_skipping(use_async: bool) -> None: + # lists of ints are left as-is + data = [1, 2, 3] + assert await transform(data, List[int], use_async) is data + + # iterables of ints are converted to a list + data = iter([1, 2, 3]) + assert await transform(data, Iterable[int], use_async) == [1, 2, 3] From 48c200ac0d732b030a87012575c1843957e98718 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 8 Apr 2025 14:25:27 +0000 Subject: [PATCH 276/769] chore(tests): improve enum examples (#2286) --- tests/api_resources/test_images.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/api_resources/test_images.py b/tests/api_resources/test_images.py index 9bc9719bc5..2e31f3354a 100644 --- a/tests/api_resources/test_images.py +++ b/tests/api_resources/test_images.py @@ -31,7 +31,7 @@ def test_method_create_variation_with_all_params(self, client: OpenAI) -> None: model="dall-e-2", n=1, response_format="url", - size="256x256", + size="1024x1024", user="user-1234", ) assert_matches_type(ImagesResponse, image, path=["response"]) @@ -77,7 +77,7 @@ def test_method_edit_with_all_params(self, client: OpenAI) -> None: model="dall-e-2", n=1, response_format="url", - size="256x256", + size="1024x1024", user="user-1234", ) assert_matches_type(ImagesResponse, image, path=["response"]) @@ -123,7 +123,7 @@ def test_method_generate_with_all_params(self, client: OpenAI) -> None: n=1, quality="standard", response_format="url", - size="256x256", + size="1024x1024", style="vivid", user="user-1234", ) @@ -171,7 +171,7 @@ async def test_method_create_variation_with_all_params(self, async_client: Async model="dall-e-2", n=1, response_format="url", - size="256x256", + size="1024x1024", user="user-1234", ) assert_matches_type(ImagesResponse, image, path=["response"]) @@ -217,7 +217,7 @@ async def test_method_edit_with_all_params(self, async_client: AsyncOpenAI) -> N model="dall-e-2", n=1, response_format="url", - size="256x256", + size="1024x1024", user="user-1234", ) assert_matches_type(ImagesResponse, image, path=["response"]) @@ -263,7 +263,7 @@ async def test_method_generate_with_all_params(self, async_client: AsyncOpenAI) n=1, quality="standard", response_format="url", - size="256x256", + size="1024x1024", style="vivid", user="user-1234", ) From 8da9f46bedc954cb4ceba2eb5acf5f9d3c22df57 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 8 Apr 2025 18:50:02 +0000 Subject: [PATCH 277/769] feat(api): Add evalapi to sdk (#2287) Adding the evalsapi to the sdk. --- .stats.yml | 8 +- api.md | 85 + src/openai/__init__.py | 1 + src/openai/_client.py | 9 + src/openai/_module_client.py | 7 + src/openai/resources/__init__.py | 14 + src/openai/resources/evals/__init__.py | 33 + src/openai/resources/evals/evals.py | 663 +++++++ src/openai/resources/evals/runs/__init__.py | 33 + .../resources/evals/runs/output_items.py | 315 +++ src/openai/resources/evals/runs/runs.py | 635 ++++++ src/openai/resources/fine_tuning/__init__.py | 14 + .../fine_tuning/checkpoints/__init__.py | 33 + .../fine_tuning/checkpoints/checkpoints.py | 102 + .../fine_tuning/checkpoints/permissions.py | 416 ++++ .../resources/fine_tuning/fine_tuning.py | 32 + src/openai/types/__init__.py | 17 + src/openai/types/eval_create_params.py | 153 ++ src/openai/types/eval_create_response.py | 56 + .../types/eval_custom_data_source_config.py | 21 + src/openai/types/eval_delete_response.py | 14 + src/openai/types/eval_label_model_grader.py | 74 + src/openai/types/eval_list_params.py | 27 + src/openai/types/eval_list_response.py | 56 + src/openai/types/eval_retrieve_response.py | 56 + ...l_stored_completions_data_source_config.py | 32 + src/openai/types/eval_string_check_grader.py | 24 + .../types/eval_string_check_grader_param.py | 24 + .../types/eval_text_similarity_grader.py | 44 + .../eval_text_similarity_grader_param.py | 45 + src/openai/types/eval_update_params.py | 25 + src/openai/types/eval_update_response.py | 56 + src/openai/types/evals/__init__.py | 22 + ...create_eval_completions_run_data_source.py | 185 ++ ..._eval_completions_run_data_source_param.py | 181 ++ .../create_eval_jsonl_run_data_source.py | 41 + ...create_eval_jsonl_run_data_source_param.py | 46 + src/openai/types/evals/eval_api_error.py | 14 + src/openai/types/evals/run_cancel_response.py | 115 ++ src/openai/types/evals/run_create_params.py | 33 + src/openai/types/evals/run_create_response.py | 115 ++ src/openai/types/evals/run_delete_response.py | 15 + src/openai/types/evals/run_list_params.py | 27 + src/openai/types/evals/run_list_response.py | 115 ++ .../types/evals/run_retrieve_response.py | 115 ++ src/openai/types/evals/runs/__init__.py | 7 + .../evals/runs/output_item_list_params.py | 30 + .../evals/runs/output_item_list_response.py | 104 + .../runs/output_item_retrieve_response.py | 104 + .../types/fine_tuning/checkpoints/__init__.py | 9 + .../checkpoints/permission_create_params.py | 13 + .../checkpoints/permission_create_response.py | 21 + .../checkpoints/permission_delete_response.py | 18 + .../checkpoints/permission_retrieve_params.py | 21 + .../permission_retrieve_response.py | 34 + tests/api_resources/evals/__init__.py | 1 + tests/api_resources/evals/runs/__init__.py | 1 + .../evals/runs/test_output_items.py | 263 +++ tests/api_resources/evals/test_runs.py | 589 ++++++ .../fine_tuning/checkpoints/__init__.py | 1 + .../checkpoints/test_permissions.py | 297 +++ tests/api_resources/test_evals.py | 1701 +++++++++++++++++ 62 files changed, 7358 insertions(+), 4 deletions(-) create mode 100644 src/openai/resources/evals/__init__.py create mode 100644 src/openai/resources/evals/evals.py create mode 100644 src/openai/resources/evals/runs/__init__.py create mode 100644 src/openai/resources/evals/runs/output_items.py create mode 100644 src/openai/resources/evals/runs/runs.py create mode 100644 src/openai/resources/fine_tuning/checkpoints/__init__.py create mode 100644 src/openai/resources/fine_tuning/checkpoints/checkpoints.py create mode 100644 src/openai/resources/fine_tuning/checkpoints/permissions.py create mode 100644 src/openai/types/eval_create_params.py create mode 100644 src/openai/types/eval_create_response.py create mode 100644 src/openai/types/eval_custom_data_source_config.py create mode 100644 src/openai/types/eval_delete_response.py create mode 100644 src/openai/types/eval_label_model_grader.py create mode 100644 src/openai/types/eval_list_params.py create mode 100644 src/openai/types/eval_list_response.py create mode 100644 src/openai/types/eval_retrieve_response.py create mode 100644 src/openai/types/eval_stored_completions_data_source_config.py create mode 100644 src/openai/types/eval_string_check_grader.py create mode 100644 src/openai/types/eval_string_check_grader_param.py create mode 100644 src/openai/types/eval_text_similarity_grader.py create mode 100644 src/openai/types/eval_text_similarity_grader_param.py create mode 100644 src/openai/types/eval_update_params.py create mode 100644 src/openai/types/eval_update_response.py create mode 100644 src/openai/types/evals/__init__.py create mode 100644 src/openai/types/evals/create_eval_completions_run_data_source.py create mode 100644 src/openai/types/evals/create_eval_completions_run_data_source_param.py create mode 100644 src/openai/types/evals/create_eval_jsonl_run_data_source.py create mode 100644 src/openai/types/evals/create_eval_jsonl_run_data_source_param.py create mode 100644 src/openai/types/evals/eval_api_error.py create mode 100644 src/openai/types/evals/run_cancel_response.py create mode 100644 src/openai/types/evals/run_create_params.py create mode 100644 src/openai/types/evals/run_create_response.py create mode 100644 src/openai/types/evals/run_delete_response.py create mode 100644 src/openai/types/evals/run_list_params.py create mode 100644 src/openai/types/evals/run_list_response.py create mode 100644 src/openai/types/evals/run_retrieve_response.py create mode 100644 src/openai/types/evals/runs/__init__.py create mode 100644 src/openai/types/evals/runs/output_item_list_params.py create mode 100644 src/openai/types/evals/runs/output_item_list_response.py create mode 100644 src/openai/types/evals/runs/output_item_retrieve_response.py create mode 100644 src/openai/types/fine_tuning/checkpoints/__init__.py create mode 100644 src/openai/types/fine_tuning/checkpoints/permission_create_params.py create mode 100644 src/openai/types/fine_tuning/checkpoints/permission_create_response.py create mode 100644 src/openai/types/fine_tuning/checkpoints/permission_delete_response.py create mode 100644 src/openai/types/fine_tuning/checkpoints/permission_retrieve_params.py create mode 100644 src/openai/types/fine_tuning/checkpoints/permission_retrieve_response.py create mode 100644 tests/api_resources/evals/__init__.py create mode 100644 tests/api_resources/evals/runs/__init__.py create mode 100644 tests/api_resources/evals/runs/test_output_items.py create mode 100644 tests/api_resources/evals/test_runs.py create mode 100644 tests/api_resources/fine_tuning/checkpoints/__init__.py create mode 100644 tests/api_resources/fine_tuning/checkpoints/test_permissions.py create mode 100644 tests/api_resources/test_evals.py diff --git a/.stats.yml b/.stats.yml index aebb90c8cf..ebe07c1372 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 82 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-4bce8217a697c729ac98046d4caf2c9e826b54c427fb0ab4f98e549a2e0ce31c.yml -openapi_spec_hash: 7996d2c34cc44fe2ce9ffe93c0ab774e -config_hash: bcd2cacdcb9fae9938f273cd167f613c +configured_endpoints: 97 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-472fe3036ea745365257fe870c0330917fb3153705c2826f49873cd631319b0a.yml +openapi_spec_hash: ea86343b5e9858a74e85da8ab2c532f6 +config_hash: ef19d36c307306f14f2e1cd5c834a151 diff --git a/api.md b/api.md index a5f81c624c..e06f55c2cc 100644 --- a/api.md +++ b/api.md @@ -259,6 +259,26 @@ Methods: - client.fine_tuning.jobs.checkpoints.list(fine_tuning_job_id, \*\*params) -> SyncCursorPage[FineTuningJobCheckpoint] +## Checkpoints + +### Permissions + +Types: + +```python +from openai.types.fine_tuning.checkpoints import ( + PermissionCreateResponse, + PermissionRetrieveResponse, + PermissionDeleteResponse, +) +``` + +Methods: + +- client.fine_tuning.checkpoints.permissions.create(fine_tuned_model_checkpoint, \*\*params) -> SyncPage[PermissionCreateResponse] +- client.fine_tuning.checkpoints.permissions.retrieve(fine_tuned_model_checkpoint, \*\*params) -> PermissionRetrieveResponse +- client.fine_tuning.checkpoints.permissions.delete(fine_tuned_model_checkpoint) -> PermissionDeleteResponse + # VectorStores Types: @@ -706,3 +726,68 @@ from openai.types.responses import ResponseItemList Methods: - client.responses.input_items.list(response_id, \*\*params) -> SyncCursorPage[ResponseItem] + +# Evals + +Types: + +```python +from openai.types import ( + EvalCustomDataSourceConfig, + EvalLabelModelGrader, + EvalStoredCompletionsDataSourceConfig, + EvalStringCheckGrader, + EvalTextSimilarityGrader, + EvalCreateResponse, + EvalRetrieveResponse, + EvalUpdateResponse, + EvalListResponse, + EvalDeleteResponse, +) +``` + +Methods: + +- client.evals.create(\*\*params) -> EvalCreateResponse +- client.evals.retrieve(eval_id) -> EvalRetrieveResponse +- client.evals.update(eval_id, \*\*params) -> EvalUpdateResponse +- client.evals.list(\*\*params) -> SyncCursorPage[EvalListResponse] +- client.evals.delete(eval_id) -> EvalDeleteResponse + +## Runs + +Types: + +```python +from openai.types.evals import ( + CreateEvalCompletionsRunDataSource, + CreateEvalJSONLRunDataSource, + EvalAPIError, + RunCreateResponse, + RunRetrieveResponse, + RunListResponse, + RunDeleteResponse, + RunCancelResponse, +) +``` + +Methods: + +- client.evals.runs.create(eval_id, \*\*params) -> RunCreateResponse +- client.evals.runs.retrieve(run_id, \*, eval_id) -> RunRetrieveResponse +- client.evals.runs.list(eval_id, \*\*params) -> SyncCursorPage[RunListResponse] +- client.evals.runs.delete(run_id, \*, eval_id) -> RunDeleteResponse +- client.evals.runs.cancel(run_id, \*, eval_id) -> RunCancelResponse + +### OutputItems + +Types: + +```python +from openai.types.evals.runs import OutputItemRetrieveResponse, OutputItemListResponse +``` + +Methods: + +- client.evals.runs.output_items.retrieve(output_item_id, \*, eval_id, run_id) -> OutputItemRetrieveResponse +- client.evals.runs.output_items.list(run_id, \*, eval_id, \*\*params) -> SyncCursorPage[OutputItemListResponse] diff --git a/src/openai/__init__.py b/src/openai/__init__.py index 7ce6df0817..9e97098bb0 100644 --- a/src/openai/__init__.py +++ b/src/openai/__init__.py @@ -352,6 +352,7 @@ def _reset_client() -> None: # type: ignore[reportUnusedFunction] beta as beta, chat as chat, audio as audio, + evals as evals, files as files, images as images, models as models, diff --git a/src/openai/_client.py b/src/openai/_client.py index 18d96da9a3..3aca6cb124 100644 --- a/src/openai/_client.py +++ b/src/openai/_client.py @@ -36,6 +36,7 @@ from .resources.beta import beta from .resources.chat import chat from .resources.audio import audio +from .resources.evals import evals from .resources.uploads import uploads from .resources.responses import responses from .resources.fine_tuning import fine_tuning @@ -59,6 +60,7 @@ class OpenAI(SyncAPIClient): batches: batches.Batches uploads: uploads.Uploads responses: responses.Responses + evals: evals.Evals with_raw_response: OpenAIWithRawResponse with_streaming_response: OpenAIWithStreamedResponse @@ -158,6 +160,7 @@ def __init__( self.batches = batches.Batches(self) self.uploads = uploads.Uploads(self) self.responses = responses.Responses(self) + self.evals = evals.Evals(self) self.with_raw_response = OpenAIWithRawResponse(self) self.with_streaming_response = OpenAIWithStreamedResponse(self) @@ -290,6 +293,7 @@ class AsyncOpenAI(AsyncAPIClient): batches: batches.AsyncBatches uploads: uploads.AsyncUploads responses: responses.AsyncResponses + evals: evals.AsyncEvals with_raw_response: AsyncOpenAIWithRawResponse with_streaming_response: AsyncOpenAIWithStreamedResponse @@ -389,6 +393,7 @@ def __init__( self.batches = batches.AsyncBatches(self) self.uploads = uploads.AsyncUploads(self) self.responses = responses.AsyncResponses(self) + self.evals = evals.AsyncEvals(self) self.with_raw_response = AsyncOpenAIWithRawResponse(self) self.with_streaming_response = AsyncOpenAIWithStreamedResponse(self) @@ -522,6 +527,7 @@ def __init__(self, client: OpenAI) -> None: self.batches = batches.BatchesWithRawResponse(client.batches) self.uploads = uploads.UploadsWithRawResponse(client.uploads) self.responses = responses.ResponsesWithRawResponse(client.responses) + self.evals = evals.EvalsWithRawResponse(client.evals) class AsyncOpenAIWithRawResponse: @@ -540,6 +546,7 @@ def __init__(self, client: AsyncOpenAI) -> None: self.batches = batches.AsyncBatchesWithRawResponse(client.batches) self.uploads = uploads.AsyncUploadsWithRawResponse(client.uploads) self.responses = responses.AsyncResponsesWithRawResponse(client.responses) + self.evals = evals.AsyncEvalsWithRawResponse(client.evals) class OpenAIWithStreamedResponse: @@ -558,6 +565,7 @@ def __init__(self, client: OpenAI) -> None: self.batches = batches.BatchesWithStreamingResponse(client.batches) self.uploads = uploads.UploadsWithStreamingResponse(client.uploads) self.responses = responses.ResponsesWithStreamingResponse(client.responses) + self.evals = evals.EvalsWithStreamingResponse(client.evals) class AsyncOpenAIWithStreamedResponse: @@ -576,6 +584,7 @@ def __init__(self, client: AsyncOpenAI) -> None: self.batches = batches.AsyncBatchesWithStreamingResponse(client.batches) self.uploads = uploads.AsyncUploadsWithStreamingResponse(client.uploads) self.responses = responses.AsyncResponsesWithStreamingResponse(client.responses) + self.evals = evals.AsyncEvalsWithStreamingResponse(client.evals) Client = OpenAI diff --git a/src/openai/_module_client.py b/src/openai/_module_client.py index e7d2657860..cf12f7a31e 100644 --- a/src/openai/_module_client.py +++ b/src/openai/_module_client.py @@ -30,6 +30,12 @@ def __load__(self) -> resources.Audio: return _load_client().audio +class EvalsProxy(LazyProxy[resources.Evals]): + @override + def __load__(self) -> resources.Evals: + return _load_client().evals + + class ImagesProxy(LazyProxy[resources.Images]): @override def __load__(self) -> resources.Images: @@ -94,6 +100,7 @@ def __load__(self) -> resources.VectorStores: beta: resources.Beta = BetaProxy().__as_proxied__() files: resources.Files = FilesProxy().__as_proxied__() audio: resources.Audio = AudioProxy().__as_proxied__() +evals: resources.Evals = EvalsProxy().__as_proxied__() images: resources.Images = ImagesProxy().__as_proxied__() models: resources.Models = ModelsProxy().__as_proxied__() batches: resources.Batches = BatchesProxy().__as_proxied__() diff --git a/src/openai/resources/__init__.py b/src/openai/resources/__init__.py index d3457cf319..ab9cd73e81 100644 --- a/src/openai/resources/__init__.py +++ b/src/openai/resources/__init__.py @@ -24,6 +24,14 @@ AudioWithStreamingResponse, AsyncAudioWithStreamingResponse, ) +from .evals import ( + Evals, + AsyncEvals, + EvalsWithRawResponse, + AsyncEvalsWithRawResponse, + EvalsWithStreamingResponse, + AsyncEvalsWithStreamingResponse, +) from .files import ( Files, AsyncFiles, @@ -198,4 +206,10 @@ "AsyncResponsesWithRawResponse", "ResponsesWithStreamingResponse", "AsyncResponsesWithStreamingResponse", + "Evals", + "AsyncEvals", + "EvalsWithRawResponse", + "AsyncEvalsWithRawResponse", + "EvalsWithStreamingResponse", + "AsyncEvalsWithStreamingResponse", ] diff --git a/src/openai/resources/evals/__init__.py b/src/openai/resources/evals/__init__.py new file mode 100644 index 0000000000..84f707511d --- /dev/null +++ b/src/openai/resources/evals/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .runs import ( + Runs, + AsyncRuns, + RunsWithRawResponse, + AsyncRunsWithRawResponse, + RunsWithStreamingResponse, + AsyncRunsWithStreamingResponse, +) +from .evals import ( + Evals, + AsyncEvals, + EvalsWithRawResponse, + AsyncEvalsWithRawResponse, + EvalsWithStreamingResponse, + AsyncEvalsWithStreamingResponse, +) + +__all__ = [ + "Runs", + "AsyncRuns", + "RunsWithRawResponse", + "AsyncRunsWithRawResponse", + "RunsWithStreamingResponse", + "AsyncRunsWithStreamingResponse", + "Evals", + "AsyncEvals", + "EvalsWithRawResponse", + "AsyncEvalsWithRawResponse", + "EvalsWithStreamingResponse", + "AsyncEvalsWithStreamingResponse", +] diff --git a/src/openai/resources/evals/evals.py b/src/openai/resources/evals/evals.py new file mode 100644 index 0000000000..24a0350cfb --- /dev/null +++ b/src/openai/resources/evals/evals.py @@ -0,0 +1,663 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Literal + +import httpx + +from ... import _legacy_response +from ...types import eval_list_params, eval_create_params, eval_update_params +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._utils import ( + maybe_transform, + async_maybe_transform, +) +from ..._compat import cached_property +from .runs.runs import ( + Runs, + AsyncRuns, + RunsWithRawResponse, + AsyncRunsWithRawResponse, + RunsWithStreamingResponse, + AsyncRunsWithStreamingResponse, +) +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ...pagination import SyncCursorPage, AsyncCursorPage +from ..._base_client import AsyncPaginator, make_request_options +from ...types.eval_list_response import EvalListResponse +from ...types.eval_create_response import EvalCreateResponse +from ...types.eval_delete_response import EvalDeleteResponse +from ...types.eval_update_response import EvalUpdateResponse +from ...types.eval_retrieve_response import EvalRetrieveResponse +from ...types.shared_params.metadata import Metadata + +__all__ = ["Evals", "AsyncEvals"] + + +class Evals(SyncAPIResource): + @cached_property + def runs(self) -> Runs: + return Runs(self._client) + + @cached_property + def with_raw_response(self) -> EvalsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return EvalsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> EvalsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return EvalsWithStreamingResponse(self) + + def create( + self, + *, + data_source_config: eval_create_params.DataSourceConfig, + testing_criteria: Iterable[eval_create_params.TestingCriterion], + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + name: str | NotGiven = NOT_GIVEN, + share_with_openai: bool | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> EvalCreateResponse: + """ + Create the structure of an evaluation that can be used to test a model's + performance. An evaluation is a set of testing criteria and a datasource. After + creating an evaluation, you can run it on different models and model parameters. + We support several types of graders and datasources. For more information, see + the [Evals guide](https://platform.openai.com/docs/guides/evals). + + Args: + data_source_config: The configuration for the data source used for the evaluation runs. + + testing_criteria: A list of graders for all eval runs in this group. + + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + + name: The name of the evaluation. + + share_with_openai: Indicates whether the evaluation is shared with OpenAI. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/evals", + body=maybe_transform( + { + "data_source_config": data_source_config, + "testing_criteria": testing_criteria, + "metadata": metadata, + "name": name, + "share_with_openai": share_with_openai, + }, + eval_create_params.EvalCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EvalCreateResponse, + ) + + def retrieve( + self, + eval_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> EvalRetrieveResponse: + """ + Get an evaluation by ID. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not eval_id: + raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") + return self._get( + f"/evals/{eval_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EvalRetrieveResponse, + ) + + def update( + self, + eval_id: str, + *, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + name: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> EvalUpdateResponse: + """ + Update certain properties of an evaluation. + + Args: + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + + name: Rename the evaluation. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not eval_id: + raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") + return self._post( + f"/evals/{eval_id}", + body=maybe_transform( + { + "metadata": metadata, + "name": name, + }, + eval_update_params.EvalUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EvalUpdateResponse, + ) + + def list( + self, + *, + after: str | NotGiven = NOT_GIVEN, + limit: int | NotGiven = NOT_GIVEN, + order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + order_by: Literal["created_at", "updated_at"] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> SyncCursorPage[EvalListResponse]: + """ + List evaluations for a project. + + Args: + after: Identifier for the last eval from the previous pagination request. + + limit: Number of evals to retrieve. + + order: Sort order for evals by timestamp. Use `asc` for ascending order or `desc` for + descending order. + + order_by: Evals can be ordered by creation time or last updated time. Use `created_at` for + creation time or `updated_at` for last updated time. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/evals", + page=SyncCursorPage[EvalListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + "order_by": order_by, + }, + eval_list_params.EvalListParams, + ), + ), + model=EvalListResponse, + ) + + def delete( + self, + eval_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> EvalDeleteResponse: + """ + Delete an evaluation. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not eval_id: + raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") + return self._delete( + f"/evals/{eval_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EvalDeleteResponse, + ) + + +class AsyncEvals(AsyncAPIResource): + @cached_property + def runs(self) -> AsyncRuns: + return AsyncRuns(self._client) + + @cached_property + def with_raw_response(self) -> AsyncEvalsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncEvalsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncEvalsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncEvalsWithStreamingResponse(self) + + async def create( + self, + *, + data_source_config: eval_create_params.DataSourceConfig, + testing_criteria: Iterable[eval_create_params.TestingCriterion], + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + name: str | NotGiven = NOT_GIVEN, + share_with_openai: bool | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> EvalCreateResponse: + """ + Create the structure of an evaluation that can be used to test a model's + performance. An evaluation is a set of testing criteria and a datasource. After + creating an evaluation, you can run it on different models and model parameters. + We support several types of graders and datasources. For more information, see + the [Evals guide](https://platform.openai.com/docs/guides/evals). + + Args: + data_source_config: The configuration for the data source used for the evaluation runs. + + testing_criteria: A list of graders for all eval runs in this group. + + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + + name: The name of the evaluation. + + share_with_openai: Indicates whether the evaluation is shared with OpenAI. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/evals", + body=await async_maybe_transform( + { + "data_source_config": data_source_config, + "testing_criteria": testing_criteria, + "metadata": metadata, + "name": name, + "share_with_openai": share_with_openai, + }, + eval_create_params.EvalCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EvalCreateResponse, + ) + + async def retrieve( + self, + eval_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> EvalRetrieveResponse: + """ + Get an evaluation by ID. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not eval_id: + raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") + return await self._get( + f"/evals/{eval_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EvalRetrieveResponse, + ) + + async def update( + self, + eval_id: str, + *, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + name: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> EvalUpdateResponse: + """ + Update certain properties of an evaluation. + + Args: + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + + name: Rename the evaluation. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not eval_id: + raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") + return await self._post( + f"/evals/{eval_id}", + body=await async_maybe_transform( + { + "metadata": metadata, + "name": name, + }, + eval_update_params.EvalUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EvalUpdateResponse, + ) + + def list( + self, + *, + after: str | NotGiven = NOT_GIVEN, + limit: int | NotGiven = NOT_GIVEN, + order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + order_by: Literal["created_at", "updated_at"] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> AsyncPaginator[EvalListResponse, AsyncCursorPage[EvalListResponse]]: + """ + List evaluations for a project. + + Args: + after: Identifier for the last eval from the previous pagination request. + + limit: Number of evals to retrieve. + + order: Sort order for evals by timestamp. Use `asc` for ascending order or `desc` for + descending order. + + order_by: Evals can be ordered by creation time or last updated time. Use `created_at` for + creation time or `updated_at` for last updated time. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/evals", + page=AsyncCursorPage[EvalListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + "order_by": order_by, + }, + eval_list_params.EvalListParams, + ), + ), + model=EvalListResponse, + ) + + async def delete( + self, + eval_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> EvalDeleteResponse: + """ + Delete an evaluation. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not eval_id: + raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") + return await self._delete( + f"/evals/{eval_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EvalDeleteResponse, + ) + + +class EvalsWithRawResponse: + def __init__(self, evals: Evals) -> None: + self._evals = evals + + self.create = _legacy_response.to_raw_response_wrapper( + evals.create, + ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + evals.retrieve, + ) + self.update = _legacy_response.to_raw_response_wrapper( + evals.update, + ) + self.list = _legacy_response.to_raw_response_wrapper( + evals.list, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + evals.delete, + ) + + @cached_property + def runs(self) -> RunsWithRawResponse: + return RunsWithRawResponse(self._evals.runs) + + +class AsyncEvalsWithRawResponse: + def __init__(self, evals: AsyncEvals) -> None: + self._evals = evals + + self.create = _legacy_response.async_to_raw_response_wrapper( + evals.create, + ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + evals.retrieve, + ) + self.update = _legacy_response.async_to_raw_response_wrapper( + evals.update, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + evals.list, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + evals.delete, + ) + + @cached_property + def runs(self) -> AsyncRunsWithRawResponse: + return AsyncRunsWithRawResponse(self._evals.runs) + + +class EvalsWithStreamingResponse: + def __init__(self, evals: Evals) -> None: + self._evals = evals + + self.create = to_streamed_response_wrapper( + evals.create, + ) + self.retrieve = to_streamed_response_wrapper( + evals.retrieve, + ) + self.update = to_streamed_response_wrapper( + evals.update, + ) + self.list = to_streamed_response_wrapper( + evals.list, + ) + self.delete = to_streamed_response_wrapper( + evals.delete, + ) + + @cached_property + def runs(self) -> RunsWithStreamingResponse: + return RunsWithStreamingResponse(self._evals.runs) + + +class AsyncEvalsWithStreamingResponse: + def __init__(self, evals: AsyncEvals) -> None: + self._evals = evals + + self.create = async_to_streamed_response_wrapper( + evals.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + evals.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + evals.update, + ) + self.list = async_to_streamed_response_wrapper( + evals.list, + ) + self.delete = async_to_streamed_response_wrapper( + evals.delete, + ) + + @cached_property + def runs(self) -> AsyncRunsWithStreamingResponse: + return AsyncRunsWithStreamingResponse(self._evals.runs) diff --git a/src/openai/resources/evals/runs/__init__.py b/src/openai/resources/evals/runs/__init__.py new file mode 100644 index 0000000000..d189f16fb7 --- /dev/null +++ b/src/openai/resources/evals/runs/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .runs import ( + Runs, + AsyncRuns, + RunsWithRawResponse, + AsyncRunsWithRawResponse, + RunsWithStreamingResponse, + AsyncRunsWithStreamingResponse, +) +from .output_items import ( + OutputItems, + AsyncOutputItems, + OutputItemsWithRawResponse, + AsyncOutputItemsWithRawResponse, + OutputItemsWithStreamingResponse, + AsyncOutputItemsWithStreamingResponse, +) + +__all__ = [ + "OutputItems", + "AsyncOutputItems", + "OutputItemsWithRawResponse", + "AsyncOutputItemsWithRawResponse", + "OutputItemsWithStreamingResponse", + "AsyncOutputItemsWithStreamingResponse", + "Runs", + "AsyncRuns", + "RunsWithRawResponse", + "AsyncRunsWithRawResponse", + "RunsWithStreamingResponse", + "AsyncRunsWithStreamingResponse", +] diff --git a/src/openai/resources/evals/runs/output_items.py b/src/openai/resources/evals/runs/output_items.py new file mode 100644 index 0000000000..8fd0fdea92 --- /dev/null +++ b/src/openai/resources/evals/runs/output_items.py @@ -0,0 +1,315 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from .... import _legacy_response +from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._utils import maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ....pagination import SyncCursorPage, AsyncCursorPage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.evals.runs import output_item_list_params +from ....types.evals.runs.output_item_list_response import OutputItemListResponse +from ....types.evals.runs.output_item_retrieve_response import OutputItemRetrieveResponse + +__all__ = ["OutputItems", "AsyncOutputItems"] + + +class OutputItems(SyncAPIResource): + @cached_property + def with_raw_response(self) -> OutputItemsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return OutputItemsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> OutputItemsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return OutputItemsWithStreamingResponse(self) + + def retrieve( + self, + output_item_id: str, + *, + eval_id: str, + run_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> OutputItemRetrieveResponse: + """ + Get an evaluation run output item by ID. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not eval_id: + raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") + if not run_id: + raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") + if not output_item_id: + raise ValueError(f"Expected a non-empty value for `output_item_id` but received {output_item_id!r}") + return self._get( + f"/evals/{eval_id}/runs/{run_id}/output_items/{output_item_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=OutputItemRetrieveResponse, + ) + + def list( + self, + run_id: str, + *, + eval_id: str, + after: str | NotGiven = NOT_GIVEN, + limit: int | NotGiven = NOT_GIVEN, + order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + status: Literal["fail", "pass"] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> SyncCursorPage[OutputItemListResponse]: + """ + Get a list of output items for an evaluation run. + + Args: + after: Identifier for the last output item from the previous pagination request. + + limit: Number of output items to retrieve. + + order: Sort order for output items by timestamp. Use `asc` for ascending order or + `desc` for descending order. Defaults to `asc`. + + status: Filter output items by status. Use `failed` to filter by failed output items or + `pass` to filter by passed output items. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not eval_id: + raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") + if not run_id: + raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") + return self._get_api_list( + f"/evals/{eval_id}/runs/{run_id}/output_items", + page=SyncCursorPage[OutputItemListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + "status": status, + }, + output_item_list_params.OutputItemListParams, + ), + ), + model=OutputItemListResponse, + ) + + +class AsyncOutputItems(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncOutputItemsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncOutputItemsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncOutputItemsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncOutputItemsWithStreamingResponse(self) + + async def retrieve( + self, + output_item_id: str, + *, + eval_id: str, + run_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> OutputItemRetrieveResponse: + """ + Get an evaluation run output item by ID. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not eval_id: + raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") + if not run_id: + raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") + if not output_item_id: + raise ValueError(f"Expected a non-empty value for `output_item_id` but received {output_item_id!r}") + return await self._get( + f"/evals/{eval_id}/runs/{run_id}/output_items/{output_item_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=OutputItemRetrieveResponse, + ) + + def list( + self, + run_id: str, + *, + eval_id: str, + after: str | NotGiven = NOT_GIVEN, + limit: int | NotGiven = NOT_GIVEN, + order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + status: Literal["fail", "pass"] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> AsyncPaginator[OutputItemListResponse, AsyncCursorPage[OutputItemListResponse]]: + """ + Get a list of output items for an evaluation run. + + Args: + after: Identifier for the last output item from the previous pagination request. + + limit: Number of output items to retrieve. + + order: Sort order for output items by timestamp. Use `asc` for ascending order or + `desc` for descending order. Defaults to `asc`. + + status: Filter output items by status. Use `failed` to filter by failed output items or + `pass` to filter by passed output items. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not eval_id: + raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") + if not run_id: + raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") + return self._get_api_list( + f"/evals/{eval_id}/runs/{run_id}/output_items", + page=AsyncCursorPage[OutputItemListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + "status": status, + }, + output_item_list_params.OutputItemListParams, + ), + ), + model=OutputItemListResponse, + ) + + +class OutputItemsWithRawResponse: + def __init__(self, output_items: OutputItems) -> None: + self._output_items = output_items + + self.retrieve = _legacy_response.to_raw_response_wrapper( + output_items.retrieve, + ) + self.list = _legacy_response.to_raw_response_wrapper( + output_items.list, + ) + + +class AsyncOutputItemsWithRawResponse: + def __init__(self, output_items: AsyncOutputItems) -> None: + self._output_items = output_items + + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + output_items.retrieve, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + output_items.list, + ) + + +class OutputItemsWithStreamingResponse: + def __init__(self, output_items: OutputItems) -> None: + self._output_items = output_items + + self.retrieve = to_streamed_response_wrapper( + output_items.retrieve, + ) + self.list = to_streamed_response_wrapper( + output_items.list, + ) + + +class AsyncOutputItemsWithStreamingResponse: + def __init__(self, output_items: AsyncOutputItems) -> None: + self._output_items = output_items + + self.retrieve = async_to_streamed_response_wrapper( + output_items.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + output_items.list, + ) diff --git a/src/openai/resources/evals/runs/runs.py b/src/openai/resources/evals/runs/runs.py new file mode 100644 index 0000000000..6df0b6d121 --- /dev/null +++ b/src/openai/resources/evals/runs/runs.py @@ -0,0 +1,635 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal + +import httpx + +from .... import _legacy_response +from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._utils import ( + maybe_transform, + async_maybe_transform, +) +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from .output_items import ( + OutputItems, + AsyncOutputItems, + OutputItemsWithRawResponse, + AsyncOutputItemsWithRawResponse, + OutputItemsWithStreamingResponse, + AsyncOutputItemsWithStreamingResponse, +) +from ....pagination import SyncCursorPage, AsyncCursorPage +from ....types.evals import run_list_params, run_create_params +from ...._base_client import AsyncPaginator, make_request_options +from ....types.shared_params.metadata import Metadata +from ....types.evals.run_list_response import RunListResponse +from ....types.evals.run_cancel_response import RunCancelResponse +from ....types.evals.run_create_response import RunCreateResponse +from ....types.evals.run_delete_response import RunDeleteResponse +from ....types.evals.run_retrieve_response import RunRetrieveResponse + +__all__ = ["Runs", "AsyncRuns"] + + +class Runs(SyncAPIResource): + @cached_property + def output_items(self) -> OutputItems: + return OutputItems(self._client) + + @cached_property + def with_raw_response(self) -> RunsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return RunsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> RunsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return RunsWithStreamingResponse(self) + + def create( + self, + eval_id: str, + *, + data_source: run_create_params.DataSource, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + name: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> RunCreateResponse: + """Create a new evaluation run. + + This is the endpoint that will kick off grading. + + Args: + data_source: Details about the run's data source. + + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + + name: The name of the run. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not eval_id: + raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") + return self._post( + f"/evals/{eval_id}/runs", + body=maybe_transform( + { + "data_source": data_source, + "metadata": metadata, + "name": name, + }, + run_create_params.RunCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RunCreateResponse, + ) + + def retrieve( + self, + run_id: str, + *, + eval_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> RunRetrieveResponse: + """ + Get an evaluation run by ID. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not eval_id: + raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") + if not run_id: + raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") + return self._get( + f"/evals/{eval_id}/runs/{run_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RunRetrieveResponse, + ) + + def list( + self, + eval_id: str, + *, + after: str | NotGiven = NOT_GIVEN, + limit: int | NotGiven = NOT_GIVEN, + order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + status: Literal["queued", "in_progress", "completed", "canceled", "failed"] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> SyncCursorPage[RunListResponse]: + """ + Get a list of runs for an evaluation. + + Args: + after: Identifier for the last run from the previous pagination request. + + limit: Number of runs to retrieve. + + order: Sort order for runs by timestamp. Use `asc` for ascending order or `desc` for + descending order. Defaults to `asc`. + + status: Filter runs by status. Use "queued" | "in_progress" | "failed" | "completed" | + "canceled". + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not eval_id: + raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") + return self._get_api_list( + f"/evals/{eval_id}/runs", + page=SyncCursorPage[RunListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + "status": status, + }, + run_list_params.RunListParams, + ), + ), + model=RunListResponse, + ) + + def delete( + self, + run_id: str, + *, + eval_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> RunDeleteResponse: + """ + Delete an eval run. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not eval_id: + raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") + if not run_id: + raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") + return self._delete( + f"/evals/{eval_id}/runs/{run_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RunDeleteResponse, + ) + + def cancel( + self, + run_id: str, + *, + eval_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> RunCancelResponse: + """ + Cancel an ongoing evaluation run. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not eval_id: + raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") + if not run_id: + raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") + return self._post( + f"/evals/{eval_id}/runs/{run_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RunCancelResponse, + ) + + +class AsyncRuns(AsyncAPIResource): + @cached_property + def output_items(self) -> AsyncOutputItems: + return AsyncOutputItems(self._client) + + @cached_property + def with_raw_response(self) -> AsyncRunsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncRunsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncRunsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncRunsWithStreamingResponse(self) + + async def create( + self, + eval_id: str, + *, + data_source: run_create_params.DataSource, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + name: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> RunCreateResponse: + """Create a new evaluation run. + + This is the endpoint that will kick off grading. + + Args: + data_source: Details about the run's data source. + + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + + name: The name of the run. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not eval_id: + raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") + return await self._post( + f"/evals/{eval_id}/runs", + body=await async_maybe_transform( + { + "data_source": data_source, + "metadata": metadata, + "name": name, + }, + run_create_params.RunCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RunCreateResponse, + ) + + async def retrieve( + self, + run_id: str, + *, + eval_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> RunRetrieveResponse: + """ + Get an evaluation run by ID. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not eval_id: + raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") + if not run_id: + raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") + return await self._get( + f"/evals/{eval_id}/runs/{run_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RunRetrieveResponse, + ) + + def list( + self, + eval_id: str, + *, + after: str | NotGiven = NOT_GIVEN, + limit: int | NotGiven = NOT_GIVEN, + order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + status: Literal["queued", "in_progress", "completed", "canceled", "failed"] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> AsyncPaginator[RunListResponse, AsyncCursorPage[RunListResponse]]: + """ + Get a list of runs for an evaluation. + + Args: + after: Identifier for the last run from the previous pagination request. + + limit: Number of runs to retrieve. + + order: Sort order for runs by timestamp. Use `asc` for ascending order or `desc` for + descending order. Defaults to `asc`. + + status: Filter runs by status. Use "queued" | "in_progress" | "failed" | "completed" | + "canceled". + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not eval_id: + raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") + return self._get_api_list( + f"/evals/{eval_id}/runs", + page=AsyncCursorPage[RunListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + "status": status, + }, + run_list_params.RunListParams, + ), + ), + model=RunListResponse, + ) + + async def delete( + self, + run_id: str, + *, + eval_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> RunDeleteResponse: + """ + Delete an eval run. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not eval_id: + raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") + if not run_id: + raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") + return await self._delete( + f"/evals/{eval_id}/runs/{run_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RunDeleteResponse, + ) + + async def cancel( + self, + run_id: str, + *, + eval_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> RunCancelResponse: + """ + Cancel an ongoing evaluation run. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not eval_id: + raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") + if not run_id: + raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") + return await self._post( + f"/evals/{eval_id}/runs/{run_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RunCancelResponse, + ) + + +class RunsWithRawResponse: + def __init__(self, runs: Runs) -> None: + self._runs = runs + + self.create = _legacy_response.to_raw_response_wrapper( + runs.create, + ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + runs.retrieve, + ) + self.list = _legacy_response.to_raw_response_wrapper( + runs.list, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + runs.delete, + ) + self.cancel = _legacy_response.to_raw_response_wrapper( + runs.cancel, + ) + + @cached_property + def output_items(self) -> OutputItemsWithRawResponse: + return OutputItemsWithRawResponse(self._runs.output_items) + + +class AsyncRunsWithRawResponse: + def __init__(self, runs: AsyncRuns) -> None: + self._runs = runs + + self.create = _legacy_response.async_to_raw_response_wrapper( + runs.create, + ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + runs.retrieve, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + runs.list, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + runs.delete, + ) + self.cancel = _legacy_response.async_to_raw_response_wrapper( + runs.cancel, + ) + + @cached_property + def output_items(self) -> AsyncOutputItemsWithRawResponse: + return AsyncOutputItemsWithRawResponse(self._runs.output_items) + + +class RunsWithStreamingResponse: + def __init__(self, runs: Runs) -> None: + self._runs = runs + + self.create = to_streamed_response_wrapper( + runs.create, + ) + self.retrieve = to_streamed_response_wrapper( + runs.retrieve, + ) + self.list = to_streamed_response_wrapper( + runs.list, + ) + self.delete = to_streamed_response_wrapper( + runs.delete, + ) + self.cancel = to_streamed_response_wrapper( + runs.cancel, + ) + + @cached_property + def output_items(self) -> OutputItemsWithStreamingResponse: + return OutputItemsWithStreamingResponse(self._runs.output_items) + + +class AsyncRunsWithStreamingResponse: + def __init__(self, runs: AsyncRuns) -> None: + self._runs = runs + + self.create = async_to_streamed_response_wrapper( + runs.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + runs.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + runs.list, + ) + self.delete = async_to_streamed_response_wrapper( + runs.delete, + ) + self.cancel = async_to_streamed_response_wrapper( + runs.cancel, + ) + + @cached_property + def output_items(self) -> AsyncOutputItemsWithStreamingResponse: + return AsyncOutputItemsWithStreamingResponse(self._runs.output_items) diff --git a/src/openai/resources/fine_tuning/__init__.py b/src/openai/resources/fine_tuning/__init__.py index 7765231fee..ed7db4f4e0 100644 --- a/src/openai/resources/fine_tuning/__init__.py +++ b/src/openai/resources/fine_tuning/__init__.py @@ -8,6 +8,14 @@ JobsWithStreamingResponse, AsyncJobsWithStreamingResponse, ) +from .checkpoints import ( + Checkpoints, + AsyncCheckpoints, + CheckpointsWithRawResponse, + AsyncCheckpointsWithRawResponse, + CheckpointsWithStreamingResponse, + AsyncCheckpointsWithStreamingResponse, +) from .fine_tuning import ( FineTuning, AsyncFineTuning, @@ -24,6 +32,12 @@ "AsyncJobsWithRawResponse", "JobsWithStreamingResponse", "AsyncJobsWithStreamingResponse", + "Checkpoints", + "AsyncCheckpoints", + "CheckpointsWithRawResponse", + "AsyncCheckpointsWithRawResponse", + "CheckpointsWithStreamingResponse", + "AsyncCheckpointsWithStreamingResponse", "FineTuning", "AsyncFineTuning", "FineTuningWithRawResponse", diff --git a/src/openai/resources/fine_tuning/checkpoints/__init__.py b/src/openai/resources/fine_tuning/checkpoints/__init__.py new file mode 100644 index 0000000000..fdc37940f9 --- /dev/null +++ b/src/openai/resources/fine_tuning/checkpoints/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .checkpoints import ( + Checkpoints, + AsyncCheckpoints, + CheckpointsWithRawResponse, + AsyncCheckpointsWithRawResponse, + CheckpointsWithStreamingResponse, + AsyncCheckpointsWithStreamingResponse, +) +from .permissions import ( + Permissions, + AsyncPermissions, + PermissionsWithRawResponse, + AsyncPermissionsWithRawResponse, + PermissionsWithStreamingResponse, + AsyncPermissionsWithStreamingResponse, +) + +__all__ = [ + "Permissions", + "AsyncPermissions", + "PermissionsWithRawResponse", + "AsyncPermissionsWithRawResponse", + "PermissionsWithStreamingResponse", + "AsyncPermissionsWithStreamingResponse", + "Checkpoints", + "AsyncCheckpoints", + "CheckpointsWithRawResponse", + "AsyncCheckpointsWithRawResponse", + "CheckpointsWithStreamingResponse", + "AsyncCheckpointsWithStreamingResponse", +] diff --git a/src/openai/resources/fine_tuning/checkpoints/checkpoints.py b/src/openai/resources/fine_tuning/checkpoints/checkpoints.py new file mode 100644 index 0000000000..f59976a264 --- /dev/null +++ b/src/openai/resources/fine_tuning/checkpoints/checkpoints.py @@ -0,0 +1,102 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from ...._compat import cached_property +from .permissions import ( + Permissions, + AsyncPermissions, + PermissionsWithRawResponse, + AsyncPermissionsWithRawResponse, + PermissionsWithStreamingResponse, + AsyncPermissionsWithStreamingResponse, +) +from ...._resource import SyncAPIResource, AsyncAPIResource + +__all__ = ["Checkpoints", "AsyncCheckpoints"] + + +class Checkpoints(SyncAPIResource): + @cached_property + def permissions(self) -> Permissions: + return Permissions(self._client) + + @cached_property + def with_raw_response(self) -> CheckpointsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return CheckpointsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> CheckpointsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return CheckpointsWithStreamingResponse(self) + + +class AsyncCheckpoints(AsyncAPIResource): + @cached_property + def permissions(self) -> AsyncPermissions: + return AsyncPermissions(self._client) + + @cached_property + def with_raw_response(self) -> AsyncCheckpointsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncCheckpointsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncCheckpointsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncCheckpointsWithStreamingResponse(self) + + +class CheckpointsWithRawResponse: + def __init__(self, checkpoints: Checkpoints) -> None: + self._checkpoints = checkpoints + + @cached_property + def permissions(self) -> PermissionsWithRawResponse: + return PermissionsWithRawResponse(self._checkpoints.permissions) + + +class AsyncCheckpointsWithRawResponse: + def __init__(self, checkpoints: AsyncCheckpoints) -> None: + self._checkpoints = checkpoints + + @cached_property + def permissions(self) -> AsyncPermissionsWithRawResponse: + return AsyncPermissionsWithRawResponse(self._checkpoints.permissions) + + +class CheckpointsWithStreamingResponse: + def __init__(self, checkpoints: Checkpoints) -> None: + self._checkpoints = checkpoints + + @cached_property + def permissions(self) -> PermissionsWithStreamingResponse: + return PermissionsWithStreamingResponse(self._checkpoints.permissions) + + +class AsyncCheckpointsWithStreamingResponse: + def __init__(self, checkpoints: AsyncCheckpoints) -> None: + self._checkpoints = checkpoints + + @cached_property + def permissions(self) -> AsyncPermissionsWithStreamingResponse: + return AsyncPermissionsWithStreamingResponse(self._checkpoints.permissions) diff --git a/src/openai/resources/fine_tuning/checkpoints/permissions.py b/src/openai/resources/fine_tuning/checkpoints/permissions.py new file mode 100644 index 0000000000..beb7b099d3 --- /dev/null +++ b/src/openai/resources/fine_tuning/checkpoints/permissions.py @@ -0,0 +1,416 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Literal + +import httpx + +from .... import _legacy_response +from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._utils import ( + maybe_transform, + async_maybe_transform, +) +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ....pagination import SyncPage, AsyncPage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.fine_tuning.checkpoints import permission_create_params, permission_retrieve_params +from ....types.fine_tuning.checkpoints.permission_create_response import PermissionCreateResponse +from ....types.fine_tuning.checkpoints.permission_delete_response import PermissionDeleteResponse +from ....types.fine_tuning.checkpoints.permission_retrieve_response import PermissionRetrieveResponse + +__all__ = ["Permissions", "AsyncPermissions"] + + +class Permissions(SyncAPIResource): + @cached_property + def with_raw_response(self) -> PermissionsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return PermissionsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> PermissionsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return PermissionsWithStreamingResponse(self) + + def create( + self, + fine_tuned_model_checkpoint: str, + *, + project_ids: List[str], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> SyncPage[PermissionCreateResponse]: + """ + **NOTE:** Calling this endpoint requires an [admin API key](../admin-api-keys). + + This enables organization owners to share fine-tuned models with other projects + in their organization. + + Args: + project_ids: The project identifiers to grant access to. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not fine_tuned_model_checkpoint: + raise ValueError( + f"Expected a non-empty value for `fine_tuned_model_checkpoint` but received {fine_tuned_model_checkpoint!r}" + ) + return self._get_api_list( + f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + page=SyncPage[PermissionCreateResponse], + body=maybe_transform({"project_ids": project_ids}, permission_create_params.PermissionCreateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + model=PermissionCreateResponse, + method="post", + ) + + def retrieve( + self, + fine_tuned_model_checkpoint: str, + *, + after: str | NotGiven = NOT_GIVEN, + limit: int | NotGiven = NOT_GIVEN, + order: Literal["ascending", "descending"] | NotGiven = NOT_GIVEN, + project_id: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> PermissionRetrieveResponse: + """ + **NOTE:** This endpoint requires an [admin API key](../admin-api-keys). + + Organization owners can use this endpoint to view all permissions for a + fine-tuned model checkpoint. + + Args: + after: Identifier for the last permission ID from the previous pagination request. + + limit: Number of permissions to retrieve. + + order: The order in which to retrieve permissions. + + project_id: The ID of the project to get permissions for. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not fine_tuned_model_checkpoint: + raise ValueError( + f"Expected a non-empty value for `fine_tuned_model_checkpoint` but received {fine_tuned_model_checkpoint!r}" + ) + return self._get( + f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + "project_id": project_id, + }, + permission_retrieve_params.PermissionRetrieveParams, + ), + ), + cast_to=PermissionRetrieveResponse, + ) + + def delete( + self, + fine_tuned_model_checkpoint: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> PermissionDeleteResponse: + """ + **NOTE:** This endpoint requires an [admin API key](../admin-api-keys). + + Organization owners can use this endpoint to delete a permission for a + fine-tuned model checkpoint. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not fine_tuned_model_checkpoint: + raise ValueError( + f"Expected a non-empty value for `fine_tuned_model_checkpoint` but received {fine_tuned_model_checkpoint!r}" + ) + return self._delete( + f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PermissionDeleteResponse, + ) + + +class AsyncPermissions(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncPermissionsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncPermissionsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncPermissionsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncPermissionsWithStreamingResponse(self) + + def create( + self, + fine_tuned_model_checkpoint: str, + *, + project_ids: List[str], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> AsyncPaginator[PermissionCreateResponse, AsyncPage[PermissionCreateResponse]]: + """ + **NOTE:** Calling this endpoint requires an [admin API key](../admin-api-keys). + + This enables organization owners to share fine-tuned models with other projects + in their organization. + + Args: + project_ids: The project identifiers to grant access to. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not fine_tuned_model_checkpoint: + raise ValueError( + f"Expected a non-empty value for `fine_tuned_model_checkpoint` but received {fine_tuned_model_checkpoint!r}" + ) + return self._get_api_list( + f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + page=AsyncPage[PermissionCreateResponse], + body=maybe_transform({"project_ids": project_ids}, permission_create_params.PermissionCreateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + model=PermissionCreateResponse, + method="post", + ) + + async def retrieve( + self, + fine_tuned_model_checkpoint: str, + *, + after: str | NotGiven = NOT_GIVEN, + limit: int | NotGiven = NOT_GIVEN, + order: Literal["ascending", "descending"] | NotGiven = NOT_GIVEN, + project_id: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> PermissionRetrieveResponse: + """ + **NOTE:** This endpoint requires an [admin API key](../admin-api-keys). + + Organization owners can use this endpoint to view all permissions for a + fine-tuned model checkpoint. + + Args: + after: Identifier for the last permission ID from the previous pagination request. + + limit: Number of permissions to retrieve. + + order: The order in which to retrieve permissions. + + project_id: The ID of the project to get permissions for. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not fine_tuned_model_checkpoint: + raise ValueError( + f"Expected a non-empty value for `fine_tuned_model_checkpoint` but received {fine_tuned_model_checkpoint!r}" + ) + return await self._get( + f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + "project_id": project_id, + }, + permission_retrieve_params.PermissionRetrieveParams, + ), + ), + cast_to=PermissionRetrieveResponse, + ) + + async def delete( + self, + fine_tuned_model_checkpoint: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> PermissionDeleteResponse: + """ + **NOTE:** This endpoint requires an [admin API key](../admin-api-keys). + + Organization owners can use this endpoint to delete a permission for a + fine-tuned model checkpoint. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not fine_tuned_model_checkpoint: + raise ValueError( + f"Expected a non-empty value for `fine_tuned_model_checkpoint` but received {fine_tuned_model_checkpoint!r}" + ) + return await self._delete( + f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PermissionDeleteResponse, + ) + + +class PermissionsWithRawResponse: + def __init__(self, permissions: Permissions) -> None: + self._permissions = permissions + + self.create = _legacy_response.to_raw_response_wrapper( + permissions.create, + ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + permissions.retrieve, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + permissions.delete, + ) + + +class AsyncPermissionsWithRawResponse: + def __init__(self, permissions: AsyncPermissions) -> None: + self._permissions = permissions + + self.create = _legacy_response.async_to_raw_response_wrapper( + permissions.create, + ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + permissions.retrieve, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + permissions.delete, + ) + + +class PermissionsWithStreamingResponse: + def __init__(self, permissions: Permissions) -> None: + self._permissions = permissions + + self.create = to_streamed_response_wrapper( + permissions.create, + ) + self.retrieve = to_streamed_response_wrapper( + permissions.retrieve, + ) + self.delete = to_streamed_response_wrapper( + permissions.delete, + ) + + +class AsyncPermissionsWithStreamingResponse: + def __init__(self, permissions: AsyncPermissions) -> None: + self._permissions = permissions + + self.create = async_to_streamed_response_wrapper( + permissions.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + permissions.retrieve, + ) + self.delete = async_to_streamed_response_wrapper( + permissions.delete, + ) diff --git a/src/openai/resources/fine_tuning/fine_tuning.py b/src/openai/resources/fine_tuning/fine_tuning.py index eebde07d81..1388c8230c 100644 --- a/src/openai/resources/fine_tuning/fine_tuning.py +++ b/src/openai/resources/fine_tuning/fine_tuning.py @@ -12,6 +12,14 @@ AsyncJobsWithStreamingResponse, ) from ..._resource import SyncAPIResource, AsyncAPIResource +from .checkpoints.checkpoints import ( + Checkpoints, + AsyncCheckpoints, + CheckpointsWithRawResponse, + AsyncCheckpointsWithRawResponse, + CheckpointsWithStreamingResponse, + AsyncCheckpointsWithStreamingResponse, +) __all__ = ["FineTuning", "AsyncFineTuning"] @@ -21,6 +29,10 @@ class FineTuning(SyncAPIResource): def jobs(self) -> Jobs: return Jobs(self._client) + @cached_property + def checkpoints(self) -> Checkpoints: + return Checkpoints(self._client) + @cached_property def with_raw_response(self) -> FineTuningWithRawResponse: """ @@ -46,6 +58,10 @@ class AsyncFineTuning(AsyncAPIResource): def jobs(self) -> AsyncJobs: return AsyncJobs(self._client) + @cached_property + def checkpoints(self) -> AsyncCheckpoints: + return AsyncCheckpoints(self._client) + @cached_property def with_raw_response(self) -> AsyncFineTuningWithRawResponse: """ @@ -74,6 +90,10 @@ def __init__(self, fine_tuning: FineTuning) -> None: def jobs(self) -> JobsWithRawResponse: return JobsWithRawResponse(self._fine_tuning.jobs) + @cached_property + def checkpoints(self) -> CheckpointsWithRawResponse: + return CheckpointsWithRawResponse(self._fine_tuning.checkpoints) + class AsyncFineTuningWithRawResponse: def __init__(self, fine_tuning: AsyncFineTuning) -> None: @@ -83,6 +103,10 @@ def __init__(self, fine_tuning: AsyncFineTuning) -> None: def jobs(self) -> AsyncJobsWithRawResponse: return AsyncJobsWithRawResponse(self._fine_tuning.jobs) + @cached_property + def checkpoints(self) -> AsyncCheckpointsWithRawResponse: + return AsyncCheckpointsWithRawResponse(self._fine_tuning.checkpoints) + class FineTuningWithStreamingResponse: def __init__(self, fine_tuning: FineTuning) -> None: @@ -92,6 +116,10 @@ def __init__(self, fine_tuning: FineTuning) -> None: def jobs(self) -> JobsWithStreamingResponse: return JobsWithStreamingResponse(self._fine_tuning.jobs) + @cached_property + def checkpoints(self) -> CheckpointsWithStreamingResponse: + return CheckpointsWithStreamingResponse(self._fine_tuning.checkpoints) + class AsyncFineTuningWithStreamingResponse: def __init__(self, fine_tuning: AsyncFineTuning) -> None: @@ -100,3 +128,7 @@ def __init__(self, fine_tuning: AsyncFineTuning) -> None: @cached_property def jobs(self) -> AsyncJobsWithStreamingResponse: return AsyncJobsWithStreamingResponse(self._fine_tuning.jobs) + + @cached_property + def checkpoints(self) -> AsyncCheckpointsWithStreamingResponse: + return AsyncCheckpointsWithStreamingResponse(self._fine_tuning.checkpoints) diff --git a/src/openai/types/__init__.py b/src/openai/types/__init__.py index 11761534c9..57c91811b9 100644 --- a/src/openai/types/__init__.py +++ b/src/openai/types/__init__.py @@ -38,22 +38,32 @@ from .embedding_model import EmbeddingModel as EmbeddingModel from .images_response import ImagesResponse as ImagesResponse from .completion_usage import CompletionUsage as CompletionUsage +from .eval_list_params import EvalListParams as EvalListParams from .file_list_params import FileListParams as FileListParams from .moderation_model import ModerationModel as ModerationModel from .batch_list_params import BatchListParams as BatchListParams from .completion_choice import CompletionChoice as CompletionChoice from .image_edit_params import ImageEditParams as ImageEditParams +from .eval_create_params import EvalCreateParams as EvalCreateParams +from .eval_list_response import EvalListResponse as EvalListResponse +from .eval_update_params import EvalUpdateParams as EvalUpdateParams from .file_create_params import FileCreateParams as FileCreateParams from .batch_create_params import BatchCreateParams as BatchCreateParams from .batch_request_counts import BatchRequestCounts as BatchRequestCounts +from .eval_create_response import EvalCreateResponse as EvalCreateResponse +from .eval_delete_response import EvalDeleteResponse as EvalDeleteResponse +from .eval_update_response import EvalUpdateResponse as EvalUpdateResponse from .upload_create_params import UploadCreateParams as UploadCreateParams from .vector_store_deleted import VectorStoreDeleted as VectorStoreDeleted from .audio_response_format import AudioResponseFormat as AudioResponseFormat from .image_generate_params import ImageGenerateParams as ImageGenerateParams +from .eval_retrieve_response import EvalRetrieveResponse as EvalRetrieveResponse from .file_chunking_strategy import FileChunkingStrategy as FileChunkingStrategy from .upload_complete_params import UploadCompleteParams as UploadCompleteParams from .embedding_create_params import EmbeddingCreateParams as EmbeddingCreateParams +from .eval_label_model_grader import EvalLabelModelGrader as EvalLabelModelGrader from .completion_create_params import CompletionCreateParams as CompletionCreateParams +from .eval_string_check_grader import EvalStringCheckGrader as EvalStringCheckGrader from .moderation_create_params import ModerationCreateParams as ModerationCreateParams from .vector_store_list_params import VectorStoreListParams as VectorStoreListParams from .create_embedding_response import CreateEmbeddingResponse as CreateEmbeddingResponse @@ -61,18 +71,25 @@ from .vector_store_create_params import VectorStoreCreateParams as VectorStoreCreateParams from .vector_store_search_params import VectorStoreSearchParams as VectorStoreSearchParams from .vector_store_update_params import VectorStoreUpdateParams as VectorStoreUpdateParams +from .eval_text_similarity_grader import EvalTextSimilarityGrader as EvalTextSimilarityGrader from .moderation_text_input_param import ModerationTextInputParam as ModerationTextInputParam from .file_chunking_strategy_param import FileChunkingStrategyParam as FileChunkingStrategyParam from .vector_store_search_response import VectorStoreSearchResponse as VectorStoreSearchResponse from .websocket_connection_options import WebsocketConnectionOptions as WebsocketConnectionOptions from .image_create_variation_params import ImageCreateVariationParams as ImageCreateVariationParams from .static_file_chunking_strategy import StaticFileChunkingStrategy as StaticFileChunkingStrategy +from .eval_custom_data_source_config import EvalCustomDataSourceConfig as EvalCustomDataSourceConfig +from .eval_string_check_grader_param import EvalStringCheckGraderParam as EvalStringCheckGraderParam from .moderation_image_url_input_param import ModerationImageURLInputParam as ModerationImageURLInputParam from .auto_file_chunking_strategy_param import AutoFileChunkingStrategyParam as AutoFileChunkingStrategyParam +from .eval_text_similarity_grader_param import EvalTextSimilarityGraderParam as EvalTextSimilarityGraderParam from .moderation_multi_modal_input_param import ModerationMultiModalInputParam as ModerationMultiModalInputParam from .other_file_chunking_strategy_object import OtherFileChunkingStrategyObject as OtherFileChunkingStrategyObject from .static_file_chunking_strategy_param import StaticFileChunkingStrategyParam as StaticFileChunkingStrategyParam from .static_file_chunking_strategy_object import StaticFileChunkingStrategyObject as StaticFileChunkingStrategyObject +from .eval_stored_completions_data_source_config import ( + EvalStoredCompletionsDataSourceConfig as EvalStoredCompletionsDataSourceConfig, +) from .static_file_chunking_strategy_object_param import ( StaticFileChunkingStrategyObjectParam as StaticFileChunkingStrategyObjectParam, ) diff --git a/src/openai/types/eval_create_params.py b/src/openai/types/eval_create_params.py new file mode 100644 index 0000000000..8b28e51a6b --- /dev/null +++ b/src/openai/types/eval_create_params.py @@ -0,0 +1,153 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, List, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .shared_params.metadata import Metadata +from .eval_string_check_grader_param import EvalStringCheckGraderParam +from .eval_text_similarity_grader_param import EvalTextSimilarityGraderParam + +__all__ = [ + "EvalCreateParams", + "DataSourceConfig", + "DataSourceConfigCustom", + "DataSourceConfigStoredCompletions", + "TestingCriterion", + "TestingCriterionLabelModel", + "TestingCriterionLabelModelInput", + "TestingCriterionLabelModelInputSimpleInputMessage", + "TestingCriterionLabelModelInputInputMessage", + "TestingCriterionLabelModelInputInputMessageContent", + "TestingCriterionLabelModelInputOutputMessage", + "TestingCriterionLabelModelInputOutputMessageContent", +] + + +class EvalCreateParams(TypedDict, total=False): + data_source_config: Required[DataSourceConfig] + """The configuration for the data source used for the evaluation runs.""" + + testing_criteria: Required[Iterable[TestingCriterion]] + """A list of graders for all eval runs in this group.""" + + metadata: Optional[Metadata] + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + """ + + name: str + """The name of the evaluation.""" + + share_with_openai: bool + """Indicates whether the evaluation is shared with OpenAI.""" + + +class DataSourceConfigCustom(TypedDict, total=False): + item_schema: Required[Dict[str, object]] + """The json schema for the run data source items.""" + + type: Required[Literal["custom"]] + """The type of data source. Always `custom`.""" + + include_sample_schema: bool + """Whether to include the sample schema in the data source.""" + + +class DataSourceConfigStoredCompletions(TypedDict, total=False): + type: Required[Literal["stored_completions"]] + """The type of data source. Always `stored_completions`.""" + + metadata: Optional[Metadata] + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + """ + + +DataSourceConfig: TypeAlias = Union[DataSourceConfigCustom, DataSourceConfigStoredCompletions] + + +class TestingCriterionLabelModelInputSimpleInputMessage(TypedDict, total=False): + content: Required[str] + """The content of the message.""" + + role: Required[str] + """The role of the message (e.g. "system", "assistant", "user").""" + + +class TestingCriterionLabelModelInputInputMessageContent(TypedDict, total=False): + text: Required[str] + """The text content.""" + + type: Required[Literal["input_text"]] + """The type of content, which is always `input_text`.""" + + +class TestingCriterionLabelModelInputInputMessage(TypedDict, total=False): + content: Required[TestingCriterionLabelModelInputInputMessageContent] + + role: Required[Literal["user", "system", "developer"]] + """The role of the message. One of `user`, `system`, or `developer`.""" + + type: Required[Literal["message"]] + """The type of item, which is always `message`.""" + + +class TestingCriterionLabelModelInputOutputMessageContent(TypedDict, total=False): + text: Required[str] + """The text content.""" + + type: Required[Literal["output_text"]] + """The type of content, which is always `output_text`.""" + + +class TestingCriterionLabelModelInputOutputMessage(TypedDict, total=False): + content: Required[TestingCriterionLabelModelInputOutputMessageContent] + + role: Required[Literal["assistant"]] + """The role of the message. Must be `assistant` for output.""" + + type: Required[Literal["message"]] + """The type of item, which is always `message`.""" + + +TestingCriterionLabelModelInput: TypeAlias = Union[ + TestingCriterionLabelModelInputSimpleInputMessage, + TestingCriterionLabelModelInputInputMessage, + TestingCriterionLabelModelInputOutputMessage, +] + + +class TestingCriterionLabelModel(TypedDict, total=False): + input: Required[Iterable[TestingCriterionLabelModelInput]] + + labels: Required[List[str]] + """The labels to classify to each item in the evaluation.""" + + model: Required[str] + """The model to use for the evaluation. Must support structured outputs.""" + + name: Required[str] + """The name of the grader.""" + + passing_labels: Required[List[str]] + """The labels that indicate a passing result. Must be a subset of labels.""" + + type: Required[Literal["label_model"]] + """The object type, which is always `label_model`.""" + + +TestingCriterion: TypeAlias = Union[ + TestingCriterionLabelModel, EvalStringCheckGraderParam, EvalTextSimilarityGraderParam +] diff --git a/src/openai/types/eval_create_response.py b/src/openai/types/eval_create_response.py new file mode 100644 index 0000000000..a1c2853a2a --- /dev/null +++ b/src/openai/types/eval_create_response.py @@ -0,0 +1,56 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from .._utils import PropertyInfo +from .._models import BaseModel +from .shared.metadata import Metadata +from .eval_label_model_grader import EvalLabelModelGrader +from .eval_string_check_grader import EvalStringCheckGrader +from .eval_text_similarity_grader import EvalTextSimilarityGrader +from .eval_custom_data_source_config import EvalCustomDataSourceConfig +from .eval_stored_completions_data_source_config import EvalStoredCompletionsDataSourceConfig + +__all__ = ["EvalCreateResponse", "DataSourceConfig", "TestingCriterion"] + +DataSourceConfig: TypeAlias = Annotated[ + Union[EvalCustomDataSourceConfig, EvalStoredCompletionsDataSourceConfig], PropertyInfo(discriminator="type") +] + +TestingCriterion: TypeAlias = Annotated[ + Union[EvalLabelModelGrader, EvalStringCheckGrader, EvalTextSimilarityGrader], PropertyInfo(discriminator="type") +] + + +class EvalCreateResponse(BaseModel): + id: str + """Unique identifier for the evaluation.""" + + created_at: int + """The Unix timestamp (in seconds) for when the eval was created.""" + + data_source_config: DataSourceConfig + """Configuration of data sources used in runs of the evaluation.""" + + metadata: Optional[Metadata] = None + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + """ + + name: str + """The name of the evaluation.""" + + object: Literal["eval"] + """The object type.""" + + share_with_openai: bool + """Indicates whether the evaluation is shared with OpenAI.""" + + testing_criteria: List[TestingCriterion] + """A list of testing criteria.""" diff --git a/src/openai/types/eval_custom_data_source_config.py b/src/openai/types/eval_custom_data_source_config.py new file mode 100644 index 0000000000..d99701cc71 --- /dev/null +++ b/src/openai/types/eval_custom_data_source_config.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["EvalCustomDataSourceConfig"] + + +class EvalCustomDataSourceConfig(BaseModel): + schema_: Dict[str, object] = FieldInfo(alias="schema") + """ + The json schema for the run data source items. Learn how to build JSON schemas + [here](https://json-schema.org/). + """ + + type: Literal["custom"] + """The type of data source. Always `custom`.""" diff --git a/src/openai/types/eval_delete_response.py b/src/openai/types/eval_delete_response.py new file mode 100644 index 0000000000..adb460ddbb --- /dev/null +++ b/src/openai/types/eval_delete_response.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + + +from .._models import BaseModel + +__all__ = ["EvalDeleteResponse"] + + +class EvalDeleteResponse(BaseModel): + deleted: bool + + eval_id: str + + object: str diff --git a/src/openai/types/eval_label_model_grader.py b/src/openai/types/eval_label_model_grader.py new file mode 100644 index 0000000000..826b116287 --- /dev/null +++ b/src/openai/types/eval_label_model_grader.py @@ -0,0 +1,74 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union +from typing_extensions import Literal, Annotated, TypeAlias + +from .._utils import PropertyInfo +from .._models import BaseModel + +__all__ = [ + "EvalLabelModelGrader", + "Input", + "InputInputMessage", + "InputInputMessageContent", + "InputAssistant", + "InputAssistantContent", +] + + +class InputInputMessageContent(BaseModel): + text: str + """The text content.""" + + type: Literal["input_text"] + """The type of content, which is always `input_text`.""" + + +class InputInputMessage(BaseModel): + content: InputInputMessageContent + + role: Literal["user", "system", "developer"] + """The role of the message. One of `user`, `system`, or `developer`.""" + + type: Literal["message"] + """The type of item, which is always `message`.""" + + +class InputAssistantContent(BaseModel): + text: str + """The text content.""" + + type: Literal["output_text"] + """The type of content, which is always `output_text`.""" + + +class InputAssistant(BaseModel): + content: InputAssistantContent + + role: Literal["assistant"] + """The role of the message. Must be `assistant` for output.""" + + type: Literal["message"] + """The type of item, which is always `message`.""" + + +Input: TypeAlias = Annotated[Union[InputInputMessage, InputAssistant], PropertyInfo(discriminator="role")] + + +class EvalLabelModelGrader(BaseModel): + input: List[Input] + + labels: List[str] + """The labels to assign to each item in the evaluation.""" + + model: str + """The model to use for the evaluation. Must support structured outputs.""" + + name: str + """The name of the grader.""" + + passing_labels: List[str] + """The labels that indicate a passing result. Must be a subset of labels.""" + + type: Literal["label_model"] + """The object type, which is always `label_model`.""" diff --git a/src/openai/types/eval_list_params.py b/src/openai/types/eval_list_params.py new file mode 100644 index 0000000000..d9a12d0ddf --- /dev/null +++ b/src/openai/types/eval_list_params.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["EvalListParams"] + + +class EvalListParams(TypedDict, total=False): + after: str + """Identifier for the last eval from the previous pagination request.""" + + limit: int + """Number of evals to retrieve.""" + + order: Literal["asc", "desc"] + """Sort order for evals by timestamp. + + Use `asc` for ascending order or `desc` for descending order. + """ + + order_by: Literal["created_at", "updated_at"] + """Evals can be ordered by creation time or last updated time. + + Use `created_at` for creation time or `updated_at` for last updated time. + """ diff --git a/src/openai/types/eval_list_response.py b/src/openai/types/eval_list_response.py new file mode 100644 index 0000000000..eb54569011 --- /dev/null +++ b/src/openai/types/eval_list_response.py @@ -0,0 +1,56 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from .._utils import PropertyInfo +from .._models import BaseModel +from .shared.metadata import Metadata +from .eval_label_model_grader import EvalLabelModelGrader +from .eval_string_check_grader import EvalStringCheckGrader +from .eval_text_similarity_grader import EvalTextSimilarityGrader +from .eval_custom_data_source_config import EvalCustomDataSourceConfig +from .eval_stored_completions_data_source_config import EvalStoredCompletionsDataSourceConfig + +__all__ = ["EvalListResponse", "DataSourceConfig", "TestingCriterion"] + +DataSourceConfig: TypeAlias = Annotated[ + Union[EvalCustomDataSourceConfig, EvalStoredCompletionsDataSourceConfig], PropertyInfo(discriminator="type") +] + +TestingCriterion: TypeAlias = Annotated[ + Union[EvalLabelModelGrader, EvalStringCheckGrader, EvalTextSimilarityGrader], PropertyInfo(discriminator="type") +] + + +class EvalListResponse(BaseModel): + id: str + """Unique identifier for the evaluation.""" + + created_at: int + """The Unix timestamp (in seconds) for when the eval was created.""" + + data_source_config: DataSourceConfig + """Configuration of data sources used in runs of the evaluation.""" + + metadata: Optional[Metadata] = None + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + """ + + name: str + """The name of the evaluation.""" + + object: Literal["eval"] + """The object type.""" + + share_with_openai: bool + """Indicates whether the evaluation is shared with OpenAI.""" + + testing_criteria: List[TestingCriterion] + """A list of testing criteria.""" diff --git a/src/openai/types/eval_retrieve_response.py b/src/openai/types/eval_retrieve_response.py new file mode 100644 index 0000000000..8f3bfdf902 --- /dev/null +++ b/src/openai/types/eval_retrieve_response.py @@ -0,0 +1,56 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from .._utils import PropertyInfo +from .._models import BaseModel +from .shared.metadata import Metadata +from .eval_label_model_grader import EvalLabelModelGrader +from .eval_string_check_grader import EvalStringCheckGrader +from .eval_text_similarity_grader import EvalTextSimilarityGrader +from .eval_custom_data_source_config import EvalCustomDataSourceConfig +from .eval_stored_completions_data_source_config import EvalStoredCompletionsDataSourceConfig + +__all__ = ["EvalRetrieveResponse", "DataSourceConfig", "TestingCriterion"] + +DataSourceConfig: TypeAlias = Annotated[ + Union[EvalCustomDataSourceConfig, EvalStoredCompletionsDataSourceConfig], PropertyInfo(discriminator="type") +] + +TestingCriterion: TypeAlias = Annotated[ + Union[EvalLabelModelGrader, EvalStringCheckGrader, EvalTextSimilarityGrader], PropertyInfo(discriminator="type") +] + + +class EvalRetrieveResponse(BaseModel): + id: str + """Unique identifier for the evaluation.""" + + created_at: int + """The Unix timestamp (in seconds) for when the eval was created.""" + + data_source_config: DataSourceConfig + """Configuration of data sources used in runs of the evaluation.""" + + metadata: Optional[Metadata] = None + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + """ + + name: str + """The name of the evaluation.""" + + object: Literal["eval"] + """The object type.""" + + share_with_openai: bool + """Indicates whether the evaluation is shared with OpenAI.""" + + testing_criteria: List[TestingCriterion] + """A list of testing criteria.""" diff --git a/src/openai/types/eval_stored_completions_data_source_config.py b/src/openai/types/eval_stored_completions_data_source_config.py new file mode 100644 index 0000000000..98f86a4719 --- /dev/null +++ b/src/openai/types/eval_stored_completions_data_source_config.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from .._models import BaseModel +from .shared.metadata import Metadata + +__all__ = ["EvalStoredCompletionsDataSourceConfig"] + + +class EvalStoredCompletionsDataSourceConfig(BaseModel): + schema_: Dict[str, object] = FieldInfo(alias="schema") + """ + The json schema for the run data source items. Learn how to build JSON schemas + [here](https://json-schema.org/). + """ + + type: Literal["stored_completions"] + """The type of data source. Always `stored_completions`.""" + + metadata: Optional[Metadata] = None + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + """ diff --git a/src/openai/types/eval_string_check_grader.py b/src/openai/types/eval_string_check_grader.py new file mode 100644 index 0000000000..4dfc8035f9 --- /dev/null +++ b/src/openai/types/eval_string_check_grader.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["EvalStringCheckGrader"] + + +class EvalStringCheckGrader(BaseModel): + input: str + """The input text. This may include template strings.""" + + name: str + """The name of the grader.""" + + operation: Literal["eq", "ne", "like", "ilike"] + """The string check operation to perform. One of `eq`, `ne`, `like`, or `ilike`.""" + + reference: str + """The reference text. This may include template strings.""" + + type: Literal["string_check"] + """The object type, which is always `string_check`.""" diff --git a/src/openai/types/eval_string_check_grader_param.py b/src/openai/types/eval_string_check_grader_param.py new file mode 100644 index 0000000000..3511329f8b --- /dev/null +++ b/src/openai/types/eval_string_check_grader_param.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["EvalStringCheckGraderParam"] + + +class EvalStringCheckGraderParam(TypedDict, total=False): + input: Required[str] + """The input text. This may include template strings.""" + + name: Required[str] + """The name of the grader.""" + + operation: Required[Literal["eq", "ne", "like", "ilike"]] + """The string check operation to perform. One of `eq`, `ne`, `like`, or `ilike`.""" + + reference: Required[str] + """The reference text. This may include template strings.""" + + type: Required[Literal["string_check"]] + """The object type, which is always `string_check`.""" diff --git a/src/openai/types/eval_text_similarity_grader.py b/src/openai/types/eval_text_similarity_grader.py new file mode 100644 index 0000000000..7c6897a4a7 --- /dev/null +++ b/src/openai/types/eval_text_similarity_grader.py @@ -0,0 +1,44 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["EvalTextSimilarityGrader"] + + +class EvalTextSimilarityGrader(BaseModel): + evaluation_metric: Literal[ + "fuzzy_match", + "bleu", + "gleu", + "meteor", + "rouge_1", + "rouge_2", + "rouge_3", + "rouge_4", + "rouge_5", + "rouge_l", + "cosine", + ] + """The evaluation metric to use. + + One of `cosine`, `fuzzy_match`, `bleu`, `gleu`, `meteor`, `rouge_1`, `rouge_2`, + `rouge_3`, `rouge_4`, `rouge_5`, or `rouge_l`. + """ + + input: str + """The text being graded.""" + + pass_threshold: float + """A float score where a value greater than or equal indicates a passing grade.""" + + reference: str + """The text being graded against.""" + + type: Literal["text_similarity"] + """The type of grader.""" + + name: Optional[str] = None + """The name of the grader.""" diff --git a/src/openai/types/eval_text_similarity_grader_param.py b/src/openai/types/eval_text_similarity_grader_param.py new file mode 100644 index 0000000000..4bf5d586f3 --- /dev/null +++ b/src/openai/types/eval_text_similarity_grader_param.py @@ -0,0 +1,45 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["EvalTextSimilarityGraderParam"] + + +class EvalTextSimilarityGraderParam(TypedDict, total=False): + evaluation_metric: Required[ + Literal[ + "fuzzy_match", + "bleu", + "gleu", + "meteor", + "rouge_1", + "rouge_2", + "rouge_3", + "rouge_4", + "rouge_5", + "rouge_l", + "cosine", + ] + ] + """The evaluation metric to use. + + One of `cosine`, `fuzzy_match`, `bleu`, `gleu`, `meteor`, `rouge_1`, `rouge_2`, + `rouge_3`, `rouge_4`, `rouge_5`, or `rouge_l`. + """ + + input: Required[str] + """The text being graded.""" + + pass_threshold: Required[float] + """A float score where a value greater than or equal indicates a passing grade.""" + + reference: Required[str] + """The text being graded against.""" + + type: Required[Literal["text_similarity"]] + """The type of grader.""" + + name: str + """The name of the grader.""" diff --git a/src/openai/types/eval_update_params.py b/src/openai/types/eval_update_params.py new file mode 100644 index 0000000000..042db29af5 --- /dev/null +++ b/src/openai/types/eval_update_params.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import TypedDict + +from .shared_params.metadata import Metadata + +__all__ = ["EvalUpdateParams"] + + +class EvalUpdateParams(TypedDict, total=False): + metadata: Optional[Metadata] + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + """ + + name: str + """Rename the evaluation.""" diff --git a/src/openai/types/eval_update_response.py b/src/openai/types/eval_update_response.py new file mode 100644 index 0000000000..728a291736 --- /dev/null +++ b/src/openai/types/eval_update_response.py @@ -0,0 +1,56 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from .._utils import PropertyInfo +from .._models import BaseModel +from .shared.metadata import Metadata +from .eval_label_model_grader import EvalLabelModelGrader +from .eval_string_check_grader import EvalStringCheckGrader +from .eval_text_similarity_grader import EvalTextSimilarityGrader +from .eval_custom_data_source_config import EvalCustomDataSourceConfig +from .eval_stored_completions_data_source_config import EvalStoredCompletionsDataSourceConfig + +__all__ = ["EvalUpdateResponse", "DataSourceConfig", "TestingCriterion"] + +DataSourceConfig: TypeAlias = Annotated[ + Union[EvalCustomDataSourceConfig, EvalStoredCompletionsDataSourceConfig], PropertyInfo(discriminator="type") +] + +TestingCriterion: TypeAlias = Annotated[ + Union[EvalLabelModelGrader, EvalStringCheckGrader, EvalTextSimilarityGrader], PropertyInfo(discriminator="type") +] + + +class EvalUpdateResponse(BaseModel): + id: str + """Unique identifier for the evaluation.""" + + created_at: int + """The Unix timestamp (in seconds) for when the eval was created.""" + + data_source_config: DataSourceConfig + """Configuration of data sources used in runs of the evaluation.""" + + metadata: Optional[Metadata] = None + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + """ + + name: str + """The name of the evaluation.""" + + object: Literal["eval"] + """The object type.""" + + share_with_openai: bool + """Indicates whether the evaluation is shared with OpenAI.""" + + testing_criteria: List[TestingCriterion] + """A list of testing criteria.""" diff --git a/src/openai/types/evals/__init__.py b/src/openai/types/evals/__init__.py new file mode 100644 index 0000000000..ebf84c6b8d --- /dev/null +++ b/src/openai/types/evals/__init__.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .eval_api_error import EvalAPIError as EvalAPIError +from .run_list_params import RunListParams as RunListParams +from .run_create_params import RunCreateParams as RunCreateParams +from .run_list_response import RunListResponse as RunListResponse +from .run_cancel_response import RunCancelResponse as RunCancelResponse +from .run_create_response import RunCreateResponse as RunCreateResponse +from .run_delete_response import RunDeleteResponse as RunDeleteResponse +from .run_retrieve_response import RunRetrieveResponse as RunRetrieveResponse +from .create_eval_jsonl_run_data_source import CreateEvalJSONLRunDataSource as CreateEvalJSONLRunDataSource +from .create_eval_completions_run_data_source import ( + CreateEvalCompletionsRunDataSource as CreateEvalCompletionsRunDataSource, +) +from .create_eval_jsonl_run_data_source_param import ( + CreateEvalJSONLRunDataSourceParam as CreateEvalJSONLRunDataSourceParam, +) +from .create_eval_completions_run_data_source_param import ( + CreateEvalCompletionsRunDataSourceParam as CreateEvalCompletionsRunDataSourceParam, +) diff --git a/src/openai/types/evals/create_eval_completions_run_data_source.py b/src/openai/types/evals/create_eval_completions_run_data_source.py new file mode 100644 index 0000000000..07b88129e2 --- /dev/null +++ b/src/openai/types/evals/create_eval_completions_run_data_source.py @@ -0,0 +1,185 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from ..shared.metadata import Metadata + +__all__ = [ + "CreateEvalCompletionsRunDataSource", + "InputMessages", + "InputMessagesTemplate", + "InputMessagesTemplateTemplate", + "InputMessagesTemplateTemplateChatMessage", + "InputMessagesTemplateTemplateInputMessage", + "InputMessagesTemplateTemplateInputMessageContent", + "InputMessagesTemplateTemplateOutputMessage", + "InputMessagesTemplateTemplateOutputMessageContent", + "InputMessagesItemReference", + "Source", + "SourceFileContent", + "SourceFileContentContent", + "SourceFileID", + "SourceStoredCompletions", + "SamplingParams", +] + + +class InputMessagesTemplateTemplateChatMessage(BaseModel): + content: str + """The content of the message.""" + + role: str + """The role of the message (e.g. "system", "assistant", "user").""" + + +class InputMessagesTemplateTemplateInputMessageContent(BaseModel): + text: str + """The text content.""" + + type: Literal["input_text"] + """The type of content, which is always `input_text`.""" + + +class InputMessagesTemplateTemplateInputMessage(BaseModel): + content: InputMessagesTemplateTemplateInputMessageContent + + role: Literal["user", "system", "developer"] + """The role of the message. One of `user`, `system`, or `developer`.""" + + type: Literal["message"] + """The type of item, which is always `message`.""" + + +class InputMessagesTemplateTemplateOutputMessageContent(BaseModel): + text: str + """The text content.""" + + type: Literal["output_text"] + """The type of content, which is always `output_text`.""" + + +class InputMessagesTemplateTemplateOutputMessage(BaseModel): + content: InputMessagesTemplateTemplateOutputMessageContent + + role: Literal["assistant"] + """The role of the message. Must be `assistant` for output.""" + + type: Literal["message"] + """The type of item, which is always `message`.""" + + +InputMessagesTemplateTemplate: TypeAlias = Union[ + InputMessagesTemplateTemplateChatMessage, + InputMessagesTemplateTemplateInputMessage, + InputMessagesTemplateTemplateOutputMessage, +] + + +class InputMessagesTemplate(BaseModel): + template: List[InputMessagesTemplateTemplate] + """A list of chat messages forming the prompt or context. + + May include variable references to the "item" namespace, ie {{item.name}}. + """ + + type: Literal["template"] + """The type of input messages. Always `template`.""" + + +class InputMessagesItemReference(BaseModel): + item_reference: str + """A reference to a variable in the "item" namespace. Ie, "item.name" """ + + type: Literal["item_reference"] + """The type of input messages. Always `item_reference`.""" + + +InputMessages: TypeAlias = Annotated[ + Union[InputMessagesTemplate, InputMessagesItemReference], PropertyInfo(discriminator="type") +] + + +class SourceFileContentContent(BaseModel): + item: Dict[str, object] + + sample: Optional[Dict[str, object]] = None + + +class SourceFileContent(BaseModel): + content: List[SourceFileContentContent] + """The content of the jsonl file.""" + + type: Literal["file_content"] + """The type of jsonl source. Always `file_content`.""" + + +class SourceFileID(BaseModel): + id: str + """The identifier of the file.""" + + type: Literal["file_id"] + """The type of jsonl source. Always `file_id`.""" + + +class SourceStoredCompletions(BaseModel): + created_after: Optional[int] = None + """An optional Unix timestamp to filter items created after this time.""" + + created_before: Optional[int] = None + """An optional Unix timestamp to filter items created before this time.""" + + limit: Optional[int] = None + """An optional maximum number of items to return.""" + + metadata: Optional[Metadata] = None + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + """ + + model: Optional[str] = None + """An optional model to filter by (e.g., 'gpt-4o').""" + + type: Literal["stored_completions"] + """The type of source. Always `stored_completions`.""" + + +Source: TypeAlias = Annotated[ + Union[SourceFileContent, SourceFileID, SourceStoredCompletions], PropertyInfo(discriminator="type") +] + + +class SamplingParams(BaseModel): + max_completion_tokens: Optional[int] = None + """The maximum number of tokens in the generated output.""" + + seed: Optional[int] = None + """A seed value to initialize the randomness, during sampling.""" + + temperature: Optional[float] = None + """A higher temperature increases randomness in the outputs.""" + + top_p: Optional[float] = None + """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" + + +class CreateEvalCompletionsRunDataSource(BaseModel): + input_messages: InputMessages + + model: str + """The name of the model to use for generating completions (e.g. "o3-mini").""" + + source: Source + """A StoredCompletionsRunDataSource configuration describing a set of filters""" + + type: Literal["completions"] + """The type of run data source. Always `completions`.""" + + sampling_params: Optional[SamplingParams] = None diff --git a/src/openai/types/evals/create_eval_completions_run_data_source_param.py b/src/openai/types/evals/create_eval_completions_run_data_source_param.py new file mode 100644 index 0000000000..be4a6f1ec6 --- /dev/null +++ b/src/openai/types/evals/create_eval_completions_run_data_source_param.py @@ -0,0 +1,181 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from ..shared_params.metadata import Metadata + +__all__ = [ + "CreateEvalCompletionsRunDataSourceParam", + "InputMessages", + "InputMessagesTemplate", + "InputMessagesTemplateTemplate", + "InputMessagesTemplateTemplateChatMessage", + "InputMessagesTemplateTemplateInputMessage", + "InputMessagesTemplateTemplateInputMessageContent", + "InputMessagesTemplateTemplateOutputMessage", + "InputMessagesTemplateTemplateOutputMessageContent", + "InputMessagesItemReference", + "Source", + "SourceFileContent", + "SourceFileContentContent", + "SourceFileID", + "SourceStoredCompletions", + "SamplingParams", +] + + +class InputMessagesTemplateTemplateChatMessage(TypedDict, total=False): + content: Required[str] + """The content of the message.""" + + role: Required[str] + """The role of the message (e.g. "system", "assistant", "user").""" + + +class InputMessagesTemplateTemplateInputMessageContent(TypedDict, total=False): + text: Required[str] + """The text content.""" + + type: Required[Literal["input_text"]] + """The type of content, which is always `input_text`.""" + + +class InputMessagesTemplateTemplateInputMessage(TypedDict, total=False): + content: Required[InputMessagesTemplateTemplateInputMessageContent] + + role: Required[Literal["user", "system", "developer"]] + """The role of the message. One of `user`, `system`, or `developer`.""" + + type: Required[Literal["message"]] + """The type of item, which is always `message`.""" + + +class InputMessagesTemplateTemplateOutputMessageContent(TypedDict, total=False): + text: Required[str] + """The text content.""" + + type: Required[Literal["output_text"]] + """The type of content, which is always `output_text`.""" + + +class InputMessagesTemplateTemplateOutputMessage(TypedDict, total=False): + content: Required[InputMessagesTemplateTemplateOutputMessageContent] + + role: Required[Literal["assistant"]] + """The role of the message. Must be `assistant` for output.""" + + type: Required[Literal["message"]] + """The type of item, which is always `message`.""" + + +InputMessagesTemplateTemplate: TypeAlias = Union[ + InputMessagesTemplateTemplateChatMessage, + InputMessagesTemplateTemplateInputMessage, + InputMessagesTemplateTemplateOutputMessage, +] + + +class InputMessagesTemplate(TypedDict, total=False): + template: Required[Iterable[InputMessagesTemplateTemplate]] + """A list of chat messages forming the prompt or context. + + May include variable references to the "item" namespace, ie {{item.name}}. + """ + + type: Required[Literal["template"]] + """The type of input messages. Always `template`.""" + + +class InputMessagesItemReference(TypedDict, total=False): + item_reference: Required[str] + """A reference to a variable in the "item" namespace. Ie, "item.name" """ + + type: Required[Literal["item_reference"]] + """The type of input messages. Always `item_reference`.""" + + +InputMessages: TypeAlias = Union[InputMessagesTemplate, InputMessagesItemReference] + + +class SourceFileContentContent(TypedDict, total=False): + item: Required[Dict[str, object]] + + sample: Dict[str, object] + + +class SourceFileContent(TypedDict, total=False): + content: Required[Iterable[SourceFileContentContent]] + """The content of the jsonl file.""" + + type: Required[Literal["file_content"]] + """The type of jsonl source. Always `file_content`.""" + + +class SourceFileID(TypedDict, total=False): + id: Required[str] + """The identifier of the file.""" + + type: Required[Literal["file_id"]] + """The type of jsonl source. Always `file_id`.""" + + +class SourceStoredCompletions(TypedDict, total=False): + created_after: Required[Optional[int]] + """An optional Unix timestamp to filter items created after this time.""" + + created_before: Required[Optional[int]] + """An optional Unix timestamp to filter items created before this time.""" + + limit: Required[Optional[int]] + """An optional maximum number of items to return.""" + + metadata: Required[Optional[Metadata]] + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + """ + + model: Required[Optional[str]] + """An optional model to filter by (e.g., 'gpt-4o').""" + + type: Required[Literal["stored_completions"]] + """The type of source. Always `stored_completions`.""" + + +Source: TypeAlias = Union[SourceFileContent, SourceFileID, SourceStoredCompletions] + + +class SamplingParams(TypedDict, total=False): + max_completion_tokens: int + """The maximum number of tokens in the generated output.""" + + seed: int + """A seed value to initialize the randomness, during sampling.""" + + temperature: float + """A higher temperature increases randomness in the outputs.""" + + top_p: float + """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" + + +class CreateEvalCompletionsRunDataSourceParam(TypedDict, total=False): + input_messages: Required[InputMessages] + + model: Required[str] + """The name of the model to use for generating completions (e.g. "o3-mini").""" + + source: Required[Source] + """A StoredCompletionsRunDataSource configuration describing a set of filters""" + + type: Required[Literal["completions"]] + """The type of run data source. Always `completions`.""" + + sampling_params: SamplingParams diff --git a/src/openai/types/evals/create_eval_jsonl_run_data_source.py b/src/openai/types/evals/create_eval_jsonl_run_data_source.py new file mode 100644 index 0000000000..d2be56243b --- /dev/null +++ b/src/openai/types/evals/create_eval_jsonl_run_data_source.py @@ -0,0 +1,41 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel + +__all__ = ["CreateEvalJSONLRunDataSource", "Source", "SourceFileContent", "SourceFileContentContent", "SourceFileID"] + + +class SourceFileContentContent(BaseModel): + item: Dict[str, object] + + sample: Optional[Dict[str, object]] = None + + +class SourceFileContent(BaseModel): + content: List[SourceFileContentContent] + """The content of the jsonl file.""" + + type: Literal["file_content"] + """The type of jsonl source. Always `file_content`.""" + + +class SourceFileID(BaseModel): + id: str + """The identifier of the file.""" + + type: Literal["file_id"] + """The type of jsonl source. Always `file_id`.""" + + +Source: TypeAlias = Annotated[Union[SourceFileContent, SourceFileID], PropertyInfo(discriminator="type")] + + +class CreateEvalJSONLRunDataSource(BaseModel): + source: Source + + type: Literal["jsonl"] + """The type of data source. Always `jsonl`.""" diff --git a/src/openai/types/evals/create_eval_jsonl_run_data_source_param.py b/src/openai/types/evals/create_eval_jsonl_run_data_source_param.py new file mode 100644 index 0000000000..b8ba48a666 --- /dev/null +++ b/src/openai/types/evals/create_eval_jsonl_run_data_source_param.py @@ -0,0 +1,46 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +__all__ = [ + "CreateEvalJSONLRunDataSourceParam", + "Source", + "SourceFileContent", + "SourceFileContentContent", + "SourceFileID", +] + + +class SourceFileContentContent(TypedDict, total=False): + item: Required[Dict[str, object]] + + sample: Dict[str, object] + + +class SourceFileContent(TypedDict, total=False): + content: Required[Iterable[SourceFileContentContent]] + """The content of the jsonl file.""" + + type: Required[Literal["file_content"]] + """The type of jsonl source. Always `file_content`.""" + + +class SourceFileID(TypedDict, total=False): + id: Required[str] + """The identifier of the file.""" + + type: Required[Literal["file_id"]] + """The type of jsonl source. Always `file_id`.""" + + +Source: TypeAlias = Union[SourceFileContent, SourceFileID] + + +class CreateEvalJSONLRunDataSourceParam(TypedDict, total=False): + source: Required[Source] + + type: Required[Literal["jsonl"]] + """The type of data source. Always `jsonl`.""" diff --git a/src/openai/types/evals/eval_api_error.py b/src/openai/types/evals/eval_api_error.py new file mode 100644 index 0000000000..d67185e981 --- /dev/null +++ b/src/openai/types/evals/eval_api_error.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + + +from ..._models import BaseModel + +__all__ = ["EvalAPIError"] + + +class EvalAPIError(BaseModel): + code: str + """The error code.""" + + message: str + """The error message.""" diff --git a/src/openai/types/evals/run_cancel_response.py b/src/openai/types/evals/run_cancel_response.py new file mode 100644 index 0000000000..90e52241a6 --- /dev/null +++ b/src/openai/types/evals/run_cancel_response.py @@ -0,0 +1,115 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .eval_api_error import EvalAPIError +from ..shared.metadata import Metadata +from .create_eval_jsonl_run_data_source import CreateEvalJSONLRunDataSource +from .create_eval_completions_run_data_source import CreateEvalCompletionsRunDataSource + +__all__ = ["RunCancelResponse", "DataSource", "PerModelUsage", "PerTestingCriteriaResult", "ResultCounts"] + +DataSource: TypeAlias = Annotated[ + Union[CreateEvalJSONLRunDataSource, CreateEvalCompletionsRunDataSource], PropertyInfo(discriminator="type") +] + + +class PerModelUsage(BaseModel): + cached_tokens: int + """The number of tokens retrieved from cache.""" + + completion_tokens: int + """The number of completion tokens generated.""" + + invocation_count: int + """The number of invocations.""" + + run_model_name: str = FieldInfo(alias="model_name") + """The name of the model.""" + + prompt_tokens: int + """The number of prompt tokens used.""" + + total_tokens: int + """The total number of tokens used.""" + + +class PerTestingCriteriaResult(BaseModel): + failed: int + """Number of tests failed for this criteria.""" + + passed: int + """Number of tests passed for this criteria.""" + + testing_criteria: str + """A description of the testing criteria.""" + + +class ResultCounts(BaseModel): + errored: int + """Number of output items that resulted in an error.""" + + failed: int + """Number of output items that failed to pass the evaluation.""" + + passed: int + """Number of output items that passed the evaluation.""" + + total: int + """Total number of executed output items.""" + + +class RunCancelResponse(BaseModel): + id: str + """Unique identifier for the evaluation run.""" + + created_at: int + """Unix timestamp (in seconds) when the evaluation run was created.""" + + data_source: DataSource + """Information about the run's data source.""" + + error: EvalAPIError + """An object representing an error response from the Eval API.""" + + eval_id: str + """The identifier of the associated evaluation.""" + + metadata: Optional[Metadata] = None + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + """ + + model: str + """The model that is evaluated, if applicable.""" + + name: str + """The name of the evaluation run.""" + + object: Literal["eval.run"] + """The type of the object. Always "eval.run".""" + + per_model_usage: List[PerModelUsage] + """Usage statistics for each model during the evaluation run.""" + + per_testing_criteria_results: List[PerTestingCriteriaResult] + """Results per testing criteria applied during the evaluation run.""" + + report_url: str + """The URL to the rendered evaluation run report on the UI dashboard.""" + + result_counts: ResultCounts + """Counters summarizing the outcomes of the evaluation run.""" + + status: str + """The status of the evaluation run.""" diff --git a/src/openai/types/evals/run_create_params.py b/src/openai/types/evals/run_create_params.py new file mode 100644 index 0000000000..acf7b1b126 --- /dev/null +++ b/src/openai/types/evals/run_create_params.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Optional +from typing_extensions import Required, TypeAlias, TypedDict + +from ..shared_params.metadata import Metadata +from .create_eval_jsonl_run_data_source_param import CreateEvalJSONLRunDataSourceParam +from .create_eval_completions_run_data_source_param import CreateEvalCompletionsRunDataSourceParam + +__all__ = ["RunCreateParams", "DataSource"] + + +class RunCreateParams(TypedDict, total=False): + data_source: Required[DataSource] + """Details about the run's data source.""" + + metadata: Optional[Metadata] + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + """ + + name: str + """The name of the run.""" + + +DataSource: TypeAlias = Union[CreateEvalJSONLRunDataSourceParam, CreateEvalCompletionsRunDataSourceParam] diff --git a/src/openai/types/evals/run_create_response.py b/src/openai/types/evals/run_create_response.py new file mode 100644 index 0000000000..14ca426427 --- /dev/null +++ b/src/openai/types/evals/run_create_response.py @@ -0,0 +1,115 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .eval_api_error import EvalAPIError +from ..shared.metadata import Metadata +from .create_eval_jsonl_run_data_source import CreateEvalJSONLRunDataSource +from .create_eval_completions_run_data_source import CreateEvalCompletionsRunDataSource + +__all__ = ["RunCreateResponse", "DataSource", "PerModelUsage", "PerTestingCriteriaResult", "ResultCounts"] + +DataSource: TypeAlias = Annotated[ + Union[CreateEvalJSONLRunDataSource, CreateEvalCompletionsRunDataSource], PropertyInfo(discriminator="type") +] + + +class PerModelUsage(BaseModel): + cached_tokens: int + """The number of tokens retrieved from cache.""" + + completion_tokens: int + """The number of completion tokens generated.""" + + invocation_count: int + """The number of invocations.""" + + run_model_name: str = FieldInfo(alias="model_name") + """The name of the model.""" + + prompt_tokens: int + """The number of prompt tokens used.""" + + total_tokens: int + """The total number of tokens used.""" + + +class PerTestingCriteriaResult(BaseModel): + failed: int + """Number of tests failed for this criteria.""" + + passed: int + """Number of tests passed for this criteria.""" + + testing_criteria: str + """A description of the testing criteria.""" + + +class ResultCounts(BaseModel): + errored: int + """Number of output items that resulted in an error.""" + + failed: int + """Number of output items that failed to pass the evaluation.""" + + passed: int + """Number of output items that passed the evaluation.""" + + total: int + """Total number of executed output items.""" + + +class RunCreateResponse(BaseModel): + id: str + """Unique identifier for the evaluation run.""" + + created_at: int + """Unix timestamp (in seconds) when the evaluation run was created.""" + + data_source: DataSource + """Information about the run's data source.""" + + error: EvalAPIError + """An object representing an error response from the Eval API.""" + + eval_id: str + """The identifier of the associated evaluation.""" + + metadata: Optional[Metadata] = None + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + """ + + model: str + """The model that is evaluated, if applicable.""" + + name: str + """The name of the evaluation run.""" + + object: Literal["eval.run"] + """The type of the object. Always "eval.run".""" + + per_model_usage: List[PerModelUsage] + """Usage statistics for each model during the evaluation run.""" + + per_testing_criteria_results: List[PerTestingCriteriaResult] + """Results per testing criteria applied during the evaluation run.""" + + report_url: str + """The URL to the rendered evaluation run report on the UI dashboard.""" + + result_counts: ResultCounts + """Counters summarizing the outcomes of the evaluation run.""" + + status: str + """The status of the evaluation run.""" diff --git a/src/openai/types/evals/run_delete_response.py b/src/openai/types/evals/run_delete_response.py new file mode 100644 index 0000000000..d48d01f86c --- /dev/null +++ b/src/openai/types/evals/run_delete_response.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["RunDeleteResponse"] + + +class RunDeleteResponse(BaseModel): + deleted: Optional[bool] = None + + object: Optional[str] = None + + run_id: Optional[str] = None diff --git a/src/openai/types/evals/run_list_params.py b/src/openai/types/evals/run_list_params.py new file mode 100644 index 0000000000..6060eafb97 --- /dev/null +++ b/src/openai/types/evals/run_list_params.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["RunListParams"] + + +class RunListParams(TypedDict, total=False): + after: str + """Identifier for the last run from the previous pagination request.""" + + limit: int + """Number of runs to retrieve.""" + + order: Literal["asc", "desc"] + """Sort order for runs by timestamp. + + Use `asc` for ascending order or `desc` for descending order. Defaults to `asc`. + """ + + status: Literal["queued", "in_progress", "completed", "canceled", "failed"] + """Filter runs by status. + + Use "queued" | "in_progress" | "failed" | "completed" | "canceled". + """ diff --git a/src/openai/types/evals/run_list_response.py b/src/openai/types/evals/run_list_response.py new file mode 100644 index 0000000000..a1022f542f --- /dev/null +++ b/src/openai/types/evals/run_list_response.py @@ -0,0 +1,115 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .eval_api_error import EvalAPIError +from ..shared.metadata import Metadata +from .create_eval_jsonl_run_data_source import CreateEvalJSONLRunDataSource +from .create_eval_completions_run_data_source import CreateEvalCompletionsRunDataSource + +__all__ = ["RunListResponse", "DataSource", "PerModelUsage", "PerTestingCriteriaResult", "ResultCounts"] + +DataSource: TypeAlias = Annotated[ + Union[CreateEvalJSONLRunDataSource, CreateEvalCompletionsRunDataSource], PropertyInfo(discriminator="type") +] + + +class PerModelUsage(BaseModel): + cached_tokens: int + """The number of tokens retrieved from cache.""" + + completion_tokens: int + """The number of completion tokens generated.""" + + invocation_count: int + """The number of invocations.""" + + run_model_name: str = FieldInfo(alias="model_name") + """The name of the model.""" + + prompt_tokens: int + """The number of prompt tokens used.""" + + total_tokens: int + """The total number of tokens used.""" + + +class PerTestingCriteriaResult(BaseModel): + failed: int + """Number of tests failed for this criteria.""" + + passed: int + """Number of tests passed for this criteria.""" + + testing_criteria: str + """A description of the testing criteria.""" + + +class ResultCounts(BaseModel): + errored: int + """Number of output items that resulted in an error.""" + + failed: int + """Number of output items that failed to pass the evaluation.""" + + passed: int + """Number of output items that passed the evaluation.""" + + total: int + """Total number of executed output items.""" + + +class RunListResponse(BaseModel): + id: str + """Unique identifier for the evaluation run.""" + + created_at: int + """Unix timestamp (in seconds) when the evaluation run was created.""" + + data_source: DataSource + """Information about the run's data source.""" + + error: EvalAPIError + """An object representing an error response from the Eval API.""" + + eval_id: str + """The identifier of the associated evaluation.""" + + metadata: Optional[Metadata] = None + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + """ + + model: str + """The model that is evaluated, if applicable.""" + + name: str + """The name of the evaluation run.""" + + object: Literal["eval.run"] + """The type of the object. Always "eval.run".""" + + per_model_usage: List[PerModelUsage] + """Usage statistics for each model during the evaluation run.""" + + per_testing_criteria_results: List[PerTestingCriteriaResult] + """Results per testing criteria applied during the evaluation run.""" + + report_url: str + """The URL to the rendered evaluation run report on the UI dashboard.""" + + result_counts: ResultCounts + """Counters summarizing the outcomes of the evaluation run.""" + + status: str + """The status of the evaluation run.""" diff --git a/src/openai/types/evals/run_retrieve_response.py b/src/openai/types/evals/run_retrieve_response.py new file mode 100644 index 0000000000..461ed43dda --- /dev/null +++ b/src/openai/types/evals/run_retrieve_response.py @@ -0,0 +1,115 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .eval_api_error import EvalAPIError +from ..shared.metadata import Metadata +from .create_eval_jsonl_run_data_source import CreateEvalJSONLRunDataSource +from .create_eval_completions_run_data_source import CreateEvalCompletionsRunDataSource + +__all__ = ["RunRetrieveResponse", "DataSource", "PerModelUsage", "PerTestingCriteriaResult", "ResultCounts"] + +DataSource: TypeAlias = Annotated[ + Union[CreateEvalJSONLRunDataSource, CreateEvalCompletionsRunDataSource], PropertyInfo(discriminator="type") +] + + +class PerModelUsage(BaseModel): + cached_tokens: int + """The number of tokens retrieved from cache.""" + + completion_tokens: int + """The number of completion tokens generated.""" + + invocation_count: int + """The number of invocations.""" + + run_model_name: str = FieldInfo(alias="model_name") + """The name of the model.""" + + prompt_tokens: int + """The number of prompt tokens used.""" + + total_tokens: int + """The total number of tokens used.""" + + +class PerTestingCriteriaResult(BaseModel): + failed: int + """Number of tests failed for this criteria.""" + + passed: int + """Number of tests passed for this criteria.""" + + testing_criteria: str + """A description of the testing criteria.""" + + +class ResultCounts(BaseModel): + errored: int + """Number of output items that resulted in an error.""" + + failed: int + """Number of output items that failed to pass the evaluation.""" + + passed: int + """Number of output items that passed the evaluation.""" + + total: int + """Total number of executed output items.""" + + +class RunRetrieveResponse(BaseModel): + id: str + """Unique identifier for the evaluation run.""" + + created_at: int + """Unix timestamp (in seconds) when the evaluation run was created.""" + + data_source: DataSource + """Information about the run's data source.""" + + error: EvalAPIError + """An object representing an error response from the Eval API.""" + + eval_id: str + """The identifier of the associated evaluation.""" + + metadata: Optional[Metadata] = None + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + """ + + model: str + """The model that is evaluated, if applicable.""" + + name: str + """The name of the evaluation run.""" + + object: Literal["eval.run"] + """The type of the object. Always "eval.run".""" + + per_model_usage: List[PerModelUsage] + """Usage statistics for each model during the evaluation run.""" + + per_testing_criteria_results: List[PerTestingCriteriaResult] + """Results per testing criteria applied during the evaluation run.""" + + report_url: str + """The URL to the rendered evaluation run report on the UI dashboard.""" + + result_counts: ResultCounts + """Counters summarizing the outcomes of the evaluation run.""" + + status: str + """The status of the evaluation run.""" diff --git a/src/openai/types/evals/runs/__init__.py b/src/openai/types/evals/runs/__init__.py new file mode 100644 index 0000000000..b77cbb6acd --- /dev/null +++ b/src/openai/types/evals/runs/__init__.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .output_item_list_params import OutputItemListParams as OutputItemListParams +from .output_item_list_response import OutputItemListResponse as OutputItemListResponse +from .output_item_retrieve_response import OutputItemRetrieveResponse as OutputItemRetrieveResponse diff --git a/src/openai/types/evals/runs/output_item_list_params.py b/src/openai/types/evals/runs/output_item_list_params.py new file mode 100644 index 0000000000..073bfc69a7 --- /dev/null +++ b/src/openai/types/evals/runs/output_item_list_params.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["OutputItemListParams"] + + +class OutputItemListParams(TypedDict, total=False): + eval_id: Required[str] + + after: str + """Identifier for the last output item from the previous pagination request.""" + + limit: int + """Number of output items to retrieve.""" + + order: Literal["asc", "desc"] + """Sort order for output items by timestamp. + + Use `asc` for ascending order or `desc` for descending order. Defaults to `asc`. + """ + + status: Literal["fail", "pass"] + """Filter output items by status. + + Use `failed` to filter by failed output items or `pass` to filter by passed + output items. + """ diff --git a/src/openai/types/evals/runs/output_item_list_response.py b/src/openai/types/evals/runs/output_item_list_response.py new file mode 100644 index 0000000000..72b1049f7b --- /dev/null +++ b/src/openai/types/evals/runs/output_item_list_response.py @@ -0,0 +1,104 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import builtins +from typing import Dict, List, Optional +from typing_extensions import Literal + +from ...._models import BaseModel +from ..eval_api_error import EvalAPIError + +__all__ = ["OutputItemListResponse", "Sample", "SampleInput", "SampleOutput", "SampleUsage"] + + +class SampleInput(BaseModel): + content: str + """The content of the message.""" + + role: str + """The role of the message sender (e.g., system, user, developer).""" + + +class SampleOutput(BaseModel): + content: Optional[str] = None + """The content of the message.""" + + role: Optional[str] = None + """The role of the message (e.g. "system", "assistant", "user").""" + + +class SampleUsage(BaseModel): + cached_tokens: int + """The number of tokens retrieved from cache.""" + + completion_tokens: int + """The number of completion tokens generated.""" + + prompt_tokens: int + """The number of prompt tokens used.""" + + total_tokens: int + """The total number of tokens used.""" + + +class Sample(BaseModel): + error: EvalAPIError + """An object representing an error response from the Eval API.""" + + finish_reason: str + """The reason why the sample generation was finished.""" + + input: List[SampleInput] + """An array of input messages.""" + + max_completion_tokens: int + """The maximum number of tokens allowed for completion.""" + + model: str + """The model used for generating the sample.""" + + output: List[SampleOutput] + """An array of output messages.""" + + seed: int + """The seed used for generating the sample.""" + + temperature: float + """The sampling temperature used.""" + + top_p: float + """The top_p value used for sampling.""" + + usage: SampleUsage + """Token usage details for the sample.""" + + +class OutputItemListResponse(BaseModel): + id: str + """Unique identifier for the evaluation run output item.""" + + created_at: int + """Unix timestamp (in seconds) when the evaluation run was created.""" + + datasource_item: Dict[str, object] + """Details of the input data source item.""" + + datasource_item_id: int + """The identifier for the data source item.""" + + eval_id: str + """The identifier of the evaluation group.""" + + object: Literal["eval.run.output_item"] + """The type of the object. Always "eval.run.output_item".""" + + results: List[Dict[str, builtins.object]] + """A list of results from the evaluation run.""" + + run_id: str + """The identifier of the evaluation run associated with this output item.""" + + sample: Sample + """A sample containing the input and output of the evaluation run.""" + + status: str + """The status of the evaluation run.""" diff --git a/src/openai/types/evals/runs/output_item_retrieve_response.py b/src/openai/types/evals/runs/output_item_retrieve_response.py new file mode 100644 index 0000000000..63aab5565f --- /dev/null +++ b/src/openai/types/evals/runs/output_item_retrieve_response.py @@ -0,0 +1,104 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import builtins +from typing import Dict, List, Optional +from typing_extensions import Literal + +from ...._models import BaseModel +from ..eval_api_error import EvalAPIError + +__all__ = ["OutputItemRetrieveResponse", "Sample", "SampleInput", "SampleOutput", "SampleUsage"] + + +class SampleInput(BaseModel): + content: str + """The content of the message.""" + + role: str + """The role of the message sender (e.g., system, user, developer).""" + + +class SampleOutput(BaseModel): + content: Optional[str] = None + """The content of the message.""" + + role: Optional[str] = None + """The role of the message (e.g. "system", "assistant", "user").""" + + +class SampleUsage(BaseModel): + cached_tokens: int + """The number of tokens retrieved from cache.""" + + completion_tokens: int + """The number of completion tokens generated.""" + + prompt_tokens: int + """The number of prompt tokens used.""" + + total_tokens: int + """The total number of tokens used.""" + + +class Sample(BaseModel): + error: EvalAPIError + """An object representing an error response from the Eval API.""" + + finish_reason: str + """The reason why the sample generation was finished.""" + + input: List[SampleInput] + """An array of input messages.""" + + max_completion_tokens: int + """The maximum number of tokens allowed for completion.""" + + model: str + """The model used for generating the sample.""" + + output: List[SampleOutput] + """An array of output messages.""" + + seed: int + """The seed used for generating the sample.""" + + temperature: float + """The sampling temperature used.""" + + top_p: float + """The top_p value used for sampling.""" + + usage: SampleUsage + """Token usage details for the sample.""" + + +class OutputItemRetrieveResponse(BaseModel): + id: str + """Unique identifier for the evaluation run output item.""" + + created_at: int + """Unix timestamp (in seconds) when the evaluation run was created.""" + + datasource_item: Dict[str, object] + """Details of the input data source item.""" + + datasource_item_id: int + """The identifier for the data source item.""" + + eval_id: str + """The identifier of the evaluation group.""" + + object: Literal["eval.run.output_item"] + """The type of the object. Always "eval.run.output_item".""" + + results: List[Dict[str, builtins.object]] + """A list of results from the evaluation run.""" + + run_id: str + """The identifier of the evaluation run associated with this output item.""" + + sample: Sample + """A sample containing the input and output of the evaluation run.""" + + status: str + """The status of the evaluation run.""" diff --git a/src/openai/types/fine_tuning/checkpoints/__init__.py b/src/openai/types/fine_tuning/checkpoints/__init__.py new file mode 100644 index 0000000000..2947b33145 --- /dev/null +++ b/src/openai/types/fine_tuning/checkpoints/__init__.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .permission_create_params import PermissionCreateParams as PermissionCreateParams +from .permission_create_response import PermissionCreateResponse as PermissionCreateResponse +from .permission_delete_response import PermissionDeleteResponse as PermissionDeleteResponse +from .permission_retrieve_params import PermissionRetrieveParams as PermissionRetrieveParams +from .permission_retrieve_response import PermissionRetrieveResponse as PermissionRetrieveResponse diff --git a/src/openai/types/fine_tuning/checkpoints/permission_create_params.py b/src/openai/types/fine_tuning/checkpoints/permission_create_params.py new file mode 100644 index 0000000000..92f98f21b9 --- /dev/null +++ b/src/openai/types/fine_tuning/checkpoints/permission_create_params.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Required, TypedDict + +__all__ = ["PermissionCreateParams"] + + +class PermissionCreateParams(TypedDict, total=False): + project_ids: Required[List[str]] + """The project identifiers to grant access to.""" diff --git a/src/openai/types/fine_tuning/checkpoints/permission_create_response.py b/src/openai/types/fine_tuning/checkpoints/permission_create_response.py new file mode 100644 index 0000000000..9bc14c00cc --- /dev/null +++ b/src/openai/types/fine_tuning/checkpoints/permission_create_response.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["PermissionCreateResponse"] + + +class PermissionCreateResponse(BaseModel): + id: str + """The permission identifier, which can be referenced in the API endpoints.""" + + created_at: int + """The Unix timestamp (in seconds) for when the permission was created.""" + + object: Literal["checkpoint.permission"] + """The object type, which is always "checkpoint.permission".""" + + project_id: str + """The project identifier that the permission is for.""" diff --git a/src/openai/types/fine_tuning/checkpoints/permission_delete_response.py b/src/openai/types/fine_tuning/checkpoints/permission_delete_response.py new file mode 100644 index 0000000000..1a92d912fa --- /dev/null +++ b/src/openai/types/fine_tuning/checkpoints/permission_delete_response.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["PermissionDeleteResponse"] + + +class PermissionDeleteResponse(BaseModel): + id: str + """The ID of the fine-tuned model checkpoint permission that was deleted.""" + + deleted: bool + """Whether the fine-tuned model checkpoint permission was successfully deleted.""" + + object: Literal["checkpoint.permission"] + """The object type, which is always "checkpoint.permission".""" diff --git a/src/openai/types/fine_tuning/checkpoints/permission_retrieve_params.py b/src/openai/types/fine_tuning/checkpoints/permission_retrieve_params.py new file mode 100644 index 0000000000..6e66a867ca --- /dev/null +++ b/src/openai/types/fine_tuning/checkpoints/permission_retrieve_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["PermissionRetrieveParams"] + + +class PermissionRetrieveParams(TypedDict, total=False): + after: str + """Identifier for the last permission ID from the previous pagination request.""" + + limit: int + """Number of permissions to retrieve.""" + + order: Literal["ascending", "descending"] + """The order in which to retrieve permissions.""" + + project_id: str + """The ID of the project to get permissions for.""" diff --git a/src/openai/types/fine_tuning/checkpoints/permission_retrieve_response.py b/src/openai/types/fine_tuning/checkpoints/permission_retrieve_response.py new file mode 100644 index 0000000000..14c73b55d0 --- /dev/null +++ b/src/openai/types/fine_tuning/checkpoints/permission_retrieve_response.py @@ -0,0 +1,34 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["PermissionRetrieveResponse", "Data"] + + +class Data(BaseModel): + id: str + """The permission identifier, which can be referenced in the API endpoints.""" + + created_at: int + """The Unix timestamp (in seconds) for when the permission was created.""" + + object: Literal["checkpoint.permission"] + """The object type, which is always "checkpoint.permission".""" + + project_id: str + """The project identifier that the permission is for.""" + + +class PermissionRetrieveResponse(BaseModel): + data: List[Data] + + has_more: bool + + object: Literal["list"] + + first_id: Optional[str] = None + + last_id: Optional[str] = None diff --git a/tests/api_resources/evals/__init__.py b/tests/api_resources/evals/__init__.py new file mode 100644 index 0000000000..fd8019a9a1 --- /dev/null +++ b/tests/api_resources/evals/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/evals/runs/__init__.py b/tests/api_resources/evals/runs/__init__.py new file mode 100644 index 0000000000..fd8019a9a1 --- /dev/null +++ b/tests/api_resources/evals/runs/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/evals/runs/test_output_items.py b/tests/api_resources/evals/runs/test_output_items.py new file mode 100644 index 0000000000..f764f0336e --- /dev/null +++ b/tests/api_resources/evals/runs/test_output_items.py @@ -0,0 +1,263 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.pagination import SyncCursorPage, AsyncCursorPage +from openai.types.evals.runs import OutputItemListResponse, OutputItemRetrieveResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestOutputItems: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + output_item = client.evals.runs.output_items.retrieve( + output_item_id="output_item_id", + eval_id="eval_id", + run_id="run_id", + ) + assert_matches_type(OutputItemRetrieveResponse, output_item, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.evals.runs.output_items.with_raw_response.retrieve( + output_item_id="output_item_id", + eval_id="eval_id", + run_id="run_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + output_item = response.parse() + assert_matches_type(OutputItemRetrieveResponse, output_item, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.evals.runs.output_items.with_streaming_response.retrieve( + output_item_id="output_item_id", + eval_id="eval_id", + run_id="run_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + output_item = response.parse() + assert_matches_type(OutputItemRetrieveResponse, output_item, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `eval_id` but received ''"): + client.evals.runs.output_items.with_raw_response.retrieve( + output_item_id="output_item_id", + eval_id="", + run_id="run_id", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): + client.evals.runs.output_items.with_raw_response.retrieve( + output_item_id="output_item_id", + eval_id="eval_id", + run_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `output_item_id` but received ''"): + client.evals.runs.output_items.with_raw_response.retrieve( + output_item_id="", + eval_id="eval_id", + run_id="run_id", + ) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + output_item = client.evals.runs.output_items.list( + run_id="run_id", + eval_id="eval_id", + ) + assert_matches_type(SyncCursorPage[OutputItemListResponse], output_item, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + output_item = client.evals.runs.output_items.list( + run_id="run_id", + eval_id="eval_id", + after="after", + limit=0, + order="asc", + status="fail", + ) + assert_matches_type(SyncCursorPage[OutputItemListResponse], output_item, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.evals.runs.output_items.with_raw_response.list( + run_id="run_id", + eval_id="eval_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + output_item = response.parse() + assert_matches_type(SyncCursorPage[OutputItemListResponse], output_item, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.evals.runs.output_items.with_streaming_response.list( + run_id="run_id", + eval_id="eval_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + output_item = response.parse() + assert_matches_type(SyncCursorPage[OutputItemListResponse], output_item, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `eval_id` but received ''"): + client.evals.runs.output_items.with_raw_response.list( + run_id="run_id", + eval_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): + client.evals.runs.output_items.with_raw_response.list( + run_id="", + eval_id="eval_id", + ) + + +class TestAsyncOutputItems: + parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + output_item = await async_client.evals.runs.output_items.retrieve( + output_item_id="output_item_id", + eval_id="eval_id", + run_id="run_id", + ) + assert_matches_type(OutputItemRetrieveResponse, output_item, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.evals.runs.output_items.with_raw_response.retrieve( + output_item_id="output_item_id", + eval_id="eval_id", + run_id="run_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + output_item = response.parse() + assert_matches_type(OutputItemRetrieveResponse, output_item, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.evals.runs.output_items.with_streaming_response.retrieve( + output_item_id="output_item_id", + eval_id="eval_id", + run_id="run_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + output_item = await response.parse() + assert_matches_type(OutputItemRetrieveResponse, output_item, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `eval_id` but received ''"): + await async_client.evals.runs.output_items.with_raw_response.retrieve( + output_item_id="output_item_id", + eval_id="", + run_id="run_id", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): + await async_client.evals.runs.output_items.with_raw_response.retrieve( + output_item_id="output_item_id", + eval_id="eval_id", + run_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `output_item_id` but received ''"): + await async_client.evals.runs.output_items.with_raw_response.retrieve( + output_item_id="", + eval_id="eval_id", + run_id="run_id", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + output_item = await async_client.evals.runs.output_items.list( + run_id="run_id", + eval_id="eval_id", + ) + assert_matches_type(AsyncCursorPage[OutputItemListResponse], output_item, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + output_item = await async_client.evals.runs.output_items.list( + run_id="run_id", + eval_id="eval_id", + after="after", + limit=0, + order="asc", + status="fail", + ) + assert_matches_type(AsyncCursorPage[OutputItemListResponse], output_item, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.evals.runs.output_items.with_raw_response.list( + run_id="run_id", + eval_id="eval_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + output_item = response.parse() + assert_matches_type(AsyncCursorPage[OutputItemListResponse], output_item, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.evals.runs.output_items.with_streaming_response.list( + run_id="run_id", + eval_id="eval_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + output_item = await response.parse() + assert_matches_type(AsyncCursorPage[OutputItemListResponse], output_item, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `eval_id` but received ''"): + await async_client.evals.runs.output_items.with_raw_response.list( + run_id="run_id", + eval_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): + await async_client.evals.runs.output_items.with_raw_response.list( + run_id="", + eval_id="eval_id", + ) diff --git a/tests/api_resources/evals/test_runs.py b/tests/api_resources/evals/test_runs.py new file mode 100644 index 0000000000..cefb1c82ff --- /dev/null +++ b/tests/api_resources/evals/test_runs.py @@ -0,0 +1,589 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.pagination import SyncCursorPage, AsyncCursorPage +from openai.types.evals import ( + RunListResponse, + RunCancelResponse, + RunCreateResponse, + RunDeleteResponse, + RunRetrieveResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestRuns: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: OpenAI) -> None: + run = client.evals.runs.create( + eval_id="eval_id", + data_source={ + "source": { + "content": [{"item": {"foo": "bar"}}], + "type": "file_content", + }, + "type": "jsonl", + }, + ) + assert_matches_type(RunCreateResponse, run, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: OpenAI) -> None: + run = client.evals.runs.create( + eval_id="eval_id", + data_source={ + "source": { + "content": [ + { + "item": {"foo": "bar"}, + "sample": {"foo": "bar"}, + } + ], + "type": "file_content", + }, + "type": "jsonl", + }, + metadata={"foo": "string"}, + name="name", + ) + assert_matches_type(RunCreateResponse, run, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: OpenAI) -> None: + response = client.evals.runs.with_raw_response.create( + eval_id="eval_id", + data_source={ + "source": { + "content": [{"item": {"foo": "bar"}}], + "type": "file_content", + }, + "type": "jsonl", + }, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + run = response.parse() + assert_matches_type(RunCreateResponse, run, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: OpenAI) -> None: + with client.evals.runs.with_streaming_response.create( + eval_id="eval_id", + data_source={ + "source": { + "content": [{"item": {"foo": "bar"}}], + "type": "file_content", + }, + "type": "jsonl", + }, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + run = response.parse() + assert_matches_type(RunCreateResponse, run, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_create(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `eval_id` but received ''"): + client.evals.runs.with_raw_response.create( + eval_id="", + data_source={ + "source": { + "content": [{"item": {"foo": "bar"}}], + "type": "file_content", + }, + "type": "jsonl", + }, + ) + + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + run = client.evals.runs.retrieve( + run_id="run_id", + eval_id="eval_id", + ) + assert_matches_type(RunRetrieveResponse, run, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.evals.runs.with_raw_response.retrieve( + run_id="run_id", + eval_id="eval_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + run = response.parse() + assert_matches_type(RunRetrieveResponse, run, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.evals.runs.with_streaming_response.retrieve( + run_id="run_id", + eval_id="eval_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + run = response.parse() + assert_matches_type(RunRetrieveResponse, run, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `eval_id` but received ''"): + client.evals.runs.with_raw_response.retrieve( + run_id="run_id", + eval_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): + client.evals.runs.with_raw_response.retrieve( + run_id="", + eval_id="eval_id", + ) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + run = client.evals.runs.list( + eval_id="eval_id", + ) + assert_matches_type(SyncCursorPage[RunListResponse], run, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + run = client.evals.runs.list( + eval_id="eval_id", + after="after", + limit=0, + order="asc", + status="queued", + ) + assert_matches_type(SyncCursorPage[RunListResponse], run, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.evals.runs.with_raw_response.list( + eval_id="eval_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + run = response.parse() + assert_matches_type(SyncCursorPage[RunListResponse], run, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.evals.runs.with_streaming_response.list( + eval_id="eval_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + run = response.parse() + assert_matches_type(SyncCursorPage[RunListResponse], run, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `eval_id` but received ''"): + client.evals.runs.with_raw_response.list( + eval_id="", + ) + + @parametrize + def test_method_delete(self, client: OpenAI) -> None: + run = client.evals.runs.delete( + run_id="run_id", + eval_id="eval_id", + ) + assert_matches_type(RunDeleteResponse, run, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: OpenAI) -> None: + response = client.evals.runs.with_raw_response.delete( + run_id="run_id", + eval_id="eval_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + run = response.parse() + assert_matches_type(RunDeleteResponse, run, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: OpenAI) -> None: + with client.evals.runs.with_streaming_response.delete( + run_id="run_id", + eval_id="eval_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + run = response.parse() + assert_matches_type(RunDeleteResponse, run, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `eval_id` but received ''"): + client.evals.runs.with_raw_response.delete( + run_id="run_id", + eval_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): + client.evals.runs.with_raw_response.delete( + run_id="", + eval_id="eval_id", + ) + + @parametrize + def test_method_cancel(self, client: OpenAI) -> None: + run = client.evals.runs.cancel( + run_id="run_id", + eval_id="eval_id", + ) + assert_matches_type(RunCancelResponse, run, path=["response"]) + + @parametrize + def test_raw_response_cancel(self, client: OpenAI) -> None: + response = client.evals.runs.with_raw_response.cancel( + run_id="run_id", + eval_id="eval_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + run = response.parse() + assert_matches_type(RunCancelResponse, run, path=["response"]) + + @parametrize + def test_streaming_response_cancel(self, client: OpenAI) -> None: + with client.evals.runs.with_streaming_response.cancel( + run_id="run_id", + eval_id="eval_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + run = response.parse() + assert_matches_type(RunCancelResponse, run, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_cancel(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `eval_id` but received ''"): + client.evals.runs.with_raw_response.cancel( + run_id="run_id", + eval_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): + client.evals.runs.with_raw_response.cancel( + run_id="", + eval_id="eval_id", + ) + + +class TestAsyncRuns: + parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + async def test_method_create(self, async_client: AsyncOpenAI) -> None: + run = await async_client.evals.runs.create( + eval_id="eval_id", + data_source={ + "source": { + "content": [{"item": {"foo": "bar"}}], + "type": "file_content", + }, + "type": "jsonl", + }, + ) + assert_matches_type(RunCreateResponse, run, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: + run = await async_client.evals.runs.create( + eval_id="eval_id", + data_source={ + "source": { + "content": [ + { + "item": {"foo": "bar"}, + "sample": {"foo": "bar"}, + } + ], + "type": "file_content", + }, + "type": "jsonl", + }, + metadata={"foo": "string"}, + name="name", + ) + assert_matches_type(RunCreateResponse, run, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: + response = await async_client.evals.runs.with_raw_response.create( + eval_id="eval_id", + data_source={ + "source": { + "content": [{"item": {"foo": "bar"}}], + "type": "file_content", + }, + "type": "jsonl", + }, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + run = response.parse() + assert_matches_type(RunCreateResponse, run, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: + async with async_client.evals.runs.with_streaming_response.create( + eval_id="eval_id", + data_source={ + "source": { + "content": [{"item": {"foo": "bar"}}], + "type": "file_content", + }, + "type": "jsonl", + }, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + run = await response.parse() + assert_matches_type(RunCreateResponse, run, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `eval_id` but received ''"): + await async_client.evals.runs.with_raw_response.create( + eval_id="", + data_source={ + "source": { + "content": [{"item": {"foo": "bar"}}], + "type": "file_content", + }, + "type": "jsonl", + }, + ) + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + run = await async_client.evals.runs.retrieve( + run_id="run_id", + eval_id="eval_id", + ) + assert_matches_type(RunRetrieveResponse, run, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.evals.runs.with_raw_response.retrieve( + run_id="run_id", + eval_id="eval_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + run = response.parse() + assert_matches_type(RunRetrieveResponse, run, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.evals.runs.with_streaming_response.retrieve( + run_id="run_id", + eval_id="eval_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + run = await response.parse() + assert_matches_type(RunRetrieveResponse, run, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `eval_id` but received ''"): + await async_client.evals.runs.with_raw_response.retrieve( + run_id="run_id", + eval_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): + await async_client.evals.runs.with_raw_response.retrieve( + run_id="", + eval_id="eval_id", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + run = await async_client.evals.runs.list( + eval_id="eval_id", + ) + assert_matches_type(AsyncCursorPage[RunListResponse], run, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + run = await async_client.evals.runs.list( + eval_id="eval_id", + after="after", + limit=0, + order="asc", + status="queued", + ) + assert_matches_type(AsyncCursorPage[RunListResponse], run, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.evals.runs.with_raw_response.list( + eval_id="eval_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + run = response.parse() + assert_matches_type(AsyncCursorPage[RunListResponse], run, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.evals.runs.with_streaming_response.list( + eval_id="eval_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + run = await response.parse() + assert_matches_type(AsyncCursorPage[RunListResponse], run, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `eval_id` but received ''"): + await async_client.evals.runs.with_raw_response.list( + eval_id="", + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncOpenAI) -> None: + run = await async_client.evals.runs.delete( + run_id="run_id", + eval_id="eval_id", + ) + assert_matches_type(RunDeleteResponse, run, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: + response = await async_client.evals.runs.with_raw_response.delete( + run_id="run_id", + eval_id="eval_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + run = response.parse() + assert_matches_type(RunDeleteResponse, run, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: + async with async_client.evals.runs.with_streaming_response.delete( + run_id="run_id", + eval_id="eval_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + run = await response.parse() + assert_matches_type(RunDeleteResponse, run, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `eval_id` but received ''"): + await async_client.evals.runs.with_raw_response.delete( + run_id="run_id", + eval_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): + await async_client.evals.runs.with_raw_response.delete( + run_id="", + eval_id="eval_id", + ) + + @parametrize + async def test_method_cancel(self, async_client: AsyncOpenAI) -> None: + run = await async_client.evals.runs.cancel( + run_id="run_id", + eval_id="eval_id", + ) + assert_matches_type(RunCancelResponse, run, path=["response"]) + + @parametrize + async def test_raw_response_cancel(self, async_client: AsyncOpenAI) -> None: + response = await async_client.evals.runs.with_raw_response.cancel( + run_id="run_id", + eval_id="eval_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + run = response.parse() + assert_matches_type(RunCancelResponse, run, path=["response"]) + + @parametrize + async def test_streaming_response_cancel(self, async_client: AsyncOpenAI) -> None: + async with async_client.evals.runs.with_streaming_response.cancel( + run_id="run_id", + eval_id="eval_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + run = await response.parse() + assert_matches_type(RunCancelResponse, run, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_cancel(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `eval_id` but received ''"): + await async_client.evals.runs.with_raw_response.cancel( + run_id="run_id", + eval_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): + await async_client.evals.runs.with_raw_response.cancel( + run_id="", + eval_id="eval_id", + ) diff --git a/tests/api_resources/fine_tuning/checkpoints/__init__.py b/tests/api_resources/fine_tuning/checkpoints/__init__.py new file mode 100644 index 0000000000..fd8019a9a1 --- /dev/null +++ b/tests/api_resources/fine_tuning/checkpoints/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/fine_tuning/checkpoints/test_permissions.py b/tests/api_resources/fine_tuning/checkpoints/test_permissions.py new file mode 100644 index 0000000000..d25c784c33 --- /dev/null +++ b/tests/api_resources/fine_tuning/checkpoints/test_permissions.py @@ -0,0 +1,297 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.pagination import SyncPage, AsyncPage +from openai.types.fine_tuning.checkpoints import ( + PermissionCreateResponse, + PermissionDeleteResponse, + PermissionRetrieveResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestPermissions: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: OpenAI) -> None: + permission = client.fine_tuning.checkpoints.permissions.create( + fine_tuned_model_checkpoint="ft:gpt-4o-mini-2024-07-18:org:weather:B7R9VjQd", + project_ids=["string"], + ) + assert_matches_type(SyncPage[PermissionCreateResponse], permission, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: OpenAI) -> None: + response = client.fine_tuning.checkpoints.permissions.with_raw_response.create( + fine_tuned_model_checkpoint="ft:gpt-4o-mini-2024-07-18:org:weather:B7R9VjQd", + project_ids=["string"], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + permission = response.parse() + assert_matches_type(SyncPage[PermissionCreateResponse], permission, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: OpenAI) -> None: + with client.fine_tuning.checkpoints.permissions.with_streaming_response.create( + fine_tuned_model_checkpoint="ft:gpt-4o-mini-2024-07-18:org:weather:B7R9VjQd", + project_ids=["string"], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + permission = response.parse() + assert_matches_type(SyncPage[PermissionCreateResponse], permission, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_create(self, client: OpenAI) -> None: + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `fine_tuned_model_checkpoint` but received ''" + ): + client.fine_tuning.checkpoints.permissions.with_raw_response.create( + fine_tuned_model_checkpoint="", + project_ids=["string"], + ) + + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + permission = client.fine_tuning.checkpoints.permissions.retrieve( + fine_tuned_model_checkpoint="ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) + assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) + + @parametrize + def test_method_retrieve_with_all_params(self, client: OpenAI) -> None: + permission = client.fine_tuning.checkpoints.permissions.retrieve( + fine_tuned_model_checkpoint="ft-AF1WoRqd3aJAHsqc9NY7iL8F", + after="after", + limit=0, + order="ascending", + project_id="project_id", + ) + assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.fine_tuning.checkpoints.permissions.with_raw_response.retrieve( + fine_tuned_model_checkpoint="ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + permission = response.parse() + assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.fine_tuning.checkpoints.permissions.with_streaming_response.retrieve( + fine_tuned_model_checkpoint="ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + permission = response.parse() + assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `fine_tuned_model_checkpoint` but received ''" + ): + client.fine_tuning.checkpoints.permissions.with_raw_response.retrieve( + fine_tuned_model_checkpoint="", + ) + + @parametrize + def test_method_delete(self, client: OpenAI) -> None: + permission = client.fine_tuning.checkpoints.permissions.delete( + "ft:gpt-4o-mini-2024-07-18:org:weather:B7R9VjQd", + ) + assert_matches_type(PermissionDeleteResponse, permission, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: OpenAI) -> None: + response = client.fine_tuning.checkpoints.permissions.with_raw_response.delete( + "ft:gpt-4o-mini-2024-07-18:org:weather:B7R9VjQd", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + permission = response.parse() + assert_matches_type(PermissionDeleteResponse, permission, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: OpenAI) -> None: + with client.fine_tuning.checkpoints.permissions.with_streaming_response.delete( + "ft:gpt-4o-mini-2024-07-18:org:weather:B7R9VjQd", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + permission = response.parse() + assert_matches_type(PermissionDeleteResponse, permission, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: OpenAI) -> None: + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `fine_tuned_model_checkpoint` but received ''" + ): + client.fine_tuning.checkpoints.permissions.with_raw_response.delete( + "", + ) + + +class TestAsyncPermissions: + parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + async def test_method_create(self, async_client: AsyncOpenAI) -> None: + permission = await async_client.fine_tuning.checkpoints.permissions.create( + fine_tuned_model_checkpoint="ft:gpt-4o-mini-2024-07-18:org:weather:B7R9VjQd", + project_ids=["string"], + ) + assert_matches_type(AsyncPage[PermissionCreateResponse], permission, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: + response = await async_client.fine_tuning.checkpoints.permissions.with_raw_response.create( + fine_tuned_model_checkpoint="ft:gpt-4o-mini-2024-07-18:org:weather:B7R9VjQd", + project_ids=["string"], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + permission = response.parse() + assert_matches_type(AsyncPage[PermissionCreateResponse], permission, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: + async with async_client.fine_tuning.checkpoints.permissions.with_streaming_response.create( + fine_tuned_model_checkpoint="ft:gpt-4o-mini-2024-07-18:org:weather:B7R9VjQd", + project_ids=["string"], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + permission = await response.parse() + assert_matches_type(AsyncPage[PermissionCreateResponse], permission, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create(self, async_client: AsyncOpenAI) -> None: + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `fine_tuned_model_checkpoint` but received ''" + ): + await async_client.fine_tuning.checkpoints.permissions.with_raw_response.create( + fine_tuned_model_checkpoint="", + project_ids=["string"], + ) + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + permission = await async_client.fine_tuning.checkpoints.permissions.retrieve( + fine_tuned_model_checkpoint="ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) + assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) + + @parametrize + async def test_method_retrieve_with_all_params(self, async_client: AsyncOpenAI) -> None: + permission = await async_client.fine_tuning.checkpoints.permissions.retrieve( + fine_tuned_model_checkpoint="ft-AF1WoRqd3aJAHsqc9NY7iL8F", + after="after", + limit=0, + order="ascending", + project_id="project_id", + ) + assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.fine_tuning.checkpoints.permissions.with_raw_response.retrieve( + fine_tuned_model_checkpoint="ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + permission = response.parse() + assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.fine_tuning.checkpoints.permissions.with_streaming_response.retrieve( + fine_tuned_model_checkpoint="ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + permission = await response.parse() + assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `fine_tuned_model_checkpoint` but received ''" + ): + await async_client.fine_tuning.checkpoints.permissions.with_raw_response.retrieve( + fine_tuned_model_checkpoint="", + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncOpenAI) -> None: + permission = await async_client.fine_tuning.checkpoints.permissions.delete( + "ft:gpt-4o-mini-2024-07-18:org:weather:B7R9VjQd", + ) + assert_matches_type(PermissionDeleteResponse, permission, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: + response = await async_client.fine_tuning.checkpoints.permissions.with_raw_response.delete( + "ft:gpt-4o-mini-2024-07-18:org:weather:B7R9VjQd", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + permission = response.parse() + assert_matches_type(PermissionDeleteResponse, permission, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: + async with async_client.fine_tuning.checkpoints.permissions.with_streaming_response.delete( + "ft:gpt-4o-mini-2024-07-18:org:weather:B7R9VjQd", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + permission = await response.parse() + assert_matches_type(PermissionDeleteResponse, permission, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `fine_tuned_model_checkpoint` but received ''" + ): + await async_client.fine_tuning.checkpoints.permissions.with_raw_response.delete( + "", + ) diff --git a/tests/api_resources/test_evals.py b/tests/api_resources/test_evals.py new file mode 100644 index 0000000000..33ba92cda5 --- /dev/null +++ b/tests/api_resources/test_evals.py @@ -0,0 +1,1701 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.types import ( + EvalListResponse, + EvalCreateResponse, + EvalDeleteResponse, + EvalUpdateResponse, + EvalRetrieveResponse, +) +from openai.pagination import SyncCursorPage, AsyncCursorPage + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestEvals: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: OpenAI) -> None: + eval = client.evals.create( + data_source_config={ + "item_schema": { + "0": "bar", + "1": "bar", + "2": "bar", + "3": "bar", + "4": "bar", + "5": "bar", + "6": "bar", + "7": "bar", + "8": "bar", + "9": "bar", + "10": "bar", + "11": "bar", + "12": "bar", + "13": "bar", + "14": "bar", + "15": "bar", + "16": "bar", + "17": "bar", + "18": "bar", + "19": "bar", + "20": "bar", + "21": "bar", + "22": "bar", + "23": "bar", + "24": "bar", + "25": "bar", + "26": "bar", + "27": "bar", + "28": "bar", + "29": "bar", + "30": "bar", + "31": "bar", + "32": "bar", + "33": "bar", + "34": "bar", + "35": "bar", + "36": "bar", + "37": "bar", + "38": "bar", + "39": "bar", + "40": "bar", + "41": "bar", + "42": "bar", + "43": "bar", + "44": "bar", + "45": "bar", + "46": "bar", + "47": "bar", + "48": "bar", + "49": "bar", + "50": "bar", + "51": "bar", + "52": "bar", + "53": "bar", + "54": "bar", + "55": "bar", + "56": "bar", + "57": "bar", + "58": "bar", + "59": "bar", + "60": "bar", + "61": "bar", + "62": "bar", + "63": "bar", + "64": "bar", + "65": "bar", + "66": "bar", + "67": "bar", + "68": "bar", + "69": "bar", + "70": "bar", + "71": "bar", + "72": "bar", + "73": "bar", + "74": "bar", + "75": "bar", + "76": "bar", + "77": "bar", + "78": "bar", + "79": "bar", + "80": "bar", + "81": "bar", + "82": "bar", + "83": "bar", + "84": "bar", + "85": "bar", + "86": "bar", + "87": "bar", + "88": "bar", + "89": "bar", + "90": "bar", + "91": "bar", + "92": "bar", + "93": "bar", + "94": "bar", + "95": "bar", + "96": "bar", + "97": "bar", + "98": "bar", + "99": "bar", + "100": "bar", + "101": "bar", + "102": "bar", + "103": "bar", + "104": "bar", + "105": "bar", + "106": "bar", + "107": "bar", + "108": "bar", + "109": "bar", + "110": "bar", + "111": "bar", + "112": "bar", + "113": "bar", + "114": "bar", + "115": "bar", + "116": "bar", + "117": "bar", + "118": "bar", + "119": "bar", + "120": "bar", + "121": "bar", + "122": "bar", + "123": "bar", + "124": "bar", + "125": "bar", + "126": "bar", + "127": "bar", + "128": "bar", + "129": "bar", + "130": "bar", + "131": "bar", + "132": "bar", + "133": "bar", + "134": "bar", + "135": "bar", + "136": "bar", + "137": "bar", + "138": "bar", + "139": "bar", + }, + "type": "custom", + }, + testing_criteria=[ + { + "input": [ + { + "content": "content", + "role": "role", + } + ], + "labels": ["string"], + "model": "model", + "name": "name", + "passing_labels": ["string"], + "type": "label_model", + } + ], + ) + assert_matches_type(EvalCreateResponse, eval, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: OpenAI) -> None: + eval = client.evals.create( + data_source_config={ + "item_schema": { + "0": "bar", + "1": "bar", + "2": "bar", + "3": "bar", + "4": "bar", + "5": "bar", + "6": "bar", + "7": "bar", + "8": "bar", + "9": "bar", + "10": "bar", + "11": "bar", + "12": "bar", + "13": "bar", + "14": "bar", + "15": "bar", + "16": "bar", + "17": "bar", + "18": "bar", + "19": "bar", + "20": "bar", + "21": "bar", + "22": "bar", + "23": "bar", + "24": "bar", + "25": "bar", + "26": "bar", + "27": "bar", + "28": "bar", + "29": "bar", + "30": "bar", + "31": "bar", + "32": "bar", + "33": "bar", + "34": "bar", + "35": "bar", + "36": "bar", + "37": "bar", + "38": "bar", + "39": "bar", + "40": "bar", + "41": "bar", + "42": "bar", + "43": "bar", + "44": "bar", + "45": "bar", + "46": "bar", + "47": "bar", + "48": "bar", + "49": "bar", + "50": "bar", + "51": "bar", + "52": "bar", + "53": "bar", + "54": "bar", + "55": "bar", + "56": "bar", + "57": "bar", + "58": "bar", + "59": "bar", + "60": "bar", + "61": "bar", + "62": "bar", + "63": "bar", + "64": "bar", + "65": "bar", + "66": "bar", + "67": "bar", + "68": "bar", + "69": "bar", + "70": "bar", + "71": "bar", + "72": "bar", + "73": "bar", + "74": "bar", + "75": "bar", + "76": "bar", + "77": "bar", + "78": "bar", + "79": "bar", + "80": "bar", + "81": "bar", + "82": "bar", + "83": "bar", + "84": "bar", + "85": "bar", + "86": "bar", + "87": "bar", + "88": "bar", + "89": "bar", + "90": "bar", + "91": "bar", + "92": "bar", + "93": "bar", + "94": "bar", + "95": "bar", + "96": "bar", + "97": "bar", + "98": "bar", + "99": "bar", + "100": "bar", + "101": "bar", + "102": "bar", + "103": "bar", + "104": "bar", + "105": "bar", + "106": "bar", + "107": "bar", + "108": "bar", + "109": "bar", + "110": "bar", + "111": "bar", + "112": "bar", + "113": "bar", + "114": "bar", + "115": "bar", + "116": "bar", + "117": "bar", + "118": "bar", + "119": "bar", + "120": "bar", + "121": "bar", + "122": "bar", + "123": "bar", + "124": "bar", + "125": "bar", + "126": "bar", + "127": "bar", + "128": "bar", + "129": "bar", + "130": "bar", + "131": "bar", + "132": "bar", + "133": "bar", + "134": "bar", + "135": "bar", + "136": "bar", + "137": "bar", + "138": "bar", + "139": "bar", + }, + "type": "custom", + "include_sample_schema": True, + }, + testing_criteria=[ + { + "input": [ + { + "content": "content", + "role": "role", + } + ], + "labels": ["string"], + "model": "model", + "name": "name", + "passing_labels": ["string"], + "type": "label_model", + } + ], + metadata={"foo": "string"}, + name="name", + share_with_openai=True, + ) + assert_matches_type(EvalCreateResponse, eval, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: OpenAI) -> None: + response = client.evals.with_raw_response.create( + data_source_config={ + "item_schema": { + "0": "bar", + "1": "bar", + "2": "bar", + "3": "bar", + "4": "bar", + "5": "bar", + "6": "bar", + "7": "bar", + "8": "bar", + "9": "bar", + "10": "bar", + "11": "bar", + "12": "bar", + "13": "bar", + "14": "bar", + "15": "bar", + "16": "bar", + "17": "bar", + "18": "bar", + "19": "bar", + "20": "bar", + "21": "bar", + "22": "bar", + "23": "bar", + "24": "bar", + "25": "bar", + "26": "bar", + "27": "bar", + "28": "bar", + "29": "bar", + "30": "bar", + "31": "bar", + "32": "bar", + "33": "bar", + "34": "bar", + "35": "bar", + "36": "bar", + "37": "bar", + "38": "bar", + "39": "bar", + "40": "bar", + "41": "bar", + "42": "bar", + "43": "bar", + "44": "bar", + "45": "bar", + "46": "bar", + "47": "bar", + "48": "bar", + "49": "bar", + "50": "bar", + "51": "bar", + "52": "bar", + "53": "bar", + "54": "bar", + "55": "bar", + "56": "bar", + "57": "bar", + "58": "bar", + "59": "bar", + "60": "bar", + "61": "bar", + "62": "bar", + "63": "bar", + "64": "bar", + "65": "bar", + "66": "bar", + "67": "bar", + "68": "bar", + "69": "bar", + "70": "bar", + "71": "bar", + "72": "bar", + "73": "bar", + "74": "bar", + "75": "bar", + "76": "bar", + "77": "bar", + "78": "bar", + "79": "bar", + "80": "bar", + "81": "bar", + "82": "bar", + "83": "bar", + "84": "bar", + "85": "bar", + "86": "bar", + "87": "bar", + "88": "bar", + "89": "bar", + "90": "bar", + "91": "bar", + "92": "bar", + "93": "bar", + "94": "bar", + "95": "bar", + "96": "bar", + "97": "bar", + "98": "bar", + "99": "bar", + "100": "bar", + "101": "bar", + "102": "bar", + "103": "bar", + "104": "bar", + "105": "bar", + "106": "bar", + "107": "bar", + "108": "bar", + "109": "bar", + "110": "bar", + "111": "bar", + "112": "bar", + "113": "bar", + "114": "bar", + "115": "bar", + "116": "bar", + "117": "bar", + "118": "bar", + "119": "bar", + "120": "bar", + "121": "bar", + "122": "bar", + "123": "bar", + "124": "bar", + "125": "bar", + "126": "bar", + "127": "bar", + "128": "bar", + "129": "bar", + "130": "bar", + "131": "bar", + "132": "bar", + "133": "bar", + "134": "bar", + "135": "bar", + "136": "bar", + "137": "bar", + "138": "bar", + "139": "bar", + }, + "type": "custom", + }, + testing_criteria=[ + { + "input": [ + { + "content": "content", + "role": "role", + } + ], + "labels": ["string"], + "model": "model", + "name": "name", + "passing_labels": ["string"], + "type": "label_model", + } + ], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + eval = response.parse() + assert_matches_type(EvalCreateResponse, eval, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: OpenAI) -> None: + with client.evals.with_streaming_response.create( + data_source_config={ + "item_schema": { + "0": "bar", + "1": "bar", + "2": "bar", + "3": "bar", + "4": "bar", + "5": "bar", + "6": "bar", + "7": "bar", + "8": "bar", + "9": "bar", + "10": "bar", + "11": "bar", + "12": "bar", + "13": "bar", + "14": "bar", + "15": "bar", + "16": "bar", + "17": "bar", + "18": "bar", + "19": "bar", + "20": "bar", + "21": "bar", + "22": "bar", + "23": "bar", + "24": "bar", + "25": "bar", + "26": "bar", + "27": "bar", + "28": "bar", + "29": "bar", + "30": "bar", + "31": "bar", + "32": "bar", + "33": "bar", + "34": "bar", + "35": "bar", + "36": "bar", + "37": "bar", + "38": "bar", + "39": "bar", + "40": "bar", + "41": "bar", + "42": "bar", + "43": "bar", + "44": "bar", + "45": "bar", + "46": "bar", + "47": "bar", + "48": "bar", + "49": "bar", + "50": "bar", + "51": "bar", + "52": "bar", + "53": "bar", + "54": "bar", + "55": "bar", + "56": "bar", + "57": "bar", + "58": "bar", + "59": "bar", + "60": "bar", + "61": "bar", + "62": "bar", + "63": "bar", + "64": "bar", + "65": "bar", + "66": "bar", + "67": "bar", + "68": "bar", + "69": "bar", + "70": "bar", + "71": "bar", + "72": "bar", + "73": "bar", + "74": "bar", + "75": "bar", + "76": "bar", + "77": "bar", + "78": "bar", + "79": "bar", + "80": "bar", + "81": "bar", + "82": "bar", + "83": "bar", + "84": "bar", + "85": "bar", + "86": "bar", + "87": "bar", + "88": "bar", + "89": "bar", + "90": "bar", + "91": "bar", + "92": "bar", + "93": "bar", + "94": "bar", + "95": "bar", + "96": "bar", + "97": "bar", + "98": "bar", + "99": "bar", + "100": "bar", + "101": "bar", + "102": "bar", + "103": "bar", + "104": "bar", + "105": "bar", + "106": "bar", + "107": "bar", + "108": "bar", + "109": "bar", + "110": "bar", + "111": "bar", + "112": "bar", + "113": "bar", + "114": "bar", + "115": "bar", + "116": "bar", + "117": "bar", + "118": "bar", + "119": "bar", + "120": "bar", + "121": "bar", + "122": "bar", + "123": "bar", + "124": "bar", + "125": "bar", + "126": "bar", + "127": "bar", + "128": "bar", + "129": "bar", + "130": "bar", + "131": "bar", + "132": "bar", + "133": "bar", + "134": "bar", + "135": "bar", + "136": "bar", + "137": "bar", + "138": "bar", + "139": "bar", + }, + "type": "custom", + }, + testing_criteria=[ + { + "input": [ + { + "content": "content", + "role": "role", + } + ], + "labels": ["string"], + "model": "model", + "name": "name", + "passing_labels": ["string"], + "type": "label_model", + } + ], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + eval = response.parse() + assert_matches_type(EvalCreateResponse, eval, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + eval = client.evals.retrieve( + "eval_id", + ) + assert_matches_type(EvalRetrieveResponse, eval, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.evals.with_raw_response.retrieve( + "eval_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + eval = response.parse() + assert_matches_type(EvalRetrieveResponse, eval, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.evals.with_streaming_response.retrieve( + "eval_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + eval = response.parse() + assert_matches_type(EvalRetrieveResponse, eval, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `eval_id` but received ''"): + client.evals.with_raw_response.retrieve( + "", + ) + + @parametrize + def test_method_update(self, client: OpenAI) -> None: + eval = client.evals.update( + eval_id="eval_id", + ) + assert_matches_type(EvalUpdateResponse, eval, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: OpenAI) -> None: + eval = client.evals.update( + eval_id="eval_id", + metadata={"foo": "string"}, + name="name", + ) + assert_matches_type(EvalUpdateResponse, eval, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: OpenAI) -> None: + response = client.evals.with_raw_response.update( + eval_id="eval_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + eval = response.parse() + assert_matches_type(EvalUpdateResponse, eval, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: OpenAI) -> None: + with client.evals.with_streaming_response.update( + eval_id="eval_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + eval = response.parse() + assert_matches_type(EvalUpdateResponse, eval, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `eval_id` but received ''"): + client.evals.with_raw_response.update( + eval_id="", + ) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + eval = client.evals.list() + assert_matches_type(SyncCursorPage[EvalListResponse], eval, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + eval = client.evals.list( + after="after", + limit=0, + order="asc", + order_by="created_at", + ) + assert_matches_type(SyncCursorPage[EvalListResponse], eval, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.evals.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + eval = response.parse() + assert_matches_type(SyncCursorPage[EvalListResponse], eval, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.evals.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + eval = response.parse() + assert_matches_type(SyncCursorPage[EvalListResponse], eval, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: OpenAI) -> None: + eval = client.evals.delete( + "eval_id", + ) + assert_matches_type(EvalDeleteResponse, eval, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: OpenAI) -> None: + response = client.evals.with_raw_response.delete( + "eval_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + eval = response.parse() + assert_matches_type(EvalDeleteResponse, eval, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: OpenAI) -> None: + with client.evals.with_streaming_response.delete( + "eval_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + eval = response.parse() + assert_matches_type(EvalDeleteResponse, eval, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `eval_id` but received ''"): + client.evals.with_raw_response.delete( + "", + ) + + +class TestAsyncEvals: + parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + async def test_method_create(self, async_client: AsyncOpenAI) -> None: + eval = await async_client.evals.create( + data_source_config={ + "item_schema": { + "0": "bar", + "1": "bar", + "2": "bar", + "3": "bar", + "4": "bar", + "5": "bar", + "6": "bar", + "7": "bar", + "8": "bar", + "9": "bar", + "10": "bar", + "11": "bar", + "12": "bar", + "13": "bar", + "14": "bar", + "15": "bar", + "16": "bar", + "17": "bar", + "18": "bar", + "19": "bar", + "20": "bar", + "21": "bar", + "22": "bar", + "23": "bar", + "24": "bar", + "25": "bar", + "26": "bar", + "27": "bar", + "28": "bar", + "29": "bar", + "30": "bar", + "31": "bar", + "32": "bar", + "33": "bar", + "34": "bar", + "35": "bar", + "36": "bar", + "37": "bar", + "38": "bar", + "39": "bar", + "40": "bar", + "41": "bar", + "42": "bar", + "43": "bar", + "44": "bar", + "45": "bar", + "46": "bar", + "47": "bar", + "48": "bar", + "49": "bar", + "50": "bar", + "51": "bar", + "52": "bar", + "53": "bar", + "54": "bar", + "55": "bar", + "56": "bar", + "57": "bar", + "58": "bar", + "59": "bar", + "60": "bar", + "61": "bar", + "62": "bar", + "63": "bar", + "64": "bar", + "65": "bar", + "66": "bar", + "67": "bar", + "68": "bar", + "69": "bar", + "70": "bar", + "71": "bar", + "72": "bar", + "73": "bar", + "74": "bar", + "75": "bar", + "76": "bar", + "77": "bar", + "78": "bar", + "79": "bar", + "80": "bar", + "81": "bar", + "82": "bar", + "83": "bar", + "84": "bar", + "85": "bar", + "86": "bar", + "87": "bar", + "88": "bar", + "89": "bar", + "90": "bar", + "91": "bar", + "92": "bar", + "93": "bar", + "94": "bar", + "95": "bar", + "96": "bar", + "97": "bar", + "98": "bar", + "99": "bar", + "100": "bar", + "101": "bar", + "102": "bar", + "103": "bar", + "104": "bar", + "105": "bar", + "106": "bar", + "107": "bar", + "108": "bar", + "109": "bar", + "110": "bar", + "111": "bar", + "112": "bar", + "113": "bar", + "114": "bar", + "115": "bar", + "116": "bar", + "117": "bar", + "118": "bar", + "119": "bar", + "120": "bar", + "121": "bar", + "122": "bar", + "123": "bar", + "124": "bar", + "125": "bar", + "126": "bar", + "127": "bar", + "128": "bar", + "129": "bar", + "130": "bar", + "131": "bar", + "132": "bar", + "133": "bar", + "134": "bar", + "135": "bar", + "136": "bar", + "137": "bar", + "138": "bar", + "139": "bar", + }, + "type": "custom", + }, + testing_criteria=[ + { + "input": [ + { + "content": "content", + "role": "role", + } + ], + "labels": ["string"], + "model": "model", + "name": "name", + "passing_labels": ["string"], + "type": "label_model", + } + ], + ) + assert_matches_type(EvalCreateResponse, eval, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: + eval = await async_client.evals.create( + data_source_config={ + "item_schema": { + "0": "bar", + "1": "bar", + "2": "bar", + "3": "bar", + "4": "bar", + "5": "bar", + "6": "bar", + "7": "bar", + "8": "bar", + "9": "bar", + "10": "bar", + "11": "bar", + "12": "bar", + "13": "bar", + "14": "bar", + "15": "bar", + "16": "bar", + "17": "bar", + "18": "bar", + "19": "bar", + "20": "bar", + "21": "bar", + "22": "bar", + "23": "bar", + "24": "bar", + "25": "bar", + "26": "bar", + "27": "bar", + "28": "bar", + "29": "bar", + "30": "bar", + "31": "bar", + "32": "bar", + "33": "bar", + "34": "bar", + "35": "bar", + "36": "bar", + "37": "bar", + "38": "bar", + "39": "bar", + "40": "bar", + "41": "bar", + "42": "bar", + "43": "bar", + "44": "bar", + "45": "bar", + "46": "bar", + "47": "bar", + "48": "bar", + "49": "bar", + "50": "bar", + "51": "bar", + "52": "bar", + "53": "bar", + "54": "bar", + "55": "bar", + "56": "bar", + "57": "bar", + "58": "bar", + "59": "bar", + "60": "bar", + "61": "bar", + "62": "bar", + "63": "bar", + "64": "bar", + "65": "bar", + "66": "bar", + "67": "bar", + "68": "bar", + "69": "bar", + "70": "bar", + "71": "bar", + "72": "bar", + "73": "bar", + "74": "bar", + "75": "bar", + "76": "bar", + "77": "bar", + "78": "bar", + "79": "bar", + "80": "bar", + "81": "bar", + "82": "bar", + "83": "bar", + "84": "bar", + "85": "bar", + "86": "bar", + "87": "bar", + "88": "bar", + "89": "bar", + "90": "bar", + "91": "bar", + "92": "bar", + "93": "bar", + "94": "bar", + "95": "bar", + "96": "bar", + "97": "bar", + "98": "bar", + "99": "bar", + "100": "bar", + "101": "bar", + "102": "bar", + "103": "bar", + "104": "bar", + "105": "bar", + "106": "bar", + "107": "bar", + "108": "bar", + "109": "bar", + "110": "bar", + "111": "bar", + "112": "bar", + "113": "bar", + "114": "bar", + "115": "bar", + "116": "bar", + "117": "bar", + "118": "bar", + "119": "bar", + "120": "bar", + "121": "bar", + "122": "bar", + "123": "bar", + "124": "bar", + "125": "bar", + "126": "bar", + "127": "bar", + "128": "bar", + "129": "bar", + "130": "bar", + "131": "bar", + "132": "bar", + "133": "bar", + "134": "bar", + "135": "bar", + "136": "bar", + "137": "bar", + "138": "bar", + "139": "bar", + }, + "type": "custom", + "include_sample_schema": True, + }, + testing_criteria=[ + { + "input": [ + { + "content": "content", + "role": "role", + } + ], + "labels": ["string"], + "model": "model", + "name": "name", + "passing_labels": ["string"], + "type": "label_model", + } + ], + metadata={"foo": "string"}, + name="name", + share_with_openai=True, + ) + assert_matches_type(EvalCreateResponse, eval, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: + response = await async_client.evals.with_raw_response.create( + data_source_config={ + "item_schema": { + "0": "bar", + "1": "bar", + "2": "bar", + "3": "bar", + "4": "bar", + "5": "bar", + "6": "bar", + "7": "bar", + "8": "bar", + "9": "bar", + "10": "bar", + "11": "bar", + "12": "bar", + "13": "bar", + "14": "bar", + "15": "bar", + "16": "bar", + "17": "bar", + "18": "bar", + "19": "bar", + "20": "bar", + "21": "bar", + "22": "bar", + "23": "bar", + "24": "bar", + "25": "bar", + "26": "bar", + "27": "bar", + "28": "bar", + "29": "bar", + "30": "bar", + "31": "bar", + "32": "bar", + "33": "bar", + "34": "bar", + "35": "bar", + "36": "bar", + "37": "bar", + "38": "bar", + "39": "bar", + "40": "bar", + "41": "bar", + "42": "bar", + "43": "bar", + "44": "bar", + "45": "bar", + "46": "bar", + "47": "bar", + "48": "bar", + "49": "bar", + "50": "bar", + "51": "bar", + "52": "bar", + "53": "bar", + "54": "bar", + "55": "bar", + "56": "bar", + "57": "bar", + "58": "bar", + "59": "bar", + "60": "bar", + "61": "bar", + "62": "bar", + "63": "bar", + "64": "bar", + "65": "bar", + "66": "bar", + "67": "bar", + "68": "bar", + "69": "bar", + "70": "bar", + "71": "bar", + "72": "bar", + "73": "bar", + "74": "bar", + "75": "bar", + "76": "bar", + "77": "bar", + "78": "bar", + "79": "bar", + "80": "bar", + "81": "bar", + "82": "bar", + "83": "bar", + "84": "bar", + "85": "bar", + "86": "bar", + "87": "bar", + "88": "bar", + "89": "bar", + "90": "bar", + "91": "bar", + "92": "bar", + "93": "bar", + "94": "bar", + "95": "bar", + "96": "bar", + "97": "bar", + "98": "bar", + "99": "bar", + "100": "bar", + "101": "bar", + "102": "bar", + "103": "bar", + "104": "bar", + "105": "bar", + "106": "bar", + "107": "bar", + "108": "bar", + "109": "bar", + "110": "bar", + "111": "bar", + "112": "bar", + "113": "bar", + "114": "bar", + "115": "bar", + "116": "bar", + "117": "bar", + "118": "bar", + "119": "bar", + "120": "bar", + "121": "bar", + "122": "bar", + "123": "bar", + "124": "bar", + "125": "bar", + "126": "bar", + "127": "bar", + "128": "bar", + "129": "bar", + "130": "bar", + "131": "bar", + "132": "bar", + "133": "bar", + "134": "bar", + "135": "bar", + "136": "bar", + "137": "bar", + "138": "bar", + "139": "bar", + }, + "type": "custom", + }, + testing_criteria=[ + { + "input": [ + { + "content": "content", + "role": "role", + } + ], + "labels": ["string"], + "model": "model", + "name": "name", + "passing_labels": ["string"], + "type": "label_model", + } + ], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + eval = response.parse() + assert_matches_type(EvalCreateResponse, eval, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: + async with async_client.evals.with_streaming_response.create( + data_source_config={ + "item_schema": { + "0": "bar", + "1": "bar", + "2": "bar", + "3": "bar", + "4": "bar", + "5": "bar", + "6": "bar", + "7": "bar", + "8": "bar", + "9": "bar", + "10": "bar", + "11": "bar", + "12": "bar", + "13": "bar", + "14": "bar", + "15": "bar", + "16": "bar", + "17": "bar", + "18": "bar", + "19": "bar", + "20": "bar", + "21": "bar", + "22": "bar", + "23": "bar", + "24": "bar", + "25": "bar", + "26": "bar", + "27": "bar", + "28": "bar", + "29": "bar", + "30": "bar", + "31": "bar", + "32": "bar", + "33": "bar", + "34": "bar", + "35": "bar", + "36": "bar", + "37": "bar", + "38": "bar", + "39": "bar", + "40": "bar", + "41": "bar", + "42": "bar", + "43": "bar", + "44": "bar", + "45": "bar", + "46": "bar", + "47": "bar", + "48": "bar", + "49": "bar", + "50": "bar", + "51": "bar", + "52": "bar", + "53": "bar", + "54": "bar", + "55": "bar", + "56": "bar", + "57": "bar", + "58": "bar", + "59": "bar", + "60": "bar", + "61": "bar", + "62": "bar", + "63": "bar", + "64": "bar", + "65": "bar", + "66": "bar", + "67": "bar", + "68": "bar", + "69": "bar", + "70": "bar", + "71": "bar", + "72": "bar", + "73": "bar", + "74": "bar", + "75": "bar", + "76": "bar", + "77": "bar", + "78": "bar", + "79": "bar", + "80": "bar", + "81": "bar", + "82": "bar", + "83": "bar", + "84": "bar", + "85": "bar", + "86": "bar", + "87": "bar", + "88": "bar", + "89": "bar", + "90": "bar", + "91": "bar", + "92": "bar", + "93": "bar", + "94": "bar", + "95": "bar", + "96": "bar", + "97": "bar", + "98": "bar", + "99": "bar", + "100": "bar", + "101": "bar", + "102": "bar", + "103": "bar", + "104": "bar", + "105": "bar", + "106": "bar", + "107": "bar", + "108": "bar", + "109": "bar", + "110": "bar", + "111": "bar", + "112": "bar", + "113": "bar", + "114": "bar", + "115": "bar", + "116": "bar", + "117": "bar", + "118": "bar", + "119": "bar", + "120": "bar", + "121": "bar", + "122": "bar", + "123": "bar", + "124": "bar", + "125": "bar", + "126": "bar", + "127": "bar", + "128": "bar", + "129": "bar", + "130": "bar", + "131": "bar", + "132": "bar", + "133": "bar", + "134": "bar", + "135": "bar", + "136": "bar", + "137": "bar", + "138": "bar", + "139": "bar", + }, + "type": "custom", + }, + testing_criteria=[ + { + "input": [ + { + "content": "content", + "role": "role", + } + ], + "labels": ["string"], + "model": "model", + "name": "name", + "passing_labels": ["string"], + "type": "label_model", + } + ], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + eval = await response.parse() + assert_matches_type(EvalCreateResponse, eval, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + eval = await async_client.evals.retrieve( + "eval_id", + ) + assert_matches_type(EvalRetrieveResponse, eval, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.evals.with_raw_response.retrieve( + "eval_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + eval = response.parse() + assert_matches_type(EvalRetrieveResponse, eval, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.evals.with_streaming_response.retrieve( + "eval_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + eval = await response.parse() + assert_matches_type(EvalRetrieveResponse, eval, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `eval_id` but received ''"): + await async_client.evals.with_raw_response.retrieve( + "", + ) + + @parametrize + async def test_method_update(self, async_client: AsyncOpenAI) -> None: + eval = await async_client.evals.update( + eval_id="eval_id", + ) + assert_matches_type(EvalUpdateResponse, eval, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncOpenAI) -> None: + eval = await async_client.evals.update( + eval_id="eval_id", + metadata={"foo": "string"}, + name="name", + ) + assert_matches_type(EvalUpdateResponse, eval, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: + response = await async_client.evals.with_raw_response.update( + eval_id="eval_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + eval = response.parse() + assert_matches_type(EvalUpdateResponse, eval, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncOpenAI) -> None: + async with async_client.evals.with_streaming_response.update( + eval_id="eval_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + eval = await response.parse() + assert_matches_type(EvalUpdateResponse, eval, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `eval_id` but received ''"): + await async_client.evals.with_raw_response.update( + eval_id="", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + eval = await async_client.evals.list() + assert_matches_type(AsyncCursorPage[EvalListResponse], eval, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + eval = await async_client.evals.list( + after="after", + limit=0, + order="asc", + order_by="created_at", + ) + assert_matches_type(AsyncCursorPage[EvalListResponse], eval, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.evals.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + eval = response.parse() + assert_matches_type(AsyncCursorPage[EvalListResponse], eval, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.evals.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + eval = await response.parse() + assert_matches_type(AsyncCursorPage[EvalListResponse], eval, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncOpenAI) -> None: + eval = await async_client.evals.delete( + "eval_id", + ) + assert_matches_type(EvalDeleteResponse, eval, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: + response = await async_client.evals.with_raw_response.delete( + "eval_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + eval = response.parse() + assert_matches_type(EvalDeleteResponse, eval, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: + async with async_client.evals.with_streaming_response.delete( + "eval_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + eval = await response.parse() + assert_matches_type(EvalDeleteResponse, eval, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `eval_id` but received ''"): + await async_client.evals.with_raw_response.delete( + "", + ) From 58163842137c006c37e833c7d08e02dc7415a59b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 8 Apr 2025 19:44:37 +0000 Subject: [PATCH 278/769] chore(internal): fix examples (#2288) --- .stats.yml | 4 +- tests/api_resources/beta/test_threads.py | 8 +- tests/api_resources/beta/threads/test_runs.py | 8 +- tests/api_resources/test_evals.py | 1144 +---------------- tests/api_resources/test_images.py | 12 +- tests/api_resources/test_moderations.py | 4 +- 6 files changed, 26 insertions(+), 1154 deletions(-) diff --git a/.stats.yml b/.stats.yml index ebe07c1372..4a82ee242d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 97 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-472fe3036ea745365257fe870c0330917fb3153705c2826f49873cd631319b0a.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-32de3bc513663c5fac922c49be41c222b6ee8c0b841d8966bcdfa489d441daa3.yml openapi_spec_hash: ea86343b5e9858a74e85da8ab2c532f6 -config_hash: ef19d36c307306f14f2e1cd5c834a151 +config_hash: d6c61213488683418adb860a9ee1501b diff --git a/tests/api_resources/beta/test_threads.py b/tests/api_resources/beta/test_threads.py index ecf5b11102..9916d5bdc6 100644 --- a/tests/api_resources/beta/test_threads.py +++ b/tests/api_resources/beta/test_threads.py @@ -220,7 +220,7 @@ def test_method_create_and_run_with_all_params_overload_1(self, client: OpenAI) max_completion_tokens=256, max_prompt_tokens=256, metadata={"foo": "string"}, - model="gpt-4o", + model="string", parallel_tool_calls=True, response_format="auto", stream=False, @@ -309,7 +309,7 @@ def test_method_create_and_run_with_all_params_overload_2(self, client: OpenAI) max_completion_tokens=256, max_prompt_tokens=256, metadata={"foo": "string"}, - model="gpt-4o", + model="string", parallel_tool_calls=True, response_format="auto", temperature=1, @@ -584,7 +584,7 @@ async def test_method_create_and_run_with_all_params_overload_1(self, async_clie max_completion_tokens=256, max_prompt_tokens=256, metadata={"foo": "string"}, - model="gpt-4o", + model="string", parallel_tool_calls=True, response_format="auto", stream=False, @@ -673,7 +673,7 @@ async def test_method_create_and_run_with_all_params_overload_2(self, async_clie max_completion_tokens=256, max_prompt_tokens=256, metadata={"foo": "string"}, - model="gpt-4o", + model="string", parallel_tool_calls=True, response_format="auto", temperature=1, diff --git a/tests/api_resources/beta/threads/test_runs.py b/tests/api_resources/beta/threads/test_runs.py index d05ee96144..4230ccebe4 100644 --- a/tests/api_resources/beta/threads/test_runs.py +++ b/tests/api_resources/beta/threads/test_runs.py @@ -54,7 +54,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: max_completion_tokens=256, max_prompt_tokens=256, metadata={"foo": "string"}, - model="gpt-4o", + model="string", parallel_tool_calls=True, reasoning_effort="low", response_format="auto", @@ -138,7 +138,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: max_completion_tokens=256, max_prompt_tokens=256, metadata={"foo": "string"}, - model="gpt-4o", + model="string", parallel_tool_calls=True, reasoning_effort="low", response_format="auto", @@ -552,7 +552,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn max_completion_tokens=256, max_prompt_tokens=256, metadata={"foo": "string"}, - model="gpt-4o", + model="string", parallel_tool_calls=True, reasoning_effort="low", response_format="auto", @@ -636,7 +636,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn max_completion_tokens=256, max_prompt_tokens=256, metadata={"foo": "string"}, - model="gpt-4o", + model="string", parallel_tool_calls=True, reasoning_effort="low", response_format="auto", diff --git a/tests/api_resources/test_evals.py b/tests/api_resources/test_evals.py index 33ba92cda5..8d03513b32 100644 --- a/tests/api_resources/test_evals.py +++ b/tests/api_resources/test_evals.py @@ -28,148 +28,7 @@ class TestEvals: def test_method_create(self, client: OpenAI) -> None: eval = client.evals.create( data_source_config={ - "item_schema": { - "0": "bar", - "1": "bar", - "2": "bar", - "3": "bar", - "4": "bar", - "5": "bar", - "6": "bar", - "7": "bar", - "8": "bar", - "9": "bar", - "10": "bar", - "11": "bar", - "12": "bar", - "13": "bar", - "14": "bar", - "15": "bar", - "16": "bar", - "17": "bar", - "18": "bar", - "19": "bar", - "20": "bar", - "21": "bar", - "22": "bar", - "23": "bar", - "24": "bar", - "25": "bar", - "26": "bar", - "27": "bar", - "28": "bar", - "29": "bar", - "30": "bar", - "31": "bar", - "32": "bar", - "33": "bar", - "34": "bar", - "35": "bar", - "36": "bar", - "37": "bar", - "38": "bar", - "39": "bar", - "40": "bar", - "41": "bar", - "42": "bar", - "43": "bar", - "44": "bar", - "45": "bar", - "46": "bar", - "47": "bar", - "48": "bar", - "49": "bar", - "50": "bar", - "51": "bar", - "52": "bar", - "53": "bar", - "54": "bar", - "55": "bar", - "56": "bar", - "57": "bar", - "58": "bar", - "59": "bar", - "60": "bar", - "61": "bar", - "62": "bar", - "63": "bar", - "64": "bar", - "65": "bar", - "66": "bar", - "67": "bar", - "68": "bar", - "69": "bar", - "70": "bar", - "71": "bar", - "72": "bar", - "73": "bar", - "74": "bar", - "75": "bar", - "76": "bar", - "77": "bar", - "78": "bar", - "79": "bar", - "80": "bar", - "81": "bar", - "82": "bar", - "83": "bar", - "84": "bar", - "85": "bar", - "86": "bar", - "87": "bar", - "88": "bar", - "89": "bar", - "90": "bar", - "91": "bar", - "92": "bar", - "93": "bar", - "94": "bar", - "95": "bar", - "96": "bar", - "97": "bar", - "98": "bar", - "99": "bar", - "100": "bar", - "101": "bar", - "102": "bar", - "103": "bar", - "104": "bar", - "105": "bar", - "106": "bar", - "107": "bar", - "108": "bar", - "109": "bar", - "110": "bar", - "111": "bar", - "112": "bar", - "113": "bar", - "114": "bar", - "115": "bar", - "116": "bar", - "117": "bar", - "118": "bar", - "119": "bar", - "120": "bar", - "121": "bar", - "122": "bar", - "123": "bar", - "124": "bar", - "125": "bar", - "126": "bar", - "127": "bar", - "128": "bar", - "129": "bar", - "130": "bar", - "131": "bar", - "132": "bar", - "133": "bar", - "134": "bar", - "135": "bar", - "136": "bar", - "137": "bar", - "138": "bar", - "139": "bar", - }, + "item_schema": {"foo": "bar"}, "type": "custom", }, testing_criteria=[ @@ -194,148 +53,7 @@ def test_method_create(self, client: OpenAI) -> None: def test_method_create_with_all_params(self, client: OpenAI) -> None: eval = client.evals.create( data_source_config={ - "item_schema": { - "0": "bar", - "1": "bar", - "2": "bar", - "3": "bar", - "4": "bar", - "5": "bar", - "6": "bar", - "7": "bar", - "8": "bar", - "9": "bar", - "10": "bar", - "11": "bar", - "12": "bar", - "13": "bar", - "14": "bar", - "15": "bar", - "16": "bar", - "17": "bar", - "18": "bar", - "19": "bar", - "20": "bar", - "21": "bar", - "22": "bar", - "23": "bar", - "24": "bar", - "25": "bar", - "26": "bar", - "27": "bar", - "28": "bar", - "29": "bar", - "30": "bar", - "31": "bar", - "32": "bar", - "33": "bar", - "34": "bar", - "35": "bar", - "36": "bar", - "37": "bar", - "38": "bar", - "39": "bar", - "40": "bar", - "41": "bar", - "42": "bar", - "43": "bar", - "44": "bar", - "45": "bar", - "46": "bar", - "47": "bar", - "48": "bar", - "49": "bar", - "50": "bar", - "51": "bar", - "52": "bar", - "53": "bar", - "54": "bar", - "55": "bar", - "56": "bar", - "57": "bar", - "58": "bar", - "59": "bar", - "60": "bar", - "61": "bar", - "62": "bar", - "63": "bar", - "64": "bar", - "65": "bar", - "66": "bar", - "67": "bar", - "68": "bar", - "69": "bar", - "70": "bar", - "71": "bar", - "72": "bar", - "73": "bar", - "74": "bar", - "75": "bar", - "76": "bar", - "77": "bar", - "78": "bar", - "79": "bar", - "80": "bar", - "81": "bar", - "82": "bar", - "83": "bar", - "84": "bar", - "85": "bar", - "86": "bar", - "87": "bar", - "88": "bar", - "89": "bar", - "90": "bar", - "91": "bar", - "92": "bar", - "93": "bar", - "94": "bar", - "95": "bar", - "96": "bar", - "97": "bar", - "98": "bar", - "99": "bar", - "100": "bar", - "101": "bar", - "102": "bar", - "103": "bar", - "104": "bar", - "105": "bar", - "106": "bar", - "107": "bar", - "108": "bar", - "109": "bar", - "110": "bar", - "111": "bar", - "112": "bar", - "113": "bar", - "114": "bar", - "115": "bar", - "116": "bar", - "117": "bar", - "118": "bar", - "119": "bar", - "120": "bar", - "121": "bar", - "122": "bar", - "123": "bar", - "124": "bar", - "125": "bar", - "126": "bar", - "127": "bar", - "128": "bar", - "129": "bar", - "130": "bar", - "131": "bar", - "132": "bar", - "133": "bar", - "134": "bar", - "135": "bar", - "136": "bar", - "137": "bar", - "138": "bar", - "139": "bar", - }, + "item_schema": {"foo": "bar"}, "type": "custom", "include_sample_schema": True, }, @@ -364,148 +82,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: def test_raw_response_create(self, client: OpenAI) -> None: response = client.evals.with_raw_response.create( data_source_config={ - "item_schema": { - "0": "bar", - "1": "bar", - "2": "bar", - "3": "bar", - "4": "bar", - "5": "bar", - "6": "bar", - "7": "bar", - "8": "bar", - "9": "bar", - "10": "bar", - "11": "bar", - "12": "bar", - "13": "bar", - "14": "bar", - "15": "bar", - "16": "bar", - "17": "bar", - "18": "bar", - "19": "bar", - "20": "bar", - "21": "bar", - "22": "bar", - "23": "bar", - "24": "bar", - "25": "bar", - "26": "bar", - "27": "bar", - "28": "bar", - "29": "bar", - "30": "bar", - "31": "bar", - "32": "bar", - "33": "bar", - "34": "bar", - "35": "bar", - "36": "bar", - "37": "bar", - "38": "bar", - "39": "bar", - "40": "bar", - "41": "bar", - "42": "bar", - "43": "bar", - "44": "bar", - "45": "bar", - "46": "bar", - "47": "bar", - "48": "bar", - "49": "bar", - "50": "bar", - "51": "bar", - "52": "bar", - "53": "bar", - "54": "bar", - "55": "bar", - "56": "bar", - "57": "bar", - "58": "bar", - "59": "bar", - "60": "bar", - "61": "bar", - "62": "bar", - "63": "bar", - "64": "bar", - "65": "bar", - "66": "bar", - "67": "bar", - "68": "bar", - "69": "bar", - "70": "bar", - "71": "bar", - "72": "bar", - "73": "bar", - "74": "bar", - "75": "bar", - "76": "bar", - "77": "bar", - "78": "bar", - "79": "bar", - "80": "bar", - "81": "bar", - "82": "bar", - "83": "bar", - "84": "bar", - "85": "bar", - "86": "bar", - "87": "bar", - "88": "bar", - "89": "bar", - "90": "bar", - "91": "bar", - "92": "bar", - "93": "bar", - "94": "bar", - "95": "bar", - "96": "bar", - "97": "bar", - "98": "bar", - "99": "bar", - "100": "bar", - "101": "bar", - "102": "bar", - "103": "bar", - "104": "bar", - "105": "bar", - "106": "bar", - "107": "bar", - "108": "bar", - "109": "bar", - "110": "bar", - "111": "bar", - "112": "bar", - "113": "bar", - "114": "bar", - "115": "bar", - "116": "bar", - "117": "bar", - "118": "bar", - "119": "bar", - "120": "bar", - "121": "bar", - "122": "bar", - "123": "bar", - "124": "bar", - "125": "bar", - "126": "bar", - "127": "bar", - "128": "bar", - "129": "bar", - "130": "bar", - "131": "bar", - "132": "bar", - "133": "bar", - "134": "bar", - "135": "bar", - "136": "bar", - "137": "bar", - "138": "bar", - "139": "bar", - }, + "item_schema": {"foo": "bar"}, "type": "custom", }, testing_criteria=[ @@ -534,148 +111,7 @@ def test_raw_response_create(self, client: OpenAI) -> None: def test_streaming_response_create(self, client: OpenAI) -> None: with client.evals.with_streaming_response.create( data_source_config={ - "item_schema": { - "0": "bar", - "1": "bar", - "2": "bar", - "3": "bar", - "4": "bar", - "5": "bar", - "6": "bar", - "7": "bar", - "8": "bar", - "9": "bar", - "10": "bar", - "11": "bar", - "12": "bar", - "13": "bar", - "14": "bar", - "15": "bar", - "16": "bar", - "17": "bar", - "18": "bar", - "19": "bar", - "20": "bar", - "21": "bar", - "22": "bar", - "23": "bar", - "24": "bar", - "25": "bar", - "26": "bar", - "27": "bar", - "28": "bar", - "29": "bar", - "30": "bar", - "31": "bar", - "32": "bar", - "33": "bar", - "34": "bar", - "35": "bar", - "36": "bar", - "37": "bar", - "38": "bar", - "39": "bar", - "40": "bar", - "41": "bar", - "42": "bar", - "43": "bar", - "44": "bar", - "45": "bar", - "46": "bar", - "47": "bar", - "48": "bar", - "49": "bar", - "50": "bar", - "51": "bar", - "52": "bar", - "53": "bar", - "54": "bar", - "55": "bar", - "56": "bar", - "57": "bar", - "58": "bar", - "59": "bar", - "60": "bar", - "61": "bar", - "62": "bar", - "63": "bar", - "64": "bar", - "65": "bar", - "66": "bar", - "67": "bar", - "68": "bar", - "69": "bar", - "70": "bar", - "71": "bar", - "72": "bar", - "73": "bar", - "74": "bar", - "75": "bar", - "76": "bar", - "77": "bar", - "78": "bar", - "79": "bar", - "80": "bar", - "81": "bar", - "82": "bar", - "83": "bar", - "84": "bar", - "85": "bar", - "86": "bar", - "87": "bar", - "88": "bar", - "89": "bar", - "90": "bar", - "91": "bar", - "92": "bar", - "93": "bar", - "94": "bar", - "95": "bar", - "96": "bar", - "97": "bar", - "98": "bar", - "99": "bar", - "100": "bar", - "101": "bar", - "102": "bar", - "103": "bar", - "104": "bar", - "105": "bar", - "106": "bar", - "107": "bar", - "108": "bar", - "109": "bar", - "110": "bar", - "111": "bar", - "112": "bar", - "113": "bar", - "114": "bar", - "115": "bar", - "116": "bar", - "117": "bar", - "118": "bar", - "119": "bar", - "120": "bar", - "121": "bar", - "122": "bar", - "123": "bar", - "124": "bar", - "125": "bar", - "126": "bar", - "127": "bar", - "128": "bar", - "129": "bar", - "130": "bar", - "131": "bar", - "132": "bar", - "133": "bar", - "134": "bar", - "135": "bar", - "136": "bar", - "137": "bar", - "138": "bar", - "139": "bar", - }, + "item_schema": {"foo": "bar"}, "type": "custom", }, testing_criteria=[ @@ -868,148 +304,7 @@ class TestAsyncEvals: async def test_method_create(self, async_client: AsyncOpenAI) -> None: eval = await async_client.evals.create( data_source_config={ - "item_schema": { - "0": "bar", - "1": "bar", - "2": "bar", - "3": "bar", - "4": "bar", - "5": "bar", - "6": "bar", - "7": "bar", - "8": "bar", - "9": "bar", - "10": "bar", - "11": "bar", - "12": "bar", - "13": "bar", - "14": "bar", - "15": "bar", - "16": "bar", - "17": "bar", - "18": "bar", - "19": "bar", - "20": "bar", - "21": "bar", - "22": "bar", - "23": "bar", - "24": "bar", - "25": "bar", - "26": "bar", - "27": "bar", - "28": "bar", - "29": "bar", - "30": "bar", - "31": "bar", - "32": "bar", - "33": "bar", - "34": "bar", - "35": "bar", - "36": "bar", - "37": "bar", - "38": "bar", - "39": "bar", - "40": "bar", - "41": "bar", - "42": "bar", - "43": "bar", - "44": "bar", - "45": "bar", - "46": "bar", - "47": "bar", - "48": "bar", - "49": "bar", - "50": "bar", - "51": "bar", - "52": "bar", - "53": "bar", - "54": "bar", - "55": "bar", - "56": "bar", - "57": "bar", - "58": "bar", - "59": "bar", - "60": "bar", - "61": "bar", - "62": "bar", - "63": "bar", - "64": "bar", - "65": "bar", - "66": "bar", - "67": "bar", - "68": "bar", - "69": "bar", - "70": "bar", - "71": "bar", - "72": "bar", - "73": "bar", - "74": "bar", - "75": "bar", - "76": "bar", - "77": "bar", - "78": "bar", - "79": "bar", - "80": "bar", - "81": "bar", - "82": "bar", - "83": "bar", - "84": "bar", - "85": "bar", - "86": "bar", - "87": "bar", - "88": "bar", - "89": "bar", - "90": "bar", - "91": "bar", - "92": "bar", - "93": "bar", - "94": "bar", - "95": "bar", - "96": "bar", - "97": "bar", - "98": "bar", - "99": "bar", - "100": "bar", - "101": "bar", - "102": "bar", - "103": "bar", - "104": "bar", - "105": "bar", - "106": "bar", - "107": "bar", - "108": "bar", - "109": "bar", - "110": "bar", - "111": "bar", - "112": "bar", - "113": "bar", - "114": "bar", - "115": "bar", - "116": "bar", - "117": "bar", - "118": "bar", - "119": "bar", - "120": "bar", - "121": "bar", - "122": "bar", - "123": "bar", - "124": "bar", - "125": "bar", - "126": "bar", - "127": "bar", - "128": "bar", - "129": "bar", - "130": "bar", - "131": "bar", - "132": "bar", - "133": "bar", - "134": "bar", - "135": "bar", - "136": "bar", - "137": "bar", - "138": "bar", - "139": "bar", - }, + "item_schema": {"foo": "bar"}, "type": "custom", }, testing_criteria=[ @@ -1034,148 +329,7 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None: async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: eval = await async_client.evals.create( data_source_config={ - "item_schema": { - "0": "bar", - "1": "bar", - "2": "bar", - "3": "bar", - "4": "bar", - "5": "bar", - "6": "bar", - "7": "bar", - "8": "bar", - "9": "bar", - "10": "bar", - "11": "bar", - "12": "bar", - "13": "bar", - "14": "bar", - "15": "bar", - "16": "bar", - "17": "bar", - "18": "bar", - "19": "bar", - "20": "bar", - "21": "bar", - "22": "bar", - "23": "bar", - "24": "bar", - "25": "bar", - "26": "bar", - "27": "bar", - "28": "bar", - "29": "bar", - "30": "bar", - "31": "bar", - "32": "bar", - "33": "bar", - "34": "bar", - "35": "bar", - "36": "bar", - "37": "bar", - "38": "bar", - "39": "bar", - "40": "bar", - "41": "bar", - "42": "bar", - "43": "bar", - "44": "bar", - "45": "bar", - "46": "bar", - "47": "bar", - "48": "bar", - "49": "bar", - "50": "bar", - "51": "bar", - "52": "bar", - "53": "bar", - "54": "bar", - "55": "bar", - "56": "bar", - "57": "bar", - "58": "bar", - "59": "bar", - "60": "bar", - "61": "bar", - "62": "bar", - "63": "bar", - "64": "bar", - "65": "bar", - "66": "bar", - "67": "bar", - "68": "bar", - "69": "bar", - "70": "bar", - "71": "bar", - "72": "bar", - "73": "bar", - "74": "bar", - "75": "bar", - "76": "bar", - "77": "bar", - "78": "bar", - "79": "bar", - "80": "bar", - "81": "bar", - "82": "bar", - "83": "bar", - "84": "bar", - "85": "bar", - "86": "bar", - "87": "bar", - "88": "bar", - "89": "bar", - "90": "bar", - "91": "bar", - "92": "bar", - "93": "bar", - "94": "bar", - "95": "bar", - "96": "bar", - "97": "bar", - "98": "bar", - "99": "bar", - "100": "bar", - "101": "bar", - "102": "bar", - "103": "bar", - "104": "bar", - "105": "bar", - "106": "bar", - "107": "bar", - "108": "bar", - "109": "bar", - "110": "bar", - "111": "bar", - "112": "bar", - "113": "bar", - "114": "bar", - "115": "bar", - "116": "bar", - "117": "bar", - "118": "bar", - "119": "bar", - "120": "bar", - "121": "bar", - "122": "bar", - "123": "bar", - "124": "bar", - "125": "bar", - "126": "bar", - "127": "bar", - "128": "bar", - "129": "bar", - "130": "bar", - "131": "bar", - "132": "bar", - "133": "bar", - "134": "bar", - "135": "bar", - "136": "bar", - "137": "bar", - "138": "bar", - "139": "bar", - }, + "item_schema": {"foo": "bar"}, "type": "custom", "include_sample_schema": True, }, @@ -1204,148 +358,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: response = await async_client.evals.with_raw_response.create( data_source_config={ - "item_schema": { - "0": "bar", - "1": "bar", - "2": "bar", - "3": "bar", - "4": "bar", - "5": "bar", - "6": "bar", - "7": "bar", - "8": "bar", - "9": "bar", - "10": "bar", - "11": "bar", - "12": "bar", - "13": "bar", - "14": "bar", - "15": "bar", - "16": "bar", - "17": "bar", - "18": "bar", - "19": "bar", - "20": "bar", - "21": "bar", - "22": "bar", - "23": "bar", - "24": "bar", - "25": "bar", - "26": "bar", - "27": "bar", - "28": "bar", - "29": "bar", - "30": "bar", - "31": "bar", - "32": "bar", - "33": "bar", - "34": "bar", - "35": "bar", - "36": "bar", - "37": "bar", - "38": "bar", - "39": "bar", - "40": "bar", - "41": "bar", - "42": "bar", - "43": "bar", - "44": "bar", - "45": "bar", - "46": "bar", - "47": "bar", - "48": "bar", - "49": "bar", - "50": "bar", - "51": "bar", - "52": "bar", - "53": "bar", - "54": "bar", - "55": "bar", - "56": "bar", - "57": "bar", - "58": "bar", - "59": "bar", - "60": "bar", - "61": "bar", - "62": "bar", - "63": "bar", - "64": "bar", - "65": "bar", - "66": "bar", - "67": "bar", - "68": "bar", - "69": "bar", - "70": "bar", - "71": "bar", - "72": "bar", - "73": "bar", - "74": "bar", - "75": "bar", - "76": "bar", - "77": "bar", - "78": "bar", - "79": "bar", - "80": "bar", - "81": "bar", - "82": "bar", - "83": "bar", - "84": "bar", - "85": "bar", - "86": "bar", - "87": "bar", - "88": "bar", - "89": "bar", - "90": "bar", - "91": "bar", - "92": "bar", - "93": "bar", - "94": "bar", - "95": "bar", - "96": "bar", - "97": "bar", - "98": "bar", - "99": "bar", - "100": "bar", - "101": "bar", - "102": "bar", - "103": "bar", - "104": "bar", - "105": "bar", - "106": "bar", - "107": "bar", - "108": "bar", - "109": "bar", - "110": "bar", - "111": "bar", - "112": "bar", - "113": "bar", - "114": "bar", - "115": "bar", - "116": "bar", - "117": "bar", - "118": "bar", - "119": "bar", - "120": "bar", - "121": "bar", - "122": "bar", - "123": "bar", - "124": "bar", - "125": "bar", - "126": "bar", - "127": "bar", - "128": "bar", - "129": "bar", - "130": "bar", - "131": "bar", - "132": "bar", - "133": "bar", - "134": "bar", - "135": "bar", - "136": "bar", - "137": "bar", - "138": "bar", - "139": "bar", - }, + "item_schema": {"foo": "bar"}, "type": "custom", }, testing_criteria=[ @@ -1374,148 +387,7 @@ async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: async with async_client.evals.with_streaming_response.create( data_source_config={ - "item_schema": { - "0": "bar", - "1": "bar", - "2": "bar", - "3": "bar", - "4": "bar", - "5": "bar", - "6": "bar", - "7": "bar", - "8": "bar", - "9": "bar", - "10": "bar", - "11": "bar", - "12": "bar", - "13": "bar", - "14": "bar", - "15": "bar", - "16": "bar", - "17": "bar", - "18": "bar", - "19": "bar", - "20": "bar", - "21": "bar", - "22": "bar", - "23": "bar", - "24": "bar", - "25": "bar", - "26": "bar", - "27": "bar", - "28": "bar", - "29": "bar", - "30": "bar", - "31": "bar", - "32": "bar", - "33": "bar", - "34": "bar", - "35": "bar", - "36": "bar", - "37": "bar", - "38": "bar", - "39": "bar", - "40": "bar", - "41": "bar", - "42": "bar", - "43": "bar", - "44": "bar", - "45": "bar", - "46": "bar", - "47": "bar", - "48": "bar", - "49": "bar", - "50": "bar", - "51": "bar", - "52": "bar", - "53": "bar", - "54": "bar", - "55": "bar", - "56": "bar", - "57": "bar", - "58": "bar", - "59": "bar", - "60": "bar", - "61": "bar", - "62": "bar", - "63": "bar", - "64": "bar", - "65": "bar", - "66": "bar", - "67": "bar", - "68": "bar", - "69": "bar", - "70": "bar", - "71": "bar", - "72": "bar", - "73": "bar", - "74": "bar", - "75": "bar", - "76": "bar", - "77": "bar", - "78": "bar", - "79": "bar", - "80": "bar", - "81": "bar", - "82": "bar", - "83": "bar", - "84": "bar", - "85": "bar", - "86": "bar", - "87": "bar", - "88": "bar", - "89": "bar", - "90": "bar", - "91": "bar", - "92": "bar", - "93": "bar", - "94": "bar", - "95": "bar", - "96": "bar", - "97": "bar", - "98": "bar", - "99": "bar", - "100": "bar", - "101": "bar", - "102": "bar", - "103": "bar", - "104": "bar", - "105": "bar", - "106": "bar", - "107": "bar", - "108": "bar", - "109": "bar", - "110": "bar", - "111": "bar", - "112": "bar", - "113": "bar", - "114": "bar", - "115": "bar", - "116": "bar", - "117": "bar", - "118": "bar", - "119": "bar", - "120": "bar", - "121": "bar", - "122": "bar", - "123": "bar", - "124": "bar", - "125": "bar", - "126": "bar", - "127": "bar", - "128": "bar", - "129": "bar", - "130": "bar", - "131": "bar", - "132": "bar", - "133": "bar", - "134": "bar", - "135": "bar", - "136": "bar", - "137": "bar", - "138": "bar", - "139": "bar", - }, + "item_schema": {"foo": "bar"}, "type": "custom", }, testing_criteria=[ diff --git a/tests/api_resources/test_images.py b/tests/api_resources/test_images.py index 2e31f3354a..0a88f2ebcf 100644 --- a/tests/api_resources/test_images.py +++ b/tests/api_resources/test_images.py @@ -28,7 +28,7 @@ def test_method_create_variation(self, client: OpenAI) -> None: def test_method_create_variation_with_all_params(self, client: OpenAI) -> None: image = client.images.create_variation( image=b"raw file contents", - model="dall-e-2", + model="string", n=1, response_format="url", size="1024x1024", @@ -74,7 +74,7 @@ def test_method_edit_with_all_params(self, client: OpenAI) -> None: image=b"raw file contents", prompt="A cute baby sea otter wearing a beret", mask=b"raw file contents", - model="dall-e-2", + model="string", n=1, response_format="url", size="1024x1024", @@ -119,7 +119,7 @@ def test_method_generate(self, client: OpenAI) -> None: def test_method_generate_with_all_params(self, client: OpenAI) -> None: image = client.images.generate( prompt="A cute baby sea otter", - model="dall-e-3", + model="string", n=1, quality="standard", response_format="url", @@ -168,7 +168,7 @@ async def test_method_create_variation(self, async_client: AsyncOpenAI) -> None: async def test_method_create_variation_with_all_params(self, async_client: AsyncOpenAI) -> None: image = await async_client.images.create_variation( image=b"raw file contents", - model="dall-e-2", + model="string", n=1, response_format="url", size="1024x1024", @@ -214,7 +214,7 @@ async def test_method_edit_with_all_params(self, async_client: AsyncOpenAI) -> N image=b"raw file contents", prompt="A cute baby sea otter wearing a beret", mask=b"raw file contents", - model="dall-e-2", + model="string", n=1, response_format="url", size="1024x1024", @@ -259,7 +259,7 @@ async def test_method_generate(self, async_client: AsyncOpenAI) -> None: async def test_method_generate_with_all_params(self, async_client: AsyncOpenAI) -> None: image = await async_client.images.generate( prompt="A cute baby sea otter", - model="dall-e-3", + model="string", n=1, quality="standard", response_format="url", diff --git a/tests/api_resources/test_moderations.py b/tests/api_resources/test_moderations.py index bbdeb63e49..6df6464110 100644 --- a/tests/api_resources/test_moderations.py +++ b/tests/api_resources/test_moderations.py @@ -28,7 +28,7 @@ def test_method_create(self, client: OpenAI) -> None: def test_method_create_with_all_params(self, client: OpenAI) -> None: moderation = client.moderations.create( input="I want to kill them.", - model="omni-moderation-2024-09-26", + model="string", ) assert_matches_type(ModerationCreateResponse, moderation, path=["response"]) @@ -71,7 +71,7 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None: async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: moderation = await async_client.moderations.create( input="I want to kill them.", - model="omni-moderation-2024-09-26", + model="string", ) assert_matches_type(ModerationCreateResponse, moderation, path=["response"]) From 13ff6dd33e45d3c3c470d5673e81d3777b51aa5b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 8 Apr 2025 19:46:29 +0000 Subject: [PATCH 279/769] chore(internal): skip broken test (#2289) --- .stats.yml | 2 +- .../fine_tuning/checkpoints/test_permissions.py | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 4a82ee242d..c39ce1186a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 97 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-32de3bc513663c5fac922c49be41c222b6ee8c0b841d8966bcdfa489d441daa3.yml openapi_spec_hash: ea86343b5e9858a74e85da8ab2c532f6 -config_hash: d6c61213488683418adb860a9ee1501b +config_hash: 43dc8df20ffec9d1503f91866cb2b7d9 diff --git a/tests/api_resources/fine_tuning/checkpoints/test_permissions.py b/tests/api_resources/fine_tuning/checkpoints/test_permissions.py index d25c784c33..d40466919a 100644 --- a/tests/api_resources/fine_tuning/checkpoints/test_permissions.py +++ b/tests/api_resources/fine_tuning/checkpoints/test_permissions.py @@ -117,6 +117,7 @@ def test_path_params_retrieve(self, client: OpenAI) -> None: fine_tuned_model_checkpoint="", ) + @pytest.mark.skip(reason="OpenAPI spec is slightly incorrect") @parametrize def test_method_delete(self, client: OpenAI) -> None: permission = client.fine_tuning.checkpoints.permissions.delete( @@ -124,6 +125,7 @@ def test_method_delete(self, client: OpenAI) -> None: ) assert_matches_type(PermissionDeleteResponse, permission, path=["response"]) + @pytest.mark.skip(reason="OpenAPI spec is slightly incorrect") @parametrize def test_raw_response_delete(self, client: OpenAI) -> None: response = client.fine_tuning.checkpoints.permissions.with_raw_response.delete( @@ -135,6 +137,7 @@ def test_raw_response_delete(self, client: OpenAI) -> None: permission = response.parse() assert_matches_type(PermissionDeleteResponse, permission, path=["response"]) + @pytest.mark.skip(reason="OpenAPI spec is slightly incorrect") @parametrize def test_streaming_response_delete(self, client: OpenAI) -> None: with client.fine_tuning.checkpoints.permissions.with_streaming_response.delete( @@ -148,6 +151,7 @@ def test_streaming_response_delete(self, client: OpenAI) -> None: assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="OpenAPI spec is slightly incorrect") @parametrize def test_path_params_delete(self, client: OpenAI) -> None: with pytest.raises( @@ -256,6 +260,7 @@ async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: fine_tuned_model_checkpoint="", ) + @pytest.mark.skip(reason="OpenAPI spec is slightly incorrect") @parametrize async def test_method_delete(self, async_client: AsyncOpenAI) -> None: permission = await async_client.fine_tuning.checkpoints.permissions.delete( @@ -263,6 +268,7 @@ async def test_method_delete(self, async_client: AsyncOpenAI) -> None: ) assert_matches_type(PermissionDeleteResponse, permission, path=["response"]) + @pytest.mark.skip(reason="OpenAPI spec is slightly incorrect") @parametrize async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: response = await async_client.fine_tuning.checkpoints.permissions.with_raw_response.delete( @@ -274,6 +280,7 @@ async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: permission = response.parse() assert_matches_type(PermissionDeleteResponse, permission, path=["response"]) + @pytest.mark.skip(reason="OpenAPI spec is slightly incorrect") @parametrize async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: async with async_client.fine_tuning.checkpoints.permissions.with_streaming_response.delete( @@ -287,6 +294,7 @@ async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> Non assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="OpenAPI spec is slightly incorrect") @parametrize async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: with pytest.raises( From 0c8343bb928b26d42feedd2a1a039e16ac58e744 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 8 Apr 2025 19:47:02 +0000 Subject: [PATCH 280/769] release: 1.72.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 16 ++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index c7704ce953..e6484623c0 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.71.0" + ".": "1.72.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index e8f2e22cb8..b02fae7e87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # Changelog +## 1.72.0 (2025-04-08) + +Full Changelog: [v1.71.0...v1.72.0](https://github.com/openai/openai-python/compare/v1.71.0...v1.72.0) + +### Features + +* **api:** Add evalapi to sdk ([#2287](https://github.com/openai/openai-python/issues/2287)) ([35262fc](https://github.com/openai/openai-python/commit/35262fcef6ccb7d1f75c9abdfdc68c3dcf87ef53)) + + +### Chores + +* **internal:** fix examples ([#2288](https://github.com/openai/openai-python/issues/2288)) ([39defd6](https://github.com/openai/openai-python/commit/39defd61e81ea0ec6b898be12e9fb7e621c0e532)) +* **internal:** skip broken test ([#2289](https://github.com/openai/openai-python/issues/2289)) ([e2c9bce](https://github.com/openai/openai-python/commit/e2c9bce1f59686ee053b495d06ea118b4a89e09e)) +* **internal:** slight transform perf improvement ([#2284](https://github.com/openai/openai-python/issues/2284)) ([746174f](https://github.com/openai/openai-python/commit/746174fae7a018ece5dab54fb0b5a15fcdd18f2f)) +* **tests:** improve enum examples ([#2286](https://github.com/openai/openai-python/issues/2286)) ([c9dd81c](https://github.com/openai/openai-python/commit/c9dd81ce0277e8b1f5db5e0a39c4c2bcd9004bcc)) + ## 1.71.0 (2025-04-07) Full Changelog: [v1.70.0...v1.71.0](https://github.com/openai/openai-python/compare/v1.70.0...v1.71.0) diff --git a/pyproject.toml b/pyproject.toml index 4583a5531f..29abf3ac4c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.71.0" +version = "1.72.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 12e9d20bb1..e7c16742a2 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.71.0" # x-release-please-version +__version__ = "1.72.0" # x-release-please-version From ee272dd8dcfdb8cbe4faf6aa197fd03e24d978fa Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 8 Apr 2025 20:05:13 +0000 Subject: [PATCH 281/769] feat(api): manual updates --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index c39ce1186a..d4a4370a78 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 97 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-32de3bc513663c5fac922c49be41c222b6ee8c0b841d8966bcdfa489d441daa3.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-44b20fa9d24544217fe6bb48852037537030a1ad29b202936425110744fe66fb.yml openapi_spec_hash: ea86343b5e9858a74e85da8ab2c532f6 -config_hash: 43dc8df20ffec9d1503f91866cb2b7d9 +config_hash: 69e3afd56ccb0f0f822a7a9dc130fc99 From acf68ef3a57dfdae804072cc4f8abed32fd4f703 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 8 Apr 2025 21:49:05 +0000 Subject: [PATCH 282/769] chore: slight wording improvement in README (#2291) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c52bffbb5f..f7e0eb6467 100644 --- a/README.md +++ b/README.md @@ -351,7 +351,7 @@ response = client.chat.responses.create( ## File uploads -Request parameters that correspond to file uploads can be passed as `bytes`, a [`PathLike`](https://docs.python.org/3/library/os.html#os.PathLike) instance or a tuple of `(filename, contents, media type)`. +Request parameters that correspond to file uploads can be passed as `bytes`, or a [`PathLike`](https://docs.python.org/3/library/os.html#os.PathLike) instance or a tuple of `(filename, contents, media type)`. ```python from pathlib import Path From df5b323ea3963939d6a331c200116e688ce507e8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 9 Apr 2025 09:26:34 +0000 Subject: [PATCH 283/769] chore: workaround build errors --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index d4a4370a78..9d8d07c6ac 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 97 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-44b20fa9d24544217fe6bb48852037537030a1ad29b202936425110744fe66fb.yml openapi_spec_hash: ea86343b5e9858a74e85da8ab2c532f6 -config_hash: 69e3afd56ccb0f0f822a7a9dc130fc99 +config_hash: 5ea32de61ff42fcf5e66cff8d9e247ea From 5020669996e299ee268db2f2f45f7b7cefc0ccd6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 9 Apr 2025 16:31:40 +0000 Subject: [PATCH 284/769] chore(internal): expand CI branch coverage (#2295) --- .github/workflows/ci.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6d2699cca8..bcd3e9d9d3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,18 +1,18 @@ name: CI on: push: - branches: - - main - pull_request: - branches: - - main - - next + branches-ignore: + - 'generated' + - 'codegen/**' + - 'integrated/**' + - 'preview-head/**' + - 'preview-base/**' + - 'preview/**' jobs: lint: name: lint runs-on: ubuntu-latest - steps: - uses: actions/checkout@v4 @@ -33,7 +33,6 @@ jobs: test: name: test runs-on: ubuntu-latest - steps: - uses: actions/checkout@v4 From c8833fc38f9634c43d3ca4091ecda6e3c4a07a56 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 9 Apr 2025 21:08:33 +0000 Subject: [PATCH 285/769] chore(internal): reduce CI branch coverage --- .github/workflows/ci.yml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bcd3e9d9d3..6f9cf84bb4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,13 +1,12 @@ name: CI on: push: - branches-ignore: - - 'generated' - - 'codegen/**' - - 'integrated/**' - - 'preview-head/**' - - 'preview-base/**' - - 'preview/**' + branches: + - main + pull_request: + branches: + - main + - next jobs: lint: From 284415c968c031c001ad833b4b955d99c6fbbc50 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 11 Apr 2025 12:22:53 +0000 Subject: [PATCH 286/769] fix(perf): skip traversing types for NotGiven values --- src/openai/_utils/_transform.py | 11 +++++++++++ tests/test_transform.py | 9 ++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/openai/_utils/_transform.py b/src/openai/_utils/_transform.py index 3ec620818c..3b2b8e009a 100644 --- a/src/openai/_utils/_transform.py +++ b/src/openai/_utils/_transform.py @@ -12,6 +12,7 @@ from ._utils import ( is_list, + is_given, is_mapping, is_iterable, ) @@ -258,6 +259,11 @@ def _transform_typeddict( result: dict[str, object] = {} annotations = get_type_hints(expected_type, include_extras=True) for key, value in data.items(): + if not is_given(value): + # we don't need to include `NotGiven` values here as they'll + # be stripped out before the request is sent anyway + continue + type_ = annotations.get(key) if type_ is None: # we do not have a type annotation for this field, leave it as is @@ -415,6 +421,11 @@ async def _async_transform_typeddict( result: dict[str, object] = {} annotations = get_type_hints(expected_type, include_extras=True) for key, value in data.items(): + if not is_given(value): + # we don't need to include `NotGiven` values here as they'll + # be stripped out before the request is sent anyway + continue + type_ = annotations.get(key) if type_ is None: # we do not have a type annotation for this field, leave it as is diff --git a/tests/test_transform.py b/tests/test_transform.py index cd584756d7..965f65f74f 100644 --- a/tests/test_transform.py +++ b/tests/test_transform.py @@ -8,7 +8,7 @@ import pytest -from openai._types import Base64FileInput +from openai._types import NOT_GIVEN, Base64FileInput from openai._utils import ( PropertyInfo, transform as _transform, @@ -444,3 +444,10 @@ async def test_transform_skipping(use_async: bool) -> None: # iterables of ints are converted to a list data = iter([1, 2, 3]) assert await transform(data, Iterable[int], use_async) == [1, 2, 3] + + +@parametrize +@pytest.mark.asyncio +async def test_strips_notgiven(use_async: bool) -> None: + assert await transform({"foo_bar": "bar"}, Foo1, use_async) == {"fooBar": "bar"} + assert await transform({"foo_bar": NOT_GIVEN}, Foo1, use_async) == {} From 8086d61769128eeb249449eb12da9b6b3c46562e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 11 Apr 2025 13:35:38 +0000 Subject: [PATCH 287/769] fix(perf): optimize some hot paths --- src/openai/_utils/_transform.py | 14 +++++++++++++- src/openai/_utils/_typing.py | 2 ++ src/openai/resources/audio/transcriptions.py | 14 ++++++++++++-- src/openai/resources/beta/threads/runs/runs.py | 12 ++++++++---- src/openai/resources/beta/threads/threads.py | 8 ++++++-- .../resources/chat/completions/completions.py | 8 ++++++-- src/openai/resources/completions.py | 8 ++++++-- src/openai/resources/responses/responses.py | 8 ++++++-- 8 files changed, 59 insertions(+), 15 deletions(-) diff --git a/src/openai/_utils/_transform.py b/src/openai/_utils/_transform.py index 3b2b8e009a..b0cc20a735 100644 --- a/src/openai/_utils/_transform.py +++ b/src/openai/_utils/_transform.py @@ -5,7 +5,7 @@ import pathlib from typing import Any, Mapping, TypeVar, cast from datetime import date, datetime -from typing_extensions import Literal, get_args, override, get_type_hints +from typing_extensions import Literal, get_args, override, get_type_hints as _get_type_hints import anyio import pydantic @@ -13,6 +13,7 @@ from ._utils import ( is_list, is_given, + lru_cache, is_mapping, is_iterable, ) @@ -109,6 +110,7 @@ class Params(TypedDict, total=False): return cast(_T, transformed) +@lru_cache(maxsize=8096) def _get_annotated_type(type_: type) -> type | None: """If the given type is an `Annotated` type then it is returned, if not `None` is returned. @@ -433,3 +435,13 @@ async def _async_transform_typeddict( else: result[_maybe_transform_key(key, type_)] = await _async_transform_recursive(value, annotation=type_) return result + + +@lru_cache(maxsize=8096) +def get_type_hints( + obj: Any, + globalns: dict[str, Any] | None = None, + localns: Mapping[str, Any] | None = None, + include_extras: bool = False, +) -> dict[str, Any]: + return _get_type_hints(obj, globalns=globalns, localns=localns, include_extras=include_extras) diff --git a/src/openai/_utils/_typing.py b/src/openai/_utils/_typing.py index 278749b147..1958820f8d 100644 --- a/src/openai/_utils/_typing.py +++ b/src/openai/_utils/_typing.py @@ -13,6 +13,7 @@ get_origin, ) +from ._utils import lru_cache from .._types import InheritsGeneric from .._compat import is_union as _is_union @@ -66,6 +67,7 @@ def is_type_alias_type(tp: Any, /) -> TypeIs[typing_extensions.TypeAliasType]: # Extracts T from Annotated[T, ...] or from Required[Annotated[T, ...]] +@lru_cache(maxsize=8096) def strip_annotated_type(typ: type) -> type: if is_required_type(typ) or is_annotated_type(typ): return strip_annotated_type(cast(type, get_args(typ)[0])) diff --git a/src/openai/resources/audio/transcriptions.py b/src/openai/resources/audio/transcriptions.py index 2a77f91d69..7e62f70f60 100644 --- a/src/openai/resources/audio/transcriptions.py +++ b/src/openai/resources/audio/transcriptions.py @@ -321,7 +321,12 @@ def create( extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} return self._post( # type: ignore[return-value] "/audio/transcriptions", - body=maybe_transform(body, transcription_create_params.TranscriptionCreateParams), + body=maybe_transform( + body, + transcription_create_params.TranscriptionCreateParamsStreaming + if stream + else transcription_create_params.TranscriptionCreateParamsNonStreaming, + ), files=files, options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -616,7 +621,12 @@ async def create( extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} return await self._post( "/audio/transcriptions", - body=await async_maybe_transform(body, transcription_create_params.TranscriptionCreateParams), + body=await async_maybe_transform( + body, + transcription_create_params.TranscriptionCreateParamsStreaming + if stream + else transcription_create_params.TranscriptionCreateParamsNonStreaming, + ), files=files, options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout diff --git a/src/openai/resources/beta/threads/runs/runs.py b/src/openai/resources/beta/threads/runs/runs.py index acb1c9b261..4d19010fea 100644 --- a/src/openai/resources/beta/threads/runs/runs.py +++ b/src/openai/resources/beta/threads/runs/runs.py @@ -587,7 +587,7 @@ def create( "top_p": top_p, "truncation_strategy": truncation_strategy, }, - run_create_params.RunCreateParams, + run_create_params.RunCreateParamsStreaming if stream else run_create_params.RunCreateParamsNonStreaming, ), options=make_request_options( extra_headers=extra_headers, @@ -1324,7 +1324,9 @@ def submit_tool_outputs( "tool_outputs": tool_outputs, "stream": stream, }, - run_submit_tool_outputs_params.RunSubmitToolOutputsParams, + run_submit_tool_outputs_params.RunSubmitToolOutputsParamsStreaming + if stream + else run_submit_tool_outputs_params.RunSubmitToolOutputsParamsNonStreaming, ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -1996,7 +1998,7 @@ async def create( "top_p": top_p, "truncation_strategy": truncation_strategy, }, - run_create_params.RunCreateParams, + run_create_params.RunCreateParamsStreaming if stream else run_create_params.RunCreateParamsNonStreaming, ), options=make_request_options( extra_headers=extra_headers, @@ -2732,7 +2734,9 @@ async def submit_tool_outputs( "tool_outputs": tool_outputs, "stream": stream, }, - run_submit_tool_outputs_params.RunSubmitToolOutputsParams, + run_submit_tool_outputs_params.RunSubmitToolOutputsParamsStreaming + if stream + else run_submit_tool_outputs_params.RunSubmitToolOutputsParamsNonStreaming, ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout diff --git a/src/openai/resources/beta/threads/threads.py b/src/openai/resources/beta/threads/threads.py index d88559bdeb..c697be416d 100644 --- a/src/openai/resources/beta/threads/threads.py +++ b/src/openai/resources/beta/threads/threads.py @@ -717,7 +717,9 @@ def create_and_run( "top_p": top_p, "truncation_strategy": truncation_strategy, }, - thread_create_and_run_params.ThreadCreateAndRunParams, + thread_create_and_run_params.ThreadCreateAndRunParamsStreaming + if stream + else thread_create_and_run_params.ThreadCreateAndRunParamsNonStreaming, ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -1564,7 +1566,9 @@ async def create_and_run( "top_p": top_p, "truncation_strategy": truncation_strategy, }, - thread_create_and_run_params.ThreadCreateAndRunParams, + thread_create_and_run_params.ThreadCreateAndRunParamsStreaming + if stream + else thread_create_and_run_params.ThreadCreateAndRunParamsNonStreaming, ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index d28be012c9..f9e380cc72 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -947,7 +947,9 @@ def create( "user": user, "web_search_options": web_search_options, }, - completion_create_params.CompletionCreateParams, + completion_create_params.CompletionCreateParamsStreaming + if stream + else completion_create_params.CompletionCreateParamsNonStreaming, ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -2033,7 +2035,9 @@ async def create( "user": user, "web_search_options": web_search_options, }, - completion_create_params.CompletionCreateParams, + completion_create_params.CompletionCreateParamsStreaming + if stream + else completion_create_params.CompletionCreateParamsNonStreaming, ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout diff --git a/src/openai/resources/completions.py b/src/openai/resources/completions.py index 171f509352..592696f7da 100644 --- a/src/openai/resources/completions.py +++ b/src/openai/resources/completions.py @@ -559,7 +559,9 @@ def create( "top_p": top_p, "user": user, }, - completion_create_params.CompletionCreateParams, + completion_create_params.CompletionCreateParamsStreaming + if stream + else completion_create_params.CompletionCreateParamsNonStreaming, ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -1101,7 +1103,9 @@ async def create( "top_p": top_p, "user": user, }, - completion_create_params.CompletionCreateParams, + completion_create_params.CompletionCreateParamsStreaming + if stream + else completion_create_params.CompletionCreateParamsNonStreaming, ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 29ed3de42a..f8588178ed 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -623,7 +623,9 @@ def create( "truncation": truncation, "user": user, }, - response_create_params.ResponseCreateParams, + response_create_params.ResponseCreateParamsStreaming + if stream + else response_create_params.ResponseCreateParamsNonStreaming, ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -1435,7 +1437,9 @@ async def create( "truncation": truncation, "user": user, }, - response_create_params.ResponseCreateParams, + response_create_params.ResponseCreateParamsStreaming + if stream + else response_create_params.ResponseCreateParamsNonStreaming, ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout From ab091ca05349c594343dcb78ad5e7fd015d5804d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 12 Apr 2025 05:03:44 +0000 Subject: [PATCH 288/769] release: 1.73.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 e6484623c0..c174a89798 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.72.0" + ".": "1.73.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index b02fae7e87..7dffc39909 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,27 @@ # Changelog +## 1.73.0 (2025-04-12) + +Full Changelog: [v1.72.0...v1.73.0](https://github.com/openai/openai-python/compare/v1.72.0...v1.73.0) + +### Features + +* **api:** manual updates ([a3253dd](https://github.com/openai/openai-python/commit/a3253dd798c1eccd9810d4fc593e8c2a568bcf4f)) + + +### Bug Fixes + +* **perf:** optimize some hot paths ([f79d39f](https://github.com/openai/openai-python/commit/f79d39fbcaea8f366a9e48c06fb1696bab3e607d)) +* **perf:** skip traversing types for NotGiven values ([28d220d](https://github.com/openai/openai-python/commit/28d220de3b4a09d80450d0bcc9b347bbf68f81ec)) + + +### Chores + +* **internal:** expand CI branch coverage ([#2295](https://github.com/openai/openai-python/issues/2295)) ([0ae783b](https://github.com/openai/openai-python/commit/0ae783b99122975be521365de0b6d2bce46056c9)) +* **internal:** reduce CI branch coverage ([2fb7d42](https://github.com/openai/openai-python/commit/2fb7d425cda679a54aa3262090479fd747363bb4)) +* slight wording improvement in README ([#2291](https://github.com/openai/openai-python/issues/2291)) ([e020759](https://github.com/openai/openai-python/commit/e0207598d16a2a9cb3cb3a8e8e97fa9cfdccd5e8)) +* workaround build errors ([4e10c96](https://github.com/openai/openai-python/commit/4e10c96a483db28dedc2d8c2908765fb7317e049)) + ## 1.72.0 (2025-04-08) Full Changelog: [v1.71.0...v1.72.0](https://github.com/openai/openai-python/compare/v1.71.0...v1.72.0) diff --git a/pyproject.toml b/pyproject.toml index 29abf3ac4c..1126c96040 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.72.0" +version = "1.73.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 e7c16742a2..bcc08e9c6d 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.72.0" # x-release-please-version +__version__ = "1.73.0" # x-release-please-version From e3e791c85f0c508f530848025a7adeed71a8bbae Mon Sep 17 00:00:00 2001 From: Nikolai Pismennyi Date: Mon, 14 Apr 2025 12:04:43 +0300 Subject: [PATCH 289/769] fix(chat): skip azure async filter events (#2255) --- src/openai/lib/streaming/chat/_completions.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/openai/lib/streaming/chat/_completions.py b/src/openai/lib/streaming/chat/_completions.py index 2146091354..f147696cca 100644 --- a/src/openai/lib/streaming/chat/_completions.py +++ b/src/openai/lib/streaming/chat/_completions.py @@ -113,6 +113,8 @@ def current_completion_snapshot(self) -> ParsedChatCompletionSnapshot: def __stream__(self) -> Iterator[ChatCompletionStreamEvent[ResponseFormatT]]: for sse_event in self._raw_stream: + if not _is_valid_chat_completion_chunk_weak(sse_event): + continue events_to_fire = self._state.handle_chunk(sse_event) for event in events_to_fire: yield event @@ -234,6 +236,8 @@ def current_completion_snapshot(self) -> ParsedChatCompletionSnapshot: async def __stream__(self) -> AsyncIterator[ChatCompletionStreamEvent[ResponseFormatT]]: async for sse_event in self._raw_stream: + if not _is_valid_chat_completion_chunk_weak(sse_event): + continue events_to_fire = self._state.handle_chunk(sse_event) for event in events_to_fire: yield event @@ -753,3 +757,12 @@ def _convert_initial_chunk_into_snapshot(chunk: ChatCompletionChunk) -> ParsedCh }, ), ) + + +def _is_valid_chat_completion_chunk_weak(sse_event: ChatCompletionChunk) -> bool: + # Although the _raw_stream is always supposed to contain only objects adhering to ChatCompletionChunk schema, + # this is broken by the Azure OpenAI in case of Asynchronous Filter enabled. + # An easy filter is to check for the "object" property: + # - should be "chat.completion.chunk" for a ChatCompletionChunk; + # - is an empty string for Asynchronous Filter events. + return sse_event.object == "chat.completion.chunk" # type: ignore # pylance reports this as a useless check From 1828fb6a71b12ba5deb7d57e7caa8584d2fe1aeb Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 14 Apr 2025 12:24:00 +0000 Subject: [PATCH 290/769] chore(internal): update pyright settings --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 1126c96040..27db20295f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -166,6 +166,7 @@ exclude = [ ] reportImplicitOverride = true +reportOverlappingOverload = false reportImportCycles = false reportPrivateUsage = false From 77ba4182e4e4a6f7e986762f6aef925ebb40f2f0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 14 Apr 2025 14:30:49 +0000 Subject: [PATCH 291/769] chore(client): minor internal fixes --- src/openai/_base_client.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index f31e5af54b..1dd3a4772c 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -411,7 +411,8 @@ def _build_headers(self, options: FinalRequestOptions, *, retries_taken: int = 0 idempotency_header = self._idempotency_header if idempotency_header and options.method.lower() != "get" and idempotency_header not in headers: - headers[idempotency_header] = options.idempotency_key or self._idempotency_key() + options.idempotency_key = options.idempotency_key or self._idempotency_key() + headers[idempotency_header] = options.idempotency_key # 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. @@ -945,6 +946,10 @@ def _request( request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) + if options.idempotency_key: + # ensure the idempotency key is reused between requests + input_options.idempotency_key = options.idempotency_key + kwargs: HttpxSendArgs = {} if self.custom_auth is not None: kwargs["auth"] = self.custom_auth @@ -1492,6 +1497,10 @@ async def _request( request = self._build_request(options, retries_taken=retries_taken) await self._prepare_request(request) + if options.idempotency_key: + # ensure the idempotency key is reused between requests + input_options.idempotency_key = options.idempotency_key + kwargs: HttpxSendArgs = {} if self.custom_auth is not None: kwargs["auth"] = self.custom_auth From 7d2b97d660882f68283cb2b54303660d1f73bec1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 14 Apr 2025 16:40:51 +0000 Subject: [PATCH 292/769] feat(api): adding gpt-4.1 family of model IDs --- .stats.yml | 4 ++-- src/openai/resources/beta/assistants.py | 12 ++++++++++++ src/openai/types/beta/assistant_update_params.py | 6 ++++++ src/openai/types/shared/chat_model.py | 6 ++++++ src/openai/types/shared_params/chat_model.py | 6 ++++++ 5 files changed, 32 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 9d8d07c6ac..b40485bd0a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 97 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-44b20fa9d24544217fe6bb48852037537030a1ad29b202936425110744fe66fb.yml -openapi_spec_hash: ea86343b5e9858a74e85da8ab2c532f6 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-a555f81249cb084f463dcefa4aba069f9341fdaf3dd6ac27d7f237fc90e8f488.yml +openapi_spec_hash: 8e590296cd1a54b9508510b0c7a2c45a config_hash: 5ea32de61ff42fcf5e66cff8d9e247ea diff --git a/src/openai/resources/beta/assistants.py b/src/openai/resources/beta/assistants.py index 1c7cbf3737..43f6a7f135 100644 --- a/src/openai/resources/beta/assistants.py +++ b/src/openai/resources/beta/assistants.py @@ -223,6 +223,12 @@ def update( model: Union[ str, Literal[ + "gpt-4.1", + "gpt-4.1-mini", + "gpt-4.1-nano", + "gpt-4.1-2025-04-14", + "gpt-4.1-mini-2025-04-14", + "gpt-4.1-nano-2025-04-14", "o3-mini", "o3-mini-2025-01-31", "o1", @@ -666,6 +672,12 @@ async def update( model: Union[ str, Literal[ + "gpt-4.1", + "gpt-4.1-mini", + "gpt-4.1-nano", + "gpt-4.1-2025-04-14", + "gpt-4.1-mini-2025-04-14", + "gpt-4.1-nano-2025-04-14", "o3-mini", "o3-mini-2025-01-31", "o1", diff --git a/src/openai/types/beta/assistant_update_params.py b/src/openai/types/beta/assistant_update_params.py index d3ec7614fd..b28094a6a5 100644 --- a/src/openai/types/beta/assistant_update_params.py +++ b/src/openai/types/beta/assistant_update_params.py @@ -36,6 +36,12 @@ class AssistantUpdateParams(TypedDict, total=False): model: Union[ str, Literal[ + "gpt-4.1", + "gpt-4.1-mini", + "gpt-4.1-nano", + "gpt-4.1-2025-04-14", + "gpt-4.1-mini-2025-04-14", + "gpt-4.1-nano-2025-04-14", "o3-mini", "o3-mini-2025-01-31", "o1", diff --git a/src/openai/types/shared/chat_model.py b/src/openai/types/shared/chat_model.py index b19375725d..30878b4347 100644 --- a/src/openai/types/shared/chat_model.py +++ b/src/openai/types/shared/chat_model.py @@ -5,6 +5,12 @@ __all__ = ["ChatModel"] ChatModel: TypeAlias = Literal[ + "gpt-4.1", + "gpt-4.1-mini", + "gpt-4.1-nano", + "gpt-4.1-2025-04-14", + "gpt-4.1-mini-2025-04-14", + "gpt-4.1-nano-2025-04-14", "o3-mini", "o3-mini-2025-01-31", "o1", diff --git a/src/openai/types/shared_params/chat_model.py b/src/openai/types/shared_params/chat_model.py index ff81b07ac3..f606beb693 100644 --- a/src/openai/types/shared_params/chat_model.py +++ b/src/openai/types/shared_params/chat_model.py @@ -7,6 +7,12 @@ __all__ = ["ChatModel"] ChatModel: TypeAlias = Literal[ + "gpt-4.1", + "gpt-4.1-mini", + "gpt-4.1-nano", + "gpt-4.1-2025-04-14", + "gpt-4.1-mini-2025-04-14", + "gpt-4.1-nano-2025-04-14", "o3-mini", "o3-mini-2025-01-31", "o1", From 05810dd4088b6dbfc4194d7b0bea03eec236c83a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 14 Apr 2025 16:41:56 +0000 Subject: [PATCH 293/769] release: 1.74.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 19 +++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index c174a89798..71a38f2845 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.73.0" + ".": "1.74.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 7dffc39909..90af38d900 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## 1.74.0 (2025-04-14) + +Full Changelog: [v1.73.0...v1.74.0](https://github.com/openai/openai-python/compare/v1.73.0...v1.74.0) + +### Features + +* **api:** adding gpt-4.1 family of model IDs ([d4dae55](https://github.com/openai/openai-python/commit/d4dae5553ff3a2879b9ab79a6423661b212421f9)) + + +### Bug Fixes + +* **chat:** skip azure async filter events ([#2255](https://github.com/openai/openai-python/issues/2255)) ([fd3a38b](https://github.com/openai/openai-python/commit/fd3a38b1ed30af0a9f3302c1cfc6be6b352e65de)) + + +### Chores + +* **client:** minor internal fixes ([6071ae5](https://github.com/openai/openai-python/commit/6071ae5e8b4faa465afc8d07370737e66901900a)) +* **internal:** update pyright settings ([c8f8beb](https://github.com/openai/openai-python/commit/c8f8bebf852380a224701bc36826291d6387c53d)) + ## 1.73.0 (2025-04-12) Full Changelog: [v1.72.0...v1.73.0](https://github.com/openai/openai-python/compare/v1.72.0...v1.73.0) diff --git a/pyproject.toml b/pyproject.toml index 27db20295f..eb07cd5ba7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.73.0" +version = "1.74.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 bcc08e9c6d..b203ed859f 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.73.0" # x-release-please-version +__version__ = "1.74.0" # x-release-please-version From 6d110a147f91cc5e9352ab1e823ed5eb4db06137 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 16 Apr 2025 12:06:05 +0000 Subject: [PATCH 294/769] chore(internal): bump pyright version --- pyproject.toml | 2 +- requirements-dev.lock | 2 +- src/openai/_base_client.py | 6 +++++- src/openai/_models.py | 1 - src/openai/_utils/_typing.py | 2 +- tests/conftest.py | 2 +- tests/test_models.py | 2 +- 7 files changed, 10 insertions(+), 7 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index eb07cd5ba7..244dd2ecb1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,7 +51,7 @@ voice_helpers = ["sounddevice>=0.5.1", "numpy>=2.0.2"] managed = true # version pins are in requirements-dev.lock dev-dependencies = [ - "pyright>=1.1.359", + "pyright==1.1.399", "mypy", "respx", "pytest", diff --git a/requirements-dev.lock b/requirements-dev.lock index 11bb5c1b30..9875a2b860 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -126,7 +126,7 @@ pygments==2.18.0 # via rich pyjwt==2.8.0 # via msal -pyright==1.1.392.post0 +pyright==1.1.399 pytest==8.3.3 # via pytest-asyncio pytest-asyncio==0.24.0 diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index 1dd3a4772c..d167c43763 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -100,7 +100,11 @@ _AsyncStreamT = TypeVar("_AsyncStreamT", bound=AsyncStream[Any]) if TYPE_CHECKING: - from httpx._config import DEFAULT_TIMEOUT_CONFIG as HTTPX_DEFAULT_TIMEOUT + from httpx._config import ( + DEFAULT_TIMEOUT_CONFIG, # pyright: ignore[reportPrivateImportUsage] + ) + + HTTPX_DEFAULT_TIMEOUT = DEFAULT_TIMEOUT_CONFIG else: try: from httpx._config import DEFAULT_TIMEOUT_CONFIG as HTTPX_DEFAULT_TIMEOUT diff --git a/src/openai/_models.py b/src/openai/_models.py index fc4f201e4e..9b1aeb30bf 100644 --- a/src/openai/_models.py +++ b/src/openai/_models.py @@ -20,7 +20,6 @@ ) import pydantic -import pydantic.generics from pydantic.fields import FieldInfo from ._types import ( diff --git a/src/openai/_utils/_typing.py b/src/openai/_utils/_typing.py index 1958820f8d..1bac9542e2 100644 --- a/src/openai/_utils/_typing.py +++ b/src/openai/_utils/_typing.py @@ -110,7 +110,7 @@ class MyResponse(Foo[_T]): ``` """ cls = cast(object, get_origin(typ) or typ) - if cls in generic_bases: + if cls in generic_bases: # pyright: ignore[reportUnnecessaryContains] # we're given the class directly return extract_type_arg(typ, index) diff --git a/tests/conftest.py b/tests/conftest.py index fa82d39d86..8b01753e2f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -10,7 +10,7 @@ from openai import OpenAI, AsyncOpenAI if TYPE_CHECKING: - from _pytest.fixtures import FixtureRequest + from _pytest.fixtures import FixtureRequest # pyright: ignore[reportPrivateImportUsage] pytest.register_assert_rewrite("tests.utils") diff --git a/tests/test_models.py b/tests/test_models.py index b9be1f3ea3..4b18940b49 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -832,7 +832,7 @@ class B(BaseModel): @pytest.mark.skipif(not PYDANTIC_V2, reason="TypeAliasType is not supported in Pydantic v1") def test_type_alias_type() -> None: - Alias = TypeAliasType("Alias", str) + Alias = TypeAliasType("Alias", str) # pyright: ignore class Model(BaseModel): alias: Alias From ea638838b7aa5989516df3659a1be16825681fc6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 16 Apr 2025 12:59:19 +0000 Subject: [PATCH 295/769] chore(internal): base client updates --- src/openai/_base_client.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index d167c43763..8b43a20699 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -121,6 +121,7 @@ class PageInfo: url: URL | NotGiven params: Query | NotGiven + json: Body | NotGiven @overload def __init__( @@ -136,19 +137,30 @@ def __init__( params: Query, ) -> None: ... + @overload + def __init__( + self, + *, + json: Body, + ) -> None: ... + def __init__( self, *, url: URL | NotGiven = NOT_GIVEN, + json: Body | NotGiven = NOT_GIVEN, params: Query | NotGiven = NOT_GIVEN, ) -> None: self.url = url + self.json = json self.params = params @override def __repr__(self) -> str: if self.url: return f"{self.__class__.__name__}(url={self.url})" + if self.json: + return f"{self.__class__.__name__}(json={self.json})" return f"{self.__class__.__name__}(params={self.params})" @@ -197,6 +209,19 @@ def _info_to_options(self, info: PageInfo) -> FinalRequestOptions: options.url = str(url) return options + if not isinstance(info.json, NotGiven): + if not is_mapping(info.json): + raise TypeError("Pagination is only supported with mappings") + + if not options.json_data: + options.json_data = {**info.json} + else: + if not is_mapping(options.json_data): + raise TypeError("Pagination is only supported with mappings") + + options.json_data = {**options.json_data, **info.json} + return options + raise ValueError("Unexpected PageInfo state") From bf6dd816052d6ece746acc0339e5225d425dc1b3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 16 Apr 2025 12:59:51 +0000 Subject: [PATCH 296/769] release: 1.74.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 9 +++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 71a38f2845..6603053537 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.74.0" + ".": "1.74.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 90af38d900..b03bbedb52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 1.74.1 (2025-04-16) + +Full Changelog: [v1.74.0...v1.74.1](https://github.com/openai/openai-python/compare/v1.74.0...v1.74.1) + +### Chores + +* **internal:** base client updates ([06303b5](https://github.com/openai/openai-python/commit/06303b501f8c17040c495971a4ee79ae340f6f4a)) +* **internal:** bump pyright version ([9fd1c77](https://github.com/openai/openai-python/commit/9fd1c778c3231616bf1331cb1daa86fdfca4cb7f)) + ## 1.74.0 (2025-04-14) Full Changelog: [v1.73.0...v1.74.0](https://github.com/openai/openai-python/compare/v1.73.0...v1.74.0) diff --git a/pyproject.toml b/pyproject.toml index 244dd2ecb1..e2cd25f69c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.74.0" +version = "1.74.1" 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 b203ed859f..5bbfee3232 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.74.0" # x-release-please-version +__version__ = "1.74.1" # x-release-please-version From c5ede36c6e2138e64f5194ecd5015ddc7cf50ec7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 16 Apr 2025 16:42:28 +0000 Subject: [PATCH 297/769] feat(api): add o3 and o4-mini model IDs --- .stats.yml | 6 +- .../resources/chat/completions/completions.py | 82 +++++++---- src/openai/resources/completions.py | 24 +++- src/openai/resources/responses/responses.py | 130 +++++++++++++++++- src/openai/types/chat/chat_completion.py | 22 ++- .../types/chat/chat_completion_audio_param.py | 6 +- .../types/chat/chat_completion_chunk.py | 22 ++- .../types/chat/completion_create_params.py | 14 +- src/openai/types/completion_create_params.py | 5 +- src/openai/types/responses/response.py | 23 +++- .../types/responses/response_create_params.py | 23 +++- src/openai/types/shared/chat_model.py | 4 + src/openai/types/shared/reasoning.py | 15 +- src/openai/types/shared_params/chat_model.py | 4 + src/openai/types/shared_params/reasoning.py | 15 +- tests/api_resources/test_responses.py | 16 ++- 16 files changed, 342 insertions(+), 69 deletions(-) diff --git a/.stats.yml b/.stats.yml index b40485bd0a..848c5b5adb 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 97 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-a555f81249cb084f463dcefa4aba069f9341fdaf3dd6ac27d7f237fc90e8f488.yml -openapi_spec_hash: 8e590296cd1a54b9508510b0c7a2c45a -config_hash: 5ea32de61ff42fcf5e66cff8d9e247ea +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-5633633cc38734869cf7d993f7b549bb8e4d10e0ec45381ec2cd91507cd8eb8f.yml +openapi_spec_hash: c855121b2b2324b99499c9244c21d24d +config_hash: d20837393b73efdb19cd08e04c1cc9a1 diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index f9e380cc72..d6214225d8 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -99,7 +99,7 @@ def create( reasoning_effort: Optional[ReasoningEffort] | 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, + service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, @@ -145,7 +145,7 @@ def create( [images](https://platform.openai.com/docs/guides/vision), and [audio](https://platform.openai.com/docs/guides/audio). - model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a + model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a wide range of models with different capabilities, performance characteristics, and price points. Refer to the [model guide](https://platform.openai.com/docs/models) to browse and compare @@ -201,7 +201,7 @@ def create( This value is now deprecated in favor of `max_completion_tokens`, and is not compatible with - [o1 series models](https://platform.openai.com/docs/guides/reasoning). + [o-series models](https://platform.openai.com/docs/guides/reasoning). metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format, and @@ -270,12 +270,17 @@ def create( latency guarentee. - If set to 'default', the request will be processed using the default service tier with a lower uptime SLA and no latency guarentee. + - If set to 'flex', the request will be processed with the Flex Processing + service tier. + [Learn more](https://platform.openai.com/docs/guides/flex-processing). - When not set, the default behavior is 'auto'. When this parameter is set, the response body will include the `service_tier` utilized. - stop: Up to 4 sequences where the API will stop generating further tokens. The + stop: Not supported with latest reasoning models `o3` and `o4-mini`. + + Up to 4 sequences where the API will stop generating further tokens. The returned text will not contain the stop sequence. store: Whether or not to store the output of this chat completion request for use in @@ -364,7 +369,7 @@ def create( reasoning_effort: Optional[ReasoningEffort] | 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, + service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, @@ -409,7 +414,7 @@ def create( [images](https://platform.openai.com/docs/guides/vision), and [audio](https://platform.openai.com/docs/guides/audio). - model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a + model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a wide range of models with different capabilities, performance characteristics, and price points. Refer to the [model guide](https://platform.openai.com/docs/models) to browse and compare @@ -474,7 +479,7 @@ def create( This value is now deprecated in favor of `max_completion_tokens`, and is not compatible with - [o1 series models](https://platform.openai.com/docs/guides/reasoning). + [o-series models](https://platform.openai.com/docs/guides/reasoning). metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format, and @@ -543,12 +548,17 @@ def create( latency guarentee. - If set to 'default', the request will be processed using the default service tier with a lower uptime SLA and no latency guarentee. + - If set to 'flex', the request will be processed with the Flex Processing + service tier. + [Learn more](https://platform.openai.com/docs/guides/flex-processing). - When not set, the default behavior is 'auto'. When this parameter is set, the response body will include the `service_tier` utilized. - stop: Up to 4 sequences where the API will stop generating further tokens. The + stop: Not supported with latest reasoning models `o3` and `o4-mini`. + + Up to 4 sequences where the API will stop generating further tokens. The returned text will not contain the stop sequence. store: Whether or not to store the output of this chat completion request for use in @@ -628,7 +638,7 @@ def create( reasoning_effort: Optional[ReasoningEffort] | 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, + service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, @@ -673,7 +683,7 @@ def create( [images](https://platform.openai.com/docs/guides/vision), and [audio](https://platform.openai.com/docs/guides/audio). - model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a + model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a wide range of models with different capabilities, performance characteristics, and price points. Refer to the [model guide](https://platform.openai.com/docs/models) to browse and compare @@ -738,7 +748,7 @@ def create( This value is now deprecated in favor of `max_completion_tokens`, and is not compatible with - [o1 series models](https://platform.openai.com/docs/guides/reasoning). + [o-series models](https://platform.openai.com/docs/guides/reasoning). metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format, and @@ -807,12 +817,17 @@ def create( latency guarentee. - If set to 'default', the request will be processed using the default service tier with a lower uptime SLA and no latency guarentee. + - If set to 'flex', the request will be processed with the Flex Processing + service tier. + [Learn more](https://platform.openai.com/docs/guides/flex-processing). - When not set, the default behavior is 'auto'. When this parameter is set, the response body will include the `service_tier` utilized. - stop: Up to 4 sequences where the API will stop generating further tokens. The + stop: Not supported with latest reasoning models `o3` and `o4-mini`. + + Up to 4 sequences where the API will stop generating further tokens. The returned text will not contain the stop sequence. store: Whether or not to store the output of this chat completion request for use in @@ -891,7 +906,7 @@ def create( reasoning_effort: Optional[ReasoningEffort] | 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, + service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, @@ -1187,7 +1202,7 @@ async def create( reasoning_effort: Optional[ReasoningEffort] | 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, + service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, @@ -1233,7 +1248,7 @@ async def create( [images](https://platform.openai.com/docs/guides/vision), and [audio](https://platform.openai.com/docs/guides/audio). - model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a + model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a wide range of models with different capabilities, performance characteristics, and price points. Refer to the [model guide](https://platform.openai.com/docs/models) to browse and compare @@ -1289,7 +1304,7 @@ async def create( This value is now deprecated in favor of `max_completion_tokens`, and is not compatible with - [o1 series models](https://platform.openai.com/docs/guides/reasoning). + [o-series models](https://platform.openai.com/docs/guides/reasoning). metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format, and @@ -1358,12 +1373,17 @@ async def create( latency guarentee. - If set to 'default', the request will be processed using the default service tier with a lower uptime SLA and no latency guarentee. + - If set to 'flex', the request will be processed with the Flex Processing + service tier. + [Learn more](https://platform.openai.com/docs/guides/flex-processing). - When not set, the default behavior is 'auto'. When this parameter is set, the response body will include the `service_tier` utilized. - stop: Up to 4 sequences where the API will stop generating further tokens. The + stop: Not supported with latest reasoning models `o3` and `o4-mini`. + + Up to 4 sequences where the API will stop generating further tokens. The returned text will not contain the stop sequence. store: Whether or not to store the output of this chat completion request for use in @@ -1452,7 +1472,7 @@ async def create( reasoning_effort: Optional[ReasoningEffort] | 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, + service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, @@ -1497,7 +1517,7 @@ async def create( [images](https://platform.openai.com/docs/guides/vision), and [audio](https://platform.openai.com/docs/guides/audio). - model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a + model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a wide range of models with different capabilities, performance characteristics, and price points. Refer to the [model guide](https://platform.openai.com/docs/models) to browse and compare @@ -1562,7 +1582,7 @@ async def create( This value is now deprecated in favor of `max_completion_tokens`, and is not compatible with - [o1 series models](https://platform.openai.com/docs/guides/reasoning). + [o-series models](https://platform.openai.com/docs/guides/reasoning). metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format, and @@ -1631,12 +1651,17 @@ async def create( latency guarentee. - If set to 'default', the request will be processed using the default service tier with a lower uptime SLA and no latency guarentee. + - If set to 'flex', the request will be processed with the Flex Processing + service tier. + [Learn more](https://platform.openai.com/docs/guides/flex-processing). - When not set, the default behavior is 'auto'. When this parameter is set, the response body will include the `service_tier` utilized. - stop: Up to 4 sequences where the API will stop generating further tokens. The + stop: Not supported with latest reasoning models `o3` and `o4-mini`. + + Up to 4 sequences where the API will stop generating further tokens. The returned text will not contain the stop sequence. store: Whether or not to store the output of this chat completion request for use in @@ -1716,7 +1741,7 @@ async def create( reasoning_effort: Optional[ReasoningEffort] | 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, + service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, @@ -1761,7 +1786,7 @@ async def create( [images](https://platform.openai.com/docs/guides/vision), and [audio](https://platform.openai.com/docs/guides/audio). - model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a + model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a wide range of models with different capabilities, performance characteristics, and price points. Refer to the [model guide](https://platform.openai.com/docs/models) to browse and compare @@ -1826,7 +1851,7 @@ async def create( This value is now deprecated in favor of `max_completion_tokens`, and is not compatible with - [o1 series models](https://platform.openai.com/docs/guides/reasoning). + [o-series models](https://platform.openai.com/docs/guides/reasoning). metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format, and @@ -1895,12 +1920,17 @@ async def create( latency guarentee. - If set to 'default', the request will be processed using the default service tier with a lower uptime SLA and no latency guarentee. + - If set to 'flex', the request will be processed with the Flex Processing + service tier. + [Learn more](https://platform.openai.com/docs/guides/flex-processing). - When not set, the default behavior is 'auto'. When this parameter is set, the response body will include the `service_tier` utilized. - stop: Up to 4 sequences where the API will stop generating further tokens. The + stop: Not supported with latest reasoning models `o3` and `o4-mini`. + + Up to 4 sequences where the API will stop generating further tokens. The returned text will not contain the stop sequence. store: Whether or not to store the output of this chat completion request for use in @@ -1979,7 +2009,7 @@ async def create( reasoning_effort: Optional[ReasoningEffort] | 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, + service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, diff --git a/src/openai/resources/completions.py b/src/openai/resources/completions.py index 592696f7da..aebf35d1f1 100644 --- a/src/openai/resources/completions.py +++ b/src/openai/resources/completions.py @@ -159,7 +159,9 @@ def create( Determinism is not guaranteed, and you should refer to the `system_fingerprint` response parameter to monitor changes in the backend. - stop: Up to 4 sequences where the API will stop generating further tokens. The + stop: Not supported with latest reasoning models `o3` and `o4-mini`. + + Up to 4 sequences where the API will stop generating further tokens. The returned text will not contain the stop sequence. stream: Whether to stream back partial progress. If set, tokens will be sent as @@ -319,7 +321,9 @@ def create( Determinism is not guaranteed, and you should refer to the `system_fingerprint` response parameter to monitor changes in the backend. - stop: Up to 4 sequences where the API will stop generating further tokens. The + stop: Not supported with latest reasoning models `o3` and `o4-mini`. + + Up to 4 sequences where the API will stop generating further tokens. The returned text will not contain the stop sequence. stream_options: Options for streaming response. Only set this when you set `stream: true`. @@ -472,7 +476,9 @@ def create( Determinism is not guaranteed, and you should refer to the `system_fingerprint` response parameter to monitor changes in the backend. - stop: Up to 4 sequences where the API will stop generating further tokens. The + stop: Not supported with latest reasoning models `o3` and `o4-mini`. + + Up to 4 sequences where the API will stop generating further tokens. The returned text will not contain the stop sequence. stream_options: Options for streaming response. Only set this when you set `stream: true`. @@ -703,7 +709,9 @@ async def create( Determinism is not guaranteed, and you should refer to the `system_fingerprint` response parameter to monitor changes in the backend. - stop: Up to 4 sequences where the API will stop generating further tokens. The + stop: Not supported with latest reasoning models `o3` and `o4-mini`. + + Up to 4 sequences where the API will stop generating further tokens. The returned text will not contain the stop sequence. stream: Whether to stream back partial progress. If set, tokens will be sent as @@ -863,7 +871,9 @@ async def create( Determinism is not guaranteed, and you should refer to the `system_fingerprint` response parameter to monitor changes in the backend. - stop: Up to 4 sequences where the API will stop generating further tokens. The + stop: Not supported with latest reasoning models `o3` and `o4-mini`. + + Up to 4 sequences where the API will stop generating further tokens. The returned text will not contain the stop sequence. stream_options: Options for streaming response. Only set this when you set `stream: true`. @@ -1016,7 +1026,9 @@ async def create( Determinism is not guaranteed, and you should refer to the `system_fingerprint` response parameter to monitor changes in the backend. - stop: Up to 4 sequences where the API will stop generating further tokens. The + stop: Not supported with latest reasoning models `o3` and `o4-mini`. + + Up to 4 sequences where the API will stop generating further tokens. The returned text will not contain the stop sequence. stream_options: Options for streaming response. Only set this when you set `stream: true`. diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index f8588178ed..f07b4d8c4a 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -89,6 +89,7 @@ def create( parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -130,7 +131,7 @@ def create( - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) - [Function calling](https://platform.openai.com/docs/guides/function-calling) - model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a + model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a wide range of models with different capabilities, performance characteristics, and price points. Refer to the [model guide](https://platform.openai.com/docs/models) to browse and compare @@ -174,6 +175,24 @@ def create( Configuration options for [reasoning models](https://platform.openai.com/docs/guides/reasoning). + service_tier: Specifies the latency tier to use for processing the request. This parameter is + relevant for customers subscribed to the scale tier service: + + - If set to 'auto', and the Project is Scale tier enabled, the system will + utilize scale tier credits until they are exhausted. + - If set to 'auto', and the Project is not Scale tier enabled, the request will + be processed using the default service tier with a lower uptime SLA and no + latency guarentee. + - If set to 'default', the request will be processed using the default service + tier with a lower uptime SLA and no latency guarentee. + - If set to 'flex', the request will be processed with the Flex Processing + service tier. + [Learn more](https://platform.openai.com/docs/guides/flex-processing). + - When not set, the default behavior is 'auto'. + + When this parameter is set, the response body will include the `service_tier` + utilized. + store: Whether to store the generated model response for later retrieval via API. stream: If set to true, the model response data will be streamed to the client as it is @@ -255,6 +274,7 @@ def create( parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, @@ -295,7 +315,7 @@ def create( - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) - [Function calling](https://platform.openai.com/docs/guides/function-calling) - model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a + model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a wide range of models with different capabilities, performance characteristics, and price points. Refer to the [model guide](https://platform.openai.com/docs/models) to browse and compare @@ -346,6 +366,24 @@ def create( Configuration options for [reasoning models](https://platform.openai.com/docs/guides/reasoning). + service_tier: Specifies the latency tier to use for processing the request. This parameter is + relevant for customers subscribed to the scale tier service: + + - If set to 'auto', and the Project is Scale tier enabled, the system will + utilize scale tier credits until they are exhausted. + - If set to 'auto', and the Project is not Scale tier enabled, the request will + be processed using the default service tier with a lower uptime SLA and no + latency guarentee. + - If set to 'default', the request will be processed using the default service + tier with a lower uptime SLA and no latency guarentee. + - If set to 'flex', the request will be processed with the Flex Processing + service tier. + [Learn more](https://platform.openai.com/docs/guides/flex-processing). + - When not set, the default behavior is 'auto'. + + When this parameter is set, the response body will include the `service_tier` + utilized. + store: Whether to store the generated model response for later retrieval via API. temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will @@ -420,6 +458,7 @@ def create( parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, @@ -460,7 +499,7 @@ def create( - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) - [Function calling](https://platform.openai.com/docs/guides/function-calling) - model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a + model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a wide range of models with different capabilities, performance characteristics, and price points. Refer to the [model guide](https://platform.openai.com/docs/models) to browse and compare @@ -511,6 +550,24 @@ def create( Configuration options for [reasoning models](https://platform.openai.com/docs/guides/reasoning). + service_tier: Specifies the latency tier to use for processing the request. This parameter is + relevant for customers subscribed to the scale tier service: + + - If set to 'auto', and the Project is Scale tier enabled, the system will + utilize scale tier credits until they are exhausted. + - If set to 'auto', and the Project is not Scale tier enabled, the request will + be processed using the default service tier with a lower uptime SLA and no + latency guarentee. + - If set to 'default', the request will be processed using the default service + tier with a lower uptime SLA and no latency guarentee. + - If set to 'flex', the request will be processed with the Flex Processing + service tier. + [Learn more](https://platform.openai.com/docs/guides/flex-processing). + - When not set, the default behavior is 'auto'. + + When this parameter is set, the response body will include the `service_tier` + utilized. + store: Whether to store the generated model response for later retrieval via API. temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will @@ -584,6 +641,7 @@ def create( parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -613,6 +671,7 @@ def create( "parallel_tool_calls": parallel_tool_calls, "previous_response_id": previous_response_id, "reasoning": reasoning, + "service_tier": service_tier, "store": store, "stream": stream, "temperature": temperature, @@ -903,6 +962,7 @@ async def create( parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -944,7 +1004,7 @@ async def create( - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) - [Function calling](https://platform.openai.com/docs/guides/function-calling) - model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a + model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a wide range of models with different capabilities, performance characteristics, and price points. Refer to the [model guide](https://platform.openai.com/docs/models) to browse and compare @@ -988,6 +1048,24 @@ async def create( Configuration options for [reasoning models](https://platform.openai.com/docs/guides/reasoning). + service_tier: Specifies the latency tier to use for processing the request. This parameter is + relevant for customers subscribed to the scale tier service: + + - If set to 'auto', and the Project is Scale tier enabled, the system will + utilize scale tier credits until they are exhausted. + - If set to 'auto', and the Project is not Scale tier enabled, the request will + be processed using the default service tier with a lower uptime SLA and no + latency guarentee. + - If set to 'default', the request will be processed using the default service + tier with a lower uptime SLA and no latency guarentee. + - If set to 'flex', the request will be processed with the Flex Processing + service tier. + [Learn more](https://platform.openai.com/docs/guides/flex-processing). + - When not set, the default behavior is 'auto'. + + When this parameter is set, the response body will include the `service_tier` + utilized. + store: Whether to store the generated model response for later retrieval via API. stream: If set to true, the model response data will be streamed to the client as it is @@ -1069,6 +1147,7 @@ async def create( parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, @@ -1109,7 +1188,7 @@ async def create( - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) - [Function calling](https://platform.openai.com/docs/guides/function-calling) - model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a + model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a wide range of models with different capabilities, performance characteristics, and price points. Refer to the [model guide](https://platform.openai.com/docs/models) to browse and compare @@ -1160,6 +1239,24 @@ async def create( Configuration options for [reasoning models](https://platform.openai.com/docs/guides/reasoning). + service_tier: Specifies the latency tier to use for processing the request. This parameter is + relevant for customers subscribed to the scale tier service: + + - If set to 'auto', and the Project is Scale tier enabled, the system will + utilize scale tier credits until they are exhausted. + - If set to 'auto', and the Project is not Scale tier enabled, the request will + be processed using the default service tier with a lower uptime SLA and no + latency guarentee. + - If set to 'default', the request will be processed using the default service + tier with a lower uptime SLA and no latency guarentee. + - If set to 'flex', the request will be processed with the Flex Processing + service tier. + [Learn more](https://platform.openai.com/docs/guides/flex-processing). + - When not set, the default behavior is 'auto'. + + When this parameter is set, the response body will include the `service_tier` + utilized. + store: Whether to store the generated model response for later retrieval via API. temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will @@ -1234,6 +1331,7 @@ async def create( parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, @@ -1274,7 +1372,7 @@ async def create( - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) - [Function calling](https://platform.openai.com/docs/guides/function-calling) - model: Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a + model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a wide range of models with different capabilities, performance characteristics, and price points. Refer to the [model guide](https://platform.openai.com/docs/models) to browse and compare @@ -1325,6 +1423,24 @@ async def create( Configuration options for [reasoning models](https://platform.openai.com/docs/guides/reasoning). + service_tier: Specifies the latency tier to use for processing the request. This parameter is + relevant for customers subscribed to the scale tier service: + + - If set to 'auto', and the Project is Scale tier enabled, the system will + utilize scale tier credits until they are exhausted. + - If set to 'auto', and the Project is not Scale tier enabled, the request will + be processed using the default service tier with a lower uptime SLA and no + latency guarentee. + - If set to 'default', the request will be processed using the default service + tier with a lower uptime SLA and no latency guarentee. + - If set to 'flex', the request will be processed with the Flex Processing + service tier. + [Learn more](https://platform.openai.com/docs/guides/flex-processing). + - When not set, the default behavior is 'auto'. + + When this parameter is set, the response body will include the `service_tier` + utilized. + store: Whether to store the generated model response for later retrieval via API. temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will @@ -1398,6 +1514,7 @@ async def create( parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -1427,6 +1544,7 @@ async def create( "parallel_tool_calls": parallel_tool_calls, "previous_response_id": previous_response_id, "reasoning": reasoning, + "service_tier": service_tier, "store": store, "stream": stream, "temperature": temperature, diff --git a/src/openai/types/chat/chat_completion.py b/src/openai/types/chat/chat_completion.py index cb812a2702..3a235f89a5 100644 --- a/src/openai/types/chat/chat_completion.py +++ b/src/openai/types/chat/chat_completion.py @@ -59,8 +59,26 @@ class ChatCompletion(BaseModel): object: Literal["chat.completion"] """The object type, which is always `chat.completion`.""" - service_tier: Optional[Literal["scale", "default"]] = None - """The service tier used for processing the request.""" + service_tier: Optional[Literal["auto", "default", "flex"]] = None + """Specifies the latency tier to use for processing the request. + + This parameter is relevant for customers subscribed to the scale tier service: + + - If set to 'auto', and the Project is Scale tier enabled, the system will + utilize scale tier credits until they are exhausted. + - If set to 'auto', and the Project is not Scale tier enabled, the request will + be processed using the default service tier with a lower uptime SLA and no + latency guarentee. + - If set to 'default', the request will be processed using the default service + tier with a lower uptime SLA and no latency guarentee. + - If set to 'flex', the request will be processed with the Flex Processing + service tier. + [Learn more](https://platform.openai.com/docs/guides/flex-processing). + - When not set, the default behavior is 'auto'. + + When this parameter is set, the response body will include the `service_tier` + utilized. + """ system_fingerprint: Optional[str] = None """This fingerprint represents the backend configuration that the model runs with. diff --git a/src/openai/types/chat/chat_completion_audio_param.py b/src/openai/types/chat/chat_completion_audio_param.py index b902f2667f..25caada177 100644 --- a/src/openai/types/chat/chat_completion_audio_param.py +++ b/src/openai/types/chat/chat_completion_audio_param.py @@ -9,7 +9,7 @@ class ChatCompletionAudioParam(TypedDict, total=False): - format: Required[Literal["wav", "mp3", "flac", "opus", "pcm16"]] + format: Required[Literal["wav", "aac", "mp3", "flac", "opus", "pcm16"]] """Specifies the output audio format. Must be one of `wav`, `mp3`, `flac`, `opus`, or `pcm16`. @@ -22,6 +22,6 @@ class ChatCompletionAudioParam(TypedDict, total=False): ] """The voice the model uses to respond. - Supported voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`, and - `shimmer`. + Supported voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, `fable`, `nova`, + `onyx`, `sage`, and `shimmer`. """ diff --git a/src/openai/types/chat/chat_completion_chunk.py b/src/openai/types/chat/chat_completion_chunk.py index 31b9cb5456..6fe996dd95 100644 --- a/src/openai/types/chat/chat_completion_chunk.py +++ b/src/openai/types/chat/chat_completion_chunk.py @@ -128,8 +128,26 @@ class ChatCompletionChunk(BaseModel): object: Literal["chat.completion.chunk"] """The object type, which is always `chat.completion.chunk`.""" - service_tier: Optional[Literal["scale", "default"]] = None - """The service tier used for processing the request.""" + service_tier: Optional[Literal["auto", "default", "flex"]] = None + """Specifies the latency tier to use for processing the request. + + This parameter is relevant for customers subscribed to the scale tier service: + + - If set to 'auto', and the Project is Scale tier enabled, the system will + utilize scale tier credits until they are exhausted. + - If set to 'auto', and the Project is not Scale tier enabled, the request will + be processed using the default service tier with a lower uptime SLA and no + latency guarentee. + - If set to 'default', the request will be processed using the default service + tier with a lower uptime SLA and no latency guarentee. + - If set to 'flex', the request will be processed with the Flex Processing + service tier. + [Learn more](https://platform.openai.com/docs/guides/flex-processing). + - When not set, the default behavior is 'auto'. + + When this parameter is set, the response body will include the `service_tier` + utilized. + """ system_fingerprint: Optional[str] = None """ diff --git a/src/openai/types/chat/completion_create_params.py b/src/openai/types/chat/completion_create_params.py index 05103fba91..60d5f53cdd 100644 --- a/src/openai/types/chat/completion_create_params.py +++ b/src/openai/types/chat/completion_create_params.py @@ -45,7 +45,7 @@ class CompletionCreateParamsBase(TypedDict, total=False): """ model: Required[Union[str, ChatModel]] - """Model ID used to generate the response, like `gpt-4o` or `o1`. + """Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a wide range of models with different capabilities, performance characteristics, and price points. Refer to the @@ -123,7 +123,7 @@ class CompletionCreateParamsBase(TypedDict, total=False): This value is now deprecated in favor of `max_completion_tokens`, and is not compatible with - [o1 series models](https://platform.openai.com/docs/guides/reasoning). + [o-series models](https://platform.openai.com/docs/guides/reasoning). """ metadata: Optional[Metadata] @@ -208,7 +208,7 @@ class CompletionCreateParamsBase(TypedDict, total=False): in the backend. """ - service_tier: Optional[Literal["auto", "default"]] + service_tier: Optional[Literal["auto", "default", "flex"]] """Specifies the latency tier to use for processing the request. This parameter is relevant for customers subscribed to the scale tier service: @@ -220,6 +220,9 @@ class CompletionCreateParamsBase(TypedDict, total=False): latency guarentee. - If set to 'default', the request will be processed using the default service tier with a lower uptime SLA and no latency guarentee. + - If set to 'flex', the request will be processed with the Flex Processing + service tier. + [Learn more](https://platform.openai.com/docs/guides/flex-processing). - When not set, the default behavior is 'auto'. When this parameter is set, the response body will include the `service_tier` @@ -227,9 +230,10 @@ class CompletionCreateParamsBase(TypedDict, total=False): """ stop: Union[Optional[str], List[str], None] - """Up to 4 sequences where the API will stop generating further tokens. + """Not supported with latest reasoning models `o3` and `o4-mini`. - The returned text will not contain the stop sequence. + Up to 4 sequences where the API will stop generating further tokens. The + returned text will not contain the stop sequence. """ store: Optional[bool] diff --git a/src/openai/types/completion_create_params.py b/src/openai/types/completion_create_params.py index fdb1680d26..6ae20cff83 100644 --- a/src/openai/types/completion_create_params.py +++ b/src/openai/types/completion_create_params.py @@ -120,9 +120,10 @@ class CompletionCreateParamsBase(TypedDict, total=False): """ stop: Union[Optional[str], List[str], None] - """Up to 4 sequences where the API will stop generating further tokens. + """Not supported with latest reasoning models `o3` and `o4-mini`. - The returned text will not contain the stop sequence. + Up to 4 sequences where the API will stop generating further tokens. The + returned text will not contain the stop sequence. """ stream_options: Optional[ChatCompletionStreamOptionsParam] diff --git a/src/openai/types/responses/response.py b/src/openai/types/responses/response.py index 8cd1e01144..254f7e204b 100644 --- a/src/openai/types/responses/response.py +++ b/src/openai/types/responses/response.py @@ -62,7 +62,7 @@ class Response(BaseModel): """ model: ResponsesModel - """Model ID used to generate the response, like `gpt-4o` or `o1`. + """Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a wide range of models with different capabilities, performance characteristics, and price points. Refer to the @@ -149,6 +149,27 @@ class Response(BaseModel): [reasoning models](https://platform.openai.com/docs/guides/reasoning). """ + service_tier: Optional[Literal["auto", "default", "flex"]] = None + """Specifies the latency tier to use for processing the request. + + This parameter is relevant for customers subscribed to the scale tier service: + + - If set to 'auto', and the Project is Scale tier enabled, the system will + utilize scale tier credits until they are exhausted. + - If set to 'auto', and the Project is not Scale tier enabled, the request will + be processed using the default service tier with a lower uptime SLA and no + latency guarentee. + - If set to 'default', the request will be processed using the default service + tier with a lower uptime SLA and no latency guarentee. + - If set to 'flex', the request will be processed with the Flex Processing + service tier. + [Learn more](https://platform.openai.com/docs/guides/flex-processing). + - When not set, the default behavior is 'auto'. + + When this parameter is set, the response body will include the `service_tier` + utilized. + """ + status: Optional[ResponseStatus] = None """The status of the response generation. diff --git a/src/openai/types/responses/response_create_params.py b/src/openai/types/responses/response_create_params.py index ed82e678e5..3c0a9d7b8a 100644 --- a/src/openai/types/responses/response_create_params.py +++ b/src/openai/types/responses/response_create_params.py @@ -38,7 +38,7 @@ class ResponseCreateParamsBase(TypedDict, total=False): """ model: Required[ResponsesModel] - """Model ID used to generate the response, like `gpt-4o` or `o1`. + """Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a wide range of models with different capabilities, performance characteristics, and price points. Refer to the @@ -102,6 +102,27 @@ class ResponseCreateParamsBase(TypedDict, total=False): [reasoning models](https://platform.openai.com/docs/guides/reasoning). """ + service_tier: Optional[Literal["auto", "default", "flex"]] + """Specifies the latency tier to use for processing the request. + + This parameter is relevant for customers subscribed to the scale tier service: + + - If set to 'auto', and the Project is Scale tier enabled, the system will + utilize scale tier credits until they are exhausted. + - If set to 'auto', and the Project is not Scale tier enabled, the request will + be processed using the default service tier with a lower uptime SLA and no + latency guarentee. + - If set to 'default', the request will be processed using the default service + tier with a lower uptime SLA and no latency guarentee. + - If set to 'flex', the request will be processed with the Flex Processing + service tier. + [Learn more](https://platform.openai.com/docs/guides/flex-processing). + - When not set, the default behavior is 'auto'. + + When this parameter is set, the response body will include the `service_tier` + utilized. + """ + store: Optional[bool] """Whether to store the generated model response for later retrieval via API.""" diff --git a/src/openai/types/shared/chat_model.py b/src/openai/types/shared/chat_model.py index 30878b4347..4869cd325c 100644 --- a/src/openai/types/shared/chat_model.py +++ b/src/openai/types/shared/chat_model.py @@ -11,6 +11,10 @@ "gpt-4.1-2025-04-14", "gpt-4.1-mini-2025-04-14", "gpt-4.1-nano-2025-04-14", + "o4-mini", + "o4-mini-2025-04-16", + "o3", + "o3-2025-04-16", "o3-mini", "o3-mini-2025-01-31", "o1", diff --git a/src/openai/types/shared/reasoning.py b/src/openai/types/shared/reasoning.py index 78a396d738..107aab2e4a 100644 --- a/src/openai/types/shared/reasoning.py +++ b/src/openai/types/shared/reasoning.py @@ -19,10 +19,17 @@ class Reasoning(BaseModel): result in faster responses and fewer tokens used on reasoning in a response. """ - generate_summary: Optional[Literal["concise", "detailed"]] = None - """**computer_use_preview only** + generate_summary: Optional[Literal["auto", "concise", "detailed"]] = None + """**Deprecated:** use `summary` instead. A summary of the reasoning performed by the model. This can be useful for - debugging and understanding the model's reasoning process. One of `concise` or - `detailed`. + debugging and understanding the model's reasoning process. One of `auto`, + `concise`, or `detailed`. + """ + + summary: Optional[Literal["auto", "concise", "detailed"]] = None + """A summary of the reasoning performed by the model. + + This can be useful for debugging and understanding the model's reasoning + process. One of `auto`, `concise`, or `detailed`. """ diff --git a/src/openai/types/shared_params/chat_model.py b/src/openai/types/shared_params/chat_model.py index f606beb693..99e082fc11 100644 --- a/src/openai/types/shared_params/chat_model.py +++ b/src/openai/types/shared_params/chat_model.py @@ -13,6 +13,10 @@ "gpt-4.1-2025-04-14", "gpt-4.1-mini-2025-04-14", "gpt-4.1-nano-2025-04-14", + "o4-mini", + "o4-mini-2025-04-16", + "o3", + "o3-2025-04-16", "o3-mini", "o3-mini-2025-01-31", "o1", diff --git a/src/openai/types/shared_params/reasoning.py b/src/openai/types/shared_params/reasoning.py index 2953b895c4..73e1a008df 100644 --- a/src/openai/types/shared_params/reasoning.py +++ b/src/openai/types/shared_params/reasoning.py @@ -20,10 +20,17 @@ class Reasoning(TypedDict, total=False): result in faster responses and fewer tokens used on reasoning in a response. """ - generate_summary: Optional[Literal["concise", "detailed"]] - """**computer_use_preview only** + generate_summary: Optional[Literal["auto", "concise", "detailed"]] + """**Deprecated:** use `summary` instead. A summary of the reasoning performed by the model. This can be useful for - debugging and understanding the model's reasoning process. One of `concise` or - `detailed`. + debugging and understanding the model's reasoning process. One of `auto`, + `concise`, or `detailed`. + """ + + summary: Optional[Literal["auto", "concise", "detailed"]] + """A summary of the reasoning performed by the model. + + This can be useful for debugging and understanding the model's reasoning + process. One of `auto`, `concise`, or `detailed`. """ diff --git a/tests/api_resources/test_responses.py b/tests/api_resources/test_responses.py index e45a5becf3..3753af8fdb 100644 --- a/tests/api_resources/test_responses.py +++ b/tests/api_resources/test_responses.py @@ -38,8 +38,10 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: previous_response_id="previous_response_id", reasoning={ "effort": "low", - "generate_summary": "concise", + "generate_summary": "auto", + "summary": "auto", }, + service_tier="auto", store=True, stream=False, temperature=1, @@ -116,8 +118,10 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: previous_response_id="previous_response_id", reasoning={ "effort": "low", - "generate_summary": "concise", + "generate_summary": "auto", + "summary": "auto", }, + service_tier="auto", store=True, temperature=1, text={"format": {"type": "text"}}, @@ -280,8 +284,10 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn previous_response_id="previous_response_id", reasoning={ "effort": "low", - "generate_summary": "concise", + "generate_summary": "auto", + "summary": "auto", }, + service_tier="auto", store=True, stream=False, temperature=1, @@ -358,8 +364,10 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn previous_response_id="previous_response_id", reasoning={ "effort": "low", - "generate_summary": "concise", + "generate_summary": "auto", + "summary": "auto", }, + service_tier="auto", store=True, temperature=1, text={"format": {"type": "text"}}, From ed53107e10e6c86754866b48f8bd862659134ca8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 16 Apr 2025 16:43:01 +0000 Subject: [PATCH 298/769] release: 1.75.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 6603053537..cb464946f0 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.74.1" + ".": "1.75.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index b03bbedb52..fb077b91c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.75.0 (2025-04-16) + +Full Changelog: [v1.74.1...v1.75.0](https://github.com/openai/openai-python/compare/v1.74.1...v1.75.0) + +### Features + +* **api:** add o3 and o4-mini model IDs ([4bacbd5](https://github.com/openai/openai-python/commit/4bacbd5503137e266c127dc643ebae496cb4f158)) + ## 1.74.1 (2025-04-16) Full Changelog: [v1.74.0...v1.74.1](https://github.com/openai/openai-python/compare/v1.74.0...v1.74.1) diff --git a/pyproject.toml b/pyproject.toml index e2cd25f69c..b5648e9e51 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.74.1" +version = "1.75.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 5bbfee3232..8eab2d7416 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.74.1" # x-release-please-version +__version__ = "1.75.0" # x-release-please-version From 5d65ddfa34ed9c910f9a695e0a52f1458cc95b71 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 18 Apr 2025 10:17:31 +0000 Subject: [PATCH 299/769] chore(internal): update models test --- tests/test_models.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test_models.py b/tests/test_models.py index 4b18940b49..440e17a08c 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -492,12 +492,15 @@ class Model(BaseModel): resource_id: Optional[str] = None m = Model.construct() + assert m.resource_id is None assert "resource_id" not in m.model_fields_set m = Model.construct(resource_id=None) + assert m.resource_id is None assert "resource_id" in m.model_fields_set m = Model.construct(resource_id="foo") + assert m.resource_id == "foo" assert "resource_id" in m.model_fields_set From 15902dc595a69ca37452d8bf9682ebf229d460d3 Mon Sep 17 00:00:00 2001 From: dogisgreat Date: Mon, 21 Apr 2025 14:23:33 -0400 Subject: [PATCH 300/769] chore: update completion parse signature --- src/openai/resources/beta/chat/completions.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/openai/resources/beta/chat/completions.py b/src/openai/resources/beta/chat/completions.py index 545a3f4087..80e015615f 100644 --- a/src/openai/resources/beta/chat/completions.py +++ b/src/openai/resources/beta/chat/completions.py @@ -81,7 +81,7 @@ def parse( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, @@ -228,7 +228,7 @@ def stream( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, @@ -360,7 +360,7 @@ async def parse( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, @@ -507,7 +507,7 @@ def stream( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, From 271d979a0893b7afa892d5109968c3fcfb6c13b4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 22 Apr 2025 20:12:49 +0000 Subject: [PATCH 301/769] chore(ci): add timeout thresholds for CI jobs --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6f9cf84bb4..d148b34a9e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,6 +10,7 @@ on: jobs: lint: + timeout-minutes: 10 name: lint runs-on: ubuntu-latest steps: @@ -30,6 +31,7 @@ jobs: run: ./scripts/lint test: + timeout-minutes: 10 name: test runs-on: ubuntu-latest steps: @@ -50,6 +52,7 @@ jobs: run: ./scripts/test examples: + timeout-minutes: 10 name: examples runs-on: ubuntu-latest if: github.repository == 'openai/openai-python' From 1157528d952d02036058943f08fba99ef0d79d4f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 22 Apr 2025 20:37:29 +0000 Subject: [PATCH 302/769] chore(internal): import reformatting --- src/openai/resources/audio/speech.py | 5 +---- src/openai/resources/audio/transcriptions.py | 8 +------- src/openai/resources/audio/translations.py | 7 +------ src/openai/resources/batches.py | 5 +---- src/openai/resources/beta/assistants.py | 5 +---- src/openai/resources/beta/realtime/sessions.py | 5 +---- .../resources/beta/realtime/transcription_sessions.py | 5 +---- src/openai/resources/beta/threads/messages.py | 5 +---- src/openai/resources/beta/threads/runs/steps.py | 5 +---- src/openai/resources/beta/threads/threads.py | 6 +----- src/openai/resources/chat/completions/completions.py | 6 +----- src/openai/resources/completions.py | 6 +----- src/openai/resources/evals/evals.py | 5 +---- src/openai/resources/evals/runs/runs.py | 5 +---- src/openai/resources/files.py | 7 +------ .../resources/fine_tuning/checkpoints/permissions.py | 5 +---- src/openai/resources/fine_tuning/jobs/jobs.py | 5 +---- src/openai/resources/images.py | 7 +------ src/openai/resources/moderations.py | 5 +---- src/openai/resources/responses/responses.py | 7 +------ src/openai/resources/uploads/parts.py | 7 +------ src/openai/resources/uploads/uploads.py | 5 +---- src/openai/resources/vector_stores/file_batches.py | 6 +----- src/openai/resources/vector_stores/files.py | 6 +----- src/openai/resources/vector_stores/vector_stores.py | 5 +---- 25 files changed, 25 insertions(+), 118 deletions(-) diff --git a/src/openai/resources/audio/speech.py b/src/openai/resources/audio/speech.py index 1ee53db9d5..fad18dcdf5 100644 --- a/src/openai/resources/audio/speech.py +++ b/src/openai/resources/audio/speech.py @@ -9,10 +9,7 @@ from ... import _legacy_response from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ..._utils import ( - maybe_transform, - async_maybe_transform, -) +from ..._utils import maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import ( diff --git a/src/openai/resources/audio/transcriptions.py b/src/openai/resources/audio/transcriptions.py index 7e62f70f60..0c7ebca7a6 100644 --- a/src/openai/resources/audio/transcriptions.py +++ b/src/openai/resources/audio/transcriptions.py @@ -11,13 +11,7 @@ from ... import _legacy_response from ...types import AudioResponseFormat from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven, FileTypes -from ..._utils import ( - extract_files, - required_args, - maybe_transform, - deepcopy_minimal, - async_maybe_transform, -) +from ..._utils import extract_files, required_args, maybe_transform, deepcopy_minimal, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper diff --git a/src/openai/resources/audio/translations.py b/src/openai/resources/audio/translations.py index f55dbd0ee5..28b577ce2e 100644 --- a/src/openai/resources/audio/translations.py +++ b/src/openai/resources/audio/translations.py @@ -10,12 +10,7 @@ from ... import _legacy_response from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven, FileTypes -from ..._utils import ( - extract_files, - maybe_transform, - deepcopy_minimal, - async_maybe_transform, -) +from ..._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper diff --git a/src/openai/resources/batches.py b/src/openai/resources/batches.py index b7a299be12..26ea498b31 100644 --- a/src/openai/resources/batches.py +++ b/src/openai/resources/batches.py @@ -10,10 +10,7 @@ from .. import _legacy_response from ..types import batch_list_params, batch_create_params from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from .._utils import ( - maybe_transform, - async_maybe_transform, -) +from .._utils import maybe_transform, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper diff --git a/src/openai/resources/beta/assistants.py b/src/openai/resources/beta/assistants.py index 43f6a7f135..9059d93616 100644 --- a/src/openai/resources/beta/assistants.py +++ b/src/openai/resources/beta/assistants.py @@ -9,10 +9,7 @@ from ... import _legacy_response from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ..._utils import ( - maybe_transform, - async_maybe_transform, -) +from ..._utils import maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper diff --git a/src/openai/resources/beta/realtime/sessions.py b/src/openai/resources/beta/realtime/sessions.py index 3e1c956fe4..3c0d4d47c1 100644 --- a/src/openai/resources/beta/realtime/sessions.py +++ b/src/openai/resources/beta/realtime/sessions.py @@ -9,10 +9,7 @@ from .... import _legacy_response from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ...._utils import ( - maybe_transform, - async_maybe_transform, -) +from ...._utils import maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper diff --git a/src/openai/resources/beta/realtime/transcription_sessions.py b/src/openai/resources/beta/realtime/transcription_sessions.py index 0917da71fa..dbcb1bb33b 100644 --- a/src/openai/resources/beta/realtime/transcription_sessions.py +++ b/src/openai/resources/beta/realtime/transcription_sessions.py @@ -9,10 +9,7 @@ from .... import _legacy_response from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ...._utils import ( - maybe_transform, - async_maybe_transform, -) +from ...._utils import maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper diff --git a/src/openai/resources/beta/threads/messages.py b/src/openai/resources/beta/threads/messages.py index e3374aba37..3a8913ef16 100644 --- a/src/openai/resources/beta/threads/messages.py +++ b/src/openai/resources/beta/threads/messages.py @@ -9,10 +9,7 @@ from .... import _legacy_response from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ...._utils import ( - maybe_transform, - async_maybe_transform, -) +from ...._utils import maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper diff --git a/src/openai/resources/beta/threads/runs/steps.py b/src/openai/resources/beta/threads/runs/steps.py index 709c729d45..3d2148687b 100644 --- a/src/openai/resources/beta/threads/runs/steps.py +++ b/src/openai/resources/beta/threads/runs/steps.py @@ -9,10 +9,7 @@ from ..... import _legacy_response from ....._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ....._utils import ( - maybe_transform, - async_maybe_transform, -) +from ....._utils import maybe_transform, async_maybe_transform from ....._compat import cached_property from ....._resource import SyncAPIResource, AsyncAPIResource from ....._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper diff --git a/src/openai/resources/beta/threads/threads.py b/src/openai/resources/beta/threads/threads.py index c697be416d..9c6954a9b3 100644 --- a/src/openai/resources/beta/threads/threads.py +++ b/src/openai/resources/beta/threads/threads.py @@ -18,11 +18,7 @@ AsyncMessagesWithStreamingResponse, ) from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ...._utils import ( - required_args, - maybe_transform, - async_maybe_transform, -) +from ...._utils import required_args, maybe_transform, async_maybe_transform from .runs.runs import ( Runs, AsyncRuns, diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index d6214225d8..0ab105a389 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -19,11 +19,7 @@ AsyncMessagesWithStreamingResponse, ) from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ...._utils import ( - required_args, - maybe_transform, - async_maybe_transform, -) +from ...._utils import required_args, maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper diff --git a/src/openai/resources/completions.py b/src/openai/resources/completions.py index aebf35d1f1..43b923b9b9 100644 --- a/src/openai/resources/completions.py +++ b/src/openai/resources/completions.py @@ -10,11 +10,7 @@ from .. import _legacy_response from ..types import completion_create_params from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from .._utils import ( - required_args, - maybe_transform, - async_maybe_transform, -) +from .._utils import required_args, maybe_transform, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper diff --git a/src/openai/resources/evals/evals.py b/src/openai/resources/evals/evals.py index 24a0350cfb..30ac4bdf32 100644 --- a/src/openai/resources/evals/evals.py +++ b/src/openai/resources/evals/evals.py @@ -10,10 +10,7 @@ from ... import _legacy_response from ...types import eval_list_params, eval_create_params, eval_update_params from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ..._utils import ( - maybe_transform, - async_maybe_transform, -) +from ..._utils import maybe_transform, async_maybe_transform from ..._compat import cached_property from .runs.runs import ( Runs, diff --git a/src/openai/resources/evals/runs/runs.py b/src/openai/resources/evals/runs/runs.py index 6df0b6d121..9c626d0903 100644 --- a/src/openai/resources/evals/runs/runs.py +++ b/src/openai/resources/evals/runs/runs.py @@ -9,10 +9,7 @@ from .... import _legacy_response from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ...._utils import ( - maybe_transform, - async_maybe_transform, -) +from ...._utils import maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper diff --git a/src/openai/resources/files.py b/src/openai/resources/files.py index 2eaa4a6401..179af870ba 100644 --- a/src/openai/resources/files.py +++ b/src/openai/resources/files.py @@ -12,12 +12,7 @@ from .. import _legacy_response from ..types import FilePurpose, file_list_params, file_create_params from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven, FileTypes -from .._utils import ( - extract_files, - maybe_transform, - deepcopy_minimal, - async_maybe_transform, -) +from .._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import ( diff --git a/src/openai/resources/fine_tuning/checkpoints/permissions.py b/src/openai/resources/fine_tuning/checkpoints/permissions.py index beb7b099d3..b2bcb33020 100644 --- a/src/openai/resources/fine_tuning/checkpoints/permissions.py +++ b/src/openai/resources/fine_tuning/checkpoints/permissions.py @@ -9,10 +9,7 @@ from .... import _legacy_response from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ...._utils import ( - maybe_transform, - async_maybe_transform, -) +from ...._utils import maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper diff --git a/src/openai/resources/fine_tuning/jobs/jobs.py b/src/openai/resources/fine_tuning/jobs/jobs.py index bbeff60bc6..90619c8609 100644 --- a/src/openai/resources/fine_tuning/jobs/jobs.py +++ b/src/openai/resources/fine_tuning/jobs/jobs.py @@ -9,10 +9,7 @@ from .... import _legacy_response from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ...._utils import ( - maybe_transform, - async_maybe_transform, -) +from ...._utils import maybe_transform, async_maybe_transform from ...._compat import cached_property from .checkpoints import ( Checkpoints, diff --git a/src/openai/resources/images.py b/src/openai/resources/images.py index 30473c14f7..e3398930e9 100644 --- a/src/openai/resources/images.py +++ b/src/openai/resources/images.py @@ -10,12 +10,7 @@ from .. import _legacy_response from ..types import image_edit_params, image_generate_params, image_create_variation_params from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven, FileTypes -from .._utils import ( - extract_files, - maybe_transform, - deepcopy_minimal, - async_maybe_transform, -) +from .._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper diff --git a/src/openai/resources/moderations.py b/src/openai/resources/moderations.py index a8f03142bc..f7a8b52c23 100644 --- a/src/openai/resources/moderations.py +++ b/src/openai/resources/moderations.py @@ -9,10 +9,7 @@ from .. import _legacy_response from ..types import moderation_create_params from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from .._utils import ( - maybe_transform, - async_maybe_transform, -) +from .._utils import maybe_transform, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index f07b4d8c4a..4a0687f9f3 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -10,12 +10,7 @@ from ... import _legacy_response from ..._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven -from ..._utils import ( - is_given, - required_args, - maybe_transform, - async_maybe_transform, -) +from ..._utils import is_given, required_args, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper diff --git a/src/openai/resources/uploads/parts.py b/src/openai/resources/uploads/parts.py index 777469ac8e..a32f4eb1d2 100644 --- a/src/openai/resources/uploads/parts.py +++ b/src/openai/resources/uploads/parts.py @@ -8,12 +8,7 @@ from ... import _legacy_response from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven, FileTypes -from ..._utils import ( - extract_files, - maybe_transform, - deepcopy_minimal, - async_maybe_transform, -) +from ..._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper diff --git a/src/openai/resources/uploads/uploads.py b/src/openai/resources/uploads/uploads.py index 9297dbc2c3..ecfcee4800 100644 --- a/src/openai/resources/uploads/uploads.py +++ b/src/openai/resources/uploads/uploads.py @@ -23,10 +23,7 @@ ) from ...types import FilePurpose, upload_create_params, upload_complete_params from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ..._utils import ( - maybe_transform, - async_maybe_transform, -) +from ..._utils import maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper diff --git a/src/openai/resources/vector_stores/file_batches.py b/src/openai/resources/vector_stores/file_batches.py index 9b4b64d35e..4dd4430b71 100644 --- a/src/openai/resources/vector_stores/file_batches.py +++ b/src/openai/resources/vector_stores/file_batches.py @@ -13,11 +13,7 @@ from ... import _legacy_response from ...types import FileChunkingStrategyParam from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven, FileTypes -from ..._utils import ( - is_given, - maybe_transform, - async_maybe_transform, -) +from ..._utils import is_given, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper diff --git a/src/openai/resources/vector_stores/files.py b/src/openai/resources/vector_stores/files.py index 7d93798adf..f860384629 100644 --- a/src/openai/resources/vector_stores/files.py +++ b/src/openai/resources/vector_stores/files.py @@ -10,11 +10,7 @@ from ... import _legacy_response from ...types import FileChunkingStrategyParam from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven, FileTypes -from ..._utils import ( - is_given, - maybe_transform, - async_maybe_transform, -) +from ..._utils import is_given, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper diff --git a/src/openai/resources/vector_stores/vector_stores.py b/src/openai/resources/vector_stores/vector_stores.py index aaa6ed2757..9fc17b183b 100644 --- a/src/openai/resources/vector_stores/vector_stores.py +++ b/src/openai/resources/vector_stores/vector_stores.py @@ -24,10 +24,7 @@ vector_store_update_params, ) from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ..._utils import ( - maybe_transform, - async_maybe_transform, -) +from ..._utils import maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper From 1e7dea203321d1ca50d3607aaa33f29fbe534a91 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 22 Apr 2025 22:01:33 +0000 Subject: [PATCH 303/769] chore(internal): fix list file params --- src/openai/_utils/_utils.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/openai/_utils/_utils.py b/src/openai/_utils/_utils.py index d6734e6b8f..1e7d013b51 100644 --- a/src/openai/_utils/_utils.py +++ b/src/openai/_utils/_utils.py @@ -76,8 +76,16 @@ def _extract_items( from .._files import assert_is_file_content # We have exhausted the path, return the entry we found. - assert_is_file_content(obj, key=flattened_key) assert flattened_key is not None + + if is_list(obj): + files: list[tuple[str, FileTypes]] = [] + for entry in obj: + assert_is_file_content(entry, key=flattened_key + "[]" if flattened_key else "") + files.append((flattened_key + "[]", cast(FileTypes, entry))) + return files + + assert_is_file_content(obj, key=flattened_key) return [(flattened_key, cast(FileTypes, obj))] index += 1 From 7de6c5ce26a23ca450994c412d12e4244d2bb43c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 22 Apr 2025 22:53:21 +0000 Subject: [PATCH 304/769] chore(internal): refactor retries to not use recursion --- src/openai/_base_client.py | 417 ++++++++++++++++--------------------- 1 file changed, 177 insertions(+), 240 deletions(-) diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index 8b43a20699..a0f9cce7d8 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -439,8 +439,7 @@ def _build_headers(self, options: FinalRequestOptions, *, retries_taken: int = 0 headers = httpx.Headers(headers_dict) idempotency_header = self._idempotency_header - if idempotency_header and options.method.lower() != "get" and idempotency_header not in headers: - options.idempotency_key = options.idempotency_key or self._idempotency_key() + if idempotency_header and options.idempotency_key and idempotency_header not in headers: headers[idempotency_header] = options.idempotency_key # Don't set these headers if they were already set or removed by the caller. We check @@ -905,7 +904,6 @@ def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, - remaining_retries: Optional[int] = None, *, stream: Literal[True], stream_cls: Type[_StreamT], @@ -916,7 +914,6 @@ def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, - remaining_retries: Optional[int] = None, *, stream: Literal[False] = False, ) -> ResponseT: ... @@ -926,7 +923,6 @@ def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, - remaining_retries: Optional[int] = None, *, stream: bool = False, stream_cls: Type[_StreamT] | None = None, @@ -936,126 +932,110 @@ def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, - remaining_retries: Optional[int] = None, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: - if remaining_retries is not None: - retries_taken = options.get_max_retries(self.max_retries) - remaining_retries - else: - retries_taken = 0 - - return self._request( - cast_to=cast_to, - options=options, - stream=stream, - stream_cls=stream_cls, - retries_taken=retries_taken, - ) + cast_to = self._maybe_override_cast_to(cast_to, options) - def _request( - self, - *, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - retries_taken: int, - stream: bool, - stream_cls: type[_StreamT] | None, - ) -> ResponseT | _StreamT: # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) - - cast_to = self._maybe_override_cast_to(cast_to, options) - options = self._prepare_options(options) - - remaining_retries = options.get_max_retries(self.max_retries) - retries_taken - request = self._build_request(options, retries_taken=retries_taken) - self._prepare_request(request) - - if options.idempotency_key: + if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests - input_options.idempotency_key = options.idempotency_key + input_options.idempotency_key = self._idempotency_key() - kwargs: HttpxSendArgs = {} - if self.custom_auth is not None: - kwargs["auth"] = self.custom_auth + response: httpx.Response | None = None + max_retries = input_options.get_max_retries(self.max_retries) - log.debug("Sending HTTP Request: %s %s", request.method, request.url) + retries_taken = 0 + for retries_taken in range(max_retries + 1): + options = model_copy(input_options) + options = self._prepare_options(options) - try: - response = self._client.send( - request, - stream=stream or self._should_stream_response_body(request=request), - **kwargs, - ) - except httpx.TimeoutException as err: - log.debug("Encountered httpx.TimeoutException", exc_info=True) + remaining_retries = max_retries - retries_taken + request = self._build_request(options, retries_taken=retries_taken) + self._prepare_request(request) - if remaining_retries > 0: - return self._retry_request( - input_options, - cast_to, - retries_taken=retries_taken, - stream=stream, - stream_cls=stream_cls, - response_headers=None, - ) + kwargs: HttpxSendArgs = {} + if self.custom_auth is not None: + kwargs["auth"] = self.custom_auth - log.debug("Raising timeout error") - raise APITimeoutError(request=request) from err - except Exception as err: - log.debug("Encountered Exception", exc_info=True) + log.debug("Sending HTTP Request: %s %s", request.method, request.url) - if remaining_retries > 0: - return self._retry_request( - input_options, - cast_to, - retries_taken=retries_taken, - stream=stream, - stream_cls=stream_cls, - response_headers=None, + response = None + try: + response = self._client.send( + request, + stream=stream or self._should_stream_response_body(request=request), + **kwargs, ) + except httpx.TimeoutException as err: + log.debug("Encountered httpx.TimeoutException", exc_info=True) + + if remaining_retries > 0: + self._sleep_for_retry( + retries_taken=retries_taken, + max_retries=max_retries, + options=input_options, + response=None, + ) + continue + + log.debug("Raising timeout error") + raise APITimeoutError(request=request) from err + except Exception as err: + log.debug("Encountered Exception", exc_info=True) + + if remaining_retries > 0: + self._sleep_for_retry( + retries_taken=retries_taken, + max_retries=max_retries, + options=input_options, + response=None, + ) + continue + + log.debug("Raising connection error") + raise APIConnectionError(request=request) from err + + log.debug( + 'HTTP Response: %s %s "%i %s" %s', + request.method, + request.url, + response.status_code, + response.reason_phrase, + response.headers, + ) + log.debug("request_id: %s", response.headers.get("x-request-id")) - log.debug("Raising connection error") - raise APIConnectionError(request=request) from err - - log.debug( - 'HTTP Response: %s %s "%i %s" %s', - request.method, - request.url, - response.status_code, - response.reason_phrase, - response.headers, - ) - log.debug("request_id: %s", response.headers.get("x-request-id")) + try: + response.raise_for_status() + except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code + log.debug("Encountered httpx.HTTPStatusError", exc_info=True) + + if remaining_retries > 0 and self._should_retry(err.response): + err.response.close() + self._sleep_for_retry( + retries_taken=retries_taken, + max_retries=max_retries, + options=input_options, + response=response, + ) + continue - try: - response.raise_for_status() - except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code - log.debug("Encountered httpx.HTTPStatusError", exc_info=True) - - if remaining_retries > 0 and self._should_retry(err.response): - err.response.close() - return self._retry_request( - input_options, - cast_to, - retries_taken=retries_taken, - response_headers=err.response.headers, - stream=stream, - stream_cls=stream_cls, - ) + # If the response is streamed then we need to explicitly read the response + # to completion before attempting to access the response text. + if not err.response.is_closed: + err.response.read() - # If the response is streamed then we need to explicitly read the response - # to completion before attempting to access the response text. - if not err.response.is_closed: - err.response.read() + log.debug("Re-raising status error") + raise self._make_status_error_from_response(err.response) from None - log.debug("Re-raising status error") - raise self._make_status_error_from_response(err.response) from None + break + assert response is not None, "could not resolve response (should never happen)" return self._process_response( cast_to=cast_to, options=options, @@ -1065,37 +1045,20 @@ def _request( retries_taken=retries_taken, ) - def _retry_request( - self, - options: FinalRequestOptions, - cast_to: Type[ResponseT], - *, - retries_taken: int, - response_headers: httpx.Headers | None, - stream: bool, - stream_cls: type[_StreamT] | None, - ) -> ResponseT | _StreamT: - remaining_retries = options.get_max_retries(self.max_retries) - retries_taken + def _sleep_for_retry( + self, *, retries_taken: int, max_retries: int, options: FinalRequestOptions, response: httpx.Response | None + ) -> None: + remaining_retries = max_retries - retries_taken if remaining_retries == 1: log.debug("1 retry left") else: log.debug("%i retries left", remaining_retries) - timeout = self._calculate_retry_timeout(remaining_retries, options, response_headers) + timeout = self._calculate_retry_timeout(remaining_retries, options, response.headers if response else None) log.info("Retrying request to %s in %f seconds", options.url, timeout) - # In a synchronous context we are blocking the entire thread. Up to the library user to run the client in a - # different thread if necessary. time.sleep(timeout) - return self._request( - options=options, - cast_to=cast_to, - retries_taken=retries_taken + 1, - stream=stream, - stream_cls=stream_cls, - ) - def _process_response( self, *, @@ -1453,7 +1416,6 @@ async def request( options: FinalRequestOptions, *, stream: Literal[False] = False, - remaining_retries: Optional[int] = None, ) -> ResponseT: ... @overload @@ -1464,7 +1426,6 @@ async def request( *, stream: Literal[True], stream_cls: type[_AsyncStreamT], - remaining_retries: Optional[int] = None, ) -> _AsyncStreamT: ... @overload @@ -1475,7 +1436,6 @@ async def request( *, stream: bool, stream_cls: type[_AsyncStreamT] | None = None, - remaining_retries: Optional[int] = None, ) -> ResponseT | _AsyncStreamT: ... async def request( @@ -1485,120 +1445,112 @@ async def request( *, stream: bool = False, stream_cls: type[_AsyncStreamT] | None = None, - remaining_retries: Optional[int] = None, - ) -> ResponseT | _AsyncStreamT: - if remaining_retries is not None: - retries_taken = options.get_max_retries(self.max_retries) - remaining_retries - else: - retries_taken = 0 - - return await self._request( - cast_to=cast_to, - options=options, - stream=stream, - stream_cls=stream_cls, - retries_taken=retries_taken, - ) - - async def _request( - self, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - *, - stream: bool, - stream_cls: type[_AsyncStreamT] | None, - retries_taken: int, ) -> ResponseT | _AsyncStreamT: if self._platform is None: # `get_platform` can make blocking IO calls so we # execute it earlier while we are in an async context self._platform = await asyncify(get_platform)() + cast_to = self._maybe_override_cast_to(cast_to, options) + # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) - - cast_to = self._maybe_override_cast_to(cast_to, options) - options = await self._prepare_options(options) - - remaining_retries = options.get_max_retries(self.max_retries) - retries_taken - request = self._build_request(options, retries_taken=retries_taken) - await self._prepare_request(request) - - if options.idempotency_key: + if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests - input_options.idempotency_key = options.idempotency_key + input_options.idempotency_key = self._idempotency_key() - kwargs: HttpxSendArgs = {} - if self.custom_auth is not None: - kwargs["auth"] = self.custom_auth + response: httpx.Response | None = None + max_retries = input_options.get_max_retries(self.max_retries) - try: - response = await self._client.send( - request, - stream=stream or self._should_stream_response_body(request=request), - **kwargs, - ) - except httpx.TimeoutException as err: - log.debug("Encountered httpx.TimeoutException", exc_info=True) + retries_taken = 0 + for retries_taken in range(max_retries + 1): + options = model_copy(input_options) + options = await self._prepare_options(options) - if remaining_retries > 0: - return await self._retry_request( - input_options, - cast_to, - retries_taken=retries_taken, - stream=stream, - stream_cls=stream_cls, - response_headers=None, - ) + remaining_retries = max_retries - retries_taken + request = self._build_request(options, retries_taken=retries_taken) + await self._prepare_request(request) - log.debug("Raising timeout error") - raise APITimeoutError(request=request) from err - except Exception as err: - log.debug("Encountered Exception", exc_info=True) + kwargs: HttpxSendArgs = {} + if self.custom_auth is not None: + kwargs["auth"] = self.custom_auth - if remaining_retries > 0: - return await self._retry_request( - input_options, - cast_to, - retries_taken=retries_taken, - stream=stream, - stream_cls=stream_cls, - response_headers=None, - ) + log.debug("Sending HTTP Request: %s %s", request.method, request.url) - log.debug("Raising connection error") - raise APIConnectionError(request=request) from err + response = None + try: + response = await self._client.send( + request, + stream=stream or self._should_stream_response_body(request=request), + **kwargs, + ) + except httpx.TimeoutException as err: + log.debug("Encountered httpx.TimeoutException", exc_info=True) + + if remaining_retries > 0: + await self._sleep_for_retry( + retries_taken=retries_taken, + max_retries=max_retries, + options=input_options, + response=None, + ) + continue + + log.debug("Raising timeout error") + raise APITimeoutError(request=request) from err + except Exception as err: + log.debug("Encountered Exception", exc_info=True) + + if remaining_retries > 0: + await self._sleep_for_retry( + retries_taken=retries_taken, + max_retries=max_retries, + options=input_options, + response=None, + ) + continue + + log.debug("Raising connection error") + raise APIConnectionError(request=request) from err + + log.debug( + 'HTTP Response: %s %s "%i %s" %s', + request.method, + request.url, + response.status_code, + response.reason_phrase, + response.headers, + ) + log.debug("request_id: %s", response.headers.get("x-request-id")) - log.debug( - 'HTTP Request: %s %s "%i %s"', request.method, request.url, response.status_code, response.reason_phrase - ) + try: + response.raise_for_status() + except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code + log.debug("Encountered httpx.HTTPStatusError", exc_info=True) + + if remaining_retries > 0 and self._should_retry(err.response): + await err.response.aclose() + await self._sleep_for_retry( + retries_taken=retries_taken, + max_retries=max_retries, + options=input_options, + response=response, + ) + continue - try: - response.raise_for_status() - except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code - log.debug("Encountered httpx.HTTPStatusError", exc_info=True) - - if remaining_retries > 0 and self._should_retry(err.response): - await err.response.aclose() - return await self._retry_request( - input_options, - cast_to, - retries_taken=retries_taken, - response_headers=err.response.headers, - stream=stream, - stream_cls=stream_cls, - ) + # If the response is streamed then we need to explicitly read the response + # to completion before attempting to access the response text. + if not err.response.is_closed: + await err.response.aread() - # If the response is streamed then we need to explicitly read the response - # to completion before attempting to access the response text. - if not err.response.is_closed: - await err.response.aread() + log.debug("Re-raising status error") + raise self._make_status_error_from_response(err.response) from None - log.debug("Re-raising status error") - raise self._make_status_error_from_response(err.response) from None + break + assert response is not None, "could not resolve response (should never happen)" return await self._process_response( cast_to=cast_to, options=options, @@ -1608,35 +1560,20 @@ async def _request( retries_taken=retries_taken, ) - async def _retry_request( - self, - options: FinalRequestOptions, - cast_to: Type[ResponseT], - *, - retries_taken: int, - response_headers: httpx.Headers | None, - stream: bool, - stream_cls: type[_AsyncStreamT] | None, - ) -> ResponseT | _AsyncStreamT: - remaining_retries = options.get_max_retries(self.max_retries) - retries_taken + async def _sleep_for_retry( + self, *, retries_taken: int, max_retries: int, options: FinalRequestOptions, response: httpx.Response | None + ) -> None: + remaining_retries = max_retries - retries_taken if remaining_retries == 1: log.debug("1 retry left") else: log.debug("%i retries left", remaining_retries) - timeout = self._calculate_retry_timeout(remaining_retries, options, response_headers) + timeout = self._calculate_retry_timeout(remaining_retries, options, response.headers if response else None) log.info("Retrying request to %s in %f seconds", options.url, timeout) await anyio.sleep(timeout) - return await self._request( - options=options, - cast_to=cast_to, - retries_taken=retries_taken + 1, - stream=stream, - stream_cls=stream_cls, - ) - async def _process_response( self, *, From 6a2dfbb86c24edea66ecc57fc25e28c4d7d73616 Mon Sep 17 00:00:00 2001 From: Konnor-Young <97478325+Konnor-Young@users.noreply.github.com> Date: Tue, 22 Apr 2025 17:24:20 -0600 Subject: [PATCH 305/769] fix(pydantic v1): more robust `ModelField.annotation` check (#2163) --------- Co-authored-by: Konnor Young Co-authored-by: Robert Craigie --- src/openai/_models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/openai/_models.py b/src/openai/_models.py index 9b1aeb30bf..6b6f8e9294 100644 --- a/src/openai/_models.py +++ b/src/openai/_models.py @@ -651,8 +651,8 @@ def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, # Note: if one variant defines an alias then they all should discriminator_alias = field_info.alias - if field_info.annotation and is_literal_type(field_info.annotation): - for entry in get_args(field_info.annotation): + if (annotation := getattr(field_info, 'annotation', None)) and is_literal_type(annotation): + for entry in get_args(annotation): if isinstance(entry, str): mapping[entry] = variant From 8830a6c9234ebcc058f7661978b961c2bbdd2c93 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 23 Apr 2025 12:00:43 +0000 Subject: [PATCH 306/769] fix(pydantic v1): more robust ModelField.annotation check --- src/openai/_models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openai/_models.py b/src/openai/_models.py index 6b6f8e9294..e2fce49250 100644 --- a/src/openai/_models.py +++ b/src/openai/_models.py @@ -651,7 +651,7 @@ def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, # Note: if one variant defines an alias then they all should discriminator_alias = field_info.alias - if (annotation := getattr(field_info, 'annotation', None)) and is_literal_type(annotation): + if (annotation := getattr(field_info, "annotation", None)) and is_literal_type(annotation): for entry in get_args(annotation): if isinstance(entry, str): mapping[entry] = variant From 1c1d144e428c60643f0fce52e3ffd9b681c9083c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 23 Apr 2025 16:20:27 +0000 Subject: [PATCH 307/769] chore(internal): minor formatting changes --- src/openai/types/audio/transcription_word.py | 1 - src/openai/types/audio/translation.py | 1 - src/openai/types/batch_request_counts.py | 1 - src/openai/types/beta/assistant_tool_choice_function.py | 1 - src/openai/types/chat/chat_completion_audio.py | 1 - src/openai/types/chat/chat_completion_reasoning_effort.py | 1 - src/openai/types/chat/chat_completion_store_message.py | 1 - src/openai/types/chat_model.py | 1 - src/openai/types/eval_delete_response.py | 1 - src/openai/types/evals/eval_api_error.py | 1 - src/openai/types/fine_tuning/fine_tuning_job_integration.py | 1 - src/openai/types/model_deleted.py | 1 - src/openai/types/responses/response_function_tool_call_item.py | 1 - src/openai/types/responses/response_usage.py | 1 - src/openai/types/static_file_chunking_strategy.py | 1 - 15 files changed, 15 deletions(-) diff --git a/src/openai/types/audio/transcription_word.py b/src/openai/types/audio/transcription_word.py index 969da32509..2ce682f957 100644 --- a/src/openai/types/audio/transcription_word.py +++ b/src/openai/types/audio/transcription_word.py @@ -1,6 +1,5 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from ..._models import BaseModel __all__ = ["TranscriptionWord"] diff --git a/src/openai/types/audio/translation.py b/src/openai/types/audio/translation.py index 7c0e905189..efc56f7f9b 100644 --- a/src/openai/types/audio/translation.py +++ b/src/openai/types/audio/translation.py @@ -1,6 +1,5 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from ..._models import BaseModel __all__ = ["Translation"] diff --git a/src/openai/types/batch_request_counts.py b/src/openai/types/batch_request_counts.py index 7e1d49fb88..068b071af1 100644 --- a/src/openai/types/batch_request_counts.py +++ b/src/openai/types/batch_request_counts.py @@ -1,6 +1,5 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from .._models import BaseModel __all__ = ["BatchRequestCounts"] diff --git a/src/openai/types/beta/assistant_tool_choice_function.py b/src/openai/types/beta/assistant_tool_choice_function.py index 0c896d8087..87f38310ca 100644 --- a/src/openai/types/beta/assistant_tool_choice_function.py +++ b/src/openai/types/beta/assistant_tool_choice_function.py @@ -1,6 +1,5 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from ..._models import BaseModel __all__ = ["AssistantToolChoiceFunction"] diff --git a/src/openai/types/chat/chat_completion_audio.py b/src/openai/types/chat/chat_completion_audio.py index dd15508ebb..232d60563d 100644 --- a/src/openai/types/chat/chat_completion_audio.py +++ b/src/openai/types/chat/chat_completion_audio.py @@ -1,6 +1,5 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from ..._models import BaseModel __all__ = ["ChatCompletionAudio"] diff --git a/src/openai/types/chat/chat_completion_reasoning_effort.py b/src/openai/types/chat/chat_completion_reasoning_effort.py index e4785c90bf..42a980c5b8 100644 --- a/src/openai/types/chat/chat_completion_reasoning_effort.py +++ b/src/openai/types/chat/chat_completion_reasoning_effort.py @@ -1,6 +1,5 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from ..shared.reasoning_effort import ReasoningEffort __all__ = ["ChatCompletionReasoningEffort"] diff --git a/src/openai/types/chat/chat_completion_store_message.py b/src/openai/types/chat/chat_completion_store_message.py index 95adc08af8..8dc093f7b8 100644 --- a/src/openai/types/chat/chat_completion_store_message.py +++ b/src/openai/types/chat/chat_completion_store_message.py @@ -1,6 +1,5 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from .chat_completion_message import ChatCompletionMessage __all__ = ["ChatCompletionStoreMessage"] diff --git a/src/openai/types/chat_model.py b/src/openai/types/chat_model.py index 9304d195d6..f3b0e310cc 100644 --- a/src/openai/types/chat_model.py +++ b/src/openai/types/chat_model.py @@ -1,6 +1,5 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from .shared import chat_model __all__ = ["ChatModel"] diff --git a/src/openai/types/eval_delete_response.py b/src/openai/types/eval_delete_response.py index adb460ddbb..a27261e242 100644 --- a/src/openai/types/eval_delete_response.py +++ b/src/openai/types/eval_delete_response.py @@ -1,6 +1,5 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from .._models import BaseModel __all__ = ["EvalDeleteResponse"] diff --git a/src/openai/types/evals/eval_api_error.py b/src/openai/types/evals/eval_api_error.py index d67185e981..fe76871024 100644 --- a/src/openai/types/evals/eval_api_error.py +++ b/src/openai/types/evals/eval_api_error.py @@ -1,6 +1,5 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from ..._models import BaseModel __all__ = ["EvalAPIError"] diff --git a/src/openai/types/fine_tuning/fine_tuning_job_integration.py b/src/openai/types/fine_tuning/fine_tuning_job_integration.py index 9a66aa4f17..2af73fbffb 100644 --- a/src/openai/types/fine_tuning/fine_tuning_job_integration.py +++ b/src/openai/types/fine_tuning/fine_tuning_job_integration.py @@ -1,6 +1,5 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from .fine_tuning_job_wandb_integration_object import FineTuningJobWandbIntegrationObject FineTuningJobIntegration = FineTuningJobWandbIntegrationObject diff --git a/src/openai/types/model_deleted.py b/src/openai/types/model_deleted.py index 7f81e1b380..e7601f74e4 100644 --- a/src/openai/types/model_deleted.py +++ b/src/openai/types/model_deleted.py @@ -1,6 +1,5 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from .._models import BaseModel __all__ = ["ModelDeleted"] diff --git a/src/openai/types/responses/response_function_tool_call_item.py b/src/openai/types/responses/response_function_tool_call_item.py index 25984f9451..762015a4b1 100644 --- a/src/openai/types/responses/response_function_tool_call_item.py +++ b/src/openai/types/responses/response_function_tool_call_item.py @@ -1,6 +1,5 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from .response_function_tool_call import ResponseFunctionToolCall __all__ = ["ResponseFunctionToolCallItem"] diff --git a/src/openai/types/responses/response_usage.py b/src/openai/types/responses/response_usage.py index 9ad36bd326..52b93ac578 100644 --- a/src/openai/types/responses/response_usage.py +++ b/src/openai/types/responses/response_usage.py @@ -1,6 +1,5 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from ..._models import BaseModel __all__ = ["ResponseUsage", "InputTokensDetails", "OutputTokensDetails"] diff --git a/src/openai/types/static_file_chunking_strategy.py b/src/openai/types/static_file_chunking_strategy.py index 2813bc6630..cb842442c1 100644 --- a/src/openai/types/static_file_chunking_strategy.py +++ b/src/openai/types/static_file_chunking_strategy.py @@ -1,6 +1,5 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from .._models import BaseModel __all__ = ["StaticFileChunkingStrategy"] From 6321004aef37251116e7b79bcde71e404fce0300 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 23 Apr 2025 16:29:55 +0000 Subject: [PATCH 308/769] feat(api): adding new image model support --- .stats.yml | 6 +- api.md | 6 +- .../resources/beta/realtime/realtime.py | 34 +++ src/openai/resources/beta/threads/threads.py | 17 +- src/openai/resources/evals/evals.py | 8 - src/openai/resources/evals/runs/runs.py | 8 +- .../fine_tuning/checkpoints/permissions.py | 14 +- src/openai/resources/images.py | 248 +++++++++++++----- .../beta/realtime/realtime_client_event.py | 17 +- .../realtime/realtime_client_event_param.py | 14 +- .../beta/realtime/realtime_server_event.py | 44 +++- .../beta/thread_create_and_run_params.py | 9 +- src/openai/types/eval_create_params.py | 166 ++++++++---- src/openai/types/eval_create_response.py | 96 ++++++- src/openai/types/eval_label_model_grader.py | 57 ++-- src/openai/types/eval_list_response.py | 96 ++++++- src/openai/types/eval_retrieve_response.py | 96 ++++++- .../types/eval_text_similarity_grader.py | 16 +- .../eval_text_similarity_grader_param.py | 16 +- src/openai/types/eval_update_response.py | 96 ++++++- ...create_eval_completions_run_data_source.py | 165 ++++++------ ..._eval_completions_run_data_source_param.py | 169 ++++++------ src/openai/types/evals/run_cancel_response.py | 218 ++++++++++++++- src/openai/types/evals/run_create_params.py | 222 +++++++++++++++- src/openai/types/evals/run_create_response.py | 218 ++++++++++++++- src/openai/types/evals/run_list_params.py | 2 +- src/openai/types/evals/run_list_response.py | 218 ++++++++++++++- .../types/evals/run_retrieve_response.py | 218 ++++++++++++++- src/openai/types/image.py | 18 +- .../types/image_create_variation_params.py | 5 +- src/openai/types/image_edit_params.py | 37 ++- src/openai/types/image_generate_params.py | 74 ++++-- src/openai/types/image_model.py | 2 +- src/openai/types/images_response.py | 33 ++- src/openai/types/responses/__init__.py | 13 + .../types/responses/easy_input_message.py | 26 ++ ...onse_reasoning_summary_part_added_event.py | 32 +++ ...ponse_reasoning_summary_part_done_event.py | 32 +++ ...onse_reasoning_summary_text_delta_event.py | 24 ++ ...ponse_reasoning_summary_text_done_event.py | 24 ++ .../types/responses/response_stream_event.py | 8 + .../checkpoints/test_permissions.py | 44 ++-- tests/api_resources/test_evals.py | 2 - tests/api_resources/test_images.py | 14 +- 44 files changed, 2367 insertions(+), 515 deletions(-) create mode 100644 src/openai/types/responses/easy_input_message.py create mode 100644 src/openai/types/responses/response_reasoning_summary_part_added_event.py create mode 100644 src/openai/types/responses/response_reasoning_summary_part_done_event.py create mode 100644 src/openai/types/responses/response_reasoning_summary_text_delta_event.py create mode 100644 src/openai/types/responses/response_reasoning_summary_text_done_event.py diff --git a/.stats.yml b/.stats.yml index 848c5b5adb..d92408173b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 97 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-5633633cc38734869cf7d993f7b549bb8e4d10e0ec45381ec2cd91507cd8eb8f.yml -openapi_spec_hash: c855121b2b2324b99499c9244c21d24d -config_hash: d20837393b73efdb19cd08e04c1cc9a1 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-8b68ae6b807dca92e914da1dd9e835a20f69b075e79102a264367fd7fddddb33.yml +openapi_spec_hash: b6ade5b1a6327339e6669e1134de2d03 +config_hash: b597cd9a31e9e5ec709e2eefb4c54122 diff --git a/api.md b/api.md index e06f55c2cc..d04c76960e 100644 --- a/api.md +++ b/api.md @@ -277,7 +277,7 @@ Methods: - client.fine_tuning.checkpoints.permissions.create(fine_tuned_model_checkpoint, \*\*params) -> SyncPage[PermissionCreateResponse] - client.fine_tuning.checkpoints.permissions.retrieve(fine_tuned_model_checkpoint, \*\*params) -> PermissionRetrieveResponse -- client.fine_tuning.checkpoints.permissions.delete(fine_tuned_model_checkpoint) -> PermissionDeleteResponse +- client.fine_tuning.checkpoints.permissions.delete(permission_id, \*, fine_tuned_model_checkpoint) -> PermissionDeleteResponse # VectorStores @@ -689,6 +689,10 @@ from openai.types.responses import ( ResponseOutputRefusal, ResponseOutputText, ResponseReasoningItem, + ResponseReasoningSummaryPartAddedEvent, + ResponseReasoningSummaryPartDoneEvent, + ResponseReasoningSummaryTextDeltaEvent, + ResponseReasoningSummaryTextDoneEvent, ResponseRefusalDeltaEvent, ResponseRefusalDoneEvent, ResponseStatus, diff --git a/src/openai/resources/beta/realtime/realtime.py b/src/openai/resources/beta/realtime/realtime.py index 5cafce1322..d39db48e05 100644 --- a/src/openai/resources/beta/realtime/realtime.py +++ b/src/openai/resources/beta/realtime/realtime.py @@ -233,6 +233,7 @@ class AsyncRealtimeConnection: response: AsyncRealtimeResponseResource input_audio_buffer: AsyncRealtimeInputAudioBufferResource conversation: AsyncRealtimeConversationResource + output_audio_buffer: AsyncRealtimeOutputAudioBufferResource transcription_session: AsyncRealtimeTranscriptionSessionResource _connection: AsyncWebsocketConnection @@ -244,6 +245,7 @@ def __init__(self, connection: AsyncWebsocketConnection) -> None: self.response = AsyncRealtimeResponseResource(self) self.input_audio_buffer = AsyncRealtimeInputAudioBufferResource(self) self.conversation = AsyncRealtimeConversationResource(self) + self.output_audio_buffer = AsyncRealtimeOutputAudioBufferResource(self) self.transcription_session = AsyncRealtimeTranscriptionSessionResource(self) async def __aiter__(self) -> AsyncIterator[RealtimeServerEvent]: @@ -413,6 +415,7 @@ class RealtimeConnection: response: RealtimeResponseResource input_audio_buffer: RealtimeInputAudioBufferResource conversation: RealtimeConversationResource + output_audio_buffer: RealtimeOutputAudioBufferResource transcription_session: RealtimeTranscriptionSessionResource _connection: WebsocketConnection @@ -424,6 +427,7 @@ def __init__(self, connection: WebsocketConnection) -> None: self.response = RealtimeResponseResource(self) self.input_audio_buffer = RealtimeInputAudioBufferResource(self) self.conversation = RealtimeConversationResource(self) + self.output_audio_buffer = RealtimeOutputAudioBufferResource(self) self.transcription_session = RealtimeTranscriptionSessionResource(self) def __iter__(self) -> Iterator[RealtimeServerEvent]: @@ -808,6 +812,21 @@ def retrieve(self, *, item_id: str, event_id: str | NotGiven = NOT_GIVEN) -> Non ) +class RealtimeOutputAudioBufferResource(BaseRealtimeConnectionResource): + def clear(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: + """**WebRTC Only:** Emit to cut off the current audio response. + + This will trigger the server to + stop generating audio and emit a `output_audio_buffer.cleared` event. This + event should be preceded by a `response.cancel` client event to stop the + generation of the current response. + [Learn more](https://platform.openai.com/docs/guides/realtime-model-capabilities#client-and-server-events-for-audio-in-webrtc). + """ + self._connection.send( + cast(RealtimeClientEventParam, strip_not_given({"type": "output_audio_buffer.clear", "event_id": event_id})) + ) + + class RealtimeTranscriptionSessionResource(BaseRealtimeConnectionResource): def update( self, *, session: transcription_session_update_param.Session, event_id: str | NotGiven = NOT_GIVEN @@ -1045,6 +1064,21 @@ async def retrieve(self, *, item_id: str, event_id: str | NotGiven = NOT_GIVEN) ) +class AsyncRealtimeOutputAudioBufferResource(BaseAsyncRealtimeConnectionResource): + async def clear(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: + """**WebRTC Only:** Emit to cut off the current audio response. + + This will trigger the server to + stop generating audio and emit a `output_audio_buffer.cleared` event. This + event should be preceded by a `response.cancel` client event to stop the + generation of the current response. + [Learn more](https://platform.openai.com/docs/guides/realtime-model-capabilities#client-and-server-events-for-audio-in-webrtc). + """ + await self._connection.send( + cast(RealtimeClientEventParam, strip_not_given({"type": "output_audio_buffer.clear", "event_id": event_id})) + ) + + class AsyncRealtimeTranscriptionSessionResource(BaseAsyncRealtimeConnectionResource): async def update( self, *, session: transcription_session_update_param.Session, event_id: str | NotGiven = NOT_GIVEN diff --git a/src/openai/resources/beta/threads/threads.py b/src/openai/resources/beta/threads/threads.py index 9c6954a9b3..22dc5fe0ea 100644 --- a/src/openai/resources/beta/threads/threads.py +++ b/src/openai/resources/beta/threads/threads.py @@ -50,6 +50,7 @@ from ....types.shared.chat_model import ChatModel from ....types.beta.thread_deleted import ThreadDeleted from ....types.shared_params.metadata import Metadata +from ....types.beta.assistant_tool_param import AssistantToolParam from ....types.beta.assistant_stream_event import AssistantStreamEvent from ....types.beta.assistant_tool_choice_option_param import AssistantToolChoiceOptionParam from ....types.beta.assistant_response_format_option_param import AssistantResponseFormatOptionParam @@ -282,7 +283,7 @@ def create_and_run( thread: thread_create_and_run_params.Thread | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[thread_create_and_run_params.Tool]] | NotGiven = NOT_GIVEN, + tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -415,7 +416,7 @@ def create_and_run( thread: thread_create_and_run_params.Thread | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[thread_create_and_run_params.Tool]] | NotGiven = NOT_GIVEN, + tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -548,7 +549,7 @@ def create_and_run( thread: thread_create_and_run_params.Thread | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[thread_create_and_run_params.Tool]] | NotGiven = NOT_GIVEN, + tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -681,7 +682,7 @@ def create_and_run( thread: thread_create_and_run_params.Thread | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[thread_create_and_run_params.Tool]] | NotGiven = NOT_GIVEN, + tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -1131,7 +1132,7 @@ async def create_and_run( thread: thread_create_and_run_params.Thread | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[thread_create_and_run_params.Tool]] | NotGiven = NOT_GIVEN, + tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -1264,7 +1265,7 @@ async def create_and_run( thread: thread_create_and_run_params.Thread | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[thread_create_and_run_params.Tool]] | NotGiven = NOT_GIVEN, + tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -1397,7 +1398,7 @@ async def create_and_run( thread: thread_create_and_run_params.Thread | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[thread_create_and_run_params.Tool]] | NotGiven = NOT_GIVEN, + tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -1530,7 +1531,7 @@ async def create_and_run( thread: thread_create_and_run_params.Thread | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[thread_create_and_run_params.Tool]] | NotGiven = NOT_GIVEN, + tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. diff --git a/src/openai/resources/evals/evals.py b/src/openai/resources/evals/evals.py index 30ac4bdf32..c12562a86d 100644 --- a/src/openai/resources/evals/evals.py +++ b/src/openai/resources/evals/evals.py @@ -65,7 +65,6 @@ def create( testing_criteria: Iterable[eval_create_params.TestingCriterion], metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, name: str | NotGiven = NOT_GIVEN, - share_with_openai: bool | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -94,8 +93,6 @@ def create( name: The name of the evaluation. - share_with_openai: Indicates whether the evaluation is shared with OpenAI. - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -112,7 +109,6 @@ def create( "testing_criteria": testing_criteria, "metadata": metadata, "name": name, - "share_with_openai": share_with_openai, }, eval_create_params.EvalCreateParams, ), @@ -328,7 +324,6 @@ async def create( testing_criteria: Iterable[eval_create_params.TestingCriterion], metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, name: str | NotGiven = NOT_GIVEN, - share_with_openai: bool | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -357,8 +352,6 @@ async def create( name: The name of the evaluation. - share_with_openai: Indicates whether the evaluation is shared with OpenAI. - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -375,7 +368,6 @@ async def create( "testing_criteria": testing_criteria, "metadata": metadata, "name": name, - "share_with_openai": share_with_openai, }, eval_create_params.EvalCreateParams, ), diff --git a/src/openai/resources/evals/runs/runs.py b/src/openai/resources/evals/runs/runs.py index 9c626d0903..d74c91e3c4 100644 --- a/src/openai/resources/evals/runs/runs.py +++ b/src/openai/resources/evals/runs/runs.py @@ -176,8 +176,8 @@ def list( order: Sort order for runs by timestamp. Use `asc` for ascending order or `desc` for descending order. Defaults to `asc`. - status: Filter runs by status. Use "queued" | "in_progress" | "failed" | "completed" | - "canceled". + status: Filter runs by status. One of `queued` | `in_progress` | `failed` | `completed` + | `canceled`. extra_headers: Send extra headers @@ -425,8 +425,8 @@ def list( order: Sort order for runs by timestamp. Use `asc` for ascending order or `desc` for descending order. Defaults to `asc`. - status: Filter runs by status. Use "queued" | "in_progress" | "failed" | "completed" | - "canceled". + status: Filter runs by status. One of `queued` | `in_progress` | `failed` | `completed` + | `canceled`. extra_headers: Send extra headers diff --git a/src/openai/resources/fine_tuning/checkpoints/permissions.py b/src/openai/resources/fine_tuning/checkpoints/permissions.py index b2bcb33020..547e42ecac 100644 --- a/src/openai/resources/fine_tuning/checkpoints/permissions.py +++ b/src/openai/resources/fine_tuning/checkpoints/permissions.py @@ -151,8 +151,9 @@ def retrieve( def delete( self, - fine_tuned_model_checkpoint: str, + permission_id: str, *, + fine_tuned_model_checkpoint: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -179,8 +180,10 @@ def delete( raise ValueError( f"Expected a non-empty value for `fine_tuned_model_checkpoint` but received {fine_tuned_model_checkpoint!r}" ) + if not permission_id: + raise ValueError(f"Expected a non-empty value for `permission_id` but received {permission_id!r}") return self._delete( - f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions/{permission_id}", options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -316,8 +319,9 @@ async def retrieve( async def delete( self, - fine_tuned_model_checkpoint: str, + permission_id: str, *, + fine_tuned_model_checkpoint: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -344,8 +348,10 @@ async def delete( raise ValueError( f"Expected a non-empty value for `fine_tuned_model_checkpoint` but received {fine_tuned_model_checkpoint!r}" ) + if not permission_id: + raise ValueError(f"Expected a non-empty value for `permission_id` but received {permission_id!r}") return await self._delete( - f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions/{permission_id}", options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/images.py b/src/openai/resources/images.py index e3398930e9..e59d0ce35c 100644 --- a/src/openai/resources/images.py +++ b/src/openai/resources/images.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Union, Mapping, Optional, cast +from typing import List, Union, Mapping, Optional, cast from typing_extensions import Literal import httpx @@ -57,8 +57,9 @@ def create_variation( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> ImagesResponse: - """ - Creates a variation of a given image. + """Creates a variation of a given image. + + This endpoint only supports `dall-e-2`. Args: image: The image to use as the basis for the variation(s). Must be a valid PNG file, @@ -67,8 +68,7 @@ def create_variation( model: The model to use for image generation. Only `dall-e-2` is supported at this time. - n: The number of images to generate. Must be between 1 and 10. For `dall-e-3`, only - `n=1` is supported. + n: The number of images to generate. Must be between 1 and 10. response_format: The format in which the generated images are returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes after the image has been @@ -117,11 +117,12 @@ def create_variation( def edit( self, *, - image: FileTypes, + image: Union[FileTypes, List[FileTypes]], prompt: str, mask: FileTypes | NotGiven = NOT_GIVEN, model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, + quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, size: Optional[Literal["256x256", "512x512", "1024x1024"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, @@ -132,31 +133,43 @@ def edit( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> ImagesResponse: - """ - Creates an edited or extended image given an original image and a prompt. + """Creates an edited or extended image given one or more source images and a + prompt. + + This endpoint only supports `gpt-image-1` and `dall-e-2`. Args: - image: The image to edit. Must be a valid PNG file, less than 4MB, and square. If mask - is not provided, image must have transparency, which will be used as the mask. + image: The image(s) to edit. Must be a supported image file or an array of images. For + `gpt-image-1`, each image should be a `png`, `webp`, or `jpg` file less than + 25MB. For `dall-e-2`, you can only provide one image, and it should be a square + `png` file less than 4MB. prompt: A text description of the desired image(s). The maximum length is 1000 - characters. + characters for `dall-e-2`, and 32000 characters for `gpt-image-1`. mask: An additional image whose fully transparent areas (e.g. where alpha is zero) - indicate where `image` should be edited. Must be a valid PNG file, less than + indicate where `image` should be edited. If there are multiple images provided, + the mask will be applied on the first image. Must be a valid PNG file, less than 4MB, and have the same dimensions as `image`. - model: The model to use for image generation. Only `dall-e-2` is supported at this - time. + model: The model to use for image generation. Only `dall-e-2` and `gpt-image-1` are + supported. Defaults to `dall-e-2` unless a parameter specific to `gpt-image-1` + is used. n: The number of images to generate. Must be between 1 and 10. + quality: The quality of the image that will be generated. `high`, `medium` and `low` are + only supported for `gpt-image-1`. `dall-e-2` only supports `standard` quality. + Defaults to `auto`. + response_format: The format in which the generated images are returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes after the image has been - generated. + generated. This parameter is only supported for `dall-e-2`, as `gpt-image-1` + will always return base64-encoded images. - size: The size of the generated images. Must be one of `256x256`, `512x512`, or - `1024x1024`. + size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` + (landscape), `1024x1536` (portrait), or `auto` (default value) for + `gpt-image-1`, and one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`. user: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. @@ -177,12 +190,13 @@ def edit( "mask": mask, "model": model, "n": n, + "quality": quality, "response_format": response_format, "size": size, "user": user, } ) - files = extract_files(cast(Mapping[str, object], body), paths=[["image"], ["mask"]]) + files = extract_files(cast(Mapping[str, object], body), paths=[["image"], ["image", ""], ["mask"]]) # It should be noted that the actual Content-Type header that will be # sent to the server will contain a `boundary` parameter, e.g. # multipart/form-data; boundary=---abc-- @@ -201,11 +215,18 @@ def generate( self, *, prompt: str, + background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, + moderation: Optional[Literal["low", "auto"]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, - quality: Literal["standard", "hd"] | NotGiven = NOT_GIVEN, + output_compression: Optional[int] | NotGiven = NOT_GIVEN, + output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, + quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, - size: Optional[Literal["256x256", "512x512", "1024x1024", "1792x1024", "1024x1792"]] | NotGiven = NOT_GIVEN, + size: Optional[ + Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] + ] + | NotGiven = NOT_GIVEN, style: Optional[Literal["vivid", "natural"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -217,32 +238,60 @@ def generate( ) -> ImagesResponse: """ Creates an image given a prompt. + [Learn more](https://platform.openai.com/docs/guides/images). Args: - prompt: A text description of the desired image(s). The maximum length is 1000 - characters for `dall-e-2` and 4000 characters for `dall-e-3`. + prompt: A text description of the desired image(s). The maximum length is 32000 + characters for `gpt-image-1`, 1000 characters for `dall-e-2` and 4000 characters + for `dall-e-3`. + + background: Allows to set transparency for the background of the generated image(s). This + parameter is only supported for `gpt-image-1`. Must be one of `transparent`, + `opaque` or `auto` (default value). When `auto` is used, the model will + automatically determine the best background for the image. + + If `transparent`, the output format needs to support transparency, so it should + be set to either `png` (default value) or `webp`. - model: The model to use for image generation. + model: The model to use for image generation. One of `dall-e-2`, `dall-e-3`, or + `gpt-image-1`. Defaults to `dall-e-2` unless a parameter specific to + `gpt-image-1` is used. + + moderation: Control the content-moderation level for images generated by `gpt-image-1`. Must + be either `low` for less restrictive filtering or `auto` (default value). n: The number of images to generate. Must be between 1 and 10. For `dall-e-3`, only `n=1` is supported. - quality: The quality of the image that will be generated. `hd` creates images with finer - details and greater consistency across the image. This param is only supported - for `dall-e-3`. + output_compression: The compression level (0-100%) for the generated images. This parameter is only + supported for `gpt-image-1` with the `webp` or `jpeg` output formats, and + defaults to 100. - response_format: The format in which the generated images are returned. Must be one of `url` or - `b64_json`. URLs are only valid for 60 minutes after the image has been - generated. + output_format: The format in which the generated images are returned. This parameter is only + supported for `gpt-image-1`. Must be one of `png`, `jpeg`, or `webp`. - size: The size of the generated images. Must be one of `256x256`, `512x512`, or - `1024x1024` for `dall-e-2`. Must be one of `1024x1024`, `1792x1024`, or - `1024x1792` for `dall-e-3` models. + quality: The quality of the image that will be generated. + + - `auto` (default value) will automatically select the best quality for the + given model. + - `high`, `medium` and `low` are supported for `gpt-image-1`. + - `hd` and `standard` are supported for `dall-e-3`. + - `standard` is the only option for `dall-e-2`. + + response_format: The format in which generated images with `dall-e-2` and `dall-e-3` are + returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes + after the image has been generated. This parameter isn't supported for + `gpt-image-1` which will always return base64-encoded images. + + size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` + (landscape), `1024x1536` (portrait), or `auto` (default value) for + `gpt-image-1`, one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`, and + one of `1024x1024`, `1792x1024`, or `1024x1792` for `dall-e-3`. - style: The style of the generated images. Must be one of `vivid` or `natural`. Vivid - causes the model to lean towards generating hyper-real and dramatic images. - Natural causes the model to produce more natural, less hyper-real looking - images. This param is only supported for `dall-e-3`. + style: The style of the generated images. This parameter is only supported for + `dall-e-3`. Must be one of `vivid` or `natural`. Vivid causes the model to lean + towards generating hyper-real and dramatic images. Natural causes the model to + produce more natural, less hyper-real looking images. user: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. @@ -261,8 +310,12 @@ def generate( body=maybe_transform( { "prompt": prompt, + "background": background, "model": model, + "moderation": moderation, "n": n, + "output_compression": output_compression, + "output_format": output_format, "quality": quality, "response_format": response_format, "size": size, @@ -314,8 +367,9 @@ async def create_variation( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> ImagesResponse: - """ - Creates a variation of a given image. + """Creates a variation of a given image. + + This endpoint only supports `dall-e-2`. Args: image: The image to use as the basis for the variation(s). Must be a valid PNG file, @@ -324,8 +378,7 @@ async def create_variation( model: The model to use for image generation. Only `dall-e-2` is supported at this time. - n: The number of images to generate. Must be between 1 and 10. For `dall-e-3`, only - `n=1` is supported. + n: The number of images to generate. Must be between 1 and 10. response_format: The format in which the generated images are returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes after the image has been @@ -374,11 +427,12 @@ async def create_variation( async def edit( self, *, - image: FileTypes, + image: Union[FileTypes, List[FileTypes]], prompt: str, mask: FileTypes | NotGiven = NOT_GIVEN, model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, + quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, size: Optional[Literal["256x256", "512x512", "1024x1024"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, @@ -389,31 +443,43 @@ async def edit( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> ImagesResponse: - """ - Creates an edited or extended image given an original image and a prompt. + """Creates an edited or extended image given one or more source images and a + prompt. + + This endpoint only supports `gpt-image-1` and `dall-e-2`. Args: - image: The image to edit. Must be a valid PNG file, less than 4MB, and square. If mask - is not provided, image must have transparency, which will be used as the mask. + image: The image(s) to edit. Must be a supported image file or an array of images. For + `gpt-image-1`, each image should be a `png`, `webp`, or `jpg` file less than + 25MB. For `dall-e-2`, you can only provide one image, and it should be a square + `png` file less than 4MB. prompt: A text description of the desired image(s). The maximum length is 1000 - characters. + characters for `dall-e-2`, and 32000 characters for `gpt-image-1`. mask: An additional image whose fully transparent areas (e.g. where alpha is zero) - indicate where `image` should be edited. Must be a valid PNG file, less than + indicate where `image` should be edited. If there are multiple images provided, + the mask will be applied on the first image. Must be a valid PNG file, less than 4MB, and have the same dimensions as `image`. - model: The model to use for image generation. Only `dall-e-2` is supported at this - time. + model: The model to use for image generation. Only `dall-e-2` and `gpt-image-1` are + supported. Defaults to `dall-e-2` unless a parameter specific to `gpt-image-1` + is used. n: The number of images to generate. Must be between 1 and 10. + quality: The quality of the image that will be generated. `high`, `medium` and `low` are + only supported for `gpt-image-1`. `dall-e-2` only supports `standard` quality. + Defaults to `auto`. + response_format: The format in which the generated images are returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes after the image has been - generated. + generated. This parameter is only supported for `dall-e-2`, as `gpt-image-1` + will always return base64-encoded images. - size: The size of the generated images. Must be one of `256x256`, `512x512`, or - `1024x1024`. + size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` + (landscape), `1024x1536` (portrait), or `auto` (default value) for + `gpt-image-1`, and one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`. user: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. @@ -434,12 +500,13 @@ async def edit( "mask": mask, "model": model, "n": n, + "quality": quality, "response_format": response_format, "size": size, "user": user, } ) - files = extract_files(cast(Mapping[str, object], body), paths=[["image"], ["mask"]]) + files = extract_files(cast(Mapping[str, object], body), paths=[["image"], ["image", ""], ["mask"]]) # It should be noted that the actual Content-Type header that will be # sent to the server will contain a `boundary` parameter, e.g. # multipart/form-data; boundary=---abc-- @@ -458,11 +525,18 @@ async def generate( self, *, prompt: str, + background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, + moderation: Optional[Literal["low", "auto"]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, - quality: Literal["standard", "hd"] | NotGiven = NOT_GIVEN, + output_compression: Optional[int] | NotGiven = NOT_GIVEN, + output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, + quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, - size: Optional[Literal["256x256", "512x512", "1024x1024", "1792x1024", "1024x1792"]] | NotGiven = NOT_GIVEN, + size: Optional[ + Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] + ] + | NotGiven = NOT_GIVEN, style: Optional[Literal["vivid", "natural"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -474,32 +548,60 @@ async def generate( ) -> ImagesResponse: """ Creates an image given a prompt. + [Learn more](https://platform.openai.com/docs/guides/images). Args: - prompt: A text description of the desired image(s). The maximum length is 1000 - characters for `dall-e-2` and 4000 characters for `dall-e-3`. + prompt: A text description of the desired image(s). The maximum length is 32000 + characters for `gpt-image-1`, 1000 characters for `dall-e-2` and 4000 characters + for `dall-e-3`. + + background: Allows to set transparency for the background of the generated image(s). This + parameter is only supported for `gpt-image-1`. Must be one of `transparent`, + `opaque` or `auto` (default value). When `auto` is used, the model will + automatically determine the best background for the image. + + If `transparent`, the output format needs to support transparency, so it should + be set to either `png` (default value) or `webp`. - model: The model to use for image generation. + model: The model to use for image generation. One of `dall-e-2`, `dall-e-3`, or + `gpt-image-1`. Defaults to `dall-e-2` unless a parameter specific to + `gpt-image-1` is used. + + moderation: Control the content-moderation level for images generated by `gpt-image-1`. Must + be either `low` for less restrictive filtering or `auto` (default value). n: The number of images to generate. Must be between 1 and 10. For `dall-e-3`, only `n=1` is supported. - quality: The quality of the image that will be generated. `hd` creates images with finer - details and greater consistency across the image. This param is only supported - for `dall-e-3`. + output_compression: The compression level (0-100%) for the generated images. This parameter is only + supported for `gpt-image-1` with the `webp` or `jpeg` output formats, and + defaults to 100. - response_format: The format in which the generated images are returned. Must be one of `url` or - `b64_json`. URLs are only valid for 60 minutes after the image has been - generated. + output_format: The format in which the generated images are returned. This parameter is only + supported for `gpt-image-1`. Must be one of `png`, `jpeg`, or `webp`. - size: The size of the generated images. Must be one of `256x256`, `512x512`, or - `1024x1024` for `dall-e-2`. Must be one of `1024x1024`, `1792x1024`, or - `1024x1792` for `dall-e-3` models. + quality: The quality of the image that will be generated. + + - `auto` (default value) will automatically select the best quality for the + given model. + - `high`, `medium` and `low` are supported for `gpt-image-1`. + - `hd` and `standard` are supported for `dall-e-3`. + - `standard` is the only option for `dall-e-2`. + + response_format: The format in which generated images with `dall-e-2` and `dall-e-3` are + returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes + after the image has been generated. This parameter isn't supported for + `gpt-image-1` which will always return base64-encoded images. + + size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` + (landscape), `1024x1536` (portrait), or `auto` (default value) for + `gpt-image-1`, one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`, and + one of `1024x1024`, `1792x1024`, or `1024x1792` for `dall-e-3`. - style: The style of the generated images. Must be one of `vivid` or `natural`. Vivid - causes the model to lean towards generating hyper-real and dramatic images. - Natural causes the model to produce more natural, less hyper-real looking - images. This param is only supported for `dall-e-3`. + style: The style of the generated images. This parameter is only supported for + `dall-e-3`. Must be one of `vivid` or `natural`. Vivid causes the model to lean + towards generating hyper-real and dramatic images. Natural causes the model to + produce more natural, less hyper-real looking images. user: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. @@ -518,8 +620,12 @@ async def generate( body=await async_maybe_transform( { "prompt": prompt, + "background": background, "model": model, + "moderation": moderation, "n": n, + "output_compression": output_compression, + "output_format": output_format, "quality": quality, "response_format": response_format, "size": size, diff --git a/src/openai/types/beta/realtime/realtime_client_event.py b/src/openai/types/beta/realtime/realtime_client_event.py index f962a505cd..5f4858d688 100644 --- a/src/openai/types/beta/realtime/realtime_client_event.py +++ b/src/openai/types/beta/realtime/realtime_client_event.py @@ -1,9 +1,10 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Union -from typing_extensions import Annotated, TypeAlias +from typing import Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias from ...._utils import PropertyInfo +from ...._models import BaseModel from .session_update_event import SessionUpdateEvent from .response_cancel_event import ResponseCancelEvent from .response_create_event import ResponseCreateEvent @@ -16,7 +17,16 @@ from .conversation_item_retrieve_event import ConversationItemRetrieveEvent from .conversation_item_truncate_event import ConversationItemTruncateEvent -__all__ = ["RealtimeClientEvent"] +__all__ = ["RealtimeClientEvent", "OutputAudioBufferClear"] + + +class OutputAudioBufferClear(BaseModel): + type: Literal["output_audio_buffer.clear"] + """The event type, must be `output_audio_buffer.clear`.""" + + event_id: Optional[str] = None + """The unique ID of the client event used for error handling.""" + RealtimeClientEvent: TypeAlias = Annotated[ Union[ @@ -26,6 +36,7 @@ ConversationItemTruncateEvent, InputAudioBufferAppendEvent, InputAudioBufferClearEvent, + OutputAudioBufferClear, InputAudioBufferCommitEvent, ResponseCancelEvent, ResponseCreateEvent, diff --git a/src/openai/types/beta/realtime/realtime_client_event_param.py b/src/openai/types/beta/realtime/realtime_client_event_param.py index 6fdba4b87c..e7dfba241e 100644 --- a/src/openai/types/beta/realtime/realtime_client_event_param.py +++ b/src/openai/types/beta/realtime/realtime_client_event_param.py @@ -3,7 +3,7 @@ from __future__ import annotations from typing import Union -from typing_extensions import TypeAlias +from typing_extensions import Literal, Required, TypeAlias, TypedDict from .session_update_event_param import SessionUpdateEventParam from .response_cancel_event_param import ResponseCancelEventParam @@ -17,7 +17,16 @@ from .conversation_item_retrieve_event_param import ConversationItemRetrieveEventParam from .conversation_item_truncate_event_param import ConversationItemTruncateEventParam -__all__ = ["RealtimeClientEventParam"] +__all__ = ["RealtimeClientEventParam", "OutputAudioBufferClear"] + + +class OutputAudioBufferClear(TypedDict, total=False): + type: Required[Literal["output_audio_buffer.clear"]] + """The event type, must be `output_audio_buffer.clear`.""" + + event_id: str + """The unique ID of the client event used for error handling.""" + RealtimeClientEventParam: TypeAlias = Union[ ConversationItemCreateEventParam, @@ -26,6 +35,7 @@ ConversationItemTruncateEventParam, InputAudioBufferAppendEventParam, InputAudioBufferClearEventParam, + OutputAudioBufferClear, InputAudioBufferCommitEventParam, ResponseCancelEventParam, ResponseCreateEventParam, diff --git a/src/openai/types/beta/realtime/realtime_server_event.py b/src/openai/types/beta/realtime/realtime_server_event.py index ba1d324445..c12f5df977 100644 --- a/src/openai/types/beta/realtime/realtime_server_event.py +++ b/src/openai/types/beta/realtime/realtime_server_event.py @@ -39,7 +39,13 @@ ConversationItemInputAudioTranscriptionCompletedEvent, ) -__all__ = ["RealtimeServerEvent", "ConversationItemRetrieved"] +__all__ = [ + "RealtimeServerEvent", + "ConversationItemRetrieved", + "OutputAudioBufferStarted", + "OutputAudioBufferStopped", + "OutputAudioBufferCleared", +] class ConversationItemRetrieved(BaseModel): @@ -53,6 +59,39 @@ class ConversationItemRetrieved(BaseModel): """The event type, must be `conversation.item.retrieved`.""" +class OutputAudioBufferStarted(BaseModel): + event_id: str + """The unique ID of the server event.""" + + response_id: str + """The unique ID of the response that produced the audio.""" + + type: Literal["output_audio_buffer.started"] + """The event type, must be `output_audio_buffer.started`.""" + + +class OutputAudioBufferStopped(BaseModel): + event_id: str + """The unique ID of the server event.""" + + response_id: str + """The unique ID of the response that produced the audio.""" + + type: Literal["output_audio_buffer.stopped"] + """The event type, must be `output_audio_buffer.stopped`.""" + + +class OutputAudioBufferCleared(BaseModel): + event_id: str + """The unique ID of the server event.""" + + response_id: str + """The unique ID of the response that produced the audio.""" + + type: Literal["output_audio_buffer.cleared"] + """The event type, must be `output_audio_buffer.cleared`.""" + + RealtimeServerEvent: TypeAlias = Annotated[ Union[ ConversationCreatedEvent, @@ -86,6 +125,9 @@ class ConversationItemRetrieved(BaseModel): SessionCreatedEvent, SessionUpdatedEvent, TranscriptionSessionUpdatedEvent, + OutputAudioBufferStarted, + OutputAudioBufferStopped, + OutputAudioBufferCleared, ], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/beta/thread_create_and_run_params.py b/src/openai/types/beta/thread_create_and_run_params.py index 065c390f4e..d813710579 100644 --- a/src/openai/types/beta/thread_create_and_run_params.py +++ b/src/openai/types/beta/thread_create_and_run_params.py @@ -6,8 +6,7 @@ from typing_extensions import Literal, Required, TypeAlias, TypedDict from ..shared.chat_model import ChatModel -from .function_tool_param import FunctionToolParam -from .file_search_tool_param import FileSearchToolParam +from .assistant_tool_param import AssistantToolParam from ..shared_params.metadata import Metadata from .code_interpreter_tool_param import CodeInterpreterToolParam from .assistant_tool_choice_option_param import AssistantToolChoiceOptionParam @@ -32,7 +31,6 @@ "ToolResources", "ToolResourcesCodeInterpreter", "ToolResourcesFileSearch", - "Tool", "TruncationStrategy", "ThreadCreateAndRunParamsNonStreaming", "ThreadCreateAndRunParamsStreaming", @@ -153,7 +151,7 @@ class ThreadCreateAndRunParamsBase(TypedDict, total=False): tool requires a list of vector store IDs. """ - tools: Optional[Iterable[Tool]] + tools: Optional[Iterable[AssistantToolParam]] """Override the tools the assistant can use for this run. This is useful for modifying the behavior on a per-run basis. @@ -360,9 +358,6 @@ class ToolResources(TypedDict, total=False): file_search: ToolResourcesFileSearch -Tool: TypeAlias = Union[CodeInterpreterToolParam, FileSearchToolParam, FunctionToolParam] - - class TruncationStrategy(TypedDict, total=False): type: Required[Literal["auto", "last_messages"]] """The truncation strategy to use for the thread. diff --git a/src/openai/types/eval_create_params.py b/src/openai/types/eval_create_params.py index 8b28e51a6b..03f44f2c8c 100644 --- a/src/openai/types/eval_create_params.py +++ b/src/openai/types/eval_create_params.py @@ -8,20 +8,25 @@ from .shared_params.metadata import Metadata from .eval_string_check_grader_param import EvalStringCheckGraderParam from .eval_text_similarity_grader_param import EvalTextSimilarityGraderParam +from .responses.response_input_text_param import ResponseInputTextParam __all__ = [ "EvalCreateParams", "DataSourceConfig", "DataSourceConfigCustom", - "DataSourceConfigStoredCompletions", + "DataSourceConfigLogs", "TestingCriterion", "TestingCriterionLabelModel", "TestingCriterionLabelModelInput", "TestingCriterionLabelModelInputSimpleInputMessage", - "TestingCriterionLabelModelInputInputMessage", - "TestingCriterionLabelModelInputInputMessageContent", - "TestingCriterionLabelModelInputOutputMessage", - "TestingCriterionLabelModelInputOutputMessageContent", + "TestingCriterionLabelModelInputEvalItem", + "TestingCriterionLabelModelInputEvalItemContent", + "TestingCriterionLabelModelInputEvalItemContentOutputText", + "TestingCriterionPython", + "TestingCriterionScoreModel", + "TestingCriterionScoreModelInput", + "TestingCriterionScoreModelInputContent", + "TestingCriterionScoreModelInputContentOutputText", ] @@ -45,37 +50,30 @@ class EvalCreateParams(TypedDict, total=False): name: str """The name of the evaluation.""" - share_with_openai: bool - """Indicates whether the evaluation is shared with OpenAI.""" - class DataSourceConfigCustom(TypedDict, total=False): item_schema: Required[Dict[str, object]] - """The json schema for the run data source items.""" + """The json schema for each row in the data source.""" type: Required[Literal["custom"]] """The type of data source. Always `custom`.""" include_sample_schema: bool - """Whether to include the sample schema in the data source.""" - - -class DataSourceConfigStoredCompletions(TypedDict, total=False): - type: Required[Literal["stored_completions"]] - """The type of data source. Always `stored_completions`.""" + """ + Whether the eval should expect you to populate the sample namespace (ie, by + generating responses off of your data source) + """ - metadata: Optional[Metadata] - """Set of 16 key-value pairs that can be attached to an object. - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. +class DataSourceConfigLogs(TypedDict, total=False): + type: Required[Literal["logs"]] + """The type of data source. Always `logs`.""" - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ + metadata: Dict[str, object] + """Metadata filters for the logs data source.""" -DataSourceConfig: TypeAlias = Union[DataSourceConfigCustom, DataSourceConfigStoredCompletions] +DataSourceConfig: TypeAlias = Union[DataSourceConfigCustom, DataSourceConfigLogs] class TestingCriterionLabelModelInputSimpleInputMessage(TypedDict, total=False): @@ -86,51 +84,44 @@ class TestingCriterionLabelModelInputSimpleInputMessage(TypedDict, total=False): """The role of the message (e.g. "system", "assistant", "user").""" -class TestingCriterionLabelModelInputInputMessageContent(TypedDict, total=False): +class TestingCriterionLabelModelInputEvalItemContentOutputText(TypedDict, total=False): text: Required[str] - """The text content.""" - - type: Required[Literal["input_text"]] - """The type of content, which is always `input_text`.""" - + """The text output from the model.""" -class TestingCriterionLabelModelInputInputMessage(TypedDict, total=False): - content: Required[TestingCriterionLabelModelInputInputMessageContent] - - role: Required[Literal["user", "system", "developer"]] - """The role of the message. One of `user`, `system`, or `developer`.""" - - type: Required[Literal["message"]] - """The type of item, which is always `message`.""" + type: Required[Literal["output_text"]] + """The type of the output text. Always `output_text`.""" -class TestingCriterionLabelModelInputOutputMessageContent(TypedDict, total=False): - text: Required[str] - """The text content.""" +TestingCriterionLabelModelInputEvalItemContent: TypeAlias = Union[ + str, ResponseInputTextParam, TestingCriterionLabelModelInputEvalItemContentOutputText +] - type: Required[Literal["output_text"]] - """The type of content, which is always `output_text`.""" +class TestingCriterionLabelModelInputEvalItem(TypedDict, total=False): + content: Required[TestingCriterionLabelModelInputEvalItemContent] + """Text inputs to the model - can contain template strings.""" -class TestingCriterionLabelModelInputOutputMessage(TypedDict, total=False): - content: Required[TestingCriterionLabelModelInputOutputMessageContent] + role: Required[Literal["user", "assistant", "system", "developer"]] + """The role of the message input. - role: Required[Literal["assistant"]] - """The role of the message. Must be `assistant` for output.""" + One of `user`, `assistant`, `system`, or `developer`. + """ - type: Required[Literal["message"]] - """The type of item, which is always `message`.""" + type: Literal["message"] + """The type of the message input. Always `message`.""" TestingCriterionLabelModelInput: TypeAlias = Union[ - TestingCriterionLabelModelInputSimpleInputMessage, - TestingCriterionLabelModelInputInputMessage, - TestingCriterionLabelModelInputOutputMessage, + TestingCriterionLabelModelInputSimpleInputMessage, TestingCriterionLabelModelInputEvalItem ] class TestingCriterionLabelModel(TypedDict, total=False): input: Required[Iterable[TestingCriterionLabelModelInput]] + """A list of chat messages forming the prompt or context. + + May include variable references to the "item" namespace, ie {{item.name}}. + """ labels: Required[List[str]] """The labels to classify to each item in the evaluation.""" @@ -148,6 +139,77 @@ class TestingCriterionLabelModel(TypedDict, total=False): """The object type, which is always `label_model`.""" +class TestingCriterionPython(TypedDict, total=False): + name: Required[str] + """The name of the grader.""" + + source: Required[str] + """The source code of the python script.""" + + type: Required[Literal["python"]] + """The object type, which is always `python`.""" + + image_tag: str + """The image tag to use for the python script.""" + + pass_threshold: float + """The threshold for the score.""" + + +class TestingCriterionScoreModelInputContentOutputText(TypedDict, total=False): + text: Required[str] + """The text output from the model.""" + + type: Required[Literal["output_text"]] + """The type of the output text. Always `output_text`.""" + + +TestingCriterionScoreModelInputContent: TypeAlias = Union[ + str, ResponseInputTextParam, TestingCriterionScoreModelInputContentOutputText +] + + +class TestingCriterionScoreModelInput(TypedDict, total=False): + content: Required[TestingCriterionScoreModelInputContent] + """Text inputs to the model - can contain template strings.""" + + role: Required[Literal["user", "assistant", "system", "developer"]] + """The role of the message input. + + One of `user`, `assistant`, `system`, or `developer`. + """ + + type: Literal["message"] + """The type of the message input. Always `message`.""" + + +class TestingCriterionScoreModel(TypedDict, total=False): + input: Required[Iterable[TestingCriterionScoreModelInput]] + """The input text. This may include template strings.""" + + model: Required[str] + """The model to use for the evaluation.""" + + name: Required[str] + """The name of the grader.""" + + type: Required[Literal["score_model"]] + """The object type, which is always `score_model`.""" + + pass_threshold: float + """The threshold for the score.""" + + range: Iterable[float] + """The range of the score. Defaults to `[0, 1]`.""" + + sampling_params: object + """The sampling parameters for the model.""" + + TestingCriterion: TypeAlias = Union[ - TestingCriterionLabelModel, EvalStringCheckGraderParam, EvalTextSimilarityGraderParam + TestingCriterionLabelModel, + EvalStringCheckGraderParam, + EvalTextSimilarityGraderParam, + TestingCriterionPython, + TestingCriterionScoreModel, ] diff --git a/src/openai/types/eval_create_response.py b/src/openai/types/eval_create_response.py index a1c2853a2a..6d77a81870 100644 --- a/src/openai/types/eval_create_response.py +++ b/src/openai/types/eval_create_response.py @@ -9,17 +9,106 @@ from .eval_label_model_grader import EvalLabelModelGrader from .eval_string_check_grader import EvalStringCheckGrader from .eval_text_similarity_grader import EvalTextSimilarityGrader +from .responses.response_input_text import ResponseInputText from .eval_custom_data_source_config import EvalCustomDataSourceConfig from .eval_stored_completions_data_source_config import EvalStoredCompletionsDataSourceConfig -__all__ = ["EvalCreateResponse", "DataSourceConfig", "TestingCriterion"] +__all__ = [ + "EvalCreateResponse", + "DataSourceConfig", + "TestingCriterion", + "TestingCriterionPython", + "TestingCriterionScoreModel", + "TestingCriterionScoreModelInput", + "TestingCriterionScoreModelInputContent", + "TestingCriterionScoreModelInputContentOutputText", +] DataSourceConfig: TypeAlias = Annotated[ Union[EvalCustomDataSourceConfig, EvalStoredCompletionsDataSourceConfig], PropertyInfo(discriminator="type") ] + +class TestingCriterionPython(BaseModel): + __test__ = False + name: str + """The name of the grader.""" + + source: str + """The source code of the python script.""" + + type: Literal["python"] + """The object type, which is always `python`.""" + + image_tag: Optional[str] = None + """The image tag to use for the python script.""" + + pass_threshold: Optional[float] = None + """The threshold for the score.""" + + +class TestingCriterionScoreModelInputContentOutputText(BaseModel): + __test__ = False + text: str + """The text output from the model.""" + + type: Literal["output_text"] + """The type of the output text. Always `output_text`.""" + + +TestingCriterionScoreModelInputContent: TypeAlias = Union[ + str, ResponseInputText, TestingCriterionScoreModelInputContentOutputText +] + + +class TestingCriterionScoreModelInput(BaseModel): + __test__ = False + content: TestingCriterionScoreModelInputContent + """Text inputs to the model - can contain template strings.""" + + role: Literal["user", "assistant", "system", "developer"] + """The role of the message input. + + One of `user`, `assistant`, `system`, or `developer`. + """ + + type: Optional[Literal["message"]] = None + """The type of the message input. Always `message`.""" + + +class TestingCriterionScoreModel(BaseModel): + __test__ = False + input: List[TestingCriterionScoreModelInput] + """The input text. This may include template strings.""" + + model: str + """The model to use for the evaluation.""" + + name: str + """The name of the grader.""" + + type: Literal["score_model"] + """The object type, which is always `score_model`.""" + + pass_threshold: Optional[float] = None + """The threshold for the score.""" + + range: Optional[List[float]] = None + """The range of the score. Defaults to `[0, 1]`.""" + + sampling_params: Optional[object] = None + """The sampling parameters for the model.""" + + TestingCriterion: TypeAlias = Annotated[ - Union[EvalLabelModelGrader, EvalStringCheckGrader, EvalTextSimilarityGrader], PropertyInfo(discriminator="type") + Union[ + EvalLabelModelGrader, + EvalStringCheckGrader, + EvalTextSimilarityGrader, + TestingCriterionPython, + TestingCriterionScoreModel, + ], + PropertyInfo(discriminator="type"), ] @@ -49,8 +138,5 @@ class EvalCreateResponse(BaseModel): object: Literal["eval"] """The object type.""" - share_with_openai: bool - """Indicates whether the evaluation is shared with OpenAI.""" - testing_criteria: List[TestingCriterion] """A list of testing criteria.""" diff --git a/src/openai/types/eval_label_model_grader.py b/src/openai/types/eval_label_model_grader.py index 826b116287..40e6bda140 100644 --- a/src/openai/types/eval_label_model_grader.py +++ b/src/openai/types/eval_label_model_grader.py @@ -1,58 +1,37 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union -from typing_extensions import Literal, Annotated, TypeAlias +from typing import List, Union, Optional +from typing_extensions import Literal, TypeAlias -from .._utils import PropertyInfo from .._models import BaseModel +from .responses.response_input_text import ResponseInputText -__all__ = [ - "EvalLabelModelGrader", - "Input", - "InputInputMessage", - "InputInputMessageContent", - "InputAssistant", - "InputAssistantContent", -] +__all__ = ["EvalLabelModelGrader", "Input", "InputContent", "InputContentOutputText"] -class InputInputMessageContent(BaseModel): +class InputContentOutputText(BaseModel): text: str - """The text content.""" - - type: Literal["input_text"] - """The type of content, which is always `input_text`.""" - - -class InputInputMessage(BaseModel): - content: InputInputMessageContent - - role: Literal["user", "system", "developer"] - """The role of the message. One of `user`, `system`, or `developer`.""" - - type: Literal["message"] - """The type of item, which is always `message`.""" - - -class InputAssistantContent(BaseModel): - text: str - """The text content.""" + """The text output from the model.""" type: Literal["output_text"] - """The type of content, which is always `output_text`.""" + """The type of the output text. Always `output_text`.""" + +InputContent: TypeAlias = Union[str, ResponseInputText, InputContentOutputText] -class InputAssistant(BaseModel): - content: InputAssistantContent - role: Literal["assistant"] - """The role of the message. Must be `assistant` for output.""" +class Input(BaseModel): + content: InputContent + """Text inputs to the model - can contain template strings.""" - type: Literal["message"] - """The type of item, which is always `message`.""" + role: Literal["user", "assistant", "system", "developer"] + """The role of the message input. + One of `user`, `assistant`, `system`, or `developer`. + """ -Input: TypeAlias = Annotated[Union[InputInputMessage, InputAssistant], PropertyInfo(discriminator="role")] + type: Optional[Literal["message"]] = None + """The type of the message input. Always `message`.""" class EvalLabelModelGrader(BaseModel): diff --git a/src/openai/types/eval_list_response.py b/src/openai/types/eval_list_response.py index eb54569011..8c7e9c5588 100644 --- a/src/openai/types/eval_list_response.py +++ b/src/openai/types/eval_list_response.py @@ -9,17 +9,106 @@ from .eval_label_model_grader import EvalLabelModelGrader from .eval_string_check_grader import EvalStringCheckGrader from .eval_text_similarity_grader import EvalTextSimilarityGrader +from .responses.response_input_text import ResponseInputText from .eval_custom_data_source_config import EvalCustomDataSourceConfig from .eval_stored_completions_data_source_config import EvalStoredCompletionsDataSourceConfig -__all__ = ["EvalListResponse", "DataSourceConfig", "TestingCriterion"] +__all__ = [ + "EvalListResponse", + "DataSourceConfig", + "TestingCriterion", + "TestingCriterionPython", + "TestingCriterionScoreModel", + "TestingCriterionScoreModelInput", + "TestingCriterionScoreModelInputContent", + "TestingCriterionScoreModelInputContentOutputText", +] DataSourceConfig: TypeAlias = Annotated[ Union[EvalCustomDataSourceConfig, EvalStoredCompletionsDataSourceConfig], PropertyInfo(discriminator="type") ] + +class TestingCriterionPython(BaseModel): + __test__ = False + name: str + """The name of the grader.""" + + source: str + """The source code of the python script.""" + + type: Literal["python"] + """The object type, which is always `python`.""" + + image_tag: Optional[str] = None + """The image tag to use for the python script.""" + + pass_threshold: Optional[float] = None + """The threshold for the score.""" + + +class TestingCriterionScoreModelInputContentOutputText(BaseModel): + __test__ = False + text: str + """The text output from the model.""" + + type: Literal["output_text"] + """The type of the output text. Always `output_text`.""" + + +TestingCriterionScoreModelInputContent: TypeAlias = Union[ + str, ResponseInputText, TestingCriterionScoreModelInputContentOutputText +] + + +class TestingCriterionScoreModelInput(BaseModel): + __test__ = False + content: TestingCriterionScoreModelInputContent + """Text inputs to the model - can contain template strings.""" + + role: Literal["user", "assistant", "system", "developer"] + """The role of the message input. + + One of `user`, `assistant`, `system`, or `developer`. + """ + + type: Optional[Literal["message"]] = None + """The type of the message input. Always `message`.""" + + +class TestingCriterionScoreModel(BaseModel): + __test__ = False + input: List[TestingCriterionScoreModelInput] + """The input text. This may include template strings.""" + + model: str + """The model to use for the evaluation.""" + + name: str + """The name of the grader.""" + + type: Literal["score_model"] + """The object type, which is always `score_model`.""" + + pass_threshold: Optional[float] = None + """The threshold for the score.""" + + range: Optional[List[float]] = None + """The range of the score. Defaults to `[0, 1]`.""" + + sampling_params: Optional[object] = None + """The sampling parameters for the model.""" + + TestingCriterion: TypeAlias = Annotated[ - Union[EvalLabelModelGrader, EvalStringCheckGrader, EvalTextSimilarityGrader], PropertyInfo(discriminator="type") + Union[ + EvalLabelModelGrader, + EvalStringCheckGrader, + EvalTextSimilarityGrader, + TestingCriterionPython, + TestingCriterionScoreModel, + ], + PropertyInfo(discriminator="type"), ] @@ -49,8 +138,5 @@ class EvalListResponse(BaseModel): object: Literal["eval"] """The object type.""" - share_with_openai: bool - """Indicates whether the evaluation is shared with OpenAI.""" - testing_criteria: List[TestingCriterion] """A list of testing criteria.""" diff --git a/src/openai/types/eval_retrieve_response.py b/src/openai/types/eval_retrieve_response.py index 8f3bfdf902..625bae80f4 100644 --- a/src/openai/types/eval_retrieve_response.py +++ b/src/openai/types/eval_retrieve_response.py @@ -9,17 +9,106 @@ from .eval_label_model_grader import EvalLabelModelGrader from .eval_string_check_grader import EvalStringCheckGrader from .eval_text_similarity_grader import EvalTextSimilarityGrader +from .responses.response_input_text import ResponseInputText from .eval_custom_data_source_config import EvalCustomDataSourceConfig from .eval_stored_completions_data_source_config import EvalStoredCompletionsDataSourceConfig -__all__ = ["EvalRetrieveResponse", "DataSourceConfig", "TestingCriterion"] +__all__ = [ + "EvalRetrieveResponse", + "DataSourceConfig", + "TestingCriterion", + "TestingCriterionPython", + "TestingCriterionScoreModel", + "TestingCriterionScoreModelInput", + "TestingCriterionScoreModelInputContent", + "TestingCriterionScoreModelInputContentOutputText", +] DataSourceConfig: TypeAlias = Annotated[ Union[EvalCustomDataSourceConfig, EvalStoredCompletionsDataSourceConfig], PropertyInfo(discriminator="type") ] + +class TestingCriterionPython(BaseModel): + __test__ = False + name: str + """The name of the grader.""" + + source: str + """The source code of the python script.""" + + type: Literal["python"] + """The object type, which is always `python`.""" + + image_tag: Optional[str] = None + """The image tag to use for the python script.""" + + pass_threshold: Optional[float] = None + """The threshold for the score.""" + + +class TestingCriterionScoreModelInputContentOutputText(BaseModel): + __test__ = False + text: str + """The text output from the model.""" + + type: Literal["output_text"] + """The type of the output text. Always `output_text`.""" + + +TestingCriterionScoreModelInputContent: TypeAlias = Union[ + str, ResponseInputText, TestingCriterionScoreModelInputContentOutputText +] + + +class TestingCriterionScoreModelInput(BaseModel): + __test__ = False + content: TestingCriterionScoreModelInputContent + """Text inputs to the model - can contain template strings.""" + + role: Literal["user", "assistant", "system", "developer"] + """The role of the message input. + + One of `user`, `assistant`, `system`, or `developer`. + """ + + type: Optional[Literal["message"]] = None + """The type of the message input. Always `message`.""" + + +class TestingCriterionScoreModel(BaseModel): + __test__ = False + input: List[TestingCriterionScoreModelInput] + """The input text. This may include template strings.""" + + model: str + """The model to use for the evaluation.""" + + name: str + """The name of the grader.""" + + type: Literal["score_model"] + """The object type, which is always `score_model`.""" + + pass_threshold: Optional[float] = None + """The threshold for the score.""" + + range: Optional[List[float]] = None + """The range of the score. Defaults to `[0, 1]`.""" + + sampling_params: Optional[object] = None + """The sampling parameters for the model.""" + + TestingCriterion: TypeAlias = Annotated[ - Union[EvalLabelModelGrader, EvalStringCheckGrader, EvalTextSimilarityGrader], PropertyInfo(discriminator="type") + Union[ + EvalLabelModelGrader, + EvalStringCheckGrader, + EvalTextSimilarityGrader, + TestingCriterionPython, + TestingCriterionScoreModel, + ], + PropertyInfo(discriminator="type"), ] @@ -49,8 +138,5 @@ class EvalRetrieveResponse(BaseModel): object: Literal["eval"] """The object type.""" - share_with_openai: bool - """Indicates whether the evaluation is shared with OpenAI.""" - testing_criteria: List[TestingCriterion] """A list of testing criteria.""" diff --git a/src/openai/types/eval_text_similarity_grader.py b/src/openai/types/eval_text_similarity_grader.py index 7c6897a4a7..853c6d4fbf 100644 --- a/src/openai/types/eval_text_similarity_grader.py +++ b/src/openai/types/eval_text_similarity_grader.py @@ -10,22 +10,12 @@ class EvalTextSimilarityGrader(BaseModel): evaluation_metric: Literal[ - "fuzzy_match", - "bleu", - "gleu", - "meteor", - "rouge_1", - "rouge_2", - "rouge_3", - "rouge_4", - "rouge_5", - "rouge_l", - "cosine", + "fuzzy_match", "bleu", "gleu", "meteor", "rouge_1", "rouge_2", "rouge_3", "rouge_4", "rouge_5", "rouge_l" ] """The evaluation metric to use. - One of `cosine`, `fuzzy_match`, `bleu`, `gleu`, `meteor`, `rouge_1`, `rouge_2`, - `rouge_3`, `rouge_4`, `rouge_5`, or `rouge_l`. + One of `fuzzy_match`, `bleu`, `gleu`, `meteor`, `rouge_1`, `rouge_2`, `rouge_3`, + `rouge_4`, `rouge_5`, or `rouge_l`. """ input: str diff --git a/src/openai/types/eval_text_similarity_grader_param.py b/src/openai/types/eval_text_similarity_grader_param.py index 4bf5d586f3..f07cc29178 100644 --- a/src/openai/types/eval_text_similarity_grader_param.py +++ b/src/openai/types/eval_text_similarity_grader_param.py @@ -10,23 +10,13 @@ class EvalTextSimilarityGraderParam(TypedDict, total=False): evaluation_metric: Required[ Literal[ - "fuzzy_match", - "bleu", - "gleu", - "meteor", - "rouge_1", - "rouge_2", - "rouge_3", - "rouge_4", - "rouge_5", - "rouge_l", - "cosine", + "fuzzy_match", "bleu", "gleu", "meteor", "rouge_1", "rouge_2", "rouge_3", "rouge_4", "rouge_5", "rouge_l" ] ] """The evaluation metric to use. - One of `cosine`, `fuzzy_match`, `bleu`, `gleu`, `meteor`, `rouge_1`, `rouge_2`, - `rouge_3`, `rouge_4`, `rouge_5`, or `rouge_l`. + One of `fuzzy_match`, `bleu`, `gleu`, `meteor`, `rouge_1`, `rouge_2`, `rouge_3`, + `rouge_4`, `rouge_5`, or `rouge_l`. """ input: Required[str] diff --git a/src/openai/types/eval_update_response.py b/src/openai/types/eval_update_response.py index 728a291736..2c280977a1 100644 --- a/src/openai/types/eval_update_response.py +++ b/src/openai/types/eval_update_response.py @@ -9,17 +9,106 @@ from .eval_label_model_grader import EvalLabelModelGrader from .eval_string_check_grader import EvalStringCheckGrader from .eval_text_similarity_grader import EvalTextSimilarityGrader +from .responses.response_input_text import ResponseInputText from .eval_custom_data_source_config import EvalCustomDataSourceConfig from .eval_stored_completions_data_source_config import EvalStoredCompletionsDataSourceConfig -__all__ = ["EvalUpdateResponse", "DataSourceConfig", "TestingCriterion"] +__all__ = [ + "EvalUpdateResponse", + "DataSourceConfig", + "TestingCriterion", + "TestingCriterionPython", + "TestingCriterionScoreModel", + "TestingCriterionScoreModelInput", + "TestingCriterionScoreModelInputContent", + "TestingCriterionScoreModelInputContentOutputText", +] DataSourceConfig: TypeAlias = Annotated[ Union[EvalCustomDataSourceConfig, EvalStoredCompletionsDataSourceConfig], PropertyInfo(discriminator="type") ] + +class TestingCriterionPython(BaseModel): + __test__ = False + name: str + """The name of the grader.""" + + source: str + """The source code of the python script.""" + + type: Literal["python"] + """The object type, which is always `python`.""" + + image_tag: Optional[str] = None + """The image tag to use for the python script.""" + + pass_threshold: Optional[float] = None + """The threshold for the score.""" + + +class TestingCriterionScoreModelInputContentOutputText(BaseModel): + __test__ = False + text: str + """The text output from the model.""" + + type: Literal["output_text"] + """The type of the output text. Always `output_text`.""" + + +TestingCriterionScoreModelInputContent: TypeAlias = Union[ + str, ResponseInputText, TestingCriterionScoreModelInputContentOutputText +] + + +class TestingCriterionScoreModelInput(BaseModel): + __test__ = False + content: TestingCriterionScoreModelInputContent + """Text inputs to the model - can contain template strings.""" + + role: Literal["user", "assistant", "system", "developer"] + """The role of the message input. + + One of `user`, `assistant`, `system`, or `developer`. + """ + + type: Optional[Literal["message"]] = None + """The type of the message input. Always `message`.""" + + +class TestingCriterionScoreModel(BaseModel): + __test__ = False + input: List[TestingCriterionScoreModelInput] + """The input text. This may include template strings.""" + + model: str + """The model to use for the evaluation.""" + + name: str + """The name of the grader.""" + + type: Literal["score_model"] + """The object type, which is always `score_model`.""" + + pass_threshold: Optional[float] = None + """The threshold for the score.""" + + range: Optional[List[float]] = None + """The range of the score. Defaults to `[0, 1]`.""" + + sampling_params: Optional[object] = None + """The sampling parameters for the model.""" + + TestingCriterion: TypeAlias = Annotated[ - Union[EvalLabelModelGrader, EvalStringCheckGrader, EvalTextSimilarityGrader], PropertyInfo(discriminator="type") + Union[ + EvalLabelModelGrader, + EvalStringCheckGrader, + EvalTextSimilarityGrader, + TestingCriterionPython, + TestingCriterionScoreModel, + ], + PropertyInfo(discriminator="type"), ] @@ -49,8 +138,5 @@ class EvalUpdateResponse(BaseModel): object: Literal["eval"] """The object type.""" - share_with_openai: bool - """Indicates whether the evaluation is shared with OpenAI.""" - testing_criteria: List[TestingCriterion] """A list of testing criteria.""" diff --git a/src/openai/types/evals/create_eval_completions_run_data_source.py b/src/openai/types/evals/create_eval_completions_run_data_source.py index 07b88129e2..29c687b542 100644 --- a/src/openai/types/evals/create_eval_completions_run_data_source.py +++ b/src/openai/types/evals/create_eval_completions_run_data_source.py @@ -6,102 +6,27 @@ from ..._utils import PropertyInfo from ..._models import BaseModel from ..shared.metadata import Metadata +from ..responses.easy_input_message import EasyInputMessage +from ..responses.response_input_text import ResponseInputText __all__ = [ "CreateEvalCompletionsRunDataSource", - "InputMessages", - "InputMessagesTemplate", - "InputMessagesTemplateTemplate", - "InputMessagesTemplateTemplateChatMessage", - "InputMessagesTemplateTemplateInputMessage", - "InputMessagesTemplateTemplateInputMessageContent", - "InputMessagesTemplateTemplateOutputMessage", - "InputMessagesTemplateTemplateOutputMessageContent", - "InputMessagesItemReference", "Source", "SourceFileContent", "SourceFileContentContent", "SourceFileID", "SourceStoredCompletions", + "InputMessages", + "InputMessagesTemplate", + "InputMessagesTemplateTemplate", + "InputMessagesTemplateTemplateMessage", + "InputMessagesTemplateTemplateMessageContent", + "InputMessagesTemplateTemplateMessageContentOutputText", + "InputMessagesItemReference", "SamplingParams", ] -class InputMessagesTemplateTemplateChatMessage(BaseModel): - content: str - """The content of the message.""" - - role: str - """The role of the message (e.g. "system", "assistant", "user").""" - - -class InputMessagesTemplateTemplateInputMessageContent(BaseModel): - text: str - """The text content.""" - - type: Literal["input_text"] - """The type of content, which is always `input_text`.""" - - -class InputMessagesTemplateTemplateInputMessage(BaseModel): - content: InputMessagesTemplateTemplateInputMessageContent - - role: Literal["user", "system", "developer"] - """The role of the message. One of `user`, `system`, or `developer`.""" - - type: Literal["message"] - """The type of item, which is always `message`.""" - - -class InputMessagesTemplateTemplateOutputMessageContent(BaseModel): - text: str - """The text content.""" - - type: Literal["output_text"] - """The type of content, which is always `output_text`.""" - - -class InputMessagesTemplateTemplateOutputMessage(BaseModel): - content: InputMessagesTemplateTemplateOutputMessageContent - - role: Literal["assistant"] - """The role of the message. Must be `assistant` for output.""" - - type: Literal["message"] - """The type of item, which is always `message`.""" - - -InputMessagesTemplateTemplate: TypeAlias = Union[ - InputMessagesTemplateTemplateChatMessage, - InputMessagesTemplateTemplateInputMessage, - InputMessagesTemplateTemplateOutputMessage, -] - - -class InputMessagesTemplate(BaseModel): - template: List[InputMessagesTemplateTemplate] - """A list of chat messages forming the prompt or context. - - May include variable references to the "item" namespace, ie {{item.name}}. - """ - - type: Literal["template"] - """The type of input messages. Always `template`.""" - - -class InputMessagesItemReference(BaseModel): - item_reference: str - """A reference to a variable in the "item" namespace. Ie, "item.name" """ - - type: Literal["item_reference"] - """The type of input messages. Always `item_reference`.""" - - -InputMessages: TypeAlias = Annotated[ - Union[InputMessagesTemplate, InputMessagesItemReference], PropertyInfo(discriminator="type") -] - - class SourceFileContentContent(BaseModel): item: Dict[str, object] @@ -125,6 +50,9 @@ class SourceFileID(BaseModel): class SourceStoredCompletions(BaseModel): + type: Literal["stored_completions"] + """The type of source. Always `stored_completions`.""" + created_after: Optional[int] = None """An optional Unix timestamp to filter items created after this time.""" @@ -147,15 +75,68 @@ class SourceStoredCompletions(BaseModel): model: Optional[str] = None """An optional model to filter by (e.g., 'gpt-4o').""" - type: Literal["stored_completions"] - """The type of source. Always `stored_completions`.""" - Source: TypeAlias = Annotated[ Union[SourceFileContent, SourceFileID, SourceStoredCompletions], PropertyInfo(discriminator="type") ] +class InputMessagesTemplateTemplateMessageContentOutputText(BaseModel): + text: str + """The text output from the model.""" + + type: Literal["output_text"] + """The type of the output text. Always `output_text`.""" + + +InputMessagesTemplateTemplateMessageContent: TypeAlias = Union[ + str, ResponseInputText, InputMessagesTemplateTemplateMessageContentOutputText +] + + +class InputMessagesTemplateTemplateMessage(BaseModel): + content: InputMessagesTemplateTemplateMessageContent + """Text inputs to the model - can contain template strings.""" + + role: Literal["user", "assistant", "system", "developer"] + """The role of the message input. + + One of `user`, `assistant`, `system`, or `developer`. + """ + + type: Optional[Literal["message"]] = None + """The type of the message input. Always `message`.""" + + +InputMessagesTemplateTemplate: TypeAlias = Annotated[ + Union[EasyInputMessage, InputMessagesTemplateTemplateMessage], PropertyInfo(discriminator="type") +] + + +class InputMessagesTemplate(BaseModel): + template: List[InputMessagesTemplateTemplate] + """A list of chat messages forming the prompt or context. + + May include variable references to the "item" namespace, ie {{item.name}}. + """ + + type: Literal["template"] + """The type of input messages. Always `template`.""" + + +class InputMessagesItemReference(BaseModel): + item_reference: str + """A reference to a variable in the "item" namespace. Ie, "item.name" """ + + type: Literal["item_reference"] + """The type of input messages. Always `item_reference`.""" + + +InputMessages: TypeAlias = Annotated[ + Union[InputMessagesTemplate, InputMessagesItemReference], PropertyInfo(discriminator="type") +] + + class SamplingParams(BaseModel): max_completion_tokens: Optional[int] = None """The maximum number of tokens in the generated output.""" @@ -171,15 +152,15 @@ class SamplingParams(BaseModel): class CreateEvalCompletionsRunDataSource(BaseModel): - input_messages: InputMessages - - model: str - """The name of the model to use for generating completions (e.g. "o3-mini").""" - source: Source """A StoredCompletionsRunDataSource configuration describing a set of filters""" type: Literal["completions"] """The type of run data source. Always `completions`.""" + input_messages: Optional[InputMessages] = None + + model: Optional[str] = None + """The name of the model to use for generating completions (e.g. "o3-mini").""" + sampling_params: Optional[SamplingParams] = None diff --git a/src/openai/types/evals/create_eval_completions_run_data_source_param.py b/src/openai/types/evals/create_eval_completions_run_data_source_param.py index be4a6f1ec6..c53064ee27 100644 --- a/src/openai/types/evals/create_eval_completions_run_data_source_param.py +++ b/src/openai/types/evals/create_eval_completions_run_data_source_param.py @@ -6,100 +6,27 @@ from typing_extensions import Literal, Required, TypeAlias, TypedDict from ..shared_params.metadata import Metadata +from ..responses.easy_input_message_param import EasyInputMessageParam +from ..responses.response_input_text_param import ResponseInputTextParam __all__ = [ "CreateEvalCompletionsRunDataSourceParam", - "InputMessages", - "InputMessagesTemplate", - "InputMessagesTemplateTemplate", - "InputMessagesTemplateTemplateChatMessage", - "InputMessagesTemplateTemplateInputMessage", - "InputMessagesTemplateTemplateInputMessageContent", - "InputMessagesTemplateTemplateOutputMessage", - "InputMessagesTemplateTemplateOutputMessageContent", - "InputMessagesItemReference", "Source", "SourceFileContent", "SourceFileContentContent", "SourceFileID", "SourceStoredCompletions", + "InputMessages", + "InputMessagesTemplate", + "InputMessagesTemplateTemplate", + "InputMessagesTemplateTemplateMessage", + "InputMessagesTemplateTemplateMessageContent", + "InputMessagesTemplateTemplateMessageContentOutputText", + "InputMessagesItemReference", "SamplingParams", ] -class InputMessagesTemplateTemplateChatMessage(TypedDict, total=False): - content: Required[str] - """The content of the message.""" - - role: Required[str] - """The role of the message (e.g. "system", "assistant", "user").""" - - -class InputMessagesTemplateTemplateInputMessageContent(TypedDict, total=False): - text: Required[str] - """The text content.""" - - type: Required[Literal["input_text"]] - """The type of content, which is always `input_text`.""" - - -class InputMessagesTemplateTemplateInputMessage(TypedDict, total=False): - content: Required[InputMessagesTemplateTemplateInputMessageContent] - - role: Required[Literal["user", "system", "developer"]] - """The role of the message. One of `user`, `system`, or `developer`.""" - - type: Required[Literal["message"]] - """The type of item, which is always `message`.""" - - -class InputMessagesTemplateTemplateOutputMessageContent(TypedDict, total=False): - text: Required[str] - """The text content.""" - - type: Required[Literal["output_text"]] - """The type of content, which is always `output_text`.""" - - -class InputMessagesTemplateTemplateOutputMessage(TypedDict, total=False): - content: Required[InputMessagesTemplateTemplateOutputMessageContent] - - role: Required[Literal["assistant"]] - """The role of the message. Must be `assistant` for output.""" - - type: Required[Literal["message"]] - """The type of item, which is always `message`.""" - - -InputMessagesTemplateTemplate: TypeAlias = Union[ - InputMessagesTemplateTemplateChatMessage, - InputMessagesTemplateTemplateInputMessage, - InputMessagesTemplateTemplateOutputMessage, -] - - -class InputMessagesTemplate(TypedDict, total=False): - template: Required[Iterable[InputMessagesTemplateTemplate]] - """A list of chat messages forming the prompt or context. - - May include variable references to the "item" namespace, ie {{item.name}}. - """ - - type: Required[Literal["template"]] - """The type of input messages. Always `template`.""" - - -class InputMessagesItemReference(TypedDict, total=False): - item_reference: Required[str] - """A reference to a variable in the "item" namespace. Ie, "item.name" """ - - type: Required[Literal["item_reference"]] - """The type of input messages. Always `item_reference`.""" - - -InputMessages: TypeAlias = Union[InputMessagesTemplate, InputMessagesItemReference] - - class SourceFileContentContent(TypedDict, total=False): item: Required[Dict[str, object]] @@ -123,16 +50,19 @@ class SourceFileID(TypedDict, total=False): class SourceStoredCompletions(TypedDict, total=False): - created_after: Required[Optional[int]] + type: Required[Literal["stored_completions"]] + """The type of source. Always `stored_completions`.""" + + created_after: Optional[int] """An optional Unix timestamp to filter items created after this time.""" - created_before: Required[Optional[int]] + created_before: Optional[int] """An optional Unix timestamp to filter items created before this time.""" - limit: Required[Optional[int]] + limit: Optional[int] """An optional maximum number of items to return.""" - metadata: Required[Optional[Metadata]] + metadata: Optional[Metadata] """Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a @@ -142,16 +72,65 @@ class SourceStoredCompletions(TypedDict, total=False): a maximum length of 512 characters. """ - model: Required[Optional[str]] + model: Optional[str] """An optional model to filter by (e.g., 'gpt-4o').""" - type: Required[Literal["stored_completions"]] - """The type of source. Always `stored_completions`.""" - Source: TypeAlias = Union[SourceFileContent, SourceFileID, SourceStoredCompletions] +class InputMessagesTemplateTemplateMessageContentOutputText(TypedDict, total=False): + text: Required[str] + """The text output from the model.""" + + type: Required[Literal["output_text"]] + """The type of the output text. Always `output_text`.""" + + +InputMessagesTemplateTemplateMessageContent: TypeAlias = Union[ + str, ResponseInputTextParam, InputMessagesTemplateTemplateMessageContentOutputText +] + + +class InputMessagesTemplateTemplateMessage(TypedDict, total=False): + content: Required[InputMessagesTemplateTemplateMessageContent] + """Text inputs to the model - can contain template strings.""" + + role: Required[Literal["user", "assistant", "system", "developer"]] + """The role of the message input. + + One of `user`, `assistant`, `system`, or `developer`. + """ + + type: Literal["message"] + """The type of the message input. Always `message`.""" + + +InputMessagesTemplateTemplate: TypeAlias = Union[EasyInputMessageParam, InputMessagesTemplateTemplateMessage] + + +class InputMessagesTemplate(TypedDict, total=False): + template: Required[Iterable[InputMessagesTemplateTemplate]] + """A list of chat messages forming the prompt or context. + + May include variable references to the "item" namespace, ie {{item.name}}. + """ + + type: Required[Literal["template"]] + """The type of input messages. Always `template`.""" + + +class InputMessagesItemReference(TypedDict, total=False): + item_reference: Required[str] + """A reference to a variable in the "item" namespace. Ie, "item.name" """ + + type: Required[Literal["item_reference"]] + """The type of input messages. Always `item_reference`.""" + + +InputMessages: TypeAlias = Union[InputMessagesTemplate, InputMessagesItemReference] + + class SamplingParams(TypedDict, total=False): max_completion_tokens: int """The maximum number of tokens in the generated output.""" @@ -167,15 +146,15 @@ class SamplingParams(TypedDict, total=False): class CreateEvalCompletionsRunDataSourceParam(TypedDict, total=False): - input_messages: Required[InputMessages] - - model: Required[str] - """The name of the model to use for generating completions (e.g. "o3-mini").""" - source: Required[Source] """A StoredCompletionsRunDataSource configuration describing a set of filters""" type: Required[Literal["completions"]] """The type of run data source. Always `completions`.""" + input_messages: InputMessages + + model: str + """The name of the model to use for generating completions (e.g. "o3-mini").""" + sampling_params: SamplingParams diff --git a/src/openai/types/evals/run_cancel_response.py b/src/openai/types/evals/run_cancel_response.py index 90e52241a6..eb6d689fc3 100644 --- a/src/openai/types/evals/run_cancel_response.py +++ b/src/openai/types/evals/run_cancel_response.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union, Optional +from typing import Dict, List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias from pydantic import Field as FieldInfo @@ -9,13 +9,225 @@ from ..._models import BaseModel from .eval_api_error import EvalAPIError from ..shared.metadata import Metadata +from ..shared.reasoning_effort import ReasoningEffort +from ..responses.response_input_text import ResponseInputText from .create_eval_jsonl_run_data_source import CreateEvalJSONLRunDataSource from .create_eval_completions_run_data_source import CreateEvalCompletionsRunDataSource -__all__ = ["RunCancelResponse", "DataSource", "PerModelUsage", "PerTestingCriteriaResult", "ResultCounts"] +__all__ = [ + "RunCancelResponse", + "DataSource", + "DataSourceCompletions", + "DataSourceCompletionsSource", + "DataSourceCompletionsSourceFileContent", + "DataSourceCompletionsSourceFileContentContent", + "DataSourceCompletionsSourceFileID", + "DataSourceCompletionsSourceResponses", + "DataSourceCompletionsInputMessages", + "DataSourceCompletionsInputMessagesTemplate", + "DataSourceCompletionsInputMessagesTemplateTemplate", + "DataSourceCompletionsInputMessagesTemplateTemplateChatMessage", + "DataSourceCompletionsInputMessagesTemplateTemplateEvalItem", + "DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContent", + "DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContentOutputText", + "DataSourceCompletionsInputMessagesItemReference", + "DataSourceCompletionsSamplingParams", + "PerModelUsage", + "PerTestingCriteriaResult", + "ResultCounts", +] + + +class DataSourceCompletionsSourceFileContentContent(BaseModel): + item: Dict[str, object] + + sample: Optional[Dict[str, object]] = None + + +class DataSourceCompletionsSourceFileContent(BaseModel): + content: List[DataSourceCompletionsSourceFileContentContent] + """The content of the jsonl file.""" + + type: Literal["file_content"] + """The type of jsonl source. Always `file_content`.""" + + +class DataSourceCompletionsSourceFileID(BaseModel): + id: str + """The identifier of the file.""" + + type: Literal["file_id"] + """The type of jsonl source. Always `file_id`.""" + + +class DataSourceCompletionsSourceResponses(BaseModel): + type: Literal["responses"] + """The type of run data source. Always `responses`.""" + + allow_parallel_tool_calls: Optional[bool] = None + """Whether to allow parallel tool calls. + + This is a query parameter used to select responses. + """ + + created_after: Optional[int] = None + """Only include items created after this timestamp (inclusive). + + This is a query parameter used to select responses. + """ + + created_before: Optional[int] = None + """Only include items created before this timestamp (inclusive). + + This is a query parameter used to select responses. + """ + + has_tool_calls: Optional[bool] = None + """Whether the response has tool calls. + + This is a query parameter used to select responses. + """ + + instructions_search: Optional[str] = None + """Optional search string for instructions. + + This is a query parameter used to select responses. + """ + + metadata: Optional[object] = None + """Metadata filter for the responses. + + This is a query parameter used to select responses. + """ + + model: Optional[str] = None + """The name of the model to find responses for. + + This is a query parameter used to select responses. + """ + + reasoning_effort: Optional[ReasoningEffort] = None + """Optional reasoning effort parameter. + + This is a query parameter used to select responses. + """ + + temperature: Optional[float] = None + """Sampling temperature. This is a query parameter used to select responses.""" + + top_p: Optional[float] = None + """Nucleus sampling parameter. This is a query parameter used to select responses.""" + + users: Optional[List[str]] = None + """List of user identifiers. This is a query parameter used to select responses.""" + + +DataSourceCompletionsSource: TypeAlias = Annotated[ + Union[ + DataSourceCompletionsSourceFileContent, DataSourceCompletionsSourceFileID, DataSourceCompletionsSourceResponses + ], + PropertyInfo(discriminator="type"), +] + + +class DataSourceCompletionsInputMessagesTemplateTemplateChatMessage(BaseModel): + content: str + """The content of the message.""" + + role: str + """The role of the message (e.g. "system", "assistant", "user").""" + + +class DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContentOutputText(BaseModel): + text: str + """The text output from the model.""" + + type: Literal["output_text"] + """The type of the output text. Always `output_text`.""" + + +DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ + str, ResponseInputText, DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContentOutputText +] + + +class DataSourceCompletionsInputMessagesTemplateTemplateEvalItem(BaseModel): + content: DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContent + """Text inputs to the model - can contain template strings.""" + + role: Literal["user", "assistant", "system", "developer"] + """The role of the message input. + + One of `user`, `assistant`, `system`, or `developer`. + """ + + type: Optional[Literal["message"]] = None + """The type of the message input. Always `message`.""" + + +DataSourceCompletionsInputMessagesTemplateTemplate: TypeAlias = Union[ + DataSourceCompletionsInputMessagesTemplateTemplateChatMessage, + DataSourceCompletionsInputMessagesTemplateTemplateEvalItem, +] + + +class DataSourceCompletionsInputMessagesTemplate(BaseModel): + template: List[DataSourceCompletionsInputMessagesTemplateTemplate] + """A list of chat messages forming the prompt or context. + + May include variable references to the "item" namespace, ie {{item.name}}. + """ + + type: Literal["template"] + """The type of input messages. Always `template`.""" + + +class DataSourceCompletionsInputMessagesItemReference(BaseModel): + item_reference: str + """A reference to a variable in the "item" namespace. Ie, "item.name" """ + + type: Literal["item_reference"] + """The type of input messages. Always `item_reference`.""" + + +DataSourceCompletionsInputMessages: TypeAlias = Annotated[ + Union[DataSourceCompletionsInputMessagesTemplate, DataSourceCompletionsInputMessagesItemReference], + PropertyInfo(discriminator="type"), +] + + +class DataSourceCompletionsSamplingParams(BaseModel): + max_completion_tokens: Optional[int] = None + """The maximum number of tokens in the generated output.""" + + seed: Optional[int] = None + """A seed value to initialize the randomness, during sampling.""" + + temperature: Optional[float] = None + """A higher temperature increases randomness in the outputs.""" + + top_p: Optional[float] = None + """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" + + +class DataSourceCompletions(BaseModel): + source: DataSourceCompletionsSource + """A EvalResponsesSource object describing a run data source configuration.""" + + type: Literal["completions"] + """The type of run data source. Always `completions`.""" + + input_messages: Optional[DataSourceCompletionsInputMessages] = None + + model: Optional[str] = None + """The name of the model to use for generating completions (e.g. "o3-mini").""" + + sampling_params: Optional[DataSourceCompletionsSamplingParams] = None + DataSource: TypeAlias = Annotated[ - Union[CreateEvalJSONLRunDataSource, CreateEvalCompletionsRunDataSource], PropertyInfo(discriminator="type") + Union[CreateEvalJSONLRunDataSource, CreateEvalCompletionsRunDataSource, DataSourceCompletions], + PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/evals/run_create_params.py b/src/openai/types/evals/run_create_params.py index acf7b1b126..0c9720ea7a 100644 --- a/src/openai/types/evals/run_create_params.py +++ b/src/openai/types/evals/run_create_params.py @@ -2,14 +2,34 @@ from __future__ import annotations -from typing import Union, Optional -from typing_extensions import Required, TypeAlias, TypedDict +from typing import Dict, List, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict from ..shared_params.metadata import Metadata +from ..shared.reasoning_effort import ReasoningEffort +from ..responses.response_input_text_param import ResponseInputTextParam from .create_eval_jsonl_run_data_source_param import CreateEvalJSONLRunDataSourceParam from .create_eval_completions_run_data_source_param import CreateEvalCompletionsRunDataSourceParam -__all__ = ["RunCreateParams", "DataSource"] +__all__ = [ + "RunCreateParams", + "DataSource", + "DataSourceCreateEvalResponsesRunDataSource", + "DataSourceCreateEvalResponsesRunDataSourceSource", + "DataSourceCreateEvalResponsesRunDataSourceSourceFileContent", + "DataSourceCreateEvalResponsesRunDataSourceSourceFileContentContent", + "DataSourceCreateEvalResponsesRunDataSourceSourceFileID", + "DataSourceCreateEvalResponsesRunDataSourceSourceResponses", + "DataSourceCreateEvalResponsesRunDataSourceInputMessages", + "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplate", + "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplate", + "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateChatMessage", + "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItem", + "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContent", + "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentOutputText", + "DataSourceCreateEvalResponsesRunDataSourceInputMessagesItemReference", + "DataSourceCreateEvalResponsesRunDataSourceSamplingParams", +] class RunCreateParams(TypedDict, total=False): @@ -30,4 +50,198 @@ class RunCreateParams(TypedDict, total=False): """The name of the run.""" -DataSource: TypeAlias = Union[CreateEvalJSONLRunDataSourceParam, CreateEvalCompletionsRunDataSourceParam] +class DataSourceCreateEvalResponsesRunDataSourceSourceFileContentContent(TypedDict, total=False): + item: Required[Dict[str, object]] + + sample: Dict[str, object] + + +class DataSourceCreateEvalResponsesRunDataSourceSourceFileContent(TypedDict, total=False): + content: Required[Iterable[DataSourceCreateEvalResponsesRunDataSourceSourceFileContentContent]] + """The content of the jsonl file.""" + + type: Required[Literal["file_content"]] + """The type of jsonl source. Always `file_content`.""" + + +class DataSourceCreateEvalResponsesRunDataSourceSourceFileID(TypedDict, total=False): + id: Required[str] + """The identifier of the file.""" + + type: Required[Literal["file_id"]] + """The type of jsonl source. Always `file_id`.""" + + +class DataSourceCreateEvalResponsesRunDataSourceSourceResponses(TypedDict, total=False): + type: Required[Literal["responses"]] + """The type of run data source. Always `responses`.""" + + allow_parallel_tool_calls: Optional[bool] + """Whether to allow parallel tool calls. + + This is a query parameter used to select responses. + """ + + created_after: Optional[int] + """Only include items created after this timestamp (inclusive). + + This is a query parameter used to select responses. + """ + + created_before: Optional[int] + """Only include items created before this timestamp (inclusive). + + This is a query parameter used to select responses. + """ + + has_tool_calls: Optional[bool] + """Whether the response has tool calls. + + This is a query parameter used to select responses. + """ + + instructions_search: Optional[str] + """Optional search string for instructions. + + This is a query parameter used to select responses. + """ + + metadata: Optional[object] + """Metadata filter for the responses. + + This is a query parameter used to select responses. + """ + + model: Optional[str] + """The name of the model to find responses for. + + This is a query parameter used to select responses. + """ + + reasoning_effort: Optional[ReasoningEffort] + """Optional reasoning effort parameter. + + This is a query parameter used to select responses. + """ + + temperature: Optional[float] + """Sampling temperature. This is a query parameter used to select responses.""" + + top_p: Optional[float] + """Nucleus sampling parameter. This is a query parameter used to select responses.""" + + users: Optional[List[str]] + """List of user identifiers. This is a query parameter used to select responses.""" + + +DataSourceCreateEvalResponsesRunDataSourceSource: TypeAlias = Union[ + DataSourceCreateEvalResponsesRunDataSourceSourceFileContent, + DataSourceCreateEvalResponsesRunDataSourceSourceFileID, + DataSourceCreateEvalResponsesRunDataSourceSourceResponses, +] + + +class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateChatMessage(TypedDict, total=False): + content: Required[str] + """The content of the message.""" + + role: Required[str] + """The role of the message (e.g. "system", "assistant", "user").""" + + +class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentOutputText( + TypedDict, total=False +): + text: Required[str] + """The text output from the model.""" + + type: Required[Literal["output_text"]] + """The type of the output text. Always `output_text`.""" + + +DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ + str, + ResponseInputTextParam, + DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentOutputText, +] + + +class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItem(TypedDict, total=False): + content: Required[DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContent] + """Text inputs to the model - can contain template strings.""" + + role: Required[Literal["user", "assistant", "system", "developer"]] + """The role of the message input. + + One of `user`, `assistant`, `system`, or `developer`. + """ + + type: Literal["message"] + """The type of the message input. Always `message`.""" + + +DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplate: TypeAlias = Union[ + DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateChatMessage, + DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItem, +] + + +class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplate(TypedDict, total=False): + template: Required[Iterable[DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplate]] + """A list of chat messages forming the prompt or context. + + May include variable references to the "item" namespace, ie {{item.name}}. + """ + + type: Required[Literal["template"]] + """The type of input messages. Always `template`.""" + + +class DataSourceCreateEvalResponsesRunDataSourceInputMessagesItemReference(TypedDict, total=False): + item_reference: Required[str] + """A reference to a variable in the "item" namespace. Ie, "item.name" """ + + type: Required[Literal["item_reference"]] + """The type of input messages. Always `item_reference`.""" + + +DataSourceCreateEvalResponsesRunDataSourceInputMessages: TypeAlias = Union[ + DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplate, + DataSourceCreateEvalResponsesRunDataSourceInputMessagesItemReference, +] + + +class DataSourceCreateEvalResponsesRunDataSourceSamplingParams(TypedDict, total=False): + max_completion_tokens: int + """The maximum number of tokens in the generated output.""" + + seed: int + """A seed value to initialize the randomness, during sampling.""" + + temperature: float + """A higher temperature increases randomness in the outputs.""" + + top_p: float + """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" + + +class DataSourceCreateEvalResponsesRunDataSource(TypedDict, total=False): + source: Required[DataSourceCreateEvalResponsesRunDataSourceSource] + """A EvalResponsesSource object describing a run data source configuration.""" + + type: Required[Literal["completions"]] + """The type of run data source. Always `completions`.""" + + input_messages: DataSourceCreateEvalResponsesRunDataSourceInputMessages + + model: str + """The name of the model to use for generating completions (e.g. "o3-mini").""" + + sampling_params: DataSourceCreateEvalResponsesRunDataSourceSamplingParams + + +DataSource: TypeAlias = Union[ + CreateEvalJSONLRunDataSourceParam, + CreateEvalCompletionsRunDataSourceParam, + DataSourceCreateEvalResponsesRunDataSource, +] diff --git a/src/openai/types/evals/run_create_response.py b/src/openai/types/evals/run_create_response.py index 14ca426427..459399511c 100644 --- a/src/openai/types/evals/run_create_response.py +++ b/src/openai/types/evals/run_create_response.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union, Optional +from typing import Dict, List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias from pydantic import Field as FieldInfo @@ -9,13 +9,225 @@ from ..._models import BaseModel from .eval_api_error import EvalAPIError from ..shared.metadata import Metadata +from ..shared.reasoning_effort import ReasoningEffort +from ..responses.response_input_text import ResponseInputText from .create_eval_jsonl_run_data_source import CreateEvalJSONLRunDataSource from .create_eval_completions_run_data_source import CreateEvalCompletionsRunDataSource -__all__ = ["RunCreateResponse", "DataSource", "PerModelUsage", "PerTestingCriteriaResult", "ResultCounts"] +__all__ = [ + "RunCreateResponse", + "DataSource", + "DataSourceCompletions", + "DataSourceCompletionsSource", + "DataSourceCompletionsSourceFileContent", + "DataSourceCompletionsSourceFileContentContent", + "DataSourceCompletionsSourceFileID", + "DataSourceCompletionsSourceResponses", + "DataSourceCompletionsInputMessages", + "DataSourceCompletionsInputMessagesTemplate", + "DataSourceCompletionsInputMessagesTemplateTemplate", + "DataSourceCompletionsInputMessagesTemplateTemplateChatMessage", + "DataSourceCompletionsInputMessagesTemplateTemplateEvalItem", + "DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContent", + "DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContentOutputText", + "DataSourceCompletionsInputMessagesItemReference", + "DataSourceCompletionsSamplingParams", + "PerModelUsage", + "PerTestingCriteriaResult", + "ResultCounts", +] + + +class DataSourceCompletionsSourceFileContentContent(BaseModel): + item: Dict[str, object] + + sample: Optional[Dict[str, object]] = None + + +class DataSourceCompletionsSourceFileContent(BaseModel): + content: List[DataSourceCompletionsSourceFileContentContent] + """The content of the jsonl file.""" + + type: Literal["file_content"] + """The type of jsonl source. Always `file_content`.""" + + +class DataSourceCompletionsSourceFileID(BaseModel): + id: str + """The identifier of the file.""" + + type: Literal["file_id"] + """The type of jsonl source. Always `file_id`.""" + + +class DataSourceCompletionsSourceResponses(BaseModel): + type: Literal["responses"] + """The type of run data source. Always `responses`.""" + + allow_parallel_tool_calls: Optional[bool] = None + """Whether to allow parallel tool calls. + + This is a query parameter used to select responses. + """ + + created_after: Optional[int] = None + """Only include items created after this timestamp (inclusive). + + This is a query parameter used to select responses. + """ + + created_before: Optional[int] = None + """Only include items created before this timestamp (inclusive). + + This is a query parameter used to select responses. + """ + + has_tool_calls: Optional[bool] = None + """Whether the response has tool calls. + + This is a query parameter used to select responses. + """ + + instructions_search: Optional[str] = None + """Optional search string for instructions. + + This is a query parameter used to select responses. + """ + + metadata: Optional[object] = None + """Metadata filter for the responses. + + This is a query parameter used to select responses. + """ + + model: Optional[str] = None + """The name of the model to find responses for. + + This is a query parameter used to select responses. + """ + + reasoning_effort: Optional[ReasoningEffort] = None + """Optional reasoning effort parameter. + + This is a query parameter used to select responses. + """ + + temperature: Optional[float] = None + """Sampling temperature. This is a query parameter used to select responses.""" + + top_p: Optional[float] = None + """Nucleus sampling parameter. This is a query parameter used to select responses.""" + + users: Optional[List[str]] = None + """List of user identifiers. This is a query parameter used to select responses.""" + + +DataSourceCompletionsSource: TypeAlias = Annotated[ + Union[ + DataSourceCompletionsSourceFileContent, DataSourceCompletionsSourceFileID, DataSourceCompletionsSourceResponses + ], + PropertyInfo(discriminator="type"), +] + + +class DataSourceCompletionsInputMessagesTemplateTemplateChatMessage(BaseModel): + content: str + """The content of the message.""" + + role: str + """The role of the message (e.g. "system", "assistant", "user").""" + + +class DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContentOutputText(BaseModel): + text: str + """The text output from the model.""" + + type: Literal["output_text"] + """The type of the output text. Always `output_text`.""" + + +DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ + str, ResponseInputText, DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContentOutputText +] + + +class DataSourceCompletionsInputMessagesTemplateTemplateEvalItem(BaseModel): + content: DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContent + """Text inputs to the model - can contain template strings.""" + + role: Literal["user", "assistant", "system", "developer"] + """The role of the message input. + + One of `user`, `assistant`, `system`, or `developer`. + """ + + type: Optional[Literal["message"]] = None + """The type of the message input. Always `message`.""" + + +DataSourceCompletionsInputMessagesTemplateTemplate: TypeAlias = Union[ + DataSourceCompletionsInputMessagesTemplateTemplateChatMessage, + DataSourceCompletionsInputMessagesTemplateTemplateEvalItem, +] + + +class DataSourceCompletionsInputMessagesTemplate(BaseModel): + template: List[DataSourceCompletionsInputMessagesTemplateTemplate] + """A list of chat messages forming the prompt or context. + + May include variable references to the "item" namespace, ie {{item.name}}. + """ + + type: Literal["template"] + """The type of input messages. Always `template`.""" + + +class DataSourceCompletionsInputMessagesItemReference(BaseModel): + item_reference: str + """A reference to a variable in the "item" namespace. Ie, "item.name" """ + + type: Literal["item_reference"] + """The type of input messages. Always `item_reference`.""" + + +DataSourceCompletionsInputMessages: TypeAlias = Annotated[ + Union[DataSourceCompletionsInputMessagesTemplate, DataSourceCompletionsInputMessagesItemReference], + PropertyInfo(discriminator="type"), +] + + +class DataSourceCompletionsSamplingParams(BaseModel): + max_completion_tokens: Optional[int] = None + """The maximum number of tokens in the generated output.""" + + seed: Optional[int] = None + """A seed value to initialize the randomness, during sampling.""" + + temperature: Optional[float] = None + """A higher temperature increases randomness in the outputs.""" + + top_p: Optional[float] = None + """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" + + +class DataSourceCompletions(BaseModel): + source: DataSourceCompletionsSource + """A EvalResponsesSource object describing a run data source configuration.""" + + type: Literal["completions"] + """The type of run data source. Always `completions`.""" + + input_messages: Optional[DataSourceCompletionsInputMessages] = None + + model: Optional[str] = None + """The name of the model to use for generating completions (e.g. "o3-mini").""" + + sampling_params: Optional[DataSourceCompletionsSamplingParams] = None + DataSource: TypeAlias = Annotated[ - Union[CreateEvalJSONLRunDataSource, CreateEvalCompletionsRunDataSource], PropertyInfo(discriminator="type") + Union[CreateEvalJSONLRunDataSource, CreateEvalCompletionsRunDataSource, DataSourceCompletions], + PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/evals/run_list_params.py b/src/openai/types/evals/run_list_params.py index 6060eafb97..383b89d85c 100644 --- a/src/openai/types/evals/run_list_params.py +++ b/src/openai/types/evals/run_list_params.py @@ -23,5 +23,5 @@ class RunListParams(TypedDict, total=False): status: Literal["queued", "in_progress", "completed", "canceled", "failed"] """Filter runs by status. - Use "queued" | "in_progress" | "failed" | "completed" | "canceled". + One of `queued` | `in_progress` | `failed` | `completed` | `canceled`. """ diff --git a/src/openai/types/evals/run_list_response.py b/src/openai/types/evals/run_list_response.py index a1022f542f..278ceeabed 100644 --- a/src/openai/types/evals/run_list_response.py +++ b/src/openai/types/evals/run_list_response.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union, Optional +from typing import Dict, List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias from pydantic import Field as FieldInfo @@ -9,13 +9,225 @@ from ..._models import BaseModel from .eval_api_error import EvalAPIError from ..shared.metadata import Metadata +from ..shared.reasoning_effort import ReasoningEffort +from ..responses.response_input_text import ResponseInputText from .create_eval_jsonl_run_data_source import CreateEvalJSONLRunDataSource from .create_eval_completions_run_data_source import CreateEvalCompletionsRunDataSource -__all__ = ["RunListResponse", "DataSource", "PerModelUsage", "PerTestingCriteriaResult", "ResultCounts"] +__all__ = [ + "RunListResponse", + "DataSource", + "DataSourceCompletions", + "DataSourceCompletionsSource", + "DataSourceCompletionsSourceFileContent", + "DataSourceCompletionsSourceFileContentContent", + "DataSourceCompletionsSourceFileID", + "DataSourceCompletionsSourceResponses", + "DataSourceCompletionsInputMessages", + "DataSourceCompletionsInputMessagesTemplate", + "DataSourceCompletionsInputMessagesTemplateTemplate", + "DataSourceCompletionsInputMessagesTemplateTemplateChatMessage", + "DataSourceCompletionsInputMessagesTemplateTemplateEvalItem", + "DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContent", + "DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContentOutputText", + "DataSourceCompletionsInputMessagesItemReference", + "DataSourceCompletionsSamplingParams", + "PerModelUsage", + "PerTestingCriteriaResult", + "ResultCounts", +] + + +class DataSourceCompletionsSourceFileContentContent(BaseModel): + item: Dict[str, object] + + sample: Optional[Dict[str, object]] = None + + +class DataSourceCompletionsSourceFileContent(BaseModel): + content: List[DataSourceCompletionsSourceFileContentContent] + """The content of the jsonl file.""" + + type: Literal["file_content"] + """The type of jsonl source. Always `file_content`.""" + + +class DataSourceCompletionsSourceFileID(BaseModel): + id: str + """The identifier of the file.""" + + type: Literal["file_id"] + """The type of jsonl source. Always `file_id`.""" + + +class DataSourceCompletionsSourceResponses(BaseModel): + type: Literal["responses"] + """The type of run data source. Always `responses`.""" + + allow_parallel_tool_calls: Optional[bool] = None + """Whether to allow parallel tool calls. + + This is a query parameter used to select responses. + """ + + created_after: Optional[int] = None + """Only include items created after this timestamp (inclusive). + + This is a query parameter used to select responses. + """ + + created_before: Optional[int] = None + """Only include items created before this timestamp (inclusive). + + This is a query parameter used to select responses. + """ + + has_tool_calls: Optional[bool] = None + """Whether the response has tool calls. + + This is a query parameter used to select responses. + """ + + instructions_search: Optional[str] = None + """Optional search string for instructions. + + This is a query parameter used to select responses. + """ + + metadata: Optional[object] = None + """Metadata filter for the responses. + + This is a query parameter used to select responses. + """ + + model: Optional[str] = None + """The name of the model to find responses for. + + This is a query parameter used to select responses. + """ + + reasoning_effort: Optional[ReasoningEffort] = None + """Optional reasoning effort parameter. + + This is a query parameter used to select responses. + """ + + temperature: Optional[float] = None + """Sampling temperature. This is a query parameter used to select responses.""" + + top_p: Optional[float] = None + """Nucleus sampling parameter. This is a query parameter used to select responses.""" + + users: Optional[List[str]] = None + """List of user identifiers. This is a query parameter used to select responses.""" + + +DataSourceCompletionsSource: TypeAlias = Annotated[ + Union[ + DataSourceCompletionsSourceFileContent, DataSourceCompletionsSourceFileID, DataSourceCompletionsSourceResponses + ], + PropertyInfo(discriminator="type"), +] + + +class DataSourceCompletionsInputMessagesTemplateTemplateChatMessage(BaseModel): + content: str + """The content of the message.""" + + role: str + """The role of the message (e.g. "system", "assistant", "user").""" + + +class DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContentOutputText(BaseModel): + text: str + """The text output from the model.""" + + type: Literal["output_text"] + """The type of the output text. Always `output_text`.""" + + +DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ + str, ResponseInputText, DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContentOutputText +] + + +class DataSourceCompletionsInputMessagesTemplateTemplateEvalItem(BaseModel): + content: DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContent + """Text inputs to the model - can contain template strings.""" + + role: Literal["user", "assistant", "system", "developer"] + """The role of the message input. + + One of `user`, `assistant`, `system`, or `developer`. + """ + + type: Optional[Literal["message"]] = None + """The type of the message input. Always `message`.""" + + +DataSourceCompletionsInputMessagesTemplateTemplate: TypeAlias = Union[ + DataSourceCompletionsInputMessagesTemplateTemplateChatMessage, + DataSourceCompletionsInputMessagesTemplateTemplateEvalItem, +] + + +class DataSourceCompletionsInputMessagesTemplate(BaseModel): + template: List[DataSourceCompletionsInputMessagesTemplateTemplate] + """A list of chat messages forming the prompt or context. + + May include variable references to the "item" namespace, ie {{item.name}}. + """ + + type: Literal["template"] + """The type of input messages. Always `template`.""" + + +class DataSourceCompletionsInputMessagesItemReference(BaseModel): + item_reference: str + """A reference to a variable in the "item" namespace. Ie, "item.name" """ + + type: Literal["item_reference"] + """The type of input messages. Always `item_reference`.""" + + +DataSourceCompletionsInputMessages: TypeAlias = Annotated[ + Union[DataSourceCompletionsInputMessagesTemplate, DataSourceCompletionsInputMessagesItemReference], + PropertyInfo(discriminator="type"), +] + + +class DataSourceCompletionsSamplingParams(BaseModel): + max_completion_tokens: Optional[int] = None + """The maximum number of tokens in the generated output.""" + + seed: Optional[int] = None + """A seed value to initialize the randomness, during sampling.""" + + temperature: Optional[float] = None + """A higher temperature increases randomness in the outputs.""" + + top_p: Optional[float] = None + """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" + + +class DataSourceCompletions(BaseModel): + source: DataSourceCompletionsSource + """A EvalResponsesSource object describing a run data source configuration.""" + + type: Literal["completions"] + """The type of run data source. Always `completions`.""" + + input_messages: Optional[DataSourceCompletionsInputMessages] = None + + model: Optional[str] = None + """The name of the model to use for generating completions (e.g. "o3-mini").""" + + sampling_params: Optional[DataSourceCompletionsSamplingParams] = None + DataSource: TypeAlias = Annotated[ - Union[CreateEvalJSONLRunDataSource, CreateEvalCompletionsRunDataSource], PropertyInfo(discriminator="type") + Union[CreateEvalJSONLRunDataSource, CreateEvalCompletionsRunDataSource, DataSourceCompletions], + PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/evals/run_retrieve_response.py b/src/openai/types/evals/run_retrieve_response.py index 461ed43dda..e142f31b14 100644 --- a/src/openai/types/evals/run_retrieve_response.py +++ b/src/openai/types/evals/run_retrieve_response.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union, Optional +from typing import Dict, List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias from pydantic import Field as FieldInfo @@ -9,13 +9,225 @@ from ..._models import BaseModel from .eval_api_error import EvalAPIError from ..shared.metadata import Metadata +from ..shared.reasoning_effort import ReasoningEffort +from ..responses.response_input_text import ResponseInputText from .create_eval_jsonl_run_data_source import CreateEvalJSONLRunDataSource from .create_eval_completions_run_data_source import CreateEvalCompletionsRunDataSource -__all__ = ["RunRetrieveResponse", "DataSource", "PerModelUsage", "PerTestingCriteriaResult", "ResultCounts"] +__all__ = [ + "RunRetrieveResponse", + "DataSource", + "DataSourceCompletions", + "DataSourceCompletionsSource", + "DataSourceCompletionsSourceFileContent", + "DataSourceCompletionsSourceFileContentContent", + "DataSourceCompletionsSourceFileID", + "DataSourceCompletionsSourceResponses", + "DataSourceCompletionsInputMessages", + "DataSourceCompletionsInputMessagesTemplate", + "DataSourceCompletionsInputMessagesTemplateTemplate", + "DataSourceCompletionsInputMessagesTemplateTemplateChatMessage", + "DataSourceCompletionsInputMessagesTemplateTemplateEvalItem", + "DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContent", + "DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContentOutputText", + "DataSourceCompletionsInputMessagesItemReference", + "DataSourceCompletionsSamplingParams", + "PerModelUsage", + "PerTestingCriteriaResult", + "ResultCounts", +] + + +class DataSourceCompletionsSourceFileContentContent(BaseModel): + item: Dict[str, object] + + sample: Optional[Dict[str, object]] = None + + +class DataSourceCompletionsSourceFileContent(BaseModel): + content: List[DataSourceCompletionsSourceFileContentContent] + """The content of the jsonl file.""" + + type: Literal["file_content"] + """The type of jsonl source. Always `file_content`.""" + + +class DataSourceCompletionsSourceFileID(BaseModel): + id: str + """The identifier of the file.""" + + type: Literal["file_id"] + """The type of jsonl source. Always `file_id`.""" + + +class DataSourceCompletionsSourceResponses(BaseModel): + type: Literal["responses"] + """The type of run data source. Always `responses`.""" + + allow_parallel_tool_calls: Optional[bool] = None + """Whether to allow parallel tool calls. + + This is a query parameter used to select responses. + """ + + created_after: Optional[int] = None + """Only include items created after this timestamp (inclusive). + + This is a query parameter used to select responses. + """ + + created_before: Optional[int] = None + """Only include items created before this timestamp (inclusive). + + This is a query parameter used to select responses. + """ + + has_tool_calls: Optional[bool] = None + """Whether the response has tool calls. + + This is a query parameter used to select responses. + """ + + instructions_search: Optional[str] = None + """Optional search string for instructions. + + This is a query parameter used to select responses. + """ + + metadata: Optional[object] = None + """Metadata filter for the responses. + + This is a query parameter used to select responses. + """ + + model: Optional[str] = None + """The name of the model to find responses for. + + This is a query parameter used to select responses. + """ + + reasoning_effort: Optional[ReasoningEffort] = None + """Optional reasoning effort parameter. + + This is a query parameter used to select responses. + """ + + temperature: Optional[float] = None + """Sampling temperature. This is a query parameter used to select responses.""" + + top_p: Optional[float] = None + """Nucleus sampling parameter. This is a query parameter used to select responses.""" + + users: Optional[List[str]] = None + """List of user identifiers. This is a query parameter used to select responses.""" + + +DataSourceCompletionsSource: TypeAlias = Annotated[ + Union[ + DataSourceCompletionsSourceFileContent, DataSourceCompletionsSourceFileID, DataSourceCompletionsSourceResponses + ], + PropertyInfo(discriminator="type"), +] + + +class DataSourceCompletionsInputMessagesTemplateTemplateChatMessage(BaseModel): + content: str + """The content of the message.""" + + role: str + """The role of the message (e.g. "system", "assistant", "user").""" + + +class DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContentOutputText(BaseModel): + text: str + """The text output from the model.""" + + type: Literal["output_text"] + """The type of the output text. Always `output_text`.""" + + +DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ + str, ResponseInputText, DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContentOutputText +] + + +class DataSourceCompletionsInputMessagesTemplateTemplateEvalItem(BaseModel): + content: DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContent + """Text inputs to the model - can contain template strings.""" + + role: Literal["user", "assistant", "system", "developer"] + """The role of the message input. + + One of `user`, `assistant`, `system`, or `developer`. + """ + + type: Optional[Literal["message"]] = None + """The type of the message input. Always `message`.""" + + +DataSourceCompletionsInputMessagesTemplateTemplate: TypeAlias = Union[ + DataSourceCompletionsInputMessagesTemplateTemplateChatMessage, + DataSourceCompletionsInputMessagesTemplateTemplateEvalItem, +] + + +class DataSourceCompletionsInputMessagesTemplate(BaseModel): + template: List[DataSourceCompletionsInputMessagesTemplateTemplate] + """A list of chat messages forming the prompt or context. + + May include variable references to the "item" namespace, ie {{item.name}}. + """ + + type: Literal["template"] + """The type of input messages. Always `template`.""" + + +class DataSourceCompletionsInputMessagesItemReference(BaseModel): + item_reference: str + """A reference to a variable in the "item" namespace. Ie, "item.name" """ + + type: Literal["item_reference"] + """The type of input messages. Always `item_reference`.""" + + +DataSourceCompletionsInputMessages: TypeAlias = Annotated[ + Union[DataSourceCompletionsInputMessagesTemplate, DataSourceCompletionsInputMessagesItemReference], + PropertyInfo(discriminator="type"), +] + + +class DataSourceCompletionsSamplingParams(BaseModel): + max_completion_tokens: Optional[int] = None + """The maximum number of tokens in the generated output.""" + + seed: Optional[int] = None + """A seed value to initialize the randomness, during sampling.""" + + temperature: Optional[float] = None + """A higher temperature increases randomness in the outputs.""" + + top_p: Optional[float] = None + """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" + + +class DataSourceCompletions(BaseModel): + source: DataSourceCompletionsSource + """A EvalResponsesSource object describing a run data source configuration.""" + + type: Literal["completions"] + """The type of run data source. Always `completions`.""" + + input_messages: Optional[DataSourceCompletionsInputMessages] = None + + model: Optional[str] = None + """The name of the model to use for generating completions (e.g. "o3-mini").""" + + sampling_params: Optional[DataSourceCompletionsSamplingParams] = None + DataSource: TypeAlias = Annotated[ - Union[CreateEvalJSONLRunDataSource, CreateEvalCompletionsRunDataSource], PropertyInfo(discriminator="type") + Union[CreateEvalJSONLRunDataSource, CreateEvalCompletionsRunDataSource, DataSourceCompletions], + PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/image.py b/src/openai/types/image.py index f48aa2c702..ecaef3fd58 100644 --- a/src/openai/types/image.py +++ b/src/openai/types/image.py @@ -9,16 +9,18 @@ class Image(BaseModel): b64_json: Optional[str] = None - """ - The base64-encoded JSON of the generated image, if `response_format` is - `b64_json`. + """The base64-encoded JSON of the generated image. + + Default value for `gpt-image-1`, and only present if `response_format` is set to + `b64_json` for `dall-e-2` and `dall-e-3`. """ revised_prompt: Optional[str] = None - """ - The prompt that was used to generate the image, if there was any revision to the - prompt. - """ + """For `dall-e-3` only, the revised prompt that was used to generate the image.""" url: Optional[str] = None - """The URL of the generated image, if `response_format` is `url` (default).""" + """ + When using `dall-e-2` or `dall-e-3`, the URL of the generated image if + `response_format` is set to `url` (default value). Unsupported for + `gpt-image-1`. + """ diff --git a/src/openai/types/image_create_variation_params.py b/src/openai/types/image_create_variation_params.py index d20f672912..d10b74b2c2 100644 --- a/src/openai/types/image_create_variation_params.py +++ b/src/openai/types/image_create_variation_params.py @@ -25,10 +25,7 @@ class ImageCreateVariationParams(TypedDict, total=False): """ n: Optional[int] - """The number of images to generate. - - Must be between 1 and 10. For `dall-e-3`, only `n=1` is supported. - """ + """The number of images to generate. Must be between 1 and 10.""" response_format: Optional[Literal["url", "b64_json"]] """The format in which the generated images are returned. diff --git a/src/openai/types/image_edit_params.py b/src/openai/types/image_edit_params.py index 1cb10611f3..f01a12c1b0 100644 --- a/src/openai/types/image_edit_params.py +++ b/src/openai/types/image_edit_params.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Union, Optional +from typing import List, Union, Optional from typing_extensions import Literal, Required, TypedDict from .._types import FileTypes @@ -12,46 +12,61 @@ class ImageEditParams(TypedDict, total=False): - image: Required[FileTypes] - """The image to edit. + image: Required[Union[FileTypes, List[FileTypes]]] + """The image(s) to edit. - Must be a valid PNG file, less than 4MB, and square. If mask is not provided, - image must have transparency, which will be used as the mask. + Must be a supported image file or an array of images. For `gpt-image-1`, each + image should be a `png`, `webp`, or `jpg` file less than 25MB. For `dall-e-2`, + you can only provide one image, and it should be a square `png` file less than + 4MB. """ prompt: Required[str] """A text description of the desired image(s). - The maximum length is 1000 characters. + The maximum length is 1000 characters for `dall-e-2`, and 32000 characters for + `gpt-image-1`. """ mask: FileTypes """An additional image whose fully transparent areas (e.g. - where alpha is zero) indicate where `image` should be edited. Must be a valid - PNG file, less than 4MB, and have the same dimensions as `image`. + where alpha is zero) indicate where `image` should be edited. If there are + multiple images provided, the mask will be applied on the first image. Must be a + valid PNG file, less than 4MB, and have the same dimensions as `image`. """ model: Union[str, ImageModel, None] """The model to use for image generation. - Only `dall-e-2` is supported at this time. + Only `dall-e-2` and `gpt-image-1` are supported. Defaults to `dall-e-2` unless a + parameter specific to `gpt-image-1` is used. """ n: Optional[int] """The number of images to generate. Must be between 1 and 10.""" + quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] + """The quality of the image that will be generated. + + `high`, `medium` and `low` are only supported for `gpt-image-1`. `dall-e-2` only + supports `standard` quality. Defaults to `auto`. + """ + response_format: Optional[Literal["url", "b64_json"]] """The format in which the generated images are returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes after the - image has been generated. + image has been generated. This parameter is only supported for `dall-e-2`, as + `gpt-image-1` will always return base64-encoded images. """ size: Optional[Literal["256x256", "512x512", "1024x1024"]] """The size of the generated images. - Must be one of `256x256`, `512x512`, or `1024x1024`. + Must be one of `1024x1024`, `1536x1024` (landscape), `1024x1536` (portrait), or + `auto` (default value) for `gpt-image-1`, and one of `256x256`, `512x512`, or + `1024x1024` for `dall-e-2`. """ user: str diff --git a/src/openai/types/image_generate_params.py b/src/openai/types/image_generate_params.py index c88c45f518..8fc10220dc 100644 --- a/src/openai/types/image_generate_params.py +++ b/src/openai/types/image_generate_params.py @@ -14,12 +14,33 @@ class ImageGenerateParams(TypedDict, total=False): prompt: Required[str] """A text description of the desired image(s). - The maximum length is 1000 characters for `dall-e-2` and 4000 characters for - `dall-e-3`. + The maximum length is 32000 characters for `gpt-image-1`, 1000 characters for + `dall-e-2` and 4000 characters for `dall-e-3`. + """ + + background: Optional[Literal["transparent", "opaque", "auto"]] + """Allows to set transparency for the background of the generated image(s). + + This parameter is only supported for `gpt-image-1`. Must be one of + `transparent`, `opaque` or `auto` (default value). When `auto` is used, the + model will automatically determine the best background for the image. + + If `transparent`, the output format needs to support transparency, so it should + be set to either `png` (default value) or `webp`. """ model: Union[str, ImageModel, None] - """The model to use for image generation.""" + """The model to use for image generation. + + One of `dall-e-2`, `dall-e-3`, or `gpt-image-1`. Defaults to `dall-e-2` unless a + parameter specific to `gpt-image-1` is used. + """ + + moderation: Optional[Literal["low", "auto"]] + """Control the content-moderation level for images generated by `gpt-image-1`. + + Must be either `low` for less restrictive filtering or `auto` (default value). + """ n: Optional[int] """The number of images to generate. @@ -27,34 +48,57 @@ class ImageGenerateParams(TypedDict, total=False): Must be between 1 and 10. For `dall-e-3`, only `n=1` is supported. """ - quality: Literal["standard", "hd"] + output_compression: Optional[int] + """The compression level (0-100%) for the generated images. + + This parameter is only supported for `gpt-image-1` with the `webp` or `jpeg` + output formats, and defaults to 100. + """ + + output_format: Optional[Literal["png", "jpeg", "webp"]] + """The format in which the generated images are returned. + + This parameter is only supported for `gpt-image-1`. Must be one of `png`, + `jpeg`, or `webp`. + """ + + quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] """The quality of the image that will be generated. - `hd` creates images with finer details and greater consistency across the image. - This param is only supported for `dall-e-3`. + - `auto` (default value) will automatically select the best quality for the + given model. + - `high`, `medium` and `low` are supported for `gpt-image-1`. + - `hd` and `standard` are supported for `dall-e-3`. + - `standard` is the only option for `dall-e-2`. """ response_format: Optional[Literal["url", "b64_json"]] - """The format in which the generated images are returned. + """The format in which generated images with `dall-e-2` and `dall-e-3` are + returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes after the - image has been generated. + image has been generated. This parameter isn't supported for `gpt-image-1` which + will always return base64-encoded images. """ - size: Optional[Literal["256x256", "512x512", "1024x1024", "1792x1024", "1024x1792"]] + size: Optional[ + Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] + ] """The size of the generated images. - Must be one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`. Must be one - of `1024x1024`, `1792x1024`, or `1024x1792` for `dall-e-3` models. + Must be one of `1024x1024`, `1536x1024` (landscape), `1024x1536` (portrait), or + `auto` (default value) for `gpt-image-1`, one of `256x256`, `512x512`, or + `1024x1024` for `dall-e-2`, and one of `1024x1024`, `1792x1024`, or `1024x1792` + for `dall-e-3`. """ style: Optional[Literal["vivid", "natural"]] """The style of the generated images. - Must be one of `vivid` or `natural`. Vivid causes the model to lean towards - generating hyper-real and dramatic images. Natural causes the model to produce - more natural, less hyper-real looking images. This param is only supported for - `dall-e-3`. + This parameter is only supported for `dall-e-3`. Must be one of `vivid` or + `natural`. Vivid causes the model to lean towards generating hyper-real and + dramatic images. Natural causes the model to produce more natural, less + hyper-real looking images. """ user: str diff --git a/src/openai/types/image_model.py b/src/openai/types/image_model.py index 1672369bea..7fed69ed82 100644 --- a/src/openai/types/image_model.py +++ b/src/openai/types/image_model.py @@ -4,4 +4,4 @@ __all__ = ["ImageModel"] -ImageModel: TypeAlias = Literal["dall-e-2", "dall-e-3"] +ImageModel: TypeAlias = Literal["dall-e-2", "dall-e-3", "gpt-image-1"] diff --git a/src/openai/types/images_response.py b/src/openai/types/images_response.py index 7cee813184..df454afa4d 100644 --- a/src/openai/types/images_response.py +++ b/src/openai/types/images_response.py @@ -1,14 +1,41 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List +from typing import List, Optional from .image import Image from .._models import BaseModel -__all__ = ["ImagesResponse"] +__all__ = ["ImagesResponse", "Usage", "UsageInputTokensDetails"] + + +class UsageInputTokensDetails(BaseModel): + image_tokens: int + """The number of image tokens in the input prompt.""" + + text_tokens: int + """The number of text tokens in the input prompt.""" + + +class Usage(BaseModel): + input_tokens: int + """The number of tokens (images and text) in the input prompt.""" + + input_tokens_details: UsageInputTokensDetails + """The input tokens detailed information for the image generation.""" + + output_tokens: int + """The number of image tokens in the output image.""" + + total_tokens: int + """The total number of tokens (images and text) used for the image generation.""" class ImagesResponse(BaseModel): created: int + """The Unix timestamp (in seconds) of when the image was created.""" + + data: Optional[List[Image]] = None + """The list of generated images.""" - data: List[Image] + usage: Optional[Usage] = None + """For `gpt-image-1` only, the token usage information for the image generation.""" diff --git a/src/openai/types/responses/__init__.py b/src/openai/types/responses/__init__.py index 4f07a3d097..22fd2a0802 100644 --- a/src/openai/types/responses/__init__.py +++ b/src/openai/types/responses/__init__.py @@ -22,6 +22,7 @@ from .web_search_tool import WebSearchTool as WebSearchTool from .file_search_tool import FileSearchTool as FileSearchTool from .tool_choice_types import ToolChoiceTypes as ToolChoiceTypes +from .easy_input_message import EasyInputMessage as EasyInputMessage from .response_item_list import ResponseItemList as ResponseItemList from .computer_tool_param import ComputerToolParam as ComputerToolParam from .function_tool_param import FunctionToolParam as FunctionToolParam @@ -117,6 +118,12 @@ from .response_input_message_content_list_param import ( ResponseInputMessageContentListParam as ResponseInputMessageContentListParam, ) +from .response_reasoning_summary_part_done_event import ( + ResponseReasoningSummaryPartDoneEvent as ResponseReasoningSummaryPartDoneEvent, +) +from .response_reasoning_summary_text_done_event import ( + ResponseReasoningSummaryTextDoneEvent as ResponseReasoningSummaryTextDoneEvent, +) from .response_web_search_call_in_progress_event import ( ResponseWebSearchCallInProgressEvent as ResponseWebSearchCallInProgressEvent, ) @@ -126,6 +133,12 @@ from .response_function_call_arguments_done_event import ( ResponseFunctionCallArgumentsDoneEvent as ResponseFunctionCallArgumentsDoneEvent, ) +from .response_reasoning_summary_part_added_event import ( + ResponseReasoningSummaryPartAddedEvent as ResponseReasoningSummaryPartAddedEvent, +) +from .response_reasoning_summary_text_delta_event import ( + ResponseReasoningSummaryTextDeltaEvent as ResponseReasoningSummaryTextDeltaEvent, +) from .response_function_call_arguments_delta_event import ( ResponseFunctionCallArgumentsDeltaEvent as ResponseFunctionCallArgumentsDeltaEvent, ) diff --git a/src/openai/types/responses/easy_input_message.py b/src/openai/types/responses/easy_input_message.py new file mode 100644 index 0000000000..4ed0194f9f --- /dev/null +++ b/src/openai/types/responses/easy_input_message.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union, Optional +from typing_extensions import Literal + +from ..._models import BaseModel +from .response_input_message_content_list import ResponseInputMessageContentList + +__all__ = ["EasyInputMessage"] + + +class EasyInputMessage(BaseModel): + content: Union[str, ResponseInputMessageContentList] + """ + Text, image, or audio input to the model, used to generate a response. Can also + contain previous assistant responses. + """ + + role: Literal["user", "assistant", "system", "developer"] + """The role of the message input. + + One of `user`, `assistant`, `system`, or `developer`. + """ + + type: Optional[Literal["message"]] = None + """The type of the message input. Always `message`.""" diff --git a/src/openai/types/responses/response_reasoning_summary_part_added_event.py b/src/openai/types/responses/response_reasoning_summary_part_added_event.py new file mode 100644 index 0000000000..fd11520170 --- /dev/null +++ b/src/openai/types/responses/response_reasoning_summary_part_added_event.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseReasoningSummaryPartAddedEvent", "Part"] + + +class Part(BaseModel): + text: str + """The text of the summary part.""" + + type: Literal["summary_text"] + """The type of the summary part. Always `summary_text`.""" + + +class ResponseReasoningSummaryPartAddedEvent(BaseModel): + item_id: str + """The ID of the item this summary part is associated with.""" + + output_index: int + """The index of the output item this summary part is associated with.""" + + part: Part + """The summary part that was added.""" + + summary_index: int + """The index of the summary part within the reasoning summary.""" + + type: Literal["response.reasoning_summary_part.added"] + """The type of the event. Always `response.reasoning_summary_part.added`.""" diff --git a/src/openai/types/responses/response_reasoning_summary_part_done_event.py b/src/openai/types/responses/response_reasoning_summary_part_done_event.py new file mode 100644 index 0000000000..7f30189a49 --- /dev/null +++ b/src/openai/types/responses/response_reasoning_summary_part_done_event.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseReasoningSummaryPartDoneEvent", "Part"] + + +class Part(BaseModel): + text: str + """The text of the summary part.""" + + type: Literal["summary_text"] + """The type of the summary part. Always `summary_text`.""" + + +class ResponseReasoningSummaryPartDoneEvent(BaseModel): + item_id: str + """The ID of the item this summary part is associated with.""" + + output_index: int + """The index of the output item this summary part is associated with.""" + + part: Part + """The completed summary part.""" + + summary_index: int + """The index of the summary part within the reasoning summary.""" + + type: Literal["response.reasoning_summary_part.done"] + """The type of the event. Always `response.reasoning_summary_part.done`.""" diff --git a/src/openai/types/responses/response_reasoning_summary_text_delta_event.py b/src/openai/types/responses/response_reasoning_summary_text_delta_event.py new file mode 100644 index 0000000000..6d0cbd8265 --- /dev/null +++ b/src/openai/types/responses/response_reasoning_summary_text_delta_event.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseReasoningSummaryTextDeltaEvent"] + + +class ResponseReasoningSummaryTextDeltaEvent(BaseModel): + delta: str + """The text delta that was added to the summary.""" + + item_id: str + """The ID of the item this summary text delta is associated with.""" + + output_index: int + """The index of the output item this summary text delta is associated with.""" + + summary_index: int + """The index of the summary part within the reasoning summary.""" + + type: Literal["response.reasoning_summary_text.delta"] + """The type of the event. Always `response.reasoning_summary_text.delta`.""" diff --git a/src/openai/types/responses/response_reasoning_summary_text_done_event.py b/src/openai/types/responses/response_reasoning_summary_text_done_event.py new file mode 100644 index 0000000000..15b894c75b --- /dev/null +++ b/src/openai/types/responses/response_reasoning_summary_text_done_event.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseReasoningSummaryTextDoneEvent"] + + +class ResponseReasoningSummaryTextDoneEvent(BaseModel): + item_id: str + """The ID of the item this summary text is associated with.""" + + output_index: int + """The index of the output item this summary text is associated with.""" + + summary_index: int + """The index of the summary part within the reasoning summary.""" + + text: str + """The full text of the completed reasoning summary.""" + + type: Literal["response.reasoning_summary_text.done"] + """The type of the event. Always `response.reasoning_summary_text.done`.""" diff --git a/src/openai/types/responses/response_stream_event.py b/src/openai/types/responses/response_stream_event.py index 446863b175..07c18bd217 100644 --- a/src/openai/types/responses/response_stream_event.py +++ b/src/openai/types/responses/response_stream_event.py @@ -27,9 +27,13 @@ from .response_web_search_call_searching_event import ResponseWebSearchCallSearchingEvent from .response_file_search_call_completed_event import ResponseFileSearchCallCompletedEvent from .response_file_search_call_searching_event import ResponseFileSearchCallSearchingEvent +from .response_reasoning_summary_part_done_event import ResponseReasoningSummaryPartDoneEvent +from .response_reasoning_summary_text_done_event import ResponseReasoningSummaryTextDoneEvent from .response_web_search_call_in_progress_event import ResponseWebSearchCallInProgressEvent from .response_file_search_call_in_progress_event import ResponseFileSearchCallInProgressEvent from .response_function_call_arguments_done_event import ResponseFunctionCallArgumentsDoneEvent +from .response_reasoning_summary_part_added_event import ResponseReasoningSummaryPartAddedEvent +from .response_reasoning_summary_text_delta_event import ResponseReasoningSummaryTextDeltaEvent from .response_function_call_arguments_delta_event import ResponseFunctionCallArgumentsDeltaEvent from .response_code_interpreter_call_code_done_event import ResponseCodeInterpreterCallCodeDoneEvent from .response_code_interpreter_call_completed_event import ResponseCodeInterpreterCallCompletedEvent @@ -65,6 +69,10 @@ ResponseIncompleteEvent, ResponseOutputItemAddedEvent, ResponseOutputItemDoneEvent, + ResponseReasoningSummaryPartAddedEvent, + ResponseReasoningSummaryPartDoneEvent, + ResponseReasoningSummaryTextDeltaEvent, + ResponseReasoningSummaryTextDoneEvent, ResponseRefusalDeltaEvent, ResponseRefusalDoneEvent, ResponseTextAnnotationDeltaEvent, diff --git a/tests/api_resources/fine_tuning/checkpoints/test_permissions.py b/tests/api_resources/fine_tuning/checkpoints/test_permissions.py index d40466919a..6aa0b867d9 100644 --- a/tests/api_resources/fine_tuning/checkpoints/test_permissions.py +++ b/tests/api_resources/fine_tuning/checkpoints/test_permissions.py @@ -117,19 +117,19 @@ def test_path_params_retrieve(self, client: OpenAI) -> None: fine_tuned_model_checkpoint="", ) - @pytest.mark.skip(reason="OpenAPI spec is slightly incorrect") @parametrize def test_method_delete(self, client: OpenAI) -> None: permission = client.fine_tuning.checkpoints.permissions.delete( - "ft:gpt-4o-mini-2024-07-18:org:weather:B7R9VjQd", + permission_id="cp_zc4Q7MP6XxulcVzj4MZdwsAB", + fine_tuned_model_checkpoint="ft:gpt-4o-mini-2024-07-18:org:weather:B7R9VjQd", ) assert_matches_type(PermissionDeleteResponse, permission, path=["response"]) - @pytest.mark.skip(reason="OpenAPI spec is slightly incorrect") @parametrize def test_raw_response_delete(self, client: OpenAI) -> None: response = client.fine_tuning.checkpoints.permissions.with_raw_response.delete( - "ft:gpt-4o-mini-2024-07-18:org:weather:B7R9VjQd", + permission_id="cp_zc4Q7MP6XxulcVzj4MZdwsAB", + fine_tuned_model_checkpoint="ft:gpt-4o-mini-2024-07-18:org:weather:B7R9VjQd", ) assert response.is_closed is True @@ -137,11 +137,11 @@ def test_raw_response_delete(self, client: OpenAI) -> None: permission = response.parse() assert_matches_type(PermissionDeleteResponse, permission, path=["response"]) - @pytest.mark.skip(reason="OpenAPI spec is slightly incorrect") @parametrize def test_streaming_response_delete(self, client: OpenAI) -> None: with client.fine_tuning.checkpoints.permissions.with_streaming_response.delete( - "ft:gpt-4o-mini-2024-07-18:org:weather:B7R9VjQd", + permission_id="cp_zc4Q7MP6XxulcVzj4MZdwsAB", + fine_tuned_model_checkpoint="ft:gpt-4o-mini-2024-07-18:org:weather:B7R9VjQd", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -151,14 +151,20 @@ def test_streaming_response_delete(self, client: OpenAI) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip(reason="OpenAPI spec is slightly incorrect") @parametrize def test_path_params_delete(self, client: OpenAI) -> None: with pytest.raises( ValueError, match=r"Expected a non-empty value for `fine_tuned_model_checkpoint` but received ''" ): client.fine_tuning.checkpoints.permissions.with_raw_response.delete( - "", + permission_id="cp_zc4Q7MP6XxulcVzj4MZdwsAB", + fine_tuned_model_checkpoint="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `permission_id` but received ''"): + client.fine_tuning.checkpoints.permissions.with_raw_response.delete( + permission_id="", + fine_tuned_model_checkpoint="ft:gpt-4o-mini-2024-07-18:org:weather:B7R9VjQd", ) @@ -260,19 +266,19 @@ async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: fine_tuned_model_checkpoint="", ) - @pytest.mark.skip(reason="OpenAPI spec is slightly incorrect") @parametrize async def test_method_delete(self, async_client: AsyncOpenAI) -> None: permission = await async_client.fine_tuning.checkpoints.permissions.delete( - "ft:gpt-4o-mini-2024-07-18:org:weather:B7R9VjQd", + permission_id="cp_zc4Q7MP6XxulcVzj4MZdwsAB", + fine_tuned_model_checkpoint="ft:gpt-4o-mini-2024-07-18:org:weather:B7R9VjQd", ) assert_matches_type(PermissionDeleteResponse, permission, path=["response"]) - @pytest.mark.skip(reason="OpenAPI spec is slightly incorrect") @parametrize async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: response = await async_client.fine_tuning.checkpoints.permissions.with_raw_response.delete( - "ft:gpt-4o-mini-2024-07-18:org:weather:B7R9VjQd", + permission_id="cp_zc4Q7MP6XxulcVzj4MZdwsAB", + fine_tuned_model_checkpoint="ft:gpt-4o-mini-2024-07-18:org:weather:B7R9VjQd", ) assert response.is_closed is True @@ -280,11 +286,11 @@ async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: permission = response.parse() assert_matches_type(PermissionDeleteResponse, permission, path=["response"]) - @pytest.mark.skip(reason="OpenAPI spec is slightly incorrect") @parametrize async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: async with async_client.fine_tuning.checkpoints.permissions.with_streaming_response.delete( - "ft:gpt-4o-mini-2024-07-18:org:weather:B7R9VjQd", + permission_id="cp_zc4Q7MP6XxulcVzj4MZdwsAB", + fine_tuned_model_checkpoint="ft:gpt-4o-mini-2024-07-18:org:weather:B7R9VjQd", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -294,12 +300,18 @@ async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> Non assert cast(Any, response.is_closed) is True - @pytest.mark.skip(reason="OpenAPI spec is slightly incorrect") @parametrize async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: with pytest.raises( ValueError, match=r"Expected a non-empty value for `fine_tuned_model_checkpoint` but received ''" ): await async_client.fine_tuning.checkpoints.permissions.with_raw_response.delete( - "", + permission_id="cp_zc4Q7MP6XxulcVzj4MZdwsAB", + fine_tuned_model_checkpoint="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `permission_id` but received ''"): + await async_client.fine_tuning.checkpoints.permissions.with_raw_response.delete( + permission_id="", + fine_tuned_model_checkpoint="ft:gpt-4o-mini-2024-07-18:org:weather:B7R9VjQd", ) diff --git a/tests/api_resources/test_evals.py b/tests/api_resources/test_evals.py index 8d03513b32..4ae2c597dd 100644 --- a/tests/api_resources/test_evals.py +++ b/tests/api_resources/test_evals.py @@ -74,7 +74,6 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: ], metadata={"foo": "string"}, name="name", - share_with_openai=True, ) assert_matches_type(EvalCreateResponse, eval, path=["response"]) @@ -350,7 +349,6 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> ], metadata={"foo": "string"}, name="name", - share_with_openai=True, ) assert_matches_type(EvalCreateResponse, eval, path=["response"]) diff --git a/tests/api_resources/test_images.py b/tests/api_resources/test_images.py index 0a88f2ebcf..7997e9f5a1 100644 --- a/tests/api_resources/test_images.py +++ b/tests/api_resources/test_images.py @@ -76,6 +76,7 @@ def test_method_edit_with_all_params(self, client: OpenAI) -> None: mask=b"raw file contents", model="string", n=1, + quality="high", response_format="url", size="1024x1024", user="user-1234", @@ -119,9 +120,13 @@ def test_method_generate(self, client: OpenAI) -> None: def test_method_generate_with_all_params(self, client: OpenAI) -> None: image = client.images.generate( prompt="A cute baby sea otter", + background="transparent", model="string", + moderation="low", n=1, - quality="standard", + output_compression=100, + output_format="png", + quality="medium", response_format="url", size="1024x1024", style="vivid", @@ -216,6 +221,7 @@ async def test_method_edit_with_all_params(self, async_client: AsyncOpenAI) -> N mask=b"raw file contents", model="string", n=1, + quality="high", response_format="url", size="1024x1024", user="user-1234", @@ -259,9 +265,13 @@ async def test_method_generate(self, async_client: AsyncOpenAI) -> None: async def test_method_generate_with_all_params(self, async_client: AsyncOpenAI) -> None: image = await async_client.images.generate( prompt="A cute baby sea otter", + background="transparent", model="string", + moderation="low", n=1, - quality="standard", + output_compression=100, + output_format="png", + quality="medium", response_format="url", size="1024x1024", style="vivid", From 8e1a1cd60d990361b934f922fd7d176f2ae0a63c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 23 Apr 2025 16:31:09 +0000 Subject: [PATCH 309/769] release: 1.76.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 25 +++++++++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index cb464946f0..df3aaa16a7 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.75.0" + ".": "1.76.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index fb077b91c3..73d8f2bf6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,30 @@ # Changelog +## 1.76.0 (2025-04-23) + +Full Changelog: [v1.75.0...v1.76.0](https://github.com/openai/openai-python/compare/v1.75.0...v1.76.0) + +### Features + +* **api:** adding new image model support ([74d7692](https://github.com/openai/openai-python/commit/74d7692e94c9dca96db8793809d75631c22dbb87)) + + +### Bug Fixes + +* **pydantic v1:** more robust `ModelField.annotation` check ([#2163](https://github.com/openai/openai-python/issues/2163)) ([7351b12](https://github.com/openai/openai-python/commit/7351b12bc981f56632b92342d9ef26f6fb28d540)) +* **pydantic v1:** more robust ModelField.annotation check ([eba7856](https://github.com/openai/openai-python/commit/eba7856db55afb8cb44376a0248587549f7bc65f)) + + +### Chores + +* **ci:** add timeout thresholds for CI jobs ([0997211](https://github.com/openai/openai-python/commit/09972119df5dd4c7c8db137c721364787e22d4c6)) +* **internal:** fix list file params ([da2113c](https://github.com/openai/openai-python/commit/da2113c60b50b4438459325fcd38d55df3f63d8e)) +* **internal:** import reformatting ([b425fb9](https://github.com/openai/openai-python/commit/b425fb906f62550c3669b09b9d8575f3d4d8496b)) +* **internal:** minor formatting changes ([aed1d76](https://github.com/openai/openai-python/commit/aed1d767898324cf90328db329e04e89a77579c3)) +* **internal:** refactor retries to not use recursion ([8cb8cfa](https://github.com/openai/openai-python/commit/8cb8cfab48a4fed70a756ce50036e7e56e1f9f87)) +* **internal:** update models test ([870ad4e](https://github.com/openai/openai-python/commit/870ad4ed3a284d75f44b825503750129284c7906)) +* update completion parse signature ([a44016c](https://github.com/openai/openai-python/commit/a44016c64cdefe404e97592808ed3c25411ab27b)) + ## 1.75.0 (2025-04-16) Full Changelog: [v1.74.1...v1.75.0](https://github.com/openai/openai-python/compare/v1.74.1...v1.75.0) diff --git a/pyproject.toml b/pyproject.toml index b5648e9e51..947e082f78 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.75.0" +version = "1.76.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 8eab2d7416..ea6b974272 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.75.0" # x-release-please-version +__version__ = "1.76.0" # x-release-please-version From c1ceebbd62400d66291173763f546a8a98f201ad Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 23 Apr 2025 19:07:40 +0000 Subject: [PATCH 310/769] chore(ci): run on more branches and use depot runners --- .github/workflows/ci.yml | 18 +++++++++--------- .github/workflows/publish-pypi.yml | 2 +- .github/workflows/release-doctor.yml | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d148b34a9e..bbf8a2c65a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,18 +1,18 @@ name: CI on: push: - branches: - - main - pull_request: - branches: - - main - - next + branches-ignore: + - 'generated' + - 'codegen/**' + - 'integrated/**' + - 'stl-preview-head/**' + - 'stl-preview-base/**' jobs: lint: timeout-minutes: 10 name: lint - runs-on: ubuntu-latest + runs-on: depot-ubuntu-24.04 steps: - uses: actions/checkout@v4 @@ -33,7 +33,7 @@ jobs: test: timeout-minutes: 10 name: test - runs-on: ubuntu-latest + runs-on: depot-ubuntu-24.04 steps: - uses: actions/checkout@v4 @@ -54,7 +54,7 @@ jobs: examples: timeout-minutes: 10 name: examples - runs-on: ubuntu-latest + runs-on: depot-ubuntu-24.04 if: github.repository == 'openai/openai-python' steps: diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml index 32bd6929e2..d669229973 100644 --- a/.github/workflows/publish-pypi.yml +++ b/.github/workflows/publish-pypi.yml @@ -7,7 +7,7 @@ on: jobs: publish: name: publish - runs-on: ubuntu-latest + runs-on: depot-ubuntu-24.04 environment: publish steps: diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml index e078964a6f..be17b9c07f 100644 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -8,7 +8,7 @@ on: jobs: release_doctor: name: release doctor - runs-on: ubuntu-latest + runs-on: depot-ubuntu-24.04 environment: publish if: github.repository == 'openai/openai-python' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next') From c9cedd8a47290ff2c95c54c1528fbc7202f6b523 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 23 Apr 2025 20:00:18 +0000 Subject: [PATCH 311/769] chore(ci): only use depot for staging repos --- .github/workflows/ci.yml | 6 +++--- .github/workflows/publish-pypi.yml | 2 +- .github/workflows/release-doctor.yml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bbf8a2c65a..e1e21f3fae 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: lint: timeout-minutes: 10 name: lint - runs-on: depot-ubuntu-24.04 + runs-on: ${{ github.repository == 'stainless-sdks/openai-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} steps: - uses: actions/checkout@v4 @@ -33,7 +33,7 @@ jobs: test: timeout-minutes: 10 name: test - runs-on: depot-ubuntu-24.04 + runs-on: ${{ github.repository == 'stainless-sdks/openai-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} steps: - uses: actions/checkout@v4 @@ -54,7 +54,7 @@ jobs: examples: timeout-minutes: 10 name: examples - runs-on: depot-ubuntu-24.04 + runs-on: ${{ github.repository == 'stainless-sdks/openai-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: github.repository == 'openai/openai-python' steps: diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml index d669229973..32bd6929e2 100644 --- a/.github/workflows/publish-pypi.yml +++ b/.github/workflows/publish-pypi.yml @@ -7,7 +7,7 @@ on: jobs: publish: name: publish - runs-on: depot-ubuntu-24.04 + runs-on: ubuntu-latest environment: publish steps: diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml index be17b9c07f..e078964a6f 100644 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -8,7 +8,7 @@ on: jobs: release_doctor: name: release doctor - runs-on: depot-ubuntu-24.04 + runs-on: ubuntu-latest environment: publish if: github.repository == 'openai/openai-python' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next') From 761be76cb7512de232b1892f8915cd022bee040a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 23 Apr 2025 22:08:18 +0000 Subject: [PATCH 312/769] chore: broadly detect json family of content-type headers --- src/openai/_legacy_response.py | 2 +- src/openai/_response.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/openai/_legacy_response.py b/src/openai/_legacy_response.py index 8880e5f104..cfabaa2fc2 100644 --- a/src/openai/_legacy_response.py +++ b/src/openai/_legacy_response.py @@ -304,7 +304,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: # split is required to handle cases where additional information is included # in the response, e.g. application/json; charset=utf-8 content_type, *_ = response.headers.get("content-type", "*").split(";") - if content_type != "application/json": + if not content_type.endswith("json"): if is_basemodel(cast_to): try: data = response.json() diff --git a/src/openai/_response.py b/src/openai/_response.py index 95e94e6537..350da38dd4 100644 --- a/src/openai/_response.py +++ b/src/openai/_response.py @@ -237,7 +237,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: # split is required to handle cases where additional information is included # in the response, e.g. application/json; charset=utf-8 content_type, *_ = response.headers.get("content-type", "*").split(";") - if content_type != "application/json": + if not content_type.endswith("json"): if is_basemodel(cast_to): try: data = response.json() From b75f4093026265d7a3f0c38998a3360f03bf44f4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 29 Apr 2025 05:03:55 +0000 Subject: [PATCH 313/769] release: 1.76.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 10 ++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index df3aaa16a7..0c3ec30cf9 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.76.0" + ".": "1.76.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 73d8f2bf6e..1c5b507e43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## 1.76.1 (2025-04-29) + +Full Changelog: [v1.76.0...v1.76.1](https://github.com/openai/openai-python/compare/v1.76.0...v1.76.1) + +### Chores + +* broadly detect json family of content-type headers ([b4b1b08](https://github.com/openai/openai-python/commit/b4b1b086b512eecc0ada7fc1efa45eb506982f13)) +* **ci:** only use depot for staging repos ([35312d8](https://github.com/openai/openai-python/commit/35312d80e6bbc1a61d06ad253af9a713b5ef040c)) +* **ci:** run on more branches and use depot runners ([a6a45d4](https://github.com/openai/openai-python/commit/a6a45d4af8a4d904b37573a9b223d56106b4887d)) + ## 1.76.0 (2025-04-23) Full Changelog: [v1.75.0...v1.76.0](https://github.com/openai/openai-python/compare/v1.75.0...v1.76.0) diff --git a/pyproject.toml b/pyproject.toml index 947e082f78..570e59ec67 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.76.0" +version = "1.76.1" 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 ea6b974272..77a1b26c42 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.76.0" # x-release-please-version +__version__ = "1.76.1" # x-release-please-version From a6460677e956762d1b9cdb59cdc5e161cd5ea370 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 29 Apr 2025 19:58:55 +0000 Subject: [PATCH 314/769] chore(api): API spec cleanup --- src/openai/lib/streaming/responses/_events.py | 8 ++++++++ src/openai/resources/beta/threads/threads.py | 16 ++++++++-------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/openai/lib/streaming/responses/_events.py b/src/openai/lib/streaming/responses/_events.py index fe17edf649..0cdc5992ee 100644 --- a/src/openai/lib/streaming/responses/_events.py +++ b/src/openai/lib/streaming/responses/_events.py @@ -32,7 +32,11 @@ ResponseFileSearchCallSearchingEvent, ResponseWebSearchCallInProgressEvent, ResponseFileSearchCallInProgressEvent, + ResponseReasoningSummaryPartDoneEvent, + ResponseReasoningSummaryTextDoneEvent, ResponseFunctionCallArgumentsDoneEvent, + ResponseReasoningSummaryPartAddedEvent, + ResponseReasoningSummaryTextDeltaEvent, ResponseFunctionCallArgumentsDeltaEvent as RawResponseFunctionCallArgumentsDeltaEvent, ResponseCodeInterpreterCallCodeDoneEvent, ResponseCodeInterpreterCallCodeDeltaEvent, @@ -101,6 +105,10 @@ class ResponseCompletedEvent(RawResponseCompletedEvent, GenericModel, Generic[Te ResponseWebSearchCallCompletedEvent, ResponseWebSearchCallInProgressEvent, ResponseWebSearchCallSearchingEvent, + ResponseReasoningSummaryPartAddedEvent, + ResponseReasoningSummaryPartDoneEvent, + ResponseReasoningSummaryTextDeltaEvent, + ResponseReasoningSummaryTextDoneEvent, ], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/resources/beta/threads/threads.py b/src/openai/resources/beta/threads/threads.py index 22dc5fe0ea..13d8cb6411 100644 --- a/src/openai/resources/beta/threads/threads.py +++ b/src/openai/resources/beta/threads/threads.py @@ -741,7 +741,7 @@ def create_and_run_poll( thread: thread_create_and_run_params.Thread | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[thread_create_and_run_params.Tool]] | NotGiven = NOT_GIVEN, + tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, poll_interval_ms: int | NotGiven = NOT_GIVEN, @@ -797,7 +797,7 @@ def create_and_run_stream( thread: thread_create_and_run_params.Thread | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[thread_create_and_run_params.Tool]] | NotGiven = NOT_GIVEN, + tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -826,7 +826,7 @@ def create_and_run_stream( thread: thread_create_and_run_params.Thread | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[thread_create_and_run_params.Tool]] | NotGiven = NOT_GIVEN, + tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, event_handler: AssistantEventHandlerT, @@ -855,7 +855,7 @@ def create_and_run_stream( thread: thread_create_and_run_params.Thread | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[thread_create_and_run_params.Tool]] | NotGiven = NOT_GIVEN, + tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, event_handler: AssistantEventHandlerT | None = None, @@ -1590,7 +1590,7 @@ async def create_and_run_poll( thread: thread_create_and_run_params.Thread | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[thread_create_and_run_params.Tool]] | NotGiven = NOT_GIVEN, + tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, poll_interval_ms: int | NotGiven = NOT_GIVEN, @@ -1648,7 +1648,7 @@ def create_and_run_stream( thread: thread_create_and_run_params.Thread | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[thread_create_and_run_params.Tool]] | NotGiven = NOT_GIVEN, + tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -1677,7 +1677,7 @@ def create_and_run_stream( thread: thread_create_and_run_params.Thread | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[thread_create_and_run_params.Tool]] | NotGiven = NOT_GIVEN, + tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, event_handler: AsyncAssistantEventHandlerT, @@ -1706,7 +1706,7 @@ def create_and_run_stream( thread: thread_create_and_run_params.Thread | NotGiven = NOT_GIVEN, tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[thread_create_and_run_params.Tool]] | NotGiven = NOT_GIVEN, + tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, event_handler: AsyncAssistantEventHandlerT | None = None, From fad098ffad7982a5150306a3d17f51ffef574f2e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 29 Apr 2025 19:59:25 +0000 Subject: [PATCH 315/769] release: 1.76.2 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 0c3ec30cf9..8bcd8a5b4f 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.76.1" + ".": "1.76.2" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c5b507e43..bc85128f6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.76.2 (2025-04-29) + +Full Changelog: [v1.76.1...v1.76.2](https://github.com/openai/openai-python/compare/v1.76.1...v1.76.2) + +### Chores + +* **api:** API spec cleanup ([0a4d3e2](https://github.com/openai/openai-python/commit/0a4d3e2b495d22dd42ce1773b870554c64f9b3b2)) + ## 1.76.1 (2025-04-29) Full Changelog: [v1.76.0...v1.76.1](https://github.com/openai/openai-python/compare/v1.76.0...v1.76.1) diff --git a/pyproject.toml b/pyproject.toml index 570e59ec67..2c3c3eaf3b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.76.1" +version = "1.76.2" 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 77a1b26c42..ef1e3fe526 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.76.1" # x-release-please-version +__version__ = "1.76.2" # x-release-please-version From b3f0daf3dbc344998b09762615a59d80621d7921 Mon Sep 17 00:00:00 2001 From: Pon Pongwachirin <138108569+maesta7@users.noreply.github.com> Date: Wed, 30 Apr 2025 22:46:30 +0700 Subject: [PATCH 316/769] fix(parsing): handle whitespace only strings (#2007) * fix: add a check to handle empty or newline-only strings before calling `from_json` * style: adjust comment format for better readability Co-authored-by: Robert Craigie --------- Co-authored-by: SenorSpes <138108569+senorNox@users.noreply.github.com> Co-authored-by: Robert Craigie --- src/openai/lib/streaming/chat/_completions.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/openai/lib/streaming/chat/_completions.py b/src/openai/lib/streaming/chat/_completions.py index f147696cca..6177ffbed2 100644 --- a/src/openai/lib/streaming/chat/_completions.py +++ b/src/openai/lib/streaming/chat/_completions.py @@ -438,6 +438,8 @@ def _accumulate_chunk(self, chunk: ChatCompletionChunk) -> ParsedChatCompletionS choice_snapshot.message.content and not choice_snapshot.message.refusal and is_given(self._rich_response_format) + # partial parsing fails on white-space + and choice_snapshot.message.content.strip() ): choice_snapshot.message.parsed = from_json( bytes(choice_snapshot.message.content, "utf-8"), From 4fc52529439c05ace100e05bf07f5e3d23abbc5b Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Wed, 30 Apr 2025 11:47:27 -0400 Subject: [PATCH 317/769] chore: only strip leading whitespace --- src/openai/lib/streaming/chat/_completions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openai/lib/streaming/chat/_completions.py b/src/openai/lib/streaming/chat/_completions.py index 6177ffbed2..a7b70c32d3 100644 --- a/src/openai/lib/streaming/chat/_completions.py +++ b/src/openai/lib/streaming/chat/_completions.py @@ -439,7 +439,7 @@ def _accumulate_chunk(self, chunk: ChatCompletionChunk) -> ParsedChatCompletionS and not choice_snapshot.message.refusal and is_given(self._rich_response_format) # partial parsing fails on white-space - and choice_snapshot.message.content.strip() + and choice_snapshot.message.content.lstrip() ): choice_snapshot.message.parsed = from_json( bytes(choice_snapshot.message.content, "utf-8"), From b8a3720ed6157dff5100c9a36f8d51fe47a2994c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 2 May 2025 19:09:24 +0000 Subject: [PATCH 318/769] feat(api): add image sizes, reasoning encryption --- .stats.yml | 6 +-- src/openai/resources/audio/speech.py | 4 +- src/openai/resources/images.py | 48 +++++++++++++++---- src/openai/resources/responses/responses.py | 30 ++++++++++++ .../types/audio/speech_create_params.py | 3 +- src/openai/types/image_edit_params.py | 24 +++++++--- src/openai/types/responses/computer_tool.py | 6 +-- .../types/responses/computer_tool_param.py | 6 +-- .../types/responses/file_search_tool.py | 12 ++--- .../types/responses/file_search_tool_param.py | 14 +++--- src/openai/types/responses/function_tool.py | 4 +- .../types/responses/function_tool_param.py | 4 +- .../types/responses/response_create_params.py | 5 ++ .../types/responses/response_includable.py | 5 +- .../responses/response_input_file_param.py | 3 +- .../types/responses/response_input_image.py | 2 +- .../responses/response_input_image_param.py | 2 +- .../responses/response_input_item_param.py | 18 +++---- .../types/responses/response_input_param.py | 18 +++---- .../responses/response_reasoning_item.py | 6 +++ .../response_reasoning_item_param.py | 8 +++- src/openai/types/responses/tool.py | 2 +- src/openai/types/responses/tool_param.py | 2 +- src/openai/types/responses/web_search_tool.py | 13 ++--- .../types/responses/web_search_tool_param.py | 21 ++++---- tests/api_resources/test_images.py | 2 + 26 files changed, 182 insertions(+), 86 deletions(-) diff --git a/.stats.yml b/.stats.yml index d92408173b..0c8278866d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 97 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-8b68ae6b807dca92e914da1dd9e835a20f69b075e79102a264367fd7fddddb33.yml -openapi_spec_hash: b6ade5b1a6327339e6669e1134de2d03 -config_hash: b597cd9a31e9e5ec709e2eefb4c54122 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-0ee6b36cf3cc278cef4199a6aec5f7d530a6c1f17a74830037e96d50ca1edc50.yml +openapi_spec_hash: e8ec5f46bc0655b34f292422d58a60f6 +config_hash: d9b6b6e6bc85744663e300eebc482067 diff --git a/src/openai/resources/audio/speech.py b/src/openai/resources/audio/speech.py index fad18dcdf5..a195d7135e 100644 --- a/src/openai/resources/audio/speech.py +++ b/src/openai/resources/audio/speech.py @@ -85,7 +85,7 @@ def create( `wav`, and `pcm`. speed: The speed of the generated audio. Select a value from `0.25` to `4.0`. `1.0` is - the default. + the default. Does not work with `gpt-4o-mini-tts`. extra_headers: Send extra headers @@ -176,7 +176,7 @@ async def create( `wav`, and `pcm`. speed: The speed of the generated audio. Select a value from `0.25` to `4.0`. `1.0` is - the default. + the default. Does not work with `gpt-4o-mini-tts`. extra_headers: Send extra headers diff --git a/src/openai/resources/images.py b/src/openai/resources/images.py index e59d0ce35c..524bebacae 100644 --- a/src/openai/resources/images.py +++ b/src/openai/resources/images.py @@ -119,12 +119,14 @@ def edit( *, image: Union[FileTypes, List[FileTypes]], prompt: str, + background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, mask: FileTypes | NotGiven = NOT_GIVEN, model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, - size: Optional[Literal["256x256", "512x512", "1024x1024"]] | NotGiven = NOT_GIVEN, + size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] + | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -139,14 +141,25 @@ def edit( This endpoint only supports `gpt-image-1` and `dall-e-2`. Args: - image: The image(s) to edit. Must be a supported image file or an array of images. For - `gpt-image-1`, each image should be a `png`, `webp`, or `jpg` file less than - 25MB. For `dall-e-2`, you can only provide one image, and it should be a square - `png` file less than 4MB. + image: The image(s) to edit. Must be a supported image file or an array of images. + + For `gpt-image-1`, each image should be a `png`, `webp`, or `jpg` file less than + 25MB. You can provide up to 16 images. + + For `dall-e-2`, you can only provide one image, and it should be a square `png` + file less than 4MB. prompt: A text description of the desired image(s). The maximum length is 1000 characters for `dall-e-2`, and 32000 characters for `gpt-image-1`. + background: Allows to set transparency for the background of the generated image(s). This + parameter is only supported for `gpt-image-1`. Must be one of `transparent`, + `opaque` or `auto` (default value). When `auto` is used, the model will + automatically determine the best background for the image. + + If `transparent`, the output format needs to support transparency, so it should + be set to either `png` (default value) or `webp`. + mask: An additional image whose fully transparent areas (e.g. where alpha is zero) indicate where `image` should be edited. If there are multiple images provided, the mask will be applied on the first image. Must be a valid PNG file, less than @@ -187,6 +200,7 @@ def edit( { "image": image, "prompt": prompt, + "background": background, "mask": mask, "model": model, "n": n, @@ -429,12 +443,14 @@ async def edit( *, image: Union[FileTypes, List[FileTypes]], prompt: str, + background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, mask: FileTypes | NotGiven = NOT_GIVEN, model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, - size: Optional[Literal["256x256", "512x512", "1024x1024"]] | NotGiven = NOT_GIVEN, + size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] + | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -449,14 +465,25 @@ async def edit( This endpoint only supports `gpt-image-1` and `dall-e-2`. Args: - image: The image(s) to edit. Must be a supported image file or an array of images. For - `gpt-image-1`, each image should be a `png`, `webp`, or `jpg` file less than - 25MB. For `dall-e-2`, you can only provide one image, and it should be a square - `png` file less than 4MB. + image: The image(s) to edit. Must be a supported image file or an array of images. + + For `gpt-image-1`, each image should be a `png`, `webp`, or `jpg` file less than + 25MB. You can provide up to 16 images. + + For `dall-e-2`, you can only provide one image, and it should be a square `png` + file less than 4MB. prompt: A text description of the desired image(s). The maximum length is 1000 characters for `dall-e-2`, and 32000 characters for `gpt-image-1`. + background: Allows to set transparency for the background of the generated image(s). This + parameter is only supported for `gpt-image-1`. Must be one of `transparent`, + `opaque` or `auto` (default value). When `auto` is used, the model will + automatically determine the best background for the image. + + If `transparent`, the output format needs to support transparency, so it should + be set to either `png` (default value) or `webp`. + mask: An additional image whose fully transparent areas (e.g. where alpha is zero) indicate where `image` should be edited. If there are multiple images provided, the mask will be applied on the first image. Must be a valid PNG file, less than @@ -497,6 +524,7 @@ async def edit( { "image": image, "prompt": prompt, + "background": background, "mask": mask, "model": model, "n": n, diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 4a0687f9f3..a905bc34b1 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -140,6 +140,11 @@ def create( - `message.input_image.image_url`: Include image urls from the input message. - `computer_call_output.output.image_url`: Include image urls from the computer call output. + - `reasoning.encrypted_content`: Includes an encrypted version of reasoning + tokens in reasoning item outputs. This enables reasoning items to be used in + multi-turn conversations when using the Responses API statelessly (like when + the `store` parameter is set to `false`, or when an organization is enrolled + in the zero data retention program). instructions: Inserts a system (or developer) message as the first item in the model's context. @@ -331,6 +336,11 @@ def create( - `message.input_image.image_url`: Include image urls from the input message. - `computer_call_output.output.image_url`: Include image urls from the computer call output. + - `reasoning.encrypted_content`: Includes an encrypted version of reasoning + tokens in reasoning item outputs. This enables reasoning items to be used in + multi-turn conversations when using the Responses API statelessly (like when + the `store` parameter is set to `false`, or when an organization is enrolled + in the zero data retention program). instructions: Inserts a system (or developer) message as the first item in the model's context. @@ -515,6 +525,11 @@ def create( - `message.input_image.image_url`: Include image urls from the input message. - `computer_call_output.output.image_url`: Include image urls from the computer call output. + - `reasoning.encrypted_content`: Includes an encrypted version of reasoning + tokens in reasoning item outputs. This enables reasoning items to be used in + multi-turn conversations when using the Responses API statelessly (like when + the `store` parameter is set to `false`, or when an organization is enrolled + in the zero data retention program). instructions: Inserts a system (or developer) message as the first item in the model's context. @@ -1013,6 +1028,11 @@ async def create( - `message.input_image.image_url`: Include image urls from the input message. - `computer_call_output.output.image_url`: Include image urls from the computer call output. + - `reasoning.encrypted_content`: Includes an encrypted version of reasoning + tokens in reasoning item outputs. This enables reasoning items to be used in + multi-turn conversations when using the Responses API statelessly (like when + the `store` parameter is set to `false`, or when an organization is enrolled + in the zero data retention program). instructions: Inserts a system (or developer) message as the first item in the model's context. @@ -1204,6 +1224,11 @@ async def create( - `message.input_image.image_url`: Include image urls from the input message. - `computer_call_output.output.image_url`: Include image urls from the computer call output. + - `reasoning.encrypted_content`: Includes an encrypted version of reasoning + tokens in reasoning item outputs. This enables reasoning items to be used in + multi-turn conversations when using the Responses API statelessly (like when + the `store` parameter is set to `false`, or when an organization is enrolled + in the zero data retention program). instructions: Inserts a system (or developer) message as the first item in the model's context. @@ -1388,6 +1413,11 @@ async def create( - `message.input_image.image_url`: Include image urls from the input message. - `computer_call_output.output.image_url`: Include image urls from the computer call output. + - `reasoning.encrypted_content`: Includes an encrypted version of reasoning + tokens in reasoning item outputs. This enables reasoning items to be used in + multi-turn conversations when using the Responses API statelessly (like when + the `store` parameter is set to `false`, or when an organization is enrolled + in the zero data retention program). instructions: Inserts a system (or developer) message as the first item in the model's context. diff --git a/src/openai/types/audio/speech_create_params.py b/src/openai/types/audio/speech_create_params.py index a4fc020532..905ca5c3a8 100644 --- a/src/openai/types/audio/speech_create_params.py +++ b/src/openai/types/audio/speech_create_params.py @@ -48,5 +48,6 @@ class SpeechCreateParams(TypedDict, total=False): speed: float """The speed of the generated audio. - Select a value from `0.25` to `4.0`. `1.0` is the default. + Select a value from `0.25` to `4.0`. `1.0` is the default. Does not work with + `gpt-4o-mini-tts`. """ diff --git a/src/openai/types/image_edit_params.py b/src/openai/types/image_edit_params.py index f01a12c1b0..6294e8ac19 100644 --- a/src/openai/types/image_edit_params.py +++ b/src/openai/types/image_edit_params.py @@ -13,12 +13,13 @@ class ImageEditParams(TypedDict, total=False): image: Required[Union[FileTypes, List[FileTypes]]] - """The image(s) to edit. + """The image(s) to edit. Must be a supported image file or an array of images. - Must be a supported image file or an array of images. For `gpt-image-1`, each - image should be a `png`, `webp`, or `jpg` file less than 25MB. For `dall-e-2`, - you can only provide one image, and it should be a square `png` file less than - 4MB. + For `gpt-image-1`, each image should be a `png`, `webp`, or `jpg` file less than + 25MB. You can provide up to 16 images. + + For `dall-e-2`, you can only provide one image, and it should be a square `png` + file less than 4MB. """ prompt: Required[str] @@ -28,6 +29,17 @@ class ImageEditParams(TypedDict, total=False): `gpt-image-1`. """ + background: Optional[Literal["transparent", "opaque", "auto"]] + """Allows to set transparency for the background of the generated image(s). + + This parameter is only supported for `gpt-image-1`. Must be one of + `transparent`, `opaque` or `auto` (default value). When `auto` is used, the + model will automatically determine the best background for the image. + + If `transparent`, the output format needs to support transparency, so it should + be set to either `png` (default value) or `webp`. + """ + mask: FileTypes """An additional image whose fully transparent areas (e.g. @@ -61,7 +73,7 @@ class ImageEditParams(TypedDict, total=False): `gpt-image-1` will always return base64-encoded images. """ - size: Optional[Literal["256x256", "512x512", "1024x1024"]] + size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] """The size of the generated images. Must be one of `1024x1024`, `1536x1024` (landscape), `1024x1536` (portrait), or diff --git a/src/openai/types/responses/computer_tool.py b/src/openai/types/responses/computer_tool.py index dffb7af7b7..5b844f5bf4 100644 --- a/src/openai/types/responses/computer_tool.py +++ b/src/openai/types/responses/computer_tool.py @@ -8,13 +8,13 @@ class ComputerTool(BaseModel): - display_height: float + display_height: int """The height of the computer display.""" - display_width: float + display_width: int """The width of the computer display.""" - environment: Literal["mac", "windows", "ubuntu", "browser"] + environment: Literal["windows", "mac", "linux", "ubuntu", "browser"] """The type of computer environment to control.""" type: Literal["computer_use_preview"] diff --git a/src/openai/types/responses/computer_tool_param.py b/src/openai/types/responses/computer_tool_param.py index 6b1072ffd2..06a5c132ec 100644 --- a/src/openai/types/responses/computer_tool_param.py +++ b/src/openai/types/responses/computer_tool_param.py @@ -8,13 +8,13 @@ class ComputerToolParam(TypedDict, total=False): - display_height: Required[float] + display_height: Required[int] """The height of the computer display.""" - display_width: Required[float] + display_width: Required[int] """The width of the computer display.""" - environment: Required[Literal["mac", "windows", "ubuntu", "browser"]] + environment: Required[Literal["windows", "mac", "linux", "ubuntu", "browser"]] """The type of computer environment to control.""" type: Required[Literal["computer_use_preview"]] diff --git a/src/openai/types/responses/file_search_tool.py b/src/openai/types/responses/file_search_tool.py index 683fc533fe..dbdd8cffab 100644 --- a/src/openai/types/responses/file_search_tool.py +++ b/src/openai/types/responses/file_search_tool.py @@ -9,7 +9,7 @@ __all__ = ["FileSearchTool", "Filters", "RankingOptions"] -Filters: TypeAlias = Union[ComparisonFilter, CompoundFilter] +Filters: TypeAlias = Union[ComparisonFilter, CompoundFilter, None] class RankingOptions(BaseModel): @@ -17,10 +17,10 @@ class RankingOptions(BaseModel): """The ranker to use for the file search.""" score_threshold: Optional[float] = None - """ - The score threshold for the file search, a number between 0 and 1. Numbers - closer to 1 will attempt to return only the most relevant results, but may - return fewer results. + """The score threshold for the file search, a number between 0 and 1. + + Numbers closer to 1 will attempt to return only the most relevant results, but + may return fewer results. """ @@ -32,7 +32,7 @@ class FileSearchTool(BaseModel): """The IDs of the vector stores to search.""" filters: Optional[Filters] = None - """A filter to apply based on file attributes.""" + """A filter to apply.""" max_num_results: Optional[int] = None """The maximum number of results to return. diff --git a/src/openai/types/responses/file_search_tool_param.py b/src/openai/types/responses/file_search_tool_param.py index 2d6af8536b..2851fae460 100644 --- a/src/openai/types/responses/file_search_tool_param.py +++ b/src/openai/types/responses/file_search_tool_param.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import List, Union +from typing import List, Union, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict from ..shared_params.compound_filter import CompoundFilter @@ -18,10 +18,10 @@ class RankingOptions(TypedDict, total=False): """The ranker to use for the file search.""" score_threshold: float - """ - The score threshold for the file search, a number between 0 and 1. Numbers - closer to 1 will attempt to return only the most relevant results, but may - return fewer results. + """The score threshold for the file search, a number between 0 and 1. + + Numbers closer to 1 will attempt to return only the most relevant results, but + may return fewer results. """ @@ -32,8 +32,8 @@ class FileSearchToolParam(TypedDict, total=False): vector_store_ids: Required[List[str]] """The IDs of the vector stores to search.""" - filters: Filters - """A filter to apply based on file attributes.""" + filters: Optional[Filters] + """A filter to apply.""" max_num_results: int """The maximum number of results to return. diff --git a/src/openai/types/responses/function_tool.py b/src/openai/types/responses/function_tool.py index 236a2c7c63..d881565356 100644 --- a/src/openai/types/responses/function_tool.py +++ b/src/openai/types/responses/function_tool.py @@ -12,10 +12,10 @@ class FunctionTool(BaseModel): name: str """The name of the function to call.""" - parameters: Dict[str, object] + parameters: Optional[Dict[str, object]] = None """A JSON schema object describing the parameters of the function.""" - strict: bool + strict: Optional[bool] = None """Whether to enforce strict parameter validation. Default `true`.""" type: Literal["function"] diff --git a/src/openai/types/responses/function_tool_param.py b/src/openai/types/responses/function_tool_param.py index 774a22e336..56bab36f47 100644 --- a/src/openai/types/responses/function_tool_param.py +++ b/src/openai/types/responses/function_tool_param.py @@ -12,10 +12,10 @@ class FunctionToolParam(TypedDict, total=False): name: Required[str] """The name of the function to call.""" - parameters: Required[Dict[str, object]] + parameters: Required[Optional[Dict[str, object]]] """A JSON schema object describing the parameters of the function.""" - strict: Required[bool] + strict: Required[Optional[bool]] """Whether to enforce strict parameter validation. Default `true`.""" type: Required[Literal["function"]] diff --git a/src/openai/types/responses/response_create_params.py b/src/openai/types/responses/response_create_params.py index 3c0a9d7b8a..972d413926 100644 --- a/src/openai/types/responses/response_create_params.py +++ b/src/openai/types/responses/response_create_params.py @@ -56,6 +56,11 @@ class ResponseCreateParamsBase(TypedDict, total=False): - `message.input_image.image_url`: Include image urls from the input message. - `computer_call_output.output.image_url`: Include image urls from the computer call output. + - `reasoning.encrypted_content`: Includes an encrypted version of reasoning + tokens in reasoning item outputs. This enables reasoning items to be used in + multi-turn conversations when using the Responses API statelessly (like when + the `store` parameter is set to `false`, or when an organization is enrolled + in the zero data retention program). """ instructions: Optional[str] diff --git a/src/openai/types/responses/response_includable.py b/src/openai/types/responses/response_includable.py index 83489fa7f1..a01dddd71d 100644 --- a/src/openai/types/responses/response_includable.py +++ b/src/openai/types/responses/response_includable.py @@ -5,5 +5,8 @@ __all__ = ["ResponseIncludable"] ResponseIncludable: TypeAlias = Literal[ - "file_search_call.results", "message.input_image.image_url", "computer_call_output.output.image_url" + "file_search_call.results", + "message.input_image.image_url", + "computer_call_output.output.image_url", + "reasoning.encrypted_content", ] diff --git a/src/openai/types/responses/response_input_file_param.py b/src/openai/types/responses/response_input_file_param.py index dc06a4ea2d..61ae46f0cb 100644 --- a/src/openai/types/responses/response_input_file_param.py +++ b/src/openai/types/responses/response_input_file_param.py @@ -2,6 +2,7 @@ from __future__ import annotations +from typing import Optional from typing_extensions import Literal, Required, TypedDict __all__ = ["ResponseInputFileParam"] @@ -14,7 +15,7 @@ class ResponseInputFileParam(TypedDict, total=False): file_data: str """The content of the file to be sent to the model.""" - file_id: str + file_id: Optional[str] """The ID of the file to be sent to the model.""" filename: str diff --git a/src/openai/types/responses/response_input_image.py b/src/openai/types/responses/response_input_image.py index d719f44e9b..f2d760b25e 100644 --- a/src/openai/types/responses/response_input_image.py +++ b/src/openai/types/responses/response_input_image.py @@ -9,7 +9,7 @@ class ResponseInputImage(BaseModel): - detail: Literal["high", "low", "auto"] + detail: Literal["low", "high", "auto"] """The detail level of the image to be sent to the model. One of `high`, `low`, or `auto`. Defaults to `auto`. diff --git a/src/openai/types/responses/response_input_image_param.py b/src/openai/types/responses/response_input_image_param.py index 5dd4db2b5d..bc17e4f1c2 100644 --- a/src/openai/types/responses/response_input_image_param.py +++ b/src/openai/types/responses/response_input_image_param.py @@ -9,7 +9,7 @@ class ResponseInputImageParam(TypedDict, total=False): - detail: Required[Literal["high", "low", "auto"]] + detail: Required[Literal["low", "high", "auto"]] """The detail level of the image to be sent to the model. One of `high`, `low`, or `auto`. Defaults to `auto`. diff --git a/src/openai/types/responses/response_input_item_param.py b/src/openai/types/responses/response_input_item_param.py index 2505f7c0b5..290953a0ef 100644 --- a/src/openai/types/responses/response_input_item_param.py +++ b/src/openai/types/responses/response_input_item_param.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Union, Iterable +from typing import Union, Iterable, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict from .easy_input_message_param import EasyInputMessageParam @@ -50,10 +50,10 @@ class ComputerCallOutputAcknowledgedSafetyCheck(TypedDict, total=False): id: Required[str] """The ID of the pending safety check.""" - code: Required[str] + code: Optional[str] """The type of the pending safety check.""" - message: Required[str] + message: Optional[str] """Details about the pending safety check.""" @@ -67,16 +67,16 @@ class ComputerCallOutput(TypedDict, total=False): type: Required[Literal["computer_call_output"]] """The type of the computer tool call output. Always `computer_call_output`.""" - id: str + id: Optional[str] """The ID of the computer tool call output.""" - acknowledged_safety_checks: Iterable[ComputerCallOutputAcknowledgedSafetyCheck] + acknowledged_safety_checks: Optional[Iterable[ComputerCallOutputAcknowledgedSafetyCheck]] """ The safety checks reported by the API that have been acknowledged by the developer. """ - status: Literal["in_progress", "completed", "incomplete"] + status: Optional[Literal["in_progress", "completed", "incomplete"]] """The status of the message input. One of `in_progress`, `completed`, or `incomplete`. Populated when input items @@ -94,13 +94,13 @@ class FunctionCallOutput(TypedDict, total=False): type: Required[Literal["function_call_output"]] """The type of the function tool call output. Always `function_call_output`.""" - id: str + id: Optional[str] """The unique ID of the function tool call output. Populated when this item is returned via API. """ - status: Literal["in_progress", "completed", "incomplete"] + status: Optional[Literal["in_progress", "completed", "incomplete"]] """The status of the item. One of `in_progress`, `completed`, or `incomplete`. Populated when items are @@ -112,7 +112,7 @@ class ItemReference(TypedDict, total=False): id: Required[str] """The ID of the item to reference.""" - type: Required[Literal["item_reference"]] + type: Optional[Literal["item_reference"]] """The type of item to reference. Always `item_reference`.""" diff --git a/src/openai/types/responses/response_input_param.py b/src/openai/types/responses/response_input_param.py index 84a80eb7c2..b24182697a 100644 --- a/src/openai/types/responses/response_input_param.py +++ b/src/openai/types/responses/response_input_param.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import List, Union, Iterable +from typing import List, Union, Iterable, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict from .easy_input_message_param import EasyInputMessageParam @@ -51,10 +51,10 @@ class ComputerCallOutputAcknowledgedSafetyCheck(TypedDict, total=False): id: Required[str] """The ID of the pending safety check.""" - code: Required[str] + code: Optional[str] """The type of the pending safety check.""" - message: Required[str] + message: Optional[str] """Details about the pending safety check.""" @@ -68,16 +68,16 @@ class ComputerCallOutput(TypedDict, total=False): type: Required[Literal["computer_call_output"]] """The type of the computer tool call output. Always `computer_call_output`.""" - id: str + id: Optional[str] """The ID of the computer tool call output.""" - acknowledged_safety_checks: Iterable[ComputerCallOutputAcknowledgedSafetyCheck] + acknowledged_safety_checks: Optional[Iterable[ComputerCallOutputAcknowledgedSafetyCheck]] """ The safety checks reported by the API that have been acknowledged by the developer. """ - status: Literal["in_progress", "completed", "incomplete"] + status: Optional[Literal["in_progress", "completed", "incomplete"]] """The status of the message input. One of `in_progress`, `completed`, or `incomplete`. Populated when input items @@ -95,13 +95,13 @@ class FunctionCallOutput(TypedDict, total=False): type: Required[Literal["function_call_output"]] """The type of the function tool call output. Always `function_call_output`.""" - id: str + id: Optional[str] """The unique ID of the function tool call output. Populated when this item is returned via API. """ - status: Literal["in_progress", "completed", "incomplete"] + status: Optional[Literal["in_progress", "completed", "incomplete"]] """The status of the item. One of `in_progress`, `completed`, or `incomplete`. Populated when items are @@ -113,7 +113,7 @@ class ItemReference(TypedDict, total=False): id: Required[str] """The ID of the item to reference.""" - type: Required[Literal["item_reference"]] + type: Optional[Literal["item_reference"]] """The type of item to reference. Always `item_reference`.""" diff --git a/src/openai/types/responses/response_reasoning_item.py b/src/openai/types/responses/response_reasoning_item.py index 57e5fbfe6d..f5da7802f8 100644 --- a/src/openai/types/responses/response_reasoning_item.py +++ b/src/openai/types/responses/response_reasoning_item.py @@ -28,6 +28,12 @@ class ResponseReasoningItem(BaseModel): type: Literal["reasoning"] """The type of the object. Always `reasoning`.""" + encrypted_content: Optional[str] = None + """ + The encrypted content of the reasoning item - populated when a response is + generated with `reasoning.encrypted_content` in the `include` parameter. + """ + status: Optional[Literal["in_progress", "completed", "incomplete"]] = None """The status of the item. diff --git a/src/openai/types/responses/response_reasoning_item_param.py b/src/openai/types/responses/response_reasoning_item_param.py index adb49d6402..2cfa5312ed 100644 --- a/src/openai/types/responses/response_reasoning_item_param.py +++ b/src/openai/types/responses/response_reasoning_item_param.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Iterable +from typing import Iterable, Optional from typing_extensions import Literal, Required, TypedDict __all__ = ["ResponseReasoningItemParam", "Summary"] @@ -28,6 +28,12 @@ class ResponseReasoningItemParam(TypedDict, total=False): type: Required[Literal["reasoning"]] """The type of the object. Always `reasoning`.""" + encrypted_content: Optional[str] + """ + The encrypted content of the reasoning item - populated when a response is + generated with `reasoning.encrypted_content` in the `include` parameter. + """ + status: Literal["in_progress", "completed", "incomplete"] """The status of the item. diff --git a/src/openai/types/responses/tool.py b/src/openai/types/responses/tool.py index de5d5524d4..d96abdbe5a 100644 --- a/src/openai/types/responses/tool.py +++ b/src/openai/types/responses/tool.py @@ -12,5 +12,5 @@ __all__ = ["Tool"] Tool: TypeAlias = Annotated[ - Union[FileSearchTool, FunctionTool, ComputerTool, WebSearchTool], PropertyInfo(discriminator="type") + Union[FileSearchTool, FunctionTool, WebSearchTool, ComputerTool], PropertyInfo(discriminator="type") ] diff --git a/src/openai/types/responses/tool_param.py b/src/openai/types/responses/tool_param.py index be1cf82452..200c347005 100644 --- a/src/openai/types/responses/tool_param.py +++ b/src/openai/types/responses/tool_param.py @@ -13,6 +13,6 @@ __all__ = ["ToolParam"] -ToolParam: TypeAlias = Union[FileSearchToolParam, FunctionToolParam, ComputerToolParam, WebSearchToolParam] +ToolParam: TypeAlias = Union[FileSearchToolParam, FunctionToolParam, WebSearchToolParam, ComputerToolParam] ParseableToolParam: TypeAlias = Union[ToolParam, ChatCompletionToolParam] diff --git a/src/openai/types/responses/web_search_tool.py b/src/openai/types/responses/web_search_tool.py index bee270bf85..a6bf951145 100644 --- a/src/openai/types/responses/web_search_tool.py +++ b/src/openai/types/responses/web_search_tool.py @@ -33,16 +33,17 @@ class UserLocation(BaseModel): class WebSearchTool(BaseModel): type: Literal["web_search_preview", "web_search_preview_2025_03_11"] - """The type of the web search tool. One of: + """The type of the web search tool. - - `web_search_preview` - - `web_search_preview_2025_03_11` + One of `web_search_preview` or `web_search_preview_2025_03_11`. """ search_context_size: Optional[Literal["low", "medium", "high"]] = None - """ - High level guidance for the amount of context window space to use for the - search. One of `low`, `medium`, or `high`. `medium` is the default. + """High level guidance for the amount of context window space to use for the + search. + + One of `low`, `medium`, or `high`. `medium` is the default. """ user_location: Optional[UserLocation] = None + """The user's location.""" diff --git a/src/openai/types/responses/web_search_tool_param.py b/src/openai/types/responses/web_search_tool_param.py index 8ee36ffb47..d0335c01a3 100644 --- a/src/openai/types/responses/web_search_tool_param.py +++ b/src/openai/types/responses/web_search_tool_param.py @@ -12,19 +12,19 @@ class UserLocation(TypedDict, total=False): type: Required[Literal["approximate"]] """The type of location approximation. Always `approximate`.""" - city: str + city: Optional[str] """Free text input for the city of the user, e.g. `San Francisco`.""" - country: str + country: Optional[str] """ The two-letter [ISO country code](https://en.wikipedia.org/wiki/ISO_3166-1) of the user, e.g. `US`. """ - region: str + region: Optional[str] """Free text input for the region of the user, e.g. `California`.""" - timezone: str + timezone: Optional[str] """ The [IANA timezone](https://timeapi.io/documentation/iana-timezones) of the user, e.g. `America/Los_Angeles`. @@ -33,16 +33,17 @@ class UserLocation(TypedDict, total=False): class WebSearchToolParam(TypedDict, total=False): type: Required[Literal["web_search_preview", "web_search_preview_2025_03_11"]] - """The type of the web search tool. One of: + """The type of the web search tool. - - `web_search_preview` - - `web_search_preview_2025_03_11` + One of `web_search_preview` or `web_search_preview_2025_03_11`. """ search_context_size: Literal["low", "medium", "high"] - """ - High level guidance for the amount of context window space to use for the - search. One of `low`, `medium`, or `high`. `medium` is the default. + """High level guidance for the amount of context window space to use for the + search. + + One of `low`, `medium`, or `high`. `medium` is the default. """ user_location: Optional[UserLocation] + """The user's location.""" diff --git a/tests/api_resources/test_images.py b/tests/api_resources/test_images.py index 7997e9f5a1..7c61453bc1 100644 --- a/tests/api_resources/test_images.py +++ b/tests/api_resources/test_images.py @@ -73,6 +73,7 @@ def test_method_edit_with_all_params(self, client: OpenAI) -> None: image = client.images.edit( image=b"raw file contents", prompt="A cute baby sea otter wearing a beret", + background="transparent", mask=b"raw file contents", model="string", n=1, @@ -218,6 +219,7 @@ async def test_method_edit_with_all_params(self, async_client: AsyncOpenAI) -> N image = await async_client.images.edit( image=b"raw file contents", prompt="A cute baby sea otter wearing a beret", + background="transparent", mask=b"raw file contents", model="string", n=1, From 67997a4ec1ebcdf8e740afb0d0b2e37897657bde Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 2 May 2025 19:10:28 +0000 Subject: [PATCH 319/769] release: 1.77.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 18 ++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 8bcd8a5b4f..33a65d75c4 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.76.2" + ".": "1.77.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index bc85128f6a..9097cdc65a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ # Changelog +## 1.77.0 (2025-05-02) + +Full Changelog: [v1.76.2...v1.77.0](https://github.com/openai/openai-python/compare/v1.76.2...v1.77.0) + +### Features + +* **api:** add image sizes, reasoning encryption ([473469a](https://github.com/openai/openai-python/commit/473469afa1a5f0a03f727bdcdadb9fd57872f9c5)) + + +### Bug Fixes + +* **parsing:** handle whitespace only strings ([#2007](https://github.com/openai/openai-python/issues/2007)) ([246bc5b](https://github.com/openai/openai-python/commit/246bc5b7559887840717667a0dad465caef66c3b)) + + +### Chores + +* only strip leading whitespace ([8467d66](https://github.com/openai/openai-python/commit/8467d666e0ddf1a9f81b8769a5c8a2fef1de20c1)) + ## 1.76.2 (2025-04-29) Full Changelog: [v1.76.1...v1.76.2](https://github.com/openai/openai-python/compare/v1.76.1...v1.76.2) diff --git a/pyproject.toml b/pyproject.toml index 2c3c3eaf3b..4b854b05e5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.76.2" +version = "1.77.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 ef1e3fe526..9d8ba015e1 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.76.2" # x-release-please-version +__version__ = "1.77.0" # x-release-please-version From 1356c89a1302a1f6c1f6d6d7e8398a741d4e7423 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 5 May 2025 08:26:41 +0000 Subject: [PATCH 320/769] chore: use lazy imports for module level client --- src/openai/_module_client.py | 112 +++++++++++++++++++++-------------- 1 file changed, 66 insertions(+), 46 deletions(-) diff --git a/src/openai/_module_client.py b/src/openai/_module_client.py index cf12f7a31e..dd601f9be9 100644 --- a/src/openai/_module_client.py +++ b/src/openai/_module_client.py @@ -1,113 +1,133 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from __future__ import annotations + +from typing import TYPE_CHECKING from typing_extensions import override -from . import resources, _load_client +if TYPE_CHECKING: + from .resources.files import Files + from .resources.images import Images + from .resources.models import Models + from .resources.batches import Batches + from .resources.beta.beta import Beta + from .resources.chat.chat import Chat + from .resources.embeddings import Embeddings + from .resources.audio.audio import Audio + from .resources.completions import Completions + from .resources.evals.evals import Evals + from .resources.moderations import Moderations + from .resources.uploads.uploads import Uploads + from .resources.responses.responses import Responses + from .resources.fine_tuning.fine_tuning import FineTuning + from .resources.vector_stores.vector_stores import VectorStores + +from . import _load_client from ._utils import LazyProxy -class ChatProxy(LazyProxy[resources.Chat]): +class ChatProxy(LazyProxy["Chat"]): @override - def __load__(self) -> resources.Chat: + def __load__(self) -> Chat: return _load_client().chat -class BetaProxy(LazyProxy[resources.Beta]): +class BetaProxy(LazyProxy["Beta"]): @override - def __load__(self) -> resources.Beta: + def __load__(self) -> Beta: return _load_client().beta -class FilesProxy(LazyProxy[resources.Files]): +class FilesProxy(LazyProxy["Files"]): @override - def __load__(self) -> resources.Files: + def __load__(self) -> Files: return _load_client().files -class AudioProxy(LazyProxy[resources.Audio]): +class AudioProxy(LazyProxy["Audio"]): @override - def __load__(self) -> resources.Audio: + def __load__(self) -> Audio: return _load_client().audio -class EvalsProxy(LazyProxy[resources.Evals]): +class EvalsProxy(LazyProxy["Evals"]): @override - def __load__(self) -> resources.Evals: + def __load__(self) -> Evals: return _load_client().evals -class ImagesProxy(LazyProxy[resources.Images]): +class ImagesProxy(LazyProxy["Images"]): @override - def __load__(self) -> resources.Images: + def __load__(self) -> Images: return _load_client().images -class ModelsProxy(LazyProxy[resources.Models]): +class ModelsProxy(LazyProxy["Models"]): @override - def __load__(self) -> resources.Models: + def __load__(self) -> Models: return _load_client().models -class BatchesProxy(LazyProxy[resources.Batches]): +class BatchesProxy(LazyProxy["Batches"]): @override - def __load__(self) -> resources.Batches: + def __load__(self) -> Batches: return _load_client().batches -class UploadsProxy(LazyProxy[resources.Uploads]): +class UploadsProxy(LazyProxy["Uploads"]): @override - def __load__(self) -> resources.Uploads: + def __load__(self) -> Uploads: return _load_client().uploads -class ResponsesProxy(LazyProxy[resources.Responses]): +class ResponsesProxy(LazyProxy["Responses"]): @override - def __load__(self) -> resources.Responses: + def __load__(self) -> Responses: return _load_client().responses -class EmbeddingsProxy(LazyProxy[resources.Embeddings]): +class EmbeddingsProxy(LazyProxy["Embeddings"]): @override - def __load__(self) -> resources.Embeddings: + def __load__(self) -> Embeddings: return _load_client().embeddings -class CompletionsProxy(LazyProxy[resources.Completions]): +class CompletionsProxy(LazyProxy["Completions"]): @override - def __load__(self) -> resources.Completions: + def __load__(self) -> Completions: return _load_client().completions -class ModerationsProxy(LazyProxy[resources.Moderations]): +class ModerationsProxy(LazyProxy["Moderations"]): @override - def __load__(self) -> resources.Moderations: + def __load__(self) -> Moderations: return _load_client().moderations -class FineTuningProxy(LazyProxy[resources.FineTuning]): +class FineTuningProxy(LazyProxy["FineTuning"]): @override - def __load__(self) -> resources.FineTuning: + def __load__(self) -> FineTuning: return _load_client().fine_tuning -class VectorStoresProxy(LazyProxy[resources.VectorStores]): +class VectorStoresProxy(LazyProxy["VectorStores"]): @override - def __load__(self) -> resources.VectorStores: + def __load__(self) -> VectorStores: return _load_client().vector_stores -chat: resources.Chat = ChatProxy().__as_proxied__() -beta: resources.Beta = BetaProxy().__as_proxied__() -files: resources.Files = FilesProxy().__as_proxied__() -audio: resources.Audio = AudioProxy().__as_proxied__() -evals: resources.Evals = EvalsProxy().__as_proxied__() -images: resources.Images = ImagesProxy().__as_proxied__() -models: resources.Models = ModelsProxy().__as_proxied__() -batches: resources.Batches = BatchesProxy().__as_proxied__() -uploads: resources.Uploads = UploadsProxy().__as_proxied__() -responses: resources.Responses = ResponsesProxy().__as_proxied__() -embeddings: resources.Embeddings = EmbeddingsProxy().__as_proxied__() -completions: resources.Completions = CompletionsProxy().__as_proxied__() -moderations: resources.Moderations = ModerationsProxy().__as_proxied__() -fine_tuning: resources.FineTuning = FineTuningProxy().__as_proxied__() -vector_stores: resources.VectorStores = VectorStoresProxy().__as_proxied__() +chat: Chat = ChatProxy().__as_proxied__() +beta: Beta = BetaProxy().__as_proxied__() +files: Files = FilesProxy().__as_proxied__() +audio: Audio = AudioProxy().__as_proxied__() +evals: Evals = EvalsProxy().__as_proxied__() +images: Images = ImagesProxy().__as_proxied__() +models: Models = ModelsProxy().__as_proxied__() +batches: Batches = BatchesProxy().__as_proxied__() +uploads: Uploads = UploadsProxy().__as_proxied__() +responses: Responses = ResponsesProxy().__as_proxied__() +embeddings: Embeddings = EmbeddingsProxy().__as_proxied__() +completions: Completions = CompletionsProxy().__as_proxied__() +moderations: Moderations = ModerationsProxy().__as_proxied__() +fine_tuning: FineTuning = FineTuningProxy().__as_proxied__() +vector_stores: VectorStores = VectorStoresProxy().__as_proxied__() From 917dade87f0243caf24d890a1ee3307ee89d145c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 5 May 2025 13:15:15 +0000 Subject: [PATCH 321/769] chore: use lazy imports for resources --- src/openai/_client.py | 742 +++++++++++++++++++++++++------ src/openai/resources/__init__.py | 14 - 2 files changed, 602 insertions(+), 154 deletions(-) diff --git a/src/openai/_client.py b/src/openai/_client.py index 3aca6cb124..b251ab0917 100644 --- a/src/openai/_client.py +++ b/src/openai/_client.py @@ -3,7 +3,7 @@ from __future__ import annotations import os -from typing import Any, Union, Mapping +from typing import TYPE_CHECKING, Any, Union, Mapping from typing_extensions import Self, override import httpx @@ -24,8 +24,8 @@ is_mapping, get_async_library, ) +from ._compat import cached_property from ._version import __version__ -from .resources import files, images, models, batches, embeddings, completions, moderations from ._streaming import Stream as Stream, AsyncStream as AsyncStream from ._exceptions import OpenAIError, APIStatusError from ._base_client import ( @@ -33,37 +33,45 @@ SyncAPIClient, AsyncAPIClient, ) -from .resources.beta import beta -from .resources.chat import chat -from .resources.audio import audio -from .resources.evals import evals -from .resources.uploads import uploads -from .resources.responses import responses -from .resources.fine_tuning import fine_tuning -from .resources.vector_stores import vector_stores + +if TYPE_CHECKING: + from .resources import ( + beta, + chat, + audio, + evals, + files, + images, + models, + batches, + uploads, + responses, + embeddings, + completions, + fine_tuning, + moderations, + vector_stores, + ) + from .resources.files import Files, AsyncFiles + from .resources.images import Images, AsyncImages + from .resources.models import Models, AsyncModels + from .resources.batches import Batches, AsyncBatches + from .resources.beta.beta import Beta, AsyncBeta + from .resources.chat.chat import Chat, AsyncChat + from .resources.embeddings import Embeddings, AsyncEmbeddings + from .resources.audio.audio import Audio, AsyncAudio + from .resources.completions import Completions, AsyncCompletions + from .resources.evals.evals import Evals, AsyncEvals + from .resources.moderations import Moderations, AsyncModerations + from .resources.uploads.uploads import Uploads, AsyncUploads + from .resources.responses.responses import Responses, AsyncResponses + from .resources.fine_tuning.fine_tuning import FineTuning, AsyncFineTuning + from .resources.vector_stores.vector_stores import VectorStores, AsyncVectorStores __all__ = ["Timeout", "Transport", "ProxiesTypes", "RequestOptions", "OpenAI", "AsyncOpenAI", "Client", "AsyncClient"] class OpenAI(SyncAPIClient): - completions: completions.Completions - chat: chat.Chat - embeddings: embeddings.Embeddings - files: files.Files - images: images.Images - audio: audio.Audio - moderations: moderations.Moderations - models: models.Models - fine_tuning: fine_tuning.FineTuning - vector_stores: vector_stores.VectorStores - beta: beta.Beta - batches: batches.Batches - uploads: uploads.Uploads - responses: responses.Responses - evals: evals.Evals - with_raw_response: OpenAIWithRawResponse - with_streaming_response: OpenAIWithStreamedResponse - # client options api_key: str organization: str | None @@ -146,23 +154,103 @@ def __init__( self._default_stream_cls = Stream - self.completions = completions.Completions(self) - self.chat = chat.Chat(self) - self.embeddings = embeddings.Embeddings(self) - self.files = files.Files(self) - self.images = images.Images(self) - self.audio = audio.Audio(self) - self.moderations = moderations.Moderations(self) - self.models = models.Models(self) - self.fine_tuning = fine_tuning.FineTuning(self) - self.vector_stores = vector_stores.VectorStores(self) - self.beta = beta.Beta(self) - self.batches = batches.Batches(self) - self.uploads = uploads.Uploads(self) - self.responses = responses.Responses(self) - self.evals = evals.Evals(self) - self.with_raw_response = OpenAIWithRawResponse(self) - self.with_streaming_response = OpenAIWithStreamedResponse(self) + @cached_property + def completions(self) -> Completions: + from .resources.completions import Completions + + return Completions(self) + + @cached_property + def chat(self) -> Chat: + from .resources.chat import Chat + + return Chat(self) + + @cached_property + def embeddings(self) -> Embeddings: + from .resources.embeddings import Embeddings + + return Embeddings(self) + + @cached_property + def files(self) -> Files: + from .resources.files import Files + + return Files(self) + + @cached_property + def images(self) -> Images: + from .resources.images import Images + + return Images(self) + + @cached_property + def audio(self) -> Audio: + from .resources.audio import Audio + + return Audio(self) + + @cached_property + def moderations(self) -> Moderations: + from .resources.moderations import Moderations + + return Moderations(self) + + @cached_property + def models(self) -> Models: + from .resources.models import Models + + return Models(self) + + @cached_property + def fine_tuning(self) -> FineTuning: + from .resources.fine_tuning import FineTuning + + return FineTuning(self) + + @cached_property + def vector_stores(self) -> VectorStores: + from .resources.vector_stores import VectorStores + + return VectorStores(self) + + @cached_property + def beta(self) -> Beta: + from .resources.beta import Beta + + return Beta(self) + + @cached_property + def batches(self) -> Batches: + from .resources.batches import Batches + + return Batches(self) + + @cached_property + def uploads(self) -> Uploads: + from .resources.uploads import Uploads + + return Uploads(self) + + @cached_property + def responses(self) -> Responses: + from .resources.responses import Responses + + return Responses(self) + + @cached_property + def evals(self) -> Evals: + from .resources.evals import Evals + + return Evals(self) + + @cached_property + def with_raw_response(self) -> OpenAIWithRawResponse: + return OpenAIWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> OpenAIWithStreamedResponse: + return OpenAIWithStreamedResponse(self) @property @override @@ -279,24 +367,6 @@ def _make_status_error( class AsyncOpenAI(AsyncAPIClient): - completions: completions.AsyncCompletions - chat: chat.AsyncChat - embeddings: embeddings.AsyncEmbeddings - files: files.AsyncFiles - images: images.AsyncImages - audio: audio.AsyncAudio - moderations: moderations.AsyncModerations - models: models.AsyncModels - fine_tuning: fine_tuning.AsyncFineTuning - vector_stores: vector_stores.AsyncVectorStores - beta: beta.AsyncBeta - batches: batches.AsyncBatches - uploads: uploads.AsyncUploads - responses: responses.AsyncResponses - evals: evals.AsyncEvals - with_raw_response: AsyncOpenAIWithRawResponse - with_streaming_response: AsyncOpenAIWithStreamedResponse - # client options api_key: str organization: str | None @@ -379,23 +449,103 @@ def __init__( self._default_stream_cls = AsyncStream - self.completions = completions.AsyncCompletions(self) - self.chat = chat.AsyncChat(self) - self.embeddings = embeddings.AsyncEmbeddings(self) - self.files = files.AsyncFiles(self) - self.images = images.AsyncImages(self) - self.audio = audio.AsyncAudio(self) - self.moderations = moderations.AsyncModerations(self) - self.models = models.AsyncModels(self) - self.fine_tuning = fine_tuning.AsyncFineTuning(self) - self.vector_stores = vector_stores.AsyncVectorStores(self) - self.beta = beta.AsyncBeta(self) - self.batches = batches.AsyncBatches(self) - self.uploads = uploads.AsyncUploads(self) - self.responses = responses.AsyncResponses(self) - self.evals = evals.AsyncEvals(self) - self.with_raw_response = AsyncOpenAIWithRawResponse(self) - self.with_streaming_response = AsyncOpenAIWithStreamedResponse(self) + @cached_property + def completions(self) -> AsyncCompletions: + from .resources.completions import AsyncCompletions + + return AsyncCompletions(self) + + @cached_property + def chat(self) -> AsyncChat: + from .resources.chat import AsyncChat + + return AsyncChat(self) + + @cached_property + def embeddings(self) -> AsyncEmbeddings: + from .resources.embeddings import AsyncEmbeddings + + return AsyncEmbeddings(self) + + @cached_property + def files(self) -> AsyncFiles: + from .resources.files import AsyncFiles + + return AsyncFiles(self) + + @cached_property + def images(self) -> AsyncImages: + from .resources.images import AsyncImages + + return AsyncImages(self) + + @cached_property + def audio(self) -> AsyncAudio: + from .resources.audio import AsyncAudio + + return AsyncAudio(self) + + @cached_property + def moderations(self) -> AsyncModerations: + from .resources.moderations import AsyncModerations + + return AsyncModerations(self) + + @cached_property + def models(self) -> AsyncModels: + from .resources.models import AsyncModels + + return AsyncModels(self) + + @cached_property + def fine_tuning(self) -> AsyncFineTuning: + from .resources.fine_tuning import AsyncFineTuning + + return AsyncFineTuning(self) + + @cached_property + def vector_stores(self) -> AsyncVectorStores: + from .resources.vector_stores import AsyncVectorStores + + return AsyncVectorStores(self) + + @cached_property + def beta(self) -> AsyncBeta: + from .resources.beta import AsyncBeta + + return AsyncBeta(self) + + @cached_property + def batches(self) -> AsyncBatches: + from .resources.batches import AsyncBatches + + return AsyncBatches(self) + + @cached_property + def uploads(self) -> AsyncUploads: + from .resources.uploads import AsyncUploads + + return AsyncUploads(self) + + @cached_property + def responses(self) -> AsyncResponses: + from .resources.responses import AsyncResponses + + return AsyncResponses(self) + + @cached_property + def evals(self) -> AsyncEvals: + from .resources.evals import AsyncEvals + + return AsyncEvals(self) + + @cached_property + def with_raw_response(self) -> AsyncOpenAIWithRawResponse: + return AsyncOpenAIWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncOpenAIWithStreamedResponse: + return AsyncOpenAIWithStreamedResponse(self) @property @override @@ -512,79 +662,391 @@ def _make_status_error( class OpenAIWithRawResponse: + _client: OpenAI + def __init__(self, client: OpenAI) -> None: - self.completions = completions.CompletionsWithRawResponse(client.completions) - self.chat = chat.ChatWithRawResponse(client.chat) - self.embeddings = embeddings.EmbeddingsWithRawResponse(client.embeddings) - self.files = files.FilesWithRawResponse(client.files) - self.images = images.ImagesWithRawResponse(client.images) - self.audio = audio.AudioWithRawResponse(client.audio) - self.moderations = moderations.ModerationsWithRawResponse(client.moderations) - self.models = models.ModelsWithRawResponse(client.models) - self.fine_tuning = fine_tuning.FineTuningWithRawResponse(client.fine_tuning) - self.vector_stores = vector_stores.VectorStoresWithRawResponse(client.vector_stores) - self.beta = beta.BetaWithRawResponse(client.beta) - self.batches = batches.BatchesWithRawResponse(client.batches) - self.uploads = uploads.UploadsWithRawResponse(client.uploads) - self.responses = responses.ResponsesWithRawResponse(client.responses) - self.evals = evals.EvalsWithRawResponse(client.evals) + self._client = client + + @cached_property + def completions(self) -> completions.CompletionsWithRawResponse: + from .resources.completions import CompletionsWithRawResponse + + return CompletionsWithRawResponse(self._client.completions) + + @cached_property + def chat(self) -> chat.ChatWithRawResponse: + from .resources.chat import ChatWithRawResponse + + return ChatWithRawResponse(self._client.chat) + + @cached_property + def embeddings(self) -> embeddings.EmbeddingsWithRawResponse: + from .resources.embeddings import EmbeddingsWithRawResponse + + return EmbeddingsWithRawResponse(self._client.embeddings) + + @cached_property + def files(self) -> files.FilesWithRawResponse: + from .resources.files import FilesWithRawResponse + + return FilesWithRawResponse(self._client.files) + + @cached_property + def images(self) -> images.ImagesWithRawResponse: + from .resources.images import ImagesWithRawResponse + + return ImagesWithRawResponse(self._client.images) + + @cached_property + def audio(self) -> audio.AudioWithRawResponse: + from .resources.audio import AudioWithRawResponse + + return AudioWithRawResponse(self._client.audio) + + @cached_property + def moderations(self) -> moderations.ModerationsWithRawResponse: + from .resources.moderations import ModerationsWithRawResponse + + return ModerationsWithRawResponse(self._client.moderations) + + @cached_property + def models(self) -> models.ModelsWithRawResponse: + from .resources.models import ModelsWithRawResponse + + return ModelsWithRawResponse(self._client.models) + + @cached_property + def fine_tuning(self) -> fine_tuning.FineTuningWithRawResponse: + from .resources.fine_tuning import FineTuningWithRawResponse + + return FineTuningWithRawResponse(self._client.fine_tuning) + + @cached_property + def vector_stores(self) -> vector_stores.VectorStoresWithRawResponse: + from .resources.vector_stores import VectorStoresWithRawResponse + + return VectorStoresWithRawResponse(self._client.vector_stores) + + @cached_property + def beta(self) -> beta.BetaWithRawResponse: + from .resources.beta import BetaWithRawResponse + + return BetaWithRawResponse(self._client.beta) + + @cached_property + def batches(self) -> batches.BatchesWithRawResponse: + from .resources.batches import BatchesWithRawResponse + + return BatchesWithRawResponse(self._client.batches) + + @cached_property + def uploads(self) -> uploads.UploadsWithRawResponse: + from .resources.uploads import UploadsWithRawResponse + + return UploadsWithRawResponse(self._client.uploads) + + @cached_property + def responses(self) -> responses.ResponsesWithRawResponse: + from .resources.responses import ResponsesWithRawResponse + + return ResponsesWithRawResponse(self._client.responses) + + @cached_property + def evals(self) -> evals.EvalsWithRawResponse: + from .resources.evals import EvalsWithRawResponse + + return EvalsWithRawResponse(self._client.evals) class AsyncOpenAIWithRawResponse: + _client: AsyncOpenAI + def __init__(self, client: AsyncOpenAI) -> None: - self.completions = completions.AsyncCompletionsWithRawResponse(client.completions) - self.chat = chat.AsyncChatWithRawResponse(client.chat) - self.embeddings = embeddings.AsyncEmbeddingsWithRawResponse(client.embeddings) - self.files = files.AsyncFilesWithRawResponse(client.files) - self.images = images.AsyncImagesWithRawResponse(client.images) - self.audio = audio.AsyncAudioWithRawResponse(client.audio) - self.moderations = moderations.AsyncModerationsWithRawResponse(client.moderations) - self.models = models.AsyncModelsWithRawResponse(client.models) - self.fine_tuning = fine_tuning.AsyncFineTuningWithRawResponse(client.fine_tuning) - self.vector_stores = vector_stores.AsyncVectorStoresWithRawResponse(client.vector_stores) - self.beta = beta.AsyncBetaWithRawResponse(client.beta) - self.batches = batches.AsyncBatchesWithRawResponse(client.batches) - self.uploads = uploads.AsyncUploadsWithRawResponse(client.uploads) - self.responses = responses.AsyncResponsesWithRawResponse(client.responses) - self.evals = evals.AsyncEvalsWithRawResponse(client.evals) + self._client = client + + @cached_property + def completions(self) -> completions.AsyncCompletionsWithRawResponse: + from .resources.completions import AsyncCompletionsWithRawResponse + + return AsyncCompletionsWithRawResponse(self._client.completions) + + @cached_property + def chat(self) -> chat.AsyncChatWithRawResponse: + from .resources.chat import AsyncChatWithRawResponse + + return AsyncChatWithRawResponse(self._client.chat) + + @cached_property + def embeddings(self) -> embeddings.AsyncEmbeddingsWithRawResponse: + from .resources.embeddings import AsyncEmbeddingsWithRawResponse + + return AsyncEmbeddingsWithRawResponse(self._client.embeddings) + + @cached_property + def files(self) -> files.AsyncFilesWithRawResponse: + from .resources.files import AsyncFilesWithRawResponse + + return AsyncFilesWithRawResponse(self._client.files) + + @cached_property + def images(self) -> images.AsyncImagesWithRawResponse: + from .resources.images import AsyncImagesWithRawResponse + + return AsyncImagesWithRawResponse(self._client.images) + + @cached_property + def audio(self) -> audio.AsyncAudioWithRawResponse: + from .resources.audio import AsyncAudioWithRawResponse + + return AsyncAudioWithRawResponse(self._client.audio) + + @cached_property + def moderations(self) -> moderations.AsyncModerationsWithRawResponse: + from .resources.moderations import AsyncModerationsWithRawResponse + + return AsyncModerationsWithRawResponse(self._client.moderations) + + @cached_property + def models(self) -> models.AsyncModelsWithRawResponse: + from .resources.models import AsyncModelsWithRawResponse + + return AsyncModelsWithRawResponse(self._client.models) + + @cached_property + def fine_tuning(self) -> fine_tuning.AsyncFineTuningWithRawResponse: + from .resources.fine_tuning import AsyncFineTuningWithRawResponse + + return AsyncFineTuningWithRawResponse(self._client.fine_tuning) + + @cached_property + def vector_stores(self) -> vector_stores.AsyncVectorStoresWithRawResponse: + from .resources.vector_stores import AsyncVectorStoresWithRawResponse + + return AsyncVectorStoresWithRawResponse(self._client.vector_stores) + + @cached_property + def beta(self) -> beta.AsyncBetaWithRawResponse: + from .resources.beta import AsyncBetaWithRawResponse + + return AsyncBetaWithRawResponse(self._client.beta) + + @cached_property + def batches(self) -> batches.AsyncBatchesWithRawResponse: + from .resources.batches import AsyncBatchesWithRawResponse + + return AsyncBatchesWithRawResponse(self._client.batches) + + @cached_property + def uploads(self) -> uploads.AsyncUploadsWithRawResponse: + from .resources.uploads import AsyncUploadsWithRawResponse + + return AsyncUploadsWithRawResponse(self._client.uploads) + + @cached_property + def responses(self) -> responses.AsyncResponsesWithRawResponse: + from .resources.responses import AsyncResponsesWithRawResponse + + return AsyncResponsesWithRawResponse(self._client.responses) + + @cached_property + def evals(self) -> evals.AsyncEvalsWithRawResponse: + from .resources.evals import AsyncEvalsWithRawResponse + + return AsyncEvalsWithRawResponse(self._client.evals) class OpenAIWithStreamedResponse: + _client: OpenAI + def __init__(self, client: OpenAI) -> None: - self.completions = completions.CompletionsWithStreamingResponse(client.completions) - self.chat = chat.ChatWithStreamingResponse(client.chat) - self.embeddings = embeddings.EmbeddingsWithStreamingResponse(client.embeddings) - self.files = files.FilesWithStreamingResponse(client.files) - self.images = images.ImagesWithStreamingResponse(client.images) - self.audio = audio.AudioWithStreamingResponse(client.audio) - self.moderations = moderations.ModerationsWithStreamingResponse(client.moderations) - self.models = models.ModelsWithStreamingResponse(client.models) - self.fine_tuning = fine_tuning.FineTuningWithStreamingResponse(client.fine_tuning) - self.vector_stores = vector_stores.VectorStoresWithStreamingResponse(client.vector_stores) - self.beta = beta.BetaWithStreamingResponse(client.beta) - self.batches = batches.BatchesWithStreamingResponse(client.batches) - self.uploads = uploads.UploadsWithStreamingResponse(client.uploads) - self.responses = responses.ResponsesWithStreamingResponse(client.responses) - self.evals = evals.EvalsWithStreamingResponse(client.evals) + self._client = client + + @cached_property + def completions(self) -> completions.CompletionsWithStreamingResponse: + from .resources.completions import CompletionsWithStreamingResponse + + return CompletionsWithStreamingResponse(self._client.completions) + + @cached_property + def chat(self) -> chat.ChatWithStreamingResponse: + from .resources.chat import ChatWithStreamingResponse + + return ChatWithStreamingResponse(self._client.chat) + + @cached_property + def embeddings(self) -> embeddings.EmbeddingsWithStreamingResponse: + from .resources.embeddings import EmbeddingsWithStreamingResponse + + return EmbeddingsWithStreamingResponse(self._client.embeddings) + + @cached_property + def files(self) -> files.FilesWithStreamingResponse: + from .resources.files import FilesWithStreamingResponse + + return FilesWithStreamingResponse(self._client.files) + + @cached_property + def images(self) -> images.ImagesWithStreamingResponse: + from .resources.images import ImagesWithStreamingResponse + + return ImagesWithStreamingResponse(self._client.images) + + @cached_property + def audio(self) -> audio.AudioWithStreamingResponse: + from .resources.audio import AudioWithStreamingResponse + + return AudioWithStreamingResponse(self._client.audio) + + @cached_property + def moderations(self) -> moderations.ModerationsWithStreamingResponse: + from .resources.moderations import ModerationsWithStreamingResponse + + return ModerationsWithStreamingResponse(self._client.moderations) + + @cached_property + def models(self) -> models.ModelsWithStreamingResponse: + from .resources.models import ModelsWithStreamingResponse + + return ModelsWithStreamingResponse(self._client.models) + + @cached_property + def fine_tuning(self) -> fine_tuning.FineTuningWithStreamingResponse: + from .resources.fine_tuning import FineTuningWithStreamingResponse + + return FineTuningWithStreamingResponse(self._client.fine_tuning) + + @cached_property + def vector_stores(self) -> vector_stores.VectorStoresWithStreamingResponse: + from .resources.vector_stores import VectorStoresWithStreamingResponse + + return VectorStoresWithStreamingResponse(self._client.vector_stores) + + @cached_property + def beta(self) -> beta.BetaWithStreamingResponse: + from .resources.beta import BetaWithStreamingResponse + + return BetaWithStreamingResponse(self._client.beta) + + @cached_property + def batches(self) -> batches.BatchesWithStreamingResponse: + from .resources.batches import BatchesWithStreamingResponse + + return BatchesWithStreamingResponse(self._client.batches) + + @cached_property + def uploads(self) -> uploads.UploadsWithStreamingResponse: + from .resources.uploads import UploadsWithStreamingResponse + + return UploadsWithStreamingResponse(self._client.uploads) + + @cached_property + def responses(self) -> responses.ResponsesWithStreamingResponse: + from .resources.responses import ResponsesWithStreamingResponse + + return ResponsesWithStreamingResponse(self._client.responses) + + @cached_property + def evals(self) -> evals.EvalsWithStreamingResponse: + from .resources.evals import EvalsWithStreamingResponse + + return EvalsWithStreamingResponse(self._client.evals) class AsyncOpenAIWithStreamedResponse: + _client: AsyncOpenAI + def __init__(self, client: AsyncOpenAI) -> None: - self.completions = completions.AsyncCompletionsWithStreamingResponse(client.completions) - self.chat = chat.AsyncChatWithStreamingResponse(client.chat) - self.embeddings = embeddings.AsyncEmbeddingsWithStreamingResponse(client.embeddings) - self.files = files.AsyncFilesWithStreamingResponse(client.files) - self.images = images.AsyncImagesWithStreamingResponse(client.images) - self.audio = audio.AsyncAudioWithStreamingResponse(client.audio) - self.moderations = moderations.AsyncModerationsWithStreamingResponse(client.moderations) - self.models = models.AsyncModelsWithStreamingResponse(client.models) - self.fine_tuning = fine_tuning.AsyncFineTuningWithStreamingResponse(client.fine_tuning) - self.vector_stores = vector_stores.AsyncVectorStoresWithStreamingResponse(client.vector_stores) - self.beta = beta.AsyncBetaWithStreamingResponse(client.beta) - self.batches = batches.AsyncBatchesWithStreamingResponse(client.batches) - self.uploads = uploads.AsyncUploadsWithStreamingResponse(client.uploads) - self.responses = responses.AsyncResponsesWithStreamingResponse(client.responses) - self.evals = evals.AsyncEvalsWithStreamingResponse(client.evals) + self._client = client + + @cached_property + def completions(self) -> completions.AsyncCompletionsWithStreamingResponse: + from .resources.completions import AsyncCompletionsWithStreamingResponse + + return AsyncCompletionsWithStreamingResponse(self._client.completions) + + @cached_property + def chat(self) -> chat.AsyncChatWithStreamingResponse: + from .resources.chat import AsyncChatWithStreamingResponse + + return AsyncChatWithStreamingResponse(self._client.chat) + + @cached_property + def embeddings(self) -> embeddings.AsyncEmbeddingsWithStreamingResponse: + from .resources.embeddings import AsyncEmbeddingsWithStreamingResponse + + return AsyncEmbeddingsWithStreamingResponse(self._client.embeddings) + + @cached_property + def files(self) -> files.AsyncFilesWithStreamingResponse: + from .resources.files import AsyncFilesWithStreamingResponse + + return AsyncFilesWithStreamingResponse(self._client.files) + + @cached_property + def images(self) -> images.AsyncImagesWithStreamingResponse: + from .resources.images import AsyncImagesWithStreamingResponse + + return AsyncImagesWithStreamingResponse(self._client.images) + + @cached_property + def audio(self) -> audio.AsyncAudioWithStreamingResponse: + from .resources.audio import AsyncAudioWithStreamingResponse + + return AsyncAudioWithStreamingResponse(self._client.audio) + + @cached_property + def moderations(self) -> moderations.AsyncModerationsWithStreamingResponse: + from .resources.moderations import AsyncModerationsWithStreamingResponse + + return AsyncModerationsWithStreamingResponse(self._client.moderations) + + @cached_property + def models(self) -> models.AsyncModelsWithStreamingResponse: + from .resources.models import AsyncModelsWithStreamingResponse + + return AsyncModelsWithStreamingResponse(self._client.models) + + @cached_property + def fine_tuning(self) -> fine_tuning.AsyncFineTuningWithStreamingResponse: + from .resources.fine_tuning import AsyncFineTuningWithStreamingResponse + + return AsyncFineTuningWithStreamingResponse(self._client.fine_tuning) + + @cached_property + def vector_stores(self) -> vector_stores.AsyncVectorStoresWithStreamingResponse: + from .resources.vector_stores import AsyncVectorStoresWithStreamingResponse + + return AsyncVectorStoresWithStreamingResponse(self._client.vector_stores) + + @cached_property + def beta(self) -> beta.AsyncBetaWithStreamingResponse: + from .resources.beta import AsyncBetaWithStreamingResponse + + return AsyncBetaWithStreamingResponse(self._client.beta) + + @cached_property + def batches(self) -> batches.AsyncBatchesWithStreamingResponse: + from .resources.batches import AsyncBatchesWithStreamingResponse + + return AsyncBatchesWithStreamingResponse(self._client.batches) + + @cached_property + def uploads(self) -> uploads.AsyncUploadsWithStreamingResponse: + from .resources.uploads import AsyncUploadsWithStreamingResponse + + return AsyncUploadsWithStreamingResponse(self._client.uploads) + + @cached_property + def responses(self) -> responses.AsyncResponsesWithStreamingResponse: + from .resources.responses import AsyncResponsesWithStreamingResponse + + return AsyncResponsesWithStreamingResponse(self._client.responses) + + @cached_property + def evals(self) -> evals.AsyncEvalsWithStreamingResponse: + from .resources.evals import AsyncEvalsWithStreamingResponse + + return AsyncEvalsWithStreamingResponse(self._client.evals) Client = OpenAI diff --git a/src/openai/resources/__init__.py b/src/openai/resources/__init__.py index ab9cd73e81..8612dec797 100644 --- a/src/openai/resources/__init__.py +++ b/src/openai/resources/__init__.py @@ -72,14 +72,6 @@ UploadsWithStreamingResponse, AsyncUploadsWithStreamingResponse, ) -from .responses import ( - Responses, - AsyncResponses, - ResponsesWithRawResponse, - AsyncResponsesWithRawResponse, - ResponsesWithStreamingResponse, - AsyncResponsesWithStreamingResponse, -) from .embeddings import ( Embeddings, AsyncEmbeddings, @@ -200,12 +192,6 @@ "AsyncUploadsWithRawResponse", "UploadsWithStreamingResponse", "AsyncUploadsWithStreamingResponse", - "Responses", - "AsyncResponses", - "ResponsesWithRawResponse", - "AsyncResponsesWithRawResponse", - "ResponsesWithStreamingResponse", - "AsyncResponsesWithStreamingResponse", "Evals", "AsyncEvals", "EvalsWithRawResponse", From 08d67adfffad61802e1ac1b3f35795040182a12d Mon Sep 17 00:00:00 2001 From: Bruno Alla Date: Wed, 7 May 2025 18:50:47 +0100 Subject: [PATCH 322/769] fix: ignore errors in isinstance() calls on LazyProxy subclasses (#2343) Fix #2056 --- src/openai/_utils/_proxy.py | 5 ++++- tests/test_utils/test_proxy.py | 12 ++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/openai/_utils/_proxy.py b/src/openai/_utils/_proxy.py index ffd883e9dd..0f239a33c6 100644 --- a/src/openai/_utils/_proxy.py +++ b/src/openai/_utils/_proxy.py @@ -46,7 +46,10 @@ def __dir__(self) -> Iterable[str]: @property # type: ignore @override def __class__(self) -> type: # pyright: ignore - proxied = self.__get_proxied__() + try: + proxied = self.__get_proxied__() + except Exception: + return type(self) if issubclass(type(proxied), LazyProxy): return type(proxied) return proxied.__class__ diff --git a/tests/test_utils/test_proxy.py b/tests/test_utils/test_proxy.py index aedd3731ee..19bedc7780 100644 --- a/tests/test_utils/test_proxy.py +++ b/tests/test_utils/test_proxy.py @@ -3,6 +3,7 @@ from typing_extensions import override from openai._utils import LazyProxy +from openai._extras._common import MissingDependencyError class RecursiveLazyProxy(LazyProxy[Any]): @@ -21,3 +22,14 @@ def test_recursive_proxy() -> None: assert dir(proxy) == [] assert type(proxy).__name__ == "RecursiveLazyProxy" assert type(operator.attrgetter("name.foo.bar.baz")(proxy)).__name__ == "RecursiveLazyProxy" + + +def test_is_instance_with_missing_dependency_error() -> None: + class MissingDepsProxy(LazyProxy[Any]): + @override + def __load__(self) -> Any: + raise MissingDependencyError("Mocking missing dependency") + + proxy = MissingDepsProxy() + assert not isinstance(proxy, dict) + assert isinstance(proxy, LazyProxy) From e241775593ce683a9888606645f0ecfa02fe6efc Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 8 May 2025 12:40:47 +0000 Subject: [PATCH 323/769] chore(internal): update proxy tests --- tests/test_utils/test_proxy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_utils/test_proxy.py b/tests/test_utils/test_proxy.py index 19bedc7780..2b5ff19dab 100644 --- a/tests/test_utils/test_proxy.py +++ b/tests/test_utils/test_proxy.py @@ -24,7 +24,7 @@ def test_recursive_proxy() -> None: assert type(operator.attrgetter("name.foo.bar.baz")(proxy)).__name__ == "RecursiveLazyProxy" -def test_is_instance_with_missing_dependency_error() -> None: +def test_isinstance_does_not_error() -> None: class MissingDepsProxy(LazyProxy[Any]): @override def __load__(self) -> Any: From a3b8e7724f505cb3f8dd9efff0f23301b6804bb6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 8 May 2025 17:23:49 +0000 Subject: [PATCH 324/769] feat(api): Add reinforcement fine-tuning api support --- .stats.yml | 8 +- api.md | 52 +++- src/openai/resources/fine_tuning/__init__.py | 14 + .../resources/fine_tuning/alpha/__init__.py | 33 ++ .../resources/fine_tuning/alpha/alpha.py | 102 +++++++ .../resources/fine_tuning/alpha/graders.py | 272 +++++++++++++++++ .../resources/fine_tuning/fine_tuning.py | 32 ++ src/openai/resources/fine_tuning/jobs/jobs.py | 156 ++++++++++ src/openai/types/__init__.py | 5 - src/openai/types/eval_create_params.py | 91 ++---- src/openai/types/eval_create_response.py | 97 ++---- src/openai/types/eval_list_response.py | 97 ++---- src/openai/types/eval_retrieve_response.py | 97 ++---- src/openai/types/eval_update_response.py | 97 ++---- src/openai/types/fine_tuning/__init__.py | 12 + .../types/fine_tuning/alpha/__init__.py | 8 + .../fine_tuning/alpha/grader_run_params.py | 30 ++ .../fine_tuning/alpha/grader_run_response.py | 67 ++++ .../alpha/grader_validate_params.py | 24 ++ .../alpha/grader_validate_response.py | 20 ++ .../types/fine_tuning/dpo_hyperparameters.py | 36 +++ .../fine_tuning/dpo_hyperparameters_param.py | 36 +++ src/openai/types/fine_tuning/dpo_method.py | 13 + .../types/fine_tuning/dpo_method_param.py | 14 + .../types/fine_tuning/fine_tuning_job.py | 86 +----- .../types/fine_tuning/job_create_params.py | 87 +----- .../reinforcement_hyperparameters.py | 43 +++ .../reinforcement_hyperparameters_param.py | 43 +++ .../types/fine_tuning/reinforcement_method.py | 24 ++ .../fine_tuning/reinforcement_method_param.py | 27 ++ .../fine_tuning/supervised_hyperparameters.py | 29 ++ .../supervised_hyperparameters_param.py | 29 ++ .../types/fine_tuning/supervised_method.py | 13 + .../fine_tuning/supervised_method_param.py | 14 + src/openai/types/graders/__init__.py | 16 + .../label_model_grader.py} | 8 +- .../types/graders/label_model_grader_param.py | 54 ++++ src/openai/types/graders/multi_grader.py | 28 ++ .../types/graders/multi_grader_param.py | 31 ++ src/openai/types/graders/python_grader.py | 22 ++ .../types/graders/python_grader_param.py | 21 ++ .../types/graders/score_model_grader.py | 54 ++++ .../types/graders/score_model_grader_param.py | 55 ++++ .../string_check_grader.py} | 6 +- .../string_check_grader_param.py} | 4 +- .../text_similarity_grader.py} | 14 +- .../text_similarity_grader_param.py} | 11 +- .../fine_tuning/alpha/__init__.py | 1 + .../fine_tuning/alpha/test_graders.py | 289 ++++++++++++++++++ tests/api_resources/fine_tuning/test_jobs.py | 192 +++++++++++- 50 files changed, 2048 insertions(+), 566 deletions(-) create mode 100644 src/openai/resources/fine_tuning/alpha/__init__.py create mode 100644 src/openai/resources/fine_tuning/alpha/alpha.py create mode 100644 src/openai/resources/fine_tuning/alpha/graders.py create mode 100644 src/openai/types/fine_tuning/alpha/__init__.py create mode 100644 src/openai/types/fine_tuning/alpha/grader_run_params.py create mode 100644 src/openai/types/fine_tuning/alpha/grader_run_response.py create mode 100644 src/openai/types/fine_tuning/alpha/grader_validate_params.py create mode 100644 src/openai/types/fine_tuning/alpha/grader_validate_response.py create mode 100644 src/openai/types/fine_tuning/dpo_hyperparameters.py create mode 100644 src/openai/types/fine_tuning/dpo_hyperparameters_param.py create mode 100644 src/openai/types/fine_tuning/dpo_method.py create mode 100644 src/openai/types/fine_tuning/dpo_method_param.py create mode 100644 src/openai/types/fine_tuning/reinforcement_hyperparameters.py create mode 100644 src/openai/types/fine_tuning/reinforcement_hyperparameters_param.py create mode 100644 src/openai/types/fine_tuning/reinforcement_method.py create mode 100644 src/openai/types/fine_tuning/reinforcement_method_param.py create mode 100644 src/openai/types/fine_tuning/supervised_hyperparameters.py create mode 100644 src/openai/types/fine_tuning/supervised_hyperparameters_param.py create mode 100644 src/openai/types/fine_tuning/supervised_method.py create mode 100644 src/openai/types/fine_tuning/supervised_method_param.py create mode 100644 src/openai/types/graders/__init__.py rename src/openai/types/{eval_label_model_grader.py => graders/label_model_grader.py} (85%) create mode 100644 src/openai/types/graders/label_model_grader_param.py create mode 100644 src/openai/types/graders/multi_grader.py create mode 100644 src/openai/types/graders/multi_grader_param.py create mode 100644 src/openai/types/graders/python_grader.py create mode 100644 src/openai/types/graders/python_grader_param.py create mode 100644 src/openai/types/graders/score_model_grader.py create mode 100644 src/openai/types/graders/score_model_grader_param.py rename src/openai/types/{eval_string_check_grader.py => graders/string_check_grader.py} (84%) rename src/openai/types/{eval_string_check_grader_param.py => graders/string_check_grader_param.py} (87%) rename src/openai/types/{eval_text_similarity_grader.py => graders/text_similarity_grader.py} (69%) rename src/openai/types/{eval_text_similarity_grader_param.py => graders/text_similarity_grader_param.py} (76%) create mode 100644 tests/api_resources/fine_tuning/alpha/__init__.py create mode 100644 tests/api_resources/fine_tuning/alpha/test_graders.py diff --git a/.stats.yml b/.stats.yml index 0c8278866d..5f1bee851b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 97 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-0ee6b36cf3cc278cef4199a6aec5f7d530a6c1f17a74830037e96d50ca1edc50.yml -openapi_spec_hash: e8ec5f46bc0655b34f292422d58a60f6 -config_hash: d9b6b6e6bc85744663e300eebc482067 +configured_endpoints: 101 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-794a6ed3c3d3d77887564755168056af8a426b17cf1ec721e3a300503dc22a41.yml +openapi_spec_hash: 25a81c220713cd5b0bafc221d1dfa79a +config_hash: 0b768ed1b56c6d82816f0fa40dc4aaf5 diff --git a/api.md b/api.md index d04c76960e..496e5548b3 100644 --- a/api.md +++ b/api.md @@ -225,6 +225,21 @@ Methods: # FineTuning +## Methods + +Types: + +```python +from openai.types.fine_tuning import ( + DpoHyperparameters, + DpoMethod, + ReinforcementHyperparameters, + ReinforcementMethod, + SupervisedHyperparameters, + SupervisedMethod, +) +``` + ## Jobs Types: @@ -246,6 +261,8 @@ Methods: - client.fine_tuning.jobs.list(\*\*params) -> SyncCursorPage[FineTuningJob] - client.fine_tuning.jobs.cancel(fine_tuning_job_id) -> FineTuningJob - client.fine_tuning.jobs.list_events(fine_tuning_job_id, \*\*params) -> SyncCursorPage[FineTuningJobEvent] +- client.fine_tuning.jobs.pause(fine_tuning_job_id) -> FineTuningJob +- client.fine_tuning.jobs.resume(fine_tuning_job_id) -> FineTuningJob ### Checkpoints @@ -279,6 +296,38 @@ Methods: - client.fine_tuning.checkpoints.permissions.retrieve(fine_tuned_model_checkpoint, \*\*params) -> PermissionRetrieveResponse - client.fine_tuning.checkpoints.permissions.delete(permission_id, \*, fine_tuned_model_checkpoint) -> PermissionDeleteResponse +## Alpha + +### Graders + +Types: + +```python +from openai.types.fine_tuning.alpha import GraderRunResponse, GraderValidateResponse +``` + +Methods: + +- client.fine_tuning.alpha.graders.run(\*\*params) -> GraderRunResponse +- client.fine_tuning.alpha.graders.validate(\*\*params) -> GraderValidateResponse + +# Graders + +## GraderModels + +Types: + +```python +from openai.types.graders import ( + LabelModelGrader, + MultiGrader, + PythonGrader, + ScoreModelGrader, + StringCheckGrader, + TextSimilarityGrader, +) +``` + # VectorStores Types: @@ -738,10 +787,7 @@ Types: ```python from openai.types import ( EvalCustomDataSourceConfig, - EvalLabelModelGrader, EvalStoredCompletionsDataSourceConfig, - EvalStringCheckGrader, - EvalTextSimilarityGrader, EvalCreateResponse, EvalRetrieveResponse, EvalUpdateResponse, diff --git a/src/openai/resources/fine_tuning/__init__.py b/src/openai/resources/fine_tuning/__init__.py index ed7db4f4e0..c76af83deb 100644 --- a/src/openai/resources/fine_tuning/__init__.py +++ b/src/openai/resources/fine_tuning/__init__.py @@ -8,6 +8,14 @@ JobsWithStreamingResponse, AsyncJobsWithStreamingResponse, ) +from .alpha import ( + Alpha, + AsyncAlpha, + AlphaWithRawResponse, + AsyncAlphaWithRawResponse, + AlphaWithStreamingResponse, + AsyncAlphaWithStreamingResponse, +) from .checkpoints import ( Checkpoints, AsyncCheckpoints, @@ -38,6 +46,12 @@ "AsyncCheckpointsWithRawResponse", "CheckpointsWithStreamingResponse", "AsyncCheckpointsWithStreamingResponse", + "Alpha", + "AsyncAlpha", + "AlphaWithRawResponse", + "AsyncAlphaWithRawResponse", + "AlphaWithStreamingResponse", + "AsyncAlphaWithStreamingResponse", "FineTuning", "AsyncFineTuning", "FineTuningWithRawResponse", diff --git a/src/openai/resources/fine_tuning/alpha/__init__.py b/src/openai/resources/fine_tuning/alpha/__init__.py new file mode 100644 index 0000000000..8bed8af4fd --- /dev/null +++ b/src/openai/resources/fine_tuning/alpha/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .alpha import ( + Alpha, + AsyncAlpha, + AlphaWithRawResponse, + AsyncAlphaWithRawResponse, + AlphaWithStreamingResponse, + AsyncAlphaWithStreamingResponse, +) +from .graders import ( + Graders, + AsyncGraders, + GradersWithRawResponse, + AsyncGradersWithRawResponse, + GradersWithStreamingResponse, + AsyncGradersWithStreamingResponse, +) + +__all__ = [ + "Graders", + "AsyncGraders", + "GradersWithRawResponse", + "AsyncGradersWithRawResponse", + "GradersWithStreamingResponse", + "AsyncGradersWithStreamingResponse", + "Alpha", + "AsyncAlpha", + "AlphaWithRawResponse", + "AsyncAlphaWithRawResponse", + "AlphaWithStreamingResponse", + "AsyncAlphaWithStreamingResponse", +] diff --git a/src/openai/resources/fine_tuning/alpha/alpha.py b/src/openai/resources/fine_tuning/alpha/alpha.py new file mode 100644 index 0000000000..54c05fab69 --- /dev/null +++ b/src/openai/resources/fine_tuning/alpha/alpha.py @@ -0,0 +1,102 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .graders import ( + Graders, + AsyncGraders, + GradersWithRawResponse, + AsyncGradersWithRawResponse, + GradersWithStreamingResponse, + AsyncGradersWithStreamingResponse, +) +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource + +__all__ = ["Alpha", "AsyncAlpha"] + + +class Alpha(SyncAPIResource): + @cached_property + def graders(self) -> Graders: + return Graders(self._client) + + @cached_property + def with_raw_response(self) -> AlphaWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AlphaWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AlphaWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AlphaWithStreamingResponse(self) + + +class AsyncAlpha(AsyncAPIResource): + @cached_property + def graders(self) -> AsyncGraders: + return AsyncGraders(self._client) + + @cached_property + def with_raw_response(self) -> AsyncAlphaWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncAlphaWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncAlphaWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncAlphaWithStreamingResponse(self) + + +class AlphaWithRawResponse: + def __init__(self, alpha: Alpha) -> None: + self._alpha = alpha + + @cached_property + def graders(self) -> GradersWithRawResponse: + return GradersWithRawResponse(self._alpha.graders) + + +class AsyncAlphaWithRawResponse: + def __init__(self, alpha: AsyncAlpha) -> None: + self._alpha = alpha + + @cached_property + def graders(self) -> AsyncGradersWithRawResponse: + return AsyncGradersWithRawResponse(self._alpha.graders) + + +class AlphaWithStreamingResponse: + def __init__(self, alpha: Alpha) -> None: + self._alpha = alpha + + @cached_property + def graders(self) -> GradersWithStreamingResponse: + return GradersWithStreamingResponse(self._alpha.graders) + + +class AsyncAlphaWithStreamingResponse: + def __init__(self, alpha: AsyncAlpha) -> None: + self._alpha = alpha + + @cached_property + def graders(self) -> AsyncGradersWithStreamingResponse: + return AsyncGradersWithStreamingResponse(self._alpha.graders) diff --git a/src/openai/resources/fine_tuning/alpha/graders.py b/src/openai/resources/fine_tuning/alpha/graders.py new file mode 100644 index 0000000000..f27acdfd9c --- /dev/null +++ b/src/openai/resources/fine_tuning/alpha/graders.py @@ -0,0 +1,272 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable + +import httpx + +from .... import _legacy_response +from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ...._base_client import make_request_options +from ....types.fine_tuning.alpha import grader_run_params, grader_validate_params +from ....types.fine_tuning.alpha.grader_run_response import GraderRunResponse +from ....types.fine_tuning.alpha.grader_validate_response import GraderValidateResponse + +__all__ = ["Graders", "AsyncGraders"] + + +class Graders(SyncAPIResource): + @cached_property + def with_raw_response(self) -> GradersWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return GradersWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> GradersWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return GradersWithStreamingResponse(self) + + def run( + self, + *, + grader: grader_run_params.Grader, + model_sample: str, + reference_answer: Union[str, Iterable[object], float, object], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> GraderRunResponse: + """ + Run a grader. + + Args: + grader: The grader used for the fine-tuning job. + + model_sample: The model sample to be evaluated. + + reference_answer: The reference answer for the evaluation. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/fine_tuning/alpha/graders/run", + body=maybe_transform( + { + "grader": grader, + "model_sample": model_sample, + "reference_answer": reference_answer, + }, + grader_run_params.GraderRunParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GraderRunResponse, + ) + + def validate( + self, + *, + grader: grader_validate_params.Grader, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> GraderValidateResponse: + """ + Validate a grader. + + Args: + grader: The grader used for the fine-tuning job. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/fine_tuning/alpha/graders/validate", + body=maybe_transform({"grader": grader}, grader_validate_params.GraderValidateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GraderValidateResponse, + ) + + +class AsyncGraders(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncGradersWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncGradersWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncGradersWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncGradersWithStreamingResponse(self) + + async def run( + self, + *, + grader: grader_run_params.Grader, + model_sample: str, + reference_answer: Union[str, Iterable[object], float, object], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> GraderRunResponse: + """ + Run a grader. + + Args: + grader: The grader used for the fine-tuning job. + + model_sample: The model sample to be evaluated. + + reference_answer: The reference answer for the evaluation. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/fine_tuning/alpha/graders/run", + body=await async_maybe_transform( + { + "grader": grader, + "model_sample": model_sample, + "reference_answer": reference_answer, + }, + grader_run_params.GraderRunParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GraderRunResponse, + ) + + async def validate( + self, + *, + grader: grader_validate_params.Grader, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> GraderValidateResponse: + """ + Validate a grader. + + Args: + grader: The grader used for the fine-tuning job. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/fine_tuning/alpha/graders/validate", + body=await async_maybe_transform({"grader": grader}, grader_validate_params.GraderValidateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GraderValidateResponse, + ) + + +class GradersWithRawResponse: + def __init__(self, graders: Graders) -> None: + self._graders = graders + + self.run = _legacy_response.to_raw_response_wrapper( + graders.run, + ) + self.validate = _legacy_response.to_raw_response_wrapper( + graders.validate, + ) + + +class AsyncGradersWithRawResponse: + def __init__(self, graders: AsyncGraders) -> None: + self._graders = graders + + self.run = _legacy_response.async_to_raw_response_wrapper( + graders.run, + ) + self.validate = _legacy_response.async_to_raw_response_wrapper( + graders.validate, + ) + + +class GradersWithStreamingResponse: + def __init__(self, graders: Graders) -> None: + self._graders = graders + + self.run = to_streamed_response_wrapper( + graders.run, + ) + self.validate = to_streamed_response_wrapper( + graders.validate, + ) + + +class AsyncGradersWithStreamingResponse: + def __init__(self, graders: AsyncGraders) -> None: + self._graders = graders + + self.run = async_to_streamed_response_wrapper( + graders.run, + ) + self.validate = async_to_streamed_response_wrapper( + graders.validate, + ) diff --git a/src/openai/resources/fine_tuning/fine_tuning.py b/src/openai/resources/fine_tuning/fine_tuning.py index 1388c8230c..25ae3e8cf4 100644 --- a/src/openai/resources/fine_tuning/fine_tuning.py +++ b/src/openai/resources/fine_tuning/fine_tuning.py @@ -12,6 +12,14 @@ AsyncJobsWithStreamingResponse, ) from ..._resource import SyncAPIResource, AsyncAPIResource +from .alpha.alpha import ( + Alpha, + AsyncAlpha, + AlphaWithRawResponse, + AsyncAlphaWithRawResponse, + AlphaWithStreamingResponse, + AsyncAlphaWithStreamingResponse, +) from .checkpoints.checkpoints import ( Checkpoints, AsyncCheckpoints, @@ -33,6 +41,10 @@ def jobs(self) -> Jobs: def checkpoints(self) -> Checkpoints: return Checkpoints(self._client) + @cached_property + def alpha(self) -> Alpha: + return Alpha(self._client) + @cached_property def with_raw_response(self) -> FineTuningWithRawResponse: """ @@ -62,6 +74,10 @@ def jobs(self) -> AsyncJobs: def checkpoints(self) -> AsyncCheckpoints: return AsyncCheckpoints(self._client) + @cached_property + def alpha(self) -> AsyncAlpha: + return AsyncAlpha(self._client) + @cached_property def with_raw_response(self) -> AsyncFineTuningWithRawResponse: """ @@ -94,6 +110,10 @@ def jobs(self) -> JobsWithRawResponse: def checkpoints(self) -> CheckpointsWithRawResponse: return CheckpointsWithRawResponse(self._fine_tuning.checkpoints) + @cached_property + def alpha(self) -> AlphaWithRawResponse: + return AlphaWithRawResponse(self._fine_tuning.alpha) + class AsyncFineTuningWithRawResponse: def __init__(self, fine_tuning: AsyncFineTuning) -> None: @@ -107,6 +127,10 @@ def jobs(self) -> AsyncJobsWithRawResponse: def checkpoints(self) -> AsyncCheckpointsWithRawResponse: return AsyncCheckpointsWithRawResponse(self._fine_tuning.checkpoints) + @cached_property + def alpha(self) -> AsyncAlphaWithRawResponse: + return AsyncAlphaWithRawResponse(self._fine_tuning.alpha) + class FineTuningWithStreamingResponse: def __init__(self, fine_tuning: FineTuning) -> None: @@ -120,6 +144,10 @@ def jobs(self) -> JobsWithStreamingResponse: def checkpoints(self) -> CheckpointsWithStreamingResponse: return CheckpointsWithStreamingResponse(self._fine_tuning.checkpoints) + @cached_property + def alpha(self) -> AlphaWithStreamingResponse: + return AlphaWithStreamingResponse(self._fine_tuning.alpha) + class AsyncFineTuningWithStreamingResponse: def __init__(self, fine_tuning: AsyncFineTuning) -> None: @@ -132,3 +160,7 @@ def jobs(self) -> AsyncJobsWithStreamingResponse: @cached_property def checkpoints(self) -> AsyncCheckpointsWithStreamingResponse: return AsyncCheckpointsWithStreamingResponse(self._fine_tuning.checkpoints) + + @cached_property + def alpha(self) -> AsyncAlphaWithStreamingResponse: + return AsyncAlphaWithStreamingResponse(self._fine_tuning.alpha) diff --git a/src/openai/resources/fine_tuning/jobs/jobs.py b/src/openai/resources/fine_tuning/jobs/jobs.py index 90619c8609..5cca219172 100644 --- a/src/openai/resources/fine_tuning/jobs/jobs.py +++ b/src/openai/resources/fine_tuning/jobs/jobs.py @@ -345,6 +345,72 @@ def list_events( model=FineTuningJobEvent, ) + def pause( + self, + fine_tuning_job_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> FineTuningJob: + """ + Pause a fine-tune job. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not fine_tuning_job_id: + raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") + return self._post( + f"/fine_tuning/jobs/{fine_tuning_job_id}/pause", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=FineTuningJob, + ) + + def resume( + self, + fine_tuning_job_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> FineTuningJob: + """ + Resume a fine-tune job. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not fine_tuning_job_id: + raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") + return self._post( + f"/fine_tuning/jobs/{fine_tuning_job_id}/resume", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=FineTuningJob, + ) + class AsyncJobs(AsyncAPIResource): @cached_property @@ -657,6 +723,72 @@ def list_events( model=FineTuningJobEvent, ) + async def pause( + self, + fine_tuning_job_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> FineTuningJob: + """ + Pause a fine-tune job. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not fine_tuning_job_id: + raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") + return await self._post( + f"/fine_tuning/jobs/{fine_tuning_job_id}/pause", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=FineTuningJob, + ) + + async def resume( + self, + fine_tuning_job_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> FineTuningJob: + """ + Resume a fine-tune job. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not fine_tuning_job_id: + raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") + return await self._post( + f"/fine_tuning/jobs/{fine_tuning_job_id}/resume", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=FineTuningJob, + ) + class JobsWithRawResponse: def __init__(self, jobs: Jobs) -> None: @@ -677,6 +809,12 @@ def __init__(self, jobs: Jobs) -> None: self.list_events = _legacy_response.to_raw_response_wrapper( jobs.list_events, ) + self.pause = _legacy_response.to_raw_response_wrapper( + jobs.pause, + ) + self.resume = _legacy_response.to_raw_response_wrapper( + jobs.resume, + ) @cached_property def checkpoints(self) -> CheckpointsWithRawResponse: @@ -702,6 +840,12 @@ def __init__(self, jobs: AsyncJobs) -> None: self.list_events = _legacy_response.async_to_raw_response_wrapper( jobs.list_events, ) + self.pause = _legacy_response.async_to_raw_response_wrapper( + jobs.pause, + ) + self.resume = _legacy_response.async_to_raw_response_wrapper( + jobs.resume, + ) @cached_property def checkpoints(self) -> AsyncCheckpointsWithRawResponse: @@ -727,6 +871,12 @@ def __init__(self, jobs: Jobs) -> None: self.list_events = to_streamed_response_wrapper( jobs.list_events, ) + self.pause = to_streamed_response_wrapper( + jobs.pause, + ) + self.resume = to_streamed_response_wrapper( + jobs.resume, + ) @cached_property def checkpoints(self) -> CheckpointsWithStreamingResponse: @@ -752,6 +902,12 @@ def __init__(self, jobs: AsyncJobs) -> None: self.list_events = async_to_streamed_response_wrapper( jobs.list_events, ) + self.pause = async_to_streamed_response_wrapper( + jobs.pause, + ) + self.resume = async_to_streamed_response_wrapper( + jobs.resume, + ) @cached_property def checkpoints(self) -> AsyncCheckpointsWithStreamingResponse: diff --git a/src/openai/types/__init__.py b/src/openai/types/__init__.py index 57c91811b9..bf5493fd62 100644 --- a/src/openai/types/__init__.py +++ b/src/openai/types/__init__.py @@ -61,9 +61,7 @@ from .file_chunking_strategy import FileChunkingStrategy as FileChunkingStrategy from .upload_complete_params import UploadCompleteParams as UploadCompleteParams from .embedding_create_params import EmbeddingCreateParams as EmbeddingCreateParams -from .eval_label_model_grader import EvalLabelModelGrader as EvalLabelModelGrader from .completion_create_params import CompletionCreateParams as CompletionCreateParams -from .eval_string_check_grader import EvalStringCheckGrader as EvalStringCheckGrader from .moderation_create_params import ModerationCreateParams as ModerationCreateParams from .vector_store_list_params import VectorStoreListParams as VectorStoreListParams from .create_embedding_response import CreateEmbeddingResponse as CreateEmbeddingResponse @@ -71,7 +69,6 @@ from .vector_store_create_params import VectorStoreCreateParams as VectorStoreCreateParams from .vector_store_search_params import VectorStoreSearchParams as VectorStoreSearchParams from .vector_store_update_params import VectorStoreUpdateParams as VectorStoreUpdateParams -from .eval_text_similarity_grader import EvalTextSimilarityGrader as EvalTextSimilarityGrader from .moderation_text_input_param import ModerationTextInputParam as ModerationTextInputParam from .file_chunking_strategy_param import FileChunkingStrategyParam as FileChunkingStrategyParam from .vector_store_search_response import VectorStoreSearchResponse as VectorStoreSearchResponse @@ -79,10 +76,8 @@ from .image_create_variation_params import ImageCreateVariationParams as ImageCreateVariationParams from .static_file_chunking_strategy import StaticFileChunkingStrategy as StaticFileChunkingStrategy from .eval_custom_data_source_config import EvalCustomDataSourceConfig as EvalCustomDataSourceConfig -from .eval_string_check_grader_param import EvalStringCheckGraderParam as EvalStringCheckGraderParam from .moderation_image_url_input_param import ModerationImageURLInputParam as ModerationImageURLInputParam from .auto_file_chunking_strategy_param import AutoFileChunkingStrategyParam as AutoFileChunkingStrategyParam -from .eval_text_similarity_grader_param import EvalTextSimilarityGraderParam as EvalTextSimilarityGraderParam from .moderation_multi_modal_input_param import ModerationMultiModalInputParam as ModerationMultiModalInputParam from .other_file_chunking_strategy_object import OtherFileChunkingStrategyObject as OtherFileChunkingStrategyObject from .static_file_chunking_strategy_param import StaticFileChunkingStrategyParam as StaticFileChunkingStrategyParam diff --git a/src/openai/types/eval_create_params.py b/src/openai/types/eval_create_params.py index 03f44f2c8c..66178287e4 100644 --- a/src/openai/types/eval_create_params.py +++ b/src/openai/types/eval_create_params.py @@ -6,15 +6,17 @@ from typing_extensions import Literal, Required, TypeAlias, TypedDict from .shared_params.metadata import Metadata -from .eval_string_check_grader_param import EvalStringCheckGraderParam -from .eval_text_similarity_grader_param import EvalTextSimilarityGraderParam +from .graders.python_grader_param import PythonGraderParam +from .graders.score_model_grader_param import ScoreModelGraderParam +from .graders.string_check_grader_param import StringCheckGraderParam from .responses.response_input_text_param import ResponseInputTextParam +from .graders.text_similarity_grader_param import TextSimilarityGraderParam __all__ = [ "EvalCreateParams", "DataSourceConfig", "DataSourceConfigCustom", - "DataSourceConfigLogs", + "DataSourceConfigStoredCompletions", "TestingCriterion", "TestingCriterionLabelModel", "TestingCriterionLabelModelInput", @@ -22,11 +24,9 @@ "TestingCriterionLabelModelInputEvalItem", "TestingCriterionLabelModelInputEvalItemContent", "TestingCriterionLabelModelInputEvalItemContentOutputText", + "TestingCriterionTextSimilarity", "TestingCriterionPython", "TestingCriterionScoreModel", - "TestingCriterionScoreModelInput", - "TestingCriterionScoreModelInputContent", - "TestingCriterionScoreModelInputContentOutputText", ] @@ -65,15 +65,15 @@ class DataSourceConfigCustom(TypedDict, total=False): """ -class DataSourceConfigLogs(TypedDict, total=False): - type: Required[Literal["logs"]] - """The type of data source. Always `logs`.""" +class DataSourceConfigStoredCompletions(TypedDict, total=False): + type: Required[Literal["stored_completions"]] + """The type of data source. Always `stored_completions`.""" metadata: Dict[str, object] - """Metadata filters for the logs data source.""" + """Metadata filters for the stored completions data source.""" -DataSourceConfig: TypeAlias = Union[DataSourceConfigCustom, DataSourceConfigLogs] +DataSourceConfig: TypeAlias = Union[DataSourceConfigCustom, DataSourceConfigStoredCompletions] class TestingCriterionLabelModelInputSimpleInputMessage(TypedDict, total=False): @@ -139,77 +139,28 @@ class TestingCriterionLabelModel(TypedDict, total=False): """The object type, which is always `label_model`.""" -class TestingCriterionPython(TypedDict, total=False): - name: Required[str] - """The name of the grader.""" - - source: Required[str] - """The source code of the python script.""" - - type: Required[Literal["python"]] - """The object type, which is always `python`.""" +class TestingCriterionTextSimilarity(TextSimilarityGraderParam, total=False): + __test__ = False + pass_threshold: Required[float] + """The threshold for the score.""" - image_tag: str - """The image tag to use for the python script.""" +class TestingCriterionPython(PythonGraderParam, total=False): + __test__ = False pass_threshold: float """The threshold for the score.""" -class TestingCriterionScoreModelInputContentOutputText(TypedDict, total=False): - text: Required[str] - """The text output from the model.""" - - type: Required[Literal["output_text"]] - """The type of the output text. Always `output_text`.""" - - -TestingCriterionScoreModelInputContent: TypeAlias = Union[ - str, ResponseInputTextParam, TestingCriterionScoreModelInputContentOutputText -] - - -class TestingCriterionScoreModelInput(TypedDict, total=False): - content: Required[TestingCriterionScoreModelInputContent] - """Text inputs to the model - can contain template strings.""" - - role: Required[Literal["user", "assistant", "system", "developer"]] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Literal["message"] - """The type of the message input. Always `message`.""" - - -class TestingCriterionScoreModel(TypedDict, total=False): - input: Required[Iterable[TestingCriterionScoreModelInput]] - """The input text. This may include template strings.""" - - model: Required[str] - """The model to use for the evaluation.""" - - name: Required[str] - """The name of the grader.""" - - type: Required[Literal["score_model"]] - """The object type, which is always `score_model`.""" - +class TestingCriterionScoreModel(ScoreModelGraderParam, total=False): + __test__ = False pass_threshold: float """The threshold for the score.""" - range: Iterable[float] - """The range of the score. Defaults to `[0, 1]`.""" - - sampling_params: object - """The sampling parameters for the model.""" - TestingCriterion: TypeAlias = Union[ TestingCriterionLabelModel, - EvalStringCheckGraderParam, - EvalTextSimilarityGraderParam, + StringCheckGraderParam, + TestingCriterionTextSimilarity, TestingCriterionPython, TestingCriterionScoreModel, ] diff --git a/src/openai/types/eval_create_response.py b/src/openai/types/eval_create_response.py index 6d77a81870..d5f158ad29 100644 --- a/src/openai/types/eval_create_response.py +++ b/src/openai/types/eval_create_response.py @@ -6,22 +6,21 @@ from .._utils import PropertyInfo from .._models import BaseModel from .shared.metadata import Metadata -from .eval_label_model_grader import EvalLabelModelGrader -from .eval_string_check_grader import EvalStringCheckGrader -from .eval_text_similarity_grader import EvalTextSimilarityGrader -from .responses.response_input_text import ResponseInputText +from .graders.python_grader import PythonGrader +from .graders.label_model_grader import LabelModelGrader +from .graders.score_model_grader import ScoreModelGrader +from .graders.string_check_grader import StringCheckGrader from .eval_custom_data_source_config import EvalCustomDataSourceConfig +from .graders.text_similarity_grader import TextSimilarityGrader from .eval_stored_completions_data_source_config import EvalStoredCompletionsDataSourceConfig __all__ = [ "EvalCreateResponse", "DataSourceConfig", "TestingCriterion", - "TestingCriterionPython", - "TestingCriterionScoreModel", - "TestingCriterionScoreModelInput", - "TestingCriterionScoreModelInputContent", - "TestingCriterionScoreModelInputContentOutputText", + "TestingCriterionEvalGraderTextSimilarity", + "TestingCriterionEvalGraderPython", + "TestingCriterionEvalGraderScoreModel", ] DataSourceConfig: TypeAlias = Annotated[ @@ -29,86 +28,30 @@ ] -class TestingCriterionPython(BaseModel): +class TestingCriterionEvalGraderTextSimilarity(TextSimilarityGrader): __test__ = False - name: str - """The name of the grader.""" - - source: str - """The source code of the python script.""" - - type: Literal["python"] - """The object type, which is always `python`.""" - - image_tag: Optional[str] = None - """The image tag to use for the python script.""" - - pass_threshold: Optional[float] = None + pass_threshold: float """The threshold for the score.""" -class TestingCriterionScoreModelInputContentOutputText(BaseModel): - __test__ = False - text: str - """The text output from the model.""" - - type: Literal["output_text"] - """The type of the output text. Always `output_text`.""" - - -TestingCriterionScoreModelInputContent: TypeAlias = Union[ - str, ResponseInputText, TestingCriterionScoreModelInputContentOutputText -] - - -class TestingCriterionScoreModelInput(BaseModel): +class TestingCriterionEvalGraderPython(PythonGrader): __test__ = False - content: TestingCriterionScoreModelInputContent - """Text inputs to the model - can contain template strings.""" - - role: Literal["user", "assistant", "system", "developer"] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Optional[Literal["message"]] = None - """The type of the message input. Always `message`.""" + pass_threshold: Optional[float] = None + """The threshold for the score.""" -class TestingCriterionScoreModel(BaseModel): +class TestingCriterionEvalGraderScoreModel(ScoreModelGrader): __test__ = False - input: List[TestingCriterionScoreModelInput] - """The input text. This may include template strings.""" - - model: str - """The model to use for the evaluation.""" - - name: str - """The name of the grader.""" - - type: Literal["score_model"] - """The object type, which is always `score_model`.""" - pass_threshold: Optional[float] = None """The threshold for the score.""" - range: Optional[List[float]] = None - """The range of the score. Defaults to `[0, 1]`.""" - - sampling_params: Optional[object] = None - """The sampling parameters for the model.""" - -TestingCriterion: TypeAlias = Annotated[ - Union[ - EvalLabelModelGrader, - EvalStringCheckGrader, - EvalTextSimilarityGrader, - TestingCriterionPython, - TestingCriterionScoreModel, - ], - PropertyInfo(discriminator="type"), +TestingCriterion: TypeAlias = Union[ + LabelModelGrader, + StringCheckGrader, + TestingCriterionEvalGraderTextSimilarity, + TestingCriterionEvalGraderPython, + TestingCriterionEvalGraderScoreModel, ] diff --git a/src/openai/types/eval_list_response.py b/src/openai/types/eval_list_response.py index 8c7e9c5588..b743f57f6a 100644 --- a/src/openai/types/eval_list_response.py +++ b/src/openai/types/eval_list_response.py @@ -6,22 +6,21 @@ from .._utils import PropertyInfo from .._models import BaseModel from .shared.metadata import Metadata -from .eval_label_model_grader import EvalLabelModelGrader -from .eval_string_check_grader import EvalStringCheckGrader -from .eval_text_similarity_grader import EvalTextSimilarityGrader -from .responses.response_input_text import ResponseInputText +from .graders.python_grader import PythonGrader +from .graders.label_model_grader import LabelModelGrader +from .graders.score_model_grader import ScoreModelGrader +from .graders.string_check_grader import StringCheckGrader from .eval_custom_data_source_config import EvalCustomDataSourceConfig +from .graders.text_similarity_grader import TextSimilarityGrader from .eval_stored_completions_data_source_config import EvalStoredCompletionsDataSourceConfig __all__ = [ "EvalListResponse", "DataSourceConfig", "TestingCriterion", - "TestingCriterionPython", - "TestingCriterionScoreModel", - "TestingCriterionScoreModelInput", - "TestingCriterionScoreModelInputContent", - "TestingCriterionScoreModelInputContentOutputText", + "TestingCriterionEvalGraderTextSimilarity", + "TestingCriterionEvalGraderPython", + "TestingCriterionEvalGraderScoreModel", ] DataSourceConfig: TypeAlias = Annotated[ @@ -29,86 +28,30 @@ ] -class TestingCriterionPython(BaseModel): +class TestingCriterionEvalGraderTextSimilarity(TextSimilarityGrader): __test__ = False - name: str - """The name of the grader.""" - - source: str - """The source code of the python script.""" - - type: Literal["python"] - """The object type, which is always `python`.""" - - image_tag: Optional[str] = None - """The image tag to use for the python script.""" - - pass_threshold: Optional[float] = None + pass_threshold: float """The threshold for the score.""" -class TestingCriterionScoreModelInputContentOutputText(BaseModel): - __test__ = False - text: str - """The text output from the model.""" - - type: Literal["output_text"] - """The type of the output text. Always `output_text`.""" - - -TestingCriterionScoreModelInputContent: TypeAlias = Union[ - str, ResponseInputText, TestingCriterionScoreModelInputContentOutputText -] - - -class TestingCriterionScoreModelInput(BaseModel): +class TestingCriterionEvalGraderPython(PythonGrader): __test__ = False - content: TestingCriterionScoreModelInputContent - """Text inputs to the model - can contain template strings.""" - - role: Literal["user", "assistant", "system", "developer"] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Optional[Literal["message"]] = None - """The type of the message input. Always `message`.""" + pass_threshold: Optional[float] = None + """The threshold for the score.""" -class TestingCriterionScoreModel(BaseModel): +class TestingCriterionEvalGraderScoreModel(ScoreModelGrader): __test__ = False - input: List[TestingCriterionScoreModelInput] - """The input text. This may include template strings.""" - - model: str - """The model to use for the evaluation.""" - - name: str - """The name of the grader.""" - - type: Literal["score_model"] - """The object type, which is always `score_model`.""" - pass_threshold: Optional[float] = None """The threshold for the score.""" - range: Optional[List[float]] = None - """The range of the score. Defaults to `[0, 1]`.""" - - sampling_params: Optional[object] = None - """The sampling parameters for the model.""" - -TestingCriterion: TypeAlias = Annotated[ - Union[ - EvalLabelModelGrader, - EvalStringCheckGrader, - EvalTextSimilarityGrader, - TestingCriterionPython, - TestingCriterionScoreModel, - ], - PropertyInfo(discriminator="type"), +TestingCriterion: TypeAlias = Union[ + LabelModelGrader, + StringCheckGrader, + TestingCriterionEvalGraderTextSimilarity, + TestingCriterionEvalGraderPython, + TestingCriterionEvalGraderScoreModel, ] diff --git a/src/openai/types/eval_retrieve_response.py b/src/openai/types/eval_retrieve_response.py index 625bae80f4..dabb20674e 100644 --- a/src/openai/types/eval_retrieve_response.py +++ b/src/openai/types/eval_retrieve_response.py @@ -6,22 +6,21 @@ from .._utils import PropertyInfo from .._models import BaseModel from .shared.metadata import Metadata -from .eval_label_model_grader import EvalLabelModelGrader -from .eval_string_check_grader import EvalStringCheckGrader -from .eval_text_similarity_grader import EvalTextSimilarityGrader -from .responses.response_input_text import ResponseInputText +from .graders.python_grader import PythonGrader +from .graders.label_model_grader import LabelModelGrader +from .graders.score_model_grader import ScoreModelGrader +from .graders.string_check_grader import StringCheckGrader from .eval_custom_data_source_config import EvalCustomDataSourceConfig +from .graders.text_similarity_grader import TextSimilarityGrader from .eval_stored_completions_data_source_config import EvalStoredCompletionsDataSourceConfig __all__ = [ "EvalRetrieveResponse", "DataSourceConfig", "TestingCriterion", - "TestingCriterionPython", - "TestingCriterionScoreModel", - "TestingCriterionScoreModelInput", - "TestingCriterionScoreModelInputContent", - "TestingCriterionScoreModelInputContentOutputText", + "TestingCriterionEvalGraderTextSimilarity", + "TestingCriterionEvalGraderPython", + "TestingCriterionEvalGraderScoreModel", ] DataSourceConfig: TypeAlias = Annotated[ @@ -29,86 +28,30 @@ ] -class TestingCriterionPython(BaseModel): +class TestingCriterionEvalGraderTextSimilarity(TextSimilarityGrader): __test__ = False - name: str - """The name of the grader.""" - - source: str - """The source code of the python script.""" - - type: Literal["python"] - """The object type, which is always `python`.""" - - image_tag: Optional[str] = None - """The image tag to use for the python script.""" - - pass_threshold: Optional[float] = None + pass_threshold: float """The threshold for the score.""" -class TestingCriterionScoreModelInputContentOutputText(BaseModel): - __test__ = False - text: str - """The text output from the model.""" - - type: Literal["output_text"] - """The type of the output text. Always `output_text`.""" - - -TestingCriterionScoreModelInputContent: TypeAlias = Union[ - str, ResponseInputText, TestingCriterionScoreModelInputContentOutputText -] - - -class TestingCriterionScoreModelInput(BaseModel): +class TestingCriterionEvalGraderPython(PythonGrader): __test__ = False - content: TestingCriterionScoreModelInputContent - """Text inputs to the model - can contain template strings.""" - - role: Literal["user", "assistant", "system", "developer"] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Optional[Literal["message"]] = None - """The type of the message input. Always `message`.""" + pass_threshold: Optional[float] = None + """The threshold for the score.""" -class TestingCriterionScoreModel(BaseModel): +class TestingCriterionEvalGraderScoreModel(ScoreModelGrader): __test__ = False - input: List[TestingCriterionScoreModelInput] - """The input text. This may include template strings.""" - - model: str - """The model to use for the evaluation.""" - - name: str - """The name of the grader.""" - - type: Literal["score_model"] - """The object type, which is always `score_model`.""" - pass_threshold: Optional[float] = None """The threshold for the score.""" - range: Optional[List[float]] = None - """The range of the score. Defaults to `[0, 1]`.""" - - sampling_params: Optional[object] = None - """The sampling parameters for the model.""" - -TestingCriterion: TypeAlias = Annotated[ - Union[ - EvalLabelModelGrader, - EvalStringCheckGrader, - EvalTextSimilarityGrader, - TestingCriterionPython, - TestingCriterionScoreModel, - ], - PropertyInfo(discriminator="type"), +TestingCriterion: TypeAlias = Union[ + LabelModelGrader, + StringCheckGrader, + TestingCriterionEvalGraderTextSimilarity, + TestingCriterionEvalGraderPython, + TestingCriterionEvalGraderScoreModel, ] diff --git a/src/openai/types/eval_update_response.py b/src/openai/types/eval_update_response.py index 2c280977a1..c5cb2622ea 100644 --- a/src/openai/types/eval_update_response.py +++ b/src/openai/types/eval_update_response.py @@ -6,22 +6,21 @@ from .._utils import PropertyInfo from .._models import BaseModel from .shared.metadata import Metadata -from .eval_label_model_grader import EvalLabelModelGrader -from .eval_string_check_grader import EvalStringCheckGrader -from .eval_text_similarity_grader import EvalTextSimilarityGrader -from .responses.response_input_text import ResponseInputText +from .graders.python_grader import PythonGrader +from .graders.label_model_grader import LabelModelGrader +from .graders.score_model_grader import ScoreModelGrader +from .graders.string_check_grader import StringCheckGrader from .eval_custom_data_source_config import EvalCustomDataSourceConfig +from .graders.text_similarity_grader import TextSimilarityGrader from .eval_stored_completions_data_source_config import EvalStoredCompletionsDataSourceConfig __all__ = [ "EvalUpdateResponse", "DataSourceConfig", "TestingCriterion", - "TestingCriterionPython", - "TestingCriterionScoreModel", - "TestingCriterionScoreModelInput", - "TestingCriterionScoreModelInputContent", - "TestingCriterionScoreModelInputContentOutputText", + "TestingCriterionEvalGraderTextSimilarity", + "TestingCriterionEvalGraderPython", + "TestingCriterionEvalGraderScoreModel", ] DataSourceConfig: TypeAlias = Annotated[ @@ -29,86 +28,30 @@ ] -class TestingCriterionPython(BaseModel): +class TestingCriterionEvalGraderTextSimilarity(TextSimilarityGrader): __test__ = False - name: str - """The name of the grader.""" - - source: str - """The source code of the python script.""" - - type: Literal["python"] - """The object type, which is always `python`.""" - - image_tag: Optional[str] = None - """The image tag to use for the python script.""" - - pass_threshold: Optional[float] = None + pass_threshold: float """The threshold for the score.""" -class TestingCriterionScoreModelInputContentOutputText(BaseModel): - __test__ = False - text: str - """The text output from the model.""" - - type: Literal["output_text"] - """The type of the output text. Always `output_text`.""" - - -TestingCriterionScoreModelInputContent: TypeAlias = Union[ - str, ResponseInputText, TestingCriterionScoreModelInputContentOutputText -] - - -class TestingCriterionScoreModelInput(BaseModel): +class TestingCriterionEvalGraderPython(PythonGrader): __test__ = False - content: TestingCriterionScoreModelInputContent - """Text inputs to the model - can contain template strings.""" - - role: Literal["user", "assistant", "system", "developer"] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Optional[Literal["message"]] = None - """The type of the message input. Always `message`.""" + pass_threshold: Optional[float] = None + """The threshold for the score.""" -class TestingCriterionScoreModel(BaseModel): +class TestingCriterionEvalGraderScoreModel(ScoreModelGrader): __test__ = False - input: List[TestingCriterionScoreModelInput] - """The input text. This may include template strings.""" - - model: str - """The model to use for the evaluation.""" - - name: str - """The name of the grader.""" - - type: Literal["score_model"] - """The object type, which is always `score_model`.""" - pass_threshold: Optional[float] = None """The threshold for the score.""" - range: Optional[List[float]] = None - """The range of the score. Defaults to `[0, 1]`.""" - - sampling_params: Optional[object] = None - """The sampling parameters for the model.""" - -TestingCriterion: TypeAlias = Annotated[ - Union[ - EvalLabelModelGrader, - EvalStringCheckGrader, - EvalTextSimilarityGrader, - TestingCriterionPython, - TestingCriterionScoreModel, - ], - PropertyInfo(discriminator="type"), +TestingCriterion: TypeAlias = Union[ + LabelModelGrader, + StringCheckGrader, + TestingCriterionEvalGraderTextSimilarity, + TestingCriterionEvalGraderPython, + TestingCriterionEvalGraderScoreModel, ] diff --git a/src/openai/types/fine_tuning/__init__.py b/src/openai/types/fine_tuning/__init__.py index 92b81329b1..cc664eacea 100644 --- a/src/openai/types/fine_tuning/__init__.py +++ b/src/openai/types/fine_tuning/__init__.py @@ -2,13 +2,25 @@ from __future__ import annotations +from .dpo_method import DpoMethod as DpoMethod from .fine_tuning_job import FineTuningJob as FineTuningJob from .job_list_params import JobListParams as JobListParams +from .dpo_method_param import DpoMethodParam as DpoMethodParam from .job_create_params import JobCreateParams as JobCreateParams +from .supervised_method import SupervisedMethod as SupervisedMethod +from .dpo_hyperparameters import DpoHyperparameters as DpoHyperparameters +from .reinforcement_method import ReinforcementMethod as ReinforcementMethod from .fine_tuning_job_event import FineTuningJobEvent as FineTuningJobEvent from .job_list_events_params import JobListEventsParams as JobListEventsParams +from .supervised_method_param import SupervisedMethodParam as SupervisedMethodParam +from .dpo_hyperparameters_param import DpoHyperparametersParam as DpoHyperparametersParam +from .reinforcement_method_param import ReinforcementMethodParam as ReinforcementMethodParam +from .supervised_hyperparameters import SupervisedHyperparameters as SupervisedHyperparameters from .fine_tuning_job_integration import FineTuningJobIntegration as FineTuningJobIntegration +from .reinforcement_hyperparameters import ReinforcementHyperparameters as ReinforcementHyperparameters +from .supervised_hyperparameters_param import SupervisedHyperparametersParam as SupervisedHyperparametersParam from .fine_tuning_job_wandb_integration import FineTuningJobWandbIntegration as FineTuningJobWandbIntegration +from .reinforcement_hyperparameters_param import ReinforcementHyperparametersParam as ReinforcementHyperparametersParam from .fine_tuning_job_wandb_integration_object import ( FineTuningJobWandbIntegrationObject as FineTuningJobWandbIntegrationObject, ) diff --git a/src/openai/types/fine_tuning/alpha/__init__.py b/src/openai/types/fine_tuning/alpha/__init__.py new file mode 100644 index 0000000000..6394961b0b --- /dev/null +++ b/src/openai/types/fine_tuning/alpha/__init__.py @@ -0,0 +1,8 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .grader_run_params import GraderRunParams as GraderRunParams +from .grader_run_response import GraderRunResponse as GraderRunResponse +from .grader_validate_params import GraderValidateParams as GraderValidateParams +from .grader_validate_response import GraderValidateResponse as GraderValidateResponse diff --git a/src/openai/types/fine_tuning/alpha/grader_run_params.py b/src/openai/types/fine_tuning/alpha/grader_run_params.py new file mode 100644 index 0000000000..fa729f55ba --- /dev/null +++ b/src/openai/types/fine_tuning/alpha/grader_run_params.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable +from typing_extensions import Required, TypeAlias, TypedDict + +from ...graders.multi_grader_param import MultiGraderParam +from ...graders.python_grader_param import PythonGraderParam +from ...graders.score_model_grader_param import ScoreModelGraderParam +from ...graders.string_check_grader_param import StringCheckGraderParam +from ...graders.text_similarity_grader_param import TextSimilarityGraderParam + +__all__ = ["GraderRunParams", "Grader"] + + +class GraderRunParams(TypedDict, total=False): + grader: Required[Grader] + """The grader used for the fine-tuning job.""" + + model_sample: Required[str] + """The model sample to be evaluated.""" + + reference_answer: Required[Union[str, Iterable[object], float, object]] + """The reference answer for the evaluation.""" + + +Grader: TypeAlias = Union[ + StringCheckGraderParam, TextSimilarityGraderParam, PythonGraderParam, ScoreModelGraderParam, MultiGraderParam +] diff --git a/src/openai/types/fine_tuning/alpha/grader_run_response.py b/src/openai/types/fine_tuning/alpha/grader_run_response.py new file mode 100644 index 0000000000..8ef046d133 --- /dev/null +++ b/src/openai/types/fine_tuning/alpha/grader_run_response.py @@ -0,0 +1,67 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Optional + +from pydantic import Field as FieldInfo + +from ...._models import BaseModel + +__all__ = ["GraderRunResponse", "Metadata", "MetadataErrors"] + + +class MetadataErrors(BaseModel): + formula_parse_error: bool + + invalid_variable_error: bool + + api_model_grader_parse_error: bool = FieldInfo(alias="model_grader_parse_error") + + api_model_grader_refusal_error: bool = FieldInfo(alias="model_grader_refusal_error") + + api_model_grader_server_error: bool = FieldInfo(alias="model_grader_server_error") + + api_model_grader_server_error_details: Optional[str] = FieldInfo( + alias="model_grader_server_error_details", default=None + ) + + other_error: bool + + python_grader_runtime_error: bool + + python_grader_runtime_error_details: Optional[str] = None + + python_grader_server_error: bool + + python_grader_server_error_type: Optional[str] = None + + sample_parse_error: bool + + truncated_observation_error: bool + + unresponsive_reward_error: bool + + +class Metadata(BaseModel): + errors: MetadataErrors + + execution_time: float + + name: str + + sampled_model_name: Optional[str] = None + + scores: Dict[str, object] + + token_usage: Optional[int] = None + + type: str + + +class GraderRunResponse(BaseModel): + metadata: Metadata + + api_model_grader_token_usage_per_model: Dict[str, object] = FieldInfo(alias="model_grader_token_usage_per_model") + + reward: float + + sub_rewards: Dict[str, object] diff --git a/src/openai/types/fine_tuning/alpha/grader_validate_params.py b/src/openai/types/fine_tuning/alpha/grader_validate_params.py new file mode 100644 index 0000000000..fe9eb44e32 --- /dev/null +++ b/src/openai/types/fine_tuning/alpha/grader_validate_params.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import Required, TypeAlias, TypedDict + +from ...graders.multi_grader_param import MultiGraderParam +from ...graders.python_grader_param import PythonGraderParam +from ...graders.score_model_grader_param import ScoreModelGraderParam +from ...graders.string_check_grader_param import StringCheckGraderParam +from ...graders.text_similarity_grader_param import TextSimilarityGraderParam + +__all__ = ["GraderValidateParams", "Grader"] + + +class GraderValidateParams(TypedDict, total=False): + grader: Required[Grader] + """The grader used for the fine-tuning job.""" + + +Grader: TypeAlias = Union[ + StringCheckGraderParam, TextSimilarityGraderParam, PythonGraderParam, ScoreModelGraderParam, MultiGraderParam +] diff --git a/src/openai/types/fine_tuning/alpha/grader_validate_response.py b/src/openai/types/fine_tuning/alpha/grader_validate_response.py new file mode 100644 index 0000000000..b373292d80 --- /dev/null +++ b/src/openai/types/fine_tuning/alpha/grader_validate_response.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union, Optional +from typing_extensions import TypeAlias + +from ...._models import BaseModel +from ...graders.multi_grader import MultiGrader +from ...graders.python_grader import PythonGrader +from ...graders.score_model_grader import ScoreModelGrader +from ...graders.string_check_grader import StringCheckGrader +from ...graders.text_similarity_grader import TextSimilarityGrader + +__all__ = ["GraderValidateResponse", "Grader"] + +Grader: TypeAlias = Union[StringCheckGrader, TextSimilarityGrader, PythonGrader, ScoreModelGrader, MultiGrader] + + +class GraderValidateResponse(BaseModel): + grader: Optional[Grader] = None + """The grader used for the fine-tuning job.""" diff --git a/src/openai/types/fine_tuning/dpo_hyperparameters.py b/src/openai/types/fine_tuning/dpo_hyperparameters.py new file mode 100644 index 0000000000..b0b3f0581b --- /dev/null +++ b/src/openai/types/fine_tuning/dpo_hyperparameters.py @@ -0,0 +1,36 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["DpoHyperparameters"] + + +class DpoHyperparameters(BaseModel): + batch_size: Union[Literal["auto"], int, None] = None + """Number of examples in each batch. + + A larger batch size means that model parameters are updated less frequently, but + with lower variance. + """ + + beta: Union[Literal["auto"], float, None] = None + """The beta value for the DPO method. + + A higher beta value will increase the weight of the penalty between the policy + and reference model. + """ + + learning_rate_multiplier: Union[Literal["auto"], float, None] = None + """Scaling factor for the learning rate. + + A smaller learning rate may be useful to avoid overfitting. + """ + + n_epochs: Union[Literal["auto"], int, None] = None + """The number of epochs to train the model for. + + An epoch refers to one full cycle through the training dataset. + """ diff --git a/src/openai/types/fine_tuning/dpo_hyperparameters_param.py b/src/openai/types/fine_tuning/dpo_hyperparameters_param.py new file mode 100644 index 0000000000..87c6ee80a5 --- /dev/null +++ b/src/openai/types/fine_tuning/dpo_hyperparameters_param.py @@ -0,0 +1,36 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import Literal, TypedDict + +__all__ = ["DpoHyperparametersParam"] + + +class DpoHyperparametersParam(TypedDict, total=False): + batch_size: Union[Literal["auto"], int] + """Number of examples in each batch. + + A larger batch size means that model parameters are updated less frequently, but + with lower variance. + """ + + beta: Union[Literal["auto"], float] + """The beta value for the DPO method. + + A higher beta value will increase the weight of the penalty between the policy + and reference model. + """ + + learning_rate_multiplier: Union[Literal["auto"], float] + """Scaling factor for the learning rate. + + A smaller learning rate may be useful to avoid overfitting. + """ + + n_epochs: Union[Literal["auto"], int] + """The number of epochs to train the model for. + + An epoch refers to one full cycle through the training dataset. + """ diff --git a/src/openai/types/fine_tuning/dpo_method.py b/src/openai/types/fine_tuning/dpo_method.py new file mode 100644 index 0000000000..3e20f360dd --- /dev/null +++ b/src/openai/types/fine_tuning/dpo_method.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel +from .dpo_hyperparameters import DpoHyperparameters + +__all__ = ["DpoMethod"] + + +class DpoMethod(BaseModel): + hyperparameters: Optional[DpoHyperparameters] = None + """The hyperparameters used for the DPO fine-tuning job.""" diff --git a/src/openai/types/fine_tuning/dpo_method_param.py b/src/openai/types/fine_tuning/dpo_method_param.py new file mode 100644 index 0000000000..ce6b6510f6 --- /dev/null +++ b/src/openai/types/fine_tuning/dpo_method_param.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +from .dpo_hyperparameters_param import DpoHyperparametersParam + +__all__ = ["DpoMethodParam"] + + +class DpoMethodParam(TypedDict, total=False): + hyperparameters: DpoHyperparametersParam + """The hyperparameters used for the DPO fine-tuning job.""" diff --git a/src/openai/types/fine_tuning/fine_tuning_job.py b/src/openai/types/fine_tuning/fine_tuning_job.py index c7fff2b7b1..f626fbba64 100644 --- a/src/openai/types/fine_tuning/fine_tuning_job.py +++ b/src/openai/types/fine_tuning/fine_tuning_job.py @@ -4,19 +4,13 @@ from typing_extensions import Literal from ..._models import BaseModel +from .dpo_method import DpoMethod from ..shared.metadata import Metadata +from .supervised_method import SupervisedMethod +from .reinforcement_method import ReinforcementMethod from .fine_tuning_job_wandb_integration_object import FineTuningJobWandbIntegrationObject -__all__ = [ - "FineTuningJob", - "Error", - "Hyperparameters", - "Method", - "MethodDpo", - "MethodDpoHyperparameters", - "MethodSupervised", - "MethodSupervisedHyperparameters", -] +__all__ = ["FineTuningJob", "Error", "Hyperparameters", "Method"] class Error(BaseModel): @@ -54,74 +48,18 @@ class Hyperparameters(BaseModel): """ -class MethodDpoHyperparameters(BaseModel): - batch_size: Union[Literal["auto"], int, None] = None - """Number of examples in each batch. - - A larger batch size means that model parameters are updated less frequently, but - with lower variance. - """ - - beta: Union[Literal["auto"], float, None] = None - """The beta value for the DPO method. - - A higher beta value will increase the weight of the penalty between the policy - and reference model. - """ - - learning_rate_multiplier: Union[Literal["auto"], float, None] = None - """Scaling factor for the learning rate. - - A smaller learning rate may be useful to avoid overfitting. - """ - - n_epochs: Union[Literal["auto"], int, None] = None - """The number of epochs to train the model for. - - An epoch refers to one full cycle through the training dataset. - """ - - -class MethodDpo(BaseModel): - hyperparameters: Optional[MethodDpoHyperparameters] = None - """The hyperparameters used for the fine-tuning job.""" - - -class MethodSupervisedHyperparameters(BaseModel): - batch_size: Union[Literal["auto"], int, None] = None - """Number of examples in each batch. - - A larger batch size means that model parameters are updated less frequently, but - with lower variance. - """ - - learning_rate_multiplier: Union[Literal["auto"], float, None] = None - """Scaling factor for the learning rate. - - A smaller learning rate may be useful to avoid overfitting. - """ - - n_epochs: Union[Literal["auto"], int, None] = None - """The number of epochs to train the model for. - - An epoch refers to one full cycle through the training dataset. - """ - - -class MethodSupervised(BaseModel): - hyperparameters: Optional[MethodSupervisedHyperparameters] = None - """The hyperparameters used for the fine-tuning job.""" - - class Method(BaseModel): - dpo: Optional[MethodDpo] = None + type: Literal["supervised", "dpo", "reinforcement"] + """The type of method. Is either `supervised`, `dpo`, or `reinforcement`.""" + + dpo: Optional[DpoMethod] = None """Configuration for the DPO fine-tuning method.""" - supervised: Optional[MethodSupervised] = None - """Configuration for the supervised fine-tuning method.""" + reinforcement: Optional[ReinforcementMethod] = None + """Configuration for the reinforcement fine-tuning method.""" - type: Optional[Literal["supervised", "dpo"]] = None - """The type of method. Is either `supervised` or `dpo`.""" + supervised: Optional[SupervisedMethod] = None + """Configuration for the supervised fine-tuning method.""" class FineTuningJob(BaseModel): diff --git a/src/openai/types/fine_tuning/job_create_params.py b/src/openai/types/fine_tuning/job_create_params.py index f4cf980b08..6b2f41cb71 100644 --- a/src/openai/types/fine_tuning/job_create_params.py +++ b/src/openai/types/fine_tuning/job_create_params.py @@ -5,19 +5,12 @@ from typing import List, Union, Iterable, Optional from typing_extensions import Literal, Required, TypedDict +from .dpo_method_param import DpoMethodParam from ..shared_params.metadata import Metadata +from .supervised_method_param import SupervisedMethodParam +from .reinforcement_method_param import ReinforcementMethodParam -__all__ = [ - "JobCreateParams", - "Hyperparameters", - "Integration", - "IntegrationWandb", - "Method", - "MethodDpo", - "MethodDpoHyperparameters", - "MethodSupervised", - "MethodSupervisedHyperparameters", -] +__all__ = ["JobCreateParams", "Hyperparameters", "Integration", "IntegrationWandb", "Method"] class JobCreateParams(TypedDict, total=False): @@ -166,71 +159,15 @@ class Integration(TypedDict, total=False): """ -class MethodDpoHyperparameters(TypedDict, total=False): - batch_size: Union[Literal["auto"], int] - """Number of examples in each batch. - - A larger batch size means that model parameters are updated less frequently, but - with lower variance. - """ - - beta: Union[Literal["auto"], float] - """The beta value for the DPO method. - - A higher beta value will increase the weight of the penalty between the policy - and reference model. - """ - - learning_rate_multiplier: Union[Literal["auto"], float] - """Scaling factor for the learning rate. - - A smaller learning rate may be useful to avoid overfitting. - """ - - n_epochs: Union[Literal["auto"], int] - """The number of epochs to train the model for. - - An epoch refers to one full cycle through the training dataset. - """ - - -class MethodDpo(TypedDict, total=False): - hyperparameters: MethodDpoHyperparameters - """The hyperparameters used for the fine-tuning job.""" - - -class MethodSupervisedHyperparameters(TypedDict, total=False): - batch_size: Union[Literal["auto"], int] - """Number of examples in each batch. - - A larger batch size means that model parameters are updated less frequently, but - with lower variance. - """ - - learning_rate_multiplier: Union[Literal["auto"], float] - """Scaling factor for the learning rate. - - A smaller learning rate may be useful to avoid overfitting. - """ - - n_epochs: Union[Literal["auto"], int] - """The number of epochs to train the model for. - - An epoch refers to one full cycle through the training dataset. - """ - - -class MethodSupervised(TypedDict, total=False): - hyperparameters: MethodSupervisedHyperparameters - """The hyperparameters used for the fine-tuning job.""" - - class Method(TypedDict, total=False): - dpo: MethodDpo + type: Required[Literal["supervised", "dpo", "reinforcement"]] + """The type of method. Is either `supervised`, `dpo`, or `reinforcement`.""" + + dpo: DpoMethodParam """Configuration for the DPO fine-tuning method.""" - supervised: MethodSupervised - """Configuration for the supervised fine-tuning method.""" + reinforcement: ReinforcementMethodParam + """Configuration for the reinforcement fine-tuning method.""" - type: Literal["supervised", "dpo"] - """The type of method. Is either `supervised` or `dpo`.""" + supervised: SupervisedMethodParam + """Configuration for the supervised fine-tuning method.""" diff --git a/src/openai/types/fine_tuning/reinforcement_hyperparameters.py b/src/openai/types/fine_tuning/reinforcement_hyperparameters.py new file mode 100644 index 0000000000..7c1762d38c --- /dev/null +++ b/src/openai/types/fine_tuning/reinforcement_hyperparameters.py @@ -0,0 +1,43 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union, Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ReinforcementHyperparameters"] + + +class ReinforcementHyperparameters(BaseModel): + batch_size: Union[Literal["auto"], int, None] = None + """Number of examples in each batch. + + A larger batch size means that model parameters are updated less frequently, but + with lower variance. + """ + + compute_multiplier: Union[Literal["auto"], float, None] = None + """ + Multiplier on amount of compute used for exploring search space during training. + """ + + eval_interval: Union[Literal["auto"], int, None] = None + """The number of training steps between evaluation runs.""" + + eval_samples: Union[Literal["auto"], int, None] = None + """Number of evaluation samples to generate per training step.""" + + learning_rate_multiplier: Union[Literal["auto"], float, None] = None + """Scaling factor for the learning rate. + + A smaller learning rate may be useful to avoid overfitting. + """ + + n_epochs: Union[Literal["auto"], int, None] = None + """The number of epochs to train the model for. + + An epoch refers to one full cycle through the training dataset. + """ + + reasoning_effort: Optional[Literal["default", "low", "medium", "high"]] = None + """Level of reasoning effort.""" diff --git a/src/openai/types/fine_tuning/reinforcement_hyperparameters_param.py b/src/openai/types/fine_tuning/reinforcement_hyperparameters_param.py new file mode 100644 index 0000000000..0cc12fcb17 --- /dev/null +++ b/src/openai/types/fine_tuning/reinforcement_hyperparameters_param.py @@ -0,0 +1,43 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import Literal, TypedDict + +__all__ = ["ReinforcementHyperparametersParam"] + + +class ReinforcementHyperparametersParam(TypedDict, total=False): + batch_size: Union[Literal["auto"], int] + """Number of examples in each batch. + + A larger batch size means that model parameters are updated less frequently, but + with lower variance. + """ + + compute_multiplier: Union[Literal["auto"], float] + """ + Multiplier on amount of compute used for exploring search space during training. + """ + + eval_interval: Union[Literal["auto"], int] + """The number of training steps between evaluation runs.""" + + eval_samples: Union[Literal["auto"], int] + """Number of evaluation samples to generate per training step.""" + + learning_rate_multiplier: Union[Literal["auto"], float] + """Scaling factor for the learning rate. + + A smaller learning rate may be useful to avoid overfitting. + """ + + n_epochs: Union[Literal["auto"], int] + """The number of epochs to train the model for. + + An epoch refers to one full cycle through the training dataset. + """ + + reasoning_effort: Literal["default", "low", "medium", "high"] + """Level of reasoning effort.""" diff --git a/src/openai/types/fine_tuning/reinforcement_method.py b/src/openai/types/fine_tuning/reinforcement_method.py new file mode 100644 index 0000000000..9b65c41033 --- /dev/null +++ b/src/openai/types/fine_tuning/reinforcement_method.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union, Optional +from typing_extensions import TypeAlias + +from ..._models import BaseModel +from ..graders.multi_grader import MultiGrader +from ..graders.python_grader import PythonGrader +from ..graders.score_model_grader import ScoreModelGrader +from ..graders.string_check_grader import StringCheckGrader +from .reinforcement_hyperparameters import ReinforcementHyperparameters +from ..graders.text_similarity_grader import TextSimilarityGrader + +__all__ = ["ReinforcementMethod", "Grader"] + +Grader: TypeAlias = Union[StringCheckGrader, TextSimilarityGrader, PythonGrader, ScoreModelGrader, MultiGrader] + + +class ReinforcementMethod(BaseModel): + grader: Grader + """The grader used for the fine-tuning job.""" + + hyperparameters: Optional[ReinforcementHyperparameters] = None + """The hyperparameters used for the reinforcement fine-tuning job.""" diff --git a/src/openai/types/fine_tuning/reinforcement_method_param.py b/src/openai/types/fine_tuning/reinforcement_method_param.py new file mode 100644 index 0000000000..00d5060536 --- /dev/null +++ b/src/openai/types/fine_tuning/reinforcement_method_param.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import Required, TypeAlias, TypedDict + +from ..graders.multi_grader_param import MultiGraderParam +from ..graders.python_grader_param import PythonGraderParam +from ..graders.score_model_grader_param import ScoreModelGraderParam +from ..graders.string_check_grader_param import StringCheckGraderParam +from .reinforcement_hyperparameters_param import ReinforcementHyperparametersParam +from ..graders.text_similarity_grader_param import TextSimilarityGraderParam + +__all__ = ["ReinforcementMethodParam", "Grader"] + +Grader: TypeAlias = Union[ + StringCheckGraderParam, TextSimilarityGraderParam, PythonGraderParam, ScoreModelGraderParam, MultiGraderParam +] + + +class ReinforcementMethodParam(TypedDict, total=False): + grader: Required[Grader] + """The grader used for the fine-tuning job.""" + + hyperparameters: ReinforcementHyperparametersParam + """The hyperparameters used for the reinforcement fine-tuning job.""" diff --git a/src/openai/types/fine_tuning/supervised_hyperparameters.py b/src/openai/types/fine_tuning/supervised_hyperparameters.py new file mode 100644 index 0000000000..3955ecf437 --- /dev/null +++ b/src/openai/types/fine_tuning/supervised_hyperparameters.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["SupervisedHyperparameters"] + + +class SupervisedHyperparameters(BaseModel): + batch_size: Union[Literal["auto"], int, None] = None + """Number of examples in each batch. + + A larger batch size means that model parameters are updated less frequently, but + with lower variance. + """ + + learning_rate_multiplier: Union[Literal["auto"], float, None] = None + """Scaling factor for the learning rate. + + A smaller learning rate may be useful to avoid overfitting. + """ + + n_epochs: Union[Literal["auto"], int, None] = None + """The number of epochs to train the model for. + + An epoch refers to one full cycle through the training dataset. + """ diff --git a/src/openai/types/fine_tuning/supervised_hyperparameters_param.py b/src/openai/types/fine_tuning/supervised_hyperparameters_param.py new file mode 100644 index 0000000000..bd37d9b239 --- /dev/null +++ b/src/openai/types/fine_tuning/supervised_hyperparameters_param.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import Literal, TypedDict + +__all__ = ["SupervisedHyperparametersParam"] + + +class SupervisedHyperparametersParam(TypedDict, total=False): + batch_size: Union[Literal["auto"], int] + """Number of examples in each batch. + + A larger batch size means that model parameters are updated less frequently, but + with lower variance. + """ + + learning_rate_multiplier: Union[Literal["auto"], float] + """Scaling factor for the learning rate. + + A smaller learning rate may be useful to avoid overfitting. + """ + + n_epochs: Union[Literal["auto"], int] + """The number of epochs to train the model for. + + An epoch refers to one full cycle through the training dataset. + """ diff --git a/src/openai/types/fine_tuning/supervised_method.py b/src/openai/types/fine_tuning/supervised_method.py new file mode 100644 index 0000000000..3a32bf27a0 --- /dev/null +++ b/src/openai/types/fine_tuning/supervised_method.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel +from .supervised_hyperparameters import SupervisedHyperparameters + +__all__ = ["SupervisedMethod"] + + +class SupervisedMethod(BaseModel): + hyperparameters: Optional[SupervisedHyperparameters] = None + """The hyperparameters used for the fine-tuning job.""" diff --git a/src/openai/types/fine_tuning/supervised_method_param.py b/src/openai/types/fine_tuning/supervised_method_param.py new file mode 100644 index 0000000000..ba277853d7 --- /dev/null +++ b/src/openai/types/fine_tuning/supervised_method_param.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +from .supervised_hyperparameters_param import SupervisedHyperparametersParam + +__all__ = ["SupervisedMethodParam"] + + +class SupervisedMethodParam(TypedDict, total=False): + hyperparameters: SupervisedHyperparametersParam + """The hyperparameters used for the fine-tuning job.""" diff --git a/src/openai/types/graders/__init__.py b/src/openai/types/graders/__init__.py new file mode 100644 index 0000000000..e0a909125e --- /dev/null +++ b/src/openai/types/graders/__init__.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .multi_grader import MultiGrader as MultiGrader +from .python_grader import PythonGrader as PythonGrader +from .label_model_grader import LabelModelGrader as LabelModelGrader +from .multi_grader_param import MultiGraderParam as MultiGraderParam +from .score_model_grader import ScoreModelGrader as ScoreModelGrader +from .python_grader_param import PythonGraderParam as PythonGraderParam +from .string_check_grader import StringCheckGrader as StringCheckGrader +from .text_similarity_grader import TextSimilarityGrader as TextSimilarityGrader +from .label_model_grader_param import LabelModelGraderParam as LabelModelGraderParam +from .score_model_grader_param import ScoreModelGraderParam as ScoreModelGraderParam +from .string_check_grader_param import StringCheckGraderParam as StringCheckGraderParam +from .text_similarity_grader_param import TextSimilarityGraderParam as TextSimilarityGraderParam diff --git a/src/openai/types/eval_label_model_grader.py b/src/openai/types/graders/label_model_grader.py similarity index 85% rename from src/openai/types/eval_label_model_grader.py rename to src/openai/types/graders/label_model_grader.py index 40e6bda140..d95ccc6df6 100644 --- a/src/openai/types/eval_label_model_grader.py +++ b/src/openai/types/graders/label_model_grader.py @@ -3,10 +3,10 @@ from typing import List, Union, Optional from typing_extensions import Literal, TypeAlias -from .._models import BaseModel -from .responses.response_input_text import ResponseInputText +from ..._models import BaseModel +from ..responses.response_input_text import ResponseInputText -__all__ = ["EvalLabelModelGrader", "Input", "InputContent", "InputContentOutputText"] +__all__ = ["LabelModelGrader", "Input", "InputContent", "InputContentOutputText"] class InputContentOutputText(BaseModel): @@ -34,7 +34,7 @@ class Input(BaseModel): """The type of the message input. Always `message`.""" -class EvalLabelModelGrader(BaseModel): +class LabelModelGrader(BaseModel): input: List[Input] labels: List[str] diff --git a/src/openai/types/graders/label_model_grader_param.py b/src/openai/types/graders/label_model_grader_param.py new file mode 100644 index 0000000000..76d01421ee --- /dev/null +++ b/src/openai/types/graders/label_model_grader_param.py @@ -0,0 +1,54 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union, Iterable +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from ..responses.response_input_text_param import ResponseInputTextParam + +__all__ = ["LabelModelGraderParam", "Input", "InputContent", "InputContentOutputText"] + + +class InputContentOutputText(TypedDict, total=False): + text: Required[str] + """The text output from the model.""" + + type: Required[Literal["output_text"]] + """The type of the output text. Always `output_text`.""" + + +InputContent: TypeAlias = Union[str, ResponseInputTextParam, InputContentOutputText] + + +class Input(TypedDict, total=False): + content: Required[InputContent] + """Text inputs to the model - can contain template strings.""" + + role: Required[Literal["user", "assistant", "system", "developer"]] + """The role of the message input. + + One of `user`, `assistant`, `system`, or `developer`. + """ + + type: Literal["message"] + """The type of the message input. Always `message`.""" + + +class LabelModelGraderParam(TypedDict, total=False): + input: Required[Iterable[Input]] + + labels: Required[List[str]] + """The labels to assign to each item in the evaluation.""" + + model: Required[str] + """The model to use for the evaluation. Must support structured outputs.""" + + name: Required[str] + """The name of the grader.""" + + passing_labels: Required[List[str]] + """The labels that indicate a passing result. Must be a subset of labels.""" + + type: Required[Literal["label_model"]] + """The object type, which is always `label_model`.""" diff --git a/src/openai/types/graders/multi_grader.py b/src/openai/types/graders/multi_grader.py new file mode 100644 index 0000000000..ee9b31d2b0 --- /dev/null +++ b/src/openai/types/graders/multi_grader.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Union +from typing_extensions import Literal, TypeAlias + +from ..._models import BaseModel +from .python_grader import PythonGrader +from .label_model_grader import LabelModelGrader +from .score_model_grader import ScoreModelGrader +from .string_check_grader import StringCheckGrader +from .text_similarity_grader import TextSimilarityGrader + +__all__ = ["MultiGrader", "Graders"] + +Graders: TypeAlias = Union[StringCheckGrader, TextSimilarityGrader, PythonGrader, ScoreModelGrader, LabelModelGrader] + + +class MultiGrader(BaseModel): + calculate_output: str + """A formula to calculate the output based on grader results.""" + + graders: Dict[str, Graders] + + name: str + """The name of the grader.""" + + type: Literal["multi"] + """The type of grader.""" diff --git a/src/openai/types/graders/multi_grader_param.py b/src/openai/types/graders/multi_grader_param.py new file mode 100644 index 0000000000..4dd1a48530 --- /dev/null +++ b/src/openai/types/graders/multi_grader_param.py @@ -0,0 +1,31 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .python_grader_param import PythonGraderParam +from .label_model_grader_param import LabelModelGraderParam +from .score_model_grader_param import ScoreModelGraderParam +from .string_check_grader_param import StringCheckGraderParam +from .text_similarity_grader_param import TextSimilarityGraderParam + +__all__ = ["MultiGraderParam", "Graders"] + +Graders: TypeAlias = Union[ + StringCheckGraderParam, TextSimilarityGraderParam, PythonGraderParam, ScoreModelGraderParam, LabelModelGraderParam +] + + +class MultiGraderParam(TypedDict, total=False): + calculate_output: Required[str] + """A formula to calculate the output based on grader results.""" + + graders: Required[Dict[str, Graders]] + + name: Required[str] + """The name of the grader.""" + + type: Required[Literal["multi"]] + """The type of grader.""" diff --git a/src/openai/types/graders/python_grader.py b/src/openai/types/graders/python_grader.py new file mode 100644 index 0000000000..faa10b1ef9 --- /dev/null +++ b/src/openai/types/graders/python_grader.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["PythonGrader"] + + +class PythonGrader(BaseModel): + name: str + """The name of the grader.""" + + source: str + """The source code of the python script.""" + + type: Literal["python"] + """The object type, which is always `python`.""" + + image_tag: Optional[str] = None + """The image tag to use for the python script.""" diff --git a/src/openai/types/graders/python_grader_param.py b/src/openai/types/graders/python_grader_param.py new file mode 100644 index 0000000000..efb923751e --- /dev/null +++ b/src/openai/types/graders/python_grader_param.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["PythonGraderParam"] + + +class PythonGraderParam(TypedDict, total=False): + name: Required[str] + """The name of the grader.""" + + source: Required[str] + """The source code of the python script.""" + + type: Required[Literal["python"]] + """The object type, which is always `python`.""" + + image_tag: str + """The image tag to use for the python script.""" diff --git a/src/openai/types/graders/score_model_grader.py b/src/openai/types/graders/score_model_grader.py new file mode 100644 index 0000000000..1349f75a58 --- /dev/null +++ b/src/openai/types/graders/score_model_grader.py @@ -0,0 +1,54 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, TypeAlias + +from ..._models import BaseModel +from ..responses.response_input_text import ResponseInputText + +__all__ = ["ScoreModelGrader", "Input", "InputContent", "InputContentOutputText"] + + +class InputContentOutputText(BaseModel): + text: str + """The text output from the model.""" + + type: Literal["output_text"] + """The type of the output text. Always `output_text`.""" + + +InputContent: TypeAlias = Union[str, ResponseInputText, InputContentOutputText] + + +class Input(BaseModel): + content: InputContent + """Text inputs to the model - can contain template strings.""" + + role: Literal["user", "assistant", "system", "developer"] + """The role of the message input. + + One of `user`, `assistant`, `system`, or `developer`. + """ + + type: Optional[Literal["message"]] = None + """The type of the message input. Always `message`.""" + + +class ScoreModelGrader(BaseModel): + input: List[Input] + """The input text. This may include template strings.""" + + model: str + """The model to use for the evaluation.""" + + name: str + """The name of the grader.""" + + type: Literal["score_model"] + """The object type, which is always `score_model`.""" + + range: Optional[List[float]] = None + """The range of the score. Defaults to `[0, 1]`.""" + + sampling_params: Optional[object] = None + """The sampling parameters for the model.""" diff --git a/src/openai/types/graders/score_model_grader_param.py b/src/openai/types/graders/score_model_grader_param.py new file mode 100644 index 0000000000..673f14e47d --- /dev/null +++ b/src/openai/types/graders/score_model_grader_param.py @@ -0,0 +1,55 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from ..responses.response_input_text_param import ResponseInputTextParam + +__all__ = ["ScoreModelGraderParam", "Input", "InputContent", "InputContentOutputText"] + + +class InputContentOutputText(TypedDict, total=False): + text: Required[str] + """The text output from the model.""" + + type: Required[Literal["output_text"]] + """The type of the output text. Always `output_text`.""" + + +InputContent: TypeAlias = Union[str, ResponseInputTextParam, InputContentOutputText] + + +class Input(TypedDict, total=False): + content: Required[InputContent] + """Text inputs to the model - can contain template strings.""" + + role: Required[Literal["user", "assistant", "system", "developer"]] + """The role of the message input. + + One of `user`, `assistant`, `system`, or `developer`. + """ + + type: Literal["message"] + """The type of the message input. Always `message`.""" + + +class ScoreModelGraderParam(TypedDict, total=False): + input: Required[Iterable[Input]] + """The input text. This may include template strings.""" + + model: Required[str] + """The model to use for the evaluation.""" + + name: Required[str] + """The name of the grader.""" + + type: Required[Literal["score_model"]] + """The object type, which is always `score_model`.""" + + range: Iterable[float] + """The range of the score. Defaults to `[0, 1]`.""" + + sampling_params: object + """The sampling parameters for the model.""" diff --git a/src/openai/types/eval_string_check_grader.py b/src/openai/types/graders/string_check_grader.py similarity index 84% rename from src/openai/types/eval_string_check_grader.py rename to src/openai/types/graders/string_check_grader.py index 4dfc8035f9..3bf0b8c868 100644 --- a/src/openai/types/eval_string_check_grader.py +++ b/src/openai/types/graders/string_check_grader.py @@ -2,12 +2,12 @@ from typing_extensions import Literal -from .._models import BaseModel +from ..._models import BaseModel -__all__ = ["EvalStringCheckGrader"] +__all__ = ["StringCheckGrader"] -class EvalStringCheckGrader(BaseModel): +class StringCheckGrader(BaseModel): input: str """The input text. This may include template strings.""" diff --git a/src/openai/types/eval_string_check_grader_param.py b/src/openai/types/graders/string_check_grader_param.py similarity index 87% rename from src/openai/types/eval_string_check_grader_param.py rename to src/openai/types/graders/string_check_grader_param.py index 3511329f8b..27b204cec0 100644 --- a/src/openai/types/eval_string_check_grader_param.py +++ b/src/openai/types/graders/string_check_grader_param.py @@ -4,10 +4,10 @@ from typing_extensions import Literal, Required, TypedDict -__all__ = ["EvalStringCheckGraderParam"] +__all__ = ["StringCheckGraderParam"] -class EvalStringCheckGraderParam(TypedDict, total=False): +class StringCheckGraderParam(TypedDict, total=False): input: Required[str] """The input text. This may include template strings.""" diff --git a/src/openai/types/eval_text_similarity_grader.py b/src/openai/types/graders/text_similarity_grader.py similarity index 69% rename from src/openai/types/eval_text_similarity_grader.py rename to src/openai/types/graders/text_similarity_grader.py index 853c6d4fbf..738d317766 100644 --- a/src/openai/types/eval_text_similarity_grader.py +++ b/src/openai/types/graders/text_similarity_grader.py @@ -1,14 +1,13 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional from typing_extensions import Literal -from .._models import BaseModel +from ..._models import BaseModel -__all__ = ["EvalTextSimilarityGrader"] +__all__ = ["TextSimilarityGrader"] -class EvalTextSimilarityGrader(BaseModel): +class TextSimilarityGrader(BaseModel): evaluation_metric: Literal[ "fuzzy_match", "bleu", "gleu", "meteor", "rouge_1", "rouge_2", "rouge_3", "rouge_4", "rouge_5", "rouge_l" ] @@ -21,14 +20,11 @@ class EvalTextSimilarityGrader(BaseModel): input: str """The text being graded.""" - pass_threshold: float - """A float score where a value greater than or equal indicates a passing grade.""" + name: str + """The name of the grader.""" reference: str """The text being graded against.""" type: Literal["text_similarity"] """The type of grader.""" - - name: Optional[str] = None - """The name of the grader.""" diff --git a/src/openai/types/eval_text_similarity_grader_param.py b/src/openai/types/graders/text_similarity_grader_param.py similarity index 76% rename from src/openai/types/eval_text_similarity_grader_param.py rename to src/openai/types/graders/text_similarity_grader_param.py index f07cc29178..db14553217 100644 --- a/src/openai/types/eval_text_similarity_grader_param.py +++ b/src/openai/types/graders/text_similarity_grader_param.py @@ -4,10 +4,10 @@ from typing_extensions import Literal, Required, TypedDict -__all__ = ["EvalTextSimilarityGraderParam"] +__all__ = ["TextSimilarityGraderParam"] -class EvalTextSimilarityGraderParam(TypedDict, total=False): +class TextSimilarityGraderParam(TypedDict, total=False): evaluation_metric: Required[ Literal[ "fuzzy_match", "bleu", "gleu", "meteor", "rouge_1", "rouge_2", "rouge_3", "rouge_4", "rouge_5", "rouge_l" @@ -22,14 +22,11 @@ class EvalTextSimilarityGraderParam(TypedDict, total=False): input: Required[str] """The text being graded.""" - pass_threshold: Required[float] - """A float score where a value greater than or equal indicates a passing grade.""" + name: Required[str] + """The name of the grader.""" reference: Required[str] """The text being graded against.""" type: Required[Literal["text_similarity"]] """The type of grader.""" - - name: str - """The name of the grader.""" diff --git a/tests/api_resources/fine_tuning/alpha/__init__.py b/tests/api_resources/fine_tuning/alpha/__init__.py new file mode 100644 index 0000000000..fd8019a9a1 --- /dev/null +++ b/tests/api_resources/fine_tuning/alpha/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/fine_tuning/alpha/test_graders.py b/tests/api_resources/fine_tuning/alpha/test_graders.py new file mode 100644 index 0000000000..b144c78c74 --- /dev/null +++ b/tests/api_resources/fine_tuning/alpha/test_graders.py @@ -0,0 +1,289 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.types.fine_tuning.alpha import ( + GraderRunResponse, + GraderValidateResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestGraders: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_run(self, client: OpenAI) -> None: + grader = client.fine_tuning.alpha.graders.run( + grader={ + "input": "input", + "name": "name", + "operation": "eq", + "reference": "reference", + "type": "string_check", + }, + model_sample="model_sample", + reference_answer="string", + ) + assert_matches_type(GraderRunResponse, grader, path=["response"]) + + @parametrize + def test_method_run_with_all_params(self, client: OpenAI) -> None: + grader = client.fine_tuning.alpha.graders.run( + grader={ + "input": "input", + "name": "name", + "operation": "eq", + "reference": "reference", + "type": "string_check", + }, + model_sample="model_sample", + reference_answer="string", + ) + assert_matches_type(GraderRunResponse, grader, path=["response"]) + + @parametrize + def test_raw_response_run(self, client: OpenAI) -> None: + response = client.fine_tuning.alpha.graders.with_raw_response.run( + grader={ + "input": "input", + "name": "name", + "operation": "eq", + "reference": "reference", + "type": "string_check", + }, + model_sample="model_sample", + reference_answer="string", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + grader = response.parse() + assert_matches_type(GraderRunResponse, grader, path=["response"]) + + @parametrize + def test_streaming_response_run(self, client: OpenAI) -> None: + with client.fine_tuning.alpha.graders.with_streaming_response.run( + grader={ + "input": "input", + "name": "name", + "operation": "eq", + "reference": "reference", + "type": "string_check", + }, + model_sample="model_sample", + reference_answer="string", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + grader = response.parse() + assert_matches_type(GraderRunResponse, grader, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_validate(self, client: OpenAI) -> None: + grader = client.fine_tuning.alpha.graders.validate( + grader={ + "input": "input", + "name": "name", + "operation": "eq", + "reference": "reference", + "type": "string_check", + }, + ) + assert_matches_type(GraderValidateResponse, grader, path=["response"]) + + @parametrize + def test_method_validate_with_all_params(self, client: OpenAI) -> None: + grader = client.fine_tuning.alpha.graders.validate( + grader={ + "input": "input", + "name": "name", + "operation": "eq", + "reference": "reference", + "type": "string_check", + }, + ) + assert_matches_type(GraderValidateResponse, grader, path=["response"]) + + @parametrize + def test_raw_response_validate(self, client: OpenAI) -> None: + response = client.fine_tuning.alpha.graders.with_raw_response.validate( + grader={ + "input": "input", + "name": "name", + "operation": "eq", + "reference": "reference", + "type": "string_check", + }, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + grader = response.parse() + assert_matches_type(GraderValidateResponse, grader, path=["response"]) + + @parametrize + def test_streaming_response_validate(self, client: OpenAI) -> None: + with client.fine_tuning.alpha.graders.with_streaming_response.validate( + grader={ + "input": "input", + "name": "name", + "operation": "eq", + "reference": "reference", + "type": "string_check", + }, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + grader = response.parse() + assert_matches_type(GraderValidateResponse, grader, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncGraders: + parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + async def test_method_run(self, async_client: AsyncOpenAI) -> None: + grader = await async_client.fine_tuning.alpha.graders.run( + grader={ + "input": "input", + "name": "name", + "operation": "eq", + "reference": "reference", + "type": "string_check", + }, + model_sample="model_sample", + reference_answer="string", + ) + assert_matches_type(GraderRunResponse, grader, path=["response"]) + + @parametrize + async def test_method_run_with_all_params(self, async_client: AsyncOpenAI) -> None: + grader = await async_client.fine_tuning.alpha.graders.run( + grader={ + "input": "input", + "name": "name", + "operation": "eq", + "reference": "reference", + "type": "string_check", + }, + model_sample="model_sample", + reference_answer="string", + ) + assert_matches_type(GraderRunResponse, grader, path=["response"]) + + @parametrize + async def test_raw_response_run(self, async_client: AsyncOpenAI) -> None: + response = await async_client.fine_tuning.alpha.graders.with_raw_response.run( + grader={ + "input": "input", + "name": "name", + "operation": "eq", + "reference": "reference", + "type": "string_check", + }, + model_sample="model_sample", + reference_answer="string", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + grader = response.parse() + assert_matches_type(GraderRunResponse, grader, path=["response"]) + + @parametrize + async def test_streaming_response_run(self, async_client: AsyncOpenAI) -> None: + async with async_client.fine_tuning.alpha.graders.with_streaming_response.run( + grader={ + "input": "input", + "name": "name", + "operation": "eq", + "reference": "reference", + "type": "string_check", + }, + model_sample="model_sample", + reference_answer="string", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + grader = await response.parse() + assert_matches_type(GraderRunResponse, grader, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_validate(self, async_client: AsyncOpenAI) -> None: + grader = await async_client.fine_tuning.alpha.graders.validate( + grader={ + "input": "input", + "name": "name", + "operation": "eq", + "reference": "reference", + "type": "string_check", + }, + ) + assert_matches_type(GraderValidateResponse, grader, path=["response"]) + + @parametrize + async def test_method_validate_with_all_params(self, async_client: AsyncOpenAI) -> None: + grader = await async_client.fine_tuning.alpha.graders.validate( + grader={ + "input": "input", + "name": "name", + "operation": "eq", + "reference": "reference", + "type": "string_check", + }, + ) + assert_matches_type(GraderValidateResponse, grader, path=["response"]) + + @parametrize + async def test_raw_response_validate(self, async_client: AsyncOpenAI) -> None: + response = await async_client.fine_tuning.alpha.graders.with_raw_response.validate( + grader={ + "input": "input", + "name": "name", + "operation": "eq", + "reference": "reference", + "type": "string_check", + }, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + grader = response.parse() + assert_matches_type(GraderValidateResponse, grader, path=["response"]) + + @parametrize + async def test_streaming_response_validate(self, async_client: AsyncOpenAI) -> None: + async with async_client.fine_tuning.alpha.graders.with_streaming_response.validate( + grader={ + "input": "input", + "name": "name", + "operation": "eq", + "reference": "reference", + "type": "string_check", + }, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + grader = await response.parse() + assert_matches_type(GraderValidateResponse, grader, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/fine_tuning/test_jobs.py b/tests/api_resources/fine_tuning/test_jobs.py index 75f72f9d09..4589f12846 100644 --- a/tests/api_resources/fine_tuning/test_jobs.py +++ b/tests/api_resources/fine_tuning/test_jobs.py @@ -52,6 +52,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: ], metadata={"foo": "string"}, method={ + "type": "supervised", "dpo": { "hyperparameters": { "batch_size": "auto", @@ -60,6 +61,24 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: "n_epochs": "auto", } }, + "reinforcement": { + "grader": { + "input": "input", + "name": "name", + "operation": "eq", + "reference": "reference", + "type": "string_check", + }, + "hyperparameters": { + "batch_size": "auto", + "compute_multiplier": "auto", + "eval_interval": "auto", + "eval_samples": "auto", + "learning_rate_multiplier": "auto", + "n_epochs": "auto", + "reasoning_effort": "default", + }, + }, "supervised": { "hyperparameters": { "batch_size": "auto", @@ -67,7 +86,6 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: "n_epochs": "auto", } }, - "type": "supervised", }, seed=42, suffix="x", @@ -258,6 +276,82 @@ def test_path_params_list_events(self, client: OpenAI) -> None: "", ) + @parametrize + def test_method_pause(self, client: OpenAI) -> None: + job = client.fine_tuning.jobs.pause( + "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) + assert_matches_type(FineTuningJob, job, path=["response"]) + + @parametrize + def test_raw_response_pause(self, client: OpenAI) -> None: + response = client.fine_tuning.jobs.with_raw_response.pause( + "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + job = response.parse() + assert_matches_type(FineTuningJob, job, path=["response"]) + + @parametrize + def test_streaming_response_pause(self, client: OpenAI) -> None: + with client.fine_tuning.jobs.with_streaming_response.pause( + "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + job = response.parse() + assert_matches_type(FineTuningJob, job, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_pause(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `fine_tuning_job_id` but received ''"): + client.fine_tuning.jobs.with_raw_response.pause( + "", + ) + + @parametrize + def test_method_resume(self, client: OpenAI) -> None: + job = client.fine_tuning.jobs.resume( + "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) + assert_matches_type(FineTuningJob, job, path=["response"]) + + @parametrize + def test_raw_response_resume(self, client: OpenAI) -> None: + response = client.fine_tuning.jobs.with_raw_response.resume( + "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + job = response.parse() + assert_matches_type(FineTuningJob, job, path=["response"]) + + @parametrize + def test_streaming_response_resume(self, client: OpenAI) -> None: + with client.fine_tuning.jobs.with_streaming_response.resume( + "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + job = response.parse() + assert_matches_type(FineTuningJob, job, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_resume(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `fine_tuning_job_id` but received ''"): + client.fine_tuning.jobs.with_raw_response.resume( + "", + ) + class TestAsyncJobs: parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) @@ -293,6 +387,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> ], metadata={"foo": "string"}, method={ + "type": "supervised", "dpo": { "hyperparameters": { "batch_size": "auto", @@ -301,6 +396,24 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> "n_epochs": "auto", } }, + "reinforcement": { + "grader": { + "input": "input", + "name": "name", + "operation": "eq", + "reference": "reference", + "type": "string_check", + }, + "hyperparameters": { + "batch_size": "auto", + "compute_multiplier": "auto", + "eval_interval": "auto", + "eval_samples": "auto", + "learning_rate_multiplier": "auto", + "n_epochs": "auto", + "reasoning_effort": "default", + }, + }, "supervised": { "hyperparameters": { "batch_size": "auto", @@ -308,7 +421,6 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> "n_epochs": "auto", } }, - "type": "supervised", }, seed=42, suffix="x", @@ -498,3 +610,79 @@ async def test_path_params_list_events(self, async_client: AsyncOpenAI) -> None: await async_client.fine_tuning.jobs.with_raw_response.list_events( "", ) + + @parametrize + async def test_method_pause(self, async_client: AsyncOpenAI) -> None: + job = await async_client.fine_tuning.jobs.pause( + "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) + assert_matches_type(FineTuningJob, job, path=["response"]) + + @parametrize + async def test_raw_response_pause(self, async_client: AsyncOpenAI) -> None: + response = await async_client.fine_tuning.jobs.with_raw_response.pause( + "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + job = response.parse() + assert_matches_type(FineTuningJob, job, path=["response"]) + + @parametrize + async def test_streaming_response_pause(self, async_client: AsyncOpenAI) -> None: + async with async_client.fine_tuning.jobs.with_streaming_response.pause( + "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + job = await response.parse() + assert_matches_type(FineTuningJob, job, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_pause(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `fine_tuning_job_id` but received ''"): + await async_client.fine_tuning.jobs.with_raw_response.pause( + "", + ) + + @parametrize + async def test_method_resume(self, async_client: AsyncOpenAI) -> None: + job = await async_client.fine_tuning.jobs.resume( + "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) + assert_matches_type(FineTuningJob, job, path=["response"]) + + @parametrize + async def test_raw_response_resume(self, async_client: AsyncOpenAI) -> None: + response = await async_client.fine_tuning.jobs.with_raw_response.resume( + "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + job = response.parse() + assert_matches_type(FineTuningJob, job, path=["response"]) + + @parametrize + async def test_streaming_response_resume(self, async_client: AsyncOpenAI) -> None: + async with async_client.fine_tuning.jobs.with_streaming_response.resume( + "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + job = await response.parse() + assert_matches_type(FineTuningJob, job, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_resume(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `fine_tuning_job_id` but received ''"): + await async_client.fine_tuning.jobs.with_raw_response.resume( + "", + ) From 01a69ab8cbed129e9edb84865893310ab52e59c7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 8 May 2025 17:25:01 +0000 Subject: [PATCH 325/769] release: 1.78.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 20 ++++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 33a65d75c4..21621582fa 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.77.0" + ".": "1.78.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 9097cdc65a..8648497457 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,25 @@ # Changelog +## 1.78.0 (2025-05-08) + +Full Changelog: [v1.77.0...v1.78.0](https://github.com/openai/openai-python/compare/v1.77.0...v1.78.0) + +### Features + +* **api:** Add reinforcement fine-tuning api support ([bebe361](https://github.com/openai/openai-python/commit/bebe36104bd3062d09ab9bbfb4bacfc99e737cb2)) + + +### Bug Fixes + +* ignore errors in isinstance() calls on LazyProxy subclasses ([#2343](https://github.com/openai/openai-python/issues/2343)) ([52cbbdf](https://github.com/openai/openai-python/commit/52cbbdf2207567741f16d18f1ea1b0d13d667375)), closes [#2056](https://github.com/openai/openai-python/issues/2056) + + +### Chores + +* **internal:** update proxy tests ([b8e848d](https://github.com/openai/openai-python/commit/b8e848d5fb58472cbfa27fb3ed01efc25a05d944)) +* use lazy imports for module level client ([4d0f409](https://github.com/openai/openai-python/commit/4d0f409e79a18cce9855fe076f5a50e52b8bafd8)) +* use lazy imports for resources ([834813c](https://github.com/openai/openai-python/commit/834813c5cb1a84effc34e5eabed760393e1de806)) + ## 1.77.0 (2025-05-02) Full Changelog: [v1.76.2...v1.77.0](https://github.com/openai/openai-python/compare/v1.76.2...v1.77.0) diff --git a/pyproject.toml b/pyproject.toml index 4b854b05e5..3d5af260cf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.77.0" +version = "1.78.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 9d8ba015e1..495a094581 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.77.0" # x-release-please-version +__version__ = "1.78.0" # x-release-please-version From 21209abbf29113c8eedcd5e2645db31ab2bda61a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 9 May 2025 14:38:23 +0000 Subject: [PATCH 326/769] fix(package): support direct resource imports --- src/openai/__init__.py | 4 ++++ src/openai/_utils/_resources_proxy.py | 24 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 src/openai/_utils/_resources_proxy.py diff --git a/src/openai/__init__.py b/src/openai/__init__.py index 9e97098bb0..6b21a9af23 100644 --- a/src/openai/__init__.py +++ b/src/openai/__init__.py @@ -3,6 +3,7 @@ from __future__ import annotations import os as _os +import typing as _t from typing_extensions import override from . import types @@ -78,6 +79,9 @@ "DefaultAsyncHttpxClient", ] +if not _t.TYPE_CHECKING: + from ._utils._resources_proxy import resources as resources + from .lib import azure as _azure, pydantic_function_tool as pydantic_function_tool from .version import VERSION as VERSION from .lib.azure import AzureOpenAI as AzureOpenAI, AsyncAzureOpenAI as AsyncAzureOpenAI diff --git a/src/openai/_utils/_resources_proxy.py b/src/openai/_utils/_resources_proxy.py new file mode 100644 index 0000000000..e5b9ec7a37 --- /dev/null +++ b/src/openai/_utils/_resources_proxy.py @@ -0,0 +1,24 @@ +from __future__ import annotations + +from typing import Any +from typing_extensions import override + +from ._proxy import LazyProxy + + +class ResourcesProxy(LazyProxy[Any]): + """A proxy for the `openai.resources` module. + + This is used so that we can lazily import `openai.resources` only when + needed *and* so that users can just import `openai` and reference `openai.resources` + """ + + @override + def __load__(self) -> Any: + import importlib + + mod = importlib.import_module("openai.resources") + return mod + + +resources = ResourcesProxy().__as_proxied__() From 12a534987d0f3d238de5774749c326ee79bcfb00 Mon Sep 17 00:00:00 2001 From: David Meadows Date: Fri, 9 May 2025 11:15:26 -0400 Subject: [PATCH 327/769] fix(internal): fix linting due to broken __test__ annotation --- src/openai/types/eval_create_params.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/openai/types/eval_create_params.py b/src/openai/types/eval_create_params.py index 66178287e4..3b712580a0 100644 --- a/src/openai/types/eval_create_params.py +++ b/src/openai/types/eval_create_params.py @@ -140,19 +140,16 @@ class TestingCriterionLabelModel(TypedDict, total=False): class TestingCriterionTextSimilarity(TextSimilarityGraderParam, total=False): - __test__ = False pass_threshold: Required[float] """The threshold for the score.""" class TestingCriterionPython(PythonGraderParam, total=False): - __test__ = False pass_threshold: float """The threshold for the score.""" class TestingCriterionScoreModel(ScoreModelGraderParam, total=False): - __test__ = False pass_threshold: float """The threshold for the score.""" From c097025779fc0bdc3389c047d4c060b5d7349f16 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 12 May 2025 05:04:02 +0000 Subject: [PATCH 328/769] release: 1.78.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 9 +++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 21621582fa..f15af035f8 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.78.0" + ".": "1.78.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 8648497457..b153f3ef05 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 1.78.1 (2025-05-12) + +Full Changelog: [v1.78.0...v1.78.1](https://github.com/openai/openai-python/compare/v1.78.0...v1.78.1) + +### Bug Fixes + +* **internal:** fix linting due to broken __test__ annotation ([5a7d7a0](https://github.com/openai/openai-python/commit/5a7d7a081138c6473bff44e60d439812ecb85cdf)) +* **package:** support direct resource imports ([2293fc0](https://github.com/openai/openai-python/commit/2293fc0dd23a9c756067cdc22b39c18448f35feb)) + ## 1.78.0 (2025-05-08) Full Changelog: [v1.77.0...v1.78.0](https://github.com/openai/openai-python/compare/v1.77.0...v1.78.0) diff --git a/pyproject.toml b/pyproject.toml index 3d5af260cf..71c86c38ea 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.78.0" +version = "1.78.1" 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 495a094581..9b430dfa8b 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.78.0" # x-release-please-version +__version__ = "1.78.1" # x-release-please-version From 98925cef766fc8d1adaaed9013ad43a44739edef Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 14 May 2025 23:07:08 +0000 Subject: [PATCH 329/769] chore(ci): upload sdks to package manager --- .github/workflows/ci.yml | 24 ++++++++++++++++++++++++ scripts/utils/upload-artifact.sh | 25 +++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100755 scripts/utils/upload-artifact.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e1e21f3fae..e853b86695 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,6 +30,30 @@ jobs: - name: Run lints run: ./scripts/lint + upload: + if: github.repository == 'stainless-sdks/openai-python' + timeout-minutes: 10 + name: upload + permissions: + contents: read + id-token: write + runs-on: depot-ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + + - name: Get GitHub OIDC Token + id: github-oidc + uses: actions/github-script@v6 + with: + script: core.setOutput('github_token', await core.getIDToken()); + + - name: Upload tarball + env: + URL: https://pkg.stainless.com/s + AUTH: ${{ steps.github-oidc.outputs.github_token }} + SHA: ${{ github.sha }} + run: ./scripts/utils/upload-artifact.sh + test: timeout-minutes: 10 name: test diff --git a/scripts/utils/upload-artifact.sh b/scripts/utils/upload-artifact.sh new file mode 100755 index 0000000000..b9ab47d945 --- /dev/null +++ b/scripts/utils/upload-artifact.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -exuo pipefail + +RESPONSE=$(curl -X POST "$URL" \ + -H "Authorization: Bearer $AUTH" \ + -H "Content-Type: application/json") + +SIGNED_URL=$(echo "$RESPONSE" | jq -r '.url') + +if [[ "$SIGNED_URL" == "null" ]]; then + echo -e "\033[31mFailed to get signed URL.\033[0m" + exit 1 +fi + +UPLOAD_RESPONSE=$(tar -cz . | curl -v -X PUT \ + -H "Content-Type: application/gzip" \ + --data-binary @- "$SIGNED_URL" 2>&1) + +if echo "$UPLOAD_RESPONSE" | grep -q "HTTP/[0-9.]* 200"; then + echo -e "\033[32mUploaded build to Stainless storage.\033[0m" + echo -e "\033[32mInstallation: npm install 'https://pkg.stainless.com/s/openai-python/$SHA'\033[0m" +else + echo -e "\033[31mFailed to upload artifact.\033[0m" + exit 1 +fi From 1701df1950a28e11c0ff3d07bc110572765837e6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 15 May 2025 12:25:19 +0000 Subject: [PATCH 330/769] chore(ci): fix installation instructions --- scripts/utils/upload-artifact.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/utils/upload-artifact.sh b/scripts/utils/upload-artifact.sh index b9ab47d945..75198de98f 100755 --- a/scripts/utils/upload-artifact.sh +++ b/scripts/utils/upload-artifact.sh @@ -18,7 +18,7 @@ UPLOAD_RESPONSE=$(tar -cz . | curl -v -X PUT \ if echo "$UPLOAD_RESPONSE" | grep -q "HTTP/[0-9.]* 200"; then echo -e "\033[32mUploaded build to Stainless storage.\033[0m" - echo -e "\033[32mInstallation: npm install 'https://pkg.stainless.com/s/openai-python/$SHA'\033[0m" + echo -e "\033[32mInstallation: pip install 'https://pkg.stainless.com/s/openai-python/$SHA'\033[0m" else echo -e "\033[31mFailed to upload artifact.\033[0m" exit 1 From 28d60d9e2717d4e0ac4daa92b190e12f70c9cffb Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 15 May 2025 21:34:07 +0000 Subject: [PATCH 331/769] feat(api): responses x eval api --- .stats.yml | 6 +- api.md | 2 + src/openai/resources/audio/transcriptions.py | 94 +++++++- src/openai/resources/embeddings.py | 14 +- src/openai/types/__init__.py | 1 + .../audio/transcription_create_params.py | 38 ++- src/openai/types/embedding_create_params.py | 9 +- src/openai/types/eval_create_params.py | 15 +- src/openai/types/eval_create_response.py | 4 +- src/openai/types/eval_list_response.py | 4 +- .../types/eval_logs_data_source_config.py | 32 +++ src/openai/types/eval_retrieve_response.py | 4 +- ...l_stored_completions_data_source_config.py | 4 +- src/openai/types/eval_update_response.py | 4 +- src/openai/types/evals/__init__.py | 4 + .../create_eval_responses_run_data_source.py | 206 ++++++++++++++++ ...te_eval_responses_run_data_source_param.py | 202 ++++++++++++++++ src/openai/types/evals/run_cancel_response.py | 218 +---------------- src/openai/types/evals/run_create_params.py | 221 +----------------- src/openai/types/evals/run_create_response.py | 218 +---------------- src/openai/types/evals/run_list_response.py | 218 +---------------- .../types/evals/run_retrieve_response.py | 218 +---------------- .../types/fine_tuning/fine_tuning_job.py | 2 +- .../audio/test_transcriptions.py | 4 + 24 files changed, 645 insertions(+), 1097 deletions(-) create mode 100644 src/openai/types/eval_logs_data_source_config.py create mode 100644 src/openai/types/evals/create_eval_responses_run_data_source.py create mode 100644 src/openai/types/evals/create_eval_responses_run_data_source_param.py diff --git a/.stats.yml b/.stats.yml index 5f1bee851b..11ba2b0101 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 101 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-794a6ed3c3d3d77887564755168056af8a426b17cf1ec721e3a300503dc22a41.yml -openapi_spec_hash: 25a81c220713cd5b0bafc221d1dfa79a -config_hash: 0b768ed1b56c6d82816f0fa40dc4aaf5 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-161ca7f1cfd7b33c1fc07d0ce25dfe4be5a7271c394f4cb526b7fb21b0729900.yml +openapi_spec_hash: 602e14add4bee018c6774e320ce309b8 +config_hash: 7da27f7260075e8813ddcea542fba1bf diff --git a/api.md b/api.md index 496e5548b3..db505b20d1 100644 --- a/api.md +++ b/api.md @@ -787,6 +787,7 @@ Types: ```python from openai.types import ( EvalCustomDataSourceConfig, + EvalLogsDataSourceConfig, EvalStoredCompletionsDataSourceConfig, EvalCreateResponse, EvalRetrieveResponse, @@ -812,6 +813,7 @@ Types: from openai.types.evals import ( CreateEvalCompletionsRunDataSource, CreateEvalJSONLRunDataSource, + CreateEvalResponsesRunDataSource, EvalAPIError, RunCreateResponse, RunRetrieveResponse, diff --git a/src/openai/resources/audio/transcriptions.py b/src/openai/resources/audio/transcriptions.py index 0c7ebca7a6..9d4f7e9255 100644 --- a/src/openai/resources/audio/transcriptions.py +++ b/src/openai/resources/audio/transcriptions.py @@ -57,6 +57,7 @@ def create( *, file: FileTypes, model: Union[str, AudioModel], + chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | NotGiven = NOT_GIVEN, include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, response_format: Union[Literal["json"], NotGiven] = NOT_GIVEN, language: str | NotGiven = NOT_GIVEN, @@ -118,6 +119,7 @@ def create( file: FileTypes, model: Union[str, AudioModel], stream: Literal[True], + chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | NotGiven = NOT_GIVEN, include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, language: str | NotGiven = NOT_GIVEN, prompt: str | NotGiven = NOT_GIVEN, @@ -152,6 +154,11 @@ def create( Note: Streaming is not supported for the `whisper-1` model and will be ignored. + chunking_strategy: Controls how the audio is cut into chunks. When set to `"auto"`, the server + first normalizes loudness and then uses voice activity detection (VAD) to choose + boundaries. `server_vad` object can be provided to tweak VAD detection + parameters manually. If unset, the audio is transcribed as a single block. + include: Additional information to include in the transcription response. `logprobs` will return the log probabilities of the tokens in the response to understand the model's confidence in the transcription. `logprobs` only works with @@ -200,6 +207,7 @@ def create( file: FileTypes, model: Union[str, AudioModel], stream: bool, + chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | NotGiven = NOT_GIVEN, include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, language: str | NotGiven = NOT_GIVEN, prompt: str | NotGiven = NOT_GIVEN, @@ -234,6 +242,11 @@ def create( Note: Streaming is not supported for the `whisper-1` model and will be ignored. + chunking_strategy: Controls how the audio is cut into chunks. When set to `"auto"`, the server + first normalizes loudness and then uses voice activity detection (VAD) to choose + boundaries. `server_vad` object can be provided to tweak VAD detection + parameters manually. If unset, the audio is transcribed as a single block. + include: Additional information to include in the transcription response. `logprobs` will return the log probabilities of the tokens in the response to understand the model's confidence in the transcription. `logprobs` only works with @@ -281,6 +294,7 @@ def create( *, file: FileTypes, model: Union[str, AudioModel], + chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | NotGiven = NOT_GIVEN, include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, language: str | NotGiven = NOT_GIVEN, prompt: str | NotGiven = NOT_GIVEN, @@ -299,6 +313,7 @@ def create( { "file": file, "model": model, + "chunking_strategy": chunking_strategy, "include": include, "language": language, "prompt": prompt, @@ -357,6 +372,8 @@ async def create( *, file: FileTypes, model: Union[str, AudioModel], + chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | NotGiven = NOT_GIVEN, + include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, response_format: Union[Literal["json"], NotGiven] = NOT_GIVEN, language: str | NotGiven = NOT_GIVEN, prompt: str | NotGiven = NOT_GIVEN, @@ -369,7 +386,68 @@ async def create( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Transcription: ... + ) -> TranscriptionCreateResponse: + """ + Transcribes audio into the input language. + + Args: + file: + The audio file object (not file name) to transcribe, in one of these formats: + flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. + + model: ID of the model to use. The options are `gpt-4o-transcribe`, + `gpt-4o-mini-transcribe`, and `whisper-1` (which is powered by our open source + Whisper V2 model). + + chunking_strategy: Controls how the audio is cut into chunks. When set to `"auto"`, the server + first normalizes loudness and then uses voice activity detection (VAD) to choose + boundaries. `server_vad` object can be provided to tweak VAD detection + parameters manually. If unset, the audio is transcribed as a single block. + + include: Additional information to include in the transcription response. `logprobs` will + return the log probabilities of the tokens in the response to understand the + model's confidence in the transcription. `logprobs` only works with + response_format set to `json` and only with the models `gpt-4o-transcribe` and + `gpt-4o-mini-transcribe`. + + language: The language of the input audio. Supplying the input language in + [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) + format will improve accuracy and latency. + + prompt: An optional text to guide the model's style or continue a previous audio + segment. The + [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) + should match the audio language. + + response_format: The format of the output, in one of these options: `json`, `text`, `srt`, + `verbose_json`, or `vtt`. For `gpt-4o-transcribe` and `gpt-4o-mini-transcribe`, + the only supported format is `json`. + + stream: If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section of the Speech-to-Text guide](https://platform.openai.com/docs/guides/speech-to-text?lang=curl#streaming-transcriptions) + for more information. + + Note: Streaming is not supported for the `whisper-1` model and will be ignored. + + temperature: The sampling temperature, between 0 and 1. Higher values like 0.8 will make the + output more random, while lower values like 0.2 will make it more focused and + deterministic. If set to 0, the model will use + [log probability](https://en.wikipedia.org/wiki/Log_probability) to + automatically increase the temperature until certain thresholds are hit. + + timestamp_granularities: The timestamp granularities to populate for this transcription. + `response_format` must be set `verbose_json` to use timestamp granularities. + Either or both of these options are supported: `word`, or `segment`. Note: There + is no additional latency for segment timestamps, but generating word timestamps + incurs additional latency. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + """ @overload async def create( @@ -418,6 +496,7 @@ async def create( file: FileTypes, model: Union[str, AudioModel], stream: Literal[True], + chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | NotGiven = NOT_GIVEN, include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, language: str | NotGiven = NOT_GIVEN, prompt: str | NotGiven = NOT_GIVEN, @@ -452,6 +531,11 @@ async def create( Note: Streaming is not supported for the `whisper-1` model and will be ignored. + chunking_strategy: Controls how the audio is cut into chunks. When set to `"auto"`, the server + first normalizes loudness and then uses voice activity detection (VAD) to choose + boundaries. `server_vad` object can be provided to tweak VAD detection + parameters manually. If unset, the audio is transcribed as a single block. + include: Additional information to include in the transcription response. `logprobs` will return the log probabilities of the tokens in the response to understand the model's confidence in the transcription. `logprobs` only works with @@ -500,6 +584,7 @@ async def create( file: FileTypes, model: Union[str, AudioModel], stream: bool, + chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | NotGiven = NOT_GIVEN, include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, language: str | NotGiven = NOT_GIVEN, prompt: str | NotGiven = NOT_GIVEN, @@ -534,6 +619,11 @@ async def create( Note: Streaming is not supported for the `whisper-1` model and will be ignored. + chunking_strategy: Controls how the audio is cut into chunks. When set to `"auto"`, the server + first normalizes loudness and then uses voice activity detection (VAD) to choose + boundaries. `server_vad` object can be provided to tweak VAD detection + parameters manually. If unset, the audio is transcribed as a single block. + include: Additional information to include in the transcription response. `logprobs` will return the log probabilities of the tokens in the response to understand the model's confidence in the transcription. `logprobs` only works with @@ -581,6 +671,7 @@ async def create( *, file: FileTypes, model: Union[str, AudioModel], + chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | NotGiven = NOT_GIVEN, include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, language: str | NotGiven = NOT_GIVEN, prompt: str | NotGiven = NOT_GIVEN, @@ -599,6 +690,7 @@ async def create( { "file": file, "model": model, + "chunking_strategy": chunking_strategy, "include": include, "language": language, "prompt": prompt, diff --git a/src/openai/resources/embeddings.py b/src/openai/resources/embeddings.py index a392d5eb17..553dacc284 100644 --- a/src/openai/resources/embeddings.py +++ b/src/openai/resources/embeddings.py @@ -66,11 +66,12 @@ def create( input: Input text to embed, encoded as a string or array of tokens. To embed multiple inputs in a single request, pass an array of strings or array of token arrays. The input must not exceed the max input tokens for the model (8192 tokens for - `text-embedding-ada-002`), cannot be an empty string, and any array must be 2048 + all embedding models), cannot be an empty string, and any array must be 2048 dimensions or less. [Example Python code](https://cookbook.openai.com/examples/how_to_count_tokens_with_tiktoken) - for counting tokens. Some models may also impose a limit on total number of - tokens summed across inputs. + for counting tokens. In addition to the per-input token limit, all embedding + models enforce a maximum of 300,000 tokens summed across all inputs in a single + request. model: ID of the model to use. You can use the [List models](https://platform.openai.com/docs/api-reference/models/list) API to @@ -181,11 +182,12 @@ async def create( input: Input text to embed, encoded as a string or array of tokens. To embed multiple inputs in a single request, pass an array of strings or array of token arrays. The input must not exceed the max input tokens for the model (8192 tokens for - `text-embedding-ada-002`), cannot be an empty string, and any array must be 2048 + all embedding models), cannot be an empty string, and any array must be 2048 dimensions or less. [Example Python code](https://cookbook.openai.com/examples/how_to_count_tokens_with_tiktoken) - for counting tokens. Some models may also impose a limit on total number of - tokens summed across inputs. + for counting tokens. In addition to the per-input token limit, all embedding + models enforce a maximum of 300,000 tokens summed across all inputs in a single + request. model: ID of the model to use. You can use the [List models](https://platform.openai.com/docs/api-reference/models/list) API to diff --git a/src/openai/types/__init__.py b/src/openai/types/__init__.py index bf5493fd62..9f40033354 100644 --- a/src/openai/types/__init__.py +++ b/src/openai/types/__init__.py @@ -70,6 +70,7 @@ from .vector_store_search_params import VectorStoreSearchParams as VectorStoreSearchParams from .vector_store_update_params import VectorStoreUpdateParams as VectorStoreUpdateParams from .moderation_text_input_param import ModerationTextInputParam as ModerationTextInputParam +from .eval_logs_data_source_config import EvalLogsDataSourceConfig as EvalLogsDataSourceConfig from .file_chunking_strategy_param import FileChunkingStrategyParam as FileChunkingStrategyParam from .vector_store_search_response import VectorStoreSearchResponse as VectorStoreSearchResponse from .websocket_connection_options import WebsocketConnectionOptions as WebsocketConnectionOptions diff --git a/src/openai/types/audio/transcription_create_params.py b/src/openai/types/audio/transcription_create_params.py index 0cda4c7907..8271b054ab 100644 --- a/src/openai/types/audio/transcription_create_params.py +++ b/src/openai/types/audio/transcription_create_params.py @@ -3,7 +3,7 @@ from __future__ import annotations from typing import List, Union, Optional -from typing_extensions import Literal, Required, TypedDict +from typing_extensions import Literal, Required, TypeAlias, TypedDict from ..._types import FileTypes from ..audio_model import AudioModel @@ -12,6 +12,8 @@ __all__ = [ "TranscriptionCreateParamsBase", + "ChunkingStrategy", + "ChunkingStrategyVadConfig", "TranscriptionCreateParamsNonStreaming", "TranscriptionCreateParamsStreaming", ] @@ -31,6 +33,15 @@ class TranscriptionCreateParamsBase(TypedDict, total=False): (which is powered by our open source Whisper V2 model). """ + chunking_strategy: Optional[ChunkingStrategy] + """Controls how the audio is cut into chunks. + + When set to `"auto"`, the server first normalizes loudness and then uses voice + activity detection (VAD) to choose boundaries. `server_vad` object can be + provided to tweak VAD detection parameters manually. If unset, the audio is + transcribed as a single block. + """ + include: List[TranscriptionInclude] """Additional information to include in the transcription response. @@ -82,6 +93,31 @@ class TranscriptionCreateParamsBase(TypedDict, total=False): """ +class ChunkingStrategyVadConfig(TypedDict, total=False): + type: Required[Literal["server_vad"]] + """Must be set to `server_vad` to enable manual chunking using server side VAD.""" + + prefix_padding_ms: int + """Amount of audio to include before the VAD detected speech (in milliseconds).""" + + silence_duration_ms: int + """ + Duration of silence to detect speech stop (in milliseconds). With shorter values + the model will respond more quickly, but may jump in on short pauses from the + user. + """ + + threshold: float + """Sensitivity threshold (0.0 to 1.0) for voice activity detection. + + A higher threshold will require louder audio to activate the model, and thus + might perform better in noisy environments. + """ + + +ChunkingStrategy: TypeAlias = Union[Literal["auto"], ChunkingStrategyVadConfig] + + class TranscriptionCreateParamsNonStreaming(TranscriptionCreateParamsBase, total=False): stream: Optional[Literal[False]] """ diff --git a/src/openai/types/embedding_create_params.py b/src/openai/types/embedding_create_params.py index a90566449b..94edce10a4 100644 --- a/src/openai/types/embedding_create_params.py +++ b/src/openai/types/embedding_create_params.py @@ -16,11 +16,12 @@ class EmbeddingCreateParams(TypedDict, total=False): To embed multiple inputs in a single request, pass an array of strings or array of token arrays. The input must not exceed the max input tokens for the model - (8192 tokens for `text-embedding-ada-002`), cannot be an empty string, and any - array must be 2048 dimensions or less. + (8192 tokens for all embedding models), cannot be an empty string, and any array + must be 2048 dimensions or less. [Example Python code](https://cookbook.openai.com/examples/how_to_count_tokens_with_tiktoken) - for counting tokens. Some models may also impose a limit on total number of - tokens summed across inputs. + for counting tokens. In addition to the per-input token limit, all embedding + models enforce a maximum of 300,000 tokens summed across all inputs in a single + request. """ model: Required[Union[str, EmbeddingModel]] diff --git a/src/openai/types/eval_create_params.py b/src/openai/types/eval_create_params.py index 3b712580a0..8d508a2d8e 100644 --- a/src/openai/types/eval_create_params.py +++ b/src/openai/types/eval_create_params.py @@ -16,6 +16,7 @@ "EvalCreateParams", "DataSourceConfig", "DataSourceConfigCustom", + "DataSourceConfigLogs", "DataSourceConfigStoredCompletions", "TestingCriterion", "TestingCriterionLabelModel", @@ -65,15 +66,23 @@ class DataSourceConfigCustom(TypedDict, total=False): """ +class DataSourceConfigLogs(TypedDict, total=False): + type: Required[Literal["logs"]] + """The type of data source. Always `logs`.""" + + metadata: Dict[str, object] + """Metadata filters for the logs data source.""" + + class DataSourceConfigStoredCompletions(TypedDict, total=False): - type: Required[Literal["stored_completions"]] - """The type of data source. Always `stored_completions`.""" + type: Required[Literal["stored-completions"]] + """The type of data source. Always `stored-completions`.""" metadata: Dict[str, object] """Metadata filters for the stored completions data source.""" -DataSourceConfig: TypeAlias = Union[DataSourceConfigCustom, DataSourceConfigStoredCompletions] +DataSourceConfig: TypeAlias = Union[DataSourceConfigCustom, DataSourceConfigLogs, DataSourceConfigStoredCompletions] class TestingCriterionLabelModelInputSimpleInputMessage(TypedDict, total=False): diff --git a/src/openai/types/eval_create_response.py b/src/openai/types/eval_create_response.py index d5f158ad29..2bf7643b53 100644 --- a/src/openai/types/eval_create_response.py +++ b/src/openai/types/eval_create_response.py @@ -10,6 +10,7 @@ from .graders.label_model_grader import LabelModelGrader from .graders.score_model_grader import ScoreModelGrader from .graders.string_check_grader import StringCheckGrader +from .eval_logs_data_source_config import EvalLogsDataSourceConfig from .eval_custom_data_source_config import EvalCustomDataSourceConfig from .graders.text_similarity_grader import TextSimilarityGrader from .eval_stored_completions_data_source_config import EvalStoredCompletionsDataSourceConfig @@ -24,7 +25,8 @@ ] DataSourceConfig: TypeAlias = Annotated[ - Union[EvalCustomDataSourceConfig, EvalStoredCompletionsDataSourceConfig], PropertyInfo(discriminator="type") + Union[EvalCustomDataSourceConfig, EvalLogsDataSourceConfig, EvalStoredCompletionsDataSourceConfig], + PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/eval_list_response.py b/src/openai/types/eval_list_response.py index b743f57f6a..e52f3db1c4 100644 --- a/src/openai/types/eval_list_response.py +++ b/src/openai/types/eval_list_response.py @@ -10,6 +10,7 @@ from .graders.label_model_grader import LabelModelGrader from .graders.score_model_grader import ScoreModelGrader from .graders.string_check_grader import StringCheckGrader +from .eval_logs_data_source_config import EvalLogsDataSourceConfig from .eval_custom_data_source_config import EvalCustomDataSourceConfig from .graders.text_similarity_grader import TextSimilarityGrader from .eval_stored_completions_data_source_config import EvalStoredCompletionsDataSourceConfig @@ -24,7 +25,8 @@ ] DataSourceConfig: TypeAlias = Annotated[ - Union[EvalCustomDataSourceConfig, EvalStoredCompletionsDataSourceConfig], PropertyInfo(discriminator="type") + Union[EvalCustomDataSourceConfig, EvalLogsDataSourceConfig, EvalStoredCompletionsDataSourceConfig], + PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/eval_logs_data_source_config.py b/src/openai/types/eval_logs_data_source_config.py new file mode 100644 index 0000000000..a3eb245e07 --- /dev/null +++ b/src/openai/types/eval_logs_data_source_config.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from .._models import BaseModel +from .shared.metadata import Metadata + +__all__ = ["EvalLogsDataSourceConfig"] + + +class EvalLogsDataSourceConfig(BaseModel): + schema_: Dict[str, object] = FieldInfo(alias="schema") + """ + The json schema for the run data source items. Learn how to build JSON schemas + [here](https://json-schema.org/). + """ + + type: Literal["logs"] + """The type of data source. Always `logs`.""" + + metadata: Optional[Metadata] = None + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + """ diff --git a/src/openai/types/eval_retrieve_response.py b/src/openai/types/eval_retrieve_response.py index dabb20674e..71ed96d5ab 100644 --- a/src/openai/types/eval_retrieve_response.py +++ b/src/openai/types/eval_retrieve_response.py @@ -10,6 +10,7 @@ from .graders.label_model_grader import LabelModelGrader from .graders.score_model_grader import ScoreModelGrader from .graders.string_check_grader import StringCheckGrader +from .eval_logs_data_source_config import EvalLogsDataSourceConfig from .eval_custom_data_source_config import EvalCustomDataSourceConfig from .graders.text_similarity_grader import TextSimilarityGrader from .eval_stored_completions_data_source_config import EvalStoredCompletionsDataSourceConfig @@ -24,7 +25,8 @@ ] DataSourceConfig: TypeAlias = Annotated[ - Union[EvalCustomDataSourceConfig, EvalStoredCompletionsDataSourceConfig], PropertyInfo(discriminator="type") + Union[EvalCustomDataSourceConfig, EvalLogsDataSourceConfig, EvalStoredCompletionsDataSourceConfig], + PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/eval_stored_completions_data_source_config.py b/src/openai/types/eval_stored_completions_data_source_config.py index 98f86a4719..5016f0ae9c 100644 --- a/src/openai/types/eval_stored_completions_data_source_config.py +++ b/src/openai/types/eval_stored_completions_data_source_config.py @@ -18,8 +18,8 @@ class EvalStoredCompletionsDataSourceConfig(BaseModel): [here](https://json-schema.org/). """ - type: Literal["stored_completions"] - """The type of data source. Always `stored_completions`.""" + type: Literal["stored-completions"] + """The type of data source. Always `stored-completions`.""" metadata: Optional[Metadata] = None """Set of 16 key-value pairs that can be attached to an object. diff --git a/src/openai/types/eval_update_response.py b/src/openai/types/eval_update_response.py index c5cb2622ea..73ee6eb58c 100644 --- a/src/openai/types/eval_update_response.py +++ b/src/openai/types/eval_update_response.py @@ -10,6 +10,7 @@ from .graders.label_model_grader import LabelModelGrader from .graders.score_model_grader import ScoreModelGrader from .graders.string_check_grader import StringCheckGrader +from .eval_logs_data_source_config import EvalLogsDataSourceConfig from .eval_custom_data_source_config import EvalCustomDataSourceConfig from .graders.text_similarity_grader import TextSimilarityGrader from .eval_stored_completions_data_source_config import EvalStoredCompletionsDataSourceConfig @@ -24,7 +25,8 @@ ] DataSourceConfig: TypeAlias = Annotated[ - Union[EvalCustomDataSourceConfig, EvalStoredCompletionsDataSourceConfig], PropertyInfo(discriminator="type") + Union[EvalCustomDataSourceConfig, EvalLogsDataSourceConfig, EvalStoredCompletionsDataSourceConfig], + PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/evals/__init__.py b/src/openai/types/evals/__init__.py index ebf84c6b8d..9d26c7d915 100644 --- a/src/openai/types/evals/__init__.py +++ b/src/openai/types/evals/__init__.py @@ -11,12 +11,16 @@ from .run_delete_response import RunDeleteResponse as RunDeleteResponse from .run_retrieve_response import RunRetrieveResponse as RunRetrieveResponse from .create_eval_jsonl_run_data_source import CreateEvalJSONLRunDataSource as CreateEvalJSONLRunDataSource +from .create_eval_responses_run_data_source import CreateEvalResponsesRunDataSource as CreateEvalResponsesRunDataSource from .create_eval_completions_run_data_source import ( CreateEvalCompletionsRunDataSource as CreateEvalCompletionsRunDataSource, ) from .create_eval_jsonl_run_data_source_param import ( CreateEvalJSONLRunDataSourceParam as CreateEvalJSONLRunDataSourceParam, ) +from .create_eval_responses_run_data_source_param import ( + CreateEvalResponsesRunDataSourceParam as CreateEvalResponsesRunDataSourceParam, +) from .create_eval_completions_run_data_source_param import ( CreateEvalCompletionsRunDataSourceParam as CreateEvalCompletionsRunDataSourceParam, ) diff --git a/src/openai/types/evals/create_eval_responses_run_data_source.py b/src/openai/types/evals/create_eval_responses_run_data_source.py new file mode 100644 index 0000000000..481fd0761e --- /dev/null +++ b/src/openai/types/evals/create_eval_responses_run_data_source.py @@ -0,0 +1,206 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from ..shared.reasoning_effort import ReasoningEffort +from ..responses.response_input_text import ResponseInputText + +__all__ = [ + "CreateEvalResponsesRunDataSource", + "Source", + "SourceFileContent", + "SourceFileContentContent", + "SourceFileID", + "SourceResponses", + "InputMessages", + "InputMessagesTemplate", + "InputMessagesTemplateTemplate", + "InputMessagesTemplateTemplateChatMessage", + "InputMessagesTemplateTemplateEvalItem", + "InputMessagesTemplateTemplateEvalItemContent", + "InputMessagesTemplateTemplateEvalItemContentOutputText", + "InputMessagesItemReference", + "SamplingParams", +] + + +class SourceFileContentContent(BaseModel): + item: Dict[str, object] + + sample: Optional[Dict[str, object]] = None + + +class SourceFileContent(BaseModel): + content: List[SourceFileContentContent] + """The content of the jsonl file.""" + + type: Literal["file_content"] + """The type of jsonl source. Always `file_content`.""" + + +class SourceFileID(BaseModel): + id: str + """The identifier of the file.""" + + type: Literal["file_id"] + """The type of jsonl source. Always `file_id`.""" + + +class SourceResponses(BaseModel): + type: Literal["responses"] + """The type of run data source. Always `responses`.""" + + created_after: Optional[int] = None + """Only include items created after this timestamp (inclusive). + + This is a query parameter used to select responses. + """ + + created_before: Optional[int] = None + """Only include items created before this timestamp (inclusive). + + This is a query parameter used to select responses. + """ + + has_tool_calls: Optional[bool] = None + """Whether the response has tool calls. + + This is a query parameter used to select responses. + """ + + instructions_search: Optional[str] = None + """Optional string to search the 'instructions' field. + + This is a query parameter used to select responses. + """ + + metadata: Optional[object] = None + """Metadata filter for the responses. + + This is a query parameter used to select responses. + """ + + model: Optional[str] = None + """The name of the model to find responses for. + + This is a query parameter used to select responses. + """ + + reasoning_effort: Optional[ReasoningEffort] = None + """Optional reasoning effort parameter. + + This is a query parameter used to select responses. + """ + + temperature: Optional[float] = None + """Sampling temperature. This is a query parameter used to select responses.""" + + tools: Optional[List[str]] = None + """List of tool names. This is a query parameter used to select responses.""" + + top_p: Optional[float] = None + """Nucleus sampling parameter. This is a query parameter used to select responses.""" + + users: Optional[List[str]] = None + """List of user identifiers. This is a query parameter used to select responses.""" + + +Source: TypeAlias = Annotated[ + Union[SourceFileContent, SourceFileID, SourceResponses], PropertyInfo(discriminator="type") +] + + +class InputMessagesTemplateTemplateChatMessage(BaseModel): + content: str + """The content of the message.""" + + role: str + """The role of the message (e.g. "system", "assistant", "user").""" + + +class InputMessagesTemplateTemplateEvalItemContentOutputText(BaseModel): + text: str + """The text output from the model.""" + + type: Literal["output_text"] + """The type of the output text. Always `output_text`.""" + + +InputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ + str, ResponseInputText, InputMessagesTemplateTemplateEvalItemContentOutputText +] + + +class InputMessagesTemplateTemplateEvalItem(BaseModel): + content: InputMessagesTemplateTemplateEvalItemContent + """Text inputs to the model - can contain template strings.""" + + role: Literal["user", "assistant", "system", "developer"] + """The role of the message input. + + One of `user`, `assistant`, `system`, or `developer`. + """ + + type: Optional[Literal["message"]] = None + """The type of the message input. Always `message`.""" + + +InputMessagesTemplateTemplate: TypeAlias = Union[ + InputMessagesTemplateTemplateChatMessage, InputMessagesTemplateTemplateEvalItem +] + + +class InputMessagesTemplate(BaseModel): + template: List[InputMessagesTemplateTemplate] + """A list of chat messages forming the prompt or context. + + May include variable references to the "item" namespace, ie {{item.name}}. + """ + + type: Literal["template"] + """The type of input messages. Always `template`.""" + + +class InputMessagesItemReference(BaseModel): + item_reference: str + """A reference to a variable in the "item" namespace. Ie, "item.name" """ + + type: Literal["item_reference"] + """The type of input messages. Always `item_reference`.""" + + +InputMessages: TypeAlias = Annotated[ + Union[InputMessagesTemplate, InputMessagesItemReference], PropertyInfo(discriminator="type") +] + + +class SamplingParams(BaseModel): + max_completion_tokens: Optional[int] = None + """The maximum number of tokens in the generated output.""" + + seed: Optional[int] = None + """A seed value to initialize the randomness, during sampling.""" + + temperature: Optional[float] = None + """A higher temperature increases randomness in the outputs.""" + + top_p: Optional[float] = None + """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" + + +class CreateEvalResponsesRunDataSource(BaseModel): + source: Source + """A EvalResponsesSource object describing a run data source configuration.""" + + type: Literal["responses"] + """The type of run data source. Always `responses`.""" + + input_messages: Optional[InputMessages] = None + + model: Optional[str] = None + """The name of the model to use for generating completions (e.g. "o3-mini").""" + + sampling_params: Optional[SamplingParams] = None diff --git a/src/openai/types/evals/create_eval_responses_run_data_source_param.py b/src/openai/types/evals/create_eval_responses_run_data_source_param.py new file mode 100644 index 0000000000..9cde20de20 --- /dev/null +++ b/src/openai/types/evals/create_eval_responses_run_data_source_param.py @@ -0,0 +1,202 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, List, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from ..shared.reasoning_effort import ReasoningEffort +from ..responses.response_input_text_param import ResponseInputTextParam + +__all__ = [ + "CreateEvalResponsesRunDataSourceParam", + "Source", + "SourceFileContent", + "SourceFileContentContent", + "SourceFileID", + "SourceResponses", + "InputMessages", + "InputMessagesTemplate", + "InputMessagesTemplateTemplate", + "InputMessagesTemplateTemplateChatMessage", + "InputMessagesTemplateTemplateEvalItem", + "InputMessagesTemplateTemplateEvalItemContent", + "InputMessagesTemplateTemplateEvalItemContentOutputText", + "InputMessagesItemReference", + "SamplingParams", +] + + +class SourceFileContentContent(TypedDict, total=False): + item: Required[Dict[str, object]] + + sample: Dict[str, object] + + +class SourceFileContent(TypedDict, total=False): + content: Required[Iterable[SourceFileContentContent]] + """The content of the jsonl file.""" + + type: Required[Literal["file_content"]] + """The type of jsonl source. Always `file_content`.""" + + +class SourceFileID(TypedDict, total=False): + id: Required[str] + """The identifier of the file.""" + + type: Required[Literal["file_id"]] + """The type of jsonl source. Always `file_id`.""" + + +class SourceResponses(TypedDict, total=False): + type: Required[Literal["responses"]] + """The type of run data source. Always `responses`.""" + + created_after: Optional[int] + """Only include items created after this timestamp (inclusive). + + This is a query parameter used to select responses. + """ + + created_before: Optional[int] + """Only include items created before this timestamp (inclusive). + + This is a query parameter used to select responses. + """ + + has_tool_calls: Optional[bool] + """Whether the response has tool calls. + + This is a query parameter used to select responses. + """ + + instructions_search: Optional[str] + """Optional string to search the 'instructions' field. + + This is a query parameter used to select responses. + """ + + metadata: Optional[object] + """Metadata filter for the responses. + + This is a query parameter used to select responses. + """ + + model: Optional[str] + """The name of the model to find responses for. + + This is a query parameter used to select responses. + """ + + reasoning_effort: Optional[ReasoningEffort] + """Optional reasoning effort parameter. + + This is a query parameter used to select responses. + """ + + temperature: Optional[float] + """Sampling temperature. This is a query parameter used to select responses.""" + + tools: Optional[List[str]] + """List of tool names. This is a query parameter used to select responses.""" + + top_p: Optional[float] + """Nucleus sampling parameter. This is a query parameter used to select responses.""" + + users: Optional[List[str]] + """List of user identifiers. This is a query parameter used to select responses.""" + + +Source: TypeAlias = Union[SourceFileContent, SourceFileID, SourceResponses] + + +class InputMessagesTemplateTemplateChatMessage(TypedDict, total=False): + content: Required[str] + """The content of the message.""" + + role: Required[str] + """The role of the message (e.g. "system", "assistant", "user").""" + + +class InputMessagesTemplateTemplateEvalItemContentOutputText(TypedDict, total=False): + text: Required[str] + """The text output from the model.""" + + type: Required[Literal["output_text"]] + """The type of the output text. Always `output_text`.""" + + +InputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ + str, ResponseInputTextParam, InputMessagesTemplateTemplateEvalItemContentOutputText +] + + +class InputMessagesTemplateTemplateEvalItem(TypedDict, total=False): + content: Required[InputMessagesTemplateTemplateEvalItemContent] + """Text inputs to the model - can contain template strings.""" + + role: Required[Literal["user", "assistant", "system", "developer"]] + """The role of the message input. + + One of `user`, `assistant`, `system`, or `developer`. + """ + + type: Literal["message"] + """The type of the message input. Always `message`.""" + + +InputMessagesTemplateTemplate: TypeAlias = Union[ + InputMessagesTemplateTemplateChatMessage, InputMessagesTemplateTemplateEvalItem +] + + +class InputMessagesTemplate(TypedDict, total=False): + template: Required[Iterable[InputMessagesTemplateTemplate]] + """A list of chat messages forming the prompt or context. + + May include variable references to the "item" namespace, ie {{item.name}}. + """ + + type: Required[Literal["template"]] + """The type of input messages. Always `template`.""" + + +class InputMessagesItemReference(TypedDict, total=False): + item_reference: Required[str] + """A reference to a variable in the "item" namespace. Ie, "item.name" """ + + type: Required[Literal["item_reference"]] + """The type of input messages. Always `item_reference`.""" + + +InputMessages: TypeAlias = Union[InputMessagesTemplate, InputMessagesItemReference] + + +class SamplingParams(TypedDict, total=False): + max_completion_tokens: int + """The maximum number of tokens in the generated output.""" + + seed: int + """A seed value to initialize the randomness, during sampling.""" + + temperature: float + """A higher temperature increases randomness in the outputs.""" + + top_p: float + """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" + + +class CreateEvalResponsesRunDataSourceParam(TypedDict, total=False): + source: Required[Source] + """A EvalResponsesSource object describing a run data source configuration.""" + + type: Required[Literal["responses"]] + """The type of run data source. Always `responses`.""" + + input_messages: InputMessages + + model: str + """The name of the model to use for generating completions (e.g. "o3-mini").""" + + sampling_params: SamplingParams diff --git a/src/openai/types/evals/run_cancel_response.py b/src/openai/types/evals/run_cancel_response.py index eb6d689fc3..a49989b60f 100644 --- a/src/openai/types/evals/run_cancel_response.py +++ b/src/openai/types/evals/run_cancel_response.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Dict, List, Union, Optional +from typing import List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias from pydantic import Field as FieldInfo @@ -9,224 +9,14 @@ from ..._models import BaseModel from .eval_api_error import EvalAPIError from ..shared.metadata import Metadata -from ..shared.reasoning_effort import ReasoningEffort -from ..responses.response_input_text import ResponseInputText from .create_eval_jsonl_run_data_source import CreateEvalJSONLRunDataSource +from .create_eval_responses_run_data_source import CreateEvalResponsesRunDataSource from .create_eval_completions_run_data_source import CreateEvalCompletionsRunDataSource -__all__ = [ - "RunCancelResponse", - "DataSource", - "DataSourceCompletions", - "DataSourceCompletionsSource", - "DataSourceCompletionsSourceFileContent", - "DataSourceCompletionsSourceFileContentContent", - "DataSourceCompletionsSourceFileID", - "DataSourceCompletionsSourceResponses", - "DataSourceCompletionsInputMessages", - "DataSourceCompletionsInputMessagesTemplate", - "DataSourceCompletionsInputMessagesTemplateTemplate", - "DataSourceCompletionsInputMessagesTemplateTemplateChatMessage", - "DataSourceCompletionsInputMessagesTemplateTemplateEvalItem", - "DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContent", - "DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContentOutputText", - "DataSourceCompletionsInputMessagesItemReference", - "DataSourceCompletionsSamplingParams", - "PerModelUsage", - "PerTestingCriteriaResult", - "ResultCounts", -] - - -class DataSourceCompletionsSourceFileContentContent(BaseModel): - item: Dict[str, object] - - sample: Optional[Dict[str, object]] = None - - -class DataSourceCompletionsSourceFileContent(BaseModel): - content: List[DataSourceCompletionsSourceFileContentContent] - """The content of the jsonl file.""" - - type: Literal["file_content"] - """The type of jsonl source. Always `file_content`.""" - - -class DataSourceCompletionsSourceFileID(BaseModel): - id: str - """The identifier of the file.""" - - type: Literal["file_id"] - """The type of jsonl source. Always `file_id`.""" - - -class DataSourceCompletionsSourceResponses(BaseModel): - type: Literal["responses"] - """The type of run data source. Always `responses`.""" - - allow_parallel_tool_calls: Optional[bool] = None - """Whether to allow parallel tool calls. - - This is a query parameter used to select responses. - """ - - created_after: Optional[int] = None - """Only include items created after this timestamp (inclusive). - - This is a query parameter used to select responses. - """ - - created_before: Optional[int] = None - """Only include items created before this timestamp (inclusive). - - This is a query parameter used to select responses. - """ - - has_tool_calls: Optional[bool] = None - """Whether the response has tool calls. - - This is a query parameter used to select responses. - """ - - instructions_search: Optional[str] = None - """Optional search string for instructions. - - This is a query parameter used to select responses. - """ - - metadata: Optional[object] = None - """Metadata filter for the responses. - - This is a query parameter used to select responses. - """ - - model: Optional[str] = None - """The name of the model to find responses for. - - This is a query parameter used to select responses. - """ - - reasoning_effort: Optional[ReasoningEffort] = None - """Optional reasoning effort parameter. - - This is a query parameter used to select responses. - """ - - temperature: Optional[float] = None - """Sampling temperature. This is a query parameter used to select responses.""" - - top_p: Optional[float] = None - """Nucleus sampling parameter. This is a query parameter used to select responses.""" - - users: Optional[List[str]] = None - """List of user identifiers. This is a query parameter used to select responses.""" - - -DataSourceCompletionsSource: TypeAlias = Annotated[ - Union[ - DataSourceCompletionsSourceFileContent, DataSourceCompletionsSourceFileID, DataSourceCompletionsSourceResponses - ], - PropertyInfo(discriminator="type"), -] - - -class DataSourceCompletionsInputMessagesTemplateTemplateChatMessage(BaseModel): - content: str - """The content of the message.""" - - role: str - """The role of the message (e.g. "system", "assistant", "user").""" - - -class DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContentOutputText(BaseModel): - text: str - """The text output from the model.""" - - type: Literal["output_text"] - """The type of the output text. Always `output_text`.""" - - -DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ - str, ResponseInputText, DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContentOutputText -] - - -class DataSourceCompletionsInputMessagesTemplateTemplateEvalItem(BaseModel): - content: DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContent - """Text inputs to the model - can contain template strings.""" - - role: Literal["user", "assistant", "system", "developer"] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Optional[Literal["message"]] = None - """The type of the message input. Always `message`.""" - - -DataSourceCompletionsInputMessagesTemplateTemplate: TypeAlias = Union[ - DataSourceCompletionsInputMessagesTemplateTemplateChatMessage, - DataSourceCompletionsInputMessagesTemplateTemplateEvalItem, -] - - -class DataSourceCompletionsInputMessagesTemplate(BaseModel): - template: List[DataSourceCompletionsInputMessagesTemplateTemplate] - """A list of chat messages forming the prompt or context. - - May include variable references to the "item" namespace, ie {{item.name}}. - """ - - type: Literal["template"] - """The type of input messages. Always `template`.""" - - -class DataSourceCompletionsInputMessagesItemReference(BaseModel): - item_reference: str - """A reference to a variable in the "item" namespace. Ie, "item.name" """ - - type: Literal["item_reference"] - """The type of input messages. Always `item_reference`.""" - - -DataSourceCompletionsInputMessages: TypeAlias = Annotated[ - Union[DataSourceCompletionsInputMessagesTemplate, DataSourceCompletionsInputMessagesItemReference], - PropertyInfo(discriminator="type"), -] - - -class DataSourceCompletionsSamplingParams(BaseModel): - max_completion_tokens: Optional[int] = None - """The maximum number of tokens in the generated output.""" - - seed: Optional[int] = None - """A seed value to initialize the randomness, during sampling.""" - - temperature: Optional[float] = None - """A higher temperature increases randomness in the outputs.""" - - top_p: Optional[float] = None - """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" - - -class DataSourceCompletions(BaseModel): - source: DataSourceCompletionsSource - """A EvalResponsesSource object describing a run data source configuration.""" - - type: Literal["completions"] - """The type of run data source. Always `completions`.""" - - input_messages: Optional[DataSourceCompletionsInputMessages] = None - - model: Optional[str] = None - """The name of the model to use for generating completions (e.g. "o3-mini").""" - - sampling_params: Optional[DataSourceCompletionsSamplingParams] = None - +__all__ = ["RunCancelResponse", "DataSource", "PerModelUsage", "PerTestingCriteriaResult", "ResultCounts"] DataSource: TypeAlias = Annotated[ - Union[CreateEvalJSONLRunDataSource, CreateEvalCompletionsRunDataSource, DataSourceCompletions], + Union[CreateEvalJSONLRunDataSource, CreateEvalCompletionsRunDataSource, CreateEvalResponsesRunDataSource], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/evals/run_create_params.py b/src/openai/types/evals/run_create_params.py index 0c9720ea7a..00c7398748 100644 --- a/src/openai/types/evals/run_create_params.py +++ b/src/openai/types/evals/run_create_params.py @@ -2,34 +2,15 @@ from __future__ import annotations -from typing import Dict, List, Union, Iterable, Optional -from typing_extensions import Literal, Required, TypeAlias, TypedDict +from typing import Union, Optional +from typing_extensions import Required, TypeAlias, TypedDict from ..shared_params.metadata import Metadata -from ..shared.reasoning_effort import ReasoningEffort -from ..responses.response_input_text_param import ResponseInputTextParam from .create_eval_jsonl_run_data_source_param import CreateEvalJSONLRunDataSourceParam +from .create_eval_responses_run_data_source_param import CreateEvalResponsesRunDataSourceParam from .create_eval_completions_run_data_source_param import CreateEvalCompletionsRunDataSourceParam -__all__ = [ - "RunCreateParams", - "DataSource", - "DataSourceCreateEvalResponsesRunDataSource", - "DataSourceCreateEvalResponsesRunDataSourceSource", - "DataSourceCreateEvalResponsesRunDataSourceSourceFileContent", - "DataSourceCreateEvalResponsesRunDataSourceSourceFileContentContent", - "DataSourceCreateEvalResponsesRunDataSourceSourceFileID", - "DataSourceCreateEvalResponsesRunDataSourceSourceResponses", - "DataSourceCreateEvalResponsesRunDataSourceInputMessages", - "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplate", - "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplate", - "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateChatMessage", - "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItem", - "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContent", - "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentOutputText", - "DataSourceCreateEvalResponsesRunDataSourceInputMessagesItemReference", - "DataSourceCreateEvalResponsesRunDataSourceSamplingParams", -] +__all__ = ["RunCreateParams", "DataSource"] class RunCreateParams(TypedDict, total=False): @@ -50,198 +31,6 @@ class RunCreateParams(TypedDict, total=False): """The name of the run.""" -class DataSourceCreateEvalResponsesRunDataSourceSourceFileContentContent(TypedDict, total=False): - item: Required[Dict[str, object]] - - sample: Dict[str, object] - - -class DataSourceCreateEvalResponsesRunDataSourceSourceFileContent(TypedDict, total=False): - content: Required[Iterable[DataSourceCreateEvalResponsesRunDataSourceSourceFileContentContent]] - """The content of the jsonl file.""" - - type: Required[Literal["file_content"]] - """The type of jsonl source. Always `file_content`.""" - - -class DataSourceCreateEvalResponsesRunDataSourceSourceFileID(TypedDict, total=False): - id: Required[str] - """The identifier of the file.""" - - type: Required[Literal["file_id"]] - """The type of jsonl source. Always `file_id`.""" - - -class DataSourceCreateEvalResponsesRunDataSourceSourceResponses(TypedDict, total=False): - type: Required[Literal["responses"]] - """The type of run data source. Always `responses`.""" - - allow_parallel_tool_calls: Optional[bool] - """Whether to allow parallel tool calls. - - This is a query parameter used to select responses. - """ - - created_after: Optional[int] - """Only include items created after this timestamp (inclusive). - - This is a query parameter used to select responses. - """ - - created_before: Optional[int] - """Only include items created before this timestamp (inclusive). - - This is a query parameter used to select responses. - """ - - has_tool_calls: Optional[bool] - """Whether the response has tool calls. - - This is a query parameter used to select responses. - """ - - instructions_search: Optional[str] - """Optional search string for instructions. - - This is a query parameter used to select responses. - """ - - metadata: Optional[object] - """Metadata filter for the responses. - - This is a query parameter used to select responses. - """ - - model: Optional[str] - """The name of the model to find responses for. - - This is a query parameter used to select responses. - """ - - reasoning_effort: Optional[ReasoningEffort] - """Optional reasoning effort parameter. - - This is a query parameter used to select responses. - """ - - temperature: Optional[float] - """Sampling temperature. This is a query parameter used to select responses.""" - - top_p: Optional[float] - """Nucleus sampling parameter. This is a query parameter used to select responses.""" - - users: Optional[List[str]] - """List of user identifiers. This is a query parameter used to select responses.""" - - -DataSourceCreateEvalResponsesRunDataSourceSource: TypeAlias = Union[ - DataSourceCreateEvalResponsesRunDataSourceSourceFileContent, - DataSourceCreateEvalResponsesRunDataSourceSourceFileID, - DataSourceCreateEvalResponsesRunDataSourceSourceResponses, -] - - -class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateChatMessage(TypedDict, total=False): - content: Required[str] - """The content of the message.""" - - role: Required[str] - """The role of the message (e.g. "system", "assistant", "user").""" - - -class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentOutputText( - TypedDict, total=False -): - text: Required[str] - """The text output from the model.""" - - type: Required[Literal["output_text"]] - """The type of the output text. Always `output_text`.""" - - -DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ - str, - ResponseInputTextParam, - DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentOutputText, -] - - -class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItem(TypedDict, total=False): - content: Required[DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContent] - """Text inputs to the model - can contain template strings.""" - - role: Required[Literal["user", "assistant", "system", "developer"]] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Literal["message"] - """The type of the message input. Always `message`.""" - - -DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplate: TypeAlias = Union[ - DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateChatMessage, - DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItem, -] - - -class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplate(TypedDict, total=False): - template: Required[Iterable[DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplate]] - """A list of chat messages forming the prompt or context. - - May include variable references to the "item" namespace, ie {{item.name}}. - """ - - type: Required[Literal["template"]] - """The type of input messages. Always `template`.""" - - -class DataSourceCreateEvalResponsesRunDataSourceInputMessagesItemReference(TypedDict, total=False): - item_reference: Required[str] - """A reference to a variable in the "item" namespace. Ie, "item.name" """ - - type: Required[Literal["item_reference"]] - """The type of input messages. Always `item_reference`.""" - - -DataSourceCreateEvalResponsesRunDataSourceInputMessages: TypeAlias = Union[ - DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplate, - DataSourceCreateEvalResponsesRunDataSourceInputMessagesItemReference, -] - - -class DataSourceCreateEvalResponsesRunDataSourceSamplingParams(TypedDict, total=False): - max_completion_tokens: int - """The maximum number of tokens in the generated output.""" - - seed: int - """A seed value to initialize the randomness, during sampling.""" - - temperature: float - """A higher temperature increases randomness in the outputs.""" - - top_p: float - """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" - - -class DataSourceCreateEvalResponsesRunDataSource(TypedDict, total=False): - source: Required[DataSourceCreateEvalResponsesRunDataSourceSource] - """A EvalResponsesSource object describing a run data source configuration.""" - - type: Required[Literal["completions"]] - """The type of run data source. Always `completions`.""" - - input_messages: DataSourceCreateEvalResponsesRunDataSourceInputMessages - - model: str - """The name of the model to use for generating completions (e.g. "o3-mini").""" - - sampling_params: DataSourceCreateEvalResponsesRunDataSourceSamplingParams - - DataSource: TypeAlias = Union[ - CreateEvalJSONLRunDataSourceParam, - CreateEvalCompletionsRunDataSourceParam, - DataSourceCreateEvalResponsesRunDataSource, + CreateEvalJSONLRunDataSourceParam, CreateEvalCompletionsRunDataSourceParam, CreateEvalResponsesRunDataSourceParam ] diff --git a/src/openai/types/evals/run_create_response.py b/src/openai/types/evals/run_create_response.py index 459399511c..8dc64cf895 100644 --- a/src/openai/types/evals/run_create_response.py +++ b/src/openai/types/evals/run_create_response.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Dict, List, Union, Optional +from typing import List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias from pydantic import Field as FieldInfo @@ -9,224 +9,14 @@ from ..._models import BaseModel from .eval_api_error import EvalAPIError from ..shared.metadata import Metadata -from ..shared.reasoning_effort import ReasoningEffort -from ..responses.response_input_text import ResponseInputText from .create_eval_jsonl_run_data_source import CreateEvalJSONLRunDataSource +from .create_eval_responses_run_data_source import CreateEvalResponsesRunDataSource from .create_eval_completions_run_data_source import CreateEvalCompletionsRunDataSource -__all__ = [ - "RunCreateResponse", - "DataSource", - "DataSourceCompletions", - "DataSourceCompletionsSource", - "DataSourceCompletionsSourceFileContent", - "DataSourceCompletionsSourceFileContentContent", - "DataSourceCompletionsSourceFileID", - "DataSourceCompletionsSourceResponses", - "DataSourceCompletionsInputMessages", - "DataSourceCompletionsInputMessagesTemplate", - "DataSourceCompletionsInputMessagesTemplateTemplate", - "DataSourceCompletionsInputMessagesTemplateTemplateChatMessage", - "DataSourceCompletionsInputMessagesTemplateTemplateEvalItem", - "DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContent", - "DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContentOutputText", - "DataSourceCompletionsInputMessagesItemReference", - "DataSourceCompletionsSamplingParams", - "PerModelUsage", - "PerTestingCriteriaResult", - "ResultCounts", -] - - -class DataSourceCompletionsSourceFileContentContent(BaseModel): - item: Dict[str, object] - - sample: Optional[Dict[str, object]] = None - - -class DataSourceCompletionsSourceFileContent(BaseModel): - content: List[DataSourceCompletionsSourceFileContentContent] - """The content of the jsonl file.""" - - type: Literal["file_content"] - """The type of jsonl source. Always `file_content`.""" - - -class DataSourceCompletionsSourceFileID(BaseModel): - id: str - """The identifier of the file.""" - - type: Literal["file_id"] - """The type of jsonl source. Always `file_id`.""" - - -class DataSourceCompletionsSourceResponses(BaseModel): - type: Literal["responses"] - """The type of run data source. Always `responses`.""" - - allow_parallel_tool_calls: Optional[bool] = None - """Whether to allow parallel tool calls. - - This is a query parameter used to select responses. - """ - - created_after: Optional[int] = None - """Only include items created after this timestamp (inclusive). - - This is a query parameter used to select responses. - """ - - created_before: Optional[int] = None - """Only include items created before this timestamp (inclusive). - - This is a query parameter used to select responses. - """ - - has_tool_calls: Optional[bool] = None - """Whether the response has tool calls. - - This is a query parameter used to select responses. - """ - - instructions_search: Optional[str] = None - """Optional search string for instructions. - - This is a query parameter used to select responses. - """ - - metadata: Optional[object] = None - """Metadata filter for the responses. - - This is a query parameter used to select responses. - """ - - model: Optional[str] = None - """The name of the model to find responses for. - - This is a query parameter used to select responses. - """ - - reasoning_effort: Optional[ReasoningEffort] = None - """Optional reasoning effort parameter. - - This is a query parameter used to select responses. - """ - - temperature: Optional[float] = None - """Sampling temperature. This is a query parameter used to select responses.""" - - top_p: Optional[float] = None - """Nucleus sampling parameter. This is a query parameter used to select responses.""" - - users: Optional[List[str]] = None - """List of user identifiers. This is a query parameter used to select responses.""" - - -DataSourceCompletionsSource: TypeAlias = Annotated[ - Union[ - DataSourceCompletionsSourceFileContent, DataSourceCompletionsSourceFileID, DataSourceCompletionsSourceResponses - ], - PropertyInfo(discriminator="type"), -] - - -class DataSourceCompletionsInputMessagesTemplateTemplateChatMessage(BaseModel): - content: str - """The content of the message.""" - - role: str - """The role of the message (e.g. "system", "assistant", "user").""" - - -class DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContentOutputText(BaseModel): - text: str - """The text output from the model.""" - - type: Literal["output_text"] - """The type of the output text. Always `output_text`.""" - - -DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ - str, ResponseInputText, DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContentOutputText -] - - -class DataSourceCompletionsInputMessagesTemplateTemplateEvalItem(BaseModel): - content: DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContent - """Text inputs to the model - can contain template strings.""" - - role: Literal["user", "assistant", "system", "developer"] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Optional[Literal["message"]] = None - """The type of the message input. Always `message`.""" - - -DataSourceCompletionsInputMessagesTemplateTemplate: TypeAlias = Union[ - DataSourceCompletionsInputMessagesTemplateTemplateChatMessage, - DataSourceCompletionsInputMessagesTemplateTemplateEvalItem, -] - - -class DataSourceCompletionsInputMessagesTemplate(BaseModel): - template: List[DataSourceCompletionsInputMessagesTemplateTemplate] - """A list of chat messages forming the prompt or context. - - May include variable references to the "item" namespace, ie {{item.name}}. - """ - - type: Literal["template"] - """The type of input messages. Always `template`.""" - - -class DataSourceCompletionsInputMessagesItemReference(BaseModel): - item_reference: str - """A reference to a variable in the "item" namespace. Ie, "item.name" """ - - type: Literal["item_reference"] - """The type of input messages. Always `item_reference`.""" - - -DataSourceCompletionsInputMessages: TypeAlias = Annotated[ - Union[DataSourceCompletionsInputMessagesTemplate, DataSourceCompletionsInputMessagesItemReference], - PropertyInfo(discriminator="type"), -] - - -class DataSourceCompletionsSamplingParams(BaseModel): - max_completion_tokens: Optional[int] = None - """The maximum number of tokens in the generated output.""" - - seed: Optional[int] = None - """A seed value to initialize the randomness, during sampling.""" - - temperature: Optional[float] = None - """A higher temperature increases randomness in the outputs.""" - - top_p: Optional[float] = None - """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" - - -class DataSourceCompletions(BaseModel): - source: DataSourceCompletionsSource - """A EvalResponsesSource object describing a run data source configuration.""" - - type: Literal["completions"] - """The type of run data source. Always `completions`.""" - - input_messages: Optional[DataSourceCompletionsInputMessages] = None - - model: Optional[str] = None - """The name of the model to use for generating completions (e.g. "o3-mini").""" - - sampling_params: Optional[DataSourceCompletionsSamplingParams] = None - +__all__ = ["RunCreateResponse", "DataSource", "PerModelUsage", "PerTestingCriteriaResult", "ResultCounts"] DataSource: TypeAlias = Annotated[ - Union[CreateEvalJSONLRunDataSource, CreateEvalCompletionsRunDataSource, DataSourceCompletions], + Union[CreateEvalJSONLRunDataSource, CreateEvalCompletionsRunDataSource, CreateEvalResponsesRunDataSource], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/evals/run_list_response.py b/src/openai/types/evals/run_list_response.py index 278ceeabed..0df3e5c7ad 100644 --- a/src/openai/types/evals/run_list_response.py +++ b/src/openai/types/evals/run_list_response.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Dict, List, Union, Optional +from typing import List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias from pydantic import Field as FieldInfo @@ -9,224 +9,14 @@ from ..._models import BaseModel from .eval_api_error import EvalAPIError from ..shared.metadata import Metadata -from ..shared.reasoning_effort import ReasoningEffort -from ..responses.response_input_text import ResponseInputText from .create_eval_jsonl_run_data_source import CreateEvalJSONLRunDataSource +from .create_eval_responses_run_data_source import CreateEvalResponsesRunDataSource from .create_eval_completions_run_data_source import CreateEvalCompletionsRunDataSource -__all__ = [ - "RunListResponse", - "DataSource", - "DataSourceCompletions", - "DataSourceCompletionsSource", - "DataSourceCompletionsSourceFileContent", - "DataSourceCompletionsSourceFileContentContent", - "DataSourceCompletionsSourceFileID", - "DataSourceCompletionsSourceResponses", - "DataSourceCompletionsInputMessages", - "DataSourceCompletionsInputMessagesTemplate", - "DataSourceCompletionsInputMessagesTemplateTemplate", - "DataSourceCompletionsInputMessagesTemplateTemplateChatMessage", - "DataSourceCompletionsInputMessagesTemplateTemplateEvalItem", - "DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContent", - "DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContentOutputText", - "DataSourceCompletionsInputMessagesItemReference", - "DataSourceCompletionsSamplingParams", - "PerModelUsage", - "PerTestingCriteriaResult", - "ResultCounts", -] - - -class DataSourceCompletionsSourceFileContentContent(BaseModel): - item: Dict[str, object] - - sample: Optional[Dict[str, object]] = None - - -class DataSourceCompletionsSourceFileContent(BaseModel): - content: List[DataSourceCompletionsSourceFileContentContent] - """The content of the jsonl file.""" - - type: Literal["file_content"] - """The type of jsonl source. Always `file_content`.""" - - -class DataSourceCompletionsSourceFileID(BaseModel): - id: str - """The identifier of the file.""" - - type: Literal["file_id"] - """The type of jsonl source. Always `file_id`.""" - - -class DataSourceCompletionsSourceResponses(BaseModel): - type: Literal["responses"] - """The type of run data source. Always `responses`.""" - - allow_parallel_tool_calls: Optional[bool] = None - """Whether to allow parallel tool calls. - - This is a query parameter used to select responses. - """ - - created_after: Optional[int] = None - """Only include items created after this timestamp (inclusive). - - This is a query parameter used to select responses. - """ - - created_before: Optional[int] = None - """Only include items created before this timestamp (inclusive). - - This is a query parameter used to select responses. - """ - - has_tool_calls: Optional[bool] = None - """Whether the response has tool calls. - - This is a query parameter used to select responses. - """ - - instructions_search: Optional[str] = None - """Optional search string for instructions. - - This is a query parameter used to select responses. - """ - - metadata: Optional[object] = None - """Metadata filter for the responses. - - This is a query parameter used to select responses. - """ - - model: Optional[str] = None - """The name of the model to find responses for. - - This is a query parameter used to select responses. - """ - - reasoning_effort: Optional[ReasoningEffort] = None - """Optional reasoning effort parameter. - - This is a query parameter used to select responses. - """ - - temperature: Optional[float] = None - """Sampling temperature. This is a query parameter used to select responses.""" - - top_p: Optional[float] = None - """Nucleus sampling parameter. This is a query parameter used to select responses.""" - - users: Optional[List[str]] = None - """List of user identifiers. This is a query parameter used to select responses.""" - - -DataSourceCompletionsSource: TypeAlias = Annotated[ - Union[ - DataSourceCompletionsSourceFileContent, DataSourceCompletionsSourceFileID, DataSourceCompletionsSourceResponses - ], - PropertyInfo(discriminator="type"), -] - - -class DataSourceCompletionsInputMessagesTemplateTemplateChatMessage(BaseModel): - content: str - """The content of the message.""" - - role: str - """The role of the message (e.g. "system", "assistant", "user").""" - - -class DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContentOutputText(BaseModel): - text: str - """The text output from the model.""" - - type: Literal["output_text"] - """The type of the output text. Always `output_text`.""" - - -DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ - str, ResponseInputText, DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContentOutputText -] - - -class DataSourceCompletionsInputMessagesTemplateTemplateEvalItem(BaseModel): - content: DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContent - """Text inputs to the model - can contain template strings.""" - - role: Literal["user", "assistant", "system", "developer"] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Optional[Literal["message"]] = None - """The type of the message input. Always `message`.""" - - -DataSourceCompletionsInputMessagesTemplateTemplate: TypeAlias = Union[ - DataSourceCompletionsInputMessagesTemplateTemplateChatMessage, - DataSourceCompletionsInputMessagesTemplateTemplateEvalItem, -] - - -class DataSourceCompletionsInputMessagesTemplate(BaseModel): - template: List[DataSourceCompletionsInputMessagesTemplateTemplate] - """A list of chat messages forming the prompt or context. - - May include variable references to the "item" namespace, ie {{item.name}}. - """ - - type: Literal["template"] - """The type of input messages. Always `template`.""" - - -class DataSourceCompletionsInputMessagesItemReference(BaseModel): - item_reference: str - """A reference to a variable in the "item" namespace. Ie, "item.name" """ - - type: Literal["item_reference"] - """The type of input messages. Always `item_reference`.""" - - -DataSourceCompletionsInputMessages: TypeAlias = Annotated[ - Union[DataSourceCompletionsInputMessagesTemplate, DataSourceCompletionsInputMessagesItemReference], - PropertyInfo(discriminator="type"), -] - - -class DataSourceCompletionsSamplingParams(BaseModel): - max_completion_tokens: Optional[int] = None - """The maximum number of tokens in the generated output.""" - - seed: Optional[int] = None - """A seed value to initialize the randomness, during sampling.""" - - temperature: Optional[float] = None - """A higher temperature increases randomness in the outputs.""" - - top_p: Optional[float] = None - """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" - - -class DataSourceCompletions(BaseModel): - source: DataSourceCompletionsSource - """A EvalResponsesSource object describing a run data source configuration.""" - - type: Literal["completions"] - """The type of run data source. Always `completions`.""" - - input_messages: Optional[DataSourceCompletionsInputMessages] = None - - model: Optional[str] = None - """The name of the model to use for generating completions (e.g. "o3-mini").""" - - sampling_params: Optional[DataSourceCompletionsSamplingParams] = None - +__all__ = ["RunListResponse", "DataSource", "PerModelUsage", "PerTestingCriteriaResult", "ResultCounts"] DataSource: TypeAlias = Annotated[ - Union[CreateEvalJSONLRunDataSource, CreateEvalCompletionsRunDataSource, DataSourceCompletions], + Union[CreateEvalJSONLRunDataSource, CreateEvalCompletionsRunDataSource, CreateEvalResponsesRunDataSource], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/evals/run_retrieve_response.py b/src/openai/types/evals/run_retrieve_response.py index e142f31b14..35cdb04efc 100644 --- a/src/openai/types/evals/run_retrieve_response.py +++ b/src/openai/types/evals/run_retrieve_response.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Dict, List, Union, Optional +from typing import List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias from pydantic import Field as FieldInfo @@ -9,224 +9,14 @@ from ..._models import BaseModel from .eval_api_error import EvalAPIError from ..shared.metadata import Metadata -from ..shared.reasoning_effort import ReasoningEffort -from ..responses.response_input_text import ResponseInputText from .create_eval_jsonl_run_data_source import CreateEvalJSONLRunDataSource +from .create_eval_responses_run_data_source import CreateEvalResponsesRunDataSource from .create_eval_completions_run_data_source import CreateEvalCompletionsRunDataSource -__all__ = [ - "RunRetrieveResponse", - "DataSource", - "DataSourceCompletions", - "DataSourceCompletionsSource", - "DataSourceCompletionsSourceFileContent", - "DataSourceCompletionsSourceFileContentContent", - "DataSourceCompletionsSourceFileID", - "DataSourceCompletionsSourceResponses", - "DataSourceCompletionsInputMessages", - "DataSourceCompletionsInputMessagesTemplate", - "DataSourceCompletionsInputMessagesTemplateTemplate", - "DataSourceCompletionsInputMessagesTemplateTemplateChatMessage", - "DataSourceCompletionsInputMessagesTemplateTemplateEvalItem", - "DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContent", - "DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContentOutputText", - "DataSourceCompletionsInputMessagesItemReference", - "DataSourceCompletionsSamplingParams", - "PerModelUsage", - "PerTestingCriteriaResult", - "ResultCounts", -] - - -class DataSourceCompletionsSourceFileContentContent(BaseModel): - item: Dict[str, object] - - sample: Optional[Dict[str, object]] = None - - -class DataSourceCompletionsSourceFileContent(BaseModel): - content: List[DataSourceCompletionsSourceFileContentContent] - """The content of the jsonl file.""" - - type: Literal["file_content"] - """The type of jsonl source. Always `file_content`.""" - - -class DataSourceCompletionsSourceFileID(BaseModel): - id: str - """The identifier of the file.""" - - type: Literal["file_id"] - """The type of jsonl source. Always `file_id`.""" - - -class DataSourceCompletionsSourceResponses(BaseModel): - type: Literal["responses"] - """The type of run data source. Always `responses`.""" - - allow_parallel_tool_calls: Optional[bool] = None - """Whether to allow parallel tool calls. - - This is a query parameter used to select responses. - """ - - created_after: Optional[int] = None - """Only include items created after this timestamp (inclusive). - - This is a query parameter used to select responses. - """ - - created_before: Optional[int] = None - """Only include items created before this timestamp (inclusive). - - This is a query parameter used to select responses. - """ - - has_tool_calls: Optional[bool] = None - """Whether the response has tool calls. - - This is a query parameter used to select responses. - """ - - instructions_search: Optional[str] = None - """Optional search string for instructions. - - This is a query parameter used to select responses. - """ - - metadata: Optional[object] = None - """Metadata filter for the responses. - - This is a query parameter used to select responses. - """ - - model: Optional[str] = None - """The name of the model to find responses for. - - This is a query parameter used to select responses. - """ - - reasoning_effort: Optional[ReasoningEffort] = None - """Optional reasoning effort parameter. - - This is a query parameter used to select responses. - """ - - temperature: Optional[float] = None - """Sampling temperature. This is a query parameter used to select responses.""" - - top_p: Optional[float] = None - """Nucleus sampling parameter. This is a query parameter used to select responses.""" - - users: Optional[List[str]] = None - """List of user identifiers. This is a query parameter used to select responses.""" - - -DataSourceCompletionsSource: TypeAlias = Annotated[ - Union[ - DataSourceCompletionsSourceFileContent, DataSourceCompletionsSourceFileID, DataSourceCompletionsSourceResponses - ], - PropertyInfo(discriminator="type"), -] - - -class DataSourceCompletionsInputMessagesTemplateTemplateChatMessage(BaseModel): - content: str - """The content of the message.""" - - role: str - """The role of the message (e.g. "system", "assistant", "user").""" - - -class DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContentOutputText(BaseModel): - text: str - """The text output from the model.""" - - type: Literal["output_text"] - """The type of the output text. Always `output_text`.""" - - -DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ - str, ResponseInputText, DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContentOutputText -] - - -class DataSourceCompletionsInputMessagesTemplateTemplateEvalItem(BaseModel): - content: DataSourceCompletionsInputMessagesTemplateTemplateEvalItemContent - """Text inputs to the model - can contain template strings.""" - - role: Literal["user", "assistant", "system", "developer"] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Optional[Literal["message"]] = None - """The type of the message input. Always `message`.""" - - -DataSourceCompletionsInputMessagesTemplateTemplate: TypeAlias = Union[ - DataSourceCompletionsInputMessagesTemplateTemplateChatMessage, - DataSourceCompletionsInputMessagesTemplateTemplateEvalItem, -] - - -class DataSourceCompletionsInputMessagesTemplate(BaseModel): - template: List[DataSourceCompletionsInputMessagesTemplateTemplate] - """A list of chat messages forming the prompt or context. - - May include variable references to the "item" namespace, ie {{item.name}}. - """ - - type: Literal["template"] - """The type of input messages. Always `template`.""" - - -class DataSourceCompletionsInputMessagesItemReference(BaseModel): - item_reference: str - """A reference to a variable in the "item" namespace. Ie, "item.name" """ - - type: Literal["item_reference"] - """The type of input messages. Always `item_reference`.""" - - -DataSourceCompletionsInputMessages: TypeAlias = Annotated[ - Union[DataSourceCompletionsInputMessagesTemplate, DataSourceCompletionsInputMessagesItemReference], - PropertyInfo(discriminator="type"), -] - - -class DataSourceCompletionsSamplingParams(BaseModel): - max_completion_tokens: Optional[int] = None - """The maximum number of tokens in the generated output.""" - - seed: Optional[int] = None - """A seed value to initialize the randomness, during sampling.""" - - temperature: Optional[float] = None - """A higher temperature increases randomness in the outputs.""" - - top_p: Optional[float] = None - """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" - - -class DataSourceCompletions(BaseModel): - source: DataSourceCompletionsSource - """A EvalResponsesSource object describing a run data source configuration.""" - - type: Literal["completions"] - """The type of run data source. Always `completions`.""" - - input_messages: Optional[DataSourceCompletionsInputMessages] = None - - model: Optional[str] = None - """The name of the model to use for generating completions (e.g. "o3-mini").""" - - sampling_params: Optional[DataSourceCompletionsSamplingParams] = None - +__all__ = ["RunRetrieveResponse", "DataSource", "PerModelUsage", "PerTestingCriteriaResult", "ResultCounts"] DataSource: TypeAlias = Annotated[ - Union[CreateEvalJSONLRunDataSource, CreateEvalCompletionsRunDataSource, DataSourceCompletions], + Union[CreateEvalJSONLRunDataSource, CreateEvalCompletionsRunDataSource, CreateEvalResponsesRunDataSource], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/fine_tuning/fine_tuning_job.py b/src/openai/types/fine_tuning/fine_tuning_job.py index f626fbba64..b6123f8ba6 100644 --- a/src/openai/types/fine_tuning/fine_tuning_job.py +++ b/src/openai/types/fine_tuning/fine_tuning_job.py @@ -28,7 +28,7 @@ class Error(BaseModel): class Hyperparameters(BaseModel): - batch_size: Union[Literal["auto"], int, None] = None + batch_size: Union[Literal["auto"], int, Optional[object], None] = None """Number of examples in each batch. A larger batch size means that model parameters are updated less frequently, but diff --git a/tests/api_resources/audio/test_transcriptions.py b/tests/api_resources/audio/test_transcriptions.py index 19215e11df..753acdecf6 100644 --- a/tests/api_resources/audio/test_transcriptions.py +++ b/tests/api_resources/audio/test_transcriptions.py @@ -30,6 +30,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: transcription = client.audio.transcriptions.create( file=b"raw file contents", model="gpt-4o-transcribe", + chunking_strategy="auto", include=["logprobs"], language="language", prompt="prompt", @@ -81,6 +82,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: file=b"raw file contents", model="gpt-4o-transcribe", stream=True, + chunking_strategy="auto", include=["logprobs"], language="language", prompt="prompt", @@ -134,6 +136,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn transcription = await async_client.audio.transcriptions.create( file=b"raw file contents", model="gpt-4o-transcribe", + chunking_strategy="auto", include=["logprobs"], language="language", prompt="prompt", @@ -185,6 +188,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn file=b"raw file contents", model="gpt-4o-transcribe", stream=True, + chunking_strategy="auto", include=["logprobs"], language="language", prompt="prompt", From d7765341eecd456ef4038e20ac94bcd2f3f0f43b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 15 May 2025 23:47:25 +0000 Subject: [PATCH 332/769] feat(api): manual updates --- .stats.yml | 2 +- api.md | 5 ++ .../resources/beta/threads/runs/runs.py | 17 ++--- src/openai/resources/beta/threads/threads.py | 17 ++--- .../resources/vector_stores/vector_stores.py | 9 +-- src/openai/types/__init__.py | 3 + src/openai/types/beta/__init__.py | 2 + .../beta/thread_create_and_run_params.py | 21 +----- src/openai/types/beta/threads/run.py | 30 +-------- .../types/beta/threads/run_create_params.py | 21 +----- src/openai/types/beta/truncation_object.py | 25 +++++++ .../types/beta/truncation_object_param.py | 25 +++++++ src/openai/types/eval_create_params.py | 36 +--------- src/openai/types/evals/__init__.py | 4 ++ ...create_eval_completions_run_data_source.py | 67 ++----------------- ..._eval_completions_run_data_source_param.py | 66 ++---------------- .../create_eval_jsonl_run_data_source.py | 33 ++------- ...create_eval_jsonl_run_data_source_param.py | 36 ++-------- .../create_eval_responses_run_data_source.py | 67 ++----------------- ...te_eval_responses_run_data_source_param.py | 67 ++----------------- .../evals/eval_jsonl_file_content_source.py | 22 ++++++ .../eval_jsonl_file_content_source_param.py | 22 ++++++ .../types/evals/eval_jsonl_file_id_source.py | 15 +++++ .../evals/eval_jsonl_file_id_source_param.py | 15 +++++ .../types/graders/label_model_grader.py | 35 ++-------- .../types/graders/label_model_grader_param.py | 35 ++-------- .../types/graders/score_model_grader.py | 35 ++-------- .../types/graders/score_model_grader_param.py | 35 ++-------- src/openai/types/shared/__init__.py | 1 + src/openai/types/shared/eval_item.py | 34 ++++++++++ src/openai/types/shared_params/__init__.py | 1 + src/openai/types/shared_params/eval_item.py | 35 ++++++++++ src/openai/types/vector_store.py | 16 +---- .../types/vector_store_create_params.py | 18 ++--- .../types/vector_store_expiration_after.py | 18 +++++ .../vector_store_expiration_after_param.py | 18 +++++ .../types/vector_store_update_params.py | 18 ++--- 37 files changed, 346 insertions(+), 580 deletions(-) create mode 100644 src/openai/types/beta/truncation_object.py create mode 100644 src/openai/types/beta/truncation_object_param.py create mode 100644 src/openai/types/evals/eval_jsonl_file_content_source.py create mode 100644 src/openai/types/evals/eval_jsonl_file_content_source_param.py create mode 100644 src/openai/types/evals/eval_jsonl_file_id_source.py create mode 100644 src/openai/types/evals/eval_jsonl_file_id_source_param.py create mode 100644 src/openai/types/shared/eval_item.py create mode 100644 src/openai/types/shared_params/eval_item.py create mode 100644 src/openai/types/vector_store_expiration_after.py create mode 100644 src/openai/types/vector_store_expiration_after_param.py diff --git a/.stats.yml b/.stats.yml index 11ba2b0101..202b915dc8 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 101 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-161ca7f1cfd7b33c1fc07d0ce25dfe4be5a7271c394f4cb526b7fb21b0729900.yml openapi_spec_hash: 602e14add4bee018c6774e320ce309b8 -config_hash: 7da27f7260075e8813ddcea542fba1bf +config_hash: bdacc55eb995c15255ec82130eb8c3bb diff --git a/api.md b/api.md index db505b20d1..869b7d5042 100644 --- a/api.md +++ b/api.md @@ -7,6 +7,7 @@ from openai.types import ( ComparisonFilter, CompoundFilter, ErrorObject, + EvalItem, FunctionDefinition, FunctionParameters, Metadata, @@ -343,6 +344,7 @@ from openai.types import ( StaticFileChunkingStrategyObjectParam, VectorStore, VectorStoreDeleted, + VectorStoreExpirationAfter, VectorStoreSearchResponse, ) ``` @@ -519,6 +521,7 @@ from openai.types.beta import ( AssistantToolChoiceOption, Thread, ThreadDeleted, + TruncationObject, ) ``` @@ -815,6 +818,8 @@ from openai.types.evals import ( CreateEvalJSONLRunDataSource, CreateEvalResponsesRunDataSource, EvalAPIError, + EvalJSONLFileContentSource, + EvalJSONLFileIDSource, RunCreateResponse, RunRetrieveResponse, RunListResponse, diff --git a/src/openai/resources/beta/threads/runs/runs.py b/src/openai/resources/beta/threads/runs/runs.py index 4d19010fea..f59fda8d5f 100644 --- a/src/openai/resources/beta/threads/runs/runs.py +++ b/src/openai/resources/beta/threads/runs/runs.py @@ -51,6 +51,7 @@ from .....types.shared.reasoning_effort import ReasoningEffort from .....types.beta.assistant_tool_param import AssistantToolParam from .....types.beta.assistant_stream_event import AssistantStreamEvent +from .....types.beta.truncation_object_param import TruncationObjectParam from .....types.beta.threads.runs.run_step_include import RunStepInclude from .....types.beta.assistant_tool_choice_option_param import AssistantToolChoiceOptionParam from .....types.beta.assistant_response_format_option_param import AssistantResponseFormatOptionParam @@ -104,7 +105,7 @@ def create( tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + truncation_strategy: Optional[TruncationObjectParam] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -254,7 +255,7 @@ def create( tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + truncation_strategy: Optional[TruncationObjectParam] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -404,7 +405,7 @@ def create( tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + truncation_strategy: Optional[TruncationObjectParam] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -554,7 +555,7 @@ def create( tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + truncation_strategy: Optional[TruncationObjectParam] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1515,7 +1516,7 @@ async def create( tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + truncation_strategy: Optional[TruncationObjectParam] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1665,7 +1666,7 @@ async def create( tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + truncation_strategy: Optional[TruncationObjectParam] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1815,7 +1816,7 @@ async def create( tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + truncation_strategy: Optional[TruncationObjectParam] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1965,7 +1966,7 @@ async def create( tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + truncation_strategy: Optional[TruncationObjectParam] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, diff --git a/src/openai/resources/beta/threads/threads.py b/src/openai/resources/beta/threads/threads.py index 13d8cb6411..ec5a8ea2cf 100644 --- a/src/openai/resources/beta/threads/threads.py +++ b/src/openai/resources/beta/threads/threads.py @@ -52,6 +52,7 @@ from ....types.shared_params.metadata import Metadata from ....types.beta.assistant_tool_param import AssistantToolParam from ....types.beta.assistant_stream_event import AssistantStreamEvent +from ....types.beta.truncation_object_param import TruncationObjectParam from ....types.beta.assistant_tool_choice_option_param import AssistantToolChoiceOptionParam from ....types.beta.assistant_response_format_option_param import AssistantResponseFormatOptionParam @@ -285,7 +286,7 @@ def create_and_run( tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + truncation_strategy: Optional[TruncationObjectParam] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -418,7 +419,7 @@ def create_and_run( tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + truncation_strategy: Optional[TruncationObjectParam] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -551,7 +552,7 @@ def create_and_run( tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + truncation_strategy: Optional[TruncationObjectParam] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -684,7 +685,7 @@ def create_and_run( tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + truncation_strategy: Optional[TruncationObjectParam] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1134,7 +1135,7 @@ async def create_and_run( tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + truncation_strategy: Optional[TruncationObjectParam] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1267,7 +1268,7 @@ async def create_and_run( tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + truncation_strategy: Optional[TruncationObjectParam] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1400,7 +1401,7 @@ async def create_and_run( tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + truncation_strategy: Optional[TruncationObjectParam] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1533,7 +1534,7 @@ async def create_and_run( tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + truncation_strategy: Optional[TruncationObjectParam] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, diff --git a/src/openai/resources/vector_stores/vector_stores.py b/src/openai/resources/vector_stores/vector_stores.py index 9fc17b183b..7f353af080 100644 --- a/src/openai/resources/vector_stores/vector_stores.py +++ b/src/openai/resources/vector_stores/vector_stores.py @@ -43,6 +43,7 @@ from ...types.shared_params.metadata import Metadata from ...types.file_chunking_strategy_param import FileChunkingStrategyParam from ...types.vector_store_search_response import VectorStoreSearchResponse +from ...types.vector_store_expiration_after_param import VectorStoreExpirationAfterParam __all__ = ["VectorStores", "AsyncVectorStores"] @@ -79,7 +80,7 @@ def create( self, *, chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, - expires_after: vector_store_create_params.ExpiresAfter | NotGiven = NOT_GIVEN, + expires_after: VectorStoreExpirationAfterParam | NotGiven = NOT_GIVEN, file_ids: List[str] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, name: str | NotGiven = NOT_GIVEN, @@ -177,7 +178,7 @@ def update( self, vector_store_id: str, *, - expires_after: Optional[vector_store_update_params.ExpiresAfter] | NotGiven = NOT_GIVEN, + expires_after: Optional[VectorStoreExpirationAfterParam] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, name: Optional[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -424,7 +425,7 @@ async def create( self, *, chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, - expires_after: vector_store_create_params.ExpiresAfter | NotGiven = NOT_GIVEN, + expires_after: VectorStoreExpirationAfterParam | NotGiven = NOT_GIVEN, file_ids: List[str] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, name: str | NotGiven = NOT_GIVEN, @@ -522,7 +523,7 @@ async def update( self, vector_store_id: str, *, - expires_after: Optional[vector_store_update_params.ExpiresAfter] | NotGiven = NOT_GIVEN, + expires_after: Optional[VectorStoreExpirationAfterParam] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, name: Optional[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. diff --git a/src/openai/types/__init__.py b/src/openai/types/__init__.py index 9f40033354..de6665155f 100644 --- a/src/openai/types/__init__.py +++ b/src/openai/types/__init__.py @@ -6,6 +6,7 @@ from .image import Image as Image from .model import Model as Model from .shared import ( + EvalItem as EvalItem, Metadata as Metadata, AllModels as AllModels, ChatModel as ChatModel, @@ -76,12 +77,14 @@ from .websocket_connection_options import WebsocketConnectionOptions as WebsocketConnectionOptions from .image_create_variation_params import ImageCreateVariationParams as ImageCreateVariationParams from .static_file_chunking_strategy import StaticFileChunkingStrategy as StaticFileChunkingStrategy +from .vector_store_expiration_after import VectorStoreExpirationAfter as VectorStoreExpirationAfter from .eval_custom_data_source_config import EvalCustomDataSourceConfig as EvalCustomDataSourceConfig from .moderation_image_url_input_param import ModerationImageURLInputParam as ModerationImageURLInputParam from .auto_file_chunking_strategy_param import AutoFileChunkingStrategyParam as AutoFileChunkingStrategyParam from .moderation_multi_modal_input_param import ModerationMultiModalInputParam as ModerationMultiModalInputParam from .other_file_chunking_strategy_object import OtherFileChunkingStrategyObject as OtherFileChunkingStrategyObject from .static_file_chunking_strategy_param import StaticFileChunkingStrategyParam as StaticFileChunkingStrategyParam +from .vector_store_expiration_after_param import VectorStoreExpirationAfterParam as VectorStoreExpirationAfterParam from .static_file_chunking_strategy_object import StaticFileChunkingStrategyObject as StaticFileChunkingStrategyObject from .eval_stored_completions_data_source_config import ( EvalStoredCompletionsDataSourceConfig as EvalStoredCompletionsDataSourceConfig, diff --git a/src/openai/types/beta/__init__.py b/src/openai/types/beta/__init__.py index 5ba3eadf3c..bfcaed7532 100644 --- a/src/openai/types/beta/__init__.py +++ b/src/openai/types/beta/__init__.py @@ -9,6 +9,7 @@ from .thread_deleted import ThreadDeleted as ThreadDeleted from .file_search_tool import FileSearchTool as FileSearchTool from .assistant_deleted import AssistantDeleted as AssistantDeleted +from .truncation_object import TruncationObject as TruncationObject from .function_tool_param import FunctionToolParam as FunctionToolParam from .assistant_tool_param import AssistantToolParam as AssistantToolParam from .thread_create_params import ThreadCreateParams as ThreadCreateParams @@ -20,6 +21,7 @@ from .file_search_tool_param import FileSearchToolParam as FileSearchToolParam from .assistant_create_params import AssistantCreateParams as AssistantCreateParams from .assistant_update_params import AssistantUpdateParams as AssistantUpdateParams +from .truncation_object_param import TruncationObjectParam as TruncationObjectParam from .assistant_tool_choice_param import AssistantToolChoiceParam as AssistantToolChoiceParam from .code_interpreter_tool_param import CodeInterpreterToolParam as CodeInterpreterToolParam from .assistant_tool_choice_option import AssistantToolChoiceOption as AssistantToolChoiceOption diff --git a/src/openai/types/beta/thread_create_and_run_params.py b/src/openai/types/beta/thread_create_and_run_params.py index d813710579..7ba71b0ba3 100644 --- a/src/openai/types/beta/thread_create_and_run_params.py +++ b/src/openai/types/beta/thread_create_and_run_params.py @@ -8,6 +8,7 @@ from ..shared.chat_model import ChatModel from .assistant_tool_param import AssistantToolParam from ..shared_params.metadata import Metadata +from .truncation_object_param import TruncationObjectParam from .code_interpreter_tool_param import CodeInterpreterToolParam from .assistant_tool_choice_option_param import AssistantToolChoiceOptionParam from .threads.message_content_part_param import MessageContentPartParam @@ -31,7 +32,6 @@ "ToolResources", "ToolResourcesCodeInterpreter", "ToolResourcesFileSearch", - "TruncationStrategy", "ThreadCreateAndRunParamsNonStreaming", "ThreadCreateAndRunParamsStreaming", ] @@ -166,7 +166,7 @@ class ThreadCreateAndRunParamsBase(TypedDict, total=False): We generally recommend altering this or temperature but not both. """ - truncation_strategy: Optional[TruncationStrategy] + truncation_strategy: Optional[TruncationObjectParam] """Controls for how a thread will be truncated prior to the run. Use this to control the intial context window of the run. @@ -358,23 +358,6 @@ class ToolResources(TypedDict, total=False): file_search: ToolResourcesFileSearch -class TruncationStrategy(TypedDict, total=False): - type: Required[Literal["auto", "last_messages"]] - """The truncation strategy to use for the thread. - - The default is `auto`. If set to `last_messages`, the thread will be truncated - to the n most recent messages in the thread. When set to `auto`, messages in the - middle of the thread will be dropped to fit the context length of the model, - `max_prompt_tokens`. - """ - - last_messages: Optional[int] - """ - The number of most recent messages from the thread when constructing the context - for the run. - """ - - class ThreadCreateAndRunParamsNonStreaming(ThreadCreateAndRunParamsBase, total=False): stream: Optional[Literal[False]] """ diff --git a/src/openai/types/beta/threads/run.py b/src/openai/types/beta/threads/run.py index da9418d6f9..e5a7808417 100644 --- a/src/openai/types/beta/threads/run.py +++ b/src/openai/types/beta/threads/run.py @@ -7,19 +7,12 @@ from .run_status import RunStatus from ..assistant_tool import AssistantTool from ...shared.metadata import Metadata +from ..truncation_object import TruncationObject from ..assistant_tool_choice_option import AssistantToolChoiceOption from ..assistant_response_format_option import AssistantResponseFormatOption from .required_action_function_tool_call import RequiredActionFunctionToolCall -__all__ = [ - "Run", - "IncompleteDetails", - "LastError", - "RequiredAction", - "RequiredActionSubmitToolOutputs", - "TruncationStrategy", - "Usage", -] +__all__ = ["Run", "IncompleteDetails", "LastError", "RequiredAction", "RequiredActionSubmitToolOutputs", "Usage"] class IncompleteDetails(BaseModel): @@ -52,23 +45,6 @@ class RequiredAction(BaseModel): """For now, this is always `submit_tool_outputs`.""" -class TruncationStrategy(BaseModel): - type: Literal["auto", "last_messages"] - """The truncation strategy to use for the thread. - - The default is `auto`. If set to `last_messages`, the thread will be truncated - to the n most recent messages in the thread. When set to `auto`, messages in the - middle of the thread will be dropped to fit the context length of the model, - `max_prompt_tokens`. - """ - - last_messages: Optional[int] = None - """ - The number of most recent messages from the thread when constructing the context - for the run. - """ - - class Usage(BaseModel): completion_tokens: int """Number of completion tokens used over the course of the run.""" @@ -225,7 +201,7 @@ class Run(BaseModel): this run. """ - truncation_strategy: Optional[TruncationStrategy] = None + truncation_strategy: Optional[TruncationObject] = None """Controls for how a thread will be truncated prior to the run. Use this to control the intial context window of the run. diff --git a/src/openai/types/beta/threads/run_create_params.py b/src/openai/types/beta/threads/run_create_params.py index fc70227862..80656aada4 100644 --- a/src/openai/types/beta/threads/run_create_params.py +++ b/src/openai/types/beta/threads/run_create_params.py @@ -9,6 +9,7 @@ from ..assistant_tool_param import AssistantToolParam from .runs.run_step_include import RunStepInclude from ...shared_params.metadata import Metadata +from ..truncation_object_param import TruncationObjectParam from ...shared.reasoning_effort import ReasoningEffort from .message_content_part_param import MessageContentPartParam from ..code_interpreter_tool_param import CodeInterpreterToolParam @@ -21,7 +22,6 @@ "AdditionalMessageAttachment", "AdditionalMessageAttachmentTool", "AdditionalMessageAttachmentToolFileSearch", - "TruncationStrategy", "RunCreateParamsNonStreaming", "RunCreateParamsStreaming", ] @@ -173,7 +173,7 @@ class RunCreateParamsBase(TypedDict, total=False): We generally recommend altering this or temperature but not both. """ - truncation_strategy: Optional[TruncationStrategy] + truncation_strategy: Optional[TruncationObjectParam] """Controls for how a thread will be truncated prior to the run. Use this to control the intial context window of the run. @@ -223,23 +223,6 @@ class AdditionalMessage(TypedDict, total=False): """ -class TruncationStrategy(TypedDict, total=False): - type: Required[Literal["auto", "last_messages"]] - """The truncation strategy to use for the thread. - - The default is `auto`. If set to `last_messages`, the thread will be truncated - to the n most recent messages in the thread. When set to `auto`, messages in the - middle of the thread will be dropped to fit the context length of the model, - `max_prompt_tokens`. - """ - - last_messages: Optional[int] - """ - The number of most recent messages from the thread when constructing the context - for the run. - """ - - class RunCreateParamsNonStreaming(RunCreateParamsBase, total=False): stream: Optional[Literal[False]] """ diff --git a/src/openai/types/beta/truncation_object.py b/src/openai/types/beta/truncation_object.py new file mode 100644 index 0000000000..7c81b3b5bc --- /dev/null +++ b/src/openai/types/beta/truncation_object.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["TruncationObject"] + + +class TruncationObject(BaseModel): + type: Literal["auto", "last_messages"] + """The truncation strategy to use for the thread. + + The default is `auto`. If set to `last_messages`, the thread will be truncated + to the n most recent messages in the thread. When set to `auto`, messages in the + middle of the thread will be dropped to fit the context length of the model, + `max_prompt_tokens`. + """ + + last_messages: Optional[int] = None + """ + The number of most recent messages from the thread when constructing the context + for the run. + """ diff --git a/src/openai/types/beta/truncation_object_param.py b/src/openai/types/beta/truncation_object_param.py new file mode 100644 index 0000000000..98d942fa09 --- /dev/null +++ b/src/openai/types/beta/truncation_object_param.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["TruncationObjectParam"] + + +class TruncationObjectParam(TypedDict, total=False): + type: Required[Literal["auto", "last_messages"]] + """The truncation strategy to use for the thread. + + The default is `auto`. If set to `last_messages`, the thread will be truncated + to the n most recent messages in the thread. When set to `auto`, messages in the + middle of the thread will be dropped to fit the context length of the model, + `max_prompt_tokens`. + """ + + last_messages: Optional[int] + """ + The number of most recent messages from the thread when constructing the context + for the run. + """ diff --git a/src/openai/types/eval_create_params.py b/src/openai/types/eval_create_params.py index 8d508a2d8e..95fd0bb8d8 100644 --- a/src/openai/types/eval_create_params.py +++ b/src/openai/types/eval_create_params.py @@ -6,10 +6,10 @@ from typing_extensions import Literal, Required, TypeAlias, TypedDict from .shared_params.metadata import Metadata +from .shared_params.eval_item import EvalItem from .graders.python_grader_param import PythonGraderParam from .graders.score_model_grader_param import ScoreModelGraderParam from .graders.string_check_grader_param import StringCheckGraderParam -from .responses.response_input_text_param import ResponseInputTextParam from .graders.text_similarity_grader_param import TextSimilarityGraderParam __all__ = [ @@ -22,9 +22,6 @@ "TestingCriterionLabelModel", "TestingCriterionLabelModelInput", "TestingCriterionLabelModelInputSimpleInputMessage", - "TestingCriterionLabelModelInputEvalItem", - "TestingCriterionLabelModelInputEvalItemContent", - "TestingCriterionLabelModelInputEvalItemContentOutputText", "TestingCriterionTextSimilarity", "TestingCriterionPython", "TestingCriterionScoreModel", @@ -93,36 +90,7 @@ class TestingCriterionLabelModelInputSimpleInputMessage(TypedDict, total=False): """The role of the message (e.g. "system", "assistant", "user").""" -class TestingCriterionLabelModelInputEvalItemContentOutputText(TypedDict, total=False): - text: Required[str] - """The text output from the model.""" - - type: Required[Literal["output_text"]] - """The type of the output text. Always `output_text`.""" - - -TestingCriterionLabelModelInputEvalItemContent: TypeAlias = Union[ - str, ResponseInputTextParam, TestingCriterionLabelModelInputEvalItemContentOutputText -] - - -class TestingCriterionLabelModelInputEvalItem(TypedDict, total=False): - content: Required[TestingCriterionLabelModelInputEvalItemContent] - """Text inputs to the model - can contain template strings.""" - - role: Required[Literal["user", "assistant", "system", "developer"]] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Literal["message"] - """The type of the message input. Always `message`.""" - - -TestingCriterionLabelModelInput: TypeAlias = Union[ - TestingCriterionLabelModelInputSimpleInputMessage, TestingCriterionLabelModelInputEvalItem -] +TestingCriterionLabelModelInput: TypeAlias = Union[TestingCriterionLabelModelInputSimpleInputMessage, EvalItem] class TestingCriterionLabelModel(TypedDict, total=False): diff --git a/src/openai/types/evals/__init__.py b/src/openai/types/evals/__init__.py index 9d26c7d915..7841a40382 100644 --- a/src/openai/types/evals/__init__.py +++ b/src/openai/types/evals/__init__.py @@ -10,7 +10,11 @@ from .run_create_response import RunCreateResponse as RunCreateResponse from .run_delete_response import RunDeleteResponse as RunDeleteResponse from .run_retrieve_response import RunRetrieveResponse as RunRetrieveResponse +from .eval_jsonl_file_id_source import EvalJSONLFileIDSource as EvalJSONLFileIDSource +from .eval_jsonl_file_content_source import EvalJSONLFileContentSource as EvalJSONLFileContentSource +from .eval_jsonl_file_id_source_param import EvalJSONLFileIDSourceParam as EvalJSONLFileIDSourceParam from .create_eval_jsonl_run_data_source import CreateEvalJSONLRunDataSource as CreateEvalJSONLRunDataSource +from .eval_jsonl_file_content_source_param import EvalJSONLFileContentSourceParam as EvalJSONLFileContentSourceParam from .create_eval_responses_run_data_source import CreateEvalResponsesRunDataSource as CreateEvalResponsesRunDataSource from .create_eval_completions_run_data_source import ( CreateEvalCompletionsRunDataSource as CreateEvalCompletionsRunDataSource, diff --git a/src/openai/types/evals/create_eval_completions_run_data_source.py b/src/openai/types/evals/create_eval_completions_run_data_source.py index 29c687b542..439fcc5d7b 100644 --- a/src/openai/types/evals/create_eval_completions_run_data_source.py +++ b/src/openai/types/evals/create_eval_completions_run_data_source.py @@ -1,54 +1,28 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Dict, List, Union, Optional +from typing import List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias from ..._utils import PropertyInfo from ..._models import BaseModel from ..shared.metadata import Metadata +from ..shared.eval_item import EvalItem +from .eval_jsonl_file_id_source import EvalJSONLFileIDSource from ..responses.easy_input_message import EasyInputMessage -from ..responses.response_input_text import ResponseInputText +from .eval_jsonl_file_content_source import EvalJSONLFileContentSource __all__ = [ "CreateEvalCompletionsRunDataSource", "Source", - "SourceFileContent", - "SourceFileContentContent", - "SourceFileID", "SourceStoredCompletions", "InputMessages", "InputMessagesTemplate", "InputMessagesTemplateTemplate", - "InputMessagesTemplateTemplateMessage", - "InputMessagesTemplateTemplateMessageContent", - "InputMessagesTemplateTemplateMessageContentOutputText", "InputMessagesItemReference", "SamplingParams", ] -class SourceFileContentContent(BaseModel): - item: Dict[str, object] - - sample: Optional[Dict[str, object]] = None - - -class SourceFileContent(BaseModel): - content: List[SourceFileContentContent] - """The content of the jsonl file.""" - - type: Literal["file_content"] - """The type of jsonl source. Always `file_content`.""" - - -class SourceFileID(BaseModel): - id: str - """The identifier of the file.""" - - type: Literal["file_id"] - """The type of jsonl source. Always `file_id`.""" - - class SourceStoredCompletions(BaseModel): type: Literal["stored_completions"] """The type of source. Always `stored_completions`.""" @@ -77,39 +51,12 @@ class SourceStoredCompletions(BaseModel): Source: TypeAlias = Annotated[ - Union[SourceFileContent, SourceFileID, SourceStoredCompletions], PropertyInfo(discriminator="type") -] - - -class InputMessagesTemplateTemplateMessageContentOutputText(BaseModel): - text: str - """The text output from the model.""" - - type: Literal["output_text"] - """The type of the output text. Always `output_text`.""" - - -InputMessagesTemplateTemplateMessageContent: TypeAlias = Union[ - str, ResponseInputText, InputMessagesTemplateTemplateMessageContentOutputText + Union[EvalJSONLFileContentSource, EvalJSONLFileIDSource, SourceStoredCompletions], + PropertyInfo(discriminator="type"), ] - -class InputMessagesTemplateTemplateMessage(BaseModel): - content: InputMessagesTemplateTemplateMessageContent - """Text inputs to the model - can contain template strings.""" - - role: Literal["user", "assistant", "system", "developer"] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Optional[Literal["message"]] = None - """The type of the message input. Always `message`.""" - - InputMessagesTemplateTemplate: TypeAlias = Annotated[ - Union[EasyInputMessage, InputMessagesTemplateTemplateMessage], PropertyInfo(discriminator="type") + Union[EasyInputMessage, EvalItem], PropertyInfo(discriminator="type") ] diff --git a/src/openai/types/evals/create_eval_completions_run_data_source_param.py b/src/openai/types/evals/create_eval_completions_run_data_source_param.py index c53064ee27..e94443d953 100644 --- a/src/openai/types/evals/create_eval_completions_run_data_source_param.py +++ b/src/openai/types/evals/create_eval_completions_run_data_source_param.py @@ -2,53 +2,27 @@ from __future__ import annotations -from typing import Dict, Union, Iterable, Optional +from typing import Union, Iterable, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict from ..shared_params.metadata import Metadata +from ..shared_params.eval_item import EvalItem +from .eval_jsonl_file_id_source_param import EvalJSONLFileIDSourceParam from ..responses.easy_input_message_param import EasyInputMessageParam -from ..responses.response_input_text_param import ResponseInputTextParam +from .eval_jsonl_file_content_source_param import EvalJSONLFileContentSourceParam __all__ = [ "CreateEvalCompletionsRunDataSourceParam", "Source", - "SourceFileContent", - "SourceFileContentContent", - "SourceFileID", "SourceStoredCompletions", "InputMessages", "InputMessagesTemplate", "InputMessagesTemplateTemplate", - "InputMessagesTemplateTemplateMessage", - "InputMessagesTemplateTemplateMessageContent", - "InputMessagesTemplateTemplateMessageContentOutputText", "InputMessagesItemReference", "SamplingParams", ] -class SourceFileContentContent(TypedDict, total=False): - item: Required[Dict[str, object]] - - sample: Dict[str, object] - - -class SourceFileContent(TypedDict, total=False): - content: Required[Iterable[SourceFileContentContent]] - """The content of the jsonl file.""" - - type: Required[Literal["file_content"]] - """The type of jsonl source. Always `file_content`.""" - - -class SourceFileID(TypedDict, total=False): - id: Required[str] - """The identifier of the file.""" - - type: Required[Literal["file_id"]] - """The type of jsonl source. Always `file_id`.""" - - class SourceStoredCompletions(TypedDict, total=False): type: Required[Literal["stored_completions"]] """The type of source. Always `stored_completions`.""" @@ -76,37 +50,9 @@ class SourceStoredCompletions(TypedDict, total=False): """An optional model to filter by (e.g., 'gpt-4o').""" -Source: TypeAlias = Union[SourceFileContent, SourceFileID, SourceStoredCompletions] - - -class InputMessagesTemplateTemplateMessageContentOutputText(TypedDict, total=False): - text: Required[str] - """The text output from the model.""" - - type: Required[Literal["output_text"]] - """The type of the output text. Always `output_text`.""" - - -InputMessagesTemplateTemplateMessageContent: TypeAlias = Union[ - str, ResponseInputTextParam, InputMessagesTemplateTemplateMessageContentOutputText -] - - -class InputMessagesTemplateTemplateMessage(TypedDict, total=False): - content: Required[InputMessagesTemplateTemplateMessageContent] - """Text inputs to the model - can contain template strings.""" - - role: Required[Literal["user", "assistant", "system", "developer"]] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Literal["message"] - """The type of the message input. Always `message`.""" - +Source: TypeAlias = Union[EvalJSONLFileContentSourceParam, EvalJSONLFileIDSourceParam, SourceStoredCompletions] -InputMessagesTemplateTemplate: TypeAlias = Union[EasyInputMessageParam, InputMessagesTemplateTemplateMessage] +InputMessagesTemplateTemplate: TypeAlias = Union[EasyInputMessageParam, EvalItem] class InputMessagesTemplate(TypedDict, total=False): diff --git a/src/openai/types/evals/create_eval_jsonl_run_data_source.py b/src/openai/types/evals/create_eval_jsonl_run_data_source.py index d2be56243b..03c6550744 100644 --- a/src/openai/types/evals/create_eval_jsonl_run_data_source.py +++ b/src/openai/types/evals/create_eval_jsonl_run_data_source.py @@ -1,37 +1,18 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Dict, List, Union, Optional +from typing import Union from typing_extensions import Literal, Annotated, TypeAlias from ..._utils import PropertyInfo from ..._models import BaseModel +from .eval_jsonl_file_id_source import EvalJSONLFileIDSource +from .eval_jsonl_file_content_source import EvalJSONLFileContentSource -__all__ = ["CreateEvalJSONLRunDataSource", "Source", "SourceFileContent", "SourceFileContentContent", "SourceFileID"] +__all__ = ["CreateEvalJSONLRunDataSource", "Source"] - -class SourceFileContentContent(BaseModel): - item: Dict[str, object] - - sample: Optional[Dict[str, object]] = None - - -class SourceFileContent(BaseModel): - content: List[SourceFileContentContent] - """The content of the jsonl file.""" - - type: Literal["file_content"] - """The type of jsonl source. Always `file_content`.""" - - -class SourceFileID(BaseModel): - id: str - """The identifier of the file.""" - - type: Literal["file_id"] - """The type of jsonl source. Always `file_id`.""" - - -Source: TypeAlias = Annotated[Union[SourceFileContent, SourceFileID], PropertyInfo(discriminator="type")] +Source: TypeAlias = Annotated[ + Union[EvalJSONLFileContentSource, EvalJSONLFileIDSource], PropertyInfo(discriminator="type") +] class CreateEvalJSONLRunDataSource(BaseModel): diff --git a/src/openai/types/evals/create_eval_jsonl_run_data_source_param.py b/src/openai/types/evals/create_eval_jsonl_run_data_source_param.py index b8ba48a666..cc71925782 100644 --- a/src/openai/types/evals/create_eval_jsonl_run_data_source_param.py +++ b/src/openai/types/evals/create_eval_jsonl_run_data_source_param.py @@ -2,41 +2,15 @@ from __future__ import annotations -from typing import Dict, Union, Iterable +from typing import Union from typing_extensions import Literal, Required, TypeAlias, TypedDict -__all__ = [ - "CreateEvalJSONLRunDataSourceParam", - "Source", - "SourceFileContent", - "SourceFileContentContent", - "SourceFileID", -] +from .eval_jsonl_file_id_source_param import EvalJSONLFileIDSourceParam +from .eval_jsonl_file_content_source_param import EvalJSONLFileContentSourceParam +__all__ = ["CreateEvalJSONLRunDataSourceParam", "Source"] -class SourceFileContentContent(TypedDict, total=False): - item: Required[Dict[str, object]] - - sample: Dict[str, object] - - -class SourceFileContent(TypedDict, total=False): - content: Required[Iterable[SourceFileContentContent]] - """The content of the jsonl file.""" - - type: Required[Literal["file_content"]] - """The type of jsonl source. Always `file_content`.""" - - -class SourceFileID(TypedDict, total=False): - id: Required[str] - """The identifier of the file.""" - - type: Required[Literal["file_id"]] - """The type of jsonl source. Always `file_id`.""" - - -Source: TypeAlias = Union[SourceFileContent, SourceFileID] +Source: TypeAlias = Union[EvalJSONLFileContentSourceParam, EvalJSONLFileIDSourceParam] class CreateEvalJSONLRunDataSourceParam(TypedDict, total=False): diff --git a/src/openai/types/evals/create_eval_responses_run_data_source.py b/src/openai/types/evals/create_eval_responses_run_data_source.py index 481fd0761e..268eab2173 100644 --- a/src/openai/types/evals/create_eval_responses_run_data_source.py +++ b/src/openai/types/evals/create_eval_responses_run_data_source.py @@ -1,54 +1,28 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Dict, List, Union, Optional +from typing import List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias from ..._utils import PropertyInfo from ..._models import BaseModel +from ..shared.eval_item import EvalItem from ..shared.reasoning_effort import ReasoningEffort -from ..responses.response_input_text import ResponseInputText +from .eval_jsonl_file_id_source import EvalJSONLFileIDSource +from .eval_jsonl_file_content_source import EvalJSONLFileContentSource __all__ = [ "CreateEvalResponsesRunDataSource", "Source", - "SourceFileContent", - "SourceFileContentContent", - "SourceFileID", "SourceResponses", "InputMessages", "InputMessagesTemplate", "InputMessagesTemplateTemplate", "InputMessagesTemplateTemplateChatMessage", - "InputMessagesTemplateTemplateEvalItem", - "InputMessagesTemplateTemplateEvalItemContent", - "InputMessagesTemplateTemplateEvalItemContentOutputText", "InputMessagesItemReference", "SamplingParams", ] -class SourceFileContentContent(BaseModel): - item: Dict[str, object] - - sample: Optional[Dict[str, object]] = None - - -class SourceFileContent(BaseModel): - content: List[SourceFileContentContent] - """The content of the jsonl file.""" - - type: Literal["file_content"] - """The type of jsonl source. Always `file_content`.""" - - -class SourceFileID(BaseModel): - id: str - """The identifier of the file.""" - - type: Literal["file_id"] - """The type of jsonl source. Always `file_id`.""" - - class SourceResponses(BaseModel): type: Literal["responses"] """The type of run data source. Always `responses`.""" @@ -109,7 +83,7 @@ class SourceResponses(BaseModel): Source: TypeAlias = Annotated[ - Union[SourceFileContent, SourceFileID, SourceResponses], PropertyInfo(discriminator="type") + Union[EvalJSONLFileContentSource, EvalJSONLFileIDSource, SourceResponses], PropertyInfo(discriminator="type") ] @@ -121,36 +95,7 @@ class InputMessagesTemplateTemplateChatMessage(BaseModel): """The role of the message (e.g. "system", "assistant", "user").""" -class InputMessagesTemplateTemplateEvalItemContentOutputText(BaseModel): - text: str - """The text output from the model.""" - - type: Literal["output_text"] - """The type of the output text. Always `output_text`.""" - - -InputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ - str, ResponseInputText, InputMessagesTemplateTemplateEvalItemContentOutputText -] - - -class InputMessagesTemplateTemplateEvalItem(BaseModel): - content: InputMessagesTemplateTemplateEvalItemContent - """Text inputs to the model - can contain template strings.""" - - role: Literal["user", "assistant", "system", "developer"] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Optional[Literal["message"]] = None - """The type of the message input. Always `message`.""" - - -InputMessagesTemplateTemplate: TypeAlias = Union[ - InputMessagesTemplateTemplateChatMessage, InputMessagesTemplateTemplateEvalItem -] +InputMessagesTemplateTemplate: TypeAlias = Union[InputMessagesTemplateTemplateChatMessage, EvalItem] class InputMessagesTemplate(BaseModel): diff --git a/src/openai/types/evals/create_eval_responses_run_data_source_param.py b/src/openai/types/evals/create_eval_responses_run_data_source_param.py index 9cde20de20..02d45a9e13 100644 --- a/src/openai/types/evals/create_eval_responses_run_data_source_param.py +++ b/src/openai/types/evals/create_eval_responses_run_data_source_param.py @@ -2,53 +2,27 @@ from __future__ import annotations -from typing import Dict, List, Union, Iterable, Optional +from typing import List, Union, Iterable, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict from ..shared.reasoning_effort import ReasoningEffort -from ..responses.response_input_text_param import ResponseInputTextParam +from ..shared_params.eval_item import EvalItem +from .eval_jsonl_file_id_source_param import EvalJSONLFileIDSourceParam +from .eval_jsonl_file_content_source_param import EvalJSONLFileContentSourceParam __all__ = [ "CreateEvalResponsesRunDataSourceParam", "Source", - "SourceFileContent", - "SourceFileContentContent", - "SourceFileID", "SourceResponses", "InputMessages", "InputMessagesTemplate", "InputMessagesTemplateTemplate", "InputMessagesTemplateTemplateChatMessage", - "InputMessagesTemplateTemplateEvalItem", - "InputMessagesTemplateTemplateEvalItemContent", - "InputMessagesTemplateTemplateEvalItemContentOutputText", "InputMessagesItemReference", "SamplingParams", ] -class SourceFileContentContent(TypedDict, total=False): - item: Required[Dict[str, object]] - - sample: Dict[str, object] - - -class SourceFileContent(TypedDict, total=False): - content: Required[Iterable[SourceFileContentContent]] - """The content of the jsonl file.""" - - type: Required[Literal["file_content"]] - """The type of jsonl source. Always `file_content`.""" - - -class SourceFileID(TypedDict, total=False): - id: Required[str] - """The identifier of the file.""" - - type: Required[Literal["file_id"]] - """The type of jsonl source. Always `file_id`.""" - - class SourceResponses(TypedDict, total=False): type: Required[Literal["responses"]] """The type of run data source. Always `responses`.""" @@ -108,7 +82,7 @@ class SourceResponses(TypedDict, total=False): """List of user identifiers. This is a query parameter used to select responses.""" -Source: TypeAlias = Union[SourceFileContent, SourceFileID, SourceResponses] +Source: TypeAlias = Union[EvalJSONLFileContentSourceParam, EvalJSONLFileIDSourceParam, SourceResponses] class InputMessagesTemplateTemplateChatMessage(TypedDict, total=False): @@ -119,36 +93,7 @@ class InputMessagesTemplateTemplateChatMessage(TypedDict, total=False): """The role of the message (e.g. "system", "assistant", "user").""" -class InputMessagesTemplateTemplateEvalItemContentOutputText(TypedDict, total=False): - text: Required[str] - """The text output from the model.""" - - type: Required[Literal["output_text"]] - """The type of the output text. Always `output_text`.""" - - -InputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ - str, ResponseInputTextParam, InputMessagesTemplateTemplateEvalItemContentOutputText -] - - -class InputMessagesTemplateTemplateEvalItem(TypedDict, total=False): - content: Required[InputMessagesTemplateTemplateEvalItemContent] - """Text inputs to the model - can contain template strings.""" - - role: Required[Literal["user", "assistant", "system", "developer"]] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Literal["message"] - """The type of the message input. Always `message`.""" - - -InputMessagesTemplateTemplate: TypeAlias = Union[ - InputMessagesTemplateTemplateChatMessage, InputMessagesTemplateTemplateEvalItem -] +InputMessagesTemplateTemplate: TypeAlias = Union[InputMessagesTemplateTemplateChatMessage, EvalItem] class InputMessagesTemplate(TypedDict, total=False): diff --git a/src/openai/types/evals/eval_jsonl_file_content_source.py b/src/openai/types/evals/eval_jsonl_file_content_source.py new file mode 100644 index 0000000000..b18fe8937b --- /dev/null +++ b/src/openai/types/evals/eval_jsonl_file_content_source.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["EvalJSONLFileContentSource", "Content"] + + +class Content(BaseModel): + item: Dict[str, object] + + sample: Optional[Dict[str, object]] = None + + +class EvalJSONLFileContentSource(BaseModel): + content: List[Content] + """The content of the jsonl file.""" + + type: Literal["file_content"] + """The type of jsonl source. Always `file_content`.""" diff --git a/src/openai/types/evals/eval_jsonl_file_content_source_param.py b/src/openai/types/evals/eval_jsonl_file_content_source_param.py new file mode 100644 index 0000000000..a70f688762 --- /dev/null +++ b/src/openai/types/evals/eval_jsonl_file_content_source_param.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Iterable +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["EvalJSONLFileContentSourceParam", "Content"] + + +class Content(TypedDict, total=False): + item: Required[Dict[str, object]] + + sample: Dict[str, object] + + +class EvalJSONLFileContentSourceParam(TypedDict, total=False): + content: Required[Iterable[Content]] + """The content of the jsonl file.""" + + type: Required[Literal["file_content"]] + """The type of jsonl source. Always `file_content`.""" diff --git a/src/openai/types/evals/eval_jsonl_file_id_source.py b/src/openai/types/evals/eval_jsonl_file_id_source.py new file mode 100644 index 0000000000..2d317f2ce1 --- /dev/null +++ b/src/openai/types/evals/eval_jsonl_file_id_source.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["EvalJSONLFileIDSource"] + + +class EvalJSONLFileIDSource(BaseModel): + id: str + """The identifier of the file.""" + + type: Literal["file_id"] + """The type of jsonl source. Always `file_id`.""" diff --git a/src/openai/types/evals/eval_jsonl_file_id_source_param.py b/src/openai/types/evals/eval_jsonl_file_id_source_param.py new file mode 100644 index 0000000000..76b8662cd6 --- /dev/null +++ b/src/openai/types/evals/eval_jsonl_file_id_source_param.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["EvalJSONLFileIDSourceParam"] + + +class EvalJSONLFileIDSourceParam(TypedDict, total=False): + id: Required[str] + """The identifier of the file.""" + + type: Required[Literal["file_id"]] + """The type of jsonl source. Always `file_id`.""" diff --git a/src/openai/types/graders/label_model_grader.py b/src/openai/types/graders/label_model_grader.py index d95ccc6df6..16f5b5aa1b 100644 --- a/src/openai/types/graders/label_model_grader.py +++ b/src/openai/types/graders/label_model_grader.py @@ -1,41 +1,16 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union, Optional -from typing_extensions import Literal, TypeAlias +from typing import List +from typing_extensions import Literal from ..._models import BaseModel -from ..responses.response_input_text import ResponseInputText +from ..shared.eval_item import EvalItem -__all__ = ["LabelModelGrader", "Input", "InputContent", "InputContentOutputText"] - - -class InputContentOutputText(BaseModel): - text: str - """The text output from the model.""" - - type: Literal["output_text"] - """The type of the output text. Always `output_text`.""" - - -InputContent: TypeAlias = Union[str, ResponseInputText, InputContentOutputText] - - -class Input(BaseModel): - content: InputContent - """Text inputs to the model - can contain template strings.""" - - role: Literal["user", "assistant", "system", "developer"] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Optional[Literal["message"]] = None - """The type of the message input. Always `message`.""" +__all__ = ["LabelModelGrader"] class LabelModelGrader(BaseModel): - input: List[Input] + input: List[EvalItem] labels: List[str] """The labels to assign to each item in the evaluation.""" diff --git a/src/openai/types/graders/label_model_grader_param.py b/src/openai/types/graders/label_model_grader_param.py index 76d01421ee..34f5de7726 100644 --- a/src/openai/types/graders/label_model_grader_param.py +++ b/src/openai/types/graders/label_model_grader_param.py @@ -2,41 +2,16 @@ from __future__ import annotations -from typing import List, Union, Iterable -from typing_extensions import Literal, Required, TypeAlias, TypedDict +from typing import List, Iterable +from typing_extensions import Literal, Required, TypedDict -from ..responses.response_input_text_param import ResponseInputTextParam +from ..shared_params.eval_item import EvalItem -__all__ = ["LabelModelGraderParam", "Input", "InputContent", "InputContentOutputText"] - - -class InputContentOutputText(TypedDict, total=False): - text: Required[str] - """The text output from the model.""" - - type: Required[Literal["output_text"]] - """The type of the output text. Always `output_text`.""" - - -InputContent: TypeAlias = Union[str, ResponseInputTextParam, InputContentOutputText] - - -class Input(TypedDict, total=False): - content: Required[InputContent] - """Text inputs to the model - can contain template strings.""" - - role: Required[Literal["user", "assistant", "system", "developer"]] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Literal["message"] - """The type of the message input. Always `message`.""" +__all__ = ["LabelModelGraderParam"] class LabelModelGraderParam(TypedDict, total=False): - input: Required[Iterable[Input]] + input: Required[Iterable[EvalItem]] labels: Required[List[str]] """The labels to assign to each item in the evaluation.""" diff --git a/src/openai/types/graders/score_model_grader.py b/src/openai/types/graders/score_model_grader.py index 1349f75a58..6d81019c26 100644 --- a/src/openai/types/graders/score_model_grader.py +++ b/src/openai/types/graders/score_model_grader.py @@ -1,41 +1,16 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union, Optional -from typing_extensions import Literal, TypeAlias +from typing import List, Optional +from typing_extensions import Literal from ..._models import BaseModel -from ..responses.response_input_text import ResponseInputText +from ..shared.eval_item import EvalItem -__all__ = ["ScoreModelGrader", "Input", "InputContent", "InputContentOutputText"] - - -class InputContentOutputText(BaseModel): - text: str - """The text output from the model.""" - - type: Literal["output_text"] - """The type of the output text. Always `output_text`.""" - - -InputContent: TypeAlias = Union[str, ResponseInputText, InputContentOutputText] - - -class Input(BaseModel): - content: InputContent - """Text inputs to the model - can contain template strings.""" - - role: Literal["user", "assistant", "system", "developer"] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Optional[Literal["message"]] = None - """The type of the message input. Always `message`.""" +__all__ = ["ScoreModelGrader"] class ScoreModelGrader(BaseModel): - input: List[Input] + input: List[EvalItem] """The input text. This may include template strings.""" model: str diff --git a/src/openai/types/graders/score_model_grader_param.py b/src/openai/types/graders/score_model_grader_param.py index 673f14e47d..3e0b9d08eb 100644 --- a/src/openai/types/graders/score_model_grader_param.py +++ b/src/openai/types/graders/score_model_grader_param.py @@ -2,41 +2,16 @@ from __future__ import annotations -from typing import Union, Iterable -from typing_extensions import Literal, Required, TypeAlias, TypedDict +from typing import Iterable +from typing_extensions import Literal, Required, TypedDict -from ..responses.response_input_text_param import ResponseInputTextParam +from ..shared_params.eval_item import EvalItem -__all__ = ["ScoreModelGraderParam", "Input", "InputContent", "InputContentOutputText"] - - -class InputContentOutputText(TypedDict, total=False): - text: Required[str] - """The text output from the model.""" - - type: Required[Literal["output_text"]] - """The type of the output text. Always `output_text`.""" - - -InputContent: TypeAlias = Union[str, ResponseInputTextParam, InputContentOutputText] - - -class Input(TypedDict, total=False): - content: Required[InputContent] - """Text inputs to the model - can contain template strings.""" - - role: Required[Literal["user", "assistant", "system", "developer"]] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Literal["message"] - """The type of the message input. Always `message`.""" +__all__ = ["ScoreModelGraderParam"] class ScoreModelGraderParam(TypedDict, total=False): - input: Required[Iterable[Input]] + input: Required[Iterable[EvalItem]] """The input text. This may include template strings.""" model: Required[str] diff --git a/src/openai/types/shared/__init__.py b/src/openai/types/shared/__init__.py index 6ad0ed5e01..10450d8c70 100644 --- a/src/openai/types/shared/__init__.py +++ b/src/openai/types/shared/__init__.py @@ -1,6 +1,7 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from .metadata import Metadata as Metadata +from .eval_item import EvalItem as EvalItem from .reasoning import Reasoning as Reasoning from .all_models import AllModels as AllModels from .chat_model import ChatModel as ChatModel diff --git a/src/openai/types/shared/eval_item.py b/src/openai/types/shared/eval_item.py new file mode 100644 index 0000000000..f235d1ef17 --- /dev/null +++ b/src/openai/types/shared/eval_item.py @@ -0,0 +1,34 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union, Optional +from typing_extensions import Literal, TypeAlias + +from ..._models import BaseModel +from ..responses.response_input_text import ResponseInputText + +__all__ = ["EvalItem", "Content", "ContentOutputText"] + + +class ContentOutputText(BaseModel): + text: str + """The text output from the model.""" + + type: Literal["output_text"] + """The type of the output text. Always `output_text`.""" + + +Content: TypeAlias = Union[str, ResponseInputText, ContentOutputText] + + +class EvalItem(BaseModel): + content: Content + """Text inputs to the model - can contain template strings.""" + + role: Literal["user", "assistant", "system", "developer"] + """The role of the message input. + + One of `user`, `assistant`, `system`, or `developer`. + """ + + type: Optional[Literal["message"]] = None + """The type of the message input. Always `message`.""" diff --git a/src/openai/types/shared_params/__init__.py b/src/openai/types/shared_params/__init__.py index 8894710807..68d16b90dc 100644 --- a/src/openai/types/shared_params/__init__.py +++ b/src/openai/types/shared_params/__init__.py @@ -1,6 +1,7 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from .metadata import Metadata as Metadata +from .eval_item import EvalItem as EvalItem from .reasoning import Reasoning as Reasoning from .chat_model import ChatModel as ChatModel from .compound_filter import CompoundFilter as CompoundFilter diff --git a/src/openai/types/shared_params/eval_item.py b/src/openai/types/shared_params/eval_item.py new file mode 100644 index 0000000000..7740ccc165 --- /dev/null +++ b/src/openai/types/shared_params/eval_item.py @@ -0,0 +1,35 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from ..responses.response_input_text_param import ResponseInputTextParam + +__all__ = ["EvalItem", "Content", "ContentOutputText"] + + +class ContentOutputText(TypedDict, total=False): + text: Required[str] + """The text output from the model.""" + + type: Required[Literal["output_text"]] + """The type of the output text. Always `output_text`.""" + + +Content: TypeAlias = Union[str, ResponseInputTextParam, ContentOutputText] + + +class EvalItem(TypedDict, total=False): + content: Required[Content] + """Text inputs to the model - can contain template strings.""" + + role: Required[Literal["user", "assistant", "system", "developer"]] + """The role of the message input. + + One of `user`, `assistant`, `system`, or `developer`. + """ + + type: Literal["message"] + """The type of the message input. Always `message`.""" diff --git a/src/openai/types/vector_store.py b/src/openai/types/vector_store.py index 2473a442d2..2af120350e 100644 --- a/src/openai/types/vector_store.py +++ b/src/openai/types/vector_store.py @@ -5,8 +5,9 @@ from .._models import BaseModel from .shared.metadata import Metadata +from .vector_store_expiration_after import VectorStoreExpirationAfter -__all__ = ["VectorStore", "FileCounts", "ExpiresAfter"] +__all__ = ["VectorStore", "FileCounts"] class FileCounts(BaseModel): @@ -26,17 +27,6 @@ class FileCounts(BaseModel): """The total number of files.""" -class ExpiresAfter(BaseModel): - anchor: Literal["last_active_at"] - """Anchor timestamp after which the expiration policy applies. - - Supported anchors: `last_active_at`. - """ - - days: int - """The number of days after the anchor time that the vector store will expire.""" - - class VectorStore(BaseModel): id: str """The identifier, which can be referenced in API endpoints.""" @@ -75,7 +65,7 @@ class VectorStore(BaseModel): usage_bytes: int """The total number of bytes used by the files in the vector store.""" - expires_after: Optional[ExpiresAfter] = None + expires_after: Optional[VectorStoreExpirationAfter] = None """The expiration policy for a vector store.""" expires_at: Optional[int] = None diff --git a/src/openai/types/vector_store_create_params.py b/src/openai/types/vector_store_create_params.py index 365d0936b1..dbcedac188 100644 --- a/src/openai/types/vector_store_create_params.py +++ b/src/openai/types/vector_store_create_params.py @@ -3,12 +3,13 @@ from __future__ import annotations from typing import List, Optional -from typing_extensions import Literal, Required, TypedDict +from typing_extensions import TypedDict from .shared_params.metadata import Metadata from .file_chunking_strategy_param import FileChunkingStrategyParam +from .vector_store_expiration_after_param import VectorStoreExpirationAfterParam -__all__ = ["VectorStoreCreateParams", "ExpiresAfter"] +__all__ = ["VectorStoreCreateParams"] class VectorStoreCreateParams(TypedDict, total=False): @@ -19,7 +20,7 @@ class VectorStoreCreateParams(TypedDict, total=False): non-empty. """ - expires_after: ExpiresAfter + expires_after: VectorStoreExpirationAfterParam """The expiration policy for a vector store.""" file_ids: List[str] @@ -41,14 +42,3 @@ class VectorStoreCreateParams(TypedDict, total=False): name: str """The name of the vector store.""" - - -class ExpiresAfter(TypedDict, total=False): - anchor: Required[Literal["last_active_at"]] - """Anchor timestamp after which the expiration policy applies. - - Supported anchors: `last_active_at`. - """ - - days: Required[int] - """The number of days after the anchor time that the vector store will expire.""" diff --git a/src/openai/types/vector_store_expiration_after.py b/src/openai/types/vector_store_expiration_after.py new file mode 100644 index 0000000000..1d417d526b --- /dev/null +++ b/src/openai/types/vector_store_expiration_after.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["VectorStoreExpirationAfter"] + + +class VectorStoreExpirationAfter(BaseModel): + anchor: Literal["last_active_at"] + """Anchor timestamp after which the expiration policy applies. + + Supported anchors: `last_active_at`. + """ + + days: int + """The number of days after the anchor time that the vector store will expire.""" diff --git a/src/openai/types/vector_store_expiration_after_param.py b/src/openai/types/vector_store_expiration_after_param.py new file mode 100644 index 0000000000..29a008c713 --- /dev/null +++ b/src/openai/types/vector_store_expiration_after_param.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["VectorStoreExpirationAfterParam"] + + +class VectorStoreExpirationAfterParam(TypedDict, total=False): + anchor: Required[Literal["last_active_at"]] + """Anchor timestamp after which the expiration policy applies. + + Supported anchors: `last_active_at`. + """ + + days: Required[int] + """The number of days after the anchor time that the vector store will expire.""" diff --git a/src/openai/types/vector_store_update_params.py b/src/openai/types/vector_store_update_params.py index 4f6ac63963..7c90784dfd 100644 --- a/src/openai/types/vector_store_update_params.py +++ b/src/openai/types/vector_store_update_params.py @@ -3,15 +3,16 @@ from __future__ import annotations from typing import Optional -from typing_extensions import Literal, Required, TypedDict +from typing_extensions import TypedDict from .shared_params.metadata import Metadata +from .vector_store_expiration_after_param import VectorStoreExpirationAfterParam -__all__ = ["VectorStoreUpdateParams", "ExpiresAfter"] +__all__ = ["VectorStoreUpdateParams"] class VectorStoreUpdateParams(TypedDict, total=False): - expires_after: Optional[ExpiresAfter] + expires_after: Optional[VectorStoreExpirationAfterParam] """The expiration policy for a vector store.""" metadata: Optional[Metadata] @@ -26,14 +27,3 @@ class VectorStoreUpdateParams(TypedDict, total=False): name: Optional[str] """The name of the vector store.""" - - -class ExpiresAfter(TypedDict, total=False): - anchor: Required[Literal["last_active_at"]] - """Anchor timestamp after which the expiration policy applies. - - Supported anchors: `last_active_at`. - """ - - days: Required[int] - """The number of days after the anchor time that the vector store will expire.""" From 4ebfd515114ed852396d2dd7509464895809fd53 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 16 May 2025 17:11:07 +0000 Subject: [PATCH 333/769] feat(api): Updating Assistants and Evals API schemas --- .stats.yml | 6 +- api.md | 7 - .../resources/beta/threads/runs/runs.py | 17 +- src/openai/resources/beta/threads/threads.py | 17 +- .../resources/vector_stores/vector_stores.py | 9 +- src/openai/types/__init__.py | 4 - src/openai/types/beta/__init__.py | 2 - .../beta/thread_create_and_run_params.py | 21 +- src/openai/types/beta/threads/run.py | 30 ++- .../types/beta/threads/run_create_params.py | 21 +- src/openai/types/beta/truncation_object.py | 25 -- .../types/beta/truncation_object_param.py | 25 -- src/openai/types/eval_create_params.py | 36 ++- src/openai/types/eval_create_response.py | 30 ++- src/openai/types/eval_list_response.py | 30 ++- .../types/eval_logs_data_source_config.py | 32 --- src/openai/types/eval_retrieve_response.py | 30 ++- src/openai/types/eval_update_response.py | 30 ++- src/openai/types/evals/__init__.py | 8 - ...create_eval_completions_run_data_source.py | 67 +++++- ..._eval_completions_run_data_source_param.py | 66 +++++- .../create_eval_jsonl_run_data_source.py | 33 ++- ...create_eval_jsonl_run_data_source_param.py | 36 ++- .../create_eval_responses_run_data_source.py | 151 ------------ ...te_eval_responses_run_data_source_param.py | 147 ------------ .../evals/eval_jsonl_file_content_source.py | 22 -- .../eval_jsonl_file_content_source_param.py | 22 -- .../types/evals/eval_jsonl_file_id_source.py | 15 -- .../evals/eval_jsonl_file_id_source_param.py | 15 -- src/openai/types/evals/run_cancel_response.py | 213 ++++++++++++++++- src/openai/types/evals/run_create_params.py | 218 +++++++++++++++++- src/openai/types/evals/run_create_response.py | 213 ++++++++++++++++- src/openai/types/evals/run_list_response.py | 213 ++++++++++++++++- .../types/evals/run_retrieve_response.py | 213 ++++++++++++++++- .../types/graders/label_model_grader.py | 35 ++- .../types/graders/label_model_grader_param.py | 35 ++- src/openai/types/graders/multi_grader.py | 2 +- .../types/graders/multi_grader_param.py | 2 +- .../types/graders/score_model_grader.py | 35 ++- .../types/graders/score_model_grader_param.py | 35 ++- src/openai/types/shared/__init__.py | 1 - src/openai/types/shared/chat_model.py | 1 + src/openai/types/shared/eval_item.py | 34 --- src/openai/types/shared_params/__init__.py | 1 - src/openai/types/shared_params/chat_model.py | 1 + src/openai/types/shared_params/eval_item.py | 35 --- src/openai/types/vector_store.py | 16 +- .../types/vector_store_create_params.py | 18 +- .../types/vector_store_expiration_after.py | 18 -- .../vector_store_expiration_after_param.py | 18 -- .../types/vector_store_update_params.py | 18 +- 51 files changed, 1621 insertions(+), 708 deletions(-) delete mode 100644 src/openai/types/beta/truncation_object.py delete mode 100644 src/openai/types/beta/truncation_object_param.py delete mode 100644 src/openai/types/eval_logs_data_source_config.py delete mode 100644 src/openai/types/evals/create_eval_responses_run_data_source.py delete mode 100644 src/openai/types/evals/create_eval_responses_run_data_source_param.py delete mode 100644 src/openai/types/evals/eval_jsonl_file_content_source.py delete mode 100644 src/openai/types/evals/eval_jsonl_file_content_source_param.py delete mode 100644 src/openai/types/evals/eval_jsonl_file_id_source.py delete mode 100644 src/openai/types/evals/eval_jsonl_file_id_source_param.py delete mode 100644 src/openai/types/shared/eval_item.py delete mode 100644 src/openai/types/shared_params/eval_item.py delete mode 100644 src/openai/types/vector_store_expiration_after.py delete mode 100644 src/openai/types/vector_store_expiration_after_param.py diff --git a/.stats.yml b/.stats.yml index 202b915dc8..a3c5d081d4 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 101 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-161ca7f1cfd7b33c1fc07d0ce25dfe4be5a7271c394f4cb526b7fb21b0729900.yml -openapi_spec_hash: 602e14add4bee018c6774e320ce309b8 -config_hash: bdacc55eb995c15255ec82130eb8c3bb +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-5fa16b9a02985ae06e41be14946a9c325dc672fb014b3c19abca65880c6990e6.yml +openapi_spec_hash: da3e669f65130043b1170048c0727890 +config_hash: d8d5fda350f6db77c784f35429741a2e diff --git a/api.md b/api.md index 869b7d5042..496e5548b3 100644 --- a/api.md +++ b/api.md @@ -7,7 +7,6 @@ from openai.types import ( ComparisonFilter, CompoundFilter, ErrorObject, - EvalItem, FunctionDefinition, FunctionParameters, Metadata, @@ -344,7 +343,6 @@ from openai.types import ( StaticFileChunkingStrategyObjectParam, VectorStore, VectorStoreDeleted, - VectorStoreExpirationAfter, VectorStoreSearchResponse, ) ``` @@ -521,7 +519,6 @@ from openai.types.beta import ( AssistantToolChoiceOption, Thread, ThreadDeleted, - TruncationObject, ) ``` @@ -790,7 +787,6 @@ Types: ```python from openai.types import ( EvalCustomDataSourceConfig, - EvalLogsDataSourceConfig, EvalStoredCompletionsDataSourceConfig, EvalCreateResponse, EvalRetrieveResponse, @@ -816,10 +812,7 @@ Types: from openai.types.evals import ( CreateEvalCompletionsRunDataSource, CreateEvalJSONLRunDataSource, - CreateEvalResponsesRunDataSource, EvalAPIError, - EvalJSONLFileContentSource, - EvalJSONLFileIDSource, RunCreateResponse, RunRetrieveResponse, RunListResponse, diff --git a/src/openai/resources/beta/threads/runs/runs.py b/src/openai/resources/beta/threads/runs/runs.py index f59fda8d5f..4d19010fea 100644 --- a/src/openai/resources/beta/threads/runs/runs.py +++ b/src/openai/resources/beta/threads/runs/runs.py @@ -51,7 +51,6 @@ from .....types.shared.reasoning_effort import ReasoningEffort from .....types.beta.assistant_tool_param import AssistantToolParam from .....types.beta.assistant_stream_event import AssistantStreamEvent -from .....types.beta.truncation_object_param import TruncationObjectParam from .....types.beta.threads.runs.run_step_include import RunStepInclude from .....types.beta.assistant_tool_choice_option_param import AssistantToolChoiceOptionParam from .....types.beta.assistant_response_format_option_param import AssistantResponseFormatOptionParam @@ -105,7 +104,7 @@ def create( tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[TruncationObjectParam] | NotGiven = NOT_GIVEN, + truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -255,7 +254,7 @@ def create( tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[TruncationObjectParam] | NotGiven = NOT_GIVEN, + truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -405,7 +404,7 @@ def create( tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[TruncationObjectParam] | NotGiven = NOT_GIVEN, + truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -555,7 +554,7 @@ def create( tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[TruncationObjectParam] | NotGiven = NOT_GIVEN, + truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1516,7 +1515,7 @@ async def create( tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[TruncationObjectParam] | NotGiven = NOT_GIVEN, + truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1666,7 +1665,7 @@ async def create( tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[TruncationObjectParam] | NotGiven = NOT_GIVEN, + truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1816,7 +1815,7 @@ async def create( tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[TruncationObjectParam] | NotGiven = NOT_GIVEN, + truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1966,7 +1965,7 @@ async def create( tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[TruncationObjectParam] | NotGiven = NOT_GIVEN, + truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, diff --git a/src/openai/resources/beta/threads/threads.py b/src/openai/resources/beta/threads/threads.py index ec5a8ea2cf..13d8cb6411 100644 --- a/src/openai/resources/beta/threads/threads.py +++ b/src/openai/resources/beta/threads/threads.py @@ -52,7 +52,6 @@ from ....types.shared_params.metadata import Metadata from ....types.beta.assistant_tool_param import AssistantToolParam from ....types.beta.assistant_stream_event import AssistantStreamEvent -from ....types.beta.truncation_object_param import TruncationObjectParam from ....types.beta.assistant_tool_choice_option_param import AssistantToolChoiceOptionParam from ....types.beta.assistant_response_format_option_param import AssistantResponseFormatOptionParam @@ -286,7 +285,7 @@ def create_and_run( tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[TruncationObjectParam] | NotGiven = NOT_GIVEN, + truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -419,7 +418,7 @@ def create_and_run( tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[TruncationObjectParam] | NotGiven = NOT_GIVEN, + truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -552,7 +551,7 @@ def create_and_run( tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[TruncationObjectParam] | NotGiven = NOT_GIVEN, + truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -685,7 +684,7 @@ def create_and_run( tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[TruncationObjectParam] | NotGiven = NOT_GIVEN, + truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1135,7 +1134,7 @@ async def create_and_run( tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[TruncationObjectParam] | NotGiven = NOT_GIVEN, + truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1268,7 +1267,7 @@ async def create_and_run( tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[TruncationObjectParam] | NotGiven = NOT_GIVEN, + truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1401,7 +1400,7 @@ async def create_and_run( tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[TruncationObjectParam] | NotGiven = NOT_GIVEN, + truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1534,7 +1533,7 @@ async def create_and_run( tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[TruncationObjectParam] | NotGiven = NOT_GIVEN, + truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, diff --git a/src/openai/resources/vector_stores/vector_stores.py b/src/openai/resources/vector_stores/vector_stores.py index 7f353af080..9fc17b183b 100644 --- a/src/openai/resources/vector_stores/vector_stores.py +++ b/src/openai/resources/vector_stores/vector_stores.py @@ -43,7 +43,6 @@ from ...types.shared_params.metadata import Metadata from ...types.file_chunking_strategy_param import FileChunkingStrategyParam from ...types.vector_store_search_response import VectorStoreSearchResponse -from ...types.vector_store_expiration_after_param import VectorStoreExpirationAfterParam __all__ = ["VectorStores", "AsyncVectorStores"] @@ -80,7 +79,7 @@ def create( self, *, chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, - expires_after: VectorStoreExpirationAfterParam | NotGiven = NOT_GIVEN, + expires_after: vector_store_create_params.ExpiresAfter | NotGiven = NOT_GIVEN, file_ids: List[str] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, name: str | NotGiven = NOT_GIVEN, @@ -178,7 +177,7 @@ def update( self, vector_store_id: str, *, - expires_after: Optional[VectorStoreExpirationAfterParam] | NotGiven = NOT_GIVEN, + expires_after: Optional[vector_store_update_params.ExpiresAfter] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, name: Optional[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -425,7 +424,7 @@ async def create( self, *, chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, - expires_after: VectorStoreExpirationAfterParam | NotGiven = NOT_GIVEN, + expires_after: vector_store_create_params.ExpiresAfter | NotGiven = NOT_GIVEN, file_ids: List[str] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, name: str | NotGiven = NOT_GIVEN, @@ -523,7 +522,7 @@ async def update( self, vector_store_id: str, *, - expires_after: Optional[VectorStoreExpirationAfterParam] | NotGiven = NOT_GIVEN, + expires_after: Optional[vector_store_update_params.ExpiresAfter] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, name: Optional[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. diff --git a/src/openai/types/__init__.py b/src/openai/types/__init__.py index de6665155f..bf5493fd62 100644 --- a/src/openai/types/__init__.py +++ b/src/openai/types/__init__.py @@ -6,7 +6,6 @@ from .image import Image as Image from .model import Model as Model from .shared import ( - EvalItem as EvalItem, Metadata as Metadata, AllModels as AllModels, ChatModel as ChatModel, @@ -71,20 +70,17 @@ from .vector_store_search_params import VectorStoreSearchParams as VectorStoreSearchParams from .vector_store_update_params import VectorStoreUpdateParams as VectorStoreUpdateParams from .moderation_text_input_param import ModerationTextInputParam as ModerationTextInputParam -from .eval_logs_data_source_config import EvalLogsDataSourceConfig as EvalLogsDataSourceConfig from .file_chunking_strategy_param import FileChunkingStrategyParam as FileChunkingStrategyParam from .vector_store_search_response import VectorStoreSearchResponse as VectorStoreSearchResponse from .websocket_connection_options import WebsocketConnectionOptions as WebsocketConnectionOptions from .image_create_variation_params import ImageCreateVariationParams as ImageCreateVariationParams from .static_file_chunking_strategy import StaticFileChunkingStrategy as StaticFileChunkingStrategy -from .vector_store_expiration_after import VectorStoreExpirationAfter as VectorStoreExpirationAfter from .eval_custom_data_source_config import EvalCustomDataSourceConfig as EvalCustomDataSourceConfig from .moderation_image_url_input_param import ModerationImageURLInputParam as ModerationImageURLInputParam from .auto_file_chunking_strategy_param import AutoFileChunkingStrategyParam as AutoFileChunkingStrategyParam from .moderation_multi_modal_input_param import ModerationMultiModalInputParam as ModerationMultiModalInputParam from .other_file_chunking_strategy_object import OtherFileChunkingStrategyObject as OtherFileChunkingStrategyObject from .static_file_chunking_strategy_param import StaticFileChunkingStrategyParam as StaticFileChunkingStrategyParam -from .vector_store_expiration_after_param import VectorStoreExpirationAfterParam as VectorStoreExpirationAfterParam from .static_file_chunking_strategy_object import StaticFileChunkingStrategyObject as StaticFileChunkingStrategyObject from .eval_stored_completions_data_source_config import ( EvalStoredCompletionsDataSourceConfig as EvalStoredCompletionsDataSourceConfig, diff --git a/src/openai/types/beta/__init__.py b/src/openai/types/beta/__init__.py index bfcaed7532..5ba3eadf3c 100644 --- a/src/openai/types/beta/__init__.py +++ b/src/openai/types/beta/__init__.py @@ -9,7 +9,6 @@ from .thread_deleted import ThreadDeleted as ThreadDeleted from .file_search_tool import FileSearchTool as FileSearchTool from .assistant_deleted import AssistantDeleted as AssistantDeleted -from .truncation_object import TruncationObject as TruncationObject from .function_tool_param import FunctionToolParam as FunctionToolParam from .assistant_tool_param import AssistantToolParam as AssistantToolParam from .thread_create_params import ThreadCreateParams as ThreadCreateParams @@ -21,7 +20,6 @@ from .file_search_tool_param import FileSearchToolParam as FileSearchToolParam from .assistant_create_params import AssistantCreateParams as AssistantCreateParams from .assistant_update_params import AssistantUpdateParams as AssistantUpdateParams -from .truncation_object_param import TruncationObjectParam as TruncationObjectParam from .assistant_tool_choice_param import AssistantToolChoiceParam as AssistantToolChoiceParam from .code_interpreter_tool_param import CodeInterpreterToolParam as CodeInterpreterToolParam from .assistant_tool_choice_option import AssistantToolChoiceOption as AssistantToolChoiceOption diff --git a/src/openai/types/beta/thread_create_and_run_params.py b/src/openai/types/beta/thread_create_and_run_params.py index 7ba71b0ba3..d813710579 100644 --- a/src/openai/types/beta/thread_create_and_run_params.py +++ b/src/openai/types/beta/thread_create_and_run_params.py @@ -8,7 +8,6 @@ from ..shared.chat_model import ChatModel from .assistant_tool_param import AssistantToolParam from ..shared_params.metadata import Metadata -from .truncation_object_param import TruncationObjectParam from .code_interpreter_tool_param import CodeInterpreterToolParam from .assistant_tool_choice_option_param import AssistantToolChoiceOptionParam from .threads.message_content_part_param import MessageContentPartParam @@ -32,6 +31,7 @@ "ToolResources", "ToolResourcesCodeInterpreter", "ToolResourcesFileSearch", + "TruncationStrategy", "ThreadCreateAndRunParamsNonStreaming", "ThreadCreateAndRunParamsStreaming", ] @@ -166,7 +166,7 @@ class ThreadCreateAndRunParamsBase(TypedDict, total=False): We generally recommend altering this or temperature but not both. """ - truncation_strategy: Optional[TruncationObjectParam] + truncation_strategy: Optional[TruncationStrategy] """Controls for how a thread will be truncated prior to the run. Use this to control the intial context window of the run. @@ -358,6 +358,23 @@ class ToolResources(TypedDict, total=False): file_search: ToolResourcesFileSearch +class TruncationStrategy(TypedDict, total=False): + type: Required[Literal["auto", "last_messages"]] + """The truncation strategy to use for the thread. + + The default is `auto`. If set to `last_messages`, the thread will be truncated + to the n most recent messages in the thread. When set to `auto`, messages in the + middle of the thread will be dropped to fit the context length of the model, + `max_prompt_tokens`. + """ + + last_messages: Optional[int] + """ + The number of most recent messages from the thread when constructing the context + for the run. + """ + + class ThreadCreateAndRunParamsNonStreaming(ThreadCreateAndRunParamsBase, total=False): stream: Optional[Literal[False]] """ diff --git a/src/openai/types/beta/threads/run.py b/src/openai/types/beta/threads/run.py index e5a7808417..da9418d6f9 100644 --- a/src/openai/types/beta/threads/run.py +++ b/src/openai/types/beta/threads/run.py @@ -7,12 +7,19 @@ from .run_status import RunStatus from ..assistant_tool import AssistantTool from ...shared.metadata import Metadata -from ..truncation_object import TruncationObject from ..assistant_tool_choice_option import AssistantToolChoiceOption from ..assistant_response_format_option import AssistantResponseFormatOption from .required_action_function_tool_call import RequiredActionFunctionToolCall -__all__ = ["Run", "IncompleteDetails", "LastError", "RequiredAction", "RequiredActionSubmitToolOutputs", "Usage"] +__all__ = [ + "Run", + "IncompleteDetails", + "LastError", + "RequiredAction", + "RequiredActionSubmitToolOutputs", + "TruncationStrategy", + "Usage", +] class IncompleteDetails(BaseModel): @@ -45,6 +52,23 @@ class RequiredAction(BaseModel): """For now, this is always `submit_tool_outputs`.""" +class TruncationStrategy(BaseModel): + type: Literal["auto", "last_messages"] + """The truncation strategy to use for the thread. + + The default is `auto`. If set to `last_messages`, the thread will be truncated + to the n most recent messages in the thread. When set to `auto`, messages in the + middle of the thread will be dropped to fit the context length of the model, + `max_prompt_tokens`. + """ + + last_messages: Optional[int] = None + """ + The number of most recent messages from the thread when constructing the context + for the run. + """ + + class Usage(BaseModel): completion_tokens: int """Number of completion tokens used over the course of the run.""" @@ -201,7 +225,7 @@ class Run(BaseModel): this run. """ - truncation_strategy: Optional[TruncationObject] = None + truncation_strategy: Optional[TruncationStrategy] = None """Controls for how a thread will be truncated prior to the run. Use this to control the intial context window of the run. diff --git a/src/openai/types/beta/threads/run_create_params.py b/src/openai/types/beta/threads/run_create_params.py index 80656aada4..fc70227862 100644 --- a/src/openai/types/beta/threads/run_create_params.py +++ b/src/openai/types/beta/threads/run_create_params.py @@ -9,7 +9,6 @@ from ..assistant_tool_param import AssistantToolParam from .runs.run_step_include import RunStepInclude from ...shared_params.metadata import Metadata -from ..truncation_object_param import TruncationObjectParam from ...shared.reasoning_effort import ReasoningEffort from .message_content_part_param import MessageContentPartParam from ..code_interpreter_tool_param import CodeInterpreterToolParam @@ -22,6 +21,7 @@ "AdditionalMessageAttachment", "AdditionalMessageAttachmentTool", "AdditionalMessageAttachmentToolFileSearch", + "TruncationStrategy", "RunCreateParamsNonStreaming", "RunCreateParamsStreaming", ] @@ -173,7 +173,7 @@ class RunCreateParamsBase(TypedDict, total=False): We generally recommend altering this or temperature but not both. """ - truncation_strategy: Optional[TruncationObjectParam] + truncation_strategy: Optional[TruncationStrategy] """Controls for how a thread will be truncated prior to the run. Use this to control the intial context window of the run. @@ -223,6 +223,23 @@ class AdditionalMessage(TypedDict, total=False): """ +class TruncationStrategy(TypedDict, total=False): + type: Required[Literal["auto", "last_messages"]] + """The truncation strategy to use for the thread. + + The default is `auto`. If set to `last_messages`, the thread will be truncated + to the n most recent messages in the thread. When set to `auto`, messages in the + middle of the thread will be dropped to fit the context length of the model, + `max_prompt_tokens`. + """ + + last_messages: Optional[int] + """ + The number of most recent messages from the thread when constructing the context + for the run. + """ + + class RunCreateParamsNonStreaming(RunCreateParamsBase, total=False): stream: Optional[Literal[False]] """ diff --git a/src/openai/types/beta/truncation_object.py b/src/openai/types/beta/truncation_object.py deleted file mode 100644 index 7c81b3b5bc..0000000000 --- a/src/openai/types/beta/truncation_object.py +++ /dev/null @@ -1,25 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["TruncationObject"] - - -class TruncationObject(BaseModel): - type: Literal["auto", "last_messages"] - """The truncation strategy to use for the thread. - - The default is `auto`. If set to `last_messages`, the thread will be truncated - to the n most recent messages in the thread. When set to `auto`, messages in the - middle of the thread will be dropped to fit the context length of the model, - `max_prompt_tokens`. - """ - - last_messages: Optional[int] = None - """ - The number of most recent messages from the thread when constructing the context - for the run. - """ diff --git a/src/openai/types/beta/truncation_object_param.py b/src/openai/types/beta/truncation_object_param.py deleted file mode 100644 index 98d942fa09..0000000000 --- a/src/openai/types/beta/truncation_object_param.py +++ /dev/null @@ -1,25 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["TruncationObjectParam"] - - -class TruncationObjectParam(TypedDict, total=False): - type: Required[Literal["auto", "last_messages"]] - """The truncation strategy to use for the thread. - - The default is `auto`. If set to `last_messages`, the thread will be truncated - to the n most recent messages in the thread. When set to `auto`, messages in the - middle of the thread will be dropped to fit the context length of the model, - `max_prompt_tokens`. - """ - - last_messages: Optional[int] - """ - The number of most recent messages from the thread when constructing the context - for the run. - """ diff --git a/src/openai/types/eval_create_params.py b/src/openai/types/eval_create_params.py index 95fd0bb8d8..8d508a2d8e 100644 --- a/src/openai/types/eval_create_params.py +++ b/src/openai/types/eval_create_params.py @@ -6,10 +6,10 @@ from typing_extensions import Literal, Required, TypeAlias, TypedDict from .shared_params.metadata import Metadata -from .shared_params.eval_item import EvalItem from .graders.python_grader_param import PythonGraderParam from .graders.score_model_grader_param import ScoreModelGraderParam from .graders.string_check_grader_param import StringCheckGraderParam +from .responses.response_input_text_param import ResponseInputTextParam from .graders.text_similarity_grader_param import TextSimilarityGraderParam __all__ = [ @@ -22,6 +22,9 @@ "TestingCriterionLabelModel", "TestingCriterionLabelModelInput", "TestingCriterionLabelModelInputSimpleInputMessage", + "TestingCriterionLabelModelInputEvalItem", + "TestingCriterionLabelModelInputEvalItemContent", + "TestingCriterionLabelModelInputEvalItemContentOutputText", "TestingCriterionTextSimilarity", "TestingCriterionPython", "TestingCriterionScoreModel", @@ -90,7 +93,36 @@ class TestingCriterionLabelModelInputSimpleInputMessage(TypedDict, total=False): """The role of the message (e.g. "system", "assistant", "user").""" -TestingCriterionLabelModelInput: TypeAlias = Union[TestingCriterionLabelModelInputSimpleInputMessage, EvalItem] +class TestingCriterionLabelModelInputEvalItemContentOutputText(TypedDict, total=False): + text: Required[str] + """The text output from the model.""" + + type: Required[Literal["output_text"]] + """The type of the output text. Always `output_text`.""" + + +TestingCriterionLabelModelInputEvalItemContent: TypeAlias = Union[ + str, ResponseInputTextParam, TestingCriterionLabelModelInputEvalItemContentOutputText +] + + +class TestingCriterionLabelModelInputEvalItem(TypedDict, total=False): + content: Required[TestingCriterionLabelModelInputEvalItemContent] + """Text inputs to the model - can contain template strings.""" + + role: Required[Literal["user", "assistant", "system", "developer"]] + """The role of the message input. + + One of `user`, `assistant`, `system`, or `developer`. + """ + + type: Literal["message"] + """The type of the message input. Always `message`.""" + + +TestingCriterionLabelModelInput: TypeAlias = Union[ + TestingCriterionLabelModelInputSimpleInputMessage, TestingCriterionLabelModelInputEvalItem +] class TestingCriterionLabelModel(TypedDict, total=False): diff --git a/src/openai/types/eval_create_response.py b/src/openai/types/eval_create_response.py index 2bf7643b53..20b0e3127f 100644 --- a/src/openai/types/eval_create_response.py +++ b/src/openai/types/eval_create_response.py @@ -1,8 +1,10 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union, Optional +from typing import Dict, List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias +from pydantic import Field as FieldInfo + from .._utils import PropertyInfo from .._models import BaseModel from .shared.metadata import Metadata @@ -10,7 +12,6 @@ from .graders.label_model_grader import LabelModelGrader from .graders.score_model_grader import ScoreModelGrader from .graders.string_check_grader import StringCheckGrader -from .eval_logs_data_source_config import EvalLogsDataSourceConfig from .eval_custom_data_source_config import EvalCustomDataSourceConfig from .graders.text_similarity_grader import TextSimilarityGrader from .eval_stored_completions_data_source_config import EvalStoredCompletionsDataSourceConfig @@ -18,14 +19,37 @@ __all__ = [ "EvalCreateResponse", "DataSourceConfig", + "DataSourceConfigLogs", "TestingCriterion", "TestingCriterionEvalGraderTextSimilarity", "TestingCriterionEvalGraderPython", "TestingCriterionEvalGraderScoreModel", ] + +class DataSourceConfigLogs(BaseModel): + schema_: Dict[str, object] = FieldInfo(alias="schema") + """ + The json schema for the run data source items. Learn how to build JSON schemas + [here](https://json-schema.org/). + """ + + type: Literal["logs"] + """The type of data source. Always `logs`.""" + + metadata: Optional[Metadata] = None + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + """ + + DataSourceConfig: TypeAlias = Annotated[ - Union[EvalCustomDataSourceConfig, EvalLogsDataSourceConfig, EvalStoredCompletionsDataSourceConfig], + Union[EvalCustomDataSourceConfig, DataSourceConfigLogs, EvalStoredCompletionsDataSourceConfig], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/eval_list_response.py b/src/openai/types/eval_list_response.py index e52f3db1c4..5ac4997cf6 100644 --- a/src/openai/types/eval_list_response.py +++ b/src/openai/types/eval_list_response.py @@ -1,8 +1,10 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union, Optional +from typing import Dict, List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias +from pydantic import Field as FieldInfo + from .._utils import PropertyInfo from .._models import BaseModel from .shared.metadata import Metadata @@ -10,7 +12,6 @@ from .graders.label_model_grader import LabelModelGrader from .graders.score_model_grader import ScoreModelGrader from .graders.string_check_grader import StringCheckGrader -from .eval_logs_data_source_config import EvalLogsDataSourceConfig from .eval_custom_data_source_config import EvalCustomDataSourceConfig from .graders.text_similarity_grader import TextSimilarityGrader from .eval_stored_completions_data_source_config import EvalStoredCompletionsDataSourceConfig @@ -18,14 +19,37 @@ __all__ = [ "EvalListResponse", "DataSourceConfig", + "DataSourceConfigLogs", "TestingCriterion", "TestingCriterionEvalGraderTextSimilarity", "TestingCriterionEvalGraderPython", "TestingCriterionEvalGraderScoreModel", ] + +class DataSourceConfigLogs(BaseModel): + schema_: Dict[str, object] = FieldInfo(alias="schema") + """ + The json schema for the run data source items. Learn how to build JSON schemas + [here](https://json-schema.org/). + """ + + type: Literal["logs"] + """The type of data source. Always `logs`.""" + + metadata: Optional[Metadata] = None + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + """ + + DataSourceConfig: TypeAlias = Annotated[ - Union[EvalCustomDataSourceConfig, EvalLogsDataSourceConfig, EvalStoredCompletionsDataSourceConfig], + Union[EvalCustomDataSourceConfig, DataSourceConfigLogs, EvalStoredCompletionsDataSourceConfig], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/eval_logs_data_source_config.py b/src/openai/types/eval_logs_data_source_config.py deleted file mode 100644 index a3eb245e07..0000000000 --- a/src/openai/types/eval_logs_data_source_config.py +++ /dev/null @@ -1,32 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, Optional -from typing_extensions import Literal - -from pydantic import Field as FieldInfo - -from .._models import BaseModel -from .shared.metadata import Metadata - -__all__ = ["EvalLogsDataSourceConfig"] - - -class EvalLogsDataSourceConfig(BaseModel): - schema_: Dict[str, object] = FieldInfo(alias="schema") - """ - The json schema for the run data source items. Learn how to build JSON schemas - [here](https://json-schema.org/). - """ - - type: Literal["logs"] - """The type of data source. Always `logs`.""" - - metadata: Optional[Metadata] = None - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ diff --git a/src/openai/types/eval_retrieve_response.py b/src/openai/types/eval_retrieve_response.py index 71ed96d5ab..758f9cc040 100644 --- a/src/openai/types/eval_retrieve_response.py +++ b/src/openai/types/eval_retrieve_response.py @@ -1,8 +1,10 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union, Optional +from typing import Dict, List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias +from pydantic import Field as FieldInfo + from .._utils import PropertyInfo from .._models import BaseModel from .shared.metadata import Metadata @@ -10,7 +12,6 @@ from .graders.label_model_grader import LabelModelGrader from .graders.score_model_grader import ScoreModelGrader from .graders.string_check_grader import StringCheckGrader -from .eval_logs_data_source_config import EvalLogsDataSourceConfig from .eval_custom_data_source_config import EvalCustomDataSourceConfig from .graders.text_similarity_grader import TextSimilarityGrader from .eval_stored_completions_data_source_config import EvalStoredCompletionsDataSourceConfig @@ -18,14 +19,37 @@ __all__ = [ "EvalRetrieveResponse", "DataSourceConfig", + "DataSourceConfigLogs", "TestingCriterion", "TestingCriterionEvalGraderTextSimilarity", "TestingCriterionEvalGraderPython", "TestingCriterionEvalGraderScoreModel", ] + +class DataSourceConfigLogs(BaseModel): + schema_: Dict[str, object] = FieldInfo(alias="schema") + """ + The json schema for the run data source items. Learn how to build JSON schemas + [here](https://json-schema.org/). + """ + + type: Literal["logs"] + """The type of data source. Always `logs`.""" + + metadata: Optional[Metadata] = None + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + """ + + DataSourceConfig: TypeAlias = Annotated[ - Union[EvalCustomDataSourceConfig, EvalLogsDataSourceConfig, EvalStoredCompletionsDataSourceConfig], + Union[EvalCustomDataSourceConfig, DataSourceConfigLogs, EvalStoredCompletionsDataSourceConfig], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/eval_update_response.py b/src/openai/types/eval_update_response.py index 73ee6eb58c..3f0b90ae03 100644 --- a/src/openai/types/eval_update_response.py +++ b/src/openai/types/eval_update_response.py @@ -1,8 +1,10 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union, Optional +from typing import Dict, List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias +from pydantic import Field as FieldInfo + from .._utils import PropertyInfo from .._models import BaseModel from .shared.metadata import Metadata @@ -10,7 +12,6 @@ from .graders.label_model_grader import LabelModelGrader from .graders.score_model_grader import ScoreModelGrader from .graders.string_check_grader import StringCheckGrader -from .eval_logs_data_source_config import EvalLogsDataSourceConfig from .eval_custom_data_source_config import EvalCustomDataSourceConfig from .graders.text_similarity_grader import TextSimilarityGrader from .eval_stored_completions_data_source_config import EvalStoredCompletionsDataSourceConfig @@ -18,14 +19,37 @@ __all__ = [ "EvalUpdateResponse", "DataSourceConfig", + "DataSourceConfigLogs", "TestingCriterion", "TestingCriterionEvalGraderTextSimilarity", "TestingCriterionEvalGraderPython", "TestingCriterionEvalGraderScoreModel", ] + +class DataSourceConfigLogs(BaseModel): + schema_: Dict[str, object] = FieldInfo(alias="schema") + """ + The json schema for the run data source items. Learn how to build JSON schemas + [here](https://json-schema.org/). + """ + + type: Literal["logs"] + """The type of data source. Always `logs`.""" + + metadata: Optional[Metadata] = None + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + """ + + DataSourceConfig: TypeAlias = Annotated[ - Union[EvalCustomDataSourceConfig, EvalLogsDataSourceConfig, EvalStoredCompletionsDataSourceConfig], + Union[EvalCustomDataSourceConfig, DataSourceConfigLogs, EvalStoredCompletionsDataSourceConfig], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/evals/__init__.py b/src/openai/types/evals/__init__.py index 7841a40382..ebf84c6b8d 100644 --- a/src/openai/types/evals/__init__.py +++ b/src/openai/types/evals/__init__.py @@ -10,21 +10,13 @@ from .run_create_response import RunCreateResponse as RunCreateResponse from .run_delete_response import RunDeleteResponse as RunDeleteResponse from .run_retrieve_response import RunRetrieveResponse as RunRetrieveResponse -from .eval_jsonl_file_id_source import EvalJSONLFileIDSource as EvalJSONLFileIDSource -from .eval_jsonl_file_content_source import EvalJSONLFileContentSource as EvalJSONLFileContentSource -from .eval_jsonl_file_id_source_param import EvalJSONLFileIDSourceParam as EvalJSONLFileIDSourceParam from .create_eval_jsonl_run_data_source import CreateEvalJSONLRunDataSource as CreateEvalJSONLRunDataSource -from .eval_jsonl_file_content_source_param import EvalJSONLFileContentSourceParam as EvalJSONLFileContentSourceParam -from .create_eval_responses_run_data_source import CreateEvalResponsesRunDataSource as CreateEvalResponsesRunDataSource from .create_eval_completions_run_data_source import ( CreateEvalCompletionsRunDataSource as CreateEvalCompletionsRunDataSource, ) from .create_eval_jsonl_run_data_source_param import ( CreateEvalJSONLRunDataSourceParam as CreateEvalJSONLRunDataSourceParam, ) -from .create_eval_responses_run_data_source_param import ( - CreateEvalResponsesRunDataSourceParam as CreateEvalResponsesRunDataSourceParam, -) from .create_eval_completions_run_data_source_param import ( CreateEvalCompletionsRunDataSourceParam as CreateEvalCompletionsRunDataSourceParam, ) diff --git a/src/openai/types/evals/create_eval_completions_run_data_source.py b/src/openai/types/evals/create_eval_completions_run_data_source.py index 439fcc5d7b..29c687b542 100644 --- a/src/openai/types/evals/create_eval_completions_run_data_source.py +++ b/src/openai/types/evals/create_eval_completions_run_data_source.py @@ -1,28 +1,54 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union, Optional +from typing import Dict, List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias from ..._utils import PropertyInfo from ..._models import BaseModel from ..shared.metadata import Metadata -from ..shared.eval_item import EvalItem -from .eval_jsonl_file_id_source import EvalJSONLFileIDSource from ..responses.easy_input_message import EasyInputMessage -from .eval_jsonl_file_content_source import EvalJSONLFileContentSource +from ..responses.response_input_text import ResponseInputText __all__ = [ "CreateEvalCompletionsRunDataSource", "Source", + "SourceFileContent", + "SourceFileContentContent", + "SourceFileID", "SourceStoredCompletions", "InputMessages", "InputMessagesTemplate", "InputMessagesTemplateTemplate", + "InputMessagesTemplateTemplateMessage", + "InputMessagesTemplateTemplateMessageContent", + "InputMessagesTemplateTemplateMessageContentOutputText", "InputMessagesItemReference", "SamplingParams", ] +class SourceFileContentContent(BaseModel): + item: Dict[str, object] + + sample: Optional[Dict[str, object]] = None + + +class SourceFileContent(BaseModel): + content: List[SourceFileContentContent] + """The content of the jsonl file.""" + + type: Literal["file_content"] + """The type of jsonl source. Always `file_content`.""" + + +class SourceFileID(BaseModel): + id: str + """The identifier of the file.""" + + type: Literal["file_id"] + """The type of jsonl source. Always `file_id`.""" + + class SourceStoredCompletions(BaseModel): type: Literal["stored_completions"] """The type of source. Always `stored_completions`.""" @@ -51,12 +77,39 @@ class SourceStoredCompletions(BaseModel): Source: TypeAlias = Annotated[ - Union[EvalJSONLFileContentSource, EvalJSONLFileIDSource, SourceStoredCompletions], - PropertyInfo(discriminator="type"), + Union[SourceFileContent, SourceFileID, SourceStoredCompletions], PropertyInfo(discriminator="type") +] + + +class InputMessagesTemplateTemplateMessageContentOutputText(BaseModel): + text: str + """The text output from the model.""" + + type: Literal["output_text"] + """The type of the output text. Always `output_text`.""" + + +InputMessagesTemplateTemplateMessageContent: TypeAlias = Union[ + str, ResponseInputText, InputMessagesTemplateTemplateMessageContentOutputText ] + +class InputMessagesTemplateTemplateMessage(BaseModel): + content: InputMessagesTemplateTemplateMessageContent + """Text inputs to the model - can contain template strings.""" + + role: Literal["user", "assistant", "system", "developer"] + """The role of the message input. + + One of `user`, `assistant`, `system`, or `developer`. + """ + + type: Optional[Literal["message"]] = None + """The type of the message input. Always `message`.""" + + InputMessagesTemplateTemplate: TypeAlias = Annotated[ - Union[EasyInputMessage, EvalItem], PropertyInfo(discriminator="type") + Union[EasyInputMessage, InputMessagesTemplateTemplateMessage], PropertyInfo(discriminator="type") ] diff --git a/src/openai/types/evals/create_eval_completions_run_data_source_param.py b/src/openai/types/evals/create_eval_completions_run_data_source_param.py index e94443d953..c53064ee27 100644 --- a/src/openai/types/evals/create_eval_completions_run_data_source_param.py +++ b/src/openai/types/evals/create_eval_completions_run_data_source_param.py @@ -2,27 +2,53 @@ from __future__ import annotations -from typing import Union, Iterable, Optional +from typing import Dict, Union, Iterable, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict from ..shared_params.metadata import Metadata -from ..shared_params.eval_item import EvalItem -from .eval_jsonl_file_id_source_param import EvalJSONLFileIDSourceParam from ..responses.easy_input_message_param import EasyInputMessageParam -from .eval_jsonl_file_content_source_param import EvalJSONLFileContentSourceParam +from ..responses.response_input_text_param import ResponseInputTextParam __all__ = [ "CreateEvalCompletionsRunDataSourceParam", "Source", + "SourceFileContent", + "SourceFileContentContent", + "SourceFileID", "SourceStoredCompletions", "InputMessages", "InputMessagesTemplate", "InputMessagesTemplateTemplate", + "InputMessagesTemplateTemplateMessage", + "InputMessagesTemplateTemplateMessageContent", + "InputMessagesTemplateTemplateMessageContentOutputText", "InputMessagesItemReference", "SamplingParams", ] +class SourceFileContentContent(TypedDict, total=False): + item: Required[Dict[str, object]] + + sample: Dict[str, object] + + +class SourceFileContent(TypedDict, total=False): + content: Required[Iterable[SourceFileContentContent]] + """The content of the jsonl file.""" + + type: Required[Literal["file_content"]] + """The type of jsonl source. Always `file_content`.""" + + +class SourceFileID(TypedDict, total=False): + id: Required[str] + """The identifier of the file.""" + + type: Required[Literal["file_id"]] + """The type of jsonl source. Always `file_id`.""" + + class SourceStoredCompletions(TypedDict, total=False): type: Required[Literal["stored_completions"]] """The type of source. Always `stored_completions`.""" @@ -50,9 +76,37 @@ class SourceStoredCompletions(TypedDict, total=False): """An optional model to filter by (e.g., 'gpt-4o').""" -Source: TypeAlias = Union[EvalJSONLFileContentSourceParam, EvalJSONLFileIDSourceParam, SourceStoredCompletions] +Source: TypeAlias = Union[SourceFileContent, SourceFileID, SourceStoredCompletions] + + +class InputMessagesTemplateTemplateMessageContentOutputText(TypedDict, total=False): + text: Required[str] + """The text output from the model.""" + + type: Required[Literal["output_text"]] + """The type of the output text. Always `output_text`.""" + + +InputMessagesTemplateTemplateMessageContent: TypeAlias = Union[ + str, ResponseInputTextParam, InputMessagesTemplateTemplateMessageContentOutputText +] + + +class InputMessagesTemplateTemplateMessage(TypedDict, total=False): + content: Required[InputMessagesTemplateTemplateMessageContent] + """Text inputs to the model - can contain template strings.""" + + role: Required[Literal["user", "assistant", "system", "developer"]] + """The role of the message input. + + One of `user`, `assistant`, `system`, or `developer`. + """ + + type: Literal["message"] + """The type of the message input. Always `message`.""" + -InputMessagesTemplateTemplate: TypeAlias = Union[EasyInputMessageParam, EvalItem] +InputMessagesTemplateTemplate: TypeAlias = Union[EasyInputMessageParam, InputMessagesTemplateTemplateMessage] class InputMessagesTemplate(TypedDict, total=False): diff --git a/src/openai/types/evals/create_eval_jsonl_run_data_source.py b/src/openai/types/evals/create_eval_jsonl_run_data_source.py index 03c6550744..d2be56243b 100644 --- a/src/openai/types/evals/create_eval_jsonl_run_data_source.py +++ b/src/openai/types/evals/create_eval_jsonl_run_data_source.py @@ -1,18 +1,37 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Union +from typing import Dict, List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias from ..._utils import PropertyInfo from ..._models import BaseModel -from .eval_jsonl_file_id_source import EvalJSONLFileIDSource -from .eval_jsonl_file_content_source import EvalJSONLFileContentSource -__all__ = ["CreateEvalJSONLRunDataSource", "Source"] +__all__ = ["CreateEvalJSONLRunDataSource", "Source", "SourceFileContent", "SourceFileContentContent", "SourceFileID"] -Source: TypeAlias = Annotated[ - Union[EvalJSONLFileContentSource, EvalJSONLFileIDSource], PropertyInfo(discriminator="type") -] + +class SourceFileContentContent(BaseModel): + item: Dict[str, object] + + sample: Optional[Dict[str, object]] = None + + +class SourceFileContent(BaseModel): + content: List[SourceFileContentContent] + """The content of the jsonl file.""" + + type: Literal["file_content"] + """The type of jsonl source. Always `file_content`.""" + + +class SourceFileID(BaseModel): + id: str + """The identifier of the file.""" + + type: Literal["file_id"] + """The type of jsonl source. Always `file_id`.""" + + +Source: TypeAlias = Annotated[Union[SourceFileContent, SourceFileID], PropertyInfo(discriminator="type")] class CreateEvalJSONLRunDataSource(BaseModel): diff --git a/src/openai/types/evals/create_eval_jsonl_run_data_source_param.py b/src/openai/types/evals/create_eval_jsonl_run_data_source_param.py index cc71925782..b8ba48a666 100644 --- a/src/openai/types/evals/create_eval_jsonl_run_data_source_param.py +++ b/src/openai/types/evals/create_eval_jsonl_run_data_source_param.py @@ -2,15 +2,41 @@ from __future__ import annotations -from typing import Union +from typing import Dict, Union, Iterable from typing_extensions import Literal, Required, TypeAlias, TypedDict -from .eval_jsonl_file_id_source_param import EvalJSONLFileIDSourceParam -from .eval_jsonl_file_content_source_param import EvalJSONLFileContentSourceParam +__all__ = [ + "CreateEvalJSONLRunDataSourceParam", + "Source", + "SourceFileContent", + "SourceFileContentContent", + "SourceFileID", +] -__all__ = ["CreateEvalJSONLRunDataSourceParam", "Source"] -Source: TypeAlias = Union[EvalJSONLFileContentSourceParam, EvalJSONLFileIDSourceParam] +class SourceFileContentContent(TypedDict, total=False): + item: Required[Dict[str, object]] + + sample: Dict[str, object] + + +class SourceFileContent(TypedDict, total=False): + content: Required[Iterable[SourceFileContentContent]] + """The content of the jsonl file.""" + + type: Required[Literal["file_content"]] + """The type of jsonl source. Always `file_content`.""" + + +class SourceFileID(TypedDict, total=False): + id: Required[str] + """The identifier of the file.""" + + type: Required[Literal["file_id"]] + """The type of jsonl source. Always `file_id`.""" + + +Source: TypeAlias = Union[SourceFileContent, SourceFileID] class CreateEvalJSONLRunDataSourceParam(TypedDict, total=False): diff --git a/src/openai/types/evals/create_eval_responses_run_data_source.py b/src/openai/types/evals/create_eval_responses_run_data_source.py deleted file mode 100644 index 268eab2173..0000000000 --- a/src/openai/types/evals/create_eval_responses_run_data_source.py +++ /dev/null @@ -1,151 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from ..._utils import PropertyInfo -from ..._models import BaseModel -from ..shared.eval_item import EvalItem -from ..shared.reasoning_effort import ReasoningEffort -from .eval_jsonl_file_id_source import EvalJSONLFileIDSource -from .eval_jsonl_file_content_source import EvalJSONLFileContentSource - -__all__ = [ - "CreateEvalResponsesRunDataSource", - "Source", - "SourceResponses", - "InputMessages", - "InputMessagesTemplate", - "InputMessagesTemplateTemplate", - "InputMessagesTemplateTemplateChatMessage", - "InputMessagesItemReference", - "SamplingParams", -] - - -class SourceResponses(BaseModel): - type: Literal["responses"] - """The type of run data source. Always `responses`.""" - - created_after: Optional[int] = None - """Only include items created after this timestamp (inclusive). - - This is a query parameter used to select responses. - """ - - created_before: Optional[int] = None - """Only include items created before this timestamp (inclusive). - - This is a query parameter used to select responses. - """ - - has_tool_calls: Optional[bool] = None - """Whether the response has tool calls. - - This is a query parameter used to select responses. - """ - - instructions_search: Optional[str] = None - """Optional string to search the 'instructions' field. - - This is a query parameter used to select responses. - """ - - metadata: Optional[object] = None - """Metadata filter for the responses. - - This is a query parameter used to select responses. - """ - - model: Optional[str] = None - """The name of the model to find responses for. - - This is a query parameter used to select responses. - """ - - reasoning_effort: Optional[ReasoningEffort] = None - """Optional reasoning effort parameter. - - This is a query parameter used to select responses. - """ - - temperature: Optional[float] = None - """Sampling temperature. This is a query parameter used to select responses.""" - - tools: Optional[List[str]] = None - """List of tool names. This is a query parameter used to select responses.""" - - top_p: Optional[float] = None - """Nucleus sampling parameter. This is a query parameter used to select responses.""" - - users: Optional[List[str]] = None - """List of user identifiers. This is a query parameter used to select responses.""" - - -Source: TypeAlias = Annotated[ - Union[EvalJSONLFileContentSource, EvalJSONLFileIDSource, SourceResponses], PropertyInfo(discriminator="type") -] - - -class InputMessagesTemplateTemplateChatMessage(BaseModel): - content: str - """The content of the message.""" - - role: str - """The role of the message (e.g. "system", "assistant", "user").""" - - -InputMessagesTemplateTemplate: TypeAlias = Union[InputMessagesTemplateTemplateChatMessage, EvalItem] - - -class InputMessagesTemplate(BaseModel): - template: List[InputMessagesTemplateTemplate] - """A list of chat messages forming the prompt or context. - - May include variable references to the "item" namespace, ie {{item.name}}. - """ - - type: Literal["template"] - """The type of input messages. Always `template`.""" - - -class InputMessagesItemReference(BaseModel): - item_reference: str - """A reference to a variable in the "item" namespace. Ie, "item.name" """ - - type: Literal["item_reference"] - """The type of input messages. Always `item_reference`.""" - - -InputMessages: TypeAlias = Annotated[ - Union[InputMessagesTemplate, InputMessagesItemReference], PropertyInfo(discriminator="type") -] - - -class SamplingParams(BaseModel): - max_completion_tokens: Optional[int] = None - """The maximum number of tokens in the generated output.""" - - seed: Optional[int] = None - """A seed value to initialize the randomness, during sampling.""" - - temperature: Optional[float] = None - """A higher temperature increases randomness in the outputs.""" - - top_p: Optional[float] = None - """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" - - -class CreateEvalResponsesRunDataSource(BaseModel): - source: Source - """A EvalResponsesSource object describing a run data source configuration.""" - - type: Literal["responses"] - """The type of run data source. Always `responses`.""" - - input_messages: Optional[InputMessages] = None - - model: Optional[str] = None - """The name of the model to use for generating completions (e.g. "o3-mini").""" - - sampling_params: Optional[SamplingParams] = None diff --git a/src/openai/types/evals/create_eval_responses_run_data_source_param.py b/src/openai/types/evals/create_eval_responses_run_data_source_param.py deleted file mode 100644 index 02d45a9e13..0000000000 --- a/src/openai/types/evals/create_eval_responses_run_data_source_param.py +++ /dev/null @@ -1,147 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Union, Iterable, Optional -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from ..shared.reasoning_effort import ReasoningEffort -from ..shared_params.eval_item import EvalItem -from .eval_jsonl_file_id_source_param import EvalJSONLFileIDSourceParam -from .eval_jsonl_file_content_source_param import EvalJSONLFileContentSourceParam - -__all__ = [ - "CreateEvalResponsesRunDataSourceParam", - "Source", - "SourceResponses", - "InputMessages", - "InputMessagesTemplate", - "InputMessagesTemplateTemplate", - "InputMessagesTemplateTemplateChatMessage", - "InputMessagesItemReference", - "SamplingParams", -] - - -class SourceResponses(TypedDict, total=False): - type: Required[Literal["responses"]] - """The type of run data source. Always `responses`.""" - - created_after: Optional[int] - """Only include items created after this timestamp (inclusive). - - This is a query parameter used to select responses. - """ - - created_before: Optional[int] - """Only include items created before this timestamp (inclusive). - - This is a query parameter used to select responses. - """ - - has_tool_calls: Optional[bool] - """Whether the response has tool calls. - - This is a query parameter used to select responses. - """ - - instructions_search: Optional[str] - """Optional string to search the 'instructions' field. - - This is a query parameter used to select responses. - """ - - metadata: Optional[object] - """Metadata filter for the responses. - - This is a query parameter used to select responses. - """ - - model: Optional[str] - """The name of the model to find responses for. - - This is a query parameter used to select responses. - """ - - reasoning_effort: Optional[ReasoningEffort] - """Optional reasoning effort parameter. - - This is a query parameter used to select responses. - """ - - temperature: Optional[float] - """Sampling temperature. This is a query parameter used to select responses.""" - - tools: Optional[List[str]] - """List of tool names. This is a query parameter used to select responses.""" - - top_p: Optional[float] - """Nucleus sampling parameter. This is a query parameter used to select responses.""" - - users: Optional[List[str]] - """List of user identifiers. This is a query parameter used to select responses.""" - - -Source: TypeAlias = Union[EvalJSONLFileContentSourceParam, EvalJSONLFileIDSourceParam, SourceResponses] - - -class InputMessagesTemplateTemplateChatMessage(TypedDict, total=False): - content: Required[str] - """The content of the message.""" - - role: Required[str] - """The role of the message (e.g. "system", "assistant", "user").""" - - -InputMessagesTemplateTemplate: TypeAlias = Union[InputMessagesTemplateTemplateChatMessage, EvalItem] - - -class InputMessagesTemplate(TypedDict, total=False): - template: Required[Iterable[InputMessagesTemplateTemplate]] - """A list of chat messages forming the prompt or context. - - May include variable references to the "item" namespace, ie {{item.name}}. - """ - - type: Required[Literal["template"]] - """The type of input messages. Always `template`.""" - - -class InputMessagesItemReference(TypedDict, total=False): - item_reference: Required[str] - """A reference to a variable in the "item" namespace. Ie, "item.name" """ - - type: Required[Literal["item_reference"]] - """The type of input messages. Always `item_reference`.""" - - -InputMessages: TypeAlias = Union[InputMessagesTemplate, InputMessagesItemReference] - - -class SamplingParams(TypedDict, total=False): - max_completion_tokens: int - """The maximum number of tokens in the generated output.""" - - seed: int - """A seed value to initialize the randomness, during sampling.""" - - temperature: float - """A higher temperature increases randomness in the outputs.""" - - top_p: float - """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" - - -class CreateEvalResponsesRunDataSourceParam(TypedDict, total=False): - source: Required[Source] - """A EvalResponsesSource object describing a run data source configuration.""" - - type: Required[Literal["responses"]] - """The type of run data source. Always `responses`.""" - - input_messages: InputMessages - - model: str - """The name of the model to use for generating completions (e.g. "o3-mini").""" - - sampling_params: SamplingParams diff --git a/src/openai/types/evals/eval_jsonl_file_content_source.py b/src/openai/types/evals/eval_jsonl_file_content_source.py deleted file mode 100644 index b18fe8937b..0000000000 --- a/src/openai/types/evals/eval_jsonl_file_content_source.py +++ /dev/null @@ -1,22 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["EvalJSONLFileContentSource", "Content"] - - -class Content(BaseModel): - item: Dict[str, object] - - sample: Optional[Dict[str, object]] = None - - -class EvalJSONLFileContentSource(BaseModel): - content: List[Content] - """The content of the jsonl file.""" - - type: Literal["file_content"] - """The type of jsonl source. Always `file_content`.""" diff --git a/src/openai/types/evals/eval_jsonl_file_content_source_param.py b/src/openai/types/evals/eval_jsonl_file_content_source_param.py deleted file mode 100644 index a70f688762..0000000000 --- a/src/openai/types/evals/eval_jsonl_file_content_source_param.py +++ /dev/null @@ -1,22 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Iterable -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["EvalJSONLFileContentSourceParam", "Content"] - - -class Content(TypedDict, total=False): - item: Required[Dict[str, object]] - - sample: Dict[str, object] - - -class EvalJSONLFileContentSourceParam(TypedDict, total=False): - content: Required[Iterable[Content]] - """The content of the jsonl file.""" - - type: Required[Literal["file_content"]] - """The type of jsonl source. Always `file_content`.""" diff --git a/src/openai/types/evals/eval_jsonl_file_id_source.py b/src/openai/types/evals/eval_jsonl_file_id_source.py deleted file mode 100644 index 2d317f2ce1..0000000000 --- a/src/openai/types/evals/eval_jsonl_file_id_source.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["EvalJSONLFileIDSource"] - - -class EvalJSONLFileIDSource(BaseModel): - id: str - """The identifier of the file.""" - - type: Literal["file_id"] - """The type of jsonl source. Always `file_id`.""" diff --git a/src/openai/types/evals/eval_jsonl_file_id_source_param.py b/src/openai/types/evals/eval_jsonl_file_id_source_param.py deleted file mode 100644 index 76b8662cd6..0000000000 --- a/src/openai/types/evals/eval_jsonl_file_id_source_param.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["EvalJSONLFileIDSourceParam"] - - -class EvalJSONLFileIDSourceParam(TypedDict, total=False): - id: Required[str] - """The identifier of the file.""" - - type: Required[Literal["file_id"]] - """The type of jsonl source. Always `file_id`.""" diff --git a/src/openai/types/evals/run_cancel_response.py b/src/openai/types/evals/run_cancel_response.py index a49989b60f..318e7abc35 100644 --- a/src/openai/types/evals/run_cancel_response.py +++ b/src/openai/types/evals/run_cancel_response.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union, Optional +from typing import Dict, List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias from pydantic import Field as FieldInfo @@ -9,14 +9,219 @@ from ..._models import BaseModel from .eval_api_error import EvalAPIError from ..shared.metadata import Metadata +from ..shared.reasoning_effort import ReasoningEffort +from ..responses.response_input_text import ResponseInputText from .create_eval_jsonl_run_data_source import CreateEvalJSONLRunDataSource -from .create_eval_responses_run_data_source import CreateEvalResponsesRunDataSource from .create_eval_completions_run_data_source import CreateEvalCompletionsRunDataSource -__all__ = ["RunCancelResponse", "DataSource", "PerModelUsage", "PerTestingCriteriaResult", "ResultCounts"] +__all__ = [ + "RunCancelResponse", + "DataSource", + "DataSourceResponses", + "DataSourceResponsesSource", + "DataSourceResponsesSourceFileContent", + "DataSourceResponsesSourceFileContentContent", + "DataSourceResponsesSourceFileID", + "DataSourceResponsesSourceResponses", + "DataSourceResponsesInputMessages", + "DataSourceResponsesInputMessagesTemplate", + "DataSourceResponsesInputMessagesTemplateTemplate", + "DataSourceResponsesInputMessagesTemplateTemplateChatMessage", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItem", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText", + "DataSourceResponsesInputMessagesItemReference", + "DataSourceResponsesSamplingParams", + "PerModelUsage", + "PerTestingCriteriaResult", + "ResultCounts", +] + + +class DataSourceResponsesSourceFileContentContent(BaseModel): + item: Dict[str, object] + + sample: Optional[Dict[str, object]] = None + + +class DataSourceResponsesSourceFileContent(BaseModel): + content: List[DataSourceResponsesSourceFileContentContent] + """The content of the jsonl file.""" + + type: Literal["file_content"] + """The type of jsonl source. Always `file_content`.""" + + +class DataSourceResponsesSourceFileID(BaseModel): + id: str + """The identifier of the file.""" + + type: Literal["file_id"] + """The type of jsonl source. Always `file_id`.""" + + +class DataSourceResponsesSourceResponses(BaseModel): + type: Literal["responses"] + """The type of run data source. Always `responses`.""" + + created_after: Optional[int] = None + """Only include items created after this timestamp (inclusive). + + This is a query parameter used to select responses. + """ + + created_before: Optional[int] = None + """Only include items created before this timestamp (inclusive). + + This is a query parameter used to select responses. + """ + + has_tool_calls: Optional[bool] = None + """Whether the response has tool calls. + + This is a query parameter used to select responses. + """ + + instructions_search: Optional[str] = None + """Optional string to search the 'instructions' field. + + This is a query parameter used to select responses. + """ + + metadata: Optional[object] = None + """Metadata filter for the responses. + + This is a query parameter used to select responses. + """ + + model: Optional[str] = None + """The name of the model to find responses for. + + This is a query parameter used to select responses. + """ + + reasoning_effort: Optional[ReasoningEffort] = None + """Optional reasoning effort parameter. + + This is a query parameter used to select responses. + """ + + temperature: Optional[float] = None + """Sampling temperature. This is a query parameter used to select responses.""" + + tools: Optional[List[str]] = None + """List of tool names. This is a query parameter used to select responses.""" + + top_p: Optional[float] = None + """Nucleus sampling parameter. This is a query parameter used to select responses.""" + + users: Optional[List[str]] = None + """List of user identifiers. This is a query parameter used to select responses.""" + + +DataSourceResponsesSource: TypeAlias = Annotated[ + Union[DataSourceResponsesSourceFileContent, DataSourceResponsesSourceFileID, DataSourceResponsesSourceResponses], + PropertyInfo(discriminator="type"), +] + + +class DataSourceResponsesInputMessagesTemplateTemplateChatMessage(BaseModel): + content: str + """The content of the message.""" + + role: str + """The role of the message (e.g. "system", "assistant", "user").""" + + +class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText(BaseModel): + text: str + """The text output from the model.""" + + type: Literal["output_text"] + """The type of the output text. Always `output_text`.""" + + +DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ + str, ResponseInputText, DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText +] + + +class DataSourceResponsesInputMessagesTemplateTemplateEvalItem(BaseModel): + content: DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent + """Text inputs to the model - can contain template strings.""" + + role: Literal["user", "assistant", "system", "developer"] + """The role of the message input. + + One of `user`, `assistant`, `system`, or `developer`. + """ + + type: Optional[Literal["message"]] = None + """The type of the message input. Always `message`.""" + + +DataSourceResponsesInputMessagesTemplateTemplate: TypeAlias = Union[ + DataSourceResponsesInputMessagesTemplateTemplateChatMessage, + DataSourceResponsesInputMessagesTemplateTemplateEvalItem, +] + + +class DataSourceResponsesInputMessagesTemplate(BaseModel): + template: List[DataSourceResponsesInputMessagesTemplateTemplate] + """A list of chat messages forming the prompt or context. + + May include variable references to the "item" namespace, ie {{item.name}}. + """ + + type: Literal["template"] + """The type of input messages. Always `template`.""" + + +class DataSourceResponsesInputMessagesItemReference(BaseModel): + item_reference: str + """A reference to a variable in the "item" namespace. Ie, "item.name" """ + + type: Literal["item_reference"] + """The type of input messages. Always `item_reference`.""" + + +DataSourceResponsesInputMessages: TypeAlias = Annotated[ + Union[DataSourceResponsesInputMessagesTemplate, DataSourceResponsesInputMessagesItemReference], + PropertyInfo(discriminator="type"), +] + + +class DataSourceResponsesSamplingParams(BaseModel): + max_completion_tokens: Optional[int] = None + """The maximum number of tokens in the generated output.""" + + seed: Optional[int] = None + """A seed value to initialize the randomness, during sampling.""" + + temperature: Optional[float] = None + """A higher temperature increases randomness in the outputs.""" + + top_p: Optional[float] = None + """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" + + +class DataSourceResponses(BaseModel): + source: DataSourceResponsesSource + """A EvalResponsesSource object describing a run data source configuration.""" + + type: Literal["responses"] + """The type of run data source. Always `responses`.""" + + input_messages: Optional[DataSourceResponsesInputMessages] = None + + model: Optional[str] = None + """The name of the model to use for generating completions (e.g. "o3-mini").""" + + sampling_params: Optional[DataSourceResponsesSamplingParams] = None + DataSource: TypeAlias = Annotated[ - Union[CreateEvalJSONLRunDataSource, CreateEvalCompletionsRunDataSource, CreateEvalResponsesRunDataSource], + Union[CreateEvalJSONLRunDataSource, CreateEvalCompletionsRunDataSource, DataSourceResponses], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/evals/run_create_params.py b/src/openai/types/evals/run_create_params.py index 00c7398748..e030224dcb 100644 --- a/src/openai/types/evals/run_create_params.py +++ b/src/openai/types/evals/run_create_params.py @@ -2,15 +2,34 @@ from __future__ import annotations -from typing import Union, Optional -from typing_extensions import Required, TypeAlias, TypedDict +from typing import Dict, List, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict from ..shared_params.metadata import Metadata +from ..shared.reasoning_effort import ReasoningEffort +from ..responses.response_input_text_param import ResponseInputTextParam from .create_eval_jsonl_run_data_source_param import CreateEvalJSONLRunDataSourceParam -from .create_eval_responses_run_data_source_param import CreateEvalResponsesRunDataSourceParam from .create_eval_completions_run_data_source_param import CreateEvalCompletionsRunDataSourceParam -__all__ = ["RunCreateParams", "DataSource"] +__all__ = [ + "RunCreateParams", + "DataSource", + "DataSourceCreateEvalResponsesRunDataSource", + "DataSourceCreateEvalResponsesRunDataSourceSource", + "DataSourceCreateEvalResponsesRunDataSourceSourceFileContent", + "DataSourceCreateEvalResponsesRunDataSourceSourceFileContentContent", + "DataSourceCreateEvalResponsesRunDataSourceSourceFileID", + "DataSourceCreateEvalResponsesRunDataSourceSourceResponses", + "DataSourceCreateEvalResponsesRunDataSourceInputMessages", + "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplate", + "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplate", + "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateChatMessage", + "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItem", + "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContent", + "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentOutputText", + "DataSourceCreateEvalResponsesRunDataSourceInputMessagesItemReference", + "DataSourceCreateEvalResponsesRunDataSourceSamplingParams", +] class RunCreateParams(TypedDict, total=False): @@ -31,6 +50,195 @@ class RunCreateParams(TypedDict, total=False): """The name of the run.""" +class DataSourceCreateEvalResponsesRunDataSourceSourceFileContentContent(TypedDict, total=False): + item: Required[Dict[str, object]] + + sample: Dict[str, object] + + +class DataSourceCreateEvalResponsesRunDataSourceSourceFileContent(TypedDict, total=False): + content: Required[Iterable[DataSourceCreateEvalResponsesRunDataSourceSourceFileContentContent]] + """The content of the jsonl file.""" + + type: Required[Literal["file_content"]] + """The type of jsonl source. Always `file_content`.""" + + +class DataSourceCreateEvalResponsesRunDataSourceSourceFileID(TypedDict, total=False): + id: Required[str] + """The identifier of the file.""" + + type: Required[Literal["file_id"]] + """The type of jsonl source. Always `file_id`.""" + + +class DataSourceCreateEvalResponsesRunDataSourceSourceResponses(TypedDict, total=False): + type: Required[Literal["responses"]] + """The type of run data source. Always `responses`.""" + + created_after: Optional[int] + """Only include items created after this timestamp (inclusive). + + This is a query parameter used to select responses. + """ + + created_before: Optional[int] + """Only include items created before this timestamp (inclusive). + + This is a query parameter used to select responses. + """ + + has_tool_calls: Optional[bool] + """Whether the response has tool calls. + + This is a query parameter used to select responses. + """ + + instructions_search: Optional[str] + """Optional string to search the 'instructions' field. + + This is a query parameter used to select responses. + """ + + metadata: Optional[object] + """Metadata filter for the responses. + + This is a query parameter used to select responses. + """ + + model: Optional[str] + """The name of the model to find responses for. + + This is a query parameter used to select responses. + """ + + reasoning_effort: Optional[ReasoningEffort] + """Optional reasoning effort parameter. + + This is a query parameter used to select responses. + """ + + temperature: Optional[float] + """Sampling temperature. This is a query parameter used to select responses.""" + + tools: Optional[List[str]] + """List of tool names. This is a query parameter used to select responses.""" + + top_p: Optional[float] + """Nucleus sampling parameter. This is a query parameter used to select responses.""" + + users: Optional[List[str]] + """List of user identifiers. This is a query parameter used to select responses.""" + + +DataSourceCreateEvalResponsesRunDataSourceSource: TypeAlias = Union[ + DataSourceCreateEvalResponsesRunDataSourceSourceFileContent, + DataSourceCreateEvalResponsesRunDataSourceSourceFileID, + DataSourceCreateEvalResponsesRunDataSourceSourceResponses, +] + + +class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateChatMessage(TypedDict, total=False): + content: Required[str] + """The content of the message.""" + + role: Required[str] + """The role of the message (e.g. "system", "assistant", "user").""" + + +class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentOutputText( + TypedDict, total=False +): + text: Required[str] + """The text output from the model.""" + + type: Required[Literal["output_text"]] + """The type of the output text. Always `output_text`.""" + + +DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ + str, + ResponseInputTextParam, + DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentOutputText, +] + + +class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItem(TypedDict, total=False): + content: Required[DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContent] + """Text inputs to the model - can contain template strings.""" + + role: Required[Literal["user", "assistant", "system", "developer"]] + """The role of the message input. + + One of `user`, `assistant`, `system`, or `developer`. + """ + + type: Literal["message"] + """The type of the message input. Always `message`.""" + + +DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplate: TypeAlias = Union[ + DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateChatMessage, + DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItem, +] + + +class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplate(TypedDict, total=False): + template: Required[Iterable[DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplate]] + """A list of chat messages forming the prompt or context. + + May include variable references to the "item" namespace, ie {{item.name}}. + """ + + type: Required[Literal["template"]] + """The type of input messages. Always `template`.""" + + +class DataSourceCreateEvalResponsesRunDataSourceInputMessagesItemReference(TypedDict, total=False): + item_reference: Required[str] + """A reference to a variable in the "item" namespace. Ie, "item.name" """ + + type: Required[Literal["item_reference"]] + """The type of input messages. Always `item_reference`.""" + + +DataSourceCreateEvalResponsesRunDataSourceInputMessages: TypeAlias = Union[ + DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplate, + DataSourceCreateEvalResponsesRunDataSourceInputMessagesItemReference, +] + + +class DataSourceCreateEvalResponsesRunDataSourceSamplingParams(TypedDict, total=False): + max_completion_tokens: int + """The maximum number of tokens in the generated output.""" + + seed: int + """A seed value to initialize the randomness, during sampling.""" + + temperature: float + """A higher temperature increases randomness in the outputs.""" + + top_p: float + """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" + + +class DataSourceCreateEvalResponsesRunDataSource(TypedDict, total=False): + source: Required[DataSourceCreateEvalResponsesRunDataSourceSource] + """A EvalResponsesSource object describing a run data source configuration.""" + + type: Required[Literal["responses"]] + """The type of run data source. Always `responses`.""" + + input_messages: DataSourceCreateEvalResponsesRunDataSourceInputMessages + + model: str + """The name of the model to use for generating completions (e.g. "o3-mini").""" + + sampling_params: DataSourceCreateEvalResponsesRunDataSourceSamplingParams + + DataSource: TypeAlias = Union[ - CreateEvalJSONLRunDataSourceParam, CreateEvalCompletionsRunDataSourceParam, CreateEvalResponsesRunDataSourceParam + CreateEvalJSONLRunDataSourceParam, + CreateEvalCompletionsRunDataSourceParam, + DataSourceCreateEvalResponsesRunDataSource, ] diff --git a/src/openai/types/evals/run_create_response.py b/src/openai/types/evals/run_create_response.py index 8dc64cf895..902e45c9bc 100644 --- a/src/openai/types/evals/run_create_response.py +++ b/src/openai/types/evals/run_create_response.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union, Optional +from typing import Dict, List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias from pydantic import Field as FieldInfo @@ -9,14 +9,219 @@ from ..._models import BaseModel from .eval_api_error import EvalAPIError from ..shared.metadata import Metadata +from ..shared.reasoning_effort import ReasoningEffort +from ..responses.response_input_text import ResponseInputText from .create_eval_jsonl_run_data_source import CreateEvalJSONLRunDataSource -from .create_eval_responses_run_data_source import CreateEvalResponsesRunDataSource from .create_eval_completions_run_data_source import CreateEvalCompletionsRunDataSource -__all__ = ["RunCreateResponse", "DataSource", "PerModelUsage", "PerTestingCriteriaResult", "ResultCounts"] +__all__ = [ + "RunCreateResponse", + "DataSource", + "DataSourceResponses", + "DataSourceResponsesSource", + "DataSourceResponsesSourceFileContent", + "DataSourceResponsesSourceFileContentContent", + "DataSourceResponsesSourceFileID", + "DataSourceResponsesSourceResponses", + "DataSourceResponsesInputMessages", + "DataSourceResponsesInputMessagesTemplate", + "DataSourceResponsesInputMessagesTemplateTemplate", + "DataSourceResponsesInputMessagesTemplateTemplateChatMessage", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItem", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText", + "DataSourceResponsesInputMessagesItemReference", + "DataSourceResponsesSamplingParams", + "PerModelUsage", + "PerTestingCriteriaResult", + "ResultCounts", +] + + +class DataSourceResponsesSourceFileContentContent(BaseModel): + item: Dict[str, object] + + sample: Optional[Dict[str, object]] = None + + +class DataSourceResponsesSourceFileContent(BaseModel): + content: List[DataSourceResponsesSourceFileContentContent] + """The content of the jsonl file.""" + + type: Literal["file_content"] + """The type of jsonl source. Always `file_content`.""" + + +class DataSourceResponsesSourceFileID(BaseModel): + id: str + """The identifier of the file.""" + + type: Literal["file_id"] + """The type of jsonl source. Always `file_id`.""" + + +class DataSourceResponsesSourceResponses(BaseModel): + type: Literal["responses"] + """The type of run data source. Always `responses`.""" + + created_after: Optional[int] = None + """Only include items created after this timestamp (inclusive). + + This is a query parameter used to select responses. + """ + + created_before: Optional[int] = None + """Only include items created before this timestamp (inclusive). + + This is a query parameter used to select responses. + """ + + has_tool_calls: Optional[bool] = None + """Whether the response has tool calls. + + This is a query parameter used to select responses. + """ + + instructions_search: Optional[str] = None + """Optional string to search the 'instructions' field. + + This is a query parameter used to select responses. + """ + + metadata: Optional[object] = None + """Metadata filter for the responses. + + This is a query parameter used to select responses. + """ + + model: Optional[str] = None + """The name of the model to find responses for. + + This is a query parameter used to select responses. + """ + + reasoning_effort: Optional[ReasoningEffort] = None + """Optional reasoning effort parameter. + + This is a query parameter used to select responses. + """ + + temperature: Optional[float] = None + """Sampling temperature. This is a query parameter used to select responses.""" + + tools: Optional[List[str]] = None + """List of tool names. This is a query parameter used to select responses.""" + + top_p: Optional[float] = None + """Nucleus sampling parameter. This is a query parameter used to select responses.""" + + users: Optional[List[str]] = None + """List of user identifiers. This is a query parameter used to select responses.""" + + +DataSourceResponsesSource: TypeAlias = Annotated[ + Union[DataSourceResponsesSourceFileContent, DataSourceResponsesSourceFileID, DataSourceResponsesSourceResponses], + PropertyInfo(discriminator="type"), +] + + +class DataSourceResponsesInputMessagesTemplateTemplateChatMessage(BaseModel): + content: str + """The content of the message.""" + + role: str + """The role of the message (e.g. "system", "assistant", "user").""" + + +class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText(BaseModel): + text: str + """The text output from the model.""" + + type: Literal["output_text"] + """The type of the output text. Always `output_text`.""" + + +DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ + str, ResponseInputText, DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText +] + + +class DataSourceResponsesInputMessagesTemplateTemplateEvalItem(BaseModel): + content: DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent + """Text inputs to the model - can contain template strings.""" + + role: Literal["user", "assistant", "system", "developer"] + """The role of the message input. + + One of `user`, `assistant`, `system`, or `developer`. + """ + + type: Optional[Literal["message"]] = None + """The type of the message input. Always `message`.""" + + +DataSourceResponsesInputMessagesTemplateTemplate: TypeAlias = Union[ + DataSourceResponsesInputMessagesTemplateTemplateChatMessage, + DataSourceResponsesInputMessagesTemplateTemplateEvalItem, +] + + +class DataSourceResponsesInputMessagesTemplate(BaseModel): + template: List[DataSourceResponsesInputMessagesTemplateTemplate] + """A list of chat messages forming the prompt or context. + + May include variable references to the "item" namespace, ie {{item.name}}. + """ + + type: Literal["template"] + """The type of input messages. Always `template`.""" + + +class DataSourceResponsesInputMessagesItemReference(BaseModel): + item_reference: str + """A reference to a variable in the "item" namespace. Ie, "item.name" """ + + type: Literal["item_reference"] + """The type of input messages. Always `item_reference`.""" + + +DataSourceResponsesInputMessages: TypeAlias = Annotated[ + Union[DataSourceResponsesInputMessagesTemplate, DataSourceResponsesInputMessagesItemReference], + PropertyInfo(discriminator="type"), +] + + +class DataSourceResponsesSamplingParams(BaseModel): + max_completion_tokens: Optional[int] = None + """The maximum number of tokens in the generated output.""" + + seed: Optional[int] = None + """A seed value to initialize the randomness, during sampling.""" + + temperature: Optional[float] = None + """A higher temperature increases randomness in the outputs.""" + + top_p: Optional[float] = None + """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" + + +class DataSourceResponses(BaseModel): + source: DataSourceResponsesSource + """A EvalResponsesSource object describing a run data source configuration.""" + + type: Literal["responses"] + """The type of run data source. Always `responses`.""" + + input_messages: Optional[DataSourceResponsesInputMessages] = None + + model: Optional[str] = None + """The name of the model to use for generating completions (e.g. "o3-mini").""" + + sampling_params: Optional[DataSourceResponsesSamplingParams] = None + DataSource: TypeAlias = Annotated[ - Union[CreateEvalJSONLRunDataSource, CreateEvalCompletionsRunDataSource, CreateEvalResponsesRunDataSource], + Union[CreateEvalJSONLRunDataSource, CreateEvalCompletionsRunDataSource, DataSourceResponses], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/evals/run_list_response.py b/src/openai/types/evals/run_list_response.py index 0df3e5c7ad..80327aa912 100644 --- a/src/openai/types/evals/run_list_response.py +++ b/src/openai/types/evals/run_list_response.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union, Optional +from typing import Dict, List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias from pydantic import Field as FieldInfo @@ -9,14 +9,219 @@ from ..._models import BaseModel from .eval_api_error import EvalAPIError from ..shared.metadata import Metadata +from ..shared.reasoning_effort import ReasoningEffort +from ..responses.response_input_text import ResponseInputText from .create_eval_jsonl_run_data_source import CreateEvalJSONLRunDataSource -from .create_eval_responses_run_data_source import CreateEvalResponsesRunDataSource from .create_eval_completions_run_data_source import CreateEvalCompletionsRunDataSource -__all__ = ["RunListResponse", "DataSource", "PerModelUsage", "PerTestingCriteriaResult", "ResultCounts"] +__all__ = [ + "RunListResponse", + "DataSource", + "DataSourceResponses", + "DataSourceResponsesSource", + "DataSourceResponsesSourceFileContent", + "DataSourceResponsesSourceFileContentContent", + "DataSourceResponsesSourceFileID", + "DataSourceResponsesSourceResponses", + "DataSourceResponsesInputMessages", + "DataSourceResponsesInputMessagesTemplate", + "DataSourceResponsesInputMessagesTemplateTemplate", + "DataSourceResponsesInputMessagesTemplateTemplateChatMessage", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItem", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText", + "DataSourceResponsesInputMessagesItemReference", + "DataSourceResponsesSamplingParams", + "PerModelUsage", + "PerTestingCriteriaResult", + "ResultCounts", +] + + +class DataSourceResponsesSourceFileContentContent(BaseModel): + item: Dict[str, object] + + sample: Optional[Dict[str, object]] = None + + +class DataSourceResponsesSourceFileContent(BaseModel): + content: List[DataSourceResponsesSourceFileContentContent] + """The content of the jsonl file.""" + + type: Literal["file_content"] + """The type of jsonl source. Always `file_content`.""" + + +class DataSourceResponsesSourceFileID(BaseModel): + id: str + """The identifier of the file.""" + + type: Literal["file_id"] + """The type of jsonl source. Always `file_id`.""" + + +class DataSourceResponsesSourceResponses(BaseModel): + type: Literal["responses"] + """The type of run data source. Always `responses`.""" + + created_after: Optional[int] = None + """Only include items created after this timestamp (inclusive). + + This is a query parameter used to select responses. + """ + + created_before: Optional[int] = None + """Only include items created before this timestamp (inclusive). + + This is a query parameter used to select responses. + """ + + has_tool_calls: Optional[bool] = None + """Whether the response has tool calls. + + This is a query parameter used to select responses. + """ + + instructions_search: Optional[str] = None + """Optional string to search the 'instructions' field. + + This is a query parameter used to select responses. + """ + + metadata: Optional[object] = None + """Metadata filter for the responses. + + This is a query parameter used to select responses. + """ + + model: Optional[str] = None + """The name of the model to find responses for. + + This is a query parameter used to select responses. + """ + + reasoning_effort: Optional[ReasoningEffort] = None + """Optional reasoning effort parameter. + + This is a query parameter used to select responses. + """ + + temperature: Optional[float] = None + """Sampling temperature. This is a query parameter used to select responses.""" + + tools: Optional[List[str]] = None + """List of tool names. This is a query parameter used to select responses.""" + + top_p: Optional[float] = None + """Nucleus sampling parameter. This is a query parameter used to select responses.""" + + users: Optional[List[str]] = None + """List of user identifiers. This is a query parameter used to select responses.""" + + +DataSourceResponsesSource: TypeAlias = Annotated[ + Union[DataSourceResponsesSourceFileContent, DataSourceResponsesSourceFileID, DataSourceResponsesSourceResponses], + PropertyInfo(discriminator="type"), +] + + +class DataSourceResponsesInputMessagesTemplateTemplateChatMessage(BaseModel): + content: str + """The content of the message.""" + + role: str + """The role of the message (e.g. "system", "assistant", "user").""" + + +class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText(BaseModel): + text: str + """The text output from the model.""" + + type: Literal["output_text"] + """The type of the output text. Always `output_text`.""" + + +DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ + str, ResponseInputText, DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText +] + + +class DataSourceResponsesInputMessagesTemplateTemplateEvalItem(BaseModel): + content: DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent + """Text inputs to the model - can contain template strings.""" + + role: Literal["user", "assistant", "system", "developer"] + """The role of the message input. + + One of `user`, `assistant`, `system`, or `developer`. + """ + + type: Optional[Literal["message"]] = None + """The type of the message input. Always `message`.""" + + +DataSourceResponsesInputMessagesTemplateTemplate: TypeAlias = Union[ + DataSourceResponsesInputMessagesTemplateTemplateChatMessage, + DataSourceResponsesInputMessagesTemplateTemplateEvalItem, +] + + +class DataSourceResponsesInputMessagesTemplate(BaseModel): + template: List[DataSourceResponsesInputMessagesTemplateTemplate] + """A list of chat messages forming the prompt or context. + + May include variable references to the "item" namespace, ie {{item.name}}. + """ + + type: Literal["template"] + """The type of input messages. Always `template`.""" + + +class DataSourceResponsesInputMessagesItemReference(BaseModel): + item_reference: str + """A reference to a variable in the "item" namespace. Ie, "item.name" """ + + type: Literal["item_reference"] + """The type of input messages. Always `item_reference`.""" + + +DataSourceResponsesInputMessages: TypeAlias = Annotated[ + Union[DataSourceResponsesInputMessagesTemplate, DataSourceResponsesInputMessagesItemReference], + PropertyInfo(discriminator="type"), +] + + +class DataSourceResponsesSamplingParams(BaseModel): + max_completion_tokens: Optional[int] = None + """The maximum number of tokens in the generated output.""" + + seed: Optional[int] = None + """A seed value to initialize the randomness, during sampling.""" + + temperature: Optional[float] = None + """A higher temperature increases randomness in the outputs.""" + + top_p: Optional[float] = None + """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" + + +class DataSourceResponses(BaseModel): + source: DataSourceResponsesSource + """A EvalResponsesSource object describing a run data source configuration.""" + + type: Literal["responses"] + """The type of run data source. Always `responses`.""" + + input_messages: Optional[DataSourceResponsesInputMessages] = None + + model: Optional[str] = None + """The name of the model to use for generating completions (e.g. "o3-mini").""" + + sampling_params: Optional[DataSourceResponsesSamplingParams] = None + DataSource: TypeAlias = Annotated[ - Union[CreateEvalJSONLRunDataSource, CreateEvalCompletionsRunDataSource, CreateEvalResponsesRunDataSource], + Union[CreateEvalJSONLRunDataSource, CreateEvalCompletionsRunDataSource, DataSourceResponses], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/evals/run_retrieve_response.py b/src/openai/types/evals/run_retrieve_response.py index 35cdb04efc..9756dcb919 100644 --- a/src/openai/types/evals/run_retrieve_response.py +++ b/src/openai/types/evals/run_retrieve_response.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union, Optional +from typing import Dict, List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias from pydantic import Field as FieldInfo @@ -9,14 +9,219 @@ from ..._models import BaseModel from .eval_api_error import EvalAPIError from ..shared.metadata import Metadata +from ..shared.reasoning_effort import ReasoningEffort +from ..responses.response_input_text import ResponseInputText from .create_eval_jsonl_run_data_source import CreateEvalJSONLRunDataSource -from .create_eval_responses_run_data_source import CreateEvalResponsesRunDataSource from .create_eval_completions_run_data_source import CreateEvalCompletionsRunDataSource -__all__ = ["RunRetrieveResponse", "DataSource", "PerModelUsage", "PerTestingCriteriaResult", "ResultCounts"] +__all__ = [ + "RunRetrieveResponse", + "DataSource", + "DataSourceResponses", + "DataSourceResponsesSource", + "DataSourceResponsesSourceFileContent", + "DataSourceResponsesSourceFileContentContent", + "DataSourceResponsesSourceFileID", + "DataSourceResponsesSourceResponses", + "DataSourceResponsesInputMessages", + "DataSourceResponsesInputMessagesTemplate", + "DataSourceResponsesInputMessagesTemplateTemplate", + "DataSourceResponsesInputMessagesTemplateTemplateChatMessage", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItem", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText", + "DataSourceResponsesInputMessagesItemReference", + "DataSourceResponsesSamplingParams", + "PerModelUsage", + "PerTestingCriteriaResult", + "ResultCounts", +] + + +class DataSourceResponsesSourceFileContentContent(BaseModel): + item: Dict[str, object] + + sample: Optional[Dict[str, object]] = None + + +class DataSourceResponsesSourceFileContent(BaseModel): + content: List[DataSourceResponsesSourceFileContentContent] + """The content of the jsonl file.""" + + type: Literal["file_content"] + """The type of jsonl source. Always `file_content`.""" + + +class DataSourceResponsesSourceFileID(BaseModel): + id: str + """The identifier of the file.""" + + type: Literal["file_id"] + """The type of jsonl source. Always `file_id`.""" + + +class DataSourceResponsesSourceResponses(BaseModel): + type: Literal["responses"] + """The type of run data source. Always `responses`.""" + + created_after: Optional[int] = None + """Only include items created after this timestamp (inclusive). + + This is a query parameter used to select responses. + """ + + created_before: Optional[int] = None + """Only include items created before this timestamp (inclusive). + + This is a query parameter used to select responses. + """ + + has_tool_calls: Optional[bool] = None + """Whether the response has tool calls. + + This is a query parameter used to select responses. + """ + + instructions_search: Optional[str] = None + """Optional string to search the 'instructions' field. + + This is a query parameter used to select responses. + """ + + metadata: Optional[object] = None + """Metadata filter for the responses. + + This is a query parameter used to select responses. + """ + + model: Optional[str] = None + """The name of the model to find responses for. + + This is a query parameter used to select responses. + """ + + reasoning_effort: Optional[ReasoningEffort] = None + """Optional reasoning effort parameter. + + This is a query parameter used to select responses. + """ + + temperature: Optional[float] = None + """Sampling temperature. This is a query parameter used to select responses.""" + + tools: Optional[List[str]] = None + """List of tool names. This is a query parameter used to select responses.""" + + top_p: Optional[float] = None + """Nucleus sampling parameter. This is a query parameter used to select responses.""" + + users: Optional[List[str]] = None + """List of user identifiers. This is a query parameter used to select responses.""" + + +DataSourceResponsesSource: TypeAlias = Annotated[ + Union[DataSourceResponsesSourceFileContent, DataSourceResponsesSourceFileID, DataSourceResponsesSourceResponses], + PropertyInfo(discriminator="type"), +] + + +class DataSourceResponsesInputMessagesTemplateTemplateChatMessage(BaseModel): + content: str + """The content of the message.""" + + role: str + """The role of the message (e.g. "system", "assistant", "user").""" + + +class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText(BaseModel): + text: str + """The text output from the model.""" + + type: Literal["output_text"] + """The type of the output text. Always `output_text`.""" + + +DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ + str, ResponseInputText, DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText +] + + +class DataSourceResponsesInputMessagesTemplateTemplateEvalItem(BaseModel): + content: DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent + """Text inputs to the model - can contain template strings.""" + + role: Literal["user", "assistant", "system", "developer"] + """The role of the message input. + + One of `user`, `assistant`, `system`, or `developer`. + """ + + type: Optional[Literal["message"]] = None + """The type of the message input. Always `message`.""" + + +DataSourceResponsesInputMessagesTemplateTemplate: TypeAlias = Union[ + DataSourceResponsesInputMessagesTemplateTemplateChatMessage, + DataSourceResponsesInputMessagesTemplateTemplateEvalItem, +] + + +class DataSourceResponsesInputMessagesTemplate(BaseModel): + template: List[DataSourceResponsesInputMessagesTemplateTemplate] + """A list of chat messages forming the prompt or context. + + May include variable references to the "item" namespace, ie {{item.name}}. + """ + + type: Literal["template"] + """The type of input messages. Always `template`.""" + + +class DataSourceResponsesInputMessagesItemReference(BaseModel): + item_reference: str + """A reference to a variable in the "item" namespace. Ie, "item.name" """ + + type: Literal["item_reference"] + """The type of input messages. Always `item_reference`.""" + + +DataSourceResponsesInputMessages: TypeAlias = Annotated[ + Union[DataSourceResponsesInputMessagesTemplate, DataSourceResponsesInputMessagesItemReference], + PropertyInfo(discriminator="type"), +] + + +class DataSourceResponsesSamplingParams(BaseModel): + max_completion_tokens: Optional[int] = None + """The maximum number of tokens in the generated output.""" + + seed: Optional[int] = None + """A seed value to initialize the randomness, during sampling.""" + + temperature: Optional[float] = None + """A higher temperature increases randomness in the outputs.""" + + top_p: Optional[float] = None + """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" + + +class DataSourceResponses(BaseModel): + source: DataSourceResponsesSource + """A EvalResponsesSource object describing a run data source configuration.""" + + type: Literal["responses"] + """The type of run data source. Always `responses`.""" + + input_messages: Optional[DataSourceResponsesInputMessages] = None + + model: Optional[str] = None + """The name of the model to use for generating completions (e.g. "o3-mini").""" + + sampling_params: Optional[DataSourceResponsesSamplingParams] = None + DataSource: TypeAlias = Annotated[ - Union[CreateEvalJSONLRunDataSource, CreateEvalCompletionsRunDataSource, CreateEvalResponsesRunDataSource], + Union[CreateEvalJSONLRunDataSource, CreateEvalCompletionsRunDataSource, DataSourceResponses], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/graders/label_model_grader.py b/src/openai/types/graders/label_model_grader.py index 16f5b5aa1b..d95ccc6df6 100644 --- a/src/openai/types/graders/label_model_grader.py +++ b/src/openai/types/graders/label_model_grader.py @@ -1,16 +1,41 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List -from typing_extensions import Literal +from typing import List, Union, Optional +from typing_extensions import Literal, TypeAlias from ..._models import BaseModel -from ..shared.eval_item import EvalItem +from ..responses.response_input_text import ResponseInputText -__all__ = ["LabelModelGrader"] +__all__ = ["LabelModelGrader", "Input", "InputContent", "InputContentOutputText"] + + +class InputContentOutputText(BaseModel): + text: str + """The text output from the model.""" + + type: Literal["output_text"] + """The type of the output text. Always `output_text`.""" + + +InputContent: TypeAlias = Union[str, ResponseInputText, InputContentOutputText] + + +class Input(BaseModel): + content: InputContent + """Text inputs to the model - can contain template strings.""" + + role: Literal["user", "assistant", "system", "developer"] + """The role of the message input. + + One of `user`, `assistant`, `system`, or `developer`. + """ + + type: Optional[Literal["message"]] = None + """The type of the message input. Always `message`.""" class LabelModelGrader(BaseModel): - input: List[EvalItem] + input: List[Input] labels: List[str] """The labels to assign to each item in the evaluation.""" diff --git a/src/openai/types/graders/label_model_grader_param.py b/src/openai/types/graders/label_model_grader_param.py index 34f5de7726..76d01421ee 100644 --- a/src/openai/types/graders/label_model_grader_param.py +++ b/src/openai/types/graders/label_model_grader_param.py @@ -2,16 +2,41 @@ from __future__ import annotations -from typing import List, Iterable -from typing_extensions import Literal, Required, TypedDict +from typing import List, Union, Iterable +from typing_extensions import Literal, Required, TypeAlias, TypedDict -from ..shared_params.eval_item import EvalItem +from ..responses.response_input_text_param import ResponseInputTextParam -__all__ = ["LabelModelGraderParam"] +__all__ = ["LabelModelGraderParam", "Input", "InputContent", "InputContentOutputText"] + + +class InputContentOutputText(TypedDict, total=False): + text: Required[str] + """The text output from the model.""" + + type: Required[Literal["output_text"]] + """The type of the output text. Always `output_text`.""" + + +InputContent: TypeAlias = Union[str, ResponseInputTextParam, InputContentOutputText] + + +class Input(TypedDict, total=False): + content: Required[InputContent] + """Text inputs to the model - can contain template strings.""" + + role: Required[Literal["user", "assistant", "system", "developer"]] + """The role of the message input. + + One of `user`, `assistant`, `system`, or `developer`. + """ + + type: Literal["message"] + """The type of the message input. Always `message`.""" class LabelModelGraderParam(TypedDict, total=False): - input: Required[Iterable[EvalItem]] + input: Required[Iterable[Input]] labels: Required[List[str]] """The labels to assign to each item in the evaluation.""" diff --git a/src/openai/types/graders/multi_grader.py b/src/openai/types/graders/multi_grader.py index ee9b31d2b0..220de2e61b 100644 --- a/src/openai/types/graders/multi_grader.py +++ b/src/openai/types/graders/multi_grader.py @@ -25,4 +25,4 @@ class MultiGrader(BaseModel): """The name of the grader.""" type: Literal["multi"] - """The type of grader.""" + """The object type, which is always `multi`.""" diff --git a/src/openai/types/graders/multi_grader_param.py b/src/openai/types/graders/multi_grader_param.py index 4dd1a48530..2984b5668f 100644 --- a/src/openai/types/graders/multi_grader_param.py +++ b/src/openai/types/graders/multi_grader_param.py @@ -28,4 +28,4 @@ class MultiGraderParam(TypedDict, total=False): """The name of the grader.""" type: Required[Literal["multi"]] - """The type of grader.""" + """The object type, which is always `multi`.""" diff --git a/src/openai/types/graders/score_model_grader.py b/src/openai/types/graders/score_model_grader.py index 6d81019c26..1349f75a58 100644 --- a/src/openai/types/graders/score_model_grader.py +++ b/src/openai/types/graders/score_model_grader.py @@ -1,16 +1,41 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Optional -from typing_extensions import Literal +from typing import List, Union, Optional +from typing_extensions import Literal, TypeAlias from ..._models import BaseModel -from ..shared.eval_item import EvalItem +from ..responses.response_input_text import ResponseInputText -__all__ = ["ScoreModelGrader"] +__all__ = ["ScoreModelGrader", "Input", "InputContent", "InputContentOutputText"] + + +class InputContentOutputText(BaseModel): + text: str + """The text output from the model.""" + + type: Literal["output_text"] + """The type of the output text. Always `output_text`.""" + + +InputContent: TypeAlias = Union[str, ResponseInputText, InputContentOutputText] + + +class Input(BaseModel): + content: InputContent + """Text inputs to the model - can contain template strings.""" + + role: Literal["user", "assistant", "system", "developer"] + """The role of the message input. + + One of `user`, `assistant`, `system`, or `developer`. + """ + + type: Optional[Literal["message"]] = None + """The type of the message input. Always `message`.""" class ScoreModelGrader(BaseModel): - input: List[EvalItem] + input: List[Input] """The input text. This may include template strings.""" model: str diff --git a/src/openai/types/graders/score_model_grader_param.py b/src/openai/types/graders/score_model_grader_param.py index 3e0b9d08eb..673f14e47d 100644 --- a/src/openai/types/graders/score_model_grader_param.py +++ b/src/openai/types/graders/score_model_grader_param.py @@ -2,16 +2,41 @@ from __future__ import annotations -from typing import Iterable -from typing_extensions import Literal, Required, TypedDict +from typing import Union, Iterable +from typing_extensions import Literal, Required, TypeAlias, TypedDict -from ..shared_params.eval_item import EvalItem +from ..responses.response_input_text_param import ResponseInputTextParam -__all__ = ["ScoreModelGraderParam"] +__all__ = ["ScoreModelGraderParam", "Input", "InputContent", "InputContentOutputText"] + + +class InputContentOutputText(TypedDict, total=False): + text: Required[str] + """The text output from the model.""" + + type: Required[Literal["output_text"]] + """The type of the output text. Always `output_text`.""" + + +InputContent: TypeAlias = Union[str, ResponseInputTextParam, InputContentOutputText] + + +class Input(TypedDict, total=False): + content: Required[InputContent] + """Text inputs to the model - can contain template strings.""" + + role: Required[Literal["user", "assistant", "system", "developer"]] + """The role of the message input. + + One of `user`, `assistant`, `system`, or `developer`. + """ + + type: Literal["message"] + """The type of the message input. Always `message`.""" class ScoreModelGraderParam(TypedDict, total=False): - input: Required[Iterable[EvalItem]] + input: Required[Iterable[Input]] """The input text. This may include template strings.""" model: Required[str] diff --git a/src/openai/types/shared/__init__.py b/src/openai/types/shared/__init__.py index 10450d8c70..6ad0ed5e01 100644 --- a/src/openai/types/shared/__init__.py +++ b/src/openai/types/shared/__init__.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from .metadata import Metadata as Metadata -from .eval_item import EvalItem as EvalItem from .reasoning import Reasoning as Reasoning from .all_models import AllModels as AllModels from .chat_model import ChatModel as ChatModel diff --git a/src/openai/types/shared/chat_model.py b/src/openai/types/shared/chat_model.py index 4869cd325c..75069e7a98 100644 --- a/src/openai/types/shared/chat_model.py +++ b/src/openai/types/shared/chat_model.py @@ -37,6 +37,7 @@ "gpt-4o-search-preview-2025-03-11", "gpt-4o-mini-search-preview-2025-03-11", "chatgpt-4o-latest", + "codex-mini-latest", "gpt-4o-mini", "gpt-4o-mini-2024-07-18", "gpt-4-turbo", diff --git a/src/openai/types/shared/eval_item.py b/src/openai/types/shared/eval_item.py deleted file mode 100644 index f235d1ef17..0000000000 --- a/src/openai/types/shared/eval_item.py +++ /dev/null @@ -1,34 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union, Optional -from typing_extensions import Literal, TypeAlias - -from ..._models import BaseModel -from ..responses.response_input_text import ResponseInputText - -__all__ = ["EvalItem", "Content", "ContentOutputText"] - - -class ContentOutputText(BaseModel): - text: str - """The text output from the model.""" - - type: Literal["output_text"] - """The type of the output text. Always `output_text`.""" - - -Content: TypeAlias = Union[str, ResponseInputText, ContentOutputText] - - -class EvalItem(BaseModel): - content: Content - """Text inputs to the model - can contain template strings.""" - - role: Literal["user", "assistant", "system", "developer"] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Optional[Literal["message"]] = None - """The type of the message input. Always `message`.""" diff --git a/src/openai/types/shared_params/__init__.py b/src/openai/types/shared_params/__init__.py index 68d16b90dc..8894710807 100644 --- a/src/openai/types/shared_params/__init__.py +++ b/src/openai/types/shared_params/__init__.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from .metadata import Metadata as Metadata -from .eval_item import EvalItem as EvalItem from .reasoning import Reasoning as Reasoning from .chat_model import ChatModel as ChatModel from .compound_filter import CompoundFilter as CompoundFilter diff --git a/src/openai/types/shared_params/chat_model.py b/src/openai/types/shared_params/chat_model.py index 99e082fc11..c421744b8a 100644 --- a/src/openai/types/shared_params/chat_model.py +++ b/src/openai/types/shared_params/chat_model.py @@ -39,6 +39,7 @@ "gpt-4o-search-preview-2025-03-11", "gpt-4o-mini-search-preview-2025-03-11", "chatgpt-4o-latest", + "codex-mini-latest", "gpt-4o-mini", "gpt-4o-mini-2024-07-18", "gpt-4-turbo", diff --git a/src/openai/types/shared_params/eval_item.py b/src/openai/types/shared_params/eval_item.py deleted file mode 100644 index 7740ccc165..0000000000 --- a/src/openai/types/shared_params/eval_item.py +++ /dev/null @@ -1,35 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from ..responses.response_input_text_param import ResponseInputTextParam - -__all__ = ["EvalItem", "Content", "ContentOutputText"] - - -class ContentOutputText(TypedDict, total=False): - text: Required[str] - """The text output from the model.""" - - type: Required[Literal["output_text"]] - """The type of the output text. Always `output_text`.""" - - -Content: TypeAlias = Union[str, ResponseInputTextParam, ContentOutputText] - - -class EvalItem(TypedDict, total=False): - content: Required[Content] - """Text inputs to the model - can contain template strings.""" - - role: Required[Literal["user", "assistant", "system", "developer"]] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Literal["message"] - """The type of the message input. Always `message`.""" diff --git a/src/openai/types/vector_store.py b/src/openai/types/vector_store.py index 2af120350e..2473a442d2 100644 --- a/src/openai/types/vector_store.py +++ b/src/openai/types/vector_store.py @@ -5,9 +5,8 @@ from .._models import BaseModel from .shared.metadata import Metadata -from .vector_store_expiration_after import VectorStoreExpirationAfter -__all__ = ["VectorStore", "FileCounts"] +__all__ = ["VectorStore", "FileCounts", "ExpiresAfter"] class FileCounts(BaseModel): @@ -27,6 +26,17 @@ class FileCounts(BaseModel): """The total number of files.""" +class ExpiresAfter(BaseModel): + anchor: Literal["last_active_at"] + """Anchor timestamp after which the expiration policy applies. + + Supported anchors: `last_active_at`. + """ + + days: int + """The number of days after the anchor time that the vector store will expire.""" + + class VectorStore(BaseModel): id: str """The identifier, which can be referenced in API endpoints.""" @@ -65,7 +75,7 @@ class VectorStore(BaseModel): usage_bytes: int """The total number of bytes used by the files in the vector store.""" - expires_after: Optional[VectorStoreExpirationAfter] = None + expires_after: Optional[ExpiresAfter] = None """The expiration policy for a vector store.""" expires_at: Optional[int] = None diff --git a/src/openai/types/vector_store_create_params.py b/src/openai/types/vector_store_create_params.py index dbcedac188..365d0936b1 100644 --- a/src/openai/types/vector_store_create_params.py +++ b/src/openai/types/vector_store_create_params.py @@ -3,13 +3,12 @@ from __future__ import annotations from typing import List, Optional -from typing_extensions import TypedDict +from typing_extensions import Literal, Required, TypedDict from .shared_params.metadata import Metadata from .file_chunking_strategy_param import FileChunkingStrategyParam -from .vector_store_expiration_after_param import VectorStoreExpirationAfterParam -__all__ = ["VectorStoreCreateParams"] +__all__ = ["VectorStoreCreateParams", "ExpiresAfter"] class VectorStoreCreateParams(TypedDict, total=False): @@ -20,7 +19,7 @@ class VectorStoreCreateParams(TypedDict, total=False): non-empty. """ - expires_after: VectorStoreExpirationAfterParam + expires_after: ExpiresAfter """The expiration policy for a vector store.""" file_ids: List[str] @@ -42,3 +41,14 @@ class VectorStoreCreateParams(TypedDict, total=False): name: str """The name of the vector store.""" + + +class ExpiresAfter(TypedDict, total=False): + anchor: Required[Literal["last_active_at"]] + """Anchor timestamp after which the expiration policy applies. + + Supported anchors: `last_active_at`. + """ + + days: Required[int] + """The number of days after the anchor time that the vector store will expire.""" diff --git a/src/openai/types/vector_store_expiration_after.py b/src/openai/types/vector_store_expiration_after.py deleted file mode 100644 index 1d417d526b..0000000000 --- a/src/openai/types/vector_store_expiration_after.py +++ /dev/null @@ -1,18 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["VectorStoreExpirationAfter"] - - -class VectorStoreExpirationAfter(BaseModel): - anchor: Literal["last_active_at"] - """Anchor timestamp after which the expiration policy applies. - - Supported anchors: `last_active_at`. - """ - - days: int - """The number of days after the anchor time that the vector store will expire.""" diff --git a/src/openai/types/vector_store_expiration_after_param.py b/src/openai/types/vector_store_expiration_after_param.py deleted file mode 100644 index 29a008c713..0000000000 --- a/src/openai/types/vector_store_expiration_after_param.py +++ /dev/null @@ -1,18 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["VectorStoreExpirationAfterParam"] - - -class VectorStoreExpirationAfterParam(TypedDict, total=False): - anchor: Required[Literal["last_active_at"]] - """Anchor timestamp after which the expiration policy applies. - - Supported anchors: `last_active_at`. - """ - - days: Required[int] - """The number of days after the anchor time that the vector store will expire.""" diff --git a/src/openai/types/vector_store_update_params.py b/src/openai/types/vector_store_update_params.py index 7c90784dfd..4f6ac63963 100644 --- a/src/openai/types/vector_store_update_params.py +++ b/src/openai/types/vector_store_update_params.py @@ -3,16 +3,15 @@ from __future__ import annotations from typing import Optional -from typing_extensions import TypedDict +from typing_extensions import Literal, Required, TypedDict from .shared_params.metadata import Metadata -from .vector_store_expiration_after_param import VectorStoreExpirationAfterParam -__all__ = ["VectorStoreUpdateParams"] +__all__ = ["VectorStoreUpdateParams", "ExpiresAfter"] class VectorStoreUpdateParams(TypedDict, total=False): - expires_after: Optional[VectorStoreExpirationAfterParam] + expires_after: Optional[ExpiresAfter] """The expiration policy for a vector store.""" metadata: Optional[Metadata] @@ -27,3 +26,14 @@ class VectorStoreUpdateParams(TypedDict, total=False): name: Optional[str] """The name of the vector store.""" + + +class ExpiresAfter(TypedDict, total=False): + anchor: Required[Literal["last_active_at"]] + """Anchor timestamp after which the expiration policy applies. + + Supported anchors: `last_active_at`. + """ + + days: Required[int] + """The number of days after the anchor time that the vector store will expire.""" From e5de7941d6968d1d2042a8fcd2e626e687aff8be Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 16 May 2025 13:44:14 -0400 Subject: [PATCH 334/769] fix: fix create audio transcription endpoint --- src/openai/resources/audio/transcriptions.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/openai/resources/audio/transcriptions.py b/src/openai/resources/audio/transcriptions.py index 9d4f7e9255..bca8210a83 100644 --- a/src/openai/resources/audio/transcriptions.py +++ b/src/openai/resources/audio/transcriptions.py @@ -78,6 +78,7 @@ def create( *, file: FileTypes, model: Union[str, AudioModel], + chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | NotGiven = NOT_GIVEN, include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, response_format: Literal["verbose_json"], language: str | NotGiven = NOT_GIVEN, @@ -98,6 +99,7 @@ def create( *, file: FileTypes, model: Union[str, AudioModel], + chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | NotGiven = NOT_GIVEN, response_format: Literal["text", "srt", "vtt"], include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, language: str | NotGiven = NOT_GIVEN, @@ -374,11 +376,11 @@ async def create( model: Union[str, AudioModel], chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | NotGiven = NOT_GIVEN, include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, - response_format: Union[Literal["json"], NotGiven] = NOT_GIVEN, language: str | NotGiven = NOT_GIVEN, prompt: str | NotGiven = NOT_GIVEN, + response_format: Union[Literal["json"], NotGiven] = NOT_GIVEN, + stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, temperature: float | NotGiven = NOT_GIVEN, - include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, timestamp_granularities: List[Literal["word", "segment"]] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -455,6 +457,7 @@ async def create( *, file: FileTypes, model: Union[str, AudioModel], + chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | NotGiven = NOT_GIVEN, include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, response_format: Literal["verbose_json"], language: str | NotGiven = NOT_GIVEN, @@ -475,6 +478,7 @@ async def create( *, file: FileTypes, model: Union[str, AudioModel], + chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | NotGiven = NOT_GIVEN, include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, response_format: Literal["text", "srt", "vtt"], language: str | NotGiven = NOT_GIVEN, From 66a0b8d4b2864d74a383bd117a5f26053ae9ca60 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 16 May 2025 19:41:25 +0000 Subject: [PATCH 335/769] feat(api): further updates for evals API --- .stats.yml | 4 ++-- src/openai/resources/evals/evals.py | 22 ++++++++++++++----- src/openai/resources/evals/runs/runs.py | 14 +++++++----- .../transcription_session_updated_event.py | 2 +- src/openai/types/eval_create_params.py | 18 ++++++++++----- ...l_stored_completions_data_source_config.py | 4 ++-- ...create_eval_completions_run_data_source.py | 12 +++++++--- ..._eval_completions_run_data_source_param.py | 12 +++++++--- .../create_eval_jsonl_run_data_source.py | 1 + ...create_eval_jsonl_run_data_source_param.py | 1 + src/openai/types/evals/run_cancel_response.py | 18 +++++++-------- src/openai/types/evals/run_create_params.py | 18 +++++++-------- src/openai/types/evals/run_create_response.py | 18 +++++++-------- src/openai/types/evals/run_list_response.py | 18 +++++++-------- .../types/evals/run_retrieve_response.py | 18 +++++++-------- 15 files changed, 107 insertions(+), 73 deletions(-) diff --git a/.stats.yml b/.stats.yml index a3c5d081d4..afa33d93bd 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 101 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-5fa16b9a02985ae06e41be14946a9c325dc672fb014b3c19abca65880c6990e6.yml -openapi_spec_hash: da3e669f65130043b1170048c0727890 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-262e171d0a8150ea1192474d16ba3afdf9a054b399f1a49a9c9b697a3073c136.yml +openapi_spec_hash: 33e00a48df8f94c94f46290c489f132b config_hash: d8d5fda350f6db77c784f35429741a2e diff --git a/src/openai/resources/evals/evals.py b/src/openai/resources/evals/evals.py index c12562a86d..7aba192c51 100644 --- a/src/openai/resources/evals/evals.py +++ b/src/openai/resources/evals/evals.py @@ -74,15 +74,20 @@ def create( ) -> EvalCreateResponse: """ Create the structure of an evaluation that can be used to test a model's - performance. An evaluation is a set of testing criteria and a datasource. After + performance. An evaluation is a set of testing criteria and the config for a + data source, which dictates the schema of the data used in the evaluation. After creating an evaluation, you can run it on different models and model parameters. We support several types of graders and datasources. For more information, see the [Evals guide](https://platform.openai.com/docs/guides/evals). Args: - data_source_config: The configuration for the data source used for the evaluation runs. + data_source_config: The configuration for the data source used for the evaluation runs. Dictates the + schema of the data used in the evaluation. - testing_criteria: A list of graders for all eval runs in this group. + testing_criteria: A list of graders for all eval runs in this group. Graders can reference + variables in the data source using double curly braces notation, like + `{{item.variable_name}}`. To reference the model's output, use the `sample` + namespace (ie, `{{sample.output_text}}`). metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format, and @@ -333,15 +338,20 @@ async def create( ) -> EvalCreateResponse: """ Create the structure of an evaluation that can be used to test a model's - performance. An evaluation is a set of testing criteria and a datasource. After + performance. An evaluation is a set of testing criteria and the config for a + data source, which dictates the schema of the data used in the evaluation. After creating an evaluation, you can run it on different models and model parameters. We support several types of graders and datasources. For more information, see the [Evals guide](https://platform.openai.com/docs/guides/evals). Args: - data_source_config: The configuration for the data source used for the evaluation runs. + data_source_config: The configuration for the data source used for the evaluation runs. Dictates the + schema of the data used in the evaluation. - testing_criteria: A list of graders for all eval runs in this group. + testing_criteria: A list of graders for all eval runs in this group. Graders can reference + variables in the data source using double curly braces notation, like + `{{item.variable_name}}`. To reference the model's output, use the `sample` + namespace (ie, `{{sample.output_text}}`). metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format, and diff --git a/src/openai/resources/evals/runs/runs.py b/src/openai/resources/evals/runs/runs.py index d74c91e3c4..7efc61292c 100644 --- a/src/openai/resources/evals/runs/runs.py +++ b/src/openai/resources/evals/runs/runs.py @@ -72,9 +72,10 @@ def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> RunCreateResponse: - """Create a new evaluation run. - - This is the endpoint that will kick off grading. + """ + Kicks off a new run for a given evaluation, specifying the data source, and what + model configuration to use to test. The datasource will be validated against the + schema specified in the config of the evaluation. Args: data_source: Details about the run's data source. @@ -321,9 +322,10 @@ async def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> RunCreateResponse: - """Create a new evaluation run. - - This is the endpoint that will kick off grading. + """ + Kicks off a new run for a given evaluation, specifying the data source, and what + model configuration to use to test. The datasource will be validated against the + schema specified in the config of the evaluation. Args: data_source: Details about the run's data source. diff --git a/src/openai/types/beta/realtime/transcription_session_updated_event.py b/src/openai/types/beta/realtime/transcription_session_updated_event.py index ffc100bcc2..1f1fbdae14 100644 --- a/src/openai/types/beta/realtime/transcription_session_updated_event.py +++ b/src/openai/types/beta/realtime/transcription_session_updated_event.py @@ -16,7 +16,7 @@ class TranscriptionSessionUpdatedEvent(BaseModel): """A new Realtime transcription session configuration. When a session is created on the server via REST API, the session object also - contains an ephemeral key. Default TTL for keys is one minute. This property is + contains an ephemeral key. Default TTL for keys is 10 minutes. This property is not present when a session is updated via the WebSocket API. """ diff --git a/src/openai/types/eval_create_params.py b/src/openai/types/eval_create_params.py index 8d508a2d8e..20a3765481 100644 --- a/src/openai/types/eval_create_params.py +++ b/src/openai/types/eval_create_params.py @@ -33,10 +33,18 @@ class EvalCreateParams(TypedDict, total=False): data_source_config: Required[DataSourceConfig] - """The configuration for the data source used for the evaluation runs.""" + """The configuration for the data source used for the evaluation runs. + + Dictates the schema of the data used in the evaluation. + """ testing_criteria: Required[Iterable[TestingCriterion]] - """A list of graders for all eval runs in this group.""" + """A list of graders for all eval runs in this group. + + Graders can reference variables in the data source using double curly braces + notation, like `{{item.variable_name}}`. To reference the model's output, use + the `sample` namespace (ie, `{{sample.output_text}}`). + """ metadata: Optional[Metadata] """Set of 16 key-value pairs that can be attached to an object. @@ -75,8 +83,8 @@ class DataSourceConfigLogs(TypedDict, total=False): class DataSourceConfigStoredCompletions(TypedDict, total=False): - type: Required[Literal["stored-completions"]] - """The type of data source. Always `stored-completions`.""" + type: Required[Literal["stored_completions"]] + """The type of data source. Always `stored_completions`.""" metadata: Dict[str, object] """Metadata filters for the stored completions data source.""" @@ -129,7 +137,7 @@ class TestingCriterionLabelModel(TypedDict, total=False): input: Required[Iterable[TestingCriterionLabelModelInput]] """A list of chat messages forming the prompt or context. - May include variable references to the "item" namespace, ie {{item.name}}. + May include variable references to the `item` namespace, ie {{item.name}}. """ labels: Required[List[str]] diff --git a/src/openai/types/eval_stored_completions_data_source_config.py b/src/openai/types/eval_stored_completions_data_source_config.py index 5016f0ae9c..98f86a4719 100644 --- a/src/openai/types/eval_stored_completions_data_source_config.py +++ b/src/openai/types/eval_stored_completions_data_source_config.py @@ -18,8 +18,8 @@ class EvalStoredCompletionsDataSourceConfig(BaseModel): [here](https://json-schema.org/). """ - type: Literal["stored-completions"] - """The type of data source. Always `stored-completions`.""" + type: Literal["stored_completions"] + """The type of data source. Always `stored_completions`.""" metadata: Optional[Metadata] = None """Set of 16 key-value pairs that can be attached to an object. diff --git a/src/openai/types/evals/create_eval_completions_run_data_source.py b/src/openai/types/evals/create_eval_completions_run_data_source.py index 29c687b542..064ef3a310 100644 --- a/src/openai/types/evals/create_eval_completions_run_data_source.py +++ b/src/openai/types/evals/create_eval_completions_run_data_source.py @@ -117,7 +117,7 @@ class InputMessagesTemplate(BaseModel): template: List[InputMessagesTemplateTemplate] """A list of chat messages forming the prompt or context. - May include variable references to the "item" namespace, ie {{item.name}}. + May include variable references to the `item` namespace, ie {{item.name}}. """ type: Literal["template"] @@ -126,7 +126,7 @@ class InputMessagesTemplate(BaseModel): class InputMessagesItemReference(BaseModel): item_reference: str - """A reference to a variable in the "item" namespace. Ie, "item.name" """ + """A reference to a variable in the `item` namespace. Ie, "item.input_trajectory" """ type: Literal["item_reference"] """The type of input messages. Always `item_reference`.""" @@ -153,12 +153,18 @@ class SamplingParams(BaseModel): class CreateEvalCompletionsRunDataSource(BaseModel): source: Source - """A StoredCompletionsRunDataSource configuration describing a set of filters""" + """Determines what populates the `item` namespace in this run's data source.""" type: Literal["completions"] """The type of run data source. Always `completions`.""" input_messages: Optional[InputMessages] = None + """Used when sampling from a model. + + Dictates the structure of the messages passed into the model. Can either be a + reference to a prebuilt trajectory (ie, `item.input_trajectory`), or a template + with variable references to the `item` namespace. + """ model: Optional[str] = None """The name of the model to use for generating completions (e.g. "o3-mini").""" diff --git a/src/openai/types/evals/create_eval_completions_run_data_source_param.py b/src/openai/types/evals/create_eval_completions_run_data_source_param.py index c53064ee27..3fa4c19ad2 100644 --- a/src/openai/types/evals/create_eval_completions_run_data_source_param.py +++ b/src/openai/types/evals/create_eval_completions_run_data_source_param.py @@ -113,7 +113,7 @@ class InputMessagesTemplate(TypedDict, total=False): template: Required[Iterable[InputMessagesTemplateTemplate]] """A list of chat messages forming the prompt or context. - May include variable references to the "item" namespace, ie {{item.name}}. + May include variable references to the `item` namespace, ie {{item.name}}. """ type: Required[Literal["template"]] @@ -122,7 +122,7 @@ class InputMessagesTemplate(TypedDict, total=False): class InputMessagesItemReference(TypedDict, total=False): item_reference: Required[str] - """A reference to a variable in the "item" namespace. Ie, "item.name" """ + """A reference to a variable in the `item` namespace. Ie, "item.input_trajectory" """ type: Required[Literal["item_reference"]] """The type of input messages. Always `item_reference`.""" @@ -147,12 +147,18 @@ class SamplingParams(TypedDict, total=False): class CreateEvalCompletionsRunDataSourceParam(TypedDict, total=False): source: Required[Source] - """A StoredCompletionsRunDataSource configuration describing a set of filters""" + """Determines what populates the `item` namespace in this run's data source.""" type: Required[Literal["completions"]] """The type of run data source. Always `completions`.""" input_messages: InputMessages + """Used when sampling from a model. + + Dictates the structure of the messages passed into the model. Can either be a + reference to a prebuilt trajectory (ie, `item.input_trajectory`), or a template + with variable references to the `item` namespace. + """ model: str """The name of the model to use for generating completions (e.g. "o3-mini").""" diff --git a/src/openai/types/evals/create_eval_jsonl_run_data_source.py b/src/openai/types/evals/create_eval_jsonl_run_data_source.py index d2be56243b..ae36f8c55f 100644 --- a/src/openai/types/evals/create_eval_jsonl_run_data_source.py +++ b/src/openai/types/evals/create_eval_jsonl_run_data_source.py @@ -36,6 +36,7 @@ class SourceFileID(BaseModel): class CreateEvalJSONLRunDataSource(BaseModel): source: Source + """Determines what populates the `item` namespace in the data source.""" type: Literal["jsonl"] """The type of data source. Always `jsonl`.""" diff --git a/src/openai/types/evals/create_eval_jsonl_run_data_source_param.py b/src/openai/types/evals/create_eval_jsonl_run_data_source_param.py index b8ba48a666..217ee36346 100644 --- a/src/openai/types/evals/create_eval_jsonl_run_data_source_param.py +++ b/src/openai/types/evals/create_eval_jsonl_run_data_source_param.py @@ -41,6 +41,7 @@ class SourceFileID(TypedDict, total=False): class CreateEvalJSONLRunDataSourceParam(TypedDict, total=False): source: Required[Source] + """Determines what populates the `item` namespace in the data source.""" type: Required[Literal["jsonl"]] """The type of data source. Always `jsonl`.""" diff --git a/src/openai/types/evals/run_cancel_response.py b/src/openai/types/evals/run_cancel_response.py index 318e7abc35..d3416129af 100644 --- a/src/openai/types/evals/run_cancel_response.py +++ b/src/openai/types/evals/run_cancel_response.py @@ -76,12 +76,6 @@ class DataSourceResponsesSourceResponses(BaseModel): This is a query parameter used to select responses. """ - has_tool_calls: Optional[bool] = None - """Whether the response has tool calls. - - This is a query parameter used to select responses. - """ - instructions_search: Optional[str] = None """Optional string to search the 'instructions' field. @@ -170,7 +164,7 @@ class DataSourceResponsesInputMessagesTemplate(BaseModel): template: List[DataSourceResponsesInputMessagesTemplateTemplate] """A list of chat messages forming the prompt or context. - May include variable references to the "item" namespace, ie {{item.name}}. + May include variable references to the `item` namespace, ie {{item.name}}. """ type: Literal["template"] @@ -179,7 +173,7 @@ class DataSourceResponsesInputMessagesTemplate(BaseModel): class DataSourceResponsesInputMessagesItemReference(BaseModel): item_reference: str - """A reference to a variable in the "item" namespace. Ie, "item.name" """ + """A reference to a variable in the `item` namespace. Ie, "item.name" """ type: Literal["item_reference"] """The type of input messages. Always `item_reference`.""" @@ -207,12 +201,18 @@ class DataSourceResponsesSamplingParams(BaseModel): class DataSourceResponses(BaseModel): source: DataSourceResponsesSource - """A EvalResponsesSource object describing a run data source configuration.""" + """Determines what populates the `item` namespace in this run's data source.""" type: Literal["responses"] """The type of run data source. Always `responses`.""" input_messages: Optional[DataSourceResponsesInputMessages] = None + """Used when sampling from a model. + + Dictates the structure of the messages passed into the model. Can either be a + reference to a prebuilt trajectory (ie, `item.input_trajectory`), or a template + with variable references to the `item` namespace. + """ model: Optional[str] = None """The name of the model to use for generating completions (e.g. "o3-mini").""" diff --git a/src/openai/types/evals/run_create_params.py b/src/openai/types/evals/run_create_params.py index e030224dcb..5aa2398f36 100644 --- a/src/openai/types/evals/run_create_params.py +++ b/src/openai/types/evals/run_create_params.py @@ -88,12 +88,6 @@ class DataSourceCreateEvalResponsesRunDataSourceSourceResponses(TypedDict, total This is a query parameter used to select responses. """ - has_tool_calls: Optional[bool] - """Whether the response has tool calls. - - This is a query parameter used to select responses. - """ - instructions_search: Optional[str] """Optional string to search the 'instructions' field. @@ -187,7 +181,7 @@ class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplate(TypedDict, template: Required[Iterable[DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplate]] """A list of chat messages forming the prompt or context. - May include variable references to the "item" namespace, ie {{item.name}}. + May include variable references to the `item` namespace, ie {{item.name}}. """ type: Required[Literal["template"]] @@ -196,7 +190,7 @@ class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplate(TypedDict, class DataSourceCreateEvalResponsesRunDataSourceInputMessagesItemReference(TypedDict, total=False): item_reference: Required[str] - """A reference to a variable in the "item" namespace. Ie, "item.name" """ + """A reference to a variable in the `item` namespace. Ie, "item.name" """ type: Required[Literal["item_reference"]] """The type of input messages. Always `item_reference`.""" @@ -224,12 +218,18 @@ class DataSourceCreateEvalResponsesRunDataSourceSamplingParams(TypedDict, total= class DataSourceCreateEvalResponsesRunDataSource(TypedDict, total=False): source: Required[DataSourceCreateEvalResponsesRunDataSourceSource] - """A EvalResponsesSource object describing a run data source configuration.""" + """Determines what populates the `item` namespace in this run's data source.""" type: Required[Literal["responses"]] """The type of run data source. Always `responses`.""" input_messages: DataSourceCreateEvalResponsesRunDataSourceInputMessages + """Used when sampling from a model. + + Dictates the structure of the messages passed into the model. Can either be a + reference to a prebuilt trajectory (ie, `item.input_trajectory`), or a template + with variable references to the `item` namespace. + """ model: str """The name of the model to use for generating completions (e.g. "o3-mini").""" diff --git a/src/openai/types/evals/run_create_response.py b/src/openai/types/evals/run_create_response.py index 902e45c9bc..51aed2080f 100644 --- a/src/openai/types/evals/run_create_response.py +++ b/src/openai/types/evals/run_create_response.py @@ -76,12 +76,6 @@ class DataSourceResponsesSourceResponses(BaseModel): This is a query parameter used to select responses. """ - has_tool_calls: Optional[bool] = None - """Whether the response has tool calls. - - This is a query parameter used to select responses. - """ - instructions_search: Optional[str] = None """Optional string to search the 'instructions' field. @@ -170,7 +164,7 @@ class DataSourceResponsesInputMessagesTemplate(BaseModel): template: List[DataSourceResponsesInputMessagesTemplateTemplate] """A list of chat messages forming the prompt or context. - May include variable references to the "item" namespace, ie {{item.name}}. + May include variable references to the `item` namespace, ie {{item.name}}. """ type: Literal["template"] @@ -179,7 +173,7 @@ class DataSourceResponsesInputMessagesTemplate(BaseModel): class DataSourceResponsesInputMessagesItemReference(BaseModel): item_reference: str - """A reference to a variable in the "item" namespace. Ie, "item.name" """ + """A reference to a variable in the `item` namespace. Ie, "item.name" """ type: Literal["item_reference"] """The type of input messages. Always `item_reference`.""" @@ -207,12 +201,18 @@ class DataSourceResponsesSamplingParams(BaseModel): class DataSourceResponses(BaseModel): source: DataSourceResponsesSource - """A EvalResponsesSource object describing a run data source configuration.""" + """Determines what populates the `item` namespace in this run's data source.""" type: Literal["responses"] """The type of run data source. Always `responses`.""" input_messages: Optional[DataSourceResponsesInputMessages] = None + """Used when sampling from a model. + + Dictates the structure of the messages passed into the model. Can either be a + reference to a prebuilt trajectory (ie, `item.input_trajectory`), or a template + with variable references to the `item` namespace. + """ model: Optional[str] = None """The name of the model to use for generating completions (e.g. "o3-mini").""" diff --git a/src/openai/types/evals/run_list_response.py b/src/openai/types/evals/run_list_response.py index 80327aa912..f1d0b01da9 100644 --- a/src/openai/types/evals/run_list_response.py +++ b/src/openai/types/evals/run_list_response.py @@ -76,12 +76,6 @@ class DataSourceResponsesSourceResponses(BaseModel): This is a query parameter used to select responses. """ - has_tool_calls: Optional[bool] = None - """Whether the response has tool calls. - - This is a query parameter used to select responses. - """ - instructions_search: Optional[str] = None """Optional string to search the 'instructions' field. @@ -170,7 +164,7 @@ class DataSourceResponsesInputMessagesTemplate(BaseModel): template: List[DataSourceResponsesInputMessagesTemplateTemplate] """A list of chat messages forming the prompt or context. - May include variable references to the "item" namespace, ie {{item.name}}. + May include variable references to the `item` namespace, ie {{item.name}}. """ type: Literal["template"] @@ -179,7 +173,7 @@ class DataSourceResponsesInputMessagesTemplate(BaseModel): class DataSourceResponsesInputMessagesItemReference(BaseModel): item_reference: str - """A reference to a variable in the "item" namespace. Ie, "item.name" """ + """A reference to a variable in the `item` namespace. Ie, "item.name" """ type: Literal["item_reference"] """The type of input messages. Always `item_reference`.""" @@ -207,12 +201,18 @@ class DataSourceResponsesSamplingParams(BaseModel): class DataSourceResponses(BaseModel): source: DataSourceResponsesSource - """A EvalResponsesSource object describing a run data source configuration.""" + """Determines what populates the `item` namespace in this run's data source.""" type: Literal["responses"] """The type of run data source. Always `responses`.""" input_messages: Optional[DataSourceResponsesInputMessages] = None + """Used when sampling from a model. + + Dictates the structure of the messages passed into the model. Can either be a + reference to a prebuilt trajectory (ie, `item.input_trajectory`), or a template + with variable references to the `item` namespace. + """ model: Optional[str] = None """The name of the model to use for generating completions (e.g. "o3-mini").""" diff --git a/src/openai/types/evals/run_retrieve_response.py b/src/openai/types/evals/run_retrieve_response.py index 9756dcb919..6c5951b4eb 100644 --- a/src/openai/types/evals/run_retrieve_response.py +++ b/src/openai/types/evals/run_retrieve_response.py @@ -76,12 +76,6 @@ class DataSourceResponsesSourceResponses(BaseModel): This is a query parameter used to select responses. """ - has_tool_calls: Optional[bool] = None - """Whether the response has tool calls. - - This is a query parameter used to select responses. - """ - instructions_search: Optional[str] = None """Optional string to search the 'instructions' field. @@ -170,7 +164,7 @@ class DataSourceResponsesInputMessagesTemplate(BaseModel): template: List[DataSourceResponsesInputMessagesTemplateTemplate] """A list of chat messages forming the prompt or context. - May include variable references to the "item" namespace, ie {{item.name}}. + May include variable references to the `item` namespace, ie {{item.name}}. """ type: Literal["template"] @@ -179,7 +173,7 @@ class DataSourceResponsesInputMessagesTemplate(BaseModel): class DataSourceResponsesInputMessagesItemReference(BaseModel): item_reference: str - """A reference to a variable in the "item" namespace. Ie, "item.name" """ + """A reference to a variable in the `item` namespace. Ie, "item.name" """ type: Literal["item_reference"] """The type of input messages. Always `item_reference`.""" @@ -207,12 +201,18 @@ class DataSourceResponsesSamplingParams(BaseModel): class DataSourceResponses(BaseModel): source: DataSourceResponsesSource - """A EvalResponsesSource object describing a run data source configuration.""" + """Determines what populates the `item` namespace in this run's data source.""" type: Literal["responses"] """The type of run data source. Always `responses`.""" input_messages: Optional[DataSourceResponsesInputMessages] = None + """Used when sampling from a model. + + Dictates the structure of the messages passed into the model. Can either be a + reference to a prebuilt trajectory (ie, `item.input_trajectory`), or a template + with variable references to the `item` namespace. + """ model: Optional[str] = None """The name of the model to use for generating completions (e.g. "o3-mini").""" From 5bc730732ddee4a93fd777359c94202ec0db143b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 16 May 2025 19:41:54 +0000 Subject: [PATCH 336/769] release: 1.79.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 f15af035f8..36925cfe97 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.78.1" + ".": "1.79.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index b153f3ef05..9ec3e61533 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,27 @@ # Changelog +## 1.79.0 (2025-05-16) + +Full Changelog: [v1.78.1...v1.79.0](https://github.com/openai/openai-python/compare/v1.78.1...v1.79.0) + +### Features + +* **api:** further updates for evals API ([32c99a6](https://github.com/openai/openai-python/commit/32c99a6f5885d4bf3511a7f06b70000edd274301)) +* **api:** manual updates ([25245e5](https://github.com/openai/openai-python/commit/25245e5e3d0713abfb65b760aee1f12bc61deb41)) +* **api:** responses x eval api ([fd586cb](https://github.com/openai/openai-python/commit/fd586cbdf889c9a5c6b9be177ff02fbfffa3eba5)) +* **api:** Updating Assistants and Evals API schemas ([98ba7d3](https://github.com/openai/openai-python/commit/98ba7d355551213a13803f68d5642eecbb4ffd39)) + + +### Bug Fixes + +* fix create audio transcription endpoint ([e9a89ab](https://github.com/openai/openai-python/commit/e9a89ab7b6387610e433550207a23973b7edda3a)) + + +### Chores + +* **ci:** fix installation instructions ([f26c5fc](https://github.com/openai/openai-python/commit/f26c5fc85d98d700b68cb55c8be5d15983a9aeaf)) +* **ci:** upload sdks to package manager ([861f105](https://github.com/openai/openai-python/commit/861f1055768168ab04987a42efcd32a07bc93542)) + ## 1.78.1 (2025-05-12) Full Changelog: [v1.78.0...v1.78.1](https://github.com/openai/openai-python/compare/v1.78.0...v1.78.1) diff --git a/pyproject.toml b/pyproject.toml index 71c86c38ea..5affe3c483 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.78.1" +version = "1.79.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 9b430dfa8b..77c73cdfd9 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.78.1" # x-release-please-version +__version__ = "1.79.0" # x-release-please-version From 4a81b4eda050ffe2681e31113ed65250d3355aa2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 21 May 2025 11:39:41 -0500 Subject: [PATCH 337/769] release: 1.80.0 (#2367) * codegen metadata * chore(docs): grammar improvements * feat(api): new API tools * release: 1.80.0 --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- .stats.yml | 6 +- CHANGELOG.md | 13 ++ SECURITY.md | 4 +- api.md | 18 ++ pyproject.toml | 2 +- src/openai/_streaming.py | 4 +- src/openai/_version.py | 2 +- src/openai/helpers/local_audio_player.py | 2 +- src/openai/lib/_parsing/_responses.py | 7 + src/openai/lib/streaming/responses/_events.py | 36 ++++ src/openai/resources/audio/transcriptions.py | 2 +- src/openai/resources/responses/responses.py | 28 +++ src/openai/types/responses/__init__.py | 43 +++++ src/openai/types/responses/parsed_response.py | 16 ++ src/openai/types/responses/response.py | 9 +- .../response_code_interpreter_tool_call.py | 5 +- ...sponse_code_interpreter_tool_call_param.py | 54 ++++++ .../types/responses/response_create_params.py | 6 + ...response_image_gen_call_completed_event.py | 18 ++ ...esponse_image_gen_call_generating_event.py | 22 +++ ...sponse_image_gen_call_in_progress_event.py | 21 ++ ...onse_image_gen_call_partial_image_event.py | 30 +++ .../responses/response_input_item_param.py | 173 ++++++++++++++++- .../types/responses/response_input_param.py | 173 ++++++++++++++++- src/openai/types/responses/response_item.py | 181 +++++++++++++++++- ...response_mcp_call_arguments_delta_event.py | 21 ++ .../response_mcp_call_arguments_done_event.py | 21 ++ .../response_mcp_call_completed_event.py | 12 ++ .../response_mcp_call_failed_event.py | 12 ++ .../response_mcp_call_in_progress_event.py | 18 ++ ...response_mcp_list_tools_completed_event.py | 12 ++ .../response_mcp_list_tools_failed_event.py | 12 ++ ...sponse_mcp_list_tools_in_progress_event.py | 12 ++ .../types/responses/response_output_item.py | 146 +++++++++++++- ...onse_output_text_annotation_added_event.py | 27 +++ .../types/responses/response_queued_event.py | 16 ++ .../response_reasoning_delta_event.py | 24 +++ .../response_reasoning_done_event.py | 24 +++ .../response_reasoning_summary_delta_event.py | 27 +++ .../response_reasoning_summary_done_event.py | 24 +++ src/openai/types/responses/response_status.py | 2 +- .../types/responses/response_stream_event.py | 36 ++++ src/openai/types/responses/tool.py | 167 +++++++++++++++- .../types/responses/tool_choice_types.py | 13 +- .../responses/tool_choice_types_param.py | 13 +- src/openai/types/responses/tool_param.py | 174 ++++++++++++++++- tests/api_resources/test_responses.py | 72 +++---- 48 files changed, 1681 insertions(+), 81 deletions(-) create mode 100644 src/openai/types/responses/response_code_interpreter_tool_call_param.py create mode 100644 src/openai/types/responses/response_image_gen_call_completed_event.py create mode 100644 src/openai/types/responses/response_image_gen_call_generating_event.py create mode 100644 src/openai/types/responses/response_image_gen_call_in_progress_event.py create mode 100644 src/openai/types/responses/response_image_gen_call_partial_image_event.py create mode 100644 src/openai/types/responses/response_mcp_call_arguments_delta_event.py create mode 100644 src/openai/types/responses/response_mcp_call_arguments_done_event.py create mode 100644 src/openai/types/responses/response_mcp_call_completed_event.py create mode 100644 src/openai/types/responses/response_mcp_call_failed_event.py create mode 100644 src/openai/types/responses/response_mcp_call_in_progress_event.py create mode 100644 src/openai/types/responses/response_mcp_list_tools_completed_event.py create mode 100644 src/openai/types/responses/response_mcp_list_tools_failed_event.py create mode 100644 src/openai/types/responses/response_mcp_list_tools_in_progress_event.py create mode 100644 src/openai/types/responses/response_output_text_annotation_added_event.py create mode 100644 src/openai/types/responses/response_queued_event.py create mode 100644 src/openai/types/responses/response_reasoning_delta_event.py create mode 100644 src/openai/types/responses/response_reasoning_done_event.py create mode 100644 src/openai/types/responses/response_reasoning_summary_delta_event.py create mode 100644 src/openai/types/responses/response_reasoning_summary_done_event.py diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 36925cfe97..73077f4afb 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.79.0" + ".": "1.80.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index afa33d93bd..4b4f19c91f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 101 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-262e171d0a8150ea1192474d16ba3afdf9a054b399f1a49a9c9b697a3073c136.yml -openapi_spec_hash: 33e00a48df8f94c94f46290c489f132b -config_hash: d8d5fda350f6db77c784f35429741a2e +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-a5651cb97f86d1e2531af6aef8c5230f1ea350560fbae790ca2e481b30a6c217.yml +openapi_spec_hash: 66a5104fd3bb43383cf919225df7a6fd +config_hash: bb657c3fed232a56930035de3aaed936 diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ec3e61533..6517b7d1b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 1.80.0 (2025-05-21) + +Full Changelog: [v1.79.0...v1.80.0](https://github.com/openai/openai-python/compare/v1.79.0...v1.80.0) + +### Features + +* **api:** new API tools ([d36ae52](https://github.com/openai/openai-python/commit/d36ae528d55fe87067c4b8c6b2c947cbad5e5002)) + + +### Chores + +* **docs:** grammar improvements ([e746145](https://github.com/openai/openai-python/commit/e746145a12b5335d8841aff95c91bbbde8bae8e3)) + ## 1.79.0 (2025-05-16) Full Changelog: [v1.78.1...v1.79.0](https://github.com/openai/openai-python/compare/v1.78.1...v1.79.0) diff --git a/SECURITY.md b/SECURITY.md index 3b3bd8a662..4adb0c54f1 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -16,13 +16,13 @@ before making any information public. ## Reporting Non-SDK Related Security Issues If you encounter security issues that are not directly related to SDKs but pertain to the services -or products provided by OpenAI please follow the respective company's security reporting guidelines. +or products provided by OpenAI, please follow the respective company's security reporting guidelines. ### OpenAI Terms and Policies Our Security Policy can be found at [Security Policy URL](https://openai.com/policies/coordinated-vulnerability-disclosure-policy). -Please contact disclosure@openai.com for any questions or concerns regarding security of our services. +Please contact disclosure@openai.com for any questions or concerns regarding the security of our services. --- diff --git a/api.md b/api.md index 496e5548b3..4eb3c09c66 100644 --- a/api.md +++ b/api.md @@ -717,6 +717,10 @@ from openai.types.responses import ( ResponseFunctionToolCallItem, ResponseFunctionToolCallOutputItem, ResponseFunctionWebSearch, + ResponseImageGenCallCompletedEvent, + ResponseImageGenCallGeneratingEvent, + ResponseImageGenCallInProgressEvent, + ResponseImageGenCallPartialImageEvent, ResponseInProgressEvent, ResponseIncludable, ResponseIncompleteEvent, @@ -730,6 +734,14 @@ from openai.types.responses import ( ResponseInputMessageItem, ResponseInputText, ResponseItem, + ResponseMcpCallArgumentsDeltaEvent, + ResponseMcpCallArgumentsDoneEvent, + ResponseMcpCallCompletedEvent, + ResponseMcpCallFailedEvent, + ResponseMcpCallInProgressEvent, + ResponseMcpListToolsCompletedEvent, + ResponseMcpListToolsFailedEvent, + ResponseMcpListToolsInProgressEvent, ResponseOutputAudio, ResponseOutputItem, ResponseOutputItemAddedEvent, @@ -737,7 +749,13 @@ from openai.types.responses import ( ResponseOutputMessage, ResponseOutputRefusal, ResponseOutputText, + ResponseOutputTextAnnotationAddedEvent, + ResponseQueuedEvent, + ResponseReasoningDeltaEvent, + ResponseReasoningDoneEvent, ResponseReasoningItem, + ResponseReasoningSummaryDeltaEvent, + ResponseReasoningSummaryDoneEvent, ResponseReasoningSummaryPartAddedEvent, ResponseReasoningSummaryPartDoneEvent, ResponseReasoningSummaryTextDeltaEvent, diff --git a/pyproject.toml b/pyproject.toml index 5affe3c483..3c3d246a18 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.79.0" +version = "1.80.0" description = "The official Python library for the openai API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/openai/_streaming.py b/src/openai/_streaming.py index 641c3a7a72..f5621f92a7 100644 --- a/src/openai/_streaming.py +++ b/src/openai/_streaming.py @@ -59,7 +59,7 @@ def __stream__(self) -> Iterator[_T]: if sse.data.startswith("[DONE]"): break - if sse.event is None or sse.event.startswith("response.") or sse.event.startswith('transcript.'): + if sse.event is None or sse.event.startswith("response.") or sse.event.startswith("transcript."): data = sse.json() if is_mapping(data) and data.get("error"): message = None @@ -161,7 +161,7 @@ async def __stream__(self) -> AsyncIterator[_T]: if sse.data.startswith("[DONE]"): break - if sse.event is None or sse.event.startswith("response.") or sse.event.startswith('transcript.'): + if sse.event is None or sse.event.startswith("response.") or sse.event.startswith("transcript."): data = sse.json() if is_mapping(data) and data.get("error"): message = None diff --git a/src/openai/_version.py b/src/openai/_version.py index 77c73cdfd9..7bf2bbc038 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.79.0" # x-release-please-version +__version__ = "1.80.0" # x-release-please-version diff --git a/src/openai/helpers/local_audio_player.py b/src/openai/helpers/local_audio_player.py index eed68aa21d..8f12c27a56 100644 --- a/src/openai/helpers/local_audio_player.py +++ b/src/openai/helpers/local_audio_player.py @@ -65,7 +65,7 @@ async def play( if input.dtype == np.int16 and self.dtype == np.float32: audio_content = (input.astype(np.float32) / 32767.0).reshape(-1, self.channels) elif input.dtype == np.float32: - audio_content = cast('npt.NDArray[np.float32]', input) + audio_content = cast("npt.NDArray[np.float32]", input) else: raise ValueError(f"Unsupported dtype: {input.dtype}") else: diff --git a/src/openai/lib/_parsing/_responses.py b/src/openai/lib/_parsing/_responses.py index a189dcf937..235f912405 100644 --- a/src/openai/lib/_parsing/_responses.py +++ b/src/openai/lib/_parsing/_responses.py @@ -103,6 +103,13 @@ def parse_response( or output.type == "file_search_call" or output.type == "web_search_call" or output.type == "reasoning" + or output.type == "mcp_call" + or output.type == "mcp_approval_request" + or output.type == "image_generation_call" + or output.type == "code_interpreter_call" + or output.type == "local_shell_call" + or output.type == "mcp_list_tools" + or output.type == 'exec' ): output_list.append(output) elif TYPE_CHECKING: # type: ignore diff --git a/src/openai/lib/streaming/responses/_events.py b/src/openai/lib/streaming/responses/_events.py index 0cdc5992ee..09b84488b5 100644 --- a/src/openai/lib/streaming/responses/_events.py +++ b/src/openai/lib/streaming/responses/_events.py @@ -9,6 +9,7 @@ ParsedResponse, ResponseErrorEvent, ResponseFailedEvent, + ResponseQueuedEvent, ResponseCreatedEvent, ResponseTextDoneEvent as RawResponseTextDoneEvent, ResponseAudioDoneEvent, @@ -19,22 +20,39 @@ ResponseInProgressEvent, ResponseRefusalDoneEvent, ResponseRefusalDeltaEvent, + ResponseMcpCallFailedEvent, + ResponseReasoningDoneEvent, ResponseOutputItemDoneEvent, + ResponseReasoningDeltaEvent, ResponseContentPartDoneEvent, ResponseOutputItemAddedEvent, ResponseContentPartAddedEvent, + ResponseMcpCallCompletedEvent, + ResponseMcpCallInProgressEvent, + ResponseMcpListToolsFailedEvent, ResponseAudioTranscriptDoneEvent, ResponseTextAnnotationDeltaEvent, ResponseAudioTranscriptDeltaEvent, + ResponseMcpCallArgumentsDoneEvent, + ResponseReasoningSummaryDoneEvent, + ResponseImageGenCallCompletedEvent, + ResponseMcpCallArgumentsDeltaEvent, + ResponseMcpListToolsCompletedEvent, + ResponseReasoningSummaryDeltaEvent, + ResponseImageGenCallGeneratingEvent, + ResponseImageGenCallInProgressEvent, + ResponseMcpListToolsInProgressEvent, ResponseWebSearchCallCompletedEvent, ResponseWebSearchCallSearchingEvent, ResponseFileSearchCallCompletedEvent, ResponseFileSearchCallSearchingEvent, ResponseWebSearchCallInProgressEvent, ResponseFileSearchCallInProgressEvent, + ResponseImageGenCallPartialImageEvent, ResponseReasoningSummaryPartDoneEvent, ResponseReasoningSummaryTextDoneEvent, ResponseFunctionCallArgumentsDoneEvent, + ResponseOutputTextAnnotationAddedEvent, ResponseReasoningSummaryPartAddedEvent, ResponseReasoningSummaryTextDeltaEvent, ResponseFunctionCallArgumentsDeltaEvent as RawResponseFunctionCallArgumentsDeltaEvent, @@ -109,6 +127,24 @@ class ResponseCompletedEvent(RawResponseCompletedEvent, GenericModel, Generic[Te ResponseReasoningSummaryPartDoneEvent, ResponseReasoningSummaryTextDeltaEvent, ResponseReasoningSummaryTextDoneEvent, + ResponseImageGenCallCompletedEvent, + ResponseImageGenCallInProgressEvent, + ResponseImageGenCallGeneratingEvent, + ResponseImageGenCallPartialImageEvent, + ResponseMcpCallCompletedEvent, + ResponseMcpCallArgumentsDeltaEvent, + ResponseMcpCallArgumentsDoneEvent, + ResponseMcpCallFailedEvent, + ResponseMcpCallInProgressEvent, + ResponseMcpListToolsCompletedEvent, + ResponseMcpListToolsFailedEvent, + ResponseMcpListToolsInProgressEvent, + ResponseOutputTextAnnotationAddedEvent, + ResponseQueuedEvent, + ResponseReasoningDeltaEvent, + ResponseReasoningSummaryDeltaEvent, + ResponseReasoningSummaryDoneEvent, + ResponseReasoningDoneEvent, ], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/resources/audio/transcriptions.py b/src/openai/resources/audio/transcriptions.py index bca8210a83..208f6e8b05 100644 --- a/src/openai/resources/audio/transcriptions.py +++ b/src/openai/resources/audio/transcriptions.py @@ -449,7 +449,7 @@ async def create( extra_headers: Send extra headers extra_query: Add additional query parameters to the request - """ + """ @overload async def create( diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index a905bc34b1..ad9576983f 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -77,6 +77,7 @@ def create( *, input: Union[str, ResponseInputParam], model: ResponsesModel, + background: Optional[bool] | NotGiven = NOT_GIVEN, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, @@ -132,6 +133,9 @@ def create( [model guide](https://platform.openai.com/docs/models) to browse and compare available models. + background: Whether to run the model response in the background. + [Learn more](https://platform.openai.com/docs/guides/background). + include: Specify additional output data to include in the model response. Currently supported values are: @@ -267,6 +271,7 @@ def create( input: Union[str, ResponseInputParam], model: ResponsesModel, stream: Literal[True], + background: Optional[bool] | NotGiven = NOT_GIVEN, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, @@ -328,6 +333,9 @@ def create( [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) for more information. + background: Whether to run the model response in the background. + [Learn more](https://platform.openai.com/docs/guides/background). + include: Specify additional output data to include in the model response. Currently supported values are: @@ -456,6 +464,7 @@ def create( input: Union[str, ResponseInputParam], model: ResponsesModel, stream: bool, + background: Optional[bool] | NotGiven = NOT_GIVEN, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, @@ -517,6 +526,9 @@ def create( [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) for more information. + background: Whether to run the model response in the background. + [Learn more](https://platform.openai.com/docs/guides/background). + include: Specify additional output data to include in the model response. Currently supported values are: @@ -644,6 +656,7 @@ def create( *, input: Union[str, ResponseInputParam], model: ResponsesModel, + background: Optional[bool] | NotGiven = NOT_GIVEN, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, @@ -674,6 +687,7 @@ def create( { "input": input, "model": model, + "background": background, "include": include, "instructions": instructions, "max_output_tokens": max_output_tokens, @@ -965,6 +979,7 @@ async def create( *, input: Union[str, ResponseInputParam], model: ResponsesModel, + background: Optional[bool] | NotGiven = NOT_GIVEN, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, @@ -1020,6 +1035,9 @@ async def create( [model guide](https://platform.openai.com/docs/models) to browse and compare available models. + background: Whether to run the model response in the background. + [Learn more](https://platform.openai.com/docs/guides/background). + include: Specify additional output data to include in the model response. Currently supported values are: @@ -1155,6 +1173,7 @@ async def create( input: Union[str, ResponseInputParam], model: ResponsesModel, stream: Literal[True], + background: Optional[bool] | NotGiven = NOT_GIVEN, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, @@ -1216,6 +1235,9 @@ async def create( [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) for more information. + background: Whether to run the model response in the background. + [Learn more](https://platform.openai.com/docs/guides/background). + include: Specify additional output data to include in the model response. Currently supported values are: @@ -1344,6 +1366,7 @@ async def create( input: Union[str, ResponseInputParam], model: ResponsesModel, stream: bool, + background: Optional[bool] | NotGiven = NOT_GIVEN, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, @@ -1405,6 +1428,9 @@ async def create( [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) for more information. + background: Whether to run the model response in the background. + [Learn more](https://platform.openai.com/docs/guides/background). + include: Specify additional output data to include in the model response. Currently supported values are: @@ -1532,6 +1558,7 @@ async def create( *, input: Union[str, ResponseInputParam], model: ResponsesModel, + background: Optional[bool] | NotGiven = NOT_GIVEN, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, @@ -1562,6 +1589,7 @@ async def create( { "input": input, "model": model, + "background": background, "include": include, "instructions": instructions, "max_output_tokens": max_output_tokens, diff --git a/src/openai/types/responses/__init__.py b/src/openai/types/responses/__init__.py index 22fd2a0802..5cb00904f7 100644 --- a/src/openai/types/responses/__init__.py +++ b/src/openai/types/responses/__init__.py @@ -38,6 +38,7 @@ from .response_text_config import ResponseTextConfig as ResponseTextConfig from .tool_choice_function import ToolChoiceFunction as ToolChoiceFunction from .response_failed_event import ResponseFailedEvent as ResponseFailedEvent +from .response_queued_event import ResponseQueuedEvent as ResponseQueuedEvent from .response_stream_event import ResponseStreamEvent as ResponseStreamEvent from .web_search_tool_param import WebSearchToolParam as WebSearchToolParam from .file_search_tool_param import FileSearchToolParam as FileSearchToolParam @@ -75,8 +76,11 @@ from .response_refusal_delta_event import ResponseRefusalDeltaEvent as ResponseRefusalDeltaEvent from .response_output_message_param import ResponseOutputMessageParam as ResponseOutputMessageParam from .response_output_refusal_param import ResponseOutputRefusalParam as ResponseOutputRefusalParam +from .response_reasoning_done_event import ResponseReasoningDoneEvent as ResponseReasoningDoneEvent from .response_reasoning_item_param import ResponseReasoningItemParam as ResponseReasoningItemParam from .response_file_search_tool_call import ResponseFileSearchToolCall as ResponseFileSearchToolCall +from .response_mcp_call_failed_event import ResponseMcpCallFailedEvent as ResponseMcpCallFailedEvent +from .response_reasoning_delta_event import ResponseReasoningDeltaEvent as ResponseReasoningDeltaEvent from .response_output_item_done_event import ResponseOutputItemDoneEvent as ResponseOutputItemDoneEvent from .response_content_part_done_event import ResponseContentPartDoneEvent as ResponseContentPartDoneEvent from .response_function_tool_call_item import ResponseFunctionToolCallItem as ResponseFunctionToolCallItem @@ -85,15 +89,27 @@ from .response_content_part_added_event import ResponseContentPartAddedEvent as ResponseContentPartAddedEvent from .response_format_text_config_param import ResponseFormatTextConfigParam as ResponseFormatTextConfigParam from .response_function_tool_call_param import ResponseFunctionToolCallParam as ResponseFunctionToolCallParam +from .response_mcp_call_completed_event import ResponseMcpCallCompletedEvent as ResponseMcpCallCompletedEvent from .response_function_web_search_param import ResponseFunctionWebSearchParam as ResponseFunctionWebSearchParam from .response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall as ResponseCodeInterpreterToolCall from .response_input_message_content_list import ResponseInputMessageContentList as ResponseInputMessageContentList +from .response_mcp_call_in_progress_event import ResponseMcpCallInProgressEvent as ResponseMcpCallInProgressEvent from .response_audio_transcript_done_event import ResponseAudioTranscriptDoneEvent as ResponseAudioTranscriptDoneEvent from .response_file_search_tool_call_param import ResponseFileSearchToolCallParam as ResponseFileSearchToolCallParam +from .response_mcp_list_tools_failed_event import ResponseMcpListToolsFailedEvent as ResponseMcpListToolsFailedEvent from .response_text_annotation_delta_event import ResponseTextAnnotationDeltaEvent as ResponseTextAnnotationDeltaEvent from .response_audio_transcript_delta_event import ( ResponseAudioTranscriptDeltaEvent as ResponseAudioTranscriptDeltaEvent, ) +from .response_reasoning_summary_done_event import ( + ResponseReasoningSummaryDoneEvent as ResponseReasoningSummaryDoneEvent, +) +from .response_mcp_call_arguments_done_event import ( + ResponseMcpCallArgumentsDoneEvent as ResponseMcpCallArgumentsDoneEvent, +) +from .response_reasoning_summary_delta_event import ( + ResponseReasoningSummaryDeltaEvent as ResponseReasoningSummaryDeltaEvent, +) from .response_computer_tool_call_output_item import ( ResponseComputerToolCallOutputItem as ResponseComputerToolCallOutputItem, ) @@ -103,21 +119,42 @@ from .response_function_tool_call_output_item import ( ResponseFunctionToolCallOutputItem as ResponseFunctionToolCallOutputItem, ) +from .response_image_gen_call_completed_event import ( + ResponseImageGenCallCompletedEvent as ResponseImageGenCallCompletedEvent, +) +from .response_mcp_call_arguments_delta_event import ( + ResponseMcpCallArgumentsDeltaEvent as ResponseMcpCallArgumentsDeltaEvent, +) +from .response_mcp_list_tools_completed_event import ( + ResponseMcpListToolsCompletedEvent as ResponseMcpListToolsCompletedEvent, +) +from .response_image_gen_call_generating_event import ( + ResponseImageGenCallGeneratingEvent as ResponseImageGenCallGeneratingEvent, +) from .response_web_search_call_completed_event import ( ResponseWebSearchCallCompletedEvent as ResponseWebSearchCallCompletedEvent, ) from .response_web_search_call_searching_event import ( ResponseWebSearchCallSearchingEvent as ResponseWebSearchCallSearchingEvent, ) +from .response_code_interpreter_tool_call_param import ( + ResponseCodeInterpreterToolCallParam as ResponseCodeInterpreterToolCallParam, +) from .response_file_search_call_completed_event import ( ResponseFileSearchCallCompletedEvent as ResponseFileSearchCallCompletedEvent, ) from .response_file_search_call_searching_event import ( ResponseFileSearchCallSearchingEvent as ResponseFileSearchCallSearchingEvent, ) +from .response_image_gen_call_in_progress_event import ( + ResponseImageGenCallInProgressEvent as ResponseImageGenCallInProgressEvent, +) from .response_input_message_content_list_param import ( ResponseInputMessageContentListParam as ResponseInputMessageContentListParam, ) +from .response_mcp_list_tools_in_progress_event import ( + ResponseMcpListToolsInProgressEvent as ResponseMcpListToolsInProgressEvent, +) from .response_reasoning_summary_part_done_event import ( ResponseReasoningSummaryPartDoneEvent as ResponseReasoningSummaryPartDoneEvent, ) @@ -133,6 +170,12 @@ from .response_function_call_arguments_done_event import ( ResponseFunctionCallArgumentsDoneEvent as ResponseFunctionCallArgumentsDoneEvent, ) +from .response_image_gen_call_partial_image_event import ( + ResponseImageGenCallPartialImageEvent as ResponseImageGenCallPartialImageEvent, +) +from .response_output_text_annotation_added_event import ( + ResponseOutputTextAnnotationAddedEvent as ResponseOutputTextAnnotationAddedEvent, +) from .response_reasoning_summary_part_added_event import ( ResponseReasoningSummaryPartAddedEvent as ResponseReasoningSummaryPartAddedEvent, ) diff --git a/src/openai/types/responses/parsed_response.py b/src/openai/types/responses/parsed_response.py index 1263dfd648..923e9debba 100644 --- a/src/openai/types/responses/parsed_response.py +++ b/src/openai/types/responses/parsed_response.py @@ -7,6 +7,14 @@ from .response import Response from ..._models import GenericModel from ..._utils._transform import PropertyInfo +from .response_output_item import ( + McpCall, + McpListTools, + LocalShellCall, + McpApprovalRequest, + ImageGenerationCall, + LocalShellCallAction, +) from .response_output_text import ResponseOutputText from .response_output_message import ResponseOutputMessage from .response_output_refusal import ResponseOutputRefusal @@ -15,6 +23,7 @@ from .response_function_tool_call import ResponseFunctionToolCall from .response_function_web_search import ResponseFunctionWebSearch from .response_file_search_tool_call import ResponseFileSearchToolCall +from .response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall __all__ = ["ParsedResponse", "ParsedResponseOutputMessage", "ParsedResponseOutputText"] @@ -55,6 +64,13 @@ class ParsedResponseFunctionToolCall(ResponseFunctionToolCall): ResponseFunctionWebSearch, ResponseComputerToolCall, ResponseReasoningItem, + McpCall, + McpApprovalRequest, + ImageGenerationCall, + LocalShellCall, + LocalShellCallAction, + McpListTools, + ResponseCodeInterpreterToolCall, ], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/responses/response.py b/src/openai/types/responses/response.py index 254f7e204b..14656f5aec 100644 --- a/src/openai/types/responses/response.py +++ b/src/openai/types/responses/response.py @@ -128,6 +128,12 @@ class Response(BaseModel): We generally recommend altering this or `temperature` but not both. """ + background: Optional[bool] = None + """Whether to run the model response in the background. + + [Learn more](https://platform.openai.com/docs/guides/background). + """ + max_output_tokens: Optional[int] = None """ An upper bound for the number of tokens that can be generated for a response, @@ -173,7 +179,8 @@ class Response(BaseModel): status: Optional[ResponseStatus] = None """The status of the response generation. - One of `completed`, `failed`, `in_progress`, or `incomplete`. + One of `completed`, `failed`, `in_progress`, `cancelled`, `queued`, or + `incomplete`. """ text: Optional[ResponseTextConfig] = None diff --git a/src/openai/types/responses/response_code_interpreter_tool_call.py b/src/openai/types/responses/response_code_interpreter_tool_call.py index d5a5057074..762542f398 100644 --- a/src/openai/types/responses/response_code_interpreter_tool_call.py +++ b/src/openai/types/responses/response_code_interpreter_tool_call.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union +from typing import List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias from ..._utils import PropertyInfo @@ -50,3 +50,6 @@ class ResponseCodeInterpreterToolCall(BaseModel): type: Literal["code_interpreter_call"] """The type of the code interpreter tool call. Always `code_interpreter_call`.""" + + container_id: Optional[str] = None + """The ID of the container used to run the code.""" diff --git a/src/openai/types/responses/response_code_interpreter_tool_call_param.py b/src/openai/types/responses/response_code_interpreter_tool_call_param.py new file mode 100644 index 0000000000..be0f909a6a --- /dev/null +++ b/src/openai/types/responses/response_code_interpreter_tool_call_param.py @@ -0,0 +1,54 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +__all__ = ["ResponseCodeInterpreterToolCallParam", "Result", "ResultLogs", "ResultFiles", "ResultFilesFile"] + + +class ResultLogs(TypedDict, total=False): + logs: Required[str] + """The logs of the code interpreter tool call.""" + + type: Required[Literal["logs"]] + """The type of the code interpreter text output. Always `logs`.""" + + +class ResultFilesFile(TypedDict, total=False): + file_id: Required[str] + """The ID of the file.""" + + mime_type: Required[str] + """The MIME type of the file.""" + + +class ResultFiles(TypedDict, total=False): + files: Required[Iterable[ResultFilesFile]] + + type: Required[Literal["files"]] + """The type of the code interpreter file output. Always `files`.""" + + +Result: TypeAlias = Union[ResultLogs, ResultFiles] + + +class ResponseCodeInterpreterToolCallParam(TypedDict, total=False): + id: Required[str] + """The unique ID of the code interpreter tool call.""" + + code: Required[str] + """The code to run.""" + + results: Required[Iterable[Result]] + """The results of the code interpreter tool call.""" + + status: Required[Literal["in_progress", "interpreting", "completed"]] + """The status of the code interpreter tool call.""" + + type: Required[Literal["code_interpreter_call"]] + """The type of the code interpreter tool call. Always `code_interpreter_call`.""" + + container_id: str + """The ID of the container used to run the code.""" diff --git a/src/openai/types/responses/response_create_params.py b/src/openai/types/responses/response_create_params.py index 972d413926..d7bb5817c2 100644 --- a/src/openai/types/responses/response_create_params.py +++ b/src/openai/types/responses/response_create_params.py @@ -46,6 +46,12 @@ class ResponseCreateParamsBase(TypedDict, total=False): available models. """ + background: Optional[bool] + """Whether to run the model response in the background. + + [Learn more](https://platform.openai.com/docs/guides/background). + """ + include: Optional[List[ResponseIncludable]] """Specify additional output data to include in the model response. diff --git a/src/openai/types/responses/response_image_gen_call_completed_event.py b/src/openai/types/responses/response_image_gen_call_completed_event.py new file mode 100644 index 0000000000..fd499f909e --- /dev/null +++ b/src/openai/types/responses/response_image_gen_call_completed_event.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseImageGenCallCompletedEvent"] + + +class ResponseImageGenCallCompletedEvent(BaseModel): + item_id: str + """The unique identifier of the image generation item being processed.""" + + output_index: int + """The index of the output item in the response's output array.""" + + type: Literal["response.image_generation_call.completed"] + """The type of the event. Always 'response.image_generation_call.completed'.""" diff --git a/src/openai/types/responses/response_image_gen_call_generating_event.py b/src/openai/types/responses/response_image_gen_call_generating_event.py new file mode 100644 index 0000000000..6e7e3efe5c --- /dev/null +++ b/src/openai/types/responses/response_image_gen_call_generating_event.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseImageGenCallGeneratingEvent"] + + +class ResponseImageGenCallGeneratingEvent(BaseModel): + item_id: str + """The unique identifier of the image generation item being processed.""" + + output_index: int + """The index of the output item in the response's output array.""" + + type: Literal["response.image_generation_call.generating"] + """The type of the event. Always 'response.image_generation_call.generating'.""" + + sequence_number: Optional[int] = None + """The sequence number of the image generation item being processed.""" diff --git a/src/openai/types/responses/response_image_gen_call_in_progress_event.py b/src/openai/types/responses/response_image_gen_call_in_progress_event.py new file mode 100644 index 0000000000..b36ff5fa47 --- /dev/null +++ b/src/openai/types/responses/response_image_gen_call_in_progress_event.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseImageGenCallInProgressEvent"] + + +class ResponseImageGenCallInProgressEvent(BaseModel): + item_id: str + """The unique identifier of the image generation item being processed.""" + + output_index: int + """The index of the output item in the response's output array.""" + + sequence_number: int + """The sequence number of the image generation item being processed.""" + + type: Literal["response.image_generation_call.in_progress"] + """The type of the event. Always 'response.image_generation_call.in_progress'.""" diff --git a/src/openai/types/responses/response_image_gen_call_partial_image_event.py b/src/openai/types/responses/response_image_gen_call_partial_image_event.py new file mode 100644 index 0000000000..e69c95fb33 --- /dev/null +++ b/src/openai/types/responses/response_image_gen_call_partial_image_event.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseImageGenCallPartialImageEvent"] + + +class ResponseImageGenCallPartialImageEvent(BaseModel): + item_id: str + """The unique identifier of the image generation item being processed.""" + + output_index: int + """The index of the output item in the response's output array.""" + + partial_image_b64: str + """Base64-encoded partial image data, suitable for rendering as an image.""" + + partial_image_index: int + """ + 0-based index for the partial image (backend is 1-based, but this is 0-based for + the user). + """ + + sequence_number: int + """The sequence number of the image generation item being processed.""" + + type: Literal["response.image_generation_call.partial_image"] + """The type of the event. Always 'response.image_generation_call.partial_image'.""" diff --git a/src/openai/types/responses/response_input_item_param.py b/src/openai/types/responses/response_input_item_param.py index 290953a0ef..70cd9116a9 100644 --- a/src/openai/types/responses/response_input_item_param.py +++ b/src/openai/types/responses/response_input_item_param.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Union, Iterable, Optional +from typing import Dict, List, Union, Iterable, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict from .easy_input_message_param import EasyInputMessageParam @@ -12,6 +12,7 @@ from .response_function_tool_call_param import ResponseFunctionToolCallParam from .response_function_web_search_param import ResponseFunctionWebSearchParam from .response_file_search_tool_call_param import ResponseFileSearchToolCallParam +from .response_code_interpreter_tool_call_param import ResponseCodeInterpreterToolCallParam from .response_input_message_content_list_param import ResponseInputMessageContentListParam from .response_computer_tool_call_output_screenshot_param import ResponseComputerToolCallOutputScreenshotParam @@ -21,6 +22,15 @@ "ComputerCallOutput", "ComputerCallOutputAcknowledgedSafetyCheck", "FunctionCallOutput", + "ImageGenerationCall", + "LocalShellCall", + "LocalShellCallAction", + "LocalShellCallOutput", + "McpListTools", + "McpListToolsTool", + "McpApprovalRequest", + "McpApprovalResponse", + "McpCall", "ItemReference", ] @@ -108,6 +118,159 @@ class FunctionCallOutput(TypedDict, total=False): """ +class ImageGenerationCall(TypedDict, total=False): + id: Required[str] + """The unique ID of the image generation call.""" + + result: Required[Optional[str]] + """The generated image encoded in base64.""" + + status: Required[Literal["in_progress", "completed", "generating", "failed"]] + """The status of the image generation call.""" + + type: Required[Literal["image_generation_call"]] + """The type of the image generation call. Always `image_generation_call`.""" + + +class LocalShellCallAction(TypedDict, total=False): + command: Required[List[str]] + """The command to run.""" + + env: Required[Dict[str, str]] + """Environment variables to set for the command.""" + + type: Required[Literal["exec"]] + """The type of the local shell action. Always `exec`.""" + + timeout_ms: Optional[int] + """Optional timeout in milliseconds for the command.""" + + user: Optional[str] + """Optional user to run the command as.""" + + working_directory: Optional[str] + """Optional working directory to run the command in.""" + + +class LocalShellCall(TypedDict, total=False): + id: Required[str] + """The unique ID of the local shell call.""" + + action: Required[LocalShellCallAction] + """Execute a shell command on the server.""" + + call_id: Required[str] + """The unique ID of the local shell tool call generated by the model.""" + + status: Required[Literal["in_progress", "completed", "incomplete"]] + """The status of the local shell call.""" + + type: Required[Literal["local_shell_call"]] + """The type of the local shell call. Always `local_shell_call`.""" + + +class LocalShellCallOutput(TypedDict, total=False): + id: Required[str] + """The unique ID of the local shell tool call generated by the model.""" + + output: Required[str] + """A JSON string of the output of the local shell tool call.""" + + type: Required[Literal["local_shell_call_output"]] + """The type of the local shell tool call output. Always `local_shell_call_output`.""" + + status: Optional[Literal["in_progress", "completed", "incomplete"]] + """The status of the item. One of `in_progress`, `completed`, or `incomplete`.""" + + +class McpListToolsTool(TypedDict, total=False): + input_schema: Required[object] + """The JSON schema describing the tool's input.""" + + name: Required[str] + """The name of the tool.""" + + annotations: Optional[object] + """Additional annotations about the tool.""" + + description: Optional[str] + """The description of the tool.""" + + +class McpListTools(TypedDict, total=False): + id: Required[str] + """The unique ID of the list.""" + + server_label: Required[str] + """The label of the MCP server.""" + + tools: Required[Iterable[McpListToolsTool]] + """The tools available on the server.""" + + type: Required[Literal["mcp_list_tools"]] + """The type of the item. Always `mcp_list_tools`.""" + + error: Optional[str] + """Error message if the server could not list tools.""" + + +class McpApprovalRequest(TypedDict, total=False): + id: Required[str] + """The unique ID of the approval request.""" + + arguments: Required[str] + """A JSON string of arguments for the tool.""" + + name: Required[str] + """The name of the tool to run.""" + + server_label: Required[str] + """The label of the MCP server making the request.""" + + type: Required[Literal["mcp_approval_request"]] + """The type of the item. Always `mcp_approval_request`.""" + + +class McpApprovalResponse(TypedDict, total=False): + approval_request_id: Required[str] + """The ID of the approval request being answered.""" + + approve: Required[bool] + """Whether the request was approved.""" + + type: Required[Literal["mcp_approval_response"]] + """The type of the item. Always `mcp_approval_response`.""" + + id: Optional[str] + """The unique ID of the approval response""" + + reason: Optional[str] + """Optional reason for the decision.""" + + +class McpCall(TypedDict, total=False): + id: Required[str] + """The unique ID of the tool call.""" + + arguments: Required[str] + """A JSON string of the arguments passed to the tool.""" + + name: Required[str] + """The name of the tool that was run.""" + + server_label: Required[str] + """The label of the MCP server running the tool.""" + + type: Required[Literal["mcp_call"]] + """The type of the item. Always `mcp_call`.""" + + error: Optional[str] + """The error from the tool call, if any.""" + + output: Optional[str] + """The output from the tool call.""" + + class ItemReference(TypedDict, total=False): id: Required[str] """The ID of the item to reference.""" @@ -127,5 +290,13 @@ class ItemReference(TypedDict, total=False): ResponseFunctionToolCallParam, FunctionCallOutput, ResponseReasoningItemParam, + ImageGenerationCall, + ResponseCodeInterpreterToolCallParam, + LocalShellCall, + LocalShellCallOutput, + McpListTools, + McpApprovalRequest, + McpApprovalResponse, + McpCall, ItemReference, ] diff --git a/src/openai/types/responses/response_input_param.py b/src/openai/types/responses/response_input_param.py index b24182697a..024998671f 100644 --- a/src/openai/types/responses/response_input_param.py +++ b/src/openai/types/responses/response_input_param.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import List, Union, Iterable, Optional +from typing import Dict, List, Union, Iterable, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict from .easy_input_message_param import EasyInputMessageParam @@ -12,6 +12,7 @@ from .response_function_tool_call_param import ResponseFunctionToolCallParam from .response_function_web_search_param import ResponseFunctionWebSearchParam from .response_file_search_tool_call_param import ResponseFileSearchToolCallParam +from .response_code_interpreter_tool_call_param import ResponseCodeInterpreterToolCallParam from .response_input_message_content_list_param import ResponseInputMessageContentListParam from .response_computer_tool_call_output_screenshot_param import ResponseComputerToolCallOutputScreenshotParam @@ -22,6 +23,15 @@ "ComputerCallOutput", "ComputerCallOutputAcknowledgedSafetyCheck", "FunctionCallOutput", + "ImageGenerationCall", + "LocalShellCall", + "LocalShellCallAction", + "LocalShellCallOutput", + "McpListTools", + "McpListToolsTool", + "McpApprovalRequest", + "McpApprovalResponse", + "McpCall", "ItemReference", ] @@ -109,6 +119,159 @@ class FunctionCallOutput(TypedDict, total=False): """ +class ImageGenerationCall(TypedDict, total=False): + id: Required[str] + """The unique ID of the image generation call.""" + + result: Required[Optional[str]] + """The generated image encoded in base64.""" + + status: Required[Literal["in_progress", "completed", "generating", "failed"]] + """The status of the image generation call.""" + + type: Required[Literal["image_generation_call"]] + """The type of the image generation call. Always `image_generation_call`.""" + + +class LocalShellCallAction(TypedDict, total=False): + command: Required[List[str]] + """The command to run.""" + + env: Required[Dict[str, str]] + """Environment variables to set for the command.""" + + type: Required[Literal["exec"]] + """The type of the local shell action. Always `exec`.""" + + timeout_ms: Optional[int] + """Optional timeout in milliseconds for the command.""" + + user: Optional[str] + """Optional user to run the command as.""" + + working_directory: Optional[str] + """Optional working directory to run the command in.""" + + +class LocalShellCall(TypedDict, total=False): + id: Required[str] + """The unique ID of the local shell call.""" + + action: Required[LocalShellCallAction] + """Execute a shell command on the server.""" + + call_id: Required[str] + """The unique ID of the local shell tool call generated by the model.""" + + status: Required[Literal["in_progress", "completed", "incomplete"]] + """The status of the local shell call.""" + + type: Required[Literal["local_shell_call"]] + """The type of the local shell call. Always `local_shell_call`.""" + + +class LocalShellCallOutput(TypedDict, total=False): + id: Required[str] + """The unique ID of the local shell tool call generated by the model.""" + + output: Required[str] + """A JSON string of the output of the local shell tool call.""" + + type: Required[Literal["local_shell_call_output"]] + """The type of the local shell tool call output. Always `local_shell_call_output`.""" + + status: Optional[Literal["in_progress", "completed", "incomplete"]] + """The status of the item. One of `in_progress`, `completed`, or `incomplete`.""" + + +class McpListToolsTool(TypedDict, total=False): + input_schema: Required[object] + """The JSON schema describing the tool's input.""" + + name: Required[str] + """The name of the tool.""" + + annotations: Optional[object] + """Additional annotations about the tool.""" + + description: Optional[str] + """The description of the tool.""" + + +class McpListTools(TypedDict, total=False): + id: Required[str] + """The unique ID of the list.""" + + server_label: Required[str] + """The label of the MCP server.""" + + tools: Required[Iterable[McpListToolsTool]] + """The tools available on the server.""" + + type: Required[Literal["mcp_list_tools"]] + """The type of the item. Always `mcp_list_tools`.""" + + error: Optional[str] + """Error message if the server could not list tools.""" + + +class McpApprovalRequest(TypedDict, total=False): + id: Required[str] + """The unique ID of the approval request.""" + + arguments: Required[str] + """A JSON string of arguments for the tool.""" + + name: Required[str] + """The name of the tool to run.""" + + server_label: Required[str] + """The label of the MCP server making the request.""" + + type: Required[Literal["mcp_approval_request"]] + """The type of the item. Always `mcp_approval_request`.""" + + +class McpApprovalResponse(TypedDict, total=False): + approval_request_id: Required[str] + """The ID of the approval request being answered.""" + + approve: Required[bool] + """Whether the request was approved.""" + + type: Required[Literal["mcp_approval_response"]] + """The type of the item. Always `mcp_approval_response`.""" + + id: Optional[str] + """The unique ID of the approval response""" + + reason: Optional[str] + """Optional reason for the decision.""" + + +class McpCall(TypedDict, total=False): + id: Required[str] + """The unique ID of the tool call.""" + + arguments: Required[str] + """A JSON string of the arguments passed to the tool.""" + + name: Required[str] + """The name of the tool that was run.""" + + server_label: Required[str] + """The label of the MCP server running the tool.""" + + type: Required[Literal["mcp_call"]] + """The type of the item. Always `mcp_call`.""" + + error: Optional[str] + """The error from the tool call, if any.""" + + output: Optional[str] + """The output from the tool call.""" + + class ItemReference(TypedDict, total=False): id: Required[str] """The ID of the item to reference.""" @@ -128,6 +291,14 @@ class ItemReference(TypedDict, total=False): ResponseFunctionToolCallParam, FunctionCallOutput, ResponseReasoningItemParam, + ImageGenerationCall, + ResponseCodeInterpreterToolCallParam, + LocalShellCall, + LocalShellCallOutput, + McpListTools, + McpApprovalRequest, + McpApprovalResponse, + McpCall, ItemReference, ] diff --git a/src/openai/types/responses/response_item.py b/src/openai/types/responses/response_item.py index dc8d67d0f2..cba89390ed 100644 --- a/src/openai/types/responses/response_item.py +++ b/src/openai/types/responses/response_item.py @@ -1,19 +1,186 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Union -from typing_extensions import Annotated, TypeAlias +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias from ..._utils import PropertyInfo +from ..._models import BaseModel from .response_output_message import ResponseOutputMessage from .response_computer_tool_call import ResponseComputerToolCall from .response_input_message_item import ResponseInputMessageItem from .response_function_web_search import ResponseFunctionWebSearch from .response_file_search_tool_call import ResponseFileSearchToolCall from .response_function_tool_call_item import ResponseFunctionToolCallItem +from .response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall from .response_computer_tool_call_output_item import ResponseComputerToolCallOutputItem from .response_function_tool_call_output_item import ResponseFunctionToolCallOutputItem -__all__ = ["ResponseItem"] +__all__ = [ + "ResponseItem", + "ImageGenerationCall", + "LocalShellCall", + "LocalShellCallAction", + "LocalShellCallOutput", + "McpListTools", + "McpListToolsTool", + "McpApprovalRequest", + "McpApprovalResponse", + "McpCall", +] + + +class ImageGenerationCall(BaseModel): + id: str + """The unique ID of the image generation call.""" + + result: Optional[str] = None + """The generated image encoded in base64.""" + + status: Literal["in_progress", "completed", "generating", "failed"] + """The status of the image generation call.""" + + type: Literal["image_generation_call"] + """The type of the image generation call. Always `image_generation_call`.""" + + +class LocalShellCallAction(BaseModel): + command: List[str] + """The command to run.""" + + env: Dict[str, str] + """Environment variables to set for the command.""" + + type: Literal["exec"] + """The type of the local shell action. Always `exec`.""" + + timeout_ms: Optional[int] = None + """Optional timeout in milliseconds for the command.""" + + user: Optional[str] = None + """Optional user to run the command as.""" + + working_directory: Optional[str] = None + """Optional working directory to run the command in.""" + + +class LocalShellCall(BaseModel): + id: str + """The unique ID of the local shell call.""" + + action: LocalShellCallAction + """Execute a shell command on the server.""" + + call_id: str + """The unique ID of the local shell tool call generated by the model.""" + + status: Literal["in_progress", "completed", "incomplete"] + """The status of the local shell call.""" + + type: Literal["local_shell_call"] + """The type of the local shell call. Always `local_shell_call`.""" + + +class LocalShellCallOutput(BaseModel): + id: str + """The unique ID of the local shell tool call generated by the model.""" + + output: str + """A JSON string of the output of the local shell tool call.""" + + type: Literal["local_shell_call_output"] + """The type of the local shell tool call output. Always `local_shell_call_output`.""" + + status: Optional[Literal["in_progress", "completed", "incomplete"]] = None + """The status of the item. One of `in_progress`, `completed`, or `incomplete`.""" + + +class McpListToolsTool(BaseModel): + input_schema: object + """The JSON schema describing the tool's input.""" + + name: str + """The name of the tool.""" + + annotations: Optional[object] = None + """Additional annotations about the tool.""" + + description: Optional[str] = None + """The description of the tool.""" + + +class McpListTools(BaseModel): + id: str + """The unique ID of the list.""" + + server_label: str + """The label of the MCP server.""" + + tools: List[McpListToolsTool] + """The tools available on the server.""" + + type: Literal["mcp_list_tools"] + """The type of the item. Always `mcp_list_tools`.""" + + error: Optional[str] = None + """Error message if the server could not list tools.""" + + +class McpApprovalRequest(BaseModel): + id: str + """The unique ID of the approval request.""" + + arguments: str + """A JSON string of arguments for the tool.""" + + name: str + """The name of the tool to run.""" + + server_label: str + """The label of the MCP server making the request.""" + + type: Literal["mcp_approval_request"] + """The type of the item. Always `mcp_approval_request`.""" + + +class McpApprovalResponse(BaseModel): + id: str + """The unique ID of the approval response""" + + approval_request_id: str + """The ID of the approval request being answered.""" + + approve: bool + """Whether the request was approved.""" + + type: Literal["mcp_approval_response"] + """The type of the item. Always `mcp_approval_response`.""" + + reason: Optional[str] = None + """Optional reason for the decision.""" + + +class McpCall(BaseModel): + id: str + """The unique ID of the tool call.""" + + arguments: str + """A JSON string of the arguments passed to the tool.""" + + name: str + """The name of the tool that was run.""" + + server_label: str + """The label of the MCP server running the tool.""" + + type: Literal["mcp_call"] + """The type of the item. Always `mcp_call`.""" + + error: Optional[str] = None + """The error from the tool call, if any.""" + + output: Optional[str] = None + """The output from the tool call.""" + ResponseItem: TypeAlias = Annotated[ Union[ @@ -25,6 +192,14 @@ ResponseFunctionWebSearch, ResponseFunctionToolCallItem, ResponseFunctionToolCallOutputItem, + ImageGenerationCall, + ResponseCodeInterpreterToolCall, + LocalShellCall, + LocalShellCallOutput, + McpListTools, + McpApprovalRequest, + McpApprovalResponse, + McpCall, ], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/responses/response_mcp_call_arguments_delta_event.py b/src/openai/types/responses/response_mcp_call_arguments_delta_event.py new file mode 100644 index 0000000000..ad6738a3b8 --- /dev/null +++ b/src/openai/types/responses/response_mcp_call_arguments_delta_event.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseMcpCallArgumentsDeltaEvent"] + + +class ResponseMcpCallArgumentsDeltaEvent(BaseModel): + delta: object + """The partial update to the arguments for the MCP tool call.""" + + item_id: str + """The unique identifier of the MCP tool call item being processed.""" + + output_index: int + """The index of the output item in the response's output array.""" + + type: Literal["response.mcp_call.arguments_delta"] + """The type of the event. Always 'response.mcp_call.arguments_delta'.""" diff --git a/src/openai/types/responses/response_mcp_call_arguments_done_event.py b/src/openai/types/responses/response_mcp_call_arguments_done_event.py new file mode 100644 index 0000000000..4095cedb0f --- /dev/null +++ b/src/openai/types/responses/response_mcp_call_arguments_done_event.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseMcpCallArgumentsDoneEvent"] + + +class ResponseMcpCallArgumentsDoneEvent(BaseModel): + arguments: object + """The finalized arguments for the MCP tool call.""" + + item_id: str + """The unique identifier of the MCP tool call item being processed.""" + + output_index: int + """The index of the output item in the response's output array.""" + + type: Literal["response.mcp_call.arguments_done"] + """The type of the event. Always 'response.mcp_call.arguments_done'.""" diff --git a/src/openai/types/responses/response_mcp_call_completed_event.py b/src/openai/types/responses/response_mcp_call_completed_event.py new file mode 100644 index 0000000000..63b1b65b31 --- /dev/null +++ b/src/openai/types/responses/response_mcp_call_completed_event.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseMcpCallCompletedEvent"] + + +class ResponseMcpCallCompletedEvent(BaseModel): + type: Literal["response.mcp_call.completed"] + """The type of the event. Always 'response.mcp_call.completed'.""" diff --git a/src/openai/types/responses/response_mcp_call_failed_event.py b/src/openai/types/responses/response_mcp_call_failed_event.py new file mode 100644 index 0000000000..1f94f4d17e --- /dev/null +++ b/src/openai/types/responses/response_mcp_call_failed_event.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseMcpCallFailedEvent"] + + +class ResponseMcpCallFailedEvent(BaseModel): + type: Literal["response.mcp_call.failed"] + """The type of the event. Always 'response.mcp_call.failed'.""" diff --git a/src/openai/types/responses/response_mcp_call_in_progress_event.py b/src/openai/types/responses/response_mcp_call_in_progress_event.py new file mode 100644 index 0000000000..a90508a13c --- /dev/null +++ b/src/openai/types/responses/response_mcp_call_in_progress_event.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseMcpCallInProgressEvent"] + + +class ResponseMcpCallInProgressEvent(BaseModel): + item_id: str + """The unique identifier of the MCP tool call item being processed.""" + + output_index: int + """The index of the output item in the response's output array.""" + + type: Literal["response.mcp_call.in_progress"] + """The type of the event. Always 'response.mcp_call.in_progress'.""" diff --git a/src/openai/types/responses/response_mcp_list_tools_completed_event.py b/src/openai/types/responses/response_mcp_list_tools_completed_event.py new file mode 100644 index 0000000000..c6a921b5bc --- /dev/null +++ b/src/openai/types/responses/response_mcp_list_tools_completed_event.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseMcpListToolsCompletedEvent"] + + +class ResponseMcpListToolsCompletedEvent(BaseModel): + type: Literal["response.mcp_list_tools.completed"] + """The type of the event. Always 'response.mcp_list_tools.completed'.""" diff --git a/src/openai/types/responses/response_mcp_list_tools_failed_event.py b/src/openai/types/responses/response_mcp_list_tools_failed_event.py new file mode 100644 index 0000000000..639a2356db --- /dev/null +++ b/src/openai/types/responses/response_mcp_list_tools_failed_event.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseMcpListToolsFailedEvent"] + + +class ResponseMcpListToolsFailedEvent(BaseModel): + type: Literal["response.mcp_list_tools.failed"] + """The type of the event. Always 'response.mcp_list_tools.failed'.""" diff --git a/src/openai/types/responses/response_mcp_list_tools_in_progress_event.py b/src/openai/types/responses/response_mcp_list_tools_in_progress_event.py new file mode 100644 index 0000000000..41c2334fee --- /dev/null +++ b/src/openai/types/responses/response_mcp_list_tools_in_progress_event.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseMcpListToolsInProgressEvent"] + + +class ResponseMcpListToolsInProgressEvent(BaseModel): + type: Literal["response.mcp_list_tools.in_progress"] + """The type of the event. Always 'response.mcp_list_tools.in_progress'.""" diff --git a/src/openai/types/responses/response_output_item.py b/src/openai/types/responses/response_output_item.py index f1e9693195..62f8f6fb3f 100644 --- a/src/openai/types/responses/response_output_item.py +++ b/src/openai/types/responses/response_output_item.py @@ -1,17 +1,151 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Union -from typing_extensions import Annotated, TypeAlias +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias from ..._utils import PropertyInfo +from ..._models import BaseModel from .response_output_message import ResponseOutputMessage from .response_reasoning_item import ResponseReasoningItem from .response_computer_tool_call import ResponseComputerToolCall from .response_function_tool_call import ResponseFunctionToolCall from .response_function_web_search import ResponseFunctionWebSearch from .response_file_search_tool_call import ResponseFileSearchToolCall +from .response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall + +__all__ = [ + "ResponseOutputItem", + "ImageGenerationCall", + "LocalShellCall", + "LocalShellCallAction", + "McpCall", + "McpListTools", + "McpListToolsTool", + "McpApprovalRequest", +] + + +class ImageGenerationCall(BaseModel): + id: str + """The unique ID of the image generation call.""" + + result: Optional[str] = None + """The generated image encoded in base64.""" + + status: Literal["in_progress", "completed", "generating", "failed"] + """The status of the image generation call.""" + + type: Literal["image_generation_call"] + """The type of the image generation call. Always `image_generation_call`.""" + + +class LocalShellCallAction(BaseModel): + command: List[str] + """The command to run.""" + + env: Dict[str, str] + """Environment variables to set for the command.""" + + type: Literal["exec"] + """The type of the local shell action. Always `exec`.""" + + timeout_ms: Optional[int] = None + """Optional timeout in milliseconds for the command.""" + + user: Optional[str] = None + """Optional user to run the command as.""" + + working_directory: Optional[str] = None + """Optional working directory to run the command in.""" + + +class LocalShellCall(BaseModel): + id: str + """The unique ID of the local shell call.""" + + action: LocalShellCallAction + """Execute a shell command on the server.""" + + call_id: str + """The unique ID of the local shell tool call generated by the model.""" + + status: Literal["in_progress", "completed", "incomplete"] + """The status of the local shell call.""" + + type: Literal["local_shell_call"] + """The type of the local shell call. Always `local_shell_call`.""" + + +class McpCall(BaseModel): + id: str + """The unique ID of the tool call.""" + + arguments: str + """A JSON string of the arguments passed to the tool.""" + + name: str + """The name of the tool that was run.""" + + server_label: str + """The label of the MCP server running the tool.""" + + type: Literal["mcp_call"] + """The type of the item. Always `mcp_call`.""" + + error: Optional[str] = None + """The error from the tool call, if any.""" + + output: Optional[str] = None + """The output from the tool call.""" + + +class McpListToolsTool(BaseModel): + input_schema: object + """The JSON schema describing the tool's input.""" + + name: str + """The name of the tool.""" + + annotations: Optional[object] = None + """Additional annotations about the tool.""" + + description: Optional[str] = None + """The description of the tool.""" + + +class McpListTools(BaseModel): + id: str + """The unique ID of the list.""" + + server_label: str + """The label of the MCP server.""" + + tools: List[McpListToolsTool] + """The tools available on the server.""" + + type: Literal["mcp_list_tools"] + """The type of the item. Always `mcp_list_tools`.""" + + error: Optional[str] = None + """Error message if the server could not list tools.""" + + +class McpApprovalRequest(BaseModel): + id: str + """The unique ID of the approval request.""" + + arguments: str + """A JSON string of arguments for the tool.""" + + name: str + """The name of the tool to run.""" + + server_label: str + """The label of the MCP server making the request.""" + + type: Literal["mcp_approval_request"] + """The type of the item. Always `mcp_approval_request`.""" -__all__ = ["ResponseOutputItem"] ResponseOutputItem: TypeAlias = Annotated[ Union[ @@ -21,6 +155,12 @@ ResponseFunctionWebSearch, ResponseComputerToolCall, ResponseReasoningItem, + ImageGenerationCall, + ResponseCodeInterpreterToolCall, + LocalShellCall, + McpCall, + McpListTools, + McpApprovalRequest, ], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/responses/response_output_text_annotation_added_event.py b/src/openai/types/responses/response_output_text_annotation_added_event.py new file mode 100644 index 0000000000..8e9e340b6b --- /dev/null +++ b/src/openai/types/responses/response_output_text_annotation_added_event.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseOutputTextAnnotationAddedEvent"] + + +class ResponseOutputTextAnnotationAddedEvent(BaseModel): + annotation: object + """The annotation object being added. (See annotation schema for details.)""" + + annotation_index: int + """The index of the annotation within the content part.""" + + content_index: int + """The index of the content part within the output item.""" + + item_id: str + """The unique identifier of the item to which the annotation is being added.""" + + output_index: int + """The index of the output item in the response's output array.""" + + type: Literal["response.output_text_annotation.added"] + """The type of the event. Always 'response.output_text_annotation.added'.""" diff --git a/src/openai/types/responses/response_queued_event.py b/src/openai/types/responses/response_queued_event.py new file mode 100644 index 0000000000..90981d60d6 --- /dev/null +++ b/src/openai/types/responses/response_queued_event.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from .response import Response +from ..._models import BaseModel + +__all__ = ["ResponseQueuedEvent"] + + +class ResponseQueuedEvent(BaseModel): + response: Response + """The full response object that is queued.""" + + type: Literal["response.queued"] + """The type of the event. Always 'response.queued'.""" diff --git a/src/openai/types/responses/response_reasoning_delta_event.py b/src/openai/types/responses/response_reasoning_delta_event.py new file mode 100644 index 0000000000..5520c45c73 --- /dev/null +++ b/src/openai/types/responses/response_reasoning_delta_event.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseReasoningDeltaEvent"] + + +class ResponseReasoningDeltaEvent(BaseModel): + content_index: int + """The index of the reasoning content part within the output item.""" + + delta: object + """The partial update to the reasoning content.""" + + item_id: str + """The unique identifier of the item for which reasoning is being updated.""" + + output_index: int + """The index of the output item in the response's output array.""" + + type: Literal["response.reasoning.delta"] + """The type of the event. Always 'response.reasoning.delta'.""" diff --git a/src/openai/types/responses/response_reasoning_done_event.py b/src/openai/types/responses/response_reasoning_done_event.py new file mode 100644 index 0000000000..8b059f469f --- /dev/null +++ b/src/openai/types/responses/response_reasoning_done_event.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseReasoningDoneEvent"] + + +class ResponseReasoningDoneEvent(BaseModel): + content_index: int + """The index of the reasoning content part within the output item.""" + + item_id: str + """The unique identifier of the item for which reasoning is finalized.""" + + output_index: int + """The index of the output item in the response's output array.""" + + text: str + """The finalized reasoning text.""" + + type: Literal["response.reasoning.done"] + """The type of the event. Always 'response.reasoning.done'.""" diff --git a/src/openai/types/responses/response_reasoning_summary_delta_event.py b/src/openai/types/responses/response_reasoning_summary_delta_event.py new file mode 100644 index 0000000000..1f52d042af --- /dev/null +++ b/src/openai/types/responses/response_reasoning_summary_delta_event.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseReasoningSummaryDeltaEvent"] + + +class ResponseReasoningSummaryDeltaEvent(BaseModel): + delta: object + """The partial update to the reasoning summary content.""" + + item_id: str + """ + The unique identifier of the item for which the reasoning summary is being + updated. + """ + + output_index: int + """The index of the output item in the response's output array.""" + + summary_index: int + """The index of the summary part within the output item.""" + + type: Literal["response.reasoning_summary.delta"] + """The type of the event. Always 'response.reasoning_summary.delta'.""" diff --git a/src/openai/types/responses/response_reasoning_summary_done_event.py b/src/openai/types/responses/response_reasoning_summary_done_event.py new file mode 100644 index 0000000000..f3f9f5428c --- /dev/null +++ b/src/openai/types/responses/response_reasoning_summary_done_event.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseReasoningSummaryDoneEvent"] + + +class ResponseReasoningSummaryDoneEvent(BaseModel): + item_id: str + """The unique identifier of the item for which the reasoning summary is finalized.""" + + output_index: int + """The index of the output item in the response's output array.""" + + summary_index: int + """The index of the summary part within the output item.""" + + text: str + """The finalized reasoning summary text.""" + + type: Literal["response.reasoning_summary.done"] + """The type of the event. Always 'response.reasoning_summary.done'.""" diff --git a/src/openai/types/responses/response_status.py b/src/openai/types/responses/response_status.py index 934d17cda3..a7887b92d2 100644 --- a/src/openai/types/responses/response_status.py +++ b/src/openai/types/responses/response_status.py @@ -4,4 +4,4 @@ __all__ = ["ResponseStatus"] -ResponseStatus: TypeAlias = Literal["completed", "failed", "in_progress", "incomplete"] +ResponseStatus: TypeAlias = Literal["completed", "failed", "in_progress", "cancelled", "queued", "incomplete"] diff --git a/src/openai/types/responses/response_stream_event.py b/src/openai/types/responses/response_stream_event.py index 07c18bd217..e6e59a760a 100644 --- a/src/openai/types/responses/response_stream_event.py +++ b/src/openai/types/responses/response_stream_event.py @@ -6,6 +6,7 @@ from ..._utils import PropertyInfo from .response_error_event import ResponseErrorEvent from .response_failed_event import ResponseFailedEvent +from .response_queued_event import ResponseQueuedEvent from .response_created_event import ResponseCreatedEvent from .response_completed_event import ResponseCompletedEvent from .response_text_done_event import ResponseTextDoneEvent @@ -16,22 +17,39 @@ from .response_in_progress_event import ResponseInProgressEvent from .response_refusal_done_event import ResponseRefusalDoneEvent from .response_refusal_delta_event import ResponseRefusalDeltaEvent +from .response_reasoning_done_event import ResponseReasoningDoneEvent +from .response_mcp_call_failed_event import ResponseMcpCallFailedEvent +from .response_reasoning_delta_event import ResponseReasoningDeltaEvent from .response_output_item_done_event import ResponseOutputItemDoneEvent from .response_content_part_done_event import ResponseContentPartDoneEvent from .response_output_item_added_event import ResponseOutputItemAddedEvent from .response_content_part_added_event import ResponseContentPartAddedEvent +from .response_mcp_call_completed_event import ResponseMcpCallCompletedEvent +from .response_mcp_call_in_progress_event import ResponseMcpCallInProgressEvent from .response_audio_transcript_done_event import ResponseAudioTranscriptDoneEvent +from .response_mcp_list_tools_failed_event import ResponseMcpListToolsFailedEvent from .response_text_annotation_delta_event import ResponseTextAnnotationDeltaEvent from .response_audio_transcript_delta_event import ResponseAudioTranscriptDeltaEvent +from .response_reasoning_summary_done_event import ResponseReasoningSummaryDoneEvent +from .response_mcp_call_arguments_done_event import ResponseMcpCallArgumentsDoneEvent +from .response_reasoning_summary_delta_event import ResponseReasoningSummaryDeltaEvent +from .response_image_gen_call_completed_event import ResponseImageGenCallCompletedEvent +from .response_mcp_call_arguments_delta_event import ResponseMcpCallArgumentsDeltaEvent +from .response_mcp_list_tools_completed_event import ResponseMcpListToolsCompletedEvent +from .response_image_gen_call_generating_event import ResponseImageGenCallGeneratingEvent from .response_web_search_call_completed_event import ResponseWebSearchCallCompletedEvent from .response_web_search_call_searching_event import ResponseWebSearchCallSearchingEvent from .response_file_search_call_completed_event import ResponseFileSearchCallCompletedEvent from .response_file_search_call_searching_event import ResponseFileSearchCallSearchingEvent +from .response_image_gen_call_in_progress_event import ResponseImageGenCallInProgressEvent +from .response_mcp_list_tools_in_progress_event import ResponseMcpListToolsInProgressEvent from .response_reasoning_summary_part_done_event import ResponseReasoningSummaryPartDoneEvent from .response_reasoning_summary_text_done_event import ResponseReasoningSummaryTextDoneEvent from .response_web_search_call_in_progress_event import ResponseWebSearchCallInProgressEvent from .response_file_search_call_in_progress_event import ResponseFileSearchCallInProgressEvent from .response_function_call_arguments_done_event import ResponseFunctionCallArgumentsDoneEvent +from .response_image_gen_call_partial_image_event import ResponseImageGenCallPartialImageEvent +from .response_output_text_annotation_added_event import ResponseOutputTextAnnotationAddedEvent from .response_reasoning_summary_part_added_event import ResponseReasoningSummaryPartAddedEvent from .response_reasoning_summary_text_delta_event import ResponseReasoningSummaryTextDeltaEvent from .response_function_call_arguments_delta_event import ResponseFunctionCallArgumentsDeltaEvent @@ -81,6 +99,24 @@ ResponseWebSearchCallCompletedEvent, ResponseWebSearchCallInProgressEvent, ResponseWebSearchCallSearchingEvent, + ResponseImageGenCallCompletedEvent, + ResponseImageGenCallGeneratingEvent, + ResponseImageGenCallInProgressEvent, + ResponseImageGenCallPartialImageEvent, + ResponseMcpCallArgumentsDeltaEvent, + ResponseMcpCallArgumentsDoneEvent, + ResponseMcpCallCompletedEvent, + ResponseMcpCallFailedEvent, + ResponseMcpCallInProgressEvent, + ResponseMcpListToolsCompletedEvent, + ResponseMcpListToolsFailedEvent, + ResponseMcpListToolsInProgressEvent, + ResponseOutputTextAnnotationAddedEvent, + ResponseQueuedEvent, + ResponseReasoningDeltaEvent, + ResponseReasoningDoneEvent, + ResponseReasoningSummaryDeltaEvent, + ResponseReasoningSummaryDoneEvent, ], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/responses/tool.py b/src/openai/types/responses/tool.py index d96abdbe5a..0d80cdc89d 100644 --- a/src/openai/types/responses/tool.py +++ b/src/openai/types/responses/tool.py @@ -1,16 +1,175 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Union -from typing_extensions import Annotated, TypeAlias +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias from ..._utils import PropertyInfo +from ..._models import BaseModel from .computer_tool import ComputerTool from .function_tool import FunctionTool from .web_search_tool import WebSearchTool from .file_search_tool import FileSearchTool -__all__ = ["Tool"] +__all__ = [ + "Tool", + "Mcp", + "McpAllowedTools", + "McpAllowedToolsMcpAllowedToolsFilter", + "McpRequireApproval", + "McpRequireApprovalMcpToolApprovalFilter", + "McpRequireApprovalMcpToolApprovalFilterAlways", + "McpRequireApprovalMcpToolApprovalFilterNever", + "CodeInterpreter", + "CodeInterpreterContainer", + "CodeInterpreterContainerCodeInterpreterToolAuto", + "ImageGeneration", + "ImageGenerationInputImageMask", + "LocalShell", +] + + +class McpAllowedToolsMcpAllowedToolsFilter(BaseModel): + tool_names: Optional[List[str]] = None + """List of allowed tool names.""" + + +McpAllowedTools: TypeAlias = Union[List[str], McpAllowedToolsMcpAllowedToolsFilter, None] + + +class McpRequireApprovalMcpToolApprovalFilterAlways(BaseModel): + tool_names: Optional[List[str]] = None + """List of tools that require approval.""" + + +class McpRequireApprovalMcpToolApprovalFilterNever(BaseModel): + tool_names: Optional[List[str]] = None + """List of tools that do not require approval.""" + + +class McpRequireApprovalMcpToolApprovalFilter(BaseModel): + always: Optional[McpRequireApprovalMcpToolApprovalFilterAlways] = None + """A list of tools that always require approval.""" + + never: Optional[McpRequireApprovalMcpToolApprovalFilterNever] = None + """A list of tools that never require approval.""" + + tool_names: Optional[List[str]] = None + """List of allowed tool names.""" + + +McpRequireApproval: TypeAlias = Union[McpRequireApprovalMcpToolApprovalFilter, Literal["always", "never"], None] + + +class Mcp(BaseModel): + server_label: str + """A label for this MCP server, used to identify it in tool calls.""" + + server_url: str + """The URL for the MCP server.""" + + type: Literal["mcp"] + """The type of the MCP tool. Always `mcp`.""" + + allowed_tools: Optional[McpAllowedTools] = None + """List of allowed tool names or a filter object.""" + + headers: Optional[Dict[str, str]] = None + """Optional HTTP headers to send to the MCP server. + + Use for authentication or other purposes. + """ + + require_approval: Optional[McpRequireApproval] = None + """Specify which of the MCP server's tools require approval.""" + + +class CodeInterpreterContainerCodeInterpreterToolAuto(BaseModel): + type: Literal["auto"] + """Always `auto`.""" + + file_ids: Optional[List[str]] = None + """An optional list of uploaded files to make available to your code.""" + + +CodeInterpreterContainer: TypeAlias = Union[str, CodeInterpreterContainerCodeInterpreterToolAuto] + + +class CodeInterpreter(BaseModel): + container: CodeInterpreterContainer + """The code interpreter container. + + Can be a container ID or an object that specifies uploaded file IDs to make + available to your code. + """ + + type: Literal["code_interpreter"] + """The type of the code interpreter tool. Always `code_interpreter`.""" + + +class ImageGenerationInputImageMask(BaseModel): + file_id: Optional[str] = None + """File ID for the mask image.""" + + image_url: Optional[str] = None + """Base64-encoded mask image.""" + + +class ImageGeneration(BaseModel): + type: Literal["image_generation"] + """The type of the image generation tool. Always `image_generation`.""" + + background: Optional[Literal["transparent", "opaque", "auto"]] = None + """Background type for the generated image. + + One of `transparent`, `opaque`, or `auto`. Default: `auto`. + """ + + input_image_mask: Optional[ImageGenerationInputImageMask] = None + """Optional mask for inpainting. + + Contains `image_url` (string, optional) and `file_id` (string, optional). + """ + + model: Optional[Literal["gpt-image-1"]] = None + """The image generation model to use. Default: `gpt-image-1`.""" + + moderation: Optional[Literal["auto", "low"]] = None + """Moderation level for the generated image. Default: `auto`.""" + + output_compression: Optional[int] = None + """Compression level for the output image. Default: 100.""" + + output_format: Optional[Literal["png", "webp", "jpeg"]] = None + """The output format of the generated image. + + One of `png`, `webp`, or `jpeg`. Default: `png`. + """ + + partial_images: Optional[int] = None + """ + Number of partial images to generate in streaming mode, from 0 (default value) + to 3. + """ + + quality: Optional[Literal["low", "medium", "high", "auto"]] = None + """The quality of the generated image. + + One of `low`, `medium`, `high`, or `auto`. Default: `auto`. + """ + + size: Optional[Literal["1024x1024", "1024x1536", "1536x1024", "auto"]] = None + """The size of the generated image. + + One of `1024x1024`, `1024x1536`, `1536x1024`, or `auto`. Default: `auto`. + """ + + +class LocalShell(BaseModel): + type: Literal["local_shell"] + """The type of the local shell tool. Always `local_shell`.""" + Tool: TypeAlias = Annotated[ - Union[FileSearchTool, FunctionTool, WebSearchTool, ComputerTool], PropertyInfo(discriminator="type") + Union[FunctionTool, FileSearchTool, WebSearchTool, ComputerTool, Mcp, CodeInterpreter, ImageGeneration, LocalShell], + PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/responses/tool_choice_types.py b/src/openai/types/responses/tool_choice_types.py index 4942808f14..b968324383 100644 --- a/src/openai/types/responses/tool_choice_types.py +++ b/src/openai/types/responses/tool_choice_types.py @@ -8,7 +8,15 @@ class ToolChoiceTypes(BaseModel): - type: Literal["file_search", "web_search_preview", "computer_use_preview", "web_search_preview_2025_03_11"] + type: Literal[ + "file_search", + "web_search_preview", + "computer_use_preview", + "web_search_preview_2025_03_11", + "image_generation", + "code_interpreter", + "mcp", + ] """The type of hosted tool the model should to use. Learn more about @@ -19,4 +27,7 @@ class ToolChoiceTypes(BaseModel): - `file_search` - `web_search_preview` - `computer_use_preview` + - `code_interpreter` + - `mcp` + - `image_generation` """ diff --git a/src/openai/types/responses/tool_choice_types_param.py b/src/openai/types/responses/tool_choice_types_param.py index b14f2a9eb0..175900750c 100644 --- a/src/openai/types/responses/tool_choice_types_param.py +++ b/src/openai/types/responses/tool_choice_types_param.py @@ -9,7 +9,15 @@ class ToolChoiceTypesParam(TypedDict, total=False): type: Required[ - Literal["file_search", "web_search_preview", "computer_use_preview", "web_search_preview_2025_03_11"] + Literal[ + "file_search", + "web_search_preview", + "computer_use_preview", + "web_search_preview_2025_03_11", + "image_generation", + "code_interpreter", + "mcp", + ] ] """The type of hosted tool the model should to use. @@ -21,4 +29,7 @@ class ToolChoiceTypesParam(TypedDict, total=False): - `file_search` - `web_search_preview` - `computer_use_preview` + - `code_interpreter` + - `mcp` + - `image_generation` """ diff --git a/src/openai/types/responses/tool_param.py b/src/openai/types/responses/tool_param.py index 200c347005..e9da040908 100644 --- a/src/openai/types/responses/tool_param.py +++ b/src/openai/types/responses/tool_param.py @@ -2,8 +2,8 @@ from __future__ import annotations -from typing import Union -from typing_extensions import TypeAlias +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict from .computer_tool_param import ComputerToolParam from .function_tool_param import FunctionToolParam @@ -11,8 +11,174 @@ from .file_search_tool_param import FileSearchToolParam from ..chat.chat_completion_tool_param import ChatCompletionToolParam -__all__ = ["ToolParam"] +__all__ = [ + "ToolParam", + "Mcp", + "McpAllowedTools", + "McpAllowedToolsMcpAllowedToolsFilter", + "McpRequireApproval", + "McpRequireApprovalMcpToolApprovalFilter", + "McpRequireApprovalMcpToolApprovalFilterAlways", + "McpRequireApprovalMcpToolApprovalFilterNever", + "CodeInterpreter", + "CodeInterpreterContainer", + "CodeInterpreterContainerCodeInterpreterToolAuto", + "ImageGeneration", + "ImageGenerationInputImageMask", + "LocalShell", +] -ToolParam: TypeAlias = Union[FileSearchToolParam, FunctionToolParam, WebSearchToolParam, ComputerToolParam] +class McpAllowedToolsMcpAllowedToolsFilter(TypedDict, total=False): + tool_names: List[str] + """List of allowed tool names.""" + +McpAllowedTools: TypeAlias = Union[List[str], McpAllowedToolsMcpAllowedToolsFilter] + + +class McpRequireApprovalMcpToolApprovalFilterAlways(TypedDict, total=False): + tool_names: List[str] + """List of tools that require approval.""" + + +class McpRequireApprovalMcpToolApprovalFilterNever(TypedDict, total=False): + tool_names: List[str] + """List of tools that do not require approval.""" + + +class McpRequireApprovalMcpToolApprovalFilter(TypedDict, total=False): + always: McpRequireApprovalMcpToolApprovalFilterAlways + """A list of tools that always require approval.""" + + never: McpRequireApprovalMcpToolApprovalFilterNever + """A list of tools that never require approval.""" + + tool_names: List[str] + """List of allowed tool names.""" + + +McpRequireApproval: TypeAlias = Union[McpRequireApprovalMcpToolApprovalFilter, Literal["always", "never"]] + + +class Mcp(TypedDict, total=False): + server_label: Required[str] + """A label for this MCP server, used to identify it in tool calls.""" + + server_url: Required[str] + """The URL for the MCP server.""" + + type: Required[Literal["mcp"]] + """The type of the MCP tool. Always `mcp`.""" + + allowed_tools: Optional[McpAllowedTools] + """List of allowed tool names or a filter object.""" + + headers: Optional[Dict[str, str]] + """Optional HTTP headers to send to the MCP server. + + Use for authentication or other purposes. + """ + + require_approval: Optional[McpRequireApproval] + """Specify which of the MCP server's tools require approval.""" + + +class CodeInterpreterContainerCodeInterpreterToolAuto(TypedDict, total=False): + type: Required[Literal["auto"]] + """Always `auto`.""" + + file_ids: List[str] + """An optional list of uploaded files to make available to your code.""" + + +CodeInterpreterContainer: TypeAlias = Union[str, CodeInterpreterContainerCodeInterpreterToolAuto] + + +class CodeInterpreter(TypedDict, total=False): + container: Required[CodeInterpreterContainer] + """The code interpreter container. + + Can be a container ID or an object that specifies uploaded file IDs to make + available to your code. + """ + + type: Required[Literal["code_interpreter"]] + """The type of the code interpreter tool. Always `code_interpreter`.""" + + +class ImageGenerationInputImageMask(TypedDict, total=False): + file_id: str + """File ID for the mask image.""" + + image_url: str + """Base64-encoded mask image.""" + + +class ImageGeneration(TypedDict, total=False): + type: Required[Literal["image_generation"]] + """The type of the image generation tool. Always `image_generation`.""" + + background: Literal["transparent", "opaque", "auto"] + """Background type for the generated image. + + One of `transparent`, `opaque`, or `auto`. Default: `auto`. + """ + + input_image_mask: ImageGenerationInputImageMask + """Optional mask for inpainting. + + Contains `image_url` (string, optional) and `file_id` (string, optional). + """ + + model: Literal["gpt-image-1"] + """The image generation model to use. Default: `gpt-image-1`.""" + + moderation: Literal["auto", "low"] + """Moderation level for the generated image. Default: `auto`.""" + + output_compression: int + """Compression level for the output image. Default: 100.""" + + output_format: Literal["png", "webp", "jpeg"] + """The output format of the generated image. + + One of `png`, `webp`, or `jpeg`. Default: `png`. + """ + + partial_images: int + """ + Number of partial images to generate in streaming mode, from 0 (default value) + to 3. + """ + + quality: Literal["low", "medium", "high", "auto"] + """The quality of the generated image. + + One of `low`, `medium`, `high`, or `auto`. Default: `auto`. + """ + + size: Literal["1024x1024", "1024x1536", "1536x1024", "auto"] + """The size of the generated image. + + One of `1024x1024`, `1024x1536`, `1536x1024`, or `auto`. Default: `auto`. + """ + + +class LocalShell(TypedDict, total=False): + type: Required[Literal["local_shell"]] + """The type of the local shell tool. Always `local_shell`.""" + + +ToolParam: TypeAlias = Union[ + FunctionToolParam, + FileSearchToolParam, + WebSearchToolParam, + ComputerToolParam, + Mcp, + CodeInterpreter, + ImageGeneration, + LocalShell, +] + + ParseableToolParam: TypeAlias = Union[ToolParam, ChatCompletionToolParam] diff --git a/tests/api_resources/test_responses.py b/tests/api_resources/test_responses.py index 3753af8fdb..d7f72ce50d 100644 --- a/tests/api_resources/test_responses.py +++ b/tests/api_resources/test_responses.py @@ -30,6 +30,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: response = client.responses.create( input="string", model="gpt-4o", + background=True, include=["file_search_call.results"], instructions="instructions", max_output_tokens=0, @@ -49,18 +50,11 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: tool_choice="none", tools=[ { - "type": "file_search", - "vector_store_ids": ["string"], - "filters": { - "key": "key", - "type": "eq", - "value": "string", - }, - "max_num_results": 0, - "ranking_options": { - "ranker": "auto", - "score_threshold": 0, - }, + "name": "name", + "parameters": {"foo": "bar"}, + "strict": True, + "type": "function", + "description": "description", } ], top_p=1, @@ -110,6 +104,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: input="string", model="gpt-4o", stream=True, + background=True, include=["file_search_call.results"], instructions="instructions", max_output_tokens=0, @@ -128,18 +123,11 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: tool_choice="none", tools=[ { - "type": "file_search", - "vector_store_ids": ["string"], - "filters": { - "key": "key", - "type": "eq", - "value": "string", - }, - "max_num_results": 0, - "ranking_options": { - "ranker": "auto", - "score_threshold": 0, - }, + "name": "name", + "parameters": {"foo": "bar"}, + "strict": True, + "type": "function", + "description": "description", } ], top_p=1, @@ -276,6 +264,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn response = await async_client.responses.create( input="string", model="gpt-4o", + background=True, include=["file_search_call.results"], instructions="instructions", max_output_tokens=0, @@ -295,18 +284,11 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn tool_choice="none", tools=[ { - "type": "file_search", - "vector_store_ids": ["string"], - "filters": { - "key": "key", - "type": "eq", - "value": "string", - }, - "max_num_results": 0, - "ranking_options": { - "ranker": "auto", - "score_threshold": 0, - }, + "name": "name", + "parameters": {"foo": "bar"}, + "strict": True, + "type": "function", + "description": "description", } ], top_p=1, @@ -356,6 +338,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn input="string", model="gpt-4o", stream=True, + background=True, include=["file_search_call.results"], instructions="instructions", max_output_tokens=0, @@ -374,18 +357,11 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn tool_choice="none", tools=[ { - "type": "file_search", - "vector_store_ids": ["string"], - "filters": { - "key": "key", - "type": "eq", - "value": "string", - }, - "max_num_results": 0, - "ranking_options": { - "ranker": "auto", - "score_threshold": 0, - }, + "name": "name", + "parameters": {"foo": "bar"}, + "strict": True, + "type": "function", + "description": "description", } ], top_p=1, From 71058dd6f0a8e2e837f1b9edc91bc61a07b7837d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 21 May 2025 13:39:24 -0500 Subject: [PATCH 338/769] release: 1.81.0 (#2368) * feat(api): add container endpoint * release: 1.81.0 --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- .stats.yml | 8 +- CHANGELOG.md | 8 + api.md | 37 ++ pyproject.toml | 2 +- src/openai/__init__.py | 1 + src/openai/_client.py | 38 ++ src/openai/_module_client.py | 8 + src/openai/_version.py | 2 +- .../lib/streaming/responses/_responses.py | 4 + src/openai/resources/__init__.py | 14 + src/openai/resources/containers/__init__.py | 33 ++ src/openai/resources/containers/containers.py | 511 +++++++++++++++++ .../resources/containers/files/__init__.py | 33 ++ .../resources/containers/files/content.py | 166 ++++++ .../resources/containers/files/files.py | 532 ++++++++++++++++++ src/openai/resources/responses/responses.py | 86 +++ src/openai/types/__init__.py | 5 + src/openai/types/container_create_params.py | 29 + src/openai/types/container_create_response.py | 40 ++ src/openai/types/container_list_params.py | 30 + src/openai/types/container_list_response.py | 40 ++ .../types/container_retrieve_response.py | 40 ++ src/openai/types/containers/__init__.py | 9 + .../types/containers/file_create_params.py | 17 + .../types/containers/file_create_response.py | 30 + .../types/containers/file_list_params.py | 30 + .../types/containers/file_list_response.py | 30 + .../containers/file_retrieve_response.py | 30 + src/openai/types/containers/files/__init__.py | 3 + .../responses/response_audio_delta_event.py | 3 + .../responses/response_audio_done_event.py | 3 + .../response_audio_transcript_delta_event.py | 3 + .../response_audio_transcript_done_event.py | 3 + ..._code_interpreter_call_code_delta_event.py | 3 + ...e_code_interpreter_call_code_done_event.py | 3 + ...e_code_interpreter_call_completed_event.py | 3 + ...code_interpreter_call_in_progress_event.py | 3 + ...ode_interpreter_call_interpreting_event.py | 3 + .../responses/response_completed_event.py | 3 + .../response_content_part_added_event.py | 3 + .../response_content_part_done_event.py | 3 + .../types/responses/response_created_event.py | 3 + .../types/responses/response_error_event.py | 3 + .../types/responses/response_failed_event.py | 3 + ...sponse_file_search_call_completed_event.py | 3 + ...onse_file_search_call_in_progress_event.py | 3 + ...sponse_file_search_call_searching_event.py | 3 + ...nse_function_call_arguments_delta_event.py | 3 + ...onse_function_call_arguments_done_event.py | 3 + ...response_image_gen_call_completed_event.py | 3 + ...esponse_image_gen_call_generating_event.py | 7 +- .../responses/response_in_progress_event.py | 3 + .../responses/response_incomplete_event.py | 3 + ...response_mcp_call_arguments_delta_event.py | 3 + .../response_mcp_call_arguments_done_event.py | 3 + .../response_mcp_call_completed_event.py | 3 + .../response_mcp_call_failed_event.py | 3 + .../response_mcp_call_in_progress_event.py | 3 + ...response_mcp_list_tools_completed_event.py | 3 + .../response_mcp_list_tools_failed_event.py | 3 + ...sponse_mcp_list_tools_in_progress_event.py | 3 + .../response_output_item_added_event.py | 3 + .../response_output_item_done_event.py | 3 + ...onse_output_text_annotation_added_event.py | 3 + .../types/responses/response_queued_event.py | 3 + .../response_reasoning_delta_event.py | 3 + .../response_reasoning_done_event.py | 3 + .../response_reasoning_summary_delta_event.py | 3 + .../response_reasoning_summary_done_event.py | 3 + ...onse_reasoning_summary_part_added_event.py | 3 + ...ponse_reasoning_summary_part_done_event.py | 3 + ...onse_reasoning_summary_text_delta_event.py | 3 + ...ponse_reasoning_summary_text_done_event.py | 3 + .../responses/response_refusal_delta_event.py | 3 + .../responses/response_refusal_done_event.py | 3 + .../response_text_annotation_delta_event.py | 3 + .../responses/response_text_delta_event.py | 3 + .../responses/response_text_done_event.py | 3 + tests/api_resources/containers/__init__.py | 1 + .../containers/files/__init__.py | 1 + .../containers/files/test_content.py | 116 ++++ tests/api_resources/containers/test_files.py | 409 ++++++++++++++ tests/api_resources/test_containers.py | 333 +++++++++++ tests/api_resources/test_responses.py | 76 +++ 85 files changed, 2894 insertions(+), 11 deletions(-) create mode 100644 src/openai/resources/containers/__init__.py create mode 100644 src/openai/resources/containers/containers.py create mode 100644 src/openai/resources/containers/files/__init__.py create mode 100644 src/openai/resources/containers/files/content.py create mode 100644 src/openai/resources/containers/files/files.py create mode 100644 src/openai/types/container_create_params.py create mode 100644 src/openai/types/container_create_response.py create mode 100644 src/openai/types/container_list_params.py create mode 100644 src/openai/types/container_list_response.py create mode 100644 src/openai/types/container_retrieve_response.py create mode 100644 src/openai/types/containers/__init__.py create mode 100644 src/openai/types/containers/file_create_params.py create mode 100644 src/openai/types/containers/file_create_response.py create mode 100644 src/openai/types/containers/file_list_params.py create mode 100644 src/openai/types/containers/file_list_response.py create mode 100644 src/openai/types/containers/file_retrieve_response.py create mode 100644 src/openai/types/containers/files/__init__.py create mode 100644 tests/api_resources/containers/__init__.py create mode 100644 tests/api_resources/containers/files/__init__.py create mode 100644 tests/api_resources/containers/files/test_content.py create mode 100644 tests/api_resources/containers/test_files.py create mode 100644 tests/api_resources/test_containers.py diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 73077f4afb..7f7687b9f1 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.80.0" + ".": "1.81.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 4b4f19c91f..41319e5e5b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 101 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-a5651cb97f86d1e2531af6aef8c5230f1ea350560fbae790ca2e481b30a6c217.yml -openapi_spec_hash: 66a5104fd3bb43383cf919225df7a6fd -config_hash: bb657c3fed232a56930035de3aaed936 +configured_endpoints: 111 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-6af14840a810139bf407013167ce1c8fb21b6ef8eb0cc3db58b51af7d52c4b5a.yml +openapi_spec_hash: 3241bde6b273cfec0035e522bd07985d +config_hash: 7367b68a4e7db36885c1a886f57b17f6 diff --git a/CHANGELOG.md b/CHANGELOG.md index 6517b7d1b7..09e88ffaee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.81.0 (2025-05-21) + +Full Changelog: [v1.80.0...v1.81.0](https://github.com/openai/openai-python/compare/v1.80.0...v1.81.0) + +### Features + +* **api:** add container endpoint ([054a210](https://github.com/openai/openai-python/commit/054a210289d7e0db22d2d2a61bbe4d4d9cc0cb47)) + ## 1.80.0 (2025-05-21) Full Changelog: [v1.79.0...v1.80.0](https://github.com/openai/openai-python/compare/v1.79.0...v1.80.0) diff --git a/api.md b/api.md index 4eb3c09c66..57ac67f9f1 100644 --- a/api.md +++ b/api.md @@ -785,6 +785,7 @@ Methods: - client.responses.create(\*\*params) -> Response - client.responses.retrieve(response_id, \*\*params) -> Response - client.responses.delete(response_id) -> None +- client.responses.cancel(response_id) -> None ## InputItems @@ -859,3 +860,39 @@ Methods: - client.evals.runs.output_items.retrieve(output_item_id, \*, eval_id, run_id) -> OutputItemRetrieveResponse - client.evals.runs.output_items.list(run_id, \*, eval_id, \*\*params) -> SyncCursorPage[OutputItemListResponse] + +# Containers + +Types: + +```python +from openai.types import ContainerCreateResponse, ContainerRetrieveResponse, ContainerListResponse +``` + +Methods: + +- client.containers.create(\*\*params) -> ContainerCreateResponse +- client.containers.retrieve(container_id) -> ContainerRetrieveResponse +- client.containers.list(\*\*params) -> SyncCursorPage[ContainerListResponse] +- client.containers.delete(container_id) -> None + +## Files + +Types: + +```python +from openai.types.containers import FileCreateResponse, FileRetrieveResponse, FileListResponse +``` + +Methods: + +- client.containers.files.create(container_id, \*\*params) -> FileCreateResponse +- client.containers.files.retrieve(file_id, \*, container_id) -> FileRetrieveResponse +- client.containers.files.list(container_id, \*\*params) -> SyncCursorPage[FileListResponse] +- client.containers.files.delete(file_id, \*, container_id) -> None + +### Content + +Methods: + +- client.containers.files.content.retrieve(file_id, \*, container_id) -> None diff --git a/pyproject.toml b/pyproject.toml index 3c3d246a18..48de070573 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.80.0" +version = "1.81.0" description = "The official Python library for the openai API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/openai/__init__.py b/src/openai/__init__.py index 6b21a9af23..92beeb5da1 100644 --- a/src/openai/__init__.py +++ b/src/openai/__init__.py @@ -363,6 +363,7 @@ def _reset_client() -> None: # type: ignore[reportUnusedFunction] batches as batches, uploads as uploads, responses as responses, + containers as containers, embeddings as embeddings, completions as completions, fine_tuning as fine_tuning, diff --git a/src/openai/_client.py b/src/openai/_client.py index b251ab0917..4ed9a2f52e 100644 --- a/src/openai/_client.py +++ b/src/openai/_client.py @@ -46,6 +46,7 @@ batches, uploads, responses, + containers, embeddings, completions, fine_tuning, @@ -65,6 +66,7 @@ from .resources.moderations import Moderations, AsyncModerations from .resources.uploads.uploads import Uploads, AsyncUploads from .resources.responses.responses import Responses, AsyncResponses + from .resources.containers.containers import Containers, AsyncContainers from .resources.fine_tuning.fine_tuning import FineTuning, AsyncFineTuning from .resources.vector_stores.vector_stores import VectorStores, AsyncVectorStores @@ -244,6 +246,12 @@ def evals(self) -> Evals: return Evals(self) + @cached_property + def containers(self) -> Containers: + from .resources.containers import Containers + + return Containers(self) + @cached_property def with_raw_response(self) -> OpenAIWithRawResponse: return OpenAIWithRawResponse(self) @@ -539,6 +547,12 @@ def evals(self) -> AsyncEvals: return AsyncEvals(self) + @cached_property + def containers(self) -> AsyncContainers: + from .resources.containers import AsyncContainers + + return AsyncContainers(self) + @cached_property def with_raw_response(self) -> AsyncOpenAIWithRawResponse: return AsyncOpenAIWithRawResponse(self) @@ -757,6 +771,12 @@ def evals(self) -> evals.EvalsWithRawResponse: return EvalsWithRawResponse(self._client.evals) + @cached_property + def containers(self) -> containers.ContainersWithRawResponse: + from .resources.containers import ContainersWithRawResponse + + return ContainersWithRawResponse(self._client.containers) + class AsyncOpenAIWithRawResponse: _client: AsyncOpenAI @@ -854,6 +874,12 @@ def evals(self) -> evals.AsyncEvalsWithRawResponse: return AsyncEvalsWithRawResponse(self._client.evals) + @cached_property + def containers(self) -> containers.AsyncContainersWithRawResponse: + from .resources.containers import AsyncContainersWithRawResponse + + return AsyncContainersWithRawResponse(self._client.containers) + class OpenAIWithStreamedResponse: _client: OpenAI @@ -951,6 +977,12 @@ def evals(self) -> evals.EvalsWithStreamingResponse: return EvalsWithStreamingResponse(self._client.evals) + @cached_property + def containers(self) -> containers.ContainersWithStreamingResponse: + from .resources.containers import ContainersWithStreamingResponse + + return ContainersWithStreamingResponse(self._client.containers) + class AsyncOpenAIWithStreamedResponse: _client: AsyncOpenAI @@ -1048,6 +1080,12 @@ def evals(self) -> evals.AsyncEvalsWithStreamingResponse: return AsyncEvalsWithStreamingResponse(self._client.evals) + @cached_property + def containers(self) -> containers.AsyncContainersWithStreamingResponse: + from .resources.containers import AsyncContainersWithStreamingResponse + + return AsyncContainersWithStreamingResponse(self._client.containers) + Client = OpenAI diff --git a/src/openai/_module_client.py b/src/openai/_module_client.py index dd601f9be9..fb7c754917 100644 --- a/src/openai/_module_client.py +++ b/src/openai/_module_client.py @@ -19,6 +19,7 @@ from .resources.moderations import Moderations from .resources.uploads.uploads import Uploads from .resources.responses.responses import Responses + from .resources.containers.containers import Containers from .resources.fine_tuning.fine_tuning import FineTuning from .resources.vector_stores.vector_stores import VectorStores @@ -92,6 +93,12 @@ def __load__(self) -> Embeddings: return _load_client().embeddings +class ContainersProxy(LazyProxy["Containers"]): + @override + def __load__(self) -> Containers: + return _load_client().containers + + class CompletionsProxy(LazyProxy["Completions"]): @override def __load__(self) -> Completions: @@ -127,6 +134,7 @@ def __load__(self) -> VectorStores: uploads: Uploads = UploadsProxy().__as_proxied__() responses: Responses = ResponsesProxy().__as_proxied__() embeddings: Embeddings = EmbeddingsProxy().__as_proxied__() +containers: Containers = ContainersProxy().__as_proxied__() completions: Completions = CompletionsProxy().__as_proxied__() moderations: Moderations = ModerationsProxy().__as_proxied__() fine_tuning: FineTuning = FineTuningProxy().__as_proxied__() diff --git a/src/openai/_version.py b/src/openai/_version.py index 7bf2bbc038..56a8bcaef4 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.80.0" # x-release-please-version +__version__ = "1.81.0" # x-release-please-version diff --git a/src/openai/lib/streaming/responses/_responses.py b/src/openai/lib/streaming/responses/_responses.py index f8f4b64174..0e1e6c0e04 100644 --- a/src/openai/lib/streaming/responses/_responses.py +++ b/src/openai/lib/streaming/responses/_responses.py @@ -251,6 +251,7 @@ def handle_event(self, event: RawResponseStreamEvent) -> List[ResponseStreamEven delta=event.delta, item_id=event.item_id, output_index=event.output_index, + sequence_number=event.sequence_number, type="response.output_text.delta", snapshot=content.text, ) @@ -268,6 +269,7 @@ def handle_event(self, event: RawResponseStreamEvent) -> List[ResponseStreamEven content_index=event.content_index, item_id=event.item_id, output_index=event.output_index, + sequence_number=event.sequence_number, type="response.output_text.done", text=event.text, parsed=parse_text(event.text, text_format=self._text_format), @@ -283,6 +285,7 @@ def handle_event(self, event: RawResponseStreamEvent) -> List[ResponseStreamEven delta=event.delta, item_id=event.item_id, output_index=event.output_index, + sequence_number=event.sequence_number, type="response.function_call_arguments.delta", snapshot=output.arguments, ) @@ -295,6 +298,7 @@ def handle_event(self, event: RawResponseStreamEvent) -> List[ResponseStreamEven events.append( build( ResponseCompletedEvent, + sequence_number=event.sequence_number, type="response.completed", response=response, ) diff --git a/src/openai/resources/__init__.py b/src/openai/resources/__init__.py index 8612dec797..82c9f037d9 100644 --- a/src/openai/resources/__init__.py +++ b/src/openai/resources/__init__.py @@ -72,6 +72,14 @@ UploadsWithStreamingResponse, AsyncUploadsWithStreamingResponse, ) +from .containers import ( + Containers, + AsyncContainers, + ContainersWithRawResponse, + AsyncContainersWithRawResponse, + ContainersWithStreamingResponse, + AsyncContainersWithStreamingResponse, +) from .embeddings import ( Embeddings, AsyncEmbeddings, @@ -198,4 +206,10 @@ "AsyncEvalsWithRawResponse", "EvalsWithStreamingResponse", "AsyncEvalsWithStreamingResponse", + "Containers", + "AsyncContainers", + "ContainersWithRawResponse", + "AsyncContainersWithRawResponse", + "ContainersWithStreamingResponse", + "AsyncContainersWithStreamingResponse", ] diff --git a/src/openai/resources/containers/__init__.py b/src/openai/resources/containers/__init__.py new file mode 100644 index 0000000000..dc1936780b --- /dev/null +++ b/src/openai/resources/containers/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .files import ( + Files, + AsyncFiles, + FilesWithRawResponse, + AsyncFilesWithRawResponse, + FilesWithStreamingResponse, + AsyncFilesWithStreamingResponse, +) +from .containers import ( + Containers, + AsyncContainers, + ContainersWithRawResponse, + AsyncContainersWithRawResponse, + ContainersWithStreamingResponse, + AsyncContainersWithStreamingResponse, +) + +__all__ = [ + "Files", + "AsyncFiles", + "FilesWithRawResponse", + "AsyncFilesWithRawResponse", + "FilesWithStreamingResponse", + "AsyncFilesWithStreamingResponse", + "Containers", + "AsyncContainers", + "ContainersWithRawResponse", + "AsyncContainersWithRawResponse", + "ContainersWithStreamingResponse", + "AsyncContainersWithStreamingResponse", +] diff --git a/src/openai/resources/containers/containers.py b/src/openai/resources/containers/containers.py new file mode 100644 index 0000000000..71e5e6b08d --- /dev/null +++ b/src/openai/resources/containers/containers.py @@ -0,0 +1,511 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Literal + +import httpx + +from ... import _legacy_response +from ...types import container_list_params, container_create_params +from ..._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from .files.files import ( + Files, + AsyncFiles, + FilesWithRawResponse, + AsyncFilesWithRawResponse, + FilesWithStreamingResponse, + AsyncFilesWithStreamingResponse, +) +from ...pagination import SyncCursorPage, AsyncCursorPage +from ..._base_client import AsyncPaginator, make_request_options +from ...types.container_list_response import ContainerListResponse +from ...types.container_create_response import ContainerCreateResponse +from ...types.container_retrieve_response import ContainerRetrieveResponse + +__all__ = ["Containers", "AsyncContainers"] + + +class Containers(SyncAPIResource): + @cached_property + def files(self) -> Files: + return Files(self._client) + + @cached_property + def with_raw_response(self) -> ContainersWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return ContainersWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ContainersWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return ContainersWithStreamingResponse(self) + + def create( + self, + *, + name: str, + expires_after: container_create_params.ExpiresAfter | NotGiven = NOT_GIVEN, + file_ids: List[str] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ContainerCreateResponse: + """ + Create Container + + Args: + name: Name of the container to create. + + expires_after: Container expiration time in seconds relative to the 'anchor' time. + + file_ids: IDs of files to copy to the container. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/containers", + body=maybe_transform( + { + "name": name, + "expires_after": expires_after, + "file_ids": file_ids, + }, + container_create_params.ContainerCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ContainerCreateResponse, + ) + + def retrieve( + self, + container_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ContainerRetrieveResponse: + """ + Retrieve Container + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not container_id: + raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") + return self._get( + f"/containers/{container_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ContainerRetrieveResponse, + ) + + def list( + self, + *, + after: str | NotGiven = NOT_GIVEN, + limit: int | NotGiven = NOT_GIVEN, + order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> SyncCursorPage[ContainerListResponse]: + """List Containers + + Args: + after: A cursor for use in pagination. + + `after` is an object ID that defines your place + in the list. For instance, if you make a list request and receive 100 objects, + ending with obj_foo, your subsequent call can include after=obj_foo in order to + fetch the next page of the list. + + limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the default is 20. + + order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending + order and `desc` for descending order. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/containers", + page=SyncCursorPage[ContainerListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + container_list_params.ContainerListParams, + ), + ), + model=ContainerListResponse, + ) + + def delete( + self, + container_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> None: + """ + Delete Container + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not container_id: + raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/containers/{container_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncContainers(AsyncAPIResource): + @cached_property + def files(self) -> AsyncFiles: + return AsyncFiles(self._client) + + @cached_property + def with_raw_response(self) -> AsyncContainersWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncContainersWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncContainersWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncContainersWithStreamingResponse(self) + + async def create( + self, + *, + name: str, + expires_after: container_create_params.ExpiresAfter | NotGiven = NOT_GIVEN, + file_ids: List[str] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ContainerCreateResponse: + """ + Create Container + + Args: + name: Name of the container to create. + + expires_after: Container expiration time in seconds relative to the 'anchor' time. + + file_ids: IDs of files to copy to the container. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/containers", + body=await async_maybe_transform( + { + "name": name, + "expires_after": expires_after, + "file_ids": file_ids, + }, + container_create_params.ContainerCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ContainerCreateResponse, + ) + + async def retrieve( + self, + container_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ContainerRetrieveResponse: + """ + Retrieve Container + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not container_id: + raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") + return await self._get( + f"/containers/{container_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ContainerRetrieveResponse, + ) + + def list( + self, + *, + after: str | NotGiven = NOT_GIVEN, + limit: int | NotGiven = NOT_GIVEN, + order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> AsyncPaginator[ContainerListResponse, AsyncCursorPage[ContainerListResponse]]: + """List Containers + + Args: + after: A cursor for use in pagination. + + `after` is an object ID that defines your place + in the list. For instance, if you make a list request and receive 100 objects, + ending with obj_foo, your subsequent call can include after=obj_foo in order to + fetch the next page of the list. + + limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the default is 20. + + order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending + order and `desc` for descending order. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/containers", + page=AsyncCursorPage[ContainerListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + container_list_params.ContainerListParams, + ), + ), + model=ContainerListResponse, + ) + + async def delete( + self, + container_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> None: + """ + Delete Container + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not container_id: + raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/containers/{container_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class ContainersWithRawResponse: + def __init__(self, containers: Containers) -> None: + self._containers = containers + + self.create = _legacy_response.to_raw_response_wrapper( + containers.create, + ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + containers.retrieve, + ) + self.list = _legacy_response.to_raw_response_wrapper( + containers.list, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + containers.delete, + ) + + @cached_property + def files(self) -> FilesWithRawResponse: + return FilesWithRawResponse(self._containers.files) + + +class AsyncContainersWithRawResponse: + def __init__(self, containers: AsyncContainers) -> None: + self._containers = containers + + self.create = _legacy_response.async_to_raw_response_wrapper( + containers.create, + ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + containers.retrieve, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + containers.list, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + containers.delete, + ) + + @cached_property + def files(self) -> AsyncFilesWithRawResponse: + return AsyncFilesWithRawResponse(self._containers.files) + + +class ContainersWithStreamingResponse: + def __init__(self, containers: Containers) -> None: + self._containers = containers + + self.create = to_streamed_response_wrapper( + containers.create, + ) + self.retrieve = to_streamed_response_wrapper( + containers.retrieve, + ) + self.list = to_streamed_response_wrapper( + containers.list, + ) + self.delete = to_streamed_response_wrapper( + containers.delete, + ) + + @cached_property + def files(self) -> FilesWithStreamingResponse: + return FilesWithStreamingResponse(self._containers.files) + + +class AsyncContainersWithStreamingResponse: + def __init__(self, containers: AsyncContainers) -> None: + self._containers = containers + + self.create = async_to_streamed_response_wrapper( + containers.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + containers.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + containers.list, + ) + self.delete = async_to_streamed_response_wrapper( + containers.delete, + ) + + @cached_property + def files(self) -> AsyncFilesWithStreamingResponse: + return AsyncFilesWithStreamingResponse(self._containers.files) diff --git a/src/openai/resources/containers/files/__init__.py b/src/openai/resources/containers/files/__init__.py new file mode 100644 index 0000000000..f71f7dbf55 --- /dev/null +++ b/src/openai/resources/containers/files/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .files import ( + Files, + AsyncFiles, + FilesWithRawResponse, + AsyncFilesWithRawResponse, + FilesWithStreamingResponse, + AsyncFilesWithStreamingResponse, +) +from .content import ( + Content, + AsyncContent, + ContentWithRawResponse, + AsyncContentWithRawResponse, + ContentWithStreamingResponse, + AsyncContentWithStreamingResponse, +) + +__all__ = [ + "Content", + "AsyncContent", + "ContentWithRawResponse", + "AsyncContentWithRawResponse", + "ContentWithStreamingResponse", + "AsyncContentWithStreamingResponse", + "Files", + "AsyncFiles", + "FilesWithRawResponse", + "AsyncFilesWithRawResponse", + "FilesWithStreamingResponse", + "AsyncFilesWithStreamingResponse", +] diff --git a/src/openai/resources/containers/files/content.py b/src/openai/resources/containers/files/content.py new file mode 100644 index 0000000000..1aa2d1729d --- /dev/null +++ b/src/openai/resources/containers/files/content.py @@ -0,0 +1,166 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from .... import _legacy_response +from ...._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ...._base_client import make_request_options + +__all__ = ["Content", "AsyncContent"] + + +class Content(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ContentWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return ContentWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ContentWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return ContentWithStreamingResponse(self) + + def retrieve( + self, + file_id: str, + *, + container_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> None: + """ + Retrieve Container File Content + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not container_id: + raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") + if not file_id: + raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._get( + f"/containers/{container_id}/files/{file_id}/content", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncContent(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncContentWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncContentWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncContentWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncContentWithStreamingResponse(self) + + async def retrieve( + self, + file_id: str, + *, + container_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> None: + """ + Retrieve Container File Content + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not container_id: + raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") + if not file_id: + raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._get( + f"/containers/{container_id}/files/{file_id}/content", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class ContentWithRawResponse: + def __init__(self, content: Content) -> None: + self._content = content + + self.retrieve = _legacy_response.to_raw_response_wrapper( + content.retrieve, + ) + + +class AsyncContentWithRawResponse: + def __init__(self, content: AsyncContent) -> None: + self._content = content + + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + content.retrieve, + ) + + +class ContentWithStreamingResponse: + def __init__(self, content: Content) -> None: + self._content = content + + self.retrieve = to_streamed_response_wrapper( + content.retrieve, + ) + + +class AsyncContentWithStreamingResponse: + def __init__(self, content: AsyncContent) -> None: + self._content = content + + self.retrieve = async_to_streamed_response_wrapper( + content.retrieve, + ) diff --git a/src/openai/resources/containers/files/files.py b/src/openai/resources/containers/files/files.py new file mode 100644 index 0000000000..88b6594301 --- /dev/null +++ b/src/openai/resources/containers/files/files.py @@ -0,0 +1,532 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from .... import _legacy_response +from .content import ( + Content, + AsyncContent, + ContentWithRawResponse, + AsyncContentWithRawResponse, + ContentWithStreamingResponse, + AsyncContentWithStreamingResponse, +) +from ...._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven, FileTypes +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ....pagination import SyncCursorPage, AsyncCursorPage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.containers import file_list_params, file_create_params +from ....types.containers.file_list_response import FileListResponse +from ....types.containers.file_create_response import FileCreateResponse +from ....types.containers.file_retrieve_response import FileRetrieveResponse + +__all__ = ["Files", "AsyncFiles"] + + +class Files(SyncAPIResource): + @cached_property + def content(self) -> Content: + return Content(self._client) + + @cached_property + def with_raw_response(self) -> FilesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return FilesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> FilesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return FilesWithStreamingResponse(self) + + def create( + self, + container_id: str, + *, + file: FileTypes | NotGiven = NOT_GIVEN, + file_id: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> FileCreateResponse: + """ + Create a Container File + + You can send either a multipart/form-data request with the raw file content, or + a JSON request with a file ID. + + Args: + file: The File object (not file name) to be uploaded. + + file_id: Name of the file to create. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not container_id: + raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") + return self._post( + f"/containers/{container_id}/files", + body=maybe_transform( + { + "file": file, + "file_id": file_id, + }, + file_create_params.FileCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=FileCreateResponse, + ) + + def retrieve( + self, + file_id: str, + *, + container_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> FileRetrieveResponse: + """ + Retrieve Container File + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not container_id: + raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") + if not file_id: + raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") + return self._get( + f"/containers/{container_id}/files/{file_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=FileRetrieveResponse, + ) + + def list( + self, + container_id: str, + *, + after: str | NotGiven = NOT_GIVEN, + limit: int | NotGiven = NOT_GIVEN, + order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> SyncCursorPage[FileListResponse]: + """List Container files + + Args: + after: A cursor for use in pagination. + + `after` is an object ID that defines your place + in the list. For instance, if you make a list request and receive 100 objects, + ending with obj_foo, your subsequent call can include after=obj_foo in order to + fetch the next page of the list. + + limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the default is 20. + + order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending + order and `desc` for descending order. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not container_id: + raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") + return self._get_api_list( + f"/containers/{container_id}/files", + page=SyncCursorPage[FileListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + file_list_params.FileListParams, + ), + ), + model=FileListResponse, + ) + + def delete( + self, + file_id: str, + *, + container_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> None: + """ + Delete Container File + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not container_id: + raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") + if not file_id: + raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/containers/{container_id}/files/{file_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncFiles(AsyncAPIResource): + @cached_property + def content(self) -> AsyncContent: + return AsyncContent(self._client) + + @cached_property + def with_raw_response(self) -> AsyncFilesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncFilesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncFilesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncFilesWithStreamingResponse(self) + + async def create( + self, + container_id: str, + *, + file: FileTypes | NotGiven = NOT_GIVEN, + file_id: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> FileCreateResponse: + """ + Create a Container File + + You can send either a multipart/form-data request with the raw file content, or + a JSON request with a file ID. + + Args: + file: The File object (not file name) to be uploaded. + + file_id: Name of the file to create. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not container_id: + raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") + return await self._post( + f"/containers/{container_id}/files", + body=await async_maybe_transform( + { + "file": file, + "file_id": file_id, + }, + file_create_params.FileCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=FileCreateResponse, + ) + + async def retrieve( + self, + file_id: str, + *, + container_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> FileRetrieveResponse: + """ + Retrieve Container File + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not container_id: + raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") + if not file_id: + raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") + return await self._get( + f"/containers/{container_id}/files/{file_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=FileRetrieveResponse, + ) + + def list( + self, + container_id: str, + *, + after: str | NotGiven = NOT_GIVEN, + limit: int | NotGiven = NOT_GIVEN, + order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> AsyncPaginator[FileListResponse, AsyncCursorPage[FileListResponse]]: + """List Container files + + Args: + after: A cursor for use in pagination. + + `after` is an object ID that defines your place + in the list. For instance, if you make a list request and receive 100 objects, + ending with obj_foo, your subsequent call can include after=obj_foo in order to + fetch the next page of the list. + + limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the default is 20. + + order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending + order and `desc` for descending order. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not container_id: + raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") + return self._get_api_list( + f"/containers/{container_id}/files", + page=AsyncCursorPage[FileListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + file_list_params.FileListParams, + ), + ), + model=FileListResponse, + ) + + async def delete( + self, + file_id: str, + *, + container_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> None: + """ + Delete Container File + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not container_id: + raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") + if not file_id: + raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/containers/{container_id}/files/{file_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class FilesWithRawResponse: + def __init__(self, files: Files) -> None: + self._files = files + + self.create = _legacy_response.to_raw_response_wrapper( + files.create, + ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + files.retrieve, + ) + self.list = _legacy_response.to_raw_response_wrapper( + files.list, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + files.delete, + ) + + @cached_property + def content(self) -> ContentWithRawResponse: + return ContentWithRawResponse(self._files.content) + + +class AsyncFilesWithRawResponse: + def __init__(self, files: AsyncFiles) -> None: + self._files = files + + self.create = _legacy_response.async_to_raw_response_wrapper( + files.create, + ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + files.retrieve, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + files.list, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + files.delete, + ) + + @cached_property + def content(self) -> AsyncContentWithRawResponse: + return AsyncContentWithRawResponse(self._files.content) + + +class FilesWithStreamingResponse: + def __init__(self, files: Files) -> None: + self._files = files + + self.create = to_streamed_response_wrapper( + files.create, + ) + self.retrieve = to_streamed_response_wrapper( + files.retrieve, + ) + self.list = to_streamed_response_wrapper( + files.list, + ) + self.delete = to_streamed_response_wrapper( + files.delete, + ) + + @cached_property + def content(self) -> ContentWithStreamingResponse: + return ContentWithStreamingResponse(self._files.content) + + +class AsyncFilesWithStreamingResponse: + def __init__(self, files: AsyncFiles) -> None: + self._files = files + + self.create = async_to_streamed_response_wrapper( + files.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + files.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + files.list, + ) + self.delete = async_to_streamed_response_wrapper( + files.delete, + ) + + @cached_property + def content(self) -> AsyncContentWithStreamingResponse: + return AsyncContentWithStreamingResponse(self._files.content) diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index ad9576983f..4a456b82ea 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -948,6 +948,43 @@ def delete( cast_to=NoneType, ) + def cancel( + self, + response_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> None: + """Cancels a model response with the given ID. + + Only responses created with the + `background` parameter set to `true` can be cancelled. + [Learn more](https://platform.openai.com/docs/guides/background). + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not response_id: + raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + f"/responses/{response_id}/cancel", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + class AsyncResponses(AsyncAPIResource): @cached_property @@ -1851,6 +1888,43 @@ async def delete( cast_to=NoneType, ) + async def cancel( + self, + response_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> None: + """Cancels a model response with the given ID. + + Only responses created with the + `background` parameter set to `true` can be cancelled. + [Learn more](https://platform.openai.com/docs/guides/background). + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not response_id: + raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + f"/responses/{response_id}/cancel", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + class ResponsesWithRawResponse: def __init__(self, responses: Responses) -> None: @@ -1865,6 +1939,9 @@ def __init__(self, responses: Responses) -> None: self.delete = _legacy_response.to_raw_response_wrapper( responses.delete, ) + self.cancel = _legacy_response.to_raw_response_wrapper( + responses.cancel, + ) @cached_property def input_items(self) -> InputItemsWithRawResponse: @@ -1884,6 +1961,9 @@ def __init__(self, responses: AsyncResponses) -> None: self.delete = _legacy_response.async_to_raw_response_wrapper( responses.delete, ) + self.cancel = _legacy_response.async_to_raw_response_wrapper( + responses.cancel, + ) @cached_property def input_items(self) -> AsyncInputItemsWithRawResponse: @@ -1903,6 +1983,9 @@ def __init__(self, responses: Responses) -> None: self.delete = to_streamed_response_wrapper( responses.delete, ) + self.cancel = to_streamed_response_wrapper( + responses.cancel, + ) @cached_property def input_items(self) -> InputItemsWithStreamingResponse: @@ -1922,6 +2005,9 @@ def __init__(self, responses: AsyncResponses) -> None: self.delete = async_to_streamed_response_wrapper( responses.delete, ) + self.cancel = async_to_streamed_response_wrapper( + responses.cancel, + ) @cached_property def input_items(self) -> AsyncInputItemsWithStreamingResponse: diff --git a/src/openai/types/__init__.py b/src/openai/types/__init__.py index bf5493fd62..453b26f555 100644 --- a/src/openai/types/__init__.py +++ b/src/openai/types/__init__.py @@ -56,19 +56,24 @@ from .upload_create_params import UploadCreateParams as UploadCreateParams from .vector_store_deleted import VectorStoreDeleted as VectorStoreDeleted from .audio_response_format import AudioResponseFormat as AudioResponseFormat +from .container_list_params import ContainerListParams as ContainerListParams from .image_generate_params import ImageGenerateParams as ImageGenerateParams from .eval_retrieve_response import EvalRetrieveResponse as EvalRetrieveResponse from .file_chunking_strategy import FileChunkingStrategy as FileChunkingStrategy from .upload_complete_params import UploadCompleteParams as UploadCompleteParams +from .container_create_params import ContainerCreateParams as ContainerCreateParams +from .container_list_response import ContainerListResponse as ContainerListResponse from .embedding_create_params import EmbeddingCreateParams as EmbeddingCreateParams from .completion_create_params import CompletionCreateParams as CompletionCreateParams from .moderation_create_params import ModerationCreateParams as ModerationCreateParams from .vector_store_list_params import VectorStoreListParams as VectorStoreListParams +from .container_create_response import ContainerCreateResponse as ContainerCreateResponse from .create_embedding_response import CreateEmbeddingResponse as CreateEmbeddingResponse from .moderation_create_response import ModerationCreateResponse as ModerationCreateResponse from .vector_store_create_params import VectorStoreCreateParams as VectorStoreCreateParams from .vector_store_search_params import VectorStoreSearchParams as VectorStoreSearchParams from .vector_store_update_params import VectorStoreUpdateParams as VectorStoreUpdateParams +from .container_retrieve_response import ContainerRetrieveResponse as ContainerRetrieveResponse from .moderation_text_input_param import ModerationTextInputParam as ModerationTextInputParam from .file_chunking_strategy_param import FileChunkingStrategyParam as FileChunkingStrategyParam from .vector_store_search_response import VectorStoreSearchResponse as VectorStoreSearchResponse diff --git a/src/openai/types/container_create_params.py b/src/openai/types/container_create_params.py new file mode 100644 index 0000000000..bd27334933 --- /dev/null +++ b/src/openai/types/container_create_params.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ContainerCreateParams", "ExpiresAfter"] + + +class ContainerCreateParams(TypedDict, total=False): + name: Required[str] + """Name of the container to create.""" + + expires_after: ExpiresAfter + """Container expiration time in seconds relative to the 'anchor' time.""" + + file_ids: List[str] + """IDs of files to copy to the container.""" + + +class ExpiresAfter(TypedDict, total=False): + anchor: Required[Literal["last_active_at"]] + """Time anchor for the expiration time. + + Currently only 'last_active_at' is supported. + """ + + minutes: Required[int] diff --git a/src/openai/types/container_create_response.py b/src/openai/types/container_create_response.py new file mode 100644 index 0000000000..c0ccc45a1c --- /dev/null +++ b/src/openai/types/container_create_response.py @@ -0,0 +1,40 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["ContainerCreateResponse", "ExpiresAfter"] + + +class ExpiresAfter(BaseModel): + anchor: Optional[Literal["last_active_at"]] = None + """The reference point for the expiration.""" + + minutes: Optional[int] = None + """The number of minutes after the anchor before the container expires.""" + + +class ContainerCreateResponse(BaseModel): + id: str + """Unique identifier for the container.""" + + created_at: int + """Unix timestamp (in seconds) when the container was created.""" + + name: str + """Name of the container.""" + + object: str + """The type of this object.""" + + status: str + """Status of the container (e.g., active, deleted).""" + + expires_after: Optional[ExpiresAfter] = None + """ + The container will expire after this time period. The anchor is the reference + point for the expiration. The minutes is the number of minutes after the anchor + before the container expires. + """ diff --git a/src/openai/types/container_list_params.py b/src/openai/types/container_list_params.py new file mode 100644 index 0000000000..4821a87d18 --- /dev/null +++ b/src/openai/types/container_list_params.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["ContainerListParams"] + + +class ContainerListParams(TypedDict, total=False): + after: str + """A cursor for use in pagination. + + `after` is an object ID that defines your place in the list. For instance, if + you make a list request and receive 100 objects, ending with obj_foo, your + subsequent call can include after=obj_foo in order to fetch the next page of the + list. + """ + + limit: int + """A limit on the number of objects to be returned. + + Limit can range between 1 and 100, and the default is 20. + """ + + order: Literal["asc", "desc"] + """Sort order by the `created_at` timestamp of the objects. + + `asc` for ascending order and `desc` for descending order. + """ diff --git a/src/openai/types/container_list_response.py b/src/openai/types/container_list_response.py new file mode 100644 index 0000000000..2d9c11d8a4 --- /dev/null +++ b/src/openai/types/container_list_response.py @@ -0,0 +1,40 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["ContainerListResponse", "ExpiresAfter"] + + +class ExpiresAfter(BaseModel): + anchor: Optional[Literal["last_active_at"]] = None + """The reference point for the expiration.""" + + minutes: Optional[int] = None + """The number of minutes after the anchor before the container expires.""" + + +class ContainerListResponse(BaseModel): + id: str + """Unique identifier for the container.""" + + created_at: int + """Unix timestamp (in seconds) when the container was created.""" + + name: str + """Name of the container.""" + + object: str + """The type of this object.""" + + status: str + """Status of the container (e.g., active, deleted).""" + + expires_after: Optional[ExpiresAfter] = None + """ + The container will expire after this time period. The anchor is the reference + point for the expiration. The minutes is the number of minutes after the anchor + before the container expires. + """ diff --git a/src/openai/types/container_retrieve_response.py b/src/openai/types/container_retrieve_response.py new file mode 100644 index 0000000000..eab291b34f --- /dev/null +++ b/src/openai/types/container_retrieve_response.py @@ -0,0 +1,40 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["ContainerRetrieveResponse", "ExpiresAfter"] + + +class ExpiresAfter(BaseModel): + anchor: Optional[Literal["last_active_at"]] = None + """The reference point for the expiration.""" + + minutes: Optional[int] = None + """The number of minutes after the anchor before the container expires.""" + + +class ContainerRetrieveResponse(BaseModel): + id: str + """Unique identifier for the container.""" + + created_at: int + """Unix timestamp (in seconds) when the container was created.""" + + name: str + """Name of the container.""" + + object: str + """The type of this object.""" + + status: str + """Status of the container (e.g., active, deleted).""" + + expires_after: Optional[ExpiresAfter] = None + """ + The container will expire after this time period. The anchor is the reference + point for the expiration. The minutes is the number of minutes after the anchor + before the container expires. + """ diff --git a/src/openai/types/containers/__init__.py b/src/openai/types/containers/__init__.py new file mode 100644 index 0000000000..7d555ad3a4 --- /dev/null +++ b/src/openai/types/containers/__init__.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .file_list_params import FileListParams as FileListParams +from .file_create_params import FileCreateParams as FileCreateParams +from .file_list_response import FileListResponse as FileListResponse +from .file_create_response import FileCreateResponse as FileCreateResponse +from .file_retrieve_response import FileRetrieveResponse as FileRetrieveResponse diff --git a/src/openai/types/containers/file_create_params.py b/src/openai/types/containers/file_create_params.py new file mode 100644 index 0000000000..1e41330017 --- /dev/null +++ b/src/openai/types/containers/file_create_params.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +from ..._types import FileTypes + +__all__ = ["FileCreateParams"] + + +class FileCreateParams(TypedDict, total=False): + file: FileTypes + """The File object (not file name) to be uploaded.""" + + file_id: str + """Name of the file to create.""" diff --git a/src/openai/types/containers/file_create_response.py b/src/openai/types/containers/file_create_response.py new file mode 100644 index 0000000000..4a652483fc --- /dev/null +++ b/src/openai/types/containers/file_create_response.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["FileCreateResponse"] + + +class FileCreateResponse(BaseModel): + id: str + """Unique identifier for the file.""" + + bytes: int + """Size of the file in bytes.""" + + container_id: str + """The container this file belongs to.""" + + created_at: int + """Unix timestamp (in seconds) when the file was created.""" + + object: Literal["container.file"] + """The type of this object (`container.file`).""" + + path: str + """Path of the file in the container.""" + + source: str + """Source of the file (e.g., `user`, `assistant`).""" diff --git a/src/openai/types/containers/file_list_params.py b/src/openai/types/containers/file_list_params.py new file mode 100644 index 0000000000..3565acaf36 --- /dev/null +++ b/src/openai/types/containers/file_list_params.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["FileListParams"] + + +class FileListParams(TypedDict, total=False): + after: str + """A cursor for use in pagination. + + `after` is an object ID that defines your place in the list. For instance, if + you make a list request and receive 100 objects, ending with obj_foo, your + subsequent call can include after=obj_foo in order to fetch the next page of the + list. + """ + + limit: int + """A limit on the number of objects to be returned. + + Limit can range between 1 and 100, and the default is 20. + """ + + order: Literal["asc", "desc"] + """Sort order by the `created_at` timestamp of the objects. + + `asc` for ascending order and `desc` for descending order. + """ diff --git a/src/openai/types/containers/file_list_response.py b/src/openai/types/containers/file_list_response.py new file mode 100644 index 0000000000..e5eee38d99 --- /dev/null +++ b/src/openai/types/containers/file_list_response.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["FileListResponse"] + + +class FileListResponse(BaseModel): + id: str + """Unique identifier for the file.""" + + bytes: int + """Size of the file in bytes.""" + + container_id: str + """The container this file belongs to.""" + + created_at: int + """Unix timestamp (in seconds) when the file was created.""" + + object: Literal["container.file"] + """The type of this object (`container.file`).""" + + path: str + """Path of the file in the container.""" + + source: str + """Source of the file (e.g., `user`, `assistant`).""" diff --git a/src/openai/types/containers/file_retrieve_response.py b/src/openai/types/containers/file_retrieve_response.py new file mode 100644 index 0000000000..37fb0e43dd --- /dev/null +++ b/src/openai/types/containers/file_retrieve_response.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["FileRetrieveResponse"] + + +class FileRetrieveResponse(BaseModel): + id: str + """Unique identifier for the file.""" + + bytes: int + """Size of the file in bytes.""" + + container_id: str + """The container this file belongs to.""" + + created_at: int + """Unix timestamp (in seconds) when the file was created.""" + + object: Literal["container.file"] + """The type of this object (`container.file`).""" + + path: str + """Path of the file in the container.""" + + source: str + """Source of the file (e.g., `user`, `assistant`).""" diff --git a/src/openai/types/containers/files/__init__.py b/src/openai/types/containers/files/__init__.py new file mode 100644 index 0000000000..f8ee8b14b1 --- /dev/null +++ b/src/openai/types/containers/files/__init__.py @@ -0,0 +1,3 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations diff --git a/src/openai/types/responses/response_audio_delta_event.py b/src/openai/types/responses/response_audio_delta_event.py index f3d77fac52..6fb7887b80 100644 --- a/src/openai/types/responses/response_audio_delta_event.py +++ b/src/openai/types/responses/response_audio_delta_event.py @@ -11,5 +11,8 @@ class ResponseAudioDeltaEvent(BaseModel): delta: str """A chunk of Base64 encoded response audio bytes.""" + sequence_number: int + """A sequence number for this chunk of the stream response.""" + type: Literal["response.audio.delta"] """The type of the event. Always `response.audio.delta`.""" diff --git a/src/openai/types/responses/response_audio_done_event.py b/src/openai/types/responses/response_audio_done_event.py index 5654f8e398..2592ae8dcd 100644 --- a/src/openai/types/responses/response_audio_done_event.py +++ b/src/openai/types/responses/response_audio_done_event.py @@ -8,5 +8,8 @@ class ResponseAudioDoneEvent(BaseModel): + sequence_number: int + """The sequence number of the delta.""" + type: Literal["response.audio.done"] """The type of the event. Always `response.audio.done`.""" diff --git a/src/openai/types/responses/response_audio_transcript_delta_event.py b/src/openai/types/responses/response_audio_transcript_delta_event.py index 69b6660f3f..830c133d61 100644 --- a/src/openai/types/responses/response_audio_transcript_delta_event.py +++ b/src/openai/types/responses/response_audio_transcript_delta_event.py @@ -11,5 +11,8 @@ class ResponseAudioTranscriptDeltaEvent(BaseModel): delta: str """The partial transcript of the audio response.""" + sequence_number: int + """The sequence number of this event.""" + type: Literal["response.audio.transcript.delta"] """The type of the event. Always `response.audio.transcript.delta`.""" diff --git a/src/openai/types/responses/response_audio_transcript_done_event.py b/src/openai/types/responses/response_audio_transcript_done_event.py index 1a20319f83..e39f501cf0 100644 --- a/src/openai/types/responses/response_audio_transcript_done_event.py +++ b/src/openai/types/responses/response_audio_transcript_done_event.py @@ -8,5 +8,8 @@ class ResponseAudioTranscriptDoneEvent(BaseModel): + sequence_number: int + """The sequence number of this event.""" + type: Literal["response.audio.transcript.done"] """The type of the event. Always `response.audio.transcript.done`.""" diff --git a/src/openai/types/responses/response_code_interpreter_call_code_delta_event.py b/src/openai/types/responses/response_code_interpreter_call_code_delta_event.py index 7527238d06..f25b3f3cab 100644 --- a/src/openai/types/responses/response_code_interpreter_call_code_delta_event.py +++ b/src/openai/types/responses/response_code_interpreter_call_code_delta_event.py @@ -14,5 +14,8 @@ class ResponseCodeInterpreterCallCodeDeltaEvent(BaseModel): output_index: int """The index of the output item that the code interpreter call is in progress.""" + sequence_number: int + """The sequence number of this event.""" + type: Literal["response.code_interpreter_call.code.delta"] """The type of the event. Always `response.code_interpreter_call.code.delta`.""" diff --git a/src/openai/types/responses/response_code_interpreter_call_code_done_event.py b/src/openai/types/responses/response_code_interpreter_call_code_done_event.py index f84d4cf3e8..bf1868cf0f 100644 --- a/src/openai/types/responses/response_code_interpreter_call_code_done_event.py +++ b/src/openai/types/responses/response_code_interpreter_call_code_done_event.py @@ -14,5 +14,8 @@ class ResponseCodeInterpreterCallCodeDoneEvent(BaseModel): output_index: int """The index of the output item that the code interpreter call is in progress.""" + sequence_number: int + """The sequence number of this event.""" + type: Literal["response.code_interpreter_call.code.done"] """The type of the event. Always `response.code_interpreter_call.code.done`.""" diff --git a/src/openai/types/responses/response_code_interpreter_call_completed_event.py b/src/openai/types/responses/response_code_interpreter_call_completed_event.py index b0cb73fb72..3a3a718971 100644 --- a/src/openai/types/responses/response_code_interpreter_call_completed_event.py +++ b/src/openai/types/responses/response_code_interpreter_call_completed_event.py @@ -15,5 +15,8 @@ class ResponseCodeInterpreterCallCompletedEvent(BaseModel): output_index: int """The index of the output item that the code interpreter call is in progress.""" + sequence_number: int + """The sequence number of this event.""" + type: Literal["response.code_interpreter_call.completed"] """The type of the event. Always `response.code_interpreter_call.completed`.""" diff --git a/src/openai/types/responses/response_code_interpreter_call_in_progress_event.py b/src/openai/types/responses/response_code_interpreter_call_in_progress_event.py index 64b739f308..d1c8230919 100644 --- a/src/openai/types/responses/response_code_interpreter_call_in_progress_event.py +++ b/src/openai/types/responses/response_code_interpreter_call_in_progress_event.py @@ -15,5 +15,8 @@ class ResponseCodeInterpreterCallInProgressEvent(BaseModel): output_index: int """The index of the output item that the code interpreter call is in progress.""" + sequence_number: int + """The sequence number of this event.""" + type: Literal["response.code_interpreter_call.in_progress"] """The type of the event. Always `response.code_interpreter_call.in_progress`.""" diff --git a/src/openai/types/responses/response_code_interpreter_call_interpreting_event.py b/src/openai/types/responses/response_code_interpreter_call_interpreting_event.py index 3100eac175..7f4d294f56 100644 --- a/src/openai/types/responses/response_code_interpreter_call_interpreting_event.py +++ b/src/openai/types/responses/response_code_interpreter_call_interpreting_event.py @@ -15,5 +15,8 @@ class ResponseCodeInterpreterCallInterpretingEvent(BaseModel): output_index: int """The index of the output item that the code interpreter call is in progress.""" + sequence_number: int + """The sequence number of this event.""" + type: Literal["response.code_interpreter_call.interpreting"] """The type of the event. Always `response.code_interpreter_call.interpreting`.""" diff --git a/src/openai/types/responses/response_completed_event.py b/src/openai/types/responses/response_completed_event.py index a944f248ef..8a2bd51f75 100644 --- a/src/openai/types/responses/response_completed_event.py +++ b/src/openai/types/responses/response_completed_event.py @@ -12,5 +12,8 @@ class ResponseCompletedEvent(BaseModel): response: Response """Properties of the completed response.""" + sequence_number: int + """The sequence number for this event.""" + type: Literal["response.completed"] """The type of the event. Always `response.completed`.""" diff --git a/src/openai/types/responses/response_content_part_added_event.py b/src/openai/types/responses/response_content_part_added_event.py index 93f5ec4b0c..11e0ac7c92 100644 --- a/src/openai/types/responses/response_content_part_added_event.py +++ b/src/openai/types/responses/response_content_part_added_event.py @@ -26,5 +26,8 @@ class ResponseContentPartAddedEvent(BaseModel): part: Part """The content part that was added.""" + sequence_number: int + """The sequence number of this event.""" + type: Literal["response.content_part.added"] """The type of the event. Always `response.content_part.added`.""" diff --git a/src/openai/types/responses/response_content_part_done_event.py b/src/openai/types/responses/response_content_part_done_event.py index 4ec0739877..e1b411bb45 100644 --- a/src/openai/types/responses/response_content_part_done_event.py +++ b/src/openai/types/responses/response_content_part_done_event.py @@ -26,5 +26,8 @@ class ResponseContentPartDoneEvent(BaseModel): part: Part """The content part that is done.""" + sequence_number: int + """The sequence number of this event.""" + type: Literal["response.content_part.done"] """The type of the event. Always `response.content_part.done`.""" diff --git a/src/openai/types/responses/response_created_event.py b/src/openai/types/responses/response_created_event.py index 7a524cec87..73a9d700d4 100644 --- a/src/openai/types/responses/response_created_event.py +++ b/src/openai/types/responses/response_created_event.py @@ -12,5 +12,8 @@ class ResponseCreatedEvent(BaseModel): response: Response """The response that was created.""" + sequence_number: int + """The sequence number for this event.""" + type: Literal["response.created"] """The type of the event. Always `response.created`.""" diff --git a/src/openai/types/responses/response_error_event.py b/src/openai/types/responses/response_error_event.py index 1b7e605d02..826c395125 100644 --- a/src/openai/types/responses/response_error_event.py +++ b/src/openai/types/responses/response_error_event.py @@ -18,5 +18,8 @@ class ResponseErrorEvent(BaseModel): param: Optional[str] = None """The error parameter.""" + sequence_number: int + """The sequence number of this event.""" + type: Literal["error"] """The type of the event. Always `error`.""" diff --git a/src/openai/types/responses/response_failed_event.py b/src/openai/types/responses/response_failed_event.py index 3e8f75d8c4..cdd3d7d808 100644 --- a/src/openai/types/responses/response_failed_event.py +++ b/src/openai/types/responses/response_failed_event.py @@ -12,5 +12,8 @@ class ResponseFailedEvent(BaseModel): response: Response """The response that failed.""" + sequence_number: int + """The sequence number of this event.""" + type: Literal["response.failed"] """The type of the event. Always `response.failed`.""" diff --git a/src/openai/types/responses/response_file_search_call_completed_event.py b/src/openai/types/responses/response_file_search_call_completed_event.py index 4b86083369..08e51b2d3f 100644 --- a/src/openai/types/responses/response_file_search_call_completed_event.py +++ b/src/openai/types/responses/response_file_search_call_completed_event.py @@ -14,5 +14,8 @@ class ResponseFileSearchCallCompletedEvent(BaseModel): output_index: int """The index of the output item that the file search call is initiated.""" + sequence_number: int + """The sequence number of this event.""" + type: Literal["response.file_search_call.completed"] """The type of the event. Always `response.file_search_call.completed`.""" diff --git a/src/openai/types/responses/response_file_search_call_in_progress_event.py b/src/openai/types/responses/response_file_search_call_in_progress_event.py index eb42e3dad6..63840a649f 100644 --- a/src/openai/types/responses/response_file_search_call_in_progress_event.py +++ b/src/openai/types/responses/response_file_search_call_in_progress_event.py @@ -14,5 +14,8 @@ class ResponseFileSearchCallInProgressEvent(BaseModel): output_index: int """The index of the output item that the file search call is initiated.""" + sequence_number: int + """The sequence number of this event.""" + type: Literal["response.file_search_call.in_progress"] """The type of the event. Always `response.file_search_call.in_progress`.""" diff --git a/src/openai/types/responses/response_file_search_call_searching_event.py b/src/openai/types/responses/response_file_search_call_searching_event.py index 3cd8905de6..706c8c57ad 100644 --- a/src/openai/types/responses/response_file_search_call_searching_event.py +++ b/src/openai/types/responses/response_file_search_call_searching_event.py @@ -14,5 +14,8 @@ class ResponseFileSearchCallSearchingEvent(BaseModel): output_index: int """The index of the output item that the file search call is searching.""" + sequence_number: int + """The sequence number of this event.""" + type: Literal["response.file_search_call.searching"] """The type of the event. Always `response.file_search_call.searching`.""" diff --git a/src/openai/types/responses/response_function_call_arguments_delta_event.py b/src/openai/types/responses/response_function_call_arguments_delta_event.py index 0989b7caeb..c6bc5dfad7 100644 --- a/src/openai/types/responses/response_function_call_arguments_delta_event.py +++ b/src/openai/types/responses/response_function_call_arguments_delta_event.py @@ -19,5 +19,8 @@ class ResponseFunctionCallArgumentsDeltaEvent(BaseModel): The index of the output item that the function-call arguments delta is added to. """ + sequence_number: int + """The sequence number of this event.""" + type: Literal["response.function_call_arguments.delta"] """The type of the event. Always `response.function_call_arguments.delta`.""" diff --git a/src/openai/types/responses/response_function_call_arguments_done_event.py b/src/openai/types/responses/response_function_call_arguments_done_event.py index 1d805a57c6..875e7a6875 100644 --- a/src/openai/types/responses/response_function_call_arguments_done_event.py +++ b/src/openai/types/responses/response_function_call_arguments_done_event.py @@ -17,4 +17,7 @@ class ResponseFunctionCallArgumentsDoneEvent(BaseModel): output_index: int """The index of the output item.""" + sequence_number: int + """The sequence number of this event.""" + type: Literal["response.function_call_arguments.done"] diff --git a/src/openai/types/responses/response_image_gen_call_completed_event.py b/src/openai/types/responses/response_image_gen_call_completed_event.py index fd499f909e..a554273ed0 100644 --- a/src/openai/types/responses/response_image_gen_call_completed_event.py +++ b/src/openai/types/responses/response_image_gen_call_completed_event.py @@ -14,5 +14,8 @@ class ResponseImageGenCallCompletedEvent(BaseModel): output_index: int """The index of the output item in the response's output array.""" + sequence_number: int + """The sequence number of this event.""" + type: Literal["response.image_generation_call.completed"] """The type of the event. Always 'response.image_generation_call.completed'.""" diff --git a/src/openai/types/responses/response_image_gen_call_generating_event.py b/src/openai/types/responses/response_image_gen_call_generating_event.py index 6e7e3efe5c..74b4f57333 100644 --- a/src/openai/types/responses/response_image_gen_call_generating_event.py +++ b/src/openai/types/responses/response_image_gen_call_generating_event.py @@ -1,6 +1,5 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional from typing_extensions import Literal from ..._models import BaseModel @@ -15,8 +14,8 @@ class ResponseImageGenCallGeneratingEvent(BaseModel): output_index: int """The index of the output item in the response's output array.""" + sequence_number: int + """The sequence number of the image generation item being processed.""" + type: Literal["response.image_generation_call.generating"] """The type of the event. Always 'response.image_generation_call.generating'.""" - - sequence_number: Optional[int] = None - """The sequence number of the image generation item being processed.""" diff --git a/src/openai/types/responses/response_in_progress_event.py b/src/openai/types/responses/response_in_progress_event.py index 7d96cbb8ad..b82e10b357 100644 --- a/src/openai/types/responses/response_in_progress_event.py +++ b/src/openai/types/responses/response_in_progress_event.py @@ -12,5 +12,8 @@ class ResponseInProgressEvent(BaseModel): response: Response """The response that is in progress.""" + sequence_number: int + """The sequence number of this event.""" + type: Literal["response.in_progress"] """The type of the event. Always `response.in_progress`.""" diff --git a/src/openai/types/responses/response_incomplete_event.py b/src/openai/types/responses/response_incomplete_event.py index 742b789c7e..63c969a428 100644 --- a/src/openai/types/responses/response_incomplete_event.py +++ b/src/openai/types/responses/response_incomplete_event.py @@ -12,5 +12,8 @@ class ResponseIncompleteEvent(BaseModel): response: Response """The response that was incomplete.""" + sequence_number: int + """The sequence number of this event.""" + type: Literal["response.incomplete"] """The type of the event. Always `response.incomplete`.""" diff --git a/src/openai/types/responses/response_mcp_call_arguments_delta_event.py b/src/openai/types/responses/response_mcp_call_arguments_delta_event.py index ad6738a3b8..d6651e6999 100644 --- a/src/openai/types/responses/response_mcp_call_arguments_delta_event.py +++ b/src/openai/types/responses/response_mcp_call_arguments_delta_event.py @@ -17,5 +17,8 @@ class ResponseMcpCallArgumentsDeltaEvent(BaseModel): output_index: int """The index of the output item in the response's output array.""" + sequence_number: int + """The sequence number of this event.""" + type: Literal["response.mcp_call.arguments_delta"] """The type of the event. Always 'response.mcp_call.arguments_delta'.""" diff --git a/src/openai/types/responses/response_mcp_call_arguments_done_event.py b/src/openai/types/responses/response_mcp_call_arguments_done_event.py index 4095cedb0f..a7ce46ad36 100644 --- a/src/openai/types/responses/response_mcp_call_arguments_done_event.py +++ b/src/openai/types/responses/response_mcp_call_arguments_done_event.py @@ -17,5 +17,8 @@ class ResponseMcpCallArgumentsDoneEvent(BaseModel): output_index: int """The index of the output item in the response's output array.""" + sequence_number: int + """The sequence number of this event.""" + type: Literal["response.mcp_call.arguments_done"] """The type of the event. Always 'response.mcp_call.arguments_done'.""" diff --git a/src/openai/types/responses/response_mcp_call_completed_event.py b/src/openai/types/responses/response_mcp_call_completed_event.py index 63b1b65b31..009fbc3c60 100644 --- a/src/openai/types/responses/response_mcp_call_completed_event.py +++ b/src/openai/types/responses/response_mcp_call_completed_event.py @@ -8,5 +8,8 @@ class ResponseMcpCallCompletedEvent(BaseModel): + sequence_number: int + """The sequence number of this event.""" + type: Literal["response.mcp_call.completed"] """The type of the event. Always 'response.mcp_call.completed'.""" diff --git a/src/openai/types/responses/response_mcp_call_failed_event.py b/src/openai/types/responses/response_mcp_call_failed_event.py index 1f94f4d17e..e6edc6ded5 100644 --- a/src/openai/types/responses/response_mcp_call_failed_event.py +++ b/src/openai/types/responses/response_mcp_call_failed_event.py @@ -8,5 +8,8 @@ class ResponseMcpCallFailedEvent(BaseModel): + sequence_number: int + """The sequence number of this event.""" + type: Literal["response.mcp_call.failed"] """The type of the event. Always 'response.mcp_call.failed'.""" diff --git a/src/openai/types/responses/response_mcp_call_in_progress_event.py b/src/openai/types/responses/response_mcp_call_in_progress_event.py index a90508a13c..401c316851 100644 --- a/src/openai/types/responses/response_mcp_call_in_progress_event.py +++ b/src/openai/types/responses/response_mcp_call_in_progress_event.py @@ -14,5 +14,8 @@ class ResponseMcpCallInProgressEvent(BaseModel): output_index: int """The index of the output item in the response's output array.""" + sequence_number: int + """The sequence number of this event.""" + type: Literal["response.mcp_call.in_progress"] """The type of the event. Always 'response.mcp_call.in_progress'.""" diff --git a/src/openai/types/responses/response_mcp_list_tools_completed_event.py b/src/openai/types/responses/response_mcp_list_tools_completed_event.py index c6a921b5bc..6290c3cf9f 100644 --- a/src/openai/types/responses/response_mcp_list_tools_completed_event.py +++ b/src/openai/types/responses/response_mcp_list_tools_completed_event.py @@ -8,5 +8,8 @@ class ResponseMcpListToolsCompletedEvent(BaseModel): + sequence_number: int + """The sequence number of this event.""" + type: Literal["response.mcp_list_tools.completed"] """The type of the event. Always 'response.mcp_list_tools.completed'.""" diff --git a/src/openai/types/responses/response_mcp_list_tools_failed_event.py b/src/openai/types/responses/response_mcp_list_tools_failed_event.py index 639a2356db..1f6e325b36 100644 --- a/src/openai/types/responses/response_mcp_list_tools_failed_event.py +++ b/src/openai/types/responses/response_mcp_list_tools_failed_event.py @@ -8,5 +8,8 @@ class ResponseMcpListToolsFailedEvent(BaseModel): + sequence_number: int + """The sequence number of this event.""" + type: Literal["response.mcp_list_tools.failed"] """The type of the event. Always 'response.mcp_list_tools.failed'.""" diff --git a/src/openai/types/responses/response_mcp_list_tools_in_progress_event.py b/src/openai/types/responses/response_mcp_list_tools_in_progress_event.py index 41c2334fee..236e5fe6e7 100644 --- a/src/openai/types/responses/response_mcp_list_tools_in_progress_event.py +++ b/src/openai/types/responses/response_mcp_list_tools_in_progress_event.py @@ -8,5 +8,8 @@ class ResponseMcpListToolsInProgressEvent(BaseModel): + sequence_number: int + """The sequence number of this event.""" + type: Literal["response.mcp_list_tools.in_progress"] """The type of the event. Always 'response.mcp_list_tools.in_progress'.""" diff --git a/src/openai/types/responses/response_output_item_added_event.py b/src/openai/types/responses/response_output_item_added_event.py index 7344fb9a6c..7cd2a3946d 100644 --- a/src/openai/types/responses/response_output_item_added_event.py +++ b/src/openai/types/responses/response_output_item_added_event.py @@ -15,5 +15,8 @@ class ResponseOutputItemAddedEvent(BaseModel): output_index: int """The index of the output item that was added.""" + sequence_number: int + """The sequence number of this event.""" + type: Literal["response.output_item.added"] """The type of the event. Always `response.output_item.added`.""" diff --git a/src/openai/types/responses/response_output_item_done_event.py b/src/openai/types/responses/response_output_item_done_event.py index a0a871a019..37d3694cf7 100644 --- a/src/openai/types/responses/response_output_item_done_event.py +++ b/src/openai/types/responses/response_output_item_done_event.py @@ -15,5 +15,8 @@ class ResponseOutputItemDoneEvent(BaseModel): output_index: int """The index of the output item that was marked done.""" + sequence_number: int + """The sequence number of this event.""" + type: Literal["response.output_item.done"] """The type of the event. Always `response.output_item.done`.""" diff --git a/src/openai/types/responses/response_output_text_annotation_added_event.py b/src/openai/types/responses/response_output_text_annotation_added_event.py index 8e9e340b6b..ce96790c92 100644 --- a/src/openai/types/responses/response_output_text_annotation_added_event.py +++ b/src/openai/types/responses/response_output_text_annotation_added_event.py @@ -23,5 +23,8 @@ class ResponseOutputTextAnnotationAddedEvent(BaseModel): output_index: int """The index of the output item in the response's output array.""" + sequence_number: int + """The sequence number of this event.""" + type: Literal["response.output_text_annotation.added"] """The type of the event. Always 'response.output_text_annotation.added'.""" diff --git a/src/openai/types/responses/response_queued_event.py b/src/openai/types/responses/response_queued_event.py index 90981d60d6..40257408a4 100644 --- a/src/openai/types/responses/response_queued_event.py +++ b/src/openai/types/responses/response_queued_event.py @@ -12,5 +12,8 @@ class ResponseQueuedEvent(BaseModel): response: Response """The full response object that is queued.""" + sequence_number: int + """The sequence number for this event.""" + type: Literal["response.queued"] """The type of the event. Always 'response.queued'.""" diff --git a/src/openai/types/responses/response_reasoning_delta_event.py b/src/openai/types/responses/response_reasoning_delta_event.py index 5520c45c73..f37d3d370c 100644 --- a/src/openai/types/responses/response_reasoning_delta_event.py +++ b/src/openai/types/responses/response_reasoning_delta_event.py @@ -20,5 +20,8 @@ class ResponseReasoningDeltaEvent(BaseModel): output_index: int """The index of the output item in the response's output array.""" + sequence_number: int + """The sequence number of this event.""" + type: Literal["response.reasoning.delta"] """The type of the event. Always 'response.reasoning.delta'.""" diff --git a/src/openai/types/responses/response_reasoning_done_event.py b/src/openai/types/responses/response_reasoning_done_event.py index 8b059f469f..9f8b127d7e 100644 --- a/src/openai/types/responses/response_reasoning_done_event.py +++ b/src/openai/types/responses/response_reasoning_done_event.py @@ -17,6 +17,9 @@ class ResponseReasoningDoneEvent(BaseModel): output_index: int """The index of the output item in the response's output array.""" + sequence_number: int + """The sequence number of this event.""" + text: str """The finalized reasoning text.""" diff --git a/src/openai/types/responses/response_reasoning_summary_delta_event.py b/src/openai/types/responses/response_reasoning_summary_delta_event.py index 1f52d042af..519a4f24ac 100644 --- a/src/openai/types/responses/response_reasoning_summary_delta_event.py +++ b/src/openai/types/responses/response_reasoning_summary_delta_event.py @@ -20,6 +20,9 @@ class ResponseReasoningSummaryDeltaEvent(BaseModel): output_index: int """The index of the output item in the response's output array.""" + sequence_number: int + """The sequence number of this event.""" + summary_index: int """The index of the summary part within the output item.""" diff --git a/src/openai/types/responses/response_reasoning_summary_done_event.py b/src/openai/types/responses/response_reasoning_summary_done_event.py index f3f9f5428c..98bcf9cb9d 100644 --- a/src/openai/types/responses/response_reasoning_summary_done_event.py +++ b/src/openai/types/responses/response_reasoning_summary_done_event.py @@ -14,6 +14,9 @@ class ResponseReasoningSummaryDoneEvent(BaseModel): output_index: int """The index of the output item in the response's output array.""" + sequence_number: int + """The sequence number of this event.""" + summary_index: int """The index of the summary part within the output item.""" diff --git a/src/openai/types/responses/response_reasoning_summary_part_added_event.py b/src/openai/types/responses/response_reasoning_summary_part_added_event.py index fd11520170..dc755b253a 100644 --- a/src/openai/types/responses/response_reasoning_summary_part_added_event.py +++ b/src/openai/types/responses/response_reasoning_summary_part_added_event.py @@ -25,6 +25,9 @@ class ResponseReasoningSummaryPartAddedEvent(BaseModel): part: Part """The summary part that was added.""" + sequence_number: int + """The sequence number of this event.""" + summary_index: int """The index of the summary part within the reasoning summary.""" diff --git a/src/openai/types/responses/response_reasoning_summary_part_done_event.py b/src/openai/types/responses/response_reasoning_summary_part_done_event.py index 7f30189a49..7cc0b56d66 100644 --- a/src/openai/types/responses/response_reasoning_summary_part_done_event.py +++ b/src/openai/types/responses/response_reasoning_summary_part_done_event.py @@ -25,6 +25,9 @@ class ResponseReasoningSummaryPartDoneEvent(BaseModel): part: Part """The completed summary part.""" + sequence_number: int + """The sequence number of this event.""" + summary_index: int """The index of the summary part within the reasoning summary.""" diff --git a/src/openai/types/responses/response_reasoning_summary_text_delta_event.py b/src/openai/types/responses/response_reasoning_summary_text_delta_event.py index 6d0cbd8265..96652991b6 100644 --- a/src/openai/types/responses/response_reasoning_summary_text_delta_event.py +++ b/src/openai/types/responses/response_reasoning_summary_text_delta_event.py @@ -17,6 +17,9 @@ class ResponseReasoningSummaryTextDeltaEvent(BaseModel): output_index: int """The index of the output item this summary text delta is associated with.""" + sequence_number: int + """The sequence number of this event.""" + summary_index: int """The index of the summary part within the reasoning summary.""" diff --git a/src/openai/types/responses/response_reasoning_summary_text_done_event.py b/src/openai/types/responses/response_reasoning_summary_text_done_event.py index 15b894c75b..b35b82316a 100644 --- a/src/openai/types/responses/response_reasoning_summary_text_done_event.py +++ b/src/openai/types/responses/response_reasoning_summary_text_done_event.py @@ -14,6 +14,9 @@ class ResponseReasoningSummaryTextDoneEvent(BaseModel): output_index: int """The index of the output item this summary text is associated with.""" + sequence_number: int + """The sequence number of this event.""" + summary_index: int """The index of the summary part within the reasoning summary.""" diff --git a/src/openai/types/responses/response_refusal_delta_event.py b/src/openai/types/responses/response_refusal_delta_event.py index 04dcdf1c8c..03c903ed28 100644 --- a/src/openai/types/responses/response_refusal_delta_event.py +++ b/src/openai/types/responses/response_refusal_delta_event.py @@ -20,5 +20,8 @@ class ResponseRefusalDeltaEvent(BaseModel): output_index: int """The index of the output item that the refusal text is added to.""" + sequence_number: int + """The sequence number of this event.""" + type: Literal["response.refusal.delta"] """The type of the event. Always `response.refusal.delta`.""" diff --git a/src/openai/types/responses/response_refusal_done_event.py b/src/openai/types/responses/response_refusal_done_event.py index a9b6f4b055..61fd51aab0 100644 --- a/src/openai/types/responses/response_refusal_done_event.py +++ b/src/openai/types/responses/response_refusal_done_event.py @@ -20,5 +20,8 @@ class ResponseRefusalDoneEvent(BaseModel): refusal: str """The refusal text that is finalized.""" + sequence_number: int + """The sequence number of this event.""" + type: Literal["response.refusal.done"] """The type of the event. Always `response.refusal.done`.""" diff --git a/src/openai/types/responses/response_text_annotation_delta_event.py b/src/openai/types/responses/response_text_annotation_delta_event.py index 4f2582282a..43d70bacac 100644 --- a/src/openai/types/responses/response_text_annotation_delta_event.py +++ b/src/openai/types/responses/response_text_annotation_delta_event.py @@ -75,5 +75,8 @@ class ResponseTextAnnotationDeltaEvent(BaseModel): output_index: int """The index of the output item that the text annotation was added to.""" + sequence_number: int + """The sequence number of this event.""" + type: Literal["response.output_text.annotation.added"] """The type of the event. Always `response.output_text.annotation.added`.""" diff --git a/src/openai/types/responses/response_text_delta_event.py b/src/openai/types/responses/response_text_delta_event.py index 751a5e2a19..7e4aec7024 100644 --- a/src/openai/types/responses/response_text_delta_event.py +++ b/src/openai/types/responses/response_text_delta_event.py @@ -20,5 +20,8 @@ class ResponseTextDeltaEvent(BaseModel): output_index: int """The index of the output item that the text delta was added to.""" + sequence_number: int + """The sequence number for this event.""" + type: Literal["response.output_text.delta"] """The type of the event. Always `response.output_text.delta`.""" diff --git a/src/openai/types/responses/response_text_done_event.py b/src/openai/types/responses/response_text_done_event.py index 9b5c5e020c..0d5ed4dd19 100644 --- a/src/openai/types/responses/response_text_done_event.py +++ b/src/openai/types/responses/response_text_done_event.py @@ -17,6 +17,9 @@ class ResponseTextDoneEvent(BaseModel): output_index: int """The index of the output item that the text content is finalized.""" + sequence_number: int + """The sequence number for this event.""" + text: str """The text content that is finalized.""" diff --git a/tests/api_resources/containers/__init__.py b/tests/api_resources/containers/__init__.py new file mode 100644 index 0000000000..fd8019a9a1 --- /dev/null +++ b/tests/api_resources/containers/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/containers/files/__init__.py b/tests/api_resources/containers/files/__init__.py new file mode 100644 index 0000000000..fd8019a9a1 --- /dev/null +++ b/tests/api_resources/containers/files/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/containers/files/test_content.py b/tests/api_resources/containers/files/test_content.py new file mode 100644 index 0000000000..470353e18d --- /dev/null +++ b/tests/api_resources/containers/files/test_content.py @@ -0,0 +1,116 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestContent: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + content = client.containers.files.content.retrieve( + file_id="file_id", + container_id="container_id", + ) + assert content is None + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.containers.files.content.with_raw_response.retrieve( + file_id="file_id", + container_id="container_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + content = response.parse() + assert content is None + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.containers.files.content.with_streaming_response.retrieve( + file_id="file_id", + container_id="container_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + content = response.parse() + assert content is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `container_id` but received ''"): + client.containers.files.content.with_raw_response.retrieve( + file_id="file_id", + container_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_id` but received ''"): + client.containers.files.content.with_raw_response.retrieve( + file_id="", + container_id="container_id", + ) + + +class TestAsyncContent: + parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + content = await async_client.containers.files.content.retrieve( + file_id="file_id", + container_id="container_id", + ) + assert content is None + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.containers.files.content.with_raw_response.retrieve( + file_id="file_id", + container_id="container_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + content = response.parse() + assert content is None + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.containers.files.content.with_streaming_response.retrieve( + file_id="file_id", + container_id="container_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + content = await response.parse() + assert content is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `container_id` but received ''"): + await async_client.containers.files.content.with_raw_response.retrieve( + file_id="file_id", + container_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_id` but received ''"): + await async_client.containers.files.content.with_raw_response.retrieve( + file_id="", + container_id="container_id", + ) diff --git a/tests/api_resources/containers/test_files.py b/tests/api_resources/containers/test_files.py new file mode 100644 index 0000000000..6edcc7973a --- /dev/null +++ b/tests/api_resources/containers/test_files.py @@ -0,0 +1,409 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.pagination import SyncCursorPage, AsyncCursorPage +from openai.types.containers import ( + FileListResponse, + FileCreateResponse, + FileRetrieveResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestFiles: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: OpenAI) -> None: + file = client.containers.files.create( + container_id="container_id", + ) + assert_matches_type(FileCreateResponse, file, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: OpenAI) -> None: + file = client.containers.files.create( + container_id="container_id", + file=b"raw file contents", + file_id="file_id", + ) + assert_matches_type(FileCreateResponse, file, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: OpenAI) -> None: + response = client.containers.files.with_raw_response.create( + container_id="container_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file = response.parse() + assert_matches_type(FileCreateResponse, file, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: OpenAI) -> None: + with client.containers.files.with_streaming_response.create( + container_id="container_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file = response.parse() + assert_matches_type(FileCreateResponse, file, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_create(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `container_id` but received ''"): + client.containers.files.with_raw_response.create( + container_id="", + ) + + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + file = client.containers.files.retrieve( + file_id="file_id", + container_id="container_id", + ) + assert_matches_type(FileRetrieveResponse, file, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.containers.files.with_raw_response.retrieve( + file_id="file_id", + container_id="container_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file = response.parse() + assert_matches_type(FileRetrieveResponse, file, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.containers.files.with_streaming_response.retrieve( + file_id="file_id", + container_id="container_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file = response.parse() + assert_matches_type(FileRetrieveResponse, file, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `container_id` but received ''"): + client.containers.files.with_raw_response.retrieve( + file_id="file_id", + container_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_id` but received ''"): + client.containers.files.with_raw_response.retrieve( + file_id="", + container_id="container_id", + ) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + file = client.containers.files.list( + container_id="container_id", + ) + assert_matches_type(SyncCursorPage[FileListResponse], file, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + file = client.containers.files.list( + container_id="container_id", + after="after", + limit=0, + order="asc", + ) + assert_matches_type(SyncCursorPage[FileListResponse], file, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.containers.files.with_raw_response.list( + container_id="container_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file = response.parse() + assert_matches_type(SyncCursorPage[FileListResponse], file, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.containers.files.with_streaming_response.list( + container_id="container_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file = response.parse() + assert_matches_type(SyncCursorPage[FileListResponse], file, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `container_id` but received ''"): + client.containers.files.with_raw_response.list( + container_id="", + ) + + @parametrize + def test_method_delete(self, client: OpenAI) -> None: + file = client.containers.files.delete( + file_id="file_id", + container_id="container_id", + ) + assert file is None + + @parametrize + def test_raw_response_delete(self, client: OpenAI) -> None: + response = client.containers.files.with_raw_response.delete( + file_id="file_id", + container_id="container_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file = response.parse() + assert file is None + + @parametrize + def test_streaming_response_delete(self, client: OpenAI) -> None: + with client.containers.files.with_streaming_response.delete( + file_id="file_id", + container_id="container_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file = response.parse() + assert file is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `container_id` but received ''"): + client.containers.files.with_raw_response.delete( + file_id="file_id", + container_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_id` but received ''"): + client.containers.files.with_raw_response.delete( + file_id="", + container_id="container_id", + ) + + +class TestAsyncFiles: + parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + async def test_method_create(self, async_client: AsyncOpenAI) -> None: + file = await async_client.containers.files.create( + container_id="container_id", + ) + assert_matches_type(FileCreateResponse, file, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: + file = await async_client.containers.files.create( + container_id="container_id", + file=b"raw file contents", + file_id="file_id", + ) + assert_matches_type(FileCreateResponse, file, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: + response = await async_client.containers.files.with_raw_response.create( + container_id="container_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file = response.parse() + assert_matches_type(FileCreateResponse, file, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: + async with async_client.containers.files.with_streaming_response.create( + container_id="container_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file = await response.parse() + assert_matches_type(FileCreateResponse, file, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `container_id` but received ''"): + await async_client.containers.files.with_raw_response.create( + container_id="", + ) + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + file = await async_client.containers.files.retrieve( + file_id="file_id", + container_id="container_id", + ) + assert_matches_type(FileRetrieveResponse, file, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.containers.files.with_raw_response.retrieve( + file_id="file_id", + container_id="container_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file = response.parse() + assert_matches_type(FileRetrieveResponse, file, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.containers.files.with_streaming_response.retrieve( + file_id="file_id", + container_id="container_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file = await response.parse() + assert_matches_type(FileRetrieveResponse, file, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `container_id` but received ''"): + await async_client.containers.files.with_raw_response.retrieve( + file_id="file_id", + container_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_id` but received ''"): + await async_client.containers.files.with_raw_response.retrieve( + file_id="", + container_id="container_id", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + file = await async_client.containers.files.list( + container_id="container_id", + ) + assert_matches_type(AsyncCursorPage[FileListResponse], file, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + file = await async_client.containers.files.list( + container_id="container_id", + after="after", + limit=0, + order="asc", + ) + assert_matches_type(AsyncCursorPage[FileListResponse], file, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.containers.files.with_raw_response.list( + container_id="container_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file = response.parse() + assert_matches_type(AsyncCursorPage[FileListResponse], file, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.containers.files.with_streaming_response.list( + container_id="container_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file = await response.parse() + assert_matches_type(AsyncCursorPage[FileListResponse], file, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `container_id` but received ''"): + await async_client.containers.files.with_raw_response.list( + container_id="", + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncOpenAI) -> None: + file = await async_client.containers.files.delete( + file_id="file_id", + container_id="container_id", + ) + assert file is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: + response = await async_client.containers.files.with_raw_response.delete( + file_id="file_id", + container_id="container_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file = response.parse() + assert file is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: + async with async_client.containers.files.with_streaming_response.delete( + file_id="file_id", + container_id="container_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file = await response.parse() + assert file is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `container_id` but received ''"): + await async_client.containers.files.with_raw_response.delete( + file_id="file_id", + container_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_id` but received ''"): + await async_client.containers.files.with_raw_response.delete( + file_id="", + container_id="container_id", + ) diff --git a/tests/api_resources/test_containers.py b/tests/api_resources/test_containers.py new file mode 100644 index 0000000000..be9787c4d6 --- /dev/null +++ b/tests/api_resources/test_containers.py @@ -0,0 +1,333 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.types import ( + ContainerListResponse, + ContainerCreateResponse, + ContainerRetrieveResponse, +) +from openai.pagination import SyncCursorPage, AsyncCursorPage + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestContainers: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: OpenAI) -> None: + container = client.containers.create( + name="name", + ) + assert_matches_type(ContainerCreateResponse, container, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: OpenAI) -> None: + container = client.containers.create( + name="name", + expires_after={ + "anchor": "last_active_at", + "minutes": 0, + }, + file_ids=["string"], + ) + assert_matches_type(ContainerCreateResponse, container, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: OpenAI) -> None: + response = client.containers.with_raw_response.create( + name="name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + container = response.parse() + assert_matches_type(ContainerCreateResponse, container, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: OpenAI) -> None: + with client.containers.with_streaming_response.create( + name="name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + container = response.parse() + assert_matches_type(ContainerCreateResponse, container, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + container = client.containers.retrieve( + "container_id", + ) + assert_matches_type(ContainerRetrieveResponse, container, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.containers.with_raw_response.retrieve( + "container_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + container = response.parse() + assert_matches_type(ContainerRetrieveResponse, container, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.containers.with_streaming_response.retrieve( + "container_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + container = response.parse() + assert_matches_type(ContainerRetrieveResponse, container, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `container_id` but received ''"): + client.containers.with_raw_response.retrieve( + "", + ) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + container = client.containers.list() + assert_matches_type(SyncCursorPage[ContainerListResponse], container, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + container = client.containers.list( + after="after", + limit=0, + order="asc", + ) + assert_matches_type(SyncCursorPage[ContainerListResponse], container, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.containers.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + container = response.parse() + assert_matches_type(SyncCursorPage[ContainerListResponse], container, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.containers.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + container = response.parse() + assert_matches_type(SyncCursorPage[ContainerListResponse], container, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: OpenAI) -> None: + container = client.containers.delete( + "container_id", + ) + assert container is None + + @parametrize + def test_raw_response_delete(self, client: OpenAI) -> None: + response = client.containers.with_raw_response.delete( + "container_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + container = response.parse() + assert container is None + + @parametrize + def test_streaming_response_delete(self, client: OpenAI) -> None: + with client.containers.with_streaming_response.delete( + "container_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + container = response.parse() + assert container is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `container_id` but received ''"): + client.containers.with_raw_response.delete( + "", + ) + + +class TestAsyncContainers: + parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + async def test_method_create(self, async_client: AsyncOpenAI) -> None: + container = await async_client.containers.create( + name="name", + ) + assert_matches_type(ContainerCreateResponse, container, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: + container = await async_client.containers.create( + name="name", + expires_after={ + "anchor": "last_active_at", + "minutes": 0, + }, + file_ids=["string"], + ) + assert_matches_type(ContainerCreateResponse, container, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: + response = await async_client.containers.with_raw_response.create( + name="name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + container = response.parse() + assert_matches_type(ContainerCreateResponse, container, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: + async with async_client.containers.with_streaming_response.create( + name="name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + container = await response.parse() + assert_matches_type(ContainerCreateResponse, container, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + container = await async_client.containers.retrieve( + "container_id", + ) + assert_matches_type(ContainerRetrieveResponse, container, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.containers.with_raw_response.retrieve( + "container_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + container = response.parse() + assert_matches_type(ContainerRetrieveResponse, container, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.containers.with_streaming_response.retrieve( + "container_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + container = await response.parse() + assert_matches_type(ContainerRetrieveResponse, container, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `container_id` but received ''"): + await async_client.containers.with_raw_response.retrieve( + "", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + container = await async_client.containers.list() + assert_matches_type(AsyncCursorPage[ContainerListResponse], container, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + container = await async_client.containers.list( + after="after", + limit=0, + order="asc", + ) + assert_matches_type(AsyncCursorPage[ContainerListResponse], container, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.containers.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + container = response.parse() + assert_matches_type(AsyncCursorPage[ContainerListResponse], container, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.containers.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + container = await response.parse() + assert_matches_type(AsyncCursorPage[ContainerListResponse], container, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncOpenAI) -> None: + container = await async_client.containers.delete( + "container_id", + ) + assert container is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: + response = await async_client.containers.with_raw_response.delete( + "container_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + container = response.parse() + assert container is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: + async with async_client.containers.with_streaming_response.delete( + "container_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + container = await response.parse() + assert container is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `container_id` but received ''"): + await async_client.containers.with_raw_response.delete( + "", + ) diff --git a/tests/api_resources/test_responses.py b/tests/api_resources/test_responses.py index d7f72ce50d..0d33de4a15 100644 --- a/tests/api_resources/test_responses.py +++ b/tests/api_resources/test_responses.py @@ -247,6 +247,44 @@ def test_path_params_delete(self, client: OpenAI) -> None: "", ) + @parametrize + def test_method_cancel(self, client: OpenAI) -> None: + response = client.responses.cancel( + "resp_677efb5139a88190b512bc3fef8e535d", + ) + assert response is None + + @parametrize + def test_raw_response_cancel(self, client: OpenAI) -> None: + http_response = client.responses.with_raw_response.cancel( + "resp_677efb5139a88190b512bc3fef8e535d", + ) + + assert http_response.is_closed is True + assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" + response = http_response.parse() + assert response is None + + @parametrize + def test_streaming_response_cancel(self, client: OpenAI) -> None: + with client.responses.with_streaming_response.cancel( + "resp_677efb5139a88190b512bc3fef8e535d", + ) as http_response: + assert not http_response.is_closed + assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" + + response = http_response.parse() + assert response is None + + assert cast(Any, http_response.is_closed) is True + + @parametrize + def test_path_params_cancel(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `response_id` but received ''"): + client.responses.with_raw_response.cancel( + "", + ) + class TestAsyncResponses: parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) @@ -480,3 +518,41 @@ async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: await async_client.responses.with_raw_response.delete( "", ) + + @parametrize + async def test_method_cancel(self, async_client: AsyncOpenAI) -> None: + response = await async_client.responses.cancel( + "resp_677efb5139a88190b512bc3fef8e535d", + ) + assert response is None + + @parametrize + async def test_raw_response_cancel(self, async_client: AsyncOpenAI) -> None: + http_response = await async_client.responses.with_raw_response.cancel( + "resp_677efb5139a88190b512bc3fef8e535d", + ) + + assert http_response.is_closed is True + assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" + response = http_response.parse() + assert response is None + + @parametrize + async def test_streaming_response_cancel(self, async_client: AsyncOpenAI) -> None: + async with async_client.responses.with_streaming_response.cancel( + "resp_677efb5139a88190b512bc3fef8e535d", + ) as http_response: + assert not http_response.is_closed + assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" + + response = await http_response.parse() + assert response is None + + assert cast(Any, http_response.is_closed) is True + + @parametrize + async def test_path_params_cancel(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `response_id` but received ''"): + await async_client.responses.with_raw_response.cancel( + "", + ) From f588695f77aad9279a355f5f483d8debf92b46ed Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 22 May 2025 15:07:15 -0500 Subject: [PATCH 339/769] release: 1.82.0 (#2372) * Add background streaming * -m rest of the implementation * docs(readme): fix async example * docs(readme): another async example fix * fix(azure): mark images/edits as a deployment endpoint #2371 * feat(api): new streaming helpers for background responses * release: 1.82.0 --------- Co-authored-by: pakrym-oai Co-authored-by: Robert Craigie Co-authored-by: Kevin Whinnery Co-authored-by: Friedel van Megen Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- .stats.yml | 6 +- CHANGELOG.md | 19 + README.md | 4 +- api.md | 1 - examples/responses/background.py | 46 ++ examples/responses/background_async.py | 52 ++ examples/responses/background_streaming.py | 48 ++ .../responses/background_streaming_async.py | 53 ++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- src/openai/lib/azure.py | 1 + src/openai/lib/streaming/responses/_events.py | 2 - .../lib/streaming/responses/_responses.py | 16 +- .../resources/beta/realtime/realtime.py | 4 +- .../resources/chat/completions/completions.py | 24 +- .../resources/containers/files/files.py | 43 +- src/openai/resources/responses/input_items.py | 4 +- src/openai/resources/responses/responses.py | 513 ++++++++++++++---- .../types/chat/completion_create_params.py | 7 +- src/openai/types/responses/__init__.py | 1 - .../types/responses/input_item_list_params.py | 2 +- src/openai/types/responses/response.py | 7 +- .../types/responses/response_create_params.py | 7 +- .../types/responses/response_stream_event.py | 2 - .../response_text_annotation_delta_event.py | 82 --- ...esponse_web_search_call_completed_event.py | 3 + ...ponse_web_search_call_in_progress_event.py | 3 + ...esponse_web_search_call_searching_event.py | 3 + src/openai/types/responses/tool.py | 3 - src/openai/types/responses/tool_param.py | 3 - 31 files changed, 726 insertions(+), 239 deletions(-) create mode 100644 examples/responses/background.py create mode 100644 examples/responses/background_async.py create mode 100755 examples/responses/background_streaming.py create mode 100644 examples/responses/background_streaming_async.py delete mode 100644 src/openai/types/responses/response_text_annotation_delta_event.py diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 7f7687b9f1..fc2c3ec04d 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.81.0" + ".": "1.82.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 41319e5e5b..017aa58a1c 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-6af14840a810139bf407013167ce1c8fb21b6ef8eb0cc3db58b51af7d52c4b5a.yml -openapi_spec_hash: 3241bde6b273cfec0035e522bd07985d -config_hash: 7367b68a4e7db36885c1a886f57b17f6 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-fc64d7c2c8f51f750813375356c3f3fdfc7fc1b1b34f19c20a5410279d445d37.yml +openapi_spec_hash: 618285fc70199ee32b9ebe4bf72f7e4c +config_hash: c497f6b750cc89c0bf2eefc0bc839c70 diff --git a/CHANGELOG.md b/CHANGELOG.md index 09e88ffaee..a354b8735a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## 1.82.0 (2025-05-22) + +Full Changelog: [v1.81.0...v1.82.0](https://github.com/openai/openai-python/compare/v1.81.0...v1.82.0) + +### Features + +* **api:** new streaming helpers for background responses ([2a65d4d](https://github.com/openai/openai-python/commit/2a65d4de0aaba7801edd0df10f225530fd4969bd)) + + +### Bug Fixes + +* **azure:** mark images/edits as a deployment endpoint [#2371](https://github.com/openai/openai-python/issues/2371) ([5d1d5b4](https://github.com/openai/openai-python/commit/5d1d5b4b6072afe9fd7909b1a36014c8c11c1ad6)) + + +### Documentation + +* **readme:** another async example fix ([9ec8289](https://github.com/openai/openai-python/commit/9ec8289041f395805c67efd97847480f84eb9dac)) +* **readme:** fix async example ([37d0b25](https://github.com/openai/openai-python/commit/37d0b25b6e82cd381e5d1aa6e28f1a1311d02353)) + ## 1.81.0 (2025-05-21) Full Changelog: [v1.80.0...v1.81.0](https://github.com/openai/openai-python/compare/v1.80.0...v1.81.0) diff --git a/README.md b/README.md index f7e0eb6467..b83cb47c74 100644 --- a/README.md +++ b/README.md @@ -174,13 +174,13 @@ client = AsyncOpenAI() async def main(): - stream = client.responses.create( + stream = await client.responses.create( model="gpt-4o", input="Write a one-sentence bedtime story about a unicorn.", stream=True, ) - for event in stream: + async for event in stream: print(event) diff --git a/api.md b/api.md index 57ac67f9f1..73d50fa328 100644 --- a/api.md +++ b/api.md @@ -764,7 +764,6 @@ from openai.types.responses import ( ResponseRefusalDoneEvent, ResponseStatus, ResponseStreamEvent, - ResponseTextAnnotationDeltaEvent, ResponseTextConfig, ResponseTextDeltaEvent, ResponseTextDoneEvent, diff --git a/examples/responses/background.py b/examples/responses/background.py new file mode 100644 index 0000000000..37b00f19be --- /dev/null +++ b/examples/responses/background.py @@ -0,0 +1,46 @@ +from typing import List + +import rich +from pydantic import BaseModel + +from openai import OpenAI + + +class Step(BaseModel): + explanation: str + output: str + + +class MathResponse(BaseModel): + steps: List[Step] + final_answer: str + + +client = OpenAI() +id = None + +with client.responses.create( + input="solve 8x + 31 = 2", + model="gpt-4o-2024-08-06", + background=True, + stream=True, +) as stream: + for event in stream: + if event.type == "response.created": + id = event.response.id + if "output_text" in event.type: + rich.print(event) + if event.sequence_number == 10: + break + +print("Interrupted. Continuing...") + +assert id is not None +with client.responses.retrieve( + response_id=id, + stream=True, + starting_after=10, +) as stream: + for event in stream: + if "output_text" in event.type: + rich.print(event) diff --git a/examples/responses/background_async.py b/examples/responses/background_async.py new file mode 100644 index 0000000000..9dbc78b784 --- /dev/null +++ b/examples/responses/background_async.py @@ -0,0 +1,52 @@ +import asyncio +from typing import List + +import rich +from pydantic import BaseModel + +from openai._client import AsyncOpenAI + + +class Step(BaseModel): + explanation: str + output: str + + +class MathResponse(BaseModel): + steps: List[Step] + final_answer: str + + +async def main() -> None: + client = AsyncOpenAI() + id = None + + async with await client.responses.create( + input="solve 8x + 31 = 2", + model="gpt-4o-2024-08-06", + background=True, + stream=True, + ) as stream: + async for event in stream: + if event.type == "response.created": + id = event.response.id + if "output_text" in event.type: + rich.print(event) + if event.sequence_number == 10: + break + + print("Interrupted. Continuing...") + + assert id is not None + async with await client.responses.retrieve( + response_id=id, + stream=True, + starting_after=10, + ) as stream: + async for event in stream: + if "output_text" in event.type: + rich.print(event) + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/examples/responses/background_streaming.py b/examples/responses/background_streaming.py new file mode 100755 index 0000000000..ed830d9910 --- /dev/null +++ b/examples/responses/background_streaming.py @@ -0,0 +1,48 @@ +#!/usr/bin/env -S rye run python +from typing import List + +import rich +from pydantic import BaseModel + +from openai import OpenAI + + +class Step(BaseModel): + explanation: str + output: str + + +class MathResponse(BaseModel): + steps: List[Step] + final_answer: str + + +client = OpenAI() +id = None +with client.responses.stream( + input="solve 8x + 31 = 2", + model="gpt-4o-2024-08-06", + text_format=MathResponse, + background=True, +) as stream: + for event in stream: + if event.type == "response.created": + id = event.response.id + if "output_text" in event.type: + rich.print(event) + if event.sequence_number == 10: + break + +print("Interrupted. Continuing...") + +assert id is not None +with client.responses.stream( + response_id=id, + starting_after=10, + text_format=MathResponse, +) as stream: + for event in stream: + if "output_text" in event.type: + rich.print(event) + + rich.print(stream.get_final_response()) diff --git a/examples/responses/background_streaming_async.py b/examples/responses/background_streaming_async.py new file mode 100644 index 0000000000..178150dc15 --- /dev/null +++ b/examples/responses/background_streaming_async.py @@ -0,0 +1,53 @@ +import asyncio +from typing import List + +import rich +from pydantic import BaseModel + +from openai import AsyncOpenAI + + +class Step(BaseModel): + explanation: str + output: str + + +class MathResponse(BaseModel): + steps: List[Step] + final_answer: str + + +async def main() -> None: + client = AsyncOpenAI() + id = None + async with client.responses.stream( + input="solve 8x + 31 = 2", + model="gpt-4o-2024-08-06", + text_format=MathResponse, + background=True, + ) as stream: + async for event in stream: + if event.type == "response.created": + id = event.response.id + if "output_text" in event.type: + rich.print(event) + if event.sequence_number == 10: + break + + print("Interrupted. Continuing...") + + assert id is not None + async with client.responses.stream( + response_id=id, + starting_after=10, + text_format=MathResponse, + ) as stream: + async for event in stream: + if "output_text" in event.type: + rich.print(event) + + rich.print(stream.get_final_response()) + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/pyproject.toml b/pyproject.toml index 48de070573..b8580d854a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.81.0" +version = "1.82.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 56a8bcaef4..8fc27e8457 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.81.0" # x-release-please-version +__version__ = "1.82.0" # x-release-please-version diff --git a/src/openai/lib/azure.py b/src/openai/lib/azure.py index ea7bd20d99..655dd71d4c 100644 --- a/src/openai/lib/azure.py +++ b/src/openai/lib/azure.py @@ -25,6 +25,7 @@ "/audio/translations", "/audio/speech", "/images/generations", + "/images/edits", ] ) diff --git a/src/openai/lib/streaming/responses/_events.py b/src/openai/lib/streaming/responses/_events.py index 09b84488b5..6e547815e2 100644 --- a/src/openai/lib/streaming/responses/_events.py +++ b/src/openai/lib/streaming/responses/_events.py @@ -31,7 +31,6 @@ ResponseMcpCallInProgressEvent, ResponseMcpListToolsFailedEvent, ResponseAudioTranscriptDoneEvent, - ResponseTextAnnotationDeltaEvent, ResponseAudioTranscriptDeltaEvent, ResponseMcpCallArgumentsDoneEvent, ResponseReasoningSummaryDoneEvent, @@ -118,7 +117,6 @@ class ResponseCompletedEvent(RawResponseCompletedEvent, GenericModel, Generic[Te ResponseOutputItemDoneEvent, ResponseRefusalDeltaEvent, ResponseRefusalDoneEvent, - ResponseTextAnnotationDeltaEvent, ResponseTextDoneEvent, ResponseWebSearchCallCompletedEvent, ResponseWebSearchCallInProgressEvent, diff --git a/src/openai/lib/streaming/responses/_responses.py b/src/openai/lib/streaming/responses/_responses.py index 0e1e6c0e04..2c2fec5469 100644 --- a/src/openai/lib/streaming/responses/_responses.py +++ b/src/openai/lib/streaming/responses/_responses.py @@ -34,11 +34,13 @@ def __init__( raw_stream: Stream[RawResponseStreamEvent], text_format: type[TextFormatT] | NotGiven, input_tools: Iterable[ToolParam] | NotGiven, + starting_after: int | None, ) -> None: self._raw_stream = raw_stream self._response = raw_stream.response self._iterator = self.__stream__() self._state = ResponseStreamState(text_format=text_format, input_tools=input_tools) + self._starting_after = starting_after def __next__(self) -> ResponseStreamEvent[TextFormatT]: return self._iterator.__next__() @@ -54,7 +56,8 @@ def __stream__(self) -> Iterator[ResponseStreamEvent[TextFormatT]]: for sse_event in self._raw_stream: events_to_fire = self._state.handle_event(sse_event) for event in events_to_fire: - yield event + if self._starting_after is None or event.sequence_number > self._starting_after: + yield event def __exit__( self, @@ -96,11 +99,13 @@ def __init__( *, text_format: type[TextFormatT] | NotGiven, input_tools: Iterable[ToolParam] | NotGiven, + starting_after: int | None, ) -> None: self.__stream: ResponseStream[TextFormatT] | None = None self.__api_request = api_request self.__text_format = text_format self.__input_tools = input_tools + self.__starting_after = starting_after def __enter__(self) -> ResponseStream[TextFormatT]: raw_stream = self.__api_request() @@ -109,6 +114,7 @@ def __enter__(self) -> ResponseStream[TextFormatT]: raw_stream=raw_stream, text_format=self.__text_format, input_tools=self.__input_tools, + starting_after=self.__starting_after, ) return self.__stream @@ -130,11 +136,13 @@ def __init__( raw_stream: AsyncStream[RawResponseStreamEvent], text_format: type[TextFormatT] | NotGiven, input_tools: Iterable[ToolParam] | NotGiven, + starting_after: int | None, ) -> None: self._raw_stream = raw_stream self._response = raw_stream.response self._iterator = self.__stream__() self._state = ResponseStreamState(text_format=text_format, input_tools=input_tools) + self._starting_after = starting_after async def __anext__(self) -> ResponseStreamEvent[TextFormatT]: return await self._iterator.__anext__() @@ -147,7 +155,8 @@ async def __stream__(self) -> AsyncIterator[ResponseStreamEvent[TextFormatT]]: async for sse_event in self._raw_stream: events_to_fire = self._state.handle_event(sse_event) for event in events_to_fire: - yield event + if self._starting_after is None or event.sequence_number > self._starting_after: + yield event async def __aenter__(self) -> Self: return self @@ -192,11 +201,13 @@ def __init__( *, text_format: type[TextFormatT] | NotGiven, input_tools: Iterable[ToolParam] | NotGiven, + starting_after: int | None, ) -> None: self.__stream: AsyncResponseStream[TextFormatT] | None = None self.__api_request = api_request self.__text_format = text_format self.__input_tools = input_tools + self.__starting_after = starting_after async def __aenter__(self) -> AsyncResponseStream[TextFormatT]: raw_stream = await self.__api_request @@ -205,6 +216,7 @@ async def __aenter__(self) -> AsyncResponseStream[TextFormatT]: raw_stream=raw_stream, text_format=self.__text_format, input_tools=self.__input_tools, + starting_after=self.__starting_after, ) return self.__stream diff --git a/src/openai/resources/beta/realtime/realtime.py b/src/openai/resources/beta/realtime/realtime.py index d39db48e05..8e1b558cf3 100644 --- a/src/openai/resources/beta/realtime/realtime.py +++ b/src/openai/resources/beta/realtime/realtime.py @@ -820,7 +820,7 @@ def clear(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: stop generating audio and emit a `output_audio_buffer.cleared` event. This event should be preceded by a `response.cancel` client event to stop the generation of the current response. - [Learn more](https://platform.openai.com/docs/guides/realtime-model-capabilities#client-and-server-events-for-audio-in-webrtc). + [Learn more](https://platform.openai.com/docs/guides/realtime-conversations#client-and-server-events-for-audio-in-webrtc). """ self._connection.send( cast(RealtimeClientEventParam, strip_not_given({"type": "output_audio_buffer.clear", "event_id": event_id})) @@ -1072,7 +1072,7 @@ async def clear(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: stop generating audio and emit a `output_audio_buffer.cleared` event. This event should be preceded by a `response.cancel` client event to stop the generation of the current response. - [Learn more](https://platform.openai.com/docs/guides/realtime-model-capabilities#client-and-server-events-for-audio-in-webrtc). + [Learn more](https://platform.openai.com/docs/guides/realtime-conversations#client-and-server-events-for-audio-in-webrtc). """ await self._connection.send( cast(RealtimeClientEventParam, strip_not_given({"type": "output_audio_buffer.clear", "event_id": event_id})) diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index 0ab105a389..4dbd1e6c62 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -323,8 +323,8 @@ def create( We generally recommend altering this or `temperature` but not both. - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. + user: A stable identifier for your end-users. Used to boost cache hit rates by better + bucketing similar requests and to help OpenAI detect and prevent abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). web_search_options: This tool searches the web for relevant results to use in a response. Learn more @@ -592,8 +592,8 @@ def create( We generally recommend altering this or `temperature` but not both. - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. + user: A stable identifier for your end-users. Used to boost cache hit rates by better + bucketing similar requests and to help OpenAI detect and prevent abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). web_search_options: This tool searches the web for relevant results to use in a response. Learn more @@ -861,8 +861,8 @@ def create( We generally recommend altering this or `temperature` but not both. - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. + user: A stable identifier for your end-users. Used to boost cache hit rates by better + bucketing similar requests and to help OpenAI detect and prevent abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). web_search_options: This tool searches the web for relevant results to use in a response. Learn more @@ -1426,8 +1426,8 @@ async def create( We generally recommend altering this or `temperature` but not both. - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. + user: A stable identifier for your end-users. Used to boost cache hit rates by better + bucketing similar requests and to help OpenAI detect and prevent abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). web_search_options: This tool searches the web for relevant results to use in a response. Learn more @@ -1695,8 +1695,8 @@ async def create( We generally recommend altering this or `temperature` but not both. - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. + user: A stable identifier for your end-users. Used to boost cache hit rates by better + bucketing similar requests and to help OpenAI detect and prevent abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). web_search_options: This tool searches the web for relevant results to use in a response. Learn more @@ -1964,8 +1964,8 @@ async def create( We generally recommend altering this or `temperature` but not both. - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. + user: A stable identifier for your end-users. Used to boost cache hit rates by better + bucketing similar requests and to help OpenAI detect and prevent abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). web_search_options: This tool searches the web for relevant results to use in a response. Learn more diff --git a/src/openai/resources/containers/files/files.py b/src/openai/resources/containers/files/files.py index 88b6594301..624398b97b 100644 --- a/src/openai/resources/containers/files/files.py +++ b/src/openai/resources/containers/files/files.py @@ -2,6 +2,7 @@ from __future__ import annotations +from typing import Mapping, cast from typing_extensions import Literal import httpx @@ -16,7 +17,7 @@ AsyncContentWithStreamingResponse, ) from ...._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven, FileTypes -from ...._utils import maybe_transform, async_maybe_transform +from ...._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -88,15 +89,21 @@ def create( """ if not container_id: raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") + body = deepcopy_minimal( + { + "file": file, + "file_id": file_id, + } + ) + files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) + # It should be noted that the actual Content-Type header that will be + # sent to the server will contain a `boundary` parameter, e.g. + # multipart/form-data; boundary=---abc-- + extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} return self._post( f"/containers/{container_id}/files", - body=maybe_transform( - { - "file": file, - "file_id": file_id, - }, - file_create_params.FileCreateParams, - ), + body=maybe_transform(body, file_create_params.FileCreateParams), + files=files, options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -295,15 +302,21 @@ async def create( """ if not container_id: raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") + body = deepcopy_minimal( + { + "file": file, + "file_id": file_id, + } + ) + files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) + # It should be noted that the actual Content-Type header that will be + # sent to the server will contain a `boundary` parameter, e.g. + # multipart/form-data; boundary=---abc-- + extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} return await self._post( f"/containers/{container_id}/files", - body=await async_maybe_transform( - { - "file": file, - "file_id": file_id, - }, - file_create_params.FileCreateParams, - ), + body=await async_maybe_transform(body, file_create_params.FileCreateParams), + files=files, options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/responses/input_items.py b/src/openai/resources/responses/input_items.py index ee0e628169..a425a65c3e 100644 --- a/src/openai/resources/responses/input_items.py +++ b/src/openai/resources/responses/input_items.py @@ -72,7 +72,7 @@ def list( limit: A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 20. - order: The order to return the input items in. Default is `asc`. + order: The order to return the input items in. Default is `desc`. - `asc`: Return the input items in ascending order. - `desc`: Return the input items in descending order. @@ -160,7 +160,7 @@ def list( limit: A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 20. - order: The order to return the input items in. Default is `asc`. + order: The order to return the input items in. Default is `desc`. - `asc`: Return the input items in ascending order. - `desc`: Return the input items in descending order. diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 4a456b82ea..570e7c94d5 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -250,8 +250,8 @@ def create( - `disabled` (default): If a model response will exceed the context window size for a model, the request will fail with a 400 error. - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. + user: A stable identifier for your end-users. Used to boost cache hit rates by better + bucketing similar requests and to help OpenAI detect and prevent abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). extra_headers: Send extra headers @@ -443,8 +443,8 @@ def create( - `disabled` (default): If a model response will exceed the context window size for a model, the request will fail with a 400 error. - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. + user: A stable identifier for your end-users. Used to boost cache hit rates by better + bucketing similar requests and to help OpenAI detect and prevent abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). extra_headers: Send extra headers @@ -636,8 +636,8 @@ def create( - `disabled` (default): If a model response will exceed the context window size for a model, the request will fail with a 400 error. - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. + user: A stable identifier for your end-users. Used to boost cache hit rates by better + bucketing similar requests and to help OpenAI detect and prevent abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). extra_headers: Send extra headers @@ -718,11 +718,28 @@ def create( stream_cls=Stream[ResponseStreamEvent], ) + @overload + def stream( + self, + *, + response_id: str, + text_format: type[TextFormatT] | NotGiven = NOT_GIVEN, + starting_after: int | NotGiven = NOT_GIVEN, + tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ResponseStreamManager[TextFormatT]: ... + + @overload def stream( self, *, input: Union[str, ResponseInputParam], model: Union[str, ChatModel], + background: Optional[bool] | NotGiven = NOT_GIVEN, text_format: type[TextFormatT] | NotGiven = NOT_GIVEN, tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, @@ -745,49 +762,129 @@ def stream( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> ResponseStreamManager[TextFormatT]: - if is_given(text_format): - if not text: - text = {} - - if "format" in text: - raise TypeError("Cannot mix and match text.format with text_format") - - text["format"] = _type_to_text_format_param(text_format) + ) -> ResponseStreamManager[TextFormatT]: ... + def stream( + self, + *, + response_id: str | NotGiven = NOT_GIVEN, + input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, + model: Union[str, ChatModel] | NotGiven = NOT_GIVEN, + background: Optional[bool] | NotGiven = NOT_GIVEN, + text_format: type[TextFormatT] | NotGiven = NOT_GIVEN, + tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, + include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | NotGiven = NOT_GIVEN, + max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, + previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, + temperature: Optional[float] | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, + top_p: Optional[float] | NotGiven = NOT_GIVEN, + truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + starting_after: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ResponseStreamManager[TextFormatT]: + new_response_args = { + "input": input, + "model": model, + "include": include, + "instructions": instructions, + "max_output_tokens": max_output_tokens, + "metadata": metadata, + "parallel_tool_calls": parallel_tool_calls, + "previous_response_id": previous_response_id, + "reasoning": reasoning, + "store": store, + "temperature": temperature, + "text": text, + "tool_choice": tool_choice, + "top_p": top_p, + "truncation": truncation, + "user": user, + "background": background, + } + new_response_args_names = [k for k, v in new_response_args.items() if is_given(v)] + + if (is_given(response_id) or is_given(starting_after)) and len(new_response_args_names) > 0: + raise ValueError( + "Cannot provide both response_id/starting_after can't be provided together with " + + ", ".join(new_response_args_names) + ) tools = _make_tools(tools) + if len(new_response_args_names) > 0: + if not is_given(input): + raise ValueError("input must be provided when creating a new response") + + if not is_given(model): + raise ValueError("model must be provided when creating a new response") + + if is_given(text_format): + if not text: + text = {} + + if "format" in text: + raise TypeError("Cannot mix and match text.format with text_format") + + text["format"] = _type_to_text_format_param(text_format) + + api_request: partial[Stream[ResponseStreamEvent]] = partial( + self.create, + input=input, + model=model, + tools=tools, + include=include, + instructions=instructions, + max_output_tokens=max_output_tokens, + metadata=metadata, + parallel_tool_calls=parallel_tool_calls, + previous_response_id=previous_response_id, + store=store, + stream=True, + temperature=temperature, + text=text, + tool_choice=tool_choice, + reasoning=reasoning, + top_p=top_p, + truncation=truncation, + user=user, + background=background, + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + ) - api_request: partial[Stream[ResponseStreamEvent]] = partial( - self.create, - input=input, - model=model, - tools=tools, - include=include, - instructions=instructions, - max_output_tokens=max_output_tokens, - metadata=metadata, - parallel_tool_calls=parallel_tool_calls, - previous_response_id=previous_response_id, - store=store, - stream=True, - temperature=temperature, - text=text, - tool_choice=tool_choice, - reasoning=reasoning, - top_p=top_p, - truncation=truncation, - user=user, - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - ) - - return ResponseStreamManager( - api_request, - text_format=text_format, - input_tools=tools, - ) + return ResponseStreamManager(api_request, text_format=text_format, input_tools=tools, starting_after=None) + else: + if not is_given(response_id): + raise ValueError("id must be provided when streaming an existing response") + + return ResponseStreamManager( + lambda: self.retrieve( + response_id=response_id, + stream=True, + include=include or [], + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + starting_after=NOT_GIVEN, + timeout=timeout, + ), + text_format=text_format, + input_tools=tools, + starting_after=starting_after if is_given(starting_after) else None, + ) def parse( self, @@ -873,6 +970,7 @@ def parser(raw_response: Response) -> ParsedResponse[TextFormatT]: cast_to=cast(Type[ParsedResponse[TextFormatT]], Response), ) + @overload def retrieve( self, response_id: str, @@ -884,7 +982,54 @@ def retrieve( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Response: + ) -> Response: ... + + @overload + def retrieve( + self, + response_id: str, + *, + stream: Literal[True], + include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + starting_after: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Stream[ResponseStreamEvent]: ... + + @overload + def retrieve( + self, + response_id: str, + *, + stream: bool, + include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + starting_after: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Response | Stream[ResponseStreamEvent]: ... + + def retrieve( + self, + response_id: str, + *, + stream: bool = False, + include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + starting_after: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Response | Stream[ResponseStreamEvent]: """ Retrieves a model response with the given ID. @@ -892,6 +1037,16 @@ def retrieve( include: Additional fields to include in the response. See the `include` parameter for Response creation above for more information. + stream: If set to true, the model response data will be streamed to the client using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) + for more information. + + starting_after: When retrieving a background response, this parameter can be used to start + replaying after an event with the given sequence number. Must be used in conjunction with + the `stream` parameter set to `true`. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -909,9 +1064,18 @@ def retrieve( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - query=maybe_transform({"include": include}, response_retrieve_params.ResponseRetrieveParams), + query=maybe_transform( + { + "include": include, + "stream": stream, + "starting_after": starting_after, + }, + response_retrieve_params.ResponseRetrieveParams, + ), ), cast_to=Response, + stream=stream or False, + stream_cls=Stream[ResponseStreamEvent], ) def delete( @@ -1189,8 +1353,8 @@ async def create( - `disabled` (default): If a model response will exceed the context window size for a model, the request will fail with a 400 error. - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. + user: A stable identifier for your end-users. Used to boost cache hit rates by better + bucketing similar requests and to help OpenAI detect and prevent abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). extra_headers: Send extra headers @@ -1382,8 +1546,8 @@ async def create( - `disabled` (default): If a model response will exceed the context window size for a model, the request will fail with a 400 error. - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. + user: A stable identifier for your end-users. Used to boost cache hit rates by better + bucketing similar requests and to help OpenAI detect and prevent abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). extra_headers: Send extra headers @@ -1575,8 +1739,8 @@ async def create( - `disabled` (default): If a model response will exceed the context window size for a model, the request will fail with a 400 error. - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. + user: A stable identifier for your end-users. Used to boost cache hit rates by better + bucketing similar requests and to help OpenAI detect and prevent abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). extra_headers: Send extra headers @@ -1657,11 +1821,28 @@ async def create( stream_cls=AsyncStream[ResponseStreamEvent], ) + @overload + def stream( + self, + *, + response_id: str, + text_format: type[TextFormatT] | NotGiven = NOT_GIVEN, + starting_after: int | NotGiven = NOT_GIVEN, + tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> AsyncResponseStreamManager[TextFormatT]: ... + + @overload def stream( self, *, input: Union[str, ResponseInputParam], model: Union[str, ChatModel], + background: Optional[bool] | NotGiven = NOT_GIVEN, text_format: type[TextFormatT] | NotGiven = NOT_GIVEN, tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, @@ -1684,48 +1865,133 @@ def stream( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncResponseStreamManager[TextFormatT]: - if is_given(text_format): - if not text: - text = {} - - if "format" in text: - raise TypeError("Cannot mix and match text.format with text_format") + ) -> AsyncResponseStreamManager[TextFormatT]: ... - text["format"] = _type_to_text_format_param(text_format) + def stream( + self, + *, + response_id: str | NotGiven = NOT_GIVEN, + input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, + model: Union[str, ChatModel] | NotGiven = NOT_GIVEN, + background: Optional[bool] | NotGiven = NOT_GIVEN, + text_format: type[TextFormatT] | NotGiven = NOT_GIVEN, + tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, + include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | NotGiven = NOT_GIVEN, + max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, + previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, + temperature: Optional[float] | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, + top_p: Optional[float] | NotGiven = NOT_GIVEN, + truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + starting_after: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> AsyncResponseStreamManager[TextFormatT]: + new_response_args = { + "input": input, + "model": model, + "include": include, + "instructions": instructions, + "max_output_tokens": max_output_tokens, + "metadata": metadata, + "parallel_tool_calls": parallel_tool_calls, + "previous_response_id": previous_response_id, + "reasoning": reasoning, + "store": store, + "temperature": temperature, + "text": text, + "tool_choice": tool_choice, + "top_p": top_p, + "truncation": truncation, + "user": user, + "background": background, + } + new_response_args_names = [k for k, v in new_response_args.items() if is_given(v)] + + if (is_given(response_id) or is_given(starting_after)) and len(new_response_args_names) > 0: + raise ValueError( + "Cannot provide both response_id/starting_after can't be provided together with " + + ", ".join(new_response_args_names) + ) tools = _make_tools(tools) + if len(new_response_args_names) > 0: + if isinstance(input, NotGiven): + raise ValueError("input must be provided when creating a new response") + + if not is_given(model): + raise ValueError("model must be provided when creating a new response") + + if is_given(text_format): + if not text: + text = {} + + if "format" in text: + raise TypeError("Cannot mix and match text.format with text_format") + + text["format"] = _type_to_text_format_param(text_format) + + api_request = self.create( + input=input, + model=model, + stream=True, + tools=tools, + include=include, + instructions=instructions, + max_output_tokens=max_output_tokens, + metadata=metadata, + parallel_tool_calls=parallel_tool_calls, + previous_response_id=previous_response_id, + store=store, + temperature=temperature, + text=text, + tool_choice=tool_choice, + reasoning=reasoning, + top_p=top_p, + truncation=truncation, + user=user, + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + ) - api_request = self.create( - input=input, - model=model, - tools=tools, - include=include, - instructions=instructions, - max_output_tokens=max_output_tokens, - metadata=metadata, - parallel_tool_calls=parallel_tool_calls, - previous_response_id=previous_response_id, - store=store, - stream=True, - temperature=temperature, - text=text, - tool_choice=tool_choice, - reasoning=reasoning, - top_p=top_p, - truncation=truncation, - user=user, - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - ) - - return AsyncResponseStreamManager( - api_request, - text_format=text_format, - input_tools=tools, - ) + return AsyncResponseStreamManager( + api_request, + text_format=text_format, + input_tools=tools, + starting_after=None, + ) + else: + if isinstance(response_id, NotGiven): + raise ValueError("response_id must be provided when streaming an existing response") + + api_request = self.retrieve( + response_id, + stream=True, + include=include or [], + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + ) + return AsyncResponseStreamManager( + api_request, + text_format=text_format, + input_tools=tools, + starting_after=starting_after if is_given(starting_after) else None, + ) async def parse( self, @@ -1811,6 +2077,7 @@ def parser(raw_response: Response) -> ParsedResponse[TextFormatT]: cast_to=cast(Type[ParsedResponse[TextFormatT]], Response), ) + @overload async def retrieve( self, response_id: str, @@ -1822,7 +2089,54 @@ async def retrieve( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Response: + ) -> Response: ... + + @overload + async def retrieve( + self, + response_id: str, + *, + stream: Literal[True], + include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + starting_after: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> AsyncStream[ResponseStreamEvent]: ... + + @overload + async def retrieve( + self, + response_id: str, + *, + stream: bool, + include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + starting_after: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Response | AsyncStream[ResponseStreamEvent]: ... + + async def retrieve( + self, + response_id: str, + *, + stream: bool = False, + include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + starting_after: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Response | AsyncStream[ResponseStreamEvent]: """ Retrieves a model response with the given ID. @@ -1830,6 +2144,10 @@ async def retrieve( include: Additional fields to include in the response. See the `include` parameter for Response creation above for more information. + stream: + starting_after: When retrieving a background response, this parameter can be used to start + replaying after an event with the given sequence number. Must be used in + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -1848,10 +2166,17 @@ async def retrieve( extra_body=extra_body, timeout=timeout, query=await async_maybe_transform( - {"include": include}, response_retrieve_params.ResponseRetrieveParams + { + "include": include, + "stream": stream, + "starting_after": starting_after, + }, + response_retrieve_params.ResponseRetrieveParams, ), ), cast_to=Response, + stream=stream or False, + stream_cls=AsyncStream[ResponseStreamEvent], ) async def delete( diff --git a/src/openai/types/chat/completion_create_params.py b/src/openai/types/chat/completion_create_params.py index 60d5f53cdd..5ea1c82f3d 100644 --- a/src/openai/types/chat/completion_create_params.py +++ b/src/openai/types/chat/completion_create_params.py @@ -292,9 +292,10 @@ class CompletionCreateParamsBase(TypedDict, total=False): """ user: str - """ - A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. + """A stable identifier for your end-users. + + Used to boost cache hit rates by better bucketing similar requests and to help + OpenAI detect and prevent abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). """ diff --git a/src/openai/types/responses/__init__.py b/src/openai/types/responses/__init__.py index 5cb00904f7..d33c26d23a 100644 --- a/src/openai/types/responses/__init__.py +++ b/src/openai/types/responses/__init__.py @@ -97,7 +97,6 @@ from .response_audio_transcript_done_event import ResponseAudioTranscriptDoneEvent as ResponseAudioTranscriptDoneEvent from .response_file_search_tool_call_param import ResponseFileSearchToolCallParam as ResponseFileSearchToolCallParam from .response_mcp_list_tools_failed_event import ResponseMcpListToolsFailedEvent as ResponseMcpListToolsFailedEvent -from .response_text_annotation_delta_event import ResponseTextAnnotationDeltaEvent as ResponseTextAnnotationDeltaEvent from .response_audio_transcript_delta_event import ( ResponseAudioTranscriptDeltaEvent as ResponseAudioTranscriptDeltaEvent, ) diff --git a/src/openai/types/responses/input_item_list_params.py b/src/openai/types/responses/input_item_list_params.py index 6555d26788..6a18d920cb 100644 --- a/src/openai/types/responses/input_item_list_params.py +++ b/src/openai/types/responses/input_item_list_params.py @@ -30,7 +30,7 @@ class InputItemListParams(TypedDict, total=False): """ order: Literal["asc", "desc"] - """The order to return the input items in. Default is `asc`. + """The order to return the input items in. Default is `desc`. - `asc`: Return the input items in ascending order. - `desc`: Return the input items in descending order. diff --git a/src/openai/types/responses/response.py b/src/openai/types/responses/response.py index 14656f5aec..0d30d58ddb 100644 --- a/src/openai/types/responses/response.py +++ b/src/openai/types/responses/response.py @@ -209,9 +209,10 @@ class Response(BaseModel): """ user: Optional[str] = None - """ - A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. + """A stable identifier for your end-users. + + Used to boost cache hit rates by better bucketing similar requests and to help + OpenAI detect and prevent abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). """ diff --git a/src/openai/types/responses/response_create_params.py b/src/openai/types/responses/response_create_params.py index d7bb5817c2..28b2b59135 100644 --- a/src/openai/types/responses/response_create_params.py +++ b/src/openai/types/responses/response_create_params.py @@ -199,9 +199,10 @@ class ResponseCreateParamsBase(TypedDict, total=False): """ user: str - """ - A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. + """A stable identifier for your end-users. + + Used to boost cache hit rates by better bucketing similar requests and to help + OpenAI detect and prevent abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). """ diff --git a/src/openai/types/responses/response_stream_event.py b/src/openai/types/responses/response_stream_event.py index e6e59a760a..24a83f1aa2 100644 --- a/src/openai/types/responses/response_stream_event.py +++ b/src/openai/types/responses/response_stream_event.py @@ -28,7 +28,6 @@ from .response_mcp_call_in_progress_event import ResponseMcpCallInProgressEvent from .response_audio_transcript_done_event import ResponseAudioTranscriptDoneEvent from .response_mcp_list_tools_failed_event import ResponseMcpListToolsFailedEvent -from .response_text_annotation_delta_event import ResponseTextAnnotationDeltaEvent from .response_audio_transcript_delta_event import ResponseAudioTranscriptDeltaEvent from .response_reasoning_summary_done_event import ResponseReasoningSummaryDoneEvent from .response_mcp_call_arguments_done_event import ResponseMcpCallArgumentsDoneEvent @@ -93,7 +92,6 @@ ResponseReasoningSummaryTextDoneEvent, ResponseRefusalDeltaEvent, ResponseRefusalDoneEvent, - ResponseTextAnnotationDeltaEvent, ResponseTextDeltaEvent, ResponseTextDoneEvent, ResponseWebSearchCallCompletedEvent, diff --git a/src/openai/types/responses/response_text_annotation_delta_event.py b/src/openai/types/responses/response_text_annotation_delta_event.py deleted file mode 100644 index 43d70bacac..0000000000 --- a/src/openai/types/responses/response_text_annotation_delta_event.py +++ /dev/null @@ -1,82 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Literal, Annotated, TypeAlias - -from ..._utils import PropertyInfo -from ..._models import BaseModel - -__all__ = [ - "ResponseTextAnnotationDeltaEvent", - "Annotation", - "AnnotationFileCitation", - "AnnotationURLCitation", - "AnnotationFilePath", -] - - -class AnnotationFileCitation(BaseModel): - file_id: str - """The ID of the file.""" - - index: int - """The index of the file in the list of files.""" - - type: Literal["file_citation"] - """The type of the file citation. Always `file_citation`.""" - - -class AnnotationURLCitation(BaseModel): - end_index: int - """The index of the last character of the URL citation in the message.""" - - start_index: int - """The index of the first character of the URL citation in the message.""" - - title: str - """The title of the web resource.""" - - type: Literal["url_citation"] - """The type of the URL citation. Always `url_citation`.""" - - url: str - """The URL of the web resource.""" - - -class AnnotationFilePath(BaseModel): - file_id: str - """The ID of the file.""" - - index: int - """The index of the file in the list of files.""" - - type: Literal["file_path"] - """The type of the file path. Always `file_path`.""" - - -Annotation: TypeAlias = Annotated[ - Union[AnnotationFileCitation, AnnotationURLCitation, AnnotationFilePath], PropertyInfo(discriminator="type") -] - - -class ResponseTextAnnotationDeltaEvent(BaseModel): - annotation: Annotation - """A citation to a file.""" - - annotation_index: int - """The index of the annotation that was added.""" - - content_index: int - """The index of the content part that the text annotation was added to.""" - - item_id: str - """The ID of the output item that the text annotation was added to.""" - - output_index: int - """The index of the output item that the text annotation was added to.""" - - sequence_number: int - """The sequence number of this event.""" - - type: Literal["response.output_text.annotation.added"] - """The type of the event. Always `response.output_text.annotation.added`.""" diff --git a/src/openai/types/responses/response_web_search_call_completed_event.py b/src/openai/types/responses/response_web_search_call_completed_event.py index 76f26766a1..497f7bfe35 100644 --- a/src/openai/types/responses/response_web_search_call_completed_event.py +++ b/src/openai/types/responses/response_web_search_call_completed_event.py @@ -14,5 +14,8 @@ class ResponseWebSearchCallCompletedEvent(BaseModel): output_index: int """The index of the output item that the web search call is associated with.""" + sequence_number: int + """The sequence number of the web search call being processed.""" + type: Literal["response.web_search_call.completed"] """The type of the event. Always `response.web_search_call.completed`.""" diff --git a/src/openai/types/responses/response_web_search_call_in_progress_event.py b/src/openai/types/responses/response_web_search_call_in_progress_event.py index 681ce6d94b..da8b3fe404 100644 --- a/src/openai/types/responses/response_web_search_call_in_progress_event.py +++ b/src/openai/types/responses/response_web_search_call_in_progress_event.py @@ -14,5 +14,8 @@ class ResponseWebSearchCallInProgressEvent(BaseModel): output_index: int """The index of the output item that the web search call is associated with.""" + sequence_number: int + """The sequence number of the web search call being processed.""" + type: Literal["response.web_search_call.in_progress"] """The type of the event. Always `response.web_search_call.in_progress`.""" diff --git a/src/openai/types/responses/response_web_search_call_searching_event.py b/src/openai/types/responses/response_web_search_call_searching_event.py index c885d98918..42df9cb298 100644 --- a/src/openai/types/responses/response_web_search_call_searching_event.py +++ b/src/openai/types/responses/response_web_search_call_searching_event.py @@ -14,5 +14,8 @@ class ResponseWebSearchCallSearchingEvent(BaseModel): output_index: int """The index of the output item that the web search call is associated with.""" + sequence_number: int + """The sequence number of the web search call being processed.""" + type: Literal["response.web_search_call.searching"] """The type of the event. Always `response.web_search_call.searching`.""" diff --git a/src/openai/types/responses/tool.py b/src/openai/types/responses/tool.py index 0d80cdc89d..904c474e40 100644 --- a/src/openai/types/responses/tool.py +++ b/src/openai/types/responses/tool.py @@ -53,9 +53,6 @@ class McpRequireApprovalMcpToolApprovalFilter(BaseModel): never: Optional[McpRequireApprovalMcpToolApprovalFilterNever] = None """A list of tools that never require approval.""" - tool_names: Optional[List[str]] = None - """List of allowed tool names.""" - McpRequireApproval: TypeAlias = Union[McpRequireApprovalMcpToolApprovalFilter, Literal["always", "never"], None] diff --git a/src/openai/types/responses/tool_param.py b/src/openai/types/responses/tool_param.py index e9da040908..378226c124 100644 --- a/src/openai/types/responses/tool_param.py +++ b/src/openai/types/responses/tool_param.py @@ -53,9 +53,6 @@ class McpRequireApprovalMcpToolApprovalFilter(TypedDict, total=False): never: McpRequireApprovalMcpToolApprovalFilterNever """A list of tools that never require approval.""" - tool_names: List[str] - """List of allowed tool names.""" - McpRequireApproval: TypeAlias = Union[McpRequireApprovalMcpToolApprovalFilter, Literal["always", "never"]] From 7447544f95bbbf13bfca529b6087bab1ca10d3bd Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 22 May 2025 21:06:11 +0000 Subject: [PATCH 340/769] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 017aa58a1c..d761f22d73 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-fc64d7c2c8f51f750813375356c3f3fdfc7fc1b1b34f19c20a5410279d445d37.yml openapi_spec_hash: 618285fc70199ee32b9ebe4bf72f7e4c -config_hash: c497f6b750cc89c0bf2eefc0bc839c70 +config_hash: 535b6e5f26a295d609b259c8cb8f656c From 217f6d17e344d8925b3bdbf9b2502d0d7b9aaeea Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 22 May 2025 21:29:28 +0000 Subject: [PATCH 341/769] chore(internal): fix release workflows --- bin/check-release-environment | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bin/check-release-environment b/bin/check-release-environment index 5471b69edb..2cc5ad6352 100644 --- a/bin/check-release-environment +++ b/bin/check-release-environment @@ -2,6 +2,10 @@ errors=() +if [ -z "${STAINLESS_API_KEY}" ]; then + errors+=("The STAINLESS_API_KEY secret has not been set. Please contact Stainless for an API key & set it in your organization secrets on GitHub.") +fi + if [ -z "${PYPI_TOKEN}" ]; then errors+=("The OPENAI_PYPI_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets.") fi From 60ec9dfe7fd21a98a9e17619f4d01db294ff125e Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Tue, 27 May 2025 13:34:30 +0100 Subject: [PATCH 342/769] fix(responses): don't include `parsed_arguments` when re-serialising --- src/openai/_utils/_transform.py | 2 +- src/openai/types/responses/parsed_response.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/openai/_utils/_transform.py b/src/openai/_utils/_transform.py index b0cc20a735..60f9dfcbcb 100644 --- a/src/openai/_utils/_transform.py +++ b/src/openai/_utils/_transform.py @@ -212,7 +212,7 @@ def _transform_recursive( return data if isinstance(data, pydantic.BaseModel): - return model_dump(data, exclude_unset=True, mode="json") + return model_dump(data, exclude_unset=True, mode="json", exclude=getattr(data, '__api_exclude__', None)) annotated_type = _get_annotated_type(annotation) if annotated_type is None: diff --git a/src/openai/types/responses/parsed_response.py b/src/openai/types/responses/parsed_response.py index 923e9debba..f0b85f7209 100644 --- a/src/openai/types/responses/parsed_response.py +++ b/src/openai/types/responses/parsed_response.py @@ -55,6 +55,8 @@ class ParsedResponseOutputMessage(ResponseOutputMessage, GenericModel, Generic[C class ParsedResponseFunctionToolCall(ResponseFunctionToolCall): parsed_arguments: object = None + __api_exclude__ = {'parsed_arguments'} + ParsedResponseOutputItem: TypeAlias = Annotated[ Union[ From 9173f3d37594ba603c350ac2263e12c5423b51b9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 29 May 2025 05:03:50 +0000 Subject: [PATCH 343/769] release: 1.82.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index fc2c3ec04d..a4c14007b3 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.82.0" + ".": "1.82.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index a354b8735a..31b7792a53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 1.82.1 (2025-05-29) + +Full Changelog: [v1.82.0...v1.82.1](https://github.com/openai/openai-python/compare/v1.82.0...v1.82.1) + +### Bug Fixes + +* **responses:** don't include `parsed_arguments` when re-serialising ([6d04193](https://github.com/openai/openai-python/commit/6d041937963ce452affcfb3553146ee51acfeb7a)) + + +### Chores + +* **internal:** fix release workflows ([361a909](https://github.com/openai/openai-python/commit/361a909a0cc83e5029ea425fd72202ffa8d1a46a)) + ## 1.82.0 (2025-05-22) Full Changelog: [v1.81.0...v1.82.0](https://github.com/openai/openai-python/compare/v1.81.0...v1.82.0) diff --git a/pyproject.toml b/pyproject.toml index b8580d854a..190e9bbbfa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.82.0" +version = "1.82.1" 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 8fc27e8457..9bf34c1f6b 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.82.0" # x-release-please-version +__version__ = "1.82.1" # x-release-please-version From cca0970798c2735ffb58879ed494e81f80ffc6af Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 2 Jun 2025 14:39:03 -0500 Subject: [PATCH 344/769] release: 1.83.0 (#2393) * Fix a typo: "occurences" -> "occurrences" (#2387) * chore: deprecate Assistants API * chore(api): mark some methods as deprecated * feat(api): Config update for pakrym-stream-param * fix(client): return binary content from `get /containers/{container_id}/files/{file_id}/content` * codegen metadata * chore(docs): remove reference to rye shell * feat(client): add follow_redirects request option * fix(api): Fix evals and code interpreter interfaces * release: 1.83.0 --------- Co-authored-by: Roman A <121314722+GameRoMan@users.noreply.github.com> Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- .stats.yml | 6 +- CHANGELOG.md | 22 + CONTRIBUTING.md | 3 +- api.md | 4 +- examples/assistant.py | 37 - examples/assistant_stream.py | 33 - examples/assistant_stream_helpers.py | 78 - pyproject.toml | 2 +- src/openai/_base_client.py | 6 + src/openai/_models.py | 2 + src/openai/_types.py | 2 + src/openai/_utils/_transform.py | 2 +- src/openai/_version.py | 2 +- src/openai/lib/_parsing/_responses.py | 2 +- .../resources/beta/realtime/sessions.py | 8 + .../beta/realtime/transcription_sessions.py | 8 + src/openai/resources/beta/threads/messages.py | 131 +- .../resources/beta/threads/runs/runs.py | 209 ++- .../resources/beta/threads/runs/steps.py | 53 +- src/openai/resources/beta/threads/threads.py | 147 +- .../resources/chat/completions/completions.py | 24 +- .../resources/containers/files/content.py | 27 +- .../resources/fine_tuning/alpha/graders.py | 30 +- src/openai/resources/images.py | 4 +- src/openai/resources/responses/responses.py | 270 +++- .../audio/transcription_text_delta_event.py | 2 +- .../audio/transcription_text_done_event.py | 2 +- .../beta/realtime/session_create_params.py | 32 +- .../beta/realtime/session_update_event.py | 24 + .../realtime/session_update_event_param.py | 24 + .../transcription_session_create_params.py | 31 +- .../realtime/transcription_session_update.py | 24 + .../transcription_session_update_param.py | 24 + src/openai/types/chat/chat_completion.py | 4 +- .../types/chat/chat_completion_chunk.py | 4 +- .../types/chat/completion_create_params.py | 4 +- .../fine_tuning/alpha/grader_run_params.py | 18 +- .../types/fine_tuning/fine_tuning_job.py | 2 +- src/openai/types/graders/multi_grader.py | 8 +- .../types/graders/multi_grader_param.py | 8 +- src/openai/types/image_edit_params.py | 2 +- src/openai/types/responses/parsed_response.py | 2 +- src/openai/types/responses/response.py | 4 +- ..._code_interpreter_call_code_delta_event.py | 4 +- ...e_code_interpreter_call_code_done_event.py | 4 +- .../types/responses/response_create_params.py | 6 +- .../types/responses/response_includable.py | 1 + .../types/responses/response_output_text.py | 53 +- .../responses/response_output_text_param.py | 44 +- .../responses/response_retrieve_params.py | 38 +- src/openai/types/responses/tool_param.py | 3 +- .../beta/realtime/test_sessions.py | 12 + .../realtime/test_transcription_sessions.py | 12 + tests/api_resources/beta/test_threads.py | 966 ++++++------ .../beta/threads/runs/test_steps.py | 356 +++-- .../beta/threads/test_messages.py | 646 ++++---- tests/api_resources/beta/threads/test_runs.py | 1316 +++++++++-------- .../containers/files/test_content.py | 60 +- .../fine_tuning/alpha/test_graders.py | 10 +- tests/api_resources/test_responses.py | 138 +- tests/lib/chat/_utils.py | 2 +- tests/lib/test_assistants.py | 12 +- tests/test_client.py | 54 + 64 files changed, 3101 insertions(+), 1969 deletions(-) delete mode 100644 examples/assistant.py delete mode 100644 examples/assistant_stream.py delete mode 100644 examples/assistant_stream_helpers.py diff --git a/.release-please-manifest.json b/.release-please-manifest.json index a4c14007b3..0453d70e4a 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.82.1" + ".": "1.83.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index d761f22d73..6f5097c531 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-fc64d7c2c8f51f750813375356c3f3fdfc7fc1b1b34f19c20a5410279d445d37.yml -openapi_spec_hash: 618285fc70199ee32b9ebe4bf72f7e4c -config_hash: 535b6e5f26a295d609b259c8cb8f656c +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-2bcc845d8635bf93ddcf9ee723af4d7928248412a417bee5fc10d863a1e13867.yml +openapi_spec_hash: 865230cb3abeb01bd85de05891af23c4 +config_hash: ed1e6b3c5f93d12b80d31167f55c557c diff --git a/CHANGELOG.md b/CHANGELOG.md index 31b7792a53..645599e6df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,27 @@ # Changelog +## 1.83.0 (2025-06-02) + +Full Changelog: [v1.82.1...v1.83.0](https://github.com/openai/openai-python/compare/v1.82.1...v1.83.0) + +### Features + +* **api:** Config update for pakrym-stream-param ([88bcf3a](https://github.com/openai/openai-python/commit/88bcf3af9ce8ffa8347547d4d30aacac1ceba939)) +* **client:** add follow_redirects request option ([26d715f](https://github.com/openai/openai-python/commit/26d715f4e9b0f2b19e2ac16acc796a949338e1e1)) + + +### Bug Fixes + +* **api:** Fix evals and code interpreter interfaces ([2650159](https://github.com/openai/openai-python/commit/2650159f6d01f6eb481cf8c7942142e4fd21ce44)) +* **client:** return binary content from `get /containers/{container_id}/files/{file_id}/content` ([f7c80c4](https://github.com/openai/openai-python/commit/f7c80c4368434bd0be7436375076ba33a62f63b5)) + + +### Chores + +* **api:** mark some methods as deprecated ([3e2ca57](https://github.com/openai/openai-python/commit/3e2ca571cb6cdd9e15596590605b2f98a4c5a42e)) +* deprecate Assistants API ([9d166d7](https://github.com/openai/openai-python/commit/9d166d795e03dea49af680ec9597e9497522187c)) +* **docs:** remove reference to rye shell ([c7978e9](https://github.com/openai/openai-python/commit/c7978e9f1640c311022988fcd716cbb5c865daa8)) + ## 1.82.1 (2025-05-29) Full Changelog: [v1.82.0...v1.82.1](https://github.com/openai/openai-python/compare/v1.82.0...v1.82.1) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 52c2eb213a..c14e652328 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,8 +17,7 @@ $ rye sync --all-features You can then run scripts using `rye run python script.py` or by activating the virtual environment: ```sh -$ rye shell -# or manually activate - https://docs.python.org/3/library/venv.html#how-venvs-work +# Activate the virtual environment - https://docs.python.org/3/library/venv.html#how-venvs-work $ source .venv/bin/activate # now you can omit the `rye run` prefix diff --git a/api.md b/api.md index 73d50fa328..732436aacd 100644 --- a/api.md +++ b/api.md @@ -784,7 +784,7 @@ Methods: - client.responses.create(\*\*params) -> Response - client.responses.retrieve(response_id, \*\*params) -> Response - client.responses.delete(response_id) -> None -- client.responses.cancel(response_id) -> None +- client.responses.cancel(response_id) -> Response ## InputItems @@ -894,4 +894,4 @@ Methods: Methods: -- client.containers.files.content.retrieve(file_id, \*, container_id) -> None +- client.containers.files.content.retrieve(file_id, \*, container_id) -> HttpxBinaryResponseContent diff --git a/examples/assistant.py b/examples/assistant.py deleted file mode 100644 index f6924a0c7d..0000000000 --- a/examples/assistant.py +++ /dev/null @@ -1,37 +0,0 @@ -import openai - -# gets API Key from environment variable OPENAI_API_KEY -client = openai.OpenAI() - -assistant = client.beta.assistants.create( - name="Math Tutor", - instructions="You are a personal math tutor. Write and run code to answer math questions.", - tools=[{"type": "code_interpreter"}], - model="gpt-4-1106-preview", -) - -thread = client.beta.threads.create() - -message = client.beta.threads.messages.create( - thread_id=thread.id, - role="user", - content="I need to solve the equation `3x + 11 = 14`. Can you help me?", -) - -run = client.beta.threads.runs.create_and_poll( - thread_id=thread.id, - assistant_id=assistant.id, - instructions="Please address the user as Jane Doe. The user has a premium account.", -) - -print("Run completed with status: " + run.status) - -if run.status == "completed": - messages = client.beta.threads.messages.list(thread_id=thread.id) - - print("messages: ") - for message in messages: - assert message.content[0].type == "text" - print({"role": message.role, "message": message.content[0].text.value}) - - client.beta.assistants.delete(assistant.id) diff --git a/examples/assistant_stream.py b/examples/assistant_stream.py deleted file mode 100644 index 0465d3930f..0000000000 --- a/examples/assistant_stream.py +++ /dev/null @@ -1,33 +0,0 @@ -import openai - -# gets API Key from environment variable OPENAI_API_KEY -client = openai.OpenAI() - -assistant = client.beta.assistants.create( - name="Math Tutor", - instructions="You are a personal math tutor. Write and run code to answer math questions.", - tools=[{"type": "code_interpreter"}], - model="gpt-4-1106-preview", -) - -thread = client.beta.threads.create() - -message = client.beta.threads.messages.create( - thread_id=thread.id, - role="user", - content="I need to solve the equation `3x + 11 = 14`. Can you help me?", -) - -print("starting run stream") - -stream = client.beta.threads.runs.create( - thread_id=thread.id, - assistant_id=assistant.id, - instructions="Please address the user as Jane Doe. The user has a premium account.", - stream=True, -) - -for event in stream: - print(event.model_dump_json(indent=2, exclude_unset=True)) - -client.beta.assistants.delete(assistant.id) diff --git a/examples/assistant_stream_helpers.py b/examples/assistant_stream_helpers.py deleted file mode 100644 index 7baec77c72..0000000000 --- a/examples/assistant_stream_helpers.py +++ /dev/null @@ -1,78 +0,0 @@ -from __future__ import annotations - -from typing_extensions import override - -import openai -from openai import AssistantEventHandler -from openai.types.beta import AssistantStreamEvent -from openai.types.beta.threads import Text, TextDelta -from openai.types.beta.threads.runs import RunStep, RunStepDelta - - -class EventHandler(AssistantEventHandler): - @override - def on_event(self, event: AssistantStreamEvent) -> None: - if event.event == "thread.run.step.created": - details = event.data.step_details - if details.type == "tool_calls": - print("Generating code to interpret:\n\n```py") - elif event.event == "thread.message.created": - print("\nResponse:\n") - - @override - def on_text_delta(self, delta: TextDelta, snapshot: Text) -> None: - print(delta.value, end="", flush=True) - - @override - def on_run_step_done(self, run_step: RunStep) -> None: - details = run_step.step_details - if details.type == "tool_calls": - for tool in details.tool_calls: - if tool.type == "code_interpreter": - print("\n```\nExecuting code...") - - @override - def on_run_step_delta(self, delta: RunStepDelta, snapshot: RunStep) -> None: - details = delta.step_details - if details is not None and details.type == "tool_calls": - for tool in details.tool_calls or []: - if tool.type == "code_interpreter" and tool.code_interpreter and tool.code_interpreter.input: - print(tool.code_interpreter.input, end="", flush=True) - - -def main() -> None: - client = openai.OpenAI() - - assistant = client.beta.assistants.create( - name="Math Tutor", - instructions="You are a personal math tutor. Write and run code to answer math questions.", - tools=[{"type": "code_interpreter"}], - model="gpt-4-1106-preview", - ) - - try: - question = "I need to solve the equation `3x + 11 = 14`. Can you help me?" - - thread = client.beta.threads.create( - messages=[ - { - "role": "user", - "content": question, - }, - ] - ) - print(f"Question: {question}\n") - - with client.beta.threads.runs.stream( - thread_id=thread.id, - assistant_id=assistant.id, - instructions="Please address the user as Jane Doe. The user has a premium account.", - event_handler=EventHandler(), - ) as stream: - stream.until_done() - print() - finally: - client.beta.assistants.delete(assistant.id) - - -main() diff --git a/pyproject.toml b/pyproject.toml index 190e9bbbfa..7d3cd30413 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.82.1" +version = "1.83.0" description = "The official Python library for the openai API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index a0f9cce7d8..44b3603008 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -962,6 +962,9 @@ def request( if self.custom_auth is not None: kwargs["auth"] = self.custom_auth + if options.follow_redirects is not None: + kwargs["follow_redirects"] = options.follow_redirects + log.debug("Sending HTTP Request: %s %s", request.method, request.url) response = None @@ -1477,6 +1480,9 @@ async def request( if self.custom_auth is not None: kwargs["auth"] = self.custom_auth + if options.follow_redirects is not None: + kwargs["follow_redirects"] = options.follow_redirects + log.debug("Sending HTTP Request: %s %s", request.method, request.url) response = None diff --git a/src/openai/_models.py b/src/openai/_models.py index e2fce49250..065e8da760 100644 --- a/src/openai/_models.py +++ b/src/openai/_models.py @@ -777,6 +777,7 @@ class FinalRequestOptionsInput(TypedDict, total=False): idempotency_key: str json_data: Body extra_json: AnyMapping + follow_redirects: bool @final @@ -790,6 +791,7 @@ class FinalRequestOptions(pydantic.BaseModel): files: Union[HttpxRequestFiles, None] = None idempotency_key: Union[str, None] = None post_parser: Union[Callable[[Any], Any], NotGiven] = NotGiven() + follow_redirects: Union[bool, None] = None # It should be noted that we cannot use `json` here as that would override # a BaseModel method in an incompatible fashion. diff --git a/src/openai/_types.py b/src/openai/_types.py index a5cf207aa3..5dae55f4a9 100644 --- a/src/openai/_types.py +++ b/src/openai/_types.py @@ -101,6 +101,7 @@ class RequestOptions(TypedDict, total=False): params: Query extra_json: AnyMapping idempotency_key: str + follow_redirects: bool # Sentinel class used until PEP 0661 is accepted @@ -217,3 +218,4 @@ class _GenericAlias(Protocol): class HttpxSendArgs(TypedDict, total=False): auth: httpx.Auth + follow_redirects: bool diff --git a/src/openai/_utils/_transform.py b/src/openai/_utils/_transform.py index 60f9dfcbcb..4fd49a1908 100644 --- a/src/openai/_utils/_transform.py +++ b/src/openai/_utils/_transform.py @@ -212,7 +212,7 @@ def _transform_recursive( return data if isinstance(data, pydantic.BaseModel): - return model_dump(data, exclude_unset=True, mode="json", exclude=getattr(data, '__api_exclude__', None)) + return model_dump(data, exclude_unset=True, mode="json", exclude=getattr(data, "__api_exclude__", None)) annotated_type = _get_annotated_type(annotation) if annotated_type is None: diff --git a/src/openai/_version.py b/src/openai/_version.py index 9bf34c1f6b..d947f7a74a 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.82.1" # x-release-please-version +__version__ = "1.83.0" # x-release-please-version diff --git a/src/openai/lib/_parsing/_responses.py b/src/openai/lib/_parsing/_responses.py index 235f912405..41be1d37b0 100644 --- a/src/openai/lib/_parsing/_responses.py +++ b/src/openai/lib/_parsing/_responses.py @@ -109,7 +109,7 @@ def parse_response( or output.type == "code_interpreter_call" or output.type == "local_shell_call" or output.type == "mcp_list_tools" - or output.type == 'exec' + or output.type == "exec" ): output_list.append(output) elif TYPE_CHECKING: # type: ignore diff --git a/src/openai/resources/beta/realtime/sessions.py b/src/openai/resources/beta/realtime/sessions.py index 3c0d4d47c1..90d8b8fdc4 100644 --- a/src/openai/resources/beta/realtime/sessions.py +++ b/src/openai/resources/beta/realtime/sessions.py @@ -43,6 +43,7 @@ def with_streaming_response(self) -> SessionsWithStreamingResponse: def create( self, *, + client_secret: session_create_params.ClientSecret | NotGiven = NOT_GIVEN, input_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] | NotGiven = NOT_GIVEN, input_audio_noise_reduction: session_create_params.InputAudioNoiseReduction | NotGiven = NOT_GIVEN, input_audio_transcription: session_create_params.InputAudioTranscription | NotGiven = NOT_GIVEN, @@ -83,6 +84,8 @@ def create( the Realtime API. Args: + client_secret: Configuration options for the generated client secret. + input_audio_format: The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, input audio must be 16-bit PCM at a 24kHz sample rate, single channel (mono), and little-endian byte order. @@ -163,6 +166,7 @@ def create( "/realtime/sessions", body=maybe_transform( { + "client_secret": client_secret, "input_audio_format": input_audio_format, "input_audio_noise_reduction": input_audio_noise_reduction, "input_audio_transcription": input_audio_transcription, @@ -209,6 +213,7 @@ def with_streaming_response(self) -> AsyncSessionsWithStreamingResponse: async def create( self, *, + client_secret: session_create_params.ClientSecret | NotGiven = NOT_GIVEN, input_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] | NotGiven = NOT_GIVEN, input_audio_noise_reduction: session_create_params.InputAudioNoiseReduction | NotGiven = NOT_GIVEN, input_audio_transcription: session_create_params.InputAudioTranscription | NotGiven = NOT_GIVEN, @@ -249,6 +254,8 @@ async def create( the Realtime API. Args: + client_secret: Configuration options for the generated client secret. + input_audio_format: The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, input audio must be 16-bit PCM at a 24kHz sample rate, single channel (mono), and little-endian byte order. @@ -329,6 +336,7 @@ async def create( "/realtime/sessions", body=await async_maybe_transform( { + "client_secret": client_secret, "input_audio_format": input_audio_format, "input_audio_noise_reduction": input_audio_noise_reduction, "input_audio_transcription": input_audio_transcription, diff --git a/src/openai/resources/beta/realtime/transcription_sessions.py b/src/openai/resources/beta/realtime/transcription_sessions.py index dbcb1bb33b..5f97b3c8e3 100644 --- a/src/openai/resources/beta/realtime/transcription_sessions.py +++ b/src/openai/resources/beta/realtime/transcription_sessions.py @@ -43,6 +43,7 @@ def with_streaming_response(self) -> TranscriptionSessionsWithStreamingResponse: def create( self, *, + client_secret: transcription_session_create_params.ClientSecret | NotGiven = NOT_GIVEN, include: List[str] | NotGiven = NOT_GIVEN, input_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] | NotGiven = NOT_GIVEN, input_audio_noise_reduction: transcription_session_create_params.InputAudioNoiseReduction @@ -67,6 +68,8 @@ def create( the Realtime API. Args: + client_secret: Configuration options for the generated client secret. + include: The set of items to include in the transcription. Current available items are: @@ -113,6 +116,7 @@ def create( "/realtime/transcription_sessions", body=maybe_transform( { + "client_secret": client_secret, "include": include, "input_audio_format": input_audio_format, "input_audio_noise_reduction": input_audio_noise_reduction, @@ -152,6 +156,7 @@ def with_streaming_response(self) -> AsyncTranscriptionSessionsWithStreamingResp async def create( self, *, + client_secret: transcription_session_create_params.ClientSecret | NotGiven = NOT_GIVEN, include: List[str] | NotGiven = NOT_GIVEN, input_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] | NotGiven = NOT_GIVEN, input_audio_noise_reduction: transcription_session_create_params.InputAudioNoiseReduction @@ -176,6 +181,8 @@ async def create( the Realtime API. Args: + client_secret: Configuration options for the generated client secret. + include: The set of items to include in the transcription. Current available items are: @@ -222,6 +229,7 @@ async def create( "/realtime/transcription_sessions", body=await async_maybe_transform( { + "client_secret": client_secret, "include": include, "input_audio_format": input_audio_format, "input_audio_noise_reduction": input_audio_noise_reduction, diff --git a/src/openai/resources/beta/threads/messages.py b/src/openai/resources/beta/threads/messages.py index 3a8913ef16..943d2e7f05 100644 --- a/src/openai/resources/beta/threads/messages.py +++ b/src/openai/resources/beta/threads/messages.py @@ -2,6 +2,7 @@ from __future__ import annotations +import typing_extensions from typing import Union, Iterable, Optional from typing_extensions import Literal @@ -47,6 +48,7 @@ def with_streaming_response(self) -> MessagesWithStreamingResponse: """ return MessagesWithStreamingResponse(self) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def create( self, thread_id: str, @@ -113,6 +115,7 @@ def create( cast_to=Message, ) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def retrieve( self, message_id: str, @@ -150,6 +153,7 @@ def retrieve( cast_to=Message, ) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def update( self, message_id: str, @@ -196,6 +200,7 @@ def update( cast_to=Message, ) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def list( self, thread_id: str, @@ -267,6 +272,7 @@ def list( model=Message, ) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def delete( self, message_id: str, @@ -325,6 +331,7 @@ def with_streaming_response(self) -> AsyncMessagesWithStreamingResponse: """ return AsyncMessagesWithStreamingResponse(self) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") async def create( self, thread_id: str, @@ -391,6 +398,7 @@ async def create( cast_to=Message, ) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") async def retrieve( self, message_id: str, @@ -428,6 +436,7 @@ async def retrieve( cast_to=Message, ) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") async def update( self, message_id: str, @@ -474,6 +483,7 @@ async def update( cast_to=Message, ) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def list( self, thread_id: str, @@ -545,6 +555,7 @@ def list( model=Message, ) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") async def delete( self, message_id: str, @@ -587,20 +598,30 @@ class MessagesWithRawResponse: def __init__(self, messages: Messages) -> None: self._messages = messages - self.create = _legacy_response.to_raw_response_wrapper( - messages.create, + self.create = ( # pyright: ignore[reportDeprecated] + _legacy_response.to_raw_response_wrapper( + messages.create # pyright: ignore[reportDeprecated], + ) ) - self.retrieve = _legacy_response.to_raw_response_wrapper( - messages.retrieve, + self.retrieve = ( # pyright: ignore[reportDeprecated] + _legacy_response.to_raw_response_wrapper( + messages.retrieve # pyright: ignore[reportDeprecated], + ) ) - self.update = _legacy_response.to_raw_response_wrapper( - messages.update, + self.update = ( # pyright: ignore[reportDeprecated] + _legacy_response.to_raw_response_wrapper( + messages.update # pyright: ignore[reportDeprecated], + ) ) - self.list = _legacy_response.to_raw_response_wrapper( - messages.list, + self.list = ( # pyright: ignore[reportDeprecated] + _legacy_response.to_raw_response_wrapper( + messages.list # pyright: ignore[reportDeprecated], + ) ) - self.delete = _legacy_response.to_raw_response_wrapper( - messages.delete, + self.delete = ( # pyright: ignore[reportDeprecated] + _legacy_response.to_raw_response_wrapper( + messages.delete # pyright: ignore[reportDeprecated], + ) ) @@ -608,20 +629,30 @@ class AsyncMessagesWithRawResponse: def __init__(self, messages: AsyncMessages) -> None: self._messages = messages - self.create = _legacy_response.async_to_raw_response_wrapper( - messages.create, + self.create = ( # pyright: ignore[reportDeprecated] + _legacy_response.async_to_raw_response_wrapper( + messages.create # pyright: ignore[reportDeprecated], + ) ) - self.retrieve = _legacy_response.async_to_raw_response_wrapper( - messages.retrieve, + self.retrieve = ( # pyright: ignore[reportDeprecated] + _legacy_response.async_to_raw_response_wrapper( + messages.retrieve # pyright: ignore[reportDeprecated], + ) ) - self.update = _legacy_response.async_to_raw_response_wrapper( - messages.update, + self.update = ( # pyright: ignore[reportDeprecated] + _legacy_response.async_to_raw_response_wrapper( + messages.update # pyright: ignore[reportDeprecated], + ) ) - self.list = _legacy_response.async_to_raw_response_wrapper( - messages.list, + self.list = ( # pyright: ignore[reportDeprecated] + _legacy_response.async_to_raw_response_wrapper( + messages.list # pyright: ignore[reportDeprecated], + ) ) - self.delete = _legacy_response.async_to_raw_response_wrapper( - messages.delete, + self.delete = ( # pyright: ignore[reportDeprecated] + _legacy_response.async_to_raw_response_wrapper( + messages.delete # pyright: ignore[reportDeprecated], + ) ) @@ -629,20 +660,30 @@ class MessagesWithStreamingResponse: def __init__(self, messages: Messages) -> None: self._messages = messages - self.create = to_streamed_response_wrapper( - messages.create, + self.create = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + messages.create # pyright: ignore[reportDeprecated], + ) ) - self.retrieve = to_streamed_response_wrapper( - messages.retrieve, + self.retrieve = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + messages.retrieve # pyright: ignore[reportDeprecated], + ) ) - self.update = to_streamed_response_wrapper( - messages.update, + self.update = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + messages.update # pyright: ignore[reportDeprecated], + ) ) - self.list = to_streamed_response_wrapper( - messages.list, + self.list = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + messages.list # pyright: ignore[reportDeprecated], + ) ) - self.delete = to_streamed_response_wrapper( - messages.delete, + self.delete = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + messages.delete # pyright: ignore[reportDeprecated], + ) ) @@ -650,18 +691,28 @@ class AsyncMessagesWithStreamingResponse: def __init__(self, messages: AsyncMessages) -> None: self._messages = messages - self.create = async_to_streamed_response_wrapper( - messages.create, + self.create = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + messages.create # pyright: ignore[reportDeprecated], + ) ) - self.retrieve = async_to_streamed_response_wrapper( - messages.retrieve, + self.retrieve = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + messages.retrieve # pyright: ignore[reportDeprecated], + ) ) - self.update = async_to_streamed_response_wrapper( - messages.update, + self.update = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + messages.update # pyright: ignore[reportDeprecated], + ) ) - self.list = async_to_streamed_response_wrapper( - messages.list, + self.list = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + messages.list # pyright: ignore[reportDeprecated], + ) ) - self.delete = async_to_streamed_response_wrapper( - messages.delete, + self.delete = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + messages.delete # pyright: ignore[reportDeprecated], + ) ) diff --git a/src/openai/resources/beta/threads/runs/runs.py b/src/openai/resources/beta/threads/runs/runs.py index 4d19010fea..3d9ae9759e 100644 --- a/src/openai/resources/beta/threads/runs/runs.py +++ b/src/openai/resources/beta/threads/runs/runs.py @@ -83,6 +83,7 @@ def with_streaming_response(self) -> RunsWithStreamingResponse: return RunsWithStreamingResponse(self) @overload + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def create( self, thread_id: str, @@ -233,6 +234,7 @@ def create( ... @overload + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def create( self, thread_id: str, @@ -383,6 +385,7 @@ def create( ... @overload + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def create( self, thread_id: str, @@ -532,6 +535,7 @@ def create( """ ... + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") @required_args(["assistant_id"], ["assistant_id", "stream"]) def create( self, @@ -601,6 +605,7 @@ def create( stream_cls=Stream[AssistantStreamEvent], ) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def retrieve( self, run_id: str, @@ -638,6 +643,7 @@ def retrieve( cast_to=Run, ) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def update( self, run_id: str, @@ -684,6 +690,7 @@ def update( cast_to=Run, ) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def list( self, thread_id: str, @@ -751,6 +758,7 @@ def list( model=Run, ) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def cancel( self, run_id: str, @@ -788,6 +796,7 @@ def cancel( cast_to=Run, ) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def create_and_poll( self, *, @@ -822,7 +831,7 @@ def create_and_poll( lifecycles can be found here: https://platform.openai.com/docs/assistants/how-it-works/runs-and-run-steps """ - run = self.create( + run = self.create( # pyright: ignore[reportDeprecated] thread_id=thread_id, assistant_id=assistant_id, include=include, @@ -848,7 +857,7 @@ def create_and_poll( extra_body=extra_body, timeout=timeout, ) - return self.poll( + return self.poll( # pyright: ignore[reportDeprecated] run.id, thread_id=thread_id, extra_headers=extra_headers, @@ -996,6 +1005,7 @@ def create_and_stream( ) return AssistantStreamManager(make_request, event_handler=event_handler or AssistantEventHandler()) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def poll( self, run_id: str, @@ -1018,7 +1028,7 @@ def poll( terminal_states = {"requires_action", "cancelled", "completed", "failed", "expired", "incomplete"} while True: - response = self.with_raw_response.retrieve( + response = self.with_raw_response.retrieve( # pyright: ignore[reportDeprecated] thread_id=thread_id, run_id=run_id, extra_headers=extra_headers, @@ -1042,6 +1052,7 @@ def poll( self._sleep(poll_interval_ms / 1000) @overload + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def stream( self, *, @@ -1074,6 +1085,7 @@ def stream( ... @overload + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def stream( self, *, @@ -1106,6 +1118,7 @@ def stream( """Create a Run stream""" ... + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def stream( self, *, @@ -1184,6 +1197,7 @@ def stream( return AssistantStreamManager(make_request, event_handler=event_handler or AssistantEventHandler()) @overload + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def submit_tool_outputs( self, run_id: str, @@ -1222,6 +1236,7 @@ def submit_tool_outputs( ... @overload + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def submit_tool_outputs( self, run_id: str, @@ -1260,6 +1275,7 @@ def submit_tool_outputs( ... @overload + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def submit_tool_outputs( self, run_id: str, @@ -1297,7 +1313,9 @@ def submit_tool_outputs( """ ... + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") @required_args(["thread_id", "tool_outputs"], ["thread_id", "stream", "tool_outputs"]) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def submit_tool_outputs( self, run_id: str, @@ -1336,6 +1354,7 @@ def submit_tool_outputs( stream_cls=Stream[AssistantStreamEvent], ) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def submit_tool_outputs_and_poll( self, *, @@ -1355,7 +1374,7 @@ def submit_tool_outputs_and_poll( More information on Run lifecycles can be found here: https://platform.openai.com/docs/assistants/how-it-works/runs-and-run-steps """ - run = self.submit_tool_outputs( + run = self.submit_tool_outputs( # pyright: ignore[reportDeprecated] run_id=run_id, thread_id=thread_id, tool_outputs=tool_outputs, @@ -1365,7 +1384,7 @@ def submit_tool_outputs_and_poll( extra_body=extra_body, timeout=timeout, ) - return self.poll( + return self.poll( # pyright: ignore[reportDeprecated] run_id=run.id, thread_id=thread_id, extra_headers=extra_headers, @@ -1376,6 +1395,7 @@ def submit_tool_outputs_and_poll( ) @overload + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def submit_tool_outputs_stream( self, *, @@ -1397,6 +1417,7 @@ def submit_tool_outputs_stream( ... @overload + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def submit_tool_outputs_stream( self, *, @@ -1418,6 +1439,7 @@ def submit_tool_outputs_stream( """ ... + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def submit_tool_outputs_stream( self, *, @@ -1494,6 +1516,7 @@ def with_streaming_response(self) -> AsyncRunsWithStreamingResponse: return AsyncRunsWithStreamingResponse(self) @overload + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") async def create( self, thread_id: str, @@ -1644,6 +1667,7 @@ async def create( ... @overload + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") async def create( self, thread_id: str, @@ -1794,6 +1818,7 @@ async def create( ... @overload + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") async def create( self, thread_id: str, @@ -1943,7 +1968,9 @@ async def create( """ ... + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") @required_args(["assistant_id"], ["assistant_id", "stream"]) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") async def create( self, thread_id: str, @@ -2012,6 +2039,7 @@ async def create( stream_cls=AsyncStream[AssistantStreamEvent], ) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") async def retrieve( self, run_id: str, @@ -2049,6 +2077,7 @@ async def retrieve( cast_to=Run, ) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") async def update( self, run_id: str, @@ -2095,6 +2124,7 @@ async def update( cast_to=Run, ) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def list( self, thread_id: str, @@ -2162,6 +2192,7 @@ def list( model=Run, ) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") async def cancel( self, run_id: str, @@ -2199,6 +2230,7 @@ async def cancel( cast_to=Run, ) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") async def create_and_poll( self, *, @@ -2233,7 +2265,7 @@ async def create_and_poll( lifecycles can be found here: https://platform.openai.com/docs/assistants/how-it-works/runs-and-run-steps """ - run = await self.create( + run = await self.create( # pyright: ignore[reportDeprecated] thread_id=thread_id, assistant_id=assistant_id, include=include, @@ -2259,7 +2291,7 @@ async def create_and_poll( extra_body=extra_body, timeout=timeout, ) - return await self.poll( + return await self.poll( # pyright: ignore[reportDeprecated] run.id, thread_id=thread_id, extra_headers=extra_headers, @@ -2405,6 +2437,7 @@ def create_and_stream( ) return AsyncAssistantStreamManager(request, event_handler=event_handler or AsyncAssistantEventHandler()) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") async def poll( self, run_id: str, @@ -2427,7 +2460,7 @@ async def poll( terminal_states = {"requires_action", "cancelled", "completed", "failed", "expired", "incomplete"} while True: - response = await self.with_raw_response.retrieve( + response = await self.with_raw_response.retrieve( # pyright: ignore[reportDeprecated] thread_id=thread_id, run_id=run_id, extra_headers=extra_headers, @@ -2451,6 +2484,7 @@ async def poll( await self._sleep(poll_interval_ms / 1000) @overload + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def stream( self, *, @@ -2482,6 +2516,7 @@ def stream( ... @overload + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def stream( self, *, @@ -2514,6 +2549,7 @@ def stream( """Create a Run stream""" ... + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def stream( self, *, @@ -2594,6 +2630,7 @@ def stream( return AsyncAssistantStreamManager(request, event_handler=event_handler or AsyncAssistantEventHandler()) @overload + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") async def submit_tool_outputs( self, run_id: str, @@ -2632,6 +2669,7 @@ async def submit_tool_outputs( ... @overload + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") async def submit_tool_outputs( self, run_id: str, @@ -2670,6 +2708,7 @@ async def submit_tool_outputs( ... @overload + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") async def submit_tool_outputs( self, run_id: str, @@ -2707,7 +2746,9 @@ async def submit_tool_outputs( """ ... + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") @required_args(["thread_id", "tool_outputs"], ["thread_id", "stream", "tool_outputs"]) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") async def submit_tool_outputs( self, run_id: str, @@ -2746,6 +2787,7 @@ async def submit_tool_outputs( stream_cls=AsyncStream[AssistantStreamEvent], ) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") async def submit_tool_outputs_and_poll( self, *, @@ -2765,7 +2807,7 @@ async def submit_tool_outputs_and_poll( More information on Run lifecycles can be found here: https://platform.openai.com/docs/assistants/how-it-works/runs-and-run-steps """ - run = await self.submit_tool_outputs( + run = await self.submit_tool_outputs( # pyright: ignore[reportDeprecated] run_id=run_id, thread_id=thread_id, tool_outputs=tool_outputs, @@ -2775,7 +2817,7 @@ async def submit_tool_outputs_and_poll( extra_body=extra_body, timeout=timeout, ) - return await self.poll( + return await self.poll( # pyright: ignore[reportDeprecated] run_id=run.id, thread_id=thread_id, extra_headers=extra_headers, @@ -2786,6 +2828,7 @@ async def submit_tool_outputs_and_poll( ) @overload + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def submit_tool_outputs_stream( self, *, @@ -2807,6 +2850,7 @@ def submit_tool_outputs_stream( ... @overload + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def submit_tool_outputs_stream( self, *, @@ -2828,6 +2872,7 @@ def submit_tool_outputs_stream( """ ... + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def submit_tool_outputs_stream( self, *, @@ -2885,23 +2930,35 @@ class RunsWithRawResponse: def __init__(self, runs: Runs) -> None: self._runs = runs - self.create = _legacy_response.to_raw_response_wrapper( - runs.create, + self.create = ( # pyright: ignore[reportDeprecated] + _legacy_response.to_raw_response_wrapper( + runs.create # pyright: ignore[reportDeprecated], + ) ) - self.retrieve = _legacy_response.to_raw_response_wrapper( - runs.retrieve, + self.retrieve = ( # pyright: ignore[reportDeprecated] + _legacy_response.to_raw_response_wrapper( + runs.retrieve # pyright: ignore[reportDeprecated], + ) ) - self.update = _legacy_response.to_raw_response_wrapper( - runs.update, + self.update = ( # pyright: ignore[reportDeprecated] + _legacy_response.to_raw_response_wrapper( + runs.update # pyright: ignore[reportDeprecated], + ) ) - self.list = _legacy_response.to_raw_response_wrapper( - runs.list, + self.list = ( # pyright: ignore[reportDeprecated] + _legacy_response.to_raw_response_wrapper( + runs.list # pyright: ignore[reportDeprecated], + ) ) - self.cancel = _legacy_response.to_raw_response_wrapper( - runs.cancel, + self.cancel = ( # pyright: ignore[reportDeprecated] + _legacy_response.to_raw_response_wrapper( + runs.cancel # pyright: ignore[reportDeprecated], + ) ) - self.submit_tool_outputs = _legacy_response.to_raw_response_wrapper( - runs.submit_tool_outputs, + self.submit_tool_outputs = ( # pyright: ignore[reportDeprecated] + _legacy_response.to_raw_response_wrapper( + runs.submit_tool_outputs # pyright: ignore[reportDeprecated], + ) ) @cached_property @@ -2913,23 +2970,35 @@ class AsyncRunsWithRawResponse: def __init__(self, runs: AsyncRuns) -> None: self._runs = runs - self.create = _legacy_response.async_to_raw_response_wrapper( - runs.create, + self.create = ( # pyright: ignore[reportDeprecated] + _legacy_response.async_to_raw_response_wrapper( + runs.create # pyright: ignore[reportDeprecated], + ) ) - self.retrieve = _legacy_response.async_to_raw_response_wrapper( - runs.retrieve, + self.retrieve = ( # pyright: ignore[reportDeprecated] + _legacy_response.async_to_raw_response_wrapper( + runs.retrieve # pyright: ignore[reportDeprecated], + ) ) - self.update = _legacy_response.async_to_raw_response_wrapper( - runs.update, + self.update = ( # pyright: ignore[reportDeprecated] + _legacy_response.async_to_raw_response_wrapper( + runs.update # pyright: ignore[reportDeprecated], + ) ) - self.list = _legacy_response.async_to_raw_response_wrapper( - runs.list, + self.list = ( # pyright: ignore[reportDeprecated] + _legacy_response.async_to_raw_response_wrapper( + runs.list # pyright: ignore[reportDeprecated], + ) ) - self.cancel = _legacy_response.async_to_raw_response_wrapper( - runs.cancel, + self.cancel = ( # pyright: ignore[reportDeprecated] + _legacy_response.async_to_raw_response_wrapper( + runs.cancel # pyright: ignore[reportDeprecated], + ) ) - self.submit_tool_outputs = _legacy_response.async_to_raw_response_wrapper( - runs.submit_tool_outputs, + self.submit_tool_outputs = ( # pyright: ignore[reportDeprecated] + _legacy_response.async_to_raw_response_wrapper( + runs.submit_tool_outputs # pyright: ignore[reportDeprecated], + ) ) @cached_property @@ -2941,23 +3010,35 @@ class RunsWithStreamingResponse: def __init__(self, runs: Runs) -> None: self._runs = runs - self.create = to_streamed_response_wrapper( - runs.create, + self.create = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + runs.create # pyright: ignore[reportDeprecated], + ) ) - self.retrieve = to_streamed_response_wrapper( - runs.retrieve, + self.retrieve = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + runs.retrieve # pyright: ignore[reportDeprecated], + ) ) - self.update = to_streamed_response_wrapper( - runs.update, + self.update = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + runs.update # pyright: ignore[reportDeprecated], + ) ) - self.list = to_streamed_response_wrapper( - runs.list, + self.list = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + runs.list # pyright: ignore[reportDeprecated], + ) ) - self.cancel = to_streamed_response_wrapper( - runs.cancel, + self.cancel = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + runs.cancel # pyright: ignore[reportDeprecated], + ) ) - self.submit_tool_outputs = to_streamed_response_wrapper( - runs.submit_tool_outputs, + self.submit_tool_outputs = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + runs.submit_tool_outputs # pyright: ignore[reportDeprecated], + ) ) @cached_property @@ -2969,23 +3050,35 @@ class AsyncRunsWithStreamingResponse: def __init__(self, runs: AsyncRuns) -> None: self._runs = runs - self.create = async_to_streamed_response_wrapper( - runs.create, + self.create = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + runs.create # pyright: ignore[reportDeprecated], + ) ) - self.retrieve = async_to_streamed_response_wrapper( - runs.retrieve, + self.retrieve = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + runs.retrieve # pyright: ignore[reportDeprecated], + ) ) - self.update = async_to_streamed_response_wrapper( - runs.update, + self.update = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + runs.update # pyright: ignore[reportDeprecated], + ) ) - self.list = async_to_streamed_response_wrapper( - runs.list, + self.list = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + runs.list # pyright: ignore[reportDeprecated], + ) ) - self.cancel = async_to_streamed_response_wrapper( - runs.cancel, + self.cancel = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + runs.cancel # pyright: ignore[reportDeprecated], + ) ) - self.submit_tool_outputs = async_to_streamed_response_wrapper( - runs.submit_tool_outputs, + self.submit_tool_outputs = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + runs.submit_tool_outputs # pyright: ignore[reportDeprecated], + ) ) @cached_property diff --git a/src/openai/resources/beta/threads/runs/steps.py b/src/openai/resources/beta/threads/runs/steps.py index 3d2148687b..eebb2003b2 100644 --- a/src/openai/resources/beta/threads/runs/steps.py +++ b/src/openai/resources/beta/threads/runs/steps.py @@ -2,6 +2,7 @@ from __future__ import annotations +import typing_extensions from typing import List from typing_extensions import Literal @@ -42,6 +43,7 @@ def with_streaming_response(self) -> StepsWithStreamingResponse: """ return StepsWithStreamingResponse(self) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def retrieve( self, step_id: str, @@ -95,6 +97,7 @@ def retrieve( cast_to=RunStep, ) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def list( self, run_id: str, @@ -196,6 +199,7 @@ def with_streaming_response(self) -> AsyncStepsWithStreamingResponse: """ return AsyncStepsWithStreamingResponse(self) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") async def retrieve( self, step_id: str, @@ -249,6 +253,7 @@ async def retrieve( cast_to=RunStep, ) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def list( self, run_id: str, @@ -334,11 +339,15 @@ class StepsWithRawResponse: def __init__(self, steps: Steps) -> None: self._steps = steps - self.retrieve = _legacy_response.to_raw_response_wrapper( - steps.retrieve, + self.retrieve = ( # pyright: ignore[reportDeprecated] + _legacy_response.to_raw_response_wrapper( + steps.retrieve # pyright: ignore[reportDeprecated], + ) ) - self.list = _legacy_response.to_raw_response_wrapper( - steps.list, + self.list = ( # pyright: ignore[reportDeprecated] + _legacy_response.to_raw_response_wrapper( + steps.list # pyright: ignore[reportDeprecated], + ) ) @@ -346,11 +355,15 @@ class AsyncStepsWithRawResponse: def __init__(self, steps: AsyncSteps) -> None: self._steps = steps - self.retrieve = _legacy_response.async_to_raw_response_wrapper( - steps.retrieve, + self.retrieve = ( # pyright: ignore[reportDeprecated] + _legacy_response.async_to_raw_response_wrapper( + steps.retrieve # pyright: ignore[reportDeprecated], + ) ) - self.list = _legacy_response.async_to_raw_response_wrapper( - steps.list, + self.list = ( # pyright: ignore[reportDeprecated] + _legacy_response.async_to_raw_response_wrapper( + steps.list # pyright: ignore[reportDeprecated], + ) ) @@ -358,11 +371,15 @@ class StepsWithStreamingResponse: def __init__(self, steps: Steps) -> None: self._steps = steps - self.retrieve = to_streamed_response_wrapper( - steps.retrieve, + self.retrieve = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + steps.retrieve # pyright: ignore[reportDeprecated], + ) ) - self.list = to_streamed_response_wrapper( - steps.list, + self.list = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + steps.list # pyright: ignore[reportDeprecated], + ) ) @@ -370,9 +387,13 @@ class AsyncStepsWithStreamingResponse: def __init__(self, steps: AsyncSteps) -> None: self._steps = steps - self.retrieve = async_to_streamed_response_wrapper( - steps.retrieve, + self.retrieve = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + steps.retrieve # pyright: ignore[reportDeprecated], + ) ) - self.list = async_to_streamed_response_wrapper( - steps.list, + self.list = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + steps.list # pyright: ignore[reportDeprecated], + ) ) diff --git a/src/openai/resources/beta/threads/threads.py b/src/openai/resources/beta/threads/threads.py index 13d8cb6411..ff2a41155d 100644 --- a/src/openai/resources/beta/threads/threads.py +++ b/src/openai/resources/beta/threads/threads.py @@ -2,6 +2,7 @@ from __future__ import annotations +import typing_extensions from typing import Union, Iterable, Optional from functools import partial from typing_extensions import Literal, overload @@ -86,6 +87,7 @@ def with_streaming_response(self) -> ThreadsWithStreamingResponse: """ return ThreadsWithStreamingResponse(self) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def create( self, *, @@ -143,6 +145,7 @@ def create( cast_to=Thread, ) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def retrieve( self, thread_id: str, @@ -177,6 +180,7 @@ def retrieve( cast_to=Thread, ) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def update( self, thread_id: str, @@ -232,6 +236,7 @@ def update( cast_to=Thread, ) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def delete( self, thread_id: str, @@ -267,6 +272,7 @@ def delete( ) @overload + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def create_and_run( self, *, @@ -400,6 +406,7 @@ def create_and_run( ... @overload + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def create_and_run( self, *, @@ -533,6 +540,7 @@ def create_and_run( ... @overload + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def create_and_run( self, *, @@ -665,7 +673,9 @@ def create_and_run( """ ... + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") @required_args(["assistant_id"], ["assistant_id", "stream"]) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") def create_and_run( self, *, @@ -757,7 +767,7 @@ def create_and_run_poll( More information on Run lifecycles can be found here: https://platform.openai.com/docs/assistants/how-it-works/runs-and-run-steps """ - run = self.create_and_run( + run = self.create_and_run( # pyright: ignore[reportDeprecated] assistant_id=assistant_id, instructions=instructions, max_completion_tokens=max_completion_tokens, @@ -779,7 +789,7 @@ def create_and_run_poll( extra_body=extra_body, timeout=timeout, ) - return self.runs.poll(run.id, run.thread_id, extra_headers, extra_query, extra_body, timeout, poll_interval_ms) + return self.runs.poll(run.id, run.thread_id, extra_headers, extra_query, extra_body, timeout, poll_interval_ms) # pyright: ignore[reportDeprecated] @overload def create_and_run_stream( @@ -935,6 +945,7 @@ def with_streaming_response(self) -> AsyncThreadsWithStreamingResponse: """ return AsyncThreadsWithStreamingResponse(self) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") async def create( self, *, @@ -992,6 +1003,7 @@ async def create( cast_to=Thread, ) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") async def retrieve( self, thread_id: str, @@ -1026,6 +1038,7 @@ async def retrieve( cast_to=Thread, ) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") async def update( self, thread_id: str, @@ -1081,6 +1094,7 @@ async def update( cast_to=Thread, ) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") async def delete( self, thread_id: str, @@ -1116,6 +1130,7 @@ async def delete( ) @overload + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") async def create_and_run( self, *, @@ -1249,6 +1264,7 @@ async def create_and_run( ... @overload + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") async def create_and_run( self, *, @@ -1382,6 +1398,7 @@ async def create_and_run( ... @overload + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") async def create_and_run( self, *, @@ -1514,7 +1531,9 @@ async def create_and_run( """ ... + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") @required_args(["assistant_id"], ["assistant_id", "stream"]) + @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") async def create_and_run( self, *, @@ -1606,7 +1625,7 @@ async def create_and_run_poll( More information on Run lifecycles can be found here: https://platform.openai.com/docs/assistants/how-it-works/runs-and-run-steps """ - run = await self.create_and_run( + run = await self.create_and_run( # pyright: ignore[reportDeprecated] assistant_id=assistant_id, instructions=instructions, max_completion_tokens=max_completion_tokens, @@ -1628,7 +1647,7 @@ async def create_and_run_poll( extra_body=extra_body, timeout=timeout, ) - return await self.runs.poll( + return await self.runs.poll( # pyright: ignore[reportDeprecated] run.id, run.thread_id, extra_headers, extra_query, extra_body, timeout, poll_interval_ms ) @@ -1764,20 +1783,30 @@ class ThreadsWithRawResponse: def __init__(self, threads: Threads) -> None: self._threads = threads - self.create = _legacy_response.to_raw_response_wrapper( - threads.create, + self.create = ( # pyright: ignore[reportDeprecated] + _legacy_response.to_raw_response_wrapper( + threads.create # pyright: ignore[reportDeprecated], + ) ) - self.retrieve = _legacy_response.to_raw_response_wrapper( - threads.retrieve, + self.retrieve = ( # pyright: ignore[reportDeprecated] + _legacy_response.to_raw_response_wrapper( + threads.retrieve # pyright: ignore[reportDeprecated], + ) ) - self.update = _legacy_response.to_raw_response_wrapper( - threads.update, + self.update = ( # pyright: ignore[reportDeprecated] + _legacy_response.to_raw_response_wrapper( + threads.update # pyright: ignore[reportDeprecated], + ) ) - self.delete = _legacy_response.to_raw_response_wrapper( - threads.delete, + self.delete = ( # pyright: ignore[reportDeprecated] + _legacy_response.to_raw_response_wrapper( + threads.delete # pyright: ignore[reportDeprecated], + ) ) - self.create_and_run = _legacy_response.to_raw_response_wrapper( - threads.create_and_run, + self.create_and_run = ( # pyright: ignore[reportDeprecated] + _legacy_response.to_raw_response_wrapper( + threads.create_and_run # pyright: ignore[reportDeprecated], + ) ) @cached_property @@ -1793,20 +1822,30 @@ class AsyncThreadsWithRawResponse: def __init__(self, threads: AsyncThreads) -> None: self._threads = threads - self.create = _legacy_response.async_to_raw_response_wrapper( - threads.create, + self.create = ( # pyright: ignore[reportDeprecated] + _legacy_response.async_to_raw_response_wrapper( + threads.create # pyright: ignore[reportDeprecated], + ) ) - self.retrieve = _legacy_response.async_to_raw_response_wrapper( - threads.retrieve, + self.retrieve = ( # pyright: ignore[reportDeprecated] + _legacy_response.async_to_raw_response_wrapper( + threads.retrieve # pyright: ignore[reportDeprecated], + ) ) - self.update = _legacy_response.async_to_raw_response_wrapper( - threads.update, + self.update = ( # pyright: ignore[reportDeprecated] + _legacy_response.async_to_raw_response_wrapper( + threads.update # pyright: ignore[reportDeprecated], + ) ) - self.delete = _legacy_response.async_to_raw_response_wrapper( - threads.delete, + self.delete = ( # pyright: ignore[reportDeprecated] + _legacy_response.async_to_raw_response_wrapper( + threads.delete # pyright: ignore[reportDeprecated], + ) ) - self.create_and_run = _legacy_response.async_to_raw_response_wrapper( - threads.create_and_run, + self.create_and_run = ( # pyright: ignore[reportDeprecated] + _legacy_response.async_to_raw_response_wrapper( + threads.create_and_run # pyright: ignore[reportDeprecated], + ) ) @cached_property @@ -1822,20 +1861,30 @@ class ThreadsWithStreamingResponse: def __init__(self, threads: Threads) -> None: self._threads = threads - self.create = to_streamed_response_wrapper( - threads.create, + self.create = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + threads.create # pyright: ignore[reportDeprecated], + ) ) - self.retrieve = to_streamed_response_wrapper( - threads.retrieve, + self.retrieve = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + threads.retrieve # pyright: ignore[reportDeprecated], + ) ) - self.update = to_streamed_response_wrapper( - threads.update, + self.update = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + threads.update # pyright: ignore[reportDeprecated], + ) ) - self.delete = to_streamed_response_wrapper( - threads.delete, + self.delete = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + threads.delete # pyright: ignore[reportDeprecated], + ) ) - self.create_and_run = to_streamed_response_wrapper( - threads.create_and_run, + self.create_and_run = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + threads.create_and_run # pyright: ignore[reportDeprecated], + ) ) @cached_property @@ -1851,20 +1900,30 @@ class AsyncThreadsWithStreamingResponse: def __init__(self, threads: AsyncThreads) -> None: self._threads = threads - self.create = async_to_streamed_response_wrapper( - threads.create, + self.create = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + threads.create # pyright: ignore[reportDeprecated], + ) ) - self.retrieve = async_to_streamed_response_wrapper( - threads.retrieve, + self.retrieve = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + threads.retrieve # pyright: ignore[reportDeprecated], + ) ) - self.update = async_to_streamed_response_wrapper( - threads.update, + self.update = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + threads.update # pyright: ignore[reportDeprecated], + ) ) - self.delete = async_to_streamed_response_wrapper( - threads.delete, + self.delete = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + threads.delete # pyright: ignore[reportDeprecated], + ) ) - self.create_and_run = async_to_streamed_response_wrapper( - threads.create_and_run, + self.create_and_run = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + threads.create_and_run # pyright: ignore[reportDeprecated], + ) ) @cached_property diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index 4dbd1e6c62..a2a664ac59 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -263,9 +263,9 @@ def create( utilize scale tier credits until they are exhausted. - If set to 'auto', and the Project is not Scale tier enabled, the request will be processed using the default service tier with a lower uptime SLA and no - latency guarentee. + latency guarantee. - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarentee. + tier with a lower uptime SLA and no latency guarantee. - If set to 'flex', the request will be processed with the Flex Processing service tier. [Learn more](https://platform.openai.com/docs/guides/flex-processing). @@ -541,9 +541,9 @@ def create( utilize scale tier credits until they are exhausted. - If set to 'auto', and the Project is not Scale tier enabled, the request will be processed using the default service tier with a lower uptime SLA and no - latency guarentee. + latency guarantee. - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarentee. + tier with a lower uptime SLA and no latency guarantee. - If set to 'flex', the request will be processed with the Flex Processing service tier. [Learn more](https://platform.openai.com/docs/guides/flex-processing). @@ -810,9 +810,9 @@ def create( utilize scale tier credits until they are exhausted. - If set to 'auto', and the Project is not Scale tier enabled, the request will be processed using the default service tier with a lower uptime SLA and no - latency guarentee. + latency guarantee. - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarentee. + tier with a lower uptime SLA and no latency guarantee. - If set to 'flex', the request will be processed with the Flex Processing service tier. [Learn more](https://platform.openai.com/docs/guides/flex-processing). @@ -1366,9 +1366,9 @@ async def create( utilize scale tier credits until they are exhausted. - If set to 'auto', and the Project is not Scale tier enabled, the request will be processed using the default service tier with a lower uptime SLA and no - latency guarentee. + latency guarantee. - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarentee. + tier with a lower uptime SLA and no latency guarantee. - If set to 'flex', the request will be processed with the Flex Processing service tier. [Learn more](https://platform.openai.com/docs/guides/flex-processing). @@ -1644,9 +1644,9 @@ async def create( utilize scale tier credits until they are exhausted. - If set to 'auto', and the Project is not Scale tier enabled, the request will be processed using the default service tier with a lower uptime SLA and no - latency guarentee. + latency guarantee. - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarentee. + tier with a lower uptime SLA and no latency guarantee. - If set to 'flex', the request will be processed with the Flex Processing service tier. [Learn more](https://platform.openai.com/docs/guides/flex-processing). @@ -1913,9 +1913,9 @@ async def create( utilize scale tier credits until they are exhausted. - If set to 'auto', and the Project is not Scale tier enabled, the request will be processed using the default service tier with a lower uptime SLA and no - latency guarentee. + latency guarantee. - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarentee. + tier with a lower uptime SLA and no latency guarantee. - If set to 'flex', the request will be processed with the Flex Processing service tier. [Learn more](https://platform.openai.com/docs/guides/flex-processing). diff --git a/src/openai/resources/containers/files/content.py b/src/openai/resources/containers/files/content.py index 1aa2d1729d..a200383407 100644 --- a/src/openai/resources/containers/files/content.py +++ b/src/openai/resources/containers/files/content.py @@ -5,10 +5,15 @@ import httpx from .... import _legacy_response -from ...._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven +from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ...._response import ( + StreamedBinaryAPIResponse, + AsyncStreamedBinaryAPIResponse, + to_custom_streamed_response_wrapper, + async_to_custom_streamed_response_wrapper, +) from ...._base_client import make_request_options __all__ = ["Content", "AsyncContent"] @@ -45,7 +50,7 @@ def retrieve( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> None: + ) -> _legacy_response.HttpxBinaryResponseContent: """ Retrieve Container File Content @@ -62,13 +67,13 @@ def retrieve( raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") if not file_id: raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} + extra_headers = {"Accept": "application/binary", **(extra_headers or {})} return self._get( f"/containers/{container_id}/files/{file_id}/content", options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=NoneType, + cast_to=_legacy_response.HttpxBinaryResponseContent, ) @@ -103,7 +108,7 @@ async def retrieve( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> None: + ) -> _legacy_response.HttpxBinaryResponseContent: """ Retrieve Container File Content @@ -120,13 +125,13 @@ async def retrieve( raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") if not file_id: raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} + extra_headers = {"Accept": "application/binary", **(extra_headers or {})} return await self._get( f"/containers/{container_id}/files/{file_id}/content", options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=NoneType, + cast_to=_legacy_response.HttpxBinaryResponseContent, ) @@ -152,8 +157,9 @@ class ContentWithStreamingResponse: def __init__(self, content: Content) -> None: self._content = content - self.retrieve = to_streamed_response_wrapper( + self.retrieve = to_custom_streamed_response_wrapper( content.retrieve, + StreamedBinaryAPIResponse, ) @@ -161,6 +167,7 @@ class AsyncContentWithStreamingResponse: def __init__(self, content: AsyncContent) -> None: self._content = content - self.retrieve = async_to_streamed_response_wrapper( + self.retrieve = async_to_custom_streamed_response_wrapper( content.retrieve, + AsyncStreamedBinaryAPIResponse, ) diff --git a/src/openai/resources/fine_tuning/alpha/graders.py b/src/openai/resources/fine_tuning/alpha/graders.py index f27acdfd9c..387e6c72ff 100644 --- a/src/openai/resources/fine_tuning/alpha/graders.py +++ b/src/openai/resources/fine_tuning/alpha/graders.py @@ -2,8 +2,6 @@ from __future__ import annotations -from typing import Union, Iterable - import httpx from .... import _legacy_response @@ -45,7 +43,7 @@ def run( *, grader: grader_run_params.Grader, model_sample: str, - reference_answer: Union[str, Iterable[object], float, object], + item: object | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -59,9 +57,15 @@ def run( Args: grader: The grader used for the fine-tuning job. - model_sample: The model sample to be evaluated. + model_sample: The model sample to be evaluated. This value will be used to populate the + `sample` namespace. See + [the guide](https://platform.openai.com/docs/guides/graders) for more details. + The `output_json` variable will be populated if the model sample is a valid JSON + string. - reference_answer: The reference answer for the evaluation. + item: The dataset item provided to the grader. This will be used to populate the + `item` namespace. See + [the guide](https://platform.openai.com/docs/guides/graders) for more details. extra_headers: Send extra headers @@ -77,7 +81,7 @@ def run( { "grader": grader, "model_sample": model_sample, - "reference_answer": reference_answer, + "item": item, }, grader_run_params.GraderRunParams, ), @@ -147,7 +151,7 @@ async def run( *, grader: grader_run_params.Grader, model_sample: str, - reference_answer: Union[str, Iterable[object], float, object], + item: object | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -161,9 +165,15 @@ async def run( Args: grader: The grader used for the fine-tuning job. - model_sample: The model sample to be evaluated. + model_sample: The model sample to be evaluated. This value will be used to populate the + `sample` namespace. See + [the guide](https://platform.openai.com/docs/guides/graders) for more details. + The `output_json` variable will be populated if the model sample is a valid JSON + string. - reference_answer: The reference answer for the evaluation. + item: The dataset item provided to the grader. This will be used to populate the + `item` namespace. See + [the guide](https://platform.openai.com/docs/guides/graders) for more details. extra_headers: Send extra headers @@ -179,7 +189,7 @@ async def run( { "grader": grader, "model_sample": model_sample, - "reference_answer": reference_answer, + "item": item, }, grader_run_params.GraderRunParams, ), diff --git a/src/openai/resources/images.py b/src/openai/resources/images.py index 524bebacae..0f1c9fcb9e 100644 --- a/src/openai/resources/images.py +++ b/src/openai/resources/images.py @@ -144,7 +144,7 @@ def edit( image: The image(s) to edit. Must be a supported image file or an array of images. For `gpt-image-1`, each image should be a `png`, `webp`, or `jpg` file less than - 25MB. You can provide up to 16 images. + 50MB. You can provide up to 16 images. For `dall-e-2`, you can only provide one image, and it should be a square `png` file less than 4MB. @@ -468,7 +468,7 @@ async def edit( image: The image(s) to edit. Must be a supported image file or an array of images. For `gpt-image-1`, each image should be a `png`, `webp`, or `jpg` file less than - 25MB. You can provide up to 16 images. + 50MB. You can provide up to 16 images. For `dall-e-2`, you can only provide one image, and it should be a square `png` file less than 4MB. diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 570e7c94d5..c3bec87153 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -149,6 +149,8 @@ def create( multi-turn conversations when using the Responses API statelessly (like when the `store` parameter is set to `false`, or when an organization is enrolled in the zero data retention program). + - `code_interpreter_call.outputs`: Includes the outputs of python code execution + in code interpreter tool call items. instructions: Inserts a system (or developer) message as the first item in the model's context. @@ -186,9 +188,9 @@ def create( utilize scale tier credits until they are exhausted. - If set to 'auto', and the Project is not Scale tier enabled, the request will be processed using the default service tier with a lower uptime SLA and no - latency guarentee. + latency guarantee. - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarentee. + tier with a lower uptime SLA and no latency guarantee. - If set to 'flex', the request will be processed with the Flex Processing service tier. [Learn more](https://platform.openai.com/docs/guides/flex-processing). @@ -349,6 +351,8 @@ def create( multi-turn conversations when using the Responses API statelessly (like when the `store` parameter is set to `false`, or when an organization is enrolled in the zero data retention program). + - `code_interpreter_call.outputs`: Includes the outputs of python code execution + in code interpreter tool call items. instructions: Inserts a system (or developer) message as the first item in the model's context. @@ -386,9 +390,9 @@ def create( utilize scale tier credits until they are exhausted. - If set to 'auto', and the Project is not Scale tier enabled, the request will be processed using the default service tier with a lower uptime SLA and no - latency guarentee. + latency guarantee. - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarentee. + tier with a lower uptime SLA and no latency guarantee. - If set to 'flex', the request will be processed with the Flex Processing service tier. [Learn more](https://platform.openai.com/docs/guides/flex-processing). @@ -542,6 +546,8 @@ def create( multi-turn conversations when using the Responses API statelessly (like when the `store` parameter is set to `false`, or when an organization is enrolled in the zero data retention program). + - `code_interpreter_call.outputs`: Includes the outputs of python code execution + in code interpreter tool call items. instructions: Inserts a system (or developer) message as the first item in the model's context. @@ -579,9 +585,9 @@ def create( utilize scale tier credits until they are exhausted. - If set to 'auto', and the Project is not Scale tier enabled, the request will be processed using the default service tier with a lower uptime SLA and no - latency guarentee. + latency guarantee. - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarentee. + tier with a lower uptime SLA and no latency guarantee. - If set to 'flex', the request will be processed with the Flex Processing service tier. [Learn more](https://platform.openai.com/docs/guides/flex-processing). @@ -976,6 +982,8 @@ def retrieve( response_id: str, *, include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + starting_after: int | NotGiven = NOT_GIVEN, + stream: Literal[False] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1016,6 +1024,7 @@ def retrieve( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> Response | Stream[ResponseStreamEvent]: ... + @overload def retrieve( self, response_id: str, @@ -1037,15 +1046,55 @@ def retrieve( include: Additional fields to include in the response. See the `include` parameter for Response creation above for more information. - stream: If set to true, the model response data will be streamed to the client using + starting_after: The sequence number of the event after which to start streaming. + + stream: If set to true, the model response data will be streamed to the client as it is + generated using [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). See the [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) for more information. - starting_after: When retrieving a background response, this parameter can be used to start - replaying after an event with the given sequence number. Must be used in conjunction with - the `stream` parameter set to `true`. + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def retrieve( + self, + response_id: str, + *, + stream: Literal[True], + include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + starting_after: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Stream[ResponseStreamEvent]: + """ + Retrieves a model response with the given ID. + + Args: + stream: If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) + for more information. + + include: Additional fields to include in the response. See the `include` parameter for + Response creation above for more information. + + starting_after: The sequence number of the event after which to start streaming. extra_headers: Send extra headers @@ -1055,6 +1104,63 @@ def retrieve( timeout: Override the client-level default timeout for this request, in seconds """ + ... + + @overload + def retrieve( + self, + response_id: str, + *, + stream: bool, + include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + starting_after: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Response | Stream[ResponseStreamEvent]: + """ + Retrieves a model response with the given ID. + + Args: + stream: If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) + for more information. + + include: Additional fields to include in the response. See the `include` parameter for + Response creation above for more information. + + starting_after: The sequence number of the event after which to start streaming. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + def retrieve( + self, + response_id: str, + *, + include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + starting_after: int | NotGiven = NOT_GIVEN, + stream: Literal[False] | Literal[True] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Response | Stream[ResponseStreamEvent]: if not response_id: raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") return self._get( @@ -1067,8 +1173,8 @@ def retrieve( query=maybe_transform( { "include": include, - "stream": stream, "starting_after": starting_after, + "stream": stream, }, response_retrieve_params.ResponseRetrieveParams, ), @@ -1122,7 +1228,7 @@ def cancel( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> None: + ) -> Response: """Cancels a model response with the given ID. Only responses created with the @@ -1140,13 +1246,12 @@ def cancel( """ if not response_id: raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._post( f"/responses/{response_id}/cancel", options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=NoneType, + cast_to=Response, ) @@ -1252,6 +1357,8 @@ async def create( multi-turn conversations when using the Responses API statelessly (like when the `store` parameter is set to `false`, or when an organization is enrolled in the zero data retention program). + - `code_interpreter_call.outputs`: Includes the outputs of python code execution + in code interpreter tool call items. instructions: Inserts a system (or developer) message as the first item in the model's context. @@ -1289,9 +1396,9 @@ async def create( utilize scale tier credits until they are exhausted. - If set to 'auto', and the Project is not Scale tier enabled, the request will be processed using the default service tier with a lower uptime SLA and no - latency guarentee. + latency guarantee. - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarentee. + tier with a lower uptime SLA and no latency guarantee. - If set to 'flex', the request will be processed with the Flex Processing service tier. [Learn more](https://platform.openai.com/docs/guides/flex-processing). @@ -1452,6 +1559,8 @@ async def create( multi-turn conversations when using the Responses API statelessly (like when the `store` parameter is set to `false`, or when an organization is enrolled in the zero data retention program). + - `code_interpreter_call.outputs`: Includes the outputs of python code execution + in code interpreter tool call items. instructions: Inserts a system (or developer) message as the first item in the model's context. @@ -1489,9 +1598,9 @@ async def create( utilize scale tier credits until they are exhausted. - If set to 'auto', and the Project is not Scale tier enabled, the request will be processed using the default service tier with a lower uptime SLA and no - latency guarentee. + latency guarantee. - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarentee. + tier with a lower uptime SLA and no latency guarantee. - If set to 'flex', the request will be processed with the Flex Processing service tier. [Learn more](https://platform.openai.com/docs/guides/flex-processing). @@ -1645,6 +1754,8 @@ async def create( multi-turn conversations when using the Responses API statelessly (like when the `store` parameter is set to `false`, or when an organization is enrolled in the zero data retention program). + - `code_interpreter_call.outputs`: Includes the outputs of python code execution + in code interpreter tool call items. instructions: Inserts a system (or developer) message as the first item in the model's context. @@ -1682,9 +1793,9 @@ async def create( utilize scale tier credits until they are exhausted. - If set to 'auto', and the Project is not Scale tier enabled, the request will be processed using the default service tier with a lower uptime SLA and no - latency guarentee. + latency guarantee. - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarentee. + tier with a lower uptime SLA and no latency guarantee. - If set to 'flex', the request will be processed with the Flex Processing service tier. [Learn more](https://platform.openai.com/docs/guides/flex-processing). @@ -2083,6 +2194,8 @@ async def retrieve( response_id: str, *, include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + starting_after: int | NotGiven = NOT_GIVEN, + stream: Literal[False] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -2123,6 +2236,7 @@ async def retrieve( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> Response | AsyncStream[ResponseStreamEvent]: ... + @overload async def retrieve( self, response_id: str, @@ -2144,9 +2258,96 @@ async def retrieve( include: Additional fields to include in the response. See the `include` parameter for Response creation above for more information. - stream: - starting_after: When retrieving a background response, this parameter can be used to start - replaying after an event with the given sequence number. Must be used in + starting_after: The sequence number of the event after which to start streaming. + + stream: If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) + for more information. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def retrieve( + self, + response_id: str, + *, + stream: Literal[True], + include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + starting_after: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> AsyncStream[ResponseStreamEvent]: + """ + Retrieves a model response with the given ID. + + Args: + stream: If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) + for more information. + + include: Additional fields to include in the response. See the `include` parameter for + Response creation above for more information. + + starting_after: The sequence number of the event after which to start streaming. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def retrieve( + self, + response_id: str, + *, + stream: bool, + include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + starting_after: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Response | AsyncStream[ResponseStreamEvent]: + """ + Retrieves a model response with the given ID. + + Args: + stream: If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) + for more information. + + include: Additional fields to include in the response. See the `include` parameter for + Response creation above for more information. + + starting_after: The sequence number of the event after which to start streaming. extra_headers: Send extra headers @@ -2156,6 +2357,22 @@ async def retrieve( timeout: Override the client-level default timeout for this request, in seconds """ + ... + + async def retrieve( + self, + response_id: str, + *, + include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + starting_after: int | NotGiven = NOT_GIVEN, + stream: Literal[False] | Literal[True] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Response | AsyncStream[ResponseStreamEvent]: if not response_id: raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") return await self._get( @@ -2168,8 +2385,8 @@ async def retrieve( query=await async_maybe_transform( { "include": include, - "stream": stream, "starting_after": starting_after, + "stream": stream, }, response_retrieve_params.ResponseRetrieveParams, ), @@ -2223,7 +2440,7 @@ async def cancel( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> None: + ) -> Response: """Cancels a model response with the given ID. Only responses created with the @@ -2241,13 +2458,12 @@ async def cancel( """ if not response_id: raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._post( f"/responses/{response_id}/cancel", options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=NoneType, + cast_to=Response, ) diff --git a/src/openai/types/audio/transcription_text_delta_event.py b/src/openai/types/audio/transcription_text_delta_event.py index f8d5355491..36c52f0623 100644 --- a/src/openai/types/audio/transcription_text_delta_event.py +++ b/src/openai/types/audio/transcription_text_delta_event.py @@ -12,7 +12,7 @@ class Logprob(BaseModel): token: Optional[str] = None """The token that was used to generate the log probability.""" - bytes: Optional[List[object]] = None + bytes: Optional[List[int]] = None """The bytes that were used to generate the log probability.""" logprob: Optional[float] = None diff --git a/src/openai/types/audio/transcription_text_done_event.py b/src/openai/types/audio/transcription_text_done_event.py index 3f1a713a52..c8875a1bdb 100644 --- a/src/openai/types/audio/transcription_text_done_event.py +++ b/src/openai/types/audio/transcription_text_done_event.py @@ -12,7 +12,7 @@ class Logprob(BaseModel): token: Optional[str] = None """The token that was used to generate the log probability.""" - bytes: Optional[List[object]] = None + bytes: Optional[List[int]] = None """The bytes that were used to generate the log probability.""" logprob: Optional[float] = None diff --git a/src/openai/types/beta/realtime/session_create_params.py b/src/openai/types/beta/realtime/session_create_params.py index eadee29b28..7a8e694f45 100644 --- a/src/openai/types/beta/realtime/session_create_params.py +++ b/src/openai/types/beta/realtime/session_create_params.py @@ -5,10 +5,21 @@ from typing import List, Union, Iterable from typing_extensions import Literal, TypedDict -__all__ = ["SessionCreateParams", "InputAudioNoiseReduction", "InputAudioTranscription", "Tool", "TurnDetection"] +__all__ = [ + "SessionCreateParams", + "ClientSecret", + "ClientSecretExpiresAt", + "InputAudioNoiseReduction", + "InputAudioTranscription", + "Tool", + "TurnDetection", +] class SessionCreateParams(TypedDict, total=False): + client_secret: ClientSecret + """Configuration options for the generated client secret.""" + input_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] """The format of input audio. @@ -124,6 +135,25 @@ class SessionCreateParams(TypedDict, total=False): """ +class ClientSecretExpiresAt(TypedDict, total=False): + anchor: Literal["created_at"] + """The anchor point for the ephemeral token expiration. + + Only `created_at` is currently supported. + """ + + seconds: int + """The number of seconds from the anchor point to the expiration. + + Select a value between `10` and `7200`. + """ + + +class ClientSecret(TypedDict, total=False): + expires_at: ClientSecretExpiresAt + """Configuration for the ephemeral token expiration.""" + + class InputAudioNoiseReduction(TypedDict, total=False): type: Literal["near_field", "far_field"] """Type of noise reduction. diff --git a/src/openai/types/beta/realtime/session_update_event.py b/src/openai/types/beta/realtime/session_update_event.py index ba34b0260b..1cd3ded27c 100644 --- a/src/openai/types/beta/realtime/session_update_event.py +++ b/src/openai/types/beta/realtime/session_update_event.py @@ -8,6 +8,8 @@ __all__ = [ "SessionUpdateEvent", "Session", + "SessionClientSecret", + "SessionClientSecretExpiresAt", "SessionInputAudioNoiseReduction", "SessionInputAudioTranscription", "SessionTool", @@ -15,6 +17,25 @@ ] +class SessionClientSecretExpiresAt(BaseModel): + anchor: Optional[Literal["created_at"]] = None + """The anchor point for the ephemeral token expiration. + + Only `created_at` is currently supported. + """ + + seconds: Optional[int] = None + """The number of seconds from the anchor point to the expiration. + + Select a value between `10` and `7200`. + """ + + +class SessionClientSecret(BaseModel): + expires_at: Optional[SessionClientSecretExpiresAt] = None + """Configuration for the ephemeral token expiration.""" + + class SessionInputAudioNoiseReduction(BaseModel): type: Optional[Literal["near_field", "far_field"]] = None """Type of noise reduction. @@ -116,6 +137,9 @@ class SessionTurnDetection(BaseModel): class Session(BaseModel): + client_secret: Optional[SessionClientSecret] = None + """Configuration options for the generated client secret.""" + input_audio_format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None """The format of input audio. diff --git a/src/openai/types/beta/realtime/session_update_event_param.py b/src/openai/types/beta/realtime/session_update_event_param.py index 0984d39e91..ee18aec239 100644 --- a/src/openai/types/beta/realtime/session_update_event_param.py +++ b/src/openai/types/beta/realtime/session_update_event_param.py @@ -8,6 +8,8 @@ __all__ = [ "SessionUpdateEventParam", "Session", + "SessionClientSecret", + "SessionClientSecretExpiresAt", "SessionInputAudioNoiseReduction", "SessionInputAudioTranscription", "SessionTool", @@ -15,6 +17,25 @@ ] +class SessionClientSecretExpiresAt(TypedDict, total=False): + anchor: Literal["created_at"] + """The anchor point for the ephemeral token expiration. + + Only `created_at` is currently supported. + """ + + seconds: int + """The number of seconds from the anchor point to the expiration. + + Select a value between `10` and `7200`. + """ + + +class SessionClientSecret(TypedDict, total=False): + expires_at: SessionClientSecretExpiresAt + """Configuration for the ephemeral token expiration.""" + + class SessionInputAudioNoiseReduction(TypedDict, total=False): type: Literal["near_field", "far_field"] """Type of noise reduction. @@ -116,6 +137,9 @@ class SessionTurnDetection(TypedDict, total=False): class Session(TypedDict, total=False): + client_secret: SessionClientSecret + """Configuration options for the generated client secret.""" + input_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] """The format of input audio. diff --git a/src/openai/types/beta/realtime/transcription_session_create_params.py b/src/openai/types/beta/realtime/transcription_session_create_params.py index 1cf511f0b5..15b2f14c14 100644 --- a/src/openai/types/beta/realtime/transcription_session_create_params.py +++ b/src/openai/types/beta/realtime/transcription_session_create_params.py @@ -5,10 +5,20 @@ from typing import List from typing_extensions import Literal, TypedDict -__all__ = ["TranscriptionSessionCreateParams", "InputAudioNoiseReduction", "InputAudioTranscription", "TurnDetection"] +__all__ = [ + "TranscriptionSessionCreateParams", + "ClientSecret", + "ClientSecretExpiresAt", + "InputAudioNoiseReduction", + "InputAudioTranscription", + "TurnDetection", +] class TranscriptionSessionCreateParams(TypedDict, total=False): + client_secret: ClientSecret + """Configuration options for the generated client secret.""" + include: List[str] """The set of items to include in the transcription. Current available items are: @@ -60,6 +70,25 @@ class TranscriptionSessionCreateParams(TypedDict, total=False): """ +class ClientSecretExpiresAt(TypedDict, total=False): + anchor: Literal["created_at"] + """The anchor point for the ephemeral token expiration. + + Only `created_at` is currently supported. + """ + + seconds: int + """The number of seconds from the anchor point to the expiration. + + Select a value between `10` and `7200`. + """ + + +class ClientSecret(TypedDict, total=False): + expires_at: ClientSecretExpiresAt + """Configuration for the ephemeral token expiration.""" + + class InputAudioNoiseReduction(TypedDict, total=False): type: Literal["near_field", "far_field"] """Type of noise reduction. diff --git a/src/openai/types/beta/realtime/transcription_session_update.py b/src/openai/types/beta/realtime/transcription_session_update.py index c3e8f011c8..73253b6848 100644 --- a/src/openai/types/beta/realtime/transcription_session_update.py +++ b/src/openai/types/beta/realtime/transcription_session_update.py @@ -8,12 +8,33 @@ __all__ = [ "TranscriptionSessionUpdate", "Session", + "SessionClientSecret", + "SessionClientSecretExpiresAt", "SessionInputAudioNoiseReduction", "SessionInputAudioTranscription", "SessionTurnDetection", ] +class SessionClientSecretExpiresAt(BaseModel): + anchor: Optional[Literal["created_at"]] = None + """The anchor point for the ephemeral token expiration. + + Only `created_at` is currently supported. + """ + + seconds: Optional[int] = None + """The number of seconds from the anchor point to the expiration. + + Select a value between `10` and `7200`. + """ + + +class SessionClientSecret(BaseModel): + expires_at: Optional[SessionClientSecretExpiresAt] = None + """Configuration for the ephemeral token expiration.""" + + class SessionInputAudioNoiseReduction(BaseModel): type: Optional[Literal["near_field", "far_field"]] = None """Type of noise reduction. @@ -99,6 +120,9 @@ class SessionTurnDetection(BaseModel): class Session(BaseModel): + client_secret: Optional[SessionClientSecret] = None + """Configuration options for the generated client secret.""" + include: Optional[List[str]] = None """The set of items to include in the transcription. Current available items are: diff --git a/src/openai/types/beta/realtime/transcription_session_update_param.py b/src/openai/types/beta/realtime/transcription_session_update_param.py index 549c49011b..6b38a9af39 100644 --- a/src/openai/types/beta/realtime/transcription_session_update_param.py +++ b/src/openai/types/beta/realtime/transcription_session_update_param.py @@ -8,12 +8,33 @@ __all__ = [ "TranscriptionSessionUpdateParam", "Session", + "SessionClientSecret", + "SessionClientSecretExpiresAt", "SessionInputAudioNoiseReduction", "SessionInputAudioTranscription", "SessionTurnDetection", ] +class SessionClientSecretExpiresAt(TypedDict, total=False): + anchor: Literal["created_at"] + """The anchor point for the ephemeral token expiration. + + Only `created_at` is currently supported. + """ + + seconds: int + """The number of seconds from the anchor point to the expiration. + + Select a value between `10` and `7200`. + """ + + +class SessionClientSecret(TypedDict, total=False): + expires_at: SessionClientSecretExpiresAt + """Configuration for the ephemeral token expiration.""" + + class SessionInputAudioNoiseReduction(TypedDict, total=False): type: Literal["near_field", "far_field"] """Type of noise reduction. @@ -99,6 +120,9 @@ class SessionTurnDetection(TypedDict, total=False): class Session(TypedDict, total=False): + client_secret: SessionClientSecret + """Configuration options for the generated client secret.""" + include: List[str] """The set of items to include in the transcription. Current available items are: diff --git a/src/openai/types/chat/chat_completion.py b/src/openai/types/chat/chat_completion.py index 3a235f89a5..49af1a3d0e 100644 --- a/src/openai/types/chat/chat_completion.py +++ b/src/openai/types/chat/chat_completion.py @@ -68,9 +68,9 @@ class ChatCompletion(BaseModel): utilize scale tier credits until they are exhausted. - If set to 'auto', and the Project is not Scale tier enabled, the request will be processed using the default service tier with a lower uptime SLA and no - latency guarentee. + latency guarantee. - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarentee. + tier with a lower uptime SLA and no latency guarantee. - If set to 'flex', the request will be processed with the Flex Processing service tier. [Learn more](https://platform.openai.com/docs/guides/flex-processing). diff --git a/src/openai/types/chat/chat_completion_chunk.py b/src/openai/types/chat/chat_completion_chunk.py index 6fe996dd95..c109e10f97 100644 --- a/src/openai/types/chat/chat_completion_chunk.py +++ b/src/openai/types/chat/chat_completion_chunk.py @@ -137,9 +137,9 @@ class ChatCompletionChunk(BaseModel): utilize scale tier credits until they are exhausted. - If set to 'auto', and the Project is not Scale tier enabled, the request will be processed using the default service tier with a lower uptime SLA and no - latency guarentee. + latency guarantee. - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarentee. + tier with a lower uptime SLA and no latency guarantee. - If set to 'flex', the request will be processed with the Flex Processing service tier. [Learn more](https://platform.openai.com/docs/guides/flex-processing). diff --git a/src/openai/types/chat/completion_create_params.py b/src/openai/types/chat/completion_create_params.py index 5ea1c82f3d..e55cc2d0b7 100644 --- a/src/openai/types/chat/completion_create_params.py +++ b/src/openai/types/chat/completion_create_params.py @@ -217,9 +217,9 @@ class CompletionCreateParamsBase(TypedDict, total=False): utilize scale tier credits until they are exhausted. - If set to 'auto', and the Project is not Scale tier enabled, the request will be processed using the default service tier with a lower uptime SLA and no - latency guarentee. + latency guarantee. - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarentee. + tier with a lower uptime SLA and no latency guarantee. - If set to 'flex', the request will be processed with the Flex Processing service tier. [Learn more](https://platform.openai.com/docs/guides/flex-processing). diff --git a/src/openai/types/fine_tuning/alpha/grader_run_params.py b/src/openai/types/fine_tuning/alpha/grader_run_params.py index fa729f55ba..646407fe09 100644 --- a/src/openai/types/fine_tuning/alpha/grader_run_params.py +++ b/src/openai/types/fine_tuning/alpha/grader_run_params.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Union, Iterable +from typing import Union from typing_extensions import Required, TypeAlias, TypedDict from ...graders.multi_grader_param import MultiGraderParam @@ -19,10 +19,20 @@ class GraderRunParams(TypedDict, total=False): """The grader used for the fine-tuning job.""" model_sample: Required[str] - """The model sample to be evaluated.""" + """The model sample to be evaluated. - reference_answer: Required[Union[str, Iterable[object], float, object]] - """The reference answer for the evaluation.""" + This value will be used to populate the `sample` namespace. See + [the guide](https://platform.openai.com/docs/guides/graders) for more details. + The `output_json` variable will be populated if the model sample is a valid JSON + string. + """ + + item: object + """The dataset item provided to the grader. + + This will be used to populate the `item` namespace. See + [the guide](https://platform.openai.com/docs/guides/graders) for more details. + """ Grader: TypeAlias = Union[ diff --git a/src/openai/types/fine_tuning/fine_tuning_job.py b/src/openai/types/fine_tuning/fine_tuning_job.py index b6123f8ba6..f626fbba64 100644 --- a/src/openai/types/fine_tuning/fine_tuning_job.py +++ b/src/openai/types/fine_tuning/fine_tuning_job.py @@ -28,7 +28,7 @@ class Error(BaseModel): class Hyperparameters(BaseModel): - batch_size: Union[Literal["auto"], int, Optional[object], None] = None + batch_size: Union[Literal["auto"], int, None] = None """Number of examples in each batch. A larger batch size means that model parameters are updated less frequently, but diff --git a/src/openai/types/graders/multi_grader.py b/src/openai/types/graders/multi_grader.py index 220de2e61b..7539c68ef5 100644 --- a/src/openai/types/graders/multi_grader.py +++ b/src/openai/types/graders/multi_grader.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Dict, Union +from typing import Union from typing_extensions import Literal, TypeAlias from ..._models import BaseModel @@ -19,7 +19,11 @@ class MultiGrader(BaseModel): calculate_output: str """A formula to calculate the output based on grader results.""" - graders: Dict[str, Graders] + graders: Graders + """ + A StringCheckGrader object that performs a string comparison between input and + reference using a specified operation. + """ name: str """The name of the grader.""" diff --git a/src/openai/types/graders/multi_grader_param.py b/src/openai/types/graders/multi_grader_param.py index 2984b5668f..28a6705b81 100644 --- a/src/openai/types/graders/multi_grader_param.py +++ b/src/openai/types/graders/multi_grader_param.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict, Union +from typing import Union from typing_extensions import Literal, Required, TypeAlias, TypedDict from .python_grader_param import PythonGraderParam @@ -22,7 +22,11 @@ class MultiGraderParam(TypedDict, total=False): calculate_output: Required[str] """A formula to calculate the output based on grader results.""" - graders: Required[Dict[str, Graders]] + graders: Required[Graders] + """ + A StringCheckGrader object that performs a string comparison between input and + reference using a specified operation. + """ name: Required[str] """The name of the grader.""" diff --git a/src/openai/types/image_edit_params.py b/src/openai/types/image_edit_params.py index 6294e8ac19..4f931ce141 100644 --- a/src/openai/types/image_edit_params.py +++ b/src/openai/types/image_edit_params.py @@ -16,7 +16,7 @@ class ImageEditParams(TypedDict, total=False): """The image(s) to edit. Must be a supported image file or an array of images. For `gpt-image-1`, each image should be a `png`, `webp`, or `jpg` file less than - 25MB. You can provide up to 16 images. + 50MB. You can provide up to 16 images. For `dall-e-2`, you can only provide one image, and it should be a square `png` file less than 4MB. diff --git a/src/openai/types/responses/parsed_response.py b/src/openai/types/responses/parsed_response.py index f0b85f7209..e59e86d2b7 100644 --- a/src/openai/types/responses/parsed_response.py +++ b/src/openai/types/responses/parsed_response.py @@ -55,7 +55,7 @@ class ParsedResponseOutputMessage(ResponseOutputMessage, GenericModel, Generic[C class ParsedResponseFunctionToolCall(ResponseFunctionToolCall): parsed_arguments: object = None - __api_exclude__ = {'parsed_arguments'} + __api_exclude__ = {"parsed_arguments"} ParsedResponseOutputItem: TypeAlias = Annotated[ diff --git a/src/openai/types/responses/response.py b/src/openai/types/responses/response.py index 0d30d58ddb..441b345414 100644 --- a/src/openai/types/responses/response.py +++ b/src/openai/types/responses/response.py @@ -164,9 +164,9 @@ class Response(BaseModel): utilize scale tier credits until they are exhausted. - If set to 'auto', and the Project is not Scale tier enabled, the request will be processed using the default service tier with a lower uptime SLA and no - latency guarentee. + latency guarantee. - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarentee. + tier with a lower uptime SLA and no latency guarantee. - If set to 'flex', the request will be processed with the Flex Processing service tier. [Learn more](https://platform.openai.com/docs/guides/flex-processing). diff --git a/src/openai/types/responses/response_code_interpreter_call_code_delta_event.py b/src/openai/types/responses/response_code_interpreter_call_code_delta_event.py index f25b3f3cab..d222431504 100644 --- a/src/openai/types/responses/response_code_interpreter_call_code_delta_event.py +++ b/src/openai/types/responses/response_code_interpreter_call_code_delta_event.py @@ -17,5 +17,5 @@ class ResponseCodeInterpreterCallCodeDeltaEvent(BaseModel): sequence_number: int """The sequence number of this event.""" - type: Literal["response.code_interpreter_call.code.delta"] - """The type of the event. Always `response.code_interpreter_call.code.delta`.""" + type: Literal["response.code_interpreter_call_code.delta"] + """The type of the event. Always `response.code_interpreter_call_code.delta`.""" diff --git a/src/openai/types/responses/response_code_interpreter_call_code_done_event.py b/src/openai/types/responses/response_code_interpreter_call_code_done_event.py index bf1868cf0f..1ce6796a0e 100644 --- a/src/openai/types/responses/response_code_interpreter_call_code_done_event.py +++ b/src/openai/types/responses/response_code_interpreter_call_code_done_event.py @@ -17,5 +17,5 @@ class ResponseCodeInterpreterCallCodeDoneEvent(BaseModel): sequence_number: int """The sequence number of this event.""" - type: Literal["response.code_interpreter_call.code.done"] - """The type of the event. Always `response.code_interpreter_call.code.done`.""" + type: Literal["response.code_interpreter_call_code.done"] + """The type of the event. Always `response.code_interpreter_call_code.done`.""" diff --git a/src/openai/types/responses/response_create_params.py b/src/openai/types/responses/response_create_params.py index 28b2b59135..1abc2ccb1d 100644 --- a/src/openai/types/responses/response_create_params.py +++ b/src/openai/types/responses/response_create_params.py @@ -67,6 +67,8 @@ class ResponseCreateParamsBase(TypedDict, total=False): multi-turn conversations when using the Responses API statelessly (like when the `store` parameter is set to `false`, or when an organization is enrolled in the zero data retention program). + - `code_interpreter_call.outputs`: Includes the outputs of python code execution + in code interpreter tool call items. """ instructions: Optional[str] @@ -122,9 +124,9 @@ class ResponseCreateParamsBase(TypedDict, total=False): utilize scale tier credits until they are exhausted. - If set to 'auto', and the Project is not Scale tier enabled, the request will be processed using the default service tier with a lower uptime SLA and no - latency guarentee. + latency guarantee. - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarentee. + tier with a lower uptime SLA and no latency guarantee. - If set to 'flex', the request will be processed with the Flex Processing service tier. [Learn more](https://platform.openai.com/docs/guides/flex-processing). diff --git a/src/openai/types/responses/response_includable.py b/src/openai/types/responses/response_includable.py index a01dddd71d..28869832b0 100644 --- a/src/openai/types/responses/response_includable.py +++ b/src/openai/types/responses/response_includable.py @@ -9,4 +9,5 @@ "message.input_image.image_url", "computer_call_output.output.image_url", "reasoning.encrypted_content", + "code_interpreter_call.outputs", ] diff --git a/src/openai/types/responses/response_output_text.py b/src/openai/types/responses/response_output_text.py index fa653cd1af..1ea9a4ba93 100644 --- a/src/openai/types/responses/response_output_text.py +++ b/src/openai/types/responses/response_output_text.py @@ -1,12 +1,21 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union +from typing import List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias from ..._utils import PropertyInfo from ..._models import BaseModel -__all__ = ["ResponseOutputText", "Annotation", "AnnotationFileCitation", "AnnotationURLCitation", "AnnotationFilePath"] +__all__ = [ + "ResponseOutputText", + "Annotation", + "AnnotationFileCitation", + "AnnotationURLCitation", + "AnnotationContainerFileCitation", + "AnnotationFilePath", + "Logprob", + "LogprobTopLogprob", +] class AnnotationFileCitation(BaseModel): @@ -37,6 +46,23 @@ class AnnotationURLCitation(BaseModel): """The URL of the web resource.""" +class AnnotationContainerFileCitation(BaseModel): + container_id: str + """The ID of the container file.""" + + end_index: int + """The index of the last character of the container file citation in the message.""" + + file_id: str + """The ID of the file.""" + + start_index: int + """The index of the first character of the container file citation in the message.""" + + type: Literal["container_file_citation"] + """The type of the container file citation. Always `container_file_citation`.""" + + class AnnotationFilePath(BaseModel): file_id: str """The ID of the file.""" @@ -49,10 +75,29 @@ class AnnotationFilePath(BaseModel): Annotation: TypeAlias = Annotated[ - Union[AnnotationFileCitation, AnnotationURLCitation, AnnotationFilePath], PropertyInfo(discriminator="type") + Union[AnnotationFileCitation, AnnotationURLCitation, AnnotationContainerFileCitation, AnnotationFilePath], + PropertyInfo(discriminator="type"), ] +class LogprobTopLogprob(BaseModel): + token: str + + bytes: List[int] + + logprob: float + + +class Logprob(BaseModel): + token: str + + bytes: List[int] + + logprob: float + + top_logprobs: List[LogprobTopLogprob] + + class ResponseOutputText(BaseModel): annotations: List[Annotation] """The annotations of the text output.""" @@ -62,3 +107,5 @@ class ResponseOutputText(BaseModel): type: Literal["output_text"] """The type of the output text. Always `output_text`.""" + + logprobs: Optional[List[Logprob]] = None diff --git a/src/openai/types/responses/response_output_text_param.py b/src/openai/types/responses/response_output_text_param.py index 1f0967285f..207901e8ef 100644 --- a/src/openai/types/responses/response_output_text_param.py +++ b/src/openai/types/responses/response_output_text_param.py @@ -10,7 +10,10 @@ "Annotation", "AnnotationFileCitation", "AnnotationURLCitation", + "AnnotationContainerFileCitation", "AnnotationFilePath", + "Logprob", + "LogprobTopLogprob", ] @@ -42,6 +45,23 @@ class AnnotationURLCitation(TypedDict, total=False): """The URL of the web resource.""" +class AnnotationContainerFileCitation(TypedDict, total=False): + container_id: Required[str] + """The ID of the container file.""" + + end_index: Required[int] + """The index of the last character of the container file citation in the message.""" + + file_id: Required[str] + """The ID of the file.""" + + start_index: Required[int] + """The index of the first character of the container file citation in the message.""" + + type: Required[Literal["container_file_citation"]] + """The type of the container file citation. Always `container_file_citation`.""" + + class AnnotationFilePath(TypedDict, total=False): file_id: Required[str] """The ID of the file.""" @@ -53,7 +73,27 @@ class AnnotationFilePath(TypedDict, total=False): """The type of the file path. Always `file_path`.""" -Annotation: TypeAlias = Union[AnnotationFileCitation, AnnotationURLCitation, AnnotationFilePath] +Annotation: TypeAlias = Union[ + AnnotationFileCitation, AnnotationURLCitation, AnnotationContainerFileCitation, AnnotationFilePath +] + + +class LogprobTopLogprob(TypedDict, total=False): + token: Required[str] + + bytes: Required[Iterable[int]] + + logprob: Required[float] + + +class Logprob(TypedDict, total=False): + token: Required[str] + + bytes: Required[Iterable[int]] + + logprob: Required[float] + + top_logprobs: Required[Iterable[LogprobTopLogprob]] class ResponseOutputTextParam(TypedDict, total=False): @@ -65,3 +105,5 @@ class ResponseOutputTextParam(TypedDict, total=False): type: Required[Literal["output_text"]] """The type of the output text. Always `output_text`.""" + + logprobs: Iterable[Logprob] diff --git a/src/openai/types/responses/response_retrieve_params.py b/src/openai/types/responses/response_retrieve_params.py index 137bf4dcee..a092bd7fb8 100644 --- a/src/openai/types/responses/response_retrieve_params.py +++ b/src/openai/types/responses/response_retrieve_params.py @@ -2,17 +2,47 @@ from __future__ import annotations -from typing import List -from typing_extensions import TypedDict +from typing import List, Union +from typing_extensions import Literal, Required, TypedDict from .response_includable import ResponseIncludable -__all__ = ["ResponseRetrieveParams"] +__all__ = ["ResponseRetrieveParamsBase", "ResponseRetrieveParamsNonStreaming", "ResponseRetrieveParamsStreaming"] -class ResponseRetrieveParams(TypedDict, total=False): +class ResponseRetrieveParamsBase(TypedDict, total=False): include: List[ResponseIncludable] """Additional fields to include in the response. See the `include` parameter for Response creation above for more information. """ + + starting_after: int + """The sequence number of the event after which to start streaming.""" + + +class ResponseRetrieveParamsNonStreaming(ResponseRetrieveParamsBase, total=False): + stream: Literal[False] + """ + If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) + for more information. + """ + + +class ResponseRetrieveParamsStreaming(ResponseRetrieveParamsBase): + stream: Required[Literal[True]] + """ + If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) + for more information. + """ + + +ResponseRetrieveParams = Union[ResponseRetrieveParamsNonStreaming, ResponseRetrieveParamsStreaming] diff --git a/src/openai/types/responses/tool_param.py b/src/openai/types/responses/tool_param.py index 378226c124..4174560d42 100644 --- a/src/openai/types/responses/tool_param.py +++ b/src/openai/types/responses/tool_param.py @@ -28,6 +28,7 @@ "LocalShell", ] + class McpAllowedToolsMcpAllowedToolsFilter(TypedDict, total=False): tool_names: List[str] """List of allowed tool names.""" @@ -177,5 +178,5 @@ class LocalShell(TypedDict, total=False): LocalShell, ] - + ParseableToolParam: TypeAlias = Union[ToolParam, ChatCompletionToolParam] diff --git a/tests/api_resources/beta/realtime/test_sessions.py b/tests/api_resources/beta/realtime/test_sessions.py index f432b7d277..c2046bdb7a 100644 --- a/tests/api_resources/beta/realtime/test_sessions.py +++ b/tests/api_resources/beta/realtime/test_sessions.py @@ -25,6 +25,12 @@ def test_method_create(self, client: OpenAI) -> None: @parametrize def test_method_create_with_all_params(self, client: OpenAI) -> None: session = client.beta.realtime.sessions.create( + client_secret={ + "expires_at": { + "anchor": "created_at", + "seconds": 0, + } + }, input_audio_format="pcm16", input_audio_noise_reduction={"type": "near_field"}, input_audio_transcription={ @@ -92,6 +98,12 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: session = await async_client.beta.realtime.sessions.create( + client_secret={ + "expires_at": { + "anchor": "created_at", + "seconds": 0, + } + }, input_audio_format="pcm16", input_audio_noise_reduction={"type": "near_field"}, input_audio_transcription={ diff --git a/tests/api_resources/beta/realtime/test_transcription_sessions.py b/tests/api_resources/beta/realtime/test_transcription_sessions.py index 4826185bea..5a6b4f6c92 100644 --- a/tests/api_resources/beta/realtime/test_transcription_sessions.py +++ b/tests/api_resources/beta/realtime/test_transcription_sessions.py @@ -25,6 +25,12 @@ def test_method_create(self, client: OpenAI) -> None: @parametrize def test_method_create_with_all_params(self, client: OpenAI) -> None: transcription_session = client.beta.realtime.transcription_sessions.create( + client_secret={ + "expires_at": { + "anchor": "created_at", + "seconds": 0, + } + }, include=["string"], input_audio_format="pcm16", input_audio_noise_reduction={"type": "near_field"}, @@ -78,6 +84,12 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: transcription_session = await async_client.beta.realtime.transcription_sessions.create( + client_secret={ + "expires_at": { + "anchor": "created_at", + "seconds": 0, + } + }, include=["string"], input_audio_format="pcm16", input_audio_noise_reduction={"type": "near_field"}, diff --git a/tests/api_resources/beta/test_threads.py b/tests/api_resources/beta/test_threads.py index 9916d5bdc6..eab94f0f8a 100644 --- a/tests/api_resources/beta/test_threads.py +++ b/tests/api_resources/beta/test_threads.py @@ -15,6 +15,8 @@ ) from openai.types.beta.threads import Run +# pyright: reportDeprecated=false + base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -23,45 +25,50 @@ class TestThreads: @parametrize def test_method_create(self, client: OpenAI) -> None: - thread = client.beta.threads.create() + with pytest.warns(DeprecationWarning): + thread = client.beta.threads.create() + assert_matches_type(Thread, thread, path=["response"]) @parametrize def test_method_create_with_all_params(self, client: OpenAI) -> None: - thread = client.beta.threads.create( - messages=[ - { - "content": "string", - "role": "user", - "attachments": [ - { - "file_id": "file_id", - "tools": [{"type": "code_interpreter"}], - } - ], - "metadata": {"foo": "string"}, - } - ], - metadata={"foo": "string"}, - tool_resources={ - "code_interpreter": {"file_ids": ["string"]}, - "file_search": { - "vector_store_ids": ["string"], - "vector_stores": [ - { - "chunking_strategy": {"type": "auto"}, - "file_ids": ["string"], - "metadata": {"foo": "string"}, - } - ], + with pytest.warns(DeprecationWarning): + thread = client.beta.threads.create( + messages=[ + { + "content": "string", + "role": "user", + "attachments": [ + { + "file_id": "file_id", + "tools": [{"type": "code_interpreter"}], + } + ], + "metadata": {"foo": "string"}, + } + ], + metadata={"foo": "string"}, + tool_resources={ + "code_interpreter": {"file_ids": ["string"]}, + "file_search": { + "vector_store_ids": ["string"], + "vector_stores": [ + { + "chunking_strategy": {"type": "auto"}, + "file_ids": ["string"], + "metadata": {"foo": "string"}, + } + ], + }, }, - }, - ) + ) + assert_matches_type(Thread, thread, path=["response"]) @parametrize def test_raw_response_create(self, client: OpenAI) -> None: - response = client.beta.threads.with_raw_response.create() + with pytest.warns(DeprecationWarning): + response = client.beta.threads.with_raw_response.create() assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -70,27 +77,31 @@ def test_raw_response_create(self, client: OpenAI) -> None: @parametrize def test_streaming_response_create(self, client: OpenAI) -> None: - with client.beta.threads.with_streaming_response.create() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + with client.beta.threads.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - thread = response.parse() - assert_matches_type(Thread, thread, path=["response"]) + thread = response.parse() + assert_matches_type(Thread, thread, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize def test_method_retrieve(self, client: OpenAI) -> None: - thread = client.beta.threads.retrieve( - "string", - ) + with pytest.warns(DeprecationWarning): + thread = client.beta.threads.retrieve( + "thread_id", + ) + assert_matches_type(Thread, thread, path=["response"]) @parametrize def test_raw_response_retrieve(self, client: OpenAI) -> None: - response = client.beta.threads.with_raw_response.retrieve( - "string", - ) + with pytest.warns(DeprecationWarning): + response = client.beta.threads.with_raw_response.retrieve( + "thread_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -99,48 +110,55 @@ def test_raw_response_retrieve(self, client: OpenAI) -> None: @parametrize def test_streaming_response_retrieve(self, client: OpenAI) -> None: - with client.beta.threads.with_streaming_response.retrieve( - "string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + with client.beta.threads.with_streaming_response.retrieve( + "thread_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - thread = response.parse() - assert_matches_type(Thread, thread, path=["response"]) + thread = response.parse() + assert_matches_type(Thread, thread, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize def test_path_params_retrieve(self, client: OpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - client.beta.threads.with_raw_response.retrieve( - "", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + client.beta.threads.with_raw_response.retrieve( + "", + ) @parametrize def test_method_update(self, client: OpenAI) -> None: - thread = client.beta.threads.update( - "string", - ) + with pytest.warns(DeprecationWarning): + thread = client.beta.threads.update( + thread_id="thread_id", + ) + assert_matches_type(Thread, thread, path=["response"]) @parametrize def test_method_update_with_all_params(self, client: OpenAI) -> None: - thread = client.beta.threads.update( - thread_id="thread_id", - metadata={"foo": "string"}, - tool_resources={ - "code_interpreter": {"file_ids": ["string"]}, - "file_search": {"vector_store_ids": ["string"]}, - }, - ) + with pytest.warns(DeprecationWarning): + thread = client.beta.threads.update( + thread_id="thread_id", + metadata={"foo": "string"}, + tool_resources={ + "code_interpreter": {"file_ids": ["string"]}, + "file_search": {"vector_store_ids": ["string"]}, + }, + ) + assert_matches_type(Thread, thread, path=["response"]) @parametrize def test_raw_response_update(self, client: OpenAI) -> None: - response = client.beta.threads.with_raw_response.update( - "string", - ) + with pytest.warns(DeprecationWarning): + response = client.beta.threads.with_raw_response.update( + thread_id="thread_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -149,36 +167,41 @@ def test_raw_response_update(self, client: OpenAI) -> None: @parametrize def test_streaming_response_update(self, client: OpenAI) -> None: - with client.beta.threads.with_streaming_response.update( - "string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + with client.beta.threads.with_streaming_response.update( + thread_id="thread_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - thread = response.parse() - assert_matches_type(Thread, thread, path=["response"]) + thread = response.parse() + assert_matches_type(Thread, thread, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize def test_path_params_update(self, client: OpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - client.beta.threads.with_raw_response.update( - "", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + client.beta.threads.with_raw_response.update( + thread_id="", + ) @parametrize def test_method_delete(self, client: OpenAI) -> None: - thread = client.beta.threads.delete( - "string", - ) + with pytest.warns(DeprecationWarning): + thread = client.beta.threads.delete( + "thread_id", + ) + assert_matches_type(ThreadDeleted, thread, path=["response"]) @parametrize def test_raw_response_delete(self, client: OpenAI) -> None: - response = client.beta.threads.with_raw_response.delete( - "string", - ) + with pytest.warns(DeprecationWarning): + response = client.beta.threads.with_raw_response.delete( + "thread_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -187,92 +210,99 @@ def test_raw_response_delete(self, client: OpenAI) -> None: @parametrize def test_streaming_response_delete(self, client: OpenAI) -> None: - with client.beta.threads.with_streaming_response.delete( - "string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + with client.beta.threads.with_streaming_response.delete( + "thread_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - thread = response.parse() - assert_matches_type(ThreadDeleted, thread, path=["response"]) + thread = response.parse() + assert_matches_type(ThreadDeleted, thread, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize def test_path_params_delete(self, client: OpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - client.beta.threads.with_raw_response.delete( - "", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + client.beta.threads.with_raw_response.delete( + "", + ) @parametrize def test_method_create_and_run_overload_1(self, client: OpenAI) -> None: - thread = client.beta.threads.create_and_run( - assistant_id="string", - ) + with pytest.warns(DeprecationWarning): + thread = client.beta.threads.create_and_run( + assistant_id="assistant_id", + ) + assert_matches_type(Run, thread, path=["response"]) @parametrize def test_method_create_and_run_with_all_params_overload_1(self, client: OpenAI) -> None: - thread = client.beta.threads.create_and_run( - assistant_id="string", - instructions="string", - max_completion_tokens=256, - max_prompt_tokens=256, - metadata={"foo": "string"}, - model="string", - parallel_tool_calls=True, - response_format="auto", - stream=False, - temperature=1, - thread={ - "messages": [ - { - "content": "string", - "role": "user", - "attachments": [ - { - "file_id": "file_id", - "tools": [{"type": "code_interpreter"}], - } - ], - "metadata": {"foo": "string"}, - } - ], - "metadata": {"foo": "string"}, - "tool_resources": { - "code_interpreter": {"file_ids": ["string"]}, - "file_search": { - "vector_store_ids": ["string"], - "vector_stores": [ - { - "chunking_strategy": {"type": "auto"}, - "file_ids": ["string"], - "metadata": {"foo": "string"}, - } - ], + with pytest.warns(DeprecationWarning): + thread = client.beta.threads.create_and_run( + assistant_id="assistant_id", + instructions="instructions", + max_completion_tokens=256, + max_prompt_tokens=256, + metadata={"foo": "string"}, + model="string", + parallel_tool_calls=True, + response_format="auto", + stream=False, + temperature=1, + thread={ + "messages": [ + { + "content": "string", + "role": "user", + "attachments": [ + { + "file_id": "file_id", + "tools": [{"type": "code_interpreter"}], + } + ], + "metadata": {"foo": "string"}, + } + ], + "metadata": {"foo": "string"}, + "tool_resources": { + "code_interpreter": {"file_ids": ["string"]}, + "file_search": { + "vector_store_ids": ["string"], + "vector_stores": [ + { + "chunking_strategy": {"type": "auto"}, + "file_ids": ["string"], + "metadata": {"foo": "string"}, + } + ], + }, }, }, - }, - tool_choice="none", - tool_resources={ - "code_interpreter": {"file_ids": ["string"]}, - "file_search": {"vector_store_ids": ["string"]}, - }, - tools=[{"type": "code_interpreter"}], - top_p=1, - truncation_strategy={ - "type": "auto", - "last_messages": 1, - }, - ) + tool_choice="none", + tool_resources={ + "code_interpreter": {"file_ids": ["string"]}, + "file_search": {"vector_store_ids": ["string"]}, + }, + tools=[{"type": "code_interpreter"}], + top_p=1, + truncation_strategy={ + "type": "auto", + "last_messages": 1, + }, + ) + assert_matches_type(Run, thread, path=["response"]) @parametrize def test_raw_response_create_and_run_overload_1(self, client: OpenAI) -> None: - response = client.beta.threads.with_raw_response.create_and_run( - assistant_id="string", - ) + with pytest.warns(DeprecationWarning): + response = client.beta.threads.with_raw_response.create_and_run( + assistant_id="assistant_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -281,87 +311,93 @@ def test_raw_response_create_and_run_overload_1(self, client: OpenAI) -> None: @parametrize def test_streaming_response_create_and_run_overload_1(self, client: OpenAI) -> None: - with client.beta.threads.with_streaming_response.create_and_run( - assistant_id="string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + with client.beta.threads.with_streaming_response.create_and_run( + assistant_id="assistant_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - thread = response.parse() - assert_matches_type(Run, thread, path=["response"]) + thread = response.parse() + assert_matches_type(Run, thread, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize def test_method_create_and_run_overload_2(self, client: OpenAI) -> None: - thread_stream = client.beta.threads.create_and_run( - assistant_id="string", - stream=True, - ) + with pytest.warns(DeprecationWarning): + thread_stream = client.beta.threads.create_and_run( + assistant_id="assistant_id", + stream=True, + ) + thread_stream.response.close() @parametrize def test_method_create_and_run_with_all_params_overload_2(self, client: OpenAI) -> None: - thread_stream = client.beta.threads.create_and_run( - assistant_id="string", - stream=True, - instructions="string", - max_completion_tokens=256, - max_prompt_tokens=256, - metadata={"foo": "string"}, - model="string", - parallel_tool_calls=True, - response_format="auto", - temperature=1, - thread={ - "messages": [ - { - "content": "string", - "role": "user", - "attachments": [ - { - "file_id": "file_id", - "tools": [{"type": "code_interpreter"}], - } - ], - "metadata": {"foo": "string"}, - } - ], - "metadata": {"foo": "string"}, - "tool_resources": { - "code_interpreter": {"file_ids": ["string"]}, - "file_search": { - "vector_store_ids": ["string"], - "vector_stores": [ - { - "chunking_strategy": {"type": "auto"}, - "file_ids": ["string"], - "metadata": {"foo": "string"}, - } - ], + with pytest.warns(DeprecationWarning): + thread_stream = client.beta.threads.create_and_run( + assistant_id="assistant_id", + stream=True, + instructions="instructions", + max_completion_tokens=256, + max_prompt_tokens=256, + metadata={"foo": "string"}, + model="string", + parallel_tool_calls=True, + response_format="auto", + temperature=1, + thread={ + "messages": [ + { + "content": "string", + "role": "user", + "attachments": [ + { + "file_id": "file_id", + "tools": [{"type": "code_interpreter"}], + } + ], + "metadata": {"foo": "string"}, + } + ], + "metadata": {"foo": "string"}, + "tool_resources": { + "code_interpreter": {"file_ids": ["string"]}, + "file_search": { + "vector_store_ids": ["string"], + "vector_stores": [ + { + "chunking_strategy": {"type": "auto"}, + "file_ids": ["string"], + "metadata": {"foo": "string"}, + } + ], + }, }, }, - }, - tool_choice="none", - tool_resources={ - "code_interpreter": {"file_ids": ["string"]}, - "file_search": {"vector_store_ids": ["string"]}, - }, - tools=[{"type": "code_interpreter"}], - top_p=1, - truncation_strategy={ - "type": "auto", - "last_messages": 1, - }, - ) + tool_choice="none", + tool_resources={ + "code_interpreter": {"file_ids": ["string"]}, + "file_search": {"vector_store_ids": ["string"]}, + }, + tools=[{"type": "code_interpreter"}], + top_p=1, + truncation_strategy={ + "type": "auto", + "last_messages": 1, + }, + ) + thread_stream.response.close() @parametrize def test_raw_response_create_and_run_overload_2(self, client: OpenAI) -> None: - response = client.beta.threads.with_raw_response.create_and_run( - assistant_id="string", - stream=True, - ) + with pytest.warns(DeprecationWarning): + response = client.beta.threads.with_raw_response.create_and_run( + assistant_id="assistant_id", + stream=True, + ) assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() @@ -369,15 +405,16 @@ def test_raw_response_create_and_run_overload_2(self, client: OpenAI) -> None: @parametrize def test_streaming_response_create_and_run_overload_2(self, client: OpenAI) -> None: - with client.beta.threads.with_streaming_response.create_and_run( - assistant_id="string", - stream=True, - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + with client.beta.threads.with_streaming_response.create_and_run( + assistant_id="assistant_id", + stream=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - stream = response.parse() - stream.close() + stream = response.parse() + stream.close() assert cast(Any, response.is_closed) is True @@ -387,45 +424,50 @@ class TestAsyncThreads: @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: - thread = await async_client.beta.threads.create() + with pytest.warns(DeprecationWarning): + thread = await async_client.beta.threads.create() + assert_matches_type(Thread, thread, path=["response"]) @parametrize async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: - thread = await async_client.beta.threads.create( - messages=[ - { - "content": "string", - "role": "user", - "attachments": [ - { - "file_id": "file_id", - "tools": [{"type": "code_interpreter"}], - } - ], - "metadata": {"foo": "string"}, - } - ], - metadata={"foo": "string"}, - tool_resources={ - "code_interpreter": {"file_ids": ["string"]}, - "file_search": { - "vector_store_ids": ["string"], - "vector_stores": [ - { - "chunking_strategy": {"type": "auto"}, - "file_ids": ["string"], - "metadata": {"foo": "string"}, - } - ], + with pytest.warns(DeprecationWarning): + thread = await async_client.beta.threads.create( + messages=[ + { + "content": "string", + "role": "user", + "attachments": [ + { + "file_id": "file_id", + "tools": [{"type": "code_interpreter"}], + } + ], + "metadata": {"foo": "string"}, + } + ], + metadata={"foo": "string"}, + tool_resources={ + "code_interpreter": {"file_ids": ["string"]}, + "file_search": { + "vector_store_ids": ["string"], + "vector_stores": [ + { + "chunking_strategy": {"type": "auto"}, + "file_ids": ["string"], + "metadata": {"foo": "string"}, + } + ], + }, }, - }, - ) + ) + assert_matches_type(Thread, thread, path=["response"]) @parametrize async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.threads.with_raw_response.create() + with pytest.warns(DeprecationWarning): + response = await async_client.beta.threads.with_raw_response.create() assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -434,27 +476,31 @@ async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.threads.with_streaming_response.create() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + async with async_client.beta.threads.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - thread = await response.parse() - assert_matches_type(Thread, thread, path=["response"]) + thread = await response.parse() + assert_matches_type(Thread, thread, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: - thread = await async_client.beta.threads.retrieve( - "string", - ) + with pytest.warns(DeprecationWarning): + thread = await async_client.beta.threads.retrieve( + "thread_id", + ) + assert_matches_type(Thread, thread, path=["response"]) @parametrize async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.threads.with_raw_response.retrieve( - "string", - ) + with pytest.warns(DeprecationWarning): + response = await async_client.beta.threads.with_raw_response.retrieve( + "thread_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -463,48 +509,55 @@ async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.threads.with_streaming_response.retrieve( - "string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + async with async_client.beta.threads.with_streaming_response.retrieve( + "thread_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - thread = await response.parse() - assert_matches_type(Thread, thread, path=["response"]) + thread = await response.parse() + assert_matches_type(Thread, thread, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - await async_client.beta.threads.with_raw_response.retrieve( - "", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + await async_client.beta.threads.with_raw_response.retrieve( + "", + ) @parametrize async def test_method_update(self, async_client: AsyncOpenAI) -> None: - thread = await async_client.beta.threads.update( - "string", - ) + with pytest.warns(DeprecationWarning): + thread = await async_client.beta.threads.update( + thread_id="thread_id", + ) + assert_matches_type(Thread, thread, path=["response"]) @parametrize async def test_method_update_with_all_params(self, async_client: AsyncOpenAI) -> None: - thread = await async_client.beta.threads.update( - thread_id="thread_id", - metadata={"foo": "string"}, - tool_resources={ - "code_interpreter": {"file_ids": ["string"]}, - "file_search": {"vector_store_ids": ["string"]}, - }, - ) + with pytest.warns(DeprecationWarning): + thread = await async_client.beta.threads.update( + thread_id="thread_id", + metadata={"foo": "string"}, + tool_resources={ + "code_interpreter": {"file_ids": ["string"]}, + "file_search": {"vector_store_ids": ["string"]}, + }, + ) + assert_matches_type(Thread, thread, path=["response"]) @parametrize async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.threads.with_raw_response.update( - "string", - ) + with pytest.warns(DeprecationWarning): + response = await async_client.beta.threads.with_raw_response.update( + thread_id="thread_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -513,36 +566,41 @@ async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_update(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.threads.with_streaming_response.update( - "string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + async with async_client.beta.threads.with_streaming_response.update( + thread_id="thread_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - thread = await response.parse() - assert_matches_type(Thread, thread, path=["response"]) + thread = await response.parse() + assert_matches_type(Thread, thread, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize async def test_path_params_update(self, async_client: AsyncOpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - await async_client.beta.threads.with_raw_response.update( - "", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + await async_client.beta.threads.with_raw_response.update( + thread_id="", + ) @parametrize async def test_method_delete(self, async_client: AsyncOpenAI) -> None: - thread = await async_client.beta.threads.delete( - "string", - ) + with pytest.warns(DeprecationWarning): + thread = await async_client.beta.threads.delete( + "thread_id", + ) + assert_matches_type(ThreadDeleted, thread, path=["response"]) @parametrize async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.threads.with_raw_response.delete( - "string", - ) + with pytest.warns(DeprecationWarning): + response = await async_client.beta.threads.with_raw_response.delete( + "thread_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -551,92 +609,99 @@ async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.threads.with_streaming_response.delete( - "string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + async with async_client.beta.threads.with_streaming_response.delete( + "thread_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - thread = await response.parse() - assert_matches_type(ThreadDeleted, thread, path=["response"]) + thread = await response.parse() + assert_matches_type(ThreadDeleted, thread, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - await async_client.beta.threads.with_raw_response.delete( - "", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + await async_client.beta.threads.with_raw_response.delete( + "", + ) @parametrize async def test_method_create_and_run_overload_1(self, async_client: AsyncOpenAI) -> None: - thread = await async_client.beta.threads.create_and_run( - assistant_id="string", - ) + with pytest.warns(DeprecationWarning): + thread = await async_client.beta.threads.create_and_run( + assistant_id="assistant_id", + ) + assert_matches_type(Run, thread, path=["response"]) @parametrize async def test_method_create_and_run_with_all_params_overload_1(self, async_client: AsyncOpenAI) -> None: - thread = await async_client.beta.threads.create_and_run( - assistant_id="string", - instructions="string", - max_completion_tokens=256, - max_prompt_tokens=256, - metadata={"foo": "string"}, - model="string", - parallel_tool_calls=True, - response_format="auto", - stream=False, - temperature=1, - thread={ - "messages": [ - { - "content": "string", - "role": "user", - "attachments": [ - { - "file_id": "file_id", - "tools": [{"type": "code_interpreter"}], - } - ], - "metadata": {"foo": "string"}, - } - ], - "metadata": {"foo": "string"}, - "tool_resources": { - "code_interpreter": {"file_ids": ["string"]}, - "file_search": { - "vector_store_ids": ["string"], - "vector_stores": [ - { - "chunking_strategy": {"type": "auto"}, - "file_ids": ["string"], - "metadata": {"foo": "string"}, - } - ], + with pytest.warns(DeprecationWarning): + thread = await async_client.beta.threads.create_and_run( + assistant_id="assistant_id", + instructions="instructions", + max_completion_tokens=256, + max_prompt_tokens=256, + metadata={"foo": "string"}, + model="string", + parallel_tool_calls=True, + response_format="auto", + stream=False, + temperature=1, + thread={ + "messages": [ + { + "content": "string", + "role": "user", + "attachments": [ + { + "file_id": "file_id", + "tools": [{"type": "code_interpreter"}], + } + ], + "metadata": {"foo": "string"}, + } + ], + "metadata": {"foo": "string"}, + "tool_resources": { + "code_interpreter": {"file_ids": ["string"]}, + "file_search": { + "vector_store_ids": ["string"], + "vector_stores": [ + { + "chunking_strategy": {"type": "auto"}, + "file_ids": ["string"], + "metadata": {"foo": "string"}, + } + ], + }, }, }, - }, - tool_choice="none", - tool_resources={ - "code_interpreter": {"file_ids": ["string"]}, - "file_search": {"vector_store_ids": ["string"]}, - }, - tools=[{"type": "code_interpreter"}], - top_p=1, - truncation_strategy={ - "type": "auto", - "last_messages": 1, - }, - ) + tool_choice="none", + tool_resources={ + "code_interpreter": {"file_ids": ["string"]}, + "file_search": {"vector_store_ids": ["string"]}, + }, + tools=[{"type": "code_interpreter"}], + top_p=1, + truncation_strategy={ + "type": "auto", + "last_messages": 1, + }, + ) + assert_matches_type(Run, thread, path=["response"]) @parametrize async def test_raw_response_create_and_run_overload_1(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.threads.with_raw_response.create_and_run( - assistant_id="string", - ) + with pytest.warns(DeprecationWarning): + response = await async_client.beta.threads.with_raw_response.create_and_run( + assistant_id="assistant_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -645,87 +710,93 @@ async def test_raw_response_create_and_run_overload_1(self, async_client: AsyncO @parametrize async def test_streaming_response_create_and_run_overload_1(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.threads.with_streaming_response.create_and_run( - assistant_id="string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + async with async_client.beta.threads.with_streaming_response.create_and_run( + assistant_id="assistant_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - thread = await response.parse() - assert_matches_type(Run, thread, path=["response"]) + thread = await response.parse() + assert_matches_type(Run, thread, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize async def test_method_create_and_run_overload_2(self, async_client: AsyncOpenAI) -> None: - thread_stream = await async_client.beta.threads.create_and_run( - assistant_id="string", - stream=True, - ) + with pytest.warns(DeprecationWarning): + thread_stream = await async_client.beta.threads.create_and_run( + assistant_id="assistant_id", + stream=True, + ) + await thread_stream.response.aclose() @parametrize async def test_method_create_and_run_with_all_params_overload_2(self, async_client: AsyncOpenAI) -> None: - thread_stream = await async_client.beta.threads.create_and_run( - assistant_id="string", - stream=True, - instructions="string", - max_completion_tokens=256, - max_prompt_tokens=256, - metadata={"foo": "string"}, - model="string", - parallel_tool_calls=True, - response_format="auto", - temperature=1, - thread={ - "messages": [ - { - "content": "string", - "role": "user", - "attachments": [ - { - "file_id": "file_id", - "tools": [{"type": "code_interpreter"}], - } - ], - "metadata": {"foo": "string"}, - } - ], - "metadata": {"foo": "string"}, - "tool_resources": { - "code_interpreter": {"file_ids": ["string"]}, - "file_search": { - "vector_store_ids": ["string"], - "vector_stores": [ - { - "chunking_strategy": {"type": "auto"}, - "file_ids": ["string"], - "metadata": {"foo": "string"}, - } - ], + with pytest.warns(DeprecationWarning): + thread_stream = await async_client.beta.threads.create_and_run( + assistant_id="assistant_id", + stream=True, + instructions="instructions", + max_completion_tokens=256, + max_prompt_tokens=256, + metadata={"foo": "string"}, + model="string", + parallel_tool_calls=True, + response_format="auto", + temperature=1, + thread={ + "messages": [ + { + "content": "string", + "role": "user", + "attachments": [ + { + "file_id": "file_id", + "tools": [{"type": "code_interpreter"}], + } + ], + "metadata": {"foo": "string"}, + } + ], + "metadata": {"foo": "string"}, + "tool_resources": { + "code_interpreter": {"file_ids": ["string"]}, + "file_search": { + "vector_store_ids": ["string"], + "vector_stores": [ + { + "chunking_strategy": {"type": "auto"}, + "file_ids": ["string"], + "metadata": {"foo": "string"}, + } + ], + }, }, }, - }, - tool_choice="none", - tool_resources={ - "code_interpreter": {"file_ids": ["string"]}, - "file_search": {"vector_store_ids": ["string"]}, - }, - tools=[{"type": "code_interpreter"}], - top_p=1, - truncation_strategy={ - "type": "auto", - "last_messages": 1, - }, - ) + tool_choice="none", + tool_resources={ + "code_interpreter": {"file_ids": ["string"]}, + "file_search": {"vector_store_ids": ["string"]}, + }, + tools=[{"type": "code_interpreter"}], + top_p=1, + truncation_strategy={ + "type": "auto", + "last_messages": 1, + }, + ) + await thread_stream.response.aclose() @parametrize async def test_raw_response_create_and_run_overload_2(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.threads.with_raw_response.create_and_run( - assistant_id="string", - stream=True, - ) + with pytest.warns(DeprecationWarning): + response = await async_client.beta.threads.with_raw_response.create_and_run( + assistant_id="assistant_id", + stream=True, + ) assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() @@ -733,14 +804,15 @@ async def test_raw_response_create_and_run_overload_2(self, async_client: AsyncO @parametrize async def test_streaming_response_create_and_run_overload_2(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.threads.with_streaming_response.create_and_run( - assistant_id="string", - stream=True, - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - stream = await response.parse() - await stream.close() + with pytest.warns(DeprecationWarning): + async with async_client.beta.threads.with_streaming_response.create_and_run( + assistant_id="assistant_id", + stream=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = await response.parse() + await stream.close() assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/beta/threads/runs/test_steps.py b/tests/api_resources/beta/threads/runs/test_steps.py index f5dc17e0b5..9ca70657ec 100644 --- a/tests/api_resources/beta/threads/runs/test_steps.py +++ b/tests/api_resources/beta/threads/runs/test_steps.py @@ -12,6 +12,8 @@ from openai.pagination import SyncCursorPage, AsyncCursorPage from openai.types.beta.threads.runs import RunStep +# pyright: reportDeprecated=false + base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -20,30 +22,35 @@ class TestSteps: @parametrize def test_method_retrieve(self, client: OpenAI) -> None: - step = client.beta.threads.runs.steps.retrieve( - "string", - thread_id="string", - run_id="string", - ) + with pytest.warns(DeprecationWarning): + step = client.beta.threads.runs.steps.retrieve( + step_id="step_id", + thread_id="thread_id", + run_id="run_id", + ) + assert_matches_type(RunStep, step, path=["response"]) @parametrize def test_method_retrieve_with_all_params(self, client: OpenAI) -> None: - step = client.beta.threads.runs.steps.retrieve( - step_id="step_id", - thread_id="thread_id", - run_id="run_id", - include=["step_details.tool_calls[*].file_search.results[*].content"], - ) + with pytest.warns(DeprecationWarning): + step = client.beta.threads.runs.steps.retrieve( + step_id="step_id", + thread_id="thread_id", + run_id="run_id", + include=["step_details.tool_calls[*].file_search.results[*].content"], + ) + assert_matches_type(RunStep, step, path=["response"]) @parametrize def test_raw_response_retrieve(self, client: OpenAI) -> None: - response = client.beta.threads.runs.steps.with_raw_response.retrieve( - "string", - thread_id="string", - run_id="string", - ) + with pytest.warns(DeprecationWarning): + response = client.beta.threads.runs.steps.with_raw_response.retrieve( + step_id="step_id", + thread_id="thread_id", + run_id="run_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -52,69 +59,76 @@ def test_raw_response_retrieve(self, client: OpenAI) -> None: @parametrize def test_streaming_response_retrieve(self, client: OpenAI) -> None: - with client.beta.threads.runs.steps.with_streaming_response.retrieve( - "string", - thread_id="string", - run_id="string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - step = response.parse() - assert_matches_type(RunStep, step, path=["response"]) + with pytest.warns(DeprecationWarning): + with client.beta.threads.runs.steps.with_streaming_response.retrieve( + step_id="step_id", + thread_id="thread_id", + run_id="run_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + step = response.parse() + assert_matches_type(RunStep, step, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize def test_path_params_retrieve(self, client: OpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - client.beta.threads.runs.steps.with_raw_response.retrieve( - "string", - thread_id="", - run_id="string", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): - client.beta.threads.runs.steps.with_raw_response.retrieve( - "string", - thread_id="string", - run_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `step_id` but received ''"): - client.beta.threads.runs.steps.with_raw_response.retrieve( - "", - thread_id="string", - run_id="string", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + client.beta.threads.runs.steps.with_raw_response.retrieve( + step_id="step_id", + thread_id="", + run_id="run_id", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): + client.beta.threads.runs.steps.with_raw_response.retrieve( + step_id="step_id", + thread_id="thread_id", + run_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `step_id` but received ''"): + client.beta.threads.runs.steps.with_raw_response.retrieve( + step_id="", + thread_id="thread_id", + run_id="run_id", + ) @parametrize def test_method_list(self, client: OpenAI) -> None: - step = client.beta.threads.runs.steps.list( - "string", - thread_id="string", - ) + with pytest.warns(DeprecationWarning): + step = client.beta.threads.runs.steps.list( + run_id="run_id", + thread_id="thread_id", + ) + assert_matches_type(SyncCursorPage[RunStep], step, path=["response"]) @parametrize def test_method_list_with_all_params(self, client: OpenAI) -> None: - step = client.beta.threads.runs.steps.list( - run_id="run_id", - thread_id="thread_id", - after="after", - before="before", - include=["step_details.tool_calls[*].file_search.results[*].content"], - limit=0, - order="asc", - ) + with pytest.warns(DeprecationWarning): + step = client.beta.threads.runs.steps.list( + run_id="run_id", + thread_id="thread_id", + after="after", + before="before", + include=["step_details.tool_calls[*].file_search.results[*].content"], + limit=0, + order="asc", + ) + assert_matches_type(SyncCursorPage[RunStep], step, path=["response"]) @parametrize def test_raw_response_list(self, client: OpenAI) -> None: - response = client.beta.threads.runs.steps.with_raw_response.list( - "string", - thread_id="string", - ) + with pytest.warns(DeprecationWarning): + response = client.beta.threads.runs.steps.with_raw_response.list( + run_id="run_id", + thread_id="thread_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -123,31 +137,33 @@ def test_raw_response_list(self, client: OpenAI) -> None: @parametrize def test_streaming_response_list(self, client: OpenAI) -> None: - with client.beta.threads.runs.steps.with_streaming_response.list( - "string", - thread_id="string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + with client.beta.threads.runs.steps.with_streaming_response.list( + run_id="run_id", + thread_id="thread_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - step = response.parse() - assert_matches_type(SyncCursorPage[RunStep], step, path=["response"]) + step = response.parse() + assert_matches_type(SyncCursorPage[RunStep], step, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize def test_path_params_list(self, client: OpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - client.beta.threads.runs.steps.with_raw_response.list( - "string", - thread_id="", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + client.beta.threads.runs.steps.with_raw_response.list( + run_id="run_id", + thread_id="", + ) - with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): - client.beta.threads.runs.steps.with_raw_response.list( - "", - thread_id="string", - ) + with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): + client.beta.threads.runs.steps.with_raw_response.list( + run_id="", + thread_id="thread_id", + ) class TestAsyncSteps: @@ -155,30 +171,35 @@ class TestAsyncSteps: @parametrize async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: - step = await async_client.beta.threads.runs.steps.retrieve( - "string", - thread_id="string", - run_id="string", - ) + with pytest.warns(DeprecationWarning): + step = await async_client.beta.threads.runs.steps.retrieve( + step_id="step_id", + thread_id="thread_id", + run_id="run_id", + ) + assert_matches_type(RunStep, step, path=["response"]) @parametrize async def test_method_retrieve_with_all_params(self, async_client: AsyncOpenAI) -> None: - step = await async_client.beta.threads.runs.steps.retrieve( - step_id="step_id", - thread_id="thread_id", - run_id="run_id", - include=["step_details.tool_calls[*].file_search.results[*].content"], - ) + with pytest.warns(DeprecationWarning): + step = await async_client.beta.threads.runs.steps.retrieve( + step_id="step_id", + thread_id="thread_id", + run_id="run_id", + include=["step_details.tool_calls[*].file_search.results[*].content"], + ) + assert_matches_type(RunStep, step, path=["response"]) @parametrize async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.threads.runs.steps.with_raw_response.retrieve( - "string", - thread_id="string", - run_id="string", - ) + with pytest.warns(DeprecationWarning): + response = await async_client.beta.threads.runs.steps.with_raw_response.retrieve( + step_id="step_id", + thread_id="thread_id", + run_id="run_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -187,69 +208,76 @@ async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.threads.runs.steps.with_streaming_response.retrieve( - "string", - thread_id="string", - run_id="string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - step = await response.parse() - assert_matches_type(RunStep, step, path=["response"]) + with pytest.warns(DeprecationWarning): + async with async_client.beta.threads.runs.steps.with_streaming_response.retrieve( + step_id="step_id", + thread_id="thread_id", + run_id="run_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + step = await response.parse() + assert_matches_type(RunStep, step, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - await async_client.beta.threads.runs.steps.with_raw_response.retrieve( - "string", - thread_id="", - run_id="string", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): - await async_client.beta.threads.runs.steps.with_raw_response.retrieve( - "string", - thread_id="string", - run_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `step_id` but received ''"): - await async_client.beta.threads.runs.steps.with_raw_response.retrieve( - "", - thread_id="string", - run_id="string", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + await async_client.beta.threads.runs.steps.with_raw_response.retrieve( + step_id="step_id", + thread_id="", + run_id="run_id", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): + await async_client.beta.threads.runs.steps.with_raw_response.retrieve( + step_id="step_id", + thread_id="thread_id", + run_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `step_id` but received ''"): + await async_client.beta.threads.runs.steps.with_raw_response.retrieve( + step_id="", + thread_id="thread_id", + run_id="run_id", + ) @parametrize async def test_method_list(self, async_client: AsyncOpenAI) -> None: - step = await async_client.beta.threads.runs.steps.list( - "string", - thread_id="string", - ) + with pytest.warns(DeprecationWarning): + step = await async_client.beta.threads.runs.steps.list( + run_id="run_id", + thread_id="thread_id", + ) + assert_matches_type(AsyncCursorPage[RunStep], step, path=["response"]) @parametrize async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: - step = await async_client.beta.threads.runs.steps.list( - run_id="run_id", - thread_id="thread_id", - after="after", - before="before", - include=["step_details.tool_calls[*].file_search.results[*].content"], - limit=0, - order="asc", - ) + with pytest.warns(DeprecationWarning): + step = await async_client.beta.threads.runs.steps.list( + run_id="run_id", + thread_id="thread_id", + after="after", + before="before", + include=["step_details.tool_calls[*].file_search.results[*].content"], + limit=0, + order="asc", + ) + assert_matches_type(AsyncCursorPage[RunStep], step, path=["response"]) @parametrize async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.threads.runs.steps.with_raw_response.list( - "string", - thread_id="string", - ) + with pytest.warns(DeprecationWarning): + response = await async_client.beta.threads.runs.steps.with_raw_response.list( + run_id="run_id", + thread_id="thread_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -258,28 +286,30 @@ async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.threads.runs.steps.with_streaming_response.list( - "string", - thread_id="string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + async with async_client.beta.threads.runs.steps.with_streaming_response.list( + run_id="run_id", + thread_id="thread_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - step = await response.parse() - assert_matches_type(AsyncCursorPage[RunStep], step, path=["response"]) + step = await response.parse() + assert_matches_type(AsyncCursorPage[RunStep], step, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize async def test_path_params_list(self, async_client: AsyncOpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - await async_client.beta.threads.runs.steps.with_raw_response.list( - "string", - thread_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): - await async_client.beta.threads.runs.steps.with_raw_response.list( - "", - thread_id="string", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + await async_client.beta.threads.runs.steps.with_raw_response.list( + run_id="run_id", + thread_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): + await async_client.beta.threads.runs.steps.with_raw_response.list( + run_id="", + thread_id="thread_id", + ) diff --git a/tests/api_resources/beta/threads/test_messages.py b/tests/api_resources/beta/threads/test_messages.py index 9189a2f29e..bf3f22e8a3 100644 --- a/tests/api_resources/beta/threads/test_messages.py +++ b/tests/api_resources/beta/threads/test_messages.py @@ -15,6 +15,8 @@ MessageDeleted, ) +# pyright: reportDeprecated=false + base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -23,36 +25,41 @@ class TestMessages: @parametrize def test_method_create(self, client: OpenAI) -> None: - message = client.beta.threads.messages.create( - "string", - content="string", - role="user", - ) + with pytest.warns(DeprecationWarning): + message = client.beta.threads.messages.create( + thread_id="thread_id", + content="string", + role="user", + ) + assert_matches_type(Message, message, path=["response"]) @parametrize def test_method_create_with_all_params(self, client: OpenAI) -> None: - message = client.beta.threads.messages.create( - "string", - content="string", - role="user", - attachments=[ - { - "file_id": "file_id", - "tools": [{"type": "code_interpreter"}], - } - ], - metadata={"foo": "string"}, - ) + with pytest.warns(DeprecationWarning): + message = client.beta.threads.messages.create( + thread_id="thread_id", + content="string", + role="user", + attachments=[ + { + "file_id": "file_id", + "tools": [{"type": "code_interpreter"}], + } + ], + metadata={"foo": "string"}, + ) + assert_matches_type(Message, message, path=["response"]) @parametrize def test_raw_response_create(self, client: OpenAI) -> None: - response = client.beta.threads.messages.with_raw_response.create( - "string", - content="string", - role="user", - ) + with pytest.warns(DeprecationWarning): + response = client.beta.threads.messages.with_raw_response.create( + thread_id="thread_id", + content="string", + role="user", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -61,42 +68,47 @@ def test_raw_response_create(self, client: OpenAI) -> None: @parametrize def test_streaming_response_create(self, client: OpenAI) -> None: - with client.beta.threads.messages.with_streaming_response.create( - "string", - content="string", - role="user", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + with client.beta.threads.messages.with_streaming_response.create( + thread_id="thread_id", + content="string", + role="user", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - message = response.parse() - assert_matches_type(Message, message, path=["response"]) + message = response.parse() + assert_matches_type(Message, message, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize def test_path_params_create(self, client: OpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - client.beta.threads.messages.with_raw_response.create( - "", - content="string", - role="user", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + client.beta.threads.messages.with_raw_response.create( + thread_id="", + content="string", + role="user", + ) @parametrize def test_method_retrieve(self, client: OpenAI) -> None: - message = client.beta.threads.messages.retrieve( - "string", - thread_id="string", - ) + with pytest.warns(DeprecationWarning): + message = client.beta.threads.messages.retrieve( + message_id="message_id", + thread_id="thread_id", + ) + assert_matches_type(Message, message, path=["response"]) @parametrize def test_raw_response_retrieve(self, client: OpenAI) -> None: - response = client.beta.threads.messages.with_raw_response.retrieve( - "string", - thread_id="string", - ) + with pytest.warns(DeprecationWarning): + response = client.beta.threads.messages.with_raw_response.retrieve( + message_id="message_id", + thread_id="thread_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -105,55 +117,62 @@ def test_raw_response_retrieve(self, client: OpenAI) -> None: @parametrize def test_streaming_response_retrieve(self, client: OpenAI) -> None: - with client.beta.threads.messages.with_streaming_response.retrieve( - "string", - thread_id="string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + with client.beta.threads.messages.with_streaming_response.retrieve( + message_id="message_id", + thread_id="thread_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - message = response.parse() - assert_matches_type(Message, message, path=["response"]) + message = response.parse() + assert_matches_type(Message, message, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize def test_path_params_retrieve(self, client: OpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - client.beta.threads.messages.with_raw_response.retrieve( - "string", - thread_id="", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + client.beta.threads.messages.with_raw_response.retrieve( + message_id="message_id", + thread_id="", + ) - with pytest.raises(ValueError, match=r"Expected a non-empty value for `message_id` but received ''"): - client.beta.threads.messages.with_raw_response.retrieve( - "", - thread_id="string", - ) + with pytest.raises(ValueError, match=r"Expected a non-empty value for `message_id` but received ''"): + client.beta.threads.messages.with_raw_response.retrieve( + message_id="", + thread_id="thread_id", + ) @parametrize def test_method_update(self, client: OpenAI) -> None: - message = client.beta.threads.messages.update( - "string", - thread_id="string", - ) + with pytest.warns(DeprecationWarning): + message = client.beta.threads.messages.update( + message_id="message_id", + thread_id="thread_id", + ) + assert_matches_type(Message, message, path=["response"]) @parametrize def test_method_update_with_all_params(self, client: OpenAI) -> None: - message = client.beta.threads.messages.update( - message_id="message_id", - thread_id="thread_id", - metadata={"foo": "string"}, - ) + with pytest.warns(DeprecationWarning): + message = client.beta.threads.messages.update( + message_id="message_id", + thread_id="thread_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Message, message, path=["response"]) @parametrize def test_raw_response_update(self, client: OpenAI) -> None: - response = client.beta.threads.messages.with_raw_response.update( - "string", - thread_id="string", - ) + with pytest.warns(DeprecationWarning): + response = client.beta.threads.messages.with_raw_response.update( + message_id="message_id", + thread_id="thread_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -162,56 +181,63 @@ def test_raw_response_update(self, client: OpenAI) -> None: @parametrize def test_streaming_response_update(self, client: OpenAI) -> None: - with client.beta.threads.messages.with_streaming_response.update( - "string", - thread_id="string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + with client.beta.threads.messages.with_streaming_response.update( + message_id="message_id", + thread_id="thread_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - message = response.parse() - assert_matches_type(Message, message, path=["response"]) + message = response.parse() + assert_matches_type(Message, message, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize def test_path_params_update(self, client: OpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - client.beta.threads.messages.with_raw_response.update( - "string", - thread_id="", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + client.beta.threads.messages.with_raw_response.update( + message_id="message_id", + thread_id="", + ) - with pytest.raises(ValueError, match=r"Expected a non-empty value for `message_id` but received ''"): - client.beta.threads.messages.with_raw_response.update( - "", - thread_id="string", - ) + with pytest.raises(ValueError, match=r"Expected a non-empty value for `message_id` but received ''"): + client.beta.threads.messages.with_raw_response.update( + message_id="", + thread_id="thread_id", + ) @parametrize def test_method_list(self, client: OpenAI) -> None: - message = client.beta.threads.messages.list( - "string", - ) + with pytest.warns(DeprecationWarning): + message = client.beta.threads.messages.list( + thread_id="thread_id", + ) + assert_matches_type(SyncCursorPage[Message], message, path=["response"]) @parametrize def test_method_list_with_all_params(self, client: OpenAI) -> None: - message = client.beta.threads.messages.list( - "string", - after="string", - before="string", - limit=0, - order="asc", - run_id="string", - ) + with pytest.warns(DeprecationWarning): + message = client.beta.threads.messages.list( + thread_id="thread_id", + after="after", + before="before", + limit=0, + order="asc", + run_id="run_id", + ) + assert_matches_type(SyncCursorPage[Message], message, path=["response"]) @parametrize def test_raw_response_list(self, client: OpenAI) -> None: - response = client.beta.threads.messages.with_raw_response.list( - "string", - ) + with pytest.warns(DeprecationWarning): + response = client.beta.threads.messages.with_raw_response.list( + thread_id="thread_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -220,38 +246,43 @@ def test_raw_response_list(self, client: OpenAI) -> None: @parametrize def test_streaming_response_list(self, client: OpenAI) -> None: - with client.beta.threads.messages.with_streaming_response.list( - "string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + with client.beta.threads.messages.with_streaming_response.list( + thread_id="thread_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - message = response.parse() - assert_matches_type(SyncCursorPage[Message], message, path=["response"]) + message = response.parse() + assert_matches_type(SyncCursorPage[Message], message, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize def test_path_params_list(self, client: OpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - client.beta.threads.messages.with_raw_response.list( - "", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + client.beta.threads.messages.with_raw_response.list( + thread_id="", + ) @parametrize def test_method_delete(self, client: OpenAI) -> None: - message = client.beta.threads.messages.delete( - "string", - thread_id="string", - ) + with pytest.warns(DeprecationWarning): + message = client.beta.threads.messages.delete( + message_id="message_id", + thread_id="thread_id", + ) + assert_matches_type(MessageDeleted, message, path=["response"]) @parametrize def test_raw_response_delete(self, client: OpenAI) -> None: - response = client.beta.threads.messages.with_raw_response.delete( - "string", - thread_id="string", - ) + with pytest.warns(DeprecationWarning): + response = client.beta.threads.messages.with_raw_response.delete( + message_id="message_id", + thread_id="thread_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -260,31 +291,33 @@ def test_raw_response_delete(self, client: OpenAI) -> None: @parametrize def test_streaming_response_delete(self, client: OpenAI) -> None: - with client.beta.threads.messages.with_streaming_response.delete( - "string", - thread_id="string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + with client.beta.threads.messages.with_streaming_response.delete( + message_id="message_id", + thread_id="thread_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - message = response.parse() - assert_matches_type(MessageDeleted, message, path=["response"]) + message = response.parse() + assert_matches_type(MessageDeleted, message, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize def test_path_params_delete(self, client: OpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - client.beta.threads.messages.with_raw_response.delete( - "string", - thread_id="", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + client.beta.threads.messages.with_raw_response.delete( + message_id="message_id", + thread_id="", + ) - with pytest.raises(ValueError, match=r"Expected a non-empty value for `message_id` but received ''"): - client.beta.threads.messages.with_raw_response.delete( - "", - thread_id="string", - ) + with pytest.raises(ValueError, match=r"Expected a non-empty value for `message_id` but received ''"): + client.beta.threads.messages.with_raw_response.delete( + message_id="", + thread_id="thread_id", + ) class TestAsyncMessages: @@ -292,36 +325,41 @@ class TestAsyncMessages: @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: - message = await async_client.beta.threads.messages.create( - "string", - content="string", - role="user", - ) + with pytest.warns(DeprecationWarning): + message = await async_client.beta.threads.messages.create( + thread_id="thread_id", + content="string", + role="user", + ) + assert_matches_type(Message, message, path=["response"]) @parametrize async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: - message = await async_client.beta.threads.messages.create( - "string", - content="string", - role="user", - attachments=[ - { - "file_id": "file_id", - "tools": [{"type": "code_interpreter"}], - } - ], - metadata={"foo": "string"}, - ) + with pytest.warns(DeprecationWarning): + message = await async_client.beta.threads.messages.create( + thread_id="thread_id", + content="string", + role="user", + attachments=[ + { + "file_id": "file_id", + "tools": [{"type": "code_interpreter"}], + } + ], + metadata={"foo": "string"}, + ) + assert_matches_type(Message, message, path=["response"]) @parametrize async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.threads.messages.with_raw_response.create( - "string", - content="string", - role="user", - ) + with pytest.warns(DeprecationWarning): + response = await async_client.beta.threads.messages.with_raw_response.create( + thread_id="thread_id", + content="string", + role="user", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -330,42 +368,47 @@ async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.threads.messages.with_streaming_response.create( - "string", - content="string", - role="user", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + async with async_client.beta.threads.messages.with_streaming_response.create( + thread_id="thread_id", + content="string", + role="user", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - message = await response.parse() - assert_matches_type(Message, message, path=["response"]) + message = await response.parse() + assert_matches_type(Message, message, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize async def test_path_params_create(self, async_client: AsyncOpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - await async_client.beta.threads.messages.with_raw_response.create( - "", - content="string", - role="user", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + await async_client.beta.threads.messages.with_raw_response.create( + thread_id="", + content="string", + role="user", + ) @parametrize async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: - message = await async_client.beta.threads.messages.retrieve( - "string", - thread_id="string", - ) + with pytest.warns(DeprecationWarning): + message = await async_client.beta.threads.messages.retrieve( + message_id="message_id", + thread_id="thread_id", + ) + assert_matches_type(Message, message, path=["response"]) @parametrize async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.threads.messages.with_raw_response.retrieve( - "string", - thread_id="string", - ) + with pytest.warns(DeprecationWarning): + response = await async_client.beta.threads.messages.with_raw_response.retrieve( + message_id="message_id", + thread_id="thread_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -374,55 +417,62 @@ async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.threads.messages.with_streaming_response.retrieve( - "string", - thread_id="string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + async with async_client.beta.threads.messages.with_streaming_response.retrieve( + message_id="message_id", + thread_id="thread_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - message = await response.parse() - assert_matches_type(Message, message, path=["response"]) + message = await response.parse() + assert_matches_type(Message, message, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - await async_client.beta.threads.messages.with_raw_response.retrieve( - "string", - thread_id="", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + await async_client.beta.threads.messages.with_raw_response.retrieve( + message_id="message_id", + thread_id="", + ) - with pytest.raises(ValueError, match=r"Expected a non-empty value for `message_id` but received ''"): - await async_client.beta.threads.messages.with_raw_response.retrieve( - "", - thread_id="string", - ) + with pytest.raises(ValueError, match=r"Expected a non-empty value for `message_id` but received ''"): + await async_client.beta.threads.messages.with_raw_response.retrieve( + message_id="", + thread_id="thread_id", + ) @parametrize async def test_method_update(self, async_client: AsyncOpenAI) -> None: - message = await async_client.beta.threads.messages.update( - "string", - thread_id="string", - ) + with pytest.warns(DeprecationWarning): + message = await async_client.beta.threads.messages.update( + message_id="message_id", + thread_id="thread_id", + ) + assert_matches_type(Message, message, path=["response"]) @parametrize async def test_method_update_with_all_params(self, async_client: AsyncOpenAI) -> None: - message = await async_client.beta.threads.messages.update( - message_id="message_id", - thread_id="thread_id", - metadata={"foo": "string"}, - ) + with pytest.warns(DeprecationWarning): + message = await async_client.beta.threads.messages.update( + message_id="message_id", + thread_id="thread_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Message, message, path=["response"]) @parametrize async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.threads.messages.with_raw_response.update( - "string", - thread_id="string", - ) + with pytest.warns(DeprecationWarning): + response = await async_client.beta.threads.messages.with_raw_response.update( + message_id="message_id", + thread_id="thread_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -431,56 +481,63 @@ async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_update(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.threads.messages.with_streaming_response.update( - "string", - thread_id="string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + async with async_client.beta.threads.messages.with_streaming_response.update( + message_id="message_id", + thread_id="thread_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - message = await response.parse() - assert_matches_type(Message, message, path=["response"]) + message = await response.parse() + assert_matches_type(Message, message, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize async def test_path_params_update(self, async_client: AsyncOpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - await async_client.beta.threads.messages.with_raw_response.update( - "string", - thread_id="", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + await async_client.beta.threads.messages.with_raw_response.update( + message_id="message_id", + thread_id="", + ) - with pytest.raises(ValueError, match=r"Expected a non-empty value for `message_id` but received ''"): - await async_client.beta.threads.messages.with_raw_response.update( - "", - thread_id="string", - ) + with pytest.raises(ValueError, match=r"Expected a non-empty value for `message_id` but received ''"): + await async_client.beta.threads.messages.with_raw_response.update( + message_id="", + thread_id="thread_id", + ) @parametrize async def test_method_list(self, async_client: AsyncOpenAI) -> None: - message = await async_client.beta.threads.messages.list( - "string", - ) + with pytest.warns(DeprecationWarning): + message = await async_client.beta.threads.messages.list( + thread_id="thread_id", + ) + assert_matches_type(AsyncCursorPage[Message], message, path=["response"]) @parametrize async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: - message = await async_client.beta.threads.messages.list( - "string", - after="string", - before="string", - limit=0, - order="asc", - run_id="string", - ) + with pytest.warns(DeprecationWarning): + message = await async_client.beta.threads.messages.list( + thread_id="thread_id", + after="after", + before="before", + limit=0, + order="asc", + run_id="run_id", + ) + assert_matches_type(AsyncCursorPage[Message], message, path=["response"]) @parametrize async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.threads.messages.with_raw_response.list( - "string", - ) + with pytest.warns(DeprecationWarning): + response = await async_client.beta.threads.messages.with_raw_response.list( + thread_id="thread_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -489,38 +546,43 @@ async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.threads.messages.with_streaming_response.list( - "string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + async with async_client.beta.threads.messages.with_streaming_response.list( + thread_id="thread_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - message = await response.parse() - assert_matches_type(AsyncCursorPage[Message], message, path=["response"]) + message = await response.parse() + assert_matches_type(AsyncCursorPage[Message], message, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize async def test_path_params_list(self, async_client: AsyncOpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - await async_client.beta.threads.messages.with_raw_response.list( - "", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + await async_client.beta.threads.messages.with_raw_response.list( + thread_id="", + ) @parametrize async def test_method_delete(self, async_client: AsyncOpenAI) -> None: - message = await async_client.beta.threads.messages.delete( - "string", - thread_id="string", - ) + with pytest.warns(DeprecationWarning): + message = await async_client.beta.threads.messages.delete( + message_id="message_id", + thread_id="thread_id", + ) + assert_matches_type(MessageDeleted, message, path=["response"]) @parametrize async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.threads.messages.with_raw_response.delete( - "string", - thread_id="string", - ) + with pytest.warns(DeprecationWarning): + response = await async_client.beta.threads.messages.with_raw_response.delete( + message_id="message_id", + thread_id="thread_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -529,28 +591,30 @@ async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.threads.messages.with_streaming_response.delete( - "string", - thread_id="string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + async with async_client.beta.threads.messages.with_streaming_response.delete( + message_id="message_id", + thread_id="thread_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - message = await response.parse() - assert_matches_type(MessageDeleted, message, path=["response"]) + message = await response.parse() + assert_matches_type(MessageDeleted, message, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - await async_client.beta.threads.messages.with_raw_response.delete( - "string", - thread_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `message_id` but received ''"): - await async_client.beta.threads.messages.with_raw_response.delete( - "", - thread_id="string", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + await async_client.beta.threads.messages.with_raw_response.delete( + message_id="message_id", + thread_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `message_id` but received ''"): + await async_client.beta.threads.messages.with_raw_response.delete( + message_id="", + thread_id="thread_id", + ) diff --git a/tests/api_resources/beta/threads/test_runs.py b/tests/api_resources/beta/threads/test_runs.py index 4230ccebe4..fdef5e40db 100644 --- a/tests/api_resources/beta/threads/test_runs.py +++ b/tests/api_resources/beta/threads/test_runs.py @@ -24,58 +24,63 @@ class TestRuns: @parametrize def test_method_create_overload_1(self, client: OpenAI) -> None: - run = client.beta.threads.runs.create( - "string", - assistant_id="string", - ) + with pytest.warns(DeprecationWarning): + run = client.beta.threads.runs.create( + thread_id="thread_id", + assistant_id="assistant_id", + ) + assert_matches_type(Run, run, path=["response"]) @parametrize def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: - run = client.beta.threads.runs.create( - thread_id="thread_id", - assistant_id="assistant_id", - include=["step_details.tool_calls[*].file_search.results[*].content"], - additional_instructions="additional_instructions", - additional_messages=[ - { - "content": "string", - "role": "user", - "attachments": [ - { - "file_id": "file_id", - "tools": [{"type": "code_interpreter"}], - } - ], - "metadata": {"foo": "string"}, - } - ], - instructions="string", - max_completion_tokens=256, - max_prompt_tokens=256, - metadata={"foo": "string"}, - model="string", - parallel_tool_calls=True, - reasoning_effort="low", - response_format="auto", - stream=False, - temperature=1, - tool_choice="none", - tools=[{"type": "code_interpreter"}], - top_p=1, - truncation_strategy={ - "type": "auto", - "last_messages": 1, - }, - ) + with pytest.warns(DeprecationWarning): + run = client.beta.threads.runs.create( + thread_id="thread_id", + assistant_id="assistant_id", + include=["step_details.tool_calls[*].file_search.results[*].content"], + additional_instructions="additional_instructions", + additional_messages=[ + { + "content": "string", + "role": "user", + "attachments": [ + { + "file_id": "file_id", + "tools": [{"type": "code_interpreter"}], + } + ], + "metadata": {"foo": "string"}, + } + ], + instructions="instructions", + max_completion_tokens=256, + max_prompt_tokens=256, + metadata={"foo": "string"}, + model="string", + parallel_tool_calls=True, + reasoning_effort="low", + response_format="auto", + stream=False, + temperature=1, + tool_choice="none", + tools=[{"type": "code_interpreter"}], + top_p=1, + truncation_strategy={ + "type": "auto", + "last_messages": 1, + }, + ) + assert_matches_type(Run, run, path=["response"]) @parametrize def test_raw_response_create_overload_1(self, client: OpenAI) -> None: - response = client.beta.threads.runs.with_raw_response.create( - "string", - assistant_id="string", - ) + with pytest.warns(DeprecationWarning): + response = client.beta.threads.runs.with_raw_response.create( + thread_id="thread_id", + assistant_id="assistant_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -84,82 +89,89 @@ def test_raw_response_create_overload_1(self, client: OpenAI) -> None: @parametrize def test_streaming_response_create_overload_1(self, client: OpenAI) -> None: - with client.beta.threads.runs.with_streaming_response.create( - "string", - assistant_id="string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + with client.beta.threads.runs.with_streaming_response.create( + thread_id="thread_id", + assistant_id="assistant_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - run = response.parse() - assert_matches_type(Run, run, path=["response"]) + run = response.parse() + assert_matches_type(Run, run, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize def test_path_params_create_overload_1(self, client: OpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - client.beta.threads.runs.with_raw_response.create( - "", - assistant_id="string", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + client.beta.threads.runs.with_raw_response.create( + thread_id="", + assistant_id="assistant_id", + ) @parametrize def test_method_create_overload_2(self, client: OpenAI) -> None: - run_stream = client.beta.threads.runs.create( - "string", - assistant_id="string", - stream=True, - ) + with pytest.warns(DeprecationWarning): + run_stream = client.beta.threads.runs.create( + thread_id="thread_id", + assistant_id="assistant_id", + stream=True, + ) + run_stream.response.close() @parametrize def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: - run_stream = client.beta.threads.runs.create( - "string", - assistant_id="string", - stream=True, - include=["step_details.tool_calls[*].file_search.results[*].content"], - additional_instructions="additional_instructions", - additional_messages=[ - { - "content": "string", - "role": "user", - "attachments": [ - { - "file_id": "file_id", - "tools": [{"type": "code_interpreter"}], - } - ], - "metadata": {"foo": "string"}, - } - ], - instructions="string", - max_completion_tokens=256, - max_prompt_tokens=256, - metadata={"foo": "string"}, - model="string", - parallel_tool_calls=True, - reasoning_effort="low", - response_format="auto", - temperature=1, - tool_choice="none", - tools=[{"type": "code_interpreter"}], - top_p=1, - truncation_strategy={ - "type": "auto", - "last_messages": 1, - }, - ) + with pytest.warns(DeprecationWarning): + run_stream = client.beta.threads.runs.create( + thread_id="thread_id", + assistant_id="assistant_id", + stream=True, + include=["step_details.tool_calls[*].file_search.results[*].content"], + additional_instructions="additional_instructions", + additional_messages=[ + { + "content": "string", + "role": "user", + "attachments": [ + { + "file_id": "file_id", + "tools": [{"type": "code_interpreter"}], + } + ], + "metadata": {"foo": "string"}, + } + ], + instructions="instructions", + max_completion_tokens=256, + max_prompt_tokens=256, + metadata={"foo": "string"}, + model="string", + parallel_tool_calls=True, + reasoning_effort="low", + response_format="auto", + temperature=1, + tool_choice="none", + tools=[{"type": "code_interpreter"}], + top_p=1, + truncation_strategy={ + "type": "auto", + "last_messages": 1, + }, + ) + run_stream.response.close() @parametrize def test_raw_response_create_overload_2(self, client: OpenAI) -> None: - response = client.beta.threads.runs.with_raw_response.create( - "string", - assistant_id="string", - stream=True, - ) + with pytest.warns(DeprecationWarning): + response = client.beta.threads.runs.with_raw_response.create( + thread_id="thread_id", + assistant_id="assistant_id", + stream=True, + ) assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() @@ -167,42 +179,47 @@ def test_raw_response_create_overload_2(self, client: OpenAI) -> None: @parametrize def test_streaming_response_create_overload_2(self, client: OpenAI) -> None: - with client.beta.threads.runs.with_streaming_response.create( - "string", - assistant_id="string", - stream=True, - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + with client.beta.threads.runs.with_streaming_response.create( + thread_id="thread_id", + assistant_id="assistant_id", + stream=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - stream = response.parse() - stream.close() + stream = response.parse() + stream.close() assert cast(Any, response.is_closed) is True @parametrize def test_path_params_create_overload_2(self, client: OpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - client.beta.threads.runs.with_raw_response.create( - "", - assistant_id="string", - stream=True, - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + client.beta.threads.runs.with_raw_response.create( + thread_id="", + assistant_id="assistant_id", + stream=True, + ) @parametrize def test_method_retrieve(self, client: OpenAI) -> None: - run = client.beta.threads.runs.retrieve( - "string", - thread_id="string", - ) + with pytest.warns(DeprecationWarning): + run = client.beta.threads.runs.retrieve( + run_id="run_id", + thread_id="thread_id", + ) + assert_matches_type(Run, run, path=["response"]) @parametrize def test_raw_response_retrieve(self, client: OpenAI) -> None: - response = client.beta.threads.runs.with_raw_response.retrieve( - "string", - thread_id="string", - ) + with pytest.warns(DeprecationWarning): + response = client.beta.threads.runs.with_raw_response.retrieve( + run_id="run_id", + thread_id="thread_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -211,55 +228,62 @@ def test_raw_response_retrieve(self, client: OpenAI) -> None: @parametrize def test_streaming_response_retrieve(self, client: OpenAI) -> None: - with client.beta.threads.runs.with_streaming_response.retrieve( - "string", - thread_id="string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + with client.beta.threads.runs.with_streaming_response.retrieve( + run_id="run_id", + thread_id="thread_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - run = response.parse() - assert_matches_type(Run, run, path=["response"]) + run = response.parse() + assert_matches_type(Run, run, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize def test_path_params_retrieve(self, client: OpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - client.beta.threads.runs.with_raw_response.retrieve( - "string", - thread_id="", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + client.beta.threads.runs.with_raw_response.retrieve( + run_id="run_id", + thread_id="", + ) - with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): - client.beta.threads.runs.with_raw_response.retrieve( - "", - thread_id="string", - ) + with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): + client.beta.threads.runs.with_raw_response.retrieve( + run_id="", + thread_id="thread_id", + ) @parametrize def test_method_update(self, client: OpenAI) -> None: - run = client.beta.threads.runs.update( - "string", - thread_id="string", - ) + with pytest.warns(DeprecationWarning): + run = client.beta.threads.runs.update( + run_id="run_id", + thread_id="thread_id", + ) + assert_matches_type(Run, run, path=["response"]) @parametrize def test_method_update_with_all_params(self, client: OpenAI) -> None: - run = client.beta.threads.runs.update( - run_id="run_id", - thread_id="thread_id", - metadata={"foo": "string"}, - ) + with pytest.warns(DeprecationWarning): + run = client.beta.threads.runs.update( + run_id="run_id", + thread_id="thread_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Run, run, path=["response"]) @parametrize def test_raw_response_update(self, client: OpenAI) -> None: - response = client.beta.threads.runs.with_raw_response.update( - "string", - thread_id="string", - ) + with pytest.warns(DeprecationWarning): + response = client.beta.threads.runs.with_raw_response.update( + run_id="run_id", + thread_id="thread_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -268,55 +292,62 @@ def test_raw_response_update(self, client: OpenAI) -> None: @parametrize def test_streaming_response_update(self, client: OpenAI) -> None: - with client.beta.threads.runs.with_streaming_response.update( - "string", - thread_id="string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + with client.beta.threads.runs.with_streaming_response.update( + run_id="run_id", + thread_id="thread_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - run = response.parse() - assert_matches_type(Run, run, path=["response"]) + run = response.parse() + assert_matches_type(Run, run, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize def test_path_params_update(self, client: OpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - client.beta.threads.runs.with_raw_response.update( - "string", - thread_id="", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + client.beta.threads.runs.with_raw_response.update( + run_id="run_id", + thread_id="", + ) - with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): - client.beta.threads.runs.with_raw_response.update( - "", - thread_id="string", - ) + with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): + client.beta.threads.runs.with_raw_response.update( + run_id="", + thread_id="thread_id", + ) @parametrize def test_method_list(self, client: OpenAI) -> None: - run = client.beta.threads.runs.list( - "string", - ) + with pytest.warns(DeprecationWarning): + run = client.beta.threads.runs.list( + thread_id="thread_id", + ) + assert_matches_type(SyncCursorPage[Run], run, path=["response"]) @parametrize def test_method_list_with_all_params(self, client: OpenAI) -> None: - run = client.beta.threads.runs.list( - "string", - after="string", - before="string", - limit=0, - order="asc", - ) + with pytest.warns(DeprecationWarning): + run = client.beta.threads.runs.list( + thread_id="thread_id", + after="after", + before="before", + limit=0, + order="asc", + ) + assert_matches_type(SyncCursorPage[Run], run, path=["response"]) @parametrize def test_raw_response_list(self, client: OpenAI) -> None: - response = client.beta.threads.runs.with_raw_response.list( - "string", - ) + with pytest.warns(DeprecationWarning): + response = client.beta.threads.runs.with_raw_response.list( + thread_id="thread_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -325,38 +356,43 @@ def test_raw_response_list(self, client: OpenAI) -> None: @parametrize def test_streaming_response_list(self, client: OpenAI) -> None: - with client.beta.threads.runs.with_streaming_response.list( - "string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + with client.beta.threads.runs.with_streaming_response.list( + thread_id="thread_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - run = response.parse() - assert_matches_type(SyncCursorPage[Run], run, path=["response"]) + run = response.parse() + assert_matches_type(SyncCursorPage[Run], run, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize def test_path_params_list(self, client: OpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - client.beta.threads.runs.with_raw_response.list( - "", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + client.beta.threads.runs.with_raw_response.list( + thread_id="", + ) @parametrize def test_method_cancel(self, client: OpenAI) -> None: - run = client.beta.threads.runs.cancel( - "string", - thread_id="string", - ) + with pytest.warns(DeprecationWarning): + run = client.beta.threads.runs.cancel( + run_id="run_id", + thread_id="thread_id", + ) + assert_matches_type(Run, run, path=["response"]) @parametrize def test_raw_response_cancel(self, client: OpenAI) -> None: - response = client.beta.threads.runs.with_raw_response.cancel( - "string", - thread_id="string", - ) + with pytest.warns(DeprecationWarning): + response = client.beta.threads.runs.with_raw_response.cancel( + run_id="run_id", + thread_id="thread_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -365,63 +401,70 @@ def test_raw_response_cancel(self, client: OpenAI) -> None: @parametrize def test_streaming_response_cancel(self, client: OpenAI) -> None: - with client.beta.threads.runs.with_streaming_response.cancel( - "string", - thread_id="string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + with client.beta.threads.runs.with_streaming_response.cancel( + run_id="run_id", + thread_id="thread_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - run = response.parse() - assert_matches_type(Run, run, path=["response"]) + run = response.parse() + assert_matches_type(Run, run, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize def test_path_params_cancel(self, client: OpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - client.beta.threads.runs.with_raw_response.cancel( - "string", - thread_id="", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + client.beta.threads.runs.with_raw_response.cancel( + run_id="run_id", + thread_id="", + ) - with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): - client.beta.threads.runs.with_raw_response.cancel( - "", - thread_id="string", - ) + with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): + client.beta.threads.runs.with_raw_response.cancel( + run_id="", + thread_id="thread_id", + ) @parametrize def test_method_submit_tool_outputs_overload_1(self, client: OpenAI) -> None: - run = client.beta.threads.runs.submit_tool_outputs( - run_id="run_id", - thread_id="thread_id", - tool_outputs=[{}], - ) + with pytest.warns(DeprecationWarning): + run = client.beta.threads.runs.submit_tool_outputs( + run_id="run_id", + thread_id="thread_id", + tool_outputs=[{}], + ) + assert_matches_type(Run, run, path=["response"]) @parametrize def test_method_submit_tool_outputs_with_all_params_overload_1(self, client: OpenAI) -> None: - run = client.beta.threads.runs.submit_tool_outputs( - "string", - thread_id="string", - tool_outputs=[ - { - "output": "output", - "tool_call_id": "tool_call_id", - } - ], - stream=False, - ) + with pytest.warns(DeprecationWarning): + run = client.beta.threads.runs.submit_tool_outputs( + run_id="run_id", + thread_id="thread_id", + tool_outputs=[ + { + "output": "output", + "tool_call_id": "tool_call_id", + } + ], + stream=False, + ) + assert_matches_type(Run, run, path=["response"]) @parametrize def test_raw_response_submit_tool_outputs_overload_1(self, client: OpenAI) -> None: - response = client.beta.threads.runs.with_raw_response.submit_tool_outputs( - run_id="run_id", - thread_id="thread_id", - tool_outputs=[{}], - ) + with pytest.warns(DeprecationWarning): + response = client.beta.threads.runs.with_raw_response.submit_tool_outputs( + run_id="run_id", + thread_id="thread_id", + tool_outputs=[{}], + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -430,53 +473,58 @@ def test_raw_response_submit_tool_outputs_overload_1(self, client: OpenAI) -> No @parametrize def test_streaming_response_submit_tool_outputs_overload_1(self, client: OpenAI) -> None: - with client.beta.threads.runs.with_streaming_response.submit_tool_outputs( - run_id="run_id", - thread_id="thread_id", - tool_outputs=[{}], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + with client.beta.threads.runs.with_streaming_response.submit_tool_outputs( + run_id="run_id", + thread_id="thread_id", + tool_outputs=[{}], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - run = response.parse() - assert_matches_type(Run, run, path=["response"]) + run = response.parse() + assert_matches_type(Run, run, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize def test_path_params_submit_tool_outputs_overload_1(self, client: OpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - client.beta.threads.runs.with_raw_response.submit_tool_outputs( - "string", - thread_id="", - tool_outputs=[{}], - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + client.beta.threads.runs.with_raw_response.submit_tool_outputs( + run_id="run_id", + thread_id="", + tool_outputs=[{}], + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): + client.beta.threads.runs.with_raw_response.submit_tool_outputs( + run_id="", + thread_id="thread_id", + tool_outputs=[{}], + ) - with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): - client.beta.threads.runs.with_raw_response.submit_tool_outputs( - run_id="", + @parametrize + def test_method_submit_tool_outputs_overload_2(self, client: OpenAI) -> None: + with pytest.warns(DeprecationWarning): + run_stream = client.beta.threads.runs.submit_tool_outputs( + run_id="run_id", thread_id="thread_id", + stream=True, tool_outputs=[{}], ) - @parametrize - def test_method_submit_tool_outputs_overload_2(self, client: OpenAI) -> None: - run_stream = client.beta.threads.runs.submit_tool_outputs( - "string", - thread_id="string", - stream=True, - tool_outputs=[{}], - ) run_stream.response.close() @parametrize def test_raw_response_submit_tool_outputs_overload_2(self, client: OpenAI) -> None: - response = client.beta.threads.runs.with_raw_response.submit_tool_outputs( - "string", - thread_id="string", - stream=True, - tool_outputs=[{}], - ) + with pytest.warns(DeprecationWarning): + response = client.beta.threads.runs.with_raw_response.submit_tool_outputs( + run_id="run_id", + thread_id="thread_id", + stream=True, + tool_outputs=[{}], + ) assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() @@ -484,37 +532,39 @@ def test_raw_response_submit_tool_outputs_overload_2(self, client: OpenAI) -> No @parametrize def test_streaming_response_submit_tool_outputs_overload_2(self, client: OpenAI) -> None: - with client.beta.threads.runs.with_streaming_response.submit_tool_outputs( - "string", - thread_id="string", - stream=True, - tool_outputs=[{}], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - stream = response.parse() - stream.close() + with pytest.warns(DeprecationWarning): + with client.beta.threads.runs.with_streaming_response.submit_tool_outputs( + run_id="run_id", + thread_id="thread_id", + stream=True, + tool_outputs=[{}], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = response.parse() + stream.close() assert cast(Any, response.is_closed) is True @parametrize def test_path_params_submit_tool_outputs_overload_2(self, client: OpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - client.beta.threads.runs.with_raw_response.submit_tool_outputs( - "string", - thread_id="", - stream=True, - tool_outputs=[{}], - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): - client.beta.threads.runs.with_raw_response.submit_tool_outputs( - "", - thread_id="string", - stream=True, - tool_outputs=[{}], - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + client.beta.threads.runs.with_raw_response.submit_tool_outputs( + run_id="run_id", + thread_id="", + stream=True, + tool_outputs=[{}], + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): + client.beta.threads.runs.with_raw_response.submit_tool_outputs( + run_id="", + thread_id="thread_id", + stream=True, + tool_outputs=[{}], + ) class TestAsyncRuns: @@ -522,58 +572,63 @@ class TestAsyncRuns: @parametrize async def test_method_create_overload_1(self, async_client: AsyncOpenAI) -> None: - run = await async_client.beta.threads.runs.create( - "string", - assistant_id="string", - ) + with pytest.warns(DeprecationWarning): + run = await async_client.beta.threads.runs.create( + thread_id="thread_id", + assistant_id="assistant_id", + ) + assert_matches_type(Run, run, path=["response"]) @parametrize async def test_method_create_with_all_params_overload_1(self, async_client: AsyncOpenAI) -> None: - run = await async_client.beta.threads.runs.create( - thread_id="thread_id", - assistant_id="assistant_id", - include=["step_details.tool_calls[*].file_search.results[*].content"], - additional_instructions="additional_instructions", - additional_messages=[ - { - "content": "string", - "role": "user", - "attachments": [ - { - "file_id": "file_id", - "tools": [{"type": "code_interpreter"}], - } - ], - "metadata": {"foo": "string"}, - } - ], - instructions="string", - max_completion_tokens=256, - max_prompt_tokens=256, - metadata={"foo": "string"}, - model="string", - parallel_tool_calls=True, - reasoning_effort="low", - response_format="auto", - stream=False, - temperature=1, - tool_choice="none", - tools=[{"type": "code_interpreter"}], - top_p=1, - truncation_strategy={ - "type": "auto", - "last_messages": 1, - }, - ) + with pytest.warns(DeprecationWarning): + run = await async_client.beta.threads.runs.create( + thread_id="thread_id", + assistant_id="assistant_id", + include=["step_details.tool_calls[*].file_search.results[*].content"], + additional_instructions="additional_instructions", + additional_messages=[ + { + "content": "string", + "role": "user", + "attachments": [ + { + "file_id": "file_id", + "tools": [{"type": "code_interpreter"}], + } + ], + "metadata": {"foo": "string"}, + } + ], + instructions="instructions", + max_completion_tokens=256, + max_prompt_tokens=256, + metadata={"foo": "string"}, + model="string", + parallel_tool_calls=True, + reasoning_effort="low", + response_format="auto", + stream=False, + temperature=1, + tool_choice="none", + tools=[{"type": "code_interpreter"}], + top_p=1, + truncation_strategy={ + "type": "auto", + "last_messages": 1, + }, + ) + assert_matches_type(Run, run, path=["response"]) @parametrize async def test_raw_response_create_overload_1(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.threads.runs.with_raw_response.create( - "string", - assistant_id="string", - ) + with pytest.warns(DeprecationWarning): + response = await async_client.beta.threads.runs.with_raw_response.create( + thread_id="thread_id", + assistant_id="assistant_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -582,82 +637,89 @@ async def test_raw_response_create_overload_1(self, async_client: AsyncOpenAI) - @parametrize async def test_streaming_response_create_overload_1(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.threads.runs.with_streaming_response.create( - "string", - assistant_id="string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + async with async_client.beta.threads.runs.with_streaming_response.create( + thread_id="thread_id", + assistant_id="assistant_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - run = await response.parse() - assert_matches_type(Run, run, path=["response"]) + run = await response.parse() + assert_matches_type(Run, run, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize async def test_path_params_create_overload_1(self, async_client: AsyncOpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - await async_client.beta.threads.runs.with_raw_response.create( - "", - assistant_id="string", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + await async_client.beta.threads.runs.with_raw_response.create( + thread_id="", + assistant_id="assistant_id", + ) @parametrize async def test_method_create_overload_2(self, async_client: AsyncOpenAI) -> None: - run_stream = await async_client.beta.threads.runs.create( - "string", - assistant_id="string", - stream=True, - ) + with pytest.warns(DeprecationWarning): + run_stream = await async_client.beta.threads.runs.create( + thread_id="thread_id", + assistant_id="assistant_id", + stream=True, + ) + await run_stream.response.aclose() @parametrize async def test_method_create_with_all_params_overload_2(self, async_client: AsyncOpenAI) -> None: - run_stream = await async_client.beta.threads.runs.create( - "string", - assistant_id="string", - stream=True, - include=["step_details.tool_calls[*].file_search.results[*].content"], - additional_instructions="additional_instructions", - additional_messages=[ - { - "content": "string", - "role": "user", - "attachments": [ - { - "file_id": "file_id", - "tools": [{"type": "code_interpreter"}], - } - ], - "metadata": {"foo": "string"}, - } - ], - instructions="string", - max_completion_tokens=256, - max_prompt_tokens=256, - metadata={"foo": "string"}, - model="string", - parallel_tool_calls=True, - reasoning_effort="low", - response_format="auto", - temperature=1, - tool_choice="none", - tools=[{"type": "code_interpreter"}], - top_p=1, - truncation_strategy={ - "type": "auto", - "last_messages": 1, - }, - ) + with pytest.warns(DeprecationWarning): + run_stream = await async_client.beta.threads.runs.create( + thread_id="thread_id", + assistant_id="assistant_id", + stream=True, + include=["step_details.tool_calls[*].file_search.results[*].content"], + additional_instructions="additional_instructions", + additional_messages=[ + { + "content": "string", + "role": "user", + "attachments": [ + { + "file_id": "file_id", + "tools": [{"type": "code_interpreter"}], + } + ], + "metadata": {"foo": "string"}, + } + ], + instructions="instructions", + max_completion_tokens=256, + max_prompt_tokens=256, + metadata={"foo": "string"}, + model="string", + parallel_tool_calls=True, + reasoning_effort="low", + response_format="auto", + temperature=1, + tool_choice="none", + tools=[{"type": "code_interpreter"}], + top_p=1, + truncation_strategy={ + "type": "auto", + "last_messages": 1, + }, + ) + await run_stream.response.aclose() @parametrize async def test_raw_response_create_overload_2(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.threads.runs.with_raw_response.create( - "string", - assistant_id="string", - stream=True, - ) + with pytest.warns(DeprecationWarning): + response = await async_client.beta.threads.runs.with_raw_response.create( + thread_id="thread_id", + assistant_id="assistant_id", + stream=True, + ) assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() @@ -665,42 +727,47 @@ async def test_raw_response_create_overload_2(self, async_client: AsyncOpenAI) - @parametrize async def test_streaming_response_create_overload_2(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.threads.runs.with_streaming_response.create( - "string", - assistant_id="string", - stream=True, - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + async with async_client.beta.threads.runs.with_streaming_response.create( + thread_id="thread_id", + assistant_id="assistant_id", + stream=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - stream = await response.parse() - await stream.close() + stream = await response.parse() + await stream.close() assert cast(Any, response.is_closed) is True @parametrize async def test_path_params_create_overload_2(self, async_client: AsyncOpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - await async_client.beta.threads.runs.with_raw_response.create( - "", - assistant_id="string", - stream=True, - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + await async_client.beta.threads.runs.with_raw_response.create( + thread_id="", + assistant_id="assistant_id", + stream=True, + ) @parametrize async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: - run = await async_client.beta.threads.runs.retrieve( - "string", - thread_id="string", - ) + with pytest.warns(DeprecationWarning): + run = await async_client.beta.threads.runs.retrieve( + run_id="run_id", + thread_id="thread_id", + ) + assert_matches_type(Run, run, path=["response"]) @parametrize async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.threads.runs.with_raw_response.retrieve( - "string", - thread_id="string", - ) + with pytest.warns(DeprecationWarning): + response = await async_client.beta.threads.runs.with_raw_response.retrieve( + run_id="run_id", + thread_id="thread_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -709,55 +776,62 @@ async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.threads.runs.with_streaming_response.retrieve( - "string", - thread_id="string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + async with async_client.beta.threads.runs.with_streaming_response.retrieve( + run_id="run_id", + thread_id="thread_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - run = await response.parse() - assert_matches_type(Run, run, path=["response"]) + run = await response.parse() + assert_matches_type(Run, run, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - await async_client.beta.threads.runs.with_raw_response.retrieve( - "string", - thread_id="", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + await async_client.beta.threads.runs.with_raw_response.retrieve( + run_id="run_id", + thread_id="", + ) - with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): - await async_client.beta.threads.runs.with_raw_response.retrieve( - "", - thread_id="string", - ) + with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): + await async_client.beta.threads.runs.with_raw_response.retrieve( + run_id="", + thread_id="thread_id", + ) @parametrize async def test_method_update(self, async_client: AsyncOpenAI) -> None: - run = await async_client.beta.threads.runs.update( - "string", - thread_id="string", - ) + with pytest.warns(DeprecationWarning): + run = await async_client.beta.threads.runs.update( + run_id="run_id", + thread_id="thread_id", + ) + assert_matches_type(Run, run, path=["response"]) @parametrize async def test_method_update_with_all_params(self, async_client: AsyncOpenAI) -> None: - run = await async_client.beta.threads.runs.update( - run_id="run_id", - thread_id="thread_id", - metadata={"foo": "string"}, - ) + with pytest.warns(DeprecationWarning): + run = await async_client.beta.threads.runs.update( + run_id="run_id", + thread_id="thread_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Run, run, path=["response"]) @parametrize async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.threads.runs.with_raw_response.update( - "string", - thread_id="string", - ) + with pytest.warns(DeprecationWarning): + response = await async_client.beta.threads.runs.with_raw_response.update( + run_id="run_id", + thread_id="thread_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -766,55 +840,62 @@ async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_update(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.threads.runs.with_streaming_response.update( - "string", - thread_id="string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + async with async_client.beta.threads.runs.with_streaming_response.update( + run_id="run_id", + thread_id="thread_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - run = await response.parse() - assert_matches_type(Run, run, path=["response"]) + run = await response.parse() + assert_matches_type(Run, run, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize async def test_path_params_update(self, async_client: AsyncOpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - await async_client.beta.threads.runs.with_raw_response.update( - "string", - thread_id="", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + await async_client.beta.threads.runs.with_raw_response.update( + run_id="run_id", + thread_id="", + ) - with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): - await async_client.beta.threads.runs.with_raw_response.update( - "", - thread_id="string", - ) + with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): + await async_client.beta.threads.runs.with_raw_response.update( + run_id="", + thread_id="thread_id", + ) @parametrize async def test_method_list(self, async_client: AsyncOpenAI) -> None: - run = await async_client.beta.threads.runs.list( - "string", - ) + with pytest.warns(DeprecationWarning): + run = await async_client.beta.threads.runs.list( + thread_id="thread_id", + ) + assert_matches_type(AsyncCursorPage[Run], run, path=["response"]) @parametrize async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: - run = await async_client.beta.threads.runs.list( - "string", - after="string", - before="string", - limit=0, - order="asc", - ) + with pytest.warns(DeprecationWarning): + run = await async_client.beta.threads.runs.list( + thread_id="thread_id", + after="after", + before="before", + limit=0, + order="asc", + ) + assert_matches_type(AsyncCursorPage[Run], run, path=["response"]) @parametrize async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.threads.runs.with_raw_response.list( - "string", - ) + with pytest.warns(DeprecationWarning): + response = await async_client.beta.threads.runs.with_raw_response.list( + thread_id="thread_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -823,38 +904,43 @@ async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.threads.runs.with_streaming_response.list( - "string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + async with async_client.beta.threads.runs.with_streaming_response.list( + thread_id="thread_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - run = await response.parse() - assert_matches_type(AsyncCursorPage[Run], run, path=["response"]) + run = await response.parse() + assert_matches_type(AsyncCursorPage[Run], run, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize async def test_path_params_list(self, async_client: AsyncOpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - await async_client.beta.threads.runs.with_raw_response.list( - "", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + await async_client.beta.threads.runs.with_raw_response.list( + thread_id="", + ) @parametrize async def test_method_cancel(self, async_client: AsyncOpenAI) -> None: - run = await async_client.beta.threads.runs.cancel( - "string", - thread_id="string", - ) + with pytest.warns(DeprecationWarning): + run = await async_client.beta.threads.runs.cancel( + run_id="run_id", + thread_id="thread_id", + ) + assert_matches_type(Run, run, path=["response"]) @parametrize async def test_raw_response_cancel(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.threads.runs.with_raw_response.cancel( - "string", - thread_id="string", - ) + with pytest.warns(DeprecationWarning): + response = await async_client.beta.threads.runs.with_raw_response.cancel( + run_id="run_id", + thread_id="thread_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -863,63 +949,70 @@ async def test_raw_response_cancel(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_cancel(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.threads.runs.with_streaming_response.cancel( - "string", - thread_id="string", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + async with async_client.beta.threads.runs.with_streaming_response.cancel( + run_id="run_id", + thread_id="thread_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - run = await response.parse() - assert_matches_type(Run, run, path=["response"]) + run = await response.parse() + assert_matches_type(Run, run, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize async def test_path_params_cancel(self, async_client: AsyncOpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - await async_client.beta.threads.runs.with_raw_response.cancel( - "string", - thread_id="", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + await async_client.beta.threads.runs.with_raw_response.cancel( + run_id="run_id", + thread_id="", + ) - with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): - await async_client.beta.threads.runs.with_raw_response.cancel( - "", - thread_id="string", - ) + with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): + await async_client.beta.threads.runs.with_raw_response.cancel( + run_id="", + thread_id="thread_id", + ) @parametrize async def test_method_submit_tool_outputs_overload_1(self, async_client: AsyncOpenAI) -> None: - run = await async_client.beta.threads.runs.submit_tool_outputs( - run_id="run_id", - thread_id="thread_id", - tool_outputs=[{}], - ) + with pytest.warns(DeprecationWarning): + run = await async_client.beta.threads.runs.submit_tool_outputs( + run_id="run_id", + thread_id="thread_id", + tool_outputs=[{}], + ) + assert_matches_type(Run, run, path=["response"]) @parametrize async def test_method_submit_tool_outputs_with_all_params_overload_1(self, async_client: AsyncOpenAI) -> None: - run = await async_client.beta.threads.runs.submit_tool_outputs( - "string", - thread_id="string", - tool_outputs=[ - { - "output": "output", - "tool_call_id": "tool_call_id", - } - ], - stream=False, - ) + with pytest.warns(DeprecationWarning): + run = await async_client.beta.threads.runs.submit_tool_outputs( + run_id="run_id", + thread_id="thread_id", + tool_outputs=[ + { + "output": "output", + "tool_call_id": "tool_call_id", + } + ], + stream=False, + ) + assert_matches_type(Run, run, path=["response"]) @parametrize async def test_raw_response_submit_tool_outputs_overload_1(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.threads.runs.with_raw_response.submit_tool_outputs( - run_id="run_id", - thread_id="thread_id", - tool_outputs=[{}], - ) + with pytest.warns(DeprecationWarning): + response = await async_client.beta.threads.runs.with_raw_response.submit_tool_outputs( + run_id="run_id", + thread_id="thread_id", + tool_outputs=[{}], + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -928,53 +1021,58 @@ async def test_raw_response_submit_tool_outputs_overload_1(self, async_client: A @parametrize async def test_streaming_response_submit_tool_outputs_overload_1(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.threads.runs.with_streaming_response.submit_tool_outputs( - run_id="run_id", - thread_id="thread_id", - tool_outputs=[{}], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + async with async_client.beta.threads.runs.with_streaming_response.submit_tool_outputs( + run_id="run_id", + thread_id="thread_id", + tool_outputs=[{}], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - run = await response.parse() - assert_matches_type(Run, run, path=["response"]) + run = await response.parse() + assert_matches_type(Run, run, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize async def test_path_params_submit_tool_outputs_overload_1(self, async_client: AsyncOpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - await async_client.beta.threads.runs.with_raw_response.submit_tool_outputs( - "string", - thread_id="", - tool_outputs=[{}], - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + await async_client.beta.threads.runs.with_raw_response.submit_tool_outputs( + run_id="run_id", + thread_id="", + tool_outputs=[{}], + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): + await async_client.beta.threads.runs.with_raw_response.submit_tool_outputs( + run_id="", + thread_id="thread_id", + tool_outputs=[{}], + ) - with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): - await async_client.beta.threads.runs.with_raw_response.submit_tool_outputs( - run_id="", + @parametrize + async def test_method_submit_tool_outputs_overload_2(self, async_client: AsyncOpenAI) -> None: + with pytest.warns(DeprecationWarning): + run_stream = await async_client.beta.threads.runs.submit_tool_outputs( + run_id="run_id", thread_id="thread_id", + stream=True, tool_outputs=[{}], ) - @parametrize - async def test_method_submit_tool_outputs_overload_2(self, async_client: AsyncOpenAI) -> None: - run_stream = await async_client.beta.threads.runs.submit_tool_outputs( - "string", - thread_id="string", - stream=True, - tool_outputs=[{}], - ) await run_stream.response.aclose() @parametrize async def test_raw_response_submit_tool_outputs_overload_2(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.threads.runs.with_raw_response.submit_tool_outputs( - "string", - thread_id="string", - stream=True, - tool_outputs=[{}], - ) + with pytest.warns(DeprecationWarning): + response = await async_client.beta.threads.runs.with_raw_response.submit_tool_outputs( + run_id="run_id", + thread_id="thread_id", + stream=True, + tool_outputs=[{}], + ) assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() @@ -982,34 +1080,36 @@ async def test_raw_response_submit_tool_outputs_overload_2(self, async_client: A @parametrize async def test_streaming_response_submit_tool_outputs_overload_2(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.threads.runs.with_streaming_response.submit_tool_outputs( - "string", - thread_id="string", - stream=True, - tool_outputs=[{}], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - stream = await response.parse() - await stream.close() + with pytest.warns(DeprecationWarning): + async with async_client.beta.threads.runs.with_streaming_response.submit_tool_outputs( + run_id="run_id", + thread_id="thread_id", + stream=True, + tool_outputs=[{}], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = await response.parse() + await stream.close() assert cast(Any, response.is_closed) is True @parametrize async def test_path_params_submit_tool_outputs_overload_2(self, async_client: AsyncOpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): - await async_client.beta.threads.runs.with_raw_response.submit_tool_outputs( - "string", - thread_id="", - stream=True, - tool_outputs=[{}], - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): - await async_client.beta.threads.runs.with_raw_response.submit_tool_outputs( - "", - thread_id="string", - stream=True, - tool_outputs=[{}], - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + await async_client.beta.threads.runs.with_raw_response.submit_tool_outputs( + run_id="run_id", + thread_id="", + stream=True, + tool_outputs=[{}], + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): + await async_client.beta.threads.runs.with_raw_response.submit_tool_outputs( + run_id="", + thread_id="thread_id", + stream=True, + tool_outputs=[{}], + ) diff --git a/tests/api_resources/containers/files/test_content.py b/tests/api_resources/containers/files/test_content.py index 470353e18d..402607058f 100644 --- a/tests/api_resources/containers/files/test_content.py +++ b/tests/api_resources/containers/files/test_content.py @@ -5,9 +5,15 @@ import os from typing import Any, cast +import httpx import pytest +from respx import MockRouter +import openai._legacy_response as _legacy_response from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type + +# pyright: reportDeprecated=false base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -16,15 +22,25 @@ class TestContent: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) @parametrize - def test_method_retrieve(self, client: OpenAI) -> None: + @pytest.mark.respx(base_url=base_url) + def test_method_retrieve(self, client: OpenAI, respx_mock: MockRouter) -> None: + respx_mock.get("/containers/container_id/files/file_id/content").mock( + return_value=httpx.Response(200, json={"foo": "bar"}) + ) content = client.containers.files.content.retrieve( file_id="file_id", container_id="container_id", ) - assert content is None + assert isinstance(content, _legacy_response.HttpxBinaryResponseContent) + assert content.json() == {"foo": "bar"} @parametrize - def test_raw_response_retrieve(self, client: OpenAI) -> None: + @pytest.mark.respx(base_url=base_url) + def test_raw_response_retrieve(self, client: OpenAI, respx_mock: MockRouter) -> None: + respx_mock.get("/containers/container_id/files/file_id/content").mock( + return_value=httpx.Response(200, json={"foo": "bar"}) + ) + response = client.containers.files.content.with_raw_response.retrieve( file_id="file_id", container_id="container_id", @@ -33,10 +49,14 @@ def test_raw_response_retrieve(self, client: OpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" content = response.parse() - assert content is None + assert_matches_type(_legacy_response.HttpxBinaryResponseContent, content, path=["response"]) @parametrize - def test_streaming_response_retrieve(self, client: OpenAI) -> None: + @pytest.mark.respx(base_url=base_url) + def test_streaming_response_retrieve(self, client: OpenAI, respx_mock: MockRouter) -> None: + respx_mock.get("/containers/container_id/files/file_id/content").mock( + return_value=httpx.Response(200, json={"foo": "bar"}) + ) with client.containers.files.content.with_streaming_response.retrieve( file_id="file_id", container_id="container_id", @@ -45,11 +65,12 @@ def test_streaming_response_retrieve(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" content = response.parse() - assert content is None + assert_matches_type(bytes, content, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize + @pytest.mark.respx(base_url=base_url) def test_path_params_retrieve(self, client: OpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `container_id` but received ''"): client.containers.files.content.with_raw_response.retrieve( @@ -68,15 +89,25 @@ class TestAsyncContent: parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) @parametrize - async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + @pytest.mark.respx(base_url=base_url) + async def test_method_retrieve(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None: + respx_mock.get("/containers/container_id/files/file_id/content").mock( + return_value=httpx.Response(200, json={"foo": "bar"}) + ) content = await async_client.containers.files.content.retrieve( file_id="file_id", container_id="container_id", ) - assert content is None + assert isinstance(content, _legacy_response.HttpxBinaryResponseContent) + assert content.json() == {"foo": "bar"} @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + @pytest.mark.respx(base_url=base_url) + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None: + respx_mock.get("/containers/container_id/files/file_id/content").mock( + return_value=httpx.Response(200, json={"foo": "bar"}) + ) + response = await async_client.containers.files.content.with_raw_response.retrieve( file_id="file_id", container_id="container_id", @@ -85,10 +116,14 @@ async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" content = response.parse() - assert content is None + assert_matches_type(_legacy_response.HttpxBinaryResponseContent, content, path=["response"]) @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + @pytest.mark.respx(base_url=base_url) + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None: + respx_mock.get("/containers/container_id/files/file_id/content").mock( + return_value=httpx.Response(200, json={"foo": "bar"}) + ) async with async_client.containers.files.content.with_streaming_response.retrieve( file_id="file_id", container_id="container_id", @@ -97,11 +132,12 @@ async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> N assert response.http_request.headers.get("X-Stainless-Lang") == "python" content = await response.parse() - assert content is None + assert_matches_type(bytes, content, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize + @pytest.mark.respx(base_url=base_url) async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `container_id` but received ''"): await async_client.containers.files.content.with_raw_response.retrieve( diff --git a/tests/api_resources/fine_tuning/alpha/test_graders.py b/tests/api_resources/fine_tuning/alpha/test_graders.py index b144c78c74..c7fe6670f3 100644 --- a/tests/api_resources/fine_tuning/alpha/test_graders.py +++ b/tests/api_resources/fine_tuning/alpha/test_graders.py @@ -31,7 +31,6 @@ def test_method_run(self, client: OpenAI) -> None: "type": "string_check", }, model_sample="model_sample", - reference_answer="string", ) assert_matches_type(GraderRunResponse, grader, path=["response"]) @@ -46,7 +45,7 @@ def test_method_run_with_all_params(self, client: OpenAI) -> None: "type": "string_check", }, model_sample="model_sample", - reference_answer="string", + item={}, ) assert_matches_type(GraderRunResponse, grader, path=["response"]) @@ -61,7 +60,6 @@ def test_raw_response_run(self, client: OpenAI) -> None: "type": "string_check", }, model_sample="model_sample", - reference_answer="string", ) assert response.is_closed is True @@ -80,7 +78,6 @@ def test_streaming_response_run(self, client: OpenAI) -> None: "type": "string_check", }, model_sample="model_sample", - reference_answer="string", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -167,7 +164,6 @@ async def test_method_run(self, async_client: AsyncOpenAI) -> None: "type": "string_check", }, model_sample="model_sample", - reference_answer="string", ) assert_matches_type(GraderRunResponse, grader, path=["response"]) @@ -182,7 +178,7 @@ async def test_method_run_with_all_params(self, async_client: AsyncOpenAI) -> No "type": "string_check", }, model_sample="model_sample", - reference_answer="string", + item={}, ) assert_matches_type(GraderRunResponse, grader, path=["response"]) @@ -197,7 +193,6 @@ async def test_raw_response_run(self, async_client: AsyncOpenAI) -> None: "type": "string_check", }, model_sample="model_sample", - reference_answer="string", ) assert response.is_closed is True @@ -216,7 +211,6 @@ async def test_streaming_response_run(self, async_client: AsyncOpenAI) -> None: "type": "string_check", }, model_sample="model_sample", - reference_answer="string", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" diff --git a/tests/api_resources/test_responses.py b/tests/api_resources/test_responses.py index 0d33de4a15..7c0f980fbd 100644 --- a/tests/api_resources/test_responses.py +++ b/tests/api_resources/test_responses.py @@ -164,22 +164,24 @@ def test_streaming_response_create_overload_2(self, client: OpenAI) -> None: assert cast(Any, response.is_closed) is True @parametrize - def test_method_retrieve(self, client: OpenAI) -> None: + def test_method_retrieve_overload_1(self, client: OpenAI) -> None: response = client.responses.retrieve( response_id="resp_677efb5139a88190b512bc3fef8e535d", ) assert_matches_type(Response, response, path=["response"]) @parametrize - def test_method_retrieve_with_all_params(self, client: OpenAI) -> None: + def test_method_retrieve_with_all_params_overload_1(self, client: OpenAI) -> None: response = client.responses.retrieve( response_id="resp_677efb5139a88190b512bc3fef8e535d", include=["file_search_call.results"], + starting_after=0, + stream=False, ) assert_matches_type(Response, response, path=["response"]) @parametrize - def test_raw_response_retrieve(self, client: OpenAI) -> None: + def test_raw_response_retrieve_overload_1(self, client: OpenAI) -> None: http_response = client.responses.with_raw_response.retrieve( response_id="resp_677efb5139a88190b512bc3fef8e535d", ) @@ -190,7 +192,7 @@ def test_raw_response_retrieve(self, client: OpenAI) -> None: assert_matches_type(Response, response, path=["response"]) @parametrize - def test_streaming_response_retrieve(self, client: OpenAI) -> None: + def test_streaming_response_retrieve_overload_1(self, client: OpenAI) -> None: with client.responses.with_streaming_response.retrieve( response_id="resp_677efb5139a88190b512bc3fef8e535d", ) as http_response: @@ -203,10 +205,61 @@ def test_streaming_response_retrieve(self, client: OpenAI) -> None: assert cast(Any, http_response.is_closed) is True @parametrize - def test_path_params_retrieve(self, client: OpenAI) -> None: + def test_path_params_retrieve_overload_1(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `response_id` but received ''"): + client.responses.with_raw_response.retrieve( + response_id="", + ) + + @parametrize + def test_method_retrieve_overload_2(self, client: OpenAI) -> None: + response_stream = client.responses.retrieve( + response_id="resp_677efb5139a88190b512bc3fef8e535d", + stream=True, + ) + response_stream.response.close() + + @parametrize + def test_method_retrieve_with_all_params_overload_2(self, client: OpenAI) -> None: + response_stream = client.responses.retrieve( + response_id="resp_677efb5139a88190b512bc3fef8e535d", + stream=True, + include=["file_search_call.results"], + starting_after=0, + ) + response_stream.response.close() + + @parametrize + def test_raw_response_retrieve_overload_2(self, client: OpenAI) -> None: + response = client.responses.with_raw_response.retrieve( + response_id="resp_677efb5139a88190b512bc3fef8e535d", + stream=True, + ) + + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = response.parse() + stream.close() + + @parametrize + def test_streaming_response_retrieve_overload_2(self, client: OpenAI) -> None: + with client.responses.with_streaming_response.retrieve( + response_id="resp_677efb5139a88190b512bc3fef8e535d", + stream=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = response.parse() + stream.close() + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve_overload_2(self, client: OpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `response_id` but received ''"): client.responses.with_raw_response.retrieve( response_id="", + stream=True, ) @parametrize @@ -252,7 +305,7 @@ def test_method_cancel(self, client: OpenAI) -> None: response = client.responses.cancel( "resp_677efb5139a88190b512bc3fef8e535d", ) - assert response is None + assert_matches_type(Response, response, path=["response"]) @parametrize def test_raw_response_cancel(self, client: OpenAI) -> None: @@ -263,7 +316,7 @@ def test_raw_response_cancel(self, client: OpenAI) -> None: assert http_response.is_closed is True assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" response = http_response.parse() - assert response is None + assert_matches_type(Response, response, path=["response"]) @parametrize def test_streaming_response_cancel(self, client: OpenAI) -> None: @@ -274,7 +327,7 @@ def test_streaming_response_cancel(self, client: OpenAI) -> None: assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" response = http_response.parse() - assert response is None + assert_matches_type(Response, response, path=["response"]) assert cast(Any, http_response.is_closed) is True @@ -436,22 +489,24 @@ async def test_streaming_response_create_overload_2(self, async_client: AsyncOpe assert cast(Any, response.is_closed) is True @parametrize - async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + async def test_method_retrieve_overload_1(self, async_client: AsyncOpenAI) -> None: response = await async_client.responses.retrieve( response_id="resp_677efb5139a88190b512bc3fef8e535d", ) assert_matches_type(Response, response, path=["response"]) @parametrize - async def test_method_retrieve_with_all_params(self, async_client: AsyncOpenAI) -> None: + async def test_method_retrieve_with_all_params_overload_1(self, async_client: AsyncOpenAI) -> None: response = await async_client.responses.retrieve( response_id="resp_677efb5139a88190b512bc3fef8e535d", include=["file_search_call.results"], + starting_after=0, + stream=False, ) assert_matches_type(Response, response, path=["response"]) @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async def test_raw_response_retrieve_overload_1(self, async_client: AsyncOpenAI) -> None: http_response = await async_client.responses.with_raw_response.retrieve( response_id="resp_677efb5139a88190b512bc3fef8e535d", ) @@ -462,7 +517,7 @@ async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: assert_matches_type(Response, response, path=["response"]) @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async def test_streaming_response_retrieve_overload_1(self, async_client: AsyncOpenAI) -> None: async with async_client.responses.with_streaming_response.retrieve( response_id="resp_677efb5139a88190b512bc3fef8e535d", ) as http_response: @@ -475,10 +530,61 @@ async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> N assert cast(Any, http_response.is_closed) is True @parametrize - async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + async def test_path_params_retrieve_overload_1(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `response_id` but received ''"): + await async_client.responses.with_raw_response.retrieve( + response_id="", + ) + + @parametrize + async def test_method_retrieve_overload_2(self, async_client: AsyncOpenAI) -> None: + response_stream = await async_client.responses.retrieve( + response_id="resp_677efb5139a88190b512bc3fef8e535d", + stream=True, + ) + await response_stream.response.aclose() + + @parametrize + async def test_method_retrieve_with_all_params_overload_2(self, async_client: AsyncOpenAI) -> None: + response_stream = await async_client.responses.retrieve( + response_id="resp_677efb5139a88190b512bc3fef8e535d", + stream=True, + include=["file_search_call.results"], + starting_after=0, + ) + await response_stream.response.aclose() + + @parametrize + async def test_raw_response_retrieve_overload_2(self, async_client: AsyncOpenAI) -> None: + response = await async_client.responses.with_raw_response.retrieve( + response_id="resp_677efb5139a88190b512bc3fef8e535d", + stream=True, + ) + + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = response.parse() + await stream.close() + + @parametrize + async def test_streaming_response_retrieve_overload_2(self, async_client: AsyncOpenAI) -> None: + async with async_client.responses.with_streaming_response.retrieve( + response_id="resp_677efb5139a88190b512bc3fef8e535d", + stream=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = await response.parse() + await stream.close() + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve_overload_2(self, async_client: AsyncOpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `response_id` but received ''"): await async_client.responses.with_raw_response.retrieve( response_id="", + stream=True, ) @parametrize @@ -524,7 +630,7 @@ async def test_method_cancel(self, async_client: AsyncOpenAI) -> None: response = await async_client.responses.cancel( "resp_677efb5139a88190b512bc3fef8e535d", ) - assert response is None + assert_matches_type(Response, response, path=["response"]) @parametrize async def test_raw_response_cancel(self, async_client: AsyncOpenAI) -> None: @@ -535,7 +641,7 @@ async def test_raw_response_cancel(self, async_client: AsyncOpenAI) -> None: assert http_response.is_closed is True assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" response = http_response.parse() - assert response is None + assert_matches_type(Response, response, path=["response"]) @parametrize async def test_streaming_response_cancel(self, async_client: AsyncOpenAI) -> None: @@ -546,7 +652,7 @@ async def test_streaming_response_cancel(self, async_client: AsyncOpenAI) -> Non assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" response = await http_response.parse() - assert response is None + assert_matches_type(Response, response, path=["response"]) assert cast(Any, http_response.is_closed) is True diff --git a/tests/lib/chat/_utils.py b/tests/lib/chat/_utils.py index af08db417c..f3982278f3 100644 --- a/tests/lib/chat/_utils.py +++ b/tests/lib/chat/_utils.py @@ -28,7 +28,7 @@ def __repr_args__(self: pydantic.BaseModel) -> ReprArgs: string = rich_print_str(obj) - # we remove all `fn_name..` occurences + # we remove all `fn_name..` occurrences # so that we can share the same snapshots between # pydantic v1 and pydantic v2 as their output for # generic models differs, e.g. diff --git a/tests/lib/test_assistants.py b/tests/lib/test_assistants.py index 67d021ec35..08ea9300c3 100644 --- a/tests/lib/test_assistants.py +++ b/tests/lib/test_assistants.py @@ -11,7 +11,7 @@ def test_create_and_run_poll_method_definition_in_sync(sync: bool, client: OpenA checking_client: OpenAI | AsyncOpenAI = client if sync else async_client assert_signatures_in_sync( - checking_client.beta.threads.create_and_run, + checking_client.beta.threads.create_and_run, # pyright: ignore[reportDeprecated] checking_client.beta.threads.create_and_run_poll, exclude_params={"stream"}, ) @@ -22,7 +22,7 @@ def test_create_and_run_stream_method_definition_in_sync(sync: bool, client: Ope checking_client: OpenAI | AsyncOpenAI = client if sync else async_client assert_signatures_in_sync( - checking_client.beta.threads.create_and_run, + checking_client.beta.threads.create_and_run, # pyright: ignore[reportDeprecated] checking_client.beta.threads.create_and_run_stream, exclude_params={"stream"}, ) @@ -33,8 +33,8 @@ def test_run_stream_method_definition_in_sync(sync: bool, client: OpenAI, async_ checking_client: OpenAI | AsyncOpenAI = client if sync else async_client assert_signatures_in_sync( - checking_client.beta.threads.runs.create, - checking_client.beta.threads.runs.stream, + checking_client.beta.threads.runs.create, # pyright: ignore[reportDeprecated] + checking_client.beta.threads.runs.stream, # pyright: ignore[reportDeprecated] exclude_params={"stream"}, ) @@ -44,7 +44,7 @@ def test_create_and_poll_method_definition_in_sync(sync: bool, client: OpenAI, a checking_client: OpenAI | AsyncOpenAI = client if sync else async_client assert_signatures_in_sync( - checking_client.beta.threads.runs.create, - checking_client.beta.threads.runs.create_and_poll, + checking_client.beta.threads.runs.create, # pyright: ignore[reportDeprecated] + checking_client.beta.threads.runs.create_and_poll, # pyright: ignore[reportDeprecated] exclude_params={"stream"}, ) diff --git a/tests/test_client.py b/tests/test_client.py index 616255af3c..2b7aeaf946 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -908,6 +908,33 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: assert response.retries_taken == failures_before_success assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success + @pytest.mark.respx(base_url=base_url) + def test_follow_redirects(self, respx_mock: MockRouter) -> None: + # Test that the default follow_redirects=True allows following redirects + respx_mock.post("/redirect").mock( + return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) + ) + respx_mock.get("/redirected").mock(return_value=httpx.Response(200, json={"status": "ok"})) + + response = self.client.post("/redirect", body={"key": "value"}, cast_to=httpx.Response) + assert response.status_code == 200 + assert response.json() == {"status": "ok"} + + @pytest.mark.respx(base_url=base_url) + def test_follow_redirects_disabled(self, respx_mock: MockRouter) -> None: + # Test that follow_redirects=False prevents following redirects + respx_mock.post("/redirect").mock( + return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) + ) + + with pytest.raises(APIStatusError) as exc_info: + self.client.post( + "/redirect", body={"key": "value"}, options={"follow_redirects": False}, cast_to=httpx.Response + ) + + assert exc_info.value.response.status_code == 302 + assert exc_info.value.response.headers["Location"] == f"{base_url}/redirected" + class TestAsyncOpenAI: client = AsyncOpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=True) @@ -1829,3 +1856,30 @@ async def test_main() -> None: raise AssertionError("calling get_platform using asyncify resulted in a hung process") time.sleep(0.1) + + @pytest.mark.respx(base_url=base_url) + async def test_follow_redirects(self, respx_mock: MockRouter) -> None: + # Test that the default follow_redirects=True allows following redirects + respx_mock.post("/redirect").mock( + return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) + ) + respx_mock.get("/redirected").mock(return_value=httpx.Response(200, json={"status": "ok"})) + + response = await self.client.post("/redirect", body={"key": "value"}, cast_to=httpx.Response) + assert response.status_code == 200 + assert response.json() == {"status": "ok"} + + @pytest.mark.respx(base_url=base_url) + async def test_follow_redirects_disabled(self, respx_mock: MockRouter) -> None: + # Test that follow_redirects=False prevents following redirects + respx_mock.post("/redirect").mock( + return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) + ) + + with pytest.raises(APIStatusError) as exc_info: + await self.client.post( + "/redirect", body={"key": "value"}, options={"follow_redirects": False}, cast_to=httpx.Response + ) + + assert exc_info.value.response.status_code == 302 + assert exc_info.value.response.headers["Location"] == f"{base_url}/redirected" From 56540b32873df335aca9270715a839c2a9770639 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 3 Jun 2025 12:09:52 -0500 Subject: [PATCH 345/769] release: 1.84.0 (#2395) * feat(api): add new realtime and audio models, realtime session options * chore(api): update type names * release: 1.84.0 --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- .stats.yml | 4 +- CHANGELOG.md | 13 +++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- .../resources/beta/realtime/sessions.py | 30 ++++++++++ src/openai/types/beta/realtime/session.py | 56 ++++++++++++++++++- .../beta/realtime/session_create_params.py | 46 ++++++++++++++- .../beta/realtime/session_create_response.py | 53 +++++++++++++++++- .../beta/realtime/session_update_event.py | 46 ++++++++++++++- .../realtime/session_update_event_param.py | 46 ++++++++++++++- src/openai/types/shared/chat_model.py | 1 + src/openai/types/shared_params/chat_model.py | 1 + .../beta/realtime/test_sessions.py | 4 ++ 14 files changed, 293 insertions(+), 13 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 0453d70e4a..67871342a5 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.83.0" + ".": "1.84.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 6f5097c531..035814ecaf 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-2bcc845d8635bf93ddcf9ee723af4d7928248412a417bee5fc10d863a1e13867.yml -openapi_spec_hash: 865230cb3abeb01bd85de05891af23c4 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-0205acb1015d29b2312a48526734c0399f93026d4fe2dff5c7768f566e333fd2.yml +openapi_spec_hash: 1772cc9056c2f6dfb2a4e9cb77ee6343 config_hash: ed1e6b3c5f93d12b80d31167f55c557c diff --git a/CHANGELOG.md b/CHANGELOG.md index 645599e6df..e148567c89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 1.84.0 (2025-06-03) + +Full Changelog: [v1.83.0...v1.84.0](https://github.com/openai/openai-python/compare/v1.83.0...v1.84.0) + +### Features + +* **api:** add new realtime and audio models, realtime session options ([0acd0da](https://github.com/openai/openai-python/commit/0acd0da6bc0468c6c857711bc5e77d0bc6d31be6)) + + +### Chores + +* **api:** update type names ([1924559](https://github.com/openai/openai-python/commit/192455913b38bf0323ddd0e2b1499b114e2111a1)) + ## 1.83.0 (2025-06-02) Full Changelog: [v1.82.1...v1.83.0](https://github.com/openai/openai-python/compare/v1.82.1...v1.83.0) diff --git a/pyproject.toml b/pyproject.toml index 7d3cd30413..224d6dce0f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.83.0" +version = "1.84.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 d947f7a74a..332096f987 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.83.0" # x-release-please-version +__version__ = "1.84.0" # x-release-please-version diff --git a/src/openai/resources/beta/realtime/sessions.py b/src/openai/resources/beta/realtime/sessions.py index 90d8b8fdc4..77f1ec9059 100644 --- a/src/openai/resources/beta/realtime/sessions.py +++ b/src/openai/resources/beta/realtime/sessions.py @@ -54,14 +54,17 @@ def create( "gpt-4o-realtime-preview", "gpt-4o-realtime-preview-2024-10-01", "gpt-4o-realtime-preview-2024-12-17", + "gpt-4o-realtime-preview-2025-06-03", "gpt-4o-mini-realtime-preview", "gpt-4o-mini-realtime-preview-2024-12-17", ] | NotGiven = NOT_GIVEN, output_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] | NotGiven = NOT_GIVEN, + speed: float | NotGiven = NOT_GIVEN, temperature: float | NotGiven = NOT_GIVEN, tool_choice: str | NotGiven = NOT_GIVEN, tools: Iterable[session_create_params.Tool] | NotGiven = NOT_GIVEN, + tracing: session_create_params.Tracing | NotGiven = NOT_GIVEN, turn_detection: session_create_params.TurnDetection | NotGiven = NOT_GIVEN, voice: Union[ str, Literal["alloy", "ash", "ballad", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer", "verse"] @@ -129,6 +132,10 @@ def create( output_audio_format: The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, output audio is sampled at a rate of 24kHz. + speed: The speed of the model's spoken response. 1.0 is the default speed. 0.25 is the + minimum speed. 1.5 is the maximum speed. This value can only be changed in + between model turns, not while a response is in progress. + temperature: Sampling temperature for the model, limited to [0.6, 1.2]. For audio models a temperature of 0.8 is highly recommended for best performance. @@ -137,6 +144,12 @@ def create( tools: Tools (functions) available to the model. + tracing: Configuration options for tracing. Set to null to disable tracing. Once tracing + is enabled for a session, the configuration cannot be modified. + + `auto` will create a trace for the session with default values for the workflow + name, group id, and metadata. + turn_detection: Configuration for turn detection, ether Server VAD or Semantic VAD. This can be set to `null` to turn off, in which case the client must manually trigger model response. Server VAD means that the model will detect the start and end of @@ -175,9 +188,11 @@ def create( "modalities": modalities, "model": model, "output_audio_format": output_audio_format, + "speed": speed, "temperature": temperature, "tool_choice": tool_choice, "tools": tools, + "tracing": tracing, "turn_detection": turn_detection, "voice": voice, }, @@ -224,14 +239,17 @@ async def create( "gpt-4o-realtime-preview", "gpt-4o-realtime-preview-2024-10-01", "gpt-4o-realtime-preview-2024-12-17", + "gpt-4o-realtime-preview-2025-06-03", "gpt-4o-mini-realtime-preview", "gpt-4o-mini-realtime-preview-2024-12-17", ] | NotGiven = NOT_GIVEN, output_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] | NotGiven = NOT_GIVEN, + speed: float | NotGiven = NOT_GIVEN, temperature: float | NotGiven = NOT_GIVEN, tool_choice: str | NotGiven = NOT_GIVEN, tools: Iterable[session_create_params.Tool] | NotGiven = NOT_GIVEN, + tracing: session_create_params.Tracing | NotGiven = NOT_GIVEN, turn_detection: session_create_params.TurnDetection | NotGiven = NOT_GIVEN, voice: Union[ str, Literal["alloy", "ash", "ballad", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer", "verse"] @@ -299,6 +317,10 @@ async def create( output_audio_format: The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, output audio is sampled at a rate of 24kHz. + speed: The speed of the model's spoken response. 1.0 is the default speed. 0.25 is the + minimum speed. 1.5 is the maximum speed. This value can only be changed in + between model turns, not while a response is in progress. + temperature: Sampling temperature for the model, limited to [0.6, 1.2]. For audio models a temperature of 0.8 is highly recommended for best performance. @@ -307,6 +329,12 @@ async def create( tools: Tools (functions) available to the model. + tracing: Configuration options for tracing. Set to null to disable tracing. Once tracing + is enabled for a session, the configuration cannot be modified. + + `auto` will create a trace for the session with default values for the workflow + name, group id, and metadata. + turn_detection: Configuration for turn detection, ether Server VAD or Semantic VAD. This can be set to `null` to turn off, in which case the client must manually trigger model response. Server VAD means that the model will detect the start and end of @@ -345,9 +373,11 @@ async def create( "modalities": modalities, "model": model, "output_audio_format": output_audio_format, + "speed": speed, "temperature": temperature, "tool_choice": tool_choice, "tools": tools, + "tracing": tracing, "turn_detection": turn_detection, "voice": voice, }, diff --git a/src/openai/types/beta/realtime/session.py b/src/openai/types/beta/realtime/session.py index 6acde57f09..606fd83851 100644 --- a/src/openai/types/beta/realtime/session.py +++ b/src/openai/types/beta/realtime/session.py @@ -1,11 +1,19 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from typing import List, Union, Optional -from typing_extensions import Literal +from typing_extensions import Literal, TypeAlias from ...._models import BaseModel -__all__ = ["Session", "InputAudioNoiseReduction", "InputAudioTranscription", "Tool", "TurnDetection"] +__all__ = [ + "Session", + "InputAudioNoiseReduction", + "InputAudioTranscription", + "Tool", + "Tracing", + "TracingTracingConfiguration", + "TurnDetection", +] class InputAudioNoiseReduction(BaseModel): @@ -59,6 +67,29 @@ class Tool(BaseModel): """The type of the tool, i.e. `function`.""" +class TracingTracingConfiguration(BaseModel): + group_id: Optional[str] = None + """ + The group id to attach to this trace to enable filtering and grouping in the + traces dashboard. + """ + + metadata: Optional[object] = None + """ + The arbitrary metadata to attach to this trace to enable filtering in the traces + dashboard. + """ + + workflow_name: Optional[str] = None + """The name of the workflow to attach to this trace. + + This is used to name the trace in the traces dashboard. + """ + + +Tracing: TypeAlias = Union[Literal["auto"], TracingTracingConfiguration] + + class TurnDetection(BaseModel): create_response: Optional[bool] = None """ @@ -175,6 +206,7 @@ class Session(BaseModel): "gpt-4o-realtime-preview", "gpt-4o-realtime-preview-2024-10-01", "gpt-4o-realtime-preview-2024-12-17", + "gpt-4o-realtime-preview-2025-06-03", "gpt-4o-mini-realtime-preview", "gpt-4o-mini-realtime-preview-2024-12-17", ] @@ -188,6 +220,14 @@ class Session(BaseModel): sampled at a rate of 24kHz. """ + speed: Optional[float] = None + """The speed of the model's spoken response. + + 1.0 is the default speed. 0.25 is the minimum speed. 1.5 is the maximum speed. + This value can only be changed in between model turns, not while a response is + in progress. + """ + temperature: Optional[float] = None """Sampling temperature for the model, limited to [0.6, 1.2]. @@ -204,6 +244,16 @@ class Session(BaseModel): tools: Optional[List[Tool]] = None """Tools (functions) available to the model.""" + tracing: Optional[Tracing] = None + """Configuration options for tracing. + + Set to null to disable tracing. Once tracing is enabled for a session, the + configuration cannot be modified. + + `auto` will create a trace for the session with default values for the workflow + name, group id, and metadata. + """ + turn_detection: Optional[TurnDetection] = None """Configuration for turn detection, ether Server VAD or Semantic VAD. @@ -227,5 +277,5 @@ class Session(BaseModel): Voice cannot be changed during the session once the model has responded with audio at least once. Current voice options are `alloy`, `ash`, `ballad`, - `coral`, `echo` `sage`, `shimmer` and `verse`. + `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, `shimmer`, and `verse`. """ diff --git a/src/openai/types/beta/realtime/session_create_params.py b/src/openai/types/beta/realtime/session_create_params.py index 7a8e694f45..cebf67c732 100644 --- a/src/openai/types/beta/realtime/session_create_params.py +++ b/src/openai/types/beta/realtime/session_create_params.py @@ -3,7 +3,7 @@ from __future__ import annotations from typing import List, Union, Iterable -from typing_extensions import Literal, TypedDict +from typing_extensions import Literal, TypeAlias, TypedDict __all__ = [ "SessionCreateParams", @@ -12,6 +12,8 @@ "InputAudioNoiseReduction", "InputAudioTranscription", "Tool", + "Tracing", + "TracingTracingConfiguration", "TurnDetection", ] @@ -82,6 +84,7 @@ class SessionCreateParams(TypedDict, total=False): "gpt-4o-realtime-preview", "gpt-4o-realtime-preview-2024-10-01", "gpt-4o-realtime-preview-2024-12-17", + "gpt-4o-realtime-preview-2025-06-03", "gpt-4o-mini-realtime-preview", "gpt-4o-mini-realtime-preview-2024-12-17", ] @@ -94,6 +97,14 @@ class SessionCreateParams(TypedDict, total=False): sampled at a rate of 24kHz. """ + speed: float + """The speed of the model's spoken response. + + 1.0 is the default speed. 0.25 is the minimum speed. 1.5 is the maximum speed. + This value can only be changed in between model turns, not while a response is + in progress. + """ + temperature: float """Sampling temperature for the model, limited to [0.6, 1.2]. @@ -110,6 +121,16 @@ class SessionCreateParams(TypedDict, total=False): tools: Iterable[Tool] """Tools (functions) available to the model.""" + tracing: Tracing + """Configuration options for tracing. + + Set to null to disable tracing. Once tracing is enabled for a session, the + configuration cannot be modified. + + `auto` will create a trace for the session with default values for the workflow + name, group id, and metadata. + """ + turn_detection: TurnDetection """Configuration for turn detection, ether Server VAD or Semantic VAD. @@ -205,6 +226,29 @@ class Tool(TypedDict, total=False): """The type of the tool, i.e. `function`.""" +class TracingTracingConfiguration(TypedDict, total=False): + group_id: str + """ + The group id to attach to this trace to enable filtering and grouping in the + traces dashboard. + """ + + metadata: object + """ + The arbitrary metadata to attach to this trace to enable filtering in the traces + dashboard. + """ + + workflow_name: str + """The name of the workflow to attach to this trace. + + This is used to name the trace in the traces dashboard. + """ + + +Tracing: TypeAlias = Union[Literal["auto"], TracingTracingConfiguration] + + class TurnDetection(TypedDict, total=False): create_response: bool """ diff --git a/src/openai/types/beta/realtime/session_create_response.py b/src/openai/types/beta/realtime/session_create_response.py index 3cc8ca15ce..81fed95fa9 100644 --- a/src/openai/types/beta/realtime/session_create_response.py +++ b/src/openai/types/beta/realtime/session_create_response.py @@ -1,11 +1,19 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from typing import List, Union, Optional -from typing_extensions import Literal +from typing_extensions import Literal, TypeAlias from ...._models import BaseModel -__all__ = ["SessionCreateResponse", "ClientSecret", "InputAudioTranscription", "Tool", "TurnDetection"] +__all__ = [ + "SessionCreateResponse", + "ClientSecret", + "InputAudioTranscription", + "Tool", + "Tracing", + "TracingTracingConfiguration", + "TurnDetection", +] class ClientSecret(BaseModel): @@ -48,6 +56,29 @@ class Tool(BaseModel): """The type of the tool, i.e. `function`.""" +class TracingTracingConfiguration(BaseModel): + group_id: Optional[str] = None + """ + The group id to attach to this trace to enable filtering and grouping in the + traces dashboard. + """ + + metadata: Optional[object] = None + """ + The arbitrary metadata to attach to this trace to enable filtering in the traces + dashboard. + """ + + workflow_name: Optional[str] = None + """The name of the workflow to attach to this trace. + + This is used to name the trace in the traces dashboard. + """ + + +Tracing: TypeAlias = Union[Literal["auto"], TracingTracingConfiguration] + + class TurnDetection(BaseModel): prefix_padding_ms: Optional[int] = None """Amount of audio to include before the VAD detected speech (in milliseconds). @@ -121,6 +152,14 @@ class SessionCreateResponse(BaseModel): output_audio_format: Optional[str] = None """The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + speed: Optional[float] = None + """The speed of the model's spoken response. + + 1.0 is the default speed. 0.25 is the minimum speed. 1.5 is the maximum speed. + This value can only be changed in between model turns, not while a response is + in progress. + """ + temperature: Optional[float] = None """Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8.""" @@ -133,6 +172,16 @@ class SessionCreateResponse(BaseModel): tools: Optional[List[Tool]] = None """Tools (functions) available to the model.""" + tracing: Optional[Tracing] = None + """Configuration options for tracing. + + Set to null to disable tracing. Once tracing is enabled for a session, the + configuration cannot be modified. + + `auto` will create a trace for the session with default values for the workflow + name, group id, and metadata. + """ + turn_detection: Optional[TurnDetection] = None """Configuration for turn detection. diff --git a/src/openai/types/beta/realtime/session_update_event.py b/src/openai/types/beta/realtime/session_update_event.py index 1cd3ded27c..8bb6a0e266 100644 --- a/src/openai/types/beta/realtime/session_update_event.py +++ b/src/openai/types/beta/realtime/session_update_event.py @@ -1,7 +1,7 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from typing import List, Union, Optional -from typing_extensions import Literal +from typing_extensions import Literal, TypeAlias from ...._models import BaseModel @@ -13,6 +13,8 @@ "SessionInputAudioNoiseReduction", "SessionInputAudioTranscription", "SessionTool", + "SessionTracing", + "SessionTracingTracingConfiguration", "SessionTurnDetection", ] @@ -87,6 +89,29 @@ class SessionTool(BaseModel): """The type of the tool, i.e. `function`.""" +class SessionTracingTracingConfiguration(BaseModel): + group_id: Optional[str] = None + """ + The group id to attach to this trace to enable filtering and grouping in the + traces dashboard. + """ + + metadata: Optional[object] = None + """ + The arbitrary metadata to attach to this trace to enable filtering in the traces + dashboard. + """ + + workflow_name: Optional[str] = None + """The name of the workflow to attach to this trace. + + This is used to name the trace in the traces dashboard. + """ + + +SessionTracing: TypeAlias = Union[Literal["auto"], SessionTracingTracingConfiguration] + + class SessionTurnDetection(BaseModel): create_response: Optional[bool] = None """ @@ -203,6 +228,7 @@ class Session(BaseModel): "gpt-4o-realtime-preview", "gpt-4o-realtime-preview-2024-10-01", "gpt-4o-realtime-preview-2024-12-17", + "gpt-4o-realtime-preview-2025-06-03", "gpt-4o-mini-realtime-preview", "gpt-4o-mini-realtime-preview-2024-12-17", ] @@ -216,6 +242,14 @@ class Session(BaseModel): sampled at a rate of 24kHz. """ + speed: Optional[float] = None + """The speed of the model's spoken response. + + 1.0 is the default speed. 0.25 is the minimum speed. 1.5 is the maximum speed. + This value can only be changed in between model turns, not while a response is + in progress. + """ + temperature: Optional[float] = None """Sampling temperature for the model, limited to [0.6, 1.2]. @@ -232,6 +266,16 @@ class Session(BaseModel): tools: Optional[List[SessionTool]] = None """Tools (functions) available to the model.""" + tracing: Optional[SessionTracing] = None + """Configuration options for tracing. + + Set to null to disable tracing. Once tracing is enabled for a session, the + configuration cannot be modified. + + `auto` will create a trace for the session with default values for the workflow + name, group id, and metadata. + """ + turn_detection: Optional[SessionTurnDetection] = None """Configuration for turn detection, ether Server VAD or Semantic VAD. diff --git a/src/openai/types/beta/realtime/session_update_event_param.py b/src/openai/types/beta/realtime/session_update_event_param.py index ee18aec239..a10de540d0 100644 --- a/src/openai/types/beta/realtime/session_update_event_param.py +++ b/src/openai/types/beta/realtime/session_update_event_param.py @@ -3,7 +3,7 @@ from __future__ import annotations from typing import List, Union, Iterable -from typing_extensions import Literal, Required, TypedDict +from typing_extensions import Literal, Required, TypeAlias, TypedDict __all__ = [ "SessionUpdateEventParam", @@ -13,6 +13,8 @@ "SessionInputAudioNoiseReduction", "SessionInputAudioTranscription", "SessionTool", + "SessionTracing", + "SessionTracingTracingConfiguration", "SessionTurnDetection", ] @@ -87,6 +89,29 @@ class SessionTool(TypedDict, total=False): """The type of the tool, i.e. `function`.""" +class SessionTracingTracingConfiguration(TypedDict, total=False): + group_id: str + """ + The group id to attach to this trace to enable filtering and grouping in the + traces dashboard. + """ + + metadata: object + """ + The arbitrary metadata to attach to this trace to enable filtering in the traces + dashboard. + """ + + workflow_name: str + """The name of the workflow to attach to this trace. + + This is used to name the trace in the traces dashboard. + """ + + +SessionTracing: TypeAlias = Union[Literal["auto"], SessionTracingTracingConfiguration] + + class SessionTurnDetection(TypedDict, total=False): create_response: bool """ @@ -202,6 +227,7 @@ class Session(TypedDict, total=False): "gpt-4o-realtime-preview", "gpt-4o-realtime-preview-2024-10-01", "gpt-4o-realtime-preview-2024-12-17", + "gpt-4o-realtime-preview-2025-06-03", "gpt-4o-mini-realtime-preview", "gpt-4o-mini-realtime-preview-2024-12-17", ] @@ -214,6 +240,14 @@ class Session(TypedDict, total=False): sampled at a rate of 24kHz. """ + speed: float + """The speed of the model's spoken response. + + 1.0 is the default speed. 0.25 is the minimum speed. 1.5 is the maximum speed. + This value can only be changed in between model turns, not while a response is + in progress. + """ + temperature: float """Sampling temperature for the model, limited to [0.6, 1.2]. @@ -230,6 +264,16 @@ class Session(TypedDict, total=False): tools: Iterable[SessionTool] """Tools (functions) available to the model.""" + tracing: SessionTracing + """Configuration options for tracing. + + Set to null to disable tracing. Once tracing is enabled for a session, the + configuration cannot be modified. + + `auto` will create a trace for the session with default values for the workflow + name, group id, and metadata. + """ + turn_detection: SessionTurnDetection """Configuration for turn detection, ether Server VAD or Semantic VAD. diff --git a/src/openai/types/shared/chat_model.py b/src/openai/types/shared/chat_model.py index 75069e7a98..309368a384 100644 --- a/src/openai/types/shared/chat_model.py +++ b/src/openai/types/shared/chat_model.py @@ -30,6 +30,7 @@ "gpt-4o-audio-preview", "gpt-4o-audio-preview-2024-10-01", "gpt-4o-audio-preview-2024-12-17", + "gpt-4o-audio-preview-2025-06-03", "gpt-4o-mini-audio-preview", "gpt-4o-mini-audio-preview-2024-12-17", "gpt-4o-search-preview", diff --git a/src/openai/types/shared_params/chat_model.py b/src/openai/types/shared_params/chat_model.py index c421744b8a..6cd8e7f91f 100644 --- a/src/openai/types/shared_params/chat_model.py +++ b/src/openai/types/shared_params/chat_model.py @@ -32,6 +32,7 @@ "gpt-4o-audio-preview", "gpt-4o-audio-preview-2024-10-01", "gpt-4o-audio-preview-2024-12-17", + "gpt-4o-audio-preview-2025-06-03", "gpt-4o-mini-audio-preview", "gpt-4o-mini-audio-preview-2024-12-17", "gpt-4o-search-preview", diff --git a/tests/api_resources/beta/realtime/test_sessions.py b/tests/api_resources/beta/realtime/test_sessions.py index c2046bdb7a..efc52e0d57 100644 --- a/tests/api_resources/beta/realtime/test_sessions.py +++ b/tests/api_resources/beta/realtime/test_sessions.py @@ -43,6 +43,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: modalities=["text"], model="gpt-4o-realtime-preview", output_audio_format="pcm16", + speed=0.25, temperature=0, tool_choice="tool_choice", tools=[ @@ -53,6 +54,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: "type": "function", } ], + tracing="auto", turn_detection={ "create_response": True, "eagerness": "low", @@ -116,6 +118,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> modalities=["text"], model="gpt-4o-realtime-preview", output_audio_format="pcm16", + speed=0.25, temperature=0, tool_choice="tool_choice", tools=[ @@ -126,6 +129,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> "type": "function", } ], + tracing="auto", turn_detection={ "create_response": True, "eagerness": "low", From 498fb998f1bc95f4898469f5d8fca54b6c5cfb33 Mon Sep 17 00:00:00 2001 From: Shreehari Date: Wed, 4 Jun 2025 19:21:14 +0530 Subject: [PATCH 346/769] fix(responses): support raw responses for `parse()` --- src/openai/resources/responses/responses.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index c3bec87153..81ae4e5bd6 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -2483,6 +2483,9 @@ def __init__(self, responses: Responses) -> None: self.cancel = _legacy_response.to_raw_response_wrapper( responses.cancel, ) + self.parse = _legacy_response.to_raw_response_wrapper( + responses.parse, + ) @cached_property def input_items(self) -> InputItemsWithRawResponse: @@ -2505,6 +2508,9 @@ def __init__(self, responses: AsyncResponses) -> None: self.cancel = _legacy_response.async_to_raw_response_wrapper( responses.cancel, ) + self.parse = _legacy_response.async_to_raw_response_wrapper( + responses.parse, + ) @cached_property def input_items(self) -> AsyncInputItemsWithRawResponse: From e5e40b823d3dc5c82c0fe6a10982d012eccc051d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 9 Jun 2025 15:47:27 +0000 Subject: [PATCH 347/769] feat(api): Add tools and structured outputs to evals --- .stats.yml | 4 +- src/openai/types/chat/__init__.py | 1 + src/openai/types/chat/chat_completion_tool.py | 15 ++++++ ...create_eval_completions_run_data_source.py | 28 +++++++++++ ..._eval_completions_run_data_source_param.py | 28 +++++++++++ src/openai/types/evals/run_cancel_response.py | 48 +++++++++++++++++++ src/openai/types/evals/run_create_params.py | 48 +++++++++++++++++++ src/openai/types/evals/run_create_response.py | 48 +++++++++++++++++++ src/openai/types/evals/run_list_response.py | 48 +++++++++++++++++++ .../types/evals/run_retrieve_response.py | 48 +++++++++++++++++++ 10 files changed, 314 insertions(+), 2 deletions(-) create mode 100644 src/openai/types/chat/chat_completion_tool.py diff --git a/.stats.yml b/.stats.yml index 035814ecaf..25b4500060 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-0205acb1015d29b2312a48526734c0399f93026d4fe2dff5c7768f566e333fd2.yml -openapi_spec_hash: 1772cc9056c2f6dfb2a4e9cb77ee6343 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-4865dda2b62927bd141cbc85f81be3d88602f103e2c581e15eb1caded3e3aaa2.yml +openapi_spec_hash: 7d14a9b23ef4ac93ea46d629601b6f6b config_hash: ed1e6b3c5f93d12b80d31167f55c557c diff --git a/src/openai/types/chat/__init__.py b/src/openai/types/chat/__init__.py index b4f43b298f..0945bcad11 100644 --- a/src/openai/types/chat/__init__.py +++ b/src/openai/types/chat/__init__.py @@ -4,6 +4,7 @@ from .chat_completion import ChatCompletion as ChatCompletion from .chat_completion_role import ChatCompletionRole as ChatCompletionRole +from .chat_completion_tool import ChatCompletionTool as ChatCompletionTool from .chat_completion_audio import ChatCompletionAudio as ChatCompletionAudio from .chat_completion_chunk import ChatCompletionChunk as ChatCompletionChunk from .completion_list_params import CompletionListParams as CompletionListParams diff --git a/src/openai/types/chat/chat_completion_tool.py b/src/openai/types/chat/chat_completion_tool.py new file mode 100644 index 0000000000..ae9126f906 --- /dev/null +++ b/src/openai/types/chat/chat_completion_tool.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel +from ..shared.function_definition import FunctionDefinition + +__all__ = ["ChatCompletionTool"] + + +class ChatCompletionTool(BaseModel): + function: FunctionDefinition + + type: Literal["function"] + """The type of the tool. Currently, only `function` is supported.""" diff --git a/src/openai/types/evals/create_eval_completions_run_data_source.py b/src/openai/types/evals/create_eval_completions_run_data_source.py index 064ef3a310..0a942cd200 100644 --- a/src/openai/types/evals/create_eval_completions_run_data_source.py +++ b/src/openai/types/evals/create_eval_completions_run_data_source.py @@ -6,8 +6,12 @@ from ..._utils import PropertyInfo from ..._models import BaseModel from ..shared.metadata import Metadata +from ..chat.chat_completion_tool import ChatCompletionTool +from ..shared.response_format_text import ResponseFormatText from ..responses.easy_input_message import EasyInputMessage from ..responses.response_input_text import ResponseInputText +from ..shared.response_format_json_object import ResponseFormatJSONObject +from ..shared.response_format_json_schema import ResponseFormatJSONSchema __all__ = [ "CreateEvalCompletionsRunDataSource", @@ -24,6 +28,7 @@ "InputMessagesTemplateTemplateMessageContentOutputText", "InputMessagesItemReference", "SamplingParams", + "SamplingParamsResponseFormat", ] @@ -136,17 +141,40 @@ class InputMessagesItemReference(BaseModel): Union[InputMessagesTemplate, InputMessagesItemReference], PropertyInfo(discriminator="type") ] +SamplingParamsResponseFormat: TypeAlias = Union[ResponseFormatText, ResponseFormatJSONSchema, ResponseFormatJSONObject] + class SamplingParams(BaseModel): max_completion_tokens: Optional[int] = None """The maximum number of tokens in the generated output.""" + response_format: Optional[SamplingParamsResponseFormat] = None + """An object specifying the format that the model must output. + + Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured + Outputs which ensures the model will match your supplied JSON schema. Learn more + in the + [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). + + Setting to `{ "type": "json_object" }` enables the older JSON mode, which + ensures the message the model generates is valid JSON. Using `json_schema` is + preferred for models that support it. + """ + seed: Optional[int] = None """A seed value to initialize the randomness, during sampling.""" temperature: Optional[float] = None """A higher temperature increases randomness in the outputs.""" + tools: Optional[List[ChatCompletionTool]] = None + """A list of tools the model may call. + + Currently, only functions are supported as a tool. Use this to provide a list of + functions the model may generate JSON inputs for. A max of 128 functions are + supported. + """ + top_p: Optional[float] = None """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" diff --git a/src/openai/types/evals/create_eval_completions_run_data_source_param.py b/src/openai/types/evals/create_eval_completions_run_data_source_param.py index 3fa4c19ad2..84344fcd94 100644 --- a/src/openai/types/evals/create_eval_completions_run_data_source_param.py +++ b/src/openai/types/evals/create_eval_completions_run_data_source_param.py @@ -6,8 +6,12 @@ from typing_extensions import Literal, Required, TypeAlias, TypedDict from ..shared_params.metadata import Metadata +from ..chat.chat_completion_tool_param import ChatCompletionToolParam from ..responses.easy_input_message_param import EasyInputMessageParam +from ..shared_params.response_format_text import ResponseFormatText from ..responses.response_input_text_param import ResponseInputTextParam +from ..shared_params.response_format_json_object import ResponseFormatJSONObject +from ..shared_params.response_format_json_schema import ResponseFormatJSONSchema __all__ = [ "CreateEvalCompletionsRunDataSourceParam", @@ -24,6 +28,7 @@ "InputMessagesTemplateTemplateMessageContentOutputText", "InputMessagesItemReference", "SamplingParams", + "SamplingParamsResponseFormat", ] @@ -130,17 +135,40 @@ class InputMessagesItemReference(TypedDict, total=False): InputMessages: TypeAlias = Union[InputMessagesTemplate, InputMessagesItemReference] +SamplingParamsResponseFormat: TypeAlias = Union[ResponseFormatText, ResponseFormatJSONSchema, ResponseFormatJSONObject] + class SamplingParams(TypedDict, total=False): max_completion_tokens: int """The maximum number of tokens in the generated output.""" + response_format: SamplingParamsResponseFormat + """An object specifying the format that the model must output. + + Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured + Outputs which ensures the model will match your supplied JSON schema. Learn more + in the + [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). + + Setting to `{ "type": "json_object" }` enables the older JSON mode, which + ensures the message the model generates is valid JSON. Using `json_schema` is + preferred for models that support it. + """ + seed: int """A seed value to initialize the randomness, during sampling.""" temperature: float """A higher temperature increases randomness in the outputs.""" + tools: Iterable[ChatCompletionToolParam] + """A list of tools the model may call. + + Currently, only functions are supported as a tool. Use this to provide a list of + functions the model may generate JSON inputs for. A max of 128 functions are + supported. + """ + top_p: float """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" diff --git a/src/openai/types/evals/run_cancel_response.py b/src/openai/types/evals/run_cancel_response.py index d3416129af..12cc868045 100644 --- a/src/openai/types/evals/run_cancel_response.py +++ b/src/openai/types/evals/run_cancel_response.py @@ -8,10 +8,12 @@ from ..._utils import PropertyInfo from ..._models import BaseModel from .eval_api_error import EvalAPIError +from ..responses.tool import Tool from ..shared.metadata import Metadata from ..shared.reasoning_effort import ReasoningEffort from ..responses.response_input_text import ResponseInputText from .create_eval_jsonl_run_data_source import CreateEvalJSONLRunDataSource +from ..responses.response_format_text_config import ResponseFormatTextConfig from .create_eval_completions_run_data_source import CreateEvalCompletionsRunDataSource __all__ = [ @@ -32,6 +34,7 @@ "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText", "DataSourceResponsesInputMessagesItemReference", "DataSourceResponsesSamplingParams", + "DataSourceResponsesSamplingParamsText", "PerModelUsage", "PerTestingCriteriaResult", "ResultCounts", @@ -185,6 +188,24 @@ class DataSourceResponsesInputMessagesItemReference(BaseModel): ] +class DataSourceResponsesSamplingParamsText(BaseModel): + format: Optional[ResponseFormatTextConfig] = None + """An object specifying the format that the model must output. + + Configuring `{ "type": "json_schema" }` enables Structured Outputs, which + ensures the model will match your supplied JSON schema. Learn more in the + [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). + + The default format is `{ "type": "text" }` with no additional options. + + **Not recommended for gpt-4o and newer models:** + + Setting to `{ "type": "json_object" }` enables the older JSON mode, which + ensures the message the model generates is valid JSON. Using `json_schema` is + preferred for models that support it. + """ + + class DataSourceResponsesSamplingParams(BaseModel): max_completion_tokens: Optional[int] = None """The maximum number of tokens in the generated output.""" @@ -195,6 +216,33 @@ class DataSourceResponsesSamplingParams(BaseModel): temperature: Optional[float] = None """A higher temperature increases randomness in the outputs.""" + text: Optional[DataSourceResponsesSamplingParamsText] = None + """Configuration options for a text response from the model. + + Can be plain text or structured JSON data. Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + """ + + tools: Optional[List[Tool]] = None + """An array of tools the model may call while generating a response. + + You can specify which tool to use by setting the `tool_choice` parameter. + + The two categories of tools you can provide the model are: + + - **Built-in tools**: Tools that are provided by OpenAI that extend the model's + capabilities, like + [web search](https://platform.openai.com/docs/guides/tools-web-search) or + [file search](https://platform.openai.com/docs/guides/tools-file-search). + Learn more about + [built-in tools](https://platform.openai.com/docs/guides/tools). + - **Function calls (custom tools)**: Functions that are defined by you, enabling + the model to call your own code. Learn more about + [function calling](https://platform.openai.com/docs/guides/function-calling). + """ + top_p: Optional[float] = None """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" diff --git a/src/openai/types/evals/run_create_params.py b/src/openai/types/evals/run_create_params.py index 5aa2398f36..354a81132e 100644 --- a/src/openai/types/evals/run_create_params.py +++ b/src/openai/types/evals/run_create_params.py @@ -5,10 +5,12 @@ from typing import Dict, List, Union, Iterable, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict +from ..responses.tool_param import ToolParam from ..shared_params.metadata import Metadata from ..shared.reasoning_effort import ReasoningEffort from ..responses.response_input_text_param import ResponseInputTextParam from .create_eval_jsonl_run_data_source_param import CreateEvalJSONLRunDataSourceParam +from ..responses.response_format_text_config_param import ResponseFormatTextConfigParam from .create_eval_completions_run_data_source_param import CreateEvalCompletionsRunDataSourceParam __all__ = [ @@ -29,6 +31,7 @@ "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentOutputText", "DataSourceCreateEvalResponsesRunDataSourceInputMessagesItemReference", "DataSourceCreateEvalResponsesRunDataSourceSamplingParams", + "DataSourceCreateEvalResponsesRunDataSourceSamplingParamsText", ] @@ -202,6 +205,24 @@ class DataSourceCreateEvalResponsesRunDataSourceInputMessagesItemReference(Typed ] +class DataSourceCreateEvalResponsesRunDataSourceSamplingParamsText(TypedDict, total=False): + format: ResponseFormatTextConfigParam + """An object specifying the format that the model must output. + + Configuring `{ "type": "json_schema" }` enables Structured Outputs, which + ensures the model will match your supplied JSON schema. Learn more in the + [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). + + The default format is `{ "type": "text" }` with no additional options. + + **Not recommended for gpt-4o and newer models:** + + Setting to `{ "type": "json_object" }` enables the older JSON mode, which + ensures the message the model generates is valid JSON. Using `json_schema` is + preferred for models that support it. + """ + + class DataSourceCreateEvalResponsesRunDataSourceSamplingParams(TypedDict, total=False): max_completion_tokens: int """The maximum number of tokens in the generated output.""" @@ -212,6 +233,33 @@ class DataSourceCreateEvalResponsesRunDataSourceSamplingParams(TypedDict, total= temperature: float """A higher temperature increases randomness in the outputs.""" + text: DataSourceCreateEvalResponsesRunDataSourceSamplingParamsText + """Configuration options for a text response from the model. + + Can be plain text or structured JSON data. Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + """ + + tools: Iterable[ToolParam] + """An array of tools the model may call while generating a response. + + You can specify which tool to use by setting the `tool_choice` parameter. + + The two categories of tools you can provide the model are: + + - **Built-in tools**: Tools that are provided by OpenAI that extend the model's + capabilities, like + [web search](https://platform.openai.com/docs/guides/tools-web-search) or + [file search](https://platform.openai.com/docs/guides/tools-file-search). + Learn more about + [built-in tools](https://platform.openai.com/docs/guides/tools). + - **Function calls (custom tools)**: Functions that are defined by you, enabling + the model to call your own code. Learn more about + [function calling](https://platform.openai.com/docs/guides/function-calling). + """ + top_p: float """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" diff --git a/src/openai/types/evals/run_create_response.py b/src/openai/types/evals/run_create_response.py index 51aed2080f..776ebb413f 100644 --- a/src/openai/types/evals/run_create_response.py +++ b/src/openai/types/evals/run_create_response.py @@ -8,10 +8,12 @@ from ..._utils import PropertyInfo from ..._models import BaseModel from .eval_api_error import EvalAPIError +from ..responses.tool import Tool from ..shared.metadata import Metadata from ..shared.reasoning_effort import ReasoningEffort from ..responses.response_input_text import ResponseInputText from .create_eval_jsonl_run_data_source import CreateEvalJSONLRunDataSource +from ..responses.response_format_text_config import ResponseFormatTextConfig from .create_eval_completions_run_data_source import CreateEvalCompletionsRunDataSource __all__ = [ @@ -32,6 +34,7 @@ "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText", "DataSourceResponsesInputMessagesItemReference", "DataSourceResponsesSamplingParams", + "DataSourceResponsesSamplingParamsText", "PerModelUsage", "PerTestingCriteriaResult", "ResultCounts", @@ -185,6 +188,24 @@ class DataSourceResponsesInputMessagesItemReference(BaseModel): ] +class DataSourceResponsesSamplingParamsText(BaseModel): + format: Optional[ResponseFormatTextConfig] = None + """An object specifying the format that the model must output. + + Configuring `{ "type": "json_schema" }` enables Structured Outputs, which + ensures the model will match your supplied JSON schema. Learn more in the + [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). + + The default format is `{ "type": "text" }` with no additional options. + + **Not recommended for gpt-4o and newer models:** + + Setting to `{ "type": "json_object" }` enables the older JSON mode, which + ensures the message the model generates is valid JSON. Using `json_schema` is + preferred for models that support it. + """ + + class DataSourceResponsesSamplingParams(BaseModel): max_completion_tokens: Optional[int] = None """The maximum number of tokens in the generated output.""" @@ -195,6 +216,33 @@ class DataSourceResponsesSamplingParams(BaseModel): temperature: Optional[float] = None """A higher temperature increases randomness in the outputs.""" + text: Optional[DataSourceResponsesSamplingParamsText] = None + """Configuration options for a text response from the model. + + Can be plain text or structured JSON data. Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + """ + + tools: Optional[List[Tool]] = None + """An array of tools the model may call while generating a response. + + You can specify which tool to use by setting the `tool_choice` parameter. + + The two categories of tools you can provide the model are: + + - **Built-in tools**: Tools that are provided by OpenAI that extend the model's + capabilities, like + [web search](https://platform.openai.com/docs/guides/tools-web-search) or + [file search](https://platform.openai.com/docs/guides/tools-file-search). + Learn more about + [built-in tools](https://platform.openai.com/docs/guides/tools). + - **Function calls (custom tools)**: Functions that are defined by you, enabling + the model to call your own code. Learn more about + [function calling](https://platform.openai.com/docs/guides/function-calling). + """ + top_p: Optional[float] = None """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" diff --git a/src/openai/types/evals/run_list_response.py b/src/openai/types/evals/run_list_response.py index f1d0b01da9..9e2374f93c 100644 --- a/src/openai/types/evals/run_list_response.py +++ b/src/openai/types/evals/run_list_response.py @@ -8,10 +8,12 @@ from ..._utils import PropertyInfo from ..._models import BaseModel from .eval_api_error import EvalAPIError +from ..responses.tool import Tool from ..shared.metadata import Metadata from ..shared.reasoning_effort import ReasoningEffort from ..responses.response_input_text import ResponseInputText from .create_eval_jsonl_run_data_source import CreateEvalJSONLRunDataSource +from ..responses.response_format_text_config import ResponseFormatTextConfig from .create_eval_completions_run_data_source import CreateEvalCompletionsRunDataSource __all__ = [ @@ -32,6 +34,7 @@ "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText", "DataSourceResponsesInputMessagesItemReference", "DataSourceResponsesSamplingParams", + "DataSourceResponsesSamplingParamsText", "PerModelUsage", "PerTestingCriteriaResult", "ResultCounts", @@ -185,6 +188,24 @@ class DataSourceResponsesInputMessagesItemReference(BaseModel): ] +class DataSourceResponsesSamplingParamsText(BaseModel): + format: Optional[ResponseFormatTextConfig] = None + """An object specifying the format that the model must output. + + Configuring `{ "type": "json_schema" }` enables Structured Outputs, which + ensures the model will match your supplied JSON schema. Learn more in the + [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). + + The default format is `{ "type": "text" }` with no additional options. + + **Not recommended for gpt-4o and newer models:** + + Setting to `{ "type": "json_object" }` enables the older JSON mode, which + ensures the message the model generates is valid JSON. Using `json_schema` is + preferred for models that support it. + """ + + class DataSourceResponsesSamplingParams(BaseModel): max_completion_tokens: Optional[int] = None """The maximum number of tokens in the generated output.""" @@ -195,6 +216,33 @@ class DataSourceResponsesSamplingParams(BaseModel): temperature: Optional[float] = None """A higher temperature increases randomness in the outputs.""" + text: Optional[DataSourceResponsesSamplingParamsText] = None + """Configuration options for a text response from the model. + + Can be plain text or structured JSON data. Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + """ + + tools: Optional[List[Tool]] = None + """An array of tools the model may call while generating a response. + + You can specify which tool to use by setting the `tool_choice` parameter. + + The two categories of tools you can provide the model are: + + - **Built-in tools**: Tools that are provided by OpenAI that extend the model's + capabilities, like + [web search](https://platform.openai.com/docs/guides/tools-web-search) or + [file search](https://platform.openai.com/docs/guides/tools-file-search). + Learn more about + [built-in tools](https://platform.openai.com/docs/guides/tools). + - **Function calls (custom tools)**: Functions that are defined by you, enabling + the model to call your own code. Learn more about + [function calling](https://platform.openai.com/docs/guides/function-calling). + """ + top_p: Optional[float] = None """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" diff --git a/src/openai/types/evals/run_retrieve_response.py b/src/openai/types/evals/run_retrieve_response.py index 6c5951b4eb..a4f43ce3f9 100644 --- a/src/openai/types/evals/run_retrieve_response.py +++ b/src/openai/types/evals/run_retrieve_response.py @@ -8,10 +8,12 @@ from ..._utils import PropertyInfo from ..._models import BaseModel from .eval_api_error import EvalAPIError +from ..responses.tool import Tool from ..shared.metadata import Metadata from ..shared.reasoning_effort import ReasoningEffort from ..responses.response_input_text import ResponseInputText from .create_eval_jsonl_run_data_source import CreateEvalJSONLRunDataSource +from ..responses.response_format_text_config import ResponseFormatTextConfig from .create_eval_completions_run_data_source import CreateEvalCompletionsRunDataSource __all__ = [ @@ -32,6 +34,7 @@ "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText", "DataSourceResponsesInputMessagesItemReference", "DataSourceResponsesSamplingParams", + "DataSourceResponsesSamplingParamsText", "PerModelUsage", "PerTestingCriteriaResult", "ResultCounts", @@ -185,6 +188,24 @@ class DataSourceResponsesInputMessagesItemReference(BaseModel): ] +class DataSourceResponsesSamplingParamsText(BaseModel): + format: Optional[ResponseFormatTextConfig] = None + """An object specifying the format that the model must output. + + Configuring `{ "type": "json_schema" }` enables Structured Outputs, which + ensures the model will match your supplied JSON schema. Learn more in the + [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). + + The default format is `{ "type": "text" }` with no additional options. + + **Not recommended for gpt-4o and newer models:** + + Setting to `{ "type": "json_object" }` enables the older JSON mode, which + ensures the message the model generates is valid JSON. Using `json_schema` is + preferred for models that support it. + """ + + class DataSourceResponsesSamplingParams(BaseModel): max_completion_tokens: Optional[int] = None """The maximum number of tokens in the generated output.""" @@ -195,6 +216,33 @@ class DataSourceResponsesSamplingParams(BaseModel): temperature: Optional[float] = None """A higher temperature increases randomness in the outputs.""" + text: Optional[DataSourceResponsesSamplingParamsText] = None + """Configuration options for a text response from the model. + + Can be plain text or structured JSON data. Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + """ + + tools: Optional[List[Tool]] = None + """An array of tools the model may call while generating a response. + + You can specify which tool to use by setting the `tool_choice` parameter. + + The two categories of tools you can provide the model are: + + - **Built-in tools**: Tools that are provided by OpenAI that extend the model's + capabilities, like + [web search](https://platform.openai.com/docs/guides/tools-web-search) or + [file search](https://platform.openai.com/docs/guides/tools-file-search). + Learn more about + [built-in tools](https://platform.openai.com/docs/guides/tools). + - **Function calls (custom tools)**: Functions that are defined by you, enabling + the model to call your own code. Learn more about + [function calling](https://platform.openai.com/docs/guides/function-calling). + """ + top_p: Optional[float] = None """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" From 2a345ee7b2a49ff500412fe58f1c80d74bc1731b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 9 Jun 2025 15:48:23 +0000 Subject: [PATCH 348/769] release: 1.85.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 67871342a5..c3ef6db435 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.84.0" + ".": "1.85.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index e148567c89..412b520d51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 1.85.0 (2025-06-09) + +Full Changelog: [v1.84.0...v1.85.0](https://github.com/openai/openai-python/compare/v1.84.0...v1.85.0) + +### Features + +* **api:** Add tools and structured outputs to evals ([002cc7b](https://github.com/openai/openai-python/commit/002cc7bb3c315d95b81c2e497f55d21be7fd26f8)) + + +### Bug Fixes + +* **responses:** support raw responses for `parse()` ([d459943](https://github.com/openai/openai-python/commit/d459943cc1c81cf9ce5c426edd3ef9112fdf6723)) + ## 1.84.0 (2025-06-03) Full Changelog: [v1.83.0...v1.84.0](https://github.com/openai/openai-python/compare/v1.83.0...v1.84.0) diff --git a/pyproject.toml b/pyproject.toml index 224d6dce0f..7add11521c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.84.0" +version = "1.85.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 332096f987..0b85832b85 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.84.0" # x-release-please-version +__version__ = "1.85.0" # x-release-please-version From eed877fddc0e26ab99d10157de25e3abcb95598b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 10 Jun 2025 11:49:38 -0500 Subject: [PATCH 349/769] release: 1.86.0 (#2405) * feat(api): Add o3-pro model IDs * release: 1.86.0 --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- .stats.yml | 6 +++--- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- src/openai/types/shared/all_models.py | 11 ++++++++++- src/openai/types/shared/responses_model.py | 11 ++++++++++- src/openai/types/shared_params/responses_model.py | 11 ++++++++++- 8 files changed, 44 insertions(+), 9 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index c3ef6db435..ceafc9afb0 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.85.0" + ".": "1.86.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 25b4500060..c9e264655c 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-4865dda2b62927bd141cbc85f81be3d88602f103e2c581e15eb1caded3e3aaa2.yml -openapi_spec_hash: 7d14a9b23ef4ac93ea46d629601b6f6b -config_hash: ed1e6b3c5f93d12b80d31167f55c557c +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-3ae9c18dd7ccfc3ac5206f24394665f563a19015cfa8847b2801a2694d012abc.yml +openapi_spec_hash: 48175b03b58805cd5c80793c66fd54e5 +config_hash: 4caff63b74a41f71006987db702f2918 diff --git a/CHANGELOG.md b/CHANGELOG.md index 412b520d51..aa75f7a2fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.86.0 (2025-06-10) + +Full Changelog: [v1.85.0...v1.86.0](https://github.com/openai/openai-python/compare/v1.85.0...v1.86.0) + +### Features + +* **api:** Add o3-pro model IDs ([d8dd80b](https://github.com/openai/openai-python/commit/d8dd80b1b4e6c73687d7acb6c3f62f0bf4b8282c)) + ## 1.85.0 (2025-06-09) Full Changelog: [v1.84.0...v1.85.0](https://github.com/openai/openai-python/compare/v1.84.0...v1.85.0) diff --git a/pyproject.toml b/pyproject.toml index 7add11521c..a9ef5bec90 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.85.0" +version = "1.86.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 0b85832b85..c0f313e3c3 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.85.0" # x-release-please-version +__version__ = "1.86.0" # x-release-please-version diff --git a/src/openai/types/shared/all_models.py b/src/openai/types/shared/all_models.py index db8410773e..fae8c4c8ff 100644 --- a/src/openai/types/shared/all_models.py +++ b/src/openai/types/shared/all_models.py @@ -8,5 +8,14 @@ __all__ = ["AllModels"] AllModels: TypeAlias = Union[ - str, ChatModel, Literal["o1-pro", "o1-pro-2025-03-19", "computer-use-preview", "computer-use-preview-2025-03-11"] + str, + ChatModel, + Literal[ + "o1-pro", + "o1-pro-2025-03-19", + "o3-pro", + "o3-pro-2025-06-10", + "computer-use-preview", + "computer-use-preview-2025-03-11", + ], ] diff --git a/src/openai/types/shared/responses_model.py b/src/openai/types/shared/responses_model.py index 85f154fd84..790c1212f6 100644 --- a/src/openai/types/shared/responses_model.py +++ b/src/openai/types/shared/responses_model.py @@ -8,5 +8,14 @@ __all__ = ["ResponsesModel"] ResponsesModel: TypeAlias = Union[ - str, ChatModel, Literal["o1-pro", "o1-pro-2025-03-19", "computer-use-preview", "computer-use-preview-2025-03-11"] + str, + ChatModel, + Literal[ + "o1-pro", + "o1-pro-2025-03-19", + "o3-pro", + "o3-pro-2025-06-10", + "computer-use-preview", + "computer-use-preview-2025-03-11", + ], ] diff --git a/src/openai/types/shared_params/responses_model.py b/src/openai/types/shared_params/responses_model.py index 3bf0e13731..ca526b8f15 100644 --- a/src/openai/types/shared_params/responses_model.py +++ b/src/openai/types/shared_params/responses_model.py @@ -10,5 +10,14 @@ __all__ = ["ResponsesModel"] ResponsesModel: TypeAlias = Union[ - str, ChatModel, Literal["o1-pro", "o1-pro-2025-03-19", "computer-use-preview", "computer-use-preview-2025-03-11"] + str, + ChatModel, + Literal[ + "o1-pro", + "o1-pro-2025-03-19", + "o3-pro", + "o3-pro-2025-06-10", + "computer-use-preview", + "computer-use-preview-2025-03-11", + ], ] From cc2c1fc15fd0bf1a5bdfb7b28b4d8d34e1cccad2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 16 Jun 2025 14:03:28 -0500 Subject: [PATCH 350/769] release: 1.87.0 (#2410) * chore(internal): codegen related update * chore(tests): add tests for httpx client instantiation & proxies * feat(api): add reusable prompt IDs * fix(client): update service_tier on `client.beta.chat.completions` * chore(internal): update conftest.py * release: 1.87.0 --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> Co-authored-by: David Meadows --- .release-please-manifest.json | 2 +- .stats.yml | 6 +- CHANGELOG.md | 20 ++ api.md | 1 + pyproject.toml | 5 +- requirements-dev.lock | 4 + src/openai/_base_client.py | 18 +- src/openai/_version.py | 2 +- src/openai/resources/beta/chat/completions.py | 8 +- .../resources/chat/completions/completions.py | 16 +- src/openai/resources/fine_tuning/jobs/jobs.py | 20 +- src/openai/resources/images.py | 24 ++ src/openai/resources/responses/responses.py | 63 ++-- src/openai/types/chat/chat_completion.py | 2 +- .../types/chat/chat_completion_chunk.py | 2 +- .../types/chat/completion_create_params.py | 2 +- .../types/fine_tuning/job_create_params.py | 6 +- src/openai/types/image_edit_params.py | 14 + src/openai/types/responses/__init__.py | 3 + src/openai/types/responses/response.py | 16 +- .../types/responses/response_create_params.py | 13 +- .../types/responses/response_input_item.py | 305 ++++++++++++++++++ src/openai/types/responses/response_prompt.py | 28 ++ .../types/responses/response_prompt_param.py | 29 ++ tests/api_resources/test_images.py | 4 + tests/api_resources/test_responses.py | 24 +- tests/conftest.py | 2 + tests/test_client.py | 53 ++- 28 files changed, 627 insertions(+), 65 deletions(-) create mode 100644 src/openai/types/responses/response_input_item.py create mode 100644 src/openai/types/responses/response_prompt.py create mode 100644 src/openai/types/responses/response_prompt_param.py diff --git a/.release-please-manifest.json b/.release-please-manifest.json index ceafc9afb0..5e0920bd53 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.86.0" + ".": "1.87.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index c9e264655c..feda32cffe 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-3ae9c18dd7ccfc3ac5206f24394665f563a19015cfa8847b2801a2694d012abc.yml -openapi_spec_hash: 48175b03b58805cd5c80793c66fd54e5 -config_hash: 4caff63b74a41f71006987db702f2918 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-9e41d2d5471d2c28bff0d616f4476f5b0e6c541ef4cb51bdaaef5fdf5e13c8b2.yml +openapi_spec_hash: 86f765e18d00e32cf2ce9db7ab84d946 +config_hash: fd2af1d5eff0995bb7dc02ac9a34851d diff --git a/CHANGELOG.md b/CHANGELOG.md index aa75f7a2fe..c67c695b0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,25 @@ # Changelog +## 1.87.0 (2025-06-16) + +Full Changelog: [v1.86.0...v1.87.0](https://github.com/openai/openai-python/compare/v1.86.0...v1.87.0) + +### Features + +* **api:** add reusable prompt IDs ([36bfe6e](https://github.com/openai/openai-python/commit/36bfe6e8ae12a31624ba1a360d9260f0aeec448a)) + + +### Bug Fixes + +* **client:** update service_tier on `client.beta.chat.completions` ([aa488d5](https://github.com/openai/openai-python/commit/aa488d5cf210d8640f87216538d4ff79d7181f2a)) + + +### Chores + +* **internal:** codegen related update ([b1a31e5](https://github.com/openai/openai-python/commit/b1a31e5ef4387d9f82cf33f9461371651788d381)) +* **internal:** update conftest.py ([bba0213](https://github.com/openai/openai-python/commit/bba0213842a4c161f2235e526d50901a336eecef)) +* **tests:** add tests for httpx client instantiation & proxies ([bc93712](https://github.com/openai/openai-python/commit/bc9371204f457aee9ed9b6ec1b61c2084f32faf1)) + ## 1.86.0 (2025-06-10) Full Changelog: [v1.85.0...v1.86.0](https://github.com/openai/openai-python/compare/v1.85.0...v1.86.0) diff --git a/api.md b/api.md index 732436aacd..25360d741e 100644 --- a/api.md +++ b/api.md @@ -750,6 +750,7 @@ from openai.types.responses import ( ResponseOutputRefusal, ResponseOutputText, ResponseOutputTextAnnotationAddedEvent, + ResponsePrompt, ResponseQueuedEvent, ResponseReasoningDeltaEvent, ResponseReasoningDoneEvent, diff --git a/pyproject.toml b/pyproject.toml index a9ef5bec90..54f343064f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.86.0" +version = "1.87.0" description = "The official Python library for the openai API" dynamic = ["readme"] license = "Apache-2.0" @@ -68,6 +68,7 @@ dev-dependencies = [ "types-pyaudio > 0", "trio >=0.22.2", "nest_asyncio==1.6.0", + "pytest-xdist>=3.6.1", ] [tool.rye.scripts] @@ -139,7 +140,7 @@ replacement = '[\1](https://github.com/openai/openai-python/tree/main/\g<2>)' [tool.pytest.ini_options] testpaths = ["tests"] -addopts = "--tb=short" +addopts = "--tb=short -n auto" xfail_strict = true asyncio_mode = "auto" asyncio_default_fixture_loop_scope = "session" diff --git a/requirements-dev.lock b/requirements-dev.lock index 9875a2b860..787c15be6a 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -54,6 +54,8 @@ exceptiongroup==1.2.2 # via anyio # via pytest # via trio +execnet==2.1.1 + # via pytest-xdist executing==2.1.0 # via inline-snapshot filelock==3.12.4 @@ -129,7 +131,9 @@ pyjwt==2.8.0 pyright==1.1.399 pytest==8.3.3 # via pytest-asyncio + # via pytest-xdist pytest-asyncio==0.24.0 +pytest-xdist==3.7.0 python-dateutil==2.8.2 # via pandas # via time-machine diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index 44b3603008..2f87d23aaa 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -1088,7 +1088,14 @@ def _process_response( origin = get_origin(cast_to) or cast_to - if inspect.isclass(origin) and issubclass(origin, BaseAPIResponse): + if ( + inspect.isclass(origin) + and issubclass(origin, BaseAPIResponse) + # we only want to actually return the custom BaseAPIResponse class if we're + # returning the raw response, or if we're not streaming SSE, as if we're streaming + # SSE then `cast_to` doesn't actively reflect the type we need to parse into + and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER))) + ): if not issubclass(origin, APIResponse): raise TypeError(f"API Response types must subclass {APIResponse}; Received {origin}") @@ -1606,7 +1613,14 @@ async def _process_response( origin = get_origin(cast_to) or cast_to - if inspect.isclass(origin) and issubclass(origin, BaseAPIResponse): + if ( + inspect.isclass(origin) + and issubclass(origin, BaseAPIResponse) + # we only want to actually return the custom BaseAPIResponse class if we're + # returning the raw response, or if we're not streaming SSE, as if we're streaming + # SSE then `cast_to` doesn't actively reflect the type we need to parse into + and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER))) + ): if not issubclass(origin, AsyncAPIResponse): raise TypeError(f"API Response types must subclass {AsyncAPIResponse}; Received {origin}") diff --git a/src/openai/_version.py b/src/openai/_version.py index c0f313e3c3..4d66bc793a 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.86.0" # x-release-please-version +__version__ = "1.87.0" # x-release-please-version diff --git a/src/openai/resources/beta/chat/completions.py b/src/openai/resources/beta/chat/completions.py index 80e015615f..871c4ab48a 100644 --- a/src/openai/resources/beta/chat/completions.py +++ b/src/openai/resources/beta/chat/completions.py @@ -81,7 +81,7 @@ def parse( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, @@ -228,7 +228,7 @@ def stream( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, @@ -360,7 +360,7 @@ async def parse( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, @@ -507,7 +507,7 @@ def stream( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index a2a664ac59..a6b89fc833 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -95,7 +95,7 @@ def create( reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, @@ -365,7 +365,7 @@ def create( reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, @@ -634,7 +634,7 @@ def create( reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, @@ -902,7 +902,7 @@ def create( reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, @@ -1198,7 +1198,7 @@ async def create( reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, @@ -1468,7 +1468,7 @@ async def create( reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, @@ -1737,7 +1737,7 @@ async def create( reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, @@ -2005,7 +2005,7 @@ async def create( reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, diff --git a/src/openai/resources/fine_tuning/jobs/jobs.py b/src/openai/resources/fine_tuning/jobs/jobs.py index 5cca219172..ee21cdd280 100644 --- a/src/openai/resources/fine_tuning/jobs/jobs.py +++ b/src/openai/resources/fine_tuning/jobs/jobs.py @@ -84,7 +84,7 @@ def create( Response includes details of the enqueued job including job status and the name of the fine-tuned models once complete. - [Learn more about fine-tuning](https://platform.openai.com/docs/guides/fine-tuning) + [Learn more about fine-tuning](https://platform.openai.com/docs/guides/model-optimization) Args: model: The name of the model to fine-tune. You can select one of the @@ -105,7 +105,8 @@ def create( [preference](https://platform.openai.com/docs/api-reference/fine-tuning/preference-input) format. - See the [fine-tuning guide](https://platform.openai.com/docs/guides/fine-tuning) + See the + [fine-tuning guide](https://platform.openai.com/docs/guides/model-optimization) for more details. hyperparameters: The hyperparameters used for the fine-tuning job. This value is now deprecated @@ -142,7 +143,8 @@ def create( Your dataset must be formatted as a JSONL file. You must upload your file with the purpose `fine-tune`. - See the [fine-tuning guide](https://platform.openai.com/docs/guides/fine-tuning) + See the + [fine-tuning guide](https://platform.openai.com/docs/guides/model-optimization) for more details. extra_headers: Send extra headers @@ -189,7 +191,7 @@ def retrieve( """ Get info about a fine-tuning job. - [Learn more about fine-tuning](https://platform.openai.com/docs/guides/fine-tuning) + [Learn more about fine-tuning](https://platform.openai.com/docs/guides/model-optimization) Args: extra_headers: Send extra headers @@ -462,7 +464,7 @@ async def create( Response includes details of the enqueued job including job status and the name of the fine-tuned models once complete. - [Learn more about fine-tuning](https://platform.openai.com/docs/guides/fine-tuning) + [Learn more about fine-tuning](https://platform.openai.com/docs/guides/model-optimization) Args: model: The name of the model to fine-tune. You can select one of the @@ -483,7 +485,8 @@ async def create( [preference](https://platform.openai.com/docs/api-reference/fine-tuning/preference-input) format. - See the [fine-tuning guide](https://platform.openai.com/docs/guides/fine-tuning) + See the + [fine-tuning guide](https://platform.openai.com/docs/guides/model-optimization) for more details. hyperparameters: The hyperparameters used for the fine-tuning job. This value is now deprecated @@ -520,7 +523,8 @@ async def create( Your dataset must be formatted as a JSONL file. You must upload your file with the purpose `fine-tune`. - See the [fine-tuning guide](https://platform.openai.com/docs/guides/fine-tuning) + See the + [fine-tuning guide](https://platform.openai.com/docs/guides/model-optimization) for more details. extra_headers: Send extra headers @@ -567,7 +571,7 @@ async def retrieve( """ Get info about a fine-tuning job. - [Learn more about fine-tuning](https://platform.openai.com/docs/guides/fine-tuning) + [Learn more about fine-tuning](https://platform.openai.com/docs/guides/model-optimization) Args: extra_headers: Send extra headers diff --git a/src/openai/resources/images.py b/src/openai/resources/images.py index 0f1c9fcb9e..43f6189f91 100644 --- a/src/openai/resources/images.py +++ b/src/openai/resources/images.py @@ -123,6 +123,8 @@ def edit( mask: FileTypes | NotGiven = NOT_GIVEN, model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, + output_compression: Optional[int] | NotGiven = NOT_GIVEN, + output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] @@ -171,6 +173,14 @@ def edit( n: The number of images to generate. Must be between 1 and 10. + output_compression: The compression level (0-100%) for the generated images. This parameter is only + supported for `gpt-image-1` with the `webp` or `jpeg` output formats, and + defaults to 100. + + output_format: The format in which the generated images are returned. This parameter is only + supported for `gpt-image-1`. Must be one of `png`, `jpeg`, or `webp`. The + default value is `png`. + quality: The quality of the image that will be generated. `high`, `medium` and `low` are only supported for `gpt-image-1`. `dall-e-2` only supports `standard` quality. Defaults to `auto`. @@ -204,6 +214,8 @@ def edit( "mask": mask, "model": model, "n": n, + "output_compression": output_compression, + "output_format": output_format, "quality": quality, "response_format": response_format, "size": size, @@ -447,6 +459,8 @@ async def edit( mask: FileTypes | NotGiven = NOT_GIVEN, model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, + output_compression: Optional[int] | NotGiven = NOT_GIVEN, + output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] @@ -495,6 +509,14 @@ async def edit( n: The number of images to generate. Must be between 1 and 10. + output_compression: The compression level (0-100%) for the generated images. This parameter is only + supported for `gpt-image-1` with the `webp` or `jpeg` output formats, and + defaults to 100. + + output_format: The format in which the generated images are returned. This parameter is only + supported for `gpt-image-1`. Must be one of `png`, `jpeg`, or `webp`. The + default value is `png`. + quality: The quality of the image that will be generated. `high`, `medium` and `low` are only supported for `gpt-image-1`. `dall-e-2` only supports `standard` quality. Defaults to `auto`. @@ -528,6 +550,8 @@ async def edit( "mask": mask, "model": model, "n": n, + "output_compression": output_compression, + "output_format": output_format, "quality": quality, "response_format": response_format, "size": size, diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 81ae4e5bd6..3276501494 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -41,6 +41,7 @@ from ...types.responses.response_includable import ResponseIncludable from ...types.shared_params.responses_model import ResponsesModel from ...types.responses.response_input_param import ResponseInputParam +from ...types.responses.response_prompt_param import ResponsePromptParam from ...types.responses.response_stream_event import ResponseStreamEvent from ...types.responses.response_text_config_param import ResponseTextConfigParam @@ -84,8 +85,9 @@ def create( metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -152,8 +154,7 @@ def create( - `code_interpreter_call.outputs`: Includes the outputs of python code execution in code interpreter tool call items. - instructions: Inserts a system (or developer) message as the first item in the model's - context. + instructions: A system (or developer) message inserted into the model's context. When using along with `previous_response_id`, the instructions from a previous response will not be carried over to the next response. This makes it simple to @@ -176,6 +177,9 @@ def create( multi-turn conversations. Learn more about [conversation state](https://platform.openai.com/docs/guides/conversation-state). + prompt: Reference to a prompt template and its variables. + [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). + reasoning: **o-series models only** Configuration options for @@ -280,8 +284,9 @@ def create( metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, @@ -354,8 +359,7 @@ def create( - `code_interpreter_call.outputs`: Includes the outputs of python code execution in code interpreter tool call items. - instructions: Inserts a system (or developer) message as the first item in the model's - context. + instructions: A system (or developer) message inserted into the model's context. When using along with `previous_response_id`, the instructions from a previous response will not be carried over to the next response. This makes it simple to @@ -378,6 +382,9 @@ def create( multi-turn conversations. Learn more about [conversation state](https://platform.openai.com/docs/guides/conversation-state). + prompt: Reference to a prompt template and its variables. + [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). + reasoning: **o-series models only** Configuration options for @@ -475,8 +482,9 @@ def create( metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, @@ -549,8 +557,7 @@ def create( - `code_interpreter_call.outputs`: Includes the outputs of python code execution in code interpreter tool call items. - instructions: Inserts a system (or developer) message as the first item in the model's - context. + instructions: A system (or developer) message inserted into the model's context. When using along with `previous_response_id`, the instructions from a previous response will not be carried over to the next response. This makes it simple to @@ -573,6 +580,9 @@ def create( multi-turn conversations. Learn more about [conversation state](https://platform.openai.com/docs/guides/conversation-state). + prompt: Reference to a prompt template and its variables. + [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). + reasoning: **o-series models only** Configuration options for @@ -669,8 +679,9 @@ def create( metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -700,6 +711,7 @@ def create( "metadata": metadata, "parallel_tool_calls": parallel_tool_calls, "previous_response_id": previous_response_id, + "prompt": prompt, "reasoning": reasoning, "service_tier": service_tier, "store": store, @@ -1292,8 +1304,9 @@ async def create( metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -1360,8 +1373,7 @@ async def create( - `code_interpreter_call.outputs`: Includes the outputs of python code execution in code interpreter tool call items. - instructions: Inserts a system (or developer) message as the first item in the model's - context. + instructions: A system (or developer) message inserted into the model's context. When using along with `previous_response_id`, the instructions from a previous response will not be carried over to the next response. This makes it simple to @@ -1384,6 +1396,9 @@ async def create( multi-turn conversations. Learn more about [conversation state](https://platform.openai.com/docs/guides/conversation-state). + prompt: Reference to a prompt template and its variables. + [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). + reasoning: **o-series models only** Configuration options for @@ -1488,8 +1503,9 @@ async def create( metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, @@ -1562,8 +1578,7 @@ async def create( - `code_interpreter_call.outputs`: Includes the outputs of python code execution in code interpreter tool call items. - instructions: Inserts a system (or developer) message as the first item in the model's - context. + instructions: A system (or developer) message inserted into the model's context. When using along with `previous_response_id`, the instructions from a previous response will not be carried over to the next response. This makes it simple to @@ -1586,6 +1601,9 @@ async def create( multi-turn conversations. Learn more about [conversation state](https://platform.openai.com/docs/guides/conversation-state). + prompt: Reference to a prompt template and its variables. + [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). + reasoning: **o-series models only** Configuration options for @@ -1683,8 +1701,9 @@ async def create( metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, @@ -1757,8 +1776,7 @@ async def create( - `code_interpreter_call.outputs`: Includes the outputs of python code execution in code interpreter tool call items. - instructions: Inserts a system (or developer) message as the first item in the model's - context. + instructions: A system (or developer) message inserted into the model's context. When using along with `previous_response_id`, the instructions from a previous response will not be carried over to the next response. This makes it simple to @@ -1781,6 +1799,9 @@ async def create( multi-turn conversations. Learn more about [conversation state](https://platform.openai.com/docs/guides/conversation-state). + prompt: Reference to a prompt template and its variables. + [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). + reasoning: **o-series models only** Configuration options for @@ -1877,8 +1898,9 @@ async def create( metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -1908,6 +1930,7 @@ async def create( "metadata": metadata, "parallel_tool_calls": parallel_tool_calls, "previous_response_id": previous_response_id, + "prompt": prompt, "reasoning": reasoning, "service_tier": service_tier, "store": store, diff --git a/src/openai/types/chat/chat_completion.py b/src/openai/types/chat/chat_completion.py index 49af1a3d0e..863cc2e81a 100644 --- a/src/openai/types/chat/chat_completion.py +++ b/src/openai/types/chat/chat_completion.py @@ -59,7 +59,7 @@ class ChatCompletion(BaseModel): object: Literal["chat.completion"] """The object type, which is always `chat.completion`.""" - service_tier: Optional[Literal["auto", "default", "flex"]] = None + service_tier: Optional[Literal["auto", "default", "flex", "scale"]] = None """Specifies the latency tier to use for processing the request. This parameter is relevant for customers subscribed to the scale tier service: diff --git a/src/openai/types/chat/chat_completion_chunk.py b/src/openai/types/chat/chat_completion_chunk.py index c109e10f97..3d3d68602a 100644 --- a/src/openai/types/chat/chat_completion_chunk.py +++ b/src/openai/types/chat/chat_completion_chunk.py @@ -128,7 +128,7 @@ class ChatCompletionChunk(BaseModel): object: Literal["chat.completion.chunk"] """The object type, which is always `chat.completion.chunk`.""" - service_tier: Optional[Literal["auto", "default", "flex"]] = None + service_tier: Optional[Literal["auto", "default", "flex", "scale"]] = None """Specifies the latency tier to use for processing the request. This parameter is relevant for customers subscribed to the scale tier service: diff --git a/src/openai/types/chat/completion_create_params.py b/src/openai/types/chat/completion_create_params.py index e55cc2d0b7..f1ed444b79 100644 --- a/src/openai/types/chat/completion_create_params.py +++ b/src/openai/types/chat/completion_create_params.py @@ -208,7 +208,7 @@ class CompletionCreateParamsBase(TypedDict, total=False): in the backend. """ - service_tier: Optional[Literal["auto", "default", "flex"]] + service_tier: Optional[Literal["auto", "default", "flex", "scale"]] """Specifies the latency tier to use for processing the request. This parameter is relevant for customers subscribed to the scale tier service: diff --git a/src/openai/types/fine_tuning/job_create_params.py b/src/openai/types/fine_tuning/job_create_params.py index 6b2f41cb71..5514db1ed1 100644 --- a/src/openai/types/fine_tuning/job_create_params.py +++ b/src/openai/types/fine_tuning/job_create_params.py @@ -37,7 +37,8 @@ class JobCreateParams(TypedDict, total=False): [preference](https://platform.openai.com/docs/api-reference/fine-tuning/preference-input) format. - See the [fine-tuning guide](https://platform.openai.com/docs/guides/fine-tuning) + See the + [fine-tuning guide](https://platform.openai.com/docs/guides/model-optimization) for more details. """ @@ -91,7 +92,8 @@ class JobCreateParams(TypedDict, total=False): Your dataset must be formatted as a JSONL file. You must upload your file with the purpose `fine-tune`. - See the [fine-tuning guide](https://platform.openai.com/docs/guides/fine-tuning) + See the + [fine-tuning guide](https://platform.openai.com/docs/guides/model-optimization) for more details. """ diff --git a/src/openai/types/image_edit_params.py b/src/openai/types/image_edit_params.py index 4f931ce141..aecb98fa6f 100644 --- a/src/openai/types/image_edit_params.py +++ b/src/openai/types/image_edit_params.py @@ -58,6 +58,20 @@ class ImageEditParams(TypedDict, total=False): n: Optional[int] """The number of images to generate. Must be between 1 and 10.""" + output_compression: Optional[int] + """The compression level (0-100%) for the generated images. + + This parameter is only supported for `gpt-image-1` with the `webp` or `jpeg` + output formats, and defaults to 100. + """ + + output_format: Optional[Literal["png", "jpeg", "webp"]] + """The format in which the generated images are returned. + + This parameter is only supported for `gpt-image-1`. Must be one of `png`, + `jpeg`, or `webp`. The default value is `png`. + """ + quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] """The quality of the image that will be generated. diff --git a/src/openai/types/responses/__init__.py b/src/openai/types/responses/__init__.py index d33c26d23a..ba257eabc2 100644 --- a/src/openai/types/responses/__init__.py +++ b/src/openai/types/responses/__init__.py @@ -18,6 +18,7 @@ ParsedResponseOutputMessage as ParsedResponseOutputMessage, ParsedResponseFunctionToolCall as ParsedResponseFunctionToolCall, ) +from .response_prompt import ResponsePrompt as ResponsePrompt from .response_status import ResponseStatus as ResponseStatus from .web_search_tool import WebSearchTool as WebSearchTool from .file_search_tool import FileSearchTool as FileSearchTool @@ -28,6 +29,7 @@ from .function_tool_param import FunctionToolParam as FunctionToolParam from .response_includable import ResponseIncludable as ResponseIncludable from .response_input_file import ResponseInputFile as ResponseInputFile +from .response_input_item import ResponseInputItem as ResponseInputItem from .response_input_text import ResponseInputText as ResponseInputText from .tool_choice_options import ToolChoiceOptions as ToolChoiceOptions from .response_error_event import ResponseErrorEvent as ResponseErrorEvent @@ -38,6 +40,7 @@ from .response_text_config import ResponseTextConfig as ResponseTextConfig from .tool_choice_function import ToolChoiceFunction as ToolChoiceFunction from .response_failed_event import ResponseFailedEvent as ResponseFailedEvent +from .response_prompt_param import ResponsePromptParam as ResponsePromptParam from .response_queued_event import ResponseQueuedEvent as ResponseQueuedEvent from .response_stream_event import ResponseStreamEvent as ResponseStreamEvent from .web_search_tool_param import WebSearchToolParam as WebSearchToolParam diff --git a/src/openai/types/responses/response.py b/src/openai/types/responses/response.py index 441b345414..75d1c5e3df 100644 --- a/src/openai/types/responses/response.py +++ b/src/openai/types/responses/response.py @@ -7,10 +7,12 @@ from ..._models import BaseModel from .response_error import ResponseError from .response_usage import ResponseUsage +from .response_prompt import ResponsePrompt from .response_status import ResponseStatus from ..shared.metadata import Metadata from ..shared.reasoning import Reasoning from .tool_choice_types import ToolChoiceTypes +from .response_input_item import ResponseInputItem from .tool_choice_options import ToolChoiceOptions from .response_output_item import ResponseOutputItem from .response_text_config import ResponseTextConfig @@ -41,10 +43,8 @@ class Response(BaseModel): incomplete_details: Optional[IncompleteDetails] = None """Details about why the response is incomplete.""" - instructions: Optional[str] = None - """ - Inserts a system (or developer) message as the first item in the model's - context. + instructions: Union[str, List[ResponseInputItem], None] = None + """A system (or developer) message inserted into the model's context. When using along with `previous_response_id`, the instructions from a previous response will not be carried over to the next response. This makes it simple to @@ -148,6 +148,12 @@ class Response(BaseModel): [conversation state](https://platform.openai.com/docs/guides/conversation-state). """ + prompt: Optional[ResponsePrompt] = None + """Reference to a prompt template and its variables. + + [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). + """ + reasoning: Optional[Reasoning] = None """**o-series models only** @@ -155,7 +161,7 @@ class Response(BaseModel): [reasoning models](https://platform.openai.com/docs/guides/reasoning). """ - service_tier: Optional[Literal["auto", "default", "flex"]] = None + service_tier: Optional[Literal["auto", "default", "flex", "scale"]] = None """Specifies the latency tier to use for processing the request. This parameter is relevant for customers subscribed to the scale tier service: diff --git a/src/openai/types/responses/response_create_params.py b/src/openai/types/responses/response_create_params.py index 1abc2ccb1d..976ae9741d 100644 --- a/src/openai/types/responses/response_create_params.py +++ b/src/openai/types/responses/response_create_params.py @@ -9,6 +9,7 @@ from .response_includable import ResponseIncludable from .tool_choice_options import ToolChoiceOptions from .response_input_param import ResponseInputParam +from .response_prompt_param import ResponsePromptParam from ..shared_params.metadata import Metadata from .tool_choice_types_param import ToolChoiceTypesParam from ..shared_params.reasoning import Reasoning @@ -72,9 +73,7 @@ class ResponseCreateParamsBase(TypedDict, total=False): """ instructions: Optional[str] - """ - Inserts a system (or developer) message as the first item in the model's - context. + """A system (or developer) message inserted into the model's context. When using along with `previous_response_id`, the instructions from a previous response will not be carried over to the next response. This makes it simple to @@ -108,6 +107,12 @@ class ResponseCreateParamsBase(TypedDict, total=False): [conversation state](https://platform.openai.com/docs/guides/conversation-state). """ + prompt: Optional[ResponsePromptParam] + """Reference to a prompt template and its variables. + + [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). + """ + reasoning: Optional[Reasoning] """**o-series models only** @@ -115,7 +120,7 @@ class ResponseCreateParamsBase(TypedDict, total=False): [reasoning models](https://platform.openai.com/docs/guides/reasoning). """ - service_tier: Optional[Literal["auto", "default", "flex"]] + service_tier: Optional[Literal["auto", "default", "flex", "scale"]] """Specifies the latency tier to use for processing the request. This parameter is relevant for customers subscribed to the scale tier service: diff --git a/src/openai/types/responses/response_input_item.py b/src/openai/types/responses/response_input_item.py new file mode 100644 index 0000000000..5fbd7c274b --- /dev/null +++ b/src/openai/types/responses/response_input_item.py @@ -0,0 +1,305 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .easy_input_message import EasyInputMessage +from .response_output_message import ResponseOutputMessage +from .response_reasoning_item import ResponseReasoningItem +from .response_computer_tool_call import ResponseComputerToolCall +from .response_function_tool_call import ResponseFunctionToolCall +from .response_function_web_search import ResponseFunctionWebSearch +from .response_file_search_tool_call import ResponseFileSearchToolCall +from .response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall +from .response_input_message_content_list import ResponseInputMessageContentList +from .response_computer_tool_call_output_screenshot import ResponseComputerToolCallOutputScreenshot + +__all__ = [ + "ResponseInputItem", + "Message", + "ComputerCallOutput", + "ComputerCallOutputAcknowledgedSafetyCheck", + "FunctionCallOutput", + "ImageGenerationCall", + "LocalShellCall", + "LocalShellCallAction", + "LocalShellCallOutput", + "McpListTools", + "McpListToolsTool", + "McpApprovalRequest", + "McpApprovalResponse", + "McpCall", + "ItemReference", +] + + +class Message(BaseModel): + content: ResponseInputMessageContentList + """ + A list of one or many input items to the model, containing different content + types. + """ + + role: Literal["user", "system", "developer"] + """The role of the message input. One of `user`, `system`, or `developer`.""" + + status: Optional[Literal["in_progress", "completed", "incomplete"]] = None + """The status of item. + + One of `in_progress`, `completed`, or `incomplete`. Populated when items are + returned via API. + """ + + type: Optional[Literal["message"]] = None + """The type of the message input. Always set to `message`.""" + + +class ComputerCallOutputAcknowledgedSafetyCheck(BaseModel): + id: str + """The ID of the pending safety check.""" + + code: Optional[str] = None + """The type of the pending safety check.""" + + message: Optional[str] = None + """Details about the pending safety check.""" + + +class ComputerCallOutput(BaseModel): + call_id: str + """The ID of the computer tool call that produced the output.""" + + output: ResponseComputerToolCallOutputScreenshot + """A computer screenshot image used with the computer use tool.""" + + type: Literal["computer_call_output"] + """The type of the computer tool call output. Always `computer_call_output`.""" + + id: Optional[str] = None + """The ID of the computer tool call output.""" + + acknowledged_safety_checks: Optional[List[ComputerCallOutputAcknowledgedSafetyCheck]] = None + """ + The safety checks reported by the API that have been acknowledged by the + developer. + """ + + status: Optional[Literal["in_progress", "completed", "incomplete"]] = None + """The status of the message input. + + One of `in_progress`, `completed`, or `incomplete`. Populated when input items + are returned via API. + """ + + +class FunctionCallOutput(BaseModel): + call_id: str + """The unique ID of the function tool call generated by the model.""" + + output: str + """A JSON string of the output of the function tool call.""" + + type: Literal["function_call_output"] + """The type of the function tool call output. Always `function_call_output`.""" + + id: Optional[str] = None + """The unique ID of the function tool call output. + + Populated when this item is returned via API. + """ + + status: Optional[Literal["in_progress", "completed", "incomplete"]] = None + """The status of the item. + + One of `in_progress`, `completed`, or `incomplete`. Populated when items are + returned via API. + """ + + +class ImageGenerationCall(BaseModel): + id: str + """The unique ID of the image generation call.""" + + result: Optional[str] = None + """The generated image encoded in base64.""" + + status: Literal["in_progress", "completed", "generating", "failed"] + """The status of the image generation call.""" + + type: Literal["image_generation_call"] + """The type of the image generation call. Always `image_generation_call`.""" + + +class LocalShellCallAction(BaseModel): + command: List[str] + """The command to run.""" + + env: Dict[str, str] + """Environment variables to set for the command.""" + + type: Literal["exec"] + """The type of the local shell action. Always `exec`.""" + + timeout_ms: Optional[int] = None + """Optional timeout in milliseconds for the command.""" + + user: Optional[str] = None + """Optional user to run the command as.""" + + working_directory: Optional[str] = None + """Optional working directory to run the command in.""" + + +class LocalShellCall(BaseModel): + id: str + """The unique ID of the local shell call.""" + + action: LocalShellCallAction + """Execute a shell command on the server.""" + + call_id: str + """The unique ID of the local shell tool call generated by the model.""" + + status: Literal["in_progress", "completed", "incomplete"] + """The status of the local shell call.""" + + type: Literal["local_shell_call"] + """The type of the local shell call. Always `local_shell_call`.""" + + +class LocalShellCallOutput(BaseModel): + id: str + """The unique ID of the local shell tool call generated by the model.""" + + output: str + """A JSON string of the output of the local shell tool call.""" + + type: Literal["local_shell_call_output"] + """The type of the local shell tool call output. Always `local_shell_call_output`.""" + + status: Optional[Literal["in_progress", "completed", "incomplete"]] = None + """The status of the item. One of `in_progress`, `completed`, or `incomplete`.""" + + +class McpListToolsTool(BaseModel): + input_schema: object + """The JSON schema describing the tool's input.""" + + name: str + """The name of the tool.""" + + annotations: Optional[object] = None + """Additional annotations about the tool.""" + + description: Optional[str] = None + """The description of the tool.""" + + +class McpListTools(BaseModel): + id: str + """The unique ID of the list.""" + + server_label: str + """The label of the MCP server.""" + + tools: List[McpListToolsTool] + """The tools available on the server.""" + + type: Literal["mcp_list_tools"] + """The type of the item. Always `mcp_list_tools`.""" + + error: Optional[str] = None + """Error message if the server could not list tools.""" + + +class McpApprovalRequest(BaseModel): + id: str + """The unique ID of the approval request.""" + + arguments: str + """A JSON string of arguments for the tool.""" + + name: str + """The name of the tool to run.""" + + server_label: str + """The label of the MCP server making the request.""" + + type: Literal["mcp_approval_request"] + """The type of the item. Always `mcp_approval_request`.""" + + +class McpApprovalResponse(BaseModel): + approval_request_id: str + """The ID of the approval request being answered.""" + + approve: bool + """Whether the request was approved.""" + + type: Literal["mcp_approval_response"] + """The type of the item. Always `mcp_approval_response`.""" + + id: Optional[str] = None + """The unique ID of the approval response""" + + reason: Optional[str] = None + """Optional reason for the decision.""" + + +class McpCall(BaseModel): + id: str + """The unique ID of the tool call.""" + + arguments: str + """A JSON string of the arguments passed to the tool.""" + + name: str + """The name of the tool that was run.""" + + server_label: str + """The label of the MCP server running the tool.""" + + type: Literal["mcp_call"] + """The type of the item. Always `mcp_call`.""" + + error: Optional[str] = None + """The error from the tool call, if any.""" + + output: Optional[str] = None + """The output from the tool call.""" + + +class ItemReference(BaseModel): + id: str + """The ID of the item to reference.""" + + type: Optional[Literal["item_reference"]] = None + """The type of item to reference. Always `item_reference`.""" + + +ResponseInputItem: TypeAlias = Annotated[ + Union[ + EasyInputMessage, + Message, + ResponseOutputMessage, + ResponseFileSearchToolCall, + ResponseComputerToolCall, + ComputerCallOutput, + ResponseFunctionWebSearch, + ResponseFunctionToolCall, + FunctionCallOutput, + ResponseReasoningItem, + ImageGenerationCall, + ResponseCodeInterpreterToolCall, + LocalShellCall, + LocalShellCallOutput, + McpListTools, + McpApprovalRequest, + McpApprovalResponse, + McpCall, + ItemReference, + ], + PropertyInfo(discriminator="type"), +] diff --git a/src/openai/types/responses/response_prompt.py b/src/openai/types/responses/response_prompt.py new file mode 100644 index 0000000000..537c2f8fbc --- /dev/null +++ b/src/openai/types/responses/response_prompt.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Union, Optional +from typing_extensions import TypeAlias + +from ..._models import BaseModel +from .response_input_file import ResponseInputFile +from .response_input_text import ResponseInputText +from .response_input_image import ResponseInputImage + +__all__ = ["ResponsePrompt", "Variables"] + +Variables: TypeAlias = Union[str, ResponseInputText, ResponseInputImage, ResponseInputFile] + + +class ResponsePrompt(BaseModel): + id: str + """The unique identifier of the prompt template to use.""" + + variables: Optional[Dict[str, Variables]] = None + """Optional map of values to substitute in for variables in your prompt. + + The substitution values can either be strings, or other Response input types + like images or files. + """ + + version: Optional[str] = None + """Optional version of the prompt template.""" diff --git a/src/openai/types/responses/response_prompt_param.py b/src/openai/types/responses/response_prompt_param.py new file mode 100644 index 0000000000..d935fa5191 --- /dev/null +++ b/src/openai/types/responses/response_prompt_param.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Required, TypeAlias, TypedDict + +from .response_input_file_param import ResponseInputFileParam +from .response_input_text_param import ResponseInputTextParam +from .response_input_image_param import ResponseInputImageParam + +__all__ = ["ResponsePromptParam", "Variables"] + +Variables: TypeAlias = Union[str, ResponseInputTextParam, ResponseInputImageParam, ResponseInputFileParam] + + +class ResponsePromptParam(TypedDict, total=False): + id: Required[str] + """The unique identifier of the prompt template to use.""" + + variables: Optional[Dict[str, Variables]] + """Optional map of values to substitute in for variables in your prompt. + + The substitution values can either be strings, or other Response input types + like images or files. + """ + + version: Optional[str] + """Optional version of the prompt template.""" diff --git a/tests/api_resources/test_images.py b/tests/api_resources/test_images.py index 7c61453bc1..77bcea10ea 100644 --- a/tests/api_resources/test_images.py +++ b/tests/api_resources/test_images.py @@ -77,6 +77,8 @@ def test_method_edit_with_all_params(self, client: OpenAI) -> None: mask=b"raw file contents", model="string", n=1, + output_compression=100, + output_format="png", quality="high", response_format="url", size="1024x1024", @@ -223,6 +225,8 @@ async def test_method_edit_with_all_params(self, async_client: AsyncOpenAI) -> N mask=b"raw file contents", model="string", n=1, + output_compression=100, + output_format="png", quality="high", response_format="url", size="1024x1024", diff --git a/tests/api_resources/test_responses.py b/tests/api_resources/test_responses.py index 7c0f980fbd..3bbf21ba14 100644 --- a/tests/api_resources/test_responses.py +++ b/tests/api_resources/test_responses.py @@ -9,7 +9,9 @@ from openai import OpenAI, AsyncOpenAI from tests.utils import assert_matches_type -from openai.types.responses import Response +from openai.types.responses import ( + Response, +) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -37,6 +39,11 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: metadata={"foo": "string"}, parallel_tool_calls=True, previous_response_id="previous_response_id", + prompt={ + "id": "id", + "variables": {"foo": "string"}, + "version": "version", + }, reasoning={ "effort": "low", "generate_summary": "auto", @@ -111,6 +118,11 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: metadata={"foo": "string"}, parallel_tool_calls=True, previous_response_id="previous_response_id", + prompt={ + "id": "id", + "variables": {"foo": "string"}, + "version": "version", + }, reasoning={ "effort": "low", "generate_summary": "auto", @@ -362,6 +374,11 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn metadata={"foo": "string"}, parallel_tool_calls=True, previous_response_id="previous_response_id", + prompt={ + "id": "id", + "variables": {"foo": "string"}, + "version": "version", + }, reasoning={ "effort": "low", "generate_summary": "auto", @@ -436,6 +453,11 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn metadata={"foo": "string"}, parallel_tool_calls=True, previous_response_id="previous_response_id", + prompt={ + "id": "id", + "variables": {"foo": "string"}, + "version": "version", + }, reasoning={ "effort": "low", "generate_summary": "auto", diff --git a/tests/conftest.py b/tests/conftest.py index 8b01753e2f..4b98d20a48 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,3 +1,5 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + from __future__ import annotations import os diff --git a/tests/test_client.py b/tests/test_client.py index 2b7aeaf946..1026b78921 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -28,7 +28,14 @@ from openai._constants import RAW_RESPONSE_HEADER from openai._streaming import Stream, AsyncStream from openai._exceptions import OpenAIError, APIStatusError, APITimeoutError, APIResponseValidationError -from openai._base_client import DEFAULT_TIMEOUT, HTTPX_DEFAULT_TIMEOUT, BaseClient, make_request_options +from openai._base_client import ( + DEFAULT_TIMEOUT, + HTTPX_DEFAULT_TIMEOUT, + BaseClient, + DefaultHttpxClient, + DefaultAsyncHttpxClient, + make_request_options, +) from openai.types.chat.completion_create_params import CompletionCreateParamsNonStreaming from .utils import update_env @@ -908,6 +915,28 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: assert response.retries_taken == failures_before_success assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success + def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None: + # Test that the proxy environment variables are set correctly + monkeypatch.setenv("HTTPS_PROXY", "https://example.org") + + client = DefaultHttpxClient() + + mounts = tuple(client._mounts.items()) + assert len(mounts) == 1 + assert mounts[0][0].pattern == "https://" + + @pytest.mark.filterwarnings("ignore:.*deprecated.*:DeprecationWarning") + def test_default_client_creation(self) -> None: + # Ensure that the client can be initialized without any exceptions + DefaultHttpxClient( + verify=True, + cert=None, + trust_env=True, + http1=True, + http2=False, + limits=httpx.Limits(max_connections=100, max_keepalive_connections=20), + ) + @pytest.mark.respx(base_url=base_url) def test_follow_redirects(self, respx_mock: MockRouter) -> None: # Test that the default follow_redirects=True allows following redirects @@ -1857,6 +1886,28 @@ async def test_main() -> None: time.sleep(0.1) + async def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None: + # Test that the proxy environment variables are set correctly + monkeypatch.setenv("HTTPS_PROXY", "https://example.org") + + client = DefaultAsyncHttpxClient() + + mounts = tuple(client._mounts.items()) + assert len(mounts) == 1 + assert mounts[0][0].pattern == "https://" + + @pytest.mark.filterwarnings("ignore:.*deprecated.*:DeprecationWarning") + async def test_default_client_creation(self) -> None: + # Ensure that the client can be initialized without any exceptions + DefaultAsyncHttpxClient( + verify=True, + cert=None, + trust_env=True, + http1=True, + http2=False, + limits=httpx.Limits(max_connections=100, max_keepalive_connections=20), + ) + @pytest.mark.respx(base_url=base_url) async def test_follow_redirects(self, respx_mock: MockRouter) -> None: # Test that the default follow_redirects=True allows following redirects From e01af1c2a3319f78139802d440d8a9d617fdc986 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 16 Jun 2025 19:05:03 +0000 Subject: [PATCH 351/769] feat(api): manual updates --- .stats.yml | 2 +- api.md | 2 +- .../fine_tuning/checkpoints/permissions.py | 22 ++++++++++--------- .../permission_retrieve_response.py | 17 ++------------ .../checkpoints/test_permissions.py | 18 +++++++-------- 5 files changed, 25 insertions(+), 36 deletions(-) diff --git a/.stats.yml b/.stats.yml index feda32cffe..7e42b77a27 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-9e41d2d5471d2c28bff0d616f4476f5b0e6c541ef4cb51bdaaef5fdf5e13c8b2.yml openapi_spec_hash: 86f765e18d00e32cf2ce9db7ab84d946 -config_hash: fd2af1d5eff0995bb7dc02ac9a34851d +config_hash: dc5515e257676a27cb1ace1784aa92b3 diff --git a/api.md b/api.md index 25360d741e..db52398b97 100644 --- a/api.md +++ b/api.md @@ -293,7 +293,7 @@ from openai.types.fine_tuning.checkpoints import ( Methods: - client.fine_tuning.checkpoints.permissions.create(fine_tuned_model_checkpoint, \*\*params) -> SyncPage[PermissionCreateResponse] -- client.fine_tuning.checkpoints.permissions.retrieve(fine_tuned_model_checkpoint, \*\*params) -> PermissionRetrieveResponse +- client.fine_tuning.checkpoints.permissions.retrieve(fine_tuned_model_checkpoint, \*\*params) -> SyncCursorPage[PermissionRetrieveResponse] - client.fine_tuning.checkpoints.permissions.delete(permission_id, \*, fine_tuned_model_checkpoint) -> PermissionDeleteResponse ## Alpha diff --git a/src/openai/resources/fine_tuning/checkpoints/permissions.py b/src/openai/resources/fine_tuning/checkpoints/permissions.py index 547e42ecac..ceb747a367 100644 --- a/src/openai/resources/fine_tuning/checkpoints/permissions.py +++ b/src/openai/resources/fine_tuning/checkpoints/permissions.py @@ -9,11 +9,11 @@ from .... import _legacy_response from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ...._utils import maybe_transform, async_maybe_transform +from ...._utils import maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ....pagination import SyncPage, AsyncPage +from ....pagination import SyncPage, AsyncPage, SyncCursorPage, AsyncCursorPage from ...._base_client import AsyncPaginator, make_request_options from ....types.fine_tuning.checkpoints import permission_create_params, permission_retrieve_params from ....types.fine_tuning.checkpoints.permission_create_response import PermissionCreateResponse @@ -101,7 +101,7 @@ def retrieve( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> PermissionRetrieveResponse: + ) -> SyncCursorPage[PermissionRetrieveResponse]: """ **NOTE:** This endpoint requires an [admin API key](../admin-api-keys). @@ -129,8 +129,9 @@ def retrieve( raise ValueError( f"Expected a non-empty value for `fine_tuned_model_checkpoint` but received {fine_tuned_model_checkpoint!r}" ) - return self._get( + return self._get_api_list( f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + page=SyncCursorPage[PermissionRetrieveResponse], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -146,7 +147,7 @@ def retrieve( permission_retrieve_params.PermissionRetrieveParams, ), ), - cast_to=PermissionRetrieveResponse, + model=PermissionRetrieveResponse, ) def delete( @@ -255,7 +256,7 @@ def create( method="post", ) - async def retrieve( + def retrieve( self, fine_tuned_model_checkpoint: str, *, @@ -269,7 +270,7 @@ async def retrieve( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> PermissionRetrieveResponse: + ) -> AsyncPaginator[PermissionRetrieveResponse, AsyncCursorPage[PermissionRetrieveResponse]]: """ **NOTE:** This endpoint requires an [admin API key](../admin-api-keys). @@ -297,14 +298,15 @@ async def retrieve( raise ValueError( f"Expected a non-empty value for `fine_tuned_model_checkpoint` but received {fine_tuned_model_checkpoint!r}" ) - return await self._get( + return self._get_api_list( f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + page=AsyncCursorPage[PermissionRetrieveResponse], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, - query=await async_maybe_transform( + query=maybe_transform( { "after": after, "limit": limit, @@ -314,7 +316,7 @@ async def retrieve( permission_retrieve_params.PermissionRetrieveParams, ), ), - cast_to=PermissionRetrieveResponse, + model=PermissionRetrieveResponse, ) async def delete( diff --git a/src/openai/types/fine_tuning/checkpoints/permission_retrieve_response.py b/src/openai/types/fine_tuning/checkpoints/permission_retrieve_response.py index 14c73b55d0..4c540179e7 100644 --- a/src/openai/types/fine_tuning/checkpoints/permission_retrieve_response.py +++ b/src/openai/types/fine_tuning/checkpoints/permission_retrieve_response.py @@ -1,14 +1,13 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Optional from typing_extensions import Literal from ...._models import BaseModel -__all__ = ["PermissionRetrieveResponse", "Data"] +__all__ = ["PermissionRetrieveResponse"] -class Data(BaseModel): +class PermissionRetrieveResponse(BaseModel): id: str """The permission identifier, which can be referenced in the API endpoints.""" @@ -20,15 +19,3 @@ class Data(BaseModel): project_id: str """The project identifier that the permission is for.""" - - -class PermissionRetrieveResponse(BaseModel): - data: List[Data] - - has_more: bool - - object: Literal["list"] - - first_id: Optional[str] = None - - last_id: Optional[str] = None diff --git a/tests/api_resources/fine_tuning/checkpoints/test_permissions.py b/tests/api_resources/fine_tuning/checkpoints/test_permissions.py index 6aa0b867d9..4a7608d8df 100644 --- a/tests/api_resources/fine_tuning/checkpoints/test_permissions.py +++ b/tests/api_resources/fine_tuning/checkpoints/test_permissions.py @@ -9,7 +9,7 @@ from openai import OpenAI, AsyncOpenAI from tests.utils import assert_matches_type -from openai.pagination import SyncPage, AsyncPage +from openai.pagination import SyncPage, AsyncPage, SyncCursorPage, AsyncCursorPage from openai.types.fine_tuning.checkpoints import ( PermissionCreateResponse, PermissionDeleteResponse, @@ -71,7 +71,7 @@ def test_method_retrieve(self, client: OpenAI) -> None: permission = client.fine_tuning.checkpoints.permissions.retrieve( fine_tuned_model_checkpoint="ft-AF1WoRqd3aJAHsqc9NY7iL8F", ) - assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) + assert_matches_type(SyncCursorPage[PermissionRetrieveResponse], permission, path=["response"]) @parametrize def test_method_retrieve_with_all_params(self, client: OpenAI) -> None: @@ -82,7 +82,7 @@ def test_method_retrieve_with_all_params(self, client: OpenAI) -> None: order="ascending", project_id="project_id", ) - assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) + assert_matches_type(SyncCursorPage[PermissionRetrieveResponse], permission, path=["response"]) @parametrize def test_raw_response_retrieve(self, client: OpenAI) -> None: @@ -93,7 +93,7 @@ def test_raw_response_retrieve(self, client: OpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" permission = response.parse() - assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) + assert_matches_type(SyncCursorPage[PermissionRetrieveResponse], permission, path=["response"]) @parametrize def test_streaming_response_retrieve(self, client: OpenAI) -> None: @@ -104,7 +104,7 @@ def test_streaming_response_retrieve(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" permission = response.parse() - assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) + assert_matches_type(SyncCursorPage[PermissionRetrieveResponse], permission, path=["response"]) assert cast(Any, response.is_closed) is True @@ -220,7 +220,7 @@ async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: permission = await async_client.fine_tuning.checkpoints.permissions.retrieve( fine_tuned_model_checkpoint="ft-AF1WoRqd3aJAHsqc9NY7iL8F", ) - assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) + assert_matches_type(AsyncCursorPage[PermissionRetrieveResponse], permission, path=["response"]) @parametrize async def test_method_retrieve_with_all_params(self, async_client: AsyncOpenAI) -> None: @@ -231,7 +231,7 @@ async def test_method_retrieve_with_all_params(self, async_client: AsyncOpenAI) order="ascending", project_id="project_id", ) - assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) + assert_matches_type(AsyncCursorPage[PermissionRetrieveResponse], permission, path=["response"]) @parametrize async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: @@ -242,7 +242,7 @@ async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" permission = response.parse() - assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) + assert_matches_type(AsyncCursorPage[PermissionRetrieveResponse], permission, path=["response"]) @parametrize async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: @@ -253,7 +253,7 @@ async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> N assert response.http_request.headers.get("X-Stainless-Lang") == "python" permission = await response.parse() - assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) + assert_matches_type(AsyncCursorPage[PermissionRetrieveResponse], permission, path=["response"]) assert cast(Any, response.is_closed) is True From 52b183d55017ca67b721ddc18888bcb9c70f22dc Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 16 Jun 2025 22:26:10 +0000 Subject: [PATCH 352/769] chore(internal): minor formatting --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e853b86695..f039d92437 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -95,11 +95,11 @@ jobs: run: | rye sync --all-features - - env: + - env: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} run: | rye run python examples/demo.py - - env: + - env: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} run: | rye run python examples/async_demo.py From ec6532a7bce94dae4d8b113905e5fcffad5a801f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 00:09:03 +0000 Subject: [PATCH 353/769] chore(ci): enable for pull requests --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f039d92437..7991b3e7c7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,6 +7,10 @@ on: - 'integrated/**' - 'stl-preview-head/**' - 'stl-preview-base/**' + pull_request: + branches-ignore: + - 'stl-preview-head/**' + - 'stl-preview-base/**' jobs: lint: From 8ade764fc124bee145990ad59d0d7c4bbe27a754 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 05:03:48 +0000 Subject: [PATCH 354/769] release: 1.88.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 14 ++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 5e0920bd53..5ae95686ab 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.87.0" + ".": "1.88.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index c67c695b0e..09de5415d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## 1.88.0 (2025-06-17) + +Full Changelog: [v1.87.0...v1.88.0](https://github.com/openai/openai-python/compare/v1.87.0...v1.88.0) + +### Features + +* **api:** manual updates ([5d18a84](https://github.com/openai/openai-python/commit/5d18a8448ecbe31597e98ec7f64d7050c831901e)) + + +### Chores + +* **ci:** enable for pull requests ([542b0ce](https://github.com/openai/openai-python/commit/542b0ce98f14ccff4f9e1bcbd3a9ea5e4f846638)) +* **internal:** minor formatting ([29d723d](https://github.com/openai/openai-python/commit/29d723d1f1baf2a5843293c8647dc7baa16d56d1)) + ## 1.87.0 (2025-06-16) Full Changelog: [v1.86.0...v1.87.0](https://github.com/openai/openai-python/compare/v1.86.0...v1.87.0) diff --git a/pyproject.toml b/pyproject.toml index 54f343064f..963a8cb1aa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.87.0" +version = "1.88.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 4d66bc793a..7c606ee49c 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.87.0" # x-release-please-version +__version__ = "1.88.0" # x-release-please-version From 13b9605063a1246d409b1e68ef94e886095e16a7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 14:51:25 +0000 Subject: [PATCH 355/769] chore(readme): update badges --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b83cb47c74..80077038f9 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # OpenAI Python API library -[![PyPI version](https://img.shields.io/pypi/v/openai.svg)](https://pypi.org/project/openai/) +[![PyPI version]()](https://pypi.org/project/openai/) The OpenAI Python library provides convenient access to the OpenAI REST API from any Python 3.8+ application. The library includes type definitions for all request params and response fields, From 0bef1d02cf7c188f114f481f0d87e55f1e26b7dd Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 21:10:09 +0000 Subject: [PATCH 356/769] fix(tests): fix: tests which call HTTP endpoints directly with the example parameters --- tests/test_client.py | 129 ++++++++++++++----------------------------- 1 file changed, 40 insertions(+), 89 deletions(-) diff --git a/tests/test_client.py b/tests/test_client.py index 1026b78921..3d08a0a601 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -23,9 +23,7 @@ from openai import OpenAI, AsyncOpenAI, APIResponseValidationError from openai._types import Omit -from openai._utils import maybe_transform from openai._models import BaseModel, FinalRequestOptions -from openai._constants import RAW_RESPONSE_HEADER from openai._streaming import Stream, AsyncStream from openai._exceptions import OpenAIError, APIStatusError, APITimeoutError, APIResponseValidationError from openai._base_client import ( @@ -36,7 +34,6 @@ DefaultAsyncHttpxClient, make_request_options, ) -from openai.types.chat.completion_create_params import CompletionCreateParamsNonStreaming from .utils import update_env @@ -725,60 +722,37 @@ def test_parse_retry_after_header(self, remaining_retries: int, retry_after: str @mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter) -> None: + def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter, client: OpenAI) -> None: respx_mock.post("/chat/completions").mock(side_effect=httpx.TimeoutException("Test timeout error")) with pytest.raises(APITimeoutError): - self.client.post( - "/chat/completions", - body=cast( - object, - maybe_transform( - dict( - messages=[ - { - "role": "user", - "content": "Say this is a test", - } - ], - model="gpt-4o", - ), - CompletionCreateParamsNonStreaming, - ), - ), - cast_to=httpx.Response, - options={"headers": {RAW_RESPONSE_HEADER: "stream"}}, - ) + client.chat.completions.with_streaming_response.create( + messages=[ + { + "content": "string", + "role": "developer", + } + ], + model="gpt-4o", + ).__enter__() assert _get_open_connections(self.client) == 0 @mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter) -> None: + def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter, client: OpenAI) -> None: respx_mock.post("/chat/completions").mock(return_value=httpx.Response(500)) with pytest.raises(APIStatusError): - self.client.post( - "/chat/completions", - body=cast( - object, - maybe_transform( - dict( - messages=[ - { - "role": "user", - "content": "Say this is a test", - } - ], - model="gpt-4o", - ), - CompletionCreateParamsNonStreaming, - ), - ), - cast_to=httpx.Response, - options={"headers": {RAW_RESPONSE_HEADER: "stream"}}, - ) - + client.chat.completions.with_streaming_response.create( + messages=[ + { + "content": "string", + "role": "developer", + } + ], + model="gpt-4o", + ).__enter__() assert _get_open_connections(self.client) == 0 @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @@ -1647,60 +1621,37 @@ async def test_parse_retry_after_header(self, remaining_retries: int, retry_afte @mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - async def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter) -> None: + async def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter, async_client: AsyncOpenAI) -> None: respx_mock.post("/chat/completions").mock(side_effect=httpx.TimeoutException("Test timeout error")) with pytest.raises(APITimeoutError): - await self.client.post( - "/chat/completions", - body=cast( - object, - maybe_transform( - dict( - messages=[ - { - "role": "user", - "content": "Say this is a test", - } - ], - model="gpt-4o", - ), - CompletionCreateParamsNonStreaming, - ), - ), - cast_to=httpx.Response, - options={"headers": {RAW_RESPONSE_HEADER: "stream"}}, - ) + await async_client.chat.completions.with_streaming_response.create( + messages=[ + { + "content": "string", + "role": "developer", + } + ], + model="gpt-4o", + ).__aenter__() assert _get_open_connections(self.client) == 0 @mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - async def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter) -> None: + async def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter, async_client: AsyncOpenAI) -> None: respx_mock.post("/chat/completions").mock(return_value=httpx.Response(500)) with pytest.raises(APIStatusError): - await self.client.post( - "/chat/completions", - body=cast( - object, - maybe_transform( - dict( - messages=[ - { - "role": "user", - "content": "Say this is a test", - } - ], - model="gpt-4o", - ), - CompletionCreateParamsNonStreaming, - ), - ), - cast_to=httpx.Response, - options={"headers": {RAW_RESPONSE_HEADER: "stream"}}, - ) - + await async_client.chat.completions.with_streaming_response.create( + messages=[ + { + "content": "string", + "role": "developer", + } + ], + model="gpt-4o", + ).__aenter__() assert _get_open_connections(self.client) == 0 @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) From c62e99070389d026b77d048184fe0b05af00ce72 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Jun 2025 18:01:32 +0000 Subject: [PATCH 357/769] feat(client): add support for aiohttp --- README.md | 39 +++++++++++++++++ pyproject.toml | 1 + requirements-dev.lock | 26 +++++++++++ requirements.lock | 27 ++++++++++++ src/openai/__init__.py | 3 +- src/openai/_base_client.py | 22 ++++++++++ tests/api_resources/audio/test_speech.py | 4 +- .../audio/test_transcriptions.py | 4 +- .../api_resources/audio/test_translations.py | 4 +- .../beta/realtime/test_sessions.py | 4 +- .../realtime/test_transcription_sessions.py | 4 +- tests/api_resources/beta/test_assistants.py | 4 +- tests/api_resources/beta/test_realtime.py | 4 +- tests/api_resources/beta/test_threads.py | 4 +- .../beta/threads/runs/test_steps.py | 4 +- .../beta/threads/test_messages.py | 4 +- tests/api_resources/beta/threads/test_runs.py | 4 +- .../chat/completions/test_messages.py | 4 +- tests/api_resources/chat/test_completions.py | 4 +- .../containers/files/test_content.py | 4 +- tests/api_resources/containers/test_files.py | 4 +- .../evals/runs/test_output_items.py | 4 +- tests/api_resources/evals/test_runs.py | 4 +- .../fine_tuning/alpha/test_graders.py | 4 +- .../checkpoints/test_permissions.py | 4 +- .../fine_tuning/jobs/test_checkpoints.py | 4 +- tests/api_resources/fine_tuning/test_jobs.py | 4 +- .../responses/test_input_items.py | 4 +- tests/api_resources/test_batches.py | 4 +- tests/api_resources/test_completions.py | 4 +- tests/api_resources/test_containers.py | 4 +- tests/api_resources/test_embeddings.py | 4 +- tests/api_resources/test_evals.py | 4 +- tests/api_resources/test_files.py | 4 +- tests/api_resources/test_images.py | 4 +- tests/api_resources/test_models.py | 4 +- tests/api_resources/test_moderations.py | 4 +- tests/api_resources/test_responses.py | 4 +- tests/api_resources/test_uploads.py | 4 +- tests/api_resources/test_vector_stores.py | 4 +- tests/api_resources/uploads/test_parts.py | 4 +- .../vector_stores/test_file_batches.py | 4 +- .../api_resources/vector_stores/test_files.py | 4 +- tests/conftest.py | 43 ++++++++++++++++--- 44 files changed, 265 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index 80077038f9..4861e4aaab 100644 --- a/README.md +++ b/README.md @@ -145,6 +145,45 @@ asyncio.run(main()) Functionality between the synchronous and asynchronous clients is otherwise identical. +### With aiohttp + +By default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend. + +You can enable this by installing `aiohttp`: + +```sh +# install from PyPI +pip install openai[aiohttp] +``` + +Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`: + +```python +import os +import asyncio +from openai import DefaultAioHttpClient +from openai import AsyncOpenAI + + +async def main() -> None: + async with AsyncOpenAI( + api_key=os.environ.get("OPENAI_API_KEY"), # This is the default and can be omitted + http_client=DefaultAioHttpClient(), + ) as client: + chat_completion = await client.chat.completions.create( + messages=[ + { + "role": "user", + "content": "Say this is a test", + } + ], + model="gpt-4o", + ) + + +asyncio.run(main()) +``` + ## Streaming responses We provide support for streaming responses using Server Side Events (SSE). diff --git a/pyproject.toml b/pyproject.toml index 963a8cb1aa..b531a822dc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,6 +43,7 @@ Repository = "https://github.com/openai/openai-python" openai = "openai.cli:main" [project.optional-dependencies] +aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.6"] realtime = ["websockets >= 13, < 16"] datalib = ["numpy >= 1", "pandas >= 1.2.3", "pandas-stubs >= 1.1.0.11"] voice_helpers = ["sounddevice>=0.5.1", "numpy>=2.0.2"] diff --git a/requirements-dev.lock b/requirements-dev.lock index 787c15be6a..138fd3b4f6 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -10,6 +10,13 @@ # universal: false -e file:. +aiohappyeyeballs==2.6.1 + # via aiohttp +aiohttp==3.12.13 + # via httpx-aiohttp + # via openai +aiosignal==1.3.2 + # via aiohttp annotated-types==0.6.0 # via pydantic anyio==4.1.0 @@ -19,7 +26,10 @@ argcomplete==3.1.2 # via nox asttokens==2.4.1 # via inline-snapshot +async-timeout==5.0.1 + # via aiohttp attrs==24.2.0 + # via aiohttp # via outcome # via trio azure-core==1.31.0 @@ -60,18 +70,25 @@ executing==2.1.0 # via inline-snapshot filelock==3.12.4 # via virtualenv +frozenlist==1.7.0 + # via aiohttp + # via aiosignal h11==0.14.0 # via httpcore httpcore==1.0.2 # via httpx httpx==0.28.1 + # via httpx-aiohttp # via openai # via respx +httpx-aiohttp==0.1.6 + # via openai idna==3.4 # via anyio # via httpx # via requests # via trio + # via yarl importlib-metadata==7.0.0 iniconfig==2.0.0 # via pytest @@ -87,6 +104,9 @@ msal==1.31.0 # via msal-extensions msal-extensions==1.2.0 # via azure-identity +multidict==6.5.0 + # via aiohttp + # via yarl mypy==1.14.1 mypy-extensions==1.0.0 # via black @@ -118,6 +138,9 @@ pluggy==1.5.0 # via pytest portalocker==2.10.1 # via msal-extensions +propcache==0.3.2 + # via aiohttp + # via yarl pycparser==2.22 # via cffi pydantic==2.10.3 @@ -181,6 +204,7 @@ typing-extensions==4.12.2 # via azure-core # via azure-identity # via black + # via multidict # via mypy # via openai # via pydantic @@ -194,5 +218,7 @@ virtualenv==20.24.5 # via nox websockets==15.0.1 # via openai +yarl==1.20.1 + # via aiohttp zipp==3.17.0 # via importlib-metadata diff --git a/requirements.lock b/requirements.lock index 467abc6e90..84cb9276d8 100644 --- a/requirements.lock +++ b/requirements.lock @@ -10,11 +10,22 @@ # universal: false -e file:. +aiohappyeyeballs==2.6.1 + # via aiohttp +aiohttp==3.12.13 + # via httpx-aiohttp + # via openai +aiosignal==1.3.2 + # via aiohttp annotated-types==0.6.0 # via pydantic anyio==4.1.0 # via httpx # via openai +async-timeout==5.0.1 + # via aiohttp +attrs==25.3.0 + # via aiohttp certifi==2023.7.22 # via httpcore # via httpx @@ -24,17 +35,27 @@ distro==1.8.0 # via openai exceptiongroup==1.2.2 # via anyio +frozenlist==1.7.0 + # via aiohttp + # via aiosignal h11==0.14.0 # via httpcore httpcore==1.0.2 # via httpx httpx==0.28.1 + # via httpx-aiohttp + # via openai +httpx-aiohttp==0.1.6 # via openai idna==3.4 # via anyio # via httpx + # via yarl jiter==0.6.1 # via openai +multidict==6.5.0 + # via aiohttp + # via yarl numpy==2.0.2 # via openai # via pandas @@ -43,6 +64,9 @@ pandas==2.2.3 # via openai pandas-stubs==2.2.2.240807 # via openai +propcache==0.3.2 + # via aiohttp + # via yarl pycparser==2.22 # via cffi pydantic==2.10.3 @@ -65,6 +89,7 @@ tqdm==4.66.5 types-pytz==2024.2.0.20241003 # via pandas-stubs typing-extensions==4.12.2 + # via multidict # via openai # via pydantic # via pydantic-core @@ -72,3 +97,5 @@ tzdata==2024.1 # via pandas websockets==15.0.1 # via openai +yarl==1.20.1 + # via aiohttp diff --git a/src/openai/__init__.py b/src/openai/__init__.py index 92beeb5da1..5fb1520549 100644 --- a/src/openai/__init__.py +++ b/src/openai/__init__.py @@ -32,7 +32,7 @@ APIResponseValidationError, ContentFilterFinishReasonError, ) -from ._base_client import DefaultHttpxClient, DefaultAsyncHttpxClient +from ._base_client import DefaultHttpxClient, DefaultAioHttpClient, DefaultAsyncHttpxClient from ._utils._logs import setup_logging as _setup_logging from ._legacy_response import HttpxBinaryResponseContent as HttpxBinaryResponseContent @@ -77,6 +77,7 @@ "DEFAULT_CONNECTION_LIMITS", "DefaultHttpxClient", "DefaultAsyncHttpxClient", + "DefaultAioHttpClient", ] if not _t.TYPE_CHECKING: diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index 2f87d23aaa..0a6385a7b5 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -1306,6 +1306,24 @@ def __init__(self, **kwargs: Any) -> None: super().__init__(**kwargs) +try: + import httpx_aiohttp +except ImportError: + + class _DefaultAioHttpClient(httpx.AsyncClient): + def __init__(self, **_kwargs: Any) -> None: + raise RuntimeError("To use the aiohttp client you must have installed the package with the `aiohttp` extra") +else: + + class _DefaultAioHttpClient(httpx_aiohttp.HttpxAiohttpClient): # type: ignore + def __init__(self, **kwargs: Any) -> None: + kwargs.setdefault("timeout", DEFAULT_TIMEOUT) + kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS) + kwargs.setdefault("follow_redirects", True) + + super().__init__(**kwargs) + + if TYPE_CHECKING: DefaultAsyncHttpxClient = httpx.AsyncClient """An alias to `httpx.AsyncClient` that provides the same defaults that this SDK @@ -1314,8 +1332,12 @@ def __init__(self, **kwargs: Any) -> None: This is useful because overriding the `http_client` with your own instance of `httpx.AsyncClient` will result in httpx's defaults being used, not ours. """ + + DefaultAioHttpClient = httpx.AsyncClient + """An alias to `httpx.AsyncClient` that changes the default HTTP transport to `aiohttp`.""" else: DefaultAsyncHttpxClient = _DefaultAsyncHttpxClient + DefaultAioHttpClient = _DefaultAioHttpClient class AsyncHttpxClientWrapper(DefaultAsyncHttpxClient): diff --git a/tests/api_resources/audio/test_speech.py b/tests/api_resources/audio/test_speech.py index ce9ed59ce3..01746b3a3a 100644 --- a/tests/api_resources/audio/test_speech.py +++ b/tests/api_resources/audio/test_speech.py @@ -83,7 +83,9 @@ def test_streaming_response_create(self, client: OpenAI, respx_mock: MockRouter) class TestAsyncSpeech: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize @pytest.mark.respx(base_url=base_url) diff --git a/tests/api_resources/audio/test_transcriptions.py b/tests/api_resources/audio/test_transcriptions.py index 753acdecf6..11cbe2349c 100644 --- a/tests/api_resources/audio/test_transcriptions.py +++ b/tests/api_resources/audio/test_transcriptions.py @@ -121,7 +121,9 @@ def test_streaming_response_create_overload_2(self, client: OpenAI) -> None: class TestAsyncTranscriptions: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create_overload_1(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/audio/test_translations.py b/tests/api_resources/audio/test_translations.py index e12ab7e6c0..ead69e9369 100644 --- a/tests/api_resources/audio/test_translations.py +++ b/tests/api_resources/audio/test_translations.py @@ -64,7 +64,9 @@ def test_streaming_response_create(self, client: OpenAI) -> None: class TestAsyncTranslations: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/beta/realtime/test_sessions.py b/tests/api_resources/beta/realtime/test_sessions.py index efc52e0d57..9b78956a98 100644 --- a/tests/api_resources/beta/realtime/test_sessions.py +++ b/tests/api_resources/beta/realtime/test_sessions.py @@ -90,7 +90,9 @@ def test_streaming_response_create(self, client: OpenAI) -> None: class TestAsyncSessions: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/beta/realtime/test_transcription_sessions.py b/tests/api_resources/beta/realtime/test_transcription_sessions.py index 5a6b4f6c92..ac52489e74 100644 --- a/tests/api_resources/beta/realtime/test_transcription_sessions.py +++ b/tests/api_resources/beta/realtime/test_transcription_sessions.py @@ -74,7 +74,9 @@ def test_streaming_response_create(self, client: OpenAI) -> None: class TestAsyncTranscriptionSessions: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/beta/test_assistants.py b/tests/api_resources/beta/test_assistants.py index 82aaf87b1c..8aeb654e38 100644 --- a/tests/api_resources/beta/test_assistants.py +++ b/tests/api_resources/beta/test_assistants.py @@ -253,7 +253,9 @@ def test_path_params_delete(self, client: OpenAI) -> None: class TestAsyncAssistants: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/beta/test_realtime.py b/tests/api_resources/beta/test_realtime.py index 537017ffd3..2b0c7f7d8d 100644 --- a/tests/api_resources/beta/test_realtime.py +++ b/tests/api_resources/beta/test_realtime.py @@ -14,4 +14,6 @@ class TestRealtime: class TestAsyncRealtime: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) diff --git a/tests/api_resources/beta/test_threads.py b/tests/api_resources/beta/test_threads.py index eab94f0f8a..f392c86729 100644 --- a/tests/api_resources/beta/test_threads.py +++ b/tests/api_resources/beta/test_threads.py @@ -420,7 +420,9 @@ def test_streaming_response_create_and_run_overload_2(self, client: OpenAI) -> N class TestAsyncThreads: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/beta/threads/runs/test_steps.py b/tests/api_resources/beta/threads/runs/test_steps.py index 9ca70657ec..ba44eec63d 100644 --- a/tests/api_resources/beta/threads/runs/test_steps.py +++ b/tests/api_resources/beta/threads/runs/test_steps.py @@ -167,7 +167,9 @@ def test_path_params_list(self, client: OpenAI) -> None: class TestAsyncSteps: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/beta/threads/test_messages.py b/tests/api_resources/beta/threads/test_messages.py index bf3f22e8a3..7f57002f27 100644 --- a/tests/api_resources/beta/threads/test_messages.py +++ b/tests/api_resources/beta/threads/test_messages.py @@ -321,7 +321,9 @@ def test_path_params_delete(self, client: OpenAI) -> None: class TestAsyncMessages: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/beta/threads/test_runs.py b/tests/api_resources/beta/threads/test_runs.py index fdef5e40db..86a296627e 100644 --- a/tests/api_resources/beta/threads/test_runs.py +++ b/tests/api_resources/beta/threads/test_runs.py @@ -568,7 +568,9 @@ def test_path_params_submit_tool_outputs_overload_2(self, client: OpenAI) -> Non class TestAsyncRuns: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create_overload_1(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/chat/completions/test_messages.py b/tests/api_resources/chat/completions/test_messages.py index 5caac9ec6c..4a4267e539 100644 --- a/tests/api_resources/chat/completions/test_messages.py +++ b/tests/api_resources/chat/completions/test_messages.py @@ -68,7 +68,9 @@ def test_path_params_list(self, client: OpenAI) -> None: class TestAsyncMessages: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_list(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/chat/test_completions.py b/tests/api_resources/chat/test_completions.py index aaef82e8c5..aa8f58f0e5 100644 --- a/tests/api_resources/chat/test_completions.py +++ b/tests/api_resources/chat/test_completions.py @@ -447,7 +447,9 @@ class MyModel(pydantic.BaseModel): class TestAsyncCompletions: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create_overload_1(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/containers/files/test_content.py b/tests/api_resources/containers/files/test_content.py index 402607058f..67fcdca36c 100644 --- a/tests/api_resources/containers/files/test_content.py +++ b/tests/api_resources/containers/files/test_content.py @@ -86,7 +86,9 @@ def test_path_params_retrieve(self, client: OpenAI) -> None: class TestAsyncContent: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize @pytest.mark.respx(base_url=base_url) diff --git a/tests/api_resources/containers/test_files.py b/tests/api_resources/containers/test_files.py index 6edcc7973a..f9d82d005c 100644 --- a/tests/api_resources/containers/test_files.py +++ b/tests/api_resources/containers/test_files.py @@ -215,7 +215,9 @@ def test_path_params_delete(self, client: OpenAI) -> None: class TestAsyncFiles: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/evals/runs/test_output_items.py b/tests/api_resources/evals/runs/test_output_items.py index f764f0336e..673867ac42 100644 --- a/tests/api_resources/evals/runs/test_output_items.py +++ b/tests/api_resources/evals/runs/test_output_items.py @@ -140,7 +140,9 @@ def test_path_params_list(self, client: OpenAI) -> None: class TestAsyncOutputItems: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/evals/test_runs.py b/tests/api_resources/evals/test_runs.py index cefb1c82ff..1367cb4bab 100644 --- a/tests/api_resources/evals/test_runs.py +++ b/tests/api_resources/evals/test_runs.py @@ -306,7 +306,9 @@ def test_path_params_cancel(self, client: OpenAI) -> None: class TestAsyncRuns: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/fine_tuning/alpha/test_graders.py b/tests/api_resources/fine_tuning/alpha/test_graders.py index c7fe6670f3..4a237114b6 100644 --- a/tests/api_resources/fine_tuning/alpha/test_graders.py +++ b/tests/api_resources/fine_tuning/alpha/test_graders.py @@ -151,7 +151,9 @@ def test_streaming_response_validate(self, client: OpenAI) -> None: class TestAsyncGraders: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_run(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/fine_tuning/checkpoints/test_permissions.py b/tests/api_resources/fine_tuning/checkpoints/test_permissions.py index 4a7608d8df..4944597624 100644 --- a/tests/api_resources/fine_tuning/checkpoints/test_permissions.py +++ b/tests/api_resources/fine_tuning/checkpoints/test_permissions.py @@ -169,7 +169,9 @@ def test_path_params_delete(self, client: OpenAI) -> None: class TestAsyncPermissions: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/fine_tuning/jobs/test_checkpoints.py b/tests/api_resources/fine_tuning/jobs/test_checkpoints.py index 915d5c6f63..bb11529263 100644 --- a/tests/api_resources/fine_tuning/jobs/test_checkpoints.py +++ b/tests/api_resources/fine_tuning/jobs/test_checkpoints.py @@ -67,7 +67,9 @@ def test_path_params_list(self, client: OpenAI) -> None: class TestAsyncCheckpoints: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_list(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/fine_tuning/test_jobs.py b/tests/api_resources/fine_tuning/test_jobs.py index 4589f12846..8a35255885 100644 --- a/tests/api_resources/fine_tuning/test_jobs.py +++ b/tests/api_resources/fine_tuning/test_jobs.py @@ -354,7 +354,9 @@ def test_path_params_resume(self, client: OpenAI) -> None: class TestAsyncJobs: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/responses/test_input_items.py b/tests/api_resources/responses/test_input_items.py index 2528943c06..b28f5638c5 100644 --- a/tests/api_resources/responses/test_input_items.py +++ b/tests/api_resources/responses/test_input_items.py @@ -70,7 +70,9 @@ def test_path_params_list(self, client: OpenAI) -> None: class TestAsyncInputItems: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_list(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/test_batches.py b/tests/api_resources/test_batches.py index a2f8fb48a3..6775094a58 100644 --- a/tests/api_resources/test_batches.py +++ b/tests/api_resources/test_batches.py @@ -176,7 +176,9 @@ def test_path_params_cancel(self, client: OpenAI) -> None: class TestAsyncBatches: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/test_completions.py b/tests/api_resources/test_completions.py index 9ec503c1e3..1c5271df75 100644 --- a/tests/api_resources/test_completions.py +++ b/tests/api_resources/test_completions.py @@ -137,7 +137,9 @@ def test_streaming_response_create_overload_2(self, client: OpenAI) -> None: class TestAsyncCompletions: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create_overload_1(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/test_containers.py b/tests/api_resources/test_containers.py index be9787c4d6..c972f6539d 100644 --- a/tests/api_resources/test_containers.py +++ b/tests/api_resources/test_containers.py @@ -177,7 +177,9 @@ def test_path_params_delete(self, client: OpenAI) -> None: class TestAsyncContainers: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/test_embeddings.py b/tests/api_resources/test_embeddings.py index e75545b4e2..ce6e213d59 100644 --- a/tests/api_resources/test_embeddings.py +++ b/tests/api_resources/test_embeddings.py @@ -64,7 +64,9 @@ def test_streaming_response_create(self, client: OpenAI) -> None: class TestAsyncEmbeddings: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/test_evals.py b/tests/api_resources/test_evals.py index 4ae2c597dd..473a4711ca 100644 --- a/tests/api_resources/test_evals.py +++ b/tests/api_resources/test_evals.py @@ -297,7 +297,9 @@ def test_path_params_delete(self, client: OpenAI) -> None: class TestAsyncEvals: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/test_files.py b/tests/api_resources/test_files.py index 7402566d95..fc4bb4a18e 100644 --- a/tests/api_resources/test_files.py +++ b/tests/api_resources/test_files.py @@ -260,7 +260,9 @@ def test_path_params_retrieve_content(self, client: OpenAI) -> None: class TestAsyncFiles: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/test_images.py b/tests/api_resources/test_images.py index 77bcea10ea..10fc56d685 100644 --- a/tests/api_resources/test_images.py +++ b/tests/api_resources/test_images.py @@ -163,7 +163,9 @@ def test_streaming_response_generate(self, client: OpenAI) -> None: class TestAsyncImages: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create_variation(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/test_models.py b/tests/api_resources/test_models.py index 8791507c3e..cf70871ade 100644 --- a/tests/api_resources/test_models.py +++ b/tests/api_resources/test_models.py @@ -121,7 +121,9 @@ def test_path_params_delete(self, client: OpenAI) -> None: class TestAsyncModels: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/test_moderations.py b/tests/api_resources/test_moderations.py index 6df6464110..870c9e342f 100644 --- a/tests/api_resources/test_moderations.py +++ b/tests/api_resources/test_moderations.py @@ -58,7 +58,9 @@ def test_streaming_response_create(self, client: OpenAI) -> None: class TestAsyncModerations: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/test_responses.py b/tests/api_resources/test_responses.py index 3bbf21ba14..6aaf0ea17f 100644 --- a/tests/api_resources/test_responses.py +++ b/tests/api_resources/test_responses.py @@ -352,7 +352,9 @@ def test_path_params_cancel(self, client: OpenAI) -> None: class TestAsyncResponses: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create_overload_1(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/test_uploads.py b/tests/api_resources/test_uploads.py index a14c4f8da2..72a2f6c83d 100644 --- a/tests/api_resources/test_uploads.py +++ b/tests/api_resources/test_uploads.py @@ -148,7 +148,9 @@ def test_path_params_complete(self, client: OpenAI) -> None: class TestAsyncUploads: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/test_vector_stores.py b/tests/api_resources/test_vector_stores.py index 54bb75bc1d..5af95fec41 100644 --- a/tests/api_resources/test_vector_stores.py +++ b/tests/api_resources/test_vector_stores.py @@ -286,7 +286,9 @@ def test_path_params_search(self, client: OpenAI) -> None: class TestAsyncVectorStores: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/uploads/test_parts.py b/tests/api_resources/uploads/test_parts.py index 2bba241a6d..191d3a1b04 100644 --- a/tests/api_resources/uploads/test_parts.py +++ b/tests/api_resources/uploads/test_parts.py @@ -61,7 +61,9 @@ def test_path_params_create(self, client: OpenAI) -> None: class TestAsyncParts: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/vector_stores/test_file_batches.py b/tests/api_resources/vector_stores/test_file_batches.py index 0587cfc56a..ac678ce912 100644 --- a/tests/api_resources/vector_stores/test_file_batches.py +++ b/tests/api_resources/vector_stores/test_file_batches.py @@ -232,7 +232,9 @@ def test_path_params_list_files(self, client: OpenAI) -> None: class TestAsyncFileBatches: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/vector_stores/test_files.py b/tests/api_resources/vector_stores/test_files.py index c13442261e..0778704d5d 100644 --- a/tests/api_resources/vector_stores/test_files.py +++ b/tests/api_resources/vector_stores/test_files.py @@ -323,7 +323,9 @@ def test_path_params_content(self, client: OpenAI) -> None: class TestAsyncFiles: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/conftest.py b/tests/conftest.py index 4b98d20a48..408bcf76c0 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -6,10 +6,12 @@ import logging from typing import TYPE_CHECKING, Iterator, AsyncIterator +import httpx import pytest from pytest_asyncio import is_async_test -from openai import OpenAI, AsyncOpenAI +from openai import OpenAI, AsyncOpenAI, DefaultAioHttpClient +from openai._utils import is_dict if TYPE_CHECKING: from _pytest.fixtures import FixtureRequest # pyright: ignore[reportPrivateImportUsage] @@ -27,6 +29,19 @@ def pytest_collection_modifyitems(items: list[pytest.Function]) -> None: for async_test in pytest_asyncio_tests: async_test.add_marker(session_scope_marker, append=False) + # We skip tests that use both the aiohttp client and respx_mock as respx_mock + # doesn't support custom transports. + for item in items: + if "async_client" not in item.fixturenames or "respx_mock" not in item.fixturenames: + continue + + if not hasattr(item, "callspec"): + continue + + async_client_param = item.callspec.params.get("async_client") + if is_dict(async_client_param) and async_client_param.get("http_client") == "aiohttp": + item.add_marker(pytest.mark.skip(reason="aiohttp client is not compatible with respx_mock")) + base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -45,9 +60,25 @@ def client(request: FixtureRequest) -> Iterator[OpenAI]: @pytest.fixture(scope="session") async def async_client(request: FixtureRequest) -> AsyncIterator[AsyncOpenAI]: - strict = getattr(request, "param", True) - if not isinstance(strict, bool): - raise TypeError(f"Unexpected fixture parameter type {type(strict)}, expected {bool}") - - async with AsyncOpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=strict) as client: + param = getattr(request, "param", True) + + # defaults + strict = True + http_client: None | httpx.AsyncClient = None + + if isinstance(param, bool): + strict = param + elif is_dict(param): + strict = param.get("strict", True) + assert isinstance(strict, bool) + + http_client_type = param.get("http_client", "httpx") + if http_client_type == "aiohttp": + http_client = DefaultAioHttpClient() + else: + raise TypeError(f"Unexpected fixture parameter type {type(param)}, expected bool or dict") + + async with AsyncOpenAI( + base_url=base_url, api_key=api_key, _strict_response_validation=strict, http_client=http_client + ) as client: yield client From ca9363d4ea5fcc5ad61683bd5fc39f107bc47aa6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Jun 2025 18:02:27 +0000 Subject: [PATCH 358/769] release: 1.89.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 18 ++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 5ae95686ab..e0b8841fba 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.88.0" + ".": "1.89.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 09de5415d0..6557ddeab6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ # Changelog +## 1.89.0 (2025-06-20) + +Full Changelog: [v1.88.0...v1.89.0](https://github.com/openai/openai-python/compare/v1.88.0...v1.89.0) + +### Features + +* **client:** add support for aiohttp ([9218b07](https://github.com/openai/openai-python/commit/9218b07727bf6f6eb00953df66de6ab061fecddb)) + + +### Bug Fixes + +* **tests:** fix: tests which call HTTP endpoints directly with the example parameters ([35bcc4b](https://github.com/openai/openai-python/commit/35bcc4b80bdbaa31108650f2a515902e83794e5a)) + + +### Chores + +* **readme:** update badges ([68044ee](https://github.com/openai/openai-python/commit/68044ee85d1bf324b17d3f60c914df4725d47fc8)) + ## 1.88.0 (2025-06-17) Full Changelog: [v1.87.0...v1.88.0](https://github.com/openai/openai-python/compare/v1.87.0...v1.88.0) diff --git a/pyproject.toml b/pyproject.toml index b531a822dc..90716f994f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.88.0" +version = "1.89.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 7c606ee49c..46a41a551e 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.88.0" # x-release-please-version +__version__ = "1.89.0" # x-release-please-version From e68921654125ae733aac00c683b504bc89856df2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Jun 2025 13:21:27 -0700 Subject: [PATCH 359/769] release: 1.90.0 (#2420) * feat(api): make model and inputs not required to create response * release: 1.90.0 --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- .stats.yml | 4 +- CHANGELOG.md | 8 + pyproject.toml | 2 +- src/openai/_version.py | 2 +- src/openai/resources/responses/responses.py | 236 +++++++++--------- .../types/responses/response_create_params.py | 42 ++-- tests/api_resources/test_responses.py | 58 ++--- 8 files changed, 165 insertions(+), 189 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index e0b8841fba..407051a9fb 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.89.0" + ".": "1.90.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 7e42b77a27..f8abf5bab6 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-9e41d2d5471d2c28bff0d616f4476f5b0e6c541ef4cb51bdaaef5fdf5e13c8b2.yml -openapi_spec_hash: 86f765e18d00e32cf2ce9db7ab84d946 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-f411a68f272b8be0ab0c266043da33228687b9b2d76896724e3cef797de9563d.yml +openapi_spec_hash: 89bf866ea95ecfb3d76c8833237047d6 config_hash: dc5515e257676a27cb1ace1784aa92b3 diff --git a/CHANGELOG.md b/CHANGELOG.md index 6557ddeab6..dc45fa7bb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.90.0 (2025-06-20) + +Full Changelog: [v1.89.0...v1.90.0](https://github.com/openai/openai-python/compare/v1.89.0...v1.90.0) + +### Features + +* **api:** make model and inputs not required to create response ([11bd62e](https://github.com/openai/openai-python/commit/11bd62eb7e46eec748edaf2e0cecf253ffc1202c)) + ## 1.89.0 (2025-06-20) Full Changelog: [v1.88.0...v1.89.0](https://github.com/openai/openai-python/compare/v1.88.0...v1.89.0) diff --git a/pyproject.toml b/pyproject.toml index 90716f994f..f66dacbf6d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.89.0" +version = "1.90.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 46a41a551e..7e515c74bd 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.89.0" # x-release-please-version +__version__ = "1.90.0" # x-release-please-version diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 3276501494..841d198a5b 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -10,7 +10,7 @@ from ... import _legacy_response from ..._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven -from ..._utils import is_given, required_args, maybe_transform, async_maybe_transform +from ..._utils import is_given, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -76,13 +76,13 @@ def with_streaming_response(self) -> ResponsesWithStreamingResponse: def create( self, *, - input: Union[str, ResponseInputParam], - model: ResponsesModel, background: Optional[bool] | NotGiven = NOT_GIVEN, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + model: ResponsesModel | NotGiven = NOT_GIVEN, parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, @@ -119,22 +119,6 @@ def create( your own data as input for the model's response. Args: - input: Text, image, or file inputs to the model, used to generate a response. - - Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Image inputs](https://platform.openai.com/docs/guides/images) - - [File inputs](https://platform.openai.com/docs/guides/pdf-files) - - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) - - [Function calling](https://platform.openai.com/docs/guides/function-calling) - - model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a - wide range of models with different capabilities, performance characteristics, - and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - background: Whether to run the model response in the background. [Learn more](https://platform.openai.com/docs/guides/background). @@ -154,6 +138,16 @@ def create( - `code_interpreter_call.outputs`: Includes the outputs of python code execution in code interpreter tool call items. + input: Text, image, or file inputs to the model, used to generate a response. + + Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Image inputs](https://platform.openai.com/docs/guides/images) + - [File inputs](https://platform.openai.com/docs/guides/pdf-files) + - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) + - [Function calling](https://platform.openai.com/docs/guides/function-calling) + instructions: A system (or developer) message inserted into the model's context. When using along with `previous_response_id`, the instructions from a previous @@ -171,6 +165,12 @@ def create( Keys are strings with a maximum length of 64 characters. Values are strings with a maximum length of 512 characters. + model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a + wide range of models with different capabilities, performance characteristics, + and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + parallel_tool_calls: Whether to allow the model to run tool calls in parallel. previous_response_id: The unique ID of the previous response to the model. Use this to create @@ -274,14 +274,14 @@ def create( def create( self, *, - input: Union[str, ResponseInputParam], - model: ResponsesModel, stream: Literal[True], background: Optional[bool] | NotGiven = NOT_GIVEN, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + model: ResponsesModel | NotGiven = NOT_GIVEN, parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, @@ -317,22 +317,6 @@ def create( your own data as input for the model's response. Args: - input: Text, image, or file inputs to the model, used to generate a response. - - Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Image inputs](https://platform.openai.com/docs/guides/images) - - [File inputs](https://platform.openai.com/docs/guides/pdf-files) - - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) - - [Function calling](https://platform.openai.com/docs/guides/function-calling) - - model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a - wide range of models with different capabilities, performance characteristics, - and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - stream: If set to true, the model response data will be streamed to the client as it is generated using [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). @@ -359,6 +343,16 @@ def create( - `code_interpreter_call.outputs`: Includes the outputs of python code execution in code interpreter tool call items. + input: Text, image, or file inputs to the model, used to generate a response. + + Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Image inputs](https://platform.openai.com/docs/guides/images) + - [File inputs](https://platform.openai.com/docs/guides/pdf-files) + - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) + - [Function calling](https://platform.openai.com/docs/guides/function-calling) + instructions: A system (or developer) message inserted into the model's context. When using along with `previous_response_id`, the instructions from a previous @@ -376,6 +370,12 @@ def create( Keys are strings with a maximum length of 64 characters. Values are strings with a maximum length of 512 characters. + model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a + wide range of models with different capabilities, performance characteristics, + and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + parallel_tool_calls: Whether to allow the model to run tool calls in parallel. previous_response_id: The unique ID of the previous response to the model. Use this to create @@ -472,14 +472,14 @@ def create( def create( self, *, - input: Union[str, ResponseInputParam], - model: ResponsesModel, stream: bool, background: Optional[bool] | NotGiven = NOT_GIVEN, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + model: ResponsesModel | NotGiven = NOT_GIVEN, parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, @@ -515,22 +515,6 @@ def create( your own data as input for the model's response. Args: - input: Text, image, or file inputs to the model, used to generate a response. - - Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Image inputs](https://platform.openai.com/docs/guides/images) - - [File inputs](https://platform.openai.com/docs/guides/pdf-files) - - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) - - [Function calling](https://platform.openai.com/docs/guides/function-calling) - - model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a - wide range of models with different capabilities, performance characteristics, - and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - stream: If set to true, the model response data will be streamed to the client as it is generated using [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). @@ -557,6 +541,16 @@ def create( - `code_interpreter_call.outputs`: Includes the outputs of python code execution in code interpreter tool call items. + input: Text, image, or file inputs to the model, used to generate a response. + + Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Image inputs](https://platform.openai.com/docs/guides/images) + - [File inputs](https://platform.openai.com/docs/guides/pdf-files) + - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) + - [Function calling](https://platform.openai.com/docs/guides/function-calling) + instructions: A system (or developer) message inserted into the model's context. When using along with `previous_response_id`, the instructions from a previous @@ -574,6 +568,12 @@ def create( Keys are strings with a maximum length of 64 characters. Values are strings with a maximum length of 512 characters. + model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a + wide range of models with different capabilities, performance characteristics, + and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + parallel_tool_calls: Whether to allow the model to run tool calls in parallel. previous_response_id: The unique ID of the previous response to the model. Use this to create @@ -666,17 +666,16 @@ def create( """ ... - @required_args(["input", "model"], ["input", "model", "stream"]) def create( self, *, - input: Union[str, ResponseInputParam], - model: ResponsesModel, background: Optional[bool] | NotGiven = NOT_GIVEN, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + model: ResponsesModel | NotGiven = NOT_GIVEN, parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, @@ -702,13 +701,13 @@ def create( "/responses", body=maybe_transform( { - "input": input, - "model": model, "background": background, "include": include, + "input": input, "instructions": instructions, "max_output_tokens": max_output_tokens, "metadata": metadata, + "model": model, "parallel_tool_calls": parallel_tool_calls, "previous_response_id": previous_response_id, "prompt": prompt, @@ -1295,13 +1294,13 @@ def with_streaming_response(self) -> AsyncResponsesWithStreamingResponse: async def create( self, *, - input: Union[str, ResponseInputParam], - model: ResponsesModel, background: Optional[bool] | NotGiven = NOT_GIVEN, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + model: ResponsesModel | NotGiven = NOT_GIVEN, parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, @@ -1338,22 +1337,6 @@ async def create( your own data as input for the model's response. Args: - input: Text, image, or file inputs to the model, used to generate a response. - - Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Image inputs](https://platform.openai.com/docs/guides/images) - - [File inputs](https://platform.openai.com/docs/guides/pdf-files) - - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) - - [Function calling](https://platform.openai.com/docs/guides/function-calling) - - model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a - wide range of models with different capabilities, performance characteristics, - and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - background: Whether to run the model response in the background. [Learn more](https://platform.openai.com/docs/guides/background). @@ -1373,6 +1356,16 @@ async def create( - `code_interpreter_call.outputs`: Includes the outputs of python code execution in code interpreter tool call items. + input: Text, image, or file inputs to the model, used to generate a response. + + Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Image inputs](https://platform.openai.com/docs/guides/images) + - [File inputs](https://platform.openai.com/docs/guides/pdf-files) + - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) + - [Function calling](https://platform.openai.com/docs/guides/function-calling) + instructions: A system (or developer) message inserted into the model's context. When using along with `previous_response_id`, the instructions from a previous @@ -1390,6 +1383,12 @@ async def create( Keys are strings with a maximum length of 64 characters. Values are strings with a maximum length of 512 characters. + model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a + wide range of models with different capabilities, performance characteristics, + and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + parallel_tool_calls: Whether to allow the model to run tool calls in parallel. previous_response_id: The unique ID of the previous response to the model. Use this to create @@ -1493,14 +1492,14 @@ async def create( async def create( self, *, - input: Union[str, ResponseInputParam], - model: ResponsesModel, stream: Literal[True], background: Optional[bool] | NotGiven = NOT_GIVEN, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + model: ResponsesModel | NotGiven = NOT_GIVEN, parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, @@ -1536,22 +1535,6 @@ async def create( your own data as input for the model's response. Args: - input: Text, image, or file inputs to the model, used to generate a response. - - Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Image inputs](https://platform.openai.com/docs/guides/images) - - [File inputs](https://platform.openai.com/docs/guides/pdf-files) - - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) - - [Function calling](https://platform.openai.com/docs/guides/function-calling) - - model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a - wide range of models with different capabilities, performance characteristics, - and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - stream: If set to true, the model response data will be streamed to the client as it is generated using [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). @@ -1578,6 +1561,16 @@ async def create( - `code_interpreter_call.outputs`: Includes the outputs of python code execution in code interpreter tool call items. + input: Text, image, or file inputs to the model, used to generate a response. + + Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Image inputs](https://platform.openai.com/docs/guides/images) + - [File inputs](https://platform.openai.com/docs/guides/pdf-files) + - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) + - [Function calling](https://platform.openai.com/docs/guides/function-calling) + instructions: A system (or developer) message inserted into the model's context. When using along with `previous_response_id`, the instructions from a previous @@ -1595,6 +1588,12 @@ async def create( Keys are strings with a maximum length of 64 characters. Values are strings with a maximum length of 512 characters. + model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a + wide range of models with different capabilities, performance characteristics, + and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + parallel_tool_calls: Whether to allow the model to run tool calls in parallel. previous_response_id: The unique ID of the previous response to the model. Use this to create @@ -1691,14 +1690,14 @@ async def create( async def create( self, *, - input: Union[str, ResponseInputParam], - model: ResponsesModel, stream: bool, background: Optional[bool] | NotGiven = NOT_GIVEN, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + model: ResponsesModel | NotGiven = NOT_GIVEN, parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, @@ -1734,22 +1733,6 @@ async def create( your own data as input for the model's response. Args: - input: Text, image, or file inputs to the model, used to generate a response. - - Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Image inputs](https://platform.openai.com/docs/guides/images) - - [File inputs](https://platform.openai.com/docs/guides/pdf-files) - - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) - - [Function calling](https://platform.openai.com/docs/guides/function-calling) - - model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a - wide range of models with different capabilities, performance characteristics, - and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - stream: If set to true, the model response data will be streamed to the client as it is generated using [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). @@ -1776,6 +1759,16 @@ async def create( - `code_interpreter_call.outputs`: Includes the outputs of python code execution in code interpreter tool call items. + input: Text, image, or file inputs to the model, used to generate a response. + + Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Image inputs](https://platform.openai.com/docs/guides/images) + - [File inputs](https://platform.openai.com/docs/guides/pdf-files) + - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) + - [Function calling](https://platform.openai.com/docs/guides/function-calling) + instructions: A system (or developer) message inserted into the model's context. When using along with `previous_response_id`, the instructions from a previous @@ -1793,6 +1786,12 @@ async def create( Keys are strings with a maximum length of 64 characters. Values are strings with a maximum length of 512 characters. + model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a + wide range of models with different capabilities, performance characteristics, + and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + parallel_tool_calls: Whether to allow the model to run tool calls in parallel. previous_response_id: The unique ID of the previous response to the model. Use this to create @@ -1885,17 +1884,16 @@ async def create( """ ... - @required_args(["input", "model"], ["input", "model", "stream"]) async def create( self, *, - input: Union[str, ResponseInputParam], - model: ResponsesModel, background: Optional[bool] | NotGiven = NOT_GIVEN, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + model: ResponsesModel | NotGiven = NOT_GIVEN, parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, @@ -1921,13 +1919,13 @@ async def create( "/responses", body=await async_maybe_transform( { - "input": input, - "model": model, "background": background, "include": include, + "input": input, "instructions": instructions, "max_output_tokens": max_output_tokens, "metadata": metadata, + "model": model, "parallel_tool_calls": parallel_tool_calls, "previous_response_id": previous_response_id, "prompt": prompt, diff --git a/src/openai/types/responses/response_create_params.py b/src/openai/types/responses/response_create_params.py index 976ae9741d..22acd6f653 100644 --- a/src/openai/types/responses/response_create_params.py +++ b/src/openai/types/responses/response_create_params.py @@ -26,27 +26,6 @@ class ResponseCreateParamsBase(TypedDict, total=False): - input: Required[Union[str, ResponseInputParam]] - """Text, image, or file inputs to the model, used to generate a response. - - Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Image inputs](https://platform.openai.com/docs/guides/images) - - [File inputs](https://platform.openai.com/docs/guides/pdf-files) - - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) - - [Function calling](https://platform.openai.com/docs/guides/function-calling) - """ - - model: Required[ResponsesModel] - """Model ID used to generate the response, like `gpt-4o` or `o3`. - - OpenAI offers a wide range of models with different capabilities, performance - characteristics, and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - """ - background: Optional[bool] """Whether to run the model response in the background. @@ -72,6 +51,18 @@ class ResponseCreateParamsBase(TypedDict, total=False): in code interpreter tool call items. """ + input: Union[str, ResponseInputParam] + """Text, image, or file inputs to the model, used to generate a response. + + Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Image inputs](https://platform.openai.com/docs/guides/images) + - [File inputs](https://platform.openai.com/docs/guides/pdf-files) + - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) + - [Function calling](https://platform.openai.com/docs/guides/function-calling) + """ + instructions: Optional[str] """A system (or developer) message inserted into the model's context. @@ -97,6 +88,15 @@ class ResponseCreateParamsBase(TypedDict, total=False): a maximum length of 512 characters. """ + model: ResponsesModel + """Model ID used to generate the response, like `gpt-4o` or `o3`. + + OpenAI offers a wide range of models with different capabilities, performance + characteristics, and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + """ + parallel_tool_calls: Optional[bool] """Whether to allow the model to run tool calls in parallel.""" diff --git a/tests/api_resources/test_responses.py b/tests/api_resources/test_responses.py index 6aaf0ea17f..5b7559655a 100644 --- a/tests/api_resources/test_responses.py +++ b/tests/api_resources/test_responses.py @@ -21,22 +21,19 @@ class TestResponses: @parametrize def test_method_create_overload_1(self, client: OpenAI) -> None: - response = client.responses.create( - input="string", - model="gpt-4o", - ) + response = client.responses.create() assert_matches_type(Response, response, path=["response"]) @parametrize def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: response = client.responses.create( - input="string", - model="gpt-4o", background=True, include=["file_search_call.results"], + input="string", instructions="instructions", max_output_tokens=0, metadata={"foo": "string"}, + model="gpt-4o", parallel_tool_calls=True, previous_response_id="previous_response_id", prompt={ @@ -72,10 +69,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: @parametrize def test_raw_response_create_overload_1(self, client: OpenAI) -> None: - http_response = client.responses.with_raw_response.create( - input="string", - model="gpt-4o", - ) + http_response = client.responses.with_raw_response.create() assert http_response.is_closed is True assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -84,10 +78,7 @@ def test_raw_response_create_overload_1(self, client: OpenAI) -> None: @parametrize def test_streaming_response_create_overload_1(self, client: OpenAI) -> None: - with client.responses.with_streaming_response.create( - input="string", - model="gpt-4o", - ) as http_response: + with client.responses.with_streaming_response.create() as http_response: assert not http_response.is_closed assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -99,8 +90,6 @@ def test_streaming_response_create_overload_1(self, client: OpenAI) -> None: @parametrize def test_method_create_overload_2(self, client: OpenAI) -> None: response_stream = client.responses.create( - input="string", - model="gpt-4o", stream=True, ) response_stream.response.close() @@ -108,14 +97,14 @@ def test_method_create_overload_2(self, client: OpenAI) -> None: @parametrize def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: response_stream = client.responses.create( - input="string", - model="gpt-4o", stream=True, background=True, include=["file_search_call.results"], + input="string", instructions="instructions", max_output_tokens=0, metadata={"foo": "string"}, + model="gpt-4o", parallel_tool_calls=True, previous_response_id="previous_response_id", prompt={ @@ -151,8 +140,6 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: @parametrize def test_raw_response_create_overload_2(self, client: OpenAI) -> None: response = client.responses.with_raw_response.create( - input="string", - model="gpt-4o", stream=True, ) @@ -163,8 +150,6 @@ def test_raw_response_create_overload_2(self, client: OpenAI) -> None: @parametrize def test_streaming_response_create_overload_2(self, client: OpenAI) -> None: with client.responses.with_streaming_response.create( - input="string", - model="gpt-4o", stream=True, ) as response: assert not response.is_closed @@ -358,22 +343,19 @@ class TestAsyncResponses: @parametrize async def test_method_create_overload_1(self, async_client: AsyncOpenAI) -> None: - response = await async_client.responses.create( - input="string", - model="gpt-4o", - ) + response = await async_client.responses.create() assert_matches_type(Response, response, path=["response"]) @parametrize async def test_method_create_with_all_params_overload_1(self, async_client: AsyncOpenAI) -> None: response = await async_client.responses.create( - input="string", - model="gpt-4o", background=True, include=["file_search_call.results"], + input="string", instructions="instructions", max_output_tokens=0, metadata={"foo": "string"}, + model="gpt-4o", parallel_tool_calls=True, previous_response_id="previous_response_id", prompt={ @@ -409,10 +391,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn @parametrize async def test_raw_response_create_overload_1(self, async_client: AsyncOpenAI) -> None: - http_response = await async_client.responses.with_raw_response.create( - input="string", - model="gpt-4o", - ) + http_response = await async_client.responses.with_raw_response.create() assert http_response.is_closed is True assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -421,10 +400,7 @@ async def test_raw_response_create_overload_1(self, async_client: AsyncOpenAI) - @parametrize async def test_streaming_response_create_overload_1(self, async_client: AsyncOpenAI) -> None: - async with async_client.responses.with_streaming_response.create( - input="string", - model="gpt-4o", - ) as http_response: + async with async_client.responses.with_streaming_response.create() as http_response: assert not http_response.is_closed assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -436,8 +412,6 @@ async def test_streaming_response_create_overload_1(self, async_client: AsyncOpe @parametrize async def test_method_create_overload_2(self, async_client: AsyncOpenAI) -> None: response_stream = await async_client.responses.create( - input="string", - model="gpt-4o", stream=True, ) await response_stream.response.aclose() @@ -445,14 +419,14 @@ async def test_method_create_overload_2(self, async_client: AsyncOpenAI) -> None @parametrize async def test_method_create_with_all_params_overload_2(self, async_client: AsyncOpenAI) -> None: response_stream = await async_client.responses.create( - input="string", - model="gpt-4o", stream=True, background=True, include=["file_search_call.results"], + input="string", instructions="instructions", max_output_tokens=0, metadata={"foo": "string"}, + model="gpt-4o", parallel_tool_calls=True, previous_response_id="previous_response_id", prompt={ @@ -488,8 +462,6 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn @parametrize async def test_raw_response_create_overload_2(self, async_client: AsyncOpenAI) -> None: response = await async_client.responses.with_raw_response.create( - input="string", - model="gpt-4o", stream=True, ) @@ -500,8 +472,6 @@ async def test_raw_response_create_overload_2(self, async_client: AsyncOpenAI) - @parametrize async def test_streaming_response_create_overload_2(self, async_client: AsyncOpenAI) -> None: async with async_client.responses.with_streaming_response.create( - input="string", - model="gpt-4o", stream=True, ) as response: assert not response.is_closed From 0673da62f2f2476a3e5791122e75ec0cbfd03442 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 11:26:16 -0700 Subject: [PATCH 360/769] release: 1.91.0 (#2423) * feat(api): update api shapes for usage and code interpreter * release: 1.91.0 --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- .stats.yml | 6 +-- CHANGELOG.md | 8 ++++ api.md | 2 +- pyproject.toml | 2 +- src/openai/_version.py | 2 +- src/openai/resources/audio/speech.py | 14 +++++- .../fine_tuning/checkpoints/permissions.py | 22 ++++----- .../types/audio/speech_create_params.py | 10 +++- src/openai/types/audio/transcription.py | 45 ++++++++++++++++- .../audio/transcription_text_done_event.py | 30 +++++++++++- .../types/audio/transcription_verbose.py | 14 +++++- .../beta/realtime/session_create_params.py | 10 ++-- .../beta/realtime/session_create_response.py | 9 ++-- .../beta/realtime/session_update_event.py | 8 ++-- .../realtime/session_update_event_param.py | 8 ++-- .../permission_retrieve_response.py | 17 ++++++- ..._code_interpreter_call_code_delta_event.py | 12 +++-- ...e_code_interpreter_call_code_done_event.py | 7 ++- ...e_code_interpreter_call_completed_event.py | 12 +++-- ...code_interpreter_call_in_progress_event.py | 12 +++-- ...ode_interpreter_call_interpreting_event.py | 12 +++-- .../response_code_interpreter_tool_call.py | 46 ++++++++---------- ...sponse_code_interpreter_tool_call_param.py | 48 +++++++++---------- .../types/responses/response_output_text.py | 6 +++ .../responses/response_output_text_param.py | 6 +++ tests/api_resources/audio/test_speech.py | 2 + .../beta/realtime/test_sessions.py | 4 +- .../checkpoints/test_permissions.py | 18 +++---- 29 files changed, 264 insertions(+), 130 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 407051a9fb..f18270d528 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.90.0" + ".": "1.91.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index f8abf5bab6..1e0182cf22 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-f411a68f272b8be0ab0c266043da33228687b9b2d76896724e3cef797de9563d.yml -openapi_spec_hash: 89bf866ea95ecfb3d76c8833237047d6 -config_hash: dc5515e257676a27cb1ace1784aa92b3 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-ef4ecb19eb61e24c49d77fef769ee243e5279bc0bdbaee8d0f8dba4da8722559.yml +openapi_spec_hash: 1b8a9767c9f04e6865b06c41948cdc24 +config_hash: fd2af1d5eff0995bb7dc02ac9a34851d diff --git a/CHANGELOG.md b/CHANGELOG.md index dc45fa7bb5..14562edfac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.91.0 (2025-06-23) + +Full Changelog: [v1.90.0...v1.91.0](https://github.com/openai/openai-python/compare/v1.90.0...v1.91.0) + +### Features + +* **api:** update api shapes for usage and code interpreter ([060d566](https://github.com/openai/openai-python/commit/060d5661e4a1fcdb953c52facd3e668ee80f9295)) + ## 1.90.0 (2025-06-20) Full Changelog: [v1.89.0...v1.90.0](https://github.com/openai/openai-python/compare/v1.89.0...v1.90.0) diff --git a/api.md b/api.md index db52398b97..25360d741e 100644 --- a/api.md +++ b/api.md @@ -293,7 +293,7 @@ from openai.types.fine_tuning.checkpoints import ( Methods: - client.fine_tuning.checkpoints.permissions.create(fine_tuned_model_checkpoint, \*\*params) -> SyncPage[PermissionCreateResponse] -- client.fine_tuning.checkpoints.permissions.retrieve(fine_tuned_model_checkpoint, \*\*params) -> SyncCursorPage[PermissionRetrieveResponse] +- client.fine_tuning.checkpoints.permissions.retrieve(fine_tuned_model_checkpoint, \*\*params) -> PermissionRetrieveResponse - client.fine_tuning.checkpoints.permissions.delete(permission_id, \*, fine_tuned_model_checkpoint) -> PermissionDeleteResponse ## Alpha diff --git a/pyproject.toml b/pyproject.toml index f66dacbf6d..1f2b8a6044 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.90.0" +version = "1.91.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 7e515c74bd..d1cad1dd01 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.90.0" # x-release-please-version +__version__ = "1.91.0" # x-release-please-version diff --git a/src/openai/resources/audio/speech.py b/src/openai/resources/audio/speech.py index a195d7135e..fe776baae8 100644 --- a/src/openai/resources/audio/speech.py +++ b/src/openai/resources/audio/speech.py @@ -56,6 +56,7 @@ def create( instructions: str | NotGiven = NOT_GIVEN, response_format: Literal["mp3", "opus", "aac", "flac", "wav", "pcm"] | NotGiven = NOT_GIVEN, speed: float | NotGiven = NOT_GIVEN, + stream_format: Literal["sse", "audio"] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -85,7 +86,10 @@ def create( `wav`, and `pcm`. speed: The speed of the generated audio. Select a value from `0.25` to `4.0`. `1.0` is - the default. Does not work with `gpt-4o-mini-tts`. + the default. + + stream_format: The format to stream the audio in. Supported formats are `sse` and `audio`. + `sse` is not supported for `tts-1` or `tts-1-hd`. extra_headers: Send extra headers @@ -106,6 +110,7 @@ def create( "instructions": instructions, "response_format": response_format, "speed": speed, + "stream_format": stream_format, }, speech_create_params.SpeechCreateParams, ), @@ -147,6 +152,7 @@ async def create( instructions: str | NotGiven = NOT_GIVEN, response_format: Literal["mp3", "opus", "aac", "flac", "wav", "pcm"] | NotGiven = NOT_GIVEN, speed: float | NotGiven = NOT_GIVEN, + stream_format: Literal["sse", "audio"] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -176,7 +182,10 @@ async def create( `wav`, and `pcm`. speed: The speed of the generated audio. Select a value from `0.25` to `4.0`. `1.0` is - the default. Does not work with `gpt-4o-mini-tts`. + the default. + + stream_format: The format to stream the audio in. Supported formats are `sse` and `audio`. + `sse` is not supported for `tts-1` or `tts-1-hd`. extra_headers: Send extra headers @@ -197,6 +206,7 @@ async def create( "instructions": instructions, "response_format": response_format, "speed": speed, + "stream_format": stream_format, }, speech_create_params.SpeechCreateParams, ), diff --git a/src/openai/resources/fine_tuning/checkpoints/permissions.py b/src/openai/resources/fine_tuning/checkpoints/permissions.py index ceb747a367..547e42ecac 100644 --- a/src/openai/resources/fine_tuning/checkpoints/permissions.py +++ b/src/openai/resources/fine_tuning/checkpoints/permissions.py @@ -9,11 +9,11 @@ from .... import _legacy_response from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ...._utils import maybe_transform +from ...._utils import maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ....pagination import SyncPage, AsyncPage, SyncCursorPage, AsyncCursorPage +from ....pagination import SyncPage, AsyncPage from ...._base_client import AsyncPaginator, make_request_options from ....types.fine_tuning.checkpoints import permission_create_params, permission_retrieve_params from ....types.fine_tuning.checkpoints.permission_create_response import PermissionCreateResponse @@ -101,7 +101,7 @@ def retrieve( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> SyncCursorPage[PermissionRetrieveResponse]: + ) -> PermissionRetrieveResponse: """ **NOTE:** This endpoint requires an [admin API key](../admin-api-keys). @@ -129,9 +129,8 @@ def retrieve( raise ValueError( f"Expected a non-empty value for `fine_tuned_model_checkpoint` but received {fine_tuned_model_checkpoint!r}" ) - return self._get_api_list( + return self._get( f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", - page=SyncCursorPage[PermissionRetrieveResponse], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -147,7 +146,7 @@ def retrieve( permission_retrieve_params.PermissionRetrieveParams, ), ), - model=PermissionRetrieveResponse, + cast_to=PermissionRetrieveResponse, ) def delete( @@ -256,7 +255,7 @@ def create( method="post", ) - def retrieve( + async def retrieve( self, fine_tuned_model_checkpoint: str, *, @@ -270,7 +269,7 @@ def retrieve( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncPaginator[PermissionRetrieveResponse, AsyncCursorPage[PermissionRetrieveResponse]]: + ) -> PermissionRetrieveResponse: """ **NOTE:** This endpoint requires an [admin API key](../admin-api-keys). @@ -298,15 +297,14 @@ def retrieve( raise ValueError( f"Expected a non-empty value for `fine_tuned_model_checkpoint` but received {fine_tuned_model_checkpoint!r}" ) - return self._get_api_list( + return await self._get( f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", - page=AsyncCursorPage[PermissionRetrieveResponse], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, - query=maybe_transform( + query=await async_maybe_transform( { "after": after, "limit": limit, @@ -316,7 +314,7 @@ def retrieve( permission_retrieve_params.PermissionRetrieveParams, ), ), - model=PermissionRetrieveResponse, + cast_to=PermissionRetrieveResponse, ) async def delete( diff --git a/src/openai/types/audio/speech_create_params.py b/src/openai/types/audio/speech_create_params.py index 905ca5c3a8..4ee4a3c4e4 100644 --- a/src/openai/types/audio/speech_create_params.py +++ b/src/openai/types/audio/speech_create_params.py @@ -48,6 +48,12 @@ class SpeechCreateParams(TypedDict, total=False): speed: float """The speed of the generated audio. - Select a value from `0.25` to `4.0`. `1.0` is the default. Does not work with - `gpt-4o-mini-tts`. + Select a value from `0.25` to `4.0`. `1.0` is the default. + """ + + stream_format: Literal["sse", "audio"] + """The format to stream the audio in. + + Supported formats are `sse` and `audio`. `sse` is not supported for `tts-1` or + `tts-1-hd`. """ diff --git a/src/openai/types/audio/transcription.py b/src/openai/types/audio/transcription.py index 1576385404..7115eb9edb 100644 --- a/src/openai/types/audio/transcription.py +++ b/src/openai/types/audio/transcription.py @@ -1,10 +1,12 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Optional +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias +from ..._utils import PropertyInfo from ..._models import BaseModel -__all__ = ["Transcription", "Logprob"] +__all__ = ["Transcription", "Logprob", "Usage", "UsageTokens", "UsageTokensInputTokenDetails", "UsageDuration"] class Logprob(BaseModel): @@ -18,6 +20,42 @@ class Logprob(BaseModel): """The log probability of the token.""" +class UsageTokensInputTokenDetails(BaseModel): + audio_tokens: Optional[int] = None + """Number of audio tokens billed for this request.""" + + text_tokens: Optional[int] = None + """Number of text tokens billed for this request.""" + + +class UsageTokens(BaseModel): + input_tokens: int + """Number of input tokens billed for this request.""" + + output_tokens: int + """Number of output tokens generated.""" + + total_tokens: int + """Total number of tokens used (input + output).""" + + type: Literal["tokens"] + """The type of the usage object. Always `tokens` for this variant.""" + + input_token_details: Optional[UsageTokensInputTokenDetails] = None + """Details about the input tokens billed for this request.""" + + +class UsageDuration(BaseModel): + duration: float + """Duration of the input audio in seconds.""" + + type: Literal["duration"] + """The type of the usage object. Always `duration` for this variant.""" + + +Usage: TypeAlias = Annotated[Union[UsageTokens, UsageDuration], PropertyInfo(discriminator="type")] + + class Transcription(BaseModel): text: str """The transcribed text.""" @@ -28,3 +66,6 @@ class Transcription(BaseModel): Only returned with the models `gpt-4o-transcribe` and `gpt-4o-mini-transcribe` if `logprobs` is added to the `include` array. """ + + usage: Optional[Usage] = None + """Token usage statistics for the request.""" diff --git a/src/openai/types/audio/transcription_text_done_event.py b/src/openai/types/audio/transcription_text_done_event.py index c8875a1bdb..9665edc565 100644 --- a/src/openai/types/audio/transcription_text_done_event.py +++ b/src/openai/types/audio/transcription_text_done_event.py @@ -5,7 +5,7 @@ from ..._models import BaseModel -__all__ = ["TranscriptionTextDoneEvent", "Logprob"] +__all__ = ["TranscriptionTextDoneEvent", "Logprob", "Usage", "UsageInputTokenDetails"] class Logprob(BaseModel): @@ -19,6 +19,31 @@ class Logprob(BaseModel): """The log probability of the token.""" +class UsageInputTokenDetails(BaseModel): + audio_tokens: Optional[int] = None + """Number of audio tokens billed for this request.""" + + text_tokens: Optional[int] = None + """Number of text tokens billed for this request.""" + + +class Usage(BaseModel): + input_tokens: int + """Number of input tokens billed for this request.""" + + output_tokens: int + """Number of output tokens generated.""" + + total_tokens: int + """Total number of tokens used (input + output).""" + + type: Literal["tokens"] + """The type of the usage object. Always `tokens` for this variant.""" + + input_token_details: Optional[UsageInputTokenDetails] = None + """Details about the input tokens billed for this request.""" + + class TranscriptionTextDoneEvent(BaseModel): text: str """The text that was transcribed.""" @@ -33,3 +58,6 @@ class TranscriptionTextDoneEvent(BaseModel): [create a transcription](https://platform.openai.com/docs/api-reference/audio/create-transcription) with the `include[]` parameter set to `logprobs`. """ + + usage: Optional[Usage] = None + """Usage statistics for models billed by token usage.""" diff --git a/src/openai/types/audio/transcription_verbose.py b/src/openai/types/audio/transcription_verbose.py index 2a670189e0..cc6d769a65 100644 --- a/src/openai/types/audio/transcription_verbose.py +++ b/src/openai/types/audio/transcription_verbose.py @@ -1,12 +1,21 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from typing import List, Optional +from typing_extensions import Literal from ..._models import BaseModel from .transcription_word import TranscriptionWord from .transcription_segment import TranscriptionSegment -__all__ = ["TranscriptionVerbose"] +__all__ = ["TranscriptionVerbose", "Usage"] + + +class Usage(BaseModel): + duration: float + """Duration of the input audio in seconds.""" + + type: Literal["duration"] + """The type of the usage object. Always `duration` for this variant.""" class TranscriptionVerbose(BaseModel): @@ -22,5 +31,8 @@ class TranscriptionVerbose(BaseModel): segments: Optional[List[TranscriptionSegment]] = None """Segments of the transcribed text and their corresponding details.""" + usage: Optional[Usage] = None + """Usage statistics for models billed by audio input duration.""" + words: Optional[List[TranscriptionWord]] = None """Extracted words and their corresponding timestamps.""" diff --git a/src/openai/types/beta/realtime/session_create_params.py b/src/openai/types/beta/realtime/session_create_params.py index cebf67c732..e04985d2b6 100644 --- a/src/openai/types/beta/realtime/session_create_params.py +++ b/src/openai/types/beta/realtime/session_create_params.py @@ -3,12 +3,12 @@ from __future__ import annotations from typing import List, Union, Iterable -from typing_extensions import Literal, TypeAlias, TypedDict +from typing_extensions import Literal, Required, TypeAlias, TypedDict __all__ = [ "SessionCreateParams", "ClientSecret", - "ClientSecretExpiresAt", + "ClientSecretExpiresAfter", "InputAudioNoiseReduction", "InputAudioTranscription", "Tool", @@ -156,8 +156,8 @@ class SessionCreateParams(TypedDict, total=False): """ -class ClientSecretExpiresAt(TypedDict, total=False): - anchor: Literal["created_at"] +class ClientSecretExpiresAfter(TypedDict, total=False): + anchor: Required[Literal["created_at"]] """The anchor point for the ephemeral token expiration. Only `created_at` is currently supported. @@ -171,7 +171,7 @@ class ClientSecretExpiresAt(TypedDict, total=False): class ClientSecret(TypedDict, total=False): - expires_at: ClientSecretExpiresAt + expires_after: ClientSecretExpiresAfter """Configuration for the ephemeral token expiration.""" diff --git a/src/openai/types/beta/realtime/session_create_response.py b/src/openai/types/beta/realtime/session_create_response.py index 81fed95fa9..15d5c1742b 100644 --- a/src/openai/types/beta/realtime/session_create_response.py +++ b/src/openai/types/beta/realtime/session_create_response.py @@ -33,10 +33,7 @@ class ClientSecret(BaseModel): class InputAudioTranscription(BaseModel): model: Optional[str] = None - """ - The model to use for transcription, `whisper-1` is the only currently supported - model. - """ + """The model to use for transcription.""" class Tool(BaseModel): @@ -116,8 +113,8 @@ class SessionCreateResponse(BaseModel): Configuration for input audio transcription, defaults to off and can be set to `null` to turn off once on. Input audio transcription is not native to the model, since the model consumes audio directly. Transcription runs - asynchronously through Whisper and should be treated as rough guidance rather - than the representation understood by the model. + asynchronously and should be treated as rough guidance rather than the + representation understood by the model. """ instructions: Optional[str] = None diff --git a/src/openai/types/beta/realtime/session_update_event.py b/src/openai/types/beta/realtime/session_update_event.py index 8bb6a0e266..789b9cd1e5 100644 --- a/src/openai/types/beta/realtime/session_update_event.py +++ b/src/openai/types/beta/realtime/session_update_event.py @@ -9,7 +9,7 @@ "SessionUpdateEvent", "Session", "SessionClientSecret", - "SessionClientSecretExpiresAt", + "SessionClientSecretExpiresAfter", "SessionInputAudioNoiseReduction", "SessionInputAudioTranscription", "SessionTool", @@ -19,8 +19,8 @@ ] -class SessionClientSecretExpiresAt(BaseModel): - anchor: Optional[Literal["created_at"]] = None +class SessionClientSecretExpiresAfter(BaseModel): + anchor: Literal["created_at"] """The anchor point for the ephemeral token expiration. Only `created_at` is currently supported. @@ -34,7 +34,7 @@ class SessionClientSecretExpiresAt(BaseModel): class SessionClientSecret(BaseModel): - expires_at: Optional[SessionClientSecretExpiresAt] = None + expires_after: Optional[SessionClientSecretExpiresAfter] = None """Configuration for the ephemeral token expiration.""" diff --git a/src/openai/types/beta/realtime/session_update_event_param.py b/src/openai/types/beta/realtime/session_update_event_param.py index a10de540d0..2dfa2c26f3 100644 --- a/src/openai/types/beta/realtime/session_update_event_param.py +++ b/src/openai/types/beta/realtime/session_update_event_param.py @@ -9,7 +9,7 @@ "SessionUpdateEventParam", "Session", "SessionClientSecret", - "SessionClientSecretExpiresAt", + "SessionClientSecretExpiresAfter", "SessionInputAudioNoiseReduction", "SessionInputAudioTranscription", "SessionTool", @@ -19,8 +19,8 @@ ] -class SessionClientSecretExpiresAt(TypedDict, total=False): - anchor: Literal["created_at"] +class SessionClientSecretExpiresAfter(TypedDict, total=False): + anchor: Required[Literal["created_at"]] """The anchor point for the ephemeral token expiration. Only `created_at` is currently supported. @@ -34,7 +34,7 @@ class SessionClientSecretExpiresAt(TypedDict, total=False): class SessionClientSecret(TypedDict, total=False): - expires_at: SessionClientSecretExpiresAt + expires_after: SessionClientSecretExpiresAfter """Configuration for the ephemeral token expiration.""" diff --git a/src/openai/types/fine_tuning/checkpoints/permission_retrieve_response.py b/src/openai/types/fine_tuning/checkpoints/permission_retrieve_response.py index 4c540179e7..14c73b55d0 100644 --- a/src/openai/types/fine_tuning/checkpoints/permission_retrieve_response.py +++ b/src/openai/types/fine_tuning/checkpoints/permission_retrieve_response.py @@ -1,13 +1,14 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from typing import List, Optional from typing_extensions import Literal from ...._models import BaseModel -__all__ = ["PermissionRetrieveResponse"] +__all__ = ["PermissionRetrieveResponse", "Data"] -class PermissionRetrieveResponse(BaseModel): +class Data(BaseModel): id: str """The permission identifier, which can be referenced in the API endpoints.""" @@ -19,3 +20,15 @@ class PermissionRetrieveResponse(BaseModel): project_id: str """The project identifier that the permission is for.""" + + +class PermissionRetrieveResponse(BaseModel): + data: List[Data] + + has_more: bool + + object: Literal["list"] + + first_id: Optional[str] = None + + last_id: Optional[str] = None diff --git a/src/openai/types/responses/response_code_interpreter_call_code_delta_event.py b/src/openai/types/responses/response_code_interpreter_call_code_delta_event.py index d222431504..c5fef939b1 100644 --- a/src/openai/types/responses/response_code_interpreter_call_code_delta_event.py +++ b/src/openai/types/responses/response_code_interpreter_call_code_delta_event.py @@ -9,13 +9,19 @@ class ResponseCodeInterpreterCallCodeDeltaEvent(BaseModel): delta: str - """The partial code snippet added by the code interpreter.""" + """The partial code snippet being streamed by the code interpreter.""" + + item_id: str + """The unique identifier of the code interpreter tool call item.""" output_index: int - """The index of the output item that the code interpreter call is in progress.""" + """ + The index of the output item in the response for which the code is being + streamed. + """ sequence_number: int - """The sequence number of this event.""" + """The sequence number of this event, used to order streaming events.""" type: Literal["response.code_interpreter_call_code.delta"] """The type of the event. Always `response.code_interpreter_call_code.delta`.""" diff --git a/src/openai/types/responses/response_code_interpreter_call_code_done_event.py b/src/openai/types/responses/response_code_interpreter_call_code_done_event.py index 1ce6796a0e..5201a02d36 100644 --- a/src/openai/types/responses/response_code_interpreter_call_code_done_event.py +++ b/src/openai/types/responses/response_code_interpreter_call_code_done_event.py @@ -11,11 +11,14 @@ class ResponseCodeInterpreterCallCodeDoneEvent(BaseModel): code: str """The final code snippet output by the code interpreter.""" + item_id: str + """The unique identifier of the code interpreter tool call item.""" + output_index: int - """The index of the output item that the code interpreter call is in progress.""" + """The index of the output item in the response for which the code is finalized.""" sequence_number: int - """The sequence number of this event.""" + """The sequence number of this event, used to order streaming events.""" type: Literal["response.code_interpreter_call_code.done"] """The type of the event. Always `response.code_interpreter_call_code.done`.""" diff --git a/src/openai/types/responses/response_code_interpreter_call_completed_event.py b/src/openai/types/responses/response_code_interpreter_call_completed_event.py index 3a3a718971..bb9563a16b 100644 --- a/src/openai/types/responses/response_code_interpreter_call_completed_event.py +++ b/src/openai/types/responses/response_code_interpreter_call_completed_event.py @@ -3,20 +3,22 @@ from typing_extensions import Literal from ..._models import BaseModel -from .response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall __all__ = ["ResponseCodeInterpreterCallCompletedEvent"] class ResponseCodeInterpreterCallCompletedEvent(BaseModel): - code_interpreter_call: ResponseCodeInterpreterToolCall - """A tool call to run code.""" + item_id: str + """The unique identifier of the code interpreter tool call item.""" output_index: int - """The index of the output item that the code interpreter call is in progress.""" + """ + The index of the output item in the response for which the code interpreter call + is completed. + """ sequence_number: int - """The sequence number of this event.""" + """The sequence number of this event, used to order streaming events.""" type: Literal["response.code_interpreter_call.completed"] """The type of the event. Always `response.code_interpreter_call.completed`.""" diff --git a/src/openai/types/responses/response_code_interpreter_call_in_progress_event.py b/src/openai/types/responses/response_code_interpreter_call_in_progress_event.py index d1c8230919..9c6b221004 100644 --- a/src/openai/types/responses/response_code_interpreter_call_in_progress_event.py +++ b/src/openai/types/responses/response_code_interpreter_call_in_progress_event.py @@ -3,20 +3,22 @@ from typing_extensions import Literal from ..._models import BaseModel -from .response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall __all__ = ["ResponseCodeInterpreterCallInProgressEvent"] class ResponseCodeInterpreterCallInProgressEvent(BaseModel): - code_interpreter_call: ResponseCodeInterpreterToolCall - """A tool call to run code.""" + item_id: str + """The unique identifier of the code interpreter tool call item.""" output_index: int - """The index of the output item that the code interpreter call is in progress.""" + """ + The index of the output item in the response for which the code interpreter call + is in progress. + """ sequence_number: int - """The sequence number of this event.""" + """The sequence number of this event, used to order streaming events.""" type: Literal["response.code_interpreter_call.in_progress"] """The type of the event. Always `response.code_interpreter_call.in_progress`.""" diff --git a/src/openai/types/responses/response_code_interpreter_call_interpreting_event.py b/src/openai/types/responses/response_code_interpreter_call_interpreting_event.py index 7f4d294f56..f6191e4165 100644 --- a/src/openai/types/responses/response_code_interpreter_call_interpreting_event.py +++ b/src/openai/types/responses/response_code_interpreter_call_interpreting_event.py @@ -3,20 +3,22 @@ from typing_extensions import Literal from ..._models import BaseModel -from .response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall __all__ = ["ResponseCodeInterpreterCallInterpretingEvent"] class ResponseCodeInterpreterCallInterpretingEvent(BaseModel): - code_interpreter_call: ResponseCodeInterpreterToolCall - """A tool call to run code.""" + item_id: str + """The unique identifier of the code interpreter tool call item.""" output_index: int - """The index of the output item that the code interpreter call is in progress.""" + """ + The index of the output item in the response for which the code interpreter is + interpreting code. + """ sequence_number: int - """The sequence number of this event.""" + """The sequence number of this event, used to order streaming events.""" type: Literal["response.code_interpreter_call.interpreting"] """The type of the event. Always `response.code_interpreter_call.interpreting`.""" diff --git a/src/openai/types/responses/response_code_interpreter_tool_call.py b/src/openai/types/responses/response_code_interpreter_tool_call.py index 762542f398..7e4dc9f984 100644 --- a/src/openai/types/responses/response_code_interpreter_tool_call.py +++ b/src/openai/types/responses/response_code_interpreter_tool_call.py @@ -6,50 +6,46 @@ from ..._utils import PropertyInfo from ..._models import BaseModel -__all__ = ["ResponseCodeInterpreterToolCall", "Result", "ResultLogs", "ResultFiles", "ResultFilesFile"] +__all__ = ["ResponseCodeInterpreterToolCall", "Output", "OutputLogs", "OutputImage"] -class ResultLogs(BaseModel): +class OutputLogs(BaseModel): logs: str - """The logs of the code interpreter tool call.""" + """The logs output from the code interpreter.""" type: Literal["logs"] - """The type of the code interpreter text output. Always `logs`.""" + """The type of the output. Always 'logs'.""" -class ResultFilesFile(BaseModel): - file_id: str - """The ID of the file.""" +class OutputImage(BaseModel): + type: Literal["image"] + """The type of the output. Always 'image'.""" - mime_type: str - """The MIME type of the file.""" + url: str + """The URL of the image output from the code interpreter.""" -class ResultFiles(BaseModel): - files: List[ResultFilesFile] - - type: Literal["files"] - """The type of the code interpreter file output. Always `files`.""" - - -Result: TypeAlias = Annotated[Union[ResultLogs, ResultFiles], PropertyInfo(discriminator="type")] +Output: TypeAlias = Annotated[Union[OutputLogs, OutputImage], PropertyInfo(discriminator="type")] class ResponseCodeInterpreterToolCall(BaseModel): id: str """The unique ID of the code interpreter tool call.""" - code: str - """The code to run.""" + code: Optional[str] = None + """The code to run, or null if not available.""" + + container_id: str + """The ID of the container used to run the code.""" + + outputs: Optional[List[Output]] = None + """The outputs generated by the code interpreter, such as logs or images. - results: List[Result] - """The results of the code interpreter tool call.""" + Can be null if no outputs are available. + """ - status: Literal["in_progress", "interpreting", "completed"] + status: Literal["in_progress", "completed", "incomplete", "interpreting", "failed"] """The status of the code interpreter tool call.""" type: Literal["code_interpreter_call"] """The type of the code interpreter tool call. Always `code_interpreter_call`.""" - - container_id: Optional[str] = None - """The ID of the container used to run the code.""" diff --git a/src/openai/types/responses/response_code_interpreter_tool_call_param.py b/src/openai/types/responses/response_code_interpreter_tool_call_param.py index be0f909a6a..69e01f99ed 100644 --- a/src/openai/types/responses/response_code_interpreter_tool_call_param.py +++ b/src/openai/types/responses/response_code_interpreter_tool_call_param.py @@ -2,53 +2,49 @@ from __future__ import annotations -from typing import Union, Iterable +from typing import Union, Iterable, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict -__all__ = ["ResponseCodeInterpreterToolCallParam", "Result", "ResultLogs", "ResultFiles", "ResultFilesFile"] +__all__ = ["ResponseCodeInterpreterToolCallParam", "Output", "OutputLogs", "OutputImage"] -class ResultLogs(TypedDict, total=False): +class OutputLogs(TypedDict, total=False): logs: Required[str] - """The logs of the code interpreter tool call.""" + """The logs output from the code interpreter.""" type: Required[Literal["logs"]] - """The type of the code interpreter text output. Always `logs`.""" + """The type of the output. Always 'logs'.""" -class ResultFilesFile(TypedDict, total=False): - file_id: Required[str] - """The ID of the file.""" +class OutputImage(TypedDict, total=False): + type: Required[Literal["image"]] + """The type of the output. Always 'image'.""" - mime_type: Required[str] - """The MIME type of the file.""" + url: Required[str] + """The URL of the image output from the code interpreter.""" -class ResultFiles(TypedDict, total=False): - files: Required[Iterable[ResultFilesFile]] - - type: Required[Literal["files"]] - """The type of the code interpreter file output. Always `files`.""" - - -Result: TypeAlias = Union[ResultLogs, ResultFiles] +Output: TypeAlias = Union[OutputLogs, OutputImage] class ResponseCodeInterpreterToolCallParam(TypedDict, total=False): id: Required[str] """The unique ID of the code interpreter tool call.""" - code: Required[str] - """The code to run.""" + code: Required[Optional[str]] + """The code to run, or null if not available.""" + + container_id: Required[str] + """The ID of the container used to run the code.""" + + outputs: Required[Optional[Iterable[Output]]] + """The outputs generated by the code interpreter, such as logs or images. - results: Required[Iterable[Result]] - """The results of the code interpreter tool call.""" + Can be null if no outputs are available. + """ - status: Required[Literal["in_progress", "interpreting", "completed"]] + status: Required[Literal["in_progress", "completed", "incomplete", "interpreting", "failed"]] """The status of the code interpreter tool call.""" type: Required[Literal["code_interpreter_call"]] """The type of the code interpreter tool call. Always `code_interpreter_call`.""" - - container_id: str - """The ID of the container used to run the code.""" diff --git a/src/openai/types/responses/response_output_text.py b/src/openai/types/responses/response_output_text.py index 1ea9a4ba93..aa97b629f0 100644 --- a/src/openai/types/responses/response_output_text.py +++ b/src/openai/types/responses/response_output_text.py @@ -22,6 +22,9 @@ class AnnotationFileCitation(BaseModel): file_id: str """The ID of the file.""" + filename: str + """The filename of the file cited.""" + index: int """The index of the file in the list of files.""" @@ -56,6 +59,9 @@ class AnnotationContainerFileCitation(BaseModel): file_id: str """The ID of the file.""" + filename: str + """The filename of the container file cited.""" + start_index: int """The index of the first character of the container file citation in the message.""" diff --git a/src/openai/types/responses/response_output_text_param.py b/src/openai/types/responses/response_output_text_param.py index 207901e8ef..63d2d394a8 100644 --- a/src/openai/types/responses/response_output_text_param.py +++ b/src/openai/types/responses/response_output_text_param.py @@ -21,6 +21,9 @@ class AnnotationFileCitation(TypedDict, total=False): file_id: Required[str] """The ID of the file.""" + filename: Required[str] + """The filename of the file cited.""" + index: Required[int] """The index of the file in the list of files.""" @@ -55,6 +58,9 @@ class AnnotationContainerFileCitation(TypedDict, total=False): file_id: Required[str] """The ID of the file.""" + filename: Required[str] + """The filename of the container file cited.""" + start_index: Required[int] """The index of the first character of the container file citation in the message.""" diff --git a/tests/api_resources/audio/test_speech.py b/tests/api_resources/audio/test_speech.py index 01746b3a3a..2c77f38949 100644 --- a/tests/api_resources/audio/test_speech.py +++ b/tests/api_resources/audio/test_speech.py @@ -44,6 +44,7 @@ def test_method_create_with_all_params(self, client: OpenAI, respx_mock: MockRou instructions="instructions", response_format="mp3", speed=0.25, + stream_format="sse", ) assert isinstance(speech, _legacy_response.HttpxBinaryResponseContent) assert speech.json() == {"foo": "bar"} @@ -110,6 +111,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI, re instructions="instructions", response_format="mp3", speed=0.25, + stream_format="sse", ) assert isinstance(speech, _legacy_response.HttpxBinaryResponseContent) assert speech.json() == {"foo": "bar"} diff --git a/tests/api_resources/beta/realtime/test_sessions.py b/tests/api_resources/beta/realtime/test_sessions.py index 9b78956a98..3c55abf80c 100644 --- a/tests/api_resources/beta/realtime/test_sessions.py +++ b/tests/api_resources/beta/realtime/test_sessions.py @@ -26,7 +26,7 @@ def test_method_create(self, client: OpenAI) -> None: def test_method_create_with_all_params(self, client: OpenAI) -> None: session = client.beta.realtime.sessions.create( client_secret={ - "expires_at": { + "expires_after": { "anchor": "created_at", "seconds": 0, } @@ -103,7 +103,7 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None: async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: session = await async_client.beta.realtime.sessions.create( client_secret={ - "expires_at": { + "expires_after": { "anchor": "created_at", "seconds": 0, } diff --git a/tests/api_resources/fine_tuning/checkpoints/test_permissions.py b/tests/api_resources/fine_tuning/checkpoints/test_permissions.py index 4944597624..9420e3a34c 100644 --- a/tests/api_resources/fine_tuning/checkpoints/test_permissions.py +++ b/tests/api_resources/fine_tuning/checkpoints/test_permissions.py @@ -9,7 +9,7 @@ from openai import OpenAI, AsyncOpenAI from tests.utils import assert_matches_type -from openai.pagination import SyncPage, AsyncPage, SyncCursorPage, AsyncCursorPage +from openai.pagination import SyncPage, AsyncPage from openai.types.fine_tuning.checkpoints import ( PermissionCreateResponse, PermissionDeleteResponse, @@ -71,7 +71,7 @@ def test_method_retrieve(self, client: OpenAI) -> None: permission = client.fine_tuning.checkpoints.permissions.retrieve( fine_tuned_model_checkpoint="ft-AF1WoRqd3aJAHsqc9NY7iL8F", ) - assert_matches_type(SyncCursorPage[PermissionRetrieveResponse], permission, path=["response"]) + assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) @parametrize def test_method_retrieve_with_all_params(self, client: OpenAI) -> None: @@ -82,7 +82,7 @@ def test_method_retrieve_with_all_params(self, client: OpenAI) -> None: order="ascending", project_id="project_id", ) - assert_matches_type(SyncCursorPage[PermissionRetrieveResponse], permission, path=["response"]) + assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) @parametrize def test_raw_response_retrieve(self, client: OpenAI) -> None: @@ -93,7 +93,7 @@ def test_raw_response_retrieve(self, client: OpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" permission = response.parse() - assert_matches_type(SyncCursorPage[PermissionRetrieveResponse], permission, path=["response"]) + assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) @parametrize def test_streaming_response_retrieve(self, client: OpenAI) -> None: @@ -104,7 +104,7 @@ def test_streaming_response_retrieve(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" permission = response.parse() - assert_matches_type(SyncCursorPage[PermissionRetrieveResponse], permission, path=["response"]) + assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) assert cast(Any, response.is_closed) is True @@ -222,7 +222,7 @@ async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: permission = await async_client.fine_tuning.checkpoints.permissions.retrieve( fine_tuned_model_checkpoint="ft-AF1WoRqd3aJAHsqc9NY7iL8F", ) - assert_matches_type(AsyncCursorPage[PermissionRetrieveResponse], permission, path=["response"]) + assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) @parametrize async def test_method_retrieve_with_all_params(self, async_client: AsyncOpenAI) -> None: @@ -233,7 +233,7 @@ async def test_method_retrieve_with_all_params(self, async_client: AsyncOpenAI) order="ascending", project_id="project_id", ) - assert_matches_type(AsyncCursorPage[PermissionRetrieveResponse], permission, path=["response"]) + assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) @parametrize async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: @@ -244,7 +244,7 @@ async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" permission = response.parse() - assert_matches_type(AsyncCursorPage[PermissionRetrieveResponse], permission, path=["response"]) + assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) @parametrize async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: @@ -255,7 +255,7 @@ async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> N assert response.http_request.headers.get("X-Stainless-Lang") == "python" permission = await response.parse() - assert_matches_type(AsyncCursorPage[PermissionRetrieveResponse], permission, path=["response"]) + assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) assert cast(Any, response.is_closed) is True From 18e0b36abe7c79a8e1a055f4ed57b3752f9ea01c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 09:56:28 -0700 Subject: [PATCH 361/769] release: 1.92.0 (#2424) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(tests): skip some failing tests on the latest python versions * chore(internal): add tests for breaking change detection * move over parse and stream methods out of beta * update docs * update tests * remove old beta files * fix relative import * fix(ci): release-doctor — report correct token name * feat(api): webhook and deep research support * release: 1.92.0 --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> Co-authored-by: David Meadows --- .release-please-manifest.json | 2 +- .stats.yml | 6 +- CHANGELOG.md | 20 + README.md | 78 ++ api.md | 30 + bin/check-release-environment | 2 +- examples/parsing.py | 2 +- examples/parsing_stream.py | 2 +- examples/parsing_tools.py | 2 +- examples/parsing_tools_stream.py | 2 +- helpers.md | 17 +- pyproject.toml | 2 +- src/openai/__init__.py | 17 + src/openai/_client.py | 31 + src/openai/_exceptions.py | 5 + src/openai/_module_client.py | 8 + src/openai/_version.py | 2 +- src/openai/lib/azure.py | 14 + src/openai/lib/streaming/chat/_completions.py | 4 +- src/openai/resources/beta/beta.py | 2 +- src/openai/resources/beta/chat/__init__.py | 11 - src/openai/resources/beta/chat/chat.py | 21 - src/openai/resources/beta/chat/completions.py | 634 --------------- .../resources/chat/completions/completions.py | 750 +++++++++++++++--- src/openai/resources/responses/responses.py | 318 +++++--- src/openai/resources/webhooks.py | 210 +++++ src/openai/types/chat/chat_completion.py | 33 +- .../types/chat/chat_completion_chunk.py | 33 +- .../types/chat/completion_create_params.py | 35 +- src/openai/types/images_response.py | 19 + src/openai/types/responses/__init__.py | 2 + src/openai/types/responses/response.py | 48 +- .../types/responses/response_create_params.py | 59 +- .../responses/response_function_web_search.py | 45 +- .../response_function_web_search_param.py | 44 +- .../types/responses/response_includable.py | 5 +- src/openai/types/responses/tool_choice_mcp.py | 19 + .../types/responses/tool_choice_mcp_param.py | 19 + .../types/responses/tool_choice_types.py | 2 - .../responses/tool_choice_types_param.py | 2 - src/openai/types/shared/all_models.py | 4 + src/openai/types/shared/responses_model.py | 4 + .../types/shared_params/responses_model.py | 4 + src/openai/types/webhooks/__init__.py | 23 + .../webhooks/batch_cancelled_webhook_event.py | 30 + .../webhooks/batch_completed_webhook_event.py | 30 + .../webhooks/batch_expired_webhook_event.py | 30 + .../webhooks/batch_failed_webhook_event.py | 30 + .../eval_run_canceled_webhook_event.py | 30 + .../webhooks/eval_run_failed_webhook_event.py | 30 + .../eval_run_succeeded_webhook_event.py | 30 + ...fine_tuning_job_cancelled_webhook_event.py | 30 + .../fine_tuning_job_failed_webhook_event.py | 30 + ...fine_tuning_job_succeeded_webhook_event.py | 30 + .../response_cancelled_webhook_event.py | 30 + .../response_completed_webhook_event.py | 30 + .../webhooks/response_failed_webhook_event.py | 30 + .../response_incomplete_webhook_event.py | 30 + .../types/webhooks/unwrap_webhook_event.py | 42 + .../responses/test_input_items.py | 4 +- tests/api_resources/test_responses.py | 24 +- tests/api_resources/test_webhooks.py | 284 +++++++ tests/lib/chat/test_completions.py | 36 +- tests/lib/chat/test_completions_streaming.py | 26 +- tests/test_client.py | 2 + tests/test_module_client.py | 1 + 66 files changed, 2380 insertions(+), 1051 deletions(-) delete mode 100644 src/openai/resources/beta/chat/__init__.py delete mode 100644 src/openai/resources/beta/chat/chat.py delete mode 100644 src/openai/resources/beta/chat/completions.py create mode 100644 src/openai/resources/webhooks.py create mode 100644 src/openai/types/responses/tool_choice_mcp.py create mode 100644 src/openai/types/responses/tool_choice_mcp_param.py create mode 100644 src/openai/types/webhooks/__init__.py create mode 100644 src/openai/types/webhooks/batch_cancelled_webhook_event.py create mode 100644 src/openai/types/webhooks/batch_completed_webhook_event.py create mode 100644 src/openai/types/webhooks/batch_expired_webhook_event.py create mode 100644 src/openai/types/webhooks/batch_failed_webhook_event.py create mode 100644 src/openai/types/webhooks/eval_run_canceled_webhook_event.py create mode 100644 src/openai/types/webhooks/eval_run_failed_webhook_event.py create mode 100644 src/openai/types/webhooks/eval_run_succeeded_webhook_event.py create mode 100644 src/openai/types/webhooks/fine_tuning_job_cancelled_webhook_event.py create mode 100644 src/openai/types/webhooks/fine_tuning_job_failed_webhook_event.py create mode 100644 src/openai/types/webhooks/fine_tuning_job_succeeded_webhook_event.py create mode 100644 src/openai/types/webhooks/response_cancelled_webhook_event.py create mode 100644 src/openai/types/webhooks/response_completed_webhook_event.py create mode 100644 src/openai/types/webhooks/response_failed_webhook_event.py create mode 100644 src/openai/types/webhooks/response_incomplete_webhook_event.py create mode 100644 src/openai/types/webhooks/unwrap_webhook_event.py create mode 100644 tests/api_resources/test_webhooks.py diff --git a/.release-please-manifest.json b/.release-please-manifest.json index f18270d528..2a2ee2b8f3 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.91.0" + ".": "1.92.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 1e0182cf22..ebbf3ee296 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-ef4ecb19eb61e24c49d77fef769ee243e5279bc0bdbaee8d0f8dba4da8722559.yml -openapi_spec_hash: 1b8a9767c9f04e6865b06c41948cdc24 -config_hash: fd2af1d5eff0995bb7dc02ac9a34851d +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-cca460eaf5cc13e9d6e5293eb97aac53d66dc1385c691f74b768c97d165b6e8b.yml +openapi_spec_hash: 9ec43d443b3dd58ca5aa87eb0a7eb49f +config_hash: e74d6791681e3af1b548748ff47a22c2 diff --git a/CHANGELOG.md b/CHANGELOG.md index 14562edfac..60ab8eb6a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,25 @@ # Changelog +## 1.92.0 (2025-06-26) + +Full Changelog: [v1.91.0...v1.92.0](https://github.com/openai/openai-python/compare/v1.91.0...v1.92.0) + +### Features + +* **api:** webhook and deep research support ([d3bb116](https://github.com/openai/openai-python/commit/d3bb116f34f470502f902b88131deec43a953b12)) +* **client:** move stream and parse out of beta ([0e358ed](https://github.com/openai/openai-python/commit/0e358ed66b317038705fb38958a449d284f3cb88)) + + +### Bug Fixes + +* **ci:** release-doctor — report correct token name ([ff8c556](https://github.com/openai/openai-python/commit/ff8c5561e44e8a0902732b5934c97299d2c98d4e)) + + +### Chores + +* **internal:** add tests for breaking change detection ([710fe8f](https://github.com/openai/openai-python/commit/710fe8fd5f9e33730338341680152d3f2556dfa0)) +* **tests:** skip some failing tests on the latest python versions ([93ccc38](https://github.com/openai/openai-python/commit/93ccc38a8ef1575d77d33d031666d07d10e4af72)) + ## 1.91.0 (2025-06-23) Full Changelog: [v1.90.0...v1.91.0](https://github.com/openai/openai-python/compare/v1.90.0...v1.91.0) diff --git a/README.md b/README.md index 4861e4aaab..763428ddc8 100644 --- a/README.md +++ b/README.md @@ -406,6 +406,84 @@ client.files.create( The async client uses the exact same interface. If you pass a [`PathLike`](https://docs.python.org/3/library/os.html#os.PathLike) instance, the file contents will be read asynchronously automatically. +## Webhook Verification + +Verifying webhook signatures is _optional but encouraged_. + +### Parsing webhook payloads + +For most use cases, you will likely want to verify the webhook and parse the payload at the same time. To achieve this, we provide the method `client.webhooks.unwrap()`, which parses a webhook request and verifies that it was sent by OpenAI. This method will raise an error if the signature is invalid. + +Note that the `body` parameter must be the raw JSON string sent from the server (do not parse it first). The `.unwrap()` method will parse this JSON for you into an event object after verifying the webhook was sent from OpenAI. + +```python +from openai import OpenAI +from flask import Flask, request + +app = Flask(__name__) +client = OpenAI() # OPENAI_WEBHOOK_SECRET environment variable is used by default + + +@app.route("/webhook", methods=["POST"]) +def webhook(): + request_body = request.get_data(as_text=True) + + try: + event = client.webhooks.unwrap(request_body, request.headers) + + if event.type == "response.completed": + print("Response completed:", event.data) + elif event.type == "response.failed": + print("Response failed:", event.data) + else: + print("Unhandled event type:", event.type) + + return "ok" + except Exception as e: + print("Invalid signature:", e) + return "Invalid signature", 400 + + +if __name__ == "__main__": + app.run(port=8000) +``` + +### Verifying webhook payloads directly + +In some cases, you may want to verify the webhook separately from parsing the payload. If you prefer to handle these steps separately, we provide the method `client.webhooks.verify_signature()` to _only verify_ the signature of a webhook request. Like `.unwrap()`, this method will raise an error if the signature is invalid. + +Note that the `body` parameter must be the raw JSON string sent from the server (do not parse it first). You will then need to parse the body after verifying the signature. + +```python +import json +from openai import OpenAI +from flask import Flask, request + +app = Flask(__name__) +client = OpenAI() # OPENAI_WEBHOOK_SECRET environment variable is used by default + + +@app.route("/webhook", methods=["POST"]) +def webhook(): + request_body = request.get_data(as_text=True) + + try: + client.webhooks.verify_signature(request_body, request.headers) + + # Parse the body after verification + event = json.loads(request_body) + print("Verified event:", event) + + return "ok" + except Exception as e: + print("Invalid signature:", e) + return "Invalid signature", 400 + + +if __name__ == "__main__": + app.run(port=8000) +``` + ## Handling errors When the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `openai.APIConnectionError` is raised. diff --git a/api.md b/api.md index 25360d741e..abf0de481d 100644 --- a/api.md +++ b/api.md @@ -395,6 +395,35 @@ Methods: - client.vector_stores.file_batches.poll(\*args) -> VectorStoreFileBatch - client.vector_stores.file_batches.upload_and_poll(\*args) -> VectorStoreFileBatch +# Webhooks + +Types: + +```python +from openai.types.webhooks import ( + BatchCancelledWebhookEvent, + BatchCompletedWebhookEvent, + BatchExpiredWebhookEvent, + BatchFailedWebhookEvent, + EvalRunCanceledWebhookEvent, + EvalRunFailedWebhookEvent, + EvalRunSucceededWebhookEvent, + FineTuningJobCancelledWebhookEvent, + FineTuningJobFailedWebhookEvent, + FineTuningJobSucceededWebhookEvent, + ResponseCancelledWebhookEvent, + ResponseCompletedWebhookEvent, + ResponseFailedWebhookEvent, + ResponseIncompleteWebhookEvent, + UnwrapWebhookEvent, +) +``` + +Methods: + +- client.webhooks.unwrap(payload, headers, \*, secret) -> UnwrapWebhookEvent +- client.webhooks.verify_signature(payload, headers, \*, secret, tolerance) -> None + # Beta ## Realtime @@ -774,6 +803,7 @@ from openai.types.responses import ( ResponseWebSearchCallSearchingEvent, Tool, ToolChoiceFunction, + ToolChoiceMcp, ToolChoiceOptions, ToolChoiceTypes, WebSearchTool, diff --git a/bin/check-release-environment b/bin/check-release-environment index 2cc5ad6352..044ed525d1 100644 --- a/bin/check-release-environment +++ b/bin/check-release-environment @@ -7,7 +7,7 @@ if [ -z "${STAINLESS_API_KEY}" ]; then fi if [ -z "${PYPI_TOKEN}" ]; then - errors+=("The OPENAI_PYPI_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets.") + errors+=("The PYPI_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets.") fi lenErrors=${#errors[@]} diff --git a/examples/parsing.py b/examples/parsing.py index 17e5db52ec..906ce974c1 100644 --- a/examples/parsing.py +++ b/examples/parsing.py @@ -18,7 +18,7 @@ class MathResponse(BaseModel): client = OpenAI() -completion = client.beta.chat.completions.parse( +completion = client.chat.completions.parse( model="gpt-4o-2024-08-06", messages=[ {"role": "system", "content": "You are a helpful math tutor."}, diff --git a/examples/parsing_stream.py b/examples/parsing_stream.py index 6c6f078f77..1be7853098 100644 --- a/examples/parsing_stream.py +++ b/examples/parsing_stream.py @@ -18,7 +18,7 @@ class MathResponse(BaseModel): client = OpenAI() -with client.beta.chat.completions.stream( +with client.chat.completions.stream( model="gpt-4o-2024-08-06", messages=[ {"role": "system", "content": "You are a helpful math tutor."}, diff --git a/examples/parsing_tools.py b/examples/parsing_tools.py index c6065eeb7a..26921b1df6 100644 --- a/examples/parsing_tools.py +++ b/examples/parsing_tools.py @@ -57,7 +57,7 @@ class Query(BaseModel): client = OpenAI() -completion = client.beta.chat.completions.parse( +completion = client.chat.completions.parse( model="gpt-4o-2024-08-06", messages=[ { diff --git a/examples/parsing_tools_stream.py b/examples/parsing_tools_stream.py index eea6f6a43a..b7dcd3d230 100644 --- a/examples/parsing_tools_stream.py +++ b/examples/parsing_tools_stream.py @@ -15,7 +15,7 @@ class GetWeather(BaseModel): client = OpenAI() -with client.beta.chat.completions.stream( +with client.chat.completions.stream( model="gpt-4o-2024-08-06", messages=[ { diff --git a/helpers.md b/helpers.md index 77823fa750..21ad8ac2fb 100644 --- a/helpers.md +++ b/helpers.md @@ -2,7 +2,7 @@ The OpenAI API supports extracting JSON from the model with the `response_format` request param, for more details on the API, see [this guide](https://platform.openai.com/docs/guides/structured-outputs). -The SDK provides a `client.beta.chat.completions.parse()` method which is a wrapper over the `client.chat.completions.create()` that +The SDK provides a `client.chat.completions.parse()` method which is a wrapper over the `client.chat.completions.create()` that provides richer integrations with Python specific types & returns a `ParsedChatCompletion` object, which is a subclass of the standard `ChatCompletion` class. ## Auto-parsing response content with Pydantic models @@ -24,7 +24,7 @@ class MathResponse(BaseModel): final_answer: str client = OpenAI() -completion = client.beta.chat.completions.parse( +completion = client.chat.completions.parse( model="gpt-4o-2024-08-06", messages=[ {"role": "system", "content": "You are a helpful math tutor."}, @@ -44,6 +44,7 @@ else: ## Auto-parsing function tool calls The `.parse()` method will also automatically parse `function` tool calls if: + - You use the `openai.pydantic_function_tool()` helper method - You mark your tool schema with `"strict": True` @@ -96,7 +97,7 @@ class Query(BaseModel): order_by: OrderBy client = openai.OpenAI() -completion = client.beta.chat.completions.parse( +completion = client.chat.completions.parse( model="gpt-4o-2024-08-06", messages=[ { @@ -121,7 +122,7 @@ print(tool_call.function.parsed_arguments.table_name) ### Differences from `.create()` -The `beta.chat.completions.parse()` method imposes some additional restrictions on it's usage that `chat.completions.create()` does not. +The `chat.completions.parse()` method imposes some additional restrictions on it's usage that `chat.completions.create()` does not. - If the completion completes with `finish_reason` set to `length` or `content_filter`, the `LengthFinishReasonError` / `ContentFilterFinishReasonError` errors will be raised. - Only strict function tools can be passed, e.g. `{'type': 'function', 'function': {..., 'strict': True}}` @@ -132,7 +133,7 @@ OpenAI supports streaming responses when interacting with the [Chat Completion]( ## Chat Completions API -The SDK provides a `.beta.chat.completions.stream()` method that wraps the `.chat.completions.create(stream=True)` stream providing a more granular event API & automatic accumulation of each delta. +The SDK provides a `.chat.completions.stream()` method that wraps the `.chat.completions.create(stream=True)` stream providing a more granular event API & automatic accumulation of each delta. It also supports all aforementioned [parsing helpers](#structured-outputs-parsing-helpers). @@ -143,7 +144,7 @@ from openai import AsyncOpenAI client = AsyncOpenAI() -async with client.beta.chat.completions.stream( +async with client.chat.completions.stream( model='gpt-4o-2024-08-06', messages=[...], ) as stream: @@ -263,7 +264,7 @@ A handful of helper methods are provided on the stream class for additional conv Returns the accumulated `ParsedChatCompletion` object ```py -async with client.beta.chat.completions.stream(...) as stream: +async with client.chat.completions.stream(...) as stream: ... completion = await stream.get_final_completion() @@ -275,7 +276,7 @@ print(completion.choices[0].message) If you want to wait for the stream to complete, you can use the `.until_done()` method. ```py -async with client.beta.chat.completions.stream(...) as stream: +async with client.chat.completions.stream(...) as stream: await stream.until_done() # stream is now finished ``` diff --git a/pyproject.toml b/pyproject.toml index 1f2b8a6044..eb9008a3a6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.91.0" +version = "1.92.0" description = "The official Python library for the openai API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/openai/__init__.py b/src/openai/__init__.py index 5fb1520549..226fed9554 100644 --- a/src/openai/__init__.py +++ b/src/openai/__init__.py @@ -30,6 +30,7 @@ LengthFinishReasonError, UnprocessableEntityError, APIResponseValidationError, + InvalidWebhookSignatureError, ContentFilterFinishReasonError, ) from ._base_client import DefaultHttpxClient, DefaultAioHttpClient, DefaultAsyncHttpxClient @@ -62,6 +63,7 @@ "InternalServerError", "LengthFinishReasonError", "ContentFilterFinishReasonError", + "InvalidWebhookSignatureError", "Timeout", "RequestOptions", "Client", @@ -121,6 +123,8 @@ project: str | None = None +webhook_secret: str | None = None + base_url: str | _httpx.URL | None = None timeout: float | Timeout | None = DEFAULT_TIMEOUT @@ -183,6 +187,17 @@ def project(self, value: str | None) -> None: # type: ignore project = value + @property # type: ignore + @override + def webhook_secret(self) -> str | None: + return webhook_secret + + @webhook_secret.setter # type: ignore + def webhook_secret(self, value: str | None) -> None: # type: ignore + global webhook_secret + + webhook_secret = value + @property @override def base_url(self) -> _httpx.URL: @@ -335,6 +350,7 @@ def _load_client() -> OpenAI: # type: ignore[reportUnusedFunction] api_key=api_key, organization=organization, project=project, + webhook_secret=webhook_secret, base_url=base_url, timeout=timeout, max_retries=max_retries, @@ -363,6 +379,7 @@ def _reset_client() -> None: # type: ignore[reportUnusedFunction] models as models, batches as batches, uploads as uploads, + webhooks as webhooks, responses as responses, containers as containers, embeddings as embeddings, diff --git a/src/openai/_client.py b/src/openai/_client.py index 4ed9a2f52e..f3a83afec3 100644 --- a/src/openai/_client.py +++ b/src/openai/_client.py @@ -57,6 +57,7 @@ from .resources.images import Images, AsyncImages from .resources.models import Models, AsyncModels from .resources.batches import Batches, AsyncBatches + from .resources.webhooks import Webhooks, AsyncWebhooks from .resources.beta.beta import Beta, AsyncBeta from .resources.chat.chat import Chat, AsyncChat from .resources.embeddings import Embeddings, AsyncEmbeddings @@ -78,6 +79,7 @@ class OpenAI(SyncAPIClient): api_key: str organization: str | None project: str | None + webhook_secret: str | None websocket_base_url: str | httpx.URL | None """Base URL for WebSocket connections. @@ -93,6 +95,7 @@ def __init__( api_key: str | None = None, organization: str | None = None, project: str | None = None, + webhook_secret: str | None = None, base_url: str | httpx.URL | None = None, websocket_base_url: str | httpx.URL | None = None, timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN, @@ -119,6 +122,7 @@ def __init__( - `api_key` from `OPENAI_API_KEY` - `organization` from `OPENAI_ORG_ID` - `project` from `OPENAI_PROJECT_ID` + - `webhook_secret` from `OPENAI_WEBHOOK_SECRET` """ if api_key is None: api_key = os.environ.get("OPENAI_API_KEY") @@ -136,6 +140,10 @@ def __init__( project = os.environ.get("OPENAI_PROJECT_ID") self.project = project + if webhook_secret is None: + webhook_secret = os.environ.get("OPENAI_WEBHOOK_SECRET") + self.webhook_secret = webhook_secret + self.websocket_base_url = websocket_base_url if base_url is None: @@ -216,6 +224,12 @@ def vector_stores(self) -> VectorStores: return VectorStores(self) + @cached_property + def webhooks(self) -> Webhooks: + from .resources.webhooks import Webhooks + + return Webhooks(self) + @cached_property def beta(self) -> Beta: from .resources.beta import Beta @@ -288,6 +302,7 @@ def copy( api_key: str | None = None, organization: str | None = None, project: str | None = None, + webhook_secret: str | None = None, websocket_base_url: str | httpx.URL | None = None, base_url: str | httpx.URL | None = None, timeout: float | Timeout | None | NotGiven = NOT_GIVEN, @@ -325,6 +340,7 @@ def copy( api_key=api_key or self.api_key, organization=organization or self.organization, project=project or self.project, + webhook_secret=webhook_secret or self.webhook_secret, websocket_base_url=websocket_base_url or self.websocket_base_url, base_url=base_url or self.base_url, timeout=self.timeout if isinstance(timeout, NotGiven) else timeout, @@ -379,6 +395,7 @@ class AsyncOpenAI(AsyncAPIClient): api_key: str organization: str | None project: str | None + webhook_secret: str | None websocket_base_url: str | httpx.URL | None """Base URL for WebSocket connections. @@ -394,6 +411,7 @@ def __init__( api_key: str | None = None, organization: str | None = None, project: str | None = None, + webhook_secret: str | None = None, base_url: str | httpx.URL | None = None, websocket_base_url: str | httpx.URL | None = None, timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN, @@ -420,6 +438,7 @@ def __init__( - `api_key` from `OPENAI_API_KEY` - `organization` from `OPENAI_ORG_ID` - `project` from `OPENAI_PROJECT_ID` + - `webhook_secret` from `OPENAI_WEBHOOK_SECRET` """ if api_key is None: api_key = os.environ.get("OPENAI_API_KEY") @@ -437,6 +456,10 @@ def __init__( project = os.environ.get("OPENAI_PROJECT_ID") self.project = project + if webhook_secret is None: + webhook_secret = os.environ.get("OPENAI_WEBHOOK_SECRET") + self.webhook_secret = webhook_secret + self.websocket_base_url = websocket_base_url if base_url is None: @@ -517,6 +540,12 @@ def vector_stores(self) -> AsyncVectorStores: return AsyncVectorStores(self) + @cached_property + def webhooks(self) -> AsyncWebhooks: + from .resources.webhooks import AsyncWebhooks + + return AsyncWebhooks(self) + @cached_property def beta(self) -> AsyncBeta: from .resources.beta import AsyncBeta @@ -589,6 +618,7 @@ def copy( api_key: str | None = None, organization: str | None = None, project: str | None = None, + webhook_secret: str | None = None, websocket_base_url: str | httpx.URL | None = None, base_url: str | httpx.URL | None = None, timeout: float | Timeout | None | NotGiven = NOT_GIVEN, @@ -626,6 +656,7 @@ def copy( api_key=api_key or self.api_key, organization=organization or self.organization, project=project or self.project, + webhook_secret=webhook_secret or self.webhook_secret, websocket_base_url=websocket_base_url or self.websocket_base_url, base_url=base_url or self.base_url, timeout=self.timeout if isinstance(timeout, NotGiven) else timeout, diff --git a/src/openai/_exceptions.py b/src/openai/_exceptions.py index e326ed9578..09016dfedb 100644 --- a/src/openai/_exceptions.py +++ b/src/openai/_exceptions.py @@ -24,6 +24,7 @@ "InternalServerError", "LengthFinishReasonError", "ContentFilterFinishReasonError", + "InvalidWebhookSignatureError", ] @@ -154,3 +155,7 @@ def __init__(self) -> None: super().__init__( f"Could not parse response content as the request was rejected by the content filter", ) + + +class InvalidWebhookSignatureError(ValueError): + """Raised when a webhook signature is invalid, meaning the computed signature does not match the expected signature.""" diff --git a/src/openai/_module_client.py b/src/openai/_module_client.py index fb7c754917..a80e939300 100644 --- a/src/openai/_module_client.py +++ b/src/openai/_module_client.py @@ -10,6 +10,7 @@ from .resources.images import Images from .resources.models import Models from .resources.batches import Batches + from .resources.webhooks import Webhooks from .resources.beta.beta import Beta from .resources.chat.chat import Chat from .resources.embeddings import Embeddings @@ -81,6 +82,12 @@ def __load__(self) -> Uploads: return _load_client().uploads +class WebhooksProxy(LazyProxy["Webhooks"]): + @override + def __load__(self) -> Webhooks: + return _load_client().webhooks + + class ResponsesProxy(LazyProxy["Responses"]): @override def __load__(self) -> Responses: @@ -132,6 +139,7 @@ def __load__(self) -> VectorStores: models: Models = ModelsProxy().__as_proxied__() batches: Batches = BatchesProxy().__as_proxied__() uploads: Uploads = UploadsProxy().__as_proxied__() +webhooks: Webhooks = WebhooksProxy().__as_proxied__() responses: Responses = ResponsesProxy().__as_proxied__() embeddings: Embeddings = EmbeddingsProxy().__as_proxied__() containers: Containers = ContainersProxy().__as_proxied__() diff --git a/src/openai/_version.py b/src/openai/_version.py index d1cad1dd01..64bc847523 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.91.0" # x-release-please-version +__version__ = "1.92.0" # x-release-please-version diff --git a/src/openai/lib/azure.py b/src/openai/lib/azure.py index 655dd71d4c..a994e4256c 100644 --- a/src/openai/lib/azure.py +++ b/src/openai/lib/azure.py @@ -98,6 +98,7 @@ def __init__( azure_ad_token: str | None = None, azure_ad_token_provider: AzureADTokenProvider | None = None, organization: str | None = None, + webhook_secret: str | None = None, websocket_base_url: str | httpx.URL | None = None, timeout: float | Timeout | None | NotGiven = NOT_GIVEN, max_retries: int = DEFAULT_MAX_RETRIES, @@ -117,6 +118,7 @@ def __init__( azure_ad_token: str | None = None, azure_ad_token_provider: AzureADTokenProvider | None = None, organization: str | None = None, + webhook_secret: str | None = None, websocket_base_url: str | httpx.URL | None = None, timeout: float | Timeout | None | NotGiven = NOT_GIVEN, max_retries: int = DEFAULT_MAX_RETRIES, @@ -136,6 +138,7 @@ def __init__( azure_ad_token: str | None = None, azure_ad_token_provider: AzureADTokenProvider | None = None, organization: str | None = None, + webhook_secret: str | None = None, websocket_base_url: str | httpx.URL | None = None, timeout: float | Timeout | None | NotGiven = NOT_GIVEN, max_retries: int = DEFAULT_MAX_RETRIES, @@ -156,6 +159,7 @@ def __init__( azure_ad_token_provider: AzureADTokenProvider | None = None, organization: str | None = None, project: str | None = None, + webhook_secret: str | None = None, websocket_base_url: str | httpx.URL | None = None, base_url: str | None = None, timeout: float | Timeout | None | NotGiven = NOT_GIVEN, @@ -234,6 +238,7 @@ def __init__( api_key=api_key, organization=organization, project=project, + webhook_secret=webhook_secret, base_url=base_url, timeout=timeout, max_retries=max_retries, @@ -256,6 +261,7 @@ def copy( api_key: str | None = None, organization: str | None = None, project: str | None = None, + webhook_secret: str | None = None, websocket_base_url: str | httpx.URL | None = None, api_version: str | None = None, azure_ad_token: str | None = None, @@ -277,6 +283,7 @@ def copy( api_key=api_key, organization=organization, project=project, + webhook_secret=webhook_secret, websocket_base_url=websocket_base_url, base_url=base_url, timeout=timeout, @@ -370,6 +377,7 @@ def __init__( azure_ad_token_provider: AsyncAzureADTokenProvider | None = None, organization: str | None = None, project: str | None = None, + webhook_secret: str | None = None, websocket_base_url: str | httpx.URL | None = None, timeout: float | Timeout | None | NotGiven = NOT_GIVEN, max_retries: int = DEFAULT_MAX_RETRIES, @@ -390,6 +398,7 @@ def __init__( azure_ad_token_provider: AsyncAzureADTokenProvider | None = None, organization: str | None = None, project: str | None = None, + webhook_secret: str | None = None, websocket_base_url: str | httpx.URL | None = None, timeout: float | Timeout | None | NotGiven = NOT_GIVEN, max_retries: int = DEFAULT_MAX_RETRIES, @@ -410,6 +419,7 @@ def __init__( azure_ad_token_provider: AsyncAzureADTokenProvider | None = None, organization: str | None = None, project: str | None = None, + webhook_secret: str | None = None, websocket_base_url: str | httpx.URL | None = None, timeout: float | Timeout | None | NotGiven = NOT_GIVEN, max_retries: int = DEFAULT_MAX_RETRIES, @@ -430,6 +440,7 @@ def __init__( azure_ad_token_provider: AsyncAzureADTokenProvider | None = None, organization: str | None = None, project: str | None = None, + webhook_secret: str | None = None, base_url: str | None = None, websocket_base_url: str | httpx.URL | None = None, timeout: float | Timeout | None | NotGiven = NOT_GIVEN, @@ -508,6 +519,7 @@ def __init__( api_key=api_key, organization=organization, project=project, + webhook_secret=webhook_secret, base_url=base_url, timeout=timeout, max_retries=max_retries, @@ -530,6 +542,7 @@ def copy( api_key: str | None = None, organization: str | None = None, project: str | None = None, + webhook_secret: str | None = None, websocket_base_url: str | httpx.URL | None = None, api_version: str | None = None, azure_ad_token: str | None = None, @@ -551,6 +564,7 @@ def copy( api_key=api_key, organization=organization, project=project, + webhook_secret=webhook_secret, websocket_base_url=websocket_base_url, base_url=base_url, timeout=timeout, diff --git a/src/openai/lib/streaming/chat/_completions.py b/src/openai/lib/streaming/chat/_completions.py index a7b70c32d3..2cf37efeae 100644 --- a/src/openai/lib/streaming/chat/_completions.py +++ b/src/openai/lib/streaming/chat/_completions.py @@ -128,7 +128,7 @@ class ChatCompletionStreamManager(Generic[ResponseFormatT]): Usage: ```py - with client.beta.chat.completions.stream(...) as stream: + with client.chat.completions.stream(...) as stream: for event in stream: ... ``` @@ -251,7 +251,7 @@ class AsyncChatCompletionStreamManager(Generic[ResponseFormatT]): Usage: ```py - async with client.beta.chat.completions.stream(...) as stream: + async with client.chat.completions.stream(...) as stream: for event in stream: ... ``` diff --git a/src/openai/resources/beta/beta.py b/src/openai/resources/beta/beta.py index 62fc8258b9..4feaaab44b 100644 --- a/src/openai/resources/beta/beta.py +++ b/src/openai/resources/beta/beta.py @@ -3,7 +3,6 @@ from __future__ import annotations from ..._compat import cached_property -from .chat.chat import Chat, AsyncChat from .assistants import ( Assistants, AsyncAssistants, @@ -21,6 +20,7 @@ ThreadsWithStreamingResponse, AsyncThreadsWithStreamingResponse, ) +from ...resources.chat import Chat, AsyncChat from .realtime.realtime import ( Realtime, AsyncRealtime, diff --git a/src/openai/resources/beta/chat/__init__.py b/src/openai/resources/beta/chat/__init__.py deleted file mode 100644 index 072d7867a5..0000000000 --- a/src/openai/resources/beta/chat/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .chat import Chat, AsyncChat -from .completions import Completions, AsyncCompletions - -__all__ = [ - "Completions", - "AsyncCompletions", - "Chat", - "AsyncChat", -] diff --git a/src/openai/resources/beta/chat/chat.py b/src/openai/resources/beta/chat/chat.py deleted file mode 100644 index 6afdcea381..0000000000 --- a/src/openai/resources/beta/chat/chat.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from ...._compat import cached_property -from .completions import Completions, AsyncCompletions -from ...._resource import SyncAPIResource, AsyncAPIResource - -__all__ = ["Chat", "AsyncChat"] - - -class Chat(SyncAPIResource): - @cached_property - def completions(self) -> Completions: - return Completions(self._client) - - -class AsyncChat(AsyncAPIResource): - @cached_property - def completions(self) -> AsyncCompletions: - return AsyncCompletions(self._client) diff --git a/src/openai/resources/beta/chat/completions.py b/src/openai/resources/beta/chat/completions.py deleted file mode 100644 index 871c4ab48a..0000000000 --- a/src/openai/resources/beta/chat/completions.py +++ /dev/null @@ -1,634 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, List, Type, Union, Iterable, Optional, cast -from functools import partial -from typing_extensions import Literal - -import httpx - -from .... import _legacy_response -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ...._utils import maybe_transform, async_maybe_transform -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ...._streaming import Stream -from ....types.chat import completion_create_params -from ...._base_client import make_request_options -from ....lib._parsing import ( - ResponseFormatT, - validate_input_tools as _validate_input_tools, - parse_chat_completion as _parse_chat_completion, - type_to_response_format_param as _type_to_response_format, -) -from ....types.chat_model import ChatModel -from ....lib.streaming.chat import ChatCompletionStreamManager, AsyncChatCompletionStreamManager -from ....types.shared_params import Metadata, ReasoningEffort -from ....types.chat.chat_completion import ChatCompletion -from ....types.chat.chat_completion_chunk import ChatCompletionChunk -from ....types.chat.parsed_chat_completion import ParsedChatCompletion -from ....types.chat.chat_completion_tool_param import ChatCompletionToolParam -from ....types.chat.chat_completion_audio_param import ChatCompletionAudioParam -from ....types.chat.chat_completion_message_param import ChatCompletionMessageParam -from ....types.chat.chat_completion_stream_options_param import ChatCompletionStreamOptionsParam -from ....types.chat.chat_completion_prediction_content_param import ChatCompletionPredictionContentParam -from ....types.chat.chat_completion_tool_choice_option_param import ChatCompletionToolChoiceOptionParam - -__all__ = ["Completions", "AsyncCompletions"] - - -class Completions(SyncAPIResource): - @cached_property - def with_raw_response(self) -> CompletionsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return the - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return CompletionsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> CompletionsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return CompletionsWithStreamingResponse(self) - - def parse( - self, - *, - messages: Iterable[ChatCompletionMessageParam], - model: Union[str, ChatModel], - audio: Optional[ChatCompletionAudioParam] | NotGiven = NOT_GIVEN, - response_format: type[ResponseFormatT] | NotGiven = NOT_GIVEN, - frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, - function_call: completion_create_params.FunctionCall | NotGiven = NOT_GIVEN, - functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, - logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, - logprobs: Optional[bool] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - modalities: Optional[List[Literal["text", "audio"]]] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, - presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, - tools: Iterable[ChatCompletionToolParam] | NotGiven = NOT_GIVEN, - top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, - web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> ParsedChatCompletion[ResponseFormatT]: - """Wrapper over the `client.chat.completions.create()` method that provides richer integrations with Python specific types - & returns a `ParsedChatCompletion` object, which is a subclass of the standard `ChatCompletion` class. - - You can pass a pydantic model to this method and it will automatically convert the model - into a JSON schema, send it to the API and parse the response content back into the given model. - - This method will also automatically parse `function` tool calls if: - - You use the `openai.pydantic_function_tool()` helper method - - You mark your tool schema with `"strict": True` - - Example usage: - ```py - from pydantic import BaseModel - from openai import OpenAI - - - class Step(BaseModel): - explanation: str - output: str - - - class MathResponse(BaseModel): - steps: List[Step] - final_answer: str - - - client = OpenAI() - completion = client.beta.chat.completions.parse( - model="gpt-4o-2024-08-06", - messages=[ - {"role": "system", "content": "You are a helpful math tutor."}, - {"role": "user", "content": "solve 8x + 31 = 2"}, - ], - response_format=MathResponse, - ) - - message = completion.choices[0].message - if message.parsed: - print(message.parsed.steps) - print("answer: ", message.parsed.final_answer) - ``` - """ - _validate_input_tools(tools) - - extra_headers = { - "X-Stainless-Helper-Method": "beta.chat.completions.parse", - **(extra_headers or {}), - } - - def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseFormatT]: - return _parse_chat_completion( - response_format=response_format, - chat_completion=raw_completion, - input_tools=tools, - ) - - return self._post( - "/chat/completions", - body=maybe_transform( - { - "messages": messages, - "model": model, - "audio": audio, - "frequency_penalty": frequency_penalty, - "function_call": function_call, - "functions": functions, - "logit_bias": logit_bias, - "logprobs": logprobs, - "max_completion_tokens": max_completion_tokens, - "max_tokens": max_tokens, - "metadata": metadata, - "modalities": modalities, - "n": n, - "parallel_tool_calls": parallel_tool_calls, - "prediction": prediction, - "presence_penalty": presence_penalty, - "reasoning_effort": reasoning_effort, - "response_format": _type_to_response_format(response_format), - "seed": seed, - "service_tier": service_tier, - "stop": stop, - "store": store, - "stream": False, - "stream_options": stream_options, - "temperature": temperature, - "tool_choice": tool_choice, - "tools": tools, - "top_logprobs": top_logprobs, - "top_p": top_p, - "user": user, - "web_search_options": web_search_options, - }, - completion_create_params.CompletionCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - post_parser=parser, - ), - # we turn the `ChatCompletion` instance into a `ParsedChatCompletion` - # in the `parser` function above - cast_to=cast(Type[ParsedChatCompletion[ResponseFormatT]], ChatCompletion), - stream=False, - ) - - def stream( - self, - *, - messages: Iterable[ChatCompletionMessageParam], - model: Union[str, ChatModel], - audio: Optional[ChatCompletionAudioParam] | NotGiven = NOT_GIVEN, - response_format: completion_create_params.ResponseFormat | type[ResponseFormatT] | NotGiven = NOT_GIVEN, - frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, - function_call: completion_create_params.FunctionCall | NotGiven = NOT_GIVEN, - functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, - logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, - logprobs: Optional[bool] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - modalities: Optional[List[Literal["text", "audio"]]] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, - presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, - tools: Iterable[ChatCompletionToolParam] | NotGiven = NOT_GIVEN, - top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, - web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> ChatCompletionStreamManager[ResponseFormatT]: - """Wrapper over the `client.chat.completions.create(stream=True)` method that provides a more granular event API - and automatic accumulation of each delta. - - This also supports all of the parsing utilities that `.parse()` does. - - Unlike `.create(stream=True)`, the `.stream()` method requires usage within a context manager to prevent accidental leakage of the response: - - ```py - with client.beta.chat.completions.stream( - model="gpt-4o-2024-08-06", - messages=[...], - ) as stream: - for event in stream: - if event.type == "content.delta": - print(event.delta, flush=True, end="") - ``` - - When the context manager is entered, a `ChatCompletionStream` instance is returned which, like `.create(stream=True)` is an iterator. The full list of events that are yielded by the iterator are outlined in [these docs](https://github.com/openai/openai-python/blob/main/helpers.md#chat-completions-events). - - When the context manager exits, the response will be closed, however the `stream` instance is still available outside - the context manager. - """ - extra_headers = { - "X-Stainless-Helper-Method": "beta.chat.completions.stream", - **(extra_headers or {}), - } - - api_request: partial[Stream[ChatCompletionChunk]] = partial( - self._client.chat.completions.create, - messages=messages, - model=model, - audio=audio, - stream=True, - response_format=_type_to_response_format(response_format), - frequency_penalty=frequency_penalty, - function_call=function_call, - functions=functions, - logit_bias=logit_bias, - logprobs=logprobs, - max_completion_tokens=max_completion_tokens, - max_tokens=max_tokens, - metadata=metadata, - modalities=modalities, - n=n, - parallel_tool_calls=parallel_tool_calls, - prediction=prediction, - presence_penalty=presence_penalty, - reasoning_effort=reasoning_effort, - seed=seed, - service_tier=service_tier, - store=store, - stop=stop, - stream_options=stream_options, - temperature=temperature, - tool_choice=tool_choice, - tools=tools, - top_logprobs=top_logprobs, - top_p=top_p, - user=user, - web_search_options=web_search_options, - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - ) - return ChatCompletionStreamManager( - api_request, - response_format=response_format, - input_tools=tools, - ) - - -class AsyncCompletions(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncCompletionsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return the - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncCompletionsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncCompletionsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncCompletionsWithStreamingResponse(self) - - async def parse( - self, - *, - messages: Iterable[ChatCompletionMessageParam], - model: Union[str, ChatModel], - audio: Optional[ChatCompletionAudioParam] | NotGiven = NOT_GIVEN, - response_format: type[ResponseFormatT] | NotGiven = NOT_GIVEN, - frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, - function_call: completion_create_params.FunctionCall | NotGiven = NOT_GIVEN, - functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, - logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, - logprobs: Optional[bool] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - modalities: Optional[List[Literal["text", "audio"]]] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, - presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, - tools: Iterable[ChatCompletionToolParam] | NotGiven = NOT_GIVEN, - top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, - web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> ParsedChatCompletion[ResponseFormatT]: - """Wrapper over the `client.chat.completions.create()` method that provides richer integrations with Python specific types - & returns a `ParsedChatCompletion` object, which is a subclass of the standard `ChatCompletion` class. - - You can pass a pydantic model to this method and it will automatically convert the model - into a JSON schema, send it to the API and parse the response content back into the given model. - - This method will also automatically parse `function` tool calls if: - - You use the `openai.pydantic_function_tool()` helper method - - You mark your tool schema with `"strict": True` - - Example usage: - ```py - from pydantic import BaseModel - from openai import AsyncOpenAI - - - class Step(BaseModel): - explanation: str - output: str - - - class MathResponse(BaseModel): - steps: List[Step] - final_answer: str - - - client = AsyncOpenAI() - completion = await client.beta.chat.completions.parse( - model="gpt-4o-2024-08-06", - messages=[ - {"role": "system", "content": "You are a helpful math tutor."}, - {"role": "user", "content": "solve 8x + 31 = 2"}, - ], - response_format=MathResponse, - ) - - message = completion.choices[0].message - if message.parsed: - print(message.parsed.steps) - print("answer: ", message.parsed.final_answer) - ``` - """ - _validate_input_tools(tools) - - extra_headers = { - "X-Stainless-Helper-Method": "beta.chat.completions.parse", - **(extra_headers or {}), - } - - def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseFormatT]: - return _parse_chat_completion( - response_format=response_format, - chat_completion=raw_completion, - input_tools=tools, - ) - - return await self._post( - "/chat/completions", - body=await async_maybe_transform( - { - "messages": messages, - "model": model, - "audio": audio, - "frequency_penalty": frequency_penalty, - "function_call": function_call, - "functions": functions, - "logit_bias": logit_bias, - "logprobs": logprobs, - "max_completion_tokens": max_completion_tokens, - "max_tokens": max_tokens, - "metadata": metadata, - "modalities": modalities, - "n": n, - "parallel_tool_calls": parallel_tool_calls, - "prediction": prediction, - "presence_penalty": presence_penalty, - "reasoning_effort": reasoning_effort, - "response_format": _type_to_response_format(response_format), - "seed": seed, - "service_tier": service_tier, - "store": store, - "stop": stop, - "stream": False, - "stream_options": stream_options, - "temperature": temperature, - "tool_choice": tool_choice, - "tools": tools, - "top_logprobs": top_logprobs, - "top_p": top_p, - "user": user, - "web_search_options": web_search_options, - }, - completion_create_params.CompletionCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - post_parser=parser, - ), - # we turn the `ChatCompletion` instance into a `ParsedChatCompletion` - # in the `parser` function above - cast_to=cast(Type[ParsedChatCompletion[ResponseFormatT]], ChatCompletion), - stream=False, - ) - - def stream( - self, - *, - messages: Iterable[ChatCompletionMessageParam], - model: Union[str, ChatModel], - audio: Optional[ChatCompletionAudioParam] | NotGiven = NOT_GIVEN, - response_format: completion_create_params.ResponseFormat | type[ResponseFormatT] | NotGiven = NOT_GIVEN, - frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, - function_call: completion_create_params.FunctionCall | NotGiven = NOT_GIVEN, - functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, - logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, - logprobs: Optional[bool] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - modalities: Optional[List[Literal["text", "audio"]]] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, - presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, - tools: Iterable[ChatCompletionToolParam] | NotGiven = NOT_GIVEN, - top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, - web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncChatCompletionStreamManager[ResponseFormatT]: - """Wrapper over the `client.chat.completions.create(stream=True)` method that provides a more granular event API - and automatic accumulation of each delta. - - This also supports all of the parsing utilities that `.parse()` does. - - Unlike `.create(stream=True)`, the `.stream()` method requires usage within a context manager to prevent accidental leakage of the response: - - ```py - async with client.beta.chat.completions.stream( - model="gpt-4o-2024-08-06", - messages=[...], - ) as stream: - async for event in stream: - if event.type == "content.delta": - print(event.delta, flush=True, end="") - ``` - - When the context manager is entered, an `AsyncChatCompletionStream` instance is returned which, like `.create(stream=True)` is an async iterator. The full list of events that are yielded by the iterator are outlined in [these docs](https://github.com/openai/openai-python/blob/main/helpers.md#chat-completions-events). - - When the context manager exits, the response will be closed, however the `stream` instance is still available outside - the context manager. - """ - _validate_input_tools(tools) - - extra_headers = { - "X-Stainless-Helper-Method": "beta.chat.completions.stream", - **(extra_headers or {}), - } - - api_request = self._client.chat.completions.create( - messages=messages, - model=model, - audio=audio, - stream=True, - response_format=_type_to_response_format(response_format), - frequency_penalty=frequency_penalty, - function_call=function_call, - functions=functions, - logit_bias=logit_bias, - logprobs=logprobs, - max_completion_tokens=max_completion_tokens, - max_tokens=max_tokens, - metadata=metadata, - modalities=modalities, - n=n, - parallel_tool_calls=parallel_tool_calls, - prediction=prediction, - presence_penalty=presence_penalty, - reasoning_effort=reasoning_effort, - seed=seed, - service_tier=service_tier, - stop=stop, - store=store, - stream_options=stream_options, - temperature=temperature, - tool_choice=tool_choice, - tools=tools, - top_logprobs=top_logprobs, - top_p=top_p, - user=user, - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - web_search_options=web_search_options, - ) - return AsyncChatCompletionStreamManager( - api_request, - response_format=response_format, - input_tools=tools, - ) - - -class CompletionsWithRawResponse: - def __init__(self, completions: Completions) -> None: - self._completions = completions - - self.parse = _legacy_response.to_raw_response_wrapper( - completions.parse, - ) - - -class AsyncCompletionsWithRawResponse: - def __init__(self, completions: AsyncCompletions) -> None: - self._completions = completions - - self.parse = _legacy_response.async_to_raw_response_wrapper( - completions.parse, - ) - - -class CompletionsWithStreamingResponse: - def __init__(self, completions: Completions) -> None: - self._completions = completions - - self.parse = to_streamed_response_wrapper( - completions.parse, - ) - - -class AsyncCompletionsWithStreamingResponse: - def __init__(self, completions: AsyncCompletions) -> None: - self._completions = completions - - self.parse = async_to_streamed_response_wrapper( - completions.parse, - ) diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index a6b89fc833..2a5622b092 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -3,7 +3,8 @@ from __future__ import annotations import inspect -from typing import Dict, List, Union, Iterable, Optional +from typing import Dict, List, Type, Union, Iterable, Optional, cast +from functools import partial from typing_extensions import Literal, overload import httpx @@ -32,11 +33,19 @@ completion_update_params, ) from ...._base_client import AsyncPaginator, make_request_options +from ....lib._parsing import ( + ResponseFormatT, + validate_input_tools as _validate_input_tools, + parse_chat_completion as _parse_chat_completion, + type_to_response_format_param as _type_to_response_format, +) +from ....lib.streaming.chat import ChatCompletionStreamManager, AsyncChatCompletionStreamManager from ....types.shared.chat_model import ChatModel from ....types.chat.chat_completion import ChatCompletion from ....types.shared_params.metadata import Metadata from ....types.shared.reasoning_effort import ReasoningEffort from ....types.chat.chat_completion_chunk import ChatCompletionChunk +from ....types.chat.parsed_chat_completion import ParsedChatCompletion from ....types.chat.chat_completion_deleted import ChatCompletionDeleted from ....types.chat.chat_completion_tool_param import ChatCompletionToolParam from ....types.chat.chat_completion_audio_param import ChatCompletionAudioParam @@ -72,6 +81,153 @@ def with_streaming_response(self) -> CompletionsWithStreamingResponse: """ return CompletionsWithStreamingResponse(self) + def parse( + self, + *, + messages: Iterable[ChatCompletionMessageParam], + model: Union[str, ChatModel], + audio: Optional[ChatCompletionAudioParam] | NotGiven = NOT_GIVEN, + response_format: type[ResponseFormatT] | NotGiven = NOT_GIVEN, + frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, + function_call: completion_create_params.FunctionCall | NotGiven = NOT_GIVEN, + functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, + logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, + logprobs: Optional[bool] | NotGiven = NOT_GIVEN, + max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, + max_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + modalities: Optional[List[Literal["text", "audio"]]] | NotGiven = NOT_GIVEN, + n: Optional[int] | NotGiven = NOT_GIVEN, + parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, + presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, + seed: Optional[int] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, + stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, + stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, + temperature: Optional[float] | NotGiven = NOT_GIVEN, + tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, + tools: Iterable[ChatCompletionToolParam] | NotGiven = NOT_GIVEN, + top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, + top_p: Optional[float] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ParsedChatCompletion[ResponseFormatT]: + """Wrapper over the `client.chat.completions.create()` method that provides richer integrations with Python specific types + & returns a `ParsedChatCompletion` object, which is a subclass of the standard `ChatCompletion` class. + + You can pass a pydantic model to this method and it will automatically convert the model + into a JSON schema, send it to the API and parse the response content back into the given model. + + This method will also automatically parse `function` tool calls if: + - You use the `openai.pydantic_function_tool()` helper method + - You mark your tool schema with `"strict": True` + + Example usage: + ```py + from pydantic import BaseModel + from openai import OpenAI + + + class Step(BaseModel): + explanation: str + output: str + + + class MathResponse(BaseModel): + steps: List[Step] + final_answer: str + + + client = OpenAI() + completion = client.chat.completions.parse( + model="gpt-4o-2024-08-06", + messages=[ + {"role": "system", "content": "You are a helpful math tutor."}, + {"role": "user", "content": "solve 8x + 31 = 2"}, + ], + response_format=MathResponse, + ) + + message = completion.choices[0].message + if message.parsed: + print(message.parsed.steps) + print("answer: ", message.parsed.final_answer) + ``` + """ + _validate_input_tools(tools) + + extra_headers = { + "X-Stainless-Helper-Method": "chat.completions.parse", + **(extra_headers or {}), + } + + def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseFormatT]: + return _parse_chat_completion( + response_format=response_format, + chat_completion=raw_completion, + input_tools=tools, + ) + + return self._post( + "/chat/completions", + body=maybe_transform( + { + "messages": messages, + "model": model, + "audio": audio, + "frequency_penalty": frequency_penalty, + "function_call": function_call, + "functions": functions, + "logit_bias": logit_bias, + "logprobs": logprobs, + "max_completion_tokens": max_completion_tokens, + "max_tokens": max_tokens, + "metadata": metadata, + "modalities": modalities, + "n": n, + "parallel_tool_calls": parallel_tool_calls, + "prediction": prediction, + "presence_penalty": presence_penalty, + "reasoning_effort": reasoning_effort, + "response_format": _type_to_response_format(response_format), + "seed": seed, + "service_tier": service_tier, + "stop": stop, + "store": store, + "stream": False, + "stream_options": stream_options, + "temperature": temperature, + "tool_choice": tool_choice, + "tools": tools, + "top_logprobs": top_logprobs, + "top_p": top_p, + "user": user, + "web_search_options": web_search_options, + }, + completion_create_params.CompletionCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=parser, + ), + # we turn the `ChatCompletion` instance into a `ParsedChatCompletion` + # in the `parser` function above + cast_to=cast(Type[ParsedChatCompletion[ResponseFormatT]], ChatCompletion), + stream=False, + ) + @overload def create( self, @@ -95,7 +251,7 @@ def create( reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, @@ -256,23 +412,23 @@ def create( should refer to the `system_fingerprint` response parameter to monitor changes in the backend. - service_tier: Specifies the latency tier to use for processing the request. This parameter is - relevant for customers subscribed to the scale tier service: - - - If set to 'auto', and the Project is Scale tier enabled, the system will - utilize scale tier credits until they are exhausted. - - If set to 'auto', and the Project is not Scale tier enabled, the request will - be processed using the default service tier with a lower uptime SLA and no - latency guarantee. - - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarantee. - - If set to 'flex', the request will be processed with the Flex Processing - service tier. - [Learn more](https://platform.openai.com/docs/guides/flex-processing). + service_tier: Specifies the processing type used for serving the request. + + - If set to 'auto', then the request will be processed with the service tier + configured in the Project settings. Unless otherwise configured, the Project + will use 'default'. + - If set to 'default', then the requset will be processed with the standard + pricing and performance for the selected model. + - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or + 'priority', then the request will be processed with the corresponding service + tier. [Contact sales](https://openai.com/contact-sales) to learn more about + Priority processing. - When not set, the default behavior is 'auto'. - When this parameter is set, the response body will include the `service_tier` - utilized. + When the `service_tier` parameter is set, the response body will include the + `service_tier` value based on the processing mode actually used to serve the + request. This response value may be different from the value set in the + parameter. stop: Not supported with latest reasoning models `o3` and `o4-mini`. @@ -283,6 +439,8 @@ def create( our [model distillation](https://platform.openai.com/docs/guides/distillation) or [evals](https://platform.openai.com/docs/guides/evals) products. + Supports text and image inputs. Note: image inputs over 10MB will be dropped. + stream: If set to true, the model response data will be streamed to the client as it is generated using [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). @@ -365,7 +523,7 @@ def create( reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, @@ -534,23 +692,23 @@ def create( should refer to the `system_fingerprint` response parameter to monitor changes in the backend. - service_tier: Specifies the latency tier to use for processing the request. This parameter is - relevant for customers subscribed to the scale tier service: - - - If set to 'auto', and the Project is Scale tier enabled, the system will - utilize scale tier credits until they are exhausted. - - If set to 'auto', and the Project is not Scale tier enabled, the request will - be processed using the default service tier with a lower uptime SLA and no - latency guarantee. - - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarantee. - - If set to 'flex', the request will be processed with the Flex Processing - service tier. - [Learn more](https://platform.openai.com/docs/guides/flex-processing). + service_tier: Specifies the processing type used for serving the request. + + - If set to 'auto', then the request will be processed with the service tier + configured in the Project settings. Unless otherwise configured, the Project + will use 'default'. + - If set to 'default', then the requset will be processed with the standard + pricing and performance for the selected model. + - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or + 'priority', then the request will be processed with the corresponding service + tier. [Contact sales](https://openai.com/contact-sales) to learn more about + Priority processing. - When not set, the default behavior is 'auto'. - When this parameter is set, the response body will include the `service_tier` - utilized. + When the `service_tier` parameter is set, the response body will include the + `service_tier` value based on the processing mode actually used to serve the + request. This response value may be different from the value set in the + parameter. stop: Not supported with latest reasoning models `o3` and `o4-mini`. @@ -561,6 +719,8 @@ def create( our [model distillation](https://platform.openai.com/docs/guides/distillation) or [evals](https://platform.openai.com/docs/guides/evals) products. + Supports text and image inputs. Note: image inputs over 10MB will be dropped. + stream_options: Options for streaming response. Only set this when you set `stream: true`. temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will @@ -634,7 +794,7 @@ def create( reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, @@ -803,23 +963,23 @@ def create( should refer to the `system_fingerprint` response parameter to monitor changes in the backend. - service_tier: Specifies the latency tier to use for processing the request. This parameter is - relevant for customers subscribed to the scale tier service: - - - If set to 'auto', and the Project is Scale tier enabled, the system will - utilize scale tier credits until they are exhausted. - - If set to 'auto', and the Project is not Scale tier enabled, the request will - be processed using the default service tier with a lower uptime SLA and no - latency guarantee. - - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarantee. - - If set to 'flex', the request will be processed with the Flex Processing - service tier. - [Learn more](https://platform.openai.com/docs/guides/flex-processing). + service_tier: Specifies the processing type used for serving the request. + + - If set to 'auto', then the request will be processed with the service tier + configured in the Project settings. Unless otherwise configured, the Project + will use 'default'. + - If set to 'default', then the requset will be processed with the standard + pricing and performance for the selected model. + - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or + 'priority', then the request will be processed with the corresponding service + tier. [Contact sales](https://openai.com/contact-sales) to learn more about + Priority processing. - When not set, the default behavior is 'auto'. - When this parameter is set, the response body will include the `service_tier` - utilized. + When the `service_tier` parameter is set, the response body will include the + `service_tier` value based on the processing mode actually used to serve the + request. This response value may be different from the value set in the + parameter. stop: Not supported with latest reasoning models `o3` and `o4-mini`. @@ -830,6 +990,8 @@ def create( our [model distillation](https://platform.openai.com/docs/guides/distillation) or [evals](https://platform.openai.com/docs/guides/evals) products. + Supports text and image inputs. Note: image inputs over 10MB will be dropped. + stream_options: Options for streaming response. Only set this when you set `stream: true`. temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will @@ -902,7 +1064,7 @@ def create( reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, @@ -1150,6 +1312,117 @@ def delete( cast_to=ChatCompletionDeleted, ) + def stream( + self, + *, + messages: Iterable[ChatCompletionMessageParam], + model: Union[str, ChatModel], + audio: Optional[ChatCompletionAudioParam] | NotGiven = NOT_GIVEN, + response_format: completion_create_params.ResponseFormat | type[ResponseFormatT] | NotGiven = NOT_GIVEN, + frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, + function_call: completion_create_params.FunctionCall | NotGiven = NOT_GIVEN, + functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, + logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, + logprobs: Optional[bool] | NotGiven = NOT_GIVEN, + max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, + max_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + modalities: Optional[List[Literal["text", "audio"]]] | NotGiven = NOT_GIVEN, + n: Optional[int] | NotGiven = NOT_GIVEN, + parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, + presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, + seed: Optional[int] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, + stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, + stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, + temperature: Optional[float] | NotGiven = NOT_GIVEN, + tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, + tools: Iterable[ChatCompletionToolParam] | NotGiven = NOT_GIVEN, + top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, + top_p: Optional[float] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ChatCompletionStreamManager[ResponseFormatT]: + """Wrapper over the `client.chat.completions.create(stream=True)` method that provides a more granular event API + and automatic accumulation of each delta. + + This also supports all of the parsing utilities that `.parse()` does. + + Unlike `.create(stream=True)`, the `.stream()` method requires usage within a context manager to prevent accidental leakage of the response: + + ```py + with client.chat.completions.stream( + model="gpt-4o-2024-08-06", + messages=[...], + ) as stream: + for event in stream: + if event.type == "content.delta": + print(event.delta, flush=True, end="") + ``` + + When the context manager is entered, a `ChatCompletionStream` instance is returned which, like `.create(stream=True)` is an iterator. The full list of events that are yielded by the iterator are outlined in [these docs](https://github.com/openai/openai-python/blob/main/helpers.md#chat-completions-events). + + When the context manager exits, the response will be closed, however the `stream` instance is still available outside + the context manager. + """ + extra_headers = { + "X-Stainless-Helper-Method": "chat.completions.stream", + **(extra_headers or {}), + } + + api_request: partial[Stream[ChatCompletionChunk]] = partial( + self.create, + messages=messages, + model=model, + audio=audio, + stream=True, + response_format=_type_to_response_format(response_format), + frequency_penalty=frequency_penalty, + function_call=function_call, + functions=functions, + logit_bias=logit_bias, + logprobs=logprobs, + max_completion_tokens=max_completion_tokens, + max_tokens=max_tokens, + metadata=metadata, + modalities=modalities, + n=n, + parallel_tool_calls=parallel_tool_calls, + prediction=prediction, + presence_penalty=presence_penalty, + reasoning_effort=reasoning_effort, + seed=seed, + service_tier=service_tier, + store=store, + stop=stop, + stream_options=stream_options, + temperature=temperature, + tool_choice=tool_choice, + tools=tools, + top_logprobs=top_logprobs, + top_p=top_p, + user=user, + web_search_options=web_search_options, + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + ) + return ChatCompletionStreamManager( + api_request, + response_format=response_format, + input_tools=tools, + ) + class AsyncCompletions(AsyncAPIResource): @cached_property @@ -1175,6 +1448,153 @@ def with_streaming_response(self) -> AsyncCompletionsWithStreamingResponse: """ return AsyncCompletionsWithStreamingResponse(self) + async def parse( + self, + *, + messages: Iterable[ChatCompletionMessageParam], + model: Union[str, ChatModel], + audio: Optional[ChatCompletionAudioParam] | NotGiven = NOT_GIVEN, + response_format: type[ResponseFormatT] | NotGiven = NOT_GIVEN, + frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, + function_call: completion_create_params.FunctionCall | NotGiven = NOT_GIVEN, + functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, + logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, + logprobs: Optional[bool] | NotGiven = NOT_GIVEN, + max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, + max_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + modalities: Optional[List[Literal["text", "audio"]]] | NotGiven = NOT_GIVEN, + n: Optional[int] | NotGiven = NOT_GIVEN, + parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, + presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, + seed: Optional[int] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, + stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, + stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, + temperature: Optional[float] | NotGiven = NOT_GIVEN, + tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, + tools: Iterable[ChatCompletionToolParam] | NotGiven = NOT_GIVEN, + top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, + top_p: Optional[float] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ParsedChatCompletion[ResponseFormatT]: + """Wrapper over the `client.chat.completions.create()` method that provides richer integrations with Python specific types + & returns a `ParsedChatCompletion` object, which is a subclass of the standard `ChatCompletion` class. + + You can pass a pydantic model to this method and it will automatically convert the model + into a JSON schema, send it to the API and parse the response content back into the given model. + + This method will also automatically parse `function` tool calls if: + - You use the `openai.pydantic_function_tool()` helper method + - You mark your tool schema with `"strict": True` + + Example usage: + ```py + from pydantic import BaseModel + from openai import AsyncOpenAI + + + class Step(BaseModel): + explanation: str + output: str + + + class MathResponse(BaseModel): + steps: List[Step] + final_answer: str + + + client = AsyncOpenAI() + completion = await client.chat.completions.parse( + model="gpt-4o-2024-08-06", + messages=[ + {"role": "system", "content": "You are a helpful math tutor."}, + {"role": "user", "content": "solve 8x + 31 = 2"}, + ], + response_format=MathResponse, + ) + + message = completion.choices[0].message + if message.parsed: + print(message.parsed.steps) + print("answer: ", message.parsed.final_answer) + ``` + """ + _validate_input_tools(tools) + + extra_headers = { + "X-Stainless-Helper-Method": "chat.completions.parse", + **(extra_headers or {}), + } + + def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseFormatT]: + return _parse_chat_completion( + response_format=response_format, + chat_completion=raw_completion, + input_tools=tools, + ) + + return await self._post( + "/chat/completions", + body=await async_maybe_transform( + { + "messages": messages, + "model": model, + "audio": audio, + "frequency_penalty": frequency_penalty, + "function_call": function_call, + "functions": functions, + "logit_bias": logit_bias, + "logprobs": logprobs, + "max_completion_tokens": max_completion_tokens, + "max_tokens": max_tokens, + "metadata": metadata, + "modalities": modalities, + "n": n, + "parallel_tool_calls": parallel_tool_calls, + "prediction": prediction, + "presence_penalty": presence_penalty, + "reasoning_effort": reasoning_effort, + "response_format": _type_to_response_format(response_format), + "seed": seed, + "service_tier": service_tier, + "store": store, + "stop": stop, + "stream": False, + "stream_options": stream_options, + "temperature": temperature, + "tool_choice": tool_choice, + "tools": tools, + "top_logprobs": top_logprobs, + "top_p": top_p, + "user": user, + "web_search_options": web_search_options, + }, + completion_create_params.CompletionCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=parser, + ), + # we turn the `ChatCompletion` instance into a `ParsedChatCompletion` + # in the `parser` function above + cast_to=cast(Type[ParsedChatCompletion[ResponseFormatT]], ChatCompletion), + stream=False, + ) + @overload async def create( self, @@ -1198,7 +1618,7 @@ async def create( reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, @@ -1359,23 +1779,23 @@ async def create( should refer to the `system_fingerprint` response parameter to monitor changes in the backend. - service_tier: Specifies the latency tier to use for processing the request. This parameter is - relevant for customers subscribed to the scale tier service: - - - If set to 'auto', and the Project is Scale tier enabled, the system will - utilize scale tier credits until they are exhausted. - - If set to 'auto', and the Project is not Scale tier enabled, the request will - be processed using the default service tier with a lower uptime SLA and no - latency guarantee. - - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarantee. - - If set to 'flex', the request will be processed with the Flex Processing - service tier. - [Learn more](https://platform.openai.com/docs/guides/flex-processing). + service_tier: Specifies the processing type used for serving the request. + + - If set to 'auto', then the request will be processed with the service tier + configured in the Project settings. Unless otherwise configured, the Project + will use 'default'. + - If set to 'default', then the requset will be processed with the standard + pricing and performance for the selected model. + - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or + 'priority', then the request will be processed with the corresponding service + tier. [Contact sales](https://openai.com/contact-sales) to learn more about + Priority processing. - When not set, the default behavior is 'auto'. - When this parameter is set, the response body will include the `service_tier` - utilized. + When the `service_tier` parameter is set, the response body will include the + `service_tier` value based on the processing mode actually used to serve the + request. This response value may be different from the value set in the + parameter. stop: Not supported with latest reasoning models `o3` and `o4-mini`. @@ -1386,6 +1806,8 @@ async def create( our [model distillation](https://platform.openai.com/docs/guides/distillation) or [evals](https://platform.openai.com/docs/guides/evals) products. + Supports text and image inputs. Note: image inputs over 10MB will be dropped. + stream: If set to true, the model response data will be streamed to the client as it is generated using [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). @@ -1468,7 +1890,7 @@ async def create( reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, @@ -1637,23 +2059,23 @@ async def create( should refer to the `system_fingerprint` response parameter to monitor changes in the backend. - service_tier: Specifies the latency tier to use for processing the request. This parameter is - relevant for customers subscribed to the scale tier service: - - - If set to 'auto', and the Project is Scale tier enabled, the system will - utilize scale tier credits until they are exhausted. - - If set to 'auto', and the Project is not Scale tier enabled, the request will - be processed using the default service tier with a lower uptime SLA and no - latency guarantee. - - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarantee. - - If set to 'flex', the request will be processed with the Flex Processing - service tier. - [Learn more](https://platform.openai.com/docs/guides/flex-processing). + service_tier: Specifies the processing type used for serving the request. + + - If set to 'auto', then the request will be processed with the service tier + configured in the Project settings. Unless otherwise configured, the Project + will use 'default'. + - If set to 'default', then the requset will be processed with the standard + pricing and performance for the selected model. + - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or + 'priority', then the request will be processed with the corresponding service + tier. [Contact sales](https://openai.com/contact-sales) to learn more about + Priority processing. - When not set, the default behavior is 'auto'. - When this parameter is set, the response body will include the `service_tier` - utilized. + When the `service_tier` parameter is set, the response body will include the + `service_tier` value based on the processing mode actually used to serve the + request. This response value may be different from the value set in the + parameter. stop: Not supported with latest reasoning models `o3` and `o4-mini`. @@ -1664,6 +2086,8 @@ async def create( our [model distillation](https://platform.openai.com/docs/guides/distillation) or [evals](https://platform.openai.com/docs/guides/evals) products. + Supports text and image inputs. Note: image inputs over 10MB will be dropped. + stream_options: Options for streaming response. Only set this when you set `stream: true`. temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will @@ -1737,7 +2161,7 @@ async def create( reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, @@ -1906,23 +2330,23 @@ async def create( should refer to the `system_fingerprint` response parameter to monitor changes in the backend. - service_tier: Specifies the latency tier to use for processing the request. This parameter is - relevant for customers subscribed to the scale tier service: - - - If set to 'auto', and the Project is Scale tier enabled, the system will - utilize scale tier credits until they are exhausted. - - If set to 'auto', and the Project is not Scale tier enabled, the request will - be processed using the default service tier with a lower uptime SLA and no - latency guarantee. - - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarantee. - - If set to 'flex', the request will be processed with the Flex Processing - service tier. - [Learn more](https://platform.openai.com/docs/guides/flex-processing). + service_tier: Specifies the processing type used for serving the request. + + - If set to 'auto', then the request will be processed with the service tier + configured in the Project settings. Unless otherwise configured, the Project + will use 'default'. + - If set to 'default', then the requset will be processed with the standard + pricing and performance for the selected model. + - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or + 'priority', then the request will be processed with the corresponding service + tier. [Contact sales](https://openai.com/contact-sales) to learn more about + Priority processing. - When not set, the default behavior is 'auto'. - When this parameter is set, the response body will include the `service_tier` - utilized. + When the `service_tier` parameter is set, the response body will include the + `service_tier` value based on the processing mode actually used to serve the + request. This response value may be different from the value set in the + parameter. stop: Not supported with latest reasoning models `o3` and `o4-mini`. @@ -1933,6 +2357,8 @@ async def create( our [model distillation](https://platform.openai.com/docs/guides/distillation) or [evals](https://platform.openai.com/docs/guides/evals) products. + Supports text and image inputs. Note: image inputs over 10MB will be dropped. + stream_options: Options for streaming response. Only set this when you set `stream: true`. temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will @@ -2005,7 +2431,7 @@ async def create( reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, @@ -2253,11 +2679,126 @@ async def delete( cast_to=ChatCompletionDeleted, ) + def stream( + self, + *, + messages: Iterable[ChatCompletionMessageParam], + model: Union[str, ChatModel], + audio: Optional[ChatCompletionAudioParam] | NotGiven = NOT_GIVEN, + response_format: completion_create_params.ResponseFormat | type[ResponseFormatT] | NotGiven = NOT_GIVEN, + frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, + function_call: completion_create_params.FunctionCall | NotGiven = NOT_GIVEN, + functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, + logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, + logprobs: Optional[bool] | NotGiven = NOT_GIVEN, + max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, + max_tokens: Optional[int] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + modalities: Optional[List[Literal["text", "audio"]]] | NotGiven = NOT_GIVEN, + n: Optional[int] | NotGiven = NOT_GIVEN, + parallel_tool_calls: bool | NotGiven = NOT_GIVEN, + prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, + presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, + reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, + seed: Optional[int] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, + stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, + store: Optional[bool] | NotGiven = NOT_GIVEN, + stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, + temperature: Optional[float] | NotGiven = NOT_GIVEN, + tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, + tools: Iterable[ChatCompletionToolParam] | NotGiven = NOT_GIVEN, + top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, + top_p: Optional[float] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> AsyncChatCompletionStreamManager[ResponseFormatT]: + """Wrapper over the `client.chat.completions.create(stream=True)` method that provides a more granular event API + and automatic accumulation of each delta. + + This also supports all of the parsing utilities that `.parse()` does. + + Unlike `.create(stream=True)`, the `.stream()` method requires usage within a context manager to prevent accidental leakage of the response: + + ```py + async with client.chat.completions.stream( + model="gpt-4o-2024-08-06", + messages=[...], + ) as stream: + async for event in stream: + if event.type == "content.delta": + print(event.delta, flush=True, end="") + ``` + + When the context manager is entered, an `AsyncChatCompletionStream` instance is returned which, like `.create(stream=True)` is an async iterator. The full list of events that are yielded by the iterator are outlined in [these docs](https://github.com/openai/openai-python/blob/main/helpers.md#chat-completions-events). + + When the context manager exits, the response will be closed, however the `stream` instance is still available outside + the context manager. + """ + _validate_input_tools(tools) + + extra_headers = { + "X-Stainless-Helper-Method": "chat.completions.stream", + **(extra_headers or {}), + } + + api_request = self.create( + messages=messages, + model=model, + audio=audio, + stream=True, + response_format=_type_to_response_format(response_format), + frequency_penalty=frequency_penalty, + function_call=function_call, + functions=functions, + logit_bias=logit_bias, + logprobs=logprobs, + max_completion_tokens=max_completion_tokens, + max_tokens=max_tokens, + metadata=metadata, + modalities=modalities, + n=n, + parallel_tool_calls=parallel_tool_calls, + prediction=prediction, + presence_penalty=presence_penalty, + reasoning_effort=reasoning_effort, + seed=seed, + service_tier=service_tier, + stop=stop, + store=store, + stream_options=stream_options, + temperature=temperature, + tool_choice=tool_choice, + tools=tools, + top_logprobs=top_logprobs, + top_p=top_p, + user=user, + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + web_search_options=web_search_options, + ) + return AsyncChatCompletionStreamManager( + api_request, + response_format=response_format, + input_tools=tools, + ) + class CompletionsWithRawResponse: def __init__(self, completions: Completions) -> None: self._completions = completions + self.parse = _legacy_response.to_raw_response_wrapper( + completions.parse, + ) self.create = _legacy_response.to_raw_response_wrapper( completions.create, ) @@ -2283,6 +2824,9 @@ class AsyncCompletionsWithRawResponse: def __init__(self, completions: AsyncCompletions) -> None: self._completions = completions + self.parse = _legacy_response.async_to_raw_response_wrapper( + completions.parse, + ) self.create = _legacy_response.async_to_raw_response_wrapper( completions.create, ) @@ -2308,6 +2852,9 @@ class CompletionsWithStreamingResponse: def __init__(self, completions: Completions) -> None: self._completions = completions + self.parse = to_streamed_response_wrapper( + completions.parse, + ) self.create = to_streamed_response_wrapper( completions.create, ) @@ -2333,6 +2880,9 @@ class AsyncCompletionsWithStreamingResponse: def __init__(self, completions: AsyncCompletions) -> None: self._completions = completions + self.parse = async_to_streamed_response_wrapper( + completions.parse, + ) self.create = async_to_streamed_response_wrapper( completions.create, ) @@ -2357,5 +2907,5 @@ def messages(self) -> AsyncMessagesWithStreamingResponse: def validate_response_format(response_format: object) -> None: if inspect.isclass(response_format) and issubclass(response_format, pydantic.BaseModel): raise TypeError( - "You tried to pass a `BaseModel` class to `chat.completions.create()`; You must use `beta.chat.completions.parse()` instead" + "You tried to pass a `BaseModel` class to `chat.completions.create()`; You must use `chat.completions.parse()` instead" ) diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 841d198a5b..aaf2088f38 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -81,19 +81,21 @@ def create( input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + max_tool_calls: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: ResponsesModel | NotGiven = NOT_GIVEN, parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, + top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, @@ -125,18 +127,19 @@ def create( include: Specify additional output data to include in the model response. Currently supported values are: + - `code_interpreter_call.outputs`: Includes the outputs of python code execution + in code interpreter tool call items. + - `computer_call_output.output.image_url`: Include image urls from the computer + call output. - `file_search_call.results`: Include the search results of the file search tool call. - `message.input_image.image_url`: Include image urls from the input message. - - `computer_call_output.output.image_url`: Include image urls from the computer - call output. + - `message.output_text.logprobs`: Include logprobs with assistant messages. - `reasoning.encrypted_content`: Includes an encrypted version of reasoning tokens in reasoning item outputs. This enables reasoning items to be used in multi-turn conversations when using the Responses API statelessly (like when the `store` parameter is set to `false`, or when an organization is enrolled in the zero data retention program). - - `code_interpreter_call.outputs`: Includes the outputs of python code execution - in code interpreter tool call items. input: Text, image, or file inputs to the model, used to generate a response. @@ -158,6 +161,11 @@ def create( including visible output tokens and [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). + max_tool_calls: The maximum number of total calls to built-in tools that can be processed in a + response. This maximum number applies across all built-in tool calls, not per + individual tool. Any further attempts to call a tool by the model will be + ignored. + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format, and querying for objects via API or the dashboard. @@ -185,23 +193,23 @@ def create( Configuration options for [reasoning models](https://platform.openai.com/docs/guides/reasoning). - service_tier: Specifies the latency tier to use for processing the request. This parameter is - relevant for customers subscribed to the scale tier service: - - - If set to 'auto', and the Project is Scale tier enabled, the system will - utilize scale tier credits until they are exhausted. - - If set to 'auto', and the Project is not Scale tier enabled, the request will - be processed using the default service tier with a lower uptime SLA and no - latency guarantee. - - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarantee. - - If set to 'flex', the request will be processed with the Flex Processing - service tier. - [Learn more](https://platform.openai.com/docs/guides/flex-processing). + service_tier: Specifies the processing type used for serving the request. + + - If set to 'auto', then the request will be processed with the service tier + configured in the Project settings. Unless otherwise configured, the Project + will use 'default'. + - If set to 'default', then the requset will be processed with the standard + pricing and performance for the selected model. + - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or + 'priority', then the request will be processed with the corresponding service + tier. [Contact sales](https://openai.com/contact-sales) to learn more about + Priority processing. - When not set, the default behavior is 'auto'. - When this parameter is set, the response body will include the `service_tier` - utilized. + When the `service_tier` parameter is set, the response body will include the + `service_tier` value based on the processing mode actually used to serve the + request. This response value may be different from the value set in the + parameter. store: Whether to store the generated model response for later retrieval via API. @@ -242,6 +250,9 @@ def create( the model to call your own code. Learn more about [function calling](https://platform.openai.com/docs/guides/function-calling). + top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to + return at each token position, each with an associated log probability. + top_p: An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered. @@ -280,18 +291,20 @@ def create( input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + max_tool_calls: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: ResponsesModel | NotGiven = NOT_GIVEN, parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, + top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, @@ -330,18 +343,19 @@ def create( include: Specify additional output data to include in the model response. Currently supported values are: + - `code_interpreter_call.outputs`: Includes the outputs of python code execution + in code interpreter tool call items. + - `computer_call_output.output.image_url`: Include image urls from the computer + call output. - `file_search_call.results`: Include the search results of the file search tool call. - `message.input_image.image_url`: Include image urls from the input message. - - `computer_call_output.output.image_url`: Include image urls from the computer - call output. + - `message.output_text.logprobs`: Include logprobs with assistant messages. - `reasoning.encrypted_content`: Includes an encrypted version of reasoning tokens in reasoning item outputs. This enables reasoning items to be used in multi-turn conversations when using the Responses API statelessly (like when the `store` parameter is set to `false`, or when an organization is enrolled in the zero data retention program). - - `code_interpreter_call.outputs`: Includes the outputs of python code execution - in code interpreter tool call items. input: Text, image, or file inputs to the model, used to generate a response. @@ -363,6 +377,11 @@ def create( including visible output tokens and [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). + max_tool_calls: The maximum number of total calls to built-in tools that can be processed in a + response. This maximum number applies across all built-in tool calls, not per + individual tool. Any further attempts to call a tool by the model will be + ignored. + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format, and querying for objects via API or the dashboard. @@ -390,23 +409,23 @@ def create( Configuration options for [reasoning models](https://platform.openai.com/docs/guides/reasoning). - service_tier: Specifies the latency tier to use for processing the request. This parameter is - relevant for customers subscribed to the scale tier service: - - - If set to 'auto', and the Project is Scale tier enabled, the system will - utilize scale tier credits until they are exhausted. - - If set to 'auto', and the Project is not Scale tier enabled, the request will - be processed using the default service tier with a lower uptime SLA and no - latency guarantee. - - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarantee. - - If set to 'flex', the request will be processed with the Flex Processing - service tier. - [Learn more](https://platform.openai.com/docs/guides/flex-processing). + service_tier: Specifies the processing type used for serving the request. + + - If set to 'auto', then the request will be processed with the service tier + configured in the Project settings. Unless otherwise configured, the Project + will use 'default'. + - If set to 'default', then the requset will be processed with the standard + pricing and performance for the selected model. + - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or + 'priority', then the request will be processed with the corresponding service + tier. [Contact sales](https://openai.com/contact-sales) to learn more about + Priority processing. - When not set, the default behavior is 'auto'. - When this parameter is set, the response body will include the `service_tier` - utilized. + When the `service_tier` parameter is set, the response body will include the + `service_tier` value based on the processing mode actually used to serve the + request. This response value may be different from the value set in the + parameter. store: Whether to store the generated model response for later retrieval via API. @@ -440,6 +459,9 @@ def create( the model to call your own code. Learn more about [function calling](https://platform.openai.com/docs/guides/function-calling). + top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to + return at each token position, each with an associated log probability. + top_p: An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered. @@ -478,18 +500,20 @@ def create( input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + max_tool_calls: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: ResponsesModel | NotGiven = NOT_GIVEN, parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, + top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, @@ -528,18 +552,19 @@ def create( include: Specify additional output data to include in the model response. Currently supported values are: + - `code_interpreter_call.outputs`: Includes the outputs of python code execution + in code interpreter tool call items. + - `computer_call_output.output.image_url`: Include image urls from the computer + call output. - `file_search_call.results`: Include the search results of the file search tool call. - `message.input_image.image_url`: Include image urls from the input message. - - `computer_call_output.output.image_url`: Include image urls from the computer - call output. + - `message.output_text.logprobs`: Include logprobs with assistant messages. - `reasoning.encrypted_content`: Includes an encrypted version of reasoning tokens in reasoning item outputs. This enables reasoning items to be used in multi-turn conversations when using the Responses API statelessly (like when the `store` parameter is set to `false`, or when an organization is enrolled in the zero data retention program). - - `code_interpreter_call.outputs`: Includes the outputs of python code execution - in code interpreter tool call items. input: Text, image, or file inputs to the model, used to generate a response. @@ -561,6 +586,11 @@ def create( including visible output tokens and [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). + max_tool_calls: The maximum number of total calls to built-in tools that can be processed in a + response. This maximum number applies across all built-in tool calls, not per + individual tool. Any further attempts to call a tool by the model will be + ignored. + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format, and querying for objects via API or the dashboard. @@ -588,23 +618,23 @@ def create( Configuration options for [reasoning models](https://platform.openai.com/docs/guides/reasoning). - service_tier: Specifies the latency tier to use for processing the request. This parameter is - relevant for customers subscribed to the scale tier service: - - - If set to 'auto', and the Project is Scale tier enabled, the system will - utilize scale tier credits until they are exhausted. - - If set to 'auto', and the Project is not Scale tier enabled, the request will - be processed using the default service tier with a lower uptime SLA and no - latency guarantee. - - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarantee. - - If set to 'flex', the request will be processed with the Flex Processing - service tier. - [Learn more](https://platform.openai.com/docs/guides/flex-processing). + service_tier: Specifies the processing type used for serving the request. + + - If set to 'auto', then the request will be processed with the service tier + configured in the Project settings. Unless otherwise configured, the Project + will use 'default'. + - If set to 'default', then the requset will be processed with the standard + pricing and performance for the selected model. + - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or + 'priority', then the request will be processed with the corresponding service + tier. [Contact sales](https://openai.com/contact-sales) to learn more about + Priority processing. - When not set, the default behavior is 'auto'. - When this parameter is set, the response body will include the `service_tier` - utilized. + When the `service_tier` parameter is set, the response body will include the + `service_tier` value based on the processing mode actually used to serve the + request. This response value may be different from the value set in the + parameter. store: Whether to store the generated model response for later retrieval via API. @@ -638,6 +668,9 @@ def create( the model to call your own code. Learn more about [function calling](https://platform.openai.com/docs/guides/function-calling). + top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to + return at each token position, each with an associated log probability. + top_p: An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered. @@ -674,19 +707,21 @@ def create( input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + max_tool_calls: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: ResponsesModel | NotGiven = NOT_GIVEN, parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, + top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, @@ -706,6 +741,7 @@ def create( "input": input, "instructions": instructions, "max_output_tokens": max_output_tokens, + "max_tool_calls": max_tool_calls, "metadata": metadata, "model": model, "parallel_tool_calls": parallel_tool_calls, @@ -719,6 +755,7 @@ def create( "text": text, "tool_choice": tool_choice, "tools": tools, + "top_logprobs": top_logprobs, "top_p": top_p, "truncation": truncation, "user": user, @@ -1299,19 +1336,21 @@ async def create( input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + max_tool_calls: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: ResponsesModel | NotGiven = NOT_GIVEN, parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, + top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, @@ -1343,18 +1382,19 @@ async def create( include: Specify additional output data to include in the model response. Currently supported values are: + - `code_interpreter_call.outputs`: Includes the outputs of python code execution + in code interpreter tool call items. + - `computer_call_output.output.image_url`: Include image urls from the computer + call output. - `file_search_call.results`: Include the search results of the file search tool call. - `message.input_image.image_url`: Include image urls from the input message. - - `computer_call_output.output.image_url`: Include image urls from the computer - call output. + - `message.output_text.logprobs`: Include logprobs with assistant messages. - `reasoning.encrypted_content`: Includes an encrypted version of reasoning tokens in reasoning item outputs. This enables reasoning items to be used in multi-turn conversations when using the Responses API statelessly (like when the `store` parameter is set to `false`, or when an organization is enrolled in the zero data retention program). - - `code_interpreter_call.outputs`: Includes the outputs of python code execution - in code interpreter tool call items. input: Text, image, or file inputs to the model, used to generate a response. @@ -1376,6 +1416,11 @@ async def create( including visible output tokens and [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). + max_tool_calls: The maximum number of total calls to built-in tools that can be processed in a + response. This maximum number applies across all built-in tool calls, not per + individual tool. Any further attempts to call a tool by the model will be + ignored. + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format, and querying for objects via API or the dashboard. @@ -1403,23 +1448,23 @@ async def create( Configuration options for [reasoning models](https://platform.openai.com/docs/guides/reasoning). - service_tier: Specifies the latency tier to use for processing the request. This parameter is - relevant for customers subscribed to the scale tier service: - - - If set to 'auto', and the Project is Scale tier enabled, the system will - utilize scale tier credits until they are exhausted. - - If set to 'auto', and the Project is not Scale tier enabled, the request will - be processed using the default service tier with a lower uptime SLA and no - latency guarantee. - - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarantee. - - If set to 'flex', the request will be processed with the Flex Processing - service tier. - [Learn more](https://platform.openai.com/docs/guides/flex-processing). + service_tier: Specifies the processing type used for serving the request. + + - If set to 'auto', then the request will be processed with the service tier + configured in the Project settings. Unless otherwise configured, the Project + will use 'default'. + - If set to 'default', then the requset will be processed with the standard + pricing and performance for the selected model. + - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or + 'priority', then the request will be processed with the corresponding service + tier. [Contact sales](https://openai.com/contact-sales) to learn more about + Priority processing. - When not set, the default behavior is 'auto'. - When this parameter is set, the response body will include the `service_tier` - utilized. + When the `service_tier` parameter is set, the response body will include the + `service_tier` value based on the processing mode actually used to serve the + request. This response value may be different from the value set in the + parameter. store: Whether to store the generated model response for later retrieval via API. @@ -1460,6 +1505,9 @@ async def create( the model to call your own code. Learn more about [function calling](https://platform.openai.com/docs/guides/function-calling). + top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to + return at each token position, each with an associated log probability. + top_p: An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered. @@ -1498,18 +1546,20 @@ async def create( input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + max_tool_calls: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: ResponsesModel | NotGiven = NOT_GIVEN, parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, + top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, @@ -1548,18 +1598,19 @@ async def create( include: Specify additional output data to include in the model response. Currently supported values are: + - `code_interpreter_call.outputs`: Includes the outputs of python code execution + in code interpreter tool call items. + - `computer_call_output.output.image_url`: Include image urls from the computer + call output. - `file_search_call.results`: Include the search results of the file search tool call. - `message.input_image.image_url`: Include image urls from the input message. - - `computer_call_output.output.image_url`: Include image urls from the computer - call output. + - `message.output_text.logprobs`: Include logprobs with assistant messages. - `reasoning.encrypted_content`: Includes an encrypted version of reasoning tokens in reasoning item outputs. This enables reasoning items to be used in multi-turn conversations when using the Responses API statelessly (like when the `store` parameter is set to `false`, or when an organization is enrolled in the zero data retention program). - - `code_interpreter_call.outputs`: Includes the outputs of python code execution - in code interpreter tool call items. input: Text, image, or file inputs to the model, used to generate a response. @@ -1581,6 +1632,11 @@ async def create( including visible output tokens and [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). + max_tool_calls: The maximum number of total calls to built-in tools that can be processed in a + response. This maximum number applies across all built-in tool calls, not per + individual tool. Any further attempts to call a tool by the model will be + ignored. + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format, and querying for objects via API or the dashboard. @@ -1608,23 +1664,23 @@ async def create( Configuration options for [reasoning models](https://platform.openai.com/docs/guides/reasoning). - service_tier: Specifies the latency tier to use for processing the request. This parameter is - relevant for customers subscribed to the scale tier service: - - - If set to 'auto', and the Project is Scale tier enabled, the system will - utilize scale tier credits until they are exhausted. - - If set to 'auto', and the Project is not Scale tier enabled, the request will - be processed using the default service tier with a lower uptime SLA and no - latency guarantee. - - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarantee. - - If set to 'flex', the request will be processed with the Flex Processing - service tier. - [Learn more](https://platform.openai.com/docs/guides/flex-processing). + service_tier: Specifies the processing type used for serving the request. + + - If set to 'auto', then the request will be processed with the service tier + configured in the Project settings. Unless otherwise configured, the Project + will use 'default'. + - If set to 'default', then the requset will be processed with the standard + pricing and performance for the selected model. + - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or + 'priority', then the request will be processed with the corresponding service + tier. [Contact sales](https://openai.com/contact-sales) to learn more about + Priority processing. - When not set, the default behavior is 'auto'. - When this parameter is set, the response body will include the `service_tier` - utilized. + When the `service_tier` parameter is set, the response body will include the + `service_tier` value based on the processing mode actually used to serve the + request. This response value may be different from the value set in the + parameter. store: Whether to store the generated model response for later retrieval via API. @@ -1658,6 +1714,9 @@ async def create( the model to call your own code. Learn more about [function calling](https://platform.openai.com/docs/guides/function-calling). + top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to + return at each token position, each with an associated log probability. + top_p: An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered. @@ -1696,18 +1755,20 @@ async def create( input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + max_tool_calls: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: ResponsesModel | NotGiven = NOT_GIVEN, parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, + top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, @@ -1746,18 +1807,19 @@ async def create( include: Specify additional output data to include in the model response. Currently supported values are: + - `code_interpreter_call.outputs`: Includes the outputs of python code execution + in code interpreter tool call items. + - `computer_call_output.output.image_url`: Include image urls from the computer + call output. - `file_search_call.results`: Include the search results of the file search tool call. - `message.input_image.image_url`: Include image urls from the input message. - - `computer_call_output.output.image_url`: Include image urls from the computer - call output. + - `message.output_text.logprobs`: Include logprobs with assistant messages. - `reasoning.encrypted_content`: Includes an encrypted version of reasoning tokens in reasoning item outputs. This enables reasoning items to be used in multi-turn conversations when using the Responses API statelessly (like when the `store` parameter is set to `false`, or when an organization is enrolled in the zero data retention program). - - `code_interpreter_call.outputs`: Includes the outputs of python code execution - in code interpreter tool call items. input: Text, image, or file inputs to the model, used to generate a response. @@ -1779,6 +1841,11 @@ async def create( including visible output tokens and [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). + max_tool_calls: The maximum number of total calls to built-in tools that can be processed in a + response. This maximum number applies across all built-in tool calls, not per + individual tool. Any further attempts to call a tool by the model will be + ignored. + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format, and querying for objects via API or the dashboard. @@ -1806,23 +1873,23 @@ async def create( Configuration options for [reasoning models](https://platform.openai.com/docs/guides/reasoning). - service_tier: Specifies the latency tier to use for processing the request. This parameter is - relevant for customers subscribed to the scale tier service: - - - If set to 'auto', and the Project is Scale tier enabled, the system will - utilize scale tier credits until they are exhausted. - - If set to 'auto', and the Project is not Scale tier enabled, the request will - be processed using the default service tier with a lower uptime SLA and no - latency guarantee. - - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarantee. - - If set to 'flex', the request will be processed with the Flex Processing - service tier. - [Learn more](https://platform.openai.com/docs/guides/flex-processing). + service_tier: Specifies the processing type used for serving the request. + + - If set to 'auto', then the request will be processed with the service tier + configured in the Project settings. Unless otherwise configured, the Project + will use 'default'. + - If set to 'default', then the requset will be processed with the standard + pricing and performance for the selected model. + - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or + 'priority', then the request will be processed with the corresponding service + tier. [Contact sales](https://openai.com/contact-sales) to learn more about + Priority processing. - When not set, the default behavior is 'auto'. - When this parameter is set, the response body will include the `service_tier` - utilized. + When the `service_tier` parameter is set, the response body will include the + `service_tier` value based on the processing mode actually used to serve the + request. This response value may be different from the value set in the + parameter. store: Whether to store the generated model response for later retrieval via API. @@ -1856,6 +1923,9 @@ async def create( the model to call your own code. Learn more about [function calling](https://platform.openai.com/docs/guides/function-calling). + top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to + return at each token position, each with an associated log probability. + top_p: An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered. @@ -1892,19 +1962,21 @@ async def create( input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + max_tool_calls: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, model: ResponsesModel | NotGiven = NOT_GIVEN, parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, + top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, @@ -1924,6 +1996,7 @@ async def create( "input": input, "instructions": instructions, "max_output_tokens": max_output_tokens, + "max_tool_calls": max_tool_calls, "metadata": metadata, "model": model, "parallel_tool_calls": parallel_tool_calls, @@ -1937,6 +2010,7 @@ async def create( "text": text, "tool_choice": tool_choice, "tools": tools, + "top_logprobs": top_logprobs, "top_p": top_p, "truncation": truncation, "user": user, diff --git a/src/openai/resources/webhooks.py b/src/openai/resources/webhooks.py new file mode 100644 index 0000000000..3e13d3faae --- /dev/null +++ b/src/openai/resources/webhooks.py @@ -0,0 +1,210 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import hmac +import json +import time +import base64 +import hashlib +from typing import cast + +from .._types import HeadersLike +from .._utils import get_required_header +from .._models import construct_type +from .._resource import SyncAPIResource, AsyncAPIResource +from .._exceptions import InvalidWebhookSignatureError +from ..types.webhooks.unwrap_webhook_event import UnwrapWebhookEvent + +__all__ = ["Webhooks", "AsyncWebhooks"] + + +class Webhooks(SyncAPIResource): + def unwrap( + self, + payload: str | bytes, + headers: HeadersLike, + *, + secret: str | None = None, + ) -> UnwrapWebhookEvent: + """Validates that the given payload was sent by OpenAI and parses the payload.""" + if secret is None: + secret = self._client.webhook_secret + + self.verify_signature(payload=payload, headers=headers, secret=secret) + + return cast( + UnwrapWebhookEvent, + construct_type( + type_=UnwrapWebhookEvent, + value=json.loads(payload), + ), + ) + + def verify_signature( + self, + payload: str | bytes, + headers: HeadersLike, + *, + secret: str | None = None, + tolerance: int = 300, + ) -> None: + """Validates whether or not the webhook payload was sent by OpenAI. + + Args: + payload: The webhook payload + headers: The webhook headers + secret: The webhook secret (optional, will use client secret if not provided) + tolerance: Maximum age of the webhook in seconds (default: 300 = 5 minutes) + """ + if secret is None: + secret = self._client.webhook_secret + + if secret is None: + raise ValueError( + "The webhook secret must either be set using the env var, OPENAI_WEBHOOK_SECRET, " + "on the client class, OpenAI(webhook_secret='123'), or passed to this function" + ) + + signature_header = get_required_header(headers, "webhook-signature") + timestamp = get_required_header(headers, "webhook-timestamp") + webhook_id = get_required_header(headers, "webhook-id") + + # Validate timestamp to prevent replay attacks + try: + timestamp_seconds = int(timestamp) + except ValueError: + raise InvalidWebhookSignatureError("Invalid webhook timestamp format") from None + + now = int(time.time()) + + if now - timestamp_seconds > tolerance: + raise InvalidWebhookSignatureError("Webhook timestamp is too old") from None + + if timestamp_seconds > now + tolerance: + raise InvalidWebhookSignatureError("Webhook timestamp is too new") from None + + # Extract signatures from v1, format + # The signature header can have multiple values, separated by spaces. + # Each value is in the format v1,. We should accept if any match. + signatures: list[str] = [] + for part in signature_header.split(): + if part.startswith("v1,"): + signatures.append(part[3:]) + else: + signatures.append(part) + + # Decode the secret if it starts with whsec_ + if secret.startswith("whsec_"): + decoded_secret = base64.b64decode(secret[6:]) + else: + decoded_secret = secret.encode() + + body = payload.decode("utf-8") if isinstance(payload, bytes) else payload + + # Prepare the signed payload (OpenAI uses webhookId.timestamp.payload format) + signed_payload = f"{webhook_id}.{timestamp}.{body}" + expected_signature = base64.b64encode( + hmac.new(decoded_secret, signed_payload.encode(), hashlib.sha256).digest() + ).decode() + + # Accept if any signature matches + if not any(hmac.compare_digest(expected_signature, sig) for sig in signatures): + raise InvalidWebhookSignatureError( + "The given webhook signature does not match the expected signature" + ) from None + + +class AsyncWebhooks(AsyncAPIResource): + def unwrap( + self, + payload: str | bytes, + headers: HeadersLike, + *, + secret: str | None = None, + ) -> UnwrapWebhookEvent: + """Validates that the given payload was sent by OpenAI and parses the payload.""" + if secret is None: + secret = self._client.webhook_secret + + self.verify_signature(payload=payload, headers=headers, secret=secret) + + body = payload.decode("utf-8") if isinstance(payload, bytes) else payload + return cast( + UnwrapWebhookEvent, + construct_type( + type_=UnwrapWebhookEvent, + value=json.loads(body), + ), + ) + + def verify_signature( + self, + payload: str | bytes, + headers: HeadersLike, + *, + secret: str | None = None, + tolerance: int = 300, + ) -> None: + """Validates whether or not the webhook payload was sent by OpenAI. + + Args: + payload: The webhook payload + headers: The webhook headers + secret: The webhook secret (optional, will use client secret if not provided) + tolerance: Maximum age of the webhook in seconds (default: 300 = 5 minutes) + """ + if secret is None: + secret = self._client.webhook_secret + + if secret is None: + raise ValueError( + "The webhook secret must either be set using the env var, OPENAI_WEBHOOK_SECRET, " + "on the client class, OpenAI(webhook_secret='123'), or passed to this function" + ) from None + + signature_header = get_required_header(headers, "webhook-signature") + timestamp = get_required_header(headers, "webhook-timestamp") + webhook_id = get_required_header(headers, "webhook-id") + + # Validate timestamp to prevent replay attacks + try: + timestamp_seconds = int(timestamp) + except ValueError: + raise InvalidWebhookSignatureError("Invalid webhook timestamp format") from None + + now = int(time.time()) + + if now - timestamp_seconds > tolerance: + raise InvalidWebhookSignatureError("Webhook timestamp is too old") from None + + if timestamp_seconds > now + tolerance: + raise InvalidWebhookSignatureError("Webhook timestamp is too new") from None + + # Extract signatures from v1, format + # The signature header can have multiple values, separated by spaces. + # Each value is in the format v1,. We should accept if any match. + signatures: list[str] = [] + for part in signature_header.split(): + if part.startswith("v1,"): + signatures.append(part[3:]) + else: + signatures.append(part) + + # Decode the secret if it starts with whsec_ + if secret.startswith("whsec_"): + decoded_secret = base64.b64decode(secret[6:]) + else: + decoded_secret = secret.encode() + + body = payload.decode("utf-8") if isinstance(payload, bytes) else payload + + # Prepare the signed payload (OpenAI uses webhookId.timestamp.payload format) + signed_payload = f"{webhook_id}.{timestamp}.{body}" + expected_signature = base64.b64encode( + hmac.new(decoded_secret, signed_payload.encode(), hashlib.sha256).digest() + ).decode() + + # Accept if any signature matches + if not any(hmac.compare_digest(expected_signature, sig) for sig in signatures): + raise InvalidWebhookSignatureError("The given webhook signature does not match the expected signature") diff --git a/src/openai/types/chat/chat_completion.py b/src/openai/types/chat/chat_completion.py index 863cc2e81a..afc23e3f3d 100644 --- a/src/openai/types/chat/chat_completion.py +++ b/src/openai/types/chat/chat_completion.py @@ -59,25 +59,24 @@ class ChatCompletion(BaseModel): object: Literal["chat.completion"] """The object type, which is always `chat.completion`.""" - service_tier: Optional[Literal["auto", "default", "flex", "scale"]] = None - """Specifies the latency tier to use for processing the request. - - This parameter is relevant for customers subscribed to the scale tier service: - - - If set to 'auto', and the Project is Scale tier enabled, the system will - utilize scale tier credits until they are exhausted. - - If set to 'auto', and the Project is not Scale tier enabled, the request will - be processed using the default service tier with a lower uptime SLA and no - latency guarantee. - - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarantee. - - If set to 'flex', the request will be processed with the Flex Processing - service tier. - [Learn more](https://platform.openai.com/docs/guides/flex-processing). + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] = None + """Specifies the processing type used for serving the request. + + - If set to 'auto', then the request will be processed with the service tier + configured in the Project settings. Unless otherwise configured, the Project + will use 'default'. + - If set to 'default', then the requset will be processed with the standard + pricing and performance for the selected model. + - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or + 'priority', then the request will be processed with the corresponding service + tier. [Contact sales](https://openai.com/contact-sales) to learn more about + Priority processing. - When not set, the default behavior is 'auto'. - When this parameter is set, the response body will include the `service_tier` - utilized. + When the `service_tier` parameter is set, the response body will include the + `service_tier` value based on the processing mode actually used to serve the + request. This response value may be different from the value set in the + parameter. """ system_fingerprint: Optional[str] = None diff --git a/src/openai/types/chat/chat_completion_chunk.py b/src/openai/types/chat/chat_completion_chunk.py index 3d3d68602a..da6e315830 100644 --- a/src/openai/types/chat/chat_completion_chunk.py +++ b/src/openai/types/chat/chat_completion_chunk.py @@ -128,25 +128,24 @@ class ChatCompletionChunk(BaseModel): object: Literal["chat.completion.chunk"] """The object type, which is always `chat.completion.chunk`.""" - service_tier: Optional[Literal["auto", "default", "flex", "scale"]] = None - """Specifies the latency tier to use for processing the request. - - This parameter is relevant for customers subscribed to the scale tier service: - - - If set to 'auto', and the Project is Scale tier enabled, the system will - utilize scale tier credits until they are exhausted. - - If set to 'auto', and the Project is not Scale tier enabled, the request will - be processed using the default service tier with a lower uptime SLA and no - latency guarantee. - - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarantee. - - If set to 'flex', the request will be processed with the Flex Processing - service tier. - [Learn more](https://platform.openai.com/docs/guides/flex-processing). + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] = None + """Specifies the processing type used for serving the request. + + - If set to 'auto', then the request will be processed with the service tier + configured in the Project settings. Unless otherwise configured, the Project + will use 'default'. + - If set to 'default', then the requset will be processed with the standard + pricing and performance for the selected model. + - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or + 'priority', then the request will be processed with the corresponding service + tier. [Contact sales](https://openai.com/contact-sales) to learn more about + Priority processing. - When not set, the default behavior is 'auto'. - When this parameter is set, the response body will include the `service_tier` - utilized. + When the `service_tier` parameter is set, the response body will include the + `service_tier` value based on the processing mode actually used to serve the + request. This response value may be different from the value set in the + parameter. """ system_fingerprint: Optional[str] = None diff --git a/src/openai/types/chat/completion_create_params.py b/src/openai/types/chat/completion_create_params.py index f1ed444b79..44ea853041 100644 --- a/src/openai/types/chat/completion_create_params.py +++ b/src/openai/types/chat/completion_create_params.py @@ -208,25 +208,24 @@ class CompletionCreateParamsBase(TypedDict, total=False): in the backend. """ - service_tier: Optional[Literal["auto", "default", "flex", "scale"]] - """Specifies the latency tier to use for processing the request. - - This parameter is relevant for customers subscribed to the scale tier service: - - - If set to 'auto', and the Project is Scale tier enabled, the system will - utilize scale tier credits until they are exhausted. - - If set to 'auto', and the Project is not Scale tier enabled, the request will - be processed using the default service tier with a lower uptime SLA and no - latency guarantee. - - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarantee. - - If set to 'flex', the request will be processed with the Flex Processing - service tier. - [Learn more](https://platform.openai.com/docs/guides/flex-processing). + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] + """Specifies the processing type used for serving the request. + + - If set to 'auto', then the request will be processed with the service tier + configured in the Project settings. Unless otherwise configured, the Project + will use 'default'. + - If set to 'default', then the requset will be processed with the standard + pricing and performance for the selected model. + - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or + 'priority', then the request will be processed with the corresponding service + tier. [Contact sales](https://openai.com/contact-sales) to learn more about + Priority processing. - When not set, the default behavior is 'auto'. - When this parameter is set, the response body will include the `service_tier` - utilized. + When the `service_tier` parameter is set, the response body will include the + `service_tier` value based on the processing mode actually used to serve the + request. This response value may be different from the value set in the + parameter. """ stop: Union[Optional[str], List[str], None] @@ -241,6 +240,8 @@ class CompletionCreateParamsBase(TypedDict, total=False): Whether or not to store the output of this chat completion request for use in our [model distillation](https://platform.openai.com/docs/guides/distillation) or [evals](https://platform.openai.com/docs/guides/evals) products. + + Supports text and image inputs. Note: image inputs over 10MB will be dropped. """ stream_options: Optional[ChatCompletionStreamOptionsParam] diff --git a/src/openai/types/images_response.py b/src/openai/types/images_response.py index df454afa4d..2a8ca728ab 100644 --- a/src/openai/types/images_response.py +++ b/src/openai/types/images_response.py @@ -1,6 +1,7 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from typing import List, Optional +from typing_extensions import Literal from .image import Image from .._models import BaseModel @@ -34,8 +35,26 @@ class ImagesResponse(BaseModel): created: int """The Unix timestamp (in seconds) of when the image was created.""" + background: Optional[Literal["transparent", "opaque"]] = None + """The background parameter used for the image generation. + + Either `transparent` or `opaque`. + """ + data: Optional[List[Image]] = None """The list of generated images.""" + output_format: Optional[Literal["png", "webp", "jpeg"]] = None + """The output format of the image generation. Either `png`, `webp`, or `jpeg`.""" + + quality: Optional[Literal["low", "medium", "high"]] = None + """The quality of the image generated. Either `low`, `medium`, or `high`.""" + + size: Optional[Literal["1024x1024", "1024x1536", "1536x1024"]] = None + """The size of the image generated. + + Either `1024x1024`, `1024x1536`, or `1536x1024`. + """ + usage: Optional[Usage] = None """For `gpt-image-1` only, the token usage information for the image generation.""" diff --git a/src/openai/types/responses/__init__.py b/src/openai/types/responses/__init__.py index ba257eabc2..4316e47730 100644 --- a/src/openai/types/responses/__init__.py +++ b/src/openai/types/responses/__init__.py @@ -20,6 +20,7 @@ ) from .response_prompt import ResponsePrompt as ResponsePrompt from .response_status import ResponseStatus as ResponseStatus +from .tool_choice_mcp import ToolChoiceMcp as ToolChoiceMcp from .web_search_tool import WebSearchTool as WebSearchTool from .file_search_tool import FileSearchTool as FileSearchTool from .tool_choice_types import ToolChoiceTypes as ToolChoiceTypes @@ -43,6 +44,7 @@ from .response_prompt_param import ResponsePromptParam as ResponsePromptParam from .response_queued_event import ResponseQueuedEvent as ResponseQueuedEvent from .response_stream_event import ResponseStreamEvent as ResponseStreamEvent +from .tool_choice_mcp_param import ToolChoiceMcpParam as ToolChoiceMcpParam from .web_search_tool_param import WebSearchToolParam as WebSearchToolParam from .file_search_tool_param import FileSearchToolParam as FileSearchToolParam from .input_item_list_params import InputItemListParams as InputItemListParams diff --git a/src/openai/types/responses/response.py b/src/openai/types/responses/response.py index 75d1c5e3df..db85d87f4e 100644 --- a/src/openai/types/responses/response.py +++ b/src/openai/types/responses/response.py @@ -9,6 +9,7 @@ from .response_usage import ResponseUsage from .response_prompt import ResponsePrompt from .response_status import ResponseStatus +from .tool_choice_mcp import ToolChoiceMcp from ..shared.metadata import Metadata from ..shared.reasoning import Reasoning from .tool_choice_types import ToolChoiceTypes @@ -27,7 +28,7 @@ class IncompleteDetails(BaseModel): """The reason why the response is incomplete.""" -ToolChoice: TypeAlias = Union[ToolChoiceOptions, ToolChoiceTypes, ToolChoiceFunction] +ToolChoice: TypeAlias = Union[ToolChoiceOptions, ToolChoiceTypes, ToolChoiceFunction, ToolChoiceMcp] class Response(BaseModel): @@ -141,6 +142,14 @@ class Response(BaseModel): [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). """ + max_tool_calls: Optional[int] = None + """ + The maximum number of total calls to built-in tools that can be processed in a + response. This maximum number applies across all built-in tool calls, not per + individual tool. Any further attempts to call a tool by the model will be + ignored. + """ + previous_response_id: Optional[str] = None """The unique ID of the previous response to the model. @@ -161,25 +170,24 @@ class Response(BaseModel): [reasoning models](https://platform.openai.com/docs/guides/reasoning). """ - service_tier: Optional[Literal["auto", "default", "flex", "scale"]] = None - """Specifies the latency tier to use for processing the request. - - This parameter is relevant for customers subscribed to the scale tier service: + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] = None + """Specifies the processing type used for serving the request. - - If set to 'auto', and the Project is Scale tier enabled, the system will - utilize scale tier credits until they are exhausted. - - If set to 'auto', and the Project is not Scale tier enabled, the request will - be processed using the default service tier with a lower uptime SLA and no - latency guarantee. - - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarantee. - - If set to 'flex', the request will be processed with the Flex Processing - service tier. - [Learn more](https://platform.openai.com/docs/guides/flex-processing). + - If set to 'auto', then the request will be processed with the service tier + configured in the Project settings. Unless otherwise configured, the Project + will use 'default'. + - If set to 'default', then the requset will be processed with the standard + pricing and performance for the selected model. + - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or + 'priority', then the request will be processed with the corresponding service + tier. [Contact sales](https://openai.com/contact-sales) to learn more about + Priority processing. - When not set, the default behavior is 'auto'. - When this parameter is set, the response body will include the `service_tier` - utilized. + When the `service_tier` parameter is set, the response body will include the + `service_tier` value based on the processing mode actually used to serve the + request. This response value may be different from the value set in the + parameter. """ status: Optional[ResponseStatus] = None @@ -198,6 +206,12 @@ class Response(BaseModel): - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) """ + top_logprobs: Optional[int] = None + """ + An integer between 0 and 20 specifying the number of most likely tokens to + return at each token position, each with an associated log probability. + """ + truncation: Optional[Literal["auto", "disabled"]] = None """The truncation strategy to use for the model response. diff --git a/src/openai/types/responses/response_create_params.py b/src/openai/types/responses/response_create_params.py index 22acd6f653..0187e1fda8 100644 --- a/src/openai/types/responses/response_create_params.py +++ b/src/openai/types/responses/response_create_params.py @@ -10,6 +10,7 @@ from .tool_choice_options import ToolChoiceOptions from .response_input_param import ResponseInputParam from .response_prompt_param import ResponsePromptParam +from .tool_choice_mcp_param import ToolChoiceMcpParam from ..shared_params.metadata import Metadata from .tool_choice_types_param import ToolChoiceTypesParam from ..shared_params.reasoning import Reasoning @@ -37,18 +38,19 @@ class ResponseCreateParamsBase(TypedDict, total=False): Currently supported values are: + - `code_interpreter_call.outputs`: Includes the outputs of python code execution + in code interpreter tool call items. + - `computer_call_output.output.image_url`: Include image urls from the computer + call output. - `file_search_call.results`: Include the search results of the file search tool call. - `message.input_image.image_url`: Include image urls from the input message. - - `computer_call_output.output.image_url`: Include image urls from the computer - call output. + - `message.output_text.logprobs`: Include logprobs with assistant messages. - `reasoning.encrypted_content`: Includes an encrypted version of reasoning tokens in reasoning item outputs. This enables reasoning items to be used in multi-turn conversations when using the Responses API statelessly (like when the `store` parameter is set to `false`, or when an organization is enrolled in the zero data retention program). - - `code_interpreter_call.outputs`: Includes the outputs of python code execution - in code interpreter tool call items. """ input: Union[str, ResponseInputParam] @@ -78,6 +80,14 @@ class ResponseCreateParamsBase(TypedDict, total=False): [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). """ + max_tool_calls: Optional[int] + """ + The maximum number of total calls to built-in tools that can be processed in a + response. This maximum number applies across all built-in tool calls, not per + individual tool. Any further attempts to call a tool by the model will be + ignored. + """ + metadata: Optional[Metadata] """Set of 16 key-value pairs that can be attached to an object. @@ -120,25 +130,24 @@ class ResponseCreateParamsBase(TypedDict, total=False): [reasoning models](https://platform.openai.com/docs/guides/reasoning). """ - service_tier: Optional[Literal["auto", "default", "flex", "scale"]] - """Specifies the latency tier to use for processing the request. - - This parameter is relevant for customers subscribed to the scale tier service: - - - If set to 'auto', and the Project is Scale tier enabled, the system will - utilize scale tier credits until they are exhausted. - - If set to 'auto', and the Project is not Scale tier enabled, the request will - be processed using the default service tier with a lower uptime SLA and no - latency guarantee. - - If set to 'default', the request will be processed using the default service - tier with a lower uptime SLA and no latency guarantee. - - If set to 'flex', the request will be processed with the Flex Processing - service tier. - [Learn more](https://platform.openai.com/docs/guides/flex-processing). + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] + """Specifies the processing type used for serving the request. + + - If set to 'auto', then the request will be processed with the service tier + configured in the Project settings. Unless otherwise configured, the Project + will use 'default'. + - If set to 'default', then the requset will be processed with the standard + pricing and performance for the selected model. + - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or + 'priority', then the request will be processed with the corresponding service + tier. [Contact sales](https://openai.com/contact-sales) to learn more about + Priority processing. - When not set, the default behavior is 'auto'. - When this parameter is set, the response body will include the `service_tier` - utilized. + When the `service_tier` parameter is set, the response body will include the + `service_tier` value based on the processing mode actually used to serve the + request. This response value may be different from the value set in the + parameter. """ store: Optional[bool] @@ -186,6 +195,12 @@ class ResponseCreateParamsBase(TypedDict, total=False): [function calling](https://platform.openai.com/docs/guides/function-calling). """ + top_logprobs: Optional[int] + """ + An integer between 0 and 20 specifying the number of most likely tokens to + return at each token position, each with an associated log probability. + """ + top_p: Optional[float] """ An alternative to sampling with temperature, called nucleus sampling, where the @@ -214,7 +229,7 @@ class ResponseCreateParamsBase(TypedDict, total=False): """ -ToolChoice: TypeAlias = Union[ToolChoiceOptions, ToolChoiceTypesParam, ToolChoiceFunctionParam] +ToolChoice: TypeAlias = Union[ToolChoiceOptions, ToolChoiceTypesParam, ToolChoiceFunctionParam, ToolChoiceMcpParam] class ResponseCreateParamsNonStreaming(ResponseCreateParamsBase, total=False): diff --git a/src/openai/types/responses/response_function_web_search.py b/src/openai/types/responses/response_function_web_search.py index 44734b681f..164a1afdca 100644 --- a/src/openai/types/responses/response_function_web_search.py +++ b/src/openai/types/responses/response_function_web_search.py @@ -1,16 +1,57 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing_extensions import Literal +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias +from ..._utils import PropertyInfo from ..._models import BaseModel -__all__ = ["ResponseFunctionWebSearch"] +__all__ = ["ResponseFunctionWebSearch", "Action", "ActionSearch", "ActionOpenPage", "ActionFind"] + + +class ActionSearch(BaseModel): + query: str + """The search query.""" + + type: Literal["search"] + """The action type.""" + + domains: Optional[List[str]] = None + """Domains to restrict the search or domains where results were found.""" + + +class ActionOpenPage(BaseModel): + type: Literal["open_page"] + """The action type.""" + + url: str + """The URL opened by the model.""" + + +class ActionFind(BaseModel): + pattern: str + """The pattern or text to search for within the page.""" + + type: Literal["find"] + """The action type.""" + + url: str + """The URL of the page searched for the pattern.""" + + +Action: TypeAlias = Annotated[Union[ActionSearch, ActionOpenPage, ActionFind], PropertyInfo(discriminator="type")] class ResponseFunctionWebSearch(BaseModel): id: str """The unique ID of the web search tool call.""" + action: Action + """ + An object describing the specific action taken in this web search call. Includes + details on how the model used the web (search, open_page, find). + """ + status: Literal["in_progress", "searching", "completed", "failed"] """The status of the web search tool call.""" diff --git a/src/openai/types/responses/response_function_web_search_param.py b/src/openai/types/responses/response_function_web_search_param.py index d413e60b12..04d8a5884b 100644 --- a/src/openai/types/responses/response_function_web_search_param.py +++ b/src/openai/types/responses/response_function_web_search_param.py @@ -2,15 +2,55 @@ from __future__ import annotations -from typing_extensions import Literal, Required, TypedDict +from typing import List, Union +from typing_extensions import Literal, Required, TypeAlias, TypedDict -__all__ = ["ResponseFunctionWebSearchParam"] +__all__ = ["ResponseFunctionWebSearchParam", "Action", "ActionSearch", "ActionOpenPage", "ActionFind"] + + +class ActionSearch(TypedDict, total=False): + query: Required[str] + """The search query.""" + + type: Required[Literal["search"]] + """The action type.""" + + domains: List[str] + """Domains to restrict the search or domains where results were found.""" + + +class ActionOpenPage(TypedDict, total=False): + type: Required[Literal["open_page"]] + """The action type.""" + + url: Required[str] + """The URL opened by the model.""" + + +class ActionFind(TypedDict, total=False): + pattern: Required[str] + """The pattern or text to search for within the page.""" + + type: Required[Literal["find"]] + """The action type.""" + + url: Required[str] + """The URL of the page searched for the pattern.""" + + +Action: TypeAlias = Union[ActionSearch, ActionOpenPage, ActionFind] class ResponseFunctionWebSearchParam(TypedDict, total=False): id: Required[str] """The unique ID of the web search tool call.""" + action: Required[Action] + """ + An object describing the specific action taken in this web search call. Includes + details on how the model used the web (search, open_page, find). + """ + status: Required[Literal["in_progress", "searching", "completed", "failed"]] """The status of the web search tool call.""" diff --git a/src/openai/types/responses/response_includable.py b/src/openai/types/responses/response_includable.py index 28869832b0..c17a02560f 100644 --- a/src/openai/types/responses/response_includable.py +++ b/src/openai/types/responses/response_includable.py @@ -5,9 +5,10 @@ __all__ = ["ResponseIncludable"] ResponseIncludable: TypeAlias = Literal[ + "code_interpreter_call.outputs", + "computer_call_output.output.image_url", "file_search_call.results", "message.input_image.image_url", - "computer_call_output.output.image_url", + "message.output_text.logprobs", "reasoning.encrypted_content", - "code_interpreter_call.outputs", ] diff --git a/src/openai/types/responses/tool_choice_mcp.py b/src/openai/types/responses/tool_choice_mcp.py new file mode 100644 index 0000000000..8763d81635 --- /dev/null +++ b/src/openai/types/responses/tool_choice_mcp.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ToolChoiceMcp"] + + +class ToolChoiceMcp(BaseModel): + server_label: str + """The label of the MCP server to use.""" + + type: Literal["mcp"] + """For MCP tools, the type is always `mcp`.""" + + name: Optional[str] = None + """The name of the tool to call on the server.""" diff --git a/src/openai/types/responses/tool_choice_mcp_param.py b/src/openai/types/responses/tool_choice_mcp_param.py new file mode 100644 index 0000000000..afcceb8cc5 --- /dev/null +++ b/src/openai/types/responses/tool_choice_mcp_param.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ToolChoiceMcpParam"] + + +class ToolChoiceMcpParam(TypedDict, total=False): + server_label: Required[str] + """The label of the MCP server to use.""" + + type: Required[Literal["mcp"]] + """For MCP tools, the type is always `mcp`.""" + + name: Optional[str] + """The name of the tool to call on the server.""" diff --git a/src/openai/types/responses/tool_choice_types.py b/src/openai/types/responses/tool_choice_types.py index b968324383..b31a826051 100644 --- a/src/openai/types/responses/tool_choice_types.py +++ b/src/openai/types/responses/tool_choice_types.py @@ -15,7 +15,6 @@ class ToolChoiceTypes(BaseModel): "web_search_preview_2025_03_11", "image_generation", "code_interpreter", - "mcp", ] """The type of hosted tool the model should to use. @@ -28,6 +27,5 @@ class ToolChoiceTypes(BaseModel): - `web_search_preview` - `computer_use_preview` - `code_interpreter` - - `mcp` - `image_generation` """ diff --git a/src/openai/types/responses/tool_choice_types_param.py b/src/openai/types/responses/tool_choice_types_param.py index 175900750c..15e0357471 100644 --- a/src/openai/types/responses/tool_choice_types_param.py +++ b/src/openai/types/responses/tool_choice_types_param.py @@ -16,7 +16,6 @@ class ToolChoiceTypesParam(TypedDict, total=False): "web_search_preview_2025_03_11", "image_generation", "code_interpreter", - "mcp", ] ] """The type of hosted tool the model should to use. @@ -30,6 +29,5 @@ class ToolChoiceTypesParam(TypedDict, total=False): - `web_search_preview` - `computer_use_preview` - `code_interpreter` - - `mcp` - `image_generation` """ diff --git a/src/openai/types/shared/all_models.py b/src/openai/types/shared/all_models.py index fae8c4c8ff..828f3b5669 100644 --- a/src/openai/types/shared/all_models.py +++ b/src/openai/types/shared/all_models.py @@ -15,6 +15,10 @@ "o1-pro-2025-03-19", "o3-pro", "o3-pro-2025-06-10", + "o3-deep-research", + "o3-deep-research-2025-06-26", + "o4-mini-deep-research", + "o4-mini-deep-research-2025-06-26", "computer-use-preview", "computer-use-preview-2025-03-11", ], diff --git a/src/openai/types/shared/responses_model.py b/src/openai/types/shared/responses_model.py index 790c1212f6..4d35356806 100644 --- a/src/openai/types/shared/responses_model.py +++ b/src/openai/types/shared/responses_model.py @@ -15,6 +15,10 @@ "o1-pro-2025-03-19", "o3-pro", "o3-pro-2025-06-10", + "o3-deep-research", + "o3-deep-research-2025-06-26", + "o4-mini-deep-research", + "o4-mini-deep-research-2025-06-26", "computer-use-preview", "computer-use-preview-2025-03-11", ], diff --git a/src/openai/types/shared_params/responses_model.py b/src/openai/types/shared_params/responses_model.py index ca526b8f15..adfcecf1e5 100644 --- a/src/openai/types/shared_params/responses_model.py +++ b/src/openai/types/shared_params/responses_model.py @@ -17,6 +17,10 @@ "o1-pro-2025-03-19", "o3-pro", "o3-pro-2025-06-10", + "o3-deep-research", + "o3-deep-research-2025-06-26", + "o4-mini-deep-research", + "o4-mini-deep-research-2025-06-26", "computer-use-preview", "computer-use-preview-2025-03-11", ], diff --git a/src/openai/types/webhooks/__init__.py b/src/openai/types/webhooks/__init__.py new file mode 100644 index 0000000000..9caad38c82 --- /dev/null +++ b/src/openai/types/webhooks/__init__.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .unwrap_webhook_event import UnwrapWebhookEvent as UnwrapWebhookEvent +from .batch_failed_webhook_event import BatchFailedWebhookEvent as BatchFailedWebhookEvent +from .batch_expired_webhook_event import BatchExpiredWebhookEvent as BatchExpiredWebhookEvent +from .batch_cancelled_webhook_event import BatchCancelledWebhookEvent as BatchCancelledWebhookEvent +from .batch_completed_webhook_event import BatchCompletedWebhookEvent as BatchCompletedWebhookEvent +from .eval_run_failed_webhook_event import EvalRunFailedWebhookEvent as EvalRunFailedWebhookEvent +from .response_failed_webhook_event import ResponseFailedWebhookEvent as ResponseFailedWebhookEvent +from .eval_run_canceled_webhook_event import EvalRunCanceledWebhookEvent as EvalRunCanceledWebhookEvent +from .eval_run_succeeded_webhook_event import EvalRunSucceededWebhookEvent as EvalRunSucceededWebhookEvent +from .response_cancelled_webhook_event import ResponseCancelledWebhookEvent as ResponseCancelledWebhookEvent +from .response_completed_webhook_event import ResponseCompletedWebhookEvent as ResponseCompletedWebhookEvent +from .response_incomplete_webhook_event import ResponseIncompleteWebhookEvent as ResponseIncompleteWebhookEvent +from .fine_tuning_job_failed_webhook_event import FineTuningJobFailedWebhookEvent as FineTuningJobFailedWebhookEvent +from .fine_tuning_job_cancelled_webhook_event import ( + FineTuningJobCancelledWebhookEvent as FineTuningJobCancelledWebhookEvent, +) +from .fine_tuning_job_succeeded_webhook_event import ( + FineTuningJobSucceededWebhookEvent as FineTuningJobSucceededWebhookEvent, +) diff --git a/src/openai/types/webhooks/batch_cancelled_webhook_event.py b/src/openai/types/webhooks/batch_cancelled_webhook_event.py new file mode 100644 index 0000000000..4bbd7307a5 --- /dev/null +++ b/src/openai/types/webhooks/batch_cancelled_webhook_event.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["BatchCancelledWebhookEvent", "Data"] + + +class Data(BaseModel): + id: str + """The unique ID of the batch API request.""" + + +class BatchCancelledWebhookEvent(BaseModel): + id: str + """The unique ID of the event.""" + + created_at: int + """The Unix timestamp (in seconds) of when the batch API request was cancelled.""" + + data: Data + """Event data payload.""" + + type: Literal["batch.cancelled"] + """The type of the event. Always `batch.cancelled`.""" + + object: Optional[Literal["event"]] = None + """The object of the event. Always `event`.""" diff --git a/src/openai/types/webhooks/batch_completed_webhook_event.py b/src/openai/types/webhooks/batch_completed_webhook_event.py new file mode 100644 index 0000000000..a47ca156fa --- /dev/null +++ b/src/openai/types/webhooks/batch_completed_webhook_event.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["BatchCompletedWebhookEvent", "Data"] + + +class Data(BaseModel): + id: str + """The unique ID of the batch API request.""" + + +class BatchCompletedWebhookEvent(BaseModel): + id: str + """The unique ID of the event.""" + + created_at: int + """The Unix timestamp (in seconds) of when the batch API request was completed.""" + + data: Data + """Event data payload.""" + + type: Literal["batch.completed"] + """The type of the event. Always `batch.completed`.""" + + object: Optional[Literal["event"]] = None + """The object of the event. Always `event`.""" diff --git a/src/openai/types/webhooks/batch_expired_webhook_event.py b/src/openai/types/webhooks/batch_expired_webhook_event.py new file mode 100644 index 0000000000..e91001e8d8 --- /dev/null +++ b/src/openai/types/webhooks/batch_expired_webhook_event.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["BatchExpiredWebhookEvent", "Data"] + + +class Data(BaseModel): + id: str + """The unique ID of the batch API request.""" + + +class BatchExpiredWebhookEvent(BaseModel): + id: str + """The unique ID of the event.""" + + created_at: int + """The Unix timestamp (in seconds) of when the batch API request expired.""" + + data: Data + """Event data payload.""" + + type: Literal["batch.expired"] + """The type of the event. Always `batch.expired`.""" + + object: Optional[Literal["event"]] = None + """The object of the event. Always `event`.""" diff --git a/src/openai/types/webhooks/batch_failed_webhook_event.py b/src/openai/types/webhooks/batch_failed_webhook_event.py new file mode 100644 index 0000000000..ef80863edb --- /dev/null +++ b/src/openai/types/webhooks/batch_failed_webhook_event.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["BatchFailedWebhookEvent", "Data"] + + +class Data(BaseModel): + id: str + """The unique ID of the batch API request.""" + + +class BatchFailedWebhookEvent(BaseModel): + id: str + """The unique ID of the event.""" + + created_at: int + """The Unix timestamp (in seconds) of when the batch API request failed.""" + + data: Data + """Event data payload.""" + + type: Literal["batch.failed"] + """The type of the event. Always `batch.failed`.""" + + object: Optional[Literal["event"]] = None + """The object of the event. Always `event`.""" diff --git a/src/openai/types/webhooks/eval_run_canceled_webhook_event.py b/src/openai/types/webhooks/eval_run_canceled_webhook_event.py new file mode 100644 index 0000000000..855359f743 --- /dev/null +++ b/src/openai/types/webhooks/eval_run_canceled_webhook_event.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["EvalRunCanceledWebhookEvent", "Data"] + + +class Data(BaseModel): + id: str + """The unique ID of the eval run.""" + + +class EvalRunCanceledWebhookEvent(BaseModel): + id: str + """The unique ID of the event.""" + + created_at: int + """The Unix timestamp (in seconds) of when the eval run was canceled.""" + + data: Data + """Event data payload.""" + + type: Literal["eval.run.canceled"] + """The type of the event. Always `eval.run.canceled`.""" + + object: Optional[Literal["event"]] = None + """The object of the event. Always `event`.""" diff --git a/src/openai/types/webhooks/eval_run_failed_webhook_event.py b/src/openai/types/webhooks/eval_run_failed_webhook_event.py new file mode 100644 index 0000000000..7671680720 --- /dev/null +++ b/src/openai/types/webhooks/eval_run_failed_webhook_event.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["EvalRunFailedWebhookEvent", "Data"] + + +class Data(BaseModel): + id: str + """The unique ID of the eval run.""" + + +class EvalRunFailedWebhookEvent(BaseModel): + id: str + """The unique ID of the event.""" + + created_at: int + """The Unix timestamp (in seconds) of when the eval run failed.""" + + data: Data + """Event data payload.""" + + type: Literal["eval.run.failed"] + """The type of the event. Always `eval.run.failed`.""" + + object: Optional[Literal["event"]] = None + """The object of the event. Always `event`.""" diff --git a/src/openai/types/webhooks/eval_run_succeeded_webhook_event.py b/src/openai/types/webhooks/eval_run_succeeded_webhook_event.py new file mode 100644 index 0000000000..d0d1fc2b04 --- /dev/null +++ b/src/openai/types/webhooks/eval_run_succeeded_webhook_event.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["EvalRunSucceededWebhookEvent", "Data"] + + +class Data(BaseModel): + id: str + """The unique ID of the eval run.""" + + +class EvalRunSucceededWebhookEvent(BaseModel): + id: str + """The unique ID of the event.""" + + created_at: int + """The Unix timestamp (in seconds) of when the eval run succeeded.""" + + data: Data + """Event data payload.""" + + type: Literal["eval.run.succeeded"] + """The type of the event. Always `eval.run.succeeded`.""" + + object: Optional[Literal["event"]] = None + """The object of the event. Always `event`.""" diff --git a/src/openai/types/webhooks/fine_tuning_job_cancelled_webhook_event.py b/src/openai/types/webhooks/fine_tuning_job_cancelled_webhook_event.py new file mode 100644 index 0000000000..1fe3c06096 --- /dev/null +++ b/src/openai/types/webhooks/fine_tuning_job_cancelled_webhook_event.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["FineTuningJobCancelledWebhookEvent", "Data"] + + +class Data(BaseModel): + id: str + """The unique ID of the fine-tuning job.""" + + +class FineTuningJobCancelledWebhookEvent(BaseModel): + id: str + """The unique ID of the event.""" + + created_at: int + """The Unix timestamp (in seconds) of when the fine-tuning job was cancelled.""" + + data: Data + """Event data payload.""" + + type: Literal["fine_tuning.job.cancelled"] + """The type of the event. Always `fine_tuning.job.cancelled`.""" + + object: Optional[Literal["event"]] = None + """The object of the event. Always `event`.""" diff --git a/src/openai/types/webhooks/fine_tuning_job_failed_webhook_event.py b/src/openai/types/webhooks/fine_tuning_job_failed_webhook_event.py new file mode 100644 index 0000000000..71d899c8ef --- /dev/null +++ b/src/openai/types/webhooks/fine_tuning_job_failed_webhook_event.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["FineTuningJobFailedWebhookEvent", "Data"] + + +class Data(BaseModel): + id: str + """The unique ID of the fine-tuning job.""" + + +class FineTuningJobFailedWebhookEvent(BaseModel): + id: str + """The unique ID of the event.""" + + created_at: int + """The Unix timestamp (in seconds) of when the fine-tuning job failed.""" + + data: Data + """Event data payload.""" + + type: Literal["fine_tuning.job.failed"] + """The type of the event. Always `fine_tuning.job.failed`.""" + + object: Optional[Literal["event"]] = None + """The object of the event. Always `event`.""" diff --git a/src/openai/types/webhooks/fine_tuning_job_succeeded_webhook_event.py b/src/openai/types/webhooks/fine_tuning_job_succeeded_webhook_event.py new file mode 100644 index 0000000000..470f1fcfaa --- /dev/null +++ b/src/openai/types/webhooks/fine_tuning_job_succeeded_webhook_event.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["FineTuningJobSucceededWebhookEvent", "Data"] + + +class Data(BaseModel): + id: str + """The unique ID of the fine-tuning job.""" + + +class FineTuningJobSucceededWebhookEvent(BaseModel): + id: str + """The unique ID of the event.""" + + created_at: int + """The Unix timestamp (in seconds) of when the fine-tuning job succeeded.""" + + data: Data + """Event data payload.""" + + type: Literal["fine_tuning.job.succeeded"] + """The type of the event. Always `fine_tuning.job.succeeded`.""" + + object: Optional[Literal["event"]] = None + """The object of the event. Always `event`.""" diff --git a/src/openai/types/webhooks/response_cancelled_webhook_event.py b/src/openai/types/webhooks/response_cancelled_webhook_event.py new file mode 100644 index 0000000000..443e360e90 --- /dev/null +++ b/src/openai/types/webhooks/response_cancelled_webhook_event.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseCancelledWebhookEvent", "Data"] + + +class Data(BaseModel): + id: str + """The unique ID of the model response.""" + + +class ResponseCancelledWebhookEvent(BaseModel): + id: str + """The unique ID of the event.""" + + created_at: int + """The Unix timestamp (in seconds) of when the model response was cancelled.""" + + data: Data + """Event data payload.""" + + type: Literal["response.cancelled"] + """The type of the event. Always `response.cancelled`.""" + + object: Optional[Literal["event"]] = None + """The object of the event. Always `event`.""" diff --git a/src/openai/types/webhooks/response_completed_webhook_event.py b/src/openai/types/webhooks/response_completed_webhook_event.py new file mode 100644 index 0000000000..ac1feff32b --- /dev/null +++ b/src/openai/types/webhooks/response_completed_webhook_event.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseCompletedWebhookEvent", "Data"] + + +class Data(BaseModel): + id: str + """The unique ID of the model response.""" + + +class ResponseCompletedWebhookEvent(BaseModel): + id: str + """The unique ID of the event.""" + + created_at: int + """The Unix timestamp (in seconds) of when the model response was completed.""" + + data: Data + """Event data payload.""" + + type: Literal["response.completed"] + """The type of the event. Always `response.completed`.""" + + object: Optional[Literal["event"]] = None + """The object of the event. Always `event`.""" diff --git a/src/openai/types/webhooks/response_failed_webhook_event.py b/src/openai/types/webhooks/response_failed_webhook_event.py new file mode 100644 index 0000000000..5b4ba65e18 --- /dev/null +++ b/src/openai/types/webhooks/response_failed_webhook_event.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseFailedWebhookEvent", "Data"] + + +class Data(BaseModel): + id: str + """The unique ID of the model response.""" + + +class ResponseFailedWebhookEvent(BaseModel): + id: str + """The unique ID of the event.""" + + created_at: int + """The Unix timestamp (in seconds) of when the model response failed.""" + + data: Data + """Event data payload.""" + + type: Literal["response.failed"] + """The type of the event. Always `response.failed`.""" + + object: Optional[Literal["event"]] = None + """The object of the event. Always `event`.""" diff --git a/src/openai/types/webhooks/response_incomplete_webhook_event.py b/src/openai/types/webhooks/response_incomplete_webhook_event.py new file mode 100644 index 0000000000..01609314e0 --- /dev/null +++ b/src/openai/types/webhooks/response_incomplete_webhook_event.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseIncompleteWebhookEvent", "Data"] + + +class Data(BaseModel): + id: str + """The unique ID of the model response.""" + + +class ResponseIncompleteWebhookEvent(BaseModel): + id: str + """The unique ID of the event.""" + + created_at: int + """The Unix timestamp (in seconds) of when the model response was interrupted.""" + + data: Data + """Event data payload.""" + + type: Literal["response.incomplete"] + """The type of the event. Always `response.incomplete`.""" + + object: Optional[Literal["event"]] = None + """The object of the event. Always `event`.""" diff --git a/src/openai/types/webhooks/unwrap_webhook_event.py b/src/openai/types/webhooks/unwrap_webhook_event.py new file mode 100644 index 0000000000..91091af32f --- /dev/null +++ b/src/openai/types/webhooks/unwrap_webhook_event.py @@ -0,0 +1,42 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from typing_extensions import Annotated, TypeAlias + +from ..._utils import PropertyInfo +from .batch_failed_webhook_event import BatchFailedWebhookEvent +from .batch_expired_webhook_event import BatchExpiredWebhookEvent +from .batch_cancelled_webhook_event import BatchCancelledWebhookEvent +from .batch_completed_webhook_event import BatchCompletedWebhookEvent +from .eval_run_failed_webhook_event import EvalRunFailedWebhookEvent +from .response_failed_webhook_event import ResponseFailedWebhookEvent +from .eval_run_canceled_webhook_event import EvalRunCanceledWebhookEvent +from .eval_run_succeeded_webhook_event import EvalRunSucceededWebhookEvent +from .response_cancelled_webhook_event import ResponseCancelledWebhookEvent +from .response_completed_webhook_event import ResponseCompletedWebhookEvent +from .response_incomplete_webhook_event import ResponseIncompleteWebhookEvent +from .fine_tuning_job_failed_webhook_event import FineTuningJobFailedWebhookEvent +from .fine_tuning_job_cancelled_webhook_event import FineTuningJobCancelledWebhookEvent +from .fine_tuning_job_succeeded_webhook_event import FineTuningJobSucceededWebhookEvent + +__all__ = ["UnwrapWebhookEvent"] + +UnwrapWebhookEvent: TypeAlias = Annotated[ + Union[ + BatchCancelledWebhookEvent, + BatchCompletedWebhookEvent, + BatchExpiredWebhookEvent, + BatchFailedWebhookEvent, + EvalRunCanceledWebhookEvent, + EvalRunFailedWebhookEvent, + EvalRunSucceededWebhookEvent, + FineTuningJobCancelledWebhookEvent, + FineTuningJobFailedWebhookEvent, + FineTuningJobSucceededWebhookEvent, + ResponseCancelledWebhookEvent, + ResponseCompletedWebhookEvent, + ResponseFailedWebhookEvent, + ResponseIncompleteWebhookEvent, + ], + PropertyInfo(discriminator="type"), +] diff --git a/tests/api_resources/responses/test_input_items.py b/tests/api_resources/responses/test_input_items.py index b28f5638c5..e8e3893bad 100644 --- a/tests/api_resources/responses/test_input_items.py +++ b/tests/api_resources/responses/test_input_items.py @@ -31,7 +31,7 @@ def test_method_list_with_all_params(self, client: OpenAI) -> None: response_id="response_id", after="after", before="before", - include=["file_search_call.results"], + include=["code_interpreter_call.outputs"], limit=0, order="asc", ) @@ -87,7 +87,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> N response_id="response_id", after="after", before="before", - include=["file_search_call.results"], + include=["code_interpreter_call.outputs"], limit=0, order="asc", ) diff --git a/tests/api_resources/test_responses.py b/tests/api_resources/test_responses.py index 5b7559655a..9c76928c8c 100644 --- a/tests/api_resources/test_responses.py +++ b/tests/api_resources/test_responses.py @@ -28,10 +28,11 @@ def test_method_create_overload_1(self, client: OpenAI) -> None: def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: response = client.responses.create( background=True, - include=["file_search_call.results"], + include=["code_interpreter_call.outputs"], input="string", instructions="instructions", max_output_tokens=0, + max_tool_calls=0, metadata={"foo": "string"}, model="gpt-4o", parallel_tool_calls=True, @@ -61,6 +62,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: "description": "description", } ], + top_logprobs=0, top_p=1, truncation="auto", user="user-1234", @@ -99,10 +101,11 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: response_stream = client.responses.create( stream=True, background=True, - include=["file_search_call.results"], + include=["code_interpreter_call.outputs"], input="string", instructions="instructions", max_output_tokens=0, + max_tool_calls=0, metadata={"foo": "string"}, model="gpt-4o", parallel_tool_calls=True, @@ -131,6 +134,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: "description": "description", } ], + top_logprobs=0, top_p=1, truncation="auto", user="user-1234", @@ -171,7 +175,7 @@ def test_method_retrieve_overload_1(self, client: OpenAI) -> None: def test_method_retrieve_with_all_params_overload_1(self, client: OpenAI) -> None: response = client.responses.retrieve( response_id="resp_677efb5139a88190b512bc3fef8e535d", - include=["file_search_call.results"], + include=["code_interpreter_call.outputs"], starting_after=0, stream=False, ) @@ -221,7 +225,7 @@ def test_method_retrieve_with_all_params_overload_2(self, client: OpenAI) -> Non response_stream = client.responses.retrieve( response_id="resp_677efb5139a88190b512bc3fef8e535d", stream=True, - include=["file_search_call.results"], + include=["code_interpreter_call.outputs"], starting_after=0, ) response_stream.response.close() @@ -350,10 +354,11 @@ async def test_method_create_overload_1(self, async_client: AsyncOpenAI) -> None async def test_method_create_with_all_params_overload_1(self, async_client: AsyncOpenAI) -> None: response = await async_client.responses.create( background=True, - include=["file_search_call.results"], + include=["code_interpreter_call.outputs"], input="string", instructions="instructions", max_output_tokens=0, + max_tool_calls=0, metadata={"foo": "string"}, model="gpt-4o", parallel_tool_calls=True, @@ -383,6 +388,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn "description": "description", } ], + top_logprobs=0, top_p=1, truncation="auto", user="user-1234", @@ -421,10 +427,11 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn response_stream = await async_client.responses.create( stream=True, background=True, - include=["file_search_call.results"], + include=["code_interpreter_call.outputs"], input="string", instructions="instructions", max_output_tokens=0, + max_tool_calls=0, metadata={"foo": "string"}, model="gpt-4o", parallel_tool_calls=True, @@ -453,6 +460,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn "description": "description", } ], + top_logprobs=0, top_p=1, truncation="auto", user="user-1234", @@ -493,7 +501,7 @@ async def test_method_retrieve_overload_1(self, async_client: AsyncOpenAI) -> No async def test_method_retrieve_with_all_params_overload_1(self, async_client: AsyncOpenAI) -> None: response = await async_client.responses.retrieve( response_id="resp_677efb5139a88190b512bc3fef8e535d", - include=["file_search_call.results"], + include=["code_interpreter_call.outputs"], starting_after=0, stream=False, ) @@ -543,7 +551,7 @@ async def test_method_retrieve_with_all_params_overload_2(self, async_client: As response_stream = await async_client.responses.retrieve( response_id="resp_677efb5139a88190b512bc3fef8e535d", stream=True, - include=["file_search_call.results"], + include=["code_interpreter_call.outputs"], starting_after=0, ) await response_stream.response.aclose() diff --git a/tests/api_resources/test_webhooks.py b/tests/api_resources/test_webhooks.py new file mode 100644 index 0000000000..6b404998e1 --- /dev/null +++ b/tests/api_resources/test_webhooks.py @@ -0,0 +1,284 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from unittest import mock + +import pytest + +import openai +from openai._exceptions import InvalidWebhookSignatureError + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + +# Standardized test constants (matches TypeScript implementation) +TEST_SECRET = "whsec_RdvaYFYUXuIFuEbvZHwMfYFhUf7aMYjYcmM24+Aj40c=" +TEST_PAYLOAD = '{"id": "evt_685c059ae3a481909bdc86819b066fb6", "object": "event", "created_at": 1750861210, "type": "response.completed", "data": {"id": "resp_123"}}' +TEST_TIMESTAMP = 1750861210 # Fixed timestamp that matches our test signature +TEST_WEBHOOK_ID = "wh_685c059ae39c8190af8c71ed1022a24d" +TEST_SIGNATURE = "v1,gUAg4R2hWouRZqRQG4uJypNS8YK885G838+EHb4nKBY=" + + +def create_test_headers( + timestamp: int | None = None, signature: str | None = None, webhook_id: str | None = None +) -> dict[str, str]: + """Helper function to create test headers""" + return { + "webhook-signature": signature or TEST_SIGNATURE, + "webhook-timestamp": str(timestamp or TEST_TIMESTAMP), + "webhook-id": webhook_id or TEST_WEBHOOK_ID, + } + + +class TestWebhooks: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @mock.patch("time.time", mock.MagicMock(return_value=TEST_TIMESTAMP)) + @parametrize + def test_unwrap_with_secret(self, client: openai.OpenAI) -> None: + headers = create_test_headers() + unwrapped = client.webhooks.unwrap(TEST_PAYLOAD, headers, secret=TEST_SECRET) + assert unwrapped.id == "evt_685c059ae3a481909bdc86819b066fb6" + assert unwrapped.created_at == 1750861210 + + @parametrize + def test_unwrap_without_secret(self, client: openai.OpenAI) -> None: + headers = create_test_headers() + with pytest.raises(ValueError, match="The webhook secret must either be set"): + client.webhooks.unwrap(TEST_PAYLOAD, headers) + + @mock.patch("time.time", mock.MagicMock(return_value=TEST_TIMESTAMP)) + @parametrize + def test_verify_signature_valid(self, client: openai.OpenAI) -> None: + headers = create_test_headers() + # Should not raise - this is a truly valid signature for this timestamp + client.webhooks.verify_signature(TEST_PAYLOAD, headers, secret=TEST_SECRET) + + @parametrize + def test_verify_signature_invalid_secret_format(self, client: openai.OpenAI) -> None: + headers = create_test_headers() + with pytest.raises(ValueError, match="The webhook secret must either be set"): + client.webhooks.verify_signature(TEST_PAYLOAD, headers, secret=None) + + @mock.patch("time.time", mock.MagicMock(return_value=TEST_TIMESTAMP)) + @parametrize + def test_verify_signature_invalid(self, client: openai.OpenAI) -> None: + headers = create_test_headers() + with pytest.raises(InvalidWebhookSignatureError, match="The given webhook signature does not match"): + client.webhooks.verify_signature(TEST_PAYLOAD, headers, secret="invalid_secret") + + @parametrize + def test_verify_signature_missing_webhook_signature_header(self, client: openai.OpenAI) -> None: + headers = create_test_headers(signature=None) + del headers["webhook-signature"] + with pytest.raises(ValueError, match="Could not find webhook-signature header"): + client.webhooks.verify_signature(TEST_PAYLOAD, headers, secret=TEST_SECRET) + + @parametrize + def test_verify_signature_missing_webhook_timestamp_header(self, client: openai.OpenAI) -> None: + headers = create_test_headers() + del headers["webhook-timestamp"] + with pytest.raises(ValueError, match="Could not find webhook-timestamp header"): + client.webhooks.verify_signature(TEST_PAYLOAD, headers, secret=TEST_SECRET) + + @parametrize + def test_verify_signature_missing_webhook_id_header(self, client: openai.OpenAI) -> None: + headers = create_test_headers() + del headers["webhook-id"] + with pytest.raises(ValueError, match="Could not find webhook-id header"): + client.webhooks.verify_signature(TEST_PAYLOAD, headers, secret=TEST_SECRET) + + @mock.patch("time.time", mock.MagicMock(return_value=TEST_TIMESTAMP)) + @parametrize + def test_verify_signature_payload_bytes(self, client: openai.OpenAI) -> None: + headers = create_test_headers() + client.webhooks.verify_signature(TEST_PAYLOAD.encode("utf-8"), headers, secret=TEST_SECRET) + + @mock.patch("time.time", mock.MagicMock(return_value=TEST_TIMESTAMP)) + def test_unwrap_with_client_secret(self) -> None: + test_client = openai.OpenAI(base_url=base_url, api_key="test-api-key", webhook_secret=TEST_SECRET) + headers = create_test_headers() + + unwrapped = test_client.webhooks.unwrap(TEST_PAYLOAD, headers) + assert unwrapped.id == "evt_685c059ae3a481909bdc86819b066fb6" + assert unwrapped.created_at == 1750861210 + + @parametrize + def test_verify_signature_timestamp_too_old(self, client: openai.OpenAI) -> None: + # Use a timestamp that's older than 5 minutes from our test timestamp + old_timestamp = TEST_TIMESTAMP - 400 # 6 minutes 40 seconds ago + headers = create_test_headers(timestamp=old_timestamp, signature="v1,dummy_signature") + + with pytest.raises(InvalidWebhookSignatureError, match="Webhook timestamp is too old"): + client.webhooks.verify_signature(TEST_PAYLOAD, headers, secret=TEST_SECRET) + + @mock.patch("time.time", mock.MagicMock(return_value=TEST_TIMESTAMP)) + @parametrize + def test_verify_signature_timestamp_too_new(self, client: openai.OpenAI) -> None: + # Use a timestamp that's in the future beyond tolerance from our test timestamp + future_timestamp = TEST_TIMESTAMP + 400 # 6 minutes 40 seconds in the future + headers = create_test_headers(timestamp=future_timestamp, signature="v1,dummy_signature") + + with pytest.raises(InvalidWebhookSignatureError, match="Webhook timestamp is too new"): + client.webhooks.verify_signature(TEST_PAYLOAD, headers, secret=TEST_SECRET) + + @mock.patch("time.time", mock.MagicMock(return_value=TEST_TIMESTAMP)) + @parametrize + def test_verify_signature_custom_tolerance(self, client: openai.OpenAI) -> None: + # Use a timestamp that's older than default tolerance but within custom tolerance + old_timestamp = TEST_TIMESTAMP - 400 # 6 minutes 40 seconds ago from test timestamp + headers = create_test_headers(timestamp=old_timestamp, signature="v1,dummy_signature") + + # Should fail with default tolerance + with pytest.raises(InvalidWebhookSignatureError, match="Webhook timestamp is too old"): + client.webhooks.verify_signature(TEST_PAYLOAD, headers, secret=TEST_SECRET) + + # Should also fail with custom tolerance of 10 minutes (signature won't match) + with pytest.raises(InvalidWebhookSignatureError, match="The given webhook signature does not match"): + client.webhooks.verify_signature(TEST_PAYLOAD, headers, secret=TEST_SECRET, tolerance=600) + + @mock.patch("time.time", mock.MagicMock(return_value=TEST_TIMESTAMP)) + @parametrize + def test_verify_signature_recent_timestamp_succeeds(self, client: openai.OpenAI) -> None: + # Use a recent timestamp with dummy signature + headers = create_test_headers(signature="v1,dummy_signature") + + # Should fail on signature verification (not timestamp validation) + with pytest.raises(InvalidWebhookSignatureError, match="The given webhook signature does not match"): + client.webhooks.verify_signature(TEST_PAYLOAD, headers, secret=TEST_SECRET) + + @mock.patch("time.time", mock.MagicMock(return_value=TEST_TIMESTAMP)) + @parametrize + def test_verify_signature_multiple_signatures_one_valid(self, client: openai.OpenAI) -> None: + # Test multiple signatures: one invalid, one valid + multiple_signatures = f"v1,invalid_signature {TEST_SIGNATURE}" + headers = create_test_headers(signature=multiple_signatures) + + # Should not raise when at least one signature is valid + client.webhooks.verify_signature(TEST_PAYLOAD, headers, secret=TEST_SECRET) + + @mock.patch("time.time", mock.MagicMock(return_value=TEST_TIMESTAMP)) + @parametrize + def test_verify_signature_multiple_signatures_all_invalid(self, client: openai.OpenAI) -> None: + # Test multiple invalid signatures + multiple_invalid_signatures = "v1,invalid_signature1 v1,invalid_signature2" + headers = create_test_headers(signature=multiple_invalid_signatures) + + with pytest.raises(InvalidWebhookSignatureError, match="The given webhook signature does not match"): + client.webhooks.verify_signature(TEST_PAYLOAD, headers, secret=TEST_SECRET) + + +class TestAsyncWebhooks: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @mock.patch("time.time", mock.MagicMock(return_value=TEST_TIMESTAMP)) + @parametrize + async def test_unwrap_with_secret(self, async_client: openai.AsyncOpenAI) -> None: + headers = create_test_headers() + unwrapped = async_client.webhooks.unwrap(TEST_PAYLOAD, headers, secret=TEST_SECRET) + assert unwrapped.id == "evt_685c059ae3a481909bdc86819b066fb6" + assert unwrapped.created_at == 1750861210 + + @parametrize + async def test_unwrap_without_secret(self, async_client: openai.AsyncOpenAI) -> None: + headers = create_test_headers() + with pytest.raises(ValueError, match="The webhook secret must either be set"): + async_client.webhooks.unwrap(TEST_PAYLOAD, headers) + + @mock.patch("time.time", mock.MagicMock(return_value=TEST_TIMESTAMP)) + @parametrize + async def test_verify_signature_valid(self, async_client: openai.AsyncOpenAI) -> None: + headers = create_test_headers() + # Should not raise - this is a truly valid signature for this timestamp + async_client.webhooks.verify_signature(TEST_PAYLOAD, headers, secret=TEST_SECRET) + + @parametrize + async def test_verify_signature_invalid_secret_format(self, async_client: openai.AsyncOpenAI) -> None: + headers = create_test_headers() + with pytest.raises(ValueError, match="The webhook secret must either be set"): + async_client.webhooks.verify_signature(TEST_PAYLOAD, headers, secret=None) + + @mock.patch("time.time", mock.MagicMock(return_value=TEST_TIMESTAMP)) + @parametrize + async def test_verify_signature_invalid(self, async_client: openai.AsyncOpenAI) -> None: + headers = create_test_headers() + with pytest.raises(InvalidWebhookSignatureError, match="The given webhook signature does not match"): + async_client.webhooks.verify_signature(TEST_PAYLOAD, headers, secret="invalid_secret") + + @parametrize + async def test_verify_signature_missing_webhook_signature_header(self, async_client: openai.AsyncOpenAI) -> None: + headers = create_test_headers() + del headers["webhook-signature"] + with pytest.raises(ValueError, match="Could not find webhook-signature header"): + async_client.webhooks.verify_signature(TEST_PAYLOAD, headers, secret=TEST_SECRET) + + @parametrize + async def test_verify_signature_missing_webhook_timestamp_header(self, async_client: openai.AsyncOpenAI) -> None: + headers = create_test_headers() + del headers["webhook-timestamp"] + with pytest.raises(ValueError, match="Could not find webhook-timestamp header"): + async_client.webhooks.verify_signature(TEST_PAYLOAD, headers, secret=TEST_SECRET) + + @parametrize + async def test_verify_signature_missing_webhook_id_header(self, async_client: openai.AsyncOpenAI) -> None: + headers = create_test_headers() + del headers["webhook-id"] + with pytest.raises(ValueError, match="Could not find webhook-id header"): + async_client.webhooks.verify_signature(TEST_PAYLOAD, headers, secret=TEST_SECRET) + + @mock.patch("time.time", mock.MagicMock(return_value=TEST_TIMESTAMP)) + @parametrize + async def test_verify_signature_payload_bytes(self, async_client: openai.AsyncOpenAI) -> None: + headers = create_test_headers() + async_client.webhooks.verify_signature(TEST_PAYLOAD.encode("utf-8"), headers, secret=TEST_SECRET) + + @mock.patch("time.time", mock.MagicMock(return_value=TEST_TIMESTAMP)) + async def test_unwrap_with_client_secret(self) -> None: + test_async_client = openai.AsyncOpenAI(base_url=base_url, api_key="test-api-key", webhook_secret=TEST_SECRET) + headers = create_test_headers() + + unwrapped = test_async_client.webhooks.unwrap(TEST_PAYLOAD, headers) + assert unwrapped.id == "evt_685c059ae3a481909bdc86819b066fb6" + assert unwrapped.created_at == 1750861210 + + @parametrize + async def test_verify_signature_timestamp_too_old(self, async_client: openai.AsyncOpenAI) -> None: + # Use a timestamp that's older than 5 minutes from our test timestamp + old_timestamp = TEST_TIMESTAMP - 400 # 6 minutes 40 seconds ago + headers = create_test_headers(timestamp=old_timestamp, signature="v1,dummy_signature") + + with pytest.raises(InvalidWebhookSignatureError, match="Webhook timestamp is too old"): + async_client.webhooks.verify_signature(TEST_PAYLOAD, headers, secret=TEST_SECRET) + + @mock.patch("time.time", mock.MagicMock(return_value=TEST_TIMESTAMP)) + @parametrize + async def test_verify_signature_timestamp_too_new(self, async_client: openai.AsyncOpenAI) -> None: + # Use a timestamp that's in the future beyond tolerance from our test timestamp + future_timestamp = TEST_TIMESTAMP + 400 # 6 minutes 40 seconds in the future + headers = create_test_headers(timestamp=future_timestamp, signature="v1,dummy_signature") + + with pytest.raises(InvalidWebhookSignatureError, match="Webhook timestamp is too new"): + async_client.webhooks.verify_signature(TEST_PAYLOAD, headers, secret=TEST_SECRET) + + @mock.patch("time.time", mock.MagicMock(return_value=TEST_TIMESTAMP)) + @parametrize + async def test_verify_signature_multiple_signatures_one_valid(self, async_client: openai.AsyncOpenAI) -> None: + # Test multiple signatures: one invalid, one valid + multiple_signatures = f"v1,invalid_signature {TEST_SIGNATURE}" + headers = create_test_headers(signature=multiple_signatures) + + # Should not raise when at least one signature is valid + async_client.webhooks.verify_signature(TEST_PAYLOAD, headers, secret=TEST_SECRET) + + @mock.patch("time.time", mock.MagicMock(return_value=TEST_TIMESTAMP)) + @parametrize + async def test_verify_signature_multiple_signatures_all_invalid(self, async_client: openai.AsyncOpenAI) -> None: + # Test multiple invalid signatures + multiple_invalid_signatures = "v1,invalid_signature1 v1,invalid_signature2" + headers = create_test_headers(signature=multiple_invalid_signatures) + + with pytest.raises(InvalidWebhookSignatureError, match="The given webhook signature does not match"): + async_client.webhooks.verify_signature(TEST_PAYLOAD, headers, secret=TEST_SECRET) diff --git a/tests/lib/chat/test_completions.py b/tests/lib/chat/test_completions.py index 62fdd34c0a..e7143bbb68 100644 --- a/tests/lib/chat/test_completions.py +++ b/tests/lib/chat/test_completions.py @@ -33,7 +33,7 @@ @pytest.mark.respx(base_url=base_url) def test_parse_nothing(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None: completion = _make_snapshot_request( - lambda c: c.beta.chat.completions.parse( + lambda c: c.chat.completions.parse( model="gpt-4o-2024-08-06", messages=[ { @@ -101,7 +101,7 @@ class Location(BaseModel): units: Literal["c", "f"] completion = _make_snapshot_request( - lambda c: c.beta.chat.completions.parse( + lambda c: c.chat.completions.parse( model="gpt-4o-2024-08-06", messages=[ { @@ -171,7 +171,7 @@ class Location(BaseModel): units: Optional[Literal["c", "f"]] = None completion = _make_snapshot_request( - lambda c: c.beta.chat.completions.parse( + lambda c: c.chat.completions.parse( model="gpt-4o-2024-08-06", messages=[ { @@ -248,7 +248,7 @@ class ColorDetection(BaseModel): ColorDetection.update_forward_refs(**locals()) # type: ignore completion = _make_snapshot_request( - lambda c: c.beta.chat.completions.parse( + lambda c: c.chat.completions.parse( model="gpt-4o-2024-08-06", messages=[ {"role": "user", "content": "What color is a Coke can?"}, @@ -293,7 +293,7 @@ class Location(BaseModel): units: Literal["c", "f"] completion = _make_snapshot_request( - lambda c: c.beta.chat.completions.parse( + lambda c: c.chat.completions.parse( model="gpt-4o-2024-08-06", messages=[ { @@ -376,7 +376,7 @@ class CalendarEvent: participants: List[str] completion = _make_snapshot_request( - lambda c: c.beta.chat.completions.parse( + lambda c: c.chat.completions.parse( model="gpt-4o-2024-08-06", messages=[ {"role": "system", "content": "Extract the event information."}, @@ -437,7 +437,7 @@ class CalendarEvent: @pytest.mark.respx(base_url=base_url) def test_pydantic_tool_model_all_types(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None: completion = _make_snapshot_request( - lambda c: c.beta.chat.completions.parse( + lambda c: c.chat.completions.parse( model="gpt-4o-2024-08-06", messages=[ { @@ -522,7 +522,7 @@ class Location(BaseModel): with pytest.raises(openai.LengthFinishReasonError): _make_snapshot_request( - lambda c: c.beta.chat.completions.parse( + lambda c: c.chat.completions.parse( model="gpt-4o-2024-08-06", messages=[ { @@ -549,7 +549,7 @@ class Location(BaseModel): units: Literal["c", "f"] completion = _make_snapshot_request( - lambda c: c.beta.chat.completions.parse( + lambda c: c.chat.completions.parse( model="gpt-4o-2024-08-06", messages=[ { @@ -597,7 +597,7 @@ class GetWeatherArgs(BaseModel): units: Literal["c", "f"] = "c" completion = _make_snapshot_request( - lambda c: c.beta.chat.completions.parse( + lambda c: c.chat.completions.parse( model="gpt-4o-2024-08-06", messages=[ { @@ -663,7 +663,7 @@ class GetStockPrice(BaseModel): exchange: str completion = _make_snapshot_request( - lambda c: c.beta.chat.completions.parse( + lambda c: c.chat.completions.parse( model="gpt-4o-2024-08-06", messages=[ { @@ -734,7 +734,7 @@ class GetStockPrice(BaseModel): @pytest.mark.respx(base_url=base_url) def test_parse_strict_tools(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None: completion = _make_snapshot_request( - lambda c: c.beta.chat.completions.parse( + lambda c: c.chat.completions.parse( model="gpt-4o-2024-08-06", messages=[ { @@ -808,7 +808,7 @@ def test_parse_non_strict_tools(client: OpenAI) -> None: with pytest.raises( ValueError, match="`get_weather` is not strict. Only `strict` function tools can be auto-parsed" ): - client.beta.chat.completions.parse( + client.chat.completions.parse( model="gpt-4o-2024-08-06", messages=[], tools=[ @@ -831,7 +831,7 @@ class Location(BaseModel): units: Literal["c", "f"] response = _make_snapshot_request( - lambda c: c.beta.chat.completions.with_raw_response.parse( + lambda c: c.chat.completions.with_raw_response.parse( model="gpt-4o-2024-08-06", messages=[ { @@ -847,7 +847,7 @@ class Location(BaseModel): mock_client=client, respx_mock=respx_mock, ) - assert response.http_request.headers.get("x-stainless-helper-method") == "beta.chat.completions.parse" + assert response.http_request.headers.get("x-stainless-helper-method") == "chat.completions.parse" completion = response.parse() message = completion.choices[0].message @@ -907,7 +907,7 @@ class Location(BaseModel): units: Literal["c", "f"] response = await _make_async_snapshot_request( - lambda c: c.beta.chat.completions.with_raw_response.parse( + lambda c: c.chat.completions.with_raw_response.parse( model="gpt-4o-2024-08-06", messages=[ { @@ -923,7 +923,7 @@ class Location(BaseModel): mock_client=async_client, respx_mock=respx_mock, ) - assert response.http_request.headers.get("x-stainless-helper-method") == "beta.chat.completions.parse" + assert response.http_request.headers.get("x-stainless-helper-method") == "chat.completions.parse" completion = response.parse() message = completion.choices[0].message @@ -978,7 +978,7 @@ def test_parse_method_in_sync(sync: bool, client: OpenAI, async_client: AsyncOpe assert_signatures_in_sync( checking_client.chat.completions.create, - checking_client.beta.chat.completions.parse, + checking_client.chat.completions.parse, exclude_params={"response_format", "stream"}, ) diff --git a/tests/lib/chat/test_completions_streaming.py b/tests/lib/chat/test_completions_streaming.py index 5852c5a343..4680a73e3a 100644 --- a/tests/lib/chat/test_completions_streaming.py +++ b/tests/lib/chat/test_completions_streaming.py @@ -41,7 +41,7 @@ @pytest.mark.respx(base_url=base_url) def test_parse_nothing(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None: listener = _make_stream_snapshot_request( - lambda c: c.beta.chat.completions.stream( + lambda c: c.chat.completions.stream( model="gpt-4o-2024-08-06", messages=[ { @@ -103,7 +103,7 @@ def on_event(stream: ChatCompletionStream[Location], event: ChatCompletionStream done_snapshots.append(model_copy(stream.current_completion_snapshot, deep=True)) listener = _make_stream_snapshot_request( - lambda c: c.beta.chat.completions.stream( + lambda c: c.chat.completions.stream( model="gpt-4o-2024-08-06", messages=[ { @@ -195,7 +195,7 @@ class Location(BaseModel): units: Literal["c", "f"] listener = _make_stream_snapshot_request( - lambda c: c.beta.chat.completions.stream( + lambda c: c.chat.completions.stream( model="gpt-4o-2024-08-06", messages=[ { @@ -374,7 +374,7 @@ class Location(BaseModel): with pytest.raises(openai.LengthFinishReasonError): _make_stream_snapshot_request( - lambda c: c.beta.chat.completions.stream( + lambda c: c.chat.completions.stream( model="gpt-4o-2024-08-06", messages=[ { @@ -399,7 +399,7 @@ class Location(BaseModel): units: Literal["c", "f"] listener = _make_stream_snapshot_request( - lambda c: c.beta.chat.completions.stream( + lambda c: c.chat.completions.stream( model="gpt-4o-2024-08-06", messages=[ { @@ -444,7 +444,7 @@ class Location(BaseModel): @pytest.mark.respx(base_url=base_url) def test_content_logprobs_events(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None: listener = _make_stream_snapshot_request( - lambda c: c.beta.chat.completions.stream( + lambda c: c.chat.completions.stream( model="gpt-4o-2024-08-06", messages=[ { @@ -523,7 +523,7 @@ class Location(BaseModel): units: Literal["c", "f"] listener = _make_stream_snapshot_request( - lambda c: c.beta.chat.completions.stream( + lambda c: c.chat.completions.stream( model="gpt-4o-2024-08-06", messages=[ { @@ -635,7 +635,7 @@ class GetWeatherArgs(BaseModel): units: Literal["c", "f"] = "c" listener = _make_stream_snapshot_request( - lambda c: c.beta.chat.completions.stream( + lambda c: c.chat.completions.stream( model="gpt-4o-2024-08-06", messages=[ { @@ -733,7 +733,7 @@ class GetStockPrice(BaseModel): exchange: str listener = _make_stream_snapshot_request( - lambda c: c.beta.chat.completions.stream( + lambda c: c.chat.completions.stream( model="gpt-4o-2024-08-06", messages=[ { @@ -831,7 +831,7 @@ class GetStockPrice(BaseModel): @pytest.mark.respx(base_url=base_url) def test_parse_strict_tools(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None: listener = _make_stream_snapshot_request( - lambda c: c.beta.chat.completions.stream( + lambda c: c.chat.completions.stream( model="gpt-4o-2024-08-06", messages=[ { @@ -903,7 +903,7 @@ def test_parse_strict_tools(client: OpenAI, respx_mock: MockRouter, monkeypatch: @pytest.mark.respx(base_url=base_url) def test_non_pydantic_response_format(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None: listener = _make_stream_snapshot_request( - lambda c: c.beta.chat.completions.stream( + lambda c: c.chat.completions.stream( model="gpt-4o-2024-08-06", messages=[ { @@ -951,7 +951,7 @@ def test_allows_non_strict_tools_but_no_parsing( client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch ) -> None: listener = _make_stream_snapshot_request( - lambda c: c.beta.chat.completions.stream( + lambda c: c.chat.completions.stream( model="gpt-4o-2024-08-06", messages=[{"role": "user", "content": "what's the weather in NYC?"}], tools=[ @@ -1069,7 +1069,7 @@ def test_stream_method_in_sync(sync: bool, client: OpenAI, async_client: AsyncOp assert_signatures_in_sync( checking_client.chat.completions.create, - checking_client.beta.chat.completions.stream, + checking_client.chat.completions.stream, exclude_params={"response_format", "stream"}, ) diff --git a/tests/test_client.py b/tests/test_client.py index 3d08a0a601..988e5d994c 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -192,6 +192,7 @@ def test_copy_signature(self) -> None: copy_param = copy_signature.parameters.get(name) assert copy_param is not None, f"copy() signature is missing the {name} param" + @pytest.mark.skipif(sys.version_info >= (3, 10), reason="fails because of a memory leak that started from 3.12") def test_copy_build_request(self) -> None: options = FinalRequestOptions(method="get", url="/foo") @@ -1074,6 +1075,7 @@ def test_copy_signature(self) -> None: copy_param = copy_signature.parameters.get(name) assert copy_param is not None, f"copy() signature is missing the {name} param" + @pytest.mark.skipif(sys.version_info >= (3, 10), reason="fails because of a memory leak that started from 3.12") def test_copy_build_request(self) -> None: options = FinalRequestOptions(method="get", url="/foo") diff --git a/tests/test_module_client.py b/tests/test_module_client.py index 6bab33a1d7..9c9a1addab 100644 --- a/tests/test_module_client.py +++ b/tests/test_module_client.py @@ -17,6 +17,7 @@ def reset_state() -> None: openai.api_key = None or "My API Key" openai.organization = None openai.project = None + openai.webhook_secret = None openai.base_url = None openai.timeout = DEFAULT_TIMEOUT openai.max_retries = DEFAULT_MAX_RETRIES From 4f99c4e6f9978b91a63e7e985e271bf5cc0e30ec Mon Sep 17 00:00:00 2001 From: David Meadows Date: Thu, 26 Jun 2025 13:44:27 -0400 Subject: [PATCH 362/769] chore(docs): update README to include links to docs on Webhooks --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 763428ddc8..b38ef578d2 100644 --- a/README.md +++ b/README.md @@ -410,6 +410,8 @@ The async client uses the exact same interface. If you pass a [`PathLike`](https Verifying webhook signatures is _optional but encouraged_. +For more information about webhooks, see [the API docs](https://platform.openai.com/docs/guides/webhooks). + ### Parsing webhook payloads For most use cases, you will likely want to verify the webhook and parse the payload at the same time. To achieve this, we provide the method `client.webhooks.unwrap()`, which parses a webhook request and verifies that it was sent by OpenAI. This method will raise an error if the signature is invalid. From 85a011be2e956e0c11a80b9e787cecd98c99be3a Mon Sep 17 00:00:00 2001 From: David Meadows Date: Thu, 26 Jun 2025 14:53:37 -0400 Subject: [PATCH 363/769] chore(client): sync stream/parse methods over --- src/openai/resources/chat/completions/completions.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index 2a5622b092..5806296773 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -103,7 +103,7 @@ def parse( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, @@ -1334,7 +1334,7 @@ def stream( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, @@ -1470,7 +1470,7 @@ async def parse( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, @@ -2701,7 +2701,7 @@ def stream( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale"]] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, From 996e42fc09b2992009f09ae9f3fdad93452ee937 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 18:54:12 +0000 Subject: [PATCH 364/769] release: 1.92.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 9 +++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 2a2ee2b8f3..4bf1b35ae4 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.92.0" + ".": "1.92.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 60ab8eb6a8..02c63e5813 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 1.92.1 (2025-06-26) + +Full Changelog: [v1.92.0...v1.92.1](https://github.com/openai/openai-python/compare/v1.92.0...v1.92.1) + +### Chores + +* **client:** sync stream/parse methods over ([e2536cf](https://github.com/openai/openai-python/commit/e2536cfd74224047cece9c2ad86f0ffe51c0667c)) +* **docs:** update README to include links to docs on Webhooks ([ddbf9f1](https://github.com/openai/openai-python/commit/ddbf9f1dc47a32257716189f2056b45933328c9c)) + ## 1.92.0 (2025-06-26) Full Changelog: [v1.91.0...v1.92.0](https://github.com/openai/openai-python/compare/v1.91.0...v1.92.0) diff --git a/pyproject.toml b/pyproject.toml index eb9008a3a6..802229939c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.92.0" +version = "1.92.1" 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 64bc847523..9392416ade 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.92.0" # x-release-please-version +__version__ = "1.92.1" # x-release-please-version From 1a85f249ecdf13278d16185a1f9ae908e96e03d2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 12:37:15 -0700 Subject: [PATCH 365/769] release: 1.92.2 (#2431) * chore(api): remove unsupported property * release: 1.92.2 --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- .stats.yml | 4 ++-- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- .../types/responses/response_function_web_search.py | 5 +---- .../types/responses/response_function_web_search_param.py | 5 +---- 7 files changed, 15 insertions(+), 13 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 4bf1b35ae4..5c3e8eb512 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.92.1" + ".": "1.92.2" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index ebbf3ee296..07aa52577e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-cca460eaf5cc13e9d6e5293eb97aac53d66dc1385c691f74b768c97d165b6e8b.yml -openapi_spec_hash: 9ec43d443b3dd58ca5aa87eb0a7eb49f +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-a473967d1766dc155994d932fbc4a5bcbd1c140a37c20d0a4065e1bf0640536d.yml +openapi_spec_hash: 67cdc62b0d6c8b1de29b7dc54b265749 config_hash: e74d6791681e3af1b548748ff47a22c2 diff --git a/CHANGELOG.md b/CHANGELOG.md index 02c63e5813..355bb287d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.92.2 (2025-06-26) + +Full Changelog: [v1.92.1...v1.92.2](https://github.com/openai/openai-python/compare/v1.92.1...v1.92.2) + +### Chores + +* **api:** remove unsupported property ([ec24408](https://github.com/openai/openai-python/commit/ec2440864e03278144d7f58b97c31d87903e0843)) + ## 1.92.1 (2025-06-26) Full Changelog: [v1.92.0...v1.92.1](https://github.com/openai/openai-python/compare/v1.92.0...v1.92.1) diff --git a/pyproject.toml b/pyproject.toml index 802229939c..177fc600b9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.92.1" +version = "1.92.2" 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 9392416ade..709e848243 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.92.1" # x-release-please-version +__version__ = "1.92.2" # x-release-please-version diff --git a/src/openai/types/responses/response_function_web_search.py b/src/openai/types/responses/response_function_web_search.py index 164a1afdca..a3252956e9 100644 --- a/src/openai/types/responses/response_function_web_search.py +++ b/src/openai/types/responses/response_function_web_search.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union, Optional +from typing import Union from typing_extensions import Literal, Annotated, TypeAlias from ..._utils import PropertyInfo @@ -16,9 +16,6 @@ class ActionSearch(BaseModel): type: Literal["search"] """The action type.""" - domains: Optional[List[str]] = None - """Domains to restrict the search or domains where results were found.""" - class ActionOpenPage(BaseModel): type: Literal["open_page"] diff --git a/src/openai/types/responses/response_function_web_search_param.py b/src/openai/types/responses/response_function_web_search_param.py index 04d8a5884b..4a06132cf4 100644 --- a/src/openai/types/responses/response_function_web_search_param.py +++ b/src/openai/types/responses/response_function_web_search_param.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import List, Union +from typing import Union from typing_extensions import Literal, Required, TypeAlias, TypedDict __all__ = ["ResponseFunctionWebSearchParam", "Action", "ActionSearch", "ActionOpenPage", "ActionFind"] @@ -15,9 +15,6 @@ class ActionSearch(TypedDict, total=False): type: Required[Literal["search"]] """The action type.""" - domains: List[str] - """Domains to restrict the search or domains where results were found.""" - class ActionOpenPage(TypedDict, total=False): type: Required[Literal["open_page"]] From a186778fecf6f7fcdfc0fb6bcd5cf33fb895c005 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 16:47:03 +0000 Subject: [PATCH 366/769] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 07aa52577e..cb7aea1814 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-a473967d1766dc155994d932fbc4a5bcbd1c140a37c20d0a4065e1bf0640536d.yml openapi_spec_hash: 67cdc62b0d6c8b1de29b7dc54b265749 -config_hash: e74d6791681e3af1b548748ff47a22c2 +config_hash: 05c7d4a6f4d5983fe9550457114b47dd From 90afdfff14d0084619d71e76c66bc3cee27df81c Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Fri, 27 Jun 2025 12:49:01 -0400 Subject: [PATCH 367/769] fix(client): avoid encoding error with empty API keys --- src/openai/_client.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/openai/_client.py b/src/openai/_client.py index f3a83afec3..ed9b46f4b0 100644 --- a/src/openai/_client.py +++ b/src/openai/_client.py @@ -283,6 +283,9 @@ def qs(self) -> Querystring: @override def auth_headers(self) -> dict[str, str]: api_key = self.api_key + if not api_key: + # if the api key is an empty string, encoding the header will fail + return {} return {"Authorization": f"Bearer {api_key}"} @property @@ -599,6 +602,9 @@ def qs(self) -> Querystring: @override def auth_headers(self) -> dict[str, str]: api_key = self.api_key + if not api_key: + # if the api key is an empty string, encoding the header will fail + return {} return {"Authorization": f"Bearer {api_key}"} @property From dc550bf47b1c086e7b8358fd57798f97e87d4f41 Mon Sep 17 00:00:00 2001 From: Jeff Verkoeyen Date: Fri, 27 Jun 2025 09:56:43 -0700 Subject: [PATCH 368/769] docs(examples/realtime): mention macOS requirements (#2142) --- examples/realtime/push_to_talk_app.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/realtime/push_to_talk_app.py b/examples/realtime/push_to_talk_app.py index 8dc303a83a..02d3f762d0 100755 --- a/examples/realtime/push_to_talk_app.py +++ b/examples/realtime/push_to_talk_app.py @@ -5,6 +5,8 @@ # environment variable set, you can run this example with just # # # # `./examples/realtime/push_to_talk_app.py` # +# # +# On Mac, you'll also need `brew install portaudio ffmpeg` # #################################################################### # # /// script From 6ff802409ca1f1c614dc52ad258a93e9fd1a3d46 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 16:57:26 +0000 Subject: [PATCH 369/769] release: 1.92.3 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 5c3e8eb512..27bf032fe4 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.92.2" + ".": "1.92.3" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 355bb287d9..ac283868ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 1.92.3 (2025-06-27) + +Full Changelog: [v1.92.2...v1.92.3](https://github.com/openai/openai-python/compare/v1.92.2...v1.92.3) + +### Bug Fixes + +* **client:** avoid encoding error with empty API keys ([5a3e64e](https://github.com/openai/openai-python/commit/5a3e64e0cc761dbaa613fb22ec16e7e73c3bcf72)) + + +### Documentation + +* **examples/realtime:** mention macOS requirements ([#2142](https://github.com/openai/openai-python/issues/2142)) ([27bf6b2](https://github.com/openai/openai-python/commit/27bf6b2a933c61d5ec23fd266148af888f69f5c1)) + ## 1.92.2 (2025-06-26) Full Changelog: [v1.92.1...v1.92.2](https://github.com/openai/openai-python/compare/v1.92.1...v1.92.2) diff --git a/pyproject.toml b/pyproject.toml index 177fc600b9..2f44e58aac 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.92.2" +version = "1.92.3" 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 709e848243..81494049e6 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.92.2" # x-release-please-version +__version__ = "1.92.3" # x-release-please-version From 4f4d6fade56e1e4a7fedee56d47039541824904e Mon Sep 17 00:00:00 2001 From: "A. Ammar Naseer" Date: Fri, 27 Jun 2025 18:07:38 +0100 Subject: [PATCH 370/769] feat(cli): add support for fine_tuning.jobs (#1224) --- src/openai/cli/_api/_main.py | 3 +- src/openai/cli/_api/fine_tuning/__init__.py | 13 ++ src/openai/cli/_api/fine_tuning/jobs.py | 169 ++++++++++++++++++++ 3 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 src/openai/cli/_api/fine_tuning/__init__.py create mode 100644 src/openai/cli/_api/fine_tuning/jobs.py diff --git a/src/openai/cli/_api/_main.py b/src/openai/cli/_api/_main.py index fe5a5e6fc0..b04a3e52a4 100644 --- a/src/openai/cli/_api/_main.py +++ b/src/openai/cli/_api/_main.py @@ -2,7 +2,7 @@ from argparse import ArgumentParser -from . import chat, audio, files, image, models, completions +from . import chat, audio, files, image, models, completions, fine_tuning def register_commands(parser: ArgumentParser) -> None: @@ -14,3 +14,4 @@ def register_commands(parser: ArgumentParser) -> None: files.register(subparsers) models.register(subparsers) completions.register(subparsers) + fine_tuning.register(subparsers) diff --git a/src/openai/cli/_api/fine_tuning/__init__.py b/src/openai/cli/_api/fine_tuning/__init__.py new file mode 100644 index 0000000000..11a2dfccbd --- /dev/null +++ b/src/openai/cli/_api/fine_tuning/__init__.py @@ -0,0 +1,13 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING +from argparse import ArgumentParser + +from . import jobs + +if TYPE_CHECKING: + from argparse import _SubParsersAction + + +def register(subparser: _SubParsersAction[ArgumentParser]) -> None: + jobs.register(subparser) diff --git a/src/openai/cli/_api/fine_tuning/jobs.py b/src/openai/cli/_api/fine_tuning/jobs.py new file mode 100644 index 0000000000..806fa0f788 --- /dev/null +++ b/src/openai/cli/_api/fine_tuning/jobs.py @@ -0,0 +1,169 @@ +from __future__ import annotations + +import json +from typing import TYPE_CHECKING +from argparse import ArgumentParser + +from ..._utils import get_client, print_model +from ...._types import NOT_GIVEN, NotGivenOr +from ..._models import BaseModel +from ....pagination import SyncCursorPage +from ....types.fine_tuning import ( + FineTuningJob, + FineTuningJobEvent, +) + +if TYPE_CHECKING: + from argparse import _SubParsersAction + + +def register(subparser: _SubParsersAction[ArgumentParser]) -> None: + sub = subparser.add_parser("fine_tuning.jobs.create") + sub.add_argument( + "-m", + "--model", + help="The model to fine-tune.", + required=True, + ) + sub.add_argument( + "-F", + "--training-file", + help="The training file to fine-tune the model on.", + required=True, + ) + sub.add_argument( + "-H", + "--hyperparameters", + help="JSON string of hyperparameters to use for fine-tuning.", + type=str, + ) + sub.add_argument( + "-s", + "--suffix", + help="A suffix to add to the fine-tuned model name.", + ) + sub.add_argument( + "-V", + "--validation-file", + help="The validation file to use for fine-tuning.", + ) + sub.set_defaults(func=CLIFineTuningJobs.create, args_model=CLIFineTuningJobsCreateArgs) + + sub = subparser.add_parser("fine_tuning.jobs.retrieve") + sub.add_argument( + "-i", + "--id", + help="The ID of the fine-tuning job to retrieve.", + required=True, + ) + sub.set_defaults(func=CLIFineTuningJobs.retrieve, args_model=CLIFineTuningJobsRetrieveArgs) + + sub = subparser.add_parser("fine_tuning.jobs.list") + sub.add_argument( + "-a", + "--after", + help="Identifier for the last job from the previous pagination request. If provided, only jobs created after this job will be returned.", + ) + sub.add_argument( + "-l", + "--limit", + help="Number of fine-tuning jobs to retrieve.", + type=int, + ) + sub.set_defaults(func=CLIFineTuningJobs.list, args_model=CLIFineTuningJobsListArgs) + + sub = subparser.add_parser("fine_tuning.jobs.cancel") + sub.add_argument( + "-i", + "--id", + help="The ID of the fine-tuning job to cancel.", + required=True, + ) + sub.set_defaults(func=CLIFineTuningJobs.cancel, args_model=CLIFineTuningJobsCancelArgs) + + sub = subparser.add_parser("fine_tuning.jobs.list_events") + sub.add_argument( + "-i", + "--id", + help="The ID of the fine-tuning job to list events for.", + required=True, + ) + sub.add_argument( + "-a", + "--after", + help="Identifier for the last event from the previous pagination request. If provided, only events created after this event will be returned.", + ) + sub.add_argument( + "-l", + "--limit", + help="Number of fine-tuning job events to retrieve.", + type=int, + ) + sub.set_defaults(func=CLIFineTuningJobs.list_events, args_model=CLIFineTuningJobsListEventsArgs) + + +class CLIFineTuningJobsCreateArgs(BaseModel): + model: str + training_file: str + hyperparameters: NotGivenOr[str] = NOT_GIVEN + suffix: NotGivenOr[str] = NOT_GIVEN + validation_file: NotGivenOr[str] = NOT_GIVEN + + +class CLIFineTuningJobsRetrieveArgs(BaseModel): + id: str + + +class CLIFineTuningJobsListArgs(BaseModel): + after: NotGivenOr[str] = NOT_GIVEN + limit: NotGivenOr[int] = NOT_GIVEN + + +class CLIFineTuningJobsCancelArgs(BaseModel): + id: str + + +class CLIFineTuningJobsListEventsArgs(BaseModel): + id: str + after: NotGivenOr[str] = NOT_GIVEN + limit: NotGivenOr[int] = NOT_GIVEN + + +class CLIFineTuningJobs: + @staticmethod + def create(args: CLIFineTuningJobsCreateArgs) -> None: + hyperparameters = json.loads(str(args.hyperparameters)) if args.hyperparameters is not NOT_GIVEN else NOT_GIVEN + fine_tuning_job: FineTuningJob = get_client().fine_tuning.jobs.create( + model=args.model, + training_file=args.training_file, + hyperparameters=hyperparameters, + suffix=args.suffix, + validation_file=args.validation_file, + ) + print_model(fine_tuning_job) + + @staticmethod + def retrieve(args: CLIFineTuningJobsRetrieveArgs) -> None: + fine_tuning_job: FineTuningJob = get_client().fine_tuning.jobs.retrieve(fine_tuning_job_id=args.id) + print_model(fine_tuning_job) + + @staticmethod + def list(args: CLIFineTuningJobsListArgs) -> None: + fine_tuning_jobs: SyncCursorPage[FineTuningJob] = get_client().fine_tuning.jobs.list( + after=args.after or NOT_GIVEN, limit=args.limit or NOT_GIVEN + ) + print_model(fine_tuning_jobs) + + @staticmethod + def cancel(args: CLIFineTuningJobsCancelArgs) -> None: + fine_tuning_job: FineTuningJob = get_client().fine_tuning.jobs.cancel(fine_tuning_job_id=args.id) + print_model(fine_tuning_job) + + @staticmethod + def list_events(args: CLIFineTuningJobsListEventsArgs) -> None: + fine_tuning_job_events: SyncCursorPage[FineTuningJobEvent] = get_client().fine_tuning.jobs.list_events( + fine_tuning_job_id=args.id, + after=args.after or NOT_GIVEN, + limit=args.limit or NOT_GIVEN, + ) + print_model(fine_tuning_job_events) From 4b4d4864b041d2d93a03f4b36305b4d9c4af5b37 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 21:16:22 +0000 Subject: [PATCH 371/769] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index cb7aea1814..535155f4ae 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-a473967d1766dc155994d932fbc4a5bcbd1c140a37c20d0a4065e1bf0640536d.yml openapi_spec_hash: 67cdc62b0d6c8b1de29b7dc54b265749 -config_hash: 05c7d4a6f4d5983fe9550457114b47dd +config_hash: 7b53f96f897ca1b3407a5341a6f820db From 1dbb72b290cb360a9ccbcec17425aaba4ad114b0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 21:16:50 +0000 Subject: [PATCH 372/769] release: 1.93.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 27bf032fe4..3ceb8e2f5b 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.92.3" + ".": "1.93.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index ac283868ca..3274b67105 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.93.0 (2025-06-27) + +Full Changelog: [v1.92.3...v1.93.0](https://github.com/openai/openai-python/compare/v1.92.3...v1.93.0) + +### Features + +* **cli:** add support for fine_tuning.jobs ([#1224](https://github.com/openai/openai-python/issues/1224)) ([e362bfd](https://github.com/openai/openai-python/commit/e362bfd10dfd04176560b964470ab0c517c601f3)) + ## 1.92.3 (2025-06-27) Full Changelog: [v1.92.2...v1.92.3](https://github.com/openai/openai-python/compare/v1.92.2...v1.92.3) diff --git a/pyproject.toml b/pyproject.toml index 2f44e58aac..0a3e3e1ca8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.92.3" +version = "1.93.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 81494049e6..84c3a45a00 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.92.3" # x-release-please-version +__version__ = "1.93.0" # x-release-please-version From b106b6e57868d4a163d6c75075cb2ca3bdd0c895 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 22:37:39 +0000 Subject: [PATCH 373/769] chore(ci): only run for pushes and fork pull requests --- .github/workflows/ci.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7991b3e7c7..f92bb6ea6f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,6 +17,7 @@ jobs: timeout-minutes: 10 name: lint runs-on: ${{ github.repository == 'stainless-sdks/openai-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - uses: actions/checkout@v4 @@ -42,6 +43,7 @@ jobs: contents: read id-token: write runs-on: depot-ubuntu-24.04 + if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - uses: actions/checkout@v4 @@ -62,6 +64,7 @@ jobs: timeout-minutes: 10 name: test runs-on: ${{ github.repository == 'stainless-sdks/openai-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - uses: actions/checkout@v4 @@ -83,7 +86,7 @@ jobs: timeout-minutes: 10 name: examples runs-on: ${{ github.repository == 'stainless-sdks/openai-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} - if: github.repository == 'openai/openai-python' + if: github.repository == 'openai/openai-python && (github.event_name == 'push' || github.event.pull_request.head.repo.fork)' steps: - uses: actions/checkout@v4 From e4cacb867612ac7db956b64000bdc44e6cfc5efc Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sun, 29 Jun 2025 06:17:23 +0000 Subject: [PATCH 374/769] fix(ci): correct conditional --- .github/workflows/ci.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f92bb6ea6f..c405c77a7e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,14 +36,13 @@ jobs: run: ./scripts/lint upload: - if: github.repository == 'stainless-sdks/openai-python' + if: github.repository == 'stainless-sdks/openai-python' && (github.event_name == 'push' || github.event.pull_request.head.repo.fork) timeout-minutes: 10 name: upload permissions: contents: read id-token: write runs-on: depot-ubuntu-24.04 - if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - uses: actions/checkout@v4 @@ -86,7 +85,7 @@ jobs: timeout-minutes: 10 name: examples runs-on: ${{ github.repository == 'stainless-sdks/openai-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} - if: github.repository == 'openai/openai-python && (github.event_name == 'push' || github.event.pull_request.head.repo.fork)' + if: github.repository == 'openai/openai-python' && (github.event_name == 'push' || github.event.pull_request.head.repo.fork) steps: - uses: actions/checkout@v4 From be1f58f043f4d05488546f0c34ea1ac599ec409a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 23:33:35 +0000 Subject: [PATCH 375/769] chore(ci): change upload type --- .github/workflows/ci.yml | 18 ++++++++++++++++-- scripts/utils/upload-artifact.sh | 12 +++++++----- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c405c77a7e..8067386d5f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,10 +35,10 @@ jobs: - name: Run lints run: ./scripts/lint - upload: + build: if: github.repository == 'stainless-sdks/openai-python' && (github.event_name == 'push' || github.event.pull_request.head.repo.fork) timeout-minutes: 10 - name: upload + name: build permissions: contents: read id-token: write @@ -46,6 +46,20 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Install Rye + run: | + curl -sSf https://rye.astral.sh/get | bash + echo "$HOME/.rye/shims" >> $GITHUB_PATH + env: + RYE_VERSION: '0.44.0' + RYE_INSTALL_OPTION: '--yes' + + - name: Install dependencies + run: rye sync --all-features + + - name: Run build + run: rye build + - name: Get GitHub OIDC Token id: github-oidc uses: actions/github-script@v6 diff --git a/scripts/utils/upload-artifact.sh b/scripts/utils/upload-artifact.sh index 75198de98f..cd522975fc 100755 --- a/scripts/utils/upload-artifact.sh +++ b/scripts/utils/upload-artifact.sh @@ -1,7 +1,9 @@ #!/usr/bin/env bash set -exuo pipefail -RESPONSE=$(curl -X POST "$URL" \ +FILENAME=$(basename dist/*.whl) + +RESPONSE=$(curl -X POST "$URL?filename=$FILENAME" \ -H "Authorization: Bearer $AUTH" \ -H "Content-Type: application/json") @@ -12,13 +14,13 @@ if [[ "$SIGNED_URL" == "null" ]]; then exit 1 fi -UPLOAD_RESPONSE=$(tar -cz . | curl -v -X PUT \ - -H "Content-Type: application/gzip" \ - --data-binary @- "$SIGNED_URL" 2>&1) +UPLOAD_RESPONSE=$(curl -v -X PUT \ + -H "Content-Type: binary/octet-stream" \ + --data-binary "@dist/$FILENAME" "$SIGNED_URL" 2>&1) if echo "$UPLOAD_RESPONSE" | grep -q "HTTP/[0-9.]* 200"; then echo -e "\033[32mUploaded build to Stainless storage.\033[0m" - echo -e "\033[32mInstallation: pip install 'https://pkg.stainless.com/s/openai-python/$SHA'\033[0m" + echo -e "\033[32mInstallation: pip install 'https://pkg.stainless.com/s/openai-python/$SHA/$FILENAME'\033[0m" else echo -e "\033[31mFailed to upload artifact.\033[0m" exit 1 From 4a943ad413fe23dc75b36b5599f0669e4d53fb64 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Tue, 1 Jul 2025 17:42:49 -0700 Subject: [PATCH 376/769] fix(responses): add missing arguments to parse --- src/openai/resources/responses/responses.py | 40 +++++++++++++++------ 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index aaf2088f38..ce132bdb05 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -943,22 +943,27 @@ def stream( def parse( self, *, - input: Union[str, ResponseInputParam], - model: Union[str, ChatModel], text_format: type[TextFormatT] | NotGiven = NOT_GIVEN, - tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, + background: Optional[bool] | NotGiven = NOT_GIVEN, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + max_tool_calls: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + model: ResponsesModel | NotGiven = NOT_GIVEN, parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, + tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, + top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, @@ -991,21 +996,26 @@ def parser(raw_response: Response) -> ParsedResponse[TextFormatT]: "/responses", body=maybe_transform( { - "input": input, - "model": model, + "background": background, "include": include, + "input": input, "instructions": instructions, "max_output_tokens": max_output_tokens, + "max_tool_calls": max_tool_calls, "metadata": metadata, + "model": model, "parallel_tool_calls": parallel_tool_calls, "previous_response_id": previous_response_id, + "prompt": prompt, "reasoning": reasoning, + "service_tier": service_tier, "store": store, "stream": stream, "temperature": temperature, "text": text, "tool_choice": tool_choice, "tools": tools, + "top_logprobs": top_logprobs, "top_p": top_p, "truncation": truncation, "user": user, @@ -2202,22 +2212,27 @@ def stream( async def parse( self, *, - input: Union[str, ResponseInputParam], - model: Union[str, ChatModel], text_format: type[TextFormatT] | NotGiven = NOT_GIVEN, - tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, + background: Optional[bool] | NotGiven = NOT_GIVEN, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, + input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + max_tool_calls: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + model: ResponsesModel | NotGiven = NOT_GIVEN, parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, + tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, + top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, @@ -2250,21 +2265,26 @@ def parser(raw_response: Response) -> ParsedResponse[TextFormatT]: "/responses", body=maybe_transform( { - "input": input, - "model": model, + "background": background, "include": include, + "input": input, "instructions": instructions, "max_output_tokens": max_output_tokens, + "max_tool_calls": max_tool_calls, "metadata": metadata, + "model": model, "parallel_tool_calls": parallel_tool_calls, "previous_response_id": previous_response_id, + "prompt": prompt, "reasoning": reasoning, + "service_tier": service_tier, "store": store, "stream": stream, "temperature": temperature, "text": text, "tool_choice": tool_choice, "tools": tools, + "top_logprobs": top_logprobs, "top_p": top_p, "truncation": truncation, "user": user, From 930662d9802b8e351a5c771dfc53604747d5ad68 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Tue, 1 Jul 2025 17:36:56 -0700 Subject: [PATCH 377/769] chore(tests): ensure parse method is in sync with create --- tests/api_resources/test_responses.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/api_resources/test_responses.py b/tests/api_resources/test_responses.py index 9c76928c8c..158654ee70 100644 --- a/tests/api_resources/test_responses.py +++ b/tests/api_resources/test_responses.py @@ -9,6 +9,7 @@ from openai import OpenAI, AsyncOpenAI from tests.utils import assert_matches_type +from openai._utils import assert_signatures_in_sync from openai.types.responses import ( Response, ) @@ -340,6 +341,17 @@ def test_path_params_cancel(self, client: OpenAI) -> None: ) +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +def test_parse_method_in_sync(sync: bool, client: OpenAI, async_client: AsyncOpenAI) -> None: + checking_client: OpenAI | AsyncOpenAI = client if sync else async_client + + assert_signatures_in_sync( + checking_client.responses.create, + checking_client.responses.parse, + exclude_params={"stream", "tools"}, + ) + + class TestAsyncResponses: parametrize = pytest.mark.parametrize( "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] From 32a32967a4f0b1a62183194e6013b105ec291151 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Mon, 7 Jul 2025 13:36:19 +0100 Subject: [PATCH 378/769] fix(vector stores): add missing arguments to files.create_and_poll --- src/openai/resources/vector_stores/files.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/openai/resources/vector_stores/files.py b/src/openai/resources/vector_stores/files.py index f860384629..cf5c4c1d11 100644 --- a/src/openai/resources/vector_stores/files.py +++ b/src/openai/resources/vector_stores/files.py @@ -304,11 +304,14 @@ def create_and_poll( file_id: str, *, vector_store_id: str, + attributes: Optional[Dict[str, Union[str, float, bool]]] | NotGiven = NOT_GIVEN, poll_interval_ms: int | NotGiven = NOT_GIVEN, chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, ) -> VectorStoreFile: """Attach a file to the given vector store and wait for it to be processed.""" - self.create(vector_store_id=vector_store_id, file_id=file_id, chunking_strategy=chunking_strategy) + self.create( + vector_store_id=vector_store_id, file_id=file_id, chunking_strategy=chunking_strategy, attributes=attributes + ) return self.poll( file_id, @@ -707,11 +710,14 @@ async def create_and_poll( file_id: str, *, vector_store_id: str, + attributes: Optional[Dict[str, Union[str, float, bool]]] | NotGiven = NOT_GIVEN, poll_interval_ms: int | NotGiven = NOT_GIVEN, chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, ) -> VectorStoreFile: """Attach a file to the given vector store and wait for it to be processed.""" - await self.create(vector_store_id=vector_store_id, file_id=file_id, chunking_strategy=chunking_strategy) + await self.create( + vector_store_id=vector_store_id, file_id=file_id, chunking_strategy=chunking_strategy, attributes=attributes + ) return await self.poll( file_id, From 77d5ac2edb5d828faaff82baa524807823032188 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Mon, 7 Jul 2025 13:37:02 +0100 Subject: [PATCH 379/769] chore(tests): ensure vector store files create and poll method is in sync --- tests/api_resources/vector_stores/test_files.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/api_resources/vector_stores/test_files.py b/tests/api_resources/vector_stores/test_files.py index 0778704d5d..c951a13b3f 100644 --- a/tests/api_resources/vector_stores/test_files.py +++ b/tests/api_resources/vector_stores/test_files.py @@ -9,6 +9,7 @@ from openai import OpenAI, AsyncOpenAI from tests.utils import assert_matches_type +from openai._utils import assert_signatures_in_sync from openai.pagination import SyncPage, AsyncPage, SyncCursorPage, AsyncCursorPage from openai.types.vector_stores import ( VectorStoreFile, @@ -625,3 +626,14 @@ async def test_path_params_content(self, async_client: AsyncOpenAI) -> None: file_id="", vector_store_id="vs_abc123", ) + + +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +def test_create_and_poll_method_in_sync(sync: bool, client: OpenAI, async_client: AsyncOpenAI) -> None: + checking_client: OpenAI | AsyncOpenAI = client if sync else async_client + + assert_signatures_in_sync( + checking_client.vector_stores.files.create, + checking_client.vector_stores.files.create_and_poll, + exclude_params={"extra_headers", "extra_query", "extra_body", "timeout"}, + ) From 48121221f2797d6674c24c873a897b5eaa591671 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Mon, 7 Jul 2025 13:39:27 +0100 Subject: [PATCH 380/769] fix(vector stores): add missing arguments to files.upload_and_poll --- src/openai/resources/vector_stores/files.py | 4 ++++ tests/api_resources/vector_stores/test_files.py | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/openai/resources/vector_stores/files.py b/src/openai/resources/vector_stores/files.py index cf5c4c1d11..2c90bb7a1f 100644 --- a/src/openai/resources/vector_stores/files.py +++ b/src/openai/resources/vector_stores/files.py @@ -380,6 +380,7 @@ def upload_and_poll( *, vector_store_id: str, file: FileTypes, + attributes: Optional[Dict[str, Union[str, float, bool]]] | NotGiven = NOT_GIVEN, poll_interval_ms: int | NotGiven = NOT_GIVEN, chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, ) -> VectorStoreFile: @@ -390,6 +391,7 @@ def upload_and_poll( file_id=file_obj.id, chunking_strategy=chunking_strategy, poll_interval_ms=poll_interval_ms, + attributes=attributes, ) def content( @@ -788,6 +790,7 @@ async def upload_and_poll( *, vector_store_id: str, file: FileTypes, + attributes: Optional[Dict[str, Union[str, float, bool]]] | NotGiven = NOT_GIVEN, poll_interval_ms: int | NotGiven = NOT_GIVEN, chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, ) -> VectorStoreFile: @@ -798,6 +801,7 @@ async def upload_and_poll( file_id=file_obj.id, poll_interval_ms=poll_interval_ms, chunking_strategy=chunking_strategy, + attributes=attributes, ) def content( diff --git a/tests/api_resources/vector_stores/test_files.py b/tests/api_resources/vector_stores/test_files.py index c951a13b3f..7394b50d95 100644 --- a/tests/api_resources/vector_stores/test_files.py +++ b/tests/api_resources/vector_stores/test_files.py @@ -637,3 +637,14 @@ def test_create_and_poll_method_in_sync(sync: bool, client: OpenAI, async_client checking_client.vector_stores.files.create_and_poll, exclude_params={"extra_headers", "extra_query", "extra_body", "timeout"}, ) + + +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +def test_upload_and_poll_method_in_sync(sync: bool, client: OpenAI, async_client: AsyncOpenAI) -> None: + checking_client: OpenAI | AsyncOpenAI = client if sync else async_client + + assert_signatures_in_sync( + checking_client.vector_stores.files.create, + checking_client.vector_stores.files.upload_and_poll, + exclude_params={"file_id", "extra_headers", "extra_query", "extra_body", "timeout"}, + ) From 266008a12e68881ffa55b02501cd5fcd6ab284d9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 7 Jul 2025 15:56:20 +0000 Subject: [PATCH 381/769] chore(internal): codegen related update --- requirements-dev.lock | 2 +- requirements.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements-dev.lock b/requirements-dev.lock index 138fd3b4f6..e560d4f33c 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -81,7 +81,7 @@ httpx==0.28.1 # via httpx-aiohttp # via openai # via respx -httpx-aiohttp==0.1.6 +httpx-aiohttp==0.1.8 # via openai idna==3.4 # via anyio diff --git a/requirements.lock b/requirements.lock index 84cb9276d8..52ad2c0452 100644 --- a/requirements.lock +++ b/requirements.lock @@ -45,7 +45,7 @@ httpcore==1.0.2 httpx==0.28.1 # via httpx-aiohttp # via openai -httpx-aiohttp==0.1.6 +httpx-aiohttp==0.1.8 # via openai idna==3.4 # via anyio From c5b77db2ee8d73895b179ae859c40f4f1ae42437 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 7 Jul 2025 15:56:49 +0000 Subject: [PATCH 382/769] release: 1.93.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 20 ++++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 3ceb8e2f5b..daa7a2a062 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.93.0" + ".": "1.93.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 3274b67105..35d98e9765 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,25 @@ # Changelog +## 1.93.1 (2025-07-07) + +Full Changelog: [v1.93.0...v1.93.1](https://github.com/openai/openai-python/compare/v1.93.0...v1.93.1) + +### Bug Fixes + +* **ci:** correct conditional ([de6a9ce](https://github.com/openai/openai-python/commit/de6a9ce078731d60b0bdc42a9322548c575f11a3)) +* **responses:** add missing arguments to parse ([05590ec](https://github.com/openai/openai-python/commit/05590ec2a96399afd05baf5a3ee1d9a744f09c40)) +* **vector stores:** add missing arguments to files.create_and_poll ([3152134](https://github.com/openai/openai-python/commit/3152134510532ec7c522d6b50a820deea205b602)) +* **vector stores:** add missing arguments to files.upload_and_poll ([9d4f425](https://github.com/openai/openai-python/commit/9d4f42569d5b59311453b1b11ee1dd2e8a271268)) + + +### Chores + +* **ci:** change upload type ([cd4aa88](https://github.com/openai/openai-python/commit/cd4aa889c50581d861728c9606327992485f0d0d)) +* **ci:** only run for pushes and fork pull requests ([f89c7eb](https://github.com/openai/openai-python/commit/f89c7eb46c6f081254715d75543cbee3ffa83822)) +* **internal:** codegen related update ([bddb8d2](https://github.com/openai/openai-python/commit/bddb8d2091455920e8526068d64f3f8a5cac7ae6)) +* **tests:** ensure parse method is in sync with create ([4f58e18](https://github.com/openai/openai-python/commit/4f58e187c12dc8b2c33e9cca284b0429e5cc4de5)) +* **tests:** ensure vector store files create and poll method is in sync ([0fe75a2](https://github.com/openai/openai-python/commit/0fe75a28f6109b2d25b015dc99472a06693e0e9f)) + ## 1.93.0 (2025-06-27) Full Changelog: [v1.92.3...v1.93.0](https://github.com/openai/openai-python/compare/v1.92.3...v1.93.0) diff --git a/pyproject.toml b/pyproject.toml index 0a3e3e1ca8..73efe65b2f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.93.0" +version = "1.93.1" 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 84c3a45a00..289693a91c 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.93.0" # x-release-please-version +__version__ = "1.93.1" # x-release-please-version From cb6fa9c222079d334122b7b66e13dd3b18d5a92a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 8 Jul 2025 14:24:43 +0000 Subject: [PATCH 383/769] chore(internal): bump pinned h11 dep --- requirements-dev.lock | 4 ++-- requirements.lock | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/requirements-dev.lock b/requirements-dev.lock index e560d4f33c..1a7500d569 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -73,9 +73,9 @@ filelock==3.12.4 frozenlist==1.7.0 # via aiohttp # via aiosignal -h11==0.14.0 +h11==0.16.0 # via httpcore -httpcore==1.0.2 +httpcore==1.0.9 # via httpx httpx==0.28.1 # via httpx-aiohttp diff --git a/requirements.lock b/requirements.lock index 52ad2c0452..3b6ece87e2 100644 --- a/requirements.lock +++ b/requirements.lock @@ -38,9 +38,9 @@ exceptiongroup==1.2.2 frozenlist==1.7.0 # via aiohttp # via aiosignal -h11==0.14.0 +h11==0.16.0 # via httpcore -httpcore==1.0.2 +httpcore==1.0.9 # via httpx httpx==0.28.1 # via httpx-aiohttp From 0d42dff3bcd3d5f13c4d14a5f872054f35f53a6d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 8 Jul 2025 15:25:53 +0000 Subject: [PATCH 384/769] chore(package): mark python 3.13 as supported --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 73efe65b2f..9e43f5e7d7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,6 +26,7 @@ classifiers = [ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Operating System :: OS Independent", "Operating System :: POSIX", "Operating System :: MacOS", From fe82bb48899919803a7a59b9d6a740b4390d6cec Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 8 Jul 2025 15:26:27 +0000 Subject: [PATCH 385/769] release: 1.93.2 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 9 +++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index daa7a2a062..02609a40fd 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.93.1" + ".": "1.93.2" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 35d98e9765..92645c8e02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 1.93.2 (2025-07-08) + +Full Changelog: [v1.93.1...v1.93.2](https://github.com/openai/openai-python/compare/v1.93.1...v1.93.2) + +### Chores + +* **internal:** bump pinned h11 dep ([4fca6ae](https://github.com/openai/openai-python/commit/4fca6ae2d0d7f27cbac8d06c3917932767c8c6b8)) +* **package:** mark python 3.13 as supported ([2229047](https://github.com/openai/openai-python/commit/2229047b8a549df16c617bddfe3b4521cfd257a5)) + ## 1.93.1 (2025-07-07) Full Changelog: [v1.93.0...v1.93.1](https://github.com/openai/openai-python/compare/v1.93.0...v1.93.1) diff --git a/pyproject.toml b/pyproject.toml index 9e43f5e7d7..d1fda0244b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.93.1" +version = "1.93.2" 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 289693a91c..a5ddf48daf 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.93.1" # x-release-please-version +__version__ = "1.93.2" # x-release-please-version From 589b0e3d755e8887747ee1c7ea841de2232b9899 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 9 Jul 2025 10:16:11 +0000 Subject: [PATCH 386/769] fix(parsing): correctly handle nested discriminated unions --- src/openai/_models.py | 11 +++++++---- tests/test_models.py | 45 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/openai/_models.py b/src/openai/_models.py index 065e8da760..f347a81dac 100644 --- a/src/openai/_models.py +++ b/src/openai/_models.py @@ -5,6 +5,7 @@ from typing import TYPE_CHECKING, Any, Type, Tuple, Union, Generic, TypeVar, Callable, Optional, cast from datetime import date, datetime from typing_extensions import ( + List, Unpack, Literal, ClassVar, @@ -391,7 +392,7 @@ def _construct_field(value: object, field: FieldInfo, key: str) -> object: if type_ is None: raise RuntimeError(f"Unexpected field type is None for {key}") - return construct_type(value=value, type_=type_) + return construct_type(value=value, type_=type_, metadata=getattr(field, "metadata", None)) def is_basemodel(type_: type) -> bool: @@ -445,7 +446,7 @@ def construct_type_unchecked(*, value: object, type_: type[_T]) -> _T: return cast(_T, construct_type(value=value, type_=type_)) -def construct_type(*, value: object, type_: object) -> object: +def construct_type(*, value: object, type_: object, metadata: Optional[List[Any]] = None) -> object: """Loose coercion to the expected type with construction of nested values. If the given value does not match the expected type then it is returned as-is. @@ -463,8 +464,10 @@ def construct_type(*, value: object, type_: object) -> object: type_ = type_.__value__ # type: ignore[unreachable] # unwrap `Annotated[T, ...]` -> `T` - if is_annotated_type(type_): - meta: tuple[Any, ...] = get_args(type_)[1:] + if metadata is not None: + meta: tuple[Any, ...] = tuple(metadata) + elif is_annotated_type(type_): + meta = get_args(type_)[1:] type_ = extract_type_arg(type_, 0) else: meta = tuple() diff --git a/tests/test_models.py b/tests/test_models.py index 440e17a08c..7262f45006 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -889,3 +889,48 @@ class ModelB(BaseModel): ) assert isinstance(m, ModelB) + + +def test_nested_discriminated_union() -> None: + class InnerType1(BaseModel): + type: Literal["type_1"] + + class InnerModel(BaseModel): + inner_value: str + + class InnerType2(BaseModel): + type: Literal["type_2"] + some_inner_model: InnerModel + + class Type1(BaseModel): + base_type: Literal["base_type_1"] + value: Annotated[ + Union[ + InnerType1, + InnerType2, + ], + PropertyInfo(discriminator="type"), + ] + + class Type2(BaseModel): + base_type: Literal["base_type_2"] + + T = Annotated[ + Union[ + Type1, + Type2, + ], + PropertyInfo(discriminator="base_type"), + ] + + model = construct_type( + type_=T, + value={ + "base_type": "base_type_1", + "value": { + "type": "type_2", + }, + }, + ) + assert isinstance(model, Type1) + assert isinstance(model.value, InnerType2) From fa8e1cb37681e06da4239d8011687b7dc105365a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 9 Jul 2025 10:16:40 +0000 Subject: [PATCH 387/769] release: 1.93.3 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 02609a40fd..074ba77967 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.93.2" + ".": "1.93.3" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 92645c8e02..00931cdb79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.93.3 (2025-07-09) + +Full Changelog: [v1.93.2...v1.93.3](https://github.com/openai/openai-python/compare/v1.93.2...v1.93.3) + +### Bug Fixes + +* **parsing:** correctly handle nested discriminated unions ([fc8a677](https://github.com/openai/openai-python/commit/fc8a67715d8f1b45d8639b8b6f9f6590fe358734)) + ## 1.93.2 (2025-07-08) Full Changelog: [v1.93.1...v1.93.2](https://github.com/openai/openai-python/compare/v1.93.1...v1.93.2) diff --git a/pyproject.toml b/pyproject.toml index d1fda0244b..4f3642c922 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.93.2" +version = "1.93.3" 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 a5ddf48daf..828e93d58a 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.93.2" # x-release-please-version +__version__ = "1.93.3" # x-release-please-version From 361dc3274b6b48847860cb92bfccb31dd0b546ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Sch=C3=BCller?= Date: Thu, 10 Jul 2025 14:48:09 +0200 Subject: [PATCH 388/769] feat(api): return better error message on missing embedding (#2369) --- src/openai/resources/embeddings.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/openai/resources/embeddings.py b/src/openai/resources/embeddings.py index 553dacc284..609f33f3b4 100644 --- a/src/openai/resources/embeddings.py +++ b/src/openai/resources/embeddings.py @@ -112,6 +112,9 @@ def parser(obj: CreateEmbeddingResponse) -> CreateEmbeddingResponse: # don't modify the response object if a user explicitly asked for a format return obj + if not obj.data: + raise ValueError("No embedding data received") + for embedding in obj.data: data = cast(object, embedding.embedding) if not isinstance(data, str): @@ -228,6 +231,9 @@ def parser(obj: CreateEmbeddingResponse) -> CreateEmbeddingResponse: # don't modify the response object if a user explicitly asked for a format return obj + if not obj.data: + raise ValueError("No embedding data received") + for embedding in obj.data: data = cast(object, embedding.embedding) if not isinstance(data, str): From 4d5fe48ee4bb44064c786d175084b7ba7f1bd792 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 10 Jul 2025 12:48:36 +0000 Subject: [PATCH 389/769] release: 1.94.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 074ba77967..6db20a9bfb 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.93.3" + ".": "1.94.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 00931cdb79..7c99b6d6c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.94.0 (2025-07-10) + +Full Changelog: [v1.93.3...v1.94.0](https://github.com/openai/openai-python/compare/v1.93.3...v1.94.0) + +### Features + +* **api:** return better error message on missing embedding ([#2369](https://github.com/openai/openai-python/issues/2369)) ([e53464a](https://github.com/openai/openai-python/commit/e53464ae95f6a041f3267762834e6156c5ce1b57)) + ## 1.93.3 (2025-07-09) Full Changelog: [v1.93.2...v1.93.3](https://github.com/openai/openai-python/compare/v1.93.2...v1.93.3) diff --git a/pyproject.toml b/pyproject.toml index 4f3642c922..2c87a67c77 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.93.3" +version = "1.94.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 828e93d58a..9ed696d5dd 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.93.3" # x-release-please-version +__version__ = "1.94.0" # x-release-please-version From db5c35049accb05f5fb03791ef9c12547fd309a7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 10 Jul 2025 13:34:57 -0500 Subject: [PATCH 390/769] release: 1.95.0 (#2456) * chore(readme): fix version rendering on pypi * feat(api): add file_url, fix event ID * release: 1.95.0 --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- .stats.yml | 6 +-- CHANGELOG.md | 13 +++++ README.md | 3 +- pyproject.toml | 2 +- src/openai/_version.py | 2 +- src/openai/types/audio/transcription.py | 2 +- .../types/audio/transcription_verbose.py | 2 +- ...put_audio_transcription_completed_event.py | 52 +++++++++++++++++-- src/openai/types/file_object.py | 11 +++- .../types/responses/response_input_file.py | 3 ++ .../responses/response_input_file_param.py | 3 ++ ...response_mcp_call_arguments_delta_event.py | 4 +- .../response_mcp_call_arguments_done_event.py | 4 +- ...onse_output_text_annotation_added_event.py | 4 +- src/openai/types/responses/tool.py | 3 ++ src/openai/types/responses/tool_param.py | 3 ++ 17 files changed, 99 insertions(+), 20 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 6db20a9bfb..9a75280778 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.94.0" + ".": "1.95.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 535155f4ae..816f05df5c 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-a473967d1766dc155994d932fbc4a5bcbd1c140a37c20d0a4065e1bf0640536d.yml -openapi_spec_hash: 67cdc62b0d6c8b1de29b7dc54b265749 -config_hash: 7b53f96f897ca1b3407a5341a6f820db +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-2d116cda53321baa3479e628512def723207a81eb1cdaebb542bd0555e563bda.yml +openapi_spec_hash: 809d958fec261a32004a4b026b718793 +config_hash: e74d6791681e3af1b548748ff47a22c2 diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c99b6d6c8..f5c49d637f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 1.95.0 (2025-07-10) + +Full Changelog: [v1.94.0...v1.95.0](https://github.com/openai/openai-python/compare/v1.94.0...v1.95.0) + +### Features + +* **api:** add file_url, fix event ID ([265e216](https://github.com/openai/openai-python/commit/265e216396196d66cdfb5f92c5ef1a2a6ff27b5b)) + + +### Chores + +* **readme:** fix version rendering on pypi ([1eee5ca](https://github.com/openai/openai-python/commit/1eee5cabf2fd93877cd3ba85d0c6ed2ffd5f159f)) + ## 1.94.0 (2025-07-10) Full Changelog: [v1.93.3...v1.94.0](https://github.com/openai/openai-python/compare/v1.93.3...v1.94.0) diff --git a/README.md b/README.md index b38ef578d2..d09de14f3c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # OpenAI Python API library -[![PyPI version]()](https://pypi.org/project/openai/) + +[![PyPI version](https://img.shields.io/pypi/v/openai.svg?label=pypi%20(stable))](https://pypi.org/project/openai/) The OpenAI Python library provides convenient access to the OpenAI REST API from any Python 3.8+ application. The library includes type definitions for all request params and response fields, diff --git a/pyproject.toml b/pyproject.toml index 2c87a67c77..774f1a35b0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.94.0" +version = "1.95.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 9ed696d5dd..342202129c 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.94.0" # x-release-please-version +__version__ = "1.95.0" # x-release-please-version diff --git a/src/openai/types/audio/transcription.py b/src/openai/types/audio/transcription.py index 7115eb9edb..4c5882152d 100644 --- a/src/openai/types/audio/transcription.py +++ b/src/openai/types/audio/transcription.py @@ -46,7 +46,7 @@ class UsageTokens(BaseModel): class UsageDuration(BaseModel): - duration: float + seconds: float """Duration of the input audio in seconds.""" type: Literal["duration"] diff --git a/src/openai/types/audio/transcription_verbose.py b/src/openai/types/audio/transcription_verbose.py index cc6d769a65..addda71ec6 100644 --- a/src/openai/types/audio/transcription_verbose.py +++ b/src/openai/types/audio/transcription_verbose.py @@ -11,7 +11,7 @@ class Usage(BaseModel): - duration: float + seconds: float """Duration of the input audio in seconds.""" type: Literal["duration"] diff --git a/src/openai/types/beta/realtime/conversation_item_input_audio_transcription_completed_event.py b/src/openai/types/beta/realtime/conversation_item_input_audio_transcription_completed_event.py index 469811693c..e7c457d4b2 100644 --- a/src/openai/types/beta/realtime/conversation_item_input_audio_transcription_completed_event.py +++ b/src/openai/types/beta/realtime/conversation_item_input_audio_transcription_completed_event.py @@ -1,11 +1,54 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Optional -from typing_extensions import Literal +from typing import List, Union, Optional +from typing_extensions import Literal, TypeAlias from ...._models import BaseModel -__all__ = ["ConversationItemInputAudioTranscriptionCompletedEvent", "Logprob"] +__all__ = [ + "ConversationItemInputAudioTranscriptionCompletedEvent", + "Usage", + "UsageTranscriptTextUsageTokens", + "UsageTranscriptTextUsageTokensInputTokenDetails", + "UsageTranscriptTextUsageDuration", + "Logprob", +] + + +class UsageTranscriptTextUsageTokensInputTokenDetails(BaseModel): + audio_tokens: Optional[int] = None + """Number of audio tokens billed for this request.""" + + text_tokens: Optional[int] = None + """Number of text tokens billed for this request.""" + + +class UsageTranscriptTextUsageTokens(BaseModel): + input_tokens: int + """Number of input tokens billed for this request.""" + + output_tokens: int + """Number of output tokens generated.""" + + total_tokens: int + """Total number of tokens used (input + output).""" + + type: Literal["tokens"] + """The type of the usage object. Always `tokens` for this variant.""" + + input_token_details: Optional[UsageTranscriptTextUsageTokensInputTokenDetails] = None + """Details about the input tokens billed for this request.""" + + +class UsageTranscriptTextUsageDuration(BaseModel): + seconds: float + """Duration of the input audio in seconds.""" + + type: Literal["duration"] + """The type of the usage object. Always `duration` for this variant.""" + + +Usage: TypeAlias = Union[UsageTranscriptTextUsageTokens, UsageTranscriptTextUsageDuration] class Logprob(BaseModel): @@ -37,5 +80,8 @@ class ConversationItemInputAudioTranscriptionCompletedEvent(BaseModel): The event type, must be `conversation.item.input_audio_transcription.completed`. """ + usage: Usage + """Usage statistics for the transcription.""" + logprobs: Optional[List[Logprob]] = None """The log probabilities of the transcription.""" diff --git a/src/openai/types/file_object.py b/src/openai/types/file_object.py index 1d65e6987d..883c2de019 100644 --- a/src/openai/types/file_object.py +++ b/src/openai/types/file_object.py @@ -25,12 +25,19 @@ class FileObject(BaseModel): """The object type, which is always `file`.""" purpose: Literal[ - "assistants", "assistants_output", "batch", "batch_output", "fine-tune", "fine-tune-results", "vision" + "assistants", + "assistants_output", + "batch", + "batch_output", + "fine-tune", + "fine-tune-results", + "vision", + "user_data", ] """The intended purpose of the file. Supported values are `assistants`, `assistants_output`, `batch`, `batch_output`, - `fine-tune`, `fine-tune-results` and `vision`. + `fine-tune`, `fine-tune-results`, `vision`, and `user_data`. """ status: Literal["uploaded", "processed", "error"] diff --git a/src/openai/types/responses/response_input_file.py b/src/openai/types/responses/response_input_file.py index 00b35dc844..1eecd6a2b6 100644 --- a/src/openai/types/responses/response_input_file.py +++ b/src/openai/types/responses/response_input_file.py @@ -18,5 +18,8 @@ class ResponseInputFile(BaseModel): file_id: Optional[str] = None """The ID of the file to be sent to the model.""" + file_url: Optional[str] = None + """The URL of the file to be sent to the model.""" + filename: Optional[str] = None """The name of the file to be sent to the model.""" diff --git a/src/openai/types/responses/response_input_file_param.py b/src/openai/types/responses/response_input_file_param.py index 61ae46f0cb..0b5f513ec6 100644 --- a/src/openai/types/responses/response_input_file_param.py +++ b/src/openai/types/responses/response_input_file_param.py @@ -18,5 +18,8 @@ class ResponseInputFileParam(TypedDict, total=False): file_id: Optional[str] """The ID of the file to be sent to the model.""" + file_url: str + """The URL of the file to be sent to the model.""" + filename: str """The name of the file to be sent to the model.""" diff --git a/src/openai/types/responses/response_mcp_call_arguments_delta_event.py b/src/openai/types/responses/response_mcp_call_arguments_delta_event.py index d6651e6999..8481506dc3 100644 --- a/src/openai/types/responses/response_mcp_call_arguments_delta_event.py +++ b/src/openai/types/responses/response_mcp_call_arguments_delta_event.py @@ -20,5 +20,5 @@ class ResponseMcpCallArgumentsDeltaEvent(BaseModel): sequence_number: int """The sequence number of this event.""" - type: Literal["response.mcp_call.arguments_delta"] - """The type of the event. Always 'response.mcp_call.arguments_delta'.""" + type: Literal["response.mcp_call_arguments.delta"] + """The type of the event. Always 'response.mcp_call_arguments.delta'.""" diff --git a/src/openai/types/responses/response_mcp_call_arguments_done_event.py b/src/openai/types/responses/response_mcp_call_arguments_done_event.py index a7ce46ad36..4be09d4862 100644 --- a/src/openai/types/responses/response_mcp_call_arguments_done_event.py +++ b/src/openai/types/responses/response_mcp_call_arguments_done_event.py @@ -20,5 +20,5 @@ class ResponseMcpCallArgumentsDoneEvent(BaseModel): sequence_number: int """The sequence number of this event.""" - type: Literal["response.mcp_call.arguments_done"] - """The type of the event. Always 'response.mcp_call.arguments_done'.""" + type: Literal["response.mcp_call_arguments.done"] + """The type of the event. Always 'response.mcp_call_arguments.done'.""" diff --git a/src/openai/types/responses/response_output_text_annotation_added_event.py b/src/openai/types/responses/response_output_text_annotation_added_event.py index ce96790c92..62d8f72863 100644 --- a/src/openai/types/responses/response_output_text_annotation_added_event.py +++ b/src/openai/types/responses/response_output_text_annotation_added_event.py @@ -26,5 +26,5 @@ class ResponseOutputTextAnnotationAddedEvent(BaseModel): sequence_number: int """The sequence number of this event.""" - type: Literal["response.output_text_annotation.added"] - """The type of the event. Always 'response.output_text_annotation.added'.""" + type: Literal["response.output_text.annotation.added"] + """The type of the event. Always 'response.output_text.annotation.added'.""" diff --git a/src/openai/types/responses/tool.py b/src/openai/types/responses/tool.py index 904c474e40..9c1573bda9 100644 --- a/src/openai/types/responses/tool.py +++ b/src/openai/types/responses/tool.py @@ -79,6 +79,9 @@ class Mcp(BaseModel): require_approval: Optional[McpRequireApproval] = None """Specify which of the MCP server's tools require approval.""" + server_description: Optional[str] = None + """Optional description of the MCP server, used to provide more context.""" + class CodeInterpreterContainerCodeInterpreterToolAuto(BaseModel): type: Literal["auto"] diff --git a/src/openai/types/responses/tool_param.py b/src/openai/types/responses/tool_param.py index 4174560d42..493a1dad9c 100644 --- a/src/openai/types/responses/tool_param.py +++ b/src/openai/types/responses/tool_param.py @@ -80,6 +80,9 @@ class Mcp(TypedDict, total=False): require_approval: Optional[McpRequireApproval] """Specify which of the MCP server's tools require approval.""" + server_description: str + """Optional description of the MCP server, used to provide more context.""" + class CodeInterpreterContainerCodeInterpreterToolAuto(TypedDict, total=False): type: Required[Literal["auto"]] From fcbb59831c12e9d0a1dae1880d4f650c57de5294 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 11 Jul 2025 12:12:33 +0000 Subject: [PATCH 391/769] fix(client): don't send Content-Type header on GET requests --- pyproject.toml | 2 +- src/openai/_base_client.py | 11 +++++++++-- tests/test_client.py | 4 ++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 774f1a35b0..f423907080 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,7 +44,7 @@ Repository = "https://github.com/openai/openai-python" openai = "openai.cli:main" [project.optional-dependencies] -aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.6"] +aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.8"] realtime = ["websockets >= 13, < 16"] datalib = ["numpy >= 1", "pandas >= 1.2.3", "pandas-stubs >= 1.1.0.11"] voice_helpers = ["sounddevice>=0.5.1", "numpy>=2.0.2"] diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index 0a6385a7b5..3fe669259f 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -531,6 +531,15 @@ def _build_request( # work around https://github.com/encode/httpx/discussions/2880 kwargs["extensions"] = {"sni_hostname": prepared_url.host.replace("_", "-")} + is_body_allowed = options.method.lower() != "get" + + if is_body_allowed: + kwargs["json"] = json_data if is_given(json_data) else None + kwargs["files"] = files + else: + headers.pop("Content-Type", None) + kwargs.pop("data", None) + # TODO: report this error to httpx return self._client.build_request( # pyright: ignore[reportUnknownMemberType] headers=headers, @@ -542,8 +551,6 @@ def _build_request( # so that passing a `TypedDict` doesn't cause an error. # https://github.com/microsoft/pyright/issues/3526#event-6715453066 params=self.qs.stringify(cast(Mapping[str, Any], params)) if params else None, - json=json_data if is_given(json_data) else None, - files=files, **kwargs, ) diff --git a/tests/test_client.py b/tests/test_client.py index 988e5d994c..ccda50a7f0 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -463,7 +463,7 @@ def test_request_extra_query(self) -> None: def test_multipart_repeating_array(self, client: OpenAI) -> None: request = client._build_request( FinalRequestOptions.construct( - method="get", + method="post", url="/foo", headers={"Content-Type": "multipart/form-data; boundary=6b7ba517decee4a450543ea6ae821c82"}, json_data={"array": ["foo", "bar"]}, @@ -1348,7 +1348,7 @@ def test_request_extra_query(self) -> None: def test_multipart_repeating_array(self, async_client: AsyncOpenAI) -> None: request = async_client._build_request( FinalRequestOptions.construct( - method="get", + method="post", url="/foo", headers={"Content-Type": "multipart/form-data; boundary=6b7ba517decee4a450543ea6ae821c82"}, json_data={"array": ["foo", "bar"]}, From 0fa4028ac5b20c49aa0d3ed69dea2dcf277db574 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 11 Jul 2025 18:29:28 +0000 Subject: [PATCH 392/769] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 816f05df5c..0a24d32759 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-2d116cda53321baa3479e628512def723207a81eb1cdaebb542bd0555e563bda.yml openapi_spec_hash: 809d958fec261a32004a4b026b718793 -config_hash: e74d6791681e3af1b548748ff47a22c2 +config_hash: 00b55237774c015fc35f58d2820759a9 From 043589aebf4848dfa977f2b9d0a40a2de0dde95e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 11 Jul 2025 18:32:46 +0000 Subject: [PATCH 393/769] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 0a24d32759..295b77b5af 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-2d116cda53321baa3479e628512def723207a81eb1cdaebb542bd0555e563bda.yml openapi_spec_hash: 809d958fec261a32004a4b026b718793 -config_hash: 00b55237774c015fc35f58d2820759a9 +config_hash: 5ef02e55671aae1ba9bd62fe4eb0f50f From 05e3755b8fd8f03adca94eb6797c0c21b564fa80 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 11 Jul 2025 20:38:34 +0000 Subject: [PATCH 394/769] codegen metadata --- .stats.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.stats.yml b/.stats.yml index 295b77b5af..b82cec4eb6 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-2d116cda53321baa3479e628512def723207a81eb1cdaebb542bd0555e563bda.yml -openapi_spec_hash: 809d958fec261a32004a4b026b718793 -config_hash: 5ef02e55671aae1ba9bd62fe4eb0f50f +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-de3e91790d0b9f3ce26d679ac07079880ccc695bd8c878f961c4d577a5025a2e.yml +openapi_spec_hash: 4b44e3f287583d01fbe7b10cd943254a +config_hash: 06b9a88561844d60d8efa4eaabf5fa3c From 1c0b4642054544af92c0c3a8cdf5ef3c3f62f1d7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 11 Jul 2025 20:39:01 +0000 Subject: [PATCH 395/769] release: 1.95.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 9a75280778..ffcd85673c 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.95.0" + ".": "1.95.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index f5c49d637f..14d61de1bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.95.1 (2025-07-11) + +Full Changelog: [v1.95.0...v1.95.1](https://github.com/openai/openai-python/compare/v1.95.0...v1.95.1) + +### Bug Fixes + +* **client:** don't send Content-Type header on GET requests ([182b763](https://github.com/openai/openai-python/commit/182b763065fbaaf68491a7e4a15fcb23cac361de)) + ## 1.95.0 (2025-07-10) Full Changelog: [v1.94.0...v1.95.0](https://github.com/openai/openai-python/compare/v1.94.0...v1.95.0) diff --git a/pyproject.toml b/pyproject.toml index f423907080..d9305c5469 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.95.0" +version = "1.95.1" 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 342202129c..6e2b83bbaa 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.95.0" # x-release-please-version +__version__ = "1.95.1" # x-release-please-version From 2028ad2b95f3e8f7736d45d730c0cc53852c392c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 14 Jul 2025 17:29:56 +0000 Subject: [PATCH 396/769] feat: clean up environment call outs --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index d09de14f3c..d4b8d8d170 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,6 @@ pip install openai[aiohttp] Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`: ```python -import os import asyncio from openai import DefaultAioHttpClient from openai import AsyncOpenAI @@ -168,7 +167,7 @@ from openai import AsyncOpenAI async def main() -> None: async with AsyncOpenAI( - api_key=os.environ.get("OPENAI_API_KEY"), # This is the default and can be omitted + api_key="My API Key", http_client=DefaultAioHttpClient(), ) as client: chat_completion = await client.chat.completions.create( From 1cb2bf6e0afa3d4c52c0f4d5e2ffeccaa7339624 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 15 Jul 2025 13:48:50 +0000 Subject: [PATCH 397/769] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index b82cec4eb6..a146676471 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-de3e91790d0b9f3ce26d679ac07079880ccc695bd8c878f961c4d577a5025a2e.yml openapi_spec_hash: 4b44e3f287583d01fbe7b10cd943254a -config_hash: 06b9a88561844d60d8efa4eaabf5fa3c +config_hash: cc92d0be2a0f3c77bfc988082dd0573e From 34a565164878d97d13fb2d3f7b5602fe73ad332d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 15 Jul 2025 15:46:45 +0000 Subject: [PATCH 398/769] chore(api): update realtime specs, build config --- .stats.yml | 6 ++--- .../types/beta/realtime/conversation_item.py | 4 ++-- .../conversation_item_created_event.py | 12 ++++++---- .../beta/realtime/conversation_item_param.py | 4 ++-- .../conversation_item_with_reference.py | 4 ++-- .../conversation_item_with_reference_param.py | 4 ++-- .../input_audio_buffer_committed_event.py | 10 +++++--- .../types/beta/realtime/realtime_response.py | 4 ++-- src/openai/types/eval_create_params.py | 23 +++++++++++++++++-- ...create_eval_completions_run_data_source.py | 23 +++++++++++++++++-- ..._eval_completions_run_data_source_param.py | 23 +++++++++++++++++-- src/openai/types/evals/run_cancel_response.py | 23 +++++++++++++++++-- src/openai/types/evals/run_create_params.py | 21 ++++++++++++++++- src/openai/types/evals/run_create_response.py | 23 +++++++++++++++++-- src/openai/types/evals/run_list_response.py | 23 +++++++++++++++++-- .../types/evals/run_retrieve_response.py | 23 +++++++++++++++++-- .../types/graders/label_model_grader.py | 20 +++++++++++++--- .../types/graders/label_model_grader_param.py | 22 +++++++++++++++--- .../types/graders/score_model_grader.py | 20 +++++++++++++--- .../types/graders/score_model_grader_param.py | 22 +++++++++++++++--- 20 files changed, 266 insertions(+), 48 deletions(-) diff --git a/.stats.yml b/.stats.yml index a146676471..12a179baf6 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-de3e91790d0b9f3ce26d679ac07079880ccc695bd8c878f961c4d577a5025a2e.yml -openapi_spec_hash: 4b44e3f287583d01fbe7b10cd943254a -config_hash: cc92d0be2a0f3c77bfc988082dd0573e +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-82fd6fcb3eea81cbbe09a6f831c82219f1251e1b76474b4c41f424bf277e6a71.yml +openapi_spec_hash: c8d54bd1ae3d704f6b6f72ffd2f876d8 +config_hash: 3315d58b60faf63b1bee251b81837cda diff --git a/src/openai/types/beta/realtime/conversation_item.py b/src/openai/types/beta/realtime/conversation_item.py index 4edf6c4d5f..21b7a8ac1f 100644 --- a/src/openai/types/beta/realtime/conversation_item.py +++ b/src/openai/types/beta/realtime/conversation_item.py @@ -50,8 +50,8 @@ class ConversationItem(BaseModel): for `message` items. """ - status: Optional[Literal["completed", "incomplete"]] = None - """The status of the item (`completed`, `incomplete`). + status: Optional[Literal["completed", "incomplete", "in_progress"]] = None + """The status of the item (`completed`, `incomplete`, `in_progress`). These have no effect on the conversation, but are accepted for consistency with the `conversation.item.created` event. diff --git a/src/openai/types/beta/realtime/conversation_item_created_event.py b/src/openai/types/beta/realtime/conversation_item_created_event.py index 2f20388246..aea7ad5b4b 100644 --- a/src/openai/types/beta/realtime/conversation_item_created_event.py +++ b/src/openai/types/beta/realtime/conversation_item_created_event.py @@ -1,5 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from typing import Optional from typing_extensions import Literal from ...._models import BaseModel @@ -15,11 +16,12 @@ class ConversationItemCreatedEvent(BaseModel): item: ConversationItem """The item to add to the conversation.""" - previous_item_id: str + type: Literal["conversation.item.created"] + """The event type, must be `conversation.item.created`.""" + + previous_item_id: Optional[str] = None """ The ID of the preceding item in the Conversation context, allows the client to - understand the order of the conversation. + understand the order of the conversation. Can be `null` if the item has no + predecessor. """ - - type: Literal["conversation.item.created"] - """The event type, must be `conversation.item.created`.""" diff --git a/src/openai/types/beta/realtime/conversation_item_param.py b/src/openai/types/beta/realtime/conversation_item_param.py index ac0f8431e5..8bbd539c0c 100644 --- a/src/openai/types/beta/realtime/conversation_item_param.py +++ b/src/openai/types/beta/realtime/conversation_item_param.py @@ -51,8 +51,8 @@ class ConversationItemParam(TypedDict, total=False): for `message` items. """ - status: Literal["completed", "incomplete"] - """The status of the item (`completed`, `incomplete`). + status: Literal["completed", "incomplete", "in_progress"] + """The status of the item (`completed`, `incomplete`, `in_progress`). These have no effect on the conversation, but are accepted for consistency with the `conversation.item.created` event. diff --git a/src/openai/types/beta/realtime/conversation_item_with_reference.py b/src/openai/types/beta/realtime/conversation_item_with_reference.py index 31806afc33..dec7a5a409 100644 --- a/src/openai/types/beta/realtime/conversation_item_with_reference.py +++ b/src/openai/types/beta/realtime/conversation_item_with_reference.py @@ -53,8 +53,8 @@ class ConversationItemWithReference(BaseModel): for `message` items. """ - status: Optional[Literal["completed", "incomplete"]] = None - """The status of the item (`completed`, `incomplete`). + status: Optional[Literal["completed", "incomplete", "in_progress"]] = None + """The status of the item (`completed`, `incomplete`, `in_progress`). These have no effect on the conversation, but are accepted for consistency with the `conversation.item.created` event. diff --git a/src/openai/types/beta/realtime/conversation_item_with_reference_param.py b/src/openai/types/beta/realtime/conversation_item_with_reference_param.py index e266cdce32..3778373a4c 100644 --- a/src/openai/types/beta/realtime/conversation_item_with_reference_param.py +++ b/src/openai/types/beta/realtime/conversation_item_with_reference_param.py @@ -54,8 +54,8 @@ class ConversationItemWithReferenceParam(TypedDict, total=False): for `message` items. """ - status: Literal["completed", "incomplete"] - """The status of the item (`completed`, `incomplete`). + status: Literal["completed", "incomplete", "in_progress"] + """The status of the item (`completed`, `incomplete`, `in_progress`). These have no effect on the conversation, but are accepted for consistency with the `conversation.item.created` event. diff --git a/src/openai/types/beta/realtime/input_audio_buffer_committed_event.py b/src/openai/types/beta/realtime/input_audio_buffer_committed_event.py index 3071eff357..22eb53b117 100644 --- a/src/openai/types/beta/realtime/input_audio_buffer_committed_event.py +++ b/src/openai/types/beta/realtime/input_audio_buffer_committed_event.py @@ -1,5 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from typing import Optional from typing_extensions import Literal from ...._models import BaseModel @@ -14,8 +15,11 @@ class InputAudioBufferCommittedEvent(BaseModel): item_id: str """The ID of the user message item that will be created.""" - previous_item_id: str - """The ID of the preceding item after which the new item will be inserted.""" - type: Literal["input_audio_buffer.committed"] """The event type, must be `input_audio_buffer.committed`.""" + + previous_item_id: Optional[str] = None + """ + The ID of the preceding item after which the new item will be inserted. Can be + `null` if the item has no predecessor. + """ diff --git a/src/openai/types/beta/realtime/realtime_response.py b/src/openai/types/beta/realtime/realtime_response.py index 8ecfb91c31..28e03c8717 100644 --- a/src/openai/types/beta/realtime/realtime_response.py +++ b/src/openai/types/beta/realtime/realtime_response.py @@ -60,10 +60,10 @@ class RealtimeResponse(BaseModel): output_audio_format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None """The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" - status: Optional[Literal["completed", "cancelled", "failed", "incomplete"]] = None + status: Optional[Literal["completed", "cancelled", "failed", "incomplete", "in_progress"]] = None """ The final status of the response (`completed`, `cancelled`, `failed`, or - `incomplete`). + `incomplete`, `in_progress`). """ status_details: Optional[RealtimeResponseStatus] = None diff --git a/src/openai/types/eval_create_params.py b/src/openai/types/eval_create_params.py index 20a3765481..9674785701 100644 --- a/src/openai/types/eval_create_params.py +++ b/src/openai/types/eval_create_params.py @@ -25,6 +25,7 @@ "TestingCriterionLabelModelInputEvalItem", "TestingCriterionLabelModelInputEvalItemContent", "TestingCriterionLabelModelInputEvalItemContentOutputText", + "TestingCriterionLabelModelInputEvalItemContentInputImage", "TestingCriterionTextSimilarity", "TestingCriterionPython", "TestingCriterionScoreModel", @@ -109,14 +110,32 @@ class TestingCriterionLabelModelInputEvalItemContentOutputText(TypedDict, total= """The type of the output text. Always `output_text`.""" +class TestingCriterionLabelModelInputEvalItemContentInputImage(TypedDict, total=False): + image_url: Required[str] + """The URL of the image input.""" + + type: Required[Literal["input_image"]] + """The type of the image input. Always `input_image`.""" + + detail: str + """The detail level of the image to be sent to the model. + + One of `high`, `low`, or `auto`. Defaults to `auto`. + """ + + TestingCriterionLabelModelInputEvalItemContent: TypeAlias = Union[ - str, ResponseInputTextParam, TestingCriterionLabelModelInputEvalItemContentOutputText + str, + ResponseInputTextParam, + TestingCriterionLabelModelInputEvalItemContentOutputText, + TestingCriterionLabelModelInputEvalItemContentInputImage, + Iterable[object], ] class TestingCriterionLabelModelInputEvalItem(TypedDict, total=False): content: Required[TestingCriterionLabelModelInputEvalItemContent] - """Text inputs to the model - can contain template strings.""" + """Inputs to the model - can contain template strings.""" role: Required[Literal["user", "assistant", "system", "developer"]] """The role of the message input. diff --git a/src/openai/types/evals/create_eval_completions_run_data_source.py b/src/openai/types/evals/create_eval_completions_run_data_source.py index 0a942cd200..a0eaa5addb 100644 --- a/src/openai/types/evals/create_eval_completions_run_data_source.py +++ b/src/openai/types/evals/create_eval_completions_run_data_source.py @@ -26,6 +26,7 @@ "InputMessagesTemplateTemplateMessage", "InputMessagesTemplateTemplateMessageContent", "InputMessagesTemplateTemplateMessageContentOutputText", + "InputMessagesTemplateTemplateMessageContentInputImage", "InputMessagesItemReference", "SamplingParams", "SamplingParamsResponseFormat", @@ -94,14 +95,32 @@ class InputMessagesTemplateTemplateMessageContentOutputText(BaseModel): """The type of the output text. Always `output_text`.""" +class InputMessagesTemplateTemplateMessageContentInputImage(BaseModel): + image_url: str + """The URL of the image input.""" + + type: Literal["input_image"] + """The type of the image input. Always `input_image`.""" + + detail: Optional[str] = None + """The detail level of the image to be sent to the model. + + One of `high`, `low`, or `auto`. Defaults to `auto`. + """ + + InputMessagesTemplateTemplateMessageContent: TypeAlias = Union[ - str, ResponseInputText, InputMessagesTemplateTemplateMessageContentOutputText + str, + ResponseInputText, + InputMessagesTemplateTemplateMessageContentOutputText, + InputMessagesTemplateTemplateMessageContentInputImage, + List[object], ] class InputMessagesTemplateTemplateMessage(BaseModel): content: InputMessagesTemplateTemplateMessageContent - """Text inputs to the model - can contain template strings.""" + """Inputs to the model - can contain template strings.""" role: Literal["user", "assistant", "system", "developer"] """The role of the message input. diff --git a/src/openai/types/evals/create_eval_completions_run_data_source_param.py b/src/openai/types/evals/create_eval_completions_run_data_source_param.py index 84344fcd94..8892b68b17 100644 --- a/src/openai/types/evals/create_eval_completions_run_data_source_param.py +++ b/src/openai/types/evals/create_eval_completions_run_data_source_param.py @@ -26,6 +26,7 @@ "InputMessagesTemplateTemplateMessage", "InputMessagesTemplateTemplateMessageContent", "InputMessagesTemplateTemplateMessageContentOutputText", + "InputMessagesTemplateTemplateMessageContentInputImage", "InputMessagesItemReference", "SamplingParams", "SamplingParamsResponseFormat", @@ -92,14 +93,32 @@ class InputMessagesTemplateTemplateMessageContentOutputText(TypedDict, total=Fal """The type of the output text. Always `output_text`.""" +class InputMessagesTemplateTemplateMessageContentInputImage(TypedDict, total=False): + image_url: Required[str] + """The URL of the image input.""" + + type: Required[Literal["input_image"]] + """The type of the image input. Always `input_image`.""" + + detail: str + """The detail level of the image to be sent to the model. + + One of `high`, `low`, or `auto`. Defaults to `auto`. + """ + + InputMessagesTemplateTemplateMessageContent: TypeAlias = Union[ - str, ResponseInputTextParam, InputMessagesTemplateTemplateMessageContentOutputText + str, + ResponseInputTextParam, + InputMessagesTemplateTemplateMessageContentOutputText, + InputMessagesTemplateTemplateMessageContentInputImage, + Iterable[object], ] class InputMessagesTemplateTemplateMessage(TypedDict, total=False): content: Required[InputMessagesTemplateTemplateMessageContent] - """Text inputs to the model - can contain template strings.""" + """Inputs to the model - can contain template strings.""" role: Required[Literal["user", "assistant", "system", "developer"]] """The role of the message input. diff --git a/src/openai/types/evals/run_cancel_response.py b/src/openai/types/evals/run_cancel_response.py index 12cc868045..7f4f4c9cc4 100644 --- a/src/openai/types/evals/run_cancel_response.py +++ b/src/openai/types/evals/run_cancel_response.py @@ -32,6 +32,7 @@ "DataSourceResponsesInputMessagesTemplateTemplateEvalItem", "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent", "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage", "DataSourceResponsesInputMessagesItemReference", "DataSourceResponsesSamplingParams", "DataSourceResponsesSamplingParamsText", @@ -138,14 +139,32 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText( """The type of the output text. Always `output_text`.""" +class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage(BaseModel): + image_url: str + """The URL of the image input.""" + + type: Literal["input_image"] + """The type of the image input. Always `input_image`.""" + + detail: Optional[str] = None + """The detail level of the image to be sent to the model. + + One of `high`, `low`, or `auto`. Defaults to `auto`. + """ + + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ - str, ResponseInputText, DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText + str, + ResponseInputText, + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText, + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage, + List[object], ] class DataSourceResponsesInputMessagesTemplateTemplateEvalItem(BaseModel): content: DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent - """Text inputs to the model - can contain template strings.""" + """Inputs to the model - can contain template strings.""" role: Literal["user", "assistant", "system", "developer"] """The role of the message input. diff --git a/src/openai/types/evals/run_create_params.py b/src/openai/types/evals/run_create_params.py index 354a81132e..1622b00eb7 100644 --- a/src/openai/types/evals/run_create_params.py +++ b/src/openai/types/evals/run_create_params.py @@ -29,6 +29,7 @@ "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItem", "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContent", "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentOutputText", + "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentInputImage", "DataSourceCreateEvalResponsesRunDataSourceInputMessagesItemReference", "DataSourceCreateEvalResponsesRunDataSourceSamplingParams", "DataSourceCreateEvalResponsesRunDataSourceSamplingParamsText", @@ -153,16 +154,34 @@ class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEva """The type of the output text. Always `output_text`.""" +class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentInputImage( + TypedDict, total=False +): + image_url: Required[str] + """The URL of the image input.""" + + type: Required[Literal["input_image"]] + """The type of the image input. Always `input_image`.""" + + detail: str + """The detail level of the image to be sent to the model. + + One of `high`, `low`, or `auto`. Defaults to `auto`. + """ + + DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ str, ResponseInputTextParam, DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentOutputText, + DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentInputImage, + Iterable[object], ] class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItem(TypedDict, total=False): content: Required[DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContent] - """Text inputs to the model - can contain template strings.""" + """Inputs to the model - can contain template strings.""" role: Required[Literal["user", "assistant", "system", "developer"]] """The role of the message input. diff --git a/src/openai/types/evals/run_create_response.py b/src/openai/types/evals/run_create_response.py index 776ebb413f..fba5321552 100644 --- a/src/openai/types/evals/run_create_response.py +++ b/src/openai/types/evals/run_create_response.py @@ -32,6 +32,7 @@ "DataSourceResponsesInputMessagesTemplateTemplateEvalItem", "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent", "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage", "DataSourceResponsesInputMessagesItemReference", "DataSourceResponsesSamplingParams", "DataSourceResponsesSamplingParamsText", @@ -138,14 +139,32 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText( """The type of the output text. Always `output_text`.""" +class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage(BaseModel): + image_url: str + """The URL of the image input.""" + + type: Literal["input_image"] + """The type of the image input. Always `input_image`.""" + + detail: Optional[str] = None + """The detail level of the image to be sent to the model. + + One of `high`, `low`, or `auto`. Defaults to `auto`. + """ + + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ - str, ResponseInputText, DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText + str, + ResponseInputText, + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText, + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage, + List[object], ] class DataSourceResponsesInputMessagesTemplateTemplateEvalItem(BaseModel): content: DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent - """Text inputs to the model - can contain template strings.""" + """Inputs to the model - can contain template strings.""" role: Literal["user", "assistant", "system", "developer"] """The role of the message input. diff --git a/src/openai/types/evals/run_list_response.py b/src/openai/types/evals/run_list_response.py index 9e2374f93c..e9e445af5c 100644 --- a/src/openai/types/evals/run_list_response.py +++ b/src/openai/types/evals/run_list_response.py @@ -32,6 +32,7 @@ "DataSourceResponsesInputMessagesTemplateTemplateEvalItem", "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent", "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage", "DataSourceResponsesInputMessagesItemReference", "DataSourceResponsesSamplingParams", "DataSourceResponsesSamplingParamsText", @@ -138,14 +139,32 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText( """The type of the output text. Always `output_text`.""" +class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage(BaseModel): + image_url: str + """The URL of the image input.""" + + type: Literal["input_image"] + """The type of the image input. Always `input_image`.""" + + detail: Optional[str] = None + """The detail level of the image to be sent to the model. + + One of `high`, `low`, or `auto`. Defaults to `auto`. + """ + + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ - str, ResponseInputText, DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText + str, + ResponseInputText, + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText, + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage, + List[object], ] class DataSourceResponsesInputMessagesTemplateTemplateEvalItem(BaseModel): content: DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent - """Text inputs to the model - can contain template strings.""" + """Inputs to the model - can contain template strings.""" role: Literal["user", "assistant", "system", "developer"] """The role of the message input. diff --git a/src/openai/types/evals/run_retrieve_response.py b/src/openai/types/evals/run_retrieve_response.py index a4f43ce3f9..e13f1abe42 100644 --- a/src/openai/types/evals/run_retrieve_response.py +++ b/src/openai/types/evals/run_retrieve_response.py @@ -32,6 +32,7 @@ "DataSourceResponsesInputMessagesTemplateTemplateEvalItem", "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent", "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage", "DataSourceResponsesInputMessagesItemReference", "DataSourceResponsesSamplingParams", "DataSourceResponsesSamplingParamsText", @@ -138,14 +139,32 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText( """The type of the output text. Always `output_text`.""" +class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage(BaseModel): + image_url: str + """The URL of the image input.""" + + type: Literal["input_image"] + """The type of the image input. Always `input_image`.""" + + detail: Optional[str] = None + """The detail level of the image to be sent to the model. + + One of `high`, `low`, or `auto`. Defaults to `auto`. + """ + + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ - str, ResponseInputText, DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText + str, + ResponseInputText, + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText, + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage, + List[object], ] class DataSourceResponsesInputMessagesTemplateTemplateEvalItem(BaseModel): content: DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent - """Text inputs to the model - can contain template strings.""" + """Inputs to the model - can contain template strings.""" role: Literal["user", "assistant", "system", "developer"] """The role of the message input. diff --git a/src/openai/types/graders/label_model_grader.py b/src/openai/types/graders/label_model_grader.py index d95ccc6df6..76dbfb854a 100644 --- a/src/openai/types/graders/label_model_grader.py +++ b/src/openai/types/graders/label_model_grader.py @@ -6,7 +6,7 @@ from ..._models import BaseModel from ..responses.response_input_text import ResponseInputText -__all__ = ["LabelModelGrader", "Input", "InputContent", "InputContentOutputText"] +__all__ = ["LabelModelGrader", "Input", "InputContent", "InputContentOutputText", "InputContentInputImage"] class InputContentOutputText(BaseModel): @@ -17,12 +17,26 @@ class InputContentOutputText(BaseModel): """The type of the output text. Always `output_text`.""" -InputContent: TypeAlias = Union[str, ResponseInputText, InputContentOutputText] +class InputContentInputImage(BaseModel): + image_url: str + """The URL of the image input.""" + + type: Literal["input_image"] + """The type of the image input. Always `input_image`.""" + + detail: Optional[str] = None + """The detail level of the image to be sent to the model. + + One of `high`, `low`, or `auto`. Defaults to `auto`. + """ + + +InputContent: TypeAlias = Union[str, ResponseInputText, InputContentOutputText, InputContentInputImage, List[object]] class Input(BaseModel): content: InputContent - """Text inputs to the model - can contain template strings.""" + """Inputs to the model - can contain template strings.""" role: Literal["user", "assistant", "system", "developer"] """The role of the message input. diff --git a/src/openai/types/graders/label_model_grader_param.py b/src/openai/types/graders/label_model_grader_param.py index 76d01421ee..941c8a1bd0 100644 --- a/src/openai/types/graders/label_model_grader_param.py +++ b/src/openai/types/graders/label_model_grader_param.py @@ -7,7 +7,7 @@ from ..responses.response_input_text_param import ResponseInputTextParam -__all__ = ["LabelModelGraderParam", "Input", "InputContent", "InputContentOutputText"] +__all__ = ["LabelModelGraderParam", "Input", "InputContent", "InputContentOutputText", "InputContentInputImage"] class InputContentOutputText(TypedDict, total=False): @@ -18,12 +18,28 @@ class InputContentOutputText(TypedDict, total=False): """The type of the output text. Always `output_text`.""" -InputContent: TypeAlias = Union[str, ResponseInputTextParam, InputContentOutputText] +class InputContentInputImage(TypedDict, total=False): + image_url: Required[str] + """The URL of the image input.""" + + type: Required[Literal["input_image"]] + """The type of the image input. Always `input_image`.""" + + detail: str + """The detail level of the image to be sent to the model. + + One of `high`, `low`, or `auto`. Defaults to `auto`. + """ + + +InputContent: TypeAlias = Union[ + str, ResponseInputTextParam, InputContentOutputText, InputContentInputImage, Iterable[object] +] class Input(TypedDict, total=False): content: Required[InputContent] - """Text inputs to the model - can contain template strings.""" + """Inputs to the model - can contain template strings.""" role: Required[Literal["user", "assistant", "system", "developer"]] """The role of the message input. diff --git a/src/openai/types/graders/score_model_grader.py b/src/openai/types/graders/score_model_grader.py index 1349f75a58..e6af0ebcf7 100644 --- a/src/openai/types/graders/score_model_grader.py +++ b/src/openai/types/graders/score_model_grader.py @@ -6,7 +6,7 @@ from ..._models import BaseModel from ..responses.response_input_text import ResponseInputText -__all__ = ["ScoreModelGrader", "Input", "InputContent", "InputContentOutputText"] +__all__ = ["ScoreModelGrader", "Input", "InputContent", "InputContentOutputText", "InputContentInputImage"] class InputContentOutputText(BaseModel): @@ -17,12 +17,26 @@ class InputContentOutputText(BaseModel): """The type of the output text. Always `output_text`.""" -InputContent: TypeAlias = Union[str, ResponseInputText, InputContentOutputText] +class InputContentInputImage(BaseModel): + image_url: str + """The URL of the image input.""" + + type: Literal["input_image"] + """The type of the image input. Always `input_image`.""" + + detail: Optional[str] = None + """The detail level of the image to be sent to the model. + + One of `high`, `low`, or `auto`. Defaults to `auto`. + """ + + +InputContent: TypeAlias = Union[str, ResponseInputText, InputContentOutputText, InputContentInputImage, List[object]] class Input(BaseModel): content: InputContent - """Text inputs to the model - can contain template strings.""" + """Inputs to the model - can contain template strings.""" role: Literal["user", "assistant", "system", "developer"] """The role of the message input. diff --git a/src/openai/types/graders/score_model_grader_param.py b/src/openai/types/graders/score_model_grader_param.py index 673f14e47d..47c9928076 100644 --- a/src/openai/types/graders/score_model_grader_param.py +++ b/src/openai/types/graders/score_model_grader_param.py @@ -7,7 +7,7 @@ from ..responses.response_input_text_param import ResponseInputTextParam -__all__ = ["ScoreModelGraderParam", "Input", "InputContent", "InputContentOutputText"] +__all__ = ["ScoreModelGraderParam", "Input", "InputContent", "InputContentOutputText", "InputContentInputImage"] class InputContentOutputText(TypedDict, total=False): @@ -18,12 +18,28 @@ class InputContentOutputText(TypedDict, total=False): """The type of the output text. Always `output_text`.""" -InputContent: TypeAlias = Union[str, ResponseInputTextParam, InputContentOutputText] +class InputContentInputImage(TypedDict, total=False): + image_url: Required[str] + """The URL of the image input.""" + + type: Required[Literal["input_image"]] + """The type of the image input. Always `input_image`.""" + + detail: str + """The detail level of the image to be sent to the model. + + One of `high`, `low`, or `auto`. Defaults to `auto`. + """ + + +InputContent: TypeAlias = Union[ + str, ResponseInputTextParam, InputContentOutputText, InputContentInputImage, Iterable[object] +] class Input(TypedDict, total=False): content: Required[InputContent] - """Text inputs to the model - can contain template strings.""" + """Inputs to the model - can contain template strings.""" role: Required[Literal["user", "assistant", "system", "developer"]] """The role of the message input. From 1d77265e3d31afda8df6528a1926c854ef27de3b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 15 Jul 2025 15:47:15 +0000 Subject: [PATCH 399/769] release: 1.96.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index ffcd85673c..db912a0d0f 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.95.1" + ".": "1.96.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 14d61de1bf..c91c4c4b35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 1.96.0 (2025-07-15) + +Full Changelog: [v1.95.1...v1.96.0](https://github.com/openai/openai-python/compare/v1.95.1...v1.96.0) + +### Features + +* clean up environment call outs ([87c2e97](https://github.com/openai/openai-python/commit/87c2e979e0ec37347b7f595c2696408acd25fe20)) + + +### Chores + +* **api:** update realtime specs, build config ([bf06d88](https://github.com/openai/openai-python/commit/bf06d88b33f9af82a51d9a8af5b7a38925906f7a)) + ## 1.95.1 (2025-07-11) Full Changelog: [v1.95.0...v1.95.1](https://github.com/openai/openai-python/compare/v1.95.0...v1.95.1) diff --git a/pyproject.toml b/pyproject.toml index d9305c5469..65055d926a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.95.1" +version = "1.96.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 6e2b83bbaa..b1025f4a31 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.95.1" # x-release-please-version +__version__ = "1.96.0" # x-release-please-version From 7bbb31cba0b056a191277a63e9798ffc4c3f7586 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 15 Jul 2025 16:20:27 +0000 Subject: [PATCH 400/769] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 12a179baf6..7d1cdd14ad 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-82fd6fcb3eea81cbbe09a6f831c82219f1251e1b76474b4c41f424bf277e6a71.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-79dcb0ae501ac17004f50aecb112a798290ab3727fbe7c7d1b34299e38ed4f8e.yml openapi_spec_hash: c8d54bd1ae3d704f6b6f72ffd2f876d8 -config_hash: 3315d58b60faf63b1bee251b81837cda +config_hash: 167ad0ca036d0f023c78e6496b4311e8 From 3876ddc28e833aca190d6ec8eaf3b42c979f6e99 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 15 Jul 2025 21:27:39 +0000 Subject: [PATCH 401/769] chore(api): update realtime specs --- .stats.yml | 4 +-- .../realtime/conversation_item_content.py | 9 ++++--- .../conversation_item_content_param.py | 9 ++++--- .../conversation_item_with_reference.py | 26 ++++++++++++++++--- .../conversation_item_with_reference_param.py | 25 +++++++++++++++--- 5 files changed, 59 insertions(+), 14 deletions(-) diff --git a/.stats.yml b/.stats.yml index 7d1cdd14ad..571b0ee797 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-79dcb0ae501ac17004f50aecb112a798290ab3727fbe7c7d1b34299e38ed4f8e.yml -openapi_spec_hash: c8d54bd1ae3d704f6b6f72ffd2f876d8 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-c7dacca97e28bceff218684bb429481a70aa47aadad983ed9178bfda75ff4cd2.yml +openapi_spec_hash: 28eb1bb901ca10d2e37db4606d2bcfa7 config_hash: 167ad0ca036d0f023c78e6496b4311e8 diff --git a/src/openai/types/beta/realtime/conversation_item_content.py b/src/openai/types/beta/realtime/conversation_item_content.py index ab40a4a1a7..fe9cef80e3 100644 --- a/src/openai/types/beta/realtime/conversation_item_content.py +++ b/src/openai/types/beta/realtime/conversation_item_content.py @@ -23,7 +23,10 @@ class ConversationItemContent(BaseModel): """The text content, used for `input_text` and `text` content types.""" transcript: Optional[str] = None - """The transcript of the audio, used for `input_audio` content type.""" + """The transcript of the audio, used for `input_audio` and `audio` content types.""" - type: Optional[Literal["input_text", "input_audio", "item_reference", "text"]] = None - """The content type (`input_text`, `input_audio`, `item_reference`, `text`).""" + type: Optional[Literal["input_text", "input_audio", "item_reference", "text", "audio"]] = None + """ + The content type (`input_text`, `input_audio`, `item_reference`, `text`, + `audio`). + """ diff --git a/src/openai/types/beta/realtime/conversation_item_content_param.py b/src/openai/types/beta/realtime/conversation_item_content_param.py index 7a3a92a39d..6042e7f90f 100644 --- a/src/openai/types/beta/realtime/conversation_item_content_param.py +++ b/src/openai/types/beta/realtime/conversation_item_content_param.py @@ -22,7 +22,10 @@ class ConversationItemContentParam(TypedDict, total=False): """The text content, used for `input_text` and `text` content types.""" transcript: str - """The transcript of the audio, used for `input_audio` content type.""" + """The transcript of the audio, used for `input_audio` and `audio` content types.""" - type: Literal["input_text", "input_audio", "item_reference", "text"] - """The content type (`input_text`, `input_audio`, `item_reference`, `text`).""" + type: Literal["input_text", "input_audio", "item_reference", "text", "audio"] + """ + The content type (`input_text`, `input_audio`, `item_reference`, `text`, + `audio`). + """ diff --git a/src/openai/types/beta/realtime/conversation_item_with_reference.py b/src/openai/types/beta/realtime/conversation_item_with_reference.py index dec7a5a409..0edcfc76b6 100644 --- a/src/openai/types/beta/realtime/conversation_item_with_reference.py +++ b/src/openai/types/beta/realtime/conversation_item_with_reference.py @@ -4,9 +4,29 @@ from typing_extensions import Literal from ...._models import BaseModel -from .conversation_item_content import ConversationItemContent -__all__ = ["ConversationItemWithReference"] +__all__ = ["ConversationItemWithReference", "Content"] + + +class Content(BaseModel): + id: Optional[str] = None + """ + ID of a previous conversation item to reference (for `item_reference` content + types in `response.create` events). These can reference both client and server + created items. + """ + + audio: Optional[str] = None + """Base64-encoded audio bytes, used for `input_audio` content type.""" + + text: Optional[str] = None + """The text content, used for `input_text` and `text` content types.""" + + transcript: Optional[str] = None + """The transcript of the audio, used for `input_audio` content type.""" + + type: Optional[Literal["input_text", "input_audio", "item_reference", "text"]] = None + """The content type (`input_text`, `input_audio`, `item_reference`, `text`).""" class ConversationItemWithReference(BaseModel): @@ -30,7 +50,7 @@ class ConversationItemWithReference(BaseModel): `function_call` item with the same ID exists in the conversation history. """ - content: Optional[List[ConversationItemContent]] = None + content: Optional[List[Content]] = None """The content of the message, applicable for `message` items. - Message items of role `system` support only `input_text` content diff --git a/src/openai/types/beta/realtime/conversation_item_with_reference_param.py b/src/openai/types/beta/realtime/conversation_item_with_reference_param.py index 3778373a4c..c83dc92ab7 100644 --- a/src/openai/types/beta/realtime/conversation_item_with_reference_param.py +++ b/src/openai/types/beta/realtime/conversation_item_with_reference_param.py @@ -5,9 +5,28 @@ from typing import Iterable from typing_extensions import Literal, TypedDict -from .conversation_item_content_param import ConversationItemContentParam +__all__ = ["ConversationItemWithReferenceParam", "Content"] -__all__ = ["ConversationItemWithReferenceParam"] + +class Content(TypedDict, total=False): + id: str + """ + ID of a previous conversation item to reference (for `item_reference` content + types in `response.create` events). These can reference both client and server + created items. + """ + + audio: str + """Base64-encoded audio bytes, used for `input_audio` content type.""" + + text: str + """The text content, used for `input_text` and `text` content types.""" + + transcript: str + """The transcript of the audio, used for `input_audio` content type.""" + + type: Literal["input_text", "input_audio", "item_reference", "text"] + """The content type (`input_text`, `input_audio`, `item_reference`, `text`).""" class ConversationItemWithReferenceParam(TypedDict, total=False): @@ -31,7 +50,7 @@ class ConversationItemWithReferenceParam(TypedDict, total=False): `function_call` item with the same ID exists in the conversation history. """ - content: Iterable[ConversationItemContentParam] + content: Iterable[Content] """The content of the message, applicable for `message` items. - Message items of role `system` support only `input_text` content From 859b4db4a7b3c229cd4c19eb21642faca007530b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 15 Jul 2025 21:28:05 +0000 Subject: [PATCH 402/769] release: 1.96.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index db912a0d0f..6b38a1bd5a 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.96.0" + ".": "1.96.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index c91c4c4b35..93bfb63f37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.96.1 (2025-07-15) + +Full Changelog: [v1.96.0...v1.96.1](https://github.com/openai/openai-python/compare/v1.96.0...v1.96.1) + +### Chores + +* **api:** update realtime specs ([b68b71b](https://github.com/openai/openai-python/commit/b68b71b178719e0b49ecfe34486b9d9ac0627924)) + ## 1.96.0 (2025-07-15) Full Changelog: [v1.95.1...v1.96.0](https://github.com/openai/openai-python/compare/v1.95.1...v1.96.0) diff --git a/pyproject.toml b/pyproject.toml index 65055d926a..0f655d058d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.96.0" +version = "1.96.1" 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 b1025f4a31..39be0338f6 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.96.0" # x-release-please-version +__version__ = "1.96.1" # x-release-please-version From a85ad051aa4e6cf4f81a51714afc7bc90310e047 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 16 Jul 2025 16:24:53 +0000 Subject: [PATCH 403/769] feat(api): manual updates --- .stats.yml | 6 +- api.md | 12 +- examples/image_stream.py | 53 + src/openai/_streaming.py | 7 +- src/openai/resources/images.py | 1453 ++++++++++++++--- src/openai/types/__init__.py | 6 + .../types/image_edit_completed_event.py | 55 + src/openai/types/image_edit_params.py | 42 +- .../types/image_edit_partial_image_event.py | 33 + src/openai/types/image_edit_stream_event.py | 14 + src/openai/types/image_gen_completed_event.py | 55 + .../types/image_gen_partial_image_event.py | 33 + src/openai/types/image_gen_stream_event.py | 14 + src/openai/types/image_generate_params.py | 35 +- .../responses/response_output_refusal.py | 2 +- .../response_output_refusal_param.py | 2 +- src/openai/types/responses/tool.py | 7 + src/openai/types/responses/tool_param.py | 7 + tests/api_resources/test_images.py | 262 ++- 19 files changed, 1880 insertions(+), 218 deletions(-) create mode 100644 examples/image_stream.py create mode 100644 src/openai/types/image_edit_completed_event.py create mode 100644 src/openai/types/image_edit_partial_image_event.py create mode 100644 src/openai/types/image_edit_stream_event.py create mode 100644 src/openai/types/image_gen_completed_event.py create mode 100644 src/openai/types/image_gen_partial_image_event.py create mode 100644 src/openai/types/image_gen_stream_event.py diff --git a/.stats.yml b/.stats.yml index 571b0ee797..2b9160cf6e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-c7dacca97e28bceff218684bb429481a70aa47aadad983ed9178bfda75ff4cd2.yml -openapi_spec_hash: 28eb1bb901ca10d2e37db4606d2bcfa7 -config_hash: 167ad0ca036d0f023c78e6496b4311e8 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-670ea0d2cc44f52a87dd3cadea45632953283e0636ba30788fdbdb22a232ccac.yml +openapi_spec_hash: d8b7d38911fead545adf3e4297956410 +config_hash: 5525bda35e48ea6387c6175c4d1651fa diff --git a/api.md b/api.md index abf0de481d..b3a2245cdd 100644 --- a/api.md +++ b/api.md @@ -127,7 +127,17 @@ Methods: Types: ```python -from openai.types import Image, ImageModel, ImagesResponse +from openai.types import ( + Image, + ImageEditCompletedEvent, + ImageEditPartialImageEvent, + ImageEditStreamEvent, + ImageGenCompletedEvent, + ImageGenPartialImageEvent, + ImageGenStreamEvent, + ImageModel, + ImagesResponse, +) ``` Methods: diff --git a/examples/image_stream.py b/examples/image_stream.py new file mode 100644 index 0000000000..c188e68717 --- /dev/null +++ b/examples/image_stream.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python + +import base64 +from pathlib import Path + +from openai import OpenAI + +client = OpenAI() + + +def main() -> None: + """Example of OpenAI image streaming with partial images.""" + stream = client.images.generate( + model="gpt-image-1", + prompt="A cute baby sea otter", + n=1, + size="1024x1024", + stream=True, + partial_images=3, + ) + + for event in stream: + if event.type == "image_generation.partial_image": + print(f" Partial image {event.partial_image_index + 1}/3 received") + print(f" Size: {len(event.b64_json)} characters (base64)") + + # Save partial image to file + filename = f"partial_{event.partial_image_index + 1}.png" + image_data = base64.b64decode(event.b64_json) + with open(filename, "wb") as f: + f.write(image_data) + print(f" 💾 Saved to: {Path(filename).resolve()}") + + elif event.type == "image_generation.completed": + print(f"\n✅ Final image completed!") + print(f" Size: {len(event.b64_json)} characters (base64)") + + # Save final image to file + filename = "final_image.png" + image_data = base64.b64decode(event.b64_json) + with open(filename, "wb") as f: + f.write(image_data) + print(f" 💾 Saved to: {Path(filename).resolve()}") + + else: + print(f"❓ Unknown event: {event}") # type: ignore[unreachable] + + +if __name__ == "__main__": + try: + main() + except Exception as error: + print(f"Error generating image: {error}") \ No newline at end of file diff --git a/src/openai/_streaming.py b/src/openai/_streaming.py index f5621f92a7..fa0a30e183 100644 --- a/src/openai/_streaming.py +++ b/src/openai/_streaming.py @@ -59,7 +59,12 @@ def __stream__(self) -> Iterator[_T]: if sse.data.startswith("[DONE]"): break - if sse.event is None or sse.event.startswith("response.") or sse.event.startswith("transcript."): + if sse.event is None or ( + sse.event.startswith("response.") or + sse.event.startswith("transcript.") or + sse.event.startswith("image_edit.") or + sse.event.startswith("image_generation.") + ): data = sse.json() if is_mapping(data) and data.get("error"): message = None diff --git a/src/openai/resources/images.py b/src/openai/resources/images.py index 43f6189f91..77b7a1b24e 100644 --- a/src/openai/resources/images.py +++ b/src/openai/resources/images.py @@ -3,20 +3,23 @@ from __future__ import annotations from typing import List, Union, Mapping, Optional, cast -from typing_extensions import Literal +from typing_extensions import Literal, overload import httpx from .. import _legacy_response from ..types import image_edit_params, image_generate_params, image_create_variation_params from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven, FileTypes -from .._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform +from .._utils import extract_files, required_args, maybe_transform, deepcopy_minimal, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from .._streaming import Stream, AsyncStream from .._base_client import make_request_options from ..types.image_model import ImageModel from ..types.images_response import ImagesResponse +from ..types.image_gen_stream_event import ImageGenStreamEvent +from ..types.image_edit_stream_event import ImageEditStreamEvent __all__ = ["Images", "AsyncImages"] @@ -114,21 +117,25 @@ def create_variation( cast_to=ImagesResponse, ) + @overload def edit( self, *, image: Union[FileTypes, List[FileTypes]], prompt: str, background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, + input_fidelity: Optional[Literal["high", "low"]] | NotGiven = NOT_GIVEN, mask: FileTypes | NotGiven = NOT_GIVEN, model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, output_compression: Optional[int] | NotGiven = NOT_GIVEN, output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, + partial_images: Optional[int] | NotGiven = NOT_GIVEN, quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] | NotGiven = NOT_GIVEN, + stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -162,6 +169,234 @@ def edit( If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. + input_fidelity: Control how much effort the model will exert to match the style and features, + especially facial features, of input images. This parameter is only supported + for `gpt-image-1`. Supports `high` and `low`. Defaults to `low`. + + mask: An additional image whose fully transparent areas (e.g. where alpha is zero) + indicate where `image` should be edited. If there are multiple images provided, + the mask will be applied on the first image. Must be a valid PNG file, less than + 4MB, and have the same dimensions as `image`. + + model: The model to use for image generation. Only `dall-e-2` and `gpt-image-1` are + supported. Defaults to `dall-e-2` unless a parameter specific to `gpt-image-1` + is used. + + n: The number of images to generate. Must be between 1 and 10. + + output_compression: The compression level (0-100%) for the generated images. This parameter is only + supported for `gpt-image-1` with the `webp` or `jpeg` output formats, and + defaults to 100. + + output_format: The format in which the generated images are returned. This parameter is only + supported for `gpt-image-1`. Must be one of `png`, `jpeg`, or `webp`. The + default value is `png`. + + partial_images: The number of partial images to generate. This parameter is used for streaming + responses that return partial images. Value must be between 0 and 3. When set to + 0, the response will be a single image sent in one streaming event. + + quality: The quality of the image that will be generated. `high`, `medium` and `low` are + only supported for `gpt-image-1`. `dall-e-2` only supports `standard` quality. + Defaults to `auto`. + + response_format: The format in which the generated images are returned. Must be one of `url` or + `b64_json`. URLs are only valid for 60 minutes after the image has been + generated. This parameter is only supported for `dall-e-2`, as `gpt-image-1` + will always return base64-encoded images. + + size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` + (landscape), `1024x1536` (portrait), or `auto` (default value) for + `gpt-image-1`, and one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`. + + stream: Edit the image in streaming mode. Defaults to `false`. See the + [Image generation guide](https://platform.openai.com/docs/guides/image-generation) + for more information. + + user: A unique identifier representing your end-user, which can help OpenAI to monitor + and detect abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def edit( + self, + *, + image: Union[FileTypes, List[FileTypes]], + prompt: str, + stream: Literal[True], + background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, + input_fidelity: Optional[Literal["high", "low"]] | NotGiven = NOT_GIVEN, + mask: FileTypes | NotGiven = NOT_GIVEN, + model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, + n: Optional[int] | NotGiven = NOT_GIVEN, + output_compression: Optional[int] | NotGiven = NOT_GIVEN, + output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, + partial_images: Optional[int] | NotGiven = NOT_GIVEN, + quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, + response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, + size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] + | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Stream[ImageEditStreamEvent]: + """Creates an edited or extended image given one or more source images and a + prompt. + + This endpoint only supports `gpt-image-1` and `dall-e-2`. + + Args: + image: The image(s) to edit. Must be a supported image file or an array of images. + + For `gpt-image-1`, each image should be a `png`, `webp`, or `jpg` file less than + 50MB. You can provide up to 16 images. + + For `dall-e-2`, you can only provide one image, and it should be a square `png` + file less than 4MB. + + prompt: A text description of the desired image(s). The maximum length is 1000 + characters for `dall-e-2`, and 32000 characters for `gpt-image-1`. + + stream: Edit the image in streaming mode. Defaults to `false`. See the + [Image generation guide](https://platform.openai.com/docs/guides/image-generation) + for more information. + + background: Allows to set transparency for the background of the generated image(s). This + parameter is only supported for `gpt-image-1`. Must be one of `transparent`, + `opaque` or `auto` (default value). When `auto` is used, the model will + automatically determine the best background for the image. + + If `transparent`, the output format needs to support transparency, so it should + be set to either `png` (default value) or `webp`. + + input_fidelity: Control how much effort the model will exert to match the style and features, + especially facial features, of input images. This parameter is only supported + for `gpt-image-1`. Supports `high` and `low`. Defaults to `low`. + + mask: An additional image whose fully transparent areas (e.g. where alpha is zero) + indicate where `image` should be edited. If there are multiple images provided, + the mask will be applied on the first image. Must be a valid PNG file, less than + 4MB, and have the same dimensions as `image`. + + model: The model to use for image generation. Only `dall-e-2` and `gpt-image-1` are + supported. Defaults to `dall-e-2` unless a parameter specific to `gpt-image-1` + is used. + + n: The number of images to generate. Must be between 1 and 10. + + output_compression: The compression level (0-100%) for the generated images. This parameter is only + supported for `gpt-image-1` with the `webp` or `jpeg` output formats, and + defaults to 100. + + output_format: The format in which the generated images are returned. This parameter is only + supported for `gpt-image-1`. Must be one of `png`, `jpeg`, or `webp`. The + default value is `png`. + + partial_images: The number of partial images to generate. This parameter is used for streaming + responses that return partial images. Value must be between 0 and 3. When set to + 0, the response will be a single image sent in one streaming event. + + quality: The quality of the image that will be generated. `high`, `medium` and `low` are + only supported for `gpt-image-1`. `dall-e-2` only supports `standard` quality. + Defaults to `auto`. + + response_format: The format in which the generated images are returned. Must be one of `url` or + `b64_json`. URLs are only valid for 60 minutes after the image has been + generated. This parameter is only supported for `dall-e-2`, as `gpt-image-1` + will always return base64-encoded images. + + size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` + (landscape), `1024x1536` (portrait), or `auto` (default value) for + `gpt-image-1`, and one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`. + + user: A unique identifier representing your end-user, which can help OpenAI to monitor + and detect abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def edit( + self, + *, + image: Union[FileTypes, List[FileTypes]], + prompt: str, + stream: bool, + background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, + input_fidelity: Optional[Literal["high", "low"]] | NotGiven = NOT_GIVEN, + mask: FileTypes | NotGiven = NOT_GIVEN, + model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, + n: Optional[int] | NotGiven = NOT_GIVEN, + output_compression: Optional[int] | NotGiven = NOT_GIVEN, + output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, + partial_images: Optional[int] | NotGiven = NOT_GIVEN, + quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, + response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, + size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] + | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ImagesResponse | Stream[ImageEditStreamEvent]: + """Creates an edited or extended image given one or more source images and a + prompt. + + This endpoint only supports `gpt-image-1` and `dall-e-2`. + + Args: + image: The image(s) to edit. Must be a supported image file or an array of images. + + For `gpt-image-1`, each image should be a `png`, `webp`, or `jpg` file less than + 50MB. You can provide up to 16 images. + + For `dall-e-2`, you can only provide one image, and it should be a square `png` + file less than 4MB. + + prompt: A text description of the desired image(s). The maximum length is 1000 + characters for `dall-e-2`, and 32000 characters for `gpt-image-1`. + + stream: Edit the image in streaming mode. Defaults to `false`. See the + [Image generation guide](https://platform.openai.com/docs/guides/image-generation) + for more information. + + background: Allows to set transparency for the background of the generated image(s). This + parameter is only supported for `gpt-image-1`. Must be one of `transparent`, + `opaque` or `auto` (default value). When `auto` is used, the model will + automatically determine the best background for the image. + + If `transparent`, the output format needs to support transparency, so it should + be set to either `png` (default value) or `webp`. + + input_fidelity: Control how much effort the model will exert to match the style and features, + especially facial features, of input images. This parameter is only supported + for `gpt-image-1`. Supports `high` and `low`. Defaults to `low`. + mask: An additional image whose fully transparent areas (e.g. where alpha is zero) indicate where `image` should be edited. If there are multiple images provided, the mask will be applied on the first image. Must be a valid PNG file, less than @@ -181,6 +416,10 @@ def edit( supported for `gpt-image-1`. Must be one of `png`, `jpeg`, or `webp`. The default value is `png`. + partial_images: The number of partial images to generate. This parameter is used for streaming + responses that return partial images. Value must be between 0 and 3. When set to + 0, the response will be a single image sent in one streaming event. + quality: The quality of the image that will be generated. `high`, `medium` and `low` are only supported for `gpt-image-1`. `dall-e-2` only supports `standard` quality. Defaults to `auto`. @@ -206,19 +445,51 @@ def edit( timeout: Override the client-level default timeout for this request, in seconds """ + ... + + @required_args(["image", "prompt"], ["image", "prompt", "stream"]) + def edit( + self, + *, + image: Union[FileTypes, List[FileTypes]], + prompt: str, + background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, + input_fidelity: Optional[Literal["high", "low"]] | NotGiven = NOT_GIVEN, + mask: FileTypes | NotGiven = NOT_GIVEN, + model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, + n: Optional[int] | NotGiven = NOT_GIVEN, + output_compression: Optional[int] | NotGiven = NOT_GIVEN, + output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, + partial_images: Optional[int] | NotGiven = NOT_GIVEN, + quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, + response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, + size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] + | NotGiven = NOT_GIVEN, + stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ImagesResponse | Stream[ImageEditStreamEvent]: body = deepcopy_minimal( { "image": image, "prompt": prompt, "background": background, + "input_fidelity": input_fidelity, "mask": mask, "model": model, "n": n, "output_compression": output_compression, "output_format": output_format, + "partial_images": partial_images, "quality": quality, "response_format": response_format, "size": size, + "stream": stream, "user": user, } ) @@ -229,15 +500,891 @@ def edit( extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} return self._post( "/images/edits", - body=maybe_transform(body, image_edit_params.ImageEditParams), + body=maybe_transform( + body, + image_edit_params.ImageEditParamsStreaming if stream else image_edit_params.ImageEditParamsNonStreaming, + ), + files=files, + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ImagesResponse, + stream=stream or False, + stream_cls=Stream[ImageEditStreamEvent], + ) + + @overload + def generate( + self, + *, + prompt: str, + background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, + model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, + moderation: Optional[Literal["low", "auto"]] | NotGiven = NOT_GIVEN, + n: Optional[int] | NotGiven = NOT_GIVEN, + output_compression: Optional[int] | NotGiven = NOT_GIVEN, + output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, + partial_images: Optional[int] | NotGiven = NOT_GIVEN, + quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, + response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, + size: Optional[ + Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] + ] + | NotGiven = NOT_GIVEN, + stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, + style: Optional[Literal["vivid", "natural"]] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ImagesResponse: + """ + Creates an image given a prompt. + [Learn more](https://platform.openai.com/docs/guides/images). + + Args: + prompt: A text description of the desired image(s). The maximum length is 32000 + characters for `gpt-image-1`, 1000 characters for `dall-e-2` and 4000 characters + for `dall-e-3`. + + background: Allows to set transparency for the background of the generated image(s). This + parameter is only supported for `gpt-image-1`. Must be one of `transparent`, + `opaque` or `auto` (default value). When `auto` is used, the model will + automatically determine the best background for the image. + + If `transparent`, the output format needs to support transparency, so it should + be set to either `png` (default value) or `webp`. + + model: The model to use for image generation. One of `dall-e-2`, `dall-e-3`, or + `gpt-image-1`. Defaults to `dall-e-2` unless a parameter specific to + `gpt-image-1` is used. + + moderation: Control the content-moderation level for images generated by `gpt-image-1`. Must + be either `low` for less restrictive filtering or `auto` (default value). + + n: The number of images to generate. Must be between 1 and 10. For `dall-e-3`, only + `n=1` is supported. + + output_compression: The compression level (0-100%) for the generated images. This parameter is only + supported for `gpt-image-1` with the `webp` or `jpeg` output formats, and + defaults to 100. + + output_format: The format in which the generated images are returned. This parameter is only + supported for `gpt-image-1`. Must be one of `png`, `jpeg`, or `webp`. + + partial_images: The number of partial images to generate. This parameter is used for streaming + responses that return partial images. Value must be between 0 and 3. When set to + 0, the response will be a single image sent in one streaming event. + + quality: The quality of the image that will be generated. + + - `auto` (default value) will automatically select the best quality for the + given model. + - `high`, `medium` and `low` are supported for `gpt-image-1`. + - `hd` and `standard` are supported for `dall-e-3`. + - `standard` is the only option for `dall-e-2`. + + response_format: The format in which generated images with `dall-e-2` and `dall-e-3` are + returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes + after the image has been generated. This parameter isn't supported for + `gpt-image-1` which will always return base64-encoded images. + + size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` + (landscape), `1024x1536` (portrait), or `auto` (default value) for + `gpt-image-1`, one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`, and + one of `1024x1024`, `1792x1024`, or `1024x1792` for `dall-e-3`. + + stream: Generate the image in streaming mode. Defaults to `false`. See the + [Image generation guide](https://platform.openai.com/docs/guides/image-generation) + for more information. This parameter is only supported for `gpt-image-1`. + + style: The style of the generated images. This parameter is only supported for + `dall-e-3`. Must be one of `vivid` or `natural`. Vivid causes the model to lean + towards generating hyper-real and dramatic images. Natural causes the model to + produce more natural, less hyper-real looking images. + + user: A unique identifier representing your end-user, which can help OpenAI to monitor + and detect abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def generate( + self, + *, + prompt: str, + stream: Literal[True], + background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, + model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, + moderation: Optional[Literal["low", "auto"]] | NotGiven = NOT_GIVEN, + n: Optional[int] | NotGiven = NOT_GIVEN, + output_compression: Optional[int] | NotGiven = NOT_GIVEN, + output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, + partial_images: Optional[int] | NotGiven = NOT_GIVEN, + quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, + response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, + size: Optional[ + Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] + ] + | NotGiven = NOT_GIVEN, + style: Optional[Literal["vivid", "natural"]] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Stream[ImageGenStreamEvent]: + """ + Creates an image given a prompt. + [Learn more](https://platform.openai.com/docs/guides/images). + + Args: + prompt: A text description of the desired image(s). The maximum length is 32000 + characters for `gpt-image-1`, 1000 characters for `dall-e-2` and 4000 characters + for `dall-e-3`. + + stream: Generate the image in streaming mode. Defaults to `false`. See the + [Image generation guide](https://platform.openai.com/docs/guides/image-generation) + for more information. This parameter is only supported for `gpt-image-1`. + + background: Allows to set transparency for the background of the generated image(s). This + parameter is only supported for `gpt-image-1`. Must be one of `transparent`, + `opaque` or `auto` (default value). When `auto` is used, the model will + automatically determine the best background for the image. + + If `transparent`, the output format needs to support transparency, so it should + be set to either `png` (default value) or `webp`. + + model: The model to use for image generation. One of `dall-e-2`, `dall-e-3`, or + `gpt-image-1`. Defaults to `dall-e-2` unless a parameter specific to + `gpt-image-1` is used. + + moderation: Control the content-moderation level for images generated by `gpt-image-1`. Must + be either `low` for less restrictive filtering or `auto` (default value). + + n: The number of images to generate. Must be between 1 and 10. For `dall-e-3`, only + `n=1` is supported. + + output_compression: The compression level (0-100%) for the generated images. This parameter is only + supported for `gpt-image-1` with the `webp` or `jpeg` output formats, and + defaults to 100. + + output_format: The format in which the generated images are returned. This parameter is only + supported for `gpt-image-1`. Must be one of `png`, `jpeg`, or `webp`. + + partial_images: The number of partial images to generate. This parameter is used for streaming + responses that return partial images. Value must be between 0 and 3. When set to + 0, the response will be a single image sent in one streaming event. + + quality: The quality of the image that will be generated. + + - `auto` (default value) will automatically select the best quality for the + given model. + - `high`, `medium` and `low` are supported for `gpt-image-1`. + - `hd` and `standard` are supported for `dall-e-3`. + - `standard` is the only option for `dall-e-2`. + + response_format: The format in which generated images with `dall-e-2` and `dall-e-3` are + returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes + after the image has been generated. This parameter isn't supported for + `gpt-image-1` which will always return base64-encoded images. + + size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` + (landscape), `1024x1536` (portrait), or `auto` (default value) for + `gpt-image-1`, one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`, and + one of `1024x1024`, `1792x1024`, or `1024x1792` for `dall-e-3`. + + style: The style of the generated images. This parameter is only supported for + `dall-e-3`. Must be one of `vivid` or `natural`. Vivid causes the model to lean + towards generating hyper-real and dramatic images. Natural causes the model to + produce more natural, less hyper-real looking images. + + user: A unique identifier representing your end-user, which can help OpenAI to monitor + and detect abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def generate( + self, + *, + prompt: str, + stream: bool, + background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, + model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, + moderation: Optional[Literal["low", "auto"]] | NotGiven = NOT_GIVEN, + n: Optional[int] | NotGiven = NOT_GIVEN, + output_compression: Optional[int] | NotGiven = NOT_GIVEN, + output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, + partial_images: Optional[int] | NotGiven = NOT_GIVEN, + quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, + response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, + size: Optional[ + Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] + ] + | NotGiven = NOT_GIVEN, + style: Optional[Literal["vivid", "natural"]] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ImagesResponse | Stream[ImageGenStreamEvent]: + """ + Creates an image given a prompt. + [Learn more](https://platform.openai.com/docs/guides/images). + + Args: + prompt: A text description of the desired image(s). The maximum length is 32000 + characters for `gpt-image-1`, 1000 characters for `dall-e-2` and 4000 characters + for `dall-e-3`. + + stream: Generate the image in streaming mode. Defaults to `false`. See the + [Image generation guide](https://platform.openai.com/docs/guides/image-generation) + for more information. This parameter is only supported for `gpt-image-1`. + + background: Allows to set transparency for the background of the generated image(s). This + parameter is only supported for `gpt-image-1`. Must be one of `transparent`, + `opaque` or `auto` (default value). When `auto` is used, the model will + automatically determine the best background for the image. + + If `transparent`, the output format needs to support transparency, so it should + be set to either `png` (default value) or `webp`. + + model: The model to use for image generation. One of `dall-e-2`, `dall-e-3`, or + `gpt-image-1`. Defaults to `dall-e-2` unless a parameter specific to + `gpt-image-1` is used. + + moderation: Control the content-moderation level for images generated by `gpt-image-1`. Must + be either `low` for less restrictive filtering or `auto` (default value). + + n: The number of images to generate. Must be between 1 and 10. For `dall-e-3`, only + `n=1` is supported. + + output_compression: The compression level (0-100%) for the generated images. This parameter is only + supported for `gpt-image-1` with the `webp` or `jpeg` output formats, and + defaults to 100. + + output_format: The format in which the generated images are returned. This parameter is only + supported for `gpt-image-1`. Must be one of `png`, `jpeg`, or `webp`. + + partial_images: The number of partial images to generate. This parameter is used for streaming + responses that return partial images. Value must be between 0 and 3. When set to + 0, the response will be a single image sent in one streaming event. + + quality: The quality of the image that will be generated. + + - `auto` (default value) will automatically select the best quality for the + given model. + - `high`, `medium` and `low` are supported for `gpt-image-1`. + - `hd` and `standard` are supported for `dall-e-3`. + - `standard` is the only option for `dall-e-2`. + + response_format: The format in which generated images with `dall-e-2` and `dall-e-3` are + returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes + after the image has been generated. This parameter isn't supported for + `gpt-image-1` which will always return base64-encoded images. + + size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` + (landscape), `1024x1536` (portrait), or `auto` (default value) for + `gpt-image-1`, one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`, and + one of `1024x1024`, `1792x1024`, or `1024x1792` for `dall-e-3`. + + style: The style of the generated images. This parameter is only supported for + `dall-e-3`. Must be one of `vivid` or `natural`. Vivid causes the model to lean + towards generating hyper-real and dramatic images. Natural causes the model to + produce more natural, less hyper-real looking images. + + user: A unique identifier representing your end-user, which can help OpenAI to monitor + and detect abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @required_args(["prompt"], ["prompt", "stream"]) + def generate( + self, + *, + prompt: str, + background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, + model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, + moderation: Optional[Literal["low", "auto"]] | NotGiven = NOT_GIVEN, + n: Optional[int] | NotGiven = NOT_GIVEN, + output_compression: Optional[int] | NotGiven = NOT_GIVEN, + output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, + partial_images: Optional[int] | NotGiven = NOT_GIVEN, + quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, + response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, + size: Optional[ + Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] + ] + | NotGiven = NOT_GIVEN, + stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, + style: Optional[Literal["vivid", "natural"]] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ImagesResponse | Stream[ImageGenStreamEvent]: + return self._post( + "/images/generations", + body=maybe_transform( + { + "prompt": prompt, + "background": background, + "model": model, + "moderation": moderation, + "n": n, + "output_compression": output_compression, + "output_format": output_format, + "partial_images": partial_images, + "quality": quality, + "response_format": response_format, + "size": size, + "stream": stream, + "style": style, + "user": user, + }, + image_generate_params.ImageGenerateParamsStreaming + if stream + else image_generate_params.ImageGenerateParamsNonStreaming, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ImagesResponse, + stream=stream or False, + stream_cls=Stream[ImageGenStreamEvent], + ) + + +class AsyncImages(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncImagesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncImagesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncImagesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncImagesWithStreamingResponse(self) + + async def create_variation( + self, + *, + image: FileTypes, + model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, + n: Optional[int] | NotGiven = NOT_GIVEN, + response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, + size: Optional[Literal["256x256", "512x512", "1024x1024"]] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ImagesResponse: + """Creates a variation of a given image. + + This endpoint only supports `dall-e-2`. + + Args: + image: The image to use as the basis for the variation(s). Must be a valid PNG file, + less than 4MB, and square. + + model: The model to use for image generation. Only `dall-e-2` is supported at this + time. + + n: The number of images to generate. Must be between 1 and 10. + + response_format: The format in which the generated images are returned. Must be one of `url` or + `b64_json`. URLs are only valid for 60 minutes after the image has been + generated. + + size: The size of the generated images. Must be one of `256x256`, `512x512`, or + `1024x1024`. + + user: A unique identifier representing your end-user, which can help OpenAI to monitor + and detect abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + body = deepcopy_minimal( + { + "image": image, + "model": model, + "n": n, + "response_format": response_format, + "size": size, + "user": user, + } + ) + files = extract_files(cast(Mapping[str, object], body), paths=[["image"]]) + # It should be noted that the actual Content-Type header that will be + # sent to the server will contain a `boundary` parameter, e.g. + # multipart/form-data; boundary=---abc-- + extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} + return await self._post( + "/images/variations", + body=await async_maybe_transform(body, image_create_variation_params.ImageCreateVariationParams), + files=files, + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ImagesResponse, + ) + + @overload + async def edit( + self, + *, + image: Union[FileTypes, List[FileTypes]], + prompt: str, + background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, + input_fidelity: Optional[Literal["high", "low"]] | NotGiven = NOT_GIVEN, + mask: FileTypes | NotGiven = NOT_GIVEN, + model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, + n: Optional[int] | NotGiven = NOT_GIVEN, + output_compression: Optional[int] | NotGiven = NOT_GIVEN, + output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, + partial_images: Optional[int] | NotGiven = NOT_GIVEN, + quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, + response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, + size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] + | NotGiven = NOT_GIVEN, + stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ImagesResponse: + """Creates an edited or extended image given one or more source images and a + prompt. + + This endpoint only supports `gpt-image-1` and `dall-e-2`. + + Args: + image: The image(s) to edit. Must be a supported image file or an array of images. + + For `gpt-image-1`, each image should be a `png`, `webp`, or `jpg` file less than + 50MB. You can provide up to 16 images. + + For `dall-e-2`, you can only provide one image, and it should be a square `png` + file less than 4MB. + + prompt: A text description of the desired image(s). The maximum length is 1000 + characters for `dall-e-2`, and 32000 characters for `gpt-image-1`. + + background: Allows to set transparency for the background of the generated image(s). This + parameter is only supported for `gpt-image-1`. Must be one of `transparent`, + `opaque` or `auto` (default value). When `auto` is used, the model will + automatically determine the best background for the image. + + If `transparent`, the output format needs to support transparency, so it should + be set to either `png` (default value) or `webp`. + + input_fidelity: Control how much effort the model will exert to match the style and features, + especially facial features, of input images. This parameter is only supported + for `gpt-image-1`. Supports `high` and `low`. Defaults to `low`. + + mask: An additional image whose fully transparent areas (e.g. where alpha is zero) + indicate where `image` should be edited. If there are multiple images provided, + the mask will be applied on the first image. Must be a valid PNG file, less than + 4MB, and have the same dimensions as `image`. + + model: The model to use for image generation. Only `dall-e-2` and `gpt-image-1` are + supported. Defaults to `dall-e-2` unless a parameter specific to `gpt-image-1` + is used. + + n: The number of images to generate. Must be between 1 and 10. + + output_compression: The compression level (0-100%) for the generated images. This parameter is only + supported for `gpt-image-1` with the `webp` or `jpeg` output formats, and + defaults to 100. + + output_format: The format in which the generated images are returned. This parameter is only + supported for `gpt-image-1`. Must be one of `png`, `jpeg`, or `webp`. The + default value is `png`. + + partial_images: The number of partial images to generate. This parameter is used for streaming + responses that return partial images. Value must be between 0 and 3. When set to + 0, the response will be a single image sent in one streaming event. + + quality: The quality of the image that will be generated. `high`, `medium` and `low` are + only supported for `gpt-image-1`. `dall-e-2` only supports `standard` quality. + Defaults to `auto`. + + response_format: The format in which the generated images are returned. Must be one of `url` or + `b64_json`. URLs are only valid for 60 minutes after the image has been + generated. This parameter is only supported for `dall-e-2`, as `gpt-image-1` + will always return base64-encoded images. + + size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` + (landscape), `1024x1536` (portrait), or `auto` (default value) for + `gpt-image-1`, and one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`. + + stream: Edit the image in streaming mode. Defaults to `false`. See the + [Image generation guide](https://platform.openai.com/docs/guides/image-generation) + for more information. + + user: A unique identifier representing your end-user, which can help OpenAI to monitor + and detect abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def edit( + self, + *, + image: Union[FileTypes, List[FileTypes]], + prompt: str, + stream: Literal[True], + background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, + input_fidelity: Optional[Literal["high", "low"]] | NotGiven = NOT_GIVEN, + mask: FileTypes | NotGiven = NOT_GIVEN, + model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, + n: Optional[int] | NotGiven = NOT_GIVEN, + output_compression: Optional[int] | NotGiven = NOT_GIVEN, + output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, + partial_images: Optional[int] | NotGiven = NOT_GIVEN, + quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, + response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, + size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] + | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> AsyncStream[ImageEditStreamEvent]: + """Creates an edited or extended image given one or more source images and a + prompt. + + This endpoint only supports `gpt-image-1` and `dall-e-2`. + + Args: + image: The image(s) to edit. Must be a supported image file or an array of images. + + For `gpt-image-1`, each image should be a `png`, `webp`, or `jpg` file less than + 50MB. You can provide up to 16 images. + + For `dall-e-2`, you can only provide one image, and it should be a square `png` + file less than 4MB. + + prompt: A text description of the desired image(s). The maximum length is 1000 + characters for `dall-e-2`, and 32000 characters for `gpt-image-1`. + + stream: Edit the image in streaming mode. Defaults to `false`. See the + [Image generation guide](https://platform.openai.com/docs/guides/image-generation) + for more information. + + background: Allows to set transparency for the background of the generated image(s). This + parameter is only supported for `gpt-image-1`. Must be one of `transparent`, + `opaque` or `auto` (default value). When `auto` is used, the model will + automatically determine the best background for the image. + + If `transparent`, the output format needs to support transparency, so it should + be set to either `png` (default value) or `webp`. + + input_fidelity: Control how much effort the model will exert to match the style and features, + especially facial features, of input images. This parameter is only supported + for `gpt-image-1`. Supports `high` and `low`. Defaults to `low`. + + mask: An additional image whose fully transparent areas (e.g. where alpha is zero) + indicate where `image` should be edited. If there are multiple images provided, + the mask will be applied on the first image. Must be a valid PNG file, less than + 4MB, and have the same dimensions as `image`. + + model: The model to use for image generation. Only `dall-e-2` and `gpt-image-1` are + supported. Defaults to `dall-e-2` unless a parameter specific to `gpt-image-1` + is used. + + n: The number of images to generate. Must be between 1 and 10. + + output_compression: The compression level (0-100%) for the generated images. This parameter is only + supported for `gpt-image-1` with the `webp` or `jpeg` output formats, and + defaults to 100. + + output_format: The format in which the generated images are returned. This parameter is only + supported for `gpt-image-1`. Must be one of `png`, `jpeg`, or `webp`. The + default value is `png`. + + partial_images: The number of partial images to generate. This parameter is used for streaming + responses that return partial images. Value must be between 0 and 3. When set to + 0, the response will be a single image sent in one streaming event. + + quality: The quality of the image that will be generated. `high`, `medium` and `low` are + only supported for `gpt-image-1`. `dall-e-2` only supports `standard` quality. + Defaults to `auto`. + + response_format: The format in which the generated images are returned. Must be one of `url` or + `b64_json`. URLs are only valid for 60 minutes after the image has been + generated. This parameter is only supported for `dall-e-2`, as `gpt-image-1` + will always return base64-encoded images. + + size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` + (landscape), `1024x1536` (portrait), or `auto` (default value) for + `gpt-image-1`, and one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`. + + user: A unique identifier representing your end-user, which can help OpenAI to monitor + and detect abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def edit( + self, + *, + image: Union[FileTypes, List[FileTypes]], + prompt: str, + stream: bool, + background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, + input_fidelity: Optional[Literal["high", "low"]] | NotGiven = NOT_GIVEN, + mask: FileTypes | NotGiven = NOT_GIVEN, + model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, + n: Optional[int] | NotGiven = NOT_GIVEN, + output_compression: Optional[int] | NotGiven = NOT_GIVEN, + output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, + partial_images: Optional[int] | NotGiven = NOT_GIVEN, + quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, + response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, + size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] + | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ImagesResponse | AsyncStream[ImageEditStreamEvent]: + """Creates an edited or extended image given one or more source images and a + prompt. + + This endpoint only supports `gpt-image-1` and `dall-e-2`. + + Args: + image: The image(s) to edit. Must be a supported image file or an array of images. + + For `gpt-image-1`, each image should be a `png`, `webp`, or `jpg` file less than + 50MB. You can provide up to 16 images. + + For `dall-e-2`, you can only provide one image, and it should be a square `png` + file less than 4MB. + + prompt: A text description of the desired image(s). The maximum length is 1000 + characters for `dall-e-2`, and 32000 characters for `gpt-image-1`. + + stream: Edit the image in streaming mode. Defaults to `false`. See the + [Image generation guide](https://platform.openai.com/docs/guides/image-generation) + for more information. + + background: Allows to set transparency for the background of the generated image(s). This + parameter is only supported for `gpt-image-1`. Must be one of `transparent`, + `opaque` or `auto` (default value). When `auto` is used, the model will + automatically determine the best background for the image. + + If `transparent`, the output format needs to support transparency, so it should + be set to either `png` (default value) or `webp`. + + input_fidelity: Control how much effort the model will exert to match the style and features, + especially facial features, of input images. This parameter is only supported + for `gpt-image-1`. Supports `high` and `low`. Defaults to `low`. + + mask: An additional image whose fully transparent areas (e.g. where alpha is zero) + indicate where `image` should be edited. If there are multiple images provided, + the mask will be applied on the first image. Must be a valid PNG file, less than + 4MB, and have the same dimensions as `image`. + + model: The model to use for image generation. Only `dall-e-2` and `gpt-image-1` are + supported. Defaults to `dall-e-2` unless a parameter specific to `gpt-image-1` + is used. + + n: The number of images to generate. Must be between 1 and 10. + + output_compression: The compression level (0-100%) for the generated images. This parameter is only + supported for `gpt-image-1` with the `webp` or `jpeg` output formats, and + defaults to 100. + + output_format: The format in which the generated images are returned. This parameter is only + supported for `gpt-image-1`. Must be one of `png`, `jpeg`, or `webp`. The + default value is `png`. + + partial_images: The number of partial images to generate. This parameter is used for streaming + responses that return partial images. Value must be between 0 and 3. When set to + 0, the response will be a single image sent in one streaming event. + + quality: The quality of the image that will be generated. `high`, `medium` and `low` are + only supported for `gpt-image-1`. `dall-e-2` only supports `standard` quality. + Defaults to `auto`. + + response_format: The format in which the generated images are returned. Must be one of `url` or + `b64_json`. URLs are only valid for 60 minutes after the image has been + generated. This parameter is only supported for `dall-e-2`, as `gpt-image-1` + will always return base64-encoded images. + + size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` + (landscape), `1024x1536` (portrait), or `auto` (default value) for + `gpt-image-1`, and one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`. + + user: A unique identifier representing your end-user, which can help OpenAI to monitor + and detect abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @required_args(["image", "prompt"], ["image", "prompt", "stream"]) + async def edit( + self, + *, + image: Union[FileTypes, List[FileTypes]], + prompt: str, + background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, + input_fidelity: Optional[Literal["high", "low"]] | NotGiven = NOT_GIVEN, + mask: FileTypes | NotGiven = NOT_GIVEN, + model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, + n: Optional[int] | NotGiven = NOT_GIVEN, + output_compression: Optional[int] | NotGiven = NOT_GIVEN, + output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, + partial_images: Optional[int] | NotGiven = NOT_GIVEN, + quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, + response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, + size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] + | NotGiven = NOT_GIVEN, + stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ImagesResponse | AsyncStream[ImageEditStreamEvent]: + body = deepcopy_minimal( + { + "image": image, + "prompt": prompt, + "background": background, + "input_fidelity": input_fidelity, + "mask": mask, + "model": model, + "n": n, + "output_compression": output_compression, + "output_format": output_format, + "partial_images": partial_images, + "quality": quality, + "response_format": response_format, + "size": size, + "stream": stream, + "user": user, + } + ) + files = extract_files(cast(Mapping[str, object], body), paths=[["image"], ["image", ""], ["mask"]]) + # It should be noted that the actual Content-Type header that will be + # sent to the server will contain a `boundary` parameter, e.g. + # multipart/form-data; boundary=---abc-- + extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} + return await self._post( + "/images/edits", + body=await async_maybe_transform( + body, + image_edit_params.ImageEditParamsStreaming if stream else image_edit_params.ImageEditParamsNonStreaming, + ), files=files, options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), cast_to=ImagesResponse, + stream=stream or False, + stream_cls=AsyncStream[ImageEditStreamEvent], ) - def generate( + @overload + async def generate( self, *, prompt: str, @@ -247,12 +1394,14 @@ def generate( n: Optional[int] | NotGiven = NOT_GIVEN, output_compression: Optional[int] | NotGiven = NOT_GIVEN, output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, + partial_images: Optional[int] | NotGiven = NOT_GIVEN, quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, size: Optional[ Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] ] | NotGiven = NOT_GIVEN, + stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, style: Optional[Literal["vivid", "natural"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -296,6 +1445,10 @@ def generate( output_format: The format in which the generated images are returned. This parameter is only supported for `gpt-image-1`. Must be one of `png`, `jpeg`, or `webp`. + partial_images: The number of partial images to generate. This parameter is used for streaming + responses that return partial images. Value must be between 0 and 3. When set to + 0, the response will be a single image sent in one streaming event. + quality: The quality of the image that will be generated. - `auto` (default value) will automatically select the best quality for the @@ -314,6 +1467,10 @@ def generate( `gpt-image-1`, one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`, and one of `1024x1024`, `1792x1024`, or `1024x1792` for `dall-e-3`. + stream: Generate the image in streaming mode. Defaults to `false`. See the + [Image generation guide](https://platform.openai.com/docs/guides/image-generation) + for more information. This parameter is only supported for `gpt-image-1`. + style: The style of the generated images. This parameter is only supported for `dall-e-3`. Must be one of `vivid` or `natural`. Vivid causes the model to lean towards generating hyper-real and dramatic images. Natural causes the model to @@ -331,140 +1488,28 @@ def generate( timeout: Override the client-level default timeout for this request, in seconds """ - return self._post( - "/images/generations", - body=maybe_transform( - { - "prompt": prompt, - "background": background, - "model": model, - "moderation": moderation, - "n": n, - "output_compression": output_compression, - "output_format": output_format, - "quality": quality, - "response_format": response_format, - "size": size, - "style": style, - "user": user, - }, - image_generate_params.ImageGenerateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ImagesResponse, - ) - - -class AsyncImages(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncImagesWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncImagesWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncImagesWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncImagesWithStreamingResponse(self) - - async def create_variation( - self, - *, - image: FileTypes, - model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, - size: Optional[Literal["256x256", "512x512", "1024x1024"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> ImagesResponse: - """Creates a variation of a given image. - - This endpoint only supports `dall-e-2`. - - Args: - image: The image to use as the basis for the variation(s). Must be a valid PNG file, - less than 4MB, and square. - - model: The model to use for image generation. Only `dall-e-2` is supported at this - time. - - n: The number of images to generate. Must be between 1 and 10. - - response_format: The format in which the generated images are returned. Must be one of `url` or - `b64_json`. URLs are only valid for 60 minutes after the image has been - generated. - - size: The size of the generated images. Must be one of `256x256`, `512x512`, or - `1024x1024`. - - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - body = deepcopy_minimal( - { - "image": image, - "model": model, - "n": n, - "response_format": response_format, - "size": size, - "user": user, - } - ) - files = extract_files(cast(Mapping[str, object], body), paths=[["image"]]) - # It should be noted that the actual Content-Type header that will be - # sent to the server will contain a `boundary` parameter, e.g. - # multipart/form-data; boundary=---abc-- - extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} - return await self._post( - "/images/variations", - body=await async_maybe_transform(body, image_create_variation_params.ImageCreateVariationParams), - files=files, - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ImagesResponse, - ) + ... - async def edit( + @overload + async def generate( self, *, - image: Union[FileTypes, List[FileTypes]], prompt: str, + stream: Literal[True], background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, - mask: FileTypes | NotGiven = NOT_GIVEN, model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, + moderation: Optional[Literal["low", "auto"]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, output_compression: Optional[int] | NotGiven = NOT_GIVEN, output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, - quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, + partial_images: Optional[int] | NotGiven = NOT_GIVEN, + quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, - size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] + size: Optional[ + Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] + ] | NotGiven = NOT_GIVEN, + style: Optional[Literal["vivid", "natural"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -472,23 +1517,19 @@ async def edit( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> ImagesResponse: - """Creates an edited or extended image given one or more source images and a - prompt. - - This endpoint only supports `gpt-image-1` and `dall-e-2`. + ) -> AsyncStream[ImageGenStreamEvent]: + """ + Creates an image given a prompt. + [Learn more](https://platform.openai.com/docs/guides/images). Args: - image: The image(s) to edit. Must be a supported image file or an array of images. - - For `gpt-image-1`, each image should be a `png`, `webp`, or `jpg` file less than - 50MB. You can provide up to 16 images. - - For `dall-e-2`, you can only provide one image, and it should be a square `png` - file less than 4MB. + prompt: A text description of the desired image(s). The maximum length is 32000 + characters for `gpt-image-1`, 1000 characters for `dall-e-2` and 4000 characters + for `dall-e-3`. - prompt: A text description of the desired image(s). The maximum length is 1000 - characters for `dall-e-2`, and 32000 characters for `gpt-image-1`. + stream: Generate the image in streaming mode. Defaults to `false`. See the + [Image generation guide](https://platform.openai.com/docs/guides/image-generation) + for more information. This parameter is only supported for `gpt-image-1`. background: Allows to set transparency for the background of the generated image(s). This parameter is only supported for `gpt-image-1`. Must be one of `transparent`, @@ -498,37 +1539,49 @@ async def edit( If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. - mask: An additional image whose fully transparent areas (e.g. where alpha is zero) - indicate where `image` should be edited. If there are multiple images provided, - the mask will be applied on the first image. Must be a valid PNG file, less than - 4MB, and have the same dimensions as `image`. + model: The model to use for image generation. One of `dall-e-2`, `dall-e-3`, or + `gpt-image-1`. Defaults to `dall-e-2` unless a parameter specific to + `gpt-image-1` is used. - model: The model to use for image generation. Only `dall-e-2` and `gpt-image-1` are - supported. Defaults to `dall-e-2` unless a parameter specific to `gpt-image-1` - is used. + moderation: Control the content-moderation level for images generated by `gpt-image-1`. Must + be either `low` for less restrictive filtering or `auto` (default value). - n: The number of images to generate. Must be between 1 and 10. + n: The number of images to generate. Must be between 1 and 10. For `dall-e-3`, only + `n=1` is supported. output_compression: The compression level (0-100%) for the generated images. This parameter is only supported for `gpt-image-1` with the `webp` or `jpeg` output formats, and defaults to 100. output_format: The format in which the generated images are returned. This parameter is only - supported for `gpt-image-1`. Must be one of `png`, `jpeg`, or `webp`. The - default value is `png`. + supported for `gpt-image-1`. Must be one of `png`, `jpeg`, or `webp`. - quality: The quality of the image that will be generated. `high`, `medium` and `low` are - only supported for `gpt-image-1`. `dall-e-2` only supports `standard` quality. - Defaults to `auto`. + partial_images: The number of partial images to generate. This parameter is used for streaming + responses that return partial images. Value must be between 0 and 3. When set to + 0, the response will be a single image sent in one streaming event. - response_format: The format in which the generated images are returned. Must be one of `url` or - `b64_json`. URLs are only valid for 60 minutes after the image has been - generated. This parameter is only supported for `dall-e-2`, as `gpt-image-1` - will always return base64-encoded images. + quality: The quality of the image that will be generated. + + - `auto` (default value) will automatically select the best quality for the + given model. + - `high`, `medium` and `low` are supported for `gpt-image-1`. + - `hd` and `standard` are supported for `dall-e-3`. + - `standard` is the only option for `dall-e-2`. + + response_format: The format in which generated images with `dall-e-2` and `dall-e-3` are + returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes + after the image has been generated. This parameter isn't supported for + `gpt-image-1` which will always return base64-encoded images. size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` (landscape), `1024x1536` (portrait), or `auto` (default value) for - `gpt-image-1`, and one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`. + `gpt-image-1`, one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`, and + one of `1024x1024`, `1792x1024`, or `1024x1792` for `dall-e-3`. + + style: The style of the generated images. This parameter is only supported for + `dall-e-3`. Must be one of `vivid` or `natural`. Vivid causes the model to lean + towards generating hyper-real and dramatic images. Natural causes the model to + produce more natural, less hyper-real looking images. user: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. @@ -542,47 +1595,21 @@ async def edit( timeout: Override the client-level default timeout for this request, in seconds """ - body = deepcopy_minimal( - { - "image": image, - "prompt": prompt, - "background": background, - "mask": mask, - "model": model, - "n": n, - "output_compression": output_compression, - "output_format": output_format, - "quality": quality, - "response_format": response_format, - "size": size, - "user": user, - } - ) - files = extract_files(cast(Mapping[str, object], body), paths=[["image"], ["image", ""], ["mask"]]) - # It should be noted that the actual Content-Type header that will be - # sent to the server will contain a `boundary` parameter, e.g. - # multipart/form-data; boundary=---abc-- - extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} - return await self._post( - "/images/edits", - body=await async_maybe_transform(body, image_edit_params.ImageEditParams), - files=files, - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ImagesResponse, - ) + ... + @overload async def generate( self, *, prompt: str, + stream: bool, background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, moderation: Optional[Literal["low", "auto"]] | NotGiven = NOT_GIVEN, n: Optional[int] | NotGiven = NOT_GIVEN, output_compression: Optional[int] | NotGiven = NOT_GIVEN, output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, + partial_images: Optional[int] | NotGiven = NOT_GIVEN, quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, size: Optional[ @@ -597,7 +1624,7 @@ async def generate( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> ImagesResponse: + ) -> ImagesResponse | AsyncStream[ImageGenStreamEvent]: """ Creates an image given a prompt. [Learn more](https://platform.openai.com/docs/guides/images). @@ -607,6 +1634,10 @@ async def generate( characters for `gpt-image-1`, 1000 characters for `dall-e-2` and 4000 characters for `dall-e-3`. + stream: Generate the image in streaming mode. Defaults to `false`. See the + [Image generation guide](https://platform.openai.com/docs/guides/image-generation) + for more information. This parameter is only supported for `gpt-image-1`. + background: Allows to set transparency for the background of the generated image(s). This parameter is only supported for `gpt-image-1`. Must be one of `transparent`, `opaque` or `auto` (default value). When `auto` is used, the model will @@ -632,6 +1663,10 @@ async def generate( output_format: The format in which the generated images are returned. This parameter is only supported for `gpt-image-1`. Must be one of `png`, `jpeg`, or `webp`. + partial_images: The number of partial images to generate. This parameter is used for streaming + responses that return partial images. Value must be between 0 and 3. When set to + 0, the response will be a single image sent in one streaming event. + quality: The quality of the image that will be generated. - `auto` (default value) will automatically select the best quality for the @@ -667,6 +1702,36 @@ async def generate( timeout: Override the client-level default timeout for this request, in seconds """ + ... + + @required_args(["prompt"], ["prompt", "stream"]) + async def generate( + self, + *, + prompt: str, + background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, + model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, + moderation: Optional[Literal["low", "auto"]] | NotGiven = NOT_GIVEN, + n: Optional[int] | NotGiven = NOT_GIVEN, + output_compression: Optional[int] | NotGiven = NOT_GIVEN, + output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, + partial_images: Optional[int] | NotGiven = NOT_GIVEN, + quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, + response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, + size: Optional[ + Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] + ] + | NotGiven = NOT_GIVEN, + stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, + style: Optional[Literal["vivid", "natural"]] | NotGiven = NOT_GIVEN, + user: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ImagesResponse | AsyncStream[ImageGenStreamEvent]: return await self._post( "/images/generations", body=await async_maybe_transform( @@ -678,18 +1743,24 @@ async def generate( "n": n, "output_compression": output_compression, "output_format": output_format, + "partial_images": partial_images, "quality": quality, "response_format": response_format, "size": size, + "stream": stream, "style": style, "user": user, }, - image_generate_params.ImageGenerateParams, + image_generate_params.ImageGenerateParamsStreaming + if stream + else image_generate_params.ImageGenerateParamsNonStreaming, ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), cast_to=ImagesResponse, + stream=stream or False, + stream_cls=AsyncStream[ImageGenStreamEvent], ) diff --git a/src/openai/types/__init__.py b/src/openai/types/__init__.py index 453b26f555..51f3ee5c9b 100644 --- a/src/openai/types/__init__.py +++ b/src/openai/types/__init__.py @@ -60,15 +60,19 @@ from .image_generate_params import ImageGenerateParams as ImageGenerateParams from .eval_retrieve_response import EvalRetrieveResponse as EvalRetrieveResponse from .file_chunking_strategy import FileChunkingStrategy as FileChunkingStrategy +from .image_gen_stream_event import ImageGenStreamEvent as ImageGenStreamEvent from .upload_complete_params import UploadCompleteParams as UploadCompleteParams from .container_create_params import ContainerCreateParams as ContainerCreateParams from .container_list_response import ContainerListResponse as ContainerListResponse from .embedding_create_params import EmbeddingCreateParams as EmbeddingCreateParams +from .image_edit_stream_event import ImageEditStreamEvent as ImageEditStreamEvent from .completion_create_params import CompletionCreateParams as CompletionCreateParams from .moderation_create_params import ModerationCreateParams as ModerationCreateParams from .vector_store_list_params import VectorStoreListParams as VectorStoreListParams from .container_create_response import ContainerCreateResponse as ContainerCreateResponse from .create_embedding_response import CreateEmbeddingResponse as CreateEmbeddingResponse +from .image_gen_completed_event import ImageGenCompletedEvent as ImageGenCompletedEvent +from .image_edit_completed_event import ImageEditCompletedEvent as ImageEditCompletedEvent from .moderation_create_response import ModerationCreateResponse as ModerationCreateResponse from .vector_store_create_params import VectorStoreCreateParams as VectorStoreCreateParams from .vector_store_search_params import VectorStoreSearchParams as VectorStoreSearchParams @@ -79,8 +83,10 @@ from .vector_store_search_response import VectorStoreSearchResponse as VectorStoreSearchResponse from .websocket_connection_options import WebsocketConnectionOptions as WebsocketConnectionOptions from .image_create_variation_params import ImageCreateVariationParams as ImageCreateVariationParams +from .image_gen_partial_image_event import ImageGenPartialImageEvent as ImageGenPartialImageEvent from .static_file_chunking_strategy import StaticFileChunkingStrategy as StaticFileChunkingStrategy from .eval_custom_data_source_config import EvalCustomDataSourceConfig as EvalCustomDataSourceConfig +from .image_edit_partial_image_event import ImageEditPartialImageEvent as ImageEditPartialImageEvent from .moderation_image_url_input_param import ModerationImageURLInputParam as ModerationImageURLInputParam from .auto_file_chunking_strategy_param import AutoFileChunkingStrategyParam as AutoFileChunkingStrategyParam from .moderation_multi_modal_input_param import ModerationMultiModalInputParam as ModerationMultiModalInputParam diff --git a/src/openai/types/image_edit_completed_event.py b/src/openai/types/image_edit_completed_event.py new file mode 100644 index 0000000000..a40682da6a --- /dev/null +++ b/src/openai/types/image_edit_completed_event.py @@ -0,0 +1,55 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["ImageEditCompletedEvent", "Usage", "UsageInputTokensDetails"] + + +class UsageInputTokensDetails(BaseModel): + image_tokens: int + """The number of image tokens in the input prompt.""" + + text_tokens: int + """The number of text tokens in the input prompt.""" + + +class Usage(BaseModel): + input_tokens: int + """The number of tokens (images and text) in the input prompt.""" + + input_tokens_details: UsageInputTokensDetails + """The input tokens detailed information for the image generation.""" + + output_tokens: int + """The number of image tokens in the output image.""" + + total_tokens: int + """The total number of tokens (images and text) used for the image generation.""" + + +class ImageEditCompletedEvent(BaseModel): + b64_json: str + """Base64-encoded final edited image data, suitable for rendering as an image.""" + + background: Literal["transparent", "opaque", "auto"] + """The background setting for the edited image.""" + + created_at: int + """The Unix timestamp when the event was created.""" + + output_format: Literal["png", "webp", "jpeg"] + """The output format for the edited image.""" + + quality: Literal["low", "medium", "high", "auto"] + """The quality setting for the edited image.""" + + size: Literal["1024x1024", "1024x1536", "1536x1024", "auto"] + """The size of the edited image.""" + + type: Literal["image_edit.completed"] + """The type of the event. Always `image_edit.completed`.""" + + usage: Usage + """For `gpt-image-1` only, the token usage information for the image generation.""" diff --git a/src/openai/types/image_edit_params.py b/src/openai/types/image_edit_params.py index aecb98fa6f..d839e2fcbe 100644 --- a/src/openai/types/image_edit_params.py +++ b/src/openai/types/image_edit_params.py @@ -8,10 +8,10 @@ from .._types import FileTypes from .image_model import ImageModel -__all__ = ["ImageEditParams"] +__all__ = ["ImageEditParamsBase", "ImageEditParamsNonStreaming", "ImageEditParamsStreaming"] -class ImageEditParams(TypedDict, total=False): +class ImageEditParamsBase(TypedDict, total=False): image: Required[Union[FileTypes, List[FileTypes]]] """The image(s) to edit. Must be a supported image file or an array of images. @@ -40,6 +40,13 @@ class ImageEditParams(TypedDict, total=False): be set to either `png` (default value) or `webp`. """ + input_fidelity: Optional[Literal["high", "low"]] + """ + Control how much effort the model will exert to match the style and features, + especially facial features, of input images. This parameter is only supported + for `gpt-image-1`. Supports `high` and `low`. Defaults to `low`. + """ + mask: FileTypes """An additional image whose fully transparent areas (e.g. @@ -72,6 +79,14 @@ class ImageEditParams(TypedDict, total=False): `jpeg`, or `webp`. The default value is `png`. """ + partial_images: Optional[int] + """The number of partial images to generate. + + This parameter is used for streaming responses that return partial images. Value + must be between 0 and 3. When set to 0, the response will be a single image sent + in one streaming event. + """ + quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] """The quality of the image that will be generated. @@ -101,3 +116,26 @@ class ImageEditParams(TypedDict, total=False): and detect abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). """ + + +class ImageEditParamsNonStreaming(ImageEditParamsBase, total=False): + stream: Optional[Literal[False]] + """Edit the image in streaming mode. + + Defaults to `false`. See the + [Image generation guide](https://platform.openai.com/docs/guides/image-generation) + for more information. + """ + + +class ImageEditParamsStreaming(ImageEditParamsBase): + stream: Required[Literal[True]] + """Edit the image in streaming mode. + + Defaults to `false`. See the + [Image generation guide](https://platform.openai.com/docs/guides/image-generation) + for more information. + """ + + +ImageEditParams = Union[ImageEditParamsNonStreaming, ImageEditParamsStreaming] diff --git a/src/openai/types/image_edit_partial_image_event.py b/src/openai/types/image_edit_partial_image_event.py new file mode 100644 index 0000000000..20da45efc3 --- /dev/null +++ b/src/openai/types/image_edit_partial_image_event.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["ImageEditPartialImageEvent"] + + +class ImageEditPartialImageEvent(BaseModel): + b64_json: str + """Base64-encoded partial image data, suitable for rendering as an image.""" + + background: Literal["transparent", "opaque", "auto"] + """The background setting for the requested edited image.""" + + created_at: int + """The Unix timestamp when the event was created.""" + + output_format: Literal["png", "webp", "jpeg"] + """The output format for the requested edited image.""" + + partial_image_index: int + """0-based index for the partial image (streaming).""" + + quality: Literal["low", "medium", "high", "auto"] + """The quality setting for the requested edited image.""" + + size: Literal["1024x1024", "1024x1536", "1536x1024", "auto"] + """The size of the requested edited image.""" + + type: Literal["image_edit.partial_image"] + """The type of the event. Always `image_edit.partial_image`.""" diff --git a/src/openai/types/image_edit_stream_event.py b/src/openai/types/image_edit_stream_event.py new file mode 100644 index 0000000000..759f6c6db5 --- /dev/null +++ b/src/openai/types/image_edit_stream_event.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from typing_extensions import Annotated, TypeAlias + +from .._utils import PropertyInfo +from .image_edit_completed_event import ImageEditCompletedEvent +from .image_edit_partial_image_event import ImageEditPartialImageEvent + +__all__ = ["ImageEditStreamEvent"] + +ImageEditStreamEvent: TypeAlias = Annotated[ + Union[ImageEditPartialImageEvent, ImageEditCompletedEvent], PropertyInfo(discriminator="type") +] diff --git a/src/openai/types/image_gen_completed_event.py b/src/openai/types/image_gen_completed_event.py new file mode 100644 index 0000000000..e78da842d4 --- /dev/null +++ b/src/openai/types/image_gen_completed_event.py @@ -0,0 +1,55 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["ImageGenCompletedEvent", "Usage", "UsageInputTokensDetails"] + + +class UsageInputTokensDetails(BaseModel): + image_tokens: int + """The number of image tokens in the input prompt.""" + + text_tokens: int + """The number of text tokens in the input prompt.""" + + +class Usage(BaseModel): + input_tokens: int + """The number of tokens (images and text) in the input prompt.""" + + input_tokens_details: UsageInputTokensDetails + """The input tokens detailed information for the image generation.""" + + output_tokens: int + """The number of image tokens in the output image.""" + + total_tokens: int + """The total number of tokens (images and text) used for the image generation.""" + + +class ImageGenCompletedEvent(BaseModel): + b64_json: str + """Base64-encoded image data, suitable for rendering as an image.""" + + background: Literal["transparent", "opaque", "auto"] + """The background setting for the generated image.""" + + created_at: int + """The Unix timestamp when the event was created.""" + + output_format: Literal["png", "webp", "jpeg"] + """The output format for the generated image.""" + + quality: Literal["low", "medium", "high", "auto"] + """The quality setting for the generated image.""" + + size: Literal["1024x1024", "1024x1536", "1536x1024", "auto"] + """The size of the generated image.""" + + type: Literal["image_generation.completed"] + """The type of the event. Always `image_generation.completed`.""" + + usage: Usage + """For `gpt-image-1` only, the token usage information for the image generation.""" diff --git a/src/openai/types/image_gen_partial_image_event.py b/src/openai/types/image_gen_partial_image_event.py new file mode 100644 index 0000000000..965d450604 --- /dev/null +++ b/src/openai/types/image_gen_partial_image_event.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["ImageGenPartialImageEvent"] + + +class ImageGenPartialImageEvent(BaseModel): + b64_json: str + """Base64-encoded partial image data, suitable for rendering as an image.""" + + background: Literal["transparent", "opaque", "auto"] + """The background setting for the requested image.""" + + created_at: int + """The Unix timestamp when the event was created.""" + + output_format: Literal["png", "webp", "jpeg"] + """The output format for the requested image.""" + + partial_image_index: int + """0-based index for the partial image (streaming).""" + + quality: Literal["low", "medium", "high", "auto"] + """The quality setting for the requested image.""" + + size: Literal["1024x1024", "1024x1536", "1536x1024", "auto"] + """The size of the requested image.""" + + type: Literal["image_generation.partial_image"] + """The type of the event. Always `image_generation.partial_image`.""" diff --git a/src/openai/types/image_gen_stream_event.py b/src/openai/types/image_gen_stream_event.py new file mode 100644 index 0000000000..7dde5d5245 --- /dev/null +++ b/src/openai/types/image_gen_stream_event.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from typing_extensions import Annotated, TypeAlias + +from .._utils import PropertyInfo +from .image_gen_completed_event import ImageGenCompletedEvent +from .image_gen_partial_image_event import ImageGenPartialImageEvent + +__all__ = ["ImageGenStreamEvent"] + +ImageGenStreamEvent: TypeAlias = Annotated[ + Union[ImageGenPartialImageEvent, ImageGenCompletedEvent], PropertyInfo(discriminator="type") +] diff --git a/src/openai/types/image_generate_params.py b/src/openai/types/image_generate_params.py index 8fc10220dc..bd9f34b28e 100644 --- a/src/openai/types/image_generate_params.py +++ b/src/openai/types/image_generate_params.py @@ -7,10 +7,10 @@ from .image_model import ImageModel -__all__ = ["ImageGenerateParams"] +__all__ = ["ImageGenerateParamsBase", "ImageGenerateParamsNonStreaming", "ImageGenerateParamsStreaming"] -class ImageGenerateParams(TypedDict, total=False): +class ImageGenerateParamsBase(TypedDict, total=False): prompt: Required[str] """A text description of the desired image(s). @@ -62,6 +62,14 @@ class ImageGenerateParams(TypedDict, total=False): `jpeg`, or `webp`. """ + partial_images: Optional[int] + """The number of partial images to generate. + + This parameter is used for streaming responses that return partial images. Value + must be between 0 and 3. When set to 0, the response will be a single image sent + in one streaming event. + """ + quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] """The quality of the image that will be generated. @@ -107,3 +115,26 @@ class ImageGenerateParams(TypedDict, total=False): and detect abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). """ + + +class ImageGenerateParamsNonStreaming(ImageGenerateParamsBase, total=False): + stream: Optional[Literal[False]] + """Generate the image in streaming mode. + + Defaults to `false`. See the + [Image generation guide](https://platform.openai.com/docs/guides/image-generation) + for more information. This parameter is only supported for `gpt-image-1`. + """ + + +class ImageGenerateParamsStreaming(ImageGenerateParamsBase): + stream: Required[Literal[True]] + """Generate the image in streaming mode. + + Defaults to `false`. See the + [Image generation guide](https://platform.openai.com/docs/guides/image-generation) + for more information. This parameter is only supported for `gpt-image-1`. + """ + + +ImageGenerateParams = Union[ImageGenerateParamsNonStreaming, ImageGenerateParamsStreaming] diff --git a/src/openai/types/responses/response_output_refusal.py b/src/openai/types/responses/response_output_refusal.py index eba581070d..685c8722a6 100644 --- a/src/openai/types/responses/response_output_refusal.py +++ b/src/openai/types/responses/response_output_refusal.py @@ -9,7 +9,7 @@ class ResponseOutputRefusal(BaseModel): refusal: str - """The refusal explanationfrom the model.""" + """The refusal explanation from the model.""" type: Literal["refusal"] """The type of the refusal. Always `refusal`.""" diff --git a/src/openai/types/responses/response_output_refusal_param.py b/src/openai/types/responses/response_output_refusal_param.py index 53140a6080..54cfaf0791 100644 --- a/src/openai/types/responses/response_output_refusal_param.py +++ b/src/openai/types/responses/response_output_refusal_param.py @@ -9,7 +9,7 @@ class ResponseOutputRefusalParam(TypedDict, total=False): refusal: Required[str] - """The refusal explanationfrom the model.""" + """The refusal explanation from the model.""" type: Required[Literal["refusal"]] """The type of the refusal. Always `refusal`.""" diff --git a/src/openai/types/responses/tool.py b/src/openai/types/responses/tool.py index 9c1573bda9..4399871e29 100644 --- a/src/openai/types/responses/tool.py +++ b/src/openai/types/responses/tool.py @@ -124,6 +124,13 @@ class ImageGeneration(BaseModel): One of `transparent`, `opaque`, or `auto`. Default: `auto`. """ + input_fidelity: Optional[Literal["high", "low"]] = None + """ + Control how much effort the model will exert to match the style and features, + especially facial features, of input images. This parameter is only supported + for `gpt-image-1`. Supports `high` and `low`. Defaults to `low`. + """ + input_image_mask: Optional[ImageGenerationInputImageMask] = None """Optional mask for inpainting. diff --git a/src/openai/types/responses/tool_param.py b/src/openai/types/responses/tool_param.py index 493a1dad9c..a977f06e3f 100644 --- a/src/openai/types/responses/tool_param.py +++ b/src/openai/types/responses/tool_param.py @@ -125,6 +125,13 @@ class ImageGeneration(TypedDict, total=False): One of `transparent`, `opaque`, or `auto`. Default: `auto`. """ + input_fidelity: Optional[Literal["high", "low"]] + """ + Control how much effort the model will exert to match the style and features, + especially facial features, of input images. This parameter is only supported + for `gpt-image-1`. Supports `high` and `low`. Defaults to `low`. + """ + input_image_mask: ImageGenerationInputImageMask """Optional mask for inpainting. diff --git a/tests/api_resources/test_images.py b/tests/api_resources/test_images.py index 10fc56d685..99fe77d8e0 100644 --- a/tests/api_resources/test_images.py +++ b/tests/api_resources/test_images.py @@ -61,7 +61,7 @@ def test_streaming_response_create_variation(self, client: OpenAI) -> None: assert cast(Any, response.is_closed) is True @parametrize - def test_method_edit(self, client: OpenAI) -> None: + def test_method_edit_overload_1(self, client: OpenAI) -> None: image = client.images.edit( image=b"raw file contents", prompt="A cute baby sea otter wearing a beret", @@ -69,25 +69,28 @@ def test_method_edit(self, client: OpenAI) -> None: assert_matches_type(ImagesResponse, image, path=["response"]) @parametrize - def test_method_edit_with_all_params(self, client: OpenAI) -> None: + def test_method_edit_with_all_params_overload_1(self, client: OpenAI) -> None: image = client.images.edit( image=b"raw file contents", prompt="A cute baby sea otter wearing a beret", background="transparent", + input_fidelity="high", mask=b"raw file contents", model="string", n=1, output_compression=100, output_format="png", + partial_images=1, quality="high", response_format="url", size="1024x1024", + stream=False, user="user-1234", ) assert_matches_type(ImagesResponse, image, path=["response"]) @parametrize - def test_raw_response_edit(self, client: OpenAI) -> None: + def test_raw_response_edit_overload_1(self, client: OpenAI) -> None: response = client.images.with_raw_response.edit( image=b"raw file contents", prompt="A cute baby sea otter wearing a beret", @@ -99,7 +102,7 @@ def test_raw_response_edit(self, client: OpenAI) -> None: assert_matches_type(ImagesResponse, image, path=["response"]) @parametrize - def test_streaming_response_edit(self, client: OpenAI) -> None: + def test_streaming_response_edit_overload_1(self, client: OpenAI) -> None: with client.images.with_streaming_response.edit( image=b"raw file contents", prompt="A cute baby sea otter wearing a beret", @@ -113,14 +116,71 @@ def test_streaming_response_edit(self, client: OpenAI) -> None: assert cast(Any, response.is_closed) is True @parametrize - def test_method_generate(self, client: OpenAI) -> None: + def test_method_edit_overload_2(self, client: OpenAI) -> None: + image_stream = client.images.edit( + image=b"raw file contents", + prompt="A cute baby sea otter wearing a beret", + stream=True, + ) + image_stream.response.close() + + @parametrize + def test_method_edit_with_all_params_overload_2(self, client: OpenAI) -> None: + image_stream = client.images.edit( + image=b"raw file contents", + prompt="A cute baby sea otter wearing a beret", + stream=True, + background="transparent", + input_fidelity="high", + mask=b"raw file contents", + model="string", + n=1, + output_compression=100, + output_format="png", + partial_images=1, + quality="high", + response_format="url", + size="1024x1024", + user="user-1234", + ) + image_stream.response.close() + + @parametrize + def test_raw_response_edit_overload_2(self, client: OpenAI) -> None: + response = client.images.with_raw_response.edit( + image=b"raw file contents", + prompt="A cute baby sea otter wearing a beret", + stream=True, + ) + + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = response.parse() + stream.close() + + @parametrize + def test_streaming_response_edit_overload_2(self, client: OpenAI) -> None: + with client.images.with_streaming_response.edit( + image=b"raw file contents", + prompt="A cute baby sea otter wearing a beret", + stream=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = response.parse() + stream.close() + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_generate_overload_1(self, client: OpenAI) -> None: image = client.images.generate( prompt="A cute baby sea otter", ) assert_matches_type(ImagesResponse, image, path=["response"]) @parametrize - def test_method_generate_with_all_params(self, client: OpenAI) -> None: + def test_method_generate_with_all_params_overload_1(self, client: OpenAI) -> None: image = client.images.generate( prompt="A cute baby sea otter", background="transparent", @@ -129,16 +189,18 @@ def test_method_generate_with_all_params(self, client: OpenAI) -> None: n=1, output_compression=100, output_format="png", + partial_images=1, quality="medium", response_format="url", size="1024x1024", + stream=False, style="vivid", user="user-1234", ) assert_matches_type(ImagesResponse, image, path=["response"]) @parametrize - def test_raw_response_generate(self, client: OpenAI) -> None: + def test_raw_response_generate_overload_1(self, client: OpenAI) -> None: response = client.images.with_raw_response.generate( prompt="A cute baby sea otter", ) @@ -149,7 +211,7 @@ def test_raw_response_generate(self, client: OpenAI) -> None: assert_matches_type(ImagesResponse, image, path=["response"]) @parametrize - def test_streaming_response_generate(self, client: OpenAI) -> None: + def test_streaming_response_generate_overload_1(self, client: OpenAI) -> None: with client.images.with_streaming_response.generate( prompt="A cute baby sea otter", ) as response: @@ -161,6 +223,59 @@ def test_streaming_response_generate(self, client: OpenAI) -> None: assert cast(Any, response.is_closed) is True + @parametrize + def test_method_generate_overload_2(self, client: OpenAI) -> None: + image_stream = client.images.generate( + prompt="A cute baby sea otter", + stream=True, + ) + image_stream.response.close() + + @parametrize + def test_method_generate_with_all_params_overload_2(self, client: OpenAI) -> None: + image_stream = client.images.generate( + prompt="A cute baby sea otter", + stream=True, + background="transparent", + model="string", + moderation="low", + n=1, + output_compression=100, + output_format="png", + partial_images=1, + quality="medium", + response_format="url", + size="1024x1024", + style="vivid", + user="user-1234", + ) + image_stream.response.close() + + @parametrize + def test_raw_response_generate_overload_2(self, client: OpenAI) -> None: + response = client.images.with_raw_response.generate( + prompt="A cute baby sea otter", + stream=True, + ) + + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = response.parse() + stream.close() + + @parametrize + def test_streaming_response_generate_overload_2(self, client: OpenAI) -> None: + with client.images.with_streaming_response.generate( + prompt="A cute baby sea otter", + stream=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = response.parse() + stream.close() + + assert cast(Any, response.is_closed) is True + class TestAsyncImages: parametrize = pytest.mark.parametrize( @@ -211,7 +326,7 @@ async def test_streaming_response_create_variation(self, async_client: AsyncOpen assert cast(Any, response.is_closed) is True @parametrize - async def test_method_edit(self, async_client: AsyncOpenAI) -> None: + async def test_method_edit_overload_1(self, async_client: AsyncOpenAI) -> None: image = await async_client.images.edit( image=b"raw file contents", prompt="A cute baby sea otter wearing a beret", @@ -219,25 +334,28 @@ async def test_method_edit(self, async_client: AsyncOpenAI) -> None: assert_matches_type(ImagesResponse, image, path=["response"]) @parametrize - async def test_method_edit_with_all_params(self, async_client: AsyncOpenAI) -> None: + async def test_method_edit_with_all_params_overload_1(self, async_client: AsyncOpenAI) -> None: image = await async_client.images.edit( image=b"raw file contents", prompt="A cute baby sea otter wearing a beret", background="transparent", + input_fidelity="high", mask=b"raw file contents", model="string", n=1, output_compression=100, output_format="png", + partial_images=1, quality="high", response_format="url", size="1024x1024", + stream=False, user="user-1234", ) assert_matches_type(ImagesResponse, image, path=["response"]) @parametrize - async def test_raw_response_edit(self, async_client: AsyncOpenAI) -> None: + async def test_raw_response_edit_overload_1(self, async_client: AsyncOpenAI) -> None: response = await async_client.images.with_raw_response.edit( image=b"raw file contents", prompt="A cute baby sea otter wearing a beret", @@ -249,7 +367,7 @@ async def test_raw_response_edit(self, async_client: AsyncOpenAI) -> None: assert_matches_type(ImagesResponse, image, path=["response"]) @parametrize - async def test_streaming_response_edit(self, async_client: AsyncOpenAI) -> None: + async def test_streaming_response_edit_overload_1(self, async_client: AsyncOpenAI) -> None: async with async_client.images.with_streaming_response.edit( image=b"raw file contents", prompt="A cute baby sea otter wearing a beret", @@ -263,14 +381,71 @@ async def test_streaming_response_edit(self, async_client: AsyncOpenAI) -> None: assert cast(Any, response.is_closed) is True @parametrize - async def test_method_generate(self, async_client: AsyncOpenAI) -> None: + async def test_method_edit_overload_2(self, async_client: AsyncOpenAI) -> None: + image_stream = await async_client.images.edit( + image=b"raw file contents", + prompt="A cute baby sea otter wearing a beret", + stream=True, + ) + await image_stream.response.aclose() + + @parametrize + async def test_method_edit_with_all_params_overload_2(self, async_client: AsyncOpenAI) -> None: + image_stream = await async_client.images.edit( + image=b"raw file contents", + prompt="A cute baby sea otter wearing a beret", + stream=True, + background="transparent", + input_fidelity="high", + mask=b"raw file contents", + model="string", + n=1, + output_compression=100, + output_format="png", + partial_images=1, + quality="high", + response_format="url", + size="1024x1024", + user="user-1234", + ) + await image_stream.response.aclose() + + @parametrize + async def test_raw_response_edit_overload_2(self, async_client: AsyncOpenAI) -> None: + response = await async_client.images.with_raw_response.edit( + image=b"raw file contents", + prompt="A cute baby sea otter wearing a beret", + stream=True, + ) + + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = response.parse() + await stream.close() + + @parametrize + async def test_streaming_response_edit_overload_2(self, async_client: AsyncOpenAI) -> None: + async with async_client.images.with_streaming_response.edit( + image=b"raw file contents", + prompt="A cute baby sea otter wearing a beret", + stream=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = await response.parse() + await stream.close() + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_generate_overload_1(self, async_client: AsyncOpenAI) -> None: image = await async_client.images.generate( prompt="A cute baby sea otter", ) assert_matches_type(ImagesResponse, image, path=["response"]) @parametrize - async def test_method_generate_with_all_params(self, async_client: AsyncOpenAI) -> None: + async def test_method_generate_with_all_params_overload_1(self, async_client: AsyncOpenAI) -> None: image = await async_client.images.generate( prompt="A cute baby sea otter", background="transparent", @@ -279,16 +454,18 @@ async def test_method_generate_with_all_params(self, async_client: AsyncOpenAI) n=1, output_compression=100, output_format="png", + partial_images=1, quality="medium", response_format="url", size="1024x1024", + stream=False, style="vivid", user="user-1234", ) assert_matches_type(ImagesResponse, image, path=["response"]) @parametrize - async def test_raw_response_generate(self, async_client: AsyncOpenAI) -> None: + async def test_raw_response_generate_overload_1(self, async_client: AsyncOpenAI) -> None: response = await async_client.images.with_raw_response.generate( prompt="A cute baby sea otter", ) @@ -299,7 +476,7 @@ async def test_raw_response_generate(self, async_client: AsyncOpenAI) -> None: assert_matches_type(ImagesResponse, image, path=["response"]) @parametrize - async def test_streaming_response_generate(self, async_client: AsyncOpenAI) -> None: + async def test_streaming_response_generate_overload_1(self, async_client: AsyncOpenAI) -> None: async with async_client.images.with_streaming_response.generate( prompt="A cute baby sea otter", ) as response: @@ -310,3 +487,56 @@ async def test_streaming_response_generate(self, async_client: AsyncOpenAI) -> N assert_matches_type(ImagesResponse, image, path=["response"]) assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_generate_overload_2(self, async_client: AsyncOpenAI) -> None: + image_stream = await async_client.images.generate( + prompt="A cute baby sea otter", + stream=True, + ) + await image_stream.response.aclose() + + @parametrize + async def test_method_generate_with_all_params_overload_2(self, async_client: AsyncOpenAI) -> None: + image_stream = await async_client.images.generate( + prompt="A cute baby sea otter", + stream=True, + background="transparent", + model="string", + moderation="low", + n=1, + output_compression=100, + output_format="png", + partial_images=1, + quality="medium", + response_format="url", + size="1024x1024", + style="vivid", + user="user-1234", + ) + await image_stream.response.aclose() + + @parametrize + async def test_raw_response_generate_overload_2(self, async_client: AsyncOpenAI) -> None: + response = await async_client.images.with_raw_response.generate( + prompt="A cute baby sea otter", + stream=True, + ) + + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = response.parse() + await stream.close() + + @parametrize + async def test_streaming_response_generate_overload_2(self, async_client: AsyncOpenAI) -> None: + async with async_client.images.with_streaming_response.generate( + prompt="A cute baby sea otter", + stream=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = await response.parse() + await stream.close() + + assert cast(Any, response.is_closed) is True From 35df552d032873b62c2ae127a0efce60947dbed0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 16 Jul 2025 16:25:26 +0000 Subject: [PATCH 404/769] release: 1.97.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 6b38a1bd5a..7b33636f46 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.96.1" + ".": "1.97.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 93bfb63f37..2e603f06be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.97.0 (2025-07-16) + +Full Changelog: [v1.96.1...v1.97.0](https://github.com/openai/openai-python/compare/v1.96.1...v1.97.0) + +### Features + +* **api:** manual updates ([ed8e899](https://github.com/openai/openai-python/commit/ed8e89953d11bd5f44fa531422bdbb7a577ab426)) + ## 1.96.1 (2025-07-15) Full Changelog: [v1.96.0...v1.96.1](https://github.com/openai/openai-python/compare/v1.96.0...v1.96.1) diff --git a/pyproject.toml b/pyproject.toml index 0f655d058d..533379d52a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.96.1" +version = "1.97.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 39be0338f6..8e5ed5fa86 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.96.1" # x-release-please-version +__version__ = "1.97.0" # x-release-please-version From fa466c099aab0213f3ce09d5adcfca5ae2bf58a4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 16 Jul 2025 19:06:17 +0000 Subject: [PATCH 405/769] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 2b9160cf6e..bc75e5c98c 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-670ea0d2cc44f52a87dd3cadea45632953283e0636ba30788fdbdb22a232ccac.yml openapi_spec_hash: d8b7d38911fead545adf3e4297956410 -config_hash: 5525bda35e48ea6387c6175c4d1651fa +config_hash: b2a4028fdbb27a08de89831ed310e244 From c6b933520213cddea927c4fe83c1abe2f66893d8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 12:27:19 +0000 Subject: [PATCH 406/769] fix(parsing): ignore empty metadata --- src/openai/_models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openai/_models.py b/src/openai/_models.py index f347a81dac..dee5551948 100644 --- a/src/openai/_models.py +++ b/src/openai/_models.py @@ -464,7 +464,7 @@ def construct_type(*, value: object, type_: object, metadata: Optional[List[Any] type_ = type_.__value__ # type: ignore[unreachable] # unwrap `Annotated[T, ...]` -> `T` - if metadata is not None: + if metadata is not None and len(metadata) > 0: meta: tuple[Any, ...] = tuple(metadata) elif is_annotated_type(type_): meta = get_args(type_)[1:] From bf4a9a422e5eaffa90863439ddfd8a82cbaaa636 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 21:17:00 +0000 Subject: [PATCH 407/769] chore(api): event shapes more accurate --- .stats.yml | 6 ++-- api.md | 2 -- src/openai/lib/streaming/responses/_events.py | 4 --- .../lib/streaming/responses/_responses.py | 2 ++ src/openai/resources/audio/speech.py | 8 ++--- .../resources/beta/realtime/sessions.py | 14 +++----- .../resources/chat/completions/completions.py | 12 +++---- src/openai/resources/images.py | 36 +++++++++++++++++++ src/openai/resources/responses/responses.py | 12 +++---- .../types/audio/speech_create_params.py | 6 +--- .../types/beta/realtime/realtime_response.py | 9 ++--- .../beta/realtime/response_create_event.py | 8 ++--- .../realtime/response_create_event_param.py | 6 ++-- src/openai/types/beta/realtime/session.py | 8 ++--- .../beta/realtime/session_create_params.py | 6 ++-- .../beta/realtime/session_create_response.py | 8 ++--- .../beta/realtime/session_update_event.py | 8 ++--- .../realtime/session_update_event_param.py | 6 ++-- src/openai/types/chat/chat_completion.py | 2 +- .../types/chat/chat_completion_audio_param.py | 6 +--- .../types/chat/chat_completion_chunk.py | 2 +- .../types/chat/completion_create_params.py | 2 +- src/openai/types/image_edit_params.py | 3 ++ src/openai/types/image_generate_params.py | 3 ++ src/openai/types/images_response.py | 2 +- src/openai/types/responses/__init__.py | 2 -- src/openai/types/responses/response.py | 2 +- .../response_code_interpreter_tool_call.py | 6 +++- ...sponse_code_interpreter_tool_call_param.py | 6 +++- .../types/responses/response_create_params.py | 2 +- ...response_mcp_call_arguments_delta_event.py | 7 ++-- .../response_mcp_call_arguments_done_event.py | 4 +-- .../response_mcp_call_completed_event.py | 6 ++++ .../response_mcp_call_failed_event.py | 6 ++++ ...response_mcp_list_tools_completed_event.py | 6 ++++ .../response_mcp_list_tools_failed_event.py | 6 ++++ ...sponse_mcp_list_tools_in_progress_event.py | 6 ++++ .../response_reasoning_delta_event.py | 27 -------------- .../response_reasoning_done_event.py | 27 -------------- .../types/responses/response_stream_event.py | 4 --- .../responses/response_text_delta_event.py | 25 ++++++++++++- .../responses/response_text_done_event.py | 25 ++++++++++++- .../types/shared/function_definition.py | 2 +- .../shared_params/function_definition.py | 2 +- 44 files changed, 186 insertions(+), 166 deletions(-) delete mode 100644 src/openai/types/responses/response_reasoning_delta_event.py delete mode 100644 src/openai/types/responses/response_reasoning_done_event.py diff --git a/.stats.yml b/.stats.yml index bc75e5c98c..2dc4f680a9 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-670ea0d2cc44f52a87dd3cadea45632953283e0636ba30788fdbdb22a232ccac.yml -openapi_spec_hash: d8b7d38911fead545adf3e4297956410 -config_hash: b2a4028fdbb27a08de89831ed310e244 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-b2a451656ca64d30d174391ebfd94806b4de3ab76dc55b92843cfb7f1a54ecb6.yml +openapi_spec_hash: 27d9691b400f28c17ef063a1374048b0 +config_hash: e822d0c9082c8b312264403949243179 diff --git a/api.md b/api.md index b3a2245cdd..0280b886d1 100644 --- a/api.md +++ b/api.md @@ -791,8 +791,6 @@ from openai.types.responses import ( ResponseOutputTextAnnotationAddedEvent, ResponsePrompt, ResponseQueuedEvent, - ResponseReasoningDeltaEvent, - ResponseReasoningDoneEvent, ResponseReasoningItem, ResponseReasoningSummaryDeltaEvent, ResponseReasoningSummaryDoneEvent, diff --git a/src/openai/lib/streaming/responses/_events.py b/src/openai/lib/streaming/responses/_events.py index 6e547815e2..4c8a588944 100644 --- a/src/openai/lib/streaming/responses/_events.py +++ b/src/openai/lib/streaming/responses/_events.py @@ -21,9 +21,7 @@ ResponseRefusalDoneEvent, ResponseRefusalDeltaEvent, ResponseMcpCallFailedEvent, - ResponseReasoningDoneEvent, ResponseOutputItemDoneEvent, - ResponseReasoningDeltaEvent, ResponseContentPartDoneEvent, ResponseOutputItemAddedEvent, ResponseContentPartAddedEvent, @@ -139,10 +137,8 @@ class ResponseCompletedEvent(RawResponseCompletedEvent, GenericModel, Generic[Te ResponseMcpListToolsInProgressEvent, ResponseOutputTextAnnotationAddedEvent, ResponseQueuedEvent, - ResponseReasoningDeltaEvent, ResponseReasoningSummaryDeltaEvent, ResponseReasoningSummaryDoneEvent, - ResponseReasoningDoneEvent, ], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/lib/streaming/responses/_responses.py b/src/openai/lib/streaming/responses/_responses.py index 2c2fec5469..d45664de45 100644 --- a/src/openai/lib/streaming/responses/_responses.py +++ b/src/openai/lib/streaming/responses/_responses.py @@ -264,6 +264,7 @@ def handle_event(self, event: RawResponseStreamEvent) -> List[ResponseStreamEven item_id=event.item_id, output_index=event.output_index, sequence_number=event.sequence_number, + logprobs=event.logprobs, type="response.output_text.delta", snapshot=content.text, ) @@ -282,6 +283,7 @@ def handle_event(self, event: RawResponseStreamEvent) -> List[ResponseStreamEven item_id=event.item_id, output_index=event.output_index, sequence_number=event.sequence_number, + logprobs=event.logprobs, type="response.output_text.done", text=event.text, parsed=parse_text(event.text, text_format=self._text_format), diff --git a/src/openai/resources/audio/speech.py b/src/openai/resources/audio/speech.py index fe776baae8..6251cfed4e 100644 --- a/src/openai/resources/audio/speech.py +++ b/src/openai/resources/audio/speech.py @@ -50,9 +50,7 @@ def create( *, input: str, model: Union[str, SpeechModel], - voice: Union[ - str, Literal["alloy", "ash", "ballad", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer", "verse"] - ], + voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"]], instructions: str | NotGiven = NOT_GIVEN, response_format: Literal["mp3", "opus", "aac", "flac", "wav", "pcm"] | NotGiven = NOT_GIVEN, speed: float | NotGiven = NOT_GIVEN, @@ -146,9 +144,7 @@ async def create( *, input: str, model: Union[str, SpeechModel], - voice: Union[ - str, Literal["alloy", "ash", "ballad", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer", "verse"] - ], + voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"]], instructions: str | NotGiven = NOT_GIVEN, response_format: Literal["mp3", "opus", "aac", "flac", "wav", "pcm"] | NotGiven = NOT_GIVEN, speed: float | NotGiven = NOT_GIVEN, diff --git a/src/openai/resources/beta/realtime/sessions.py b/src/openai/resources/beta/realtime/sessions.py index 77f1ec9059..e639c0ba43 100644 --- a/src/openai/resources/beta/realtime/sessions.py +++ b/src/openai/resources/beta/realtime/sessions.py @@ -66,9 +66,7 @@ def create( tools: Iterable[session_create_params.Tool] | NotGiven = NOT_GIVEN, tracing: session_create_params.Tracing | NotGiven = NOT_GIVEN, turn_detection: session_create_params.TurnDetection | NotGiven = NOT_GIVEN, - voice: Union[ - str, Literal["alloy", "ash", "ballad", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer", "verse"] - ] + voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"]] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -163,8 +161,7 @@ def create( voice: The voice the model uses to respond. Voice cannot be changed during the session once the model has responded with audio at least once. Current voice options are - `alloy`, `ash`, `ballad`, `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, - `shimmer`, and `verse`. + `alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`, `shimmer`, and `verse`. extra_headers: Send extra headers @@ -251,9 +248,7 @@ async def create( tools: Iterable[session_create_params.Tool] | NotGiven = NOT_GIVEN, tracing: session_create_params.Tracing | NotGiven = NOT_GIVEN, turn_detection: session_create_params.TurnDetection | NotGiven = NOT_GIVEN, - voice: Union[ - str, Literal["alloy", "ash", "ballad", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer", "verse"] - ] + voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"]] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -348,8 +343,7 @@ async def create( voice: The voice the model uses to respond. Voice cannot be changed during the session once the model has responded with audio at least once. Current voice options are - `alloy`, `ash`, `ballad`, `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, - `shimmer`, and `verse`. + `alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`, `shimmer`, and `verse`. extra_headers: Send extra headers diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index 5806296773..739aa662d4 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -417,7 +417,7 @@ def create( - If set to 'auto', then the request will be processed with the service tier configured in the Project settings. Unless otherwise configured, the Project will use 'default'. - - If set to 'default', then the requset will be processed with the standard + - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or 'priority', then the request will be processed with the corresponding service @@ -697,7 +697,7 @@ def create( - If set to 'auto', then the request will be processed with the service tier configured in the Project settings. Unless otherwise configured, the Project will use 'default'. - - If set to 'default', then the requset will be processed with the standard + - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or 'priority', then the request will be processed with the corresponding service @@ -968,7 +968,7 @@ def create( - If set to 'auto', then the request will be processed with the service tier configured in the Project settings. Unless otherwise configured, the Project will use 'default'. - - If set to 'default', then the requset will be processed with the standard + - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or 'priority', then the request will be processed with the corresponding service @@ -1784,7 +1784,7 @@ async def create( - If set to 'auto', then the request will be processed with the service tier configured in the Project settings. Unless otherwise configured, the Project will use 'default'. - - If set to 'default', then the requset will be processed with the standard + - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or 'priority', then the request will be processed with the corresponding service @@ -2064,7 +2064,7 @@ async def create( - If set to 'auto', then the request will be processed with the service tier configured in the Project settings. Unless otherwise configured, the Project will use 'default'. - - If set to 'default', then the requset will be processed with the standard + - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or 'priority', then the request will be processed with the corresponding service @@ -2335,7 +2335,7 @@ async def create( - If set to 'auto', then the request will be processed with the service tier configured in the Project settings. Unless otherwise configured, the Project will use 'default'. - - If set to 'default', then the requset will be processed with the standard + - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or 'priority', then the request will be processed with the corresponding service diff --git a/src/openai/resources/images.py b/src/openai/resources/images.py index 77b7a1b24e..c8eda8a76f 100644 --- a/src/openai/resources/images.py +++ b/src/openai/resources/images.py @@ -196,6 +196,9 @@ def edit( responses that return partial images. Value must be between 0 and 3. When set to 0, the response will be a single image sent in one streaming event. + Note that the final image may be sent before the full number of partial images + are generated if the full image is generated more quickly. + quality: The quality of the image that will be generated. `high`, `medium` and `low` are only supported for `gpt-image-1`. `dall-e-2` only supports `standard` quality. Defaults to `auto`. @@ -310,6 +313,9 @@ def edit( responses that return partial images. Value must be between 0 and 3. When set to 0, the response will be a single image sent in one streaming event. + Note that the final image may be sent before the full number of partial images + are generated if the full image is generated more quickly. + quality: The quality of the image that will be generated. `high`, `medium` and `low` are only supported for `gpt-image-1`. `dall-e-2` only supports `standard` quality. Defaults to `auto`. @@ -420,6 +426,9 @@ def edit( responses that return partial images. Value must be between 0 and 3. When set to 0, the response will be a single image sent in one streaming event. + Note that the final image may be sent before the full number of partial images + are generated if the full image is generated more quickly. + quality: The quality of the image that will be generated. `high`, `medium` and `low` are only supported for `gpt-image-1`. `dall-e-2` only supports `standard` quality. Defaults to `auto`. @@ -579,6 +588,9 @@ def generate( responses that return partial images. Value must be between 0 and 3. When set to 0, the response will be a single image sent in one streaming event. + Note that the final image may be sent before the full number of partial images + are generated if the full image is generated more quickly. + quality: The quality of the image that will be generated. - `auto` (default value) will automatically select the best quality for the @@ -690,6 +702,9 @@ def generate( responses that return partial images. Value must be between 0 and 3. When set to 0, the response will be a single image sent in one streaming event. + Note that the final image may be sent before the full number of partial images + are generated if the full image is generated more quickly. + quality: The quality of the image that will be generated. - `auto` (default value) will automatically select the best quality for the @@ -797,6 +812,9 @@ def generate( responses that return partial images. Value must be between 0 and 3. When set to 0, the response will be a single image sent in one streaming event. + Note that the final image may be sent before the full number of partial images + are generated if the full image is generated more quickly. + quality: The quality of the image that will be generated. - `auto` (default value) will automatically select the best quality for the @@ -1066,6 +1084,9 @@ async def edit( responses that return partial images. Value must be between 0 and 3. When set to 0, the response will be a single image sent in one streaming event. + Note that the final image may be sent before the full number of partial images + are generated if the full image is generated more quickly. + quality: The quality of the image that will be generated. `high`, `medium` and `low` are only supported for `gpt-image-1`. `dall-e-2` only supports `standard` quality. Defaults to `auto`. @@ -1180,6 +1201,9 @@ async def edit( responses that return partial images. Value must be between 0 and 3. When set to 0, the response will be a single image sent in one streaming event. + Note that the final image may be sent before the full number of partial images + are generated if the full image is generated more quickly. + quality: The quality of the image that will be generated. `high`, `medium` and `low` are only supported for `gpt-image-1`. `dall-e-2` only supports `standard` quality. Defaults to `auto`. @@ -1290,6 +1314,9 @@ async def edit( responses that return partial images. Value must be between 0 and 3. When set to 0, the response will be a single image sent in one streaming event. + Note that the final image may be sent before the full number of partial images + are generated if the full image is generated more quickly. + quality: The quality of the image that will be generated. `high`, `medium` and `low` are only supported for `gpt-image-1`. `dall-e-2` only supports `standard` quality. Defaults to `auto`. @@ -1449,6 +1476,9 @@ async def generate( responses that return partial images. Value must be between 0 and 3. When set to 0, the response will be a single image sent in one streaming event. + Note that the final image may be sent before the full number of partial images + are generated if the full image is generated more quickly. + quality: The quality of the image that will be generated. - `auto` (default value) will automatically select the best quality for the @@ -1560,6 +1590,9 @@ async def generate( responses that return partial images. Value must be between 0 and 3. When set to 0, the response will be a single image sent in one streaming event. + Note that the final image may be sent before the full number of partial images + are generated if the full image is generated more quickly. + quality: The quality of the image that will be generated. - `auto` (default value) will automatically select the best quality for the @@ -1667,6 +1700,9 @@ async def generate( responses that return partial images. Value must be between 0 and 3. When set to 0, the response will be a single image sent in one streaming event. + Note that the final image may be sent before the full number of partial images + are generated if the full image is generated more quickly. + quality: The quality of the image that will be generated. - `auto` (default value) will automatically select the best quality for the diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index ce132bdb05..fe99aa851d 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -198,7 +198,7 @@ def create( - If set to 'auto', then the request will be processed with the service tier configured in the Project settings. Unless otherwise configured, the Project will use 'default'. - - If set to 'default', then the requset will be processed with the standard + - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or 'priority', then the request will be processed with the corresponding service @@ -414,7 +414,7 @@ def create( - If set to 'auto', then the request will be processed with the service tier configured in the Project settings. Unless otherwise configured, the Project will use 'default'. - - If set to 'default', then the requset will be processed with the standard + - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or 'priority', then the request will be processed with the corresponding service @@ -623,7 +623,7 @@ def create( - If set to 'auto', then the request will be processed with the service tier configured in the Project settings. Unless otherwise configured, the Project will use 'default'. - - If set to 'default', then the requset will be processed with the standard + - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or 'priority', then the request will be processed with the corresponding service @@ -1463,7 +1463,7 @@ async def create( - If set to 'auto', then the request will be processed with the service tier configured in the Project settings. Unless otherwise configured, the Project will use 'default'. - - If set to 'default', then the requset will be processed with the standard + - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or 'priority', then the request will be processed with the corresponding service @@ -1679,7 +1679,7 @@ async def create( - If set to 'auto', then the request will be processed with the service tier configured in the Project settings. Unless otherwise configured, the Project will use 'default'. - - If set to 'default', then the requset will be processed with the standard + - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or 'priority', then the request will be processed with the corresponding service @@ -1888,7 +1888,7 @@ async def create( - If set to 'auto', then the request will be processed with the service tier configured in the Project settings. Unless otherwise configured, the Project will use 'default'. - - If set to 'default', then the requset will be processed with the standard + - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or 'priority', then the request will be processed with the corresponding service diff --git a/src/openai/types/audio/speech_create_params.py b/src/openai/types/audio/speech_create_params.py index 4ee4a3c4e4..feeb68c68b 100644 --- a/src/openai/types/audio/speech_create_params.py +++ b/src/openai/types/audio/speech_create_params.py @@ -20,11 +20,7 @@ class SpeechCreateParams(TypedDict, total=False): `tts-1`, `tts-1-hd` or `gpt-4o-mini-tts`. """ - voice: Required[ - Union[ - str, Literal["alloy", "ash", "ballad", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer", "verse"] - ] - ] + voice: Required[Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"]]] """The voice to use when generating the audio. Supported voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, `fable`, `onyx`, diff --git a/src/openai/types/beta/realtime/realtime_response.py b/src/openai/types/beta/realtime/realtime_response.py index 28e03c8717..ccc97c5d22 100644 --- a/src/openai/types/beta/realtime/realtime_response.py +++ b/src/openai/types/beta/realtime/realtime_response.py @@ -80,13 +80,8 @@ class RealtimeResponse(BaseModel): will become the input for later turns. """ - voice: Union[ - str, - Literal["alloy", "ash", "ballad", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer", "verse"], - None, - ] = None + voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"], None] = None """ The voice the model used to respond. Current voice options are `alloy`, `ash`, - `ballad`, `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, `shimmer`, and - `verse`. + `ballad`, `coral`, `echo`, `sage`, `shimmer`, and `verse`. """ diff --git a/src/openai/types/beta/realtime/response_create_event.py b/src/openai/types/beta/realtime/response_create_event.py index 3b8a6de8df..7219cedbf3 100644 --- a/src/openai/types/beta/realtime/response_create_event.py +++ b/src/openai/types/beta/realtime/response_create_event.py @@ -101,16 +101,12 @@ class Response(BaseModel): tools: Optional[List[ResponseTool]] = None """Tools (functions) available to the model.""" - voice: Union[ - str, - Literal["alloy", "ash", "ballad", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer", "verse"], - None, - ] = None + voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"], None] = None """The voice the model uses to respond. Voice cannot be changed during the session once the model has responded with audio at least once. Current voice options are `alloy`, `ash`, `ballad`, - `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, `shimmer`, and `verse`. + `coral`, `echo`, `sage`, `shimmer`, and `verse`. """ diff --git a/src/openai/types/beta/realtime/response_create_event_param.py b/src/openai/types/beta/realtime/response_create_event_param.py index c569d507a0..b4d54bba92 100644 --- a/src/openai/types/beta/realtime/response_create_event_param.py +++ b/src/openai/types/beta/realtime/response_create_event_param.py @@ -102,14 +102,12 @@ class Response(TypedDict, total=False): tools: Iterable[ResponseTool] """Tools (functions) available to the model.""" - voice: Union[ - str, Literal["alloy", "ash", "ballad", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer", "verse"] - ] + voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"]] """The voice the model uses to respond. Voice cannot be changed during the session once the model has responded with audio at least once. Current voice options are `alloy`, `ash`, `ballad`, - `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, `shimmer`, and `verse`. + `coral`, `echo`, `sage`, `shimmer`, and `verse`. """ diff --git a/src/openai/types/beta/realtime/session.py b/src/openai/types/beta/realtime/session.py index 606fd83851..f84b3ee4a0 100644 --- a/src/openai/types/beta/realtime/session.py +++ b/src/openai/types/beta/realtime/session.py @@ -268,14 +268,10 @@ class Session(BaseModel): natural conversations, but may have a higher latency. """ - voice: Union[ - str, - Literal["alloy", "ash", "ballad", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer", "verse"], - None, - ] = None + voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"], None] = None """The voice the model uses to respond. Voice cannot be changed during the session once the model has responded with audio at least once. Current voice options are `alloy`, `ash`, `ballad`, - `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, `shimmer`, and `verse`. + `coral`, `echo`, `sage`, `shimmer`, and `verse`. """ diff --git a/src/openai/types/beta/realtime/session_create_params.py b/src/openai/types/beta/realtime/session_create_params.py index e04985d2b6..6be09d8bae 100644 --- a/src/openai/types/beta/realtime/session_create_params.py +++ b/src/openai/types/beta/realtime/session_create_params.py @@ -145,14 +145,12 @@ class SessionCreateParams(TypedDict, total=False): natural conversations, but may have a higher latency. """ - voice: Union[ - str, Literal["alloy", "ash", "ballad", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer", "verse"] - ] + voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"]] """The voice the model uses to respond. Voice cannot be changed during the session once the model has responded with audio at least once. Current voice options are `alloy`, `ash`, `ballad`, - `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, `shimmer`, and `verse`. + `coral`, `echo`, `sage`, `shimmer`, and `verse`. """ diff --git a/src/openai/types/beta/realtime/session_create_response.py b/src/openai/types/beta/realtime/session_create_response.py index 15d5c1742b..471da03691 100644 --- a/src/openai/types/beta/realtime/session_create_response.py +++ b/src/openai/types/beta/realtime/session_create_response.py @@ -187,14 +187,10 @@ class SessionCreateResponse(BaseModel): speech. """ - voice: Union[ - str, - Literal["alloy", "ash", "ballad", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer", "verse"], - None, - ] = None + voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"], None] = None """The voice the model uses to respond. Voice cannot be changed during the session once the model has responded with audio at least once. Current voice options are `alloy`, `ash`, `ballad`, - `coral`, `echo` `sage`, `shimmer` and `verse`. + `coral`, `echo`, `sage`, `shimmer`, and `verse`. """ diff --git a/src/openai/types/beta/realtime/session_update_event.py b/src/openai/types/beta/realtime/session_update_event.py index 789b9cd1e5..5b4185dbf6 100644 --- a/src/openai/types/beta/realtime/session_update_event.py +++ b/src/openai/types/beta/realtime/session_update_event.py @@ -290,16 +290,12 @@ class Session(BaseModel): natural conversations, but may have a higher latency. """ - voice: Union[ - str, - Literal["alloy", "ash", "ballad", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer", "verse"], - None, - ] = None + voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"], None] = None """The voice the model uses to respond. Voice cannot be changed during the session once the model has responded with audio at least once. Current voice options are `alloy`, `ash`, `ballad`, - `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, `shimmer`, and `verse`. + `coral`, `echo`, `sage`, `shimmer`, and `verse`. """ diff --git a/src/openai/types/beta/realtime/session_update_event_param.py b/src/openai/types/beta/realtime/session_update_event_param.py index 2dfa2c26f3..3063449bfd 100644 --- a/src/openai/types/beta/realtime/session_update_event_param.py +++ b/src/openai/types/beta/realtime/session_update_event_param.py @@ -288,14 +288,12 @@ class Session(TypedDict, total=False): natural conversations, but may have a higher latency. """ - voice: Union[ - str, Literal["alloy", "ash", "ballad", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer", "verse"] - ] + voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"]] """The voice the model uses to respond. Voice cannot be changed during the session once the model has responded with audio at least once. Current voice options are `alloy`, `ash`, `ballad`, - `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, `shimmer`, and `verse`. + `coral`, `echo`, `sage`, `shimmer`, and `verse`. """ diff --git a/src/openai/types/chat/chat_completion.py b/src/openai/types/chat/chat_completion.py index afc23e3f3d..42463f7ec8 100644 --- a/src/openai/types/chat/chat_completion.py +++ b/src/openai/types/chat/chat_completion.py @@ -65,7 +65,7 @@ class ChatCompletion(BaseModel): - If set to 'auto', then the request will be processed with the service tier configured in the Project settings. Unless otherwise configured, the Project will use 'default'. - - If set to 'default', then the requset will be processed with the standard + - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or 'priority', then the request will be processed with the corresponding service diff --git a/src/openai/types/chat/chat_completion_audio_param.py b/src/openai/types/chat/chat_completion_audio_param.py index 25caada177..dc68159c1e 100644 --- a/src/openai/types/chat/chat_completion_audio_param.py +++ b/src/openai/types/chat/chat_completion_audio_param.py @@ -15,11 +15,7 @@ class ChatCompletionAudioParam(TypedDict, total=False): Must be one of `wav`, `mp3`, `flac`, `opus`, or `pcm16`. """ - voice: Required[ - Union[ - str, Literal["alloy", "ash", "ballad", "coral", "echo", "fable", "onyx", "nova", "sage", "shimmer", "verse"] - ] - ] + voice: Required[Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"]]] """The voice the model uses to respond. Supported voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, `fable`, `nova`, diff --git a/src/openai/types/chat/chat_completion_chunk.py b/src/openai/types/chat/chat_completion_chunk.py index da6e315830..082bb6cc19 100644 --- a/src/openai/types/chat/chat_completion_chunk.py +++ b/src/openai/types/chat/chat_completion_chunk.py @@ -134,7 +134,7 @@ class ChatCompletionChunk(BaseModel): - If set to 'auto', then the request will be processed with the service tier configured in the Project settings. Unless otherwise configured, the Project will use 'default'. - - If set to 'default', then the requset will be processed with the standard + - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or 'priority', then the request will be processed with the corresponding service diff --git a/src/openai/types/chat/completion_create_params.py b/src/openai/types/chat/completion_create_params.py index 44ea853041..191793c18f 100644 --- a/src/openai/types/chat/completion_create_params.py +++ b/src/openai/types/chat/completion_create_params.py @@ -214,7 +214,7 @@ class CompletionCreateParamsBase(TypedDict, total=False): - If set to 'auto', then the request will be processed with the service tier configured in the Project settings. Unless otherwise configured, the Project will use 'default'. - - If set to 'default', then the requset will be processed with the standard + - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or 'priority', then the request will be processed with the corresponding service diff --git a/src/openai/types/image_edit_params.py b/src/openai/types/image_edit_params.py index d839e2fcbe..c0481012e4 100644 --- a/src/openai/types/image_edit_params.py +++ b/src/openai/types/image_edit_params.py @@ -85,6 +85,9 @@ class ImageEditParamsBase(TypedDict, total=False): This parameter is used for streaming responses that return partial images. Value must be between 0 and 3. When set to 0, the response will be a single image sent in one streaming event. + + Note that the final image may be sent before the full number of partial images + are generated if the full image is generated more quickly. """ quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] diff --git a/src/openai/types/image_generate_params.py b/src/openai/types/image_generate_params.py index bd9f34b28e..e9e9292cc2 100644 --- a/src/openai/types/image_generate_params.py +++ b/src/openai/types/image_generate_params.py @@ -68,6 +68,9 @@ class ImageGenerateParamsBase(TypedDict, total=False): This parameter is used for streaming responses that return partial images. Value must be between 0 and 3. When set to 0, the response will be a single image sent in one streaming event. + + Note that the final image may be sent before the full number of partial images + are generated if the full image is generated more quickly. """ quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] diff --git a/src/openai/types/images_response.py b/src/openai/types/images_response.py index 2a8ca728ab..89cc71df24 100644 --- a/src/openai/types/images_response.py +++ b/src/openai/types/images_response.py @@ -25,7 +25,7 @@ class Usage(BaseModel): """The input tokens detailed information for the image generation.""" output_tokens: int - """The number of image tokens in the output image.""" + """The number of output tokens generated by the model.""" total_tokens: int """The total number of tokens (images and text) used for the image generation.""" diff --git a/src/openai/types/responses/__init__.py b/src/openai/types/responses/__init__.py index 4316e47730..b563035e78 100644 --- a/src/openai/types/responses/__init__.py +++ b/src/openai/types/responses/__init__.py @@ -81,11 +81,9 @@ from .response_refusal_delta_event import ResponseRefusalDeltaEvent as ResponseRefusalDeltaEvent from .response_output_message_param import ResponseOutputMessageParam as ResponseOutputMessageParam from .response_output_refusal_param import ResponseOutputRefusalParam as ResponseOutputRefusalParam -from .response_reasoning_done_event import ResponseReasoningDoneEvent as ResponseReasoningDoneEvent from .response_reasoning_item_param import ResponseReasoningItemParam as ResponseReasoningItemParam from .response_file_search_tool_call import ResponseFileSearchToolCall as ResponseFileSearchToolCall from .response_mcp_call_failed_event import ResponseMcpCallFailedEvent as ResponseMcpCallFailedEvent -from .response_reasoning_delta_event import ResponseReasoningDeltaEvent as ResponseReasoningDeltaEvent from .response_output_item_done_event import ResponseOutputItemDoneEvent as ResponseOutputItemDoneEvent from .response_content_part_done_event import ResponseContentPartDoneEvent as ResponseContentPartDoneEvent from .response_function_tool_call_item import ResponseFunctionToolCallItem as ResponseFunctionToolCallItem diff --git a/src/openai/types/responses/response.py b/src/openai/types/responses/response.py index db85d87f4e..2af85d03fb 100644 --- a/src/openai/types/responses/response.py +++ b/src/openai/types/responses/response.py @@ -176,7 +176,7 @@ class Response(BaseModel): - If set to 'auto', then the request will be processed with the service tier configured in the Project settings. Unless otherwise configured, the Project will use 'default'. - - If set to 'default', then the requset will be processed with the standard + - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or 'priority', then the request will be processed with the corresponding service diff --git a/src/openai/types/responses/response_code_interpreter_tool_call.py b/src/openai/types/responses/response_code_interpreter_tool_call.py index 7e4dc9f984..257937118b 100644 --- a/src/openai/types/responses/response_code_interpreter_tool_call.py +++ b/src/openai/types/responses/response_code_interpreter_tool_call.py @@ -45,7 +45,11 @@ class ResponseCodeInterpreterToolCall(BaseModel): """ status: Literal["in_progress", "completed", "incomplete", "interpreting", "failed"] - """The status of the code interpreter tool call.""" + """The status of the code interpreter tool call. + + Valid values are `in_progress`, `completed`, `incomplete`, `interpreting`, and + `failed`. + """ type: Literal["code_interpreter_call"] """The type of the code interpreter tool call. Always `code_interpreter_call`.""" diff --git a/src/openai/types/responses/response_code_interpreter_tool_call_param.py b/src/openai/types/responses/response_code_interpreter_tool_call_param.py index 69e01f99ed..435091001f 100644 --- a/src/openai/types/responses/response_code_interpreter_tool_call_param.py +++ b/src/openai/types/responses/response_code_interpreter_tool_call_param.py @@ -44,7 +44,11 @@ class ResponseCodeInterpreterToolCallParam(TypedDict, total=False): """ status: Required[Literal["in_progress", "completed", "incomplete", "interpreting", "failed"]] - """The status of the code interpreter tool call.""" + """The status of the code interpreter tool call. + + Valid values are `in_progress`, `completed`, `incomplete`, `interpreting`, and + `failed`. + """ type: Required[Literal["code_interpreter_call"]] """The type of the code interpreter tool call. Always `code_interpreter_call`.""" diff --git a/src/openai/types/responses/response_create_params.py b/src/openai/types/responses/response_create_params.py index 0187e1fda8..08feefd081 100644 --- a/src/openai/types/responses/response_create_params.py +++ b/src/openai/types/responses/response_create_params.py @@ -136,7 +136,7 @@ class ResponseCreateParamsBase(TypedDict, total=False): - If set to 'auto', then the request will be processed with the service tier configured in the Project settings. Unless otherwise configured, the Project will use 'default'. - - If set to 'default', then the requset will be processed with the standard + - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or 'priority', then the request will be processed with the corresponding service diff --git a/src/openai/types/responses/response_mcp_call_arguments_delta_event.py b/src/openai/types/responses/response_mcp_call_arguments_delta_event.py index 8481506dc3..54eff38373 100644 --- a/src/openai/types/responses/response_mcp_call_arguments_delta_event.py +++ b/src/openai/types/responses/response_mcp_call_arguments_delta_event.py @@ -8,8 +8,11 @@ class ResponseMcpCallArgumentsDeltaEvent(BaseModel): - delta: object - """The partial update to the arguments for the MCP tool call.""" + delta: str + """ + A JSON string containing the partial update to the arguments for the MCP tool + call. + """ item_id: str """The unique identifier of the MCP tool call item being processed.""" diff --git a/src/openai/types/responses/response_mcp_call_arguments_done_event.py b/src/openai/types/responses/response_mcp_call_arguments_done_event.py index 4be09d4862..59ce9bc944 100644 --- a/src/openai/types/responses/response_mcp_call_arguments_done_event.py +++ b/src/openai/types/responses/response_mcp_call_arguments_done_event.py @@ -8,8 +8,8 @@ class ResponseMcpCallArgumentsDoneEvent(BaseModel): - arguments: object - """The finalized arguments for the MCP tool call.""" + arguments: str + """A JSON string containing the finalized arguments for the MCP tool call.""" item_id: str """The unique identifier of the MCP tool call item being processed.""" diff --git a/src/openai/types/responses/response_mcp_call_completed_event.py b/src/openai/types/responses/response_mcp_call_completed_event.py index 009fbc3c60..2fee5dff81 100644 --- a/src/openai/types/responses/response_mcp_call_completed_event.py +++ b/src/openai/types/responses/response_mcp_call_completed_event.py @@ -8,6 +8,12 @@ class ResponseMcpCallCompletedEvent(BaseModel): + item_id: str + """The ID of the MCP tool call item that completed.""" + + output_index: int + """The index of the output item that completed.""" + sequence_number: int """The sequence number of this event.""" diff --git a/src/openai/types/responses/response_mcp_call_failed_event.py b/src/openai/types/responses/response_mcp_call_failed_event.py index e6edc6ded5..ca41ab7159 100644 --- a/src/openai/types/responses/response_mcp_call_failed_event.py +++ b/src/openai/types/responses/response_mcp_call_failed_event.py @@ -8,6 +8,12 @@ class ResponseMcpCallFailedEvent(BaseModel): + item_id: str + """The ID of the MCP tool call item that failed.""" + + output_index: int + """The index of the output item that failed.""" + sequence_number: int """The sequence number of this event.""" diff --git a/src/openai/types/responses/response_mcp_list_tools_completed_event.py b/src/openai/types/responses/response_mcp_list_tools_completed_event.py index 6290c3cf9f..c60ad88ee5 100644 --- a/src/openai/types/responses/response_mcp_list_tools_completed_event.py +++ b/src/openai/types/responses/response_mcp_list_tools_completed_event.py @@ -8,6 +8,12 @@ class ResponseMcpListToolsCompletedEvent(BaseModel): + item_id: str + """The ID of the MCP tool call item that produced this output.""" + + output_index: int + """The index of the output item that was processed.""" + sequence_number: int """The sequence number of this event.""" diff --git a/src/openai/types/responses/response_mcp_list_tools_failed_event.py b/src/openai/types/responses/response_mcp_list_tools_failed_event.py index 1f6e325b36..0c966c447a 100644 --- a/src/openai/types/responses/response_mcp_list_tools_failed_event.py +++ b/src/openai/types/responses/response_mcp_list_tools_failed_event.py @@ -8,6 +8,12 @@ class ResponseMcpListToolsFailedEvent(BaseModel): + item_id: str + """The ID of the MCP tool call item that failed.""" + + output_index: int + """The index of the output item that failed.""" + sequence_number: int """The sequence number of this event.""" diff --git a/src/openai/types/responses/response_mcp_list_tools_in_progress_event.py b/src/openai/types/responses/response_mcp_list_tools_in_progress_event.py index 236e5fe6e7..f451db1ed5 100644 --- a/src/openai/types/responses/response_mcp_list_tools_in_progress_event.py +++ b/src/openai/types/responses/response_mcp_list_tools_in_progress_event.py @@ -8,6 +8,12 @@ class ResponseMcpListToolsInProgressEvent(BaseModel): + item_id: str + """The ID of the MCP tool call item that is being processed.""" + + output_index: int + """The index of the output item that is being processed.""" + sequence_number: int """The sequence number of this event.""" diff --git a/src/openai/types/responses/response_reasoning_delta_event.py b/src/openai/types/responses/response_reasoning_delta_event.py deleted file mode 100644 index f37d3d370c..0000000000 --- a/src/openai/types/responses/response_reasoning_delta_event.py +++ /dev/null @@ -1,27 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseReasoningDeltaEvent"] - - -class ResponseReasoningDeltaEvent(BaseModel): - content_index: int - """The index of the reasoning content part within the output item.""" - - delta: object - """The partial update to the reasoning content.""" - - item_id: str - """The unique identifier of the item for which reasoning is being updated.""" - - output_index: int - """The index of the output item in the response's output array.""" - - sequence_number: int - """The sequence number of this event.""" - - type: Literal["response.reasoning.delta"] - """The type of the event. Always 'response.reasoning.delta'.""" diff --git a/src/openai/types/responses/response_reasoning_done_event.py b/src/openai/types/responses/response_reasoning_done_event.py deleted file mode 100644 index 9f8b127d7e..0000000000 --- a/src/openai/types/responses/response_reasoning_done_event.py +++ /dev/null @@ -1,27 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseReasoningDoneEvent"] - - -class ResponseReasoningDoneEvent(BaseModel): - content_index: int - """The index of the reasoning content part within the output item.""" - - item_id: str - """The unique identifier of the item for which reasoning is finalized.""" - - output_index: int - """The index of the output item in the response's output array.""" - - sequence_number: int - """The sequence number of this event.""" - - text: str - """The finalized reasoning text.""" - - type: Literal["response.reasoning.done"] - """The type of the event. Always 'response.reasoning.done'.""" diff --git a/src/openai/types/responses/response_stream_event.py b/src/openai/types/responses/response_stream_event.py index 24a83f1aa2..98e1d6c34d 100644 --- a/src/openai/types/responses/response_stream_event.py +++ b/src/openai/types/responses/response_stream_event.py @@ -17,9 +17,7 @@ from .response_in_progress_event import ResponseInProgressEvent from .response_refusal_done_event import ResponseRefusalDoneEvent from .response_refusal_delta_event import ResponseRefusalDeltaEvent -from .response_reasoning_done_event import ResponseReasoningDoneEvent from .response_mcp_call_failed_event import ResponseMcpCallFailedEvent -from .response_reasoning_delta_event import ResponseReasoningDeltaEvent from .response_output_item_done_event import ResponseOutputItemDoneEvent from .response_content_part_done_event import ResponseContentPartDoneEvent from .response_output_item_added_event import ResponseOutputItemAddedEvent @@ -111,8 +109,6 @@ ResponseMcpListToolsInProgressEvent, ResponseOutputTextAnnotationAddedEvent, ResponseQueuedEvent, - ResponseReasoningDeltaEvent, - ResponseReasoningDoneEvent, ResponseReasoningSummaryDeltaEvent, ResponseReasoningSummaryDoneEvent, ], diff --git a/src/openai/types/responses/response_text_delta_event.py b/src/openai/types/responses/response_text_delta_event.py index 7e4aec7024..b5379b7ac3 100644 --- a/src/openai/types/responses/response_text_delta_event.py +++ b/src/openai/types/responses/response_text_delta_event.py @@ -1,10 +1,30 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from typing import List, Optional from typing_extensions import Literal from ..._models import BaseModel -__all__ = ["ResponseTextDeltaEvent"] +__all__ = ["ResponseTextDeltaEvent", "Logprob", "LogprobTopLogprob"] + + +class LogprobTopLogprob(BaseModel): + token: Optional[str] = None + """A possible text token.""" + + logprob: Optional[float] = None + """The log probability of this token.""" + + +class Logprob(BaseModel): + token: str + """A possible text token.""" + + logprob: float + """The log probability of this token.""" + + top_logprobs: Optional[List[LogprobTopLogprob]] = None + """The log probability of the top 20 most likely tokens.""" class ResponseTextDeltaEvent(BaseModel): @@ -17,6 +37,9 @@ class ResponseTextDeltaEvent(BaseModel): item_id: str """The ID of the output item that the text delta was added to.""" + logprobs: List[Logprob] + """The log probabilities of the tokens in the delta.""" + output_index: int """The index of the output item that the text delta was added to.""" diff --git a/src/openai/types/responses/response_text_done_event.py b/src/openai/types/responses/response_text_done_event.py index 0d5ed4dd19..d9776a1844 100644 --- a/src/openai/types/responses/response_text_done_event.py +++ b/src/openai/types/responses/response_text_done_event.py @@ -1,10 +1,30 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from typing import List, Optional from typing_extensions import Literal from ..._models import BaseModel -__all__ = ["ResponseTextDoneEvent"] +__all__ = ["ResponseTextDoneEvent", "Logprob", "LogprobTopLogprob"] + + +class LogprobTopLogprob(BaseModel): + token: Optional[str] = None + """A possible text token.""" + + logprob: Optional[float] = None + """The log probability of this token.""" + + +class Logprob(BaseModel): + token: str + """A possible text token.""" + + logprob: float + """The log probability of this token.""" + + top_logprobs: Optional[List[LogprobTopLogprob]] = None + """The log probability of the top 20 most likely tokens.""" class ResponseTextDoneEvent(BaseModel): @@ -14,6 +34,9 @@ class ResponseTextDoneEvent(BaseModel): item_id: str """The ID of the output item that the text content is finalized.""" + logprobs: List[Logprob] + """The log probabilities of the tokens in the delta.""" + output_index: int """The index of the output item that the text content is finalized.""" diff --git a/src/openai/types/shared/function_definition.py b/src/openai/types/shared/function_definition.py index 06baa23170..33ebb9ad3e 100644 --- a/src/openai/types/shared/function_definition.py +++ b/src/openai/types/shared/function_definition.py @@ -39,5 +39,5 @@ class FunctionDefinition(BaseModel): If set to true, the model will follow the exact schema defined in the `parameters` field. Only a subset of JSON Schema is supported when `strict` is `true`. Learn more about Structured Outputs in the - [function calling guide](docs/guides/function-calling). + [function calling guide](https://platform.openai.com/docs/guides/function-calling). """ diff --git a/src/openai/types/shared_params/function_definition.py b/src/openai/types/shared_params/function_definition.py index d45ec13f1e..b3fdaf86ff 100644 --- a/src/openai/types/shared_params/function_definition.py +++ b/src/openai/types/shared_params/function_definition.py @@ -41,5 +41,5 @@ class FunctionDefinition(TypedDict, total=False): If set to true, the model will follow the exact schema defined in the `parameters` field. Only a subset of JSON Schema is supported when `strict` is `true`. Learn more about Structured Outputs in the - [function calling guide](docs/guides/function-calling). + [function calling guide](https://platform.openai.com/docs/guides/function-calling). """ From 48df6b4c30d7e4b1f8a60cf3d34bce8dab06a30b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 22 Jul 2025 12:04:02 +0000 Subject: [PATCH 408/769] fix(parsing): parse extra field types --- src/openai/_models.py | 25 +++++++++++++++++++++++-- tests/test_models.py | 29 ++++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/src/openai/_models.py b/src/openai/_models.py index dee5551948..d84d51d913 100644 --- a/src/openai/_models.py +++ b/src/openai/_models.py @@ -233,14 +233,18 @@ def construct( # pyright: ignore[reportIncompatibleMethodOverride] else: fields_values[name] = field_get_default(field) + extra_field_type = _get_extra_fields_type(__cls) + _extra = {} for key, value in values.items(): if key not in model_fields: + parsed = construct_type(value=value, type_=extra_field_type) if extra_field_type is not None else value + if PYDANTIC_V2: - _extra[key] = value + _extra[key] = parsed else: _fields_set.add(key) - fields_values[key] = value + fields_values[key] = parsed object.__setattr__(m, "__dict__", fields_values) @@ -395,6 +399,23 @@ def _construct_field(value: object, field: FieldInfo, key: str) -> object: return construct_type(value=value, type_=type_, metadata=getattr(field, "metadata", None)) +def _get_extra_fields_type(cls: type[pydantic.BaseModel]) -> type | None: + if not PYDANTIC_V2: + # TODO + return None + + schema = cls.__pydantic_core_schema__ + if schema["type"] == "model": + fields = schema["schema"] + if fields["type"] == "model-fields": + extras = fields.get("extras_schema") + if extras and "cls" in extras: + # mypy can't narrow the type + return extras["cls"] # type: ignore[no-any-return] + + return None + + def is_basemodel(type_: type) -> bool: """Returns whether or not the given type is either a `BaseModel` or a union of `BaseModel`""" if is_union(type_): diff --git a/tests/test_models.py b/tests/test_models.py index 7262f45006..54a3a32048 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -1,5 +1,5 @@ import json -from typing import Any, Dict, List, Union, Optional, cast +from typing import TYPE_CHECKING, Any, Dict, List, Union, Optional, cast from datetime import datetime, timezone from typing_extensions import Literal, Annotated, TypeAliasType @@ -934,3 +934,30 @@ class Type2(BaseModel): ) assert isinstance(model, Type1) assert isinstance(model.value, InnerType2) + + +@pytest.mark.skipif(not PYDANTIC_V2, reason="this is only supported in pydantic v2 for now") +def test_extra_properties() -> None: + class Item(BaseModel): + prop: int + + class Model(BaseModel): + __pydantic_extra__: Dict[str, Item] = Field(init=False) # pyright: ignore[reportIncompatibleVariableOverride] + + other: str + + if TYPE_CHECKING: + + def __getattr__(self, attr: str) -> Item: ... + + model = construct_type( + type_=Model, + value={ + "a": {"prop": 1}, + "other": "foo", + }, + ) + assert isinstance(model, Model) + assert model.a.prop == 1 + assert isinstance(model.a, Item) + assert model.other == "foo" From e6c6757553bbdb777c31d0daf5916fb9e2b47ff8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 22 Jul 2025 12:04:35 +0000 Subject: [PATCH 409/769] release: 1.97.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 14 ++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 7b33636f46..9cdfd7b049 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.97.0" + ".": "1.97.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e603f06be..0c8d06cbb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## 1.97.1 (2025-07-22) + +Full Changelog: [v1.97.0...v1.97.1](https://github.com/openai/openai-python/compare/v1.97.0...v1.97.1) + +### Bug Fixes + +* **parsing:** ignore empty metadata ([58c359f](https://github.com/openai/openai-python/commit/58c359ff67fd6103268e4405600fd58844b6f27b)) +* **parsing:** parse extra field types ([d524b7e](https://github.com/openai/openai-python/commit/d524b7e201418ccc9b5c2206da06d1be011808e5)) + + +### Chores + +* **api:** event shapes more accurate ([f3a9a92](https://github.com/openai/openai-python/commit/f3a9a9229280ecb7e0b2779dd44290df6d9824ef)) + ## 1.97.0 (2025-07-16) Full Changelog: [v1.96.1...v1.97.0](https://github.com/openai/openai-python/compare/v1.96.1...v1.97.0) diff --git a/pyproject.toml b/pyproject.toml index 533379d52a..af1366b34e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.97.0" +version = "1.97.1" 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 8e5ed5fa86..9073c643cc 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.97.0" # x-release-please-version +__version__ = "1.97.1" # x-release-please-version From 48188cc8d5af8c8c4359f84848ea9e436739819f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 30 Jul 2025 07:40:14 -0400 Subject: [PATCH 410/769] release: 1.97.2 (#2494) * codegen metadata * fix(parsing): ignore empty metadata * chore(internal): refactor stream event processing to be more future proof * fixup! * fixup! * fixup! * update comment * chore(project): add settings file for vscode * flip logic around * release: 1.97.2 --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> Co-authored-by: David Meadows --- .gitignore | 1 - .release-please-manifest.json | 2 +- .vscode/settings.json | 3 +++ CHANGELOG.md | 9 +++++++++ pyproject.toml | 2 +- src/openai/_streaming.py | 33 ++++++++++++++------------------- src/openai/_version.py | 2 +- 7 files changed, 29 insertions(+), 23 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.gitignore b/.gitignore index 70815df7f6..55c6ca861f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ .prism.log -.vscode _dev __pycache__ diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 9cdfd7b049..1137af1259 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.97.1" + ".": "1.97.2" } \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..5b01030785 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.analysis.importFormat": "relative", +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c8d06cbb6..945e224cf9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 1.97.2 (2025-07-30) + +Full Changelog: [v1.97.1...v1.97.2](https://github.com/openai/openai-python/compare/v1.97.1...v1.97.2) + +### Chores + +* **client:** refactor streaming slightly to better future proof it ([71c0c74](https://github.com/openai/openai-python/commit/71c0c747132221b798e419bc5a37baf67173d34e)) +* **project:** add settings file for vscode ([29c22c9](https://github.com/openai/openai-python/commit/29c22c90fd229983355089f95d0bba9de15efedb)) + ## 1.97.1 (2025-07-22) Full Changelog: [v1.97.0...v1.97.1](https://github.com/openai/openai-python/compare/v1.97.0...v1.97.1) diff --git a/pyproject.toml b/pyproject.toml index af1366b34e..5b59053d02 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.97.1" +version = "1.97.2" description = "The official Python library for the openai API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/openai/_streaming.py b/src/openai/_streaming.py index fa0a30e183..f586de74ff 100644 --- a/src/openai/_streaming.py +++ b/src/openai/_streaming.py @@ -59,14 +59,11 @@ def __stream__(self) -> Iterator[_T]: if sse.data.startswith("[DONE]"): break - if sse.event is None or ( - sse.event.startswith("response.") or - sse.event.startswith("transcript.") or - sse.event.startswith("image_edit.") or - sse.event.startswith("image_generation.") - ): + # we have to special case the Assistants `thread.` events since we won't have an "event" key in the data + if sse.event and sse.event.startswith("thread."): data = sse.json() - if is_mapping(data) and data.get("error"): + + if sse.event == "error" and is_mapping(data) and data.get("error"): message = None error = data.get("error") if is_mapping(error): @@ -80,12 +77,10 @@ def __stream__(self) -> Iterator[_T]: body=data["error"], ) - yield process_data(data=data, cast_to=cast_to, response=response) - + yield process_data(data={"data": data, "event": sse.event}, cast_to=cast_to, response=response) else: data = sse.json() - - if sse.event == "error" and is_mapping(data) and data.get("error"): + if is_mapping(data) and data.get("error"): message = None error = data.get("error") if is_mapping(error): @@ -99,7 +94,7 @@ def __stream__(self) -> Iterator[_T]: body=data["error"], ) - yield process_data(data={"data": data, "event": sse.event}, cast_to=cast_to, response=response) + yield process_data(data=data, cast_to=cast_to, response=response) # Ensure the entire stream is consumed for _sse in iterator: @@ -166,9 +161,11 @@ async def __stream__(self) -> AsyncIterator[_T]: if sse.data.startswith("[DONE]"): break - if sse.event is None or sse.event.startswith("response.") or sse.event.startswith("transcript."): + # we have to special case the Assistants `thread.` events since we won't have an "event" key in the data + if sse.event and sse.event.startswith("thread."): data = sse.json() - if is_mapping(data) and data.get("error"): + + if sse.event == "error" and is_mapping(data) and data.get("error"): message = None error = data.get("error") if is_mapping(error): @@ -182,12 +179,10 @@ async def __stream__(self) -> AsyncIterator[_T]: body=data["error"], ) - yield process_data(data=data, cast_to=cast_to, response=response) - + yield process_data(data={"data": data, "event": sse.event}, cast_to=cast_to, response=response) else: data = sse.json() - - if sse.event == "error" and is_mapping(data) and data.get("error"): + if is_mapping(data) and data.get("error"): message = None error = data.get("error") if is_mapping(error): @@ -201,7 +196,7 @@ async def __stream__(self) -> AsyncIterator[_T]: body=data["error"], ) - yield process_data(data={"data": data, "event": sse.event}, cast_to=cast_to, response=response) + yield process_data(data=data, cast_to=cast_to, response=response) # Ensure the entire stream is consumed async for _sse in iterator: diff --git a/src/openai/_version.py b/src/openai/_version.py index 9073c643cc..59fb46ac23 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.97.1" # x-release-please-version +__version__ = "1.97.2" # x-release-please-version From a3315d9fcc17d7583603476f088929fb2b9e71ca Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 30 Jul 2025 08:47:13 -0400 Subject: [PATCH 411/769] release: 1.98.0 (#2503) * feat(api): manual updates * release: 1.98.0 --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- .stats.yml | 6 +- CHANGELOG.md | 8 ++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- .../resources/chat/completions/completions.py | 128 +++++++++++++++--- src/openai/resources/responses/responses.py | 128 +++++++++++++++--- src/openai/types/chat/__init__.py | 2 + .../chat_completion_content_part_image.py | 27 ++++ .../chat/chat_completion_content_part_text.py | 15 ++ .../chat/chat_completion_store_message.py | 15 +- .../types/chat/completion_create_params.py | 25 +++- src/openai/types/responses/response.py | 25 +++- .../types/responses/response_create_params.py | 25 +++- tests/api_resources/chat/test_completions.py | 8 ++ tests/api_resources/test_responses.py | 8 ++ 16 files changed, 371 insertions(+), 55 deletions(-) create mode 100644 src/openai/types/chat/chat_completion_content_part_image.py create mode 100644 src/openai/types/chat/chat_completion_content_part_text.py diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 1137af1259..d12300ea76 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.97.2" + ".": "1.98.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 2dc4f680a9..e7fb0bdf9b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-b2a451656ca64d30d174391ebfd94806b4de3ab76dc55b92843cfb7f1a54ecb6.yml -openapi_spec_hash: 27d9691b400f28c17ef063a1374048b0 -config_hash: e822d0c9082c8b312264403949243179 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-721e6ccaa72205ee14c71f8163129920464fb814b95d3df9567a9476bbd9b7fb.yml +openapi_spec_hash: 2115413a21df8b5bf9e4552a74df4312 +config_hash: 9606bb315a193bfd8da0459040143242 diff --git a/CHANGELOG.md b/CHANGELOG.md index 945e224cf9..669d5a5792 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.98.0 (2025-07-30) + +Full Changelog: [v1.97.2...v1.98.0](https://github.com/openai/openai-python/compare/v1.97.2...v1.98.0) + +### Features + +* **api:** manual updates ([88a8036](https://github.com/openai/openai-python/commit/88a8036c5ea186f36c57029ef4501a0833596f56)) + ## 1.97.2 (2025-07-30) Full Changelog: [v1.97.1...v1.97.2](https://github.com/openai/openai-python/compare/v1.97.1...v1.97.2) diff --git a/pyproject.toml b/pyproject.toml index 5b59053d02..6765611fc2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.97.2" +version = "1.98.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 59fb46ac23..ca890665bc 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.97.2" # x-release-please-version +__version__ = "1.98.0" # x-release-please-version diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index 739aa662d4..c851851418 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -248,8 +248,10 @@ def create( parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, + prompt_cache_key: str | NotGiven = NOT_GIVEN, reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, + safety_identifier: str | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, @@ -388,6 +390,10 @@ def create( whether they appear in the text so far, increasing the model's likelihood to talk about new topics. + prompt_cache_key: Used by OpenAI to cache responses for similar requests to optimize your cache + hit rates. Replaces the `user` field. + [Learn more](https://platform.openai.com/docs/guides/prompt-caching). + reasoning_effort: **o-series models only** Constrains effort on reasoning for @@ -406,6 +412,12 @@ def create( ensures the message the model generates is valid JSON. Using `json_schema` is preferred for models that support it. + safety_identifier: A stable identifier used to help detect users of your application that may be + violating OpenAI's usage policies. The IDs should be a string that uniquely + identifies each user. We recommend hashing their username or email address, in + order to avoid sending us any identifying information. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). + seed: This feature is in Beta. If specified, our system will make a best effort to sample deterministically, such that repeated requests with the same `seed` and parameters should return the same result. Determinism is not guaranteed, and you @@ -481,9 +493,11 @@ def create( We generally recommend altering this or `temperature` but not both. - user: A stable identifier for your end-users. Used to boost cache hit rates by better - bucketing similar requests and to help OpenAI detect and prevent abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + user: This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use + `prompt_cache_key` instead to maintain caching optimizations. A stable + identifier for your end-users. Used to boost cache hit rates by better bucketing + similar requests and to help OpenAI detect and prevent abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). web_search_options: This tool searches the web for relevant results to use in a response. Learn more about the @@ -520,8 +534,10 @@ def create( parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, + prompt_cache_key: str | NotGiven = NOT_GIVEN, reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, + safety_identifier: str | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, @@ -668,6 +684,10 @@ def create( whether they appear in the text so far, increasing the model's likelihood to talk about new topics. + prompt_cache_key: Used by OpenAI to cache responses for similar requests to optimize your cache + hit rates. Replaces the `user` field. + [Learn more](https://platform.openai.com/docs/guides/prompt-caching). + reasoning_effort: **o-series models only** Constrains effort on reasoning for @@ -686,6 +706,12 @@ def create( ensures the message the model generates is valid JSON. Using `json_schema` is preferred for models that support it. + safety_identifier: A stable identifier used to help detect users of your application that may be + violating OpenAI's usage policies. The IDs should be a string that uniquely + identifies each user. We recommend hashing their username or email address, in + order to avoid sending us any identifying information. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). + seed: This feature is in Beta. If specified, our system will make a best effort to sample deterministically, such that repeated requests with the same `seed` and parameters should return the same result. Determinism is not guaranteed, and you @@ -752,9 +778,11 @@ def create( We generally recommend altering this or `temperature` but not both. - user: A stable identifier for your end-users. Used to boost cache hit rates by better - bucketing similar requests and to help OpenAI detect and prevent abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + user: This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use + `prompt_cache_key` instead to maintain caching optimizations. A stable + identifier for your end-users. Used to boost cache hit rates by better bucketing + similar requests and to help OpenAI detect and prevent abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). web_search_options: This tool searches the web for relevant results to use in a response. Learn more about the @@ -791,8 +819,10 @@ def create( parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, + prompt_cache_key: str | NotGiven = NOT_GIVEN, reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, + safety_identifier: str | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, @@ -939,6 +969,10 @@ def create( whether they appear in the text so far, increasing the model's likelihood to talk about new topics. + prompt_cache_key: Used by OpenAI to cache responses for similar requests to optimize your cache + hit rates. Replaces the `user` field. + [Learn more](https://platform.openai.com/docs/guides/prompt-caching). + reasoning_effort: **o-series models only** Constrains effort on reasoning for @@ -957,6 +991,12 @@ def create( ensures the message the model generates is valid JSON. Using `json_schema` is preferred for models that support it. + safety_identifier: A stable identifier used to help detect users of your application that may be + violating OpenAI's usage policies. The IDs should be a string that uniquely + identifies each user. We recommend hashing their username or email address, in + order to avoid sending us any identifying information. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). + seed: This feature is in Beta. If specified, our system will make a best effort to sample deterministically, such that repeated requests with the same `seed` and parameters should return the same result. Determinism is not guaranteed, and you @@ -1023,9 +1063,11 @@ def create( We generally recommend altering this or `temperature` but not both. - user: A stable identifier for your end-users. Used to boost cache hit rates by better - bucketing similar requests and to help OpenAI detect and prevent abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + user: This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use + `prompt_cache_key` instead to maintain caching optimizations. A stable + identifier for your end-users. Used to boost cache hit rates by better bucketing + similar requests and to help OpenAI detect and prevent abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). web_search_options: This tool searches the web for relevant results to use in a response. Learn more about the @@ -1061,8 +1103,10 @@ def create( parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, + prompt_cache_key: str | NotGiven = NOT_GIVEN, reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, + safety_identifier: str | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, @@ -1104,8 +1148,10 @@ def create( "parallel_tool_calls": parallel_tool_calls, "prediction": prediction, "presence_penalty": presence_penalty, + "prompt_cache_key": prompt_cache_key, "reasoning_effort": reasoning_effort, "response_format": response_format, + "safety_identifier": safety_identifier, "seed": seed, "service_tier": service_tier, "stop": stop, @@ -1615,8 +1661,10 @@ async def create( parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, + prompt_cache_key: str | NotGiven = NOT_GIVEN, reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, + safety_identifier: str | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, @@ -1755,6 +1803,10 @@ async def create( whether they appear in the text so far, increasing the model's likelihood to talk about new topics. + prompt_cache_key: Used by OpenAI to cache responses for similar requests to optimize your cache + hit rates. Replaces the `user` field. + [Learn more](https://platform.openai.com/docs/guides/prompt-caching). + reasoning_effort: **o-series models only** Constrains effort on reasoning for @@ -1773,6 +1825,12 @@ async def create( ensures the message the model generates is valid JSON. Using `json_schema` is preferred for models that support it. + safety_identifier: A stable identifier used to help detect users of your application that may be + violating OpenAI's usage policies. The IDs should be a string that uniquely + identifies each user. We recommend hashing their username or email address, in + order to avoid sending us any identifying information. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). + seed: This feature is in Beta. If specified, our system will make a best effort to sample deterministically, such that repeated requests with the same `seed` and parameters should return the same result. Determinism is not guaranteed, and you @@ -1848,9 +1906,11 @@ async def create( We generally recommend altering this or `temperature` but not both. - user: A stable identifier for your end-users. Used to boost cache hit rates by better - bucketing similar requests and to help OpenAI detect and prevent abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + user: This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use + `prompt_cache_key` instead to maintain caching optimizations. A stable + identifier for your end-users. Used to boost cache hit rates by better bucketing + similar requests and to help OpenAI detect and prevent abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). web_search_options: This tool searches the web for relevant results to use in a response. Learn more about the @@ -1887,8 +1947,10 @@ async def create( parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, + prompt_cache_key: str | NotGiven = NOT_GIVEN, reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, + safety_identifier: str | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, @@ -2035,6 +2097,10 @@ async def create( whether they appear in the text so far, increasing the model's likelihood to talk about new topics. + prompt_cache_key: Used by OpenAI to cache responses for similar requests to optimize your cache + hit rates. Replaces the `user` field. + [Learn more](https://platform.openai.com/docs/guides/prompt-caching). + reasoning_effort: **o-series models only** Constrains effort on reasoning for @@ -2053,6 +2119,12 @@ async def create( ensures the message the model generates is valid JSON. Using `json_schema` is preferred for models that support it. + safety_identifier: A stable identifier used to help detect users of your application that may be + violating OpenAI's usage policies. The IDs should be a string that uniquely + identifies each user. We recommend hashing their username or email address, in + order to avoid sending us any identifying information. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). + seed: This feature is in Beta. If specified, our system will make a best effort to sample deterministically, such that repeated requests with the same `seed` and parameters should return the same result. Determinism is not guaranteed, and you @@ -2119,9 +2191,11 @@ async def create( We generally recommend altering this or `temperature` but not both. - user: A stable identifier for your end-users. Used to boost cache hit rates by better - bucketing similar requests and to help OpenAI detect and prevent abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + user: This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use + `prompt_cache_key` instead to maintain caching optimizations. A stable + identifier for your end-users. Used to boost cache hit rates by better bucketing + similar requests and to help OpenAI detect and prevent abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). web_search_options: This tool searches the web for relevant results to use in a response. Learn more about the @@ -2158,8 +2232,10 @@ async def create( parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, + prompt_cache_key: str | NotGiven = NOT_GIVEN, reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, + safety_identifier: str | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, @@ -2306,6 +2382,10 @@ async def create( whether they appear in the text so far, increasing the model's likelihood to talk about new topics. + prompt_cache_key: Used by OpenAI to cache responses for similar requests to optimize your cache + hit rates. Replaces the `user` field. + [Learn more](https://platform.openai.com/docs/guides/prompt-caching). + reasoning_effort: **o-series models only** Constrains effort on reasoning for @@ -2324,6 +2404,12 @@ async def create( ensures the message the model generates is valid JSON. Using `json_schema` is preferred for models that support it. + safety_identifier: A stable identifier used to help detect users of your application that may be + violating OpenAI's usage policies. The IDs should be a string that uniquely + identifies each user. We recommend hashing their username or email address, in + order to avoid sending us any identifying information. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). + seed: This feature is in Beta. If specified, our system will make a best effort to sample deterministically, such that repeated requests with the same `seed` and parameters should return the same result. Determinism is not guaranteed, and you @@ -2390,9 +2476,11 @@ async def create( We generally recommend altering this or `temperature` but not both. - user: A stable identifier for your end-users. Used to boost cache hit rates by better - bucketing similar requests and to help OpenAI detect and prevent abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + user: This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use + `prompt_cache_key` instead to maintain caching optimizations. A stable + identifier for your end-users. Used to boost cache hit rates by better bucketing + similar requests and to help OpenAI detect and prevent abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). web_search_options: This tool searches the web for relevant results to use in a response. Learn more about the @@ -2428,8 +2516,10 @@ async def create( parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, + prompt_cache_key: str | NotGiven = NOT_GIVEN, reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, + safety_identifier: str | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, @@ -2471,8 +2561,10 @@ async def create( "parallel_tool_calls": parallel_tool_calls, "prediction": prediction, "presence_penalty": presence_penalty, + "prompt_cache_key": prompt_cache_key, "reasoning_effort": reasoning_effort, "response_format": response_format, + "safety_identifier": safety_identifier, "seed": seed, "service_tier": service_tier, "stop": stop, diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index fe99aa851d..8de46dbab8 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -87,7 +87,9 @@ def create( parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, + prompt_cache_key: str | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + safety_identifier: str | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, @@ -188,11 +190,21 @@ def create( prompt: Reference to a prompt template and its variables. [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). + prompt_cache_key: Used by OpenAI to cache responses for similar requests to optimize your cache + hit rates. Replaces the `user` field. + [Learn more](https://platform.openai.com/docs/guides/prompt-caching). + reasoning: **o-series models only** Configuration options for [reasoning models](https://platform.openai.com/docs/guides/reasoning). + safety_identifier: A stable identifier used to help detect users of your application that may be + violating OpenAI's usage policies. The IDs should be a string that uniquely + identifies each user. We recommend hashing their username or email address, in + order to avoid sending us any identifying information. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). + service_tier: Specifies the processing type used for serving the request. - If set to 'auto', then the request will be processed with the service tier @@ -267,9 +279,11 @@ def create( - `disabled` (default): If a model response will exceed the context window size for a model, the request will fail with a 400 error. - user: A stable identifier for your end-users. Used to boost cache hit rates by better - bucketing similar requests and to help OpenAI detect and prevent abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + user: This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use + `prompt_cache_key` instead to maintain caching optimizations. A stable + identifier for your end-users. Used to boost cache hit rates by better bucketing + similar requests and to help OpenAI detect and prevent abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). extra_headers: Send extra headers @@ -297,7 +311,9 @@ def create( parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, + prompt_cache_key: str | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + safety_identifier: str | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -404,11 +420,21 @@ def create( prompt: Reference to a prompt template and its variables. [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). + prompt_cache_key: Used by OpenAI to cache responses for similar requests to optimize your cache + hit rates. Replaces the `user` field. + [Learn more](https://platform.openai.com/docs/guides/prompt-caching). + reasoning: **o-series models only** Configuration options for [reasoning models](https://platform.openai.com/docs/guides/reasoning). + safety_identifier: A stable identifier used to help detect users of your application that may be + violating OpenAI's usage policies. The IDs should be a string that uniquely + identifies each user. We recommend hashing their username or email address, in + order to avoid sending us any identifying information. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). + service_tier: Specifies the processing type used for serving the request. - If set to 'auto', then the request will be processed with the service tier @@ -476,9 +502,11 @@ def create( - `disabled` (default): If a model response will exceed the context window size for a model, the request will fail with a 400 error. - user: A stable identifier for your end-users. Used to boost cache hit rates by better - bucketing similar requests and to help OpenAI detect and prevent abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + user: This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use + `prompt_cache_key` instead to maintain caching optimizations. A stable + identifier for your end-users. Used to boost cache hit rates by better bucketing + similar requests and to help OpenAI detect and prevent abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). extra_headers: Send extra headers @@ -506,7 +534,9 @@ def create( parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, + prompt_cache_key: str | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + safety_identifier: str | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -613,11 +643,21 @@ def create( prompt: Reference to a prompt template and its variables. [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). + prompt_cache_key: Used by OpenAI to cache responses for similar requests to optimize your cache + hit rates. Replaces the `user` field. + [Learn more](https://platform.openai.com/docs/guides/prompt-caching). + reasoning: **o-series models only** Configuration options for [reasoning models](https://platform.openai.com/docs/guides/reasoning). + safety_identifier: A stable identifier used to help detect users of your application that may be + violating OpenAI's usage policies. The IDs should be a string that uniquely + identifies each user. We recommend hashing their username or email address, in + order to avoid sending us any identifying information. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). + service_tier: Specifies the processing type used for serving the request. - If set to 'auto', then the request will be processed with the service tier @@ -685,9 +725,11 @@ def create( - `disabled` (default): If a model response will exceed the context window size for a model, the request will fail with a 400 error. - user: A stable identifier for your end-users. Used to boost cache hit rates by better - bucketing similar requests and to help OpenAI detect and prevent abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + user: This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use + `prompt_cache_key` instead to maintain caching optimizations. A stable + identifier for your end-users. Used to boost cache hit rates by better bucketing + similar requests and to help OpenAI detect and prevent abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). extra_headers: Send extra headers @@ -713,7 +755,9 @@ def create( parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, + prompt_cache_key: str | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + safety_identifier: str | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, @@ -747,7 +791,9 @@ def create( "parallel_tool_calls": parallel_tool_calls, "previous_response_id": previous_response_id, "prompt": prompt, + "prompt_cache_key": prompt_cache_key, "reasoning": reasoning, + "safety_identifier": safety_identifier, "service_tier": service_tier, "store": store, "stream": stream, @@ -1352,7 +1398,9 @@ async def create( parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, + prompt_cache_key: str | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + safety_identifier: str | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, @@ -1453,11 +1501,21 @@ async def create( prompt: Reference to a prompt template and its variables. [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). + prompt_cache_key: Used by OpenAI to cache responses for similar requests to optimize your cache + hit rates. Replaces the `user` field. + [Learn more](https://platform.openai.com/docs/guides/prompt-caching). + reasoning: **o-series models only** Configuration options for [reasoning models](https://platform.openai.com/docs/guides/reasoning). + safety_identifier: A stable identifier used to help detect users of your application that may be + violating OpenAI's usage policies. The IDs should be a string that uniquely + identifies each user. We recommend hashing their username or email address, in + order to avoid sending us any identifying information. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). + service_tier: Specifies the processing type used for serving the request. - If set to 'auto', then the request will be processed with the service tier @@ -1532,9 +1590,11 @@ async def create( - `disabled` (default): If a model response will exceed the context window size for a model, the request will fail with a 400 error. - user: A stable identifier for your end-users. Used to boost cache hit rates by better - bucketing similar requests and to help OpenAI detect and prevent abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + user: This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use + `prompt_cache_key` instead to maintain caching optimizations. A stable + identifier for your end-users. Used to boost cache hit rates by better bucketing + similar requests and to help OpenAI detect and prevent abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). extra_headers: Send extra headers @@ -1562,7 +1622,9 @@ async def create( parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, + prompt_cache_key: str | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + safety_identifier: str | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -1669,11 +1731,21 @@ async def create( prompt: Reference to a prompt template and its variables. [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). + prompt_cache_key: Used by OpenAI to cache responses for similar requests to optimize your cache + hit rates. Replaces the `user` field. + [Learn more](https://platform.openai.com/docs/guides/prompt-caching). + reasoning: **o-series models only** Configuration options for [reasoning models](https://platform.openai.com/docs/guides/reasoning). + safety_identifier: A stable identifier used to help detect users of your application that may be + violating OpenAI's usage policies. The IDs should be a string that uniquely + identifies each user. We recommend hashing their username or email address, in + order to avoid sending us any identifying information. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). + service_tier: Specifies the processing type used for serving the request. - If set to 'auto', then the request will be processed with the service tier @@ -1741,9 +1813,11 @@ async def create( - `disabled` (default): If a model response will exceed the context window size for a model, the request will fail with a 400 error. - user: A stable identifier for your end-users. Used to boost cache hit rates by better - bucketing similar requests and to help OpenAI detect and prevent abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + user: This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use + `prompt_cache_key` instead to maintain caching optimizations. A stable + identifier for your end-users. Used to boost cache hit rates by better bucketing + similar requests and to help OpenAI detect and prevent abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). extra_headers: Send extra headers @@ -1771,7 +1845,9 @@ async def create( parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, + prompt_cache_key: str | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + safety_identifier: str | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -1878,11 +1954,21 @@ async def create( prompt: Reference to a prompt template and its variables. [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). + prompt_cache_key: Used by OpenAI to cache responses for similar requests to optimize your cache + hit rates. Replaces the `user` field. + [Learn more](https://platform.openai.com/docs/guides/prompt-caching). + reasoning: **o-series models only** Configuration options for [reasoning models](https://platform.openai.com/docs/guides/reasoning). + safety_identifier: A stable identifier used to help detect users of your application that may be + violating OpenAI's usage policies. The IDs should be a string that uniquely + identifies each user. We recommend hashing their username or email address, in + order to avoid sending us any identifying information. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). + service_tier: Specifies the processing type used for serving the request. - If set to 'auto', then the request will be processed with the service tier @@ -1950,9 +2036,11 @@ async def create( - `disabled` (default): If a model response will exceed the context window size for a model, the request will fail with a 400 error. - user: A stable identifier for your end-users. Used to boost cache hit rates by better - bucketing similar requests and to help OpenAI detect and prevent abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + user: This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use + `prompt_cache_key` instead to maintain caching optimizations. A stable + identifier for your end-users. Used to boost cache hit rates by better bucketing + similar requests and to help OpenAI detect and prevent abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). extra_headers: Send extra headers @@ -1978,7 +2066,9 @@ async def create( parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, + prompt_cache_key: str | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + safety_identifier: str | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, @@ -2012,7 +2102,9 @@ async def create( "parallel_tool_calls": parallel_tool_calls, "previous_response_id": previous_response_id, "prompt": prompt, + "prompt_cache_key": prompt_cache_key, "reasoning": reasoning, + "safety_identifier": safety_identifier, "service_tier": service_tier, "store": store, "stream": stream, diff --git a/src/openai/types/chat/__init__.py b/src/openai/types/chat/__init__.py index 0945bcad11..dc26198567 100644 --- a/src/openai/types/chat/__init__.py +++ b/src/openai/types/chat/__init__.py @@ -28,7 +28,9 @@ from .chat_completion_store_message import ChatCompletionStoreMessage as ChatCompletionStoreMessage from .chat_completion_token_logprob import ChatCompletionTokenLogprob as ChatCompletionTokenLogprob from .chat_completion_reasoning_effort import ChatCompletionReasoningEffort as ChatCompletionReasoningEffort +from .chat_completion_content_part_text import ChatCompletionContentPartText as ChatCompletionContentPartText from .chat_completion_message_tool_call import ChatCompletionMessageToolCall as ChatCompletionMessageToolCall +from .chat_completion_content_part_image import ChatCompletionContentPartImage as ChatCompletionContentPartImage from .chat_completion_content_part_param import ChatCompletionContentPartParam as ChatCompletionContentPartParam from .chat_completion_tool_message_param import ChatCompletionToolMessageParam as ChatCompletionToolMessageParam from .chat_completion_user_message_param import ChatCompletionUserMessageParam as ChatCompletionUserMessageParam diff --git a/src/openai/types/chat/chat_completion_content_part_image.py b/src/openai/types/chat/chat_completion_content_part_image.py new file mode 100644 index 0000000000..c1386b9dd3 --- /dev/null +++ b/src/openai/types/chat/chat_completion_content_part_image.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ChatCompletionContentPartImage", "ImageURL"] + + +class ImageURL(BaseModel): + url: str + """Either a URL of the image or the base64 encoded image data.""" + + detail: Optional[Literal["auto", "low", "high"]] = None + """Specifies the detail level of the image. + + Learn more in the + [Vision guide](https://platform.openai.com/docs/guides/vision#low-or-high-fidelity-image-understanding). + """ + + +class ChatCompletionContentPartImage(BaseModel): + image_url: ImageURL + + type: Literal["image_url"] + """The type of the content part.""" diff --git a/src/openai/types/chat/chat_completion_content_part_text.py b/src/openai/types/chat/chat_completion_content_part_text.py new file mode 100644 index 0000000000..f09f35f708 --- /dev/null +++ b/src/openai/types/chat/chat_completion_content_part_text.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ChatCompletionContentPartText"] + + +class ChatCompletionContentPartText(BaseModel): + text: str + """The text content.""" + + type: Literal["text"] + """The type of the content part.""" diff --git a/src/openai/types/chat/chat_completion_store_message.py b/src/openai/types/chat/chat_completion_store_message.py index 8dc093f7b8..661342716b 100644 --- a/src/openai/types/chat/chat_completion_store_message.py +++ b/src/openai/types/chat/chat_completion_store_message.py @@ -1,10 +1,23 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from typing import List, Union, Optional +from typing_extensions import TypeAlias + from .chat_completion_message import ChatCompletionMessage +from .chat_completion_content_part_text import ChatCompletionContentPartText +from .chat_completion_content_part_image import ChatCompletionContentPartImage + +__all__ = ["ChatCompletionStoreMessage", "ChatCompletionStoreMessageContentPart"] -__all__ = ["ChatCompletionStoreMessage"] +ChatCompletionStoreMessageContentPart: TypeAlias = Union[ChatCompletionContentPartText, ChatCompletionContentPartImage] class ChatCompletionStoreMessage(ChatCompletionMessage): id: str """The identifier of the chat message.""" + + content_parts: Optional[List[ChatCompletionStoreMessageContentPart]] = None + """ + If a content parts array was provided, this is an array of `text` and + `image_url` parts. Otherwise, null. + """ diff --git a/src/openai/types/chat/completion_create_params.py b/src/openai/types/chat/completion_create_params.py index 191793c18f..20d7c187f8 100644 --- a/src/openai/types/chat/completion_create_params.py +++ b/src/openai/types/chat/completion_create_params.py @@ -177,6 +177,13 @@ class CompletionCreateParamsBase(TypedDict, total=False): far, increasing the model's likelihood to talk about new topics. """ + prompt_cache_key: str + """ + Used by OpenAI to cache responses for similar requests to optimize your cache + hit rates. Replaces the `user` field. + [Learn more](https://platform.openai.com/docs/guides/prompt-caching). + """ + reasoning_effort: Optional[ReasoningEffort] """**o-series models only** @@ -199,6 +206,15 @@ class CompletionCreateParamsBase(TypedDict, total=False): preferred for models that support it. """ + safety_identifier: str + """ + A stable identifier used to help detect users of your application that may be + violating OpenAI's usage policies. The IDs should be a string that uniquely + identifies each user. We recommend hashing their username or email address, in + order to avoid sending us any identifying information. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). + """ + seed: Optional[int] """ This feature is in Beta. If specified, our system will make a best effort to @@ -293,11 +309,12 @@ class CompletionCreateParamsBase(TypedDict, total=False): """ user: str - """A stable identifier for your end-users. + """This field is being replaced by `safety_identifier` and `prompt_cache_key`. - Used to boost cache hit rates by better bucketing similar requests and to help - OpenAI detect and prevent abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + Use `prompt_cache_key` instead to maintain caching optimizations. A stable + identifier for your end-users. Used to boost cache hit rates by better bucketing + similar requests and to help OpenAI detect and prevent abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). """ web_search_options: WebSearchOptions diff --git a/src/openai/types/responses/response.py b/src/openai/types/responses/response.py index 2af85d03fb..7db466dfe7 100644 --- a/src/openai/types/responses/response.py +++ b/src/openai/types/responses/response.py @@ -163,6 +163,13 @@ class Response(BaseModel): [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). """ + prompt_cache_key: Optional[str] = None + """ + Used by OpenAI to cache responses for similar requests to optimize your cache + hit rates. Replaces the `user` field. + [Learn more](https://platform.openai.com/docs/guides/prompt-caching). + """ + reasoning: Optional[Reasoning] = None """**o-series models only** @@ -170,6 +177,15 @@ class Response(BaseModel): [reasoning models](https://platform.openai.com/docs/guides/reasoning). """ + safety_identifier: Optional[str] = None + """ + A stable identifier used to help detect users of your application that may be + violating OpenAI's usage policies. The IDs should be a string that uniquely + identifies each user. We recommend hashing their username or email address, in + order to avoid sending us any identifying information. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). + """ + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] = None """Specifies the processing type used for serving the request. @@ -229,11 +245,12 @@ class Response(BaseModel): """ user: Optional[str] = None - """A stable identifier for your end-users. + """This field is being replaced by `safety_identifier` and `prompt_cache_key`. - Used to boost cache hit rates by better bucketing similar requests and to help - OpenAI detect and prevent abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + Use `prompt_cache_key` instead to maintain caching optimizations. A stable + identifier for your end-users. Used to boost cache hit rates by better bucketing + similar requests and to help OpenAI detect and prevent abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). """ @property diff --git a/src/openai/types/responses/response_create_params.py b/src/openai/types/responses/response_create_params.py index 08feefd081..4a78d7c028 100644 --- a/src/openai/types/responses/response_create_params.py +++ b/src/openai/types/responses/response_create_params.py @@ -123,6 +123,13 @@ class ResponseCreateParamsBase(TypedDict, total=False): [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). """ + prompt_cache_key: str + """ + Used by OpenAI to cache responses for similar requests to optimize your cache + hit rates. Replaces the `user` field. + [Learn more](https://platform.openai.com/docs/guides/prompt-caching). + """ + reasoning: Optional[Reasoning] """**o-series models only** @@ -130,6 +137,15 @@ class ResponseCreateParamsBase(TypedDict, total=False): [reasoning models](https://platform.openai.com/docs/guides/reasoning). """ + safety_identifier: str + """ + A stable identifier used to help detect users of your application that may be + violating OpenAI's usage policies. The IDs should be a string that uniquely + identifies each user. We recommend hashing their username or email address, in + order to avoid sending us any identifying information. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). + """ + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] """Specifies the processing type used for serving the request. @@ -221,11 +237,12 @@ class ResponseCreateParamsBase(TypedDict, total=False): """ user: str - """A stable identifier for your end-users. + """This field is being replaced by `safety_identifier` and `prompt_cache_key`. - Used to boost cache hit rates by better bucketing similar requests and to help - OpenAI detect and prevent abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + Use `prompt_cache_key` instead to maintain caching optimizations. A stable + identifier for your end-users. Used to boost cache hit rates by better bucketing + similar requests and to help OpenAI detect and prevent abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). """ diff --git a/tests/api_resources/chat/test_completions.py b/tests/api_resources/chat/test_completions.py index aa8f58f0e5..2758d980ed 100644 --- a/tests/api_resources/chat/test_completions.py +++ b/tests/api_resources/chat/test_completions.py @@ -72,8 +72,10 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: "type": "content", }, presence_penalty=-2, + prompt_cache_key="prompt-cache-key-1234", reasoning_effort="low", response_format={"type": "text"}, + safety_identifier="safety-identifier-1234", seed=-9007199254740991, service_tier="auto", stop="\n", @@ -199,8 +201,10 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: "type": "content", }, presence_penalty=-2, + prompt_cache_key="prompt-cache-key-1234", reasoning_effort="low", response_format={"type": "text"}, + safety_identifier="safety-identifier-1234", seed=-9007199254740991, service_tier="auto", stop="\n", @@ -501,8 +505,10 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn "type": "content", }, presence_penalty=-2, + prompt_cache_key="prompt-cache-key-1234", reasoning_effort="low", response_format={"type": "text"}, + safety_identifier="safety-identifier-1234", seed=-9007199254740991, service_tier="auto", stop="\n", @@ -628,8 +634,10 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn "type": "content", }, presence_penalty=-2, + prompt_cache_key="prompt-cache-key-1234", reasoning_effort="low", response_format={"type": "text"}, + safety_identifier="safety-identifier-1234", seed=-9007199254740991, service_tier="auto", stop="\n", diff --git a/tests/api_resources/test_responses.py b/tests/api_resources/test_responses.py index 158654ee70..63e47d8a69 100644 --- a/tests/api_resources/test_responses.py +++ b/tests/api_resources/test_responses.py @@ -43,11 +43,13 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: "variables": {"foo": "string"}, "version": "version", }, + prompt_cache_key="prompt-cache-key-1234", reasoning={ "effort": "low", "generate_summary": "auto", "summary": "auto", }, + safety_identifier="safety-identifier-1234", service_tier="auto", store=True, stream=False, @@ -116,11 +118,13 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: "variables": {"foo": "string"}, "version": "version", }, + prompt_cache_key="prompt-cache-key-1234", reasoning={ "effort": "low", "generate_summary": "auto", "summary": "auto", }, + safety_identifier="safety-identifier-1234", service_tier="auto", store=True, temperature=1, @@ -380,11 +384,13 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn "variables": {"foo": "string"}, "version": "version", }, + prompt_cache_key="prompt-cache-key-1234", reasoning={ "effort": "low", "generate_summary": "auto", "summary": "auto", }, + safety_identifier="safety-identifier-1234", service_tier="auto", store=True, stream=False, @@ -453,11 +459,13 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn "variables": {"foo": "string"}, "version": "version", }, + prompt_cache_key="prompt-cache-key-1234", reasoning={ "effort": "low", "generate_summary": "auto", "summary": "auto", }, + safety_identifier="safety-identifier-1234", service_tier="auto", store=True, temperature=1, From b204d41e0f1430b23207bbc2b809fa39e17b3564 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Wed, 30 Jul 2025 16:49:47 +0100 Subject: [PATCH 412/769] fix: add missing prompt_cache_key & prompt_cache_key params --- .../resources/chat/completions/completions.py | 16 ++++++++++++++++ src/openai/resources/responses/responses.py | 8 ++++++++ 2 files changed, 24 insertions(+) diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index c851851418..cd1cb2bd7f 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -101,7 +101,9 @@ def parse( parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, + prompt_cache_key: str | NotGiven = NOT_GIVEN, reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, + safety_identifier: str | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, @@ -197,8 +199,10 @@ def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseForma "parallel_tool_calls": parallel_tool_calls, "prediction": prediction, "presence_penalty": presence_penalty, + "prompt_cache_key": prompt_cache_key, "reasoning_effort": reasoning_effort, "response_format": _type_to_response_format(response_format), + "safety_identifier": safety_identifier, "seed": seed, "service_tier": service_tier, "stop": stop, @@ -1378,7 +1382,9 @@ def stream( parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, + prompt_cache_key: str | NotGiven = NOT_GIVEN, reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, + safety_identifier: str | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, @@ -1445,7 +1451,9 @@ def stream( parallel_tool_calls=parallel_tool_calls, prediction=prediction, presence_penalty=presence_penalty, + prompt_cache_key=prompt_cache_key, reasoning_effort=reasoning_effort, + safety_identifier=safety_identifier, seed=seed, service_tier=service_tier, store=store, @@ -1514,7 +1522,9 @@ async def parse( parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, + prompt_cache_key: str | NotGiven = NOT_GIVEN, reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, + safety_identifier: str | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, @@ -1610,8 +1620,10 @@ def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseForma "parallel_tool_calls": parallel_tool_calls, "prediction": prediction, "presence_penalty": presence_penalty, + "prompt_cache_key": prompt_cache_key, "reasoning_effort": reasoning_effort, "response_format": _type_to_response_format(response_format), + "safety_identifier": safety_identifier, "seed": seed, "service_tier": service_tier, "store": store, @@ -2791,7 +2803,9 @@ def stream( parallel_tool_calls: bool | NotGiven = NOT_GIVEN, prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, + prompt_cache_key: str | NotGiven = NOT_GIVEN, reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, + safety_identifier: str | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, @@ -2859,7 +2873,9 @@ def stream( parallel_tool_calls=parallel_tool_calls, prediction=prediction, presence_penalty=presence_penalty, + prompt_cache_key=prompt_cache_key, reasoning_effort=reasoning_effort, + safety_identifier=safety_identifier, seed=seed, service_tier=service_tier, stop=stop, diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 8de46dbab8..6d2b133110 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -1001,7 +1001,9 @@ def parse( parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, + prompt_cache_key: str | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + safety_identifier: str | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, @@ -1053,7 +1055,9 @@ def parser(raw_response: Response) -> ParsedResponse[TextFormatT]: "parallel_tool_calls": parallel_tool_calls, "previous_response_id": previous_response_id, "prompt": prompt, + "prompt_cache_key": prompt_cache_key, "reasoning": reasoning, + "safety_identifier": safety_identifier, "service_tier": service_tier, "store": store, "stream": stream, @@ -2316,7 +2320,9 @@ async def parse( parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, + prompt_cache_key: str | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + safety_identifier: str | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, @@ -2368,7 +2374,9 @@ def parser(raw_response: Response) -> ParsedResponse[TextFormatT]: "parallel_tool_calls": parallel_tool_calls, "previous_response_id": previous_response_id, "prompt": prompt, + "prompt_cache_key": prompt_cache_key, "reasoning": reasoning, + "safety_identifier": safety_identifier, "service_tier": service_tier, "store": store, "stream": stream, From b989e8c240533d7003d479a947bb1733df84fe71 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 30 Jul 2025 17:02:41 +0000 Subject: [PATCH 413/769] feat(client): support file upload requests --- src/openai/_base_client.py | 5 ++++- src/openai/_files.py | 8 ++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index 3fe669259f..f71e00f51f 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -534,7 +534,10 @@ def _build_request( is_body_allowed = options.method.lower() != "get" if is_body_allowed: - kwargs["json"] = json_data if is_given(json_data) else None + if isinstance(json_data, bytes): + kwargs["content"] = json_data + else: + kwargs["json"] = json_data if is_given(json_data) else None kwargs["files"] = files else: headers.pop("Content-Type", None) diff --git a/src/openai/_files.py b/src/openai/_files.py index 801a0d2928..7b23ca084a 100644 --- a/src/openai/_files.py +++ b/src/openai/_files.py @@ -69,12 +69,12 @@ def _transform_file(file: FileTypes) -> HttpxFileTypes: return file if is_tuple_t(file): - return (file[0], _read_file_content(file[1]), *file[2:]) + return (file[0], read_file_content(file[1]), *file[2:]) raise TypeError(f"Expected file types input to be a FileContent type or to be a tuple") -def _read_file_content(file: FileContent) -> HttpxFileContent: +def read_file_content(file: FileContent) -> HttpxFileContent: if isinstance(file, os.PathLike): return pathlib.Path(file).read_bytes() return file @@ -111,12 +111,12 @@ async def _async_transform_file(file: FileTypes) -> HttpxFileTypes: return file if is_tuple_t(file): - return (file[0], await _async_read_file_content(file[1]), *file[2:]) + return (file[0], await async_read_file_content(file[1]), *file[2:]) raise TypeError(f"Expected file types input to be a FileContent type or to be a tuple") -async def _async_read_file_content(file: FileContent) -> HttpxFileContent: +async def async_read_file_content(file: FileContent) -> HttpxFileContent: if isinstance(file, os.PathLike): return await anyio.Path(file).read_bytes() From 29ce19fcf98027c4e17f449666f62f3e8fce3486 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 5 Aug 2025 11:23:42 +0000 Subject: [PATCH 414/769] chore(internal): fix ruff target version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 6765611fc2..a495edc1a8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -177,7 +177,7 @@ reportPrivateUsage = false [tool.ruff] line-length = 120 output-format = "grouped" -target-version = "py37" +target-version = "py38" [tool.ruff.format] docstring-code-format = true From 2026d53339e61bfd5134e835bce6187baaca5b04 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 5 Aug 2025 16:50:43 +0000 Subject: [PATCH 415/769] feat(api): manual updates --- .stats.yml | 6 ++-- api.md | 4 +-- src/openai/types/responses/__init__.py | 8 ++--- .../responses/response_reasoning_item.py | 19 ++++++++---- .../response_reasoning_item_param.py | 19 ++++++++---- .../response_reasoning_summary_delta_event.py | 30 ------------------- .../response_reasoning_summary_done_event.py | 27 ----------------- .../response_reasoning_text_delta_event.py | 27 +++++++++++++++++ .../response_reasoning_text_done_event.py | 27 +++++++++++++++++ .../types/responses/response_stream_event.py | 8 ++--- .../types/vector_store_search_params.py | 3 +- tests/api_resources/test_vector_stores.py | 4 +-- 12 files changed, 97 insertions(+), 85 deletions(-) delete mode 100644 src/openai/types/responses/response_reasoning_summary_delta_event.py delete mode 100644 src/openai/types/responses/response_reasoning_summary_done_event.py create mode 100644 src/openai/types/responses/response_reasoning_text_delta_event.py create mode 100644 src/openai/types/responses/response_reasoning_text_done_event.py diff --git a/.stats.yml b/.stats.yml index e7fb0bdf9b..f86fa668b1 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-721e6ccaa72205ee14c71f8163129920464fb814b95d3df9567a9476bbd9b7fb.yml -openapi_spec_hash: 2115413a21df8b5bf9e4552a74df4312 -config_hash: 9606bb315a193bfd8da0459040143242 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-d6a16b25b969c3e5382e7d413de15bf83d5f7534d5c3ecce64d3a7e847418f9e.yml +openapi_spec_hash: 0c0bcf4aee9ca2a948dd14b890dfe728 +config_hash: aeff9289bd7f8c8482e4d738c3c2fde1 diff --git a/api.md b/api.md index 0280b886d1..657ac0905a 100644 --- a/api.md +++ b/api.md @@ -792,12 +792,12 @@ from openai.types.responses import ( ResponsePrompt, ResponseQueuedEvent, ResponseReasoningItem, - ResponseReasoningSummaryDeltaEvent, - ResponseReasoningSummaryDoneEvent, ResponseReasoningSummaryPartAddedEvent, ResponseReasoningSummaryPartDoneEvent, ResponseReasoningSummaryTextDeltaEvent, ResponseReasoningSummaryTextDoneEvent, + ResponseReasoningTextDeltaEvent, + ResponseReasoningTextDoneEvent, ResponseRefusalDeltaEvent, ResponseRefusalDoneEvent, ResponseStatus, diff --git a/src/openai/types/responses/__init__.py b/src/openai/types/responses/__init__.py index b563035e78..2e502ed69f 100644 --- a/src/openai/types/responses/__init__.py +++ b/src/openai/types/responses/__init__.py @@ -94,24 +94,20 @@ from .response_function_tool_call_param import ResponseFunctionToolCallParam as ResponseFunctionToolCallParam from .response_mcp_call_completed_event import ResponseMcpCallCompletedEvent as ResponseMcpCallCompletedEvent from .response_function_web_search_param import ResponseFunctionWebSearchParam as ResponseFunctionWebSearchParam +from .response_reasoning_text_done_event import ResponseReasoningTextDoneEvent as ResponseReasoningTextDoneEvent from .response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall as ResponseCodeInterpreterToolCall from .response_input_message_content_list import ResponseInputMessageContentList as ResponseInputMessageContentList from .response_mcp_call_in_progress_event import ResponseMcpCallInProgressEvent as ResponseMcpCallInProgressEvent +from .response_reasoning_text_delta_event import ResponseReasoningTextDeltaEvent as ResponseReasoningTextDeltaEvent from .response_audio_transcript_done_event import ResponseAudioTranscriptDoneEvent as ResponseAudioTranscriptDoneEvent from .response_file_search_tool_call_param import ResponseFileSearchToolCallParam as ResponseFileSearchToolCallParam from .response_mcp_list_tools_failed_event import ResponseMcpListToolsFailedEvent as ResponseMcpListToolsFailedEvent from .response_audio_transcript_delta_event import ( ResponseAudioTranscriptDeltaEvent as ResponseAudioTranscriptDeltaEvent, ) -from .response_reasoning_summary_done_event import ( - ResponseReasoningSummaryDoneEvent as ResponseReasoningSummaryDoneEvent, -) from .response_mcp_call_arguments_done_event import ( ResponseMcpCallArgumentsDoneEvent as ResponseMcpCallArgumentsDoneEvent, ) -from .response_reasoning_summary_delta_event import ( - ResponseReasoningSummaryDeltaEvent as ResponseReasoningSummaryDeltaEvent, -) from .response_computer_tool_call_output_item import ( ResponseComputerToolCallOutputItem as ResponseComputerToolCallOutputItem, ) diff --git a/src/openai/types/responses/response_reasoning_item.py b/src/openai/types/responses/response_reasoning_item.py index f5da7802f8..e5cb094e62 100644 --- a/src/openai/types/responses/response_reasoning_item.py +++ b/src/openai/types/responses/response_reasoning_item.py @@ -5,29 +5,38 @@ from ..._models import BaseModel -__all__ = ["ResponseReasoningItem", "Summary"] +__all__ = ["ResponseReasoningItem", "Summary", "Content"] class Summary(BaseModel): text: str - """ - A short summary of the reasoning used by the model when generating the response. - """ + """A summary of the reasoning output from the model so far.""" type: Literal["summary_text"] """The type of the object. Always `summary_text`.""" +class Content(BaseModel): + text: str + """Reasoning text output from the model.""" + + type: Literal["reasoning_text"] + """The type of the object. Always `reasoning_text`.""" + + class ResponseReasoningItem(BaseModel): id: str """The unique identifier of the reasoning content.""" summary: List[Summary] - """Reasoning text contents.""" + """Reasoning summary content.""" type: Literal["reasoning"] """The type of the object. Always `reasoning`.""" + content: Optional[List[Content]] = None + """Reasoning text content.""" + encrypted_content: Optional[str] = None """ The encrypted content of the reasoning item - populated when a response is diff --git a/src/openai/types/responses/response_reasoning_item_param.py b/src/openai/types/responses/response_reasoning_item_param.py index 2cfa5312ed..042b6c05db 100644 --- a/src/openai/types/responses/response_reasoning_item_param.py +++ b/src/openai/types/responses/response_reasoning_item_param.py @@ -5,29 +5,38 @@ from typing import Iterable, Optional from typing_extensions import Literal, Required, TypedDict -__all__ = ["ResponseReasoningItemParam", "Summary"] +__all__ = ["ResponseReasoningItemParam", "Summary", "Content"] class Summary(TypedDict, total=False): text: Required[str] - """ - A short summary of the reasoning used by the model when generating the response. - """ + """A summary of the reasoning output from the model so far.""" type: Required[Literal["summary_text"]] """The type of the object. Always `summary_text`.""" +class Content(TypedDict, total=False): + text: Required[str] + """Reasoning text output from the model.""" + + type: Required[Literal["reasoning_text"]] + """The type of the object. Always `reasoning_text`.""" + + class ResponseReasoningItemParam(TypedDict, total=False): id: Required[str] """The unique identifier of the reasoning content.""" summary: Required[Iterable[Summary]] - """Reasoning text contents.""" + """Reasoning summary content.""" type: Required[Literal["reasoning"]] """The type of the object. Always `reasoning`.""" + content: Iterable[Content] + """Reasoning text content.""" + encrypted_content: Optional[str] """ The encrypted content of the reasoning item - populated when a response is diff --git a/src/openai/types/responses/response_reasoning_summary_delta_event.py b/src/openai/types/responses/response_reasoning_summary_delta_event.py deleted file mode 100644 index 519a4f24ac..0000000000 --- a/src/openai/types/responses/response_reasoning_summary_delta_event.py +++ /dev/null @@ -1,30 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseReasoningSummaryDeltaEvent"] - - -class ResponseReasoningSummaryDeltaEvent(BaseModel): - delta: object - """The partial update to the reasoning summary content.""" - - item_id: str - """ - The unique identifier of the item for which the reasoning summary is being - updated. - """ - - output_index: int - """The index of the output item in the response's output array.""" - - sequence_number: int - """The sequence number of this event.""" - - summary_index: int - """The index of the summary part within the output item.""" - - type: Literal["response.reasoning_summary.delta"] - """The type of the event. Always 'response.reasoning_summary.delta'.""" diff --git a/src/openai/types/responses/response_reasoning_summary_done_event.py b/src/openai/types/responses/response_reasoning_summary_done_event.py deleted file mode 100644 index 98bcf9cb9d..0000000000 --- a/src/openai/types/responses/response_reasoning_summary_done_event.py +++ /dev/null @@ -1,27 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseReasoningSummaryDoneEvent"] - - -class ResponseReasoningSummaryDoneEvent(BaseModel): - item_id: str - """The unique identifier of the item for which the reasoning summary is finalized.""" - - output_index: int - """The index of the output item in the response's output array.""" - - sequence_number: int - """The sequence number of this event.""" - - summary_index: int - """The index of the summary part within the output item.""" - - text: str - """The finalized reasoning summary text.""" - - type: Literal["response.reasoning_summary.done"] - """The type of the event. Always 'response.reasoning_summary.done'.""" diff --git a/src/openai/types/responses/response_reasoning_text_delta_event.py b/src/openai/types/responses/response_reasoning_text_delta_event.py new file mode 100644 index 0000000000..e1df893bac --- /dev/null +++ b/src/openai/types/responses/response_reasoning_text_delta_event.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseReasoningTextDeltaEvent"] + + +class ResponseReasoningTextDeltaEvent(BaseModel): + content_index: int + """The index of the reasoning content part this delta is associated with.""" + + delta: str + """The text delta that was added to the reasoning content.""" + + item_id: str + """The ID of the item this reasoning text delta is associated with.""" + + output_index: int + """The index of the output item this reasoning text delta is associated with.""" + + sequence_number: int + """The sequence number of this event.""" + + type: Literal["response.reasoning_text.delta"] + """The type of the event. Always `response.reasoning_text.delta`.""" diff --git a/src/openai/types/responses/response_reasoning_text_done_event.py b/src/openai/types/responses/response_reasoning_text_done_event.py new file mode 100644 index 0000000000..d22d984e47 --- /dev/null +++ b/src/openai/types/responses/response_reasoning_text_done_event.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseReasoningTextDoneEvent"] + + +class ResponseReasoningTextDoneEvent(BaseModel): + content_index: int + """The index of the reasoning content part.""" + + item_id: str + """The ID of the item this reasoning text is associated with.""" + + output_index: int + """The index of the output item this reasoning text is associated with.""" + + sequence_number: int + """The sequence number of this event.""" + + text: str + """The full text of the completed reasoning content.""" + + type: Literal["response.reasoning_text.done"] + """The type of the event. Always `response.reasoning_text.done`.""" diff --git a/src/openai/types/responses/response_stream_event.py b/src/openai/types/responses/response_stream_event.py index 98e1d6c34d..d62cf8969b 100644 --- a/src/openai/types/responses/response_stream_event.py +++ b/src/openai/types/responses/response_stream_event.py @@ -23,13 +23,13 @@ from .response_output_item_added_event import ResponseOutputItemAddedEvent from .response_content_part_added_event import ResponseContentPartAddedEvent from .response_mcp_call_completed_event import ResponseMcpCallCompletedEvent +from .response_reasoning_text_done_event import ResponseReasoningTextDoneEvent from .response_mcp_call_in_progress_event import ResponseMcpCallInProgressEvent +from .response_reasoning_text_delta_event import ResponseReasoningTextDeltaEvent from .response_audio_transcript_done_event import ResponseAudioTranscriptDoneEvent from .response_mcp_list_tools_failed_event import ResponseMcpListToolsFailedEvent from .response_audio_transcript_delta_event import ResponseAudioTranscriptDeltaEvent -from .response_reasoning_summary_done_event import ResponseReasoningSummaryDoneEvent from .response_mcp_call_arguments_done_event import ResponseMcpCallArgumentsDoneEvent -from .response_reasoning_summary_delta_event import ResponseReasoningSummaryDeltaEvent from .response_image_gen_call_completed_event import ResponseImageGenCallCompletedEvent from .response_mcp_call_arguments_delta_event import ResponseMcpCallArgumentsDeltaEvent from .response_mcp_list_tools_completed_event import ResponseMcpListToolsCompletedEvent @@ -88,6 +88,8 @@ ResponseReasoningSummaryPartDoneEvent, ResponseReasoningSummaryTextDeltaEvent, ResponseReasoningSummaryTextDoneEvent, + ResponseReasoningTextDeltaEvent, + ResponseReasoningTextDoneEvent, ResponseRefusalDeltaEvent, ResponseRefusalDoneEvent, ResponseTextDeltaEvent, @@ -109,8 +111,6 @@ ResponseMcpListToolsInProgressEvent, ResponseOutputTextAnnotationAddedEvent, ResponseQueuedEvent, - ResponseReasoningSummaryDeltaEvent, - ResponseReasoningSummaryDoneEvent, ], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/vector_store_search_params.py b/src/openai/types/vector_store_search_params.py index 17573d0f61..973c49ff5a 100644 --- a/src/openai/types/vector_store_search_params.py +++ b/src/openai/types/vector_store_search_params.py @@ -35,6 +35,7 @@ class VectorStoreSearchParams(TypedDict, total=False): class RankingOptions(TypedDict, total=False): - ranker: Literal["auto", "default-2024-11-15"] + ranker: Literal["none", "auto", "default-2024-11-15"] + """Enable re-ranking; set to `none` to disable, which can help reduce latency.""" score_threshold: float diff --git a/tests/api_resources/test_vector_stores.py b/tests/api_resources/test_vector_stores.py index 5af95fec41..dffd2b1d07 100644 --- a/tests/api_resources/test_vector_stores.py +++ b/tests/api_resources/test_vector_stores.py @@ -243,7 +243,7 @@ def test_method_search_with_all_params(self, client: OpenAI) -> None: }, max_num_results=1, ranking_options={ - "ranker": "auto", + "ranker": "none", "score_threshold": 0, }, rewrite_query=True, @@ -511,7 +511,7 @@ async def test_method_search_with_all_params(self, async_client: AsyncOpenAI) -> }, max_num_results=1, ranking_options={ - "ranker": "auto", + "ranker": "none", "score_threshold": 0, }, rewrite_query=True, From b0ad27a67681f1b6fb473cc75c642efa1f4941d5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 5 Aug 2025 16:51:15 +0000 Subject: [PATCH 416/769] release: 1.99.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 19 +++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index d12300ea76..5c9b107c0d 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.98.0" + ".": "1.99.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 669d5a5792..e7a49bcc9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## 1.99.0 (2025-08-05) + +Full Changelog: [v1.98.0...v1.99.0](https://github.com/openai/openai-python/compare/v1.98.0...v1.99.0) + +### Features + +* **api:** manual updates ([d4aa726](https://github.com/openai/openai-python/commit/d4aa72602bf489ef270154b881b3967d497d4220)) +* **client:** support file upload requests ([0772e6e](https://github.com/openai/openai-python/commit/0772e6ed8310e15539610b003dd73f72f474ec0c)) + + +### Bug Fixes + +* add missing prompt_cache_key & prompt_cache_key params ([00b49ae](https://github.com/openai/openai-python/commit/00b49ae8d44ea396ac0536fc3ce4658fc669e2f5)) + + +### Chores + +* **internal:** fix ruff target version ([aa6b252](https://github.com/openai/openai-python/commit/aa6b252ae0f25f195dede15755e05dd2f542f42d)) + ## 1.98.0 (2025-07-30) Full Changelog: [v1.97.2...v1.98.0](https://github.com/openai/openai-python/compare/v1.97.2...v1.98.0) diff --git a/pyproject.toml b/pyproject.toml index a495edc1a8..5e0f1fe3ea 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.98.0" +version = "1.99.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 ca890665bc..a5c9b3df71 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.98.0" # x-release-please-version +__version__ = "1.99.0" # x-release-please-version From fd2c3f12cf3574f92aab2877f2903e6756018867 Mon Sep 17 00:00:00 2001 From: David Meadows Date: Tue, 5 Aug 2025 14:08:26 -0400 Subject: [PATCH 417/769] fix(internal): correct event imports --- examples/image_stream.py | 2 +- src/openai/lib/streaming/responses/_events.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/image_stream.py b/examples/image_stream.py index c188e68717..eab5932534 100644 --- a/examples/image_stream.py +++ b/examples/image_stream.py @@ -50,4 +50,4 @@ def main() -> None: try: main() except Exception as error: - print(f"Error generating image: {error}") \ No newline at end of file + print(f"Error generating image: {error}") diff --git a/src/openai/lib/streaming/responses/_events.py b/src/openai/lib/streaming/responses/_events.py index 4c8a588944..de3342ec9d 100644 --- a/src/openai/lib/streaming/responses/_events.py +++ b/src/openai/lib/streaming/responses/_events.py @@ -31,11 +31,9 @@ ResponseAudioTranscriptDoneEvent, ResponseAudioTranscriptDeltaEvent, ResponseMcpCallArgumentsDoneEvent, - ResponseReasoningSummaryDoneEvent, ResponseImageGenCallCompletedEvent, ResponseMcpCallArgumentsDeltaEvent, ResponseMcpListToolsCompletedEvent, - ResponseReasoningSummaryDeltaEvent, ResponseImageGenCallGeneratingEvent, ResponseImageGenCallInProgressEvent, ResponseMcpListToolsInProgressEvent, @@ -59,6 +57,8 @@ ResponseCodeInterpreterCallInProgressEvent, ResponseCodeInterpreterCallInterpretingEvent, ) +from ....types.responses.response_reasoning_text_done_event import ResponseReasoningTextDoneEvent +from ....types.responses.response_reasoning_text_delta_event import ResponseReasoningTextDeltaEvent TextFormatT = TypeVar( "TextFormatT", @@ -137,8 +137,8 @@ class ResponseCompletedEvent(RawResponseCompletedEvent, GenericModel, Generic[Te ResponseMcpListToolsInProgressEvent, ResponseOutputTextAnnotationAddedEvent, ResponseQueuedEvent, - ResponseReasoningSummaryDeltaEvent, - ResponseReasoningSummaryDoneEvent, + ResponseReasoningTextDeltaEvent, + ResponseReasoningTextDoneEvent, ], PropertyInfo(discriminator="type"), ] From a8258744cbecf51321587fc870e8920bd2c07809 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 5 Aug 2025 18:08:59 +0000 Subject: [PATCH 418/769] release: 1.99.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 5c9b107c0d..41be9f1017 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.99.0" + ".": "1.99.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index e7a49bcc9a..4585135511 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.99.1 (2025-08-05) + +Full Changelog: [v1.99.0...v1.99.1](https://github.com/openai/openai-python/compare/v1.99.0...v1.99.1) + +### Bug Fixes + +* **internal:** correct event imports ([2a6d143](https://github.com/openai/openai-python/commit/2a6d1436288a07f67f6afefe5c0b5d6ae32d7e70)) + ## 1.99.0 (2025-08-05) Full Changelog: [v1.98.0...v1.99.0](https://github.com/openai/openai-python/compare/v1.98.0...v1.99.0) diff --git a/pyproject.toml b/pyproject.toml index 5e0f1fe3ea..c71e8c135b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.99.0" +version = "1.99.1" 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 a5c9b3df71..3fa80adba0 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.99.0" # x-release-please-version +__version__ = "1.99.1" # x-release-please-version From 936b2f0db2812c74c966a657d45acd972d2fd088 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Thu, 7 Aug 2025 10:58:11 +0100 Subject: [PATCH 419/769] chore(tests): bump inline-snapshot dependency --- requirements-dev.lock | 25 +++++--------------- tests/lib/chat/_utils.py | 12 ++++++++++ tests/lib/chat/test_completions.py | 6 ++--- tests/lib/chat/test_completions_streaming.py | 12 ++++++---- 4 files changed, 29 insertions(+), 26 deletions(-) diff --git a/requirements-dev.lock b/requirements-dev.lock index 1a7500d569..b1886e036f 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -35,8 +35,6 @@ attrs==24.2.0 azure-core==1.31.0 # via azure-identity azure-identity==1.19.0 -black==24.10.0 - # via inline-snapshot certifi==2023.7.22 # via httpcore # via httpx @@ -46,9 +44,6 @@ cffi==1.16.0 # via sounddevice charset-normalizer==3.3.2 # via requests -click==8.1.7 - # via black - # via inline-snapshot colorlog==6.7.0 # via nox cryptography==42.0.7 @@ -66,7 +61,7 @@ exceptiongroup==1.2.2 # via trio execnet==2.1.1 # via pytest-xdist -executing==2.1.0 +executing==2.2.0 # via inline-snapshot filelock==3.12.4 # via virtualenv @@ -92,7 +87,7 @@ idna==3.4 importlib-metadata==7.0.0 iniconfig==2.0.0 # via pytest -inline-snapshot==0.10.2 +inline-snapshot==0.27.0 jiter==0.5.0 # via openai markdown-it-py==3.0.0 @@ -109,7 +104,6 @@ multidict==6.5.0 # via yarl mypy==1.14.1 mypy-extensions==1.0.0 - # via black # via mypy nest-asyncio==1.6.0 nodeenv==1.8.0 @@ -122,17 +116,13 @@ numpy==2.0.2 outcome==1.3.0.post0 # via trio packaging==23.2 - # via black # via nox # via pytest pandas==2.2.3 # via openai pandas-stubs==2.1.4.231227 # via openai -pathspec==0.12.1 - # via black platformdirs==3.11.0 - # via black # via virtualenv pluggy==1.5.0 # via pytest @@ -148,11 +138,13 @@ pydantic==2.10.3 pydantic-core==2.27.1 # via pydantic pygments==2.18.0 + # via pytest # via rich pyjwt==2.8.0 # via msal pyright==1.1.399 -pytest==8.3.3 +pytest==8.4.1 + # via inline-snapshot # via pytest-asyncio # via pytest-xdist pytest-asyncio==0.24.0 @@ -185,10 +177,8 @@ sortedcontainers==2.4.0 sounddevice==0.5.1 # via openai time-machine==2.9.0 -toml==0.10.2 - # via inline-snapshot tomli==2.0.2 - # via black + # via inline-snapshot # via mypy # via pytest tqdm==4.66.5 @@ -197,13 +187,10 @@ trio==0.27.0 types-pyaudio==0.2.16.20240516 types-pytz==2024.2.0.20241003 # via pandas-stubs -types-toml==0.10.8.20240310 - # via inline-snapshot types-tqdm==4.66.0.20240417 typing-extensions==4.12.2 # via azure-core # via azure-identity - # via black # via multidict # via mypy # via openai diff --git a/tests/lib/chat/_utils.py b/tests/lib/chat/_utils.py index f3982278f3..0cc1c99952 100644 --- a/tests/lib/chat/_utils.py +++ b/tests/lib/chat/_utils.py @@ -52,3 +52,15 @@ def get_caller_name(*, stacklevel: int = 1) -> str: def clear_locals(string: str, *, stacklevel: int) -> str: caller = get_caller_name(stacklevel=stacklevel + 1) return string.replace(f"{caller}..", "") + + +def get_snapshot_value(snapshot: Any) -> Any: + if not hasattr(snapshot, "_old_value"): + return snapshot + + old = snapshot._old_value + if not hasattr(old, "value"): + return old + + loader = getattr(old.value, "_load_value", None) + return loader() if loader else old.value diff --git a/tests/lib/chat/test_completions.py b/tests/lib/chat/test_completions.py index e7143bbb68..d0bd14ce9e 100644 --- a/tests/lib/chat/test_completions.py +++ b/tests/lib/chat/test_completions.py @@ -17,7 +17,7 @@ from openai._utils import assert_signatures_in_sync from openai._compat import PYDANTIC_V2 -from ._utils import print_obj +from ._utils import print_obj, get_snapshot_value from ...conftest import base_url from ..schema_types.query import Query @@ -1010,7 +1010,7 @@ def _on_response(response: httpx.Response) -> None: respx_mock.post("/chat/completions").mock( return_value=httpx.Response( 200, - content=content_snapshot._old_value, + content=get_snapshot_value(content_snapshot), headers={"content-type": "application/json"}, ) ) @@ -1052,7 +1052,7 @@ async def _on_response(response: httpx.Response) -> None: respx_mock.post("/chat/completions").mock( return_value=httpx.Response( 200, - content=content_snapshot._old_value, + content=get_snapshot_value(content_snapshot), headers={"content-type": "application/json"}, ) ) diff --git a/tests/lib/chat/test_completions_streaming.py b/tests/lib/chat/test_completions_streaming.py index 4680a73e3a..1daa98c6a0 100644 --- a/tests/lib/chat/test_completions_streaming.py +++ b/tests/lib/chat/test_completions_streaming.py @@ -9,7 +9,11 @@ import pytest from respx import MockRouter from pydantic import BaseModel -from inline_snapshot import external, snapshot, outsource +from inline_snapshot import ( + external, + snapshot, + outsource, # pyright: ignore[reportUnknownVariableType] +) import openai from openai import OpenAI, AsyncOpenAI @@ -26,7 +30,7 @@ ) from openai.lib._parsing._completions import ResponseFormatT -from ._utils import print_obj +from ._utils import print_obj, get_snapshot_value from ...conftest import base_url _T = TypeVar("_T") @@ -1123,7 +1127,7 @@ def _on_response(response: httpx.Response) -> None: respx_mock.post("/chat/completions").mock( return_value=httpx.Response( 200, - content=content_snapshot._old_value._load_value(), + content=get_snapshot_value(content_snapshot), headers={"content-type": "text/event-stream"}, ) ) @@ -1170,7 +1174,7 @@ def _on_response(response: httpx.Response) -> None: respx_mock.post("/chat/completions").mock( return_value=httpx.Response( 200, - content=content_snapshot._old_value._load_value(), + content=get_snapshot_value(content_snapshot), headers={"content-type": "text/event-stream"}, ) ) From caf837bb89a107e3658e56190b03f246ee23b917 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 7 Aug 2025 17:02:31 +0000 Subject: [PATCH 420/769] feat(api): adds GPT-5 and new API features: platform.openai.com/docs/guides/gpt-5 --- .stats.yml | 6 +- api.md | 17 ++ src/openai/lib/_parsing/_completions.py | 57 ++++++- src/openai/lib/_parsing/_responses.py | 1 + src/openai/lib/_tools.py | 4 +- src/openai/lib/streaming/chat/_completions.py | 3 +- src/openai/resources/beta/assistants.py | 48 +++--- .../resources/beta/threads/runs/runs.py | 54 +++---- .../resources/chat/completions/completions.py | 138 ++++++++++------ src/openai/resources/responses/responses.py | 148 +++++++++++++++++- src/openai/types/__init__.py | 3 + .../types/beta/assistant_create_params.py | 8 +- .../types/beta/assistant_update_params.py | 14 +- .../types/beta/threads/run_create_params.py | 8 +- src/openai/types/chat/__init__.py | 23 ++- ...at_completion_allowed_tool_choice_param.py | 17 ++ .../chat_completion_allowed_tools_param.py | 32 ++++ .../chat/chat_completion_custom_tool_param.py | 58 +++++++ ...ol.py => chat_completion_function_tool.py} | 4 +- .../chat_completion_function_tool_param.py | 16 ++ ...hat_completion_message_custom_tool_call.py | 26 +++ ...mpletion_message_custom_tool_call_param.py | 26 +++ ...t_completion_message_function_tool_call.py | 31 ++++ ...letion_message_function_tool_call_param.py | 31 ++++ .../chat/chat_completion_message_tool_call.py | 36 ++--- ...chat_completion_message_tool_call_param.py | 32 +--- ...mpletion_named_tool_choice_custom_param.py | 19 +++ ...chat_completion_named_tool_choice_param.py | 2 +- .../chat_completion_stream_options_param.py | 11 ++ ...hat_completion_tool_choice_option_param.py | 7 +- .../types/chat/chat_completion_tool_param.py | 13 +- .../types/chat/completion_create_params.py | 22 ++- .../types/chat/parsed_function_tool_call.py | 4 +- ...create_eval_completions_run_data_source.py | 4 +- ..._eval_completions_run_data_source_param.py | 4 +- src/openai/types/responses/__init__.py | 18 +++ src/openai/types/responses/custom_tool.py | 23 +++ .../types/responses/custom_tool_param.py | 23 +++ src/openai/types/responses/parsed_response.py | 2 + src/openai/types/responses/response.py | 29 ++-- .../types/responses/response_create_params.py | 44 +++++- .../responses/response_custom_tool_call.py | 25 +++ ...onse_custom_tool_call_input_delta_event.py | 24 +++ ...ponse_custom_tool_call_input_done_event.py | 24 +++ .../response_custom_tool_call_output.py | 22 +++ .../response_custom_tool_call_output_param.py | 21 +++ .../response_custom_tool_call_param.py | 24 +++ .../types/responses/response_input_item.py | 4 + .../responses/response_input_item_param.py | 4 + .../types/responses/response_input_param.py | 4 + .../types/responses/response_output_item.py | 2 + .../responses/response_retrieve_params.py | 11 ++ .../types/responses/response_stream_event.py | 4 + src/openai/types/responses/tool.py | 13 +- .../types/responses/tool_choice_allowed.py | 36 +++++ .../responses/tool_choice_allowed_param.py | 36 +++++ .../types/responses/tool_choice_custom.py | 15 ++ .../responses/tool_choice_custom_param.py | 15 ++ src/openai/types/responses/tool_param.py | 2 + src/openai/types/shared/__init__.py | 3 + src/openai/types/shared/chat_model.py | 7 + .../types/shared/custom_tool_input_format.py | 28 ++++ src/openai/types/shared/reasoning.py | 8 +- src/openai/types/shared/reasoning_effort.py | 2 +- .../shared/response_format_text_grammar.py | 15 ++ .../shared/response_format_text_python.py | 12 ++ src/openai/types/shared_params/__init__.py | 1 + src/openai/types/shared_params/chat_model.py | 7 + .../shared_params/custom_tool_input_format.py | 27 ++++ src/openai/types/shared_params/reasoning.py | 8 +- .../types/shared_params/reasoning_effort.py | 2 +- tests/api_resources/beta/test_assistants.py | 8 +- tests/api_resources/beta/threads/test_runs.py | 8 +- tests/api_resources/chat/test_completions.py | 32 +++- tests/api_resources/test_completions.py | 20 ++- tests/api_resources/test_responses.py | 20 ++- 76 files changed, 1293 insertions(+), 267 deletions(-) create mode 100644 src/openai/types/chat/chat_completion_allowed_tool_choice_param.py create mode 100644 src/openai/types/chat/chat_completion_allowed_tools_param.py create mode 100644 src/openai/types/chat/chat_completion_custom_tool_param.py rename src/openai/types/chat/{chat_completion_tool.py => chat_completion_function_tool.py} (80%) create mode 100644 src/openai/types/chat/chat_completion_function_tool_param.py create mode 100644 src/openai/types/chat/chat_completion_message_custom_tool_call.py create mode 100644 src/openai/types/chat/chat_completion_message_custom_tool_call_param.py create mode 100644 src/openai/types/chat/chat_completion_message_function_tool_call.py create mode 100644 src/openai/types/chat/chat_completion_message_function_tool_call_param.py create mode 100644 src/openai/types/chat/chat_completion_named_tool_choice_custom_param.py create mode 100644 src/openai/types/responses/custom_tool.py create mode 100644 src/openai/types/responses/custom_tool_param.py create mode 100644 src/openai/types/responses/response_custom_tool_call.py create mode 100644 src/openai/types/responses/response_custom_tool_call_input_delta_event.py create mode 100644 src/openai/types/responses/response_custom_tool_call_input_done_event.py create mode 100644 src/openai/types/responses/response_custom_tool_call_output.py create mode 100644 src/openai/types/responses/response_custom_tool_call_output_param.py create mode 100644 src/openai/types/responses/response_custom_tool_call_param.py create mode 100644 src/openai/types/responses/tool_choice_allowed.py create mode 100644 src/openai/types/responses/tool_choice_allowed_param.py create mode 100644 src/openai/types/responses/tool_choice_custom.py create mode 100644 src/openai/types/responses/tool_choice_custom_param.py create mode 100644 src/openai/types/shared/custom_tool_input_format.py create mode 100644 src/openai/types/shared/response_format_text_grammar.py create mode 100644 src/openai/types/shared/response_format_text_python.py create mode 100644 src/openai/types/shared_params/custom_tool_input_format.py diff --git a/.stats.yml b/.stats.yml index f86fa668b1..9c1b4e4c54 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-d6a16b25b969c3e5382e7d413de15bf83d5f7534d5c3ecce64d3a7e847418f9e.yml -openapi_spec_hash: 0c0bcf4aee9ca2a948dd14b890dfe728 -config_hash: aeff9289bd7f8c8482e4d738c3c2fde1 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-f5c45f4ae5c2075cbc603d6910bba3da31c23714c209fbd3fd82a94f634a126b.yml +openapi_spec_hash: 3eb8d86c06f0bb5e1190983e5acfc9ba +config_hash: 9a64321968e21ed72f5c0e02164ea00d diff --git a/api.md b/api.md index 657ac0905a..f05b3f61ee 100644 --- a/api.md +++ b/api.md @@ -6,6 +6,7 @@ from openai.types import ( ChatModel, ComparisonFilter, CompoundFilter, + CustomToolInputFormat, ErrorObject, FunctionDefinition, FunctionParameters, @@ -15,6 +16,8 @@ from openai.types import ( ResponseFormatJSONObject, ResponseFormatJSONSchema, ResponseFormatText, + ResponseFormatTextGrammar, + ResponseFormatTextPython, ResponsesModel, ) ``` @@ -46,6 +49,7 @@ Types: ```python from openai.types.chat import ( ChatCompletion, + ChatCompletionAllowedToolChoice, ChatCompletionAssistantMessageParam, ChatCompletionAudio, ChatCompletionAudioParam, @@ -55,15 +59,20 @@ from openai.types.chat import ( ChatCompletionContentPartInputAudio, ChatCompletionContentPartRefusal, ChatCompletionContentPartText, + ChatCompletionCustomTool, ChatCompletionDeleted, ChatCompletionDeveloperMessageParam, ChatCompletionFunctionCallOption, ChatCompletionFunctionMessageParam, + ChatCompletionFunctionTool, ChatCompletionMessage, + ChatCompletionMessageCustomToolCall, + ChatCompletionMessageFunctionToolCall, ChatCompletionMessageParam, ChatCompletionMessageToolCall, ChatCompletionModality, ChatCompletionNamedToolChoice, + ChatCompletionNamedToolChoiceCustom, ChatCompletionPredictionContent, ChatCompletionRole, ChatCompletionStoreMessage, @@ -74,6 +83,7 @@ from openai.types.chat import ( ChatCompletionToolChoiceOption, ChatCompletionToolMessageParam, ChatCompletionUserMessageParam, + ChatCompletionAllowedTools, ChatCompletionReasoningEffort, ) ``` @@ -719,6 +729,7 @@ Types: ```python from openai.types.responses import ( ComputerTool, + CustomTool, EasyInputMessage, FileSearchTool, FunctionTool, @@ -741,6 +752,10 @@ from openai.types.responses import ( ResponseContentPartAddedEvent, ResponseContentPartDoneEvent, ResponseCreatedEvent, + ResponseCustomToolCall, + ResponseCustomToolCallInputDeltaEvent, + ResponseCustomToolCallInputDoneEvent, + ResponseCustomToolCallOutput, ResponseError, ResponseErrorEvent, ResponseFailedEvent, @@ -810,6 +825,8 @@ from openai.types.responses import ( ResponseWebSearchCallInProgressEvent, ResponseWebSearchCallSearchingEvent, Tool, + ToolChoiceAllowed, + ToolChoiceCustom, ToolChoiceFunction, ToolChoiceMcp, ToolChoiceOptions, diff --git a/src/openai/lib/_parsing/_completions.py b/src/openai/lib/_parsing/_completions.py index c160070b66..e14c33864d 100644 --- a/src/openai/lib/_parsing/_completions.py +++ b/src/openai/lib/_parsing/_completions.py @@ -1,6 +1,7 @@ from __future__ import annotations import json +import logging from typing import TYPE_CHECKING, Any, Iterable, cast from typing_extensions import TypeVar, TypeGuard, assert_never @@ -19,14 +20,15 @@ ParsedChatCompletion, ChatCompletionMessage, ParsedFunctionToolCall, - ChatCompletionToolParam, ParsedChatCompletionMessage, + ChatCompletionFunctionToolParam, completion_create_params, ) from ..._exceptions import LengthFinishReasonError, ContentFilterFinishReasonError from ...types.shared_params import FunctionDefinition from ...types.chat.completion_create_params import ResponseFormat as ResponseFormatParam -from ...types.chat.chat_completion_message_tool_call import Function +from ...types.chat.chat_completion_tool_param import ChatCompletionToolParam +from ...types.chat.chat_completion_message_function_tool_call import Function ResponseFormatT = TypeVar( "ResponseFormatT", @@ -35,12 +37,36 @@ ) _default_response_format: None = None +log: logging.Logger = logging.getLogger("openai.lib.parsing") + + +def is_strict_chat_completion_tool_param( + tool: ChatCompletionToolParam, +) -> TypeGuard[ChatCompletionFunctionToolParam]: + """Check if the given tool is a strict ChatCompletionFunctionToolParam.""" + if not tool["type"] == "function": + return False + if tool["function"].get("strict") is not True: + return False + + return True + + +def select_strict_chat_completion_tools( + tools: Iterable[ChatCompletionToolParam] | NotGiven = NOT_GIVEN, +) -> Iterable[ChatCompletionFunctionToolParam] | NotGiven: + """Select only the strict ChatCompletionFunctionToolParams from the given tools.""" + if not is_given(tools): + return NOT_GIVEN + + return [t for t in tools if is_strict_chat_completion_tool_param(t)] + def validate_input_tools( tools: Iterable[ChatCompletionToolParam] | NotGiven = NOT_GIVEN, -) -> None: +) -> Iterable[ChatCompletionFunctionToolParam] | NotGiven: if not is_given(tools): - return + return NOT_GIVEN for tool in tools: if tool["type"] != "function": @@ -54,6 +80,8 @@ def validate_input_tools( f"`{tool['function']['name']}` is not strict. Only `strict` function tools can be auto-parsed" ) + return cast(Iterable[ChatCompletionFunctionToolParam], tools) + def parse_chat_completion( *, @@ -95,6 +123,14 @@ def parse_chat_completion( type_=ParsedFunctionToolCall, ) ) + elif tool_call.type == "custom": + # warn user that custom tool calls are not callable here + log.warning( + "Custom tool calls are not callable. Ignoring tool call: %s - %s", + tool_call.id, + tool_call.custom.name, + stacklevel=2, + ) elif TYPE_CHECKING: # type: ignore[unreachable] assert_never(tool_call) else: @@ -129,13 +165,15 @@ def parse_chat_completion( ) -def get_input_tool_by_name(*, input_tools: list[ChatCompletionToolParam], name: str) -> ChatCompletionToolParam | None: - return next((t for t in input_tools if t.get("function", {}).get("name") == name), None) +def get_input_tool_by_name( + *, input_tools: list[ChatCompletionToolParam], name: str +) -> ChatCompletionFunctionToolParam | None: + return next((t for t in input_tools if t["type"] == "function" and t.get("function", {}).get("name") == name), None) def parse_function_tool_arguments( *, input_tools: list[ChatCompletionToolParam], function: Function | ParsedFunction -) -> object: +) -> object | None: input_tool = get_input_tool_by_name(input_tools=input_tools, name=function.name) if not input_tool: return None @@ -149,7 +187,7 @@ def parse_function_tool_arguments( if not input_fn.get("strict"): return None - return json.loads(function.arguments) + return json.loads(function.arguments) # type: ignore[no-any-return] def maybe_parse_content( @@ -209,6 +247,9 @@ def is_response_format_param(response_format: object) -> TypeGuard[ResponseForma def is_parseable_tool(input_tool: ChatCompletionToolParam) -> bool: + if input_tool["type"] != "function": + return False + input_fn = cast(object, input_tool.get("function")) if isinstance(input_fn, PydanticFunctionTool): return True diff --git a/src/openai/lib/_parsing/_responses.py b/src/openai/lib/_parsing/_responses.py index 41be1d37b0..2a30ac836c 100644 --- a/src/openai/lib/_parsing/_responses.py +++ b/src/openai/lib/_parsing/_responses.py @@ -110,6 +110,7 @@ def parse_response( or output.type == "local_shell_call" or output.type == "mcp_list_tools" or output.type == "exec" + or output.type == "custom_tool_call" ): output_list.append(output) elif TYPE_CHECKING: # type: ignore diff --git a/src/openai/lib/_tools.py b/src/openai/lib/_tools.py index 415d750074..4070ad63bb 100644 --- a/src/openai/lib/_tools.py +++ b/src/openai/lib/_tools.py @@ -5,7 +5,7 @@ import pydantic from ._pydantic import to_strict_json_schema -from ..types.chat import ChatCompletionToolParam +from ..types.chat import ChatCompletionFunctionToolParam from ..types.shared_params import FunctionDefinition from ..types.responses.function_tool_param import FunctionToolParam as ResponsesFunctionToolParam @@ -42,7 +42,7 @@ def pydantic_function_tool( *, name: str | None = None, # inferred from class name by default description: str | None = None, # inferred from class docstring by default -) -> ChatCompletionToolParam: +) -> ChatCompletionFunctionToolParam: if description is None: # note: we intentionally don't use `.getdoc()` to avoid # including pydantic's docstrings diff --git a/src/openai/lib/streaming/chat/_completions.py b/src/openai/lib/streaming/chat/_completions.py index 2cf37efeae..1dff628a20 100644 --- a/src/openai/lib/streaming/chat/_completions.py +++ b/src/openai/lib/streaming/chat/_completions.py @@ -37,11 +37,12 @@ parse_function_tool_arguments, ) from ...._streaming import Stream, AsyncStream -from ....types.chat import ChatCompletionChunk, ParsedChatCompletion, ChatCompletionToolParam +from ....types.chat import ChatCompletionChunk, ParsedChatCompletion from ...._exceptions import LengthFinishReasonError, ContentFilterFinishReasonError from ....types.chat.chat_completion import ChoiceLogprobs from ....types.chat.chat_completion_chunk import Choice as ChoiceChunk from ....types.chat.completion_create_params import ResponseFormat as ResponseFormatParam +from ....types.chat.chat_completion_tool_param import ChatCompletionToolParam class ChatCompletionStream(Generic[ResponseFormatT]): diff --git a/src/openai/resources/beta/assistants.py b/src/openai/resources/beta/assistants.py index 9059d93616..fe0c99c88a 100644 --- a/src/openai/resources/beta/assistants.py +++ b/src/openai/resources/beta/assistants.py @@ -96,12 +96,11 @@ def create( name: The name of the assistant. The maximum length is 256 characters. - reasoning_effort: **o-series models only** - - Constrains effort on reasoning for + reasoning_effort: 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. + supported values are `minimal`, `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), @@ -220,6 +219,12 @@ def update( model: Union[ str, Literal[ + "gpt-5", + "gpt-5-mini", + "gpt-5-nano", + "gpt-5-2025-08-07", + "gpt-5-mini-2025-08-07", + "gpt-5-nano-2025-08-07", "gpt-4.1", "gpt-4.1-mini", "gpt-4.1-nano", @@ -298,12 +303,11 @@ def update( name: The name of the assistant. The maximum length is 256 characters. - reasoning_effort: **o-series models only** - - Constrains effort on reasoning for + reasoning_effort: 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. + supported values are `minimal`, `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), @@ -545,12 +549,11 @@ async def create( name: The name of the assistant. The maximum length is 256 characters. - reasoning_effort: **o-series models only** - - Constrains effort on reasoning for + reasoning_effort: 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. + supported values are `minimal`, `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), @@ -669,6 +672,12 @@ async def update( model: Union[ str, Literal[ + "gpt-5", + "gpt-5-mini", + "gpt-5-nano", + "gpt-5-2025-08-07", + "gpt-5-mini-2025-08-07", + "gpt-5-nano-2025-08-07", "gpt-4.1", "gpt-4.1-mini", "gpt-4.1-nano", @@ -747,12 +756,11 @@ async def update( name: The name of the assistant. The maximum length is 256 characters. - reasoning_effort: **o-series models only** - - Constrains effort on reasoning for + reasoning_effort: 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. + supported values are `minimal`, `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), diff --git a/src/openai/resources/beta/threads/runs/runs.py b/src/openai/resources/beta/threads/runs/runs.py index 3d9ae9759e..01246d7c12 100644 --- a/src/openai/resources/beta/threads/runs/runs.py +++ b/src/openai/resources/beta/threads/runs/runs.py @@ -167,12 +167,11 @@ def create( [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) during tool use. - reasoning_effort: **o-series models only** - - Constrains effort on reasoning for + reasoning_effort: 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. + supported values are `minimal`, `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), @@ -322,12 +321,11 @@ def create( [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) during tool use. - reasoning_effort: **o-series models only** - - Constrains effort on reasoning for + reasoning_effort: 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. + supported values are `minimal`, `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), @@ -473,12 +471,11 @@ def create( [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) during tool use. - reasoning_effort: **o-series models only** - - Constrains effort on reasoning for + reasoning_effort: 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. + supported values are `minimal`, `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), @@ -1600,12 +1597,11 @@ async def create( [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) during tool use. - reasoning_effort: **o-series models only** - - Constrains effort on reasoning for + reasoning_effort: 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. + supported values are `minimal`, `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), @@ -1755,12 +1751,11 @@ async def create( [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) during tool use. - reasoning_effort: **o-series models only** - - Constrains effort on reasoning for + reasoning_effort: 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. + supported values are `minimal`, `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), @@ -1906,12 +1901,11 @@ async def create( [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) during tool use. - reasoning_effort: **o-series models only** - - Constrains effort on reasoning for + reasoning_effort: 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. + supported values are `minimal`, `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), diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index cd1cb2bd7f..65f91396bd 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -115,6 +115,7 @@ def parse( top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, + verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -165,7 +166,7 @@ class MathResponse(BaseModel): print("answer: ", message.parsed.final_answer) ``` """ - _validate_input_tools(tools) + chat_completion_tools = _validate_input_tools(tools) extra_headers = { "X-Stainless-Helper-Method": "chat.completions.parse", @@ -176,7 +177,7 @@ def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseForma return _parse_chat_completion( response_format=response_format, chat_completion=raw_completion, - input_tools=tools, + input_tools=chat_completion_tools, ) return self._post( @@ -215,6 +216,7 @@ def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseForma "top_logprobs": top_logprobs, "top_p": top_p, "user": user, + "verbosity": verbosity, "web_search_options": web_search_options, }, completion_create_params.CompletionCreateParams, @@ -268,6 +270,7 @@ def create( top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, + verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -398,12 +401,11 @@ def create( hit rates. Replaces the `user` field. [Learn more](https://platform.openai.com/docs/guides/prompt-caching). - reasoning_effort: **o-series models only** - - Constrains effort on reasoning for + reasoning_effort: 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. + supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning + effort can result in faster responses and fewer tokens used on reasoning in a + response. response_format: An object specifying the format that the model must output. @@ -483,9 +485,9 @@ def create( `none` is the default when no tools are present. `auto` is the default if tools are present. - tools: A list of tools the model may call. Currently, only functions are supported as a - tool. Use this to provide a list of functions the model may generate JSON inputs - for. A max of 128 functions are supported. + tools: A list of tools the model may call. You can provide either + [custom tools](https://platform.openai.com/docs/guides/function-calling#custom-tools) + or [function tools](https://platform.openai.com/docs/guides/function-calling). top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to return at each token position, each with an associated log probability. @@ -503,6 +505,10 @@ def create( similar requests and to help OpenAI detect and prevent abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). + verbosity: Constrains the verbosity of the model's response. Lower values will result in + more concise responses, while higher values will result in more verbose + responses. Currently supported values are `low`, `medium`, and `high`. + web_search_options: This tool searches the web for relevant results to use in a response. Learn more about the [web search tool](https://platform.openai.com/docs/guides/tools-web-search?api-mode=chat). @@ -553,6 +559,7 @@ def create( top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, + verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -692,12 +699,11 @@ def create( hit rates. Replaces the `user` field. [Learn more](https://platform.openai.com/docs/guides/prompt-caching). - reasoning_effort: **o-series models only** - - Constrains effort on reasoning for + reasoning_effort: 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. + supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning + effort can result in faster responses and fewer tokens used on reasoning in a + response. response_format: An object specifying the format that the model must output. @@ -768,9 +774,9 @@ def create( `none` is the default when no tools are present. `auto` is the default if tools are present. - tools: A list of tools the model may call. Currently, only functions are supported as a - tool. Use this to provide a list of functions the model may generate JSON inputs - for. A max of 128 functions are supported. + tools: A list of tools the model may call. You can provide either + [custom tools](https://platform.openai.com/docs/guides/function-calling#custom-tools) + or [function tools](https://platform.openai.com/docs/guides/function-calling). top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to return at each token position, each with an associated log probability. @@ -788,6 +794,10 @@ def create( similar requests and to help OpenAI detect and prevent abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). + verbosity: Constrains the verbosity of the model's response. Lower values will result in + more concise responses, while higher values will result in more verbose + responses. Currently supported values are `low`, `medium`, and `high`. + web_search_options: This tool searches the web for relevant results to use in a response. Learn more about the [web search tool](https://platform.openai.com/docs/guides/tools-web-search?api-mode=chat). @@ -838,6 +848,7 @@ def create( top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, + verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -977,12 +988,11 @@ def create( hit rates. Replaces the `user` field. [Learn more](https://platform.openai.com/docs/guides/prompt-caching). - reasoning_effort: **o-series models only** - - Constrains effort on reasoning for + reasoning_effort: 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. + supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning + effort can result in faster responses and fewer tokens used on reasoning in a + response. response_format: An object specifying the format that the model must output. @@ -1053,9 +1063,9 @@ def create( `none` is the default when no tools are present. `auto` is the default if tools are present. - tools: A list of tools the model may call. Currently, only functions are supported as a - tool. Use this to provide a list of functions the model may generate JSON inputs - for. A max of 128 functions are supported. + tools: A list of tools the model may call. You can provide either + [custom tools](https://platform.openai.com/docs/guides/function-calling#custom-tools) + or [function tools](https://platform.openai.com/docs/guides/function-calling). top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to return at each token position, each with an associated log probability. @@ -1073,6 +1083,10 @@ def create( similar requests and to help OpenAI detect and prevent abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). + verbosity: Constrains the verbosity of the model's response. Lower values will result in + more concise responses, while higher values will result in more verbose + responses. Currently supported values are `low`, `medium`, and `high`. + web_search_options: This tool searches the web for relevant results to use in a response. Learn more about the [web search tool](https://platform.openai.com/docs/guides/tools-web-search?api-mode=chat). @@ -1123,6 +1137,7 @@ def create( top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, + verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -1168,6 +1183,7 @@ def create( "top_logprobs": top_logprobs, "top_p": top_p, "user": user, + "verbosity": verbosity, "web_search_options": web_search_options, }, completion_create_params.CompletionCreateParamsStreaming @@ -1396,6 +1412,7 @@ def stream( top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, + verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -1465,6 +1482,7 @@ def stream( top_logprobs=top_logprobs, top_p=top_p, user=user, + verbosity=verbosity, web_search_options=web_search_options, extra_headers=extra_headers, extra_query=extra_query, @@ -1536,6 +1554,7 @@ async def parse( top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, + verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -1636,6 +1655,7 @@ def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseForma "top_logprobs": top_logprobs, "top_p": top_p, "user": user, + "verbosity": verbosity, "web_search_options": web_search_options, }, completion_create_params.CompletionCreateParams, @@ -1689,6 +1709,7 @@ async def create( top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, + verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -1819,12 +1840,11 @@ async def create( hit rates. Replaces the `user` field. [Learn more](https://platform.openai.com/docs/guides/prompt-caching). - reasoning_effort: **o-series models only** - - Constrains effort on reasoning for + reasoning_effort: 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. + supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning + effort can result in faster responses and fewer tokens used on reasoning in a + response. response_format: An object specifying the format that the model must output. @@ -1904,9 +1924,9 @@ async def create( `none` is the default when no tools are present. `auto` is the default if tools are present. - tools: A list of tools the model may call. Currently, only functions are supported as a - tool. Use this to provide a list of functions the model may generate JSON inputs - for. A max of 128 functions are supported. + tools: A list of tools the model may call. You can provide either + [custom tools](https://platform.openai.com/docs/guides/function-calling#custom-tools) + or [function tools](https://platform.openai.com/docs/guides/function-calling). top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to return at each token position, each with an associated log probability. @@ -1924,6 +1944,10 @@ async def create( similar requests and to help OpenAI detect and prevent abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). + verbosity: Constrains the verbosity of the model's response. Lower values will result in + more concise responses, while higher values will result in more verbose + responses. Currently supported values are `low`, `medium`, and `high`. + web_search_options: This tool searches the web for relevant results to use in a response. Learn more about the [web search tool](https://platform.openai.com/docs/guides/tools-web-search?api-mode=chat). @@ -1974,6 +1998,7 @@ async def create( top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, + verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -2113,12 +2138,11 @@ async def create( hit rates. Replaces the `user` field. [Learn more](https://platform.openai.com/docs/guides/prompt-caching). - reasoning_effort: **o-series models only** - - Constrains effort on reasoning for + reasoning_effort: 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. + supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning + effort can result in faster responses and fewer tokens used on reasoning in a + response. response_format: An object specifying the format that the model must output. @@ -2189,9 +2213,9 @@ async def create( `none` is the default when no tools are present. `auto` is the default if tools are present. - tools: A list of tools the model may call. Currently, only functions are supported as a - tool. Use this to provide a list of functions the model may generate JSON inputs - for. A max of 128 functions are supported. + tools: A list of tools the model may call. You can provide either + [custom tools](https://platform.openai.com/docs/guides/function-calling#custom-tools) + or [function tools](https://platform.openai.com/docs/guides/function-calling). top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to return at each token position, each with an associated log probability. @@ -2209,6 +2233,10 @@ async def create( similar requests and to help OpenAI detect and prevent abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). + verbosity: Constrains the verbosity of the model's response. Lower values will result in + more concise responses, while higher values will result in more verbose + responses. Currently supported values are `low`, `medium`, and `high`. + web_search_options: This tool searches the web for relevant results to use in a response. Learn more about the [web search tool](https://platform.openai.com/docs/guides/tools-web-search?api-mode=chat). @@ -2259,6 +2287,7 @@ async def create( top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, + verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -2398,12 +2427,11 @@ async def create( hit rates. Replaces the `user` field. [Learn more](https://platform.openai.com/docs/guides/prompt-caching). - reasoning_effort: **o-series models only** - - Constrains effort on reasoning for + reasoning_effort: 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. + supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning + effort can result in faster responses and fewer tokens used on reasoning in a + response. response_format: An object specifying the format that the model must output. @@ -2474,9 +2502,9 @@ async def create( `none` is the default when no tools are present. `auto` is the default if tools are present. - tools: A list of tools the model may call. Currently, only functions are supported as a - tool. Use this to provide a list of functions the model may generate JSON inputs - for. A max of 128 functions are supported. + tools: A list of tools the model may call. You can provide either + [custom tools](https://platform.openai.com/docs/guides/function-calling#custom-tools) + or [function tools](https://platform.openai.com/docs/guides/function-calling). top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to return at each token position, each with an associated log probability. @@ -2494,6 +2522,10 @@ async def create( similar requests and to help OpenAI detect and prevent abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). + verbosity: Constrains the verbosity of the model's response. Lower values will result in + more concise responses, while higher values will result in more verbose + responses. Currently supported values are `low`, `medium`, and `high`. + web_search_options: This tool searches the web for relevant results to use in a response. Learn more about the [web search tool](https://platform.openai.com/docs/guides/tools-web-search?api-mode=chat). @@ -2544,6 +2576,7 @@ async def create( top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, + verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -2589,6 +2622,7 @@ async def create( "top_logprobs": top_logprobs, "top_p": top_p, "user": user, + "verbosity": verbosity, "web_search_options": web_search_options, }, completion_create_params.CompletionCreateParamsStreaming @@ -2817,6 +2851,7 @@ def stream( top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, + verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -2887,11 +2922,12 @@ def stream( top_logprobs=top_logprobs, top_p=top_p, user=user, + verbosity=verbosity, + web_search_options=web_search_options, extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, - web_search_options=web_search_options, ) return AsyncChatCompletionStreamManager( api_request, diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 6d2b133110..5ba22418ed 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -93,6 +93,7 @@ def create( service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, + stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, @@ -101,6 +102,7 @@ def create( top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, + verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -232,6 +234,8 @@ def create( [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) for more information. + stream_options: Options for streaming responses. Only set this when you set `stream: true`. + temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. We generally recommend altering this or `top_p` but @@ -259,8 +263,10 @@ def create( Learn more about [built-in tools](https://platform.openai.com/docs/guides/tools). - **Function calls (custom tools)**: Functions that are defined by you, enabling - the model to call your own code. Learn more about + the model to call your own code with strongly typed arguments and outputs. + Learn more about [function calling](https://platform.openai.com/docs/guides/function-calling). + You can also use custom tools to call your own code. top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to return at each token position, each with an associated log probability. @@ -285,6 +291,10 @@ def create( similar requests and to help OpenAI detect and prevent abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). + verbosity: Constrains the verbosity of the model's response. Lower values will result in + more concise responses, while higher values will result in more verbose + responses. Currently supported values are `low`, `medium`, and `high`. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -316,6 +326,7 @@ def create( safety_identifier: str | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, + stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, @@ -324,6 +335,7 @@ def create( top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, + verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -455,6 +467,8 @@ def create( store: Whether to store the generated model response for later retrieval via API. + stream_options: Options for streaming responses. Only set this when you set `stream: true`. + temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. We generally recommend altering this or `top_p` but @@ -482,8 +496,10 @@ def create( Learn more about [built-in tools](https://platform.openai.com/docs/guides/tools). - **Function calls (custom tools)**: Functions that are defined by you, enabling - the model to call your own code. Learn more about + the model to call your own code with strongly typed arguments and outputs. + Learn more about [function calling](https://platform.openai.com/docs/guides/function-calling). + You can also use custom tools to call your own code. top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to return at each token position, each with an associated log probability. @@ -508,6 +524,10 @@ def create( similar requests and to help OpenAI detect and prevent abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). + verbosity: Constrains the verbosity of the model's response. Lower values will result in + more concise responses, while higher values will result in more verbose + responses. Currently supported values are `low`, `medium`, and `high`. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -539,6 +559,7 @@ def create( safety_identifier: str | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, + stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, @@ -547,6 +568,7 @@ def create( top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, + verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -678,6 +700,8 @@ def create( store: Whether to store the generated model response for later retrieval via API. + stream_options: Options for streaming responses. Only set this when you set `stream: true`. + temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. We generally recommend altering this or `top_p` but @@ -705,8 +729,10 @@ def create( Learn more about [built-in tools](https://platform.openai.com/docs/guides/tools). - **Function calls (custom tools)**: Functions that are defined by you, enabling - the model to call your own code. Learn more about + the model to call your own code with strongly typed arguments and outputs. + Learn more about [function calling](https://platform.openai.com/docs/guides/function-calling). + You can also use custom tools to call your own code. top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to return at each token position, each with an associated log probability. @@ -731,6 +757,10 @@ def create( similar requests and to help OpenAI detect and prevent abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). + verbosity: Constrains the verbosity of the model's response. Lower values will result in + more concise responses, while higher values will result in more verbose + responses. Currently supported values are `low`, `medium`, and `high`. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -761,6 +791,7 @@ def create( service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, + stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, @@ -769,6 +800,7 @@ def create( top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, + verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -797,6 +829,7 @@ def create( "service_tier": service_tier, "store": store, "stream": stream, + "stream_options": stream_options, "temperature": temperature, "text": text, "tool_choice": tool_choice, @@ -805,6 +838,7 @@ def create( "top_p": top_p, "truncation": truncation, "user": user, + "verbosity": verbosity, }, response_create_params.ResponseCreateParamsStreaming if stream @@ -850,6 +884,7 @@ def stream( previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, + stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, @@ -881,6 +916,7 @@ def stream( previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, + stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, @@ -906,6 +942,7 @@ def stream( "previous_response_id": previous_response_id, "reasoning": reasoning, "store": store, + "stream_options": stream_options, "temperature": temperature, "text": text, "tool_choice": tool_choice, @@ -950,6 +987,7 @@ def stream( parallel_tool_calls=parallel_tool_calls, previous_response_id=previous_response_id, store=store, + stream_options=stream_options, stream=True, temperature=temperature, text=text, @@ -1007,6 +1045,7 @@ def parse( service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, + stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, @@ -1015,6 +1054,7 @@ def parse( top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, + verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1061,6 +1101,7 @@ def parser(raw_response: Response) -> ParsedResponse[TextFormatT]: "service_tier": service_tier, "store": store, "stream": stream, + "stream_options": stream_options, "temperature": temperature, "text": text, "tool_choice": tool_choice, @@ -1069,6 +1110,7 @@ def parser(raw_response: Response) -> ParsedResponse[TextFormatT]: "top_p": top_p, "truncation": truncation, "user": user, + "verbosity": verbosity, }, response_create_params.ResponseCreateParams, ), @@ -1090,6 +1132,7 @@ def retrieve( response_id: str, *, include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + include_obfuscation: bool | NotGiven = NOT_GIVEN, starting_after: int | NotGiven = NOT_GIVEN, stream: Literal[False] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -1154,6 +1197,13 @@ def retrieve( include: Additional fields to include in the response. See the `include` parameter for Response creation above for more information. + include_obfuscation: When true, stream obfuscation will be enabled. Stream obfuscation adds random + characters to an `obfuscation` field on streaming delta events to normalize + payload sizes as a mitigation to certain side-channel attacks. These obfuscation + fields are included by default, but add a small amount of overhead to the data + stream. You can set `include_obfuscation` to false to optimize for bandwidth if + you trust the network links between your application and the OpenAI API. + starting_after: The sequence number of the event after which to start streaming. stream: If set to true, the model response data will be streamed to the client as it is @@ -1180,6 +1230,7 @@ def retrieve( *, stream: Literal[True], include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + include_obfuscation: bool | NotGiven = NOT_GIVEN, starting_after: int | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -1202,6 +1253,13 @@ def retrieve( include: Additional fields to include in the response. See the `include` parameter for Response creation above for more information. + include_obfuscation: When true, stream obfuscation will be enabled. Stream obfuscation adds random + characters to an `obfuscation` field on streaming delta events to normalize + payload sizes as a mitigation to certain side-channel attacks. These obfuscation + fields are included by default, but add a small amount of overhead to the data + stream. You can set `include_obfuscation` to false to optimize for bandwidth if + you trust the network links between your application and the OpenAI API. + starting_after: The sequence number of the event after which to start streaming. extra_headers: Send extra headers @@ -1221,6 +1279,7 @@ def retrieve( *, stream: bool, include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + include_obfuscation: bool | NotGiven = NOT_GIVEN, starting_after: int | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -1243,6 +1302,13 @@ def retrieve( include: Additional fields to include in the response. See the `include` parameter for Response creation above for more information. + include_obfuscation: When true, stream obfuscation will be enabled. Stream obfuscation adds random + characters to an `obfuscation` field on streaming delta events to normalize + payload sizes as a mitigation to certain side-channel attacks. These obfuscation + fields are included by default, but add a small amount of overhead to the data + stream. You can set `include_obfuscation` to false to optimize for bandwidth if + you trust the network links between your application and the OpenAI API. + starting_after: The sequence number of the event after which to start streaming. extra_headers: Send extra headers @@ -1260,6 +1326,7 @@ def retrieve( response_id: str, *, include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + include_obfuscation: bool | NotGiven = NOT_GIVEN, starting_after: int | NotGiven = NOT_GIVEN, stream: Literal[False] | Literal[True] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -1281,6 +1348,7 @@ def retrieve( query=maybe_transform( { "include": include, + "include_obfuscation": include_obfuscation, "starting_after": starting_after, "stream": stream, }, @@ -1408,6 +1476,7 @@ async def create( service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, + stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, @@ -1416,6 +1485,7 @@ async def create( top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, + verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1547,6 +1617,8 @@ async def create( [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) for more information. + stream_options: Options for streaming responses. Only set this when you set `stream: true`. + temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. We generally recommend altering this or `top_p` but @@ -1574,8 +1646,10 @@ async def create( Learn more about [built-in tools](https://platform.openai.com/docs/guides/tools). - **Function calls (custom tools)**: Functions that are defined by you, enabling - the model to call your own code. Learn more about + the model to call your own code with strongly typed arguments and outputs. + Learn more about [function calling](https://platform.openai.com/docs/guides/function-calling). + You can also use custom tools to call your own code. top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to return at each token position, each with an associated log probability. @@ -1600,6 +1674,10 @@ async def create( similar requests and to help OpenAI detect and prevent abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). + verbosity: Constrains the verbosity of the model's response. Lower values will result in + more concise responses, while higher values will result in more verbose + responses. Currently supported values are `low`, `medium`, and `high`. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -1631,6 +1709,7 @@ async def create( safety_identifier: str | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, + stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, @@ -1639,6 +1718,7 @@ async def create( top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, + verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1770,6 +1850,8 @@ async def create( store: Whether to store the generated model response for later retrieval via API. + stream_options: Options for streaming responses. Only set this when you set `stream: true`. + temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. We generally recommend altering this or `top_p` but @@ -1797,8 +1879,10 @@ async def create( Learn more about [built-in tools](https://platform.openai.com/docs/guides/tools). - **Function calls (custom tools)**: Functions that are defined by you, enabling - the model to call your own code. Learn more about + the model to call your own code with strongly typed arguments and outputs. + Learn more about [function calling](https://platform.openai.com/docs/guides/function-calling). + You can also use custom tools to call your own code. top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to return at each token position, each with an associated log probability. @@ -1823,6 +1907,10 @@ async def create( similar requests and to help OpenAI detect and prevent abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). + verbosity: Constrains the verbosity of the model's response. Lower values will result in + more concise responses, while higher values will result in more verbose + responses. Currently supported values are `low`, `medium`, and `high`. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -1854,6 +1942,7 @@ async def create( safety_identifier: str | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, + stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, @@ -1862,6 +1951,7 @@ async def create( top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, + verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1993,6 +2083,8 @@ async def create( store: Whether to store the generated model response for later retrieval via API. + stream_options: Options for streaming responses. Only set this when you set `stream: true`. + temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. We generally recommend altering this or `top_p` but @@ -2020,8 +2112,10 @@ async def create( Learn more about [built-in tools](https://platform.openai.com/docs/guides/tools). - **Function calls (custom tools)**: Functions that are defined by you, enabling - the model to call your own code. Learn more about + the model to call your own code with strongly typed arguments and outputs. + Learn more about [function calling](https://platform.openai.com/docs/guides/function-calling). + You can also use custom tools to call your own code. top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to return at each token position, each with an associated log probability. @@ -2046,6 +2140,10 @@ async def create( similar requests and to help OpenAI detect and prevent abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). + verbosity: Constrains the verbosity of the model's response. Lower values will result in + more concise responses, while higher values will result in more verbose + responses. Currently supported values are `low`, `medium`, and `high`. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -2076,6 +2174,7 @@ async def create( service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, + stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, @@ -2084,6 +2183,7 @@ async def create( top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, + verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -2112,6 +2212,7 @@ async def create( "service_tier": service_tier, "store": store, "stream": stream, + "stream_options": stream_options, "temperature": temperature, "text": text, "tool_choice": tool_choice, @@ -2120,6 +2221,7 @@ async def create( "top_p": top_p, "truncation": truncation, "user": user, + "verbosity": verbosity, }, response_create_params.ResponseCreateParamsStreaming if stream @@ -2165,6 +2267,7 @@ def stream( previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, + stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, @@ -2196,6 +2299,7 @@ def stream( previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, + stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, @@ -2221,6 +2325,7 @@ def stream( "previous_response_id": previous_response_id, "reasoning": reasoning, "store": store, + "stream_options": stream_options, "temperature": temperature, "text": text, "tool_choice": tool_choice, @@ -2266,6 +2371,7 @@ def stream( parallel_tool_calls=parallel_tool_calls, previous_response_id=previous_response_id, store=store, + stream_options=stream_options, temperature=temperature, text=text, tool_choice=tool_choice, @@ -2326,6 +2432,7 @@ async def parse( service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, + stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, @@ -2334,6 +2441,7 @@ async def parse( top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, + verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -2380,6 +2488,7 @@ def parser(raw_response: Response) -> ParsedResponse[TextFormatT]: "service_tier": service_tier, "store": store, "stream": stream, + "stream_options": stream_options, "temperature": temperature, "text": text, "tool_choice": tool_choice, @@ -2388,6 +2497,7 @@ def parser(raw_response: Response) -> ParsedResponse[TextFormatT]: "top_p": top_p, "truncation": truncation, "user": user, + "verbosity": verbosity, }, response_create_params.ResponseCreateParams, ), @@ -2409,6 +2519,7 @@ async def retrieve( response_id: str, *, include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + include_obfuscation: bool | NotGiven = NOT_GIVEN, starting_after: int | NotGiven = NOT_GIVEN, stream: Literal[False] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -2473,6 +2584,13 @@ async def retrieve( include: Additional fields to include in the response. See the `include` parameter for Response creation above for more information. + include_obfuscation: When true, stream obfuscation will be enabled. Stream obfuscation adds random + characters to an `obfuscation` field on streaming delta events to normalize + payload sizes as a mitigation to certain side-channel attacks. These obfuscation + fields are included by default, but add a small amount of overhead to the data + stream. You can set `include_obfuscation` to false to optimize for bandwidth if + you trust the network links between your application and the OpenAI API. + starting_after: The sequence number of the event after which to start streaming. stream: If set to true, the model response data will be streamed to the client as it is @@ -2499,6 +2617,7 @@ async def retrieve( *, stream: Literal[True], include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + include_obfuscation: bool | NotGiven = NOT_GIVEN, starting_after: int | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -2521,6 +2640,13 @@ async def retrieve( include: Additional fields to include in the response. See the `include` parameter for Response creation above for more information. + include_obfuscation: When true, stream obfuscation will be enabled. Stream obfuscation adds random + characters to an `obfuscation` field on streaming delta events to normalize + payload sizes as a mitigation to certain side-channel attacks. These obfuscation + fields are included by default, but add a small amount of overhead to the data + stream. You can set `include_obfuscation` to false to optimize for bandwidth if + you trust the network links between your application and the OpenAI API. + starting_after: The sequence number of the event after which to start streaming. extra_headers: Send extra headers @@ -2540,6 +2666,7 @@ async def retrieve( *, stream: bool, include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + include_obfuscation: bool | NotGiven = NOT_GIVEN, starting_after: int | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -2562,6 +2689,13 @@ async def retrieve( include: Additional fields to include in the response. See the `include` parameter for Response creation above for more information. + include_obfuscation: When true, stream obfuscation will be enabled. Stream obfuscation adds random + characters to an `obfuscation` field on streaming delta events to normalize + payload sizes as a mitigation to certain side-channel attacks. These obfuscation + fields are included by default, but add a small amount of overhead to the data + stream. You can set `include_obfuscation` to false to optimize for bandwidth if + you trust the network links between your application and the OpenAI API. + starting_after: The sequence number of the event after which to start streaming. extra_headers: Send extra headers @@ -2579,6 +2713,7 @@ async def retrieve( response_id: str, *, include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + include_obfuscation: bool | NotGiven = NOT_GIVEN, starting_after: int | NotGiven = NOT_GIVEN, stream: Literal[False] | Literal[True] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -2600,6 +2735,7 @@ async def retrieve( query=await async_maybe_transform( { "include": include, + "include_obfuscation": include_obfuscation, "starting_after": starting_after, "stream": stream, }, diff --git a/src/openai/types/__init__.py b/src/openai/types/__init__.py index 51f3ee5c9b..1844f71ba7 100644 --- a/src/openai/types/__init__.py +++ b/src/openai/types/__init__.py @@ -18,8 +18,11 @@ FunctionDefinition as FunctionDefinition, FunctionParameters as FunctionParameters, ResponseFormatText as ResponseFormatText, + CustomToolInputFormat as CustomToolInputFormat, ResponseFormatJSONObject as ResponseFormatJSONObject, ResponseFormatJSONSchema as ResponseFormatJSONSchema, + ResponseFormatTextPython as ResponseFormatTextPython, + ResponseFormatTextGrammar as ResponseFormatTextGrammar, ) from .upload import Upload as Upload from .embedding import Embedding as Embedding diff --git a/src/openai/types/beta/assistant_create_params.py b/src/openai/types/beta/assistant_create_params.py index 8b3c331850..4b03dc0ea6 100644 --- a/src/openai/types/beta/assistant_create_params.py +++ b/src/openai/types/beta/assistant_create_params.py @@ -58,12 +58,12 @@ class AssistantCreateParams(TypedDict, total=False): """The name of the assistant. The maximum length is 256 characters.""" reasoning_effort: Optional[ReasoningEffort] - """**o-series 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. + supported values are `minimal`, `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] diff --git a/src/openai/types/beta/assistant_update_params.py b/src/openai/types/beta/assistant_update_params.py index b28094a6a5..e032554db8 100644 --- a/src/openai/types/beta/assistant_update_params.py +++ b/src/openai/types/beta/assistant_update_params.py @@ -36,6 +36,12 @@ class AssistantUpdateParams(TypedDict, total=False): model: Union[ str, Literal[ + "gpt-5", + "gpt-5-mini", + "gpt-5-nano", + "gpt-5-2025-08-07", + "gpt-5-mini-2025-08-07", + "gpt-5-nano-2025-08-07", "gpt-4.1", "gpt-4.1-mini", "gpt-4.1-nano", @@ -87,12 +93,12 @@ class AssistantUpdateParams(TypedDict, total=False): """The name of the assistant. The maximum length is 256 characters.""" reasoning_effort: Optional[ReasoningEffort] - """**o-series 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. + supported values are `minimal`, `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] diff --git a/src/openai/types/beta/threads/run_create_params.py b/src/openai/types/beta/threads/run_create_params.py index fc70227862..f9defcb19c 100644 --- a/src/openai/types/beta/threads/run_create_params.py +++ b/src/openai/types/beta/threads/run_create_params.py @@ -108,12 +108,12 @@ class RunCreateParamsBase(TypedDict, total=False): """ reasoning_effort: Optional[ReasoningEffort] - """**o-series 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. + supported values are `minimal`, `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] diff --git a/src/openai/types/chat/__init__.py b/src/openai/types/chat/__init__.py index dc26198567..ce1cf4522a 100644 --- a/src/openai/types/chat/__init__.py +++ b/src/openai/types/chat/__init__.py @@ -4,7 +4,6 @@ from .chat_completion import ChatCompletion as ChatCompletion from .chat_completion_role import ChatCompletionRole as ChatCompletionRole -from .chat_completion_tool import ChatCompletionTool as ChatCompletionTool from .chat_completion_audio import ChatCompletionAudio as ChatCompletionAudio from .chat_completion_chunk import ChatCompletionChunk as ChatCompletionChunk from .completion_list_params import CompletionListParams as CompletionListParams @@ -24,16 +23,20 @@ ) from .chat_completion_tool_param import ChatCompletionToolParam as ChatCompletionToolParam from .chat_completion_audio_param import ChatCompletionAudioParam as ChatCompletionAudioParam +from .chat_completion_function_tool import ChatCompletionFunctionTool as ChatCompletionFunctionTool from .chat_completion_message_param import ChatCompletionMessageParam as ChatCompletionMessageParam from .chat_completion_store_message import ChatCompletionStoreMessage as ChatCompletionStoreMessage from .chat_completion_token_logprob import ChatCompletionTokenLogprob as ChatCompletionTokenLogprob from .chat_completion_reasoning_effort import ChatCompletionReasoningEffort as ChatCompletionReasoningEffort from .chat_completion_content_part_text import ChatCompletionContentPartText as ChatCompletionContentPartText +from .chat_completion_custom_tool_param import ChatCompletionCustomToolParam as ChatCompletionCustomToolParam from .chat_completion_message_tool_call import ChatCompletionMessageToolCall as ChatCompletionMessageToolCall from .chat_completion_content_part_image import ChatCompletionContentPartImage as ChatCompletionContentPartImage from .chat_completion_content_part_param import ChatCompletionContentPartParam as ChatCompletionContentPartParam from .chat_completion_tool_message_param import ChatCompletionToolMessageParam as ChatCompletionToolMessageParam from .chat_completion_user_message_param import ChatCompletionUserMessageParam as ChatCompletionUserMessageParam +from .chat_completion_allowed_tools_param import ChatCompletionAllowedToolsParam as ChatCompletionAllowedToolsParam +from .chat_completion_function_tool_param import ChatCompletionFunctionToolParam as ChatCompletionFunctionToolParam from .chat_completion_stream_options_param import ChatCompletionStreamOptionsParam as ChatCompletionStreamOptionsParam from .chat_completion_system_message_param import ChatCompletionSystemMessageParam as ChatCompletionSystemMessageParam from .chat_completion_function_message_param import ( @@ -57,18 +60,36 @@ from .chat_completion_content_part_image_param import ( ChatCompletionContentPartImageParam as ChatCompletionContentPartImageParam, ) +from .chat_completion_message_custom_tool_call import ( + ChatCompletionMessageCustomToolCall as ChatCompletionMessageCustomToolCall, +) from .chat_completion_prediction_content_param import ( ChatCompletionPredictionContentParam as ChatCompletionPredictionContentParam, ) from .chat_completion_tool_choice_option_param import ( ChatCompletionToolChoiceOptionParam as ChatCompletionToolChoiceOptionParam, ) +from .chat_completion_allowed_tool_choice_param import ( + ChatCompletionAllowedToolChoiceParam as ChatCompletionAllowedToolChoiceParam, +) from .chat_completion_content_part_refusal_param import ( ChatCompletionContentPartRefusalParam as ChatCompletionContentPartRefusalParam, ) from .chat_completion_function_call_option_param import ( ChatCompletionFunctionCallOptionParam as ChatCompletionFunctionCallOptionParam, ) +from .chat_completion_message_function_tool_call import ( + ChatCompletionMessageFunctionToolCall as ChatCompletionMessageFunctionToolCall, +) from .chat_completion_content_part_input_audio_param import ( ChatCompletionContentPartInputAudioParam as ChatCompletionContentPartInputAudioParam, ) +from .chat_completion_message_custom_tool_call_param import ( + ChatCompletionMessageCustomToolCallParam as ChatCompletionMessageCustomToolCallParam, +) +from .chat_completion_named_tool_choice_custom_param import ( + ChatCompletionNamedToolChoiceCustomParam as ChatCompletionNamedToolChoiceCustomParam, +) +from .chat_completion_message_function_tool_call_param import ( + ChatCompletionMessageFunctionToolCallParam as ChatCompletionMessageFunctionToolCallParam, +) diff --git a/src/openai/types/chat/chat_completion_allowed_tool_choice_param.py b/src/openai/types/chat/chat_completion_allowed_tool_choice_param.py new file mode 100644 index 0000000000..813e6293f9 --- /dev/null +++ b/src/openai/types/chat/chat_completion_allowed_tool_choice_param.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +from .chat_completion_allowed_tools_param import ChatCompletionAllowedToolsParam + +__all__ = ["ChatCompletionAllowedToolChoiceParam"] + + +class ChatCompletionAllowedToolChoiceParam(TypedDict, total=False): + allowed_tools: Required[ChatCompletionAllowedToolsParam] + """Constrains the tools available to the model to a pre-defined set.""" + + type: Required[Literal["allowed_tools"]] + """Allowed tool configuration type. Always `allowed_tools`.""" diff --git a/src/openai/types/chat/chat_completion_allowed_tools_param.py b/src/openai/types/chat/chat_completion_allowed_tools_param.py new file mode 100644 index 0000000000..d9b72d8f34 --- /dev/null +++ b/src/openai/types/chat/chat_completion_allowed_tools_param.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Iterable +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ChatCompletionAllowedToolsParam"] + + +class ChatCompletionAllowedToolsParam(TypedDict, total=False): + mode: Required[Literal["auto", "required"]] + """Constrains the tools available to the model to a pre-defined set. + + `auto` allows the model to pick from among the allowed tools and generate a + message. + + `required` requires the model to call one or more of the allowed tools. + """ + + tools: Required[Iterable[Dict[str, object]]] + """A list of tool definitions that the model should be allowed to call. + + For the Chat Completions API, the list of tool definitions might look like: + + ```json + [ + { "type": "function", "function": { "name": "get_weather" } }, + { "type": "function", "function": { "name": "get_time" } } + ] + ``` + """ diff --git a/src/openai/types/chat/chat_completion_custom_tool_param.py b/src/openai/types/chat/chat_completion_custom_tool_param.py new file mode 100644 index 0000000000..14959ee449 --- /dev/null +++ b/src/openai/types/chat/chat_completion_custom_tool_param.py @@ -0,0 +1,58 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +__all__ = [ + "ChatCompletionCustomToolParam", + "Custom", + "CustomFormat", + "CustomFormatText", + "CustomFormatGrammar", + "CustomFormatGrammarGrammar", +] + + +class CustomFormatText(TypedDict, total=False): + type: Required[Literal["text"]] + """Unconstrained text format. Always `text`.""" + + +class CustomFormatGrammarGrammar(TypedDict, total=False): + definition: Required[str] + """The grammar definition.""" + + syntax: Required[Literal["lark", "regex"]] + """The syntax of the grammar definition. One of `lark` or `regex`.""" + + +class CustomFormatGrammar(TypedDict, total=False): + grammar: Required[CustomFormatGrammarGrammar] + """Your chosen grammar.""" + + type: Required[Literal["grammar"]] + """Grammar format. Always `grammar`.""" + + +CustomFormat: TypeAlias = Union[CustomFormatText, CustomFormatGrammar] + + +class Custom(TypedDict, total=False): + name: Required[str] + """The name of the custom tool, used to identify it in tool calls.""" + + description: str + """Optional description of the custom tool, used to provide more context.""" + + format: CustomFormat + """The input format for the custom tool. Default is unconstrained text.""" + + +class ChatCompletionCustomToolParam(TypedDict, total=False): + custom: Required[Custom] + """Properties of the custom tool.""" + + type: Required[Literal["custom"]] + """The type of the custom tool. Always `custom`.""" diff --git a/src/openai/types/chat/chat_completion_tool.py b/src/openai/types/chat/chat_completion_function_tool.py similarity index 80% rename from src/openai/types/chat/chat_completion_tool.py rename to src/openai/types/chat/chat_completion_function_tool.py index ae9126f906..641568acf1 100644 --- a/src/openai/types/chat/chat_completion_tool.py +++ b/src/openai/types/chat/chat_completion_function_tool.py @@ -5,10 +5,10 @@ from ..._models import BaseModel from ..shared.function_definition import FunctionDefinition -__all__ = ["ChatCompletionTool"] +__all__ = ["ChatCompletionFunctionTool"] -class ChatCompletionTool(BaseModel): +class ChatCompletionFunctionTool(BaseModel): function: FunctionDefinition type: Literal["function"] diff --git a/src/openai/types/chat/chat_completion_function_tool_param.py b/src/openai/types/chat/chat_completion_function_tool_param.py new file mode 100644 index 0000000000..a39feea542 --- /dev/null +++ b/src/openai/types/chat/chat_completion_function_tool_param.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +from ..shared_params.function_definition import FunctionDefinition + +__all__ = ["ChatCompletionFunctionToolParam"] + + +class ChatCompletionFunctionToolParam(TypedDict, total=False): + function: Required[FunctionDefinition] + + type: Required[Literal["function"]] + """The type of the tool. Currently, only `function` is supported.""" diff --git a/src/openai/types/chat/chat_completion_message_custom_tool_call.py b/src/openai/types/chat/chat_completion_message_custom_tool_call.py new file mode 100644 index 0000000000..b13c176afe --- /dev/null +++ b/src/openai/types/chat/chat_completion_message_custom_tool_call.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ChatCompletionMessageCustomToolCall", "Custom"] + + +class Custom(BaseModel): + input: str + """The input for the custom tool call generated by the model.""" + + name: str + """The name of the custom tool to call.""" + + +class ChatCompletionMessageCustomToolCall(BaseModel): + id: str + """The ID of the tool call.""" + + custom: Custom + """The custom tool that the model called.""" + + type: Literal["custom"] + """The type of the tool. Always `custom`.""" diff --git a/src/openai/types/chat/chat_completion_message_custom_tool_call_param.py b/src/openai/types/chat/chat_completion_message_custom_tool_call_param.py new file mode 100644 index 0000000000..3753e0f200 --- /dev/null +++ b/src/openai/types/chat/chat_completion_message_custom_tool_call_param.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ChatCompletionMessageCustomToolCallParam", "Custom"] + + +class Custom(TypedDict, total=False): + input: Required[str] + """The input for the custom tool call generated by the model.""" + + name: Required[str] + """The name of the custom tool to call.""" + + +class ChatCompletionMessageCustomToolCallParam(TypedDict, total=False): + id: Required[str] + """The ID of the tool call.""" + + custom: Required[Custom] + """The custom tool that the model called.""" + + type: Required[Literal["custom"]] + """The type of the tool. Always `custom`.""" diff --git a/src/openai/types/chat/chat_completion_message_function_tool_call.py b/src/openai/types/chat/chat_completion_message_function_tool_call.py new file mode 100644 index 0000000000..d056d9aff6 --- /dev/null +++ b/src/openai/types/chat/chat_completion_message_function_tool_call.py @@ -0,0 +1,31 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ChatCompletionMessageFunctionToolCall", "Function"] + + +class Function(BaseModel): + arguments: str + """ + The arguments to call the function with, as generated by the model in JSON + format. Note that the model does not always generate valid JSON, and may + hallucinate parameters not defined by your function schema. Validate the + arguments in your code before calling your function. + """ + + name: str + """The name of the function to call.""" + + +class ChatCompletionMessageFunctionToolCall(BaseModel): + id: str + """The ID of the tool call.""" + + function: Function + """The function that the model called.""" + + type: Literal["function"] + """The type of the tool. Currently, only `function` is supported.""" diff --git a/src/openai/types/chat/chat_completion_message_function_tool_call_param.py b/src/openai/types/chat/chat_completion_message_function_tool_call_param.py new file mode 100644 index 0000000000..7c827edd2c --- /dev/null +++ b/src/openai/types/chat/chat_completion_message_function_tool_call_param.py @@ -0,0 +1,31 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ChatCompletionMessageFunctionToolCallParam", "Function"] + + +class Function(TypedDict, total=False): + arguments: Required[str] + """ + The arguments to call the function with, as generated by the model in JSON + format. Note that the model does not always generate valid JSON, and may + hallucinate parameters not defined by your function schema. Validate the + arguments in your code before calling your function. + """ + + name: Required[str] + """The name of the function to call.""" + + +class ChatCompletionMessageFunctionToolCallParam(TypedDict, total=False): + id: Required[str] + """The ID of the tool call.""" + + function: Required[Function] + """The function that the model called.""" + + type: Required[Literal["function"]] + """The type of the tool. Currently, only `function` is supported.""" diff --git a/src/openai/types/chat/chat_completion_message_tool_call.py b/src/openai/types/chat/chat_completion_message_tool_call.py index 4fec667096..c254774626 100644 --- a/src/openai/types/chat/chat_completion_message_tool_call.py +++ b/src/openai/types/chat/chat_completion_message_tool_call.py @@ -1,31 +1,15 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing_extensions import Literal +from typing import Union +from typing_extensions import Annotated, TypeAlias -from ..._models import BaseModel +from ..._utils import PropertyInfo +from .chat_completion_message_custom_tool_call import ChatCompletionMessageCustomToolCall +from .chat_completion_message_function_tool_call import ChatCompletionMessageFunctionToolCall -__all__ = ["ChatCompletionMessageToolCall", "Function"] +__all__ = ["ChatCompletionMessageToolCall"] - -class Function(BaseModel): - arguments: str - """ - The arguments to call the function with, as generated by the model in JSON - format. Note that the model does not always generate valid JSON, and may - hallucinate parameters not defined by your function schema. Validate the - arguments in your code before calling your function. - """ - - name: str - """The name of the function to call.""" - - -class ChatCompletionMessageToolCall(BaseModel): - id: str - """The ID of the tool call.""" - - function: Function - """The function that the model called.""" - - type: Literal["function"] - """The type of the tool. Currently, only `function` is supported.""" +ChatCompletionMessageToolCall: TypeAlias = Annotated[ + Union[ChatCompletionMessageFunctionToolCall, ChatCompletionMessageCustomToolCall], + PropertyInfo(discriminator="type"), +] diff --git a/src/openai/types/chat/chat_completion_message_tool_call_param.py b/src/openai/types/chat/chat_completion_message_tool_call_param.py index f616c363d0..96ba6521f0 100644 --- a/src/openai/types/chat/chat_completion_message_tool_call_param.py +++ b/src/openai/types/chat/chat_completion_message_tool_call_param.py @@ -2,30 +2,14 @@ from __future__ import annotations -from typing_extensions import Literal, Required, TypedDict +from typing import Union +from typing_extensions import TypeAlias -__all__ = ["ChatCompletionMessageToolCallParam", "Function"] +from .chat_completion_message_custom_tool_call_param import ChatCompletionMessageCustomToolCallParam +from .chat_completion_message_function_tool_call_param import ChatCompletionMessageFunctionToolCallParam +__all__ = ["ChatCompletionMessageToolCallParam"] -class Function(TypedDict, total=False): - arguments: Required[str] - """ - The arguments to call the function with, as generated by the model in JSON - format. Note that the model does not always generate valid JSON, and may - hallucinate parameters not defined by your function schema. Validate the - arguments in your code before calling your function. - """ - - name: Required[str] - """The name of the function to call.""" - - -class ChatCompletionMessageToolCallParam(TypedDict, total=False): - id: Required[str] - """The ID of the tool call.""" - - function: Required[Function] - """The function that the model called.""" - - type: Required[Literal["function"]] - """The type of the tool. Currently, only `function` is supported.""" +ChatCompletionMessageToolCallParam: TypeAlias = Union[ + ChatCompletionMessageFunctionToolCallParam, ChatCompletionMessageCustomToolCallParam +] diff --git a/src/openai/types/chat/chat_completion_named_tool_choice_custom_param.py b/src/openai/types/chat/chat_completion_named_tool_choice_custom_param.py new file mode 100644 index 0000000000..1c123c0acb --- /dev/null +++ b/src/openai/types/chat/chat_completion_named_tool_choice_custom_param.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ChatCompletionNamedToolChoiceCustomParam", "Custom"] + + +class Custom(TypedDict, total=False): + name: Required[str] + """The name of the custom tool to call.""" + + +class ChatCompletionNamedToolChoiceCustomParam(TypedDict, total=False): + custom: Required[Custom] + + type: Required[Literal["custom"]] + """For custom tool calling, the type is always `custom`.""" diff --git a/src/openai/types/chat/chat_completion_named_tool_choice_param.py b/src/openai/types/chat/chat_completion_named_tool_choice_param.py index 369f8b42dd..ae1acfb909 100644 --- a/src/openai/types/chat/chat_completion_named_tool_choice_param.py +++ b/src/openai/types/chat/chat_completion_named_tool_choice_param.py @@ -16,4 +16,4 @@ class ChatCompletionNamedToolChoiceParam(TypedDict, total=False): function: Required[Function] type: Required[Literal["function"]] - """The type of the tool. Currently, only `function` is supported.""" + """For function calling, the type is always `function`.""" diff --git a/src/openai/types/chat/chat_completion_stream_options_param.py b/src/openai/types/chat/chat_completion_stream_options_param.py index 471e0eba98..fc3191d2d1 100644 --- a/src/openai/types/chat/chat_completion_stream_options_param.py +++ b/src/openai/types/chat/chat_completion_stream_options_param.py @@ -8,6 +8,17 @@ class ChatCompletionStreamOptionsParam(TypedDict, total=False): + include_obfuscation: bool + """When true, stream obfuscation will be enabled. + + Stream obfuscation adds random characters to an `obfuscation` field on streaming + delta events to normalize payload sizes as a mitigation to certain side-channel + attacks. These obfuscation fields are included by default, but add a small + amount of overhead to the data stream. You can set `include_obfuscation` to + false to optimize for bandwidth if you trust the network links between your + application and the OpenAI API. + """ + include_usage: bool """If set, an additional chunk will be streamed before the `data: [DONE]` message. diff --git a/src/openai/types/chat/chat_completion_tool_choice_option_param.py b/src/openai/types/chat/chat_completion_tool_choice_option_param.py index 7dedf041b7..f3bb0a46df 100644 --- a/src/openai/types/chat/chat_completion_tool_choice_option_param.py +++ b/src/openai/types/chat/chat_completion_tool_choice_option_param.py @@ -6,9 +6,14 @@ from typing_extensions import Literal, TypeAlias from .chat_completion_named_tool_choice_param import ChatCompletionNamedToolChoiceParam +from .chat_completion_allowed_tool_choice_param import ChatCompletionAllowedToolChoiceParam +from .chat_completion_named_tool_choice_custom_param import ChatCompletionNamedToolChoiceCustomParam __all__ = ["ChatCompletionToolChoiceOptionParam"] ChatCompletionToolChoiceOptionParam: TypeAlias = Union[ - Literal["none", "auto", "required"], ChatCompletionNamedToolChoiceParam + Literal["none", "auto", "required"], + ChatCompletionAllowedToolChoiceParam, + ChatCompletionNamedToolChoiceParam, + ChatCompletionNamedToolChoiceCustomParam, ] diff --git a/src/openai/types/chat/chat_completion_tool_param.py b/src/openai/types/chat/chat_completion_tool_param.py index 6c2b1a36f0..7cd9743ea3 100644 --- a/src/openai/types/chat/chat_completion_tool_param.py +++ b/src/openai/types/chat/chat_completion_tool_param.py @@ -2,15 +2,12 @@ from __future__ import annotations -from typing_extensions import Literal, Required, TypedDict +from typing import Union +from typing_extensions import TypeAlias -from ..shared_params.function_definition import FunctionDefinition +from .chat_completion_custom_tool_param import ChatCompletionCustomToolParam +from .chat_completion_function_tool_param import ChatCompletionFunctionToolParam __all__ = ["ChatCompletionToolParam"] - -class ChatCompletionToolParam(TypedDict, total=False): - function: Required[FunctionDefinition] - - type: Required[Literal["function"]] - """The type of the tool. Currently, only `function` is supported.""" +ChatCompletionToolParam: TypeAlias = Union[ChatCompletionFunctionToolParam, ChatCompletionCustomToolParam] diff --git a/src/openai/types/chat/completion_create_params.py b/src/openai/types/chat/completion_create_params.py index 20d7c187f8..011067af1a 100644 --- a/src/openai/types/chat/completion_create_params.py +++ b/src/openai/types/chat/completion_create_params.py @@ -185,12 +185,12 @@ class CompletionCreateParamsBase(TypedDict, total=False): """ reasoning_effort: Optional[ReasoningEffort] - """**o-series 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. + supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning + effort can result in faster responses and fewer tokens used on reasoning in a + response. """ response_format: ResponseFormat @@ -287,9 +287,9 @@ class CompletionCreateParamsBase(TypedDict, total=False): tools: Iterable[ChatCompletionToolParam] """A list of tools the model may call. - Currently, only functions are supported as a tool. Use this to provide a list of - functions the model may generate JSON inputs for. A max of 128 functions are - supported. + You can provide either + [custom tools](https://platform.openai.com/docs/guides/function-calling#custom-tools) + or [function tools](https://platform.openai.com/docs/guides/function-calling). """ top_logprobs: Optional[int] @@ -317,6 +317,14 @@ class CompletionCreateParamsBase(TypedDict, total=False): [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). """ + verbosity: Optional[Literal["low", "medium", "high"]] + """Constrains the verbosity of the model's response. + + Lower values will result in more concise responses, while higher values will + result in more verbose responses. Currently supported values are `low`, + `medium`, and `high`. + """ + web_search_options: WebSearchOptions """ This tool searches the web for relevant results to use in a response. Learn more diff --git a/src/openai/types/chat/parsed_function_tool_call.py b/src/openai/types/chat/parsed_function_tool_call.py index 3e90789f85..e06b3546cb 100644 --- a/src/openai/types/chat/parsed_function_tool_call.py +++ b/src/openai/types/chat/parsed_function_tool_call.py @@ -2,7 +2,7 @@ from typing import Optional -from .chat_completion_message_tool_call import Function, ChatCompletionMessageToolCall +from .chat_completion_message_function_tool_call import Function, ChatCompletionMessageFunctionToolCall __all__ = ["ParsedFunctionToolCall", "ParsedFunction"] @@ -24,6 +24,6 @@ class ParsedFunction(Function): """ -class ParsedFunctionToolCall(ChatCompletionMessageToolCall): +class ParsedFunctionToolCall(ChatCompletionMessageFunctionToolCall): function: ParsedFunction """The function that the model called.""" diff --git a/src/openai/types/evals/create_eval_completions_run_data_source.py b/src/openai/types/evals/create_eval_completions_run_data_source.py index a0eaa5addb..bb39d1d3e5 100644 --- a/src/openai/types/evals/create_eval_completions_run_data_source.py +++ b/src/openai/types/evals/create_eval_completions_run_data_source.py @@ -6,10 +6,10 @@ from ..._utils import PropertyInfo from ..._models import BaseModel from ..shared.metadata import Metadata -from ..chat.chat_completion_tool import ChatCompletionTool from ..shared.response_format_text import ResponseFormatText from ..responses.easy_input_message import EasyInputMessage from ..responses.response_input_text import ResponseInputText +from ..chat.chat_completion_function_tool import ChatCompletionFunctionTool from ..shared.response_format_json_object import ResponseFormatJSONObject from ..shared.response_format_json_schema import ResponseFormatJSONSchema @@ -186,7 +186,7 @@ class SamplingParams(BaseModel): temperature: Optional[float] = None """A higher temperature increases randomness in the outputs.""" - tools: Optional[List[ChatCompletionTool]] = None + tools: Optional[List[ChatCompletionFunctionTool]] = None """A list of tools the model may call. Currently, only functions are supported as a tool. Use this to provide a list of diff --git a/src/openai/types/evals/create_eval_completions_run_data_source_param.py b/src/openai/types/evals/create_eval_completions_run_data_source_param.py index 8892b68b17..7c71ecbe88 100644 --- a/src/openai/types/evals/create_eval_completions_run_data_source_param.py +++ b/src/openai/types/evals/create_eval_completions_run_data_source_param.py @@ -6,10 +6,10 @@ from typing_extensions import Literal, Required, TypeAlias, TypedDict from ..shared_params.metadata import Metadata -from ..chat.chat_completion_tool_param import ChatCompletionToolParam from ..responses.easy_input_message_param import EasyInputMessageParam from ..shared_params.response_format_text import ResponseFormatText from ..responses.response_input_text_param import ResponseInputTextParam +from ..chat.chat_completion_function_tool_param import ChatCompletionFunctionToolParam from ..shared_params.response_format_json_object import ResponseFormatJSONObject from ..shared_params.response_format_json_schema import ResponseFormatJSONSchema @@ -180,7 +180,7 @@ class SamplingParams(TypedDict, total=False): temperature: float """A higher temperature increases randomness in the outputs.""" - tools: Iterable[ChatCompletionToolParam] + tools: Iterable[ChatCompletionFunctionToolParam] """A list of tools the model may call. Currently, only functions are supported as a tool. Use this to provide a list of diff --git a/src/openai/types/responses/__init__.py b/src/openai/types/responses/__init__.py index 2e502ed69f..74d8688081 100644 --- a/src/openai/types/responses/__init__.py +++ b/src/openai/types/responses/__init__.py @@ -5,6 +5,7 @@ from .tool import Tool as Tool from .response import Response as Response from .tool_param import ToolParam as ToolParam +from .custom_tool import CustomTool as CustomTool from .computer_tool import ComputerTool as ComputerTool from .function_tool import FunctionTool as FunctionTool from .response_item import ResponseItem as ResponseItem @@ -23,15 +24,18 @@ from .tool_choice_mcp import ToolChoiceMcp as ToolChoiceMcp from .web_search_tool import WebSearchTool as WebSearchTool from .file_search_tool import FileSearchTool as FileSearchTool +from .custom_tool_param import CustomToolParam as CustomToolParam from .tool_choice_types import ToolChoiceTypes as ToolChoiceTypes from .easy_input_message import EasyInputMessage as EasyInputMessage from .response_item_list import ResponseItemList as ResponseItemList +from .tool_choice_custom import ToolChoiceCustom as ToolChoiceCustom from .computer_tool_param import ComputerToolParam as ComputerToolParam from .function_tool_param import FunctionToolParam as FunctionToolParam from .response_includable import ResponseIncludable as ResponseIncludable from .response_input_file import ResponseInputFile as ResponseInputFile from .response_input_item import ResponseInputItem as ResponseInputItem from .response_input_text import ResponseInputText as ResponseInputText +from .tool_choice_allowed import ToolChoiceAllowed as ToolChoiceAllowed from .tool_choice_options import ToolChoiceOptions as ToolChoiceOptions from .response_error_event import ResponseErrorEvent as ResponseErrorEvent from .response_input_image import ResponseInputImage as ResponseInputImage @@ -59,12 +63,15 @@ from .response_completed_event import ResponseCompletedEvent as ResponseCompletedEvent from .response_retrieve_params import ResponseRetrieveParams as ResponseRetrieveParams from .response_text_done_event import ResponseTextDoneEvent as ResponseTextDoneEvent +from .tool_choice_custom_param import ToolChoiceCustomParam as ToolChoiceCustomParam from .response_audio_done_event import ResponseAudioDoneEvent as ResponseAudioDoneEvent +from .response_custom_tool_call import ResponseCustomToolCall as ResponseCustomToolCall from .response_incomplete_event import ResponseIncompleteEvent as ResponseIncompleteEvent from .response_input_file_param import ResponseInputFileParam as ResponseInputFileParam from .response_input_item_param import ResponseInputItemParam as ResponseInputItemParam from .response_input_text_param import ResponseInputTextParam as ResponseInputTextParam from .response_text_delta_event import ResponseTextDeltaEvent as ResponseTextDeltaEvent +from .tool_choice_allowed_param import ToolChoiceAllowedParam as ToolChoiceAllowedParam from .response_audio_delta_event import ResponseAudioDeltaEvent as ResponseAudioDeltaEvent from .response_in_progress_event import ResponseInProgressEvent as ResponseInProgressEvent from .response_input_image_param import ResponseInputImageParam as ResponseInputImageParam @@ -84,8 +91,10 @@ from .response_reasoning_item_param import ResponseReasoningItemParam as ResponseReasoningItemParam from .response_file_search_tool_call import ResponseFileSearchToolCall as ResponseFileSearchToolCall from .response_mcp_call_failed_event import ResponseMcpCallFailedEvent as ResponseMcpCallFailedEvent +from .response_custom_tool_call_param import ResponseCustomToolCallParam as ResponseCustomToolCallParam from .response_output_item_done_event import ResponseOutputItemDoneEvent as ResponseOutputItemDoneEvent from .response_content_part_done_event import ResponseContentPartDoneEvent as ResponseContentPartDoneEvent +from .response_custom_tool_call_output import ResponseCustomToolCallOutput as ResponseCustomToolCallOutput from .response_function_tool_call_item import ResponseFunctionToolCallItem as ResponseFunctionToolCallItem from .response_output_item_added_event import ResponseOutputItemAddedEvent as ResponseOutputItemAddedEvent from .response_computer_tool_call_param import ResponseComputerToolCallParam as ResponseComputerToolCallParam @@ -105,6 +114,9 @@ from .response_audio_transcript_delta_event import ( ResponseAudioTranscriptDeltaEvent as ResponseAudioTranscriptDeltaEvent, ) +from .response_custom_tool_call_output_param import ( + ResponseCustomToolCallOutputParam as ResponseCustomToolCallOutputParam, +) from .response_mcp_call_arguments_done_event import ( ResponseMcpCallArgumentsDoneEvent as ResponseMcpCallArgumentsDoneEvent, ) @@ -153,6 +165,9 @@ from .response_mcp_list_tools_in_progress_event import ( ResponseMcpListToolsInProgressEvent as ResponseMcpListToolsInProgressEvent, ) +from .response_custom_tool_call_input_done_event import ( + ResponseCustomToolCallInputDoneEvent as ResponseCustomToolCallInputDoneEvent, +) from .response_reasoning_summary_part_done_event import ( ResponseReasoningSummaryPartDoneEvent as ResponseReasoningSummaryPartDoneEvent, ) @@ -162,6 +177,9 @@ from .response_web_search_call_in_progress_event import ( ResponseWebSearchCallInProgressEvent as ResponseWebSearchCallInProgressEvent, ) +from .response_custom_tool_call_input_delta_event import ( + ResponseCustomToolCallInputDeltaEvent as ResponseCustomToolCallInputDeltaEvent, +) from .response_file_search_call_in_progress_event import ( ResponseFileSearchCallInProgressEvent as ResponseFileSearchCallInProgressEvent, ) diff --git a/src/openai/types/responses/custom_tool.py b/src/openai/types/responses/custom_tool.py new file mode 100644 index 0000000000..c16ae715eb --- /dev/null +++ b/src/openai/types/responses/custom_tool.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel +from ..shared.custom_tool_input_format import CustomToolInputFormat + +__all__ = ["CustomTool"] + + +class CustomTool(BaseModel): + name: str + """The name of the custom tool, used to identify it in tool calls.""" + + type: Literal["custom"] + """The type of the custom tool. Always `custom`.""" + + description: Optional[str] = None + """Optional description of the custom tool, used to provide more context.""" + + format: Optional[CustomToolInputFormat] = None + """The input format for the custom tool. Default is unconstrained text.""" diff --git a/src/openai/types/responses/custom_tool_param.py b/src/openai/types/responses/custom_tool_param.py new file mode 100644 index 0000000000..2afc8b19b8 --- /dev/null +++ b/src/openai/types/responses/custom_tool_param.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +from ..shared_params.custom_tool_input_format import CustomToolInputFormat + +__all__ = ["CustomToolParam"] + + +class CustomToolParam(TypedDict, total=False): + name: Required[str] + """The name of the custom tool, used to identify it in tool calls.""" + + type: Required[Literal["custom"]] + """The type of the custom tool. Always `custom`.""" + + description: str + """Optional description of the custom tool, used to provide more context.""" + + format: CustomToolInputFormat + """The input format for the custom tool. Default is unconstrained text.""" diff --git a/src/openai/types/responses/parsed_response.py b/src/openai/types/responses/parsed_response.py index e59e86d2b7..1d9db361dd 100644 --- a/src/openai/types/responses/parsed_response.py +++ b/src/openai/types/responses/parsed_response.py @@ -19,6 +19,7 @@ from .response_output_message import ResponseOutputMessage from .response_output_refusal import ResponseOutputRefusal from .response_reasoning_item import ResponseReasoningItem +from .response_custom_tool_call import ResponseCustomToolCall from .response_computer_tool_call import ResponseComputerToolCall from .response_function_tool_call import ResponseFunctionToolCall from .response_function_web_search import ResponseFunctionWebSearch @@ -73,6 +74,7 @@ class ParsedResponseFunctionToolCall(ResponseFunctionToolCall): LocalShellCallAction, McpListTools, ResponseCodeInterpreterToolCall, + ResponseCustomToolCall, ], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/responses/response.py b/src/openai/types/responses/response.py index 7db466dfe7..07a82cb4ac 100644 --- a/src/openai/types/responses/response.py +++ b/src/openai/types/responses/response.py @@ -13,7 +13,9 @@ from ..shared.metadata import Metadata from ..shared.reasoning import Reasoning from .tool_choice_types import ToolChoiceTypes +from .tool_choice_custom import ToolChoiceCustom from .response_input_item import ResponseInputItem +from .tool_choice_allowed import ToolChoiceAllowed from .tool_choice_options import ToolChoiceOptions from .response_output_item import ResponseOutputItem from .response_text_config import ResponseTextConfig @@ -28,7 +30,9 @@ class IncompleteDetails(BaseModel): """The reason why the response is incomplete.""" -ToolChoice: TypeAlias = Union[ToolChoiceOptions, ToolChoiceTypes, ToolChoiceFunction, ToolChoiceMcp] +ToolChoice: TypeAlias = Union[ + ToolChoiceOptions, ToolChoiceAllowed, ToolChoiceTypes, ToolChoiceFunction, ToolChoiceMcp, ToolChoiceCustom +] class Response(BaseModel): @@ -116,8 +120,10 @@ class Response(BaseModel): Learn more about [built-in tools](https://platform.openai.com/docs/guides/tools). - **Function calls (custom tools)**: Functions that are defined by you, enabling - the model to call your own code. Learn more about + the model to call your own code with strongly typed arguments and outputs. + Learn more about [function calling](https://platform.openai.com/docs/guides/function-calling). + You can also use custom tools to call your own code. """ top_p: Optional[float] = None @@ -130,8 +136,8 @@ class Response(BaseModel): """ background: Optional[bool] = None - """Whether to run the model response in the background. - + """ + Whether to run the model response in the background. [Learn more](https://platform.openai.com/docs/guides/background). """ @@ -253,18 +259,3 @@ class Response(BaseModel): [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). """ - @property - def output_text(self) -> str: - """Convenience property that aggregates all `output_text` items from the `output` - list. - - If no `output_text` content blocks exist, then an empty string is returned. - """ - texts: List[str] = [] - for output in self.output: - if output.type == "message": - for content in output.content: - if content.type == "output_text": - texts.append(content.text) - - return "".join(texts) diff --git a/src/openai/types/responses/response_create_params.py b/src/openai/types/responses/response_create_params.py index 4a78d7c028..53af325328 100644 --- a/src/openai/types/responses/response_create_params.py +++ b/src/openai/types/responses/response_create_params.py @@ -14,12 +14,15 @@ from ..shared_params.metadata import Metadata from .tool_choice_types_param import ToolChoiceTypesParam from ..shared_params.reasoning import Reasoning +from .tool_choice_custom_param import ToolChoiceCustomParam +from .tool_choice_allowed_param import ToolChoiceAllowedParam from .response_text_config_param import ResponseTextConfigParam from .tool_choice_function_param import ToolChoiceFunctionParam from ..shared_params.responses_model import ResponsesModel __all__ = [ "ResponseCreateParamsBase", + "StreamOptions", "ToolChoice", "ResponseCreateParamsNonStreaming", "ResponseCreateParamsStreaming", @@ -28,8 +31,8 @@ class ResponseCreateParamsBase(TypedDict, total=False): background: Optional[bool] - """Whether to run the model response in the background. - + """ + Whether to run the model response in the background. [Learn more](https://platform.openai.com/docs/guides/background). """ @@ -169,6 +172,9 @@ class ResponseCreateParamsBase(TypedDict, total=False): store: Optional[bool] """Whether to store the generated model response for later retrieval via API.""" + stream_options: Optional[StreamOptions] + """Options for streaming responses. Only set this when you set `stream: true`.""" + temperature: Optional[float] """What sampling temperature to use, between 0 and 2. @@ -207,8 +213,10 @@ class ResponseCreateParamsBase(TypedDict, total=False): Learn more about [built-in tools](https://platform.openai.com/docs/guides/tools). - **Function calls (custom tools)**: Functions that are defined by you, enabling - the model to call your own code. Learn more about + the model to call your own code with strongly typed arguments and outputs. + Learn more about [function calling](https://platform.openai.com/docs/guides/function-calling). + You can also use custom tools to call your own code. """ top_logprobs: Optional[int] @@ -245,8 +253,36 @@ class ResponseCreateParamsBase(TypedDict, total=False): [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). """ + verbosity: Optional[Literal["low", "medium", "high"]] + """Constrains the verbosity of the model's response. + + Lower values will result in more concise responses, while higher values will + result in more verbose responses. Currently supported values are `low`, + `medium`, and `high`. + """ + + +class StreamOptions(TypedDict, total=False): + include_obfuscation: bool + """When true, stream obfuscation will be enabled. + + Stream obfuscation adds random characters to an `obfuscation` field on streaming + delta events to normalize payload sizes as a mitigation to certain side-channel + attacks. These obfuscation fields are included by default, but add a small + amount of overhead to the data stream. You can set `include_obfuscation` to + false to optimize for bandwidth if you trust the network links between your + application and the OpenAI API. + """ + -ToolChoice: TypeAlias = Union[ToolChoiceOptions, ToolChoiceTypesParam, ToolChoiceFunctionParam, ToolChoiceMcpParam] +ToolChoice: TypeAlias = Union[ + ToolChoiceOptions, + ToolChoiceAllowedParam, + ToolChoiceTypesParam, + ToolChoiceFunctionParam, + ToolChoiceMcpParam, + ToolChoiceCustomParam, +] class ResponseCreateParamsNonStreaming(ResponseCreateParamsBase, total=False): diff --git a/src/openai/types/responses/response_custom_tool_call.py b/src/openai/types/responses/response_custom_tool_call.py new file mode 100644 index 0000000000..38c650e662 --- /dev/null +++ b/src/openai/types/responses/response_custom_tool_call.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseCustomToolCall"] + + +class ResponseCustomToolCall(BaseModel): + call_id: str + """An identifier used to map this custom tool call to a tool call output.""" + + input: str + """The input for the custom tool call generated by the model.""" + + name: str + """The name of the custom tool being called.""" + + type: Literal["custom_tool_call"] + """The type of the custom tool call. Always `custom_tool_call`.""" + + id: Optional[str] = None + """The unique ID of the custom tool call in the OpenAI platform.""" diff --git a/src/openai/types/responses/response_custom_tool_call_input_delta_event.py b/src/openai/types/responses/response_custom_tool_call_input_delta_event.py new file mode 100644 index 0000000000..6c33102d75 --- /dev/null +++ b/src/openai/types/responses/response_custom_tool_call_input_delta_event.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseCustomToolCallInputDeltaEvent"] + + +class ResponseCustomToolCallInputDeltaEvent(BaseModel): + delta: str + """The incremental input data (delta) for the custom tool call.""" + + item_id: str + """Unique identifier for the API item associated with this event.""" + + output_index: int + """The index of the output this delta applies to.""" + + sequence_number: int + """The sequence number of this event.""" + + type: Literal["response.custom_tool_call_input.delta"] + """The event type identifier.""" diff --git a/src/openai/types/responses/response_custom_tool_call_input_done_event.py b/src/openai/types/responses/response_custom_tool_call_input_done_event.py new file mode 100644 index 0000000000..35a2fee22b --- /dev/null +++ b/src/openai/types/responses/response_custom_tool_call_input_done_event.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseCustomToolCallInputDoneEvent"] + + +class ResponseCustomToolCallInputDoneEvent(BaseModel): + input: str + """The complete input data for the custom tool call.""" + + item_id: str + """Unique identifier for the API item associated with this event.""" + + output_index: int + """The index of the output this event applies to.""" + + sequence_number: int + """The sequence number of this event.""" + + type: Literal["response.custom_tool_call_input.done"] + """The event type identifier.""" diff --git a/src/openai/types/responses/response_custom_tool_call_output.py b/src/openai/types/responses/response_custom_tool_call_output.py new file mode 100644 index 0000000000..a2b4cc3000 --- /dev/null +++ b/src/openai/types/responses/response_custom_tool_call_output.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseCustomToolCallOutput"] + + +class ResponseCustomToolCallOutput(BaseModel): + call_id: str + """The call ID, used to map this custom tool call output to a custom tool call.""" + + output: str + """The output from the custom tool call generated by your code.""" + + type: Literal["custom_tool_call_output"] + """The type of the custom tool call output. Always `custom_tool_call_output`.""" + + id: Optional[str] = None + """The unique ID of the custom tool call output in the OpenAI platform.""" diff --git a/src/openai/types/responses/response_custom_tool_call_output_param.py b/src/openai/types/responses/response_custom_tool_call_output_param.py new file mode 100644 index 0000000000..d52c525467 --- /dev/null +++ b/src/openai/types/responses/response_custom_tool_call_output_param.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ResponseCustomToolCallOutputParam"] + + +class ResponseCustomToolCallOutputParam(TypedDict, total=False): + call_id: Required[str] + """The call ID, used to map this custom tool call output to a custom tool call.""" + + output: Required[str] + """The output from the custom tool call generated by your code.""" + + type: Required[Literal["custom_tool_call_output"]] + """The type of the custom tool call output. Always `custom_tool_call_output`.""" + + id: str + """The unique ID of the custom tool call output in the OpenAI platform.""" diff --git a/src/openai/types/responses/response_custom_tool_call_param.py b/src/openai/types/responses/response_custom_tool_call_param.py new file mode 100644 index 0000000000..e15beac29f --- /dev/null +++ b/src/openai/types/responses/response_custom_tool_call_param.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ResponseCustomToolCallParam"] + + +class ResponseCustomToolCallParam(TypedDict, total=False): + call_id: Required[str] + """An identifier used to map this custom tool call to a tool call output.""" + + input: Required[str] + """The input for the custom tool call generated by the model.""" + + name: Required[str] + """The name of the custom tool being called.""" + + type: Required[Literal["custom_tool_call"]] + """The type of the custom tool call. Always `custom_tool_call`.""" + + id: str + """The unique ID of the custom tool call in the OpenAI platform.""" diff --git a/src/openai/types/responses/response_input_item.py b/src/openai/types/responses/response_input_item.py index 5fbd7c274b..d2b454fd2c 100644 --- a/src/openai/types/responses/response_input_item.py +++ b/src/openai/types/responses/response_input_item.py @@ -8,10 +8,12 @@ from .easy_input_message import EasyInputMessage from .response_output_message import ResponseOutputMessage from .response_reasoning_item import ResponseReasoningItem +from .response_custom_tool_call import ResponseCustomToolCall from .response_computer_tool_call import ResponseComputerToolCall from .response_function_tool_call import ResponseFunctionToolCall from .response_function_web_search import ResponseFunctionWebSearch from .response_file_search_tool_call import ResponseFileSearchToolCall +from .response_custom_tool_call_output import ResponseCustomToolCallOutput from .response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall from .response_input_message_content_list import ResponseInputMessageContentList from .response_computer_tool_call_output_screenshot import ResponseComputerToolCallOutputScreenshot @@ -299,6 +301,8 @@ class ItemReference(BaseModel): McpApprovalRequest, McpApprovalResponse, McpCall, + ResponseCustomToolCallOutput, + ResponseCustomToolCall, ItemReference, ], PropertyInfo(discriminator="type"), diff --git a/src/openai/types/responses/response_input_item_param.py b/src/openai/types/responses/response_input_item_param.py index 70cd9116a9..0d5dbda85c 100644 --- a/src/openai/types/responses/response_input_item_param.py +++ b/src/openai/types/responses/response_input_item_param.py @@ -8,10 +8,12 @@ from .easy_input_message_param import EasyInputMessageParam from .response_output_message_param import ResponseOutputMessageParam from .response_reasoning_item_param import ResponseReasoningItemParam +from .response_custom_tool_call_param import ResponseCustomToolCallParam from .response_computer_tool_call_param import ResponseComputerToolCallParam from .response_function_tool_call_param import ResponseFunctionToolCallParam from .response_function_web_search_param import ResponseFunctionWebSearchParam from .response_file_search_tool_call_param import ResponseFileSearchToolCallParam +from .response_custom_tool_call_output_param import ResponseCustomToolCallOutputParam from .response_code_interpreter_tool_call_param import ResponseCodeInterpreterToolCallParam from .response_input_message_content_list_param import ResponseInputMessageContentListParam from .response_computer_tool_call_output_screenshot_param import ResponseComputerToolCallOutputScreenshotParam @@ -298,5 +300,7 @@ class ItemReference(TypedDict, total=False): McpApprovalRequest, McpApprovalResponse, McpCall, + ResponseCustomToolCallOutputParam, + ResponseCustomToolCallParam, ItemReference, ] diff --git a/src/openai/types/responses/response_input_param.py b/src/openai/types/responses/response_input_param.py index 024998671f..6ff36a4238 100644 --- a/src/openai/types/responses/response_input_param.py +++ b/src/openai/types/responses/response_input_param.py @@ -8,10 +8,12 @@ from .easy_input_message_param import EasyInputMessageParam from .response_output_message_param import ResponseOutputMessageParam from .response_reasoning_item_param import ResponseReasoningItemParam +from .response_custom_tool_call_param import ResponseCustomToolCallParam from .response_computer_tool_call_param import ResponseComputerToolCallParam from .response_function_tool_call_param import ResponseFunctionToolCallParam from .response_function_web_search_param import ResponseFunctionWebSearchParam from .response_file_search_tool_call_param import ResponseFileSearchToolCallParam +from .response_custom_tool_call_output_param import ResponseCustomToolCallOutputParam from .response_code_interpreter_tool_call_param import ResponseCodeInterpreterToolCallParam from .response_input_message_content_list_param import ResponseInputMessageContentListParam from .response_computer_tool_call_output_screenshot_param import ResponseComputerToolCallOutputScreenshotParam @@ -299,6 +301,8 @@ class ItemReference(TypedDict, total=False): McpApprovalRequest, McpApprovalResponse, McpCall, + ResponseCustomToolCallOutputParam, + ResponseCustomToolCallParam, ItemReference, ] diff --git a/src/openai/types/responses/response_output_item.py b/src/openai/types/responses/response_output_item.py index 62f8f6fb3f..2d3ee7b64e 100644 --- a/src/openai/types/responses/response_output_item.py +++ b/src/openai/types/responses/response_output_item.py @@ -7,6 +7,7 @@ from ..._models import BaseModel from .response_output_message import ResponseOutputMessage from .response_reasoning_item import ResponseReasoningItem +from .response_custom_tool_call import ResponseCustomToolCall from .response_computer_tool_call import ResponseComputerToolCall from .response_function_tool_call import ResponseFunctionToolCall from .response_function_web_search import ResponseFunctionWebSearch @@ -161,6 +162,7 @@ class McpApprovalRequest(BaseModel): McpCall, McpListTools, McpApprovalRequest, + ResponseCustomToolCall, ], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/responses/response_retrieve_params.py b/src/openai/types/responses/response_retrieve_params.py index a092bd7fb8..4013db85ce 100644 --- a/src/openai/types/responses/response_retrieve_params.py +++ b/src/openai/types/responses/response_retrieve_params.py @@ -17,6 +17,17 @@ class ResponseRetrieveParamsBase(TypedDict, total=False): See the `include` parameter for Response creation above for more information. """ + include_obfuscation: bool + """When true, stream obfuscation will be enabled. + + Stream obfuscation adds random characters to an `obfuscation` field on streaming + delta events to normalize payload sizes as a mitigation to certain side-channel + attacks. These obfuscation fields are included by default, but add a small + amount of overhead to the data stream. You can set `include_obfuscation` to + false to optimize for bandwidth if you trust the network links between your + application and the OpenAI API. + """ + starting_after: int """The sequence number of the event after which to start streaming.""" diff --git a/src/openai/types/responses/response_stream_event.py b/src/openai/types/responses/response_stream_event.py index d62cf8969b..c0a317cd9d 100644 --- a/src/openai/types/responses/response_stream_event.py +++ b/src/openai/types/responses/response_stream_event.py @@ -40,9 +40,11 @@ from .response_file_search_call_searching_event import ResponseFileSearchCallSearchingEvent from .response_image_gen_call_in_progress_event import ResponseImageGenCallInProgressEvent from .response_mcp_list_tools_in_progress_event import ResponseMcpListToolsInProgressEvent +from .response_custom_tool_call_input_done_event import ResponseCustomToolCallInputDoneEvent from .response_reasoning_summary_part_done_event import ResponseReasoningSummaryPartDoneEvent from .response_reasoning_summary_text_done_event import ResponseReasoningSummaryTextDoneEvent from .response_web_search_call_in_progress_event import ResponseWebSearchCallInProgressEvent +from .response_custom_tool_call_input_delta_event import ResponseCustomToolCallInputDeltaEvent from .response_file_search_call_in_progress_event import ResponseFileSearchCallInProgressEvent from .response_function_call_arguments_done_event import ResponseFunctionCallArgumentsDoneEvent from .response_image_gen_call_partial_image_event import ResponseImageGenCallPartialImageEvent @@ -111,6 +113,8 @@ ResponseMcpListToolsInProgressEvent, ResponseOutputTextAnnotationAddedEvent, ResponseQueuedEvent, + ResponseCustomToolCallInputDeltaEvent, + ResponseCustomToolCallInputDoneEvent, ], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/responses/tool.py b/src/openai/types/responses/tool.py index 4399871e29..455ba01666 100644 --- a/src/openai/types/responses/tool.py +++ b/src/openai/types/responses/tool.py @@ -5,6 +5,7 @@ from ..._utils import PropertyInfo from ..._models import BaseModel +from .custom_tool import CustomTool from .computer_tool import ComputerTool from .function_tool import FunctionTool from .web_search_tool import WebSearchTool @@ -177,6 +178,16 @@ class LocalShell(BaseModel): Tool: TypeAlias = Annotated[ - Union[FunctionTool, FileSearchTool, WebSearchTool, ComputerTool, Mcp, CodeInterpreter, ImageGeneration, LocalShell], + Union[ + FunctionTool, + FileSearchTool, + WebSearchTool, + ComputerTool, + Mcp, + CodeInterpreter, + ImageGeneration, + LocalShell, + CustomTool, + ], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/responses/tool_choice_allowed.py b/src/openai/types/responses/tool_choice_allowed.py new file mode 100644 index 0000000000..d7921dcb2a --- /dev/null +++ b/src/openai/types/responses/tool_choice_allowed.py @@ -0,0 +1,36 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ToolChoiceAllowed"] + + +class ToolChoiceAllowed(BaseModel): + mode: Literal["auto", "required"] + """Constrains the tools available to the model to a pre-defined set. + + `auto` allows the model to pick from among the allowed tools and generate a + message. + + `required` requires the model to call one or more of the allowed tools. + """ + + tools: List[Dict[str, object]] + """A list of tool definitions that the model should be allowed to call. + + For the Responses API, the list of tool definitions might look like: + + ```json + [ + { "type": "function", "name": "get_weather" }, + { "type": "mcp", "server_label": "deepwiki" }, + { "type": "image_generation" } + ] + ``` + """ + + type: Literal["allowed_tools"] + """Allowed tool configuration type. Always `allowed_tools`.""" diff --git a/src/openai/types/responses/tool_choice_allowed_param.py b/src/openai/types/responses/tool_choice_allowed_param.py new file mode 100644 index 0000000000..0712cab43b --- /dev/null +++ b/src/openai/types/responses/tool_choice_allowed_param.py @@ -0,0 +1,36 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Iterable +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ToolChoiceAllowedParam"] + + +class ToolChoiceAllowedParam(TypedDict, total=False): + mode: Required[Literal["auto", "required"]] + """Constrains the tools available to the model to a pre-defined set. + + `auto` allows the model to pick from among the allowed tools and generate a + message. + + `required` requires the model to call one or more of the allowed tools. + """ + + tools: Required[Iterable[Dict[str, object]]] + """A list of tool definitions that the model should be allowed to call. + + For the Responses API, the list of tool definitions might look like: + + ```json + [ + { "type": "function", "name": "get_weather" }, + { "type": "mcp", "server_label": "deepwiki" }, + { "type": "image_generation" } + ] + ``` + """ + + type: Required[Literal["allowed_tools"]] + """Allowed tool configuration type. Always `allowed_tools`.""" diff --git a/src/openai/types/responses/tool_choice_custom.py b/src/openai/types/responses/tool_choice_custom.py new file mode 100644 index 0000000000..d600e53616 --- /dev/null +++ b/src/openai/types/responses/tool_choice_custom.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ToolChoiceCustom"] + + +class ToolChoiceCustom(BaseModel): + name: str + """The name of the custom tool to call.""" + + type: Literal["custom"] + """For custom tool calling, the type is always `custom`.""" diff --git a/src/openai/types/responses/tool_choice_custom_param.py b/src/openai/types/responses/tool_choice_custom_param.py new file mode 100644 index 0000000000..55bc53b730 --- /dev/null +++ b/src/openai/types/responses/tool_choice_custom_param.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ToolChoiceCustomParam"] + + +class ToolChoiceCustomParam(TypedDict, total=False): + name: Required[str] + """The name of the custom tool to call.""" + + type: Required[Literal["custom"]] + """For custom tool calling, the type is always `custom`.""" diff --git a/src/openai/types/responses/tool_param.py b/src/openai/types/responses/tool_param.py index a977f06e3f..ef9ec2ae36 100644 --- a/src/openai/types/responses/tool_param.py +++ b/src/openai/types/responses/tool_param.py @@ -5,6 +5,7 @@ from typing import Dict, List, Union, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict +from .custom_tool_param import CustomToolParam from .computer_tool_param import ComputerToolParam from .function_tool_param import FunctionToolParam from .web_search_tool_param import WebSearchToolParam @@ -186,6 +187,7 @@ class LocalShell(TypedDict, total=False): CodeInterpreter, ImageGeneration, LocalShell, + CustomToolParam, ] diff --git a/src/openai/types/shared/__init__.py b/src/openai/types/shared/__init__.py index 6ad0ed5e01..2930b9ae3b 100644 --- a/src/openai/types/shared/__init__.py +++ b/src/openai/types/shared/__init__.py @@ -12,5 +12,8 @@ from .function_definition import FunctionDefinition as FunctionDefinition from .function_parameters import FunctionParameters as FunctionParameters from .response_format_text import ResponseFormatText as ResponseFormatText +from .custom_tool_input_format import CustomToolInputFormat as CustomToolInputFormat from .response_format_json_object import ResponseFormatJSONObject as ResponseFormatJSONObject from .response_format_json_schema import ResponseFormatJSONSchema as ResponseFormatJSONSchema +from .response_format_text_python import ResponseFormatTextPython as ResponseFormatTextPython +from .response_format_text_grammar import ResponseFormatTextGrammar as ResponseFormatTextGrammar diff --git a/src/openai/types/shared/chat_model.py b/src/openai/types/shared/chat_model.py index 309368a384..727c60c1c0 100644 --- a/src/openai/types/shared/chat_model.py +++ b/src/openai/types/shared/chat_model.py @@ -5,6 +5,13 @@ __all__ = ["ChatModel"] ChatModel: TypeAlias = Literal[ + "gpt-5", + "gpt-5-mini", + "gpt-5-nano", + "gpt-5-2025-08-07", + "gpt-5-mini-2025-08-07", + "gpt-5-nano-2025-08-07", + "gpt-5-chat-latest", "gpt-4.1", "gpt-4.1-mini", "gpt-4.1-nano", diff --git a/src/openai/types/shared/custom_tool_input_format.py b/src/openai/types/shared/custom_tool_input_format.py new file mode 100644 index 0000000000..53c8323ed2 --- /dev/null +++ b/src/openai/types/shared/custom_tool_input_format.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel + +__all__ = ["CustomToolInputFormat", "Text", "Grammar"] + + +class Text(BaseModel): + type: Literal["text"] + """Unconstrained text format. Always `text`.""" + + +class Grammar(BaseModel): + definition: str + """The grammar definition.""" + + syntax: Literal["lark", "regex"] + """The syntax of the grammar definition. One of `lark` or `regex`.""" + + type: Literal["grammar"] + """Grammar format. Always `grammar`.""" + + +CustomToolInputFormat: TypeAlias = Annotated[Union[Text, Grammar], PropertyInfo(discriminator="type")] diff --git a/src/openai/types/shared/reasoning.py b/src/openai/types/shared/reasoning.py index 107aab2e4a..24ce301526 100644 --- a/src/openai/types/shared/reasoning.py +++ b/src/openai/types/shared/reasoning.py @@ -11,12 +11,12 @@ class Reasoning(BaseModel): effort: Optional[ReasoningEffort] = None - """**o-series 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. + supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning + effort can result in faster responses and fewer tokens used on reasoning in a + response. """ generate_summary: Optional[Literal["auto", "concise", "detailed"]] = None diff --git a/src/openai/types/shared/reasoning_effort.py b/src/openai/types/shared/reasoning_effort.py index ace21b67e4..4b960cd7e6 100644 --- a/src/openai/types/shared/reasoning_effort.py +++ b/src/openai/types/shared/reasoning_effort.py @@ -5,4 +5,4 @@ __all__ = ["ReasoningEffort"] -ReasoningEffort: TypeAlias = Optional[Literal["low", "medium", "high"]] +ReasoningEffort: TypeAlias = Optional[Literal["minimal", "low", "medium", "high"]] diff --git a/src/openai/types/shared/response_format_text_grammar.py b/src/openai/types/shared/response_format_text_grammar.py new file mode 100644 index 0000000000..b02f99c1b8 --- /dev/null +++ b/src/openai/types/shared/response_format_text_grammar.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseFormatTextGrammar"] + + +class ResponseFormatTextGrammar(BaseModel): + grammar: str + """The custom grammar for the model to follow.""" + + type: Literal["grammar"] + """The type of response format being defined. Always `grammar`.""" diff --git a/src/openai/types/shared/response_format_text_python.py b/src/openai/types/shared/response_format_text_python.py new file mode 100644 index 0000000000..4cd18d46fa --- /dev/null +++ b/src/openai/types/shared/response_format_text_python.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseFormatTextPython"] + + +class ResponseFormatTextPython(BaseModel): + type: Literal["python"] + """The type of response format being defined. Always `python`.""" diff --git a/src/openai/types/shared_params/__init__.py b/src/openai/types/shared_params/__init__.py index 8894710807..b6c0912b0f 100644 --- a/src/openai/types/shared_params/__init__.py +++ b/src/openai/types/shared_params/__init__.py @@ -10,5 +10,6 @@ from .function_definition import FunctionDefinition as FunctionDefinition from .function_parameters import FunctionParameters as FunctionParameters from .response_format_text import ResponseFormatText as ResponseFormatText +from .custom_tool_input_format import CustomToolInputFormat as CustomToolInputFormat from .response_format_json_object import ResponseFormatJSONObject as ResponseFormatJSONObject from .response_format_json_schema import ResponseFormatJSONSchema as ResponseFormatJSONSchema diff --git a/src/openai/types/shared_params/chat_model.py b/src/openai/types/shared_params/chat_model.py index 6cd8e7f91f..a1e5ab9f30 100644 --- a/src/openai/types/shared_params/chat_model.py +++ b/src/openai/types/shared_params/chat_model.py @@ -7,6 +7,13 @@ __all__ = ["ChatModel"] ChatModel: TypeAlias = Literal[ + "gpt-5", + "gpt-5-mini", + "gpt-5-nano", + "gpt-5-2025-08-07", + "gpt-5-mini-2025-08-07", + "gpt-5-nano-2025-08-07", + "gpt-5-chat-latest", "gpt-4.1", "gpt-4.1-mini", "gpt-4.1-nano", diff --git a/src/openai/types/shared_params/custom_tool_input_format.py b/src/openai/types/shared_params/custom_tool_input_format.py new file mode 100644 index 0000000000..37df393e39 --- /dev/null +++ b/src/openai/types/shared_params/custom_tool_input_format.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +__all__ = ["CustomToolInputFormat", "Text", "Grammar"] + + +class Text(TypedDict, total=False): + type: Required[Literal["text"]] + """Unconstrained text format. Always `text`.""" + + +class Grammar(TypedDict, total=False): + definition: Required[str] + """The grammar definition.""" + + syntax: Required[Literal["lark", "regex"]] + """The syntax of the grammar definition. One of `lark` or `regex`.""" + + type: Required[Literal["grammar"]] + """Grammar format. Always `grammar`.""" + + +CustomToolInputFormat: TypeAlias = Union[Text, Grammar] diff --git a/src/openai/types/shared_params/reasoning.py b/src/openai/types/shared_params/reasoning.py index 73e1a008df..7eab2c76f7 100644 --- a/src/openai/types/shared_params/reasoning.py +++ b/src/openai/types/shared_params/reasoning.py @@ -12,12 +12,12 @@ class Reasoning(TypedDict, total=False): effort: Optional[ReasoningEffort] - """**o-series 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. + supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning + effort can result in faster responses and fewer tokens used on reasoning in a + response. """ generate_summary: Optional[Literal["auto", "concise", "detailed"]] diff --git a/src/openai/types/shared_params/reasoning_effort.py b/src/openai/types/shared_params/reasoning_effort.py index 6052c5ae15..4c095a28d7 100644 --- a/src/openai/types/shared_params/reasoning_effort.py +++ b/src/openai/types/shared_params/reasoning_effort.py @@ -7,4 +7,4 @@ __all__ = ["ReasoningEffort"] -ReasoningEffort: TypeAlias = Optional[Literal["low", "medium", "high"]] +ReasoningEffort: TypeAlias = Optional[Literal["minimal", "low", "medium", "high"]] diff --git a/tests/api_resources/beta/test_assistants.py b/tests/api_resources/beta/test_assistants.py index 8aeb654e38..875e024a51 100644 --- a/tests/api_resources/beta/test_assistants.py +++ b/tests/api_resources/beta/test_assistants.py @@ -36,7 +36,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: instructions="instructions", metadata={"foo": "string"}, name="name", - reasoning_effort="low", + reasoning_effort="minimal", response_format="auto", temperature=1, tool_resources={ @@ -135,7 +135,7 @@ def test_method_update_with_all_params(self, client: OpenAI) -> None: metadata={"foo": "string"}, model="string", name="name", - reasoning_effort="low", + reasoning_effort="minimal", response_format="auto", temperature=1, tool_resources={ @@ -272,7 +272,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> instructions="instructions", metadata={"foo": "string"}, name="name", - reasoning_effort="low", + reasoning_effort="minimal", response_format="auto", temperature=1, tool_resources={ @@ -371,7 +371,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncOpenAI) -> metadata={"foo": "string"}, model="string", name="name", - reasoning_effort="low", + reasoning_effort="minimal", 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 86a296627e..440486bac5 100644 --- a/tests/api_resources/beta/threads/test_runs.py +++ b/tests/api_resources/beta/threads/test_runs.py @@ -59,7 +59,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: metadata={"foo": "string"}, model="string", parallel_tool_calls=True, - reasoning_effort="low", + reasoning_effort="minimal", response_format="auto", stream=False, temperature=1, @@ -150,7 +150,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: metadata={"foo": "string"}, model="string", parallel_tool_calls=True, - reasoning_effort="low", + reasoning_effort="minimal", response_format="auto", temperature=1, tool_choice="none", @@ -609,7 +609,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn metadata={"foo": "string"}, model="string", parallel_tool_calls=True, - reasoning_effort="low", + reasoning_effort="minimal", response_format="auto", stream=False, temperature=1, @@ -700,7 +700,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn metadata={"foo": "string"}, model="string", parallel_tool_calls=True, - reasoning_effort="low", + reasoning_effort="minimal", response_format="auto", temperature=1, tool_choice="none", diff --git a/tests/api_resources/chat/test_completions.py b/tests/api_resources/chat/test_completions.py index 2758d980ed..358ea18cbb 100644 --- a/tests/api_resources/chat/test_completions.py +++ b/tests/api_resources/chat/test_completions.py @@ -73,7 +73,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: }, presence_penalty=-2, prompt_cache_key="prompt-cache-key-1234", - reasoning_effort="low", + reasoning_effort="minimal", response_format={"type": "text"}, safety_identifier="safety-identifier-1234", seed=-9007199254740991, @@ -81,7 +81,10 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: stop="\n", store=True, stream=False, - stream_options={"include_usage": True}, + stream_options={ + "include_obfuscation": True, + "include_usage": True, + }, temperature=1, tool_choice="none", tools=[ @@ -98,6 +101,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: top_logprobs=0, top_p=1, user="user-1234", + verbosity="low", web_search_options={ "search_context_size": "low", "user_location": { @@ -202,14 +206,17 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: }, presence_penalty=-2, prompt_cache_key="prompt-cache-key-1234", - reasoning_effort="low", + reasoning_effort="minimal", response_format={"type": "text"}, safety_identifier="safety-identifier-1234", seed=-9007199254740991, service_tier="auto", stop="\n", store=True, - stream_options={"include_usage": True}, + stream_options={ + "include_obfuscation": True, + "include_usage": True, + }, temperature=1, tool_choice="none", tools=[ @@ -226,6 +233,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: top_logprobs=0, top_p=1, user="user-1234", + verbosity="low", web_search_options={ "search_context_size": "low", "user_location": { @@ -506,7 +514,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn }, presence_penalty=-2, prompt_cache_key="prompt-cache-key-1234", - reasoning_effort="low", + reasoning_effort="minimal", response_format={"type": "text"}, safety_identifier="safety-identifier-1234", seed=-9007199254740991, @@ -514,7 +522,10 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn stop="\n", store=True, stream=False, - stream_options={"include_usage": True}, + stream_options={ + "include_obfuscation": True, + "include_usage": True, + }, temperature=1, tool_choice="none", tools=[ @@ -531,6 +542,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn top_logprobs=0, top_p=1, user="user-1234", + verbosity="low", web_search_options={ "search_context_size": "low", "user_location": { @@ -635,14 +647,17 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn }, presence_penalty=-2, prompt_cache_key="prompt-cache-key-1234", - reasoning_effort="low", + reasoning_effort="minimal", response_format={"type": "text"}, safety_identifier="safety-identifier-1234", seed=-9007199254740991, service_tier="auto", stop="\n", store=True, - stream_options={"include_usage": True}, + stream_options={ + "include_obfuscation": True, + "include_usage": True, + }, temperature=1, tool_choice="none", tools=[ @@ -659,6 +674,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn top_logprobs=0, top_p=1, user="user-1234", + verbosity="low", web_search_options={ "search_context_size": "low", "user_location": { diff --git a/tests/api_resources/test_completions.py b/tests/api_resources/test_completions.py index 1c5271df75..a8fb0e59eb 100644 --- a/tests/api_resources/test_completions.py +++ b/tests/api_resources/test_completions.py @@ -41,7 +41,10 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: seed=0, stop="\n", stream=False, - stream_options={"include_usage": True}, + stream_options={ + "include_obfuscation": True, + "include_usage": True, + }, suffix="test.", temperature=1, top_p=1, @@ -100,7 +103,10 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: presence_penalty=-2, seed=0, stop="\n", - stream_options={"include_usage": True}, + stream_options={ + "include_obfuscation": True, + "include_usage": True, + }, suffix="test.", temperature=1, top_p=1, @@ -165,7 +171,10 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn seed=0, stop="\n", stream=False, - stream_options={"include_usage": True}, + stream_options={ + "include_obfuscation": True, + "include_usage": True, + }, suffix="test.", temperature=1, top_p=1, @@ -224,7 +233,10 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn presence_penalty=-2, seed=0, stop="\n", - stream_options={"include_usage": True}, + stream_options={ + "include_obfuscation": True, + "include_usage": True, + }, suffix="test.", temperature=1, top_p=1, diff --git a/tests/api_resources/test_responses.py b/tests/api_resources/test_responses.py index 63e47d8a69..4f8c88fa27 100644 --- a/tests/api_resources/test_responses.py +++ b/tests/api_resources/test_responses.py @@ -45,7 +45,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: }, prompt_cache_key="prompt-cache-key-1234", reasoning={ - "effort": "low", + "effort": "minimal", "generate_summary": "auto", "summary": "auto", }, @@ -53,6 +53,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: service_tier="auto", store=True, stream=False, + stream_options={"include_obfuscation": True}, temperature=1, text={"format": {"type": "text"}}, tool_choice="none", @@ -69,6 +70,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: top_p=1, truncation="auto", user="user-1234", + verbosity="low", ) assert_matches_type(Response, response, path=["response"]) @@ -120,13 +122,14 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: }, prompt_cache_key="prompt-cache-key-1234", reasoning={ - "effort": "low", + "effort": "minimal", "generate_summary": "auto", "summary": "auto", }, safety_identifier="safety-identifier-1234", service_tier="auto", store=True, + stream_options={"include_obfuscation": True}, temperature=1, text={"format": {"type": "text"}}, tool_choice="none", @@ -143,6 +146,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: top_p=1, truncation="auto", user="user-1234", + verbosity="low", ) response_stream.response.close() @@ -181,6 +185,7 @@ def test_method_retrieve_with_all_params_overload_1(self, client: OpenAI) -> Non response = client.responses.retrieve( response_id="resp_677efb5139a88190b512bc3fef8e535d", include=["code_interpreter_call.outputs"], + include_obfuscation=True, starting_after=0, stream=False, ) @@ -231,6 +236,7 @@ def test_method_retrieve_with_all_params_overload_2(self, client: OpenAI) -> Non response_id="resp_677efb5139a88190b512bc3fef8e535d", stream=True, include=["code_interpreter_call.outputs"], + include_obfuscation=True, starting_after=0, ) response_stream.response.close() @@ -386,7 +392,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn }, prompt_cache_key="prompt-cache-key-1234", reasoning={ - "effort": "low", + "effort": "minimal", "generate_summary": "auto", "summary": "auto", }, @@ -394,6 +400,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn service_tier="auto", store=True, stream=False, + stream_options={"include_obfuscation": True}, temperature=1, text={"format": {"type": "text"}}, tool_choice="none", @@ -410,6 +417,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn top_p=1, truncation="auto", user="user-1234", + verbosity="low", ) assert_matches_type(Response, response, path=["response"]) @@ -461,13 +469,14 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn }, prompt_cache_key="prompt-cache-key-1234", reasoning={ - "effort": "low", + "effort": "minimal", "generate_summary": "auto", "summary": "auto", }, safety_identifier="safety-identifier-1234", service_tier="auto", store=True, + stream_options={"include_obfuscation": True}, temperature=1, text={"format": {"type": "text"}}, tool_choice="none", @@ -484,6 +493,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn top_p=1, truncation="auto", user="user-1234", + verbosity="low", ) await response_stream.response.aclose() @@ -522,6 +532,7 @@ async def test_method_retrieve_with_all_params_overload_1(self, async_client: As response = await async_client.responses.retrieve( response_id="resp_677efb5139a88190b512bc3fef8e535d", include=["code_interpreter_call.outputs"], + include_obfuscation=True, starting_after=0, stream=False, ) @@ -572,6 +583,7 @@ async def test_method_retrieve_with_all_params_overload_2(self, async_client: As response_id="resp_677efb5139a88190b512bc3fef8e535d", stream=True, include=["code_interpreter_call.outputs"], + include_obfuscation=True, starting_after=0, ) await response_stream.response.aclose() From 657f551dbe583ffb259d987dafae12c6211fba06 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Thu, 7 Aug 2025 18:11:34 +0100 Subject: [PATCH 421/769] fix(types): correct tool types --- src/openai/lib/streaming/responses/_events.py | 4 ++++ src/openai/types/responses/tool_param.py | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/openai/lib/streaming/responses/_events.py b/src/openai/lib/streaming/responses/_events.py index de3342ec9d..bdc47b834a 100644 --- a/src/openai/lib/streaming/responses/_events.py +++ b/src/openai/lib/streaming/responses/_events.py @@ -39,9 +39,11 @@ ResponseMcpListToolsInProgressEvent, ResponseWebSearchCallCompletedEvent, ResponseWebSearchCallSearchingEvent, + ResponseCustomToolCallInputDoneEvent, ResponseFileSearchCallCompletedEvent, ResponseFileSearchCallSearchingEvent, ResponseWebSearchCallInProgressEvent, + ResponseCustomToolCallInputDeltaEvent, ResponseFileSearchCallInProgressEvent, ResponseImageGenCallPartialImageEvent, ResponseReasoningSummaryPartDoneEvent, @@ -139,6 +141,8 @@ class ResponseCompletedEvent(RawResponseCompletedEvent, GenericModel, Generic[Te ResponseQueuedEvent, ResponseReasoningTextDeltaEvent, ResponseReasoningTextDoneEvent, + ResponseCustomToolCallInputDeltaEvent, + ResponseCustomToolCallInputDoneEvent, ], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/responses/tool_param.py b/src/openai/types/responses/tool_param.py index ef9ec2ae36..f91e758559 100644 --- a/src/openai/types/responses/tool_param.py +++ b/src/openai/types/responses/tool_param.py @@ -5,12 +5,12 @@ from typing import Dict, List, Union, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict +from ..chat import ChatCompletionFunctionToolParam from .custom_tool_param import CustomToolParam from .computer_tool_param import ComputerToolParam from .function_tool_param import FunctionToolParam from .web_search_tool_param import WebSearchToolParam from .file_search_tool_param import FileSearchToolParam -from ..chat.chat_completion_tool_param import ChatCompletionToolParam __all__ = [ "ToolParam", @@ -191,4 +191,4 @@ class LocalShell(TypedDict, total=False): ] -ParseableToolParam: TypeAlias = Union[ToolParam, ChatCompletionToolParam] +ParseableToolParam: TypeAlias = Union[ToolParam, ChatCompletionFunctionToolParam] From 445af1e3d07fcfe1d047ced2436318419b7c889c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 7 Aug 2025 17:12:09 +0000 Subject: [PATCH 422/769] release: 1.99.2 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 18 ++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 41be9f1017..9472ef89a3 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.99.1" + ".": "1.99.2" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 4585135511..a6ac2ffb3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ # Changelog +## 1.99.2 (2025-08-07) + +Full Changelog: [v1.99.1...v1.99.2](https://github.com/openai/openai-python/compare/v1.99.1...v1.99.2) + +### Features + +* **api:** adds GPT-5 and new API features: platform.openai.com/docs/guides/gpt-5 ([ed370d8](https://github.com/openai/openai-python/commit/ed370d805e4d5d1ec14a136f5b2516751277059f)) + + +### Bug Fixes + +* **types:** correct tool types ([0c57bd7](https://github.com/openai/openai-python/commit/0c57bd7f2183a20b714d04edea380a4df0464a40)) + + +### Chores + +* **tests:** bump inline-snapshot dependency ([e236fde](https://github.com/openai/openai-python/commit/e236fde99a335fcaac9760f324e4807ce2cf7cba)) + ## 1.99.1 (2025-08-05) Full Changelog: [v1.99.0...v1.99.1](https://github.com/openai/openai-python/compare/v1.99.0...v1.99.1) diff --git a/pyproject.toml b/pyproject.toml index c71e8c135b..7ea0a63597 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.99.1" +version = "1.99.2" 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 3fa80adba0..088935379f 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.99.1" # x-release-please-version +__version__ = "1.99.2" # x-release-please-version From e3c0612c2cf39e7289fa3d91116c6eae83e534e6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 7 Aug 2025 18:27:13 +0000 Subject: [PATCH 423/769] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 9c1b4e4c54..4d8b1f059e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-f5c45f4ae5c2075cbc603d6910bba3da31c23714c209fbd3fd82a94f634a126b.yml openapi_spec_hash: 3eb8d86c06f0bb5e1190983e5acfc9ba -config_hash: 9a64321968e21ed72f5c0e02164ea00d +config_hash: e53ea2d984c4e05a57eb0227fa379b2b From e574c12f9e2e738451ac010bdc52f4ee59813cfb Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Thu, 7 Aug 2025 20:22:50 +0100 Subject: [PATCH 424/769] fix(responses): add output_text back --- src/openai/types/responses/response.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/openai/types/responses/response.py b/src/openai/types/responses/response.py index 07a82cb4ac..5ebb18fda4 100644 --- a/src/openai/types/responses/response.py +++ b/src/openai/types/responses/response.py @@ -259,3 +259,17 @@ class Response(BaseModel): [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). """ + @property + def output_text(self) -> str: + """Convenience property that aggregates all `output_text` items from the `output` list. + + If no `output_text` content blocks exist, then an empty string is returned. + """ + texts: List[str] = [] + for output in self.output: + if output.type == "message": + for content in output.content: + if content.type == "output_text": + texts.append(content.text) + + return "".join(texts) From e4ec91e776d0155752ab004432dbcd1ad8a81d98 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 7 Aug 2025 19:23:26 +0000 Subject: [PATCH 425/769] release: 1.99.3 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 9472ef89a3..62255b70d8 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.99.2" + ".": "1.99.3" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index a6ac2ffb3f..6d06c6548e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.99.3 (2025-08-07) + +Full Changelog: [v1.99.2...v1.99.3](https://github.com/openai/openai-python/compare/v1.99.2...v1.99.3) + +### Bug Fixes + +* **responses:** add output_text back ([585a4f1](https://github.com/openai/openai-python/commit/585a4f15e5a088bf8afee745bc4a7803775ac283)) + ## 1.99.2 (2025-08-07) Full Changelog: [v1.99.1...v1.99.2](https://github.com/openai/openai-python/compare/v1.99.1...v1.99.2) diff --git a/pyproject.toml b/pyproject.toml index 7ea0a63597..b2fc253ae6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.99.2" +version = "1.99.3" 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 088935379f..982cd9724f 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.99.2" # x-release-please-version +__version__ = "1.99.3" # x-release-please-version From c81195ea2c8e7cded4d6e6fe66d0062efbf3d744 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 7 Aug 2025 19:56:02 +0000 Subject: [PATCH 426/769] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 4d8b1f059e..b82ecf95fa 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-f5c45f4ae5c2075cbc603d6910bba3da31c23714c209fbd3fd82a94f634a126b.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-d7e255da603b878e7e823135520211ce6a9e02890c9d549bbf3953a877ee5ef3.yml openapi_spec_hash: 3eb8d86c06f0bb5e1190983e5acfc9ba -config_hash: e53ea2d984c4e05a57eb0227fa379b2b +config_hash: f0e0ce47bee61bd779ccaad22930f186 From 2ae42a399755828f74ced0f2fa41d9bd3a83a198 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 7 Aug 2025 20:09:45 +0000 Subject: [PATCH 427/769] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index b82ecf95fa..a73b73fc2c 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-d7e255da603b878e7e823135520211ce6a9e02890c9d549bbf3953a877ee5ef3.yml openapi_spec_hash: 3eb8d86c06f0bb5e1190983e5acfc9ba -config_hash: f0e0ce47bee61bd779ccaad22930f186 +config_hash: 2e7cf948f94e24f94c7d12ba2de2734a From 458a542a5f08dcf481292dfb04879cab27629b0c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 8 Aug 2025 11:24:58 +0000 Subject: [PATCH 428/769] fix(types): rename chat completion tool --- .stats.yml | 4 +-- api.md | 2 +- src/openai/lib/_parsing/_completions.py | 18 ++++++------- src/openai/lib/streaming/chat/_completions.py | 15 +++++------ .../resources/chat/completions/completions.py | 26 +++++++++---------- src/openai/types/chat/__init__.py | 2 +- ...py => chat_completion_tool_union_param.py} | 4 +-- .../types/chat/completion_create_params.py | 4 +-- 8 files changed, 37 insertions(+), 38 deletions(-) rename src/openai/types/chat/{chat_completion_tool_param.py => chat_completion_tool_union_param.py} (69%) diff --git a/.stats.yml b/.stats.yml index a73b73fc2c..6a34d9da6e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-d7e255da603b878e7e823135520211ce6a9e02890c9d549bbf3953a877ee5ef3.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-56d3a72a5caa187aebcf9de169a6a28a9dc3f70a79d7467a03a9e22595936066.yml openapi_spec_hash: 3eb8d86c06f0bb5e1190983e5acfc9ba -config_hash: 2e7cf948f94e24f94c7d12ba2de2734a +config_hash: 7e18239879286d68a48ac5487a649aa6 diff --git a/api.md b/api.md index f05b3f61ee..f58c401311 100644 --- a/api.md +++ b/api.md @@ -79,7 +79,7 @@ from openai.types.chat import ( ChatCompletionStreamOptions, ChatCompletionSystemMessageParam, ChatCompletionTokenLogprob, - ChatCompletionTool, + ChatCompletionToolUnion, ChatCompletionToolChoiceOption, ChatCompletionToolMessageParam, ChatCompletionUserMessageParam, diff --git a/src/openai/lib/_parsing/_completions.py b/src/openai/lib/_parsing/_completions.py index e14c33864d..fc0bd05e4d 100644 --- a/src/openai/lib/_parsing/_completions.py +++ b/src/openai/lib/_parsing/_completions.py @@ -21,13 +21,13 @@ ChatCompletionMessage, ParsedFunctionToolCall, ParsedChatCompletionMessage, + ChatCompletionToolUnionParam, ChatCompletionFunctionToolParam, completion_create_params, ) from ..._exceptions import LengthFinishReasonError, ContentFilterFinishReasonError from ...types.shared_params import FunctionDefinition from ...types.chat.completion_create_params import ResponseFormat as ResponseFormatParam -from ...types.chat.chat_completion_tool_param import ChatCompletionToolParam from ...types.chat.chat_completion_message_function_tool_call import Function ResponseFormatT = TypeVar( @@ -41,7 +41,7 @@ def is_strict_chat_completion_tool_param( - tool: ChatCompletionToolParam, + tool: ChatCompletionToolUnionParam, ) -> TypeGuard[ChatCompletionFunctionToolParam]: """Check if the given tool is a strict ChatCompletionFunctionToolParam.""" if not tool["type"] == "function": @@ -53,7 +53,7 @@ def is_strict_chat_completion_tool_param( def select_strict_chat_completion_tools( - tools: Iterable[ChatCompletionToolParam] | NotGiven = NOT_GIVEN, + tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, ) -> Iterable[ChatCompletionFunctionToolParam] | NotGiven: """Select only the strict ChatCompletionFunctionToolParams from the given tools.""" if not is_given(tools): @@ -63,7 +63,7 @@ def select_strict_chat_completion_tools( def validate_input_tools( - tools: Iterable[ChatCompletionToolParam] | NotGiven = NOT_GIVEN, + tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, ) -> Iterable[ChatCompletionFunctionToolParam] | NotGiven: if not is_given(tools): return NOT_GIVEN @@ -86,7 +86,7 @@ def validate_input_tools( def parse_chat_completion( *, response_format: type[ResponseFormatT] | completion_create_params.ResponseFormat | NotGiven, - input_tools: Iterable[ChatCompletionToolParam] | NotGiven, + input_tools: Iterable[ChatCompletionToolUnionParam] | NotGiven, chat_completion: ChatCompletion | ParsedChatCompletion[object], ) -> ParsedChatCompletion[ResponseFormatT]: if is_given(input_tools): @@ -166,13 +166,13 @@ def parse_chat_completion( def get_input_tool_by_name( - *, input_tools: list[ChatCompletionToolParam], name: str + *, input_tools: list[ChatCompletionToolUnionParam], name: str ) -> ChatCompletionFunctionToolParam | None: return next((t for t in input_tools if t["type"] == "function" and t.get("function", {}).get("name") == name), None) def parse_function_tool_arguments( - *, input_tools: list[ChatCompletionToolParam], function: Function | ParsedFunction + *, input_tools: list[ChatCompletionToolUnionParam], function: Function | ParsedFunction ) -> object | None: input_tool = get_input_tool_by_name(input_tools=input_tools, name=function.name) if not input_tool: @@ -218,7 +218,7 @@ def solve_response_format_t( def has_parseable_input( *, response_format: type | ResponseFormatParam | NotGiven, - input_tools: Iterable[ChatCompletionToolParam] | NotGiven = NOT_GIVEN, + input_tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, ) -> bool: if has_rich_response_format(response_format): return True @@ -246,7 +246,7 @@ def is_response_format_param(response_format: object) -> TypeGuard[ResponseForma return is_dict(response_format) -def is_parseable_tool(input_tool: ChatCompletionToolParam) -> bool: +def is_parseable_tool(input_tool: ChatCompletionToolUnionParam) -> bool: if input_tool["type"] != "function": return False diff --git a/src/openai/lib/streaming/chat/_completions.py b/src/openai/lib/streaming/chat/_completions.py index 1dff628a20..52a6a550b2 100644 --- a/src/openai/lib/streaming/chat/_completions.py +++ b/src/openai/lib/streaming/chat/_completions.py @@ -37,12 +37,11 @@ parse_function_tool_arguments, ) from ...._streaming import Stream, AsyncStream -from ....types.chat import ChatCompletionChunk, ParsedChatCompletion +from ....types.chat import ChatCompletionChunk, ParsedChatCompletion, ChatCompletionToolUnionParam from ...._exceptions import LengthFinishReasonError, ContentFilterFinishReasonError from ....types.chat.chat_completion import ChoiceLogprobs from ....types.chat.chat_completion_chunk import Choice as ChoiceChunk from ....types.chat.completion_create_params import ResponseFormat as ResponseFormatParam -from ....types.chat.chat_completion_tool_param import ChatCompletionToolParam class ChatCompletionStream(Generic[ResponseFormatT]): @@ -59,7 +58,7 @@ def __init__( *, raw_stream: Stream[ChatCompletionChunk], response_format: type[ResponseFormatT] | ResponseFormatParam | NotGiven, - input_tools: Iterable[ChatCompletionToolParam] | NotGiven, + input_tools: Iterable[ChatCompletionToolUnionParam] | NotGiven, ) -> None: self._raw_stream = raw_stream self._response = raw_stream.response @@ -140,7 +139,7 @@ def __init__( api_request: Callable[[], Stream[ChatCompletionChunk]], *, response_format: type[ResponseFormatT] | ResponseFormatParam | NotGiven, - input_tools: Iterable[ChatCompletionToolParam] | NotGiven, + input_tools: Iterable[ChatCompletionToolUnionParam] | NotGiven, ) -> None: self.__stream: ChatCompletionStream[ResponseFormatT] | None = None self.__api_request = api_request @@ -182,7 +181,7 @@ def __init__( *, raw_stream: AsyncStream[ChatCompletionChunk], response_format: type[ResponseFormatT] | ResponseFormatParam | NotGiven, - input_tools: Iterable[ChatCompletionToolParam] | NotGiven, + input_tools: Iterable[ChatCompletionToolUnionParam] | NotGiven, ) -> None: self._raw_stream = raw_stream self._response = raw_stream.response @@ -263,7 +262,7 @@ def __init__( api_request: Awaitable[AsyncStream[ChatCompletionChunk]], *, response_format: type[ResponseFormatT] | ResponseFormatParam | NotGiven, - input_tools: Iterable[ChatCompletionToolParam] | NotGiven, + input_tools: Iterable[ChatCompletionToolUnionParam] | NotGiven, ) -> None: self.__stream: AsyncChatCompletionStream[ResponseFormatT] | None = None self.__api_request = api_request @@ -315,7 +314,7 @@ class ChatCompletionStreamState(Generic[ResponseFormatT]): def __init__( self, *, - input_tools: Iterable[ChatCompletionToolParam] | NotGiven = NOT_GIVEN, + input_tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, response_format: type[ResponseFormatT] | ResponseFormatParam | NotGiven = NOT_GIVEN, ) -> None: self.__current_completion_snapshot: ParsedChatCompletionSnapshot | None = None @@ -585,7 +584,7 @@ def _build_events( class ChoiceEventState: - def __init__(self, *, input_tools: list[ChatCompletionToolParam]) -> None: + def __init__(self, *, input_tools: list[ChatCompletionToolUnionParam]) -> None: self._input_tools = input_tools self._content_done = False diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index 65f91396bd..9404d85192 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -47,9 +47,9 @@ from ....types.chat.chat_completion_chunk import ChatCompletionChunk from ....types.chat.parsed_chat_completion import ParsedChatCompletion from ....types.chat.chat_completion_deleted import ChatCompletionDeleted -from ....types.chat.chat_completion_tool_param import ChatCompletionToolParam from ....types.chat.chat_completion_audio_param import ChatCompletionAudioParam from ....types.chat.chat_completion_message_param import ChatCompletionMessageParam +from ....types.chat.chat_completion_tool_union_param import ChatCompletionToolUnionParam from ....types.chat.chat_completion_stream_options_param import ChatCompletionStreamOptionsParam from ....types.chat.chat_completion_prediction_content_param import ChatCompletionPredictionContentParam from ....types.chat.chat_completion_tool_choice_option_param import ChatCompletionToolChoiceOptionParam @@ -111,7 +111,7 @@ def parse( stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, - tools: Iterable[ChatCompletionToolParam] | NotGiven = NOT_GIVEN, + tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, @@ -266,7 +266,7 @@ def create( stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, - tools: Iterable[ChatCompletionToolParam] | NotGiven = NOT_GIVEN, + tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, @@ -555,7 +555,7 @@ def create( stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, - tools: Iterable[ChatCompletionToolParam] | NotGiven = NOT_GIVEN, + tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, @@ -844,7 +844,7 @@ def create( stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, - tools: Iterable[ChatCompletionToolParam] | NotGiven = NOT_GIVEN, + tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, @@ -1133,7 +1133,7 @@ def create( stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, - tools: Iterable[ChatCompletionToolParam] | NotGiven = NOT_GIVEN, + tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, @@ -1408,7 +1408,7 @@ def stream( stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, - tools: Iterable[ChatCompletionToolParam] | NotGiven = NOT_GIVEN, + tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, @@ -1550,7 +1550,7 @@ async def parse( stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, - tools: Iterable[ChatCompletionToolParam] | NotGiven = NOT_GIVEN, + tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, @@ -1705,7 +1705,7 @@ async def create( stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, - tools: Iterable[ChatCompletionToolParam] | NotGiven = NOT_GIVEN, + tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, @@ -1994,7 +1994,7 @@ async def create( stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, - tools: Iterable[ChatCompletionToolParam] | NotGiven = NOT_GIVEN, + tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, @@ -2283,7 +2283,7 @@ async def create( stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, - tools: Iterable[ChatCompletionToolParam] | NotGiven = NOT_GIVEN, + tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, @@ -2572,7 +2572,7 @@ async def create( stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, - tools: Iterable[ChatCompletionToolParam] | NotGiven = NOT_GIVEN, + tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, @@ -2847,7 +2847,7 @@ def stream( stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, - tools: Iterable[ChatCompletionToolParam] | NotGiven = NOT_GIVEN, + tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, diff --git a/src/openai/types/chat/__init__.py b/src/openai/types/chat/__init__.py index ce1cf4522a..1a814816cf 100644 --- a/src/openai/types/chat/__init__.py +++ b/src/openai/types/chat/__init__.py @@ -21,13 +21,13 @@ ParsedFunction as ParsedFunction, ParsedFunctionToolCall as ParsedFunctionToolCall, ) -from .chat_completion_tool_param import ChatCompletionToolParam as ChatCompletionToolParam from .chat_completion_audio_param import ChatCompletionAudioParam as ChatCompletionAudioParam from .chat_completion_function_tool import ChatCompletionFunctionTool as ChatCompletionFunctionTool from .chat_completion_message_param import ChatCompletionMessageParam as ChatCompletionMessageParam from .chat_completion_store_message import ChatCompletionStoreMessage as ChatCompletionStoreMessage from .chat_completion_token_logprob import ChatCompletionTokenLogprob as ChatCompletionTokenLogprob from .chat_completion_reasoning_effort import ChatCompletionReasoningEffort as ChatCompletionReasoningEffort +from .chat_completion_tool_union_param import ChatCompletionToolUnionParam as ChatCompletionToolUnionParam from .chat_completion_content_part_text import ChatCompletionContentPartText as ChatCompletionContentPartText from .chat_completion_custom_tool_param import ChatCompletionCustomToolParam as ChatCompletionCustomToolParam from .chat_completion_message_tool_call import ChatCompletionMessageToolCall as ChatCompletionMessageToolCall diff --git a/src/openai/types/chat/chat_completion_tool_param.py b/src/openai/types/chat/chat_completion_tool_union_param.py similarity index 69% rename from src/openai/types/chat/chat_completion_tool_param.py rename to src/openai/types/chat/chat_completion_tool_union_param.py index 7cd9743ea3..0f8bf7b0e7 100644 --- a/src/openai/types/chat/chat_completion_tool_param.py +++ b/src/openai/types/chat/chat_completion_tool_union_param.py @@ -8,6 +8,6 @@ from .chat_completion_custom_tool_param import ChatCompletionCustomToolParam from .chat_completion_function_tool_param import ChatCompletionFunctionToolParam -__all__ = ["ChatCompletionToolParam"] +__all__ = ["ChatCompletionToolUnionParam"] -ChatCompletionToolParam: TypeAlias = Union[ChatCompletionFunctionToolParam, ChatCompletionCustomToolParam] +ChatCompletionToolUnionParam: TypeAlias = Union[ChatCompletionFunctionToolParam, ChatCompletionCustomToolParam] diff --git a/src/openai/types/chat/completion_create_params.py b/src/openai/types/chat/completion_create_params.py index 011067af1a..a3bc90b0a2 100644 --- a/src/openai/types/chat/completion_create_params.py +++ b/src/openai/types/chat/completion_create_params.py @@ -8,9 +8,9 @@ from ..shared.chat_model import ChatModel from ..shared_params.metadata import Metadata from ..shared.reasoning_effort import ReasoningEffort -from .chat_completion_tool_param import ChatCompletionToolParam from .chat_completion_audio_param import ChatCompletionAudioParam from .chat_completion_message_param import ChatCompletionMessageParam +from .chat_completion_tool_union_param import ChatCompletionToolUnionParam from ..shared_params.function_parameters import FunctionParameters from ..shared_params.response_format_text import ResponseFormatText from .chat_completion_stream_options_param import ChatCompletionStreamOptionsParam @@ -284,7 +284,7 @@ class CompletionCreateParamsBase(TypedDict, total=False): are present. """ - tools: Iterable[ChatCompletionToolParam] + tools: Iterable[ChatCompletionToolUnionParam] """A list of tools the model may call. You can provide either From 05a35a57b2fc39acd9132e9a7b9f25d4a59be698 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Fri, 8 Aug 2025 12:28:58 +0100 Subject: [PATCH 429/769] fix(types): revert ChatCompletionToolParam to a TypedDict --- src/openai/types/chat/__init__.py | 1 + src/openai/types/chat/chat_completion_tool_param.py | 11 +++++++++++ tests/compat/test_tool_param.py | 8 ++++++++ 3 files changed, 20 insertions(+) create mode 100644 src/openai/types/chat/chat_completion_tool_param.py create mode 100644 tests/compat/test_tool_param.py diff --git a/src/openai/types/chat/__init__.py b/src/openai/types/chat/__init__.py index 1a814816cf..c9e77ff41c 100644 --- a/src/openai/types/chat/__init__.py +++ b/src/openai/types/chat/__init__.py @@ -21,6 +21,7 @@ ParsedFunction as ParsedFunction, ParsedFunctionToolCall as ParsedFunctionToolCall, ) +from .chat_completion_tool_param import ChatCompletionToolParam as ChatCompletionToolParam from .chat_completion_audio_param import ChatCompletionAudioParam as ChatCompletionAudioParam from .chat_completion_function_tool import ChatCompletionFunctionTool as ChatCompletionFunctionTool from .chat_completion_message_param import ChatCompletionMessageParam as ChatCompletionMessageParam diff --git a/src/openai/types/chat/chat_completion_tool_param.py b/src/openai/types/chat/chat_completion_tool_param.py new file mode 100644 index 0000000000..ef3b6d07c6 --- /dev/null +++ b/src/openai/types/chat/chat_completion_tool_param.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +from .chat_completion_function_tool_param import ChatCompletionFunctionToolParam + +__all__ = ["ChatCompletionToolParam"] + +ChatCompletionToolParam: TypeAlias = ChatCompletionFunctionToolParam diff --git a/tests/compat/test_tool_param.py b/tests/compat/test_tool_param.py new file mode 100644 index 0000000000..f2f84c6e94 --- /dev/null +++ b/tests/compat/test_tool_param.py @@ -0,0 +1,8 @@ +from openai.types.chat import ChatCompletionToolParam + + +def test_tool_param_can_be_instantiated() -> None: + assert ChatCompletionToolParam(type="function", function={"name": "test"}) == { + "function": {"name": "test"}, + "type": "function", + } From 09f98acf6bf7b66e98a4b6c3e37433ccdee0e20e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 8 Aug 2025 11:32:31 +0000 Subject: [PATCH 430/769] release: 1.99.4 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 9 +++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 62255b70d8..cdb9c7d0d7 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.99.3" + ".": "1.99.4" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d06c6548e..f8fdb7a268 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 1.99.4 (2025-08-08) + +Full Changelog: [v1.99.3...v1.99.4](https://github.com/openai/openai-python/compare/v1.99.3...v1.99.4) + +### Bug Fixes + +* **types:** rename chat completion tool ([8d3bf88](https://github.com/openai/openai-python/commit/8d3bf88f5bc11cf30b8b050c24b2cc5a3807614f)) +* **types:** revert ChatCompletionToolParam to a TypedDict ([3f4ae72](https://github.com/openai/openai-python/commit/3f4ae725af53e631ddc128c1c6862ecf0b08e073)) + ## 1.99.3 (2025-08-07) Full Changelog: [v1.99.2...v1.99.3](https://github.com/openai/openai-python/compare/v1.99.2...v1.99.3) diff --git a/pyproject.toml b/pyproject.toml index b2fc253ae6..b041682135 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.99.3" +version = "1.99.4" 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 982cd9724f..04f835f838 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.99.3" # x-release-please-version +__version__ = "1.99.4" # x-release-please-version From f4e41b87f7bf5597dadb0e42e11d33c093e89b5c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 8 Aug 2025 14:56:34 +0000 Subject: [PATCH 431/769] fix(client): fix verbosity parameter location in Responses fixes error with unsupported `verbosity` parameter by correctly placing it inside the `text` parameter --- .stats.yml | 4 +-- src/openai/resources/responses/responses.py | 34 ------------------- .../types/responses/response_create_params.py | 8 ----- .../types/responses/response_text_config.py | 9 +++++ .../responses/response_text_config_param.py | 11 +++++- tests/api_resources/test_responses.py | 24 ++++++++----- 6 files changed, 37 insertions(+), 53 deletions(-) diff --git a/.stats.yml b/.stats.yml index 6a34d9da6e..1c85ee4a0c 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-56d3a72a5caa187aebcf9de169a6a28a9dc3f70a79d7467a03a9e22595936066.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-6a1bfd4738fff02ef5becc3fdb2bf0cd6c026f2c924d4147a2a515474477dd9a.yml openapi_spec_hash: 3eb8d86c06f0bb5e1190983e5acfc9ba -config_hash: 7e18239879286d68a48ac5487a649aa6 +config_hash: a67c5e195a59855fe8a5db0dc61a3e7f diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 5ba22418ed..8983daf278 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -102,7 +102,6 @@ def create( top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, - verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -291,10 +290,6 @@ def create( similar requests and to help OpenAI detect and prevent abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - verbosity: Constrains the verbosity of the model's response. Lower values will result in - more concise responses, while higher values will result in more verbose - responses. Currently supported values are `low`, `medium`, and `high`. - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -335,7 +330,6 @@ def create( top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, - verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -524,10 +518,6 @@ def create( similar requests and to help OpenAI detect and prevent abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - verbosity: Constrains the verbosity of the model's response. Lower values will result in - more concise responses, while higher values will result in more verbose - responses. Currently supported values are `low`, `medium`, and `high`. - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -568,7 +558,6 @@ def create( top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, - verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -757,10 +746,6 @@ def create( similar requests and to help OpenAI detect and prevent abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - verbosity: Constrains the verbosity of the model's response. Lower values will result in - more concise responses, while higher values will result in more verbose - responses. Currently supported values are `low`, `medium`, and `high`. - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -800,7 +785,6 @@ def create( top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, - verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -838,7 +822,6 @@ def create( "top_p": top_p, "truncation": truncation, "user": user, - "verbosity": verbosity, }, response_create_params.ResponseCreateParamsStreaming if stream @@ -1485,7 +1468,6 @@ async def create( top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, - verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1674,10 +1656,6 @@ async def create( similar requests and to help OpenAI detect and prevent abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - verbosity: Constrains the verbosity of the model's response. Lower values will result in - more concise responses, while higher values will result in more verbose - responses. Currently supported values are `low`, `medium`, and `high`. - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -1718,7 +1696,6 @@ async def create( top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, - verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1907,10 +1884,6 @@ async def create( similar requests and to help OpenAI detect and prevent abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - verbosity: Constrains the verbosity of the model's response. Lower values will result in - more concise responses, while higher values will result in more verbose - responses. Currently supported values are `low`, `medium`, and `high`. - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -1951,7 +1924,6 @@ async def create( top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, - verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -2140,10 +2112,6 @@ async def create( similar requests and to help OpenAI detect and prevent abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - verbosity: Constrains the verbosity of the model's response. Lower values will result in - more concise responses, while higher values will result in more verbose - responses. Currently supported values are `low`, `medium`, and `high`. - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -2183,7 +2151,6 @@ async def create( top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, - verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -2221,7 +2188,6 @@ async def create( "top_p": top_p, "truncation": truncation, "user": user, - "verbosity": verbosity, }, response_create_params.ResponseCreateParamsStreaming if stream diff --git a/src/openai/types/responses/response_create_params.py b/src/openai/types/responses/response_create_params.py index 53af325328..ea91fa1265 100644 --- a/src/openai/types/responses/response_create_params.py +++ b/src/openai/types/responses/response_create_params.py @@ -253,14 +253,6 @@ class ResponseCreateParamsBase(TypedDict, total=False): [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). """ - verbosity: Optional[Literal["low", "medium", "high"]] - """Constrains the verbosity of the model's response. - - Lower values will result in more concise responses, while higher values will - result in more verbose responses. Currently supported values are `low`, - `medium`, and `high`. - """ - class StreamOptions(TypedDict, total=False): include_obfuscation: bool diff --git a/src/openai/types/responses/response_text_config.py b/src/openai/types/responses/response_text_config.py index a1894a9176..c53546da6d 100644 --- a/src/openai/types/responses/response_text_config.py +++ b/src/openai/types/responses/response_text_config.py @@ -1,6 +1,7 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from typing import Optional +from typing_extensions import Literal from ..._models import BaseModel from .response_format_text_config import ResponseFormatTextConfig @@ -24,3 +25,11 @@ class ResponseTextConfig(BaseModel): ensures the message the model generates is valid JSON. Using `json_schema` is preferred for models that support it. """ + + verbosity: Optional[Literal["low", "medium", "high"]] = None + """Constrains the verbosity of the model's response. + + Lower values will result in more concise responses, while higher values will + result in more verbose responses. Currently supported values are `low`, + `medium`, and `high`. + """ diff --git a/src/openai/types/responses/response_text_config_param.py b/src/openai/types/responses/response_text_config_param.py index aec064bf89..1229fce35b 100644 --- a/src/openai/types/responses/response_text_config_param.py +++ b/src/openai/types/responses/response_text_config_param.py @@ -2,7 +2,8 @@ from __future__ import annotations -from typing_extensions import TypedDict +from typing import Optional +from typing_extensions import Literal, TypedDict from .response_format_text_config_param import ResponseFormatTextConfigParam @@ -25,3 +26,11 @@ class ResponseTextConfigParam(TypedDict, total=False): ensures the message the model generates is valid JSON. Using `json_schema` is preferred for models that support it. """ + + verbosity: Optional[Literal["low", "medium", "high"]] + """Constrains the verbosity of the model's response. + + Lower values will result in more concise responses, while higher values will + result in more verbose responses. Currently supported values are `low`, + `medium`, and `high`. + """ diff --git a/tests/api_resources/test_responses.py b/tests/api_resources/test_responses.py index 4f8c88fa27..310800b87e 100644 --- a/tests/api_resources/test_responses.py +++ b/tests/api_resources/test_responses.py @@ -55,7 +55,10 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: stream=False, stream_options={"include_obfuscation": True}, temperature=1, - text={"format": {"type": "text"}}, + text={ + "format": {"type": "text"}, + "verbosity": "low", + }, tool_choice="none", tools=[ { @@ -70,7 +73,6 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: top_p=1, truncation="auto", user="user-1234", - verbosity="low", ) assert_matches_type(Response, response, path=["response"]) @@ -131,7 +133,10 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: store=True, stream_options={"include_obfuscation": True}, temperature=1, - text={"format": {"type": "text"}}, + text={ + "format": {"type": "text"}, + "verbosity": "low", + }, tool_choice="none", tools=[ { @@ -146,7 +151,6 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: top_p=1, truncation="auto", user="user-1234", - verbosity="low", ) response_stream.response.close() @@ -402,7 +406,10 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn stream=False, stream_options={"include_obfuscation": True}, temperature=1, - text={"format": {"type": "text"}}, + text={ + "format": {"type": "text"}, + "verbosity": "low", + }, tool_choice="none", tools=[ { @@ -417,7 +424,6 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn top_p=1, truncation="auto", user="user-1234", - verbosity="low", ) assert_matches_type(Response, response, path=["response"]) @@ -478,7 +484,10 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn store=True, stream_options={"include_obfuscation": True}, temperature=1, - text={"format": {"type": "text"}}, + text={ + "format": {"type": "text"}, + "verbosity": "low", + }, tool_choice="none", tools=[ { @@ -493,7 +502,6 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn top_p=1, truncation="auto", user="user-1234", - verbosity="low", ) await response_stream.response.aclose() From 7aa3c787b99adf9b93f0652aacafa1200c681877 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 8 Aug 2025 14:57:03 +0000 Subject: [PATCH 432/769] release: 1.99.5 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index cdb9c7d0d7..393c24840d 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.99.4" + ".": "1.99.5" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index f8fdb7a268..3d332955ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.99.5 (2025-08-08) + +Full Changelog: [v1.99.4...v1.99.5](https://github.com/openai/openai-python/compare/v1.99.4...v1.99.5) + +### Bug Fixes + +* **client:** fix verbosity parameter location in Responses ([2764ff4](https://github.com/openai/openai-python/commit/2764ff459eb8b309d25b39b40e363b16a5b95019)) + ## 1.99.4 (2025-08-08) Full Changelog: [v1.99.3...v1.99.4](https://github.com/openai/openai-python/compare/v1.99.3...v1.99.4) diff --git a/pyproject.toml b/pyproject.toml index b041682135..ca255c95bd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.99.4" +version = "1.99.5" 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 04f835f838..12270a03d4 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.99.4" # x-release-please-version +__version__ = "1.99.5" # x-release-please-version From 52c48df8be298984eb2233fec71dc7765472f65e Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Fri, 8 Aug 2025 18:14:16 +0100 Subject: [PATCH 433/769] fix(types): re-export more tool call types --- src/openai/types/chat/chat_completion_message_tool_call.py | 4 ++-- src/openai/types/chat/chat_completion_tool_param.py | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/openai/types/chat/chat_completion_message_tool_call.py b/src/openai/types/chat/chat_completion_message_tool_call.py index c254774626..94cc086e9d 100644 --- a/src/openai/types/chat/chat_completion_message_tool_call.py +++ b/src/openai/types/chat/chat_completion_message_tool_call.py @@ -5,9 +5,9 @@ from ..._utils import PropertyInfo from .chat_completion_message_custom_tool_call import ChatCompletionMessageCustomToolCall -from .chat_completion_message_function_tool_call import ChatCompletionMessageFunctionToolCall +from .chat_completion_message_function_tool_call import Function as Function, ChatCompletionMessageFunctionToolCall -__all__ = ["ChatCompletionMessageToolCall"] +__all__ = ["ChatCompletionMessageToolCall", "Function"] ChatCompletionMessageToolCall: TypeAlias = Annotated[ Union[ChatCompletionMessageFunctionToolCall, ChatCompletionMessageCustomToolCall], diff --git a/src/openai/types/chat/chat_completion_tool_param.py b/src/openai/types/chat/chat_completion_tool_param.py index ef3b6d07c6..a18b13b471 100644 --- a/src/openai/types/chat/chat_completion_tool_param.py +++ b/src/openai/types/chat/chat_completion_tool_param.py @@ -4,8 +4,11 @@ from typing_extensions import TypeAlias -from .chat_completion_function_tool_param import ChatCompletionFunctionToolParam +from .chat_completion_function_tool_param import ( + FunctionDefinition as FunctionDefinition, + ChatCompletionFunctionToolParam, +) -__all__ = ["ChatCompletionToolParam"] +__all__ = ["ChatCompletionToolParam", "FunctionDefinition"] ChatCompletionToolParam: TypeAlias = ChatCompletionFunctionToolParam From 5dc3476754d02f487a7eefc743b97053ff4b533f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 8 Aug 2025 17:58:48 +0000 Subject: [PATCH 434/769] chore: update @stainless-api/prism-cli to v5.15.0 --- scripts/mock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/mock b/scripts/mock index d2814ae6a0..0b28f6ea23 100755 --- a/scripts/mock +++ b/scripts/mock @@ -21,7 +21,7 @@ echo "==> Starting mock server with URL ${URL}" # Run prism mock on the given spec if [ "$1" == "--daemon" ]; then - npm exec --package=@stainless-api/prism-cli@5.8.5 -- prism mock "$URL" &> .prism.log & + npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" &> .prism.log & # Wait for server to come online echo -n "Waiting for server" @@ -37,5 +37,5 @@ if [ "$1" == "--daemon" ]; then echo else - npm exec --package=@stainless-api/prism-cli@5.8.5 -- prism mock "$URL" + npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" fi From 4df12615b6dd4bcc860d4064920878749195b80e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 8 Aug 2025 21:23:11 +0000 Subject: [PATCH 435/769] chore(internal): update comment in script --- scripts/test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/test b/scripts/test index 2b87845670..dbeda2d217 100755 --- a/scripts/test +++ b/scripts/test @@ -43,7 +43,7 @@ elif ! prism_is_running ; then echo -e "To run the server, pass in the path or url of your OpenAPI" echo -e "spec to the prism command:" echo - echo -e " \$ ${YELLOW}npm exec --package=@stoplight/prism-cli@~5.3.2 -- prism mock path/to/your.openapi.yml${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock path/to/your.openapi.yml${NC}" echo exit 1 From 4d8c14cdc13772f6cc68be5eee6772b215f82c58 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 9 Aug 2025 05:04:12 +0000 Subject: [PATCH 436/769] release: 1.99.6 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 14 ++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 393c24840d..03128d3ade 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.99.5" + ".": "1.99.6" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d332955ef..8edff34439 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## 1.99.6 (2025-08-09) + +Full Changelog: [v1.99.5...v1.99.6](https://github.com/openai/openai-python/compare/v1.99.5...v1.99.6) + +### Bug Fixes + +* **types:** re-export more tool call types ([8fe5741](https://github.com/openai/openai-python/commit/8fe574131cfe8f0453788cc6105d22834e7c102f)) + + +### Chores + +* **internal:** update comment in script ([e407bb5](https://github.com/openai/openai-python/commit/e407bb52112ad73e5eedf929434ee4ff7ac5a5a8)) +* update @stainless-api/prism-cli to v5.15.0 ([a1883fc](https://github.com/openai/openai-python/commit/a1883fcdfa02b81e5129bdb43206597a51f885fa)) + ## 1.99.5 (2025-08-08) Full Changelog: [v1.99.4...v1.99.5](https://github.com/openai/openai-python/compare/v1.99.4...v1.99.5) diff --git a/pyproject.toml b/pyproject.toml index ca255c95bd..37e9d4f767 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.99.5" +version = "1.99.6" 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 12270a03d4..eed63aadba 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.99.5" # x-release-please-version +__version__ = "1.99.6" # x-release-please-version From bff85cddc49047d2e2a31c08ed1dfa2c8dcdd255 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 11 Aug 2025 12:56:29 +0000 Subject: [PATCH 437/769] fix(types): rename ChatCompletionMessageToolCallParam --- .stats.yml | 4 ++-- api.md | 2 +- src/openai/types/chat/__init__.py | 8 ++++---- .../types/chat/chat_completion_assistant_message_param.py | 4 ++-- src/openai/types/chat/chat_completion_message.py | 4 ++-- .../types/chat/chat_completion_message_tool_call.py | 4 ++-- ...y => chat_completion_message_tool_call_union_param.py} | 4 ++-- 7 files changed, 15 insertions(+), 15 deletions(-) rename src/openai/types/chat/{chat_completion_message_tool_call_param.py => chat_completion_message_tool_call_union_param.py} (81%) diff --git a/.stats.yml b/.stats.yml index 1c85ee4a0c..a098c3d40d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-6a1bfd4738fff02ef5becc3fdb2bf0cd6c026f2c924d4147a2a515474477dd9a.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-9cadfad609f94f20ebf74fdc06a80302f1a324dc69700a309a8056aabca82fd2.yml openapi_spec_hash: 3eb8d86c06f0bb5e1190983e5acfc9ba -config_hash: a67c5e195a59855fe8a5db0dc61a3e7f +config_hash: 68337b532875626269c304372a669f67 diff --git a/api.md b/api.md index f58c401311..92b068b134 100644 --- a/api.md +++ b/api.md @@ -69,7 +69,7 @@ from openai.types.chat import ( ChatCompletionMessageCustomToolCall, ChatCompletionMessageFunctionToolCall, ChatCompletionMessageParam, - ChatCompletionMessageToolCall, + ChatCompletionMessageToolCallUnion, ChatCompletionModality, ChatCompletionNamedToolChoice, ChatCompletionNamedToolChoiceCustom, diff --git a/src/openai/types/chat/__init__.py b/src/openai/types/chat/__init__.py index c9e77ff41c..25ad0bfda6 100644 --- a/src/openai/types/chat/__init__.py +++ b/src/openai/types/chat/__init__.py @@ -31,7 +31,7 @@ from .chat_completion_tool_union_param import ChatCompletionToolUnionParam as ChatCompletionToolUnionParam from .chat_completion_content_part_text import ChatCompletionContentPartText as ChatCompletionContentPartText from .chat_completion_custom_tool_param import ChatCompletionCustomToolParam as ChatCompletionCustomToolParam -from .chat_completion_message_tool_call import ChatCompletionMessageToolCall as ChatCompletionMessageToolCall +from .chat_completion_message_tool_call import ChatCompletionMessageToolCallUnion as ChatCompletionMessageToolCallUnion from .chat_completion_content_part_image import ChatCompletionContentPartImage as ChatCompletionContentPartImage from .chat_completion_content_part_param import ChatCompletionContentPartParam as ChatCompletionContentPartParam from .chat_completion_tool_message_param import ChatCompletionToolMessageParam as ChatCompletionToolMessageParam @@ -52,9 +52,6 @@ from .chat_completion_developer_message_param import ( ChatCompletionDeveloperMessageParam as ChatCompletionDeveloperMessageParam, ) -from .chat_completion_message_tool_call_param import ( - ChatCompletionMessageToolCallParam as ChatCompletionMessageToolCallParam, -) from .chat_completion_named_tool_choice_param import ( ChatCompletionNamedToolChoiceParam as ChatCompletionNamedToolChoiceParam, ) @@ -82,6 +79,9 @@ from .chat_completion_message_function_tool_call import ( ChatCompletionMessageFunctionToolCall as ChatCompletionMessageFunctionToolCall, ) +from .chat_completion_message_tool_call_union_param import ( + ChatCompletionMessageToolCallUnionParam as ChatCompletionMessageToolCallUnionParam, +) from .chat_completion_content_part_input_audio_param import ( ChatCompletionContentPartInputAudioParam as ChatCompletionContentPartInputAudioParam, ) diff --git a/src/openai/types/chat/chat_completion_assistant_message_param.py b/src/openai/types/chat/chat_completion_assistant_message_param.py index 35e3a3d784..212d933e9b 100644 --- a/src/openai/types/chat/chat_completion_assistant_message_param.py +++ b/src/openai/types/chat/chat_completion_assistant_message_param.py @@ -6,8 +6,8 @@ from typing_extensions import Literal, Required, TypeAlias, TypedDict from .chat_completion_content_part_text_param import ChatCompletionContentPartTextParam -from .chat_completion_message_tool_call_param import ChatCompletionMessageToolCallParam from .chat_completion_content_part_refusal_param import ChatCompletionContentPartRefusalParam +from .chat_completion_message_tool_call_union_param import ChatCompletionMessageToolCallUnionParam __all__ = ["ChatCompletionAssistantMessageParam", "Audio", "ContentArrayOfContentPart", "FunctionCall"] @@ -66,5 +66,5 @@ class ChatCompletionAssistantMessageParam(TypedDict, total=False): refusal: Optional[str] """The refusal message by the assistant.""" - tool_calls: Iterable[ChatCompletionMessageToolCallParam] + tool_calls: Iterable[ChatCompletionMessageToolCallUnionParam] """The tool calls generated by the model, such as function calls.""" diff --git a/src/openai/types/chat/chat_completion_message.py b/src/openai/types/chat/chat_completion_message.py index c659ac3da0..5bb153fe3f 100644 --- a/src/openai/types/chat/chat_completion_message.py +++ b/src/openai/types/chat/chat_completion_message.py @@ -5,7 +5,7 @@ from ..._models import BaseModel from .chat_completion_audio import ChatCompletionAudio -from .chat_completion_message_tool_call import ChatCompletionMessageToolCall +from .chat_completion_message_tool_call import ChatCompletionMessageToolCallUnion __all__ = ["ChatCompletionMessage", "Annotation", "AnnotationURLCitation", "FunctionCall"] @@ -75,5 +75,5 @@ class ChatCompletionMessage(BaseModel): model. """ - tool_calls: Optional[List[ChatCompletionMessageToolCall]] = None + tool_calls: Optional[List[ChatCompletionMessageToolCallUnion]] = None """The tool calls generated by the model, such as function calls.""" diff --git a/src/openai/types/chat/chat_completion_message_tool_call.py b/src/openai/types/chat/chat_completion_message_tool_call.py index 94cc086e9d..df687b19bd 100644 --- a/src/openai/types/chat/chat_completion_message_tool_call.py +++ b/src/openai/types/chat/chat_completion_message_tool_call.py @@ -7,9 +7,9 @@ from .chat_completion_message_custom_tool_call import ChatCompletionMessageCustomToolCall from .chat_completion_message_function_tool_call import Function as Function, ChatCompletionMessageFunctionToolCall -__all__ = ["ChatCompletionMessageToolCall", "Function"] +__all__ = [ "Function", "ChatCompletionMessageToolCallUnion"] -ChatCompletionMessageToolCall: TypeAlias = Annotated[ +ChatCompletionMessageToolCallUnion: TypeAlias = Annotated[ Union[ChatCompletionMessageFunctionToolCall, ChatCompletionMessageCustomToolCall], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/chat/chat_completion_message_tool_call_param.py b/src/openai/types/chat/chat_completion_message_tool_call_union_param.py similarity index 81% rename from src/openai/types/chat/chat_completion_message_tool_call_param.py rename to src/openai/types/chat/chat_completion_message_tool_call_union_param.py index 96ba6521f0..fcca9bb116 100644 --- a/src/openai/types/chat/chat_completion_message_tool_call_param.py +++ b/src/openai/types/chat/chat_completion_message_tool_call_union_param.py @@ -8,8 +8,8 @@ from .chat_completion_message_custom_tool_call_param import ChatCompletionMessageCustomToolCallParam from .chat_completion_message_function_tool_call_param import ChatCompletionMessageFunctionToolCallParam -__all__ = ["ChatCompletionMessageToolCallParam"] +__all__ = ["ChatCompletionMessageToolCallUnionParam"] -ChatCompletionMessageToolCallParam: TypeAlias = Union[ +ChatCompletionMessageToolCallUnionParam: TypeAlias = Union[ ChatCompletionMessageFunctionToolCallParam, ChatCompletionMessageCustomToolCallParam ] From a6beda8e67a29c21d2fd2c447a9cb6c61fc1685c Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Mon, 11 Aug 2025 14:08:27 +0100 Subject: [PATCH 438/769] fix(types): revert ChatCompletionMessageToolCallParam to a TypedDict --- src/openai/types/chat/__init__.py | 3 +++ .../chat_completion_message_tool_call_param.py | 14 ++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 src/openai/types/chat/chat_completion_message_tool_call_param.py diff --git a/src/openai/types/chat/__init__.py b/src/openai/types/chat/__init__.py index 25ad0bfda6..2aecaf7d0c 100644 --- a/src/openai/types/chat/__init__.py +++ b/src/openai/types/chat/__init__.py @@ -52,6 +52,9 @@ from .chat_completion_developer_message_param import ( ChatCompletionDeveloperMessageParam as ChatCompletionDeveloperMessageParam, ) +from .chat_completion_message_tool_call_param import ( + ChatCompletionMessageToolCallParam as ChatCompletionMessageToolCallParam, +) from .chat_completion_named_tool_choice_param import ( ChatCompletionNamedToolChoiceParam as ChatCompletionNamedToolChoiceParam, ) diff --git a/src/openai/types/chat/chat_completion_message_tool_call_param.py b/src/openai/types/chat/chat_completion_message_tool_call_param.py new file mode 100644 index 0000000000..6baa1b57ab --- /dev/null +++ b/src/openai/types/chat/chat_completion_message_tool_call_param.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +from .chat_completion_message_function_tool_call_param import ( + Function as Function, + ChatCompletionMessageFunctionToolCallParam, +) + +__all__ = ["ChatCompletionMessageToolCallParam", "Function"] + +ChatCompletionMessageToolCallParam: TypeAlias = ChatCompletionMessageFunctionToolCallParam From 23887e4b9180f62e634f95ae4dff1ace447a630a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 11 Aug 2025 13:09:54 +0000 Subject: [PATCH 439/769] release: 1.99.7 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 9 +++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 03128d3ade..804a6039aa 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.99.6" + ".": "1.99.7" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 8edff34439..74d0da964a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 1.99.7 (2025-08-11) + +Full Changelog: [v1.99.6...v1.99.7](https://github.com/openai/openai-python/compare/v1.99.6...v1.99.7) + +### Bug Fixes + +* **types:** rename ChatCompletionMessageToolCallParam ([48085e2](https://github.com/openai/openai-python/commit/48085e2f473799d079e71d48d2f5612a6fbeb976)) +* **types:** revert ChatCompletionMessageToolCallParam to a TypedDict ([c8e9cec](https://github.com/openai/openai-python/commit/c8e9cec5c93cc022fff546f27161717f769d1f81)) + ## 1.99.6 (2025-08-09) Full Changelog: [v1.99.5...v1.99.6](https://github.com/openai/openai-python/compare/v1.99.5...v1.99.6) diff --git a/pyproject.toml b/pyproject.toml index 37e9d4f767..d58b9b1eb2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.99.6" +version = "1.99.7" 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 eed63aadba..3db3f866cf 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.99.6" # x-release-please-version +__version__ = "1.99.7" # x-release-please-version From f03096cb7ce9343fd88f16e1c1b93dcc794279b4 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Mon, 11 Aug 2025 16:19:50 +0100 Subject: [PATCH 440/769] chore(internal/tests): add inline snapshot format command --- pyproject.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index d58b9b1eb2..97ec8cf43d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -150,6 +150,9 @@ filterwarnings = [ "error" ] +[tool.inline-snapshot] +format-command="ruff format --stdin-filename {filename}" + [tool.pyright] # this enables practically every flag given by pyright. # there are a couple of flags that are still disabled by From 266edeba335834f2009e59c0a4a1ded8cb45749d Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Mon, 11 Aug 2025 16:20:48 +0100 Subject: [PATCH 441/769] refactor(tests): share snapshot utils --- tests/lib/chat/test_completions.py | 120 +++---------------- tests/lib/chat/test_completions_streaming.py | 2 +- tests/lib/snapshots.py | 99 +++++++++++++++ tests/lib/{chat/_utils.py => utils.py} | 2 +- 4 files changed, 118 insertions(+), 105 deletions(-) create mode 100644 tests/lib/snapshots.py rename tests/lib/{chat/_utils.py => utils.py} (98%) diff --git a/tests/lib/chat/test_completions.py b/tests/lib/chat/test_completions.py index d0bd14ce9e..3ef2e74c19 100644 --- a/tests/lib/chat/test_completions.py +++ b/tests/lib/chat/test_completions.py @@ -1,12 +1,9 @@ from __future__ import annotations -import os -import json from enum import Enum -from typing import Any, List, Callable, Optional, Awaitable +from typing import List, Optional from typing_extensions import Literal, TypeVar -import httpx import pytest from respx import MockRouter from pydantic import Field, BaseModel @@ -17,8 +14,9 @@ from openai._utils import assert_signatures_in_sync from openai._compat import PYDANTIC_V2 -from ._utils import print_obj, get_snapshot_value +from ..utils import print_obj from ...conftest import base_url +from ..snapshots import make_snapshot_request, make_async_snapshot_request from ..schema_types.query import Query _T = TypeVar("_T") @@ -32,7 +30,7 @@ @pytest.mark.respx(base_url=base_url) def test_parse_nothing(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None: - completion = _make_snapshot_request( + completion = make_snapshot_request( lambda c: c.chat.completions.parse( model="gpt-4o-2024-08-06", messages=[ @@ -100,7 +98,7 @@ class Location(BaseModel): temperature: float units: Literal["c", "f"] - completion = _make_snapshot_request( + completion = make_snapshot_request( lambda c: c.chat.completions.parse( model="gpt-4o-2024-08-06", messages=[ @@ -170,7 +168,7 @@ class Location(BaseModel): temperature: float units: Optional[Literal["c", "f"]] = None - completion = _make_snapshot_request( + completion = make_snapshot_request( lambda c: c.chat.completions.parse( model="gpt-4o-2024-08-06", messages=[ @@ -247,7 +245,7 @@ class ColorDetection(BaseModel): if not PYDANTIC_V2: ColorDetection.update_forward_refs(**locals()) # type: ignore - completion = _make_snapshot_request( + completion = make_snapshot_request( lambda c: c.chat.completions.parse( model="gpt-4o-2024-08-06", messages=[ @@ -292,7 +290,7 @@ class Location(BaseModel): temperature: float units: Literal["c", "f"] - completion = _make_snapshot_request( + completion = make_snapshot_request( lambda c: c.chat.completions.parse( model="gpt-4o-2024-08-06", messages=[ @@ -375,7 +373,7 @@ class CalendarEvent: date: str participants: List[str] - completion = _make_snapshot_request( + completion = make_snapshot_request( lambda c: c.chat.completions.parse( model="gpt-4o-2024-08-06", messages=[ @@ -436,7 +434,7 @@ class CalendarEvent: @pytest.mark.respx(base_url=base_url) def test_pydantic_tool_model_all_types(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None: - completion = _make_snapshot_request( + completion = make_snapshot_request( lambda c: c.chat.completions.parse( model="gpt-4o-2024-08-06", messages=[ @@ -521,7 +519,7 @@ class Location(BaseModel): units: Literal["c", "f"] with pytest.raises(openai.LengthFinishReasonError): - _make_snapshot_request( + make_snapshot_request( lambda c: c.chat.completions.parse( model="gpt-4o-2024-08-06", messages=[ @@ -548,7 +546,7 @@ class Location(BaseModel): temperature: float units: Literal["c", "f"] - completion = _make_snapshot_request( + completion = make_snapshot_request( lambda c: c.chat.completions.parse( model="gpt-4o-2024-08-06", messages=[ @@ -596,7 +594,7 @@ class GetWeatherArgs(BaseModel): country: str units: Literal["c", "f"] = "c" - completion = _make_snapshot_request( + completion = make_snapshot_request( lambda c: c.chat.completions.parse( model="gpt-4o-2024-08-06", messages=[ @@ -662,7 +660,7 @@ class GetStockPrice(BaseModel): ticker: str exchange: str - completion = _make_snapshot_request( + completion = make_snapshot_request( lambda c: c.chat.completions.parse( model="gpt-4o-2024-08-06", messages=[ @@ -733,7 +731,7 @@ class GetStockPrice(BaseModel): @pytest.mark.respx(base_url=base_url) def test_parse_strict_tools(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None: - completion = _make_snapshot_request( + completion = make_snapshot_request( lambda c: c.chat.completions.parse( model="gpt-4o-2024-08-06", messages=[ @@ -830,7 +828,7 @@ class Location(BaseModel): temperature: float units: Literal["c", "f"] - response = _make_snapshot_request( + response = make_snapshot_request( lambda c: c.chat.completions.with_raw_response.parse( model="gpt-4o-2024-08-06", messages=[ @@ -906,7 +904,7 @@ class Location(BaseModel): temperature: float units: Literal["c", "f"] - response = await _make_async_snapshot_request( + response = await make_async_snapshot_request( lambda c: c.chat.completions.with_raw_response.parse( model="gpt-4o-2024-08-06", messages=[ @@ -981,87 +979,3 @@ def test_parse_method_in_sync(sync: bool, client: OpenAI, async_client: AsyncOpe checking_client.chat.completions.parse, exclude_params={"response_format", "stream"}, ) - - -def _make_snapshot_request( - func: Callable[[OpenAI], _T], - *, - content_snapshot: Any, - respx_mock: MockRouter, - mock_client: OpenAI, -) -> _T: - live = os.environ.get("OPENAI_LIVE") == "1" - if live: - - def _on_response(response: httpx.Response) -> None: - # update the content snapshot - assert json.dumps(json.loads(response.read())) == content_snapshot - - respx_mock.stop() - - client = OpenAI( - http_client=httpx.Client( - event_hooks={ - "response": [_on_response], - } - ) - ) - else: - respx_mock.post("/chat/completions").mock( - return_value=httpx.Response( - 200, - content=get_snapshot_value(content_snapshot), - headers={"content-type": "application/json"}, - ) - ) - - client = mock_client - - result = func(client) - - if live: - client.close() - - return result - - -async def _make_async_snapshot_request( - func: Callable[[AsyncOpenAI], Awaitable[_T]], - *, - content_snapshot: Any, - respx_mock: MockRouter, - mock_client: AsyncOpenAI, -) -> _T: - live = os.environ.get("OPENAI_LIVE") == "1" - if live: - - async def _on_response(response: httpx.Response) -> None: - # update the content snapshot - assert json.dumps(json.loads(await response.aread())) == content_snapshot - - respx_mock.stop() - - client = AsyncOpenAI( - http_client=httpx.AsyncClient( - event_hooks={ - "response": [_on_response], - } - ) - ) - else: - respx_mock.post("/chat/completions").mock( - return_value=httpx.Response( - 200, - content=get_snapshot_value(content_snapshot), - headers={"content-type": "application/json"}, - ) - ) - - client = mock_client - - result = await func(client) - - if live: - await client.close() - - return result diff --git a/tests/lib/chat/test_completions_streaming.py b/tests/lib/chat/test_completions_streaming.py index 1daa98c6a0..65826d28d9 100644 --- a/tests/lib/chat/test_completions_streaming.py +++ b/tests/lib/chat/test_completions_streaming.py @@ -30,7 +30,7 @@ ) from openai.lib._parsing._completions import ResponseFormatT -from ._utils import print_obj, get_snapshot_value +from ..utils import print_obj, get_snapshot_value from ...conftest import base_url _T = TypeVar("_T") diff --git a/tests/lib/snapshots.py b/tests/lib/snapshots.py new file mode 100644 index 0000000000..64b1163338 --- /dev/null +++ b/tests/lib/snapshots.py @@ -0,0 +1,99 @@ +from __future__ import annotations + +import os +import json +from typing import Any, Callable, Awaitable +from typing_extensions import TypeVar + +import httpx +from respx import MockRouter + +from openai import OpenAI, AsyncOpenAI + +from .utils import get_snapshot_value + +_T = TypeVar("_T") + + +def make_snapshot_request( + func: Callable[[OpenAI], _T], + *, + content_snapshot: Any, + respx_mock: MockRouter, + mock_client: OpenAI, +) -> _T: + live = os.environ.get("OPENAI_LIVE") == "1" + if live: + + def _on_response(response: httpx.Response) -> None: + # update the content snapshot + assert json.dumps(json.loads(response.read())) == content_snapshot + + respx_mock.stop() + + client = OpenAI( + http_client=httpx.Client( + event_hooks={ + "response": [_on_response], + } + ) + ) + else: + respx_mock.post("/chat/completions").mock( + return_value=httpx.Response( + 200, + content=get_snapshot_value(content_snapshot), + headers={"content-type": "application/json"}, + ) + ) + + client = mock_client + + result = func(client) + + if live: + client.close() + + return result + + +async def make_async_snapshot_request( + func: Callable[[AsyncOpenAI], Awaitable[_T]], + *, + content_snapshot: Any, + respx_mock: MockRouter, + mock_client: AsyncOpenAI, +) -> _T: + live = os.environ.get("OPENAI_LIVE") == "1" + if live: + + async def _on_response(response: httpx.Response) -> None: + # update the content snapshot + assert json.dumps(json.loads(await response.aread())) == content_snapshot + + respx_mock.stop() + + client = AsyncOpenAI( + http_client=httpx.AsyncClient( + event_hooks={ + "response": [_on_response], + } + ) + ) + else: + respx_mock.post("/chat/completions").mock( + return_value=httpx.Response( + 200, + content=get_snapshot_value(content_snapshot), + headers={"content-type": "application/json"}, + ) + ) + + client = mock_client + + result = await func(client) + + if live: + await client.close() + + return result diff --git a/tests/lib/chat/_utils.py b/tests/lib/utils.py similarity index 98% rename from tests/lib/chat/_utils.py rename to tests/lib/utils.py index 0cc1c99952..2129ee811a 100644 --- a/tests/lib/chat/_utils.py +++ b/tests/lib/utils.py @@ -7,7 +7,7 @@ import pytest import pydantic -from ...utils import rich_print_str +from ..utils import rich_print_str ReprArgs: TypeAlias = "Iterable[tuple[str | None, Any]]" From fd0af12000ff807e558039d9780e0e41bbf6bf2f Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Mon, 11 Aug 2025 16:20:56 +0100 Subject: [PATCH 442/769] chore(internal): fix formatting --- src/openai/types/chat/chat_completion_message_tool_call.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openai/types/chat/chat_completion_message_tool_call.py b/src/openai/types/chat/chat_completion_message_tool_call.py index df687b19bd..be01179701 100644 --- a/src/openai/types/chat/chat_completion_message_tool_call.py +++ b/src/openai/types/chat/chat_completion_message_tool_call.py @@ -7,7 +7,7 @@ from .chat_completion_message_custom_tool_call import ChatCompletionMessageCustomToolCall from .chat_completion_message_function_tool_call import Function as Function, ChatCompletionMessageFunctionToolCall -__all__ = [ "Function", "ChatCompletionMessageToolCallUnion"] +__all__ = ["Function", "ChatCompletionMessageToolCallUnion"] ChatCompletionMessageToolCallUnion: TypeAlias = Annotated[ Union[ChatCompletionMessageFunctionToolCall, ChatCompletionMessageCustomToolCall], From a4cd0b5086a419ccf02981f61dccb4b23f6e85a0 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Mon, 11 Aug 2025 16:28:37 +0100 Subject: [PATCH 443/769] chore(tests): add responses output_text test --- tests/lib/chat/test_completions.py | 14 ++++++++++ tests/lib/responses/__init__.py | 0 tests/lib/responses/test_responses.py | 40 +++++++++++++++++++++++++++ tests/lib/snapshots.py | 6 ++-- 4 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 tests/lib/responses/__init__.py create mode 100644 tests/lib/responses/test_responses.py diff --git a/tests/lib/chat/test_completions.py b/tests/lib/chat/test_completions.py index 3ef2e74c19..0371f6828b 100644 --- a/tests/lib/chat/test_completions.py +++ b/tests/lib/chat/test_completions.py @@ -43,6 +43,7 @@ def test_parse_nothing(client: OpenAI, respx_mock: MockRouter, monkeypatch: pyte content_snapshot=snapshot( '{"id": "chatcmpl-ABfvaueLEMLNYbT8YzpJxsmiQ6HSY", "object": "chat.completion", "created": 1727346142, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": "I\'m unable to provide real-time weather updates. To get the current weather in San Francisco, I recommend checking a reliable weather website or app like the Weather Channel or a local news station.", "refusal": null}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 14, "completion_tokens": 37, "total_tokens": 51, "completion_tokens_details": {"reasoning_tokens": 0}}, "system_fingerprint": "fp_b40fb1c6fb"}' ), + path="/chat/completions", mock_client=client, respx_mock=respx_mock, ) @@ -112,6 +113,7 @@ class Location(BaseModel): content_snapshot=snapshot( '{"id": "chatcmpl-ABfvbtVnTu5DeC4EFnRYj8mtfOM99", "object": "chat.completion", "created": 1727346143, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": "{\\"city\\":\\"San Francisco\\",\\"temperature\\":65,\\"units\\":\\"f\\"}", "refusal": null}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 79, "completion_tokens": 14, "total_tokens": 93, "completion_tokens_details": {"reasoning_tokens": 0}}, "system_fingerprint": "fp_5050236cbd"}' ), + path="/chat/completions", mock_client=client, respx_mock=respx_mock, ) @@ -182,6 +184,7 @@ class Location(BaseModel): content_snapshot=snapshot( '{"id": "chatcmpl-ABfvcC8grKYsRkSoMp9CCAhbXAd0b", "object": "chat.completion", "created": 1727346144, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": "{\\"city\\":\\"San Francisco\\",\\"temperature\\":65,\\"units\\":\\"f\\"}", "refusal": null}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 88, "completion_tokens": 14, "total_tokens": 102, "completion_tokens_details": {"reasoning_tokens": 0}}, "system_fingerprint": "fp_b40fb1c6fb"}' ), + path="/chat/completions", mock_client=client, respx_mock=respx_mock, ) @@ -256,6 +259,7 @@ class ColorDetection(BaseModel): content_snapshot=snapshot( '{"id": "chatcmpl-ABfvjIatz0zrZu50gRbMtlp0asZpz", "object": "chat.completion", "created": 1727346151, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": "{\\"color\\":\\"red\\",\\"hex_color_code\\":\\"#FF0000\\"}", "refusal": null}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 109, "completion_tokens": 14, "total_tokens": 123, "completion_tokens_details": {"reasoning_tokens": 0}}, "system_fingerprint": "fp_5050236cbd"}' ), + path="/chat/completions", mock_client=client, respx_mock=respx_mock, ) @@ -305,6 +309,7 @@ class Location(BaseModel): content_snapshot=snapshot( '{"id": "chatcmpl-ABfvp8qzboW92q8ONDF4DPHlI7ckC", "object": "chat.completion", "created": 1727346157, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": "{\\"city\\":\\"San Francisco\\",\\"temperature\\":64,\\"units\\":\\"f\\"}", "refusal": null}, "logprobs": null, "finish_reason": "stop"}, {"index": 1, "message": {"role": "assistant", "content": "{\\"city\\":\\"San Francisco\\",\\"temperature\\":65,\\"units\\":\\"f\\"}", "refusal": null}, "logprobs": null, "finish_reason": "stop"}, {"index": 2, "message": {"role": "assistant", "content": "{\\"city\\":\\"San Francisco\\",\\"temperature\\":63.0,\\"units\\":\\"f\\"}", "refusal": null}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 79, "completion_tokens": 44, "total_tokens": 123, "completion_tokens_details": {"reasoning_tokens": 0}}, "system_fingerprint": "fp_b40fb1c6fb"}' ), + path="/chat/completions", mock_client=client, respx_mock=respx_mock, ) @@ -385,6 +390,7 @@ class CalendarEvent: content_snapshot=snapshot( '{"id": "chatcmpl-ABfvqhz4uUUWsw8Ohw2Mp9B4sKKV8", "object": "chat.completion", "created": 1727346158, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": "{\\"name\\":\\"Science Fair\\",\\"date\\":\\"Friday\\",\\"participants\\":[\\"Alice\\",\\"Bob\\"]}", "refusal": null}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 92, "completion_tokens": 17, "total_tokens": 109, "completion_tokens_details": {"reasoning_tokens": 0}}, "system_fingerprint": "fp_7568d46099"}' ), + path="/chat/completions", mock_client=client, respx_mock=respx_mock, ) @@ -449,6 +455,7 @@ def test_pydantic_tool_model_all_types(client: OpenAI, respx_mock: MockRouter, m content_snapshot=snapshot( '{"id": "chatcmpl-ABfvtNiaTNUF6OymZUnEFc9lPq9p1", "object": "chat.completion", "created": 1727346161, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": null, "tool_calls": [{"id": "call_NKpApJybW1MzOjZO2FzwYw0d", "type": "function", "function": {"name": "Query", "arguments": "{\\"name\\":\\"May 2022 Fulfilled Orders Not Delivered on Time\\",\\"table_name\\":\\"orders\\",\\"columns\\":[\\"id\\",\\"status\\",\\"expected_delivery_date\\",\\"delivered_at\\",\\"shipped_at\\",\\"ordered_at\\",\\"canceled_at\\"],\\"conditions\\":[{\\"column\\":\\"ordered_at\\",\\"operator\\":\\">=\\",\\"value\\":\\"2022-05-01\\"},{\\"column\\":\\"ordered_at\\",\\"operator\\":\\"<=\\",\\"value\\":\\"2022-05-31\\"},{\\"column\\":\\"status\\",\\"operator\\":\\"=\\",\\"value\\":\\"fulfilled\\"},{\\"column\\":\\"delivered_at\\",\\"operator\\":\\">\\",\\"value\\":{\\"column_name\\":\\"expected_delivery_date\\"}}],\\"order_by\\":\\"asc\\"}"}}], "refusal": null}, "logprobs": null, "finish_reason": "tool_calls"}], "usage": {"prompt_tokens": 512, "completion_tokens": 132, "total_tokens": 644, "completion_tokens_details": {"reasoning_tokens": 0}}, "system_fingerprint": "fp_7568d46099"}' ), + path="/chat/completions", mock_client=client, respx_mock=respx_mock, ) @@ -534,6 +541,7 @@ class Location(BaseModel): content_snapshot=snapshot( '{"id": "chatcmpl-ABfvvX7eB1KsfeZj8VcF3z7G7SbaA", "object": "chat.completion", "created": 1727346163, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": "{\\"", "refusal": null}, "logprobs": null, "finish_reason": "length"}], "usage": {"prompt_tokens": 79, "completion_tokens": 1, "total_tokens": 80, "completion_tokens_details": {"reasoning_tokens": 0}}, "system_fingerprint": "fp_7568d46099"}' ), + path="/chat/completions", mock_client=client, respx_mock=respx_mock, ) @@ -560,6 +568,7 @@ class Location(BaseModel): content_snapshot=snapshot( '{"id": "chatcmpl-ABfvwoKVWPQj2UPlAcAKM7s40GsRx", "object": "chat.completion", "created": 1727346164, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": null, "refusal": "I\'m very sorry, but I can\'t assist with that."}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 79, "completion_tokens": 12, "total_tokens": 91, "completion_tokens_details": {"reasoning_tokens": 0}}, "system_fingerprint": "fp_5050236cbd"}' ), + path="/chat/completions", mock_client=client, respx_mock=respx_mock, ) @@ -610,6 +619,7 @@ class GetWeatherArgs(BaseModel): content_snapshot=snapshot( '{"id": "chatcmpl-ABfvx6Z4dchiW2nya1N8KMsHFrQRE", "object": "chat.completion", "created": 1727346165, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": null, "tool_calls": [{"id": "call_Y6qJ7ofLgOrBnMD5WbVAeiRV", "type": "function", "function": {"name": "GetWeatherArgs", "arguments": "{\\"city\\":\\"Edinburgh\\",\\"country\\":\\"UK\\",\\"units\\":\\"c\\"}"}}], "refusal": null}, "logprobs": null, "finish_reason": "tool_calls"}], "usage": {"prompt_tokens": 76, "completion_tokens": 24, "total_tokens": 100, "completion_tokens_details": {"reasoning_tokens": 0}}, "system_fingerprint": "fp_e45dabd248"}' ), + path="/chat/completions", mock_client=client, respx_mock=respx_mock, ) @@ -683,6 +693,7 @@ class GetStockPrice(BaseModel): content_snapshot=snapshot( '{"id": "chatcmpl-ABfvyvfNWKcl7Ohqos4UFrmMs1v4C", "object": "chat.completion", "created": 1727346166, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": null, "tool_calls": [{"id": "call_fdNz3vOBKYgOIpMdWotB9MjY", "type": "function", "function": {"name": "GetWeatherArgs", "arguments": "{\\"city\\": \\"Edinburgh\\", \\"country\\": \\"GB\\", \\"units\\": \\"c\\"}"}}, {"id": "call_h1DWI1POMJLb0KwIyQHWXD4p", "type": "function", "function": {"name": "get_stock_price", "arguments": "{\\"ticker\\": \\"AAPL\\", \\"exchange\\": \\"NASDAQ\\"}"}}], "refusal": null}, "logprobs": null, "finish_reason": "tool_calls"}], "usage": {"prompt_tokens": 149, "completion_tokens": 60, "total_tokens": 209, "completion_tokens_details": {"reasoning_tokens": 0}}, "system_fingerprint": "fp_b40fb1c6fb"}' ), + path="/chat/completions", mock_client=client, respx_mock=respx_mock, ) @@ -765,6 +776,7 @@ def test_parse_strict_tools(client: OpenAI, respx_mock: MockRouter, monkeypatch: content_snapshot=snapshot( '{"id": "chatcmpl-ABfvzdvCI6RaIkiEFNjqGXCSYnlzf", "object": "chat.completion", "created": 1727346167, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": null, "tool_calls": [{"id": "call_CUdUoJpsWWVdxXntucvnol1M", "type": "function", "function": {"name": "get_weather", "arguments": "{\\"city\\":\\"San Francisco\\",\\"state\\":\\"CA\\"}"}}], "refusal": null}, "logprobs": null, "finish_reason": "tool_calls"}], "usage": {"prompt_tokens": 48, "completion_tokens": 19, "total_tokens": 67, "completion_tokens_details": {"reasoning_tokens": 0}}, "system_fingerprint": "fp_5050236cbd"}' ), + path="/chat/completions", mock_client=client, respx_mock=respx_mock, ) @@ -842,6 +854,7 @@ class Location(BaseModel): content_snapshot=snapshot( '{"id": "chatcmpl-ABrDYCa8W1w66eUxKDO8TQF1m6trT", "object": "chat.completion", "created": 1727389540, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": "{\\"city\\":\\"San Francisco\\",\\"temperature\\":58,\\"units\\":\\"f\\"}", "refusal": null}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 79, "completion_tokens": 14, "total_tokens": 93, "completion_tokens_details": {"reasoning_tokens": 0}}, "system_fingerprint": "fp_5050236cbd"}' ), + path="/chat/completions", mock_client=client, respx_mock=respx_mock, ) @@ -918,6 +931,7 @@ class Location(BaseModel): content_snapshot=snapshot( '{"id": "chatcmpl-ABrDQWOiw0PK5JOsxl1D9ooeQgznq", "object": "chat.completion", "created": 1727389532, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": "{\\"city\\":\\"San Francisco\\",\\"temperature\\":65,\\"units\\":\\"f\\"}", "refusal": null}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 79, "completion_tokens": 14, "total_tokens": 93, "completion_tokens_details": {"reasoning_tokens": 0}}, "system_fingerprint": "fp_5050236cbd"}' ), + path="/chat/completions", mock_client=async_client, respx_mock=respx_mock, ) diff --git a/tests/lib/responses/__init__.py b/tests/lib/responses/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/lib/responses/test_responses.py b/tests/lib/responses/test_responses.py new file mode 100644 index 0000000000..d996127dcd --- /dev/null +++ b/tests/lib/responses/test_responses.py @@ -0,0 +1,40 @@ +from __future__ import annotations + +from typing_extensions import TypeVar + +import pytest +from respx import MockRouter +from inline_snapshot import snapshot + +from openai import OpenAI + +from ...conftest import base_url +from ..snapshots import make_snapshot_request + +_T = TypeVar("_T") + +# all the snapshots in this file are auto-generated from the live API +# +# you can update them with +# +# `OPENAI_LIVE=1 pytest --inline-snapshot=fix` + + +@pytest.mark.respx(base_url=base_url) +def test_output_text(client: OpenAI, respx_mock: MockRouter) -> None: + response = make_snapshot_request( + lambda c: c.responses.create( + model="gpt-4o-mini", + input="What's the weather like in SF?", + ), + content_snapshot=snapshot( + '{"id": "resp_689a0b2545288193953c892439b42e2800b2e36c65a1fd4b", "object": "response", "created_at": 1754925861, "status": "completed", "background": false, "error": null, "incomplete_details": null, "instructions": null, "max_output_tokens": null, "max_tool_calls": null, "model": "gpt-4o-mini-2024-07-18", "output": [{"id": "msg_689a0b2637b08193ac478e568f49e3f900b2e36c65a1fd4b", "type": "message", "status": "completed", "content": [{"type": "output_text", "annotations": [], "logprobs": [], "text": "I can\'t provide real-time updates, but you can easily check the current weather in San Francisco using a weather website or app. Typically, San Francisco has cool, foggy summers and mild winters, so it\'s good to be prepared for variable weather!"}], "role": "assistant"}], "parallel_tool_calls": true, "previous_response_id": null, "prompt_cache_key": null, "reasoning": {"effort": null, "summary": null}, "safety_identifier": null, "service_tier": "default", "store": true, "temperature": 1.0, "text": {"format": {"type": "text"}, "verbosity": "medium"}, "tool_choice": "auto", "tools": [], "top_logprobs": 0, "top_p": 1.0, "truncation": "disabled", "usage": {"input_tokens": 14, "input_tokens_details": {"cached_tokens": 0}, "output_tokens": 50, "output_tokens_details": {"reasoning_tokens": 0}, "total_tokens": 64}, "user": null, "metadata": {}}' + ), + path="/responses", + mock_client=client, + respx_mock=respx_mock, + ) + + assert response.output_text == snapshot( + "I can't provide real-time updates, but you can easily check the current weather in San Francisco using a weather website or app. Typically, San Francisco has cool, foggy summers and mild winters, so it's good to be prepared for variable weather!" + ) diff --git a/tests/lib/snapshots.py b/tests/lib/snapshots.py index 64b1163338..ed53edebcb 100644 --- a/tests/lib/snapshots.py +++ b/tests/lib/snapshots.py @@ -21,6 +21,7 @@ def make_snapshot_request( content_snapshot: Any, respx_mock: MockRouter, mock_client: OpenAI, + path: str, ) -> _T: live = os.environ.get("OPENAI_LIVE") == "1" if live: @@ -39,7 +40,7 @@ def _on_response(response: httpx.Response) -> None: ) ) else: - respx_mock.post("/chat/completions").mock( + respx_mock.post(path).mock( return_value=httpx.Response( 200, content=get_snapshot_value(content_snapshot), @@ -63,6 +64,7 @@ async def make_async_snapshot_request( content_snapshot: Any, respx_mock: MockRouter, mock_client: AsyncOpenAI, + path: str, ) -> _T: live = os.environ.get("OPENAI_LIVE") == "1" if live: @@ -81,7 +83,7 @@ async def _on_response(response: httpx.Response) -> None: ) ) else: - respx_mock.post("/chat/completions").mock( + respx_mock.post(path).mock( return_value=httpx.Response( 200, content=get_snapshot_value(content_snapshot), From 753d472ef8f14cda35bcd0a992813cb4af9ffef9 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Mon, 11 Aug 2025 16:30:26 +0100 Subject: [PATCH 444/769] fix(internal/tests): correct snapshot update comment --- tests/lib/chat/test_completions.py | 2 +- tests/lib/chat/test_completions_streaming.py | 2 +- tests/lib/responses/test_responses.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/lib/chat/test_completions.py b/tests/lib/chat/test_completions.py index 0371f6828b..f04a0e3782 100644 --- a/tests/lib/chat/test_completions.py +++ b/tests/lib/chat/test_completions.py @@ -25,7 +25,7 @@ # # you can update them with # -# `OPENAI_LIVE=1 pytest --inline-snapshot=fix` +# `OPENAI_LIVE=1 pytest --inline-snapshot=fix -p no:xdist -o addopts=""` @pytest.mark.respx(base_url=base_url) diff --git a/tests/lib/chat/test_completions_streaming.py b/tests/lib/chat/test_completions_streaming.py index 65826d28d9..fa17f67177 100644 --- a/tests/lib/chat/test_completions_streaming.py +++ b/tests/lib/chat/test_completions_streaming.py @@ -39,7 +39,7 @@ # # you can update them with # -# `OPENAI_LIVE=1 pytest --inline-snapshot=fix` +# `OPENAI_LIVE=1 pytest --inline-snapshot=fix -p no:xdist -o addopts=""` @pytest.mark.respx(base_url=base_url) diff --git a/tests/lib/responses/test_responses.py b/tests/lib/responses/test_responses.py index d996127dcd..8ce3462e76 100644 --- a/tests/lib/responses/test_responses.py +++ b/tests/lib/responses/test_responses.py @@ -17,7 +17,7 @@ # # you can update them with # -# `OPENAI_LIVE=1 pytest --inline-snapshot=fix` +# `OPENAI_LIVE=1 pytest --inline-snapshot=fix -p no:xdist -o addopts=""` @pytest.mark.respx(base_url=base_url) From 37265a9d27e3596075d60499a0336698c11530d0 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Mon, 11 Aug 2025 21:13:29 +0100 Subject: [PATCH 445/769] fix(types): revert ChatCompletionMessageToolCallUnion breaking change --- src/openai/types/chat/__init__.py | 5 ++++- src/openai/types/chat/chat_completion_message_tool_call.py | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/openai/types/chat/__init__.py b/src/openai/types/chat/__init__.py index 2aecaf7d0c..50bdac7c65 100644 --- a/src/openai/types/chat/__init__.py +++ b/src/openai/types/chat/__init__.py @@ -31,7 +31,10 @@ from .chat_completion_tool_union_param import ChatCompletionToolUnionParam as ChatCompletionToolUnionParam from .chat_completion_content_part_text import ChatCompletionContentPartText as ChatCompletionContentPartText from .chat_completion_custom_tool_param import ChatCompletionCustomToolParam as ChatCompletionCustomToolParam -from .chat_completion_message_tool_call import ChatCompletionMessageToolCallUnion as ChatCompletionMessageToolCallUnion +from .chat_completion_message_tool_call import ( + ChatCompletionMessageToolCall as ChatCompletionMessageToolCall, + ChatCompletionMessageToolCallUnion as ChatCompletionMessageToolCallUnion, +) from .chat_completion_content_part_image import ChatCompletionContentPartImage as ChatCompletionContentPartImage from .chat_completion_content_part_param import ChatCompletionContentPartParam as ChatCompletionContentPartParam from .chat_completion_tool_message_param import ChatCompletionToolMessageParam as ChatCompletionToolMessageParam diff --git a/src/openai/types/chat/chat_completion_message_tool_call.py b/src/openai/types/chat/chat_completion_message_tool_call.py index be01179701..845e639089 100644 --- a/src/openai/types/chat/chat_completion_message_tool_call.py +++ b/src/openai/types/chat/chat_completion_message_tool_call.py @@ -13,3 +13,5 @@ Union[ChatCompletionMessageFunctionToolCall, ChatCompletionMessageCustomToolCall], PropertyInfo(discriminator="type"), ] + +ChatCompletionMessageToolCall: TypeAlias = ChatCompletionMessageToolCallUnion From a02ac0dd5b4797d4a782b4b75fd0790df3e14149 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 11 Aug 2025 20:14:05 +0000 Subject: [PATCH 446/769] release: 1.99.8 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 21 +++++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 804a6039aa..5d9ceab581 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.99.7" + ".": "1.99.8" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 74d0da964a..33e0e8e948 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,26 @@ # Changelog +## 1.99.8 (2025-08-11) + +Full Changelog: [v1.99.7...v1.99.8](https://github.com/openai/openai-python/compare/v1.99.7...v1.99.8) + +### Bug Fixes + +* **internal/tests:** correct snapshot update comment ([2784a7a](https://github.com/openai/openai-python/commit/2784a7a7da24ddba74b5717f07d67546864472b9)) +* **types:** revert ChatCompletionMessageToolCallUnion breaking change ([ba54e03](https://github.com/openai/openai-python/commit/ba54e03bc2d21825d891685bf3bad4a9253cbeb0)) + + +### Chores + +* **internal/tests:** add inline snapshot format command ([8107db8](https://github.com/openai/openai-python/commit/8107db8ff738baa65fe4cf2f2d7f1acd29219c78)) +* **internal:** fix formatting ([f03a03d](https://github.com/openai/openai-python/commit/f03a03de8c84740209d021598ff8bf56b6d3c684)) +* **tests:** add responses output_text test ([971347b](https://github.com/openai/openai-python/commit/971347b3a05f79c51abd11c86b382ca73c28cefb)) + + +### Refactors + +* **tests:** share snapshot utils ([791c567](https://github.com/openai/openai-python/commit/791c567cd87fb8d587965773b1da0404c7848c68)) + ## 1.99.7 (2025-08-11) Full Changelog: [v1.99.6...v1.99.7](https://github.com/openai/openai-python/compare/v1.99.6...v1.99.7) diff --git a/pyproject.toml b/pyproject.toml index 97ec8cf43d..b4a7d01a2b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.99.7" +version = "1.99.8" 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 3db3f866cf..9d1f1f4e96 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.99.7" # x-release-please-version +__version__ = "1.99.8" # x-release-please-version From 064910b115e21837dd793390e6cfbeddd07e5f9a Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Tue, 12 Aug 2025 01:23:24 +0100 Subject: [PATCH 447/769] fix(types): actually fix ChatCompletionMessageToolCall type --- src/openai/types/chat/chat_completion_message_tool_call.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openai/types/chat/chat_completion_message_tool_call.py b/src/openai/types/chat/chat_completion_message_tool_call.py index 845e639089..71ac63f58e 100644 --- a/src/openai/types/chat/chat_completion_message_tool_call.py +++ b/src/openai/types/chat/chat_completion_message_tool_call.py @@ -14,4 +14,4 @@ PropertyInfo(discriminator="type"), ] -ChatCompletionMessageToolCall: TypeAlias = ChatCompletionMessageToolCallUnion +ChatCompletionMessageToolCall: TypeAlias = ChatCompletionMessageFunctionToolCall From 34014aedbb8946c03e97e5c8d72e03ad2259cd7c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 12 Aug 2025 00:24:03 +0000 Subject: [PATCH 448/769] release: 1.99.9 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 5d9ceab581..2dfeb2d9bb 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.99.8" + ".": "1.99.9" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 33e0e8e948..392fb8b667 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.99.9 (2025-08-12) + +Full Changelog: [v1.99.8...v1.99.9](https://github.com/openai/openai-python/compare/v1.99.8...v1.99.9) + +### Bug Fixes + +* **types:** actually fix ChatCompletionMessageToolCall type ([20cb0c8](https://github.com/openai/openai-python/commit/20cb0c86d598e196386ff43db992f6497eb756d0)) + ## 1.99.8 (2025-08-11) Full Changelog: [v1.99.7...v1.99.8](https://github.com/openai/openai-python/compare/v1.99.7...v1.99.8) diff --git a/pyproject.toml b/pyproject.toml index b4a7d01a2b..ced6079b6d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.99.8" +version = "1.99.9" 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 9d1f1f4e96..7d3b3da5d7 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.99.8" # x-release-please-version +__version__ = "1.99.9" # x-release-please-version From 0843a1116498bc3312db9904adf71a4fb0a0a77e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 15 Aug 2025 19:11:41 +0000 Subject: [PATCH 449/769] feat(api): add new text parameters, expiration options --- .stats.yml | 6 +- src/openai/resources/batches.py | 10 ++ .../resources/beta/realtime/realtime.py | 8 +- .../resources/beta/realtime/sessions.py | 4 +- .../beta/realtime/transcription_sessions.py | 4 +- .../resources/beta/threads/runs/runs.py | 12 +- src/openai/resources/beta/threads/threads.py | 12 +- .../resources/chat/completions/completions.py | 48 +++++--- src/openai/resources/files.py | 14 ++- src/openai/resources/responses/responses.py | 107 ++++++------------ src/openai/resources/uploads/uploads.py | 10 ++ src/openai/types/batch_create_params.py | 23 +++- src/openai/types/beta/realtime/session.py | 2 +- .../beta/realtime/session_create_params.py | 2 +- .../beta/realtime/session_update_event.py | 2 +- .../realtime/session_update_event_param.py | 2 +- .../transcription_session_create_params.py | 2 +- .../realtime/transcription_session_update.py | 2 +- .../transcription_session_update_param.py | 2 +- .../beta/thread_create_and_run_params.py | 2 +- src/openai/types/beta/threads/run.py | 2 +- .../types/beta/threads/run_create_params.py | 2 +- src/openai/types/chat/chat_completion.py | 5 +- .../types/chat/chat_completion_chunk.py | 5 +- .../types/chat/completion_create_params.py | 18 ++- src/openai/types/file_create_params.py | 25 +++- src/openai/types/responses/__init__.py | 2 - src/openai/types/responses/response.py | 46 +++++--- .../types/responses/response_create_params.py | 45 +++++--- .../types/responses/response_text_config.py | 35 ------ .../responses/response_text_config_param.py | 36 ------ src/openai/types/upload_create_params.py | 25 +++- tests/api_resources/chat/test_completions.py | 4 + tests/api_resources/test_batches.py | 8 ++ tests/api_resources/test_files.py | 24 ++++ tests/api_resources/test_responses.py | 4 +- tests/api_resources/test_uploads.py | 28 +++++ 37 files changed, 343 insertions(+), 245 deletions(-) delete mode 100644 src/openai/types/responses/response_text_config.py delete mode 100644 src/openai/types/responses/response_text_config_param.py diff --git a/.stats.yml b/.stats.yml index a098c3d40d..66c46e7730 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-9cadfad609f94f20ebf74fdc06a80302f1a324dc69700a309a8056aabca82fd2.yml -openapi_spec_hash: 3eb8d86c06f0bb5e1190983e5acfc9ba -config_hash: 68337b532875626269c304372a669f67 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-24be531010b354303d741fc9247c1f84f75978f9f7de68aca92cb4f240a04722.yml +openapi_spec_hash: 3e46f439f6a863beadc71577eb4efa15 +config_hash: ed87b9139ac595a04a2162d754df2fed diff --git a/src/openai/resources/batches.py b/src/openai/resources/batches.py index 26ea498b31..2340bd2e32 100644 --- a/src/openai/resources/batches.py +++ b/src/openai/resources/batches.py @@ -49,6 +49,7 @@ def create( endpoint: Literal["/v1/responses", "/v1/chat/completions", "/v1/embeddings", "/v1/completions"], input_file_id: str, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + output_expires_after: batch_create_params.OutputExpiresAfter | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -85,6 +86,9 @@ def create( Keys are strings with a maximum length of 64 characters. Values are strings with a maximum length of 512 characters. + output_expires_after: The expiration policy for the output and/or error file that are generated for a + batch. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -101,6 +105,7 @@ def create( "endpoint": endpoint, "input_file_id": input_file_id, "metadata": metadata, + "output_expires_after": output_expires_after, }, batch_create_params.BatchCreateParams, ), @@ -259,6 +264,7 @@ async def create( endpoint: Literal["/v1/responses", "/v1/chat/completions", "/v1/embeddings", "/v1/completions"], input_file_id: str, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + output_expires_after: batch_create_params.OutputExpiresAfter | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -295,6 +301,9 @@ async def create( Keys are strings with a maximum length of 64 characters. Values are strings with a maximum length of 512 characters. + output_expires_after: The expiration policy for the output and/or error file that are generated for a + batch. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -311,6 +320,7 @@ async def create( "endpoint": endpoint, "input_file_id": input_file_id, "metadata": metadata, + "output_expires_after": output_expires_after, }, batch_create_params.BatchCreateParams, ), diff --git a/src/openai/resources/beta/realtime/realtime.py b/src/openai/resources/beta/realtime/realtime.py index 8e1b558cf3..7b99c7f6c4 100644 --- a/src/openai/resources/beta/realtime/realtime.py +++ b/src/openai/resources/beta/realtime/realtime.py @@ -652,8 +652,8 @@ def cancel(self, *, event_id: str | NotGiven = NOT_GIVEN, response_id: str | Not """Send this event to cancel an in-progress response. The server will respond - with a `response.cancelled` event or an error if there is no response to - cancel. + with a `response.done` event with a status of `response.status=cancelled`. If + there is no response to cancel, the server will respond with an error. """ self._connection.send( cast( @@ -904,8 +904,8 @@ async def cancel(self, *, event_id: str | NotGiven = NOT_GIVEN, response_id: str """Send this event to cancel an in-progress response. The server will respond - with a `response.cancelled` event or an error if there is no response to - cancel. + with a `response.done` event with a status of `response.status=cancelled`. If + there is no response to cancel, the server will respond with an error. """ await self._connection.send( cast( diff --git a/src/openai/resources/beta/realtime/sessions.py b/src/openai/resources/beta/realtime/sessions.py index e639c0ba43..eaddb384ce 100644 --- a/src/openai/resources/beta/realtime/sessions.py +++ b/src/openai/resources/beta/realtime/sessions.py @@ -152,7 +152,7 @@ def create( set to `null` to turn off, in which case the client must manually trigger model response. Server VAD means that the model will detect the start and end of speech based on audio volume and respond at the end of user speech. Semantic VAD - is more advanced and uses a turn detection model (in conjuction with VAD) to + is more advanced and uses a turn detection model (in conjunction with VAD) to semantically estimate whether the user has finished speaking, then dynamically sets a timeout based on this probability. For example, if user audio trails off with "uhhm", the model will score a low probability of turn end and wait longer @@ -334,7 +334,7 @@ async def create( set to `null` to turn off, in which case the client must manually trigger model response. Server VAD means that the model will detect the start and end of speech based on audio volume and respond at the end of user speech. Semantic VAD - is more advanced and uses a turn detection model (in conjuction with VAD) to + is more advanced and uses a turn detection model (in conjunction with VAD) to semantically estimate whether the user has finished speaking, then dynamically sets a timeout based on this probability. For example, if user audio trails off with "uhhm", the model will score a low probability of turn end and wait longer diff --git a/src/openai/resources/beta/realtime/transcription_sessions.py b/src/openai/resources/beta/realtime/transcription_sessions.py index 5f97b3c8e3..54fe7d5a6c 100644 --- a/src/openai/resources/beta/realtime/transcription_sessions.py +++ b/src/openai/resources/beta/realtime/transcription_sessions.py @@ -96,7 +96,7 @@ def create( set to `null` to turn off, in which case the client must manually trigger model response. Server VAD means that the model will detect the start and end of speech based on audio volume and respond at the end of user speech. Semantic VAD - is more advanced and uses a turn detection model (in conjuction with VAD) to + is more advanced and uses a turn detection model (in conjunction with VAD) to semantically estimate whether the user has finished speaking, then dynamically sets a timeout based on this probability. For example, if user audio trails off with "uhhm", the model will score a low probability of turn end and wait longer @@ -209,7 +209,7 @@ async def create( set to `null` to turn off, in which case the client must manually trigger model response. Server VAD means that the model will detect the start and end of speech based on audio volume and respond at the end of user speech. Semantic VAD - is more advanced and uses a turn detection model (in conjuction with VAD) to + is more advanced and uses a turn detection model (in conjunction with VAD) to semantically estimate whether the user has finished speaking, then dynamically sets a timeout based on this probability. For example, if user audio trails off with "uhhm", the model will score a low probability of turn end and wait longer diff --git a/src/openai/resources/beta/threads/runs/runs.py b/src/openai/resources/beta/threads/runs/runs.py index 01246d7c12..07b43e6471 100644 --- a/src/openai/resources/beta/threads/runs/runs.py +++ b/src/openai/resources/beta/threads/runs/runs.py @@ -220,7 +220,7 @@ def create( We generally recommend altering this or temperature but not both. truncation_strategy: Controls for how a thread will be truncated prior to the run. Use this to - control the intial context window of the run. + control the initial context window of the run. extra_headers: Send extra headers @@ -370,7 +370,7 @@ def create( We generally recommend altering this or temperature but not both. truncation_strategy: Controls for how a thread will be truncated prior to the run. Use this to - control the intial context window of the run. + control the initial context window of the run. extra_headers: Send extra headers @@ -520,7 +520,7 @@ def create( We generally recommend altering this or temperature but not both. truncation_strategy: Controls for how a thread will be truncated prior to the run. Use this to - control the intial context window of the run. + control the initial context window of the run. extra_headers: Send extra headers @@ -1650,7 +1650,7 @@ async def create( We generally recommend altering this or temperature but not both. truncation_strategy: Controls for how a thread will be truncated prior to the run. Use this to - control the intial context window of the run. + control the initial context window of the run. extra_headers: Send extra headers @@ -1800,7 +1800,7 @@ async def create( We generally recommend altering this or temperature but not both. truncation_strategy: Controls for how a thread will be truncated prior to the run. Use this to - control the intial context window of the run. + control the initial context window of the run. extra_headers: Send extra headers @@ -1950,7 +1950,7 @@ async def create( We generally recommend altering this or temperature but not both. truncation_strategy: Controls for how a thread will be truncated prior to the run. Use this to - control the intial context window of the run. + control the initial context window of the run. extra_headers: Send extra headers diff --git a/src/openai/resources/beta/threads/threads.py b/src/openai/resources/beta/threads/threads.py index ff2a41155d..dbe47d2d0e 100644 --- a/src/openai/resources/beta/threads/threads.py +++ b/src/openai/resources/beta/threads/threads.py @@ -393,7 +393,7 @@ def create_and_run( We generally recommend altering this or temperature but not both. truncation_strategy: Controls for how a thread will be truncated prior to the run. Use this to - control the intial context window of the run. + control the initial context window of the run. extra_headers: Send extra headers @@ -527,7 +527,7 @@ def create_and_run( We generally recommend altering this or temperature but not both. truncation_strategy: Controls for how a thread will be truncated prior to the run. Use this to - control the intial context window of the run. + control the initial context window of the run. extra_headers: Send extra headers @@ -661,7 +661,7 @@ def create_and_run( We generally recommend altering this or temperature but not both. truncation_strategy: Controls for how a thread will be truncated prior to the run. Use this to - control the intial context window of the run. + control the initial context window of the run. extra_headers: Send extra headers @@ -1251,7 +1251,7 @@ async def create_and_run( We generally recommend altering this or temperature but not both. truncation_strategy: Controls for how a thread will be truncated prior to the run. Use this to - control the intial context window of the run. + control the initial context window of the run. extra_headers: Send extra headers @@ -1385,7 +1385,7 @@ async def create_and_run( We generally recommend altering this or temperature but not both. truncation_strategy: Controls for how a thread will be truncated prior to the run. Use this to - control the intial context window of the run. + control the initial context window of the run. extra_headers: Send extra headers @@ -1519,7 +1519,7 @@ async def create_and_run( We generally recommend altering this or temperature but not both. truncation_strategy: Controls for how a thread will be truncated prior to the run. Use this to - control the intial context window of the run. + control the initial context window of the run. extra_headers: Send extra headers diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index 9404d85192..bc5fe0fc05 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -103,6 +103,7 @@ def parse( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, prompt_cache_key: str | NotGiven = NOT_GIVEN, reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, + text: completion_create_params.Text | NotGiven = NOT_GIVEN, safety_identifier: str | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, @@ -203,6 +204,7 @@ def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseForma "prompt_cache_key": prompt_cache_key, "reasoning_effort": reasoning_effort, "response_format": _type_to_response_format(response_format), + "text": text, "safety_identifier": safety_identifier, "seed": seed, "service_tier": service_tier, @@ -265,6 +267,7 @@ def create( stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, + text: completion_create_params.Text | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -438,9 +441,8 @@ def create( - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or - 'priority', then the request will be processed with the corresponding service - tier. [Contact sales](https://openai.com/contact-sales) to learn more about - Priority processing. + '[priority](https://openai.com/api-priority-processing/)', then the request + will be processed with the corresponding service tier. - When not set, the default behavior is 'auto'. When the `service_tier` parameter is set, the response body will include the @@ -554,6 +556,7 @@ def create( store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, + text: completion_create_params.Text | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -736,9 +739,8 @@ def create( - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or - 'priority', then the request will be processed with the corresponding service - tier. [Contact sales](https://openai.com/contact-sales) to learn more about - Priority processing. + '[priority](https://openai.com/api-priority-processing/)', then the request + will be processed with the corresponding service tier. - When not set, the default behavior is 'auto'. When the `service_tier` parameter is set, the response body will include the @@ -843,6 +845,7 @@ def create( store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, + text: completion_create_params.Text | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -1025,9 +1028,8 @@ def create( - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or - 'priority', then the request will be processed with the corresponding service - tier. [Contact sales](https://openai.com/contact-sales) to learn more about - Priority processing. + '[priority](https://openai.com/api-priority-processing/)', then the request + will be processed with the corresponding service tier. - When not set, the default behavior is 'auto'. When the `service_tier` parameter is set, the response body will include the @@ -1132,6 +1134,7 @@ def create( stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, + text: completion_create_params.Text | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -1178,6 +1181,7 @@ def create( "stream": stream, "stream_options": stream_options, "temperature": temperature, + "text": text, "tool_choice": tool_choice, "tools": tools, "top_logprobs": top_logprobs, @@ -1400,6 +1404,7 @@ def stream( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, prompt_cache_key: str | NotGiven = NOT_GIVEN, reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, + text: completion_create_params.Text | NotGiven = NOT_GIVEN, safety_identifier: str | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, @@ -1470,6 +1475,7 @@ def stream( presence_penalty=presence_penalty, prompt_cache_key=prompt_cache_key, reasoning_effort=reasoning_effort, + text=text, safety_identifier=safety_identifier, seed=seed, service_tier=service_tier, @@ -1542,6 +1548,7 @@ async def parse( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, prompt_cache_key: str | NotGiven = NOT_GIVEN, reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, + text: completion_create_params.Text | NotGiven = NOT_GIVEN, safety_identifier: str | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, @@ -1642,6 +1649,7 @@ def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseForma "prompt_cache_key": prompt_cache_key, "reasoning_effort": reasoning_effort, "response_format": _type_to_response_format(response_format), + "text": text, "safety_identifier": safety_identifier, "seed": seed, "service_tier": service_tier, @@ -1704,6 +1712,7 @@ async def create( stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, + text: completion_create_params.Text | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -1877,9 +1886,8 @@ async def create( - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or - 'priority', then the request will be processed with the corresponding service - tier. [Contact sales](https://openai.com/contact-sales) to learn more about - Priority processing. + '[priority](https://openai.com/api-priority-processing/)', then the request + will be processed with the corresponding service tier. - When not set, the default behavior is 'auto'. When the `service_tier` parameter is set, the response body will include the @@ -1993,6 +2001,7 @@ async def create( store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, + text: completion_create_params.Text | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -2175,9 +2184,8 @@ async def create( - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or - 'priority', then the request will be processed with the corresponding service - tier. [Contact sales](https://openai.com/contact-sales) to learn more about - Priority processing. + '[priority](https://openai.com/api-priority-processing/)', then the request + will be processed with the corresponding service tier. - When not set, the default behavior is 'auto'. When the `service_tier` parameter is set, the response body will include the @@ -2282,6 +2290,7 @@ async def create( store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, + text: completion_create_params.Text | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -2464,9 +2473,8 @@ async def create( - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or - 'priority', then the request will be processed with the corresponding service - tier. [Contact sales](https://openai.com/contact-sales) to learn more about - Priority processing. + '[priority](https://openai.com/api-priority-processing/)', then the request + will be processed with the corresponding service tier. - When not set, the default behavior is 'auto'. When the `service_tier` parameter is set, the response body will include the @@ -2571,6 +2579,7 @@ async def create( stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, + text: completion_create_params.Text | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -2617,6 +2626,7 @@ async def create( "stream": stream, "stream_options": stream_options, "temperature": temperature, + "text": text, "tool_choice": tool_choice, "tools": tools, "top_logprobs": top_logprobs, @@ -2839,6 +2849,7 @@ def stream( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, prompt_cache_key: str | NotGiven = NOT_GIVEN, reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, + text: completion_create_params.Text | NotGiven = NOT_GIVEN, safety_identifier: str | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, @@ -2910,6 +2921,7 @@ def stream( presence_penalty=presence_penalty, prompt_cache_key=prompt_cache_key, reasoning_effort=reasoning_effort, + text=text, safety_identifier=safety_identifier, seed=seed, service_tier=service_tier, diff --git a/src/openai/resources/files.py b/src/openai/resources/files.py index 179af870ba..b45b8f303f 100644 --- a/src/openai/resources/files.py +++ b/src/openai/resources/files.py @@ -57,6 +57,7 @@ def create( *, file: FileTypes, purpose: FilePurpose, + expires_after: file_create_params.ExpiresAfter | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -68,7 +69,7 @@ def create( Individual files can be up to 512 MB, and the size of all files uploaded by one organization can be up - to 100 GB. + to 1 TB. The Assistants API supports files up to 2 million tokens and of specific file types. See the @@ -96,6 +97,9 @@ def create( fine-tuning - `vision`: Images used for vision fine-tuning - `user_data`: Flexible file type for any purpose - `evals`: Used for eval data sets + expires_after: The expiration policy for a file. By default, files with `purpose=batch` expire + after 30 days and all other files are persisted until they are manually deleted. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -108,6 +112,7 @@ def create( { "file": file, "purpose": purpose, + "expires_after": expires_after, } ) files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) @@ -369,6 +374,7 @@ async def create( *, file: FileTypes, purpose: FilePurpose, + expires_after: file_create_params.ExpiresAfter | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -380,7 +386,7 @@ async def create( Individual files can be up to 512 MB, and the size of all files uploaded by one organization can be up - to 100 GB. + to 1 TB. The Assistants API supports files up to 2 million tokens and of specific file types. See the @@ -408,6 +414,9 @@ async def create( fine-tuning - `vision`: Images used for vision fine-tuning - `user_data`: Flexible file type for any purpose - `evals`: Used for eval data sets + expires_after: The expiration policy for a file. By default, files with `purpose=batch` expire + after 30 days and all other files are persisted until they are manually deleted. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -420,6 +429,7 @@ async def create( { "file": file, "purpose": purpose, + "expires_after": expires_after, } ) files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 8983daf278..97ad0faa94 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -43,7 +43,6 @@ from ...types.responses.response_input_param import ResponseInputParam from ...types.responses.response_prompt_param import ResponsePromptParam from ...types.responses.response_stream_event import ResponseStreamEvent -from ...types.responses.response_text_config_param import ResponseTextConfigParam __all__ = ["Responses", "AsyncResponses"] @@ -95,7 +94,7 @@ def create( stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + text: response_create_params.Text | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -195,7 +194,7 @@ def create( hit rates. Replaces the `user` field. [Learn more](https://platform.openai.com/docs/guides/prompt-caching). - reasoning: **o-series models only** + reasoning: **gpt-5 and o-series models only** Configuration options for [reasoning models](https://platform.openai.com/docs/guides/reasoning). @@ -214,9 +213,8 @@ def create( - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or - 'priority', then the request will be processed with the corresponding service - tier. [Contact sales](https://openai.com/contact-sales) to learn more about - Priority processing. + '[priority](https://openai.com/api-priority-processing/)', then the request + will be processed with the corresponding service tier. - When not set, the default behavior is 'auto'. When the `service_tier` parameter is set, the response body will include the @@ -240,12 +238,6 @@ def create( focused and deterministic. We generally recommend altering this or `top_p` but not both. - text: Configuration options for a text response from the model. Can be plain text or - structured JSON data. Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - tool_choice: How the model should select which tool (or tools) to use when generating a response. See the `tools` parameter to see how to specify which tools the model can call. @@ -323,7 +315,7 @@ def create( store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + text: response_create_params.Text | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -430,7 +422,7 @@ def create( hit rates. Replaces the `user` field. [Learn more](https://platform.openai.com/docs/guides/prompt-caching). - reasoning: **o-series models only** + reasoning: **gpt-5 and o-series models only** Configuration options for [reasoning models](https://platform.openai.com/docs/guides/reasoning). @@ -449,9 +441,8 @@ def create( - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or - 'priority', then the request will be processed with the corresponding service - tier. [Contact sales](https://openai.com/contact-sales) to learn more about - Priority processing. + '[priority](https://openai.com/api-priority-processing/)', then the request + will be processed with the corresponding service tier. - When not set, the default behavior is 'auto'. When the `service_tier` parameter is set, the response body will include the @@ -468,12 +459,6 @@ def create( focused and deterministic. We generally recommend altering this or `top_p` but not both. - text: Configuration options for a text response from the model. Can be plain text or - structured JSON data. Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - tool_choice: How the model should select which tool (or tools) to use when generating a response. See the `tools` parameter to see how to specify which tools the model can call. @@ -551,7 +536,7 @@ def create( store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + text: response_create_params.Text | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -658,7 +643,7 @@ def create( hit rates. Replaces the `user` field. [Learn more](https://platform.openai.com/docs/guides/prompt-caching). - reasoning: **o-series models only** + reasoning: **gpt-5 and o-series models only** Configuration options for [reasoning models](https://platform.openai.com/docs/guides/reasoning). @@ -677,9 +662,8 @@ def create( - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or - 'priority', then the request will be processed with the corresponding service - tier. [Contact sales](https://openai.com/contact-sales) to learn more about - Priority processing. + '[priority](https://openai.com/api-priority-processing/)', then the request + will be processed with the corresponding service tier. - When not set, the default behavior is 'auto'. When the `service_tier` parameter is set, the response body will include the @@ -696,12 +680,6 @@ def create( focused and deterministic. We generally recommend altering this or `top_p` but not both. - text: Configuration options for a text response from the model. Can be plain text or - structured JSON data. Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - tool_choice: How the model should select which tool (or tools) to use when generating a response. See the `tools` parameter to see how to specify which tools the model can call. @@ -778,7 +756,7 @@ def create( stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + text: response_create_params.Text | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -869,7 +847,7 @@ def stream( store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + text: response_create_params.Text | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, @@ -901,7 +879,7 @@ def stream( store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + text: response_create_params.Text | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, @@ -1030,7 +1008,7 @@ def parse( stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + text: response_create_params.Text | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -1461,7 +1439,7 @@ async def create( stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + text: response_create_params.Text | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -1561,7 +1539,7 @@ async def create( hit rates. Replaces the `user` field. [Learn more](https://platform.openai.com/docs/guides/prompt-caching). - reasoning: **o-series models only** + reasoning: **gpt-5 and o-series models only** Configuration options for [reasoning models](https://platform.openai.com/docs/guides/reasoning). @@ -1580,9 +1558,8 @@ async def create( - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or - 'priority', then the request will be processed with the corresponding service - tier. [Contact sales](https://openai.com/contact-sales) to learn more about - Priority processing. + '[priority](https://openai.com/api-priority-processing/)', then the request + will be processed with the corresponding service tier. - When not set, the default behavior is 'auto'. When the `service_tier` parameter is set, the response body will include the @@ -1606,12 +1583,6 @@ async def create( focused and deterministic. We generally recommend altering this or `top_p` but not both. - text: Configuration options for a text response from the model. Can be plain text or - structured JSON data. Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - tool_choice: How the model should select which tool (or tools) to use when generating a response. See the `tools` parameter to see how to specify which tools the model can call. @@ -1689,7 +1660,7 @@ async def create( store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + text: response_create_params.Text | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -1796,7 +1767,7 @@ async def create( hit rates. Replaces the `user` field. [Learn more](https://platform.openai.com/docs/guides/prompt-caching). - reasoning: **o-series models only** + reasoning: **gpt-5 and o-series models only** Configuration options for [reasoning models](https://platform.openai.com/docs/guides/reasoning). @@ -1815,9 +1786,8 @@ async def create( - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or - 'priority', then the request will be processed with the corresponding service - tier. [Contact sales](https://openai.com/contact-sales) to learn more about - Priority processing. + '[priority](https://openai.com/api-priority-processing/)', then the request + will be processed with the corresponding service tier. - When not set, the default behavior is 'auto'. When the `service_tier` parameter is set, the response body will include the @@ -1834,12 +1804,6 @@ async def create( focused and deterministic. We generally recommend altering this or `top_p` but not both. - text: Configuration options for a text response from the model. Can be plain text or - structured JSON data. Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - tool_choice: How the model should select which tool (or tools) to use when generating a response. See the `tools` parameter to see how to specify which tools the model can call. @@ -1917,7 +1881,7 @@ async def create( store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + text: response_create_params.Text | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -2024,7 +1988,7 @@ async def create( hit rates. Replaces the `user` field. [Learn more](https://platform.openai.com/docs/guides/prompt-caching). - reasoning: **o-series models only** + reasoning: **gpt-5 and o-series models only** Configuration options for [reasoning models](https://platform.openai.com/docs/guides/reasoning). @@ -2043,9 +2007,8 @@ async def create( - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or - 'priority', then the request will be processed with the corresponding service - tier. [Contact sales](https://openai.com/contact-sales) to learn more about - Priority processing. + '[priority](https://openai.com/api-priority-processing/)', then the request + will be processed with the corresponding service tier. - When not set, the default behavior is 'auto'. When the `service_tier` parameter is set, the response body will include the @@ -2062,12 +2025,6 @@ async def create( focused and deterministic. We generally recommend altering this or `top_p` but not both. - text: Configuration options for a text response from the model. Can be plain text or - structured JSON data. Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - tool_choice: How the model should select which tool (or tools) to use when generating a response. See the `tools` parameter to see how to specify which tools the model can call. @@ -2144,7 +2101,7 @@ async def create( stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + text: response_create_params.Text | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -2235,7 +2192,7 @@ def stream( store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + text: response_create_params.Text | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, @@ -2267,7 +2224,7 @@ def stream( store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + text: response_create_params.Text | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, @@ -2400,7 +2357,7 @@ async def parse( stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + text: response_create_params.Text | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, diff --git a/src/openai/resources/uploads/uploads.py b/src/openai/resources/uploads/uploads.py index ecfcee4800..125a45e33c 100644 --- a/src/openai/resources/uploads/uploads.py +++ b/src/openai/resources/uploads/uploads.py @@ -170,6 +170,7 @@ def create( filename: str, mime_type: str, purpose: FilePurpose, + expires_after: upload_create_params.ExpiresAfter | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -213,6 +214,9 @@ def create( See the [documentation on File purposes](https://platform.openai.com/docs/api-reference/files/create#files-create-purpose). + expires_after: The expiration policy for a file. By default, files with `purpose=batch` expire + after 30 days and all other files are persisted until they are manually deleted. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -229,6 +233,7 @@ def create( "filename": filename, "mime_type": mime_type, "purpose": purpose, + "expires_after": expires_after, }, upload_create_params.UploadCreateParams, ), @@ -473,6 +478,7 @@ async def create( filename: str, mime_type: str, purpose: FilePurpose, + expires_after: upload_create_params.ExpiresAfter | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -516,6 +522,9 @@ async def create( See the [documentation on File purposes](https://platform.openai.com/docs/api-reference/files/create#files-create-purpose). + expires_after: The expiration policy for a file. By default, files with `purpose=batch` expire + after 30 days and all other files are persisted until they are manually deleted. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -532,6 +541,7 @@ async def create( "filename": filename, "mime_type": mime_type, "purpose": purpose, + "expires_after": expires_after, }, upload_create_params.UploadCreateParams, ), diff --git a/src/openai/types/batch_create_params.py b/src/openai/types/batch_create_params.py index cc95afd3ba..c0f9034d5e 100644 --- a/src/openai/types/batch_create_params.py +++ b/src/openai/types/batch_create_params.py @@ -7,7 +7,7 @@ from .shared_params.metadata import Metadata -__all__ = ["BatchCreateParams"] +__all__ = ["BatchCreateParams", "OutputExpiresAfter"] class BatchCreateParams(TypedDict, total=False): @@ -47,3 +47,24 @@ class BatchCreateParams(TypedDict, total=False): Keys are strings with a maximum length of 64 characters. Values are strings with a maximum length of 512 characters. """ + + output_expires_after: OutputExpiresAfter + """ + The expiration policy for the output and/or error file that are generated for a + batch. + """ + + +class OutputExpiresAfter(TypedDict, total=False): + anchor: Required[Literal["created_at"]] + """Anchor timestamp after which the expiration policy applies. + + Supported anchors: `created_at`. Note that the anchor is the file creation time, + not the time the batch is created. + """ + + seconds: Required[int] + """The number of seconds after the anchor time that the file will expire. + + Must be between 3600 (1 hour) and 2592000 (30 days). + """ diff --git a/src/openai/types/beta/realtime/session.py b/src/openai/types/beta/realtime/session.py index f84b3ee4a0..f478a92fbb 100644 --- a/src/openai/types/beta/realtime/session.py +++ b/src/openai/types/beta/realtime/session.py @@ -260,7 +260,7 @@ class Session(BaseModel): This can be set to `null` to turn off, in which case the client must manually trigger model response. Server VAD means that the model will detect the start and end of speech based on audio volume and respond at the end of user speech. - Semantic VAD is more advanced and uses a turn detection model (in conjuction + Semantic VAD is more advanced and uses a turn detection model (in conjunction with VAD) to semantically estimate whether the user has finished speaking, then dynamically sets a timeout based on this probability. For example, if user audio trails off with "uhhm", the model will score a low probability of turn end and diff --git a/src/openai/types/beta/realtime/session_create_params.py b/src/openai/types/beta/realtime/session_create_params.py index 6be09d8bae..8a477f9843 100644 --- a/src/openai/types/beta/realtime/session_create_params.py +++ b/src/openai/types/beta/realtime/session_create_params.py @@ -137,7 +137,7 @@ class SessionCreateParams(TypedDict, total=False): This can be set to `null` to turn off, in which case the client must manually trigger model response. Server VAD means that the model will detect the start and end of speech based on audio volume and respond at the end of user speech. - Semantic VAD is more advanced and uses a turn detection model (in conjuction + Semantic VAD is more advanced and uses a turn detection model (in conjunction with VAD) to semantically estimate whether the user has finished speaking, then dynamically sets a timeout based on this probability. For example, if user audio trails off with "uhhm", the model will score a low probability of turn end and diff --git a/src/openai/types/beta/realtime/session_update_event.py b/src/openai/types/beta/realtime/session_update_event.py index 5b4185dbf6..11929ab376 100644 --- a/src/openai/types/beta/realtime/session_update_event.py +++ b/src/openai/types/beta/realtime/session_update_event.py @@ -282,7 +282,7 @@ class Session(BaseModel): This can be set to `null` to turn off, in which case the client must manually trigger model response. Server VAD means that the model will detect the start and end of speech based on audio volume and respond at the end of user speech. - Semantic VAD is more advanced and uses a turn detection model (in conjuction + Semantic VAD is more advanced and uses a turn detection model (in conjunction with VAD) to semantically estimate whether the user has finished speaking, then dynamically sets a timeout based on this probability. For example, if user audio trails off with "uhhm", the model will score a low probability of turn end and diff --git a/src/openai/types/beta/realtime/session_update_event_param.py b/src/openai/types/beta/realtime/session_update_event_param.py index 3063449bfd..e939f4cc79 100644 --- a/src/openai/types/beta/realtime/session_update_event_param.py +++ b/src/openai/types/beta/realtime/session_update_event_param.py @@ -280,7 +280,7 @@ class Session(TypedDict, total=False): This can be set to `null` to turn off, in which case the client must manually trigger model response. Server VAD means that the model will detect the start and end of speech based on audio volume and respond at the end of user speech. - Semantic VAD is more advanced and uses a turn detection model (in conjuction + Semantic VAD is more advanced and uses a turn detection model (in conjunction with VAD) to semantically estimate whether the user has finished speaking, then dynamically sets a timeout based on this probability. For example, if user audio trails off with "uhhm", the model will score a low probability of turn end and diff --git a/src/openai/types/beta/realtime/transcription_session_create_params.py b/src/openai/types/beta/realtime/transcription_session_create_params.py index 15b2f14c14..3ac3af4fa9 100644 --- a/src/openai/types/beta/realtime/transcription_session_create_params.py +++ b/src/openai/types/beta/realtime/transcription_session_create_params.py @@ -61,7 +61,7 @@ class TranscriptionSessionCreateParams(TypedDict, total=False): This can be set to `null` to turn off, in which case the client must manually trigger model response. Server VAD means that the model will detect the start and end of speech based on audio volume and respond at the end of user speech. - Semantic VAD is more advanced and uses a turn detection model (in conjuction + Semantic VAD is more advanced and uses a turn detection model (in conjunction with VAD) to semantically estimate whether the user has finished speaking, then dynamically sets a timeout based on this probability. For example, if user audio trails off with "uhhm", the model will score a low probability of turn end and diff --git a/src/openai/types/beta/realtime/transcription_session_update.py b/src/openai/types/beta/realtime/transcription_session_update.py index 73253b6848..5ae1ad226d 100644 --- a/src/openai/types/beta/realtime/transcription_session_update.py +++ b/src/openai/types/beta/realtime/transcription_session_update.py @@ -165,7 +165,7 @@ class Session(BaseModel): This can be set to `null` to turn off, in which case the client must manually trigger model response. Server VAD means that the model will detect the start and end of speech based on audio volume and respond at the end of user speech. - Semantic VAD is more advanced and uses a turn detection model (in conjuction + Semantic VAD is more advanced and uses a turn detection model (in conjunction with VAD) to semantically estimate whether the user has finished speaking, then dynamically sets a timeout based on this probability. For example, if user audio trails off with "uhhm", the model will score a low probability of turn end and diff --git a/src/openai/types/beta/realtime/transcription_session_update_param.py b/src/openai/types/beta/realtime/transcription_session_update_param.py index 6b38a9af39..d7065f61c7 100644 --- a/src/openai/types/beta/realtime/transcription_session_update_param.py +++ b/src/openai/types/beta/realtime/transcription_session_update_param.py @@ -165,7 +165,7 @@ class Session(TypedDict, total=False): This can be set to `null` to turn off, in which case the client must manually trigger model response. Server VAD means that the model will detect the start and end of speech based on audio volume and respond at the end of user speech. - Semantic VAD is more advanced and uses a turn detection model (in conjuction + Semantic VAD is more advanced and uses a turn detection model (in conjunction with VAD) to semantically estimate whether the user has finished speaking, then dynamically sets a timeout based on this probability. For example, if user audio trails off with "uhhm", the model will score a low probability of turn end and diff --git a/src/openai/types/beta/thread_create_and_run_params.py b/src/openai/types/beta/thread_create_and_run_params.py index d813710579..ad148d693a 100644 --- a/src/openai/types/beta/thread_create_and_run_params.py +++ b/src/openai/types/beta/thread_create_and_run_params.py @@ -169,7 +169,7 @@ class ThreadCreateAndRunParamsBase(TypedDict, total=False): truncation_strategy: Optional[TruncationStrategy] """Controls for how a thread will be truncated prior to the run. - Use this to control the intial context window of the run. + Use this to control the initial context window of the run. """ diff --git a/src/openai/types/beta/threads/run.py b/src/openai/types/beta/threads/run.py index da9418d6f9..c545cc3759 100644 --- a/src/openai/types/beta/threads/run.py +++ b/src/openai/types/beta/threads/run.py @@ -228,7 +228,7 @@ class Run(BaseModel): truncation_strategy: Optional[TruncationStrategy] = None """Controls for how a thread will be truncated prior to the run. - Use this to control the intial context window of the run. + Use this to control the initial context window of the run. """ usage: Optional[Usage] = None diff --git a/src/openai/types/beta/threads/run_create_params.py b/src/openai/types/beta/threads/run_create_params.py index f9defcb19c..cfd272f5ad 100644 --- a/src/openai/types/beta/threads/run_create_params.py +++ b/src/openai/types/beta/threads/run_create_params.py @@ -176,7 +176,7 @@ class RunCreateParamsBase(TypedDict, total=False): truncation_strategy: Optional[TruncationStrategy] """Controls for how a thread will be truncated prior to the run. - Use this to control the intial context window of the run. + Use this to control the initial context window of the run. """ diff --git a/src/openai/types/chat/chat_completion.py b/src/openai/types/chat/chat_completion.py index 42463f7ec8..6bc4bafe79 100644 --- a/src/openai/types/chat/chat_completion.py +++ b/src/openai/types/chat/chat_completion.py @@ -68,9 +68,8 @@ class ChatCompletion(BaseModel): - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or - 'priority', then the request will be processed with the corresponding service - tier. [Contact sales](https://openai.com/contact-sales) to learn more about - Priority processing. + '[priority](https://openai.com/api-priority-processing/)', then the request + will be processed with the corresponding service tier. - When not set, the default behavior is 'auto'. When the `service_tier` parameter is set, the response body will include the diff --git a/src/openai/types/chat/chat_completion_chunk.py b/src/openai/types/chat/chat_completion_chunk.py index 082bb6cc19..ea32d157ef 100644 --- a/src/openai/types/chat/chat_completion_chunk.py +++ b/src/openai/types/chat/chat_completion_chunk.py @@ -137,9 +137,8 @@ class ChatCompletionChunk(BaseModel): - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or - 'priority', then the request will be processed with the corresponding service - tier. [Contact sales](https://openai.com/contact-sales) to learn more about - Priority processing. + '[priority](https://openai.com/api-priority-processing/)', then the request + will be processed with the corresponding service tier. - When not set, the default behavior is 'auto'. When the `service_tier` parameter is set, the response body will include the diff --git a/src/openai/types/chat/completion_create_params.py b/src/openai/types/chat/completion_create_params.py index a3bc90b0a2..3ebab45b56 100644 --- a/src/openai/types/chat/completion_create_params.py +++ b/src/openai/types/chat/completion_create_params.py @@ -25,6 +25,7 @@ "FunctionCall", "Function", "ResponseFormat", + "Text", "WebSearchOptions", "WebSearchOptionsUserLocation", "WebSearchOptionsUserLocationApproximate", @@ -233,9 +234,8 @@ class CompletionCreateParamsBase(TypedDict, total=False): - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or - 'priority', then the request will be processed with the corresponding service - tier. [Contact sales](https://openai.com/contact-sales) to learn more about - Priority processing. + '[priority](https://openai.com/api-priority-processing/)', then the request + will be processed with the corresponding service tier. - When not set, the default behavior is 'auto'. When the `service_tier` parameter is set, the response body will include the @@ -271,6 +271,8 @@ class CompletionCreateParamsBase(TypedDict, total=False): this or `top_p` but not both. """ + text: Text + tool_choice: ChatCompletionToolChoiceOptionParam """ Controls which (if any) tool is called by the model. `none` means the model will @@ -365,6 +367,16 @@ class Function(TypedDict, total=False): ResponseFormat: TypeAlias = Union[ResponseFormatText, ResponseFormatJSONSchema, ResponseFormatJSONObject] +class Text(TypedDict, total=False): + verbosity: Optional[Literal["low", "medium", "high"]] + """Constrains the verbosity of the model's response. + + Lower values will result in more concise responses, while higher values will + result in more verbose responses. Currently supported values are `low`, + `medium`, and `high`. + """ + + class WebSearchOptionsUserLocationApproximate(TypedDict, total=False): city: str """Free text input for the city of the user, e.g. `San Francisco`.""" diff --git a/src/openai/types/file_create_params.py b/src/openai/types/file_create_params.py index 728dfd350f..f4583b16a3 100644 --- a/src/openai/types/file_create_params.py +++ b/src/openai/types/file_create_params.py @@ -2,12 +2,12 @@ from __future__ import annotations -from typing_extensions import Required, TypedDict +from typing_extensions import Literal, Required, TypedDict from .._types import FileTypes from .file_purpose import FilePurpose -__all__ = ["FileCreateParams"] +__all__ = ["FileCreateParams", "ExpiresAfter"] class FileCreateParams(TypedDict, total=False): @@ -22,3 +22,24 @@ class FileCreateParams(TypedDict, total=False): fine-tuning - `user_data`: Flexible file type for any purpose - `evals`: Used for eval data sets """ + + expires_after: ExpiresAfter + """The expiration policy for a file. + + By default, files with `purpose=batch` expire after 30 days and all other files + are persisted until they are manually deleted. + """ + + +class ExpiresAfter(TypedDict, total=False): + anchor: Required[Literal["created_at"]] + """Anchor timestamp after which the expiration policy applies. + + Supported anchors: `created_at`. + """ + + seconds: Required[int] + """The number of seconds after the anchor time that the file will expire. + + Must be between 3600 (1 hour) and 2592000 (30 days). + """ diff --git a/src/openai/types/responses/__init__.py b/src/openai/types/responses/__init__.py index 74d8688081..72ec741f91 100644 --- a/src/openai/types/responses/__init__.py +++ b/src/openai/types/responses/__init__.py @@ -42,7 +42,6 @@ from .response_input_param import ResponseInputParam as ResponseInputParam from .response_output_item import ResponseOutputItem as ResponseOutputItem from .response_output_text import ResponseOutputText as ResponseOutputText -from .response_text_config import ResponseTextConfig as ResponseTextConfig from .tool_choice_function import ToolChoiceFunction as ToolChoiceFunction from .response_failed_event import ResponseFailedEvent as ResponseFailedEvent from .response_prompt_param import ResponsePromptParam as ResponsePromptParam @@ -76,7 +75,6 @@ from .response_in_progress_event import ResponseInProgressEvent as ResponseInProgressEvent from .response_input_image_param import ResponseInputImageParam as ResponseInputImageParam from .response_output_text_param import ResponseOutputTextParam as ResponseOutputTextParam -from .response_text_config_param import ResponseTextConfigParam as ResponseTextConfigParam from .tool_choice_function_param import ToolChoiceFunctionParam as ToolChoiceFunctionParam from .response_computer_tool_call import ResponseComputerToolCall as ResponseComputerToolCall from .response_format_text_config import ResponseFormatTextConfig as ResponseFormatTextConfig diff --git a/src/openai/types/responses/response.py b/src/openai/types/responses/response.py index 5ebb18fda4..49e38a46fe 100644 --- a/src/openai/types/responses/response.py +++ b/src/openai/types/responses/response.py @@ -18,11 +18,11 @@ from .tool_choice_allowed import ToolChoiceAllowed from .tool_choice_options import ToolChoiceOptions from .response_output_item import ResponseOutputItem -from .response_text_config import ResponseTextConfig from .tool_choice_function import ToolChoiceFunction from ..shared.responses_model import ResponsesModel +from .response_format_text_config import ResponseFormatTextConfig -__all__ = ["Response", "IncompleteDetails", "ToolChoice"] +__all__ = ["Response", "IncompleteDetails", "ToolChoice", "Text"] class IncompleteDetails(BaseModel): @@ -35,6 +35,32 @@ class IncompleteDetails(BaseModel): ] +class Text(BaseModel): + format: Optional[ResponseFormatTextConfig] = None + """An object specifying the format that the model must output. + + Configuring `{ "type": "json_schema" }` enables Structured Outputs, which + ensures the model will match your supplied JSON schema. Learn more in the + [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). + + The default format is `{ "type": "text" }` with no additional options. + + **Not recommended for gpt-4o and newer models:** + + Setting to `{ "type": "json_object" }` enables the older JSON mode, which + ensures the message the model generates is valid JSON. Using `json_schema` is + preferred for models that support it. + """ + + verbosity: Optional[Literal["low", "medium", "high"]] = None + """Constrains the verbosity of the model's response. + + Lower values will result in more concise responses, while higher values will + result in more verbose responses. Currently supported values are `low`, + `medium`, and `high`. + """ + + class Response(BaseModel): id: str """Unique identifier for this Response.""" @@ -177,7 +203,7 @@ class Response(BaseModel): """ reasoning: Optional[Reasoning] = None - """**o-series models only** + """**gpt-5 and o-series models only** Configuration options for [reasoning models](https://platform.openai.com/docs/guides/reasoning). @@ -201,9 +227,8 @@ class Response(BaseModel): - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or - 'priority', then the request will be processed with the corresponding service - tier. [Contact sales](https://openai.com/contact-sales) to learn more about - Priority processing. + '[priority](https://openai.com/api-priority-processing/)', then the request + will be processed with the corresponding service tier. - When not set, the default behavior is 'auto'. When the `service_tier` parameter is set, the response body will include the @@ -219,14 +244,7 @@ class Response(BaseModel): `incomplete`. """ - text: Optional[ResponseTextConfig] = None - """Configuration options for a text response from the model. - - Can be plain text or structured JSON data. Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - """ + text: Optional[Text] = None top_logprobs: Optional[int] = None """ diff --git a/src/openai/types/responses/response_create_params.py b/src/openai/types/responses/response_create_params.py index ea91fa1265..89afccf06b 100644 --- a/src/openai/types/responses/response_create_params.py +++ b/src/openai/types/responses/response_create_params.py @@ -16,13 +16,14 @@ from ..shared_params.reasoning import Reasoning from .tool_choice_custom_param import ToolChoiceCustomParam from .tool_choice_allowed_param import ToolChoiceAllowedParam -from .response_text_config_param import ResponseTextConfigParam from .tool_choice_function_param import ToolChoiceFunctionParam from ..shared_params.responses_model import ResponsesModel +from .response_format_text_config_param import ResponseFormatTextConfigParam __all__ = [ "ResponseCreateParamsBase", "StreamOptions", + "Text", "ToolChoice", "ResponseCreateParamsNonStreaming", "ResponseCreateParamsStreaming", @@ -134,7 +135,7 @@ class ResponseCreateParamsBase(TypedDict, total=False): """ reasoning: Optional[Reasoning] - """**o-series models only** + """**gpt-5 and o-series models only** Configuration options for [reasoning models](https://platform.openai.com/docs/guides/reasoning). @@ -158,9 +159,8 @@ class ResponseCreateParamsBase(TypedDict, total=False): - If set to 'default', then the request will be processed with the standard pricing and performance for the selected model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or - 'priority', then the request will be processed with the corresponding service - tier. [Contact sales](https://openai.com/contact-sales) to learn more about - Priority processing. + '[priority](https://openai.com/api-priority-processing/)', then the request + will be processed with the corresponding service tier. - When not set, the default behavior is 'auto'. When the `service_tier` parameter is set, the response body will include the @@ -183,14 +183,7 @@ class ResponseCreateParamsBase(TypedDict, total=False): this or `top_p` but not both. """ - text: ResponseTextConfigParam - """Configuration options for a text response from the model. - - Can be plain text or structured JSON data. Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - """ + text: Text tool_choice: ToolChoice """ @@ -267,6 +260,32 @@ class StreamOptions(TypedDict, total=False): """ +class Text(TypedDict, total=False): + format: ResponseFormatTextConfigParam + """An object specifying the format that the model must output. + + Configuring `{ "type": "json_schema" }` enables Structured Outputs, which + ensures the model will match your supplied JSON schema. Learn more in the + [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). + + The default format is `{ "type": "text" }` with no additional options. + + **Not recommended for gpt-4o and newer models:** + + Setting to `{ "type": "json_object" }` enables the older JSON mode, which + ensures the message the model generates is valid JSON. Using `json_schema` is + preferred for models that support it. + """ + + verbosity: Optional[Literal["low", "medium", "high"]] + """Constrains the verbosity of the model's response. + + Lower values will result in more concise responses, while higher values will + result in more verbose responses. Currently supported values are `low`, + `medium`, and `high`. + """ + + ToolChoice: TypeAlias = Union[ ToolChoiceOptions, ToolChoiceAllowedParam, diff --git a/src/openai/types/responses/response_text_config.py b/src/openai/types/responses/response_text_config.py deleted file mode 100644 index c53546da6d..0000000000 --- a/src/openai/types/responses/response_text_config.py +++ /dev/null @@ -1,35 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel -from .response_format_text_config import ResponseFormatTextConfig - -__all__ = ["ResponseTextConfig"] - - -class ResponseTextConfig(BaseModel): - format: Optional[ResponseFormatTextConfig] = None - """An object specifying the format that the model must output. - - Configuring `{ "type": "json_schema" }` enables Structured Outputs, which - ensures the model will match your supplied JSON schema. Learn more in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - The default format is `{ "type": "text" }` with no additional options. - - **Not recommended for gpt-4o and newer models:** - - Setting to `{ "type": "json_object" }` enables the older JSON mode, which - ensures the message the model generates is valid JSON. Using `json_schema` is - preferred for models that support it. - """ - - verbosity: Optional[Literal["low", "medium", "high"]] = None - """Constrains the verbosity of the model's response. - - Lower values will result in more concise responses, while higher values will - result in more verbose responses. Currently supported values are `low`, - `medium`, and `high`. - """ diff --git a/src/openai/types/responses/response_text_config_param.py b/src/openai/types/responses/response_text_config_param.py deleted file mode 100644 index 1229fce35b..0000000000 --- a/src/openai/types/responses/response_text_config_param.py +++ /dev/null @@ -1,36 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Literal, TypedDict - -from .response_format_text_config_param import ResponseFormatTextConfigParam - -__all__ = ["ResponseTextConfigParam"] - - -class ResponseTextConfigParam(TypedDict, total=False): - format: ResponseFormatTextConfigParam - """An object specifying the format that the model must output. - - Configuring `{ "type": "json_schema" }` enables Structured Outputs, which - ensures the model will match your supplied JSON schema. Learn more in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - The default format is `{ "type": "text" }` with no additional options. - - **Not recommended for gpt-4o and newer models:** - - Setting to `{ "type": "json_object" }` enables the older JSON mode, which - ensures the message the model generates is valid JSON. Using `json_schema` is - preferred for models that support it. - """ - - verbosity: Optional[Literal["low", "medium", "high"]] - """Constrains the verbosity of the model's response. - - Lower values will result in more concise responses, while higher values will - result in more verbose responses. Currently supported values are `low`, - `medium`, and `high`. - """ diff --git a/src/openai/types/upload_create_params.py b/src/openai/types/upload_create_params.py index 2ebabe6c66..ab4cded81d 100644 --- a/src/openai/types/upload_create_params.py +++ b/src/openai/types/upload_create_params.py @@ -2,11 +2,11 @@ from __future__ import annotations -from typing_extensions import Required, TypedDict +from typing_extensions import Literal, Required, TypedDict from .file_purpose import FilePurpose -__all__ = ["UploadCreateParams"] +__all__ = ["UploadCreateParams", "ExpiresAfter"] class UploadCreateParams(TypedDict, total=False): @@ -29,3 +29,24 @@ class UploadCreateParams(TypedDict, total=False): See the [documentation on File purposes](https://platform.openai.com/docs/api-reference/files/create#files-create-purpose). """ + + expires_after: ExpiresAfter + """The expiration policy for a file. + + By default, files with `purpose=batch` expire after 30 days and all other files + are persisted until they are manually deleted. + """ + + +class ExpiresAfter(TypedDict, total=False): + anchor: Required[Literal["created_at"]] + """Anchor timestamp after which the expiration policy applies. + + Supported anchors: `created_at`. + """ + + seconds: Required[int] + """The number of seconds after the anchor time that the file will expire. + + Must be between 3600 (1 hour) and 2592000 (30 days). + """ diff --git a/tests/api_resources/chat/test_completions.py b/tests/api_resources/chat/test_completions.py index 358ea18cbb..885c3bd9a6 100644 --- a/tests/api_resources/chat/test_completions.py +++ b/tests/api_resources/chat/test_completions.py @@ -86,6 +86,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: "include_usage": True, }, temperature=1, + text={"verbosity": "low"}, tool_choice="none", tools=[ { @@ -218,6 +219,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: "include_usage": True, }, temperature=1, + text={"verbosity": "low"}, tool_choice="none", tools=[ { @@ -527,6 +529,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn "include_usage": True, }, temperature=1, + text={"verbosity": "low"}, tool_choice="none", tools=[ { @@ -659,6 +662,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn "include_usage": True, }, temperature=1, + text={"verbosity": "low"}, tool_choice="none", tools=[ { diff --git a/tests/api_resources/test_batches.py b/tests/api_resources/test_batches.py index 6775094a58..95b94c4846 100644 --- a/tests/api_resources/test_batches.py +++ b/tests/api_resources/test_batches.py @@ -34,6 +34,10 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: endpoint="/v1/responses", input_file_id="string", metadata={"foo": "string"}, + output_expires_after={ + "anchor": "created_at", + "seconds": 3600, + }, ) assert_matches_type(Batch, batch, path=["response"]) @@ -196,6 +200,10 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> endpoint="/v1/responses", input_file_id="string", metadata={"foo": "string"}, + output_expires_after={ + "anchor": "created_at", + "seconds": 3600, + }, ) assert_matches_type(Batch, batch, path=["response"]) diff --git a/tests/api_resources/test_files.py b/tests/api_resources/test_files.py index fc4bb4a18e..67c809f155 100644 --- a/tests/api_resources/test_files.py +++ b/tests/api_resources/test_files.py @@ -31,6 +31,18 @@ def test_method_create(self, client: OpenAI) -> None: ) assert_matches_type(FileObject, file, path=["response"]) + @parametrize + def test_method_create_with_all_params(self, client: OpenAI) -> None: + file = client.files.create( + file=b"raw file contents", + purpose="assistants", + expires_after={ + "anchor": "created_at", + "seconds": 3600, + }, + ) + assert_matches_type(FileObject, file, path=["response"]) + @parametrize def test_raw_response_create(self, client: OpenAI) -> None: response = client.files.with_raw_response.create( @@ -272,6 +284,18 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None: ) assert_matches_type(FileObject, file, path=["response"]) + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: + file = await async_client.files.create( + file=b"raw file contents", + purpose="assistants", + expires_after={ + "anchor": "created_at", + "seconds": 3600, + }, + ) + assert_matches_type(FileObject, file, path=["response"]) + @parametrize async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: response = await async_client.files.with_raw_response.create( diff --git a/tests/api_resources/test_responses.py b/tests/api_resources/test_responses.py index 310800b87e..868ab3a4ca 100644 --- a/tests/api_resources/test_responses.py +++ b/tests/api_resources/test_responses.py @@ -10,9 +10,7 @@ from openai import OpenAI, AsyncOpenAI from tests.utils import assert_matches_type from openai._utils import assert_signatures_in_sync -from openai.types.responses import ( - Response, -) +from openai.types.responses import Response base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") diff --git a/tests/api_resources/test_uploads.py b/tests/api_resources/test_uploads.py index 72a2f6c83d..0e438a3c61 100644 --- a/tests/api_resources/test_uploads.py +++ b/tests/api_resources/test_uploads.py @@ -27,6 +27,20 @@ def test_method_create(self, client: OpenAI) -> None: ) assert_matches_type(Upload, upload, path=["response"]) + @parametrize + def test_method_create_with_all_params(self, client: OpenAI) -> None: + upload = client.uploads.create( + bytes=0, + filename="filename", + mime_type="mime_type", + purpose="assistants", + expires_after={ + "anchor": "created_at", + "seconds": 3600, + }, + ) + assert_matches_type(Upload, upload, path=["response"]) + @parametrize def test_raw_response_create(self, client: OpenAI) -> None: response = client.uploads.with_raw_response.create( @@ -162,6 +176,20 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None: ) assert_matches_type(Upload, upload, path=["response"]) + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: + upload = await async_client.uploads.create( + bytes=0, + filename="filename", + mime_type="mime_type", + purpose="assistants", + expires_after={ + "anchor": "created_at", + "seconds": 3600, + }, + ) + assert_matches_type(Upload, upload, path=["response"]) + @parametrize async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: response = await async_client.uploads.with_raw_response.create( From adb1af8073391a6d58be9c13cfa0664c04d859e2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 18 Aug 2025 05:06:39 +0000 Subject: [PATCH 450/769] release: 1.100.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 2dfeb2d9bb..e1f6d3e50c 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.99.9" + ".": "1.100.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 392fb8b667..0adb892623 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.100.0 (2025-08-18) + +Full Changelog: [v1.99.9...v1.100.0](https://github.com/openai/openai-python/compare/v1.99.9...v1.100.0) + +### Features + +* **api:** add new text parameters, expiration options ([e3dfa7c](https://github.com/openai/openai-python/commit/e3dfa7c417b8c750ff62d98650e75e72ad9b1477)) + ## 1.99.9 (2025-08-12) Full Changelog: [v1.99.8...v1.99.9](https://github.com/openai/openai-python/compare/v1.99.8...v1.99.9) diff --git a/pyproject.toml b/pyproject.toml index ced6079b6d..5fc0396a46 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.99.9" +version = "1.100.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 7d3b3da5d7..d666729b59 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.99.9" # x-release-please-version +__version__ = "1.100.0" # x-release-please-version From b3547d662e76974b8c6a670eff8c5a05f8bb7f4c Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Mon, 18 Aug 2025 16:35:21 -0400 Subject: [PATCH 451/769] fix(types): revert response text config deletion --- src/openai/types/responses/__init__.py | 2 ++ .../types/responses/response_text_config.py | 35 ++++++++++++++++++ .../responses/response_text_config_param.py | 36 +++++++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 src/openai/types/responses/response_text_config.py create mode 100644 src/openai/types/responses/response_text_config_param.py diff --git a/src/openai/types/responses/__init__.py b/src/openai/types/responses/__init__.py index 72ec741f91..74d8688081 100644 --- a/src/openai/types/responses/__init__.py +++ b/src/openai/types/responses/__init__.py @@ -42,6 +42,7 @@ from .response_input_param import ResponseInputParam as ResponseInputParam from .response_output_item import ResponseOutputItem as ResponseOutputItem from .response_output_text import ResponseOutputText as ResponseOutputText +from .response_text_config import ResponseTextConfig as ResponseTextConfig from .tool_choice_function import ToolChoiceFunction as ToolChoiceFunction from .response_failed_event import ResponseFailedEvent as ResponseFailedEvent from .response_prompt_param import ResponsePromptParam as ResponsePromptParam @@ -75,6 +76,7 @@ from .response_in_progress_event import ResponseInProgressEvent as ResponseInProgressEvent from .response_input_image_param import ResponseInputImageParam as ResponseInputImageParam from .response_output_text_param import ResponseOutputTextParam as ResponseOutputTextParam +from .response_text_config_param import ResponseTextConfigParam as ResponseTextConfigParam from .tool_choice_function_param import ToolChoiceFunctionParam as ToolChoiceFunctionParam from .response_computer_tool_call import ResponseComputerToolCall as ResponseComputerToolCall from .response_format_text_config import ResponseFormatTextConfig as ResponseFormatTextConfig diff --git a/src/openai/types/responses/response_text_config.py b/src/openai/types/responses/response_text_config.py new file mode 100644 index 0000000000..c53546da6d --- /dev/null +++ b/src/openai/types/responses/response_text_config.py @@ -0,0 +1,35 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel +from .response_format_text_config import ResponseFormatTextConfig + +__all__ = ["ResponseTextConfig"] + + +class ResponseTextConfig(BaseModel): + format: Optional[ResponseFormatTextConfig] = None + """An object specifying the format that the model must output. + + Configuring `{ "type": "json_schema" }` enables Structured Outputs, which + ensures the model will match your supplied JSON schema. Learn more in the + [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). + + The default format is `{ "type": "text" }` with no additional options. + + **Not recommended for gpt-4o and newer models:** + + Setting to `{ "type": "json_object" }` enables the older JSON mode, which + ensures the message the model generates is valid JSON. Using `json_schema` is + preferred for models that support it. + """ + + verbosity: Optional[Literal["low", "medium", "high"]] = None + """Constrains the verbosity of the model's response. + + Lower values will result in more concise responses, while higher values will + result in more verbose responses. Currently supported values are `low`, + `medium`, and `high`. + """ diff --git a/src/openai/types/responses/response_text_config_param.py b/src/openai/types/responses/response_text_config_param.py new file mode 100644 index 0000000000..1229fce35b --- /dev/null +++ b/src/openai/types/responses/response_text_config_param.py @@ -0,0 +1,36 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, TypedDict + +from .response_format_text_config_param import ResponseFormatTextConfigParam + +__all__ = ["ResponseTextConfigParam"] + + +class ResponseTextConfigParam(TypedDict, total=False): + format: ResponseFormatTextConfigParam + """An object specifying the format that the model must output. + + Configuring `{ "type": "json_schema" }` enables Structured Outputs, which + ensures the model will match your supplied JSON schema. Learn more in the + [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). + + The default format is `{ "type": "text" }` with no additional options. + + **Not recommended for gpt-4o and newer models:** + + Setting to `{ "type": "json_object" }` enables the older JSON mode, which + ensures the message the model generates is valid JSON. Using `json_schema` is + preferred for models that support it. + """ + + verbosity: Optional[Literal["low", "medium", "high"]] + """Constrains the verbosity of the model's response. + + Lower values will result in more concise responses, while higher values will + result in more verbose responses. Currently supported values are `low`, + `medium`, and `high`. + """ From f889071b8f64739998b7ac31df045881cf5bec62 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 18 Aug 2025 20:40:53 +0000 Subject: [PATCH 452/769] release: 1.100.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index e1f6d3e50c..6fb2e7075d 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.100.0" + ".": "1.100.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 0adb892623..4f3362af2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.100.1 (2025-08-18) + +Full Changelog: [v1.100.0...v1.100.1](https://github.com/openai/openai-python/compare/v1.100.0...v1.100.1) + +### Bug Fixes + +* **types:** revert response text config deletion ([ac4fb19](https://github.com/openai/openai-python/commit/ac4fb1922ae125c8310c30e402932e8bb2976f58)) + ## 1.100.0 (2025-08-18) Full Changelog: [v1.99.9...v1.100.0](https://github.com/openai/openai-python/compare/v1.99.9...v1.100.0) diff --git a/pyproject.toml b/pyproject.toml index 5fc0396a46..a9baee6a55 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.100.0" +version = "1.100.1" 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 d666729b59..608d190655 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.100.0" # x-release-please-version +__version__ = "1.100.1" # x-release-please-version From a94bd5b239ad73b1f6f7cf11a2fa9d9279096321 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 19 Aug 2025 13:48:27 +0000 Subject: [PATCH 453/769] chore(api): accurately represent shape for verbosity on Chat Completions --- .stats.yml | 6 +- .../resources/chat/completions/completions.py | 30 ++------- src/openai/resources/responses/responses.py | 65 +++++++++++++++---- .../types/chat/completion_create_params.py | 15 +---- .../types/graders/text_similarity_grader.py | 16 ++++- .../graders/text_similarity_grader_param.py | 16 ++++- src/openai/types/responses/response.py | 39 +++-------- .../types/responses/response_create_params.py | 38 +++-------- tests/api_resources/chat/test_completions.py | 4 -- tests/api_resources/test_responses.py | 4 +- tests/lib/chat/test_completions.py | 2 +- 11 files changed, 110 insertions(+), 125 deletions(-) diff --git a/.stats.yml b/.stats.yml index 66c46e7730..81c991168c 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-24be531010b354303d741fc9247c1f84f75978f9f7de68aca92cb4f240a04722.yml -openapi_spec_hash: 3e46f439f6a863beadc71577eb4efa15 -config_hash: ed87b9139ac595a04a2162d754df2fed +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-7ef7a457c3bf05364e66e48c9ca34f31bfef1f6c9b7c15b1812346105e0abb16.yml +openapi_spec_hash: a2b1f5d8fbb62175c93b0ebea9f10063 +config_hash: 76afa3236f36854a8705f1281b1990b8 diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index bc5fe0fc05..7e209ff0ee 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -103,7 +103,6 @@ def parse( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, prompt_cache_key: str | NotGiven = NOT_GIVEN, reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - text: completion_create_params.Text | NotGiven = NOT_GIVEN, safety_identifier: str | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, @@ -204,7 +203,6 @@ def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseForma "prompt_cache_key": prompt_cache_key, "reasoning_effort": reasoning_effort, "response_format": _type_to_response_format(response_format), - "text": text, "safety_identifier": safety_identifier, "seed": seed, "service_tier": service_tier, @@ -267,7 +265,6 @@ def create( stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: completion_create_params.Text | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -459,7 +456,7 @@ def create( our [model distillation](https://platform.openai.com/docs/guides/distillation) or [evals](https://platform.openai.com/docs/guides/evals) products. - Supports text and image inputs. Note: image inputs over 10MB will be dropped. + Supports text and image inputs. Note: image inputs over 8MB will be dropped. stream: If set to true, the model response data will be streamed to the client as it is generated using @@ -556,7 +553,6 @@ def create( store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: completion_create_params.Text | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -757,7 +753,7 @@ def create( our [model distillation](https://platform.openai.com/docs/guides/distillation) or [evals](https://platform.openai.com/docs/guides/evals) products. - Supports text and image inputs. Note: image inputs over 10MB will be dropped. + Supports text and image inputs. Note: image inputs over 8MB will be dropped. stream_options: Options for streaming response. Only set this when you set `stream: true`. @@ -845,7 +841,6 @@ def create( store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: completion_create_params.Text | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -1046,7 +1041,7 @@ def create( our [model distillation](https://platform.openai.com/docs/guides/distillation) or [evals](https://platform.openai.com/docs/guides/evals) products. - Supports text and image inputs. Note: image inputs over 10MB will be dropped. + Supports text and image inputs. Note: image inputs over 8MB will be dropped. stream_options: Options for streaming response. Only set this when you set `stream: true`. @@ -1134,7 +1129,6 @@ def create( stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: completion_create_params.Text | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -1181,7 +1175,6 @@ def create( "stream": stream, "stream_options": stream_options, "temperature": temperature, - "text": text, "tool_choice": tool_choice, "tools": tools, "top_logprobs": top_logprobs, @@ -1404,7 +1397,6 @@ def stream( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, prompt_cache_key: str | NotGiven = NOT_GIVEN, reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - text: completion_create_params.Text | NotGiven = NOT_GIVEN, safety_identifier: str | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, @@ -1475,7 +1467,6 @@ def stream( presence_penalty=presence_penalty, prompt_cache_key=prompt_cache_key, reasoning_effort=reasoning_effort, - text=text, safety_identifier=safety_identifier, seed=seed, service_tier=service_tier, @@ -1548,7 +1539,6 @@ async def parse( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, prompt_cache_key: str | NotGiven = NOT_GIVEN, reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - text: completion_create_params.Text | NotGiven = NOT_GIVEN, safety_identifier: str | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, @@ -1649,7 +1639,6 @@ def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseForma "prompt_cache_key": prompt_cache_key, "reasoning_effort": reasoning_effort, "response_format": _type_to_response_format(response_format), - "text": text, "safety_identifier": safety_identifier, "seed": seed, "service_tier": service_tier, @@ -1712,7 +1701,6 @@ async def create( stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: completion_create_params.Text | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -1904,7 +1892,7 @@ async def create( our [model distillation](https://platform.openai.com/docs/guides/distillation) or [evals](https://platform.openai.com/docs/guides/evals) products. - Supports text and image inputs. Note: image inputs over 10MB will be dropped. + Supports text and image inputs. Note: image inputs over 8MB will be dropped. stream: If set to true, the model response data will be streamed to the client as it is generated using @@ -2001,7 +1989,6 @@ async def create( store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: completion_create_params.Text | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -2202,7 +2189,7 @@ async def create( our [model distillation](https://platform.openai.com/docs/guides/distillation) or [evals](https://platform.openai.com/docs/guides/evals) products. - Supports text and image inputs. Note: image inputs over 10MB will be dropped. + Supports text and image inputs. Note: image inputs over 8MB will be dropped. stream_options: Options for streaming response. Only set this when you set `stream: true`. @@ -2290,7 +2277,6 @@ async def create( store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: completion_create_params.Text | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -2491,7 +2477,7 @@ async def create( our [model distillation](https://platform.openai.com/docs/guides/distillation) or [evals](https://platform.openai.com/docs/guides/evals) products. - Supports text and image inputs. Note: image inputs over 10MB will be dropped. + Supports text and image inputs. Note: image inputs over 8MB will be dropped. stream_options: Options for streaming response. Only set this when you set `stream: true`. @@ -2579,7 +2565,6 @@ async def create( stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: completion_create_params.Text | NotGiven = NOT_GIVEN, tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -2626,7 +2611,6 @@ async def create( "stream": stream, "stream_options": stream_options, "temperature": temperature, - "text": text, "tool_choice": tool_choice, "tools": tools, "top_logprobs": top_logprobs, @@ -2849,7 +2833,6 @@ def stream( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, prompt_cache_key: str | NotGiven = NOT_GIVEN, reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - text: completion_create_params.Text | NotGiven = NOT_GIVEN, safety_identifier: str | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, @@ -2921,7 +2904,6 @@ def stream( presence_penalty=presence_penalty, prompt_cache_key=prompt_cache_key, reasoning_effort=reasoning_effort, - text=text, safety_identifier=safety_identifier, seed=seed, service_tier=service_tier, diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 97ad0faa94..375f8b7e71 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -43,6 +43,7 @@ from ...types.responses.response_input_param import ResponseInputParam from ...types.responses.response_prompt_param import ResponsePromptParam from ...types.responses.response_stream_event import ResponseStreamEvent +from ...types.responses.response_text_config_param import ResponseTextConfigParam __all__ = ["Responses", "AsyncResponses"] @@ -94,7 +95,7 @@ def create( stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: response_create_params.Text | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -238,6 +239,12 @@ def create( focused and deterministic. We generally recommend altering this or `top_p` but not both. + text: Configuration options for a text response from the model. Can be plain text or + structured JSON data. Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + tool_choice: How the model should select which tool (or tools) to use when generating a response. See the `tools` parameter to see how to specify which tools the model can call. @@ -315,7 +322,7 @@ def create( store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: response_create_params.Text | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -459,6 +466,12 @@ def create( focused and deterministic. We generally recommend altering this or `top_p` but not both. + text: Configuration options for a text response from the model. Can be plain text or + structured JSON data. Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + tool_choice: How the model should select which tool (or tools) to use when generating a response. See the `tools` parameter to see how to specify which tools the model can call. @@ -536,7 +549,7 @@ def create( store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: response_create_params.Text | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -680,6 +693,12 @@ def create( focused and deterministic. We generally recommend altering this or `top_p` but not both. + text: Configuration options for a text response from the model. Can be plain text or + structured JSON data. Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + tool_choice: How the model should select which tool (or tools) to use when generating a response. See the `tools` parameter to see how to specify which tools the model can call. @@ -756,7 +775,7 @@ def create( stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: response_create_params.Text | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -847,7 +866,7 @@ def stream( store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: response_create_params.Text | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, @@ -879,7 +898,7 @@ def stream( store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: response_create_params.Text | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, @@ -1008,7 +1027,7 @@ def parse( stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: response_create_params.Text | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -1439,7 +1458,7 @@ async def create( stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: response_create_params.Text | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -1583,6 +1602,12 @@ async def create( focused and deterministic. We generally recommend altering this or `top_p` but not both. + text: Configuration options for a text response from the model. Can be plain text or + structured JSON data. Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + tool_choice: How the model should select which tool (or tools) to use when generating a response. See the `tools` parameter to see how to specify which tools the model can call. @@ -1660,7 +1685,7 @@ async def create( store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: response_create_params.Text | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -1804,6 +1829,12 @@ async def create( focused and deterministic. We generally recommend altering this or `top_p` but not both. + text: Configuration options for a text response from the model. Can be plain text or + structured JSON data. Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + tool_choice: How the model should select which tool (or tools) to use when generating a response. See the `tools` parameter to see how to specify which tools the model can call. @@ -1881,7 +1912,7 @@ async def create( store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: response_create_params.Text | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -2025,6 +2056,12 @@ async def create( focused and deterministic. We generally recommend altering this or `top_p` but not both. + text: Configuration options for a text response from the model. Can be plain text or + structured JSON data. Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + tool_choice: How the model should select which tool (or tools) to use when generating a response. See the `tools` parameter to see how to specify which tools the model can call. @@ -2101,7 +2138,7 @@ async def create( stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: response_create_params.Text | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -2192,7 +2229,7 @@ def stream( store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: response_create_params.Text | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, @@ -2224,7 +2261,7 @@ def stream( store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: response_create_params.Text | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, @@ -2357,7 +2394,7 @@ async def parse( stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: response_create_params.Text | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, diff --git a/src/openai/types/chat/completion_create_params.py b/src/openai/types/chat/completion_create_params.py index 3ebab45b56..da37ee4c13 100644 --- a/src/openai/types/chat/completion_create_params.py +++ b/src/openai/types/chat/completion_create_params.py @@ -25,7 +25,6 @@ "FunctionCall", "Function", "ResponseFormat", - "Text", "WebSearchOptions", "WebSearchOptionsUserLocation", "WebSearchOptionsUserLocationApproximate", @@ -257,7 +256,7 @@ class CompletionCreateParamsBase(TypedDict, total=False): our [model distillation](https://platform.openai.com/docs/guides/distillation) or [evals](https://platform.openai.com/docs/guides/evals) products. - Supports text and image inputs. Note: image inputs over 10MB will be dropped. + Supports text and image inputs. Note: image inputs over 8MB will be dropped. """ stream_options: Optional[ChatCompletionStreamOptionsParam] @@ -271,8 +270,6 @@ class CompletionCreateParamsBase(TypedDict, total=False): this or `top_p` but not both. """ - text: Text - tool_choice: ChatCompletionToolChoiceOptionParam """ Controls which (if any) tool is called by the model. `none` means the model will @@ -367,16 +364,6 @@ class Function(TypedDict, total=False): ResponseFormat: TypeAlias = Union[ResponseFormatText, ResponseFormatJSONSchema, ResponseFormatJSONObject] -class Text(TypedDict, total=False): - verbosity: Optional[Literal["low", "medium", "high"]] - """Constrains the verbosity of the model's response. - - Lower values will result in more concise responses, while higher values will - result in more verbose responses. Currently supported values are `low`, - `medium`, and `high`. - """ - - class WebSearchOptionsUserLocationApproximate(TypedDict, total=False): city: str """Free text input for the city of the user, e.g. `San Francisco`.""" diff --git a/src/openai/types/graders/text_similarity_grader.py b/src/openai/types/graders/text_similarity_grader.py index 738d317766..9082ac8969 100644 --- a/src/openai/types/graders/text_similarity_grader.py +++ b/src/openai/types/graders/text_similarity_grader.py @@ -9,12 +9,22 @@ class TextSimilarityGrader(BaseModel): evaluation_metric: Literal[ - "fuzzy_match", "bleu", "gleu", "meteor", "rouge_1", "rouge_2", "rouge_3", "rouge_4", "rouge_5", "rouge_l" + "cosine", + "fuzzy_match", + "bleu", + "gleu", + "meteor", + "rouge_1", + "rouge_2", + "rouge_3", + "rouge_4", + "rouge_5", + "rouge_l", ] """The evaluation metric to use. - One of `fuzzy_match`, `bleu`, `gleu`, `meteor`, `rouge_1`, `rouge_2`, `rouge_3`, - `rouge_4`, `rouge_5`, or `rouge_l`. + One of `cosine`, `fuzzy_match`, `bleu`, `gleu`, `meteor`, `rouge_1`, `rouge_2`, + `rouge_3`, `rouge_4`, `rouge_5`, or `rouge_l`. """ input: str diff --git a/src/openai/types/graders/text_similarity_grader_param.py b/src/openai/types/graders/text_similarity_grader_param.py index db14553217..1646afc84b 100644 --- a/src/openai/types/graders/text_similarity_grader_param.py +++ b/src/openai/types/graders/text_similarity_grader_param.py @@ -10,13 +10,23 @@ class TextSimilarityGraderParam(TypedDict, total=False): evaluation_metric: Required[ Literal[ - "fuzzy_match", "bleu", "gleu", "meteor", "rouge_1", "rouge_2", "rouge_3", "rouge_4", "rouge_5", "rouge_l" + "cosine", + "fuzzy_match", + "bleu", + "gleu", + "meteor", + "rouge_1", + "rouge_2", + "rouge_3", + "rouge_4", + "rouge_5", + "rouge_l", ] ] """The evaluation metric to use. - One of `fuzzy_match`, `bleu`, `gleu`, `meteor`, `rouge_1`, `rouge_2`, `rouge_3`, - `rouge_4`, `rouge_5`, or `rouge_l`. + One of `cosine`, `fuzzy_match`, `bleu`, `gleu`, `meteor`, `rouge_1`, `rouge_2`, + `rouge_3`, `rouge_4`, `rouge_5`, or `rouge_l`. """ input: Required[str] diff --git a/src/openai/types/responses/response.py b/src/openai/types/responses/response.py index 49e38a46fe..49f60bbc5c 100644 --- a/src/openai/types/responses/response.py +++ b/src/openai/types/responses/response.py @@ -18,11 +18,11 @@ from .tool_choice_allowed import ToolChoiceAllowed from .tool_choice_options import ToolChoiceOptions from .response_output_item import ResponseOutputItem +from .response_text_config import ResponseTextConfig from .tool_choice_function import ToolChoiceFunction from ..shared.responses_model import ResponsesModel -from .response_format_text_config import ResponseFormatTextConfig -__all__ = ["Response", "IncompleteDetails", "ToolChoice", "Text"] +__all__ = ["Response", "IncompleteDetails", "ToolChoice"] class IncompleteDetails(BaseModel): @@ -35,32 +35,6 @@ class IncompleteDetails(BaseModel): ] -class Text(BaseModel): - format: Optional[ResponseFormatTextConfig] = None - """An object specifying the format that the model must output. - - Configuring `{ "type": "json_schema" }` enables Structured Outputs, which - ensures the model will match your supplied JSON schema. Learn more in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - The default format is `{ "type": "text" }` with no additional options. - - **Not recommended for gpt-4o and newer models:** - - Setting to `{ "type": "json_object" }` enables the older JSON mode, which - ensures the message the model generates is valid JSON. Using `json_schema` is - preferred for models that support it. - """ - - verbosity: Optional[Literal["low", "medium", "high"]] = None - """Constrains the verbosity of the model's response. - - Lower values will result in more concise responses, while higher values will - result in more verbose responses. Currently supported values are `low`, - `medium`, and `high`. - """ - - class Response(BaseModel): id: str """Unique identifier for this Response.""" @@ -244,7 +218,14 @@ class Response(BaseModel): `incomplete`. """ - text: Optional[Text] = None + text: Optional[ResponseTextConfig] = None + """Configuration options for a text response from the model. + + Can be plain text or structured JSON data. Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + """ top_logprobs: Optional[int] = None """ diff --git a/src/openai/types/responses/response_create_params.py b/src/openai/types/responses/response_create_params.py index 89afccf06b..0cd761fcf0 100644 --- a/src/openai/types/responses/response_create_params.py +++ b/src/openai/types/responses/response_create_params.py @@ -16,14 +16,13 @@ from ..shared_params.reasoning import Reasoning from .tool_choice_custom_param import ToolChoiceCustomParam from .tool_choice_allowed_param import ToolChoiceAllowedParam +from .response_text_config_param import ResponseTextConfigParam from .tool_choice_function_param import ToolChoiceFunctionParam from ..shared_params.responses_model import ResponsesModel -from .response_format_text_config_param import ResponseFormatTextConfigParam __all__ = [ "ResponseCreateParamsBase", "StreamOptions", - "Text", "ToolChoice", "ResponseCreateParamsNonStreaming", "ResponseCreateParamsStreaming", @@ -183,7 +182,14 @@ class ResponseCreateParamsBase(TypedDict, total=False): this or `top_p` but not both. """ - text: Text + text: ResponseTextConfigParam + """Configuration options for a text response from the model. + + Can be plain text or structured JSON data. Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + """ tool_choice: ToolChoice """ @@ -260,32 +266,6 @@ class StreamOptions(TypedDict, total=False): """ -class Text(TypedDict, total=False): - format: ResponseFormatTextConfigParam - """An object specifying the format that the model must output. - - Configuring `{ "type": "json_schema" }` enables Structured Outputs, which - ensures the model will match your supplied JSON schema. Learn more in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - The default format is `{ "type": "text" }` with no additional options. - - **Not recommended for gpt-4o and newer models:** - - Setting to `{ "type": "json_object" }` enables the older JSON mode, which - ensures the message the model generates is valid JSON. Using `json_schema` is - preferred for models that support it. - """ - - verbosity: Optional[Literal["low", "medium", "high"]] - """Constrains the verbosity of the model's response. - - Lower values will result in more concise responses, while higher values will - result in more verbose responses. Currently supported values are `low`, - `medium`, and `high`. - """ - - ToolChoice: TypeAlias = Union[ ToolChoiceOptions, ToolChoiceAllowedParam, diff --git a/tests/api_resources/chat/test_completions.py b/tests/api_resources/chat/test_completions.py index 885c3bd9a6..358ea18cbb 100644 --- a/tests/api_resources/chat/test_completions.py +++ b/tests/api_resources/chat/test_completions.py @@ -86,7 +86,6 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: "include_usage": True, }, temperature=1, - text={"verbosity": "low"}, tool_choice="none", tools=[ { @@ -219,7 +218,6 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: "include_usage": True, }, temperature=1, - text={"verbosity": "low"}, tool_choice="none", tools=[ { @@ -529,7 +527,6 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn "include_usage": True, }, temperature=1, - text={"verbosity": "low"}, tool_choice="none", tools=[ { @@ -662,7 +659,6 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn "include_usage": True, }, temperature=1, - text={"verbosity": "low"}, tool_choice="none", tools=[ { diff --git a/tests/api_resources/test_responses.py b/tests/api_resources/test_responses.py index 868ab3a4ca..310800b87e 100644 --- a/tests/api_resources/test_responses.py +++ b/tests/api_resources/test_responses.py @@ -10,7 +10,9 @@ from openai import OpenAI, AsyncOpenAI from tests.utils import assert_matches_type from openai._utils import assert_signatures_in_sync -from openai.types.responses import Response +from openai.types.responses import ( + Response, +) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") diff --git a/tests/lib/chat/test_completions.py b/tests/lib/chat/test_completions.py index f04a0e3782..f69bc09ca3 100644 --- a/tests/lib/chat/test_completions.py +++ b/tests/lib/chat/test_completions.py @@ -541,7 +541,7 @@ class Location(BaseModel): content_snapshot=snapshot( '{"id": "chatcmpl-ABfvvX7eB1KsfeZj8VcF3z7G7SbaA", "object": "chat.completion", "created": 1727346163, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": "{\\"", "refusal": null}, "logprobs": null, "finish_reason": "length"}], "usage": {"prompt_tokens": 79, "completion_tokens": 1, "total_tokens": 80, "completion_tokens_details": {"reasoning_tokens": 0}}, "system_fingerprint": "fp_7568d46099"}' ), - path="/chat/completions", + path="/chat/completions", mock_client=client, respx_mock=respx_mock, ) From 4ada66f8f86473f342aa032ed021b62180422dc1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 19 Aug 2025 14:10:47 +0000 Subject: [PATCH 454/769] release: 1.100.2 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 6fb2e7075d..8910831376 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.100.1" + ".": "1.100.2" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f3362af2f..2254a59f75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.100.2 (2025-08-19) + +Full Changelog: [v1.100.1...v1.100.2](https://github.com/openai/openai-python/compare/v1.100.1...v1.100.2) + +### Chores + +* **api:** accurately represent shape for verbosity on Chat Completions ([c39d5fd](https://github.com/openai/openai-python/commit/c39d5fd3f5429c6d41f257669a1dd4c67a477455)) + ## 1.100.1 (2025-08-18) Full Changelog: [v1.100.0...v1.100.1](https://github.com/openai/openai-python/compare/v1.100.0...v1.100.1) diff --git a/pyproject.toml b/pyproject.toml index a9baee6a55..c8c3d2fd2b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.100.1" +version = "1.100.2" 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 608d190655..29840a21b8 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.100.1" # x-release-please-version +__version__ = "1.100.2" # x-release-please-version From 72e0ad60f0a6cb2c7d39651c7217b3dd1e86315b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 19 Aug 2025 19:38:10 +0000 Subject: [PATCH 455/769] chore(internal/ci): setup breaking change detection --- .github/workflows/detect-breaking-changes.yml | 42 ++++++++++ .stats.yml | 2 +- pyproject.toml | 1 + requirements-dev.lock | 3 + scripts/detect-breaking-changes | 24 ++++++ scripts/detect-breaking-changes.py | 79 +++++++++++++++++++ 6 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/detect-breaking-changes.yml create mode 100755 scripts/detect-breaking-changes create mode 100644 scripts/detect-breaking-changes.py diff --git a/.github/workflows/detect-breaking-changes.yml b/.github/workflows/detect-breaking-changes.yml new file mode 100644 index 0000000000..f10fdf3b19 --- /dev/null +++ b/.github/workflows/detect-breaking-changes.yml @@ -0,0 +1,42 @@ +name: CI +on: + pull_request: + branches: + - main + - next + +jobs: + detect_breaking_changes: + runs-on: 'ubuntu-latest' + name: detect-breaking-changes + if: github.repository == 'openai/openai-python' + steps: + - name: Calculate fetch-depth + run: | + echo "FETCH_DEPTH=$(expr ${{ github.event.pull_request.commits }} + 1)" >> $GITHUB_ENV + + - uses: actions/checkout@v4 + with: + # Ensure we can check out the pull request base in the script below. + fetch-depth: ${{ env.FETCH_DEPTH }} + + - name: Install Rye + run: | + curl -sSf https://rye.astral.sh/get | bash + echo "$HOME/.rye/shims" >> $GITHUB_PATH + env: + RYE_VERSION: '0.44.0' + RYE_INSTALL_OPTION: '--yes' + - name: Install dependencies + run: | + rye sync --all-features + - name: Detect removed symbols + run: | + rye run python scripts/detect-breaking-changes.py "${{ github.event.pull_request.base.sha }}" + + - name: Detect breaking changes + run: | + # Try to check out previous versions of the breaking change detection script. This ensures that + # we still detect breaking changes when entire files and their tests are removed. + git checkout "${{ github.event.pull_request.base.sha }}" -- ./scripts/detect-breaking-changes 2>/dev/null || true + ./scripts/detect-breaking-changes ${{ github.event.pull_request.base.sha }} \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 81c991168c..d4994342f7 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 111 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-7ef7a457c3bf05364e66e48c9ca34f31bfef1f6c9b7c15b1812346105e0abb16.yml openapi_spec_hash: a2b1f5d8fbb62175c93b0ebea9f10063 -config_hash: 76afa3236f36854a8705f1281b1990b8 +config_hash: 4870312b04f48fd717ea4151053e7fb9 diff --git a/pyproject.toml b/pyproject.toml index c8c3d2fd2b..eb1f588896 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -71,6 +71,7 @@ dev-dependencies = [ "trio >=0.22.2", "nest_asyncio==1.6.0", "pytest-xdist>=3.6.1", + "griffe>=1", ] [tool.rye.scripts] diff --git a/requirements-dev.lock b/requirements-dev.lock index b1886e036f..e619cb6b64 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -44,6 +44,8 @@ cffi==1.16.0 # via sounddevice charset-normalizer==3.3.2 # via requests +colorama==0.4.6 + # via griffe colorlog==6.7.0 # via nox cryptography==42.0.7 @@ -68,6 +70,7 @@ filelock==3.12.4 frozenlist==1.7.0 # via aiohttp # via aiosignal +griffe==1.12.1 h11==0.16.0 # via httpcore httpcore==1.0.9 diff --git a/scripts/detect-breaking-changes b/scripts/detect-breaking-changes new file mode 100755 index 0000000000..833872ef3a --- /dev/null +++ b/scripts/detect-breaking-changes @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +echo "==> Detecting breaking changes" + +TEST_PATHS=( + tests/api_resources + tests/test_client.py + tests/test_response.py + tests/test_legacy_response.py +) + +for PATHSPEC in "${TEST_PATHS[@]}"; do + # Try to check out previous versions of the test files + # with the current SDK. + git checkout "$1" -- "${PATHSPEC}" 2>/dev/null || true +done + +# Instead of running the tests, use the linter to check if an +# older test is no longer compatible with the latest SDK. +./scripts/lint diff --git a/scripts/detect-breaking-changes.py b/scripts/detect-breaking-changes.py new file mode 100644 index 0000000000..3a30f3db2f --- /dev/null +++ b/scripts/detect-breaking-changes.py @@ -0,0 +1,79 @@ +from __future__ import annotations + +import sys +from typing import Iterator +from pathlib import Path + +import rich +import griffe +from rich.text import Text +from rich.style import Style + + +def public_members(obj: griffe.Object | griffe.Alias) -> dict[str, griffe.Object | griffe.Alias]: + if isinstance(obj, griffe.Alias): + # ignore imports for now, they're technically part of the public API + # but we don't have good preventative measures in place to prevent + # changing them + return {} + + return {name: value for name, value in obj.all_members.items() if not name.startswith("_")} + + +def find_breaking_changes( + new_obj: griffe.Object | griffe.Alias, + old_obj: griffe.Object | griffe.Alias, + *, + path: list[str], +) -> Iterator[Text | str]: + new_members = public_members(new_obj) + old_members = public_members(old_obj) + + for name, old_member in old_members.items(): + if isinstance(old_member, griffe.Alias) and len(path) > 2: + # ignore imports in `/types/` for now, they're technically part of the public API + # but we don't have good preventative measures in place to prevent changing them + continue + + new_member = new_members.get(name) + if new_member is None: + cls_name = old_member.__class__.__name__ + yield Text(f"({cls_name})", style=Style(color="rgb(119, 119, 119)")) + yield from [" " for _ in range(10 - len(cls_name))] + yield f" {'.'.join(path)}.{name}" + yield "\n" + continue + + yield from find_breaking_changes(new_member, old_member, path=[*path, name]) + + +def main() -> None: + try: + against_ref = sys.argv[1] + except IndexError as err: + raise RuntimeError("You must specify a base ref to run breaking change detection against") from err + + package = griffe.load( + "openai", + search_paths=[Path(__file__).parent.parent.joinpath("src")], + ) + old_package = griffe.load_git( + "openai", + ref=against_ref, + search_paths=["src"], + ) + assert isinstance(package, griffe.Module) + assert isinstance(old_package, griffe.Module) + + output = list(find_breaking_changes(package, old_package, path=["openai"])) + if output: + rich.print(Text("Breaking changes detected!", style=Style(color="rgb(165, 79, 87)"))) + rich.print() + + for text in output: + rich.print(text, end="") + + sys.exit(1) + + +main() From e328fb4d79badc7ca28a1f599a56ab43eb420363 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 20 Aug 2025 05:04:00 +0000 Subject: [PATCH 456/769] release: 1.100.3 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 8910831376..f3cdcd790c 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.100.2" + ".": "1.100.3" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 2254a59f75..c2f89cb09b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.100.3 (2025-08-20) + +Full Changelog: [v1.100.2...v1.100.3](https://github.com/openai/openai-python/compare/v1.100.2...v1.100.3) + +### Chores + +* **internal/ci:** setup breaking change detection ([ca2f936](https://github.com/openai/openai-python/commit/ca2f93600238e875f26395faf6afbefaf15b7c97)) + ## 1.100.2 (2025-08-19) Full Changelog: [v1.100.1...v1.100.2](https://github.com/openai/openai-python/compare/v1.100.1...v1.100.2) diff --git a/pyproject.toml b/pyproject.toml index eb1f588896..4d1055bfce 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.100.2" +version = "1.100.3" 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 29840a21b8..9881b45247 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.100.2" # x-release-please-version +__version__ = "1.100.3" # x-release-please-version From 4e28a424e6afd60040e3bdf7c76eebb63bc0c407 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 21 Aug 2025 16:10:05 -0500 Subject: [PATCH 457/769] release: 1.101.0 (#2577) * feat(api): adding support for /v1/conversations to the API * chore: update github action * feat(api): Add connectors support for MCP tool * release: 1.101.0 --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 4 +- .release-please-manifest.json | 2 +- .stats.yml | 8 +- CHANGELOG.md | 14 + api.md | 49 ++ pyproject.toml | 2 +- src/openai/__init__.py | 1 + src/openai/_client.py | 38 ++ src/openai/_module_client.py | 8 + src/openai/_version.py | 2 +- src/openai/pagination.py | 67 ++- .../resources/conversations/__init__.py | 33 ++ .../resources/conversations/conversations.py | 474 +++++++++++++++ src/openai/resources/conversations/items.py | 553 ++++++++++++++++++ src/openai/resources/responses/input_items.py | 8 - src/openai/resources/responses/responses.py | 60 +- src/openai/types/conversations/__init__.py | 27 + .../computer_screenshot_content.py | 22 + .../container_file_citation_body.py | 27 + .../types/conversations/conversation.py | 30 + .../conversation_create_params.py | 26 + .../conversation_deleted_resource.py | 15 + .../types/conversations/conversation_item.py | 209 +++++++ .../conversations/conversation_item_list.py | 26 + .../conversation_update_params.py | 19 + .../types/conversations/file_citation_body.py | 21 + .../types/conversations/input_file_content.py | 22 + .../conversations/input_image_content.py | 28 + .../types/conversations/input_text_content.py | 15 + .../types/conversations/item_create_params.py | 24 + .../types/conversations/item_list_params.py | 48 ++ .../conversations/item_retrieve_params.py | 22 + src/openai/types/conversations/lob_prob.py | 18 + src/openai/types/conversations/message.py | 56 ++ .../conversations/output_text_content.py | 30 + .../types/conversations/refusal_content.py | 15 + .../conversations/summary_text_content.py | 13 + .../types/conversations/text_content.py | 13 + .../types/conversations/top_log_prob.py | 15 + .../types/conversations/url_citation_body.py | 24 + ...create_eval_completions_run_data_source.py | 26 +- ..._eval_completions_run_data_source_param.py | 24 +- src/openai/types/responses/__init__.py | 1 + .../types/responses/input_item_list_params.py | 3 - src/openai/types/responses/response.py | 15 +- .../responses/response_conversation_param.py | 12 + .../types/responses/response_create_params.py | 14 + src/openai/types/responses/tool.py | 84 ++- src/openai/types/responses/tool_param.py | 82 ++- tests/api_resources/conversations/__init__.py | 1 + .../api_resources/conversations/test_items.py | 491 ++++++++++++++++ .../responses/test_input_items.py | 2 - tests/api_resources/test_conversations.py | 341 +++++++++++ tests/api_resources/test_responses.py | 4 + 54 files changed, 3114 insertions(+), 74 deletions(-) create mode 100644 src/openai/resources/conversations/__init__.py create mode 100644 src/openai/resources/conversations/conversations.py create mode 100644 src/openai/resources/conversations/items.py create mode 100644 src/openai/types/conversations/__init__.py create mode 100644 src/openai/types/conversations/computer_screenshot_content.py create mode 100644 src/openai/types/conversations/container_file_citation_body.py create mode 100644 src/openai/types/conversations/conversation.py create mode 100644 src/openai/types/conversations/conversation_create_params.py create mode 100644 src/openai/types/conversations/conversation_deleted_resource.py create mode 100644 src/openai/types/conversations/conversation_item.py create mode 100644 src/openai/types/conversations/conversation_item_list.py create mode 100644 src/openai/types/conversations/conversation_update_params.py create mode 100644 src/openai/types/conversations/file_citation_body.py create mode 100644 src/openai/types/conversations/input_file_content.py create mode 100644 src/openai/types/conversations/input_image_content.py create mode 100644 src/openai/types/conversations/input_text_content.py create mode 100644 src/openai/types/conversations/item_create_params.py create mode 100644 src/openai/types/conversations/item_list_params.py create mode 100644 src/openai/types/conversations/item_retrieve_params.py create mode 100644 src/openai/types/conversations/lob_prob.py create mode 100644 src/openai/types/conversations/message.py create mode 100644 src/openai/types/conversations/output_text_content.py create mode 100644 src/openai/types/conversations/refusal_content.py create mode 100644 src/openai/types/conversations/summary_text_content.py create mode 100644 src/openai/types/conversations/text_content.py create mode 100644 src/openai/types/conversations/top_log_prob.py create mode 100644 src/openai/types/conversations/url_citation_body.py create mode 100644 src/openai/types/responses/response_conversation_param.py create mode 100644 tests/api_resources/conversations/__init__.py create mode 100644 tests/api_resources/conversations/test_items.py create mode 100644 tests/api_resources/test_conversations.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8067386d5f..5e56aae09a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,7 +36,7 @@ jobs: run: ./scripts/lint build: - if: github.repository == 'stainless-sdks/openai-python' && (github.event_name == 'push' || github.event.pull_request.head.repo.fork) + if: github.event_name == 'push' || github.event.pull_request.head.repo.fork timeout-minutes: 10 name: build permissions: @@ -61,12 +61,14 @@ jobs: run: rye build - name: Get GitHub OIDC Token + if: github.repository == 'stainless-sdks/openai-python' id: github-oidc uses: actions/github-script@v6 with: script: core.setOutput('github_token', await core.getIDToken()); - name: Upload tarball + if: github.repository == 'stainless-sdks/openai-python' env: URL: https://pkg.stainless.com/s AUTH: ${{ steps.github-oidc.outputs.github_token }} diff --git a/.release-please-manifest.json b/.release-please-manifest.json index f3cdcd790c..070375331a 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.100.3" + ".": "1.101.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index d4994342f7..f2d5304a5b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 111 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-7ef7a457c3bf05364e66e48c9ca34f31bfef1f6c9b7c15b1812346105e0abb16.yml -openapi_spec_hash: a2b1f5d8fbb62175c93b0ebea9f10063 -config_hash: 4870312b04f48fd717ea4151053e7fb9 +configured_endpoints: 119 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-ddbdf9343316047e8a773c54fb24e4a8d225955e202a1888fde6f9c8898ebf98.yml +openapi_spec_hash: 9802f6dd381558466c897f6e387e06ca +config_hash: fe0ea26680ac2075a6cd66416aefe7db diff --git a/CHANGELOG.md b/CHANGELOG.md index c2f89cb09b..44b25e0a4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## 1.101.0 (2025-08-21) + +Full Changelog: [v1.100.3...v1.101.0](https://github.com/openai/openai-python/compare/v1.100.3...v1.101.0) + +### Features + +* **api:** Add connectors support for MCP tool ([a47f962](https://github.com/openai/openai-python/commit/a47f962daf579c142b8af5579be732772b688a29)) +* **api:** adding support for /v1/conversations to the API ([e30bcbc](https://github.com/openai/openai-python/commit/e30bcbc0cb7c827af779bee6971f976261abfb67)) + + +### Chores + +* update github action ([7333b28](https://github.com/openai/openai-python/commit/7333b282718a5f6977f30e1a2548207b3a089bd4)) + ## 1.100.3 (2025-08-20) Full Changelog: [v1.100.2...v1.100.3](https://github.com/openai/openai-python/compare/v1.100.2...v1.100.3) diff --git a/api.md b/api.md index 92b068b134..7eb62e67f2 100644 --- a/api.md +++ b/api.md @@ -751,6 +751,7 @@ from openai.types.responses import ( ResponseContent, ResponseContentPartAddedEvent, ResponseContentPartDoneEvent, + ResponseConversationParam, ResponseCreatedEvent, ResponseCustomToolCall, ResponseCustomToolCallInputDeltaEvent, @@ -854,6 +855,54 @@ Methods: - client.responses.input_items.list(response_id, \*\*params) -> SyncCursorPage[ResponseItem] +# Conversations + +Types: + +```python +from openai.types.conversations import ( + ComputerScreenshotContent, + ContainerFileCitationBody, + Conversation, + ConversationDeleted, + ConversationDeletedResource, + FileCitationBody, + InputFileContent, + InputImageContent, + InputTextContent, + LobProb, + Message, + OutputTextContent, + RefusalContent, + SummaryTextContent, + TextContent, + TopLogProb, + URLCitationBody, +) +``` + +Methods: + +- client.conversations.create(\*\*params) -> Conversation +- client.conversations.retrieve(conversation_id) -> Conversation +- client.conversations.update(conversation_id, \*\*params) -> Conversation +- client.conversations.delete(conversation_id) -> ConversationDeletedResource + +## Items + +Types: + +```python +from openai.types.conversations import ConversationItem, ConversationItemList +``` + +Methods: + +- client.conversations.items.create(conversation_id, \*\*params) -> ConversationItemList +- client.conversations.items.retrieve(item_id, \*, conversation_id, \*\*params) -> ConversationItem +- client.conversations.items.list(conversation_id, \*\*params) -> SyncConversationCursorPage[ConversationItem] +- client.conversations.items.delete(item_id, \*, conversation_id) -> Conversation + # Evals Types: diff --git a/pyproject.toml b/pyproject.toml index 4d1055bfce..8198b178be 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.100.3" +version = "1.101.0" description = "The official Python library for the openai API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/openai/__init__.py b/src/openai/__init__.py index 226fed9554..b944fbed5e 100644 --- a/src/openai/__init__.py +++ b/src/openai/__init__.py @@ -386,5 +386,6 @@ def _reset_client() -> None: # type: ignore[reportUnusedFunction] completions as completions, fine_tuning as fine_tuning, moderations as moderations, + conversations as conversations, vector_stores as vector_stores, ) diff --git a/src/openai/_client.py b/src/openai/_client.py index ed9b46f4b0..b99db786a7 100644 --- a/src/openai/_client.py +++ b/src/openai/_client.py @@ -51,6 +51,7 @@ completions, fine_tuning, moderations, + conversations, vector_stores, ) from .resources.files import Files, AsyncFiles @@ -69,6 +70,7 @@ from .resources.responses.responses import Responses, AsyncResponses from .resources.containers.containers import Containers, AsyncContainers from .resources.fine_tuning.fine_tuning import FineTuning, AsyncFineTuning + from .resources.conversations.conversations import Conversations, AsyncConversations from .resources.vector_stores.vector_stores import VectorStores, AsyncVectorStores __all__ = ["Timeout", "Transport", "ProxiesTypes", "RequestOptions", "OpenAI", "AsyncOpenAI", "Client", "AsyncClient"] @@ -254,6 +256,12 @@ def responses(self) -> Responses: return Responses(self) + @cached_property + def conversations(self) -> Conversations: + from .resources.conversations import Conversations + + return Conversations(self) + @cached_property def evals(self) -> Evals: from .resources.evals import Evals @@ -573,6 +581,12 @@ def responses(self) -> AsyncResponses: return AsyncResponses(self) + @cached_property + def conversations(self) -> AsyncConversations: + from .resources.conversations import AsyncConversations + + return AsyncConversations(self) + @cached_property def evals(self) -> AsyncEvals: from .resources.evals import AsyncEvals @@ -802,6 +816,12 @@ def responses(self) -> responses.ResponsesWithRawResponse: return ResponsesWithRawResponse(self._client.responses) + @cached_property + def conversations(self) -> conversations.ConversationsWithRawResponse: + from .resources.conversations import ConversationsWithRawResponse + + return ConversationsWithRawResponse(self._client.conversations) + @cached_property def evals(self) -> evals.EvalsWithRawResponse: from .resources.evals import EvalsWithRawResponse @@ -905,6 +925,12 @@ def responses(self) -> responses.AsyncResponsesWithRawResponse: return AsyncResponsesWithRawResponse(self._client.responses) + @cached_property + def conversations(self) -> conversations.AsyncConversationsWithRawResponse: + from .resources.conversations import AsyncConversationsWithRawResponse + + return AsyncConversationsWithRawResponse(self._client.conversations) + @cached_property def evals(self) -> evals.AsyncEvalsWithRawResponse: from .resources.evals import AsyncEvalsWithRawResponse @@ -1008,6 +1034,12 @@ def responses(self) -> responses.ResponsesWithStreamingResponse: return ResponsesWithStreamingResponse(self._client.responses) + @cached_property + def conversations(self) -> conversations.ConversationsWithStreamingResponse: + from .resources.conversations import ConversationsWithStreamingResponse + + return ConversationsWithStreamingResponse(self._client.conversations) + @cached_property def evals(self) -> evals.EvalsWithStreamingResponse: from .resources.evals import EvalsWithStreamingResponse @@ -1111,6 +1143,12 @@ def responses(self) -> responses.AsyncResponsesWithStreamingResponse: return AsyncResponsesWithStreamingResponse(self._client.responses) + @cached_property + def conversations(self) -> conversations.AsyncConversationsWithStreamingResponse: + from .resources.conversations import AsyncConversationsWithStreamingResponse + + return AsyncConversationsWithStreamingResponse(self._client.conversations) + @cached_property def evals(self) -> evals.AsyncEvalsWithStreamingResponse: from .resources.evals import AsyncEvalsWithStreamingResponse diff --git a/src/openai/_module_client.py b/src/openai/_module_client.py index a80e939300..5c8df24014 100644 --- a/src/openai/_module_client.py +++ b/src/openai/_module_client.py @@ -22,6 +22,7 @@ from .resources.responses.responses import Responses from .resources.containers.containers import Containers from .resources.fine_tuning.fine_tuning import FineTuning + from .resources.conversations.conversations import Conversations from .resources.vector_stores.vector_stores import VectorStores from . import _load_client @@ -130,6 +131,12 @@ def __load__(self) -> VectorStores: return _load_client().vector_stores +class ConversationsProxy(LazyProxy["Conversations"]): + @override + def __load__(self) -> Conversations: + return _load_client().conversations + + chat: Chat = ChatProxy().__as_proxied__() beta: Beta = BetaProxy().__as_proxied__() files: Files = FilesProxy().__as_proxied__() @@ -147,3 +154,4 @@ def __load__(self) -> VectorStores: moderations: Moderations = ModerationsProxy().__as_proxied__() fine_tuning: FineTuning = FineTuningProxy().__as_proxied__() vector_stores: VectorStores = VectorStoresProxy().__as_proxied__() +conversations: Conversations = ConversationsProxy().__as_proxied__() diff --git a/src/openai/_version.py b/src/openai/_version.py index 9881b45247..802084af5d 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.100.3" # x-release-please-version +__version__ = "1.101.0" # x-release-please-version diff --git a/src/openai/pagination.py b/src/openai/pagination.py index a59cced854..4dd3788aa3 100644 --- a/src/openai/pagination.py +++ b/src/openai/pagination.py @@ -5,7 +5,14 @@ from ._base_client import BasePage, PageInfo, BaseSyncPage, BaseAsyncPage -__all__ = ["SyncPage", "AsyncPage", "SyncCursorPage", "AsyncCursorPage"] +__all__ = [ + "SyncPage", + "AsyncPage", + "SyncCursorPage", + "AsyncCursorPage", + "SyncConversationCursorPage", + "AsyncConversationCursorPage", +] _T = TypeVar("_T") @@ -123,3 +130,61 @@ def next_page_info(self) -> Optional[PageInfo]: return None return PageInfo(params={"after": item.id}) + + +class SyncConversationCursorPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]): + data: List[_T] + has_more: Optional[bool] = None + last_id: Optional[str] = None + + @override + def _get_page_items(self) -> List[_T]: + data = self.data + if not data: + 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]: + last_id = self.last_id + if not last_id: + return None + + return PageInfo(params={"after": last_id}) + + +class AsyncConversationCursorPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): + data: List[_T] + has_more: Optional[bool] = None + last_id: Optional[str] = None + + @override + def _get_page_items(self) -> List[_T]: + data = self.data + if not data: + 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]: + last_id = self.last_id + if not last_id: + return None + + return PageInfo(params={"after": last_id}) diff --git a/src/openai/resources/conversations/__init__.py b/src/openai/resources/conversations/__init__.py new file mode 100644 index 0000000000..c6c4fd6ee4 --- /dev/null +++ b/src/openai/resources/conversations/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .items import ( + Items, + AsyncItems, + ItemsWithRawResponse, + AsyncItemsWithRawResponse, + ItemsWithStreamingResponse, + AsyncItemsWithStreamingResponse, +) +from .conversations import ( + Conversations, + AsyncConversations, + ConversationsWithRawResponse, + AsyncConversationsWithRawResponse, + ConversationsWithStreamingResponse, + AsyncConversationsWithStreamingResponse, +) + +__all__ = [ + "Items", + "AsyncItems", + "ItemsWithRawResponse", + "AsyncItemsWithRawResponse", + "ItemsWithStreamingResponse", + "AsyncItemsWithStreamingResponse", + "Conversations", + "AsyncConversations", + "ConversationsWithRawResponse", + "AsyncConversationsWithRawResponse", + "ConversationsWithStreamingResponse", + "AsyncConversationsWithStreamingResponse", +] diff --git a/src/openai/resources/conversations/conversations.py b/src/openai/resources/conversations/conversations.py new file mode 100644 index 0000000000..13bc1fb1ce --- /dev/null +++ b/src/openai/resources/conversations/conversations.py @@ -0,0 +1,474 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Iterable, Optional + +import httpx + +from ... import _legacy_response +from .items import ( + Items, + AsyncItems, + ItemsWithRawResponse, + AsyncItemsWithRawResponse, + ItemsWithStreamingResponse, + AsyncItemsWithStreamingResponse, +) +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ..._base_client import make_request_options +from ...types.conversations import conversation_create_params, conversation_update_params +from ...types.shared_params.metadata import Metadata +from ...types.conversations.conversation import Conversation +from ...types.responses.response_input_item_param import ResponseInputItemParam +from ...types.conversations.conversation_deleted_resource import ConversationDeletedResource + +__all__ = ["Conversations", "AsyncConversations"] + + +class Conversations(SyncAPIResource): + @cached_property + def items(self) -> Items: + return Items(self._client) + + @cached_property + def with_raw_response(self) -> ConversationsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return ConversationsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ConversationsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return ConversationsWithStreamingResponse(self) + + def create( + self, + *, + items: Optional[Iterable[ResponseInputItemParam]] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Conversation: + """ + Create a conversation with the given ID. + + Args: + items: Initial items to include in the conversation context. You may add up to 20 items + at a time. + + metadata: Set of 16 key-value pairs that can be attached to an object. Useful for storing + additional information about the object in a structured format. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/conversations", + body=maybe_transform( + { + "items": items, + "metadata": metadata, + }, + conversation_create_params.ConversationCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Conversation, + ) + + def retrieve( + self, + conversation_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Conversation: + """ + Get a conversation with the given ID. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not conversation_id: + raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") + return self._get( + f"/conversations/{conversation_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Conversation, + ) + + def update( + self, + conversation_id: str, + *, + metadata: Dict[str, str], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Conversation: + """ + Update a conversation's metadata with the given ID. + + Args: + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. Keys are strings with a maximum + length of 64 characters. Values are strings with a maximum length of 512 + characters. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not conversation_id: + raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") + return self._post( + f"/conversations/{conversation_id}", + body=maybe_transform({"metadata": metadata}, conversation_update_params.ConversationUpdateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Conversation, + ) + + def delete( + self, + conversation_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ConversationDeletedResource: + """ + Delete a conversation with the given ID. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not conversation_id: + raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") + return self._delete( + f"/conversations/{conversation_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ConversationDeletedResource, + ) + + +class AsyncConversations(AsyncAPIResource): + @cached_property + def items(self) -> AsyncItems: + return AsyncItems(self._client) + + @cached_property + def with_raw_response(self) -> AsyncConversationsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncConversationsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncConversationsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncConversationsWithStreamingResponse(self) + + async def create( + self, + *, + items: Optional[Iterable[ResponseInputItemParam]] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Conversation: + """ + Create a conversation with the given ID. + + Args: + items: Initial items to include in the conversation context. You may add up to 20 items + at a time. + + metadata: Set of 16 key-value pairs that can be attached to an object. Useful for storing + additional information about the object in a structured format. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/conversations", + body=await async_maybe_transform( + { + "items": items, + "metadata": metadata, + }, + conversation_create_params.ConversationCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Conversation, + ) + + async def retrieve( + self, + conversation_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Conversation: + """ + Get a conversation with the given ID. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not conversation_id: + raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") + return await self._get( + f"/conversations/{conversation_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Conversation, + ) + + async def update( + self, + conversation_id: str, + *, + metadata: Dict[str, str], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Conversation: + """ + Update a conversation's metadata with the given ID. + + Args: + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. Keys are strings with a maximum + length of 64 characters. Values are strings with a maximum length of 512 + characters. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not conversation_id: + raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") + return await self._post( + f"/conversations/{conversation_id}", + body=await async_maybe_transform( + {"metadata": metadata}, conversation_update_params.ConversationUpdateParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Conversation, + ) + + async def delete( + self, + conversation_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ConversationDeletedResource: + """ + Delete a conversation with the given ID. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not conversation_id: + raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") + return await self._delete( + f"/conversations/{conversation_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ConversationDeletedResource, + ) + + +class ConversationsWithRawResponse: + def __init__(self, conversations: Conversations) -> None: + self._conversations = conversations + + self.create = _legacy_response.to_raw_response_wrapper( + conversations.create, + ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + conversations.retrieve, + ) + self.update = _legacy_response.to_raw_response_wrapper( + conversations.update, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + conversations.delete, + ) + + @cached_property + def items(self) -> ItemsWithRawResponse: + return ItemsWithRawResponse(self._conversations.items) + + +class AsyncConversationsWithRawResponse: + def __init__(self, conversations: AsyncConversations) -> None: + self._conversations = conversations + + self.create = _legacy_response.async_to_raw_response_wrapper( + conversations.create, + ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + conversations.retrieve, + ) + self.update = _legacy_response.async_to_raw_response_wrapper( + conversations.update, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + conversations.delete, + ) + + @cached_property + def items(self) -> AsyncItemsWithRawResponse: + return AsyncItemsWithRawResponse(self._conversations.items) + + +class ConversationsWithStreamingResponse: + def __init__(self, conversations: Conversations) -> None: + self._conversations = conversations + + self.create = to_streamed_response_wrapper( + conversations.create, + ) + self.retrieve = to_streamed_response_wrapper( + conversations.retrieve, + ) + self.update = to_streamed_response_wrapper( + conversations.update, + ) + self.delete = to_streamed_response_wrapper( + conversations.delete, + ) + + @cached_property + def items(self) -> ItemsWithStreamingResponse: + return ItemsWithStreamingResponse(self._conversations.items) + + +class AsyncConversationsWithStreamingResponse: + def __init__(self, conversations: AsyncConversations) -> None: + self._conversations = conversations + + self.create = async_to_streamed_response_wrapper( + conversations.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + conversations.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + conversations.update, + ) + self.delete = async_to_streamed_response_wrapper( + conversations.delete, + ) + + @cached_property + def items(self) -> AsyncItemsWithStreamingResponse: + return AsyncItemsWithStreamingResponse(self._conversations.items) diff --git a/src/openai/resources/conversations/items.py b/src/openai/resources/conversations/items.py new file mode 100644 index 0000000000..1e696a79ed --- /dev/null +++ b/src/openai/resources/conversations/items.py @@ -0,0 +1,553 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Any, List, Iterable, cast +from typing_extensions import Literal + +import httpx + +from ... import _legacy_response +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ...pagination import SyncConversationCursorPage, AsyncConversationCursorPage +from ..._base_client import AsyncPaginator, make_request_options +from ...types.conversations import item_list_params, item_create_params, item_retrieve_params +from ...types.conversations.conversation import Conversation +from ...types.responses.response_includable import ResponseIncludable +from ...types.conversations.conversation_item import ConversationItem +from ...types.responses.response_input_item_param import ResponseInputItemParam +from ...types.conversations.conversation_item_list import ConversationItemList + +__all__ = ["Items", "AsyncItems"] + + +class Items(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ItemsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return ItemsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ItemsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return ItemsWithStreamingResponse(self) + + def create( + self, + conversation_id: str, + *, + items: Iterable[ResponseInputItemParam], + include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ConversationItemList: + """ + Create items in a conversation with the given ID. + + Args: + items: The items to add to the conversation. You may add up to 20 items at a time. + + include: Additional fields to include in the response. See the `include` parameter for + [listing Conversation items above](https://platform.openai.com/docs/api-reference/conversations/list-items#conversations_list_items-include) + for more information. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not conversation_id: + raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") + return self._post( + f"/conversations/{conversation_id}/items", + body=maybe_transform({"items": items}, item_create_params.ItemCreateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"include": include}, item_create_params.ItemCreateParams), + ), + cast_to=ConversationItemList, + ) + + def retrieve( + self, + item_id: str, + *, + conversation_id: str, + include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ConversationItem: + """ + Get a single item from a conversation with the given IDs. + + Args: + include: Additional fields to include in the response. See the `include` parameter for + [listing Conversation items above](https://platform.openai.com/docs/api-reference/conversations/list-items#conversations_list_items-include) + for more information. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not conversation_id: + raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") + if not item_id: + raise ValueError(f"Expected a non-empty value for `item_id` but received {item_id!r}") + return cast( + ConversationItem, + self._get( + f"/conversations/{conversation_id}/items/{item_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"include": include}, item_retrieve_params.ItemRetrieveParams), + ), + cast_to=cast(Any, ConversationItem), # Union types cannot be passed in as arguments in the type system + ), + ) + + def list( + self, + conversation_id: str, + *, + after: str | NotGiven = NOT_GIVEN, + include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + limit: int | NotGiven = NOT_GIVEN, + order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> SyncConversationCursorPage[ConversationItem]: + """ + List all items for a conversation with the given ID. + + Args: + after: An item ID to list items after, used in pagination. + + include: Specify additional output data to include in the model response. Currently + supported values are: + + - `code_interpreter_call.outputs`: Includes the outputs of python code execution + in code interpreter tool call items. + - `computer_call_output.output.image_url`: Include image urls from the computer + call output. + - `file_search_call.results`: Include the search results of the file search tool + call. + - `message.input_image.image_url`: Include image urls from the input message. + - `message.output_text.logprobs`: Include logprobs with assistant messages. + - `reasoning.encrypted_content`: Includes an encrypted version of reasoning + tokens in reasoning item outputs. This enables reasoning items to be used in + multi-turn conversations when using the Responses API statelessly (like when + the `store` parameter is set to `false`, or when an organization is enrolled + in the zero data retention program). + + limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the default is 20. + + order: The order to return the input items in. Default is `desc`. + + - `asc`: Return the input items in ascending order. + - `desc`: Return the input items in descending order. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not conversation_id: + raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") + return self._get_api_list( + f"/conversations/{conversation_id}/items", + page=SyncConversationCursorPage[ConversationItem], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "include": include, + "limit": limit, + "order": order, + }, + item_list_params.ItemListParams, + ), + ), + model=cast(Any, ConversationItem), # Union types cannot be passed in as arguments in the type system + ) + + def delete( + self, + item_id: str, + *, + conversation_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Conversation: + """ + Delete an item from a conversation with the given IDs. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not conversation_id: + raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") + if not item_id: + raise ValueError(f"Expected a non-empty value for `item_id` but received {item_id!r}") + return self._delete( + f"/conversations/{conversation_id}/items/{item_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Conversation, + ) + + +class AsyncItems(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncItemsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncItemsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncItemsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncItemsWithStreamingResponse(self) + + async def create( + self, + conversation_id: str, + *, + items: Iterable[ResponseInputItemParam], + include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ConversationItemList: + """ + Create items in a conversation with the given ID. + + Args: + items: The items to add to the conversation. You may add up to 20 items at a time. + + include: Additional fields to include in the response. See the `include` parameter for + [listing Conversation items above](https://platform.openai.com/docs/api-reference/conversations/list-items#conversations_list_items-include) + for more information. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not conversation_id: + raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") + return await self._post( + f"/conversations/{conversation_id}/items", + body=await async_maybe_transform({"items": items}, item_create_params.ItemCreateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform({"include": include}, item_create_params.ItemCreateParams), + ), + cast_to=ConversationItemList, + ) + + async def retrieve( + self, + item_id: str, + *, + conversation_id: str, + include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ConversationItem: + """ + Get a single item from a conversation with the given IDs. + + Args: + include: Additional fields to include in the response. See the `include` parameter for + [listing Conversation items above](https://platform.openai.com/docs/api-reference/conversations/list-items#conversations_list_items-include) + for more information. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not conversation_id: + raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") + if not item_id: + raise ValueError(f"Expected a non-empty value for `item_id` but received {item_id!r}") + return cast( + ConversationItem, + await self._get( + f"/conversations/{conversation_id}/items/{item_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform({"include": include}, item_retrieve_params.ItemRetrieveParams), + ), + cast_to=cast(Any, ConversationItem), # Union types cannot be passed in as arguments in the type system + ), + ) + + def list( + self, + conversation_id: str, + *, + after: str | NotGiven = NOT_GIVEN, + include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + limit: int | NotGiven = NOT_GIVEN, + order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> AsyncPaginator[ConversationItem, AsyncConversationCursorPage[ConversationItem]]: + """ + List all items for a conversation with the given ID. + + Args: + after: An item ID to list items after, used in pagination. + + include: Specify additional output data to include in the model response. Currently + supported values are: + + - `code_interpreter_call.outputs`: Includes the outputs of python code execution + in code interpreter tool call items. + - `computer_call_output.output.image_url`: Include image urls from the computer + call output. + - `file_search_call.results`: Include the search results of the file search tool + call. + - `message.input_image.image_url`: Include image urls from the input message. + - `message.output_text.logprobs`: Include logprobs with assistant messages. + - `reasoning.encrypted_content`: Includes an encrypted version of reasoning + tokens in reasoning item outputs. This enables reasoning items to be used in + multi-turn conversations when using the Responses API statelessly (like when + the `store` parameter is set to `false`, or when an organization is enrolled + in the zero data retention program). + + limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the default is 20. + + order: The order to return the input items in. Default is `desc`. + + - `asc`: Return the input items in ascending order. + - `desc`: Return the input items in descending order. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not conversation_id: + raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") + return self._get_api_list( + f"/conversations/{conversation_id}/items", + page=AsyncConversationCursorPage[ConversationItem], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "include": include, + "limit": limit, + "order": order, + }, + item_list_params.ItemListParams, + ), + ), + model=cast(Any, ConversationItem), # Union types cannot be passed in as arguments in the type system + ) + + async def delete( + self, + item_id: str, + *, + conversation_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Conversation: + """ + Delete an item from a conversation with the given IDs. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not conversation_id: + raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") + if not item_id: + raise ValueError(f"Expected a non-empty value for `item_id` but received {item_id!r}") + return await self._delete( + f"/conversations/{conversation_id}/items/{item_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Conversation, + ) + + +class ItemsWithRawResponse: + def __init__(self, items: Items) -> None: + self._items = items + + self.create = _legacy_response.to_raw_response_wrapper( + items.create, + ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + items.retrieve, + ) + self.list = _legacy_response.to_raw_response_wrapper( + items.list, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + items.delete, + ) + + +class AsyncItemsWithRawResponse: + def __init__(self, items: AsyncItems) -> None: + self._items = items + + self.create = _legacy_response.async_to_raw_response_wrapper( + items.create, + ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + items.retrieve, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + items.list, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + items.delete, + ) + + +class ItemsWithStreamingResponse: + def __init__(self, items: Items) -> None: + self._items = items + + self.create = to_streamed_response_wrapper( + items.create, + ) + self.retrieve = to_streamed_response_wrapper( + items.retrieve, + ) + self.list = to_streamed_response_wrapper( + items.list, + ) + self.delete = to_streamed_response_wrapper( + items.delete, + ) + + +class AsyncItemsWithStreamingResponse: + def __init__(self, items: AsyncItems) -> None: + self._items = items + + self.create = async_to_streamed_response_wrapper( + items.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + items.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + items.list, + ) + self.delete = async_to_streamed_response_wrapper( + items.delete, + ) diff --git a/src/openai/resources/responses/input_items.py b/src/openai/resources/responses/input_items.py index a425a65c3e..9f3ef637ce 100644 --- a/src/openai/resources/responses/input_items.py +++ b/src/openai/resources/responses/input_items.py @@ -47,7 +47,6 @@ def list( response_id: str, *, after: str | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, limit: int | NotGiven = NOT_GIVEN, order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, @@ -64,8 +63,6 @@ def list( Args: after: An item ID to list items after, used in pagination. - before: An item ID to list items before, used in pagination. - include: Additional fields to include in the response. See the `include` parameter for Response creation above for more information. @@ -98,7 +95,6 @@ def list( query=maybe_transform( { "after": after, - "before": before, "include": include, "limit": limit, "order": order, @@ -135,7 +131,6 @@ def list( response_id: str, *, after: str | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, limit: int | NotGiven = NOT_GIVEN, order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, @@ -152,8 +147,6 @@ def list( Args: after: An item ID to list items after, used in pagination. - before: An item ID to list items before, used in pagination. - include: Additional fields to include in the response. See the `include` parameter for Response creation above for more information. @@ -186,7 +179,6 @@ def list( query=maybe_transform( { "after": after, - "before": before, "include": include, "limit": limit, "order": order, diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 375f8b7e71..d0862f5d76 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -77,6 +77,7 @@ def create( self, *, background: Optional[bool] | NotGiven = NOT_GIVEN, + conversation: Optional[response_create_params.Conversation] | NotGiven = NOT_GIVEN, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, @@ -127,6 +128,11 @@ def create( background: Whether to run the model response in the background. [Learn more](https://platform.openai.com/docs/guides/background). + conversation: The conversation that this response belongs to. Items from this conversation are + prepended to `input_items` for this response request. Input items and output + items from this response are automatically added to this conversation after this + response completes. + include: Specify additional output data to include in the model response. Currently supported values are: @@ -187,6 +193,7 @@ def create( previous_response_id: The unique ID of the previous response to the model. Use this to create multi-turn conversations. Learn more about [conversation state](https://platform.openai.com/docs/guides/conversation-state). + Cannot be used in conjunction with `conversation`. prompt: Reference to a prompt template and its variables. [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). @@ -305,6 +312,7 @@ def create( *, stream: Literal[True], background: Optional[bool] | NotGiven = NOT_GIVEN, + conversation: Optional[response_create_params.Conversation] | NotGiven = NOT_GIVEN, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, @@ -361,6 +369,11 @@ def create( background: Whether to run the model response in the background. [Learn more](https://platform.openai.com/docs/guides/background). + conversation: The conversation that this response belongs to. Items from this conversation are + prepended to `input_items` for this response request. Input items and output + items from this response are automatically added to this conversation after this + response completes. + include: Specify additional output data to include in the model response. Currently supported values are: @@ -421,6 +434,7 @@ def create( previous_response_id: The unique ID of the previous response to the model. Use this to create multi-turn conversations. Learn more about [conversation state](https://platform.openai.com/docs/guides/conversation-state). + Cannot be used in conjunction with `conversation`. prompt: Reference to a prompt template and its variables. [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). @@ -532,6 +546,7 @@ def create( *, stream: bool, background: Optional[bool] | NotGiven = NOT_GIVEN, + conversation: Optional[response_create_params.Conversation] | NotGiven = NOT_GIVEN, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, @@ -588,6 +603,11 @@ def create( background: Whether to run the model response in the background. [Learn more](https://platform.openai.com/docs/guides/background). + conversation: The conversation that this response belongs to. Items from this conversation are + prepended to `input_items` for this response request. Input items and output + items from this response are automatically added to this conversation after this + response completes. + include: Specify additional output data to include in the model response. Currently supported values are: @@ -648,6 +668,7 @@ def create( previous_response_id: The unique ID of the previous response to the model. Use this to create multi-turn conversations. Learn more about [conversation state](https://platform.openai.com/docs/guides/conversation-state). + Cannot be used in conjunction with `conversation`. prompt: Reference to a prompt template and its variables. [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). @@ -757,6 +778,7 @@ def create( self, *, background: Optional[bool] | NotGiven = NOT_GIVEN, + conversation: Optional[response_create_params.Conversation] | NotGiven = NOT_GIVEN, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, @@ -794,6 +816,7 @@ def create( body=maybe_transform( { "background": background, + "conversation": conversation, "include": include, "input": input, "instructions": instructions, @@ -866,7 +889,7 @@ def stream( store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam| NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, @@ -1009,6 +1032,7 @@ def parse( *, text_format: type[TextFormatT] | NotGiven = NOT_GIVEN, background: Optional[bool] | NotGiven = NOT_GIVEN, + conversation: Optional[response_create_params.Conversation] | NotGiven = NOT_GIVEN, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, @@ -1027,7 +1051,7 @@ def parse( stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam| NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -1065,6 +1089,7 @@ def parser(raw_response: Response) -> ParsedResponse[TextFormatT]: body=maybe_transform( { "background": background, + "conversation": conversation, "include": include, "input": input, "instructions": instructions, @@ -1440,6 +1465,7 @@ async def create( self, *, background: Optional[bool] | NotGiven = NOT_GIVEN, + conversation: Optional[response_create_params.Conversation] | NotGiven = NOT_GIVEN, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, @@ -1490,6 +1516,11 @@ async def create( background: Whether to run the model response in the background. [Learn more](https://platform.openai.com/docs/guides/background). + conversation: The conversation that this response belongs to. Items from this conversation are + prepended to `input_items` for this response request. Input items and output + items from this response are automatically added to this conversation after this + response completes. + include: Specify additional output data to include in the model response. Currently supported values are: @@ -1550,6 +1581,7 @@ async def create( previous_response_id: The unique ID of the previous response to the model. Use this to create multi-turn conversations. Learn more about [conversation state](https://platform.openai.com/docs/guides/conversation-state). + Cannot be used in conjunction with `conversation`. prompt: Reference to a prompt template and its variables. [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). @@ -1668,6 +1700,7 @@ async def create( *, stream: Literal[True], background: Optional[bool] | NotGiven = NOT_GIVEN, + conversation: Optional[response_create_params.Conversation] | NotGiven = NOT_GIVEN, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, @@ -1724,6 +1757,11 @@ async def create( background: Whether to run the model response in the background. [Learn more](https://platform.openai.com/docs/guides/background). + conversation: The conversation that this response belongs to. Items from this conversation are + prepended to `input_items` for this response request. Input items and output + items from this response are automatically added to this conversation after this + response completes. + include: Specify additional output data to include in the model response. Currently supported values are: @@ -1784,6 +1822,7 @@ async def create( previous_response_id: The unique ID of the previous response to the model. Use this to create multi-turn conversations. Learn more about [conversation state](https://platform.openai.com/docs/guides/conversation-state). + Cannot be used in conjunction with `conversation`. prompt: Reference to a prompt template and its variables. [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). @@ -1895,6 +1934,7 @@ async def create( *, stream: bool, background: Optional[bool] | NotGiven = NOT_GIVEN, + conversation: Optional[response_create_params.Conversation] | NotGiven = NOT_GIVEN, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, @@ -1951,6 +1991,11 @@ async def create( background: Whether to run the model response in the background. [Learn more](https://platform.openai.com/docs/guides/background). + conversation: The conversation that this response belongs to. Items from this conversation are + prepended to `input_items` for this response request. Input items and output + items from this response are automatically added to this conversation after this + response completes. + include: Specify additional output data to include in the model response. Currently supported values are: @@ -2011,6 +2056,7 @@ async def create( previous_response_id: The unique ID of the previous response to the model. Use this to create multi-turn conversations. Learn more about [conversation state](https://platform.openai.com/docs/guides/conversation-state). + Cannot be used in conjunction with `conversation`. prompt: Reference to a prompt template and its variables. [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). @@ -2120,6 +2166,7 @@ async def create( self, *, background: Optional[bool] | NotGiven = NOT_GIVEN, + conversation: Optional[response_create_params.Conversation] | NotGiven = NOT_GIVEN, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, @@ -2157,6 +2204,7 @@ async def create( body=await async_maybe_transform( { "background": background, + "conversation": conversation, "include": include, "input": input, "instructions": instructions, @@ -2229,7 +2277,7 @@ def stream( store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam| NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, @@ -2261,7 +2309,7 @@ def stream( store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam| NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, @@ -2376,6 +2424,7 @@ async def parse( *, text_format: type[TextFormatT] | NotGiven = NOT_GIVEN, background: Optional[bool] | NotGiven = NOT_GIVEN, + conversation: Optional[response_create_params.Conversation] | NotGiven = NOT_GIVEN, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, @@ -2394,7 +2443,7 @@ async def parse( stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam| NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -2432,6 +2481,7 @@ def parser(raw_response: Response) -> ParsedResponse[TextFormatT]: body=maybe_transform( { "background": background, + "conversation": conversation, "include": include, "input": input, "instructions": instructions, diff --git a/src/openai/types/conversations/__init__.py b/src/openai/types/conversations/__init__.py new file mode 100644 index 0000000000..538966db4f --- /dev/null +++ b/src/openai/types/conversations/__init__.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .message import Message as Message +from .lob_prob import LobProb as LobProb +from .conversation import Conversation as Conversation +from .text_content import TextContent as TextContent +from .top_log_prob import TopLogProb as TopLogProb +from .refusal_content import RefusalContent as RefusalContent +from .item_list_params import ItemListParams as ItemListParams +from .conversation_item import ConversationItem as ConversationItem +from .url_citation_body import URLCitationBody as URLCitationBody +from .file_citation_body import FileCitationBody as FileCitationBody +from .input_file_content import InputFileContent as InputFileContent +from .input_text_content import InputTextContent as InputTextContent +from .item_create_params import ItemCreateParams as ItemCreateParams +from .input_image_content import InputImageContent as InputImageContent +from .output_text_content import OutputTextContent as OutputTextContent +from .item_retrieve_params import ItemRetrieveParams as ItemRetrieveParams +from .summary_text_content import SummaryTextContent as SummaryTextContent +from .conversation_item_list import ConversationItemList as ConversationItemList +from .conversation_create_params import ConversationCreateParams as ConversationCreateParams +from .conversation_update_params import ConversationUpdateParams as ConversationUpdateParams +from .computer_screenshot_content import ComputerScreenshotContent as ComputerScreenshotContent +from .container_file_citation_body import ContainerFileCitationBody as ContainerFileCitationBody +from .conversation_deleted_resource import ConversationDeletedResource as ConversationDeletedResource diff --git a/src/openai/types/conversations/computer_screenshot_content.py b/src/openai/types/conversations/computer_screenshot_content.py new file mode 100644 index 0000000000..897b7ada0d --- /dev/null +++ b/src/openai/types/conversations/computer_screenshot_content.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ComputerScreenshotContent"] + + +class ComputerScreenshotContent(BaseModel): + file_id: Optional[str] = None + """The identifier of an uploaded file that contains the screenshot.""" + + image_url: Optional[str] = None + """The URL of the screenshot image.""" + + type: Literal["computer_screenshot"] + """Specifies the event type. + + For a computer screenshot, this property is always set to `computer_screenshot`. + """ diff --git a/src/openai/types/conversations/container_file_citation_body.py b/src/openai/types/conversations/container_file_citation_body.py new file mode 100644 index 0000000000..ea460df2e2 --- /dev/null +++ b/src/openai/types/conversations/container_file_citation_body.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ContainerFileCitationBody"] + + +class ContainerFileCitationBody(BaseModel): + container_id: str + """The ID of the container file.""" + + end_index: int + """The index of the last character of the container file citation in the message.""" + + file_id: str + """The ID of the file.""" + + filename: str + """The filename of the container file cited.""" + + start_index: int + """The index of the first character of the container file citation in the message.""" + + type: Literal["container_file_citation"] + """The type of the container file citation. Always `container_file_citation`.""" diff --git a/src/openai/types/conversations/conversation.py b/src/openai/types/conversations/conversation.py new file mode 100644 index 0000000000..ed63d40355 --- /dev/null +++ b/src/openai/types/conversations/conversation.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["Conversation"] + + +class Conversation(BaseModel): + id: str + """The unique ID of the conversation.""" + + created_at: int + """ + The time at which the conversation was created, measured in seconds since the + Unix epoch. + """ + + metadata: object + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. Keys are + strings with a maximum length of 64 characters. Values are strings with a + maximum length of 512 characters. + """ + + object: Literal["conversation"] + """The object type, which is always `conversation`.""" diff --git a/src/openai/types/conversations/conversation_create_params.py b/src/openai/types/conversations/conversation_create_params.py new file mode 100644 index 0000000000..7ad3f8ae2d --- /dev/null +++ b/src/openai/types/conversations/conversation_create_params.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import TypedDict + +from ..shared_params.metadata import Metadata +from ..responses.response_input_item_param import ResponseInputItemParam + +__all__ = ["ConversationCreateParams"] + + +class ConversationCreateParams(TypedDict, total=False): + items: Optional[Iterable[ResponseInputItemParam]] + """ + Initial items to include in the conversation context. You may add up to 20 items + at a time. + """ + + metadata: Optional[Metadata] + """Set of 16 key-value pairs that can be attached to an object. + + Useful for storing additional information about the object in a structured + format. + """ diff --git a/src/openai/types/conversations/conversation_deleted_resource.py b/src/openai/types/conversations/conversation_deleted_resource.py new file mode 100644 index 0000000000..7abcb2448e --- /dev/null +++ b/src/openai/types/conversations/conversation_deleted_resource.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ConversationDeletedResource"] + + +class ConversationDeletedResource(BaseModel): + id: str + + deleted: bool + + object: Literal["conversation.deleted"] diff --git a/src/openai/types/conversations/conversation_item.py b/src/openai/types/conversations/conversation_item.py new file mode 100644 index 0000000000..a7cd355f36 --- /dev/null +++ b/src/openai/types/conversations/conversation_item.py @@ -0,0 +1,209 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from .message import Message +from ..._utils import PropertyInfo +from ..._models import BaseModel +from ..responses.response_reasoning_item import ResponseReasoningItem +from ..responses.response_custom_tool_call import ResponseCustomToolCall +from ..responses.response_computer_tool_call import ResponseComputerToolCall +from ..responses.response_function_web_search import ResponseFunctionWebSearch +from ..responses.response_file_search_tool_call import ResponseFileSearchToolCall +from ..responses.response_custom_tool_call_output import ResponseCustomToolCallOutput +from ..responses.response_function_tool_call_item import ResponseFunctionToolCallItem +from ..responses.response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall +from ..responses.response_computer_tool_call_output_item import ResponseComputerToolCallOutputItem +from ..responses.response_function_tool_call_output_item import ResponseFunctionToolCallOutputItem + +__all__ = [ + "ConversationItem", + "ImageGenerationCall", + "LocalShellCall", + "LocalShellCallAction", + "LocalShellCallOutput", + "McpListTools", + "McpListToolsTool", + "McpApprovalRequest", + "McpApprovalResponse", + "McpCall", +] + + +class ImageGenerationCall(BaseModel): + id: str + """The unique ID of the image generation call.""" + + result: Optional[str] = None + """The generated image encoded in base64.""" + + status: Literal["in_progress", "completed", "generating", "failed"] + """The status of the image generation call.""" + + type: Literal["image_generation_call"] + """The type of the image generation call. Always `image_generation_call`.""" + + +class LocalShellCallAction(BaseModel): + command: List[str] + """The command to run.""" + + env: Dict[str, str] + """Environment variables to set for the command.""" + + type: Literal["exec"] + """The type of the local shell action. Always `exec`.""" + + timeout_ms: Optional[int] = None + """Optional timeout in milliseconds for the command.""" + + user: Optional[str] = None + """Optional user to run the command as.""" + + working_directory: Optional[str] = None + """Optional working directory to run the command in.""" + + +class LocalShellCall(BaseModel): + id: str + """The unique ID of the local shell call.""" + + action: LocalShellCallAction + """Execute a shell command on the server.""" + + call_id: str + """The unique ID of the local shell tool call generated by the model.""" + + status: Literal["in_progress", "completed", "incomplete"] + """The status of the local shell call.""" + + type: Literal["local_shell_call"] + """The type of the local shell call. Always `local_shell_call`.""" + + +class LocalShellCallOutput(BaseModel): + id: str + """The unique ID of the local shell tool call generated by the model.""" + + output: str + """A JSON string of the output of the local shell tool call.""" + + type: Literal["local_shell_call_output"] + """The type of the local shell tool call output. Always `local_shell_call_output`.""" + + status: Optional[Literal["in_progress", "completed", "incomplete"]] = None + """The status of the item. One of `in_progress`, `completed`, or `incomplete`.""" + + +class McpListToolsTool(BaseModel): + input_schema: object + """The JSON schema describing the tool's input.""" + + name: str + """The name of the tool.""" + + annotations: Optional[object] = None + """Additional annotations about the tool.""" + + description: Optional[str] = None + """The description of the tool.""" + + +class McpListTools(BaseModel): + id: str + """The unique ID of the list.""" + + server_label: str + """The label of the MCP server.""" + + tools: List[McpListToolsTool] + """The tools available on the server.""" + + type: Literal["mcp_list_tools"] + """The type of the item. Always `mcp_list_tools`.""" + + error: Optional[str] = None + """Error message if the server could not list tools.""" + + +class McpApprovalRequest(BaseModel): + id: str + """The unique ID of the approval request.""" + + arguments: str + """A JSON string of arguments for the tool.""" + + name: str + """The name of the tool to run.""" + + server_label: str + """The label of the MCP server making the request.""" + + type: Literal["mcp_approval_request"] + """The type of the item. Always `mcp_approval_request`.""" + + +class McpApprovalResponse(BaseModel): + id: str + """The unique ID of the approval response""" + + approval_request_id: str + """The ID of the approval request being answered.""" + + approve: bool + """Whether the request was approved.""" + + type: Literal["mcp_approval_response"] + """The type of the item. Always `mcp_approval_response`.""" + + reason: Optional[str] = None + """Optional reason for the decision.""" + + +class McpCall(BaseModel): + id: str + """The unique ID of the tool call.""" + + arguments: str + """A JSON string of the arguments passed to the tool.""" + + name: str + """The name of the tool that was run.""" + + server_label: str + """The label of the MCP server running the tool.""" + + type: Literal["mcp_call"] + """The type of the item. Always `mcp_call`.""" + + error: Optional[str] = None + """The error from the tool call, if any.""" + + output: Optional[str] = None + """The output from the tool call.""" + + +ConversationItem: TypeAlias = Annotated[ + Union[ + Message, + ResponseFunctionToolCallItem, + ResponseFunctionToolCallOutputItem, + ResponseFileSearchToolCall, + ResponseFunctionWebSearch, + ImageGenerationCall, + ResponseComputerToolCall, + ResponseComputerToolCallOutputItem, + ResponseReasoningItem, + ResponseCodeInterpreterToolCall, + LocalShellCall, + LocalShellCallOutput, + McpListTools, + McpApprovalRequest, + McpApprovalResponse, + McpCall, + ResponseCustomToolCall, + ResponseCustomToolCallOutput, + ], + PropertyInfo(discriminator="type"), +] diff --git a/src/openai/types/conversations/conversation_item_list.py b/src/openai/types/conversations/conversation_item_list.py new file mode 100644 index 0000000000..20091102cb --- /dev/null +++ b/src/openai/types/conversations/conversation_item_list.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import Literal + +from ..._models import BaseModel +from .conversation_item import ConversationItem + +__all__ = ["ConversationItemList"] + + +class ConversationItemList(BaseModel): + data: List[ConversationItem] + """A list of conversation items.""" + + first_id: str + """The ID of the first item in the list.""" + + has_more: bool + """Whether there are more items available.""" + + last_id: str + """The ID of the last item in the list.""" + + object: Literal["list"] + """The type of object returned, must be `list`.""" diff --git a/src/openai/types/conversations/conversation_update_params.py b/src/openai/types/conversations/conversation_update_params.py new file mode 100644 index 0000000000..f2aa42d833 --- /dev/null +++ b/src/openai/types/conversations/conversation_update_params.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict +from typing_extensions import Required, TypedDict + +__all__ = ["ConversationUpdateParams"] + + +class ConversationUpdateParams(TypedDict, total=False): + metadata: Required[Dict[str, str]] + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. Keys are + strings with a maximum length of 64 characters. Values are strings with a + maximum length of 512 characters. + """ diff --git a/src/openai/types/conversations/file_citation_body.py b/src/openai/types/conversations/file_citation_body.py new file mode 100644 index 0000000000..ea90ae381d --- /dev/null +++ b/src/openai/types/conversations/file_citation_body.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["FileCitationBody"] + + +class FileCitationBody(BaseModel): + file_id: str + """The ID of the file.""" + + filename: str + """The filename of the file cited.""" + + index: int + """The index of the file in the list of files.""" + + type: Literal["file_citation"] + """The type of the file citation. Always `file_citation`.""" diff --git a/src/openai/types/conversations/input_file_content.py b/src/openai/types/conversations/input_file_content.py new file mode 100644 index 0000000000..6aef7a89d9 --- /dev/null +++ b/src/openai/types/conversations/input_file_content.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["InputFileContent"] + + +class InputFileContent(BaseModel): + file_id: Optional[str] = None + """The ID of the file to be sent to the model.""" + + type: Literal["input_file"] + """The type of the input item. Always `input_file`.""" + + file_url: Optional[str] = None + """The URL of the file to be sent to the model.""" + + filename: Optional[str] = None + """The name of the file to be sent to the model.""" diff --git a/src/openai/types/conversations/input_image_content.py b/src/openai/types/conversations/input_image_content.py new file mode 100644 index 0000000000..f2587e0adc --- /dev/null +++ b/src/openai/types/conversations/input_image_content.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["InputImageContent"] + + +class InputImageContent(BaseModel): + detail: Literal["low", "high", "auto"] + """The detail level of the image to be sent to the model. + + One of `high`, `low`, or `auto`. Defaults to `auto`. + """ + + file_id: Optional[str] = None + """The ID of the file to be sent to the model.""" + + image_url: Optional[str] = None + """The URL of the image to be sent to the model. + + A fully qualified URL or base64 encoded image in a data URL. + """ + + type: Literal["input_image"] + """The type of the input item. Always `input_image`.""" diff --git a/src/openai/types/conversations/input_text_content.py b/src/openai/types/conversations/input_text_content.py new file mode 100644 index 0000000000..5e2daebdc5 --- /dev/null +++ b/src/openai/types/conversations/input_text_content.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["InputTextContent"] + + +class InputTextContent(BaseModel): + text: str + """The text input to the model.""" + + type: Literal["input_text"] + """The type of the input item. Always `input_text`.""" diff --git a/src/openai/types/conversations/item_create_params.py b/src/openai/types/conversations/item_create_params.py new file mode 100644 index 0000000000..9158b7167f --- /dev/null +++ b/src/openai/types/conversations/item_create_params.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Iterable +from typing_extensions import Required, TypedDict + +from ..responses.response_includable import ResponseIncludable +from ..responses.response_input_item_param import ResponseInputItemParam + +__all__ = ["ItemCreateParams"] + + +class ItemCreateParams(TypedDict, total=False): + items: Required[Iterable[ResponseInputItemParam]] + """The items to add to the conversation. You may add up to 20 items at a time.""" + + include: List[ResponseIncludable] + """Additional fields to include in the response. + + See the `include` parameter for + [listing Conversation items above](https://platform.openai.com/docs/api-reference/conversations/list-items#conversations_list_items-include) + for more information. + """ diff --git a/src/openai/types/conversations/item_list_params.py b/src/openai/types/conversations/item_list_params.py new file mode 100644 index 0000000000..34bf43c559 --- /dev/null +++ b/src/openai/types/conversations/item_list_params.py @@ -0,0 +1,48 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Literal, TypedDict + +from ..responses.response_includable import ResponseIncludable + +__all__ = ["ItemListParams"] + + +class ItemListParams(TypedDict, total=False): + after: str + """An item ID to list items after, used in pagination.""" + + include: List[ResponseIncludable] + """Specify additional output data to include in the model response. + + Currently supported values are: + + - `code_interpreter_call.outputs`: Includes the outputs of python code execution + in code interpreter tool call items. + - `computer_call_output.output.image_url`: Include image urls from the computer + call output. + - `file_search_call.results`: Include the search results of the file search tool + call. + - `message.input_image.image_url`: Include image urls from the input message. + - `message.output_text.logprobs`: Include logprobs with assistant messages. + - `reasoning.encrypted_content`: Includes an encrypted version of reasoning + tokens in reasoning item outputs. This enables reasoning items to be used in + multi-turn conversations when using the Responses API statelessly (like when + the `store` parameter is set to `false`, or when an organization is enrolled + in the zero data retention program). + """ + + limit: int + """A limit on the number of objects to be returned. + + Limit can range between 1 and 100, and the default is 20. + """ + + order: Literal["asc", "desc"] + """The order to return the input items in. Default is `desc`. + + - `asc`: Return the input items in ascending order. + - `desc`: Return the input items in descending order. + """ diff --git a/src/openai/types/conversations/item_retrieve_params.py b/src/openai/types/conversations/item_retrieve_params.py new file mode 100644 index 0000000000..8c5db1e533 --- /dev/null +++ b/src/openai/types/conversations/item_retrieve_params.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Required, TypedDict + +from ..responses.response_includable import ResponseIncludable + +__all__ = ["ItemRetrieveParams"] + + +class ItemRetrieveParams(TypedDict, total=False): + conversation_id: Required[str] + + include: List[ResponseIncludable] + """Additional fields to include in the response. + + See the `include` parameter for + [listing Conversation items above](https://platform.openai.com/docs/api-reference/conversations/list-items#conversations_list_items-include) + for more information. + """ diff --git a/src/openai/types/conversations/lob_prob.py b/src/openai/types/conversations/lob_prob.py new file mode 100644 index 0000000000..f7dcd62a5e --- /dev/null +++ b/src/openai/types/conversations/lob_prob.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel +from .top_log_prob import TopLogProb + +__all__ = ["LobProb"] + + +class LobProb(BaseModel): + token: str + + bytes: List[int] + + logprob: float + + top_logprobs: List[TopLogProb] diff --git a/src/openai/types/conversations/message.py b/src/openai/types/conversations/message.py new file mode 100644 index 0000000000..a070cf2869 --- /dev/null +++ b/src/openai/types/conversations/message.py @@ -0,0 +1,56 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .text_content import TextContent +from .refusal_content import RefusalContent +from .input_file_content import InputFileContent +from .input_text_content import InputTextContent +from .input_image_content import InputImageContent +from .output_text_content import OutputTextContent +from .summary_text_content import SummaryTextContent +from .computer_screenshot_content import ComputerScreenshotContent + +__all__ = ["Message", "Content"] + +Content: TypeAlias = Annotated[ + Union[ + InputTextContent, + OutputTextContent, + TextContent, + SummaryTextContent, + RefusalContent, + InputImageContent, + ComputerScreenshotContent, + InputFileContent, + ], + PropertyInfo(discriminator="type"), +] + + +class Message(BaseModel): + id: str + """The unique ID of the message.""" + + content: List[Content] + """The content of the message""" + + role: Literal["unknown", "user", "assistant", "system", "critic", "discriminator", "developer", "tool"] + """The role of the message. + + One of `unknown`, `user`, `assistant`, `system`, `critic`, `discriminator`, + `developer`, or `tool`. + """ + + status: Literal["in_progress", "completed", "incomplete"] + """The status of item. + + One of `in_progress`, `completed`, or `incomplete`. Populated when items are + returned via API. + """ + + type: Literal["message"] + """The type of the message. Always set to `message`.""" diff --git a/src/openai/types/conversations/output_text_content.py b/src/openai/types/conversations/output_text_content.py new file mode 100644 index 0000000000..2ffee76526 --- /dev/null +++ b/src/openai/types/conversations/output_text_content.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from .lob_prob import LobProb +from ..._models import BaseModel +from .url_citation_body import URLCitationBody +from .file_citation_body import FileCitationBody +from .container_file_citation_body import ContainerFileCitationBody + +__all__ = ["OutputTextContent", "Annotation"] + +Annotation: TypeAlias = Annotated[ + Union[FileCitationBody, URLCitationBody, ContainerFileCitationBody], PropertyInfo(discriminator="type") +] + + +class OutputTextContent(BaseModel): + annotations: List[Annotation] + """The annotations of the text output.""" + + text: str + """The text output from the model.""" + + type: Literal["output_text"] + """The type of the output text. Always `output_text`.""" + + logprobs: Optional[List[LobProb]] = None diff --git a/src/openai/types/conversations/refusal_content.py b/src/openai/types/conversations/refusal_content.py new file mode 100644 index 0000000000..3c8bd5e35f --- /dev/null +++ b/src/openai/types/conversations/refusal_content.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["RefusalContent"] + + +class RefusalContent(BaseModel): + refusal: str + """The refusal explanation from the model.""" + + type: Literal["refusal"] + """The type of the refusal. Always `refusal`.""" diff --git a/src/openai/types/conversations/summary_text_content.py b/src/openai/types/conversations/summary_text_content.py new file mode 100644 index 0000000000..047769ed67 --- /dev/null +++ b/src/openai/types/conversations/summary_text_content.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["SummaryTextContent"] + + +class SummaryTextContent(BaseModel): + text: str + + type: Literal["summary_text"] diff --git a/src/openai/types/conversations/text_content.py b/src/openai/types/conversations/text_content.py new file mode 100644 index 0000000000..f1ae079597 --- /dev/null +++ b/src/openai/types/conversations/text_content.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["TextContent"] + + +class TextContent(BaseModel): + text: str + + type: Literal["text"] diff --git a/src/openai/types/conversations/top_log_prob.py b/src/openai/types/conversations/top_log_prob.py new file mode 100644 index 0000000000..fafca756ae --- /dev/null +++ b/src/openai/types/conversations/top_log_prob.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel + +__all__ = ["TopLogProb"] + + +class TopLogProb(BaseModel): + token: str + + bytes: List[int] + + logprob: float diff --git a/src/openai/types/conversations/url_citation_body.py b/src/openai/types/conversations/url_citation_body.py new file mode 100644 index 0000000000..1becb44bc0 --- /dev/null +++ b/src/openai/types/conversations/url_citation_body.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["URLCitationBody"] + + +class URLCitationBody(BaseModel): + end_index: int + """The index of the last character of the URL citation in the message.""" + + start_index: int + """The index of the first character of the URL citation in the message.""" + + title: str + """The title of the web resource.""" + + type: Literal["url_citation"] + """The type of the URL citation. Always `url_citation`.""" + + url: str + """The URL of the web resource.""" diff --git a/src/openai/types/evals/create_eval_completions_run_data_source.py b/src/openai/types/evals/create_eval_completions_run_data_source.py index bb39d1d3e5..efcab9adb8 100644 --- a/src/openai/types/evals/create_eval_completions_run_data_source.py +++ b/src/openai/types/evals/create_eval_completions_run_data_source.py @@ -23,10 +23,10 @@ "InputMessages", "InputMessagesTemplate", "InputMessagesTemplateTemplate", - "InputMessagesTemplateTemplateMessage", - "InputMessagesTemplateTemplateMessageContent", - "InputMessagesTemplateTemplateMessageContentOutputText", - "InputMessagesTemplateTemplateMessageContentInputImage", + "InputMessagesTemplateTemplateEvalItem", + "InputMessagesTemplateTemplateEvalItemContent", + "InputMessagesTemplateTemplateEvalItemContentOutputText", + "InputMessagesTemplateTemplateEvalItemContentInputImage", "InputMessagesItemReference", "SamplingParams", "SamplingParamsResponseFormat", @@ -87,7 +87,7 @@ class SourceStoredCompletions(BaseModel): ] -class InputMessagesTemplateTemplateMessageContentOutputText(BaseModel): +class InputMessagesTemplateTemplateEvalItemContentOutputText(BaseModel): text: str """The text output from the model.""" @@ -95,7 +95,7 @@ class InputMessagesTemplateTemplateMessageContentOutputText(BaseModel): """The type of the output text. Always `output_text`.""" -class InputMessagesTemplateTemplateMessageContentInputImage(BaseModel): +class InputMessagesTemplateTemplateEvalItemContentInputImage(BaseModel): image_url: str """The URL of the image input.""" @@ -109,17 +109,17 @@ class InputMessagesTemplateTemplateMessageContentInputImage(BaseModel): """ -InputMessagesTemplateTemplateMessageContent: TypeAlias = Union[ +InputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ str, ResponseInputText, - InputMessagesTemplateTemplateMessageContentOutputText, - InputMessagesTemplateTemplateMessageContentInputImage, + InputMessagesTemplateTemplateEvalItemContentOutputText, + InputMessagesTemplateTemplateEvalItemContentInputImage, List[object], ] -class InputMessagesTemplateTemplateMessage(BaseModel): - content: InputMessagesTemplateTemplateMessageContent +class InputMessagesTemplateTemplateEvalItem(BaseModel): + content: InputMessagesTemplateTemplateEvalItemContent """Inputs to the model - can contain template strings.""" role: Literal["user", "assistant", "system", "developer"] @@ -132,9 +132,7 @@ class InputMessagesTemplateTemplateMessage(BaseModel): """The type of the message input. Always `message`.""" -InputMessagesTemplateTemplate: TypeAlias = Annotated[ - Union[EasyInputMessage, InputMessagesTemplateTemplateMessage], PropertyInfo(discriminator="type") -] +InputMessagesTemplateTemplate: TypeAlias = Union[EasyInputMessage, InputMessagesTemplateTemplateEvalItem] class InputMessagesTemplate(BaseModel): diff --git a/src/openai/types/evals/create_eval_completions_run_data_source_param.py b/src/openai/types/evals/create_eval_completions_run_data_source_param.py index 7c71ecbe88..effa658452 100644 --- a/src/openai/types/evals/create_eval_completions_run_data_source_param.py +++ b/src/openai/types/evals/create_eval_completions_run_data_source_param.py @@ -23,10 +23,10 @@ "InputMessages", "InputMessagesTemplate", "InputMessagesTemplateTemplate", - "InputMessagesTemplateTemplateMessage", - "InputMessagesTemplateTemplateMessageContent", - "InputMessagesTemplateTemplateMessageContentOutputText", - "InputMessagesTemplateTemplateMessageContentInputImage", + "InputMessagesTemplateTemplateEvalItem", + "InputMessagesTemplateTemplateEvalItemContent", + "InputMessagesTemplateTemplateEvalItemContentOutputText", + "InputMessagesTemplateTemplateEvalItemContentInputImage", "InputMessagesItemReference", "SamplingParams", "SamplingParamsResponseFormat", @@ -85,7 +85,7 @@ class SourceStoredCompletions(TypedDict, total=False): Source: TypeAlias = Union[SourceFileContent, SourceFileID, SourceStoredCompletions] -class InputMessagesTemplateTemplateMessageContentOutputText(TypedDict, total=False): +class InputMessagesTemplateTemplateEvalItemContentOutputText(TypedDict, total=False): text: Required[str] """The text output from the model.""" @@ -93,7 +93,7 @@ class InputMessagesTemplateTemplateMessageContentOutputText(TypedDict, total=Fal """The type of the output text. Always `output_text`.""" -class InputMessagesTemplateTemplateMessageContentInputImage(TypedDict, total=False): +class InputMessagesTemplateTemplateEvalItemContentInputImage(TypedDict, total=False): image_url: Required[str] """The URL of the image input.""" @@ -107,17 +107,17 @@ class InputMessagesTemplateTemplateMessageContentInputImage(TypedDict, total=Fal """ -InputMessagesTemplateTemplateMessageContent: TypeAlias = Union[ +InputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ str, ResponseInputTextParam, - InputMessagesTemplateTemplateMessageContentOutputText, - InputMessagesTemplateTemplateMessageContentInputImage, + InputMessagesTemplateTemplateEvalItemContentOutputText, + InputMessagesTemplateTemplateEvalItemContentInputImage, Iterable[object], ] -class InputMessagesTemplateTemplateMessage(TypedDict, total=False): - content: Required[InputMessagesTemplateTemplateMessageContent] +class InputMessagesTemplateTemplateEvalItem(TypedDict, total=False): + content: Required[InputMessagesTemplateTemplateEvalItemContent] """Inputs to the model - can contain template strings.""" role: Required[Literal["user", "assistant", "system", "developer"]] @@ -130,7 +130,7 @@ class InputMessagesTemplateTemplateMessage(TypedDict, total=False): """The type of the message input. Always `message`.""" -InputMessagesTemplateTemplate: TypeAlias = Union[EasyInputMessageParam, InputMessagesTemplateTemplateMessage] +InputMessagesTemplateTemplate: TypeAlias = Union[EasyInputMessageParam, InputMessagesTemplateTemplateEvalItem] class InputMessagesTemplate(TypedDict, total=False): diff --git a/src/openai/types/responses/__init__.py b/src/openai/types/responses/__init__.py index 74d8688081..7c574ed315 100644 --- a/src/openai/types/responses/__init__.py +++ b/src/openai/types/responses/__init__.py @@ -79,6 +79,7 @@ from .response_text_config_param import ResponseTextConfigParam as ResponseTextConfigParam from .tool_choice_function_param import ToolChoiceFunctionParam as ToolChoiceFunctionParam from .response_computer_tool_call import ResponseComputerToolCall as ResponseComputerToolCall +from .response_conversation_param import ResponseConversationParam as ResponseConversationParam from .response_format_text_config import ResponseFormatTextConfig as ResponseFormatTextConfig from .response_function_tool_call import ResponseFunctionToolCall as ResponseFunctionToolCall from .response_input_message_item import ResponseInputMessageItem as ResponseInputMessageItem diff --git a/src/openai/types/responses/input_item_list_params.py b/src/openai/types/responses/input_item_list_params.py index 6a18d920cb..44a8dc5de3 100644 --- a/src/openai/types/responses/input_item_list_params.py +++ b/src/openai/types/responses/input_item_list_params.py @@ -14,9 +14,6 @@ class InputItemListParams(TypedDict, total=False): after: str """An item ID to list items after, used in pagination.""" - before: str - """An item ID to list items before, used in pagination.""" - include: List[ResponseIncludable] """Additional fields to include in the response. diff --git a/src/openai/types/responses/response.py b/src/openai/types/responses/response.py index 49f60bbc5c..ce9effd75e 100644 --- a/src/openai/types/responses/response.py +++ b/src/openai/types/responses/response.py @@ -22,7 +22,7 @@ from .tool_choice_function import ToolChoiceFunction from ..shared.responses_model import ResponsesModel -__all__ = ["Response", "IncompleteDetails", "ToolChoice"] +__all__ = ["Response", "IncompleteDetails", "ToolChoice", "Conversation"] class IncompleteDetails(BaseModel): @@ -35,6 +35,11 @@ class IncompleteDetails(BaseModel): ] +class Conversation(BaseModel): + id: str + """The unique ID of the conversation.""" + + class Response(BaseModel): id: str """Unique identifier for this Response.""" @@ -141,6 +146,13 @@ class Response(BaseModel): [Learn more](https://platform.openai.com/docs/guides/background). """ + conversation: Optional[Conversation] = None + """The conversation that this response belongs to. + + Input items and output items from this response are automatically added to this + conversation. + """ + max_output_tokens: Optional[int] = None """ An upper bound for the number of tokens that can be generated for a response, @@ -161,6 +173,7 @@ class Response(BaseModel): Use this to create multi-turn conversations. Learn more about [conversation state](https://platform.openai.com/docs/guides/conversation-state). + Cannot be used in conjunction with `conversation`. """ prompt: Optional[ResponsePrompt] = None diff --git a/src/openai/types/responses/response_conversation_param.py b/src/openai/types/responses/response_conversation_param.py new file mode 100644 index 0000000000..067bdc7a31 --- /dev/null +++ b/src/openai/types/responses/response_conversation_param.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["ResponseConversationParam"] + + +class ResponseConversationParam(TypedDict, total=False): + id: Required[str] + """The unique ID of the conversation.""" diff --git a/src/openai/types/responses/response_create_params.py b/src/openai/types/responses/response_create_params.py index 0cd761fcf0..5129b8b771 100644 --- a/src/openai/types/responses/response_create_params.py +++ b/src/openai/types/responses/response_create_params.py @@ -18,10 +18,12 @@ from .tool_choice_allowed_param import ToolChoiceAllowedParam from .response_text_config_param import ResponseTextConfigParam from .tool_choice_function_param import ToolChoiceFunctionParam +from .response_conversation_param import ResponseConversationParam from ..shared_params.responses_model import ResponsesModel __all__ = [ "ResponseCreateParamsBase", + "Conversation", "StreamOptions", "ToolChoice", "ResponseCreateParamsNonStreaming", @@ -36,6 +38,14 @@ class ResponseCreateParamsBase(TypedDict, total=False): [Learn more](https://platform.openai.com/docs/guides/background). """ + conversation: Optional[Conversation] + """The conversation that this response belongs to. + + Items from this conversation are prepended to `input_items` for this response + request. Input items and output items from this response are automatically added + to this conversation after this response completes. + """ + include: Optional[List[ResponseIncludable]] """Specify additional output data to include in the model response. @@ -118,6 +128,7 @@ class ResponseCreateParamsBase(TypedDict, total=False): Use this to create multi-turn conversations. Learn more about [conversation state](https://platform.openai.com/docs/guides/conversation-state). + Cannot be used in conjunction with `conversation`. """ prompt: Optional[ResponsePromptParam] @@ -253,6 +264,9 @@ class ResponseCreateParamsBase(TypedDict, total=False): """ +Conversation: TypeAlias = Union[str, ResponseConversationParam] + + class StreamOptions(TypedDict, total=False): include_obfuscation: bool """When true, stream obfuscation will be enabled. diff --git a/src/openai/types/responses/tool.py b/src/openai/types/responses/tool.py index 455ba01666..d46f8cb0be 100644 --- a/src/openai/types/responses/tool.py +++ b/src/openai/types/responses/tool.py @@ -15,7 +15,7 @@ "Tool", "Mcp", "McpAllowedTools", - "McpAllowedToolsMcpAllowedToolsFilter", + "McpAllowedToolsMcpToolFilter", "McpRequireApproval", "McpRequireApprovalMcpToolApprovalFilter", "McpRequireApprovalMcpToolApprovalFilterAlways", @@ -29,30 +29,54 @@ ] -class McpAllowedToolsMcpAllowedToolsFilter(BaseModel): +class McpAllowedToolsMcpToolFilter(BaseModel): + read_only: Optional[bool] = None + """Indicates whether or not a tool modifies data or is read-only. + + If an MCP server is + [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), + it will match this filter. + """ + tool_names: Optional[List[str]] = None """List of allowed tool names.""" -McpAllowedTools: TypeAlias = Union[List[str], McpAllowedToolsMcpAllowedToolsFilter, None] +McpAllowedTools: TypeAlias = Union[List[str], McpAllowedToolsMcpToolFilter, None] class McpRequireApprovalMcpToolApprovalFilterAlways(BaseModel): + read_only: Optional[bool] = None + """Indicates whether or not a tool modifies data or is read-only. + + If an MCP server is + [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), + it will match this filter. + """ + tool_names: Optional[List[str]] = None - """List of tools that require approval.""" + """List of allowed tool names.""" class McpRequireApprovalMcpToolApprovalFilterNever(BaseModel): + read_only: Optional[bool] = None + """Indicates whether or not a tool modifies data or is read-only. + + If an MCP server is + [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), + it will match this filter. + """ + tool_names: Optional[List[str]] = None - """List of tools that do not require approval.""" + """List of allowed tool names.""" class McpRequireApprovalMcpToolApprovalFilter(BaseModel): always: Optional[McpRequireApprovalMcpToolApprovalFilterAlways] = None - """A list of tools that always require approval.""" + """A filter object to specify which tools are allowed.""" never: Optional[McpRequireApprovalMcpToolApprovalFilterNever] = None - """A list of tools that never require approval.""" + """A filter object to specify which tools are allowed.""" McpRequireApproval: TypeAlias = Union[McpRequireApprovalMcpToolApprovalFilter, Literal["always", "never"], None] @@ -62,15 +86,49 @@ class Mcp(BaseModel): server_label: str """A label for this MCP server, used to identify it in tool calls.""" - server_url: str - """The URL for the MCP server.""" - type: Literal["mcp"] """The type of the MCP tool. Always `mcp`.""" allowed_tools: Optional[McpAllowedTools] = None """List of allowed tool names or a filter object.""" + authorization: Optional[str] = None + """ + An OAuth access token that can be used with a remote MCP server, either with a + custom MCP server URL or a service connector. Your application must handle the + OAuth authorization flow and provide the token here. + """ + + connector_id: Optional[ + Literal[ + "connector_dropbox", + "connector_gmail", + "connector_googlecalendar", + "connector_googledrive", + "connector_microsoftteams", + "connector_outlookcalendar", + "connector_outlookemail", + "connector_sharepoint", + ] + ] = None + """Identifier for service connectors, like those available in ChatGPT. + + One of `server_url` or `connector_id` must be provided. Learn more about service + connectors + [here](https://platform.openai.com/docs/guides/tools-remote-mcp#connectors). + + Currently supported `connector_id` values are: + + - Dropbox: `connector_dropbox` + - Gmail: `connector_gmail` + - Google Calendar: `connector_googlecalendar` + - Google Drive: `connector_googledrive` + - Microsoft Teams: `connector_microsoftteams` + - Outlook Calendar: `connector_outlookcalendar` + - Outlook Email: `connector_outlookemail` + - SharePoint: `connector_sharepoint` + """ + headers: Optional[Dict[str, str]] = None """Optional HTTP headers to send to the MCP server. @@ -83,6 +141,12 @@ class Mcp(BaseModel): server_description: Optional[str] = None """Optional description of the MCP server, used to provide more context.""" + server_url: Optional[str] = None + """The URL for the MCP server. + + One of `server_url` or `connector_id` must be provided. + """ + class CodeInterpreterContainerCodeInterpreterToolAuto(BaseModel): type: Literal["auto"] diff --git a/src/openai/types/responses/tool_param.py b/src/openai/types/responses/tool_param.py index f91e758559..9dde42e294 100644 --- a/src/openai/types/responses/tool_param.py +++ b/src/openai/types/responses/tool_param.py @@ -16,7 +16,7 @@ "ToolParam", "Mcp", "McpAllowedTools", - "McpAllowedToolsMcpAllowedToolsFilter", + "McpAllowedToolsMcpToolFilter", "McpRequireApproval", "McpRequireApprovalMcpToolApprovalFilter", "McpRequireApprovalMcpToolApprovalFilterAlways", @@ -30,30 +30,54 @@ ] -class McpAllowedToolsMcpAllowedToolsFilter(TypedDict, total=False): +class McpAllowedToolsMcpToolFilter(TypedDict, total=False): + read_only: bool + """Indicates whether or not a tool modifies data or is read-only. + + If an MCP server is + [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), + it will match this filter. + """ + tool_names: List[str] """List of allowed tool names.""" -McpAllowedTools: TypeAlias = Union[List[str], McpAllowedToolsMcpAllowedToolsFilter] +McpAllowedTools: TypeAlias = Union[List[str], McpAllowedToolsMcpToolFilter] class McpRequireApprovalMcpToolApprovalFilterAlways(TypedDict, total=False): + read_only: bool + """Indicates whether or not a tool modifies data or is read-only. + + If an MCP server is + [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), + it will match this filter. + """ + tool_names: List[str] - """List of tools that require approval.""" + """List of allowed tool names.""" class McpRequireApprovalMcpToolApprovalFilterNever(TypedDict, total=False): + read_only: bool + """Indicates whether or not a tool modifies data or is read-only. + + If an MCP server is + [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), + it will match this filter. + """ + tool_names: List[str] - """List of tools that do not require approval.""" + """List of allowed tool names.""" class McpRequireApprovalMcpToolApprovalFilter(TypedDict, total=False): always: McpRequireApprovalMcpToolApprovalFilterAlways - """A list of tools that always require approval.""" + """A filter object to specify which tools are allowed.""" never: McpRequireApprovalMcpToolApprovalFilterNever - """A list of tools that never require approval.""" + """A filter object to specify which tools are allowed.""" McpRequireApproval: TypeAlias = Union[McpRequireApprovalMcpToolApprovalFilter, Literal["always", "never"]] @@ -63,15 +87,47 @@ class Mcp(TypedDict, total=False): server_label: Required[str] """A label for this MCP server, used to identify it in tool calls.""" - server_url: Required[str] - """The URL for the MCP server.""" - type: Required[Literal["mcp"]] """The type of the MCP tool. Always `mcp`.""" allowed_tools: Optional[McpAllowedTools] """List of allowed tool names or a filter object.""" + authorization: str + """ + An OAuth access token that can be used with a remote MCP server, either with a + custom MCP server URL or a service connector. Your application must handle the + OAuth authorization flow and provide the token here. + """ + + connector_id: Literal[ + "connector_dropbox", + "connector_gmail", + "connector_googlecalendar", + "connector_googledrive", + "connector_microsoftteams", + "connector_outlookcalendar", + "connector_outlookemail", + "connector_sharepoint", + ] + """Identifier for service connectors, like those available in ChatGPT. + + One of `server_url` or `connector_id` must be provided. Learn more about service + connectors + [here](https://platform.openai.com/docs/guides/tools-remote-mcp#connectors). + + Currently supported `connector_id` values are: + + - Dropbox: `connector_dropbox` + - Gmail: `connector_gmail` + - Google Calendar: `connector_googlecalendar` + - Google Drive: `connector_googledrive` + - Microsoft Teams: `connector_microsoftteams` + - Outlook Calendar: `connector_outlookcalendar` + - Outlook Email: `connector_outlookemail` + - SharePoint: `connector_sharepoint` + """ + headers: Optional[Dict[str, str]] """Optional HTTP headers to send to the MCP server. @@ -84,6 +140,12 @@ class Mcp(TypedDict, total=False): server_description: str """Optional description of the MCP server, used to provide more context.""" + server_url: str + """The URL for the MCP server. + + One of `server_url` or `connector_id` must be provided. + """ + class CodeInterpreterContainerCodeInterpreterToolAuto(TypedDict, total=False): type: Required[Literal["auto"]] diff --git a/tests/api_resources/conversations/__init__.py b/tests/api_resources/conversations/__init__.py new file mode 100644 index 0000000000..fd8019a9a1 --- /dev/null +++ b/tests/api_resources/conversations/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/conversations/test_items.py b/tests/api_resources/conversations/test_items.py new file mode 100644 index 0000000000..c308160543 --- /dev/null +++ b/tests/api_resources/conversations/test_items.py @@ -0,0 +1,491 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.pagination import SyncConversationCursorPage, AsyncConversationCursorPage +from openai.types.conversations import ( + Conversation, + ConversationItem, + ConversationItemList, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestItems: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: OpenAI) -> None: + item = client.conversations.items.create( + conversation_id="conv_123", + items=[ + { + "content": "string", + "role": "user", + } + ], + ) + assert_matches_type(ConversationItemList, item, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: OpenAI) -> None: + item = client.conversations.items.create( + conversation_id="conv_123", + items=[ + { + "content": "string", + "role": "user", + "type": "message", + } + ], + include=["code_interpreter_call.outputs"], + ) + assert_matches_type(ConversationItemList, item, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: OpenAI) -> None: + response = client.conversations.items.with_raw_response.create( + conversation_id="conv_123", + items=[ + { + "content": "string", + "role": "user", + } + ], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + item = response.parse() + assert_matches_type(ConversationItemList, item, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: OpenAI) -> None: + with client.conversations.items.with_streaming_response.create( + conversation_id="conv_123", + items=[ + { + "content": "string", + "role": "user", + } + ], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + item = response.parse() + assert_matches_type(ConversationItemList, item, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_create(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `conversation_id` but received ''"): + client.conversations.items.with_raw_response.create( + conversation_id="", + items=[ + { + "content": "string", + "role": "user", + } + ], + ) + + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + item = client.conversations.items.retrieve( + item_id="msg_abc", + conversation_id="conv_123", + ) + assert_matches_type(ConversationItem, item, path=["response"]) + + @parametrize + def test_method_retrieve_with_all_params(self, client: OpenAI) -> None: + item = client.conversations.items.retrieve( + item_id="msg_abc", + conversation_id="conv_123", + include=["code_interpreter_call.outputs"], + ) + assert_matches_type(ConversationItem, item, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.conversations.items.with_raw_response.retrieve( + item_id="msg_abc", + conversation_id="conv_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + item = response.parse() + assert_matches_type(ConversationItem, item, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.conversations.items.with_streaming_response.retrieve( + item_id="msg_abc", + conversation_id="conv_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + item = response.parse() + assert_matches_type(ConversationItem, item, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `conversation_id` but received ''"): + client.conversations.items.with_raw_response.retrieve( + item_id="msg_abc", + conversation_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `item_id` but received ''"): + client.conversations.items.with_raw_response.retrieve( + item_id="", + conversation_id="conv_123", + ) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + item = client.conversations.items.list( + conversation_id="conv_123", + ) + assert_matches_type(SyncConversationCursorPage[ConversationItem], item, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + item = client.conversations.items.list( + conversation_id="conv_123", + after="after", + include=["code_interpreter_call.outputs"], + limit=0, + order="asc", + ) + assert_matches_type(SyncConversationCursorPage[ConversationItem], item, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.conversations.items.with_raw_response.list( + conversation_id="conv_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + item = response.parse() + assert_matches_type(SyncConversationCursorPage[ConversationItem], item, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.conversations.items.with_streaming_response.list( + conversation_id="conv_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + item = response.parse() + assert_matches_type(SyncConversationCursorPage[ConversationItem], item, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `conversation_id` but received ''"): + client.conversations.items.with_raw_response.list( + conversation_id="", + ) + + @parametrize + def test_method_delete(self, client: OpenAI) -> None: + item = client.conversations.items.delete( + item_id="msg_abc", + conversation_id="conv_123", + ) + assert_matches_type(Conversation, item, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: OpenAI) -> None: + response = client.conversations.items.with_raw_response.delete( + item_id="msg_abc", + conversation_id="conv_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + item = response.parse() + assert_matches_type(Conversation, item, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: OpenAI) -> None: + with client.conversations.items.with_streaming_response.delete( + item_id="msg_abc", + conversation_id="conv_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + item = response.parse() + assert_matches_type(Conversation, item, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `conversation_id` but received ''"): + client.conversations.items.with_raw_response.delete( + item_id="msg_abc", + conversation_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `item_id` but received ''"): + client.conversations.items.with_raw_response.delete( + item_id="", + conversation_id="conv_123", + ) + + +class TestAsyncItems: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncOpenAI) -> None: + item = await async_client.conversations.items.create( + conversation_id="conv_123", + items=[ + { + "content": "string", + "role": "user", + } + ], + ) + assert_matches_type(ConversationItemList, item, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: + item = await async_client.conversations.items.create( + conversation_id="conv_123", + items=[ + { + "content": "string", + "role": "user", + "type": "message", + } + ], + include=["code_interpreter_call.outputs"], + ) + assert_matches_type(ConversationItemList, item, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: + response = await async_client.conversations.items.with_raw_response.create( + conversation_id="conv_123", + items=[ + { + "content": "string", + "role": "user", + } + ], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + item = response.parse() + assert_matches_type(ConversationItemList, item, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: + async with async_client.conversations.items.with_streaming_response.create( + conversation_id="conv_123", + items=[ + { + "content": "string", + "role": "user", + } + ], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + item = await response.parse() + assert_matches_type(ConversationItemList, item, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `conversation_id` but received ''"): + await async_client.conversations.items.with_raw_response.create( + conversation_id="", + items=[ + { + "content": "string", + "role": "user", + } + ], + ) + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + item = await async_client.conversations.items.retrieve( + item_id="msg_abc", + conversation_id="conv_123", + ) + assert_matches_type(ConversationItem, item, path=["response"]) + + @parametrize + async def test_method_retrieve_with_all_params(self, async_client: AsyncOpenAI) -> None: + item = await async_client.conversations.items.retrieve( + item_id="msg_abc", + conversation_id="conv_123", + include=["code_interpreter_call.outputs"], + ) + assert_matches_type(ConversationItem, item, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.conversations.items.with_raw_response.retrieve( + item_id="msg_abc", + conversation_id="conv_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + item = response.parse() + assert_matches_type(ConversationItem, item, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.conversations.items.with_streaming_response.retrieve( + item_id="msg_abc", + conversation_id="conv_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + item = await response.parse() + assert_matches_type(ConversationItem, item, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `conversation_id` but received ''"): + await async_client.conversations.items.with_raw_response.retrieve( + item_id="msg_abc", + conversation_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `item_id` but received ''"): + await async_client.conversations.items.with_raw_response.retrieve( + item_id="", + conversation_id="conv_123", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + item = await async_client.conversations.items.list( + conversation_id="conv_123", + ) + assert_matches_type(AsyncConversationCursorPage[ConversationItem], item, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + item = await async_client.conversations.items.list( + conversation_id="conv_123", + after="after", + include=["code_interpreter_call.outputs"], + limit=0, + order="asc", + ) + assert_matches_type(AsyncConversationCursorPage[ConversationItem], item, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.conversations.items.with_raw_response.list( + conversation_id="conv_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + item = response.parse() + assert_matches_type(AsyncConversationCursorPage[ConversationItem], item, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.conversations.items.with_streaming_response.list( + conversation_id="conv_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + item = await response.parse() + assert_matches_type(AsyncConversationCursorPage[ConversationItem], item, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `conversation_id` but received ''"): + await async_client.conversations.items.with_raw_response.list( + conversation_id="", + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncOpenAI) -> None: + item = await async_client.conversations.items.delete( + item_id="msg_abc", + conversation_id="conv_123", + ) + assert_matches_type(Conversation, item, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: + response = await async_client.conversations.items.with_raw_response.delete( + item_id="msg_abc", + conversation_id="conv_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + item = response.parse() + assert_matches_type(Conversation, item, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: + async with async_client.conversations.items.with_streaming_response.delete( + item_id="msg_abc", + conversation_id="conv_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + item = await response.parse() + assert_matches_type(Conversation, item, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `conversation_id` but received ''"): + await async_client.conversations.items.with_raw_response.delete( + item_id="msg_abc", + conversation_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `item_id` but received ''"): + await async_client.conversations.items.with_raw_response.delete( + item_id="", + conversation_id="conv_123", + ) diff --git a/tests/api_resources/responses/test_input_items.py b/tests/api_resources/responses/test_input_items.py index e8e3893bad..eda20c9a0b 100644 --- a/tests/api_resources/responses/test_input_items.py +++ b/tests/api_resources/responses/test_input_items.py @@ -30,7 +30,6 @@ def test_method_list_with_all_params(self, client: OpenAI) -> None: input_item = client.responses.input_items.list( response_id="response_id", after="after", - before="before", include=["code_interpreter_call.outputs"], limit=0, order="asc", @@ -86,7 +85,6 @@ async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> N input_item = await async_client.responses.input_items.list( response_id="response_id", after="after", - before="before", include=["code_interpreter_call.outputs"], limit=0, order="asc", diff --git a/tests/api_resources/test_conversations.py b/tests/api_resources/test_conversations.py new file mode 100644 index 0000000000..d21e685a04 --- /dev/null +++ b/tests/api_resources/test_conversations.py @@ -0,0 +1,341 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.types.conversations import ( + Conversation, + ConversationDeletedResource, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestConversations: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: OpenAI) -> None: + conversation = client.conversations.create() + assert_matches_type(Conversation, conversation, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: OpenAI) -> None: + conversation = client.conversations.create( + items=[ + { + "content": "string", + "role": "user", + "type": "message", + } + ], + metadata={"foo": "string"}, + ) + assert_matches_type(Conversation, conversation, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: OpenAI) -> None: + response = client.conversations.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + conversation = response.parse() + assert_matches_type(Conversation, conversation, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: OpenAI) -> None: + with client.conversations.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + conversation = response.parse() + assert_matches_type(Conversation, conversation, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + conversation = client.conversations.retrieve( + "conv_123", + ) + assert_matches_type(Conversation, conversation, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.conversations.with_raw_response.retrieve( + "conv_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + conversation = response.parse() + assert_matches_type(Conversation, conversation, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.conversations.with_streaming_response.retrieve( + "conv_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + conversation = response.parse() + assert_matches_type(Conversation, conversation, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `conversation_id` but received ''"): + client.conversations.with_raw_response.retrieve( + "", + ) + + @parametrize + def test_method_update(self, client: OpenAI) -> None: + conversation = client.conversations.update( + conversation_id="conv_123", + metadata={"foo": "string"}, + ) + assert_matches_type(Conversation, conversation, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: OpenAI) -> None: + response = client.conversations.with_raw_response.update( + conversation_id="conv_123", + metadata={"foo": "string"}, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + conversation = response.parse() + assert_matches_type(Conversation, conversation, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: OpenAI) -> None: + with client.conversations.with_streaming_response.update( + conversation_id="conv_123", + metadata={"foo": "string"}, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + conversation = response.parse() + assert_matches_type(Conversation, conversation, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `conversation_id` but received ''"): + client.conversations.with_raw_response.update( + conversation_id="", + metadata={"foo": "string"}, + ) + + @parametrize + def test_method_delete(self, client: OpenAI) -> None: + conversation = client.conversations.delete( + "conv_123", + ) + assert_matches_type(ConversationDeletedResource, conversation, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: OpenAI) -> None: + response = client.conversations.with_raw_response.delete( + "conv_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + conversation = response.parse() + assert_matches_type(ConversationDeletedResource, conversation, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: OpenAI) -> None: + with client.conversations.with_streaming_response.delete( + "conv_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + conversation = response.parse() + assert_matches_type(ConversationDeletedResource, conversation, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `conversation_id` but received ''"): + client.conversations.with_raw_response.delete( + "", + ) + + +class TestAsyncConversations: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncOpenAI) -> None: + conversation = await async_client.conversations.create() + assert_matches_type(Conversation, conversation, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: + conversation = await async_client.conversations.create( + items=[ + { + "content": "string", + "role": "user", + "type": "message", + } + ], + metadata={"foo": "string"}, + ) + assert_matches_type(Conversation, conversation, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: + response = await async_client.conversations.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + conversation = response.parse() + assert_matches_type(Conversation, conversation, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: + async with async_client.conversations.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + conversation = await response.parse() + assert_matches_type(Conversation, conversation, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + conversation = await async_client.conversations.retrieve( + "conv_123", + ) + assert_matches_type(Conversation, conversation, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.conversations.with_raw_response.retrieve( + "conv_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + conversation = response.parse() + assert_matches_type(Conversation, conversation, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.conversations.with_streaming_response.retrieve( + "conv_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + conversation = await response.parse() + assert_matches_type(Conversation, conversation, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `conversation_id` but received ''"): + await async_client.conversations.with_raw_response.retrieve( + "", + ) + + @parametrize + async def test_method_update(self, async_client: AsyncOpenAI) -> None: + conversation = await async_client.conversations.update( + conversation_id="conv_123", + metadata={"foo": "string"}, + ) + assert_matches_type(Conversation, conversation, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: + response = await async_client.conversations.with_raw_response.update( + conversation_id="conv_123", + metadata={"foo": "string"}, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + conversation = response.parse() + assert_matches_type(Conversation, conversation, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncOpenAI) -> None: + async with async_client.conversations.with_streaming_response.update( + conversation_id="conv_123", + metadata={"foo": "string"}, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + conversation = await response.parse() + assert_matches_type(Conversation, conversation, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `conversation_id` but received ''"): + await async_client.conversations.with_raw_response.update( + conversation_id="", + metadata={"foo": "string"}, + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncOpenAI) -> None: + conversation = await async_client.conversations.delete( + "conv_123", + ) + assert_matches_type(ConversationDeletedResource, conversation, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: + response = await async_client.conversations.with_raw_response.delete( + "conv_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + conversation = response.parse() + assert_matches_type(ConversationDeletedResource, conversation, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: + async with async_client.conversations.with_streaming_response.delete( + "conv_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + conversation = await response.parse() + assert_matches_type(ConversationDeletedResource, conversation, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `conversation_id` but received ''"): + await async_client.conversations.with_raw_response.delete( + "", + ) diff --git a/tests/api_resources/test_responses.py b/tests/api_resources/test_responses.py index 310800b87e..0cc20e926b 100644 --- a/tests/api_resources/test_responses.py +++ b/tests/api_resources/test_responses.py @@ -29,6 +29,7 @@ def test_method_create_overload_1(self, client: OpenAI) -> None: def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: response = client.responses.create( background=True, + conversation="string", include=["code_interpreter_call.outputs"], input="string", instructions="instructions", @@ -108,6 +109,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: response_stream = client.responses.create( stream=True, background=True, + conversation="string", include=["code_interpreter_call.outputs"], input="string", instructions="instructions", @@ -380,6 +382,7 @@ async def test_method_create_overload_1(self, async_client: AsyncOpenAI) -> None async def test_method_create_with_all_params_overload_1(self, async_client: AsyncOpenAI) -> None: response = await async_client.responses.create( background=True, + conversation="string", include=["code_interpreter_call.outputs"], input="string", instructions="instructions", @@ -459,6 +462,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn response_stream = await async_client.responses.create( stream=True, background=True, + conversation="string", include=["code_interpreter_call.outputs"], input="string", instructions="instructions", From 9fd9df51bb12956598d6e12b50a3330aa0e56272 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 25 Aug 2025 22:24:33 +0000 Subject: [PATCH 458/769] chore(internal): change ci workflow machines --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5e56aae09a..4c617a6f19 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,7 +42,7 @@ jobs: permissions: contents: read id-token: write - runs-on: depot-ubuntu-24.04 + runs-on: ${{ github.repository == 'stainless-sdks/openai-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} steps: - uses: actions/checkout@v4 From 7325cdbbaf88078d00fefdb830f5040272b35dda Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 26 Aug 2025 13:56:43 +0000 Subject: [PATCH 459/769] chore(internal): codegen related update --- requirements-dev.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.lock b/requirements-dev.lock index e619cb6b64..e8bea53014 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -70,7 +70,7 @@ filelock==3.12.4 frozenlist==1.7.0 # via aiohttp # via aiosignal -griffe==1.12.1 +griffe==1.13.0 h11==0.16.0 # via httpcore httpcore==1.0.9 From 3f21bcd0b993641402e28d21621b794db0b34cc2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 26 Aug 2025 16:02:14 +0000 Subject: [PATCH 460/769] fix: avoid newer type syntax --- src/openai/_models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openai/_models.py b/src/openai/_models.py index d84d51d913..50eb0af751 100644 --- a/src/openai/_models.py +++ b/src/openai/_models.py @@ -329,7 +329,7 @@ def model_dump( exclude_none=exclude_none, ) - return cast(dict[str, Any], json_safe(dumped)) if mode == "json" else dumped + return cast("dict[str, Any]", json_safe(dumped)) if mode == "json" else dumped @override def model_dump_json( From af5f9c4e9d26777364154c2961dce7a047a2b42d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 26 Aug 2025 20:42:47 +0000 Subject: [PATCH 461/769] feat(api): add web search filters --- .stats.yml | 4 +- .../resources/conversations/conversations.py | 4 +- src/openai/resources/conversations/items.py | 4 ++ src/openai/resources/responses/responses.py | 12 ++++ .../types/conversations/item_list_params.py | 2 + .../types/responses/response_create_params.py | 2 + .../responses/response_function_web_search.py | 15 ++++- .../response_function_web_search_param.py | 22 ++++++- src/openai/types/responses/tool.py | 63 ++++++++++++++++++- src/openai/types/responses/tool_param.py | 61 +++++++++++++++++- 10 files changed, 178 insertions(+), 11 deletions(-) diff --git a/.stats.yml b/.stats.yml index f2d5304a5b..5ad90ac5ab 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 119 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-ddbdf9343316047e8a773c54fb24e4a8d225955e202a1888fde6f9c8898ebf98.yml -openapi_spec_hash: 9802f6dd381558466c897f6e387e06ca +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-8517ffa1004e31ca2523d617629e64be6fe4f13403ddfd9db5b3be002656cbde.yml +openapi_spec_hash: b64dd8c8b23082a7aa2a3e5c5fffd8bd config_hash: fe0ea26680ac2075a6cd66416aefe7db diff --git a/src/openai/resources/conversations/conversations.py b/src/openai/resources/conversations/conversations.py index 13bc1fb1ce..802620e6ad 100644 --- a/src/openai/resources/conversations/conversations.py +++ b/src/openai/resources/conversations/conversations.py @@ -67,7 +67,7 @@ def create( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> Conversation: """ - Create a conversation with the given ID. + Create a conversation. Args: items: Initial items to include in the conversation context. You may add up to 20 items @@ -244,7 +244,7 @@ async def create( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> Conversation: """ - Create a conversation with the given ID. + Create a conversation. Args: items: Initial items to include in the conversation context. You may add up to 20 items diff --git a/src/openai/resources/conversations/items.py b/src/openai/resources/conversations/items.py index 1e696a79ed..01811f956b 100644 --- a/src/openai/resources/conversations/items.py +++ b/src/openai/resources/conversations/items.py @@ -163,6 +163,8 @@ def list( include: Specify additional output data to include in the model response. Currently supported values are: + - `web_search_call.action.sources`: Include the sources of the web search tool + call. - `code_interpreter_call.outputs`: Includes the outputs of python code execution in code interpreter tool call items. - `computer_call_output.output.image_url`: Include image urls from the computer @@ -391,6 +393,8 @@ def list( include: Specify additional output data to include in the model response. Currently supported values are: + - `web_search_call.action.sources`: Include the sources of the web search tool + call. - `code_interpreter_call.outputs`: Includes the outputs of python code execution in code interpreter tool call items. - `computer_call_output.output.image_url`: Include image urls from the computer diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index d0862f5d76..062fd491f2 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -136,6 +136,8 @@ def create( include: Specify additional output data to include in the model response. Currently supported values are: + - `web_search_call.action.sources`: Include the sources of the web search tool + call. - `code_interpreter_call.outputs`: Includes the outputs of python code execution in code interpreter tool call items. - `computer_call_output.output.image_url`: Include image urls from the computer @@ -377,6 +379,8 @@ def create( include: Specify additional output data to include in the model response. Currently supported values are: + - `web_search_call.action.sources`: Include the sources of the web search tool + call. - `code_interpreter_call.outputs`: Includes the outputs of python code execution in code interpreter tool call items. - `computer_call_output.output.image_url`: Include image urls from the computer @@ -611,6 +615,8 @@ def create( include: Specify additional output data to include in the model response. Currently supported values are: + - `web_search_call.action.sources`: Include the sources of the web search tool + call. - `code_interpreter_call.outputs`: Includes the outputs of python code execution in code interpreter tool call items. - `computer_call_output.output.image_url`: Include image urls from the computer @@ -1524,6 +1530,8 @@ async def create( include: Specify additional output data to include in the model response. Currently supported values are: + - `web_search_call.action.sources`: Include the sources of the web search tool + call. - `code_interpreter_call.outputs`: Includes the outputs of python code execution in code interpreter tool call items. - `computer_call_output.output.image_url`: Include image urls from the computer @@ -1765,6 +1773,8 @@ async def create( include: Specify additional output data to include in the model response. Currently supported values are: + - `web_search_call.action.sources`: Include the sources of the web search tool + call. - `code_interpreter_call.outputs`: Includes the outputs of python code execution in code interpreter tool call items. - `computer_call_output.output.image_url`: Include image urls from the computer @@ -1999,6 +2009,8 @@ async def create( include: Specify additional output data to include in the model response. Currently supported values are: + - `web_search_call.action.sources`: Include the sources of the web search tool + call. - `code_interpreter_call.outputs`: Includes the outputs of python code execution in code interpreter tool call items. - `computer_call_output.output.image_url`: Include image urls from the computer diff --git a/src/openai/types/conversations/item_list_params.py b/src/openai/types/conversations/item_list_params.py index 34bf43c559..a4dd61f399 100644 --- a/src/openai/types/conversations/item_list_params.py +++ b/src/openai/types/conversations/item_list_params.py @@ -19,6 +19,8 @@ class ItemListParams(TypedDict, total=False): Currently supported values are: + - `web_search_call.action.sources`: Include the sources of the web search tool + call. - `code_interpreter_call.outputs`: Includes the outputs of python code execution in code interpreter tool call items. - `computer_call_output.output.image_url`: Include image urls from the computer diff --git a/src/openai/types/responses/response_create_params.py b/src/openai/types/responses/response_create_params.py index 5129b8b771..ff28c05816 100644 --- a/src/openai/types/responses/response_create_params.py +++ b/src/openai/types/responses/response_create_params.py @@ -51,6 +51,8 @@ class ResponseCreateParamsBase(TypedDict, total=False): Currently supported values are: + - `web_search_call.action.sources`: Include the sources of the web search tool + call. - `code_interpreter_call.outputs`: Includes the outputs of python code execution in code interpreter tool call items. - `computer_call_output.output.image_url`: Include image urls from the computer diff --git a/src/openai/types/responses/response_function_web_search.py b/src/openai/types/responses/response_function_web_search.py index a3252956e9..f3e80e6a8f 100644 --- a/src/openai/types/responses/response_function_web_search.py +++ b/src/openai/types/responses/response_function_web_search.py @@ -1,12 +1,20 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Union +from typing import List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias from ..._utils import PropertyInfo from ..._models import BaseModel -__all__ = ["ResponseFunctionWebSearch", "Action", "ActionSearch", "ActionOpenPage", "ActionFind"] +__all__ = ["ResponseFunctionWebSearch", "Action", "ActionSearch", "ActionSearchSource", "ActionOpenPage", "ActionFind"] + + +class ActionSearchSource(BaseModel): + type: Literal["url"] + """The type of source. Always `url`.""" + + url: str + """The URL of the source.""" class ActionSearch(BaseModel): @@ -16,6 +24,9 @@ class ActionSearch(BaseModel): type: Literal["search"] """The action type.""" + sources: Optional[List[ActionSearchSource]] = None + """The sources used in the search.""" + class ActionOpenPage(BaseModel): type: Literal["open_page"] diff --git a/src/openai/types/responses/response_function_web_search_param.py b/src/openai/types/responses/response_function_web_search_param.py index 4a06132cf4..fc019d3eb7 100644 --- a/src/openai/types/responses/response_function_web_search_param.py +++ b/src/openai/types/responses/response_function_web_search_param.py @@ -2,10 +2,25 @@ from __future__ import annotations -from typing import Union +from typing import Union, Iterable from typing_extensions import Literal, Required, TypeAlias, TypedDict -__all__ = ["ResponseFunctionWebSearchParam", "Action", "ActionSearch", "ActionOpenPage", "ActionFind"] +__all__ = [ + "ResponseFunctionWebSearchParam", + "Action", + "ActionSearch", + "ActionSearchSource", + "ActionOpenPage", + "ActionFind", +] + + +class ActionSearchSource(TypedDict, total=False): + type: Required[Literal["url"]] + """The type of source. Always `url`.""" + + url: Required[str] + """The URL of the source.""" class ActionSearch(TypedDict, total=False): @@ -15,6 +30,9 @@ class ActionSearch(TypedDict, total=False): type: Required[Literal["search"]] """The action type.""" + sources: Iterable[ActionSearchSource] + """The sources used in the search.""" + class ActionOpenPage(TypedDict, total=False): type: Required[Literal["open_page"]] diff --git a/src/openai/types/responses/tool.py b/src/openai/types/responses/tool.py index d46f8cb0be..0fe7133804 100644 --- a/src/openai/types/responses/tool.py +++ b/src/openai/types/responses/tool.py @@ -3,16 +3,19 @@ from typing import Dict, List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias +from . import web_search_tool from ..._utils import PropertyInfo from ..._models import BaseModel from .custom_tool import CustomTool from .computer_tool import ComputerTool from .function_tool import FunctionTool -from .web_search_tool import WebSearchTool from .file_search_tool import FileSearchTool __all__ = [ "Tool", + "WebSearchTool", + "WebSearchToolFilters", + "WebSearchToolUserLocation", "Mcp", "McpAllowedTools", "McpAllowedToolsMcpToolFilter", @@ -29,6 +32,61 @@ ] +class WebSearchToolFilters(BaseModel): + allowed_domains: Optional[List[str]] = None + """Allowed domains for the search. + + If not provided, all domains are allowed. Subdomains of the provided domains are + allowed as well. + + Example: `["pubmed.ncbi.nlm.nih.gov"]` + """ + + +class WebSearchToolUserLocation(BaseModel): + city: Optional[str] = None + """Free text input for the city of the user, e.g. `San Francisco`.""" + + country: Optional[str] = None + """ + The two-letter [ISO country code](https://en.wikipedia.org/wiki/ISO_3166-1) of + the user, e.g. `US`. + """ + + region: Optional[str] = None + """Free text input for the region of the user, e.g. `California`.""" + + timezone: Optional[str] = None + """ + The [IANA timezone](https://timeapi.io/documentation/iana-timezones) of the + user, e.g. `America/Los_Angeles`. + """ + + type: Optional[Literal["approximate"]] = None + """The type of location approximation. Always `approximate`.""" + + +class WebSearchTool(BaseModel): + type: Literal["web_search", "web_search_2025_08_26"] + """The type of the web search tool. + + One of `web_search` or `web_search_2025_08_26`. + """ + + filters: Optional[WebSearchToolFilters] = None + """Filters for the search.""" + + search_context_size: Optional[Literal["low", "medium", "high"]] = None + """High level guidance for the amount of context window space to use for the + search. + + One of `low`, `medium`, or `high`. `medium` is the default. + """ + + user_location: Optional[WebSearchToolUserLocation] = None + """The approximate location of the user.""" + + class McpAllowedToolsMcpToolFilter(BaseModel): read_only: Optional[bool] = None """Indicates whether or not a tool modifies data or is read-only. @@ -245,13 +303,14 @@ class LocalShell(BaseModel): Union[ FunctionTool, FileSearchTool, - WebSearchTool, ComputerTool, + WebSearchTool, Mcp, CodeInterpreter, ImageGeneration, LocalShell, CustomTool, + web_search_tool.WebSearchTool, ], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/responses/tool_param.py b/src/openai/types/responses/tool_param.py index 9dde42e294..aff9359efa 100644 --- a/src/openai/types/responses/tool_param.py +++ b/src/openai/types/responses/tool_param.py @@ -14,6 +14,9 @@ __all__ = [ "ToolParam", + "WebSearchTool", + "WebSearchToolFilters", + "WebSearchToolUserLocation", "Mcp", "McpAllowedTools", "McpAllowedToolsMcpToolFilter", @@ -30,6 +33,61 @@ ] +class WebSearchToolFilters(TypedDict, total=False): + allowed_domains: Optional[List[str]] + """Allowed domains for the search. + + If not provided, all domains are allowed. Subdomains of the provided domains are + allowed as well. + + Example: `["pubmed.ncbi.nlm.nih.gov"]` + """ + + +class WebSearchToolUserLocation(TypedDict, total=False): + city: Optional[str] + """Free text input for the city of the user, e.g. `San Francisco`.""" + + country: Optional[str] + """ + The two-letter [ISO country code](https://en.wikipedia.org/wiki/ISO_3166-1) of + the user, e.g. `US`. + """ + + region: Optional[str] + """Free text input for the region of the user, e.g. `California`.""" + + timezone: Optional[str] + """ + The [IANA timezone](https://timeapi.io/documentation/iana-timezones) of the + user, e.g. `America/Los_Angeles`. + """ + + type: Literal["approximate"] + """The type of location approximation. Always `approximate`.""" + + +class WebSearchTool(TypedDict, total=False): + type: Required[Literal["web_search", "web_search_2025_08_26"]] + """The type of the web search tool. + + One of `web_search` or `web_search_2025_08_26`. + """ + + filters: Optional[WebSearchToolFilters] + """Filters for the search.""" + + search_context_size: Literal["low", "medium", "high"] + """High level guidance for the amount of context window space to use for the + search. + + One of `low`, `medium`, or `high`. `medium` is the default. + """ + + user_location: Optional[WebSearchToolUserLocation] + """The approximate location of the user.""" + + class McpAllowedToolsMcpToolFilter(TypedDict, total=False): read_only: bool """Indicates whether or not a tool modifies data or is read-only. @@ -243,13 +301,14 @@ class LocalShell(TypedDict, total=False): ToolParam: TypeAlias = Union[ FunctionToolParam, FileSearchToolParam, - WebSearchToolParam, ComputerToolParam, + WebSearchTool, Mcp, CodeInterpreter, ImageGeneration, LocalShell, CustomToolParam, + WebSearchToolParam, ] From 3154a78ac8cb404d64707d63cdfe72d3db8a45be Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 26 Aug 2025 20:43:47 +0000 Subject: [PATCH 462/769] release: 1.102.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 19 +++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 070375331a..98411f0f2b 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.101.0" + ".": "1.102.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 44b25e0a4c..26ca1c5cb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## 1.102.0 (2025-08-26) + +Full Changelog: [v1.101.0...v1.102.0](https://github.com/openai/openai-python/compare/v1.101.0...v1.102.0) + +### Features + +* **api:** add web search filters ([1c199a8](https://github.com/openai/openai-python/commit/1c199a8dc85f773ae656fe850fdfb80b91f8f6b1)) + + +### Bug Fixes + +* avoid newer type syntax ([bd0c668](https://github.com/openai/openai-python/commit/bd0c668d754b89c78c2c9ad2e081258c04aaece6)) + + +### Chores + +* **internal:** change ci workflow machines ([3e129d5](https://github.com/openai/openai-python/commit/3e129d5e49f6391dea7497132cb3cfed8e5dd8ee)) +* **internal:** codegen related update ([b6dc170](https://github.com/openai/openai-python/commit/b6dc170832d719fc5028cfe234748c22e6e168aa)) + ## 1.101.0 (2025-08-21) Full Changelog: [v1.100.3...v1.101.0](https://github.com/openai/openai-python/compare/v1.100.3...v1.101.0) diff --git a/pyproject.toml b/pyproject.toml index 8198b178be..6736c1ad9e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.101.0" +version = "1.102.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 802084af5d..b2d62263ff 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.101.0" # x-release-please-version +__version__ = "1.102.0" # x-release-please-version From 427c7c42c74654d068b2b83dc4622fe1ead92e23 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 26 Aug 2025 21:53:29 +0000 Subject: [PATCH 463/769] chore(internal): update pyright exclude list --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 6736c1ad9e..fbc6c31f00 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -165,6 +165,7 @@ exclude = [ "_dev", ".venv", ".nox", + ".git", # uses inline `uv` script dependencies # which means it can't be type checked From 7d0642401ec81675568d9ed2dbfb31638cfdc588 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 27 Aug 2025 14:36:29 +0000 Subject: [PATCH 464/769] chore(internal): minor formatting change --- src/openai/resources/beta/threads/messages.py | 40 ++++++++-------- .../resources/beta/threads/runs/runs.py | 48 +++++++++---------- .../resources/beta/threads/runs/steps.py | 16 +++---- src/openai/resources/beta/threads/threads.py | 40 ++++++++-------- src/openai/resources/files.py | 8 ++-- 5 files changed, 76 insertions(+), 76 deletions(-) diff --git a/src/openai/resources/beta/threads/messages.py b/src/openai/resources/beta/threads/messages.py index 943d2e7f05..8903ff0316 100644 --- a/src/openai/resources/beta/threads/messages.py +++ b/src/openai/resources/beta/threads/messages.py @@ -600,27 +600,27 @@ def __init__(self, messages: Messages) -> None: self.create = ( # pyright: ignore[reportDeprecated] _legacy_response.to_raw_response_wrapper( - messages.create # pyright: ignore[reportDeprecated], + messages.create, # pyright: ignore[reportDeprecated], ) ) self.retrieve = ( # pyright: ignore[reportDeprecated] _legacy_response.to_raw_response_wrapper( - messages.retrieve # pyright: ignore[reportDeprecated], + messages.retrieve, # pyright: ignore[reportDeprecated], ) ) self.update = ( # pyright: ignore[reportDeprecated] _legacy_response.to_raw_response_wrapper( - messages.update # pyright: ignore[reportDeprecated], + messages.update, # pyright: ignore[reportDeprecated], ) ) self.list = ( # pyright: ignore[reportDeprecated] _legacy_response.to_raw_response_wrapper( - messages.list # pyright: ignore[reportDeprecated], + messages.list, # pyright: ignore[reportDeprecated], ) ) self.delete = ( # pyright: ignore[reportDeprecated] _legacy_response.to_raw_response_wrapper( - messages.delete # pyright: ignore[reportDeprecated], + messages.delete, # pyright: ignore[reportDeprecated], ) ) @@ -631,27 +631,27 @@ def __init__(self, messages: AsyncMessages) -> None: self.create = ( # pyright: ignore[reportDeprecated] _legacy_response.async_to_raw_response_wrapper( - messages.create # pyright: ignore[reportDeprecated], + messages.create, # pyright: ignore[reportDeprecated], ) ) self.retrieve = ( # pyright: ignore[reportDeprecated] _legacy_response.async_to_raw_response_wrapper( - messages.retrieve # pyright: ignore[reportDeprecated], + messages.retrieve, # pyright: ignore[reportDeprecated], ) ) self.update = ( # pyright: ignore[reportDeprecated] _legacy_response.async_to_raw_response_wrapper( - messages.update # pyright: ignore[reportDeprecated], + messages.update, # pyright: ignore[reportDeprecated], ) ) self.list = ( # pyright: ignore[reportDeprecated] _legacy_response.async_to_raw_response_wrapper( - messages.list # pyright: ignore[reportDeprecated], + messages.list, # pyright: ignore[reportDeprecated], ) ) self.delete = ( # pyright: ignore[reportDeprecated] _legacy_response.async_to_raw_response_wrapper( - messages.delete # pyright: ignore[reportDeprecated], + messages.delete, # pyright: ignore[reportDeprecated], ) ) @@ -662,27 +662,27 @@ def __init__(self, messages: Messages) -> None: self.create = ( # pyright: ignore[reportDeprecated] to_streamed_response_wrapper( - messages.create # pyright: ignore[reportDeprecated], + messages.create, # pyright: ignore[reportDeprecated], ) ) self.retrieve = ( # pyright: ignore[reportDeprecated] to_streamed_response_wrapper( - messages.retrieve # pyright: ignore[reportDeprecated], + messages.retrieve, # pyright: ignore[reportDeprecated], ) ) self.update = ( # pyright: ignore[reportDeprecated] to_streamed_response_wrapper( - messages.update # pyright: ignore[reportDeprecated], + messages.update, # pyright: ignore[reportDeprecated], ) ) self.list = ( # pyright: ignore[reportDeprecated] to_streamed_response_wrapper( - messages.list # pyright: ignore[reportDeprecated], + messages.list, # pyright: ignore[reportDeprecated], ) ) self.delete = ( # pyright: ignore[reportDeprecated] to_streamed_response_wrapper( - messages.delete # pyright: ignore[reportDeprecated], + messages.delete, # pyright: ignore[reportDeprecated], ) ) @@ -693,26 +693,26 @@ def __init__(self, messages: AsyncMessages) -> None: self.create = ( # pyright: ignore[reportDeprecated] async_to_streamed_response_wrapper( - messages.create # pyright: ignore[reportDeprecated], + messages.create, # pyright: ignore[reportDeprecated], ) ) self.retrieve = ( # pyright: ignore[reportDeprecated] async_to_streamed_response_wrapper( - messages.retrieve # pyright: ignore[reportDeprecated], + messages.retrieve, # pyright: ignore[reportDeprecated], ) ) self.update = ( # pyright: ignore[reportDeprecated] async_to_streamed_response_wrapper( - messages.update # pyright: ignore[reportDeprecated], + messages.update, # pyright: ignore[reportDeprecated], ) ) self.list = ( # pyright: ignore[reportDeprecated] async_to_streamed_response_wrapper( - messages.list # pyright: ignore[reportDeprecated], + messages.list, # pyright: ignore[reportDeprecated], ) ) self.delete = ( # pyright: ignore[reportDeprecated] async_to_streamed_response_wrapper( - messages.delete # pyright: ignore[reportDeprecated], + messages.delete, # pyright: ignore[reportDeprecated], ) ) diff --git a/src/openai/resources/beta/threads/runs/runs.py b/src/openai/resources/beta/threads/runs/runs.py index 07b43e6471..e97d519a40 100644 --- a/src/openai/resources/beta/threads/runs/runs.py +++ b/src/openai/resources/beta/threads/runs/runs.py @@ -2926,32 +2926,32 @@ def __init__(self, runs: Runs) -> None: self.create = ( # pyright: ignore[reportDeprecated] _legacy_response.to_raw_response_wrapper( - runs.create # pyright: ignore[reportDeprecated], + runs.create, # pyright: ignore[reportDeprecated], ) ) self.retrieve = ( # pyright: ignore[reportDeprecated] _legacy_response.to_raw_response_wrapper( - runs.retrieve # pyright: ignore[reportDeprecated], + runs.retrieve, # pyright: ignore[reportDeprecated], ) ) self.update = ( # pyright: ignore[reportDeprecated] _legacy_response.to_raw_response_wrapper( - runs.update # pyright: ignore[reportDeprecated], + runs.update, # pyright: ignore[reportDeprecated], ) ) self.list = ( # pyright: ignore[reportDeprecated] _legacy_response.to_raw_response_wrapper( - runs.list # pyright: ignore[reportDeprecated], + runs.list, # pyright: ignore[reportDeprecated], ) ) self.cancel = ( # pyright: ignore[reportDeprecated] _legacy_response.to_raw_response_wrapper( - runs.cancel # pyright: ignore[reportDeprecated], + runs.cancel, # pyright: ignore[reportDeprecated], ) ) self.submit_tool_outputs = ( # pyright: ignore[reportDeprecated] _legacy_response.to_raw_response_wrapper( - runs.submit_tool_outputs # pyright: ignore[reportDeprecated], + runs.submit_tool_outputs, # pyright: ignore[reportDeprecated], ) ) @@ -2966,32 +2966,32 @@ def __init__(self, runs: AsyncRuns) -> None: self.create = ( # pyright: ignore[reportDeprecated] _legacy_response.async_to_raw_response_wrapper( - runs.create # pyright: ignore[reportDeprecated], + runs.create, # pyright: ignore[reportDeprecated], ) ) self.retrieve = ( # pyright: ignore[reportDeprecated] _legacy_response.async_to_raw_response_wrapper( - runs.retrieve # pyright: ignore[reportDeprecated], + runs.retrieve, # pyright: ignore[reportDeprecated], ) ) self.update = ( # pyright: ignore[reportDeprecated] _legacy_response.async_to_raw_response_wrapper( - runs.update # pyright: ignore[reportDeprecated], + runs.update, # pyright: ignore[reportDeprecated], ) ) self.list = ( # pyright: ignore[reportDeprecated] _legacy_response.async_to_raw_response_wrapper( - runs.list # pyright: ignore[reportDeprecated], + runs.list, # pyright: ignore[reportDeprecated], ) ) self.cancel = ( # pyright: ignore[reportDeprecated] _legacy_response.async_to_raw_response_wrapper( - runs.cancel # pyright: ignore[reportDeprecated], + runs.cancel, # pyright: ignore[reportDeprecated], ) ) self.submit_tool_outputs = ( # pyright: ignore[reportDeprecated] _legacy_response.async_to_raw_response_wrapper( - runs.submit_tool_outputs # pyright: ignore[reportDeprecated], + runs.submit_tool_outputs, # pyright: ignore[reportDeprecated], ) ) @@ -3006,32 +3006,32 @@ def __init__(self, runs: Runs) -> None: self.create = ( # pyright: ignore[reportDeprecated] to_streamed_response_wrapper( - runs.create # pyright: ignore[reportDeprecated], + runs.create, # pyright: ignore[reportDeprecated], ) ) self.retrieve = ( # pyright: ignore[reportDeprecated] to_streamed_response_wrapper( - runs.retrieve # pyright: ignore[reportDeprecated], + runs.retrieve, # pyright: ignore[reportDeprecated], ) ) self.update = ( # pyright: ignore[reportDeprecated] to_streamed_response_wrapper( - runs.update # pyright: ignore[reportDeprecated], + runs.update, # pyright: ignore[reportDeprecated], ) ) self.list = ( # pyright: ignore[reportDeprecated] to_streamed_response_wrapper( - runs.list # pyright: ignore[reportDeprecated], + runs.list, # pyright: ignore[reportDeprecated], ) ) self.cancel = ( # pyright: ignore[reportDeprecated] to_streamed_response_wrapper( - runs.cancel # pyright: ignore[reportDeprecated], + runs.cancel, # pyright: ignore[reportDeprecated], ) ) self.submit_tool_outputs = ( # pyright: ignore[reportDeprecated] to_streamed_response_wrapper( - runs.submit_tool_outputs # pyright: ignore[reportDeprecated], + runs.submit_tool_outputs, # pyright: ignore[reportDeprecated], ) ) @@ -3046,32 +3046,32 @@ def __init__(self, runs: AsyncRuns) -> None: self.create = ( # pyright: ignore[reportDeprecated] async_to_streamed_response_wrapper( - runs.create # pyright: ignore[reportDeprecated], + runs.create, # pyright: ignore[reportDeprecated], ) ) self.retrieve = ( # pyright: ignore[reportDeprecated] async_to_streamed_response_wrapper( - runs.retrieve # pyright: ignore[reportDeprecated], + runs.retrieve, # pyright: ignore[reportDeprecated], ) ) self.update = ( # pyright: ignore[reportDeprecated] async_to_streamed_response_wrapper( - runs.update # pyright: ignore[reportDeprecated], + runs.update, # pyright: ignore[reportDeprecated], ) ) self.list = ( # pyright: ignore[reportDeprecated] async_to_streamed_response_wrapper( - runs.list # pyright: ignore[reportDeprecated], + runs.list, # pyright: ignore[reportDeprecated], ) ) self.cancel = ( # pyright: ignore[reportDeprecated] async_to_streamed_response_wrapper( - runs.cancel # pyright: ignore[reportDeprecated], + runs.cancel, # pyright: ignore[reportDeprecated], ) ) self.submit_tool_outputs = ( # pyright: ignore[reportDeprecated] async_to_streamed_response_wrapper( - runs.submit_tool_outputs # pyright: ignore[reportDeprecated], + runs.submit_tool_outputs, # pyright: ignore[reportDeprecated], ) ) diff --git a/src/openai/resources/beta/threads/runs/steps.py b/src/openai/resources/beta/threads/runs/steps.py index eebb2003b2..8e34210bd7 100644 --- a/src/openai/resources/beta/threads/runs/steps.py +++ b/src/openai/resources/beta/threads/runs/steps.py @@ -341,12 +341,12 @@ def __init__(self, steps: Steps) -> None: self.retrieve = ( # pyright: ignore[reportDeprecated] _legacy_response.to_raw_response_wrapper( - steps.retrieve # pyright: ignore[reportDeprecated], + steps.retrieve, # pyright: ignore[reportDeprecated], ) ) self.list = ( # pyright: ignore[reportDeprecated] _legacy_response.to_raw_response_wrapper( - steps.list # pyright: ignore[reportDeprecated], + steps.list, # pyright: ignore[reportDeprecated], ) ) @@ -357,12 +357,12 @@ def __init__(self, steps: AsyncSteps) -> None: self.retrieve = ( # pyright: ignore[reportDeprecated] _legacy_response.async_to_raw_response_wrapper( - steps.retrieve # pyright: ignore[reportDeprecated], + steps.retrieve, # pyright: ignore[reportDeprecated], ) ) self.list = ( # pyright: ignore[reportDeprecated] _legacy_response.async_to_raw_response_wrapper( - steps.list # pyright: ignore[reportDeprecated], + steps.list, # pyright: ignore[reportDeprecated], ) ) @@ -373,12 +373,12 @@ def __init__(self, steps: Steps) -> None: self.retrieve = ( # pyright: ignore[reportDeprecated] to_streamed_response_wrapper( - steps.retrieve # pyright: ignore[reportDeprecated], + steps.retrieve, # pyright: ignore[reportDeprecated], ) ) self.list = ( # pyright: ignore[reportDeprecated] to_streamed_response_wrapper( - steps.list # pyright: ignore[reportDeprecated], + steps.list, # pyright: ignore[reportDeprecated], ) ) @@ -389,11 +389,11 @@ def __init__(self, steps: AsyncSteps) -> None: self.retrieve = ( # pyright: ignore[reportDeprecated] async_to_streamed_response_wrapper( - steps.retrieve # pyright: ignore[reportDeprecated], + steps.retrieve, # pyright: ignore[reportDeprecated], ) ) self.list = ( # pyright: ignore[reportDeprecated] async_to_streamed_response_wrapper( - steps.list # pyright: ignore[reportDeprecated], + steps.list, # pyright: ignore[reportDeprecated], ) ) diff --git a/src/openai/resources/beta/threads/threads.py b/src/openai/resources/beta/threads/threads.py index dbe47d2d0e..7121851cab 100644 --- a/src/openai/resources/beta/threads/threads.py +++ b/src/openai/resources/beta/threads/threads.py @@ -1785,27 +1785,27 @@ def __init__(self, threads: Threads) -> None: self.create = ( # pyright: ignore[reportDeprecated] _legacy_response.to_raw_response_wrapper( - threads.create # pyright: ignore[reportDeprecated], + threads.create, # pyright: ignore[reportDeprecated], ) ) self.retrieve = ( # pyright: ignore[reportDeprecated] _legacy_response.to_raw_response_wrapper( - threads.retrieve # pyright: ignore[reportDeprecated], + threads.retrieve, # pyright: ignore[reportDeprecated], ) ) self.update = ( # pyright: ignore[reportDeprecated] _legacy_response.to_raw_response_wrapper( - threads.update # pyright: ignore[reportDeprecated], + threads.update, # pyright: ignore[reportDeprecated], ) ) self.delete = ( # pyright: ignore[reportDeprecated] _legacy_response.to_raw_response_wrapper( - threads.delete # pyright: ignore[reportDeprecated], + threads.delete, # pyright: ignore[reportDeprecated], ) ) self.create_and_run = ( # pyright: ignore[reportDeprecated] _legacy_response.to_raw_response_wrapper( - threads.create_and_run # pyright: ignore[reportDeprecated], + threads.create_and_run, # pyright: ignore[reportDeprecated], ) ) @@ -1824,27 +1824,27 @@ def __init__(self, threads: AsyncThreads) -> None: self.create = ( # pyright: ignore[reportDeprecated] _legacy_response.async_to_raw_response_wrapper( - threads.create # pyright: ignore[reportDeprecated], + threads.create, # pyright: ignore[reportDeprecated], ) ) self.retrieve = ( # pyright: ignore[reportDeprecated] _legacy_response.async_to_raw_response_wrapper( - threads.retrieve # pyright: ignore[reportDeprecated], + threads.retrieve, # pyright: ignore[reportDeprecated], ) ) self.update = ( # pyright: ignore[reportDeprecated] _legacy_response.async_to_raw_response_wrapper( - threads.update # pyright: ignore[reportDeprecated], + threads.update, # pyright: ignore[reportDeprecated], ) ) self.delete = ( # pyright: ignore[reportDeprecated] _legacy_response.async_to_raw_response_wrapper( - threads.delete # pyright: ignore[reportDeprecated], + threads.delete, # pyright: ignore[reportDeprecated], ) ) self.create_and_run = ( # pyright: ignore[reportDeprecated] _legacy_response.async_to_raw_response_wrapper( - threads.create_and_run # pyright: ignore[reportDeprecated], + threads.create_and_run, # pyright: ignore[reportDeprecated], ) ) @@ -1863,27 +1863,27 @@ def __init__(self, threads: Threads) -> None: self.create = ( # pyright: ignore[reportDeprecated] to_streamed_response_wrapper( - threads.create # pyright: ignore[reportDeprecated], + threads.create, # pyright: ignore[reportDeprecated], ) ) self.retrieve = ( # pyright: ignore[reportDeprecated] to_streamed_response_wrapper( - threads.retrieve # pyright: ignore[reportDeprecated], + threads.retrieve, # pyright: ignore[reportDeprecated], ) ) self.update = ( # pyright: ignore[reportDeprecated] to_streamed_response_wrapper( - threads.update # pyright: ignore[reportDeprecated], + threads.update, # pyright: ignore[reportDeprecated], ) ) self.delete = ( # pyright: ignore[reportDeprecated] to_streamed_response_wrapper( - threads.delete # pyright: ignore[reportDeprecated], + threads.delete, # pyright: ignore[reportDeprecated], ) ) self.create_and_run = ( # pyright: ignore[reportDeprecated] to_streamed_response_wrapper( - threads.create_and_run # pyright: ignore[reportDeprecated], + threads.create_and_run, # pyright: ignore[reportDeprecated], ) ) @@ -1902,27 +1902,27 @@ def __init__(self, threads: AsyncThreads) -> None: self.create = ( # pyright: ignore[reportDeprecated] async_to_streamed_response_wrapper( - threads.create # pyright: ignore[reportDeprecated], + threads.create, # pyright: ignore[reportDeprecated], ) ) self.retrieve = ( # pyright: ignore[reportDeprecated] async_to_streamed_response_wrapper( - threads.retrieve # pyright: ignore[reportDeprecated], + threads.retrieve, # pyright: ignore[reportDeprecated], ) ) self.update = ( # pyright: ignore[reportDeprecated] async_to_streamed_response_wrapper( - threads.update # pyright: ignore[reportDeprecated], + threads.update, # pyright: ignore[reportDeprecated], ) ) self.delete = ( # pyright: ignore[reportDeprecated] async_to_streamed_response_wrapper( - threads.delete # pyright: ignore[reportDeprecated], + threads.delete, # pyright: ignore[reportDeprecated], ) ) self.create_and_run = ( # pyright: ignore[reportDeprecated] async_to_streamed_response_wrapper( - threads.create_and_run # pyright: ignore[reportDeprecated], + threads.create_and_run, # pyright: ignore[reportDeprecated], ) ) diff --git a/src/openai/resources/files.py b/src/openai/resources/files.py index b45b8f303f..963c3c0a9f 100644 --- a/src/openai/resources/files.py +++ b/src/openai/resources/files.py @@ -687,7 +687,7 @@ def __init__(self, files: Files) -> None: ) self.retrieve_content = ( # pyright: ignore[reportDeprecated] _legacy_response.to_raw_response_wrapper( - files.retrieve_content # pyright: ignore[reportDeprecated], + files.retrieve_content, # pyright: ignore[reportDeprecated], ) ) @@ -713,7 +713,7 @@ def __init__(self, files: AsyncFiles) -> None: ) self.retrieve_content = ( # pyright: ignore[reportDeprecated] _legacy_response.async_to_raw_response_wrapper( - files.retrieve_content # pyright: ignore[reportDeprecated], + files.retrieve_content, # pyright: ignore[reportDeprecated], ) ) @@ -740,7 +740,7 @@ def __init__(self, files: Files) -> None: ) self.retrieve_content = ( # pyright: ignore[reportDeprecated] to_streamed_response_wrapper( - files.retrieve_content # pyright: ignore[reportDeprecated], + files.retrieve_content, # pyright: ignore[reportDeprecated], ) ) @@ -767,6 +767,6 @@ def __init__(self, files: AsyncFiles) -> None: ) self.retrieve_content = ( # pyright: ignore[reportDeprecated] async_to_streamed_response_wrapper( - files.retrieve_content # pyright: ignore[reportDeprecated], + files.retrieve_content, # pyright: ignore[reportDeprecated], ) ) From 061ebd6325b5fabaa560d7c1432c99a284efc337 Mon Sep 17 00:00:00 2001 From: Kar Petrosyan <92274156+karpetrosyan@users.noreply.github.com> Date: Wed, 27 Aug 2025 23:29:21 +0400 Subject: [PATCH 465/769] chore: bump `inline-snapshot` version to 0.28.0 (#2590) --- pyproject.toml | 2 +- requirements-dev.lock | 2 +- tests/lib/chat/test_completions_streaming.py | 3 ++- tests/lib/snapshots.py | 3 +-- tests/lib/utils.py | 12 ------------ 5 files changed, 5 insertions(+), 17 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index fbc6c31f00..2633918fc0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -64,7 +64,7 @@ dev-dependencies = [ "dirty-equals>=0.6.0", "importlib-metadata>=6.7.0", "rich>=13.7.1", - "inline-snapshot >=0.7.0", + "inline-snapshot>=0.28.0", "azure-identity >=1.14.1", "types-tqdm > 4", "types-pyaudio > 0", diff --git a/requirements-dev.lock b/requirements-dev.lock index e8bea53014..669378387d 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -90,7 +90,7 @@ idna==3.4 importlib-metadata==7.0.0 iniconfig==2.0.0 # via pytest -inline-snapshot==0.27.0 +inline-snapshot==0.28.0 jiter==0.5.0 # via openai markdown-it-py==3.0.0 diff --git a/tests/lib/chat/test_completions_streaming.py b/tests/lib/chat/test_completions_streaming.py index fa17f67177..548416dfe2 100644 --- a/tests/lib/chat/test_completions_streaming.py +++ b/tests/lib/chat/test_completions_streaming.py @@ -13,6 +13,7 @@ external, snapshot, outsource, # pyright: ignore[reportUnknownVariableType] + get_snapshot_value, ) import openai @@ -30,7 +31,7 @@ ) from openai.lib._parsing._completions import ResponseFormatT -from ..utils import print_obj, get_snapshot_value +from ..utils import print_obj from ...conftest import base_url _T = TypeVar("_T") diff --git a/tests/lib/snapshots.py b/tests/lib/snapshots.py index ed53edebcb..91222acda1 100644 --- a/tests/lib/snapshots.py +++ b/tests/lib/snapshots.py @@ -7,11 +7,10 @@ import httpx from respx import MockRouter +from inline_snapshot import get_snapshot_value from openai import OpenAI, AsyncOpenAI -from .utils import get_snapshot_value - _T = TypeVar("_T") diff --git a/tests/lib/utils.py b/tests/lib/utils.py index 2129ee811a..e6b6a29434 100644 --- a/tests/lib/utils.py +++ b/tests/lib/utils.py @@ -52,15 +52,3 @@ def get_caller_name(*, stacklevel: int = 1) -> str: def clear_locals(string: str, *, stacklevel: int) -> str: caller = get_caller_name(stacklevel=stacklevel + 1) return string.replace(f"{caller}..", "") - - -def get_snapshot_value(snapshot: Any) -> Any: - if not hasattr(snapshot, "_old_value"): - return snapshot - - old = snapshot._old_value - if not hasattr(old, "value"): - return old - - loader = getattr(old.value, "_load_value", None) - return loader() if loader else old.value From 845466f6caddcf3eceb31e770298cecd3f4f0a6e Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Wed, 27 Aug 2025 16:27:07 -0400 Subject: [PATCH 466/769] fix(responses): add missing params to stream() method --- src/openai/resources/responses/responses.py | 76 ++++++++++++++++++--- tests/lib/responses/test_responses.py | 24 ++++++- 2 files changed, 89 insertions(+), 11 deletions(-) diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 062fd491f2..e04382a9ff 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -31,7 +31,6 @@ parse_response, type_to_text_format_param as _type_to_text_format_param, ) -from ...types.shared.chat_model import ChatModel from ...types.responses.response import Response from ...types.responses.tool_param import ToolParam, ParseableToolParam from ...types.shared_params.metadata import Metadata @@ -881,22 +880,29 @@ def stream( self, *, input: Union[str, ResponseInputParam], - model: Union[str, ChatModel], + model: ResponsesModel, background: Optional[bool] | NotGiven = NOT_GIVEN, text_format: type[TextFormatT] | NotGiven = NOT_GIVEN, tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, + conversation: Optional[response_create_params.Conversation] | NotGiven = NOT_GIVEN, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + max_tool_calls: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, + prompt_cache_key: str | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + safety_identifier: str | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam| NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, + top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, @@ -913,22 +919,29 @@ def stream( *, response_id: str | NotGiven = NOT_GIVEN, input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel] | NotGiven = NOT_GIVEN, + model: ResponsesModel | NotGiven = NOT_GIVEN, background: Optional[bool] | NotGiven = NOT_GIVEN, text_format: type[TextFormatT] | NotGiven = NOT_GIVEN, tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, + conversation: Optional[response_create_params.Conversation] | NotGiven = NOT_GIVEN, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + max_tool_calls: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, + prompt_cache_key: str | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + safety_identifier: str | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, + top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, @@ -943,18 +956,25 @@ def stream( new_response_args = { "input": input, "model": model, + "conversation": conversation, "include": include, "instructions": instructions, "max_output_tokens": max_output_tokens, + "max_tool_calls": max_tool_calls, "metadata": metadata, "parallel_tool_calls": parallel_tool_calls, "previous_response_id": previous_response_id, + "prompt": prompt, + "prompt_cache_key": prompt_cache_key, "reasoning": reasoning, + "safety_identifier": safety_identifier, + "service_tier": service_tier, "store": store, "stream_options": stream_options, "temperature": temperature, "text": text, "tool_choice": tool_choice, + "top_logprobs": top_logprobs, "top_p": top_p, "truncation": truncation, "user": user, @@ -989,12 +1009,16 @@ def stream( input=input, model=model, tools=tools, + conversation=conversation, include=include, instructions=instructions, max_output_tokens=max_output_tokens, + max_tool_calls=max_tool_calls, metadata=metadata, parallel_tool_calls=parallel_tool_calls, previous_response_id=previous_response_id, + prompt=prompt, + prompt_cache_key=prompt_cache_key, store=store, stream_options=stream_options, stream=True, @@ -1002,6 +1026,9 @@ def stream( text=text, tool_choice=tool_choice, reasoning=reasoning, + safety_identifier=safety_identifier, + service_tier=service_tier, + top_logprobs=top_logprobs, top_p=top_p, truncation=truncation, user=user, @@ -1057,7 +1084,7 @@ def parse( stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam| NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, @@ -2275,22 +2302,29 @@ def stream( self, *, input: Union[str, ResponseInputParam], - model: Union[str, ChatModel], + model: ResponsesModel, background: Optional[bool] | NotGiven = NOT_GIVEN, text_format: type[TextFormatT] | NotGiven = NOT_GIVEN, tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, + conversation: Optional[response_create_params.Conversation] | NotGiven = NOT_GIVEN, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + max_tool_calls: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, + prompt_cache_key: str | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + safety_identifier: str | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam| NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, + top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, @@ -2307,22 +2341,29 @@ def stream( *, response_id: str | NotGiven = NOT_GIVEN, input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel] | NotGiven = NOT_GIVEN, + model: ResponsesModel | NotGiven = NOT_GIVEN, background: Optional[bool] | NotGiven = NOT_GIVEN, text_format: type[TextFormatT] | NotGiven = NOT_GIVEN, tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, + conversation: Optional[response_create_params.Conversation] | NotGiven = NOT_GIVEN, include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, + max_tool_calls: Optional[int] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, + prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, + prompt_cache_key: str | NotGiven = NOT_GIVEN, reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, + safety_identifier: str | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam| NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, + top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, top_p: Optional[float] | NotGiven = NOT_GIVEN, truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, user: str | NotGiven = NOT_GIVEN, @@ -2337,18 +2378,25 @@ def stream( new_response_args = { "input": input, "model": model, + "conversation": conversation, "include": include, "instructions": instructions, "max_output_tokens": max_output_tokens, + "max_tool_calls": max_tool_calls, "metadata": metadata, "parallel_tool_calls": parallel_tool_calls, "previous_response_id": previous_response_id, + "prompt": prompt, + "prompt_cache_key": prompt_cache_key, "reasoning": reasoning, + "safety_identifier": safety_identifier, + "service_tier": service_tier, "store": store, "stream_options": stream_options, "temperature": temperature, "text": text, "tool_choice": tool_choice, + "top_logprobs": top_logprobs, "top_p": top_p, "truncation": truncation, "user": user, @@ -2384,21 +2432,29 @@ def stream( model=model, stream=True, tools=tools, + conversation=conversation, include=include, instructions=instructions, max_output_tokens=max_output_tokens, + max_tool_calls=max_tool_calls, metadata=metadata, parallel_tool_calls=parallel_tool_calls, previous_response_id=previous_response_id, + prompt=prompt, + prompt_cache_key=prompt_cache_key, store=store, stream_options=stream_options, temperature=temperature, text=text, tool_choice=tool_choice, reasoning=reasoning, + safety_identifier=safety_identifier, + service_tier=service_tier, + top_logprobs=top_logprobs, top_p=top_p, truncation=truncation, user=user, + background=background, extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, @@ -2455,7 +2511,7 @@ async def parse( stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam| NotGiven = NOT_GIVEN, + text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, diff --git a/tests/lib/responses/test_responses.py b/tests/lib/responses/test_responses.py index 8ce3462e76..31b6e55ddc 100644 --- a/tests/lib/responses/test_responses.py +++ b/tests/lib/responses/test_responses.py @@ -6,7 +6,8 @@ from respx import MockRouter from inline_snapshot import snapshot -from openai import OpenAI +from openai import OpenAI, AsyncOpenAI +from openai._utils import assert_signatures_in_sync from ...conftest import base_url from ..snapshots import make_snapshot_request @@ -38,3 +39,24 @@ def test_output_text(client: OpenAI, respx_mock: MockRouter) -> None: assert response.output_text == snapshot( "I can't provide real-time updates, but you can easily check the current weather in San Francisco using a weather website or app. Typically, San Francisco has cool, foggy summers and mild winters, so it's good to be prepared for variable weather!" ) + + +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +def test_stream_method_definition_in_sync(sync: bool, client: OpenAI, async_client: AsyncOpenAI) -> None: + checking_client: OpenAI | AsyncOpenAI = client if sync else async_client + + assert_signatures_in_sync( + checking_client.responses.create, + checking_client.responses.stream, + exclude_params={"stream", "tools"}, + ) + +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +def test_parse_method_definition_in_sync(sync: bool, client: OpenAI, async_client: AsyncOpenAI) -> None: + checking_client: OpenAI | AsyncOpenAI = client if sync else async_client + + assert_signatures_in_sync( + checking_client.responses.create, + checking_client.responses.parse, + exclude_params={"tools"}, + ) From 2843a64c9c26a720a931845a83302c72b85f241b Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Fri, 29 Aug 2025 14:45:59 -0400 Subject: [PATCH 467/769] chore(internal): fix formatting --- tests/lib/responses/test_responses.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/lib/responses/test_responses.py b/tests/lib/responses/test_responses.py index 31b6e55ddc..8e5f16df95 100644 --- a/tests/lib/responses/test_responses.py +++ b/tests/lib/responses/test_responses.py @@ -51,6 +51,7 @@ def test_stream_method_definition_in_sync(sync: bool, client: OpenAI, async_clie exclude_params={"stream", "tools"}, ) + @pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) def test_parse_method_definition_in_sync(sync: bool, client: OpenAI, async_client: AsyncOpenAI) -> None: checking_client: OpenAI | AsyncOpenAI = client if sync else async_client From 463e870dcd4ddf94dafb4808850c6fdbecd36a88 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 29 Aug 2025 19:14:21 +0000 Subject: [PATCH 468/769] chore(internal): add Sequence related utils --- src/openai/_types.py | 36 ++++++++++++++++++++++++++++++++++- src/openai/_utils/__init__.py | 1 + src/openai/_utils/_typing.py | 5 +++++ tests/utils.py | 10 +++++++++- 4 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/openai/_types.py b/src/openai/_types.py index 5dae55f4a9..0e8ffa12aa 100644 --- a/src/openai/_types.py +++ b/src/openai/_types.py @@ -13,10 +13,21 @@ Mapping, TypeVar, Callable, + Iterator, Optional, Sequence, ) -from typing_extensions import Set, Literal, Protocol, TypeAlias, TypedDict, override, runtime_checkable +from typing_extensions import ( + Set, + Literal, + Protocol, + TypeAlias, + TypedDict, + SupportsIndex, + overload, + override, + runtime_checkable, +) import httpx import pydantic @@ -219,3 +230,26 @@ class _GenericAlias(Protocol): class HttpxSendArgs(TypedDict, total=False): auth: httpx.Auth follow_redirects: bool + + +_T_co = TypeVar("_T_co", covariant=True) + + +if TYPE_CHECKING: + # This works because str.__contains__ does not accept object (either in typeshed or at runtime) + # https://github.com/hauntsaninja/useful_types/blob/5e9710f3875107d068e7679fd7fec9cfab0eff3b/useful_types/__init__.py#L285 + class SequenceNotStr(Protocol[_T_co]): + @overload + def __getitem__(self, index: SupportsIndex, /) -> _T_co: ... + @overload + def __getitem__(self, index: slice, /) -> Sequence[_T_co]: ... + def __contains__(self, value: object, /) -> bool: ... + def __len__(self) -> int: ... + def __iter__(self) -> Iterator[_T_co]: ... + def index(self, value: Any, start: int = 0, stop: int = ..., /) -> int: ... + def count(self, value: Any, /) -> int: ... + def __reversed__(self) -> Iterator[_T_co]: ... +else: + # just point this to a normal `Sequence` at runtime to avoid having to special case + # deserializing our custom sequence type + SequenceNotStr = Sequence diff --git a/src/openai/_utils/__init__.py b/src/openai/_utils/__init__.py index bd01c088dc..6471aa4c0d 100644 --- a/src/openai/_utils/__init__.py +++ b/src/openai/_utils/__init__.py @@ -41,6 +41,7 @@ extract_type_arg as extract_type_arg, is_iterable_type as is_iterable_type, is_required_type as is_required_type, + is_sequence_type as is_sequence_type, is_annotated_type as is_annotated_type, is_type_alias_type as is_type_alias_type, strip_annotated_type as strip_annotated_type, diff --git a/src/openai/_utils/_typing.py b/src/openai/_utils/_typing.py index 1bac9542e2..845cd6b287 100644 --- a/src/openai/_utils/_typing.py +++ b/src/openai/_utils/_typing.py @@ -26,6 +26,11 @@ def is_list_type(typ: type) -> bool: return (get_origin(typ) or typ) == list +def is_sequence_type(typ: type) -> bool: + origin = get_origin(typ) or typ + return origin == typing_extensions.Sequence or origin == typing.Sequence or origin == _c_abc.Sequence + + def is_iterable_type(typ: type) -> bool: """If the given type is `typing.Iterable[T]`""" origin = get_origin(typ) or typ diff --git a/tests/utils.py b/tests/utils.py index 4cf5ce171b..7740ed3f7c 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -5,7 +5,7 @@ import inspect import traceback import contextlib -from typing import Any, TypeVar, Iterator, ForwardRef, cast +from typing import Any, TypeVar, Iterator, ForwardRef, Sequence, cast from datetime import date, datetime from typing_extensions import Literal, get_args, get_origin, assert_type @@ -18,6 +18,7 @@ is_list_type, is_union_type, extract_type_arg, + is_sequence_type, is_annotated_type, is_type_alias_type, ) @@ -78,6 +79,13 @@ def assert_matches_type( if is_list_type(type_): return _assert_list_type(type_, value) + if is_sequence_type(type_): + assert isinstance(value, Sequence) + inner_type = get_args(type_)[0] + for entry in value: # type: ignore + assert_type(inner_type, entry) # type: ignore + return + if origin == str: assert isinstance(value, str) elif origin == int: From 3d3d16ab5de830665adf13df82c991b60385531d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 2 Sep 2025 13:46:20 +0000 Subject: [PATCH 469/769] feat(api): realtime API updates --- .stats.yml | 8 +- README.md | 6 +- api.md | 111 ++ examples/realtime/audio_util.py | 2 +- examples/realtime/azure_realtime.py | 16 +- examples/realtime/push_to_talk_app.py | 20 +- examples/realtime/realtime.py | 54 + src/openai/__init__.py | 1 + src/openai/_client.py | 38 + src/openai/_module_client.py | 8 + src/openai/resources/audio/speech.py | 8 +- src/openai/resources/beta/beta.py | 20 - src/openai/resources/realtime/__init__.py | 33 + .../resources/realtime/client_secrets.py | 185 +++ src/openai/resources/realtime/realtime.py | 1056 +++++++++++++++++ src/openai/resources/responses/responses.py | 30 +- .../types/audio/speech_create_params.py | 4 +- .../types/chat/chat_completion_audio_param.py | 4 +- src/openai/types/realtime/__init__.py | 184 +++ .../realtime/client_secret_create_params.py | 39 + .../realtime/client_secret_create_response.py | 110 ++ .../realtime/conversation_created_event.py | 27 + .../types/realtime/conversation_item.py | 32 + .../types/realtime/conversation_item_added.py | 26 + .../conversation_item_create_event.py | 29 + .../conversation_item_create_event_param.py | 29 + .../conversation_item_created_event.py | 27 + .../conversation_item_delete_event.py | 19 + .../conversation_item_delete_event_param.py | 18 + .../conversation_item_deleted_event.py | 18 + .../types/realtime/conversation_item_done.py | 26 + ...put_audio_transcription_completed_event.py | 76 ++ ...m_input_audio_transcription_delta_event.py | 29 + ..._input_audio_transcription_failed_event.py | 39 + ..._item_input_audio_transcription_segment.py | 36 + .../types/realtime/conversation_item_param.py | 30 + .../conversation_item_retrieve_event.py | 19 + .../conversation_item_retrieve_event_param.py | 18 + .../conversation_item_truncate_event.py | 32 + .../conversation_item_truncate_event_param.py | 31 + .../conversation_item_truncated_event.py | 24 + .../input_audio_buffer_append_event.py | 23 + .../input_audio_buffer_append_event_param.py | 22 + .../input_audio_buffer_clear_event.py | 16 + .../input_audio_buffer_clear_event_param.py | 15 + .../input_audio_buffer_cleared_event.py | 15 + .../input_audio_buffer_commit_event.py | 16 + .../input_audio_buffer_commit_event_param.py | 15 + .../input_audio_buffer_committed_event.py | 25 + ...input_audio_buffer_speech_started_event.py | 26 + ...input_audio_buffer_speech_stopped_event.py | 25 + .../input_audio_buffer_timeout_triggered.py | 24 + .../types/realtime/log_prob_properties.py | 18 + .../realtime/mcp_list_tools_completed.py | 18 + .../types/realtime/mcp_list_tools_failed.py | 18 + .../realtime/mcp_list_tools_in_progress.py | 18 + .../output_audio_buffer_clear_event.py | 16 + .../output_audio_buffer_clear_event_param.py | 15 + .../realtime/rate_limits_updated_event.py | 33 + .../types/realtime/realtime_audio_config.py | 184 +++ .../realtime/realtime_audio_config_param.py | 187 +++ .../types/realtime/realtime_client_event.py | 38 + .../realtime/realtime_client_event_param.py | 36 + .../realtime/realtime_client_secret_config.py | 27 + .../realtime_client_secret_config_param.py | 26 + .../types/realtime/realtime_connect_params.py | 11 + ...ime_conversation_item_assistant_message.py | 36 + ...nversation_item_assistant_message_param.py | 36 + ...ealtime_conversation_item_function_call.py | 31 + ..._conversation_item_function_call_output.py | 28 + ...rsation_item_function_call_output_param.py | 27 + ...e_conversation_item_function_call_param.py | 30 + ...altime_conversation_item_system_message.py | 36 + ..._conversation_item_system_message_param.py | 36 + ...realtime_conversation_item_user_message.py | 42 + ...me_conversation_item_user_message_param.py | 42 + src/openai/types/realtime/realtime_error.py | 24 + .../types/realtime/realtime_error_event.py | 19 + .../realtime/realtime_mcp_approval_request.py | 24 + .../realtime_mcp_approval_request_param.py | 24 + .../realtime_mcp_approval_response.py | 25 + .../realtime_mcp_approval_response_param.py | 25 + .../types/realtime/realtime_mcp_list_tools.py | 36 + .../realtime/realtime_mcp_list_tools_param.py | 36 + .../realtime/realtime_mcp_protocol_error.py | 15 + .../realtime_mcp_protocol_error_param.py | 15 + .../types/realtime/realtime_mcp_tool_call.py | 43 + .../realtime/realtime_mcp_tool_call_param.py | 40 + .../realtime_mcp_tool_execution_error.py | 13 + ...realtime_mcp_tool_execution_error_param.py | 13 + .../types/realtime/realtime_mcphttp_error.py | 15 + .../realtime/realtime_mcphttp_error_param.py | 15 + .../types/realtime/realtime_response.py | 89 ++ .../realtime/realtime_response_status.py | 39 + .../types/realtime/realtime_response_usage.py | 35 + ...time_response_usage_input_token_details.py | 18 + ...ime_response_usage_output_token_details.py | 15 + .../types/realtime/realtime_server_event.py | 159 +++ src/openai/types/realtime/realtime_session.py | 305 +++++ .../realtime_session_create_request.py | 116 ++ .../realtime_session_create_request_param.py | 119 ++ .../realtime_session_create_response.py | 222 ++++ .../realtime/realtime_tool_choice_config.py | 12 + .../realtime_tool_choice_config_param.py | 14 + .../types/realtime/realtime_tools_config.py | 10 + .../realtime/realtime_tools_config_param.py | 158 +++ .../realtime/realtime_tools_config_union.py | 158 +++ .../realtime_tools_config_union_param.py | 155 +++ .../types/realtime/realtime_tracing_config.py | 31 + .../realtime/realtime_tracing_config_param.py | 31 + ...me_transcription_session_create_request.py | 128 ++ ...nscription_session_create_request_param.py | 128 ++ .../types/realtime/realtime_truncation.py | 22 + .../realtime/realtime_truncation_param.py | 22 + .../realtime/response_audio_delta_event.py | 30 + .../realtime/response_audio_done_event.py | 27 + .../response_audio_transcript_delta_event.py | 30 + .../response_audio_transcript_done_event.py | 30 + .../types/realtime/response_cancel_event.py | 22 + .../realtime/response_cancel_event_param.py | 21 + .../response_content_part_added_event.py | 45 + .../response_content_part_done_event.py | 45 + .../types/realtime/response_create_event.py | 134 +++ .../realtime/response_create_event_param.py | 133 +++ .../types/realtime/response_created_event.py | 19 + .../types/realtime/response_done_event.py | 19 + ...nse_function_call_arguments_delta_event.py | 30 + ...onse_function_call_arguments_done_event.py | 30 + .../response_mcp_call_arguments_delta.py | 31 + .../response_mcp_call_arguments_done.py | 27 + .../realtime/response_mcp_call_completed.py | 21 + .../realtime/response_mcp_call_failed.py | 21 + .../realtime/response_mcp_call_in_progress.py | 21 + .../response_output_item_added_event.py | 25 + .../response_output_item_done_event.py | 25 + .../realtime/response_text_delta_event.py | 30 + .../realtime/response_text_done_event.py | 30 + .../types/realtime/session_created_event.py | 19 + .../types/realtime/session_update_event.py | 20 + .../realtime/session_update_event_param.py | 20 + .../types/realtime/session_updated_event.py | 19 + .../realtime/transcription_session_created.py | 105 ++ .../realtime/transcription_session_update.py | 20 + .../transcription_session_update_param.py | 20 + .../transcription_session_updated_event.py | 105 ++ src/openai/types/responses/__init__.py | 2 + src/openai/types/responses/response.py | 5 +- .../types/responses/response_create_params.py | 5 +- src/openai/types/responses/tool.py | 62 +- src/openai/types/responses/tool_param.py | 63 +- .../responses/web_search_preview_tool.py | 49 + .../web_search_preview_tool_param.py | 49 + src/openai/types/responses/web_search_tool.py | 30 +- .../types/responses/web_search_tool_param.py | 30 +- src/openai/types/webhooks/__init__.py | 1 + .../realtime_call_incoming_webhook_event.py | 41 + .../types/webhooks/unwrap_webhook_event.py | 2 + .../beta/realtime/test_sessions.py | 166 --- .../realtime/test_transcription_sessions.py | 134 --- tests/api_resources/beta/test_realtime.py | 2 + .../{beta => }/realtime/__init__.py | 0 .../realtime/test_client_secrets.py | 208 ++++ tests/api_resources/test_realtime.py | 19 + 163 files changed, 7657 insertions(+), 486 deletions(-) create mode 100755 examples/realtime/realtime.py create mode 100644 src/openai/resources/realtime/__init__.py create mode 100644 src/openai/resources/realtime/client_secrets.py create mode 100644 src/openai/resources/realtime/realtime.py create mode 100644 src/openai/types/realtime/__init__.py create mode 100644 src/openai/types/realtime/client_secret_create_params.py create mode 100644 src/openai/types/realtime/client_secret_create_response.py create mode 100644 src/openai/types/realtime/conversation_created_event.py create mode 100644 src/openai/types/realtime/conversation_item.py create mode 100644 src/openai/types/realtime/conversation_item_added.py create mode 100644 src/openai/types/realtime/conversation_item_create_event.py create mode 100644 src/openai/types/realtime/conversation_item_create_event_param.py create mode 100644 src/openai/types/realtime/conversation_item_created_event.py create mode 100644 src/openai/types/realtime/conversation_item_delete_event.py create mode 100644 src/openai/types/realtime/conversation_item_delete_event_param.py create mode 100644 src/openai/types/realtime/conversation_item_deleted_event.py create mode 100644 src/openai/types/realtime/conversation_item_done.py create mode 100644 src/openai/types/realtime/conversation_item_input_audio_transcription_completed_event.py create mode 100644 src/openai/types/realtime/conversation_item_input_audio_transcription_delta_event.py create mode 100644 src/openai/types/realtime/conversation_item_input_audio_transcription_failed_event.py create mode 100644 src/openai/types/realtime/conversation_item_input_audio_transcription_segment.py create mode 100644 src/openai/types/realtime/conversation_item_param.py create mode 100644 src/openai/types/realtime/conversation_item_retrieve_event.py create mode 100644 src/openai/types/realtime/conversation_item_retrieve_event_param.py create mode 100644 src/openai/types/realtime/conversation_item_truncate_event.py create mode 100644 src/openai/types/realtime/conversation_item_truncate_event_param.py create mode 100644 src/openai/types/realtime/conversation_item_truncated_event.py create mode 100644 src/openai/types/realtime/input_audio_buffer_append_event.py create mode 100644 src/openai/types/realtime/input_audio_buffer_append_event_param.py create mode 100644 src/openai/types/realtime/input_audio_buffer_clear_event.py create mode 100644 src/openai/types/realtime/input_audio_buffer_clear_event_param.py create mode 100644 src/openai/types/realtime/input_audio_buffer_cleared_event.py create mode 100644 src/openai/types/realtime/input_audio_buffer_commit_event.py create mode 100644 src/openai/types/realtime/input_audio_buffer_commit_event_param.py create mode 100644 src/openai/types/realtime/input_audio_buffer_committed_event.py create mode 100644 src/openai/types/realtime/input_audio_buffer_speech_started_event.py create mode 100644 src/openai/types/realtime/input_audio_buffer_speech_stopped_event.py create mode 100644 src/openai/types/realtime/input_audio_buffer_timeout_triggered.py create mode 100644 src/openai/types/realtime/log_prob_properties.py create mode 100644 src/openai/types/realtime/mcp_list_tools_completed.py create mode 100644 src/openai/types/realtime/mcp_list_tools_failed.py create mode 100644 src/openai/types/realtime/mcp_list_tools_in_progress.py create mode 100644 src/openai/types/realtime/output_audio_buffer_clear_event.py create mode 100644 src/openai/types/realtime/output_audio_buffer_clear_event_param.py create mode 100644 src/openai/types/realtime/rate_limits_updated_event.py create mode 100644 src/openai/types/realtime/realtime_audio_config.py create mode 100644 src/openai/types/realtime/realtime_audio_config_param.py create mode 100644 src/openai/types/realtime/realtime_client_event.py create mode 100644 src/openai/types/realtime/realtime_client_event_param.py create mode 100644 src/openai/types/realtime/realtime_client_secret_config.py create mode 100644 src/openai/types/realtime/realtime_client_secret_config_param.py create mode 100644 src/openai/types/realtime/realtime_connect_params.py create mode 100644 src/openai/types/realtime/realtime_conversation_item_assistant_message.py create mode 100644 src/openai/types/realtime/realtime_conversation_item_assistant_message_param.py create mode 100644 src/openai/types/realtime/realtime_conversation_item_function_call.py create mode 100644 src/openai/types/realtime/realtime_conversation_item_function_call_output.py create mode 100644 src/openai/types/realtime/realtime_conversation_item_function_call_output_param.py create mode 100644 src/openai/types/realtime/realtime_conversation_item_function_call_param.py create mode 100644 src/openai/types/realtime/realtime_conversation_item_system_message.py create mode 100644 src/openai/types/realtime/realtime_conversation_item_system_message_param.py create mode 100644 src/openai/types/realtime/realtime_conversation_item_user_message.py create mode 100644 src/openai/types/realtime/realtime_conversation_item_user_message_param.py create mode 100644 src/openai/types/realtime/realtime_error.py create mode 100644 src/openai/types/realtime/realtime_error_event.py create mode 100644 src/openai/types/realtime/realtime_mcp_approval_request.py create mode 100644 src/openai/types/realtime/realtime_mcp_approval_request_param.py create mode 100644 src/openai/types/realtime/realtime_mcp_approval_response.py create mode 100644 src/openai/types/realtime/realtime_mcp_approval_response_param.py create mode 100644 src/openai/types/realtime/realtime_mcp_list_tools.py create mode 100644 src/openai/types/realtime/realtime_mcp_list_tools_param.py create mode 100644 src/openai/types/realtime/realtime_mcp_protocol_error.py create mode 100644 src/openai/types/realtime/realtime_mcp_protocol_error_param.py create mode 100644 src/openai/types/realtime/realtime_mcp_tool_call.py create mode 100644 src/openai/types/realtime/realtime_mcp_tool_call_param.py create mode 100644 src/openai/types/realtime/realtime_mcp_tool_execution_error.py create mode 100644 src/openai/types/realtime/realtime_mcp_tool_execution_error_param.py create mode 100644 src/openai/types/realtime/realtime_mcphttp_error.py create mode 100644 src/openai/types/realtime/realtime_mcphttp_error_param.py create mode 100644 src/openai/types/realtime/realtime_response.py create mode 100644 src/openai/types/realtime/realtime_response_status.py create mode 100644 src/openai/types/realtime/realtime_response_usage.py create mode 100644 src/openai/types/realtime/realtime_response_usage_input_token_details.py create mode 100644 src/openai/types/realtime/realtime_response_usage_output_token_details.py create mode 100644 src/openai/types/realtime/realtime_server_event.py create mode 100644 src/openai/types/realtime/realtime_session.py create mode 100644 src/openai/types/realtime/realtime_session_create_request.py create mode 100644 src/openai/types/realtime/realtime_session_create_request_param.py create mode 100644 src/openai/types/realtime/realtime_session_create_response.py create mode 100644 src/openai/types/realtime/realtime_tool_choice_config.py create mode 100644 src/openai/types/realtime/realtime_tool_choice_config_param.py create mode 100644 src/openai/types/realtime/realtime_tools_config.py create mode 100644 src/openai/types/realtime/realtime_tools_config_param.py create mode 100644 src/openai/types/realtime/realtime_tools_config_union.py create mode 100644 src/openai/types/realtime/realtime_tools_config_union_param.py create mode 100644 src/openai/types/realtime/realtime_tracing_config.py create mode 100644 src/openai/types/realtime/realtime_tracing_config_param.py create mode 100644 src/openai/types/realtime/realtime_transcription_session_create_request.py create mode 100644 src/openai/types/realtime/realtime_transcription_session_create_request_param.py create mode 100644 src/openai/types/realtime/realtime_truncation.py create mode 100644 src/openai/types/realtime/realtime_truncation_param.py create mode 100644 src/openai/types/realtime/response_audio_delta_event.py create mode 100644 src/openai/types/realtime/response_audio_done_event.py create mode 100644 src/openai/types/realtime/response_audio_transcript_delta_event.py create mode 100644 src/openai/types/realtime/response_audio_transcript_done_event.py create mode 100644 src/openai/types/realtime/response_cancel_event.py create mode 100644 src/openai/types/realtime/response_cancel_event_param.py create mode 100644 src/openai/types/realtime/response_content_part_added_event.py create mode 100644 src/openai/types/realtime/response_content_part_done_event.py create mode 100644 src/openai/types/realtime/response_create_event.py create mode 100644 src/openai/types/realtime/response_create_event_param.py create mode 100644 src/openai/types/realtime/response_created_event.py create mode 100644 src/openai/types/realtime/response_done_event.py create mode 100644 src/openai/types/realtime/response_function_call_arguments_delta_event.py create mode 100644 src/openai/types/realtime/response_function_call_arguments_done_event.py create mode 100644 src/openai/types/realtime/response_mcp_call_arguments_delta.py create mode 100644 src/openai/types/realtime/response_mcp_call_arguments_done.py create mode 100644 src/openai/types/realtime/response_mcp_call_completed.py create mode 100644 src/openai/types/realtime/response_mcp_call_failed.py create mode 100644 src/openai/types/realtime/response_mcp_call_in_progress.py create mode 100644 src/openai/types/realtime/response_output_item_added_event.py create mode 100644 src/openai/types/realtime/response_output_item_done_event.py create mode 100644 src/openai/types/realtime/response_text_delta_event.py create mode 100644 src/openai/types/realtime/response_text_done_event.py create mode 100644 src/openai/types/realtime/session_created_event.py create mode 100644 src/openai/types/realtime/session_update_event.py create mode 100644 src/openai/types/realtime/session_update_event_param.py create mode 100644 src/openai/types/realtime/session_updated_event.py create mode 100644 src/openai/types/realtime/transcription_session_created.py create mode 100644 src/openai/types/realtime/transcription_session_update.py create mode 100644 src/openai/types/realtime/transcription_session_update_param.py create mode 100644 src/openai/types/realtime/transcription_session_updated_event.py create mode 100644 src/openai/types/responses/web_search_preview_tool.py create mode 100644 src/openai/types/responses/web_search_preview_tool_param.py create mode 100644 src/openai/types/webhooks/realtime_call_incoming_webhook_event.py delete mode 100644 tests/api_resources/beta/realtime/test_sessions.py delete mode 100644 tests/api_resources/beta/realtime/test_transcription_sessions.py rename tests/api_resources/{beta => }/realtime/__init__.py (100%) create mode 100644 tests/api_resources/realtime/test_client_secrets.py create mode 100644 tests/api_resources/test_realtime.py diff --git a/.stats.yml b/.stats.yml index 5ad90ac5ab..ebe81d146e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 119 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-8517ffa1004e31ca2523d617629e64be6fe4f13403ddfd9db5b3be002656cbde.yml -openapi_spec_hash: b64dd8c8b23082a7aa2a3e5c5fffd8bd -config_hash: fe0ea26680ac2075a6cd66416aefe7db +configured_endpoints: 118 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-356b4364203ff36d7724074cd04f6e684253bfcc3c9d969122d730aa7bc51b46.yml +openapi_spec_hash: 4ab8e96f52699bc3d2b0c4432aa92af8 +config_hash: b854932c0ea24b400bdd64e4376936bd diff --git a/README.md b/README.md index d4b8d8d170..9311b477a3 100644 --- a/README.md +++ b/README.md @@ -226,7 +226,7 @@ async def main(): asyncio.run(main()) ``` -## Realtime API beta +## Realtime API The Realtime API enables you to build low-latency, multi-modal conversational experiences. It currently supports text and audio as both input and output, as well as [function calling](https://platform.openai.com/docs/guides/function-calling) through a WebSocket connection. @@ -243,7 +243,7 @@ from openai import AsyncOpenAI async def main(): client = AsyncOpenAI() - async with client.beta.realtime.connect(model="gpt-4o-realtime-preview") as connection: + async with client.realtime.connect(model="gpt-realtime") as connection: await connection.session.update(session={'modalities': ['text']}) await connection.conversation.item.create( @@ -277,7 +277,7 @@ Whenever an error occurs, the Realtime API will send an [`error` event](https:// ```py client = AsyncOpenAI() -async with client.beta.realtime.connect(model="gpt-4o-realtime-preview") as connection: +async with client.realtime.connect(model="gpt-realtime") as connection: ... async for event in connection: if event.type == 'error': diff --git a/api.md b/api.md index 7eb62e67f2..a8a95bd23e 100644 --- a/api.md +++ b/api.md @@ -431,6 +431,7 @@ from openai.types.webhooks import ( FineTuningJobCancelledWebhookEvent, FineTuningJobFailedWebhookEvent, FineTuningJobSucceededWebhookEvent, + RealtimeCallIncomingWebhookEvent, ResponseCancelledWebhookEvent, ResponseCompletedWebhookEvent, ResponseFailedWebhookEvent, @@ -832,6 +833,7 @@ from openai.types.responses import ( ToolChoiceMcp, ToolChoiceOptions, ToolChoiceTypes, + WebSearchPreviewTool, WebSearchTool, ) ``` @@ -855,6 +857,115 @@ Methods: - client.responses.input_items.list(response_id, \*\*params) -> SyncCursorPage[ResponseItem] +# Realtime + +Types: + +```python +from openai.types.realtime import ( + ConversationCreatedEvent, + ConversationItem, + ConversationItemAdded, + ConversationItemCreateEvent, + ConversationItemCreatedEvent, + ConversationItemDeleteEvent, + ConversationItemDeletedEvent, + ConversationItemDone, + ConversationItemInputAudioTranscriptionCompletedEvent, + ConversationItemInputAudioTranscriptionDeltaEvent, + ConversationItemInputAudioTranscriptionFailedEvent, + ConversationItemInputAudioTranscriptionSegment, + ConversationItemRetrieveEvent, + ConversationItemTruncateEvent, + ConversationItemTruncatedEvent, + ConversationItemWithReference, + InputAudioBufferAppendEvent, + InputAudioBufferClearEvent, + InputAudioBufferClearedEvent, + InputAudioBufferCommitEvent, + InputAudioBufferCommittedEvent, + InputAudioBufferSpeechStartedEvent, + InputAudioBufferSpeechStoppedEvent, + InputAudioBufferTimeoutTriggered, + LogProbProperties, + McpListToolsCompleted, + McpListToolsFailed, + McpListToolsInProgress, + OutputAudioBufferClearEvent, + RateLimitsUpdatedEvent, + RealtimeAudioConfig, + RealtimeClientEvent, + RealtimeClientSecretConfig, + RealtimeConversationItemAssistantMessage, + RealtimeConversationItemFunctionCall, + RealtimeConversationItemFunctionCallOutput, + RealtimeConversationItemSystemMessage, + RealtimeConversationItemUserMessage, + RealtimeError, + RealtimeErrorEvent, + RealtimeMcpApprovalRequest, + RealtimeMcpApprovalResponse, + RealtimeMcpListTools, + RealtimeMcpProtocolError, + RealtimeMcpToolCall, + RealtimeMcpToolExecutionError, + RealtimeMcphttpError, + RealtimeResponse, + RealtimeResponseStatus, + RealtimeResponseUsage, + RealtimeResponseUsageInputTokenDetails, + RealtimeResponseUsageOutputTokenDetails, + RealtimeServerEvent, + RealtimeSession, + RealtimeSessionCreateRequest, + RealtimeToolChoiceConfig, + RealtimeToolsConfig, + RealtimeToolsConfigUnion, + RealtimeTracingConfig, + RealtimeTranscriptionSessionCreateRequest, + RealtimeTruncation, + ResponseAudioDeltaEvent, + ResponseAudioDoneEvent, + ResponseAudioTranscriptDeltaEvent, + ResponseAudioTranscriptDoneEvent, + ResponseCancelEvent, + ResponseContentPartAddedEvent, + ResponseContentPartDoneEvent, + ResponseCreateEvent, + ResponseCreatedEvent, + ResponseDoneEvent, + ResponseFunctionCallArgumentsDeltaEvent, + ResponseFunctionCallArgumentsDoneEvent, + ResponseMcpCallArgumentsDelta, + ResponseMcpCallArgumentsDone, + ResponseMcpCallCompleted, + ResponseMcpCallFailed, + ResponseMcpCallInProgress, + ResponseOutputItemAddedEvent, + ResponseOutputItemDoneEvent, + ResponseTextDeltaEvent, + ResponseTextDoneEvent, + SessionCreatedEvent, + SessionUpdateEvent, + SessionUpdatedEvent, + TranscriptionSessionCreated, + TranscriptionSessionUpdate, + TranscriptionSessionUpdatedEvent, +) +``` + +## ClientSecrets + +Types: + +```python +from openai.types.realtime import RealtimeSessionCreateResponse, ClientSecretCreateResponse +``` + +Methods: + +- client.realtime.client_secrets.create(\*\*params) -> ClientSecretCreateResponse + # Conversations Types: diff --git a/examples/realtime/audio_util.py b/examples/realtime/audio_util.py index b073cc45be..954a508675 100644 --- a/examples/realtime/audio_util.py +++ b/examples/realtime/audio_util.py @@ -11,7 +11,7 @@ import sounddevice as sd from pydub import AudioSegment -from openai.resources.beta.realtime.realtime import AsyncRealtimeConnection +from openai.resources.realtime.realtime import AsyncRealtimeConnection CHUNK_LENGTH_S = 0.05 # 100ms SAMPLE_RATE = 24000 diff --git a/examples/realtime/azure_realtime.py b/examples/realtime/azure_realtime.py index de88d47052..3cf64b8be9 100644 --- a/examples/realtime/azure_realtime.py +++ b/examples/realtime/azure_realtime.py @@ -26,10 +26,16 @@ async def main() -> None: azure_ad_token_provider=get_bearer_token_provider(credential, "https://cognitiveservices.azure.com/.default"), api_version="2024-10-01-preview", ) - async with client.beta.realtime.connect( - model="gpt-4o-realtime-preview", # deployment name for your model + async with client.realtime.connect( + model="gpt-realtime", # deployment name for your model ) as connection: - await connection.session.update(session={"modalities": ["text"]}) # type: ignore + await connection.session.update( + session={ + "output_modalities": ["text"], + "model": "gpt-realtime", + "type": "realtime", + } + ) while True: user_input = input("Enter a message: ") if user_input == "q": @@ -44,9 +50,9 @@ async def main() -> None: ) await connection.response.create() async for event in connection: - if event.type == "response.text.delta": + if event.type == "response.output_text.delta": print(event.delta, flush=True, end="") - elif event.type == "response.text.done": + elif event.type == "response.output_text.done": print() elif event.type == "response.done": break diff --git a/examples/realtime/push_to_talk_app.py b/examples/realtime/push_to_talk_app.py index 02d3f762d0..acf38995b2 100755 --- a/examples/realtime/push_to_talk_app.py +++ b/examples/realtime/push_to_talk_app.py @@ -38,8 +38,8 @@ from textual.containers import Container from openai import AsyncOpenAI -from openai.types.beta.realtime.session import Session -from openai.resources.beta.realtime.realtime import AsyncRealtimeConnection +from openai.types.realtime.session import Session +from openai.resources.realtime.realtime import AsyncRealtimeConnection class SessionDisplay(Static): @@ -154,13 +154,21 @@ async def on_mount(self) -> None: self.run_worker(self.send_mic_audio()) async def handle_realtime_connection(self) -> None: - async with self.client.beta.realtime.connect(model="gpt-4o-realtime-preview") as conn: + async with self.client.realtime.connect(model="gpt-realtime") as conn: self.connection = conn self.connected.set() # note: this is the default and can be omitted # if you want to manually handle VAD yourself, then set `'turn_detection': None` - await conn.session.update(session={"turn_detection": {"type": "server_vad"}}) + await conn.session.update( + session={ + "audio": { + "input": {"turn_detection": {"type": "server_vad"}}, + }, + "model": "gpt-realtime", + "type": "realtime", + } + ) acc_items: dict[str, Any] = {} @@ -176,7 +184,7 @@ async def handle_realtime_connection(self) -> None: self.session = event.session continue - if event.type == "response.audio.delta": + if event.type == "response.output_audio.delta": if event.item_id != self.last_audio_item_id: self.audio_player.reset_frame_count() self.last_audio_item_id = event.item_id @@ -185,7 +193,7 @@ async def handle_realtime_connection(self) -> None: self.audio_player.add_data(bytes_data) continue - if event.type == "response.audio_transcript.delta": + if event.type == "response.output_audio_transcript.delta": try: text = acc_items[event.item_id] except KeyError: diff --git a/examples/realtime/realtime.py b/examples/realtime/realtime.py new file mode 100755 index 0000000000..214961e54c --- /dev/null +++ b/examples/realtime/realtime.py @@ -0,0 +1,54 @@ +#!/usr/bin/env rye run python +import asyncio + +from openai import AsyncOpenAI + +# Azure OpenAI Realtime Docs + +# How-to: https://learn.microsoft.com/azure/ai-services/openai/how-to/realtime-audio +# Supported models and API versions: https://learn.microsoft.com/azure/ai-services/openai/how-to/realtime-audio#supported-models +# Entra ID auth: https://learn.microsoft.com/azure/ai-services/openai/how-to/managed-identity + + +async def main() -> None: + """The following example demonstrates how to configure OpenAI to use the Realtime API. + For an audio example, see push_to_talk_app.py and update the client and model parameter accordingly. + + When prompted for user input, type a message and hit enter to send it to the model. + Enter "q" to quit the conversation. + """ + + client = AsyncOpenAI() + async with client.realtime.connect( + model="gpt-realtime", + ) as connection: + await connection.session.update( + session={ + "output_modalities": ["text"], + "model": "gpt-realtime", + "type": "realtime", + } + ) + while True: + user_input = input("Enter a message: ") + if user_input == "q": + break + + await connection.conversation.item.create( + item={ + "type": "message", + "role": "user", + "content": [{"type": "input_text", "text": user_input}], + } + ) + await connection.response.create() + async for event in connection: + if event.type == "response.output_text.delta": + print(event.delta, flush=True, end="") + elif event.type == "response.output_text.done": + print() + elif event.type == "response.done": + break + + +asyncio.run(main()) diff --git a/src/openai/__init__.py b/src/openai/__init__.py index b944fbed5e..a03b49e0c4 100644 --- a/src/openai/__init__.py +++ b/src/openai/__init__.py @@ -379,6 +379,7 @@ def _reset_client() -> None: # type: ignore[reportUnusedFunction] models as models, batches as batches, uploads as uploads, + realtime as realtime, webhooks as webhooks, responses as responses, containers as containers, diff --git a/src/openai/_client.py b/src/openai/_client.py index b99db786a7..fe5ebac42a 100644 --- a/src/openai/_client.py +++ b/src/openai/_client.py @@ -45,6 +45,7 @@ models, batches, uploads, + realtime, responses, containers, embeddings, @@ -67,6 +68,7 @@ from .resources.evals.evals import Evals, AsyncEvals from .resources.moderations import Moderations, AsyncModerations from .resources.uploads.uploads import Uploads, AsyncUploads + from .resources.realtime.realtime import Realtime, AsyncRealtime from .resources.responses.responses import Responses, AsyncResponses from .resources.containers.containers import Containers, AsyncContainers from .resources.fine_tuning.fine_tuning import FineTuning, AsyncFineTuning @@ -256,6 +258,12 @@ def responses(self) -> Responses: return Responses(self) + @cached_property + def realtime(self) -> Realtime: + from .resources.realtime import Realtime + + return Realtime(self) + @cached_property def conversations(self) -> Conversations: from .resources.conversations import Conversations @@ -581,6 +589,12 @@ def responses(self) -> AsyncResponses: return AsyncResponses(self) + @cached_property + def realtime(self) -> AsyncRealtime: + from .resources.realtime import AsyncRealtime + + return AsyncRealtime(self) + @cached_property def conversations(self) -> AsyncConversations: from .resources.conversations import AsyncConversations @@ -816,6 +830,12 @@ def responses(self) -> responses.ResponsesWithRawResponse: return ResponsesWithRawResponse(self._client.responses) + @cached_property + def realtime(self) -> realtime.RealtimeWithRawResponse: + from .resources.realtime import RealtimeWithRawResponse + + return RealtimeWithRawResponse(self._client.realtime) + @cached_property def conversations(self) -> conversations.ConversationsWithRawResponse: from .resources.conversations import ConversationsWithRawResponse @@ -925,6 +945,12 @@ def responses(self) -> responses.AsyncResponsesWithRawResponse: return AsyncResponsesWithRawResponse(self._client.responses) + @cached_property + def realtime(self) -> realtime.AsyncRealtimeWithRawResponse: + from .resources.realtime import AsyncRealtimeWithRawResponse + + return AsyncRealtimeWithRawResponse(self._client.realtime) + @cached_property def conversations(self) -> conversations.AsyncConversationsWithRawResponse: from .resources.conversations import AsyncConversationsWithRawResponse @@ -1034,6 +1060,12 @@ def responses(self) -> responses.ResponsesWithStreamingResponse: return ResponsesWithStreamingResponse(self._client.responses) + @cached_property + def realtime(self) -> realtime.RealtimeWithStreamingResponse: + from .resources.realtime import RealtimeWithStreamingResponse + + return RealtimeWithStreamingResponse(self._client.realtime) + @cached_property def conversations(self) -> conversations.ConversationsWithStreamingResponse: from .resources.conversations import ConversationsWithStreamingResponse @@ -1143,6 +1175,12 @@ def responses(self) -> responses.AsyncResponsesWithStreamingResponse: return AsyncResponsesWithStreamingResponse(self._client.responses) + @cached_property + def realtime(self) -> realtime.AsyncRealtimeWithStreamingResponse: + from .resources.realtime import AsyncRealtimeWithStreamingResponse + + return AsyncRealtimeWithStreamingResponse(self._client.realtime) + @cached_property def conversations(self) -> conversations.AsyncConversationsWithStreamingResponse: from .resources.conversations import AsyncConversationsWithStreamingResponse diff --git a/src/openai/_module_client.py b/src/openai/_module_client.py index 5c8df24014..4ecc28420a 100644 --- a/src/openai/_module_client.py +++ b/src/openai/_module_client.py @@ -19,6 +19,7 @@ from .resources.evals.evals import Evals from .resources.moderations import Moderations from .resources.uploads.uploads import Uploads + from .resources.realtime.realtime import Realtime from .resources.responses.responses import Responses from .resources.containers.containers import Containers from .resources.fine_tuning.fine_tuning import FineTuning @@ -89,6 +90,12 @@ def __load__(self) -> Webhooks: return _load_client().webhooks +class RealtimeProxy(LazyProxy["Realtime"]): + @override + def __load__(self) -> Realtime: + return _load_client().realtime + + class ResponsesProxy(LazyProxy["Responses"]): @override def __load__(self) -> Responses: @@ -147,6 +154,7 @@ def __load__(self) -> Conversations: batches: Batches = BatchesProxy().__as_proxied__() uploads: Uploads = UploadsProxy().__as_proxied__() webhooks: Webhooks = WebhooksProxy().__as_proxied__() +realtime: Realtime = RealtimeProxy().__as_proxied__() responses: Responses = ResponsesProxy().__as_proxied__() embeddings: Embeddings = EmbeddingsProxy().__as_proxied__() containers: Containers = ContainersProxy().__as_proxied__() diff --git a/src/openai/resources/audio/speech.py b/src/openai/resources/audio/speech.py index 6251cfed4e..64ce5eec49 100644 --- a/src/openai/resources/audio/speech.py +++ b/src/openai/resources/audio/speech.py @@ -50,7 +50,9 @@ def create( *, input: str, model: Union[str, SpeechModel], - voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"]], + voice: Union[ + str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"] + ], instructions: str | NotGiven = NOT_GIVEN, response_format: Literal["mp3", "opus", "aac", "flac", "wav", "pcm"] | NotGiven = NOT_GIVEN, speed: float | NotGiven = NOT_GIVEN, @@ -144,7 +146,9 @@ async def create( *, input: str, model: Union[str, SpeechModel], - voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"]], + voice: Union[ + str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"] + ], instructions: str | NotGiven = NOT_GIVEN, response_format: Literal["mp3", "opus", "aac", "flac", "wav", "pcm"] | NotGiven = NOT_GIVEN, speed: float | NotGiven = NOT_GIVEN, diff --git a/src/openai/resources/beta/beta.py b/src/openai/resources/beta/beta.py index 4feaaab44b..9084c477e9 100644 --- a/src/openai/resources/beta/beta.py +++ b/src/openai/resources/beta/beta.py @@ -24,10 +24,6 @@ from .realtime.realtime import ( Realtime, AsyncRealtime, - RealtimeWithRawResponse, - AsyncRealtimeWithRawResponse, - RealtimeWithStreamingResponse, - AsyncRealtimeWithStreamingResponse, ) __all__ = ["Beta", "AsyncBeta"] @@ -111,10 +107,6 @@ class BetaWithRawResponse: def __init__(self, beta: Beta) -> None: self._beta = beta - @cached_property - def realtime(self) -> RealtimeWithRawResponse: - return RealtimeWithRawResponse(self._beta.realtime) - @cached_property def assistants(self) -> AssistantsWithRawResponse: return AssistantsWithRawResponse(self._beta.assistants) @@ -128,10 +120,6 @@ class AsyncBetaWithRawResponse: def __init__(self, beta: AsyncBeta) -> None: self._beta = beta - @cached_property - def realtime(self) -> AsyncRealtimeWithRawResponse: - return AsyncRealtimeWithRawResponse(self._beta.realtime) - @cached_property def assistants(self) -> AsyncAssistantsWithRawResponse: return AsyncAssistantsWithRawResponse(self._beta.assistants) @@ -145,10 +133,6 @@ class BetaWithStreamingResponse: def __init__(self, beta: Beta) -> None: self._beta = beta - @cached_property - def realtime(self) -> RealtimeWithStreamingResponse: - return RealtimeWithStreamingResponse(self._beta.realtime) - @cached_property def assistants(self) -> AssistantsWithStreamingResponse: return AssistantsWithStreamingResponse(self._beta.assistants) @@ -162,10 +146,6 @@ class AsyncBetaWithStreamingResponse: def __init__(self, beta: AsyncBeta) -> None: self._beta = beta - @cached_property - def realtime(self) -> AsyncRealtimeWithStreamingResponse: - return AsyncRealtimeWithStreamingResponse(self._beta.realtime) - @cached_property def assistants(self) -> AsyncAssistantsWithStreamingResponse: return AsyncAssistantsWithStreamingResponse(self._beta.assistants) diff --git a/src/openai/resources/realtime/__init__.py b/src/openai/resources/realtime/__init__.py new file mode 100644 index 0000000000..7a41de8648 --- /dev/null +++ b/src/openai/resources/realtime/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .realtime import ( + Realtime, + AsyncRealtime, + RealtimeWithRawResponse, + AsyncRealtimeWithRawResponse, + RealtimeWithStreamingResponse, + AsyncRealtimeWithStreamingResponse, +) +from .client_secrets import ( + ClientSecrets, + AsyncClientSecrets, + ClientSecretsWithRawResponse, + AsyncClientSecretsWithRawResponse, + ClientSecretsWithStreamingResponse, + AsyncClientSecretsWithStreamingResponse, +) + +__all__ = [ + "ClientSecrets", + "AsyncClientSecrets", + "ClientSecretsWithRawResponse", + "AsyncClientSecretsWithRawResponse", + "ClientSecretsWithStreamingResponse", + "AsyncClientSecretsWithStreamingResponse", + "Realtime", + "AsyncRealtime", + "RealtimeWithRawResponse", + "AsyncRealtimeWithRawResponse", + "RealtimeWithStreamingResponse", + "AsyncRealtimeWithStreamingResponse", +] diff --git a/src/openai/resources/realtime/client_secrets.py b/src/openai/resources/realtime/client_secrets.py new file mode 100644 index 0000000000..ba0f9ee538 --- /dev/null +++ b/src/openai/resources/realtime/client_secrets.py @@ -0,0 +1,185 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ... import _legacy_response +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ..._base_client import make_request_options +from ...types.realtime import client_secret_create_params +from ...types.realtime.client_secret_create_response import ClientSecretCreateResponse + +__all__ = ["ClientSecrets", "AsyncClientSecrets"] + + +class ClientSecrets(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ClientSecretsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return ClientSecretsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ClientSecretsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return ClientSecretsWithStreamingResponse(self) + + def create( + self, + *, + expires_after: client_secret_create_params.ExpiresAfter | NotGiven = NOT_GIVEN, + session: client_secret_create_params.Session | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ClientSecretCreateResponse: + """ + Create a Realtime session and client secret for either realtime or + transcription. + + Args: + expires_after: Configuration for the ephemeral token expiration. + + session: Session configuration to use for the client secret. Choose either a realtime + session or a transcription session. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/realtime/client_secrets", + body=maybe_transform( + { + "expires_after": expires_after, + "session": session, + }, + client_secret_create_params.ClientSecretCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ClientSecretCreateResponse, + ) + + +class AsyncClientSecrets(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncClientSecretsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncClientSecretsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncClientSecretsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncClientSecretsWithStreamingResponse(self) + + async def create( + self, + *, + expires_after: client_secret_create_params.ExpiresAfter | NotGiven = NOT_GIVEN, + session: client_secret_create_params.Session | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ClientSecretCreateResponse: + """ + Create a Realtime session and client secret for either realtime or + transcription. + + Args: + expires_after: Configuration for the ephemeral token expiration. + + session: Session configuration to use for the client secret. Choose either a realtime + session or a transcription session. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/realtime/client_secrets", + body=await async_maybe_transform( + { + "expires_after": expires_after, + "session": session, + }, + client_secret_create_params.ClientSecretCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ClientSecretCreateResponse, + ) + + +class ClientSecretsWithRawResponse: + def __init__(self, client_secrets: ClientSecrets) -> None: + self._client_secrets = client_secrets + + self.create = _legacy_response.to_raw_response_wrapper( + client_secrets.create, + ) + + +class AsyncClientSecretsWithRawResponse: + def __init__(self, client_secrets: AsyncClientSecrets) -> None: + self._client_secrets = client_secrets + + self.create = _legacy_response.async_to_raw_response_wrapper( + client_secrets.create, + ) + + +class ClientSecretsWithStreamingResponse: + def __init__(self, client_secrets: ClientSecrets) -> None: + self._client_secrets = client_secrets + + self.create = to_streamed_response_wrapper( + client_secrets.create, + ) + + +class AsyncClientSecretsWithStreamingResponse: + def __init__(self, client_secrets: AsyncClientSecrets) -> None: + self._client_secrets = client_secrets + + self.create = async_to_streamed_response_wrapper( + client_secrets.create, + ) diff --git a/src/openai/resources/realtime/realtime.py b/src/openai/resources/realtime/realtime.py new file mode 100644 index 0000000000..ebdfce86e3 --- /dev/null +++ b/src/openai/resources/realtime/realtime.py @@ -0,0 +1,1056 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import json +import logging +from types import TracebackType +from typing import TYPE_CHECKING, Any, Iterator, cast +from typing_extensions import AsyncIterator + +import httpx +from pydantic import BaseModel + +from ..._types import NOT_GIVEN, Query, Headers, NotGiven +from ..._utils import ( + is_azure_client, + maybe_transform, + strip_not_given, + async_maybe_transform, + is_async_azure_client, +) +from ..._compat import cached_property +from ..._models import construct_type_unchecked +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._exceptions import OpenAIError +from ..._base_client import _merge_mappings +from .client_secrets import ( + ClientSecrets, + AsyncClientSecrets, + ClientSecretsWithRawResponse, + AsyncClientSecretsWithRawResponse, + ClientSecretsWithStreamingResponse, + AsyncClientSecretsWithStreamingResponse, +) +from ...types.realtime import response_create_event_param +from ...types.websocket_connection_options import WebsocketConnectionOptions +from ...types.realtime.realtime_client_event import RealtimeClientEvent +from ...types.realtime.realtime_server_event import RealtimeServerEvent +from ...types.realtime.conversation_item_param import ConversationItemParam +from ...types.realtime.realtime_client_event_param import RealtimeClientEventParam +from ...types.realtime.realtime_session_create_request_param import RealtimeSessionCreateRequestParam +from ...types.realtime.realtime_transcription_session_create_request_param import ( + RealtimeTranscriptionSessionCreateRequestParam, +) + +if TYPE_CHECKING: + from websockets.sync.client import ClientConnection as WebsocketConnection + from websockets.asyncio.client import ClientConnection as AsyncWebsocketConnection + + from ..._client import OpenAI, AsyncOpenAI + +__all__ = ["Realtime", "AsyncRealtime"] + +log: logging.Logger = logging.getLogger(__name__) + + +class Realtime(SyncAPIResource): + @cached_property + def client_secrets(self) -> ClientSecrets: + return ClientSecrets(self._client) + + @cached_property + def with_raw_response(self) -> RealtimeWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return RealtimeWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> RealtimeWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return RealtimeWithStreamingResponse(self) + + def connect( + self, + *, + model: str, + extra_query: Query = {}, + extra_headers: Headers = {}, + websocket_connection_options: WebsocketConnectionOptions = {}, + ) -> RealtimeConnectionManager: + """ + The Realtime API enables you to build low-latency, multi-modal conversational experiences. It currently supports text and audio as both input and output, as well as function calling. + + Some notable benefits of the API include: + + - Native speech-to-speech: Skipping an intermediate text format means low latency and nuanced output. + - Natural, steerable voices: The models have natural inflection and can laugh, whisper, and adhere to tone direction. + - Simultaneous multimodal output: Text is useful for moderation; faster-than-realtime audio ensures stable playback. + + The Realtime API is a stateful, event-based API that communicates over a WebSocket. + """ + return RealtimeConnectionManager( + client=self._client, + extra_query=extra_query, + extra_headers=extra_headers, + websocket_connection_options=websocket_connection_options, + model=model, + ) + + +class AsyncRealtime(AsyncAPIResource): + @cached_property + def client_secrets(self) -> AsyncClientSecrets: + return AsyncClientSecrets(self._client) + + @cached_property + def with_raw_response(self) -> AsyncRealtimeWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncRealtimeWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncRealtimeWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncRealtimeWithStreamingResponse(self) + + def connect( + self, + *, + model: str, + extra_query: Query = {}, + extra_headers: Headers = {}, + websocket_connection_options: WebsocketConnectionOptions = {}, + ) -> AsyncRealtimeConnectionManager: + """ + The Realtime API enables you to build low-latency, multi-modal conversational experiences. It currently supports text and audio as both input and output, as well as function calling. + + Some notable benefits of the API include: + + - Native speech-to-speech: Skipping an intermediate text format means low latency and nuanced output. + - Natural, steerable voices: The models have natural inflection and can laugh, whisper, and adhere to tone direction. + - Simultaneous multimodal output: Text is useful for moderation; faster-than-realtime audio ensures stable playback. + + The Realtime API is a stateful, event-based API that communicates over a WebSocket. + """ + return AsyncRealtimeConnectionManager( + client=self._client, + extra_query=extra_query, + extra_headers=extra_headers, + websocket_connection_options=websocket_connection_options, + model=model, + ) + + +class RealtimeWithRawResponse: + def __init__(self, realtime: Realtime) -> None: + self._realtime = realtime + + @cached_property + def client_secrets(self) -> ClientSecretsWithRawResponse: + return ClientSecretsWithRawResponse(self._realtime.client_secrets) + + +class AsyncRealtimeWithRawResponse: + def __init__(self, realtime: AsyncRealtime) -> None: + self._realtime = realtime + + @cached_property + def client_secrets(self) -> AsyncClientSecretsWithRawResponse: + return AsyncClientSecretsWithRawResponse(self._realtime.client_secrets) + + +class RealtimeWithStreamingResponse: + def __init__(self, realtime: Realtime) -> None: + self._realtime = realtime + + @cached_property + def client_secrets(self) -> ClientSecretsWithStreamingResponse: + return ClientSecretsWithStreamingResponse(self._realtime.client_secrets) + + +class AsyncRealtimeWithStreamingResponse: + def __init__(self, realtime: AsyncRealtime) -> None: + self._realtime = realtime + + @cached_property + def client_secrets(self) -> AsyncClientSecretsWithStreamingResponse: + return AsyncClientSecretsWithStreamingResponse(self._realtime.client_secrets) + + +class AsyncRealtimeConnection: + """Represents a live websocket connection to the Realtime API""" + + session: AsyncRealtimeSessionResource + response: AsyncRealtimeResponseResource + input_audio_buffer: AsyncRealtimeInputAudioBufferResource + conversation: AsyncRealtimeConversationResource + output_audio_buffer: AsyncRealtimeOutputAudioBufferResource + transcription_session: AsyncRealtimeTranscriptionSessionResource + + _connection: AsyncWebsocketConnection + + def __init__(self, connection: AsyncWebsocketConnection) -> None: + self._connection = connection + + self.session = AsyncRealtimeSessionResource(self) + self.response = AsyncRealtimeResponseResource(self) + self.input_audio_buffer = AsyncRealtimeInputAudioBufferResource(self) + self.conversation = AsyncRealtimeConversationResource(self) + self.output_audio_buffer = AsyncRealtimeOutputAudioBufferResource(self) + self.transcription_session = AsyncRealtimeTranscriptionSessionResource(self) + + async def __aiter__(self) -> AsyncIterator[RealtimeServerEvent]: + """ + An infinite-iterator that will continue to yield events until + the connection is closed. + """ + from websockets.exceptions import ConnectionClosedOK + + try: + while True: + yield await self.recv() + except ConnectionClosedOK: + return + + async def recv(self) -> RealtimeServerEvent: + """ + Receive the next message from the connection and parses it into a `RealtimeServerEvent` object. + + Canceling this method is safe. There's no risk of losing data. + """ + return self.parse_event(await self.recv_bytes()) + + async def recv_bytes(self) -> bytes: + """Receive the next message from the connection as raw bytes. + + Canceling this method is safe. There's no risk of losing data. + + If you want to parse the message into a `RealtimeServerEvent` object like `.recv()` does, + then you can call `.parse_event(data)`. + """ + message = await self._connection.recv(decode=False) + log.debug(f"Received websocket message: %s", message) + return message + + async def send(self, event: RealtimeClientEvent | RealtimeClientEventParam) -> None: + data = ( + event.to_json(use_api_names=True, exclude_defaults=True, exclude_unset=True) + if isinstance(event, BaseModel) + else json.dumps(await async_maybe_transform(event, RealtimeClientEventParam)) + ) + await self._connection.send(data) + + async def close(self, *, code: int = 1000, reason: str = "") -> None: + await self._connection.close(code=code, reason=reason) + + def parse_event(self, data: str | bytes) -> RealtimeServerEvent: + """ + Converts a raw `str` or `bytes` message into a `RealtimeServerEvent` object. + + This is helpful if you're using `.recv_bytes()`. + """ + return cast( + RealtimeServerEvent, construct_type_unchecked(value=json.loads(data), type_=cast(Any, RealtimeServerEvent)) + ) + + +class AsyncRealtimeConnectionManager: + """ + Context manager over a `AsyncRealtimeConnection` that is returned by `realtime.connect()` + + This context manager ensures that the connection will be closed when it exits. + + --- + + Note that if your application doesn't work well with the context manager approach then you + can call the `.enter()` method directly to initiate a connection. + + **Warning**: You must remember to close the connection with `.close()`. + + ```py + connection = await client.realtime.connect(...).enter() + # ... + await connection.close() + ``` + """ + + def __init__( + self, + *, + client: AsyncOpenAI, + model: str, + extra_query: Query, + extra_headers: Headers, + websocket_connection_options: WebsocketConnectionOptions, + ) -> None: + self.__client = client + self.__model = model + self.__connection: AsyncRealtimeConnection | None = None + self.__extra_query = extra_query + self.__extra_headers = extra_headers + self.__websocket_connection_options = websocket_connection_options + + async def __aenter__(self) -> AsyncRealtimeConnection: + """ + 👋 If your application doesn't work well with the context manager approach then you + can call this method directly to initiate a connection. + + **Warning**: You must remember to close the connection with `.close()`. + + ```py + connection = await client.realtime.connect(...).enter() + # ... + await connection.close() + ``` + """ + try: + from websockets.asyncio.client import connect + except ImportError as exc: + raise OpenAIError("You need to install `openai[realtime]` to use this method") from exc + + extra_query = self.__extra_query + auth_headers = self.__client.auth_headers + if is_async_azure_client(self.__client): + url, auth_headers = await self.__client._configure_realtime(self.__model, extra_query) + else: + url = self._prepare_url().copy_with( + params={ + **self.__client.base_url.params, + "model": self.__model, + **extra_query, + }, + ) + log.debug("Connecting to %s", url) + if self.__websocket_connection_options: + log.debug("Connection options: %s", self.__websocket_connection_options) + + self.__connection = AsyncRealtimeConnection( + await connect( + str(url), + user_agent_header=self.__client.user_agent, + additional_headers=_merge_mappings( + { + **auth_headers, + }, + self.__extra_headers, + ), + **self.__websocket_connection_options, + ) + ) + + return self.__connection + + enter = __aenter__ + + def _prepare_url(self) -> httpx.URL: + if self.__client.websocket_base_url is not None: + base_url = httpx.URL(self.__client.websocket_base_url) + else: + base_url = self.__client._base_url.copy_with(scheme="wss") + + merge_raw_path = base_url.raw_path.rstrip(b"/") + b"/realtime" + return base_url.copy_with(raw_path=merge_raw_path) + + async def __aexit__( + self, exc_type: type[BaseException] | None, exc: BaseException | None, exc_tb: TracebackType | None + ) -> None: + if self.__connection is not None: + await self.__connection.close() + + +class RealtimeConnection: + """Represents a live websocket connection to the Realtime API""" + + session: RealtimeSessionResource + response: RealtimeResponseResource + input_audio_buffer: RealtimeInputAudioBufferResource + conversation: RealtimeConversationResource + output_audio_buffer: RealtimeOutputAudioBufferResource + transcription_session: RealtimeTranscriptionSessionResource + + _connection: WebsocketConnection + + def __init__(self, connection: WebsocketConnection) -> None: + self._connection = connection + + self.session = RealtimeSessionResource(self) + self.response = RealtimeResponseResource(self) + self.input_audio_buffer = RealtimeInputAudioBufferResource(self) + self.conversation = RealtimeConversationResource(self) + self.output_audio_buffer = RealtimeOutputAudioBufferResource(self) + self.transcription_session = RealtimeTranscriptionSessionResource(self) + + def __iter__(self) -> Iterator[RealtimeServerEvent]: + """ + An infinite-iterator that will continue to yield events until + the connection is closed. + """ + from websockets.exceptions import ConnectionClosedOK + + try: + while True: + yield self.recv() + except ConnectionClosedOK: + return + + def recv(self) -> RealtimeServerEvent: + """ + Receive the next message from the connection and parses it into a `RealtimeServerEvent` object. + + Canceling this method is safe. There's no risk of losing data. + """ + return self.parse_event(self.recv_bytes()) + + def recv_bytes(self) -> bytes: + """Receive the next message from the connection as raw bytes. + + Canceling this method is safe. There's no risk of losing data. + + If you want to parse the message into a `RealtimeServerEvent` object like `.recv()` does, + then you can call `.parse_event(data)`. + """ + message = self._connection.recv(decode=False) + log.debug(f"Received websocket message: %s", message) + return message + + def send(self, event: RealtimeClientEvent | RealtimeClientEventParam) -> None: + data = ( + event.to_json(use_api_names=True, exclude_defaults=True, exclude_unset=True) + if isinstance(event, BaseModel) + else json.dumps(maybe_transform(event, RealtimeClientEventParam)) + ) + self._connection.send(data) + + def close(self, *, code: int = 1000, reason: str = "") -> None: + self._connection.close(code=code, reason=reason) + + def parse_event(self, data: str | bytes) -> RealtimeServerEvent: + """ + Converts a raw `str` or `bytes` message into a `RealtimeServerEvent` object. + + This is helpful if you're using `.recv_bytes()`. + """ + return cast( + RealtimeServerEvent, construct_type_unchecked(value=json.loads(data), type_=cast(Any, RealtimeServerEvent)) + ) + + +class RealtimeConnectionManager: + """ + Context manager over a `RealtimeConnection` that is returned by `realtime.connect()` + + This context manager ensures that the connection will be closed when it exits. + + --- + + Note that if your application doesn't work well with the context manager approach then you + can call the `.enter()` method directly to initiate a connection. + + **Warning**: You must remember to close the connection with `.close()`. + + ```py + connection = client.realtime.connect(...).enter() + # ... + connection.close() + ``` + """ + + def __init__( + self, + *, + client: OpenAI, + model: str, + extra_query: Query, + extra_headers: Headers, + websocket_connection_options: WebsocketConnectionOptions, + ) -> None: + self.__client = client + self.__model = model + self.__connection: RealtimeConnection | None = None + self.__extra_query = extra_query + self.__extra_headers = extra_headers + self.__websocket_connection_options = websocket_connection_options + + def __enter__(self) -> RealtimeConnection: + """ + 👋 If your application doesn't work well with the context manager approach then you + can call this method directly to initiate a connection. + + **Warning**: You must remember to close the connection with `.close()`. + + ```py + connection = client.realtime.connect(...).enter() + # ... + connection.close() + ``` + """ + try: + from websockets.sync.client import connect + except ImportError as exc: + raise OpenAIError("You need to install `openai[realtime]` to use this method") from exc + + extra_query = self.__extra_query + auth_headers = self.__client.auth_headers + if is_azure_client(self.__client): + url, auth_headers = self.__client._configure_realtime(self.__model, extra_query) + else: + url = self._prepare_url().copy_with( + params={ + **self.__client.base_url.params, + "model": self.__model, + **extra_query, + }, + ) + log.debug("Connecting to %s", url) + if self.__websocket_connection_options: + log.debug("Connection options: %s", self.__websocket_connection_options) + + self.__connection = RealtimeConnection( + connect( + str(url), + user_agent_header=self.__client.user_agent, + additional_headers=_merge_mappings( + { + **auth_headers, + }, + self.__extra_headers, + ), + **self.__websocket_connection_options, + ) + ) + + return self.__connection + + enter = __enter__ + + def _prepare_url(self) -> httpx.URL: + if self.__client.websocket_base_url is not None: + base_url = httpx.URL(self.__client.websocket_base_url) + else: + base_url = self.__client._base_url.copy_with(scheme="wss") + + merge_raw_path = base_url.raw_path.rstrip(b"/") + b"/realtime" + return base_url.copy_with(raw_path=merge_raw_path) + + def __exit__( + self, exc_type: type[BaseException] | None, exc: BaseException | None, exc_tb: TracebackType | None + ) -> None: + if self.__connection is not None: + self.__connection.close() + + +class BaseRealtimeConnectionResource: + def __init__(self, connection: RealtimeConnection) -> None: + self._connection = connection + + +class RealtimeSessionResource(BaseRealtimeConnectionResource): + def update(self, *, session: RealtimeSessionCreateRequestParam, event_id: str | NotGiven = NOT_GIVEN) -> None: + """ + Send this event to update the session’s default configuration. + The client may send this event at any time to update any field, + except for `voice`. However, note that once a session has been + initialized with a particular `model`, it can’t be changed to + another model using `session.update`. + + When the server receives a `session.update`, it will respond + with a `session.updated` event showing the full, effective configuration. + Only the fields that are present are updated. To clear a field like + `instructions`, pass an empty string. + """ + self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given({"type": "session.update", "session": session, "event_id": event_id}), + ) + ) + + +class RealtimeResponseResource(BaseRealtimeConnectionResource): + def create( + self, + *, + event_id: str | NotGiven = NOT_GIVEN, + response: response_create_event_param.Response | NotGiven = NOT_GIVEN, + ) -> None: + """ + This event instructs the server to create a Response, which means triggering + model inference. When in Server VAD mode, the server will create Responses + automatically. + + A Response will include at least one Item, and may have two, in which case + the second will be a function call. These Items will be appended to the + conversation history. + + The server will respond with a `response.created` event, events for Items + and content created, and finally a `response.done` event to indicate the + Response is complete. + + The `response.create` event includes inference configuration like + `instructions`, and `temperature`. These fields will override the Session's + configuration for this Response only. + """ + self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given({"type": "response.create", "event_id": event_id, "response": response}), + ) + ) + + def cancel(self, *, event_id: str | NotGiven = NOT_GIVEN, response_id: str | NotGiven = NOT_GIVEN) -> None: + """Send this event to cancel an in-progress response. + + The server will respond + with a `response.done` event with a status of `response.status=cancelled`. If + there is no response to cancel, the server will respond with an error. + """ + self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given({"type": "response.cancel", "event_id": event_id, "response_id": response_id}), + ) + ) + + +class RealtimeInputAudioBufferResource(BaseRealtimeConnectionResource): + def clear(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: + """Send this event to clear the audio bytes in the buffer. + + The server will + respond with an `input_audio_buffer.cleared` event. + """ + self._connection.send( + cast(RealtimeClientEventParam, strip_not_given({"type": "input_audio_buffer.clear", "event_id": event_id})) + ) + + def commit(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: + """ + Send this event to commit the user input audio buffer, which will create a + new user message item in the conversation. This event will produce an error + if the input audio buffer is empty. When in Server VAD mode, the client does + not need to send this event, the server will commit the audio buffer + automatically. + + Committing the input audio buffer will trigger input audio transcription + (if enabled in session configuration), but it will not create a response + from the model. The server will respond with an `input_audio_buffer.committed` + event. + """ + self._connection.send( + cast(RealtimeClientEventParam, strip_not_given({"type": "input_audio_buffer.commit", "event_id": event_id})) + ) + + def append(self, *, audio: str, event_id: str | NotGiven = NOT_GIVEN) -> None: + """Send this event to append audio bytes to the input audio buffer. + + The audio + buffer is temporary storage you can write to and later commit. In Server VAD + mode, the audio buffer is used to detect speech and the server will decide + when to commit. When Server VAD is disabled, you must commit the audio buffer + manually. + + The client may choose how much audio to place in each event up to a maximum + of 15 MiB, for example streaming smaller chunks from the client may allow the + VAD to be more responsive. Unlike made other client events, the server will + not send a confirmation response to this event. + """ + self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given({"type": "input_audio_buffer.append", "audio": audio, "event_id": event_id}), + ) + ) + + +class RealtimeConversationResource(BaseRealtimeConnectionResource): + @cached_property + def item(self) -> RealtimeConversationItemResource: + return RealtimeConversationItemResource(self._connection) + + +class RealtimeConversationItemResource(BaseRealtimeConnectionResource): + def delete(self, *, item_id: str, event_id: str | NotGiven = NOT_GIVEN) -> None: + """Send this event when you want to remove any item from the conversation + history. + + The server will respond with a `conversation.item.deleted` event, + unless the item does not exist in the conversation history, in which case the + server will respond with an error. + """ + self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given({"type": "conversation.item.delete", "item_id": item_id, "event_id": event_id}), + ) + ) + + def create( + self, + *, + item: ConversationItemParam, + event_id: str | NotGiven = NOT_GIVEN, + previous_item_id: str | NotGiven = NOT_GIVEN, + ) -> None: + """ + Add a new Item to the Conversation's context, including messages, function + calls, and function call responses. This event can be used both to populate a + "history" of the conversation and to add new items mid-stream, but has the + current limitation that it cannot populate assistant audio messages. + + If successful, the server will respond with a `conversation.item.created` + event, otherwise an `error` event will be sent. + """ + self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given( + { + "type": "conversation.item.create", + "item": item, + "event_id": event_id, + "previous_item_id": previous_item_id, + } + ), + ) + ) + + def truncate( + self, *, audio_end_ms: int, content_index: int, item_id: str, event_id: str | NotGiven = NOT_GIVEN + ) -> None: + """Send this event to truncate a previous assistant message’s audio. + + The server + will produce audio faster than realtime, so this event is useful when the user + interrupts to truncate audio that has already been sent to the client but not + yet played. This will synchronize the server's understanding of the audio with + the client's playback. + + Truncating audio will delete the server-side text transcript to ensure there + is not text in the context that hasn't been heard by the user. + + If successful, the server will respond with a `conversation.item.truncated` + event. + """ + self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given( + { + "type": "conversation.item.truncate", + "audio_end_ms": audio_end_ms, + "content_index": content_index, + "item_id": item_id, + "event_id": event_id, + } + ), + ) + ) + + def retrieve(self, *, item_id: str, event_id: str | NotGiven = NOT_GIVEN) -> None: + """ + Send this event when you want to retrieve the server's representation of a specific item in the conversation history. This is useful, for example, to inspect user audio after noise cancellation and VAD. + The server will respond with a `conversation.item.retrieved` event, + unless the item does not exist in the conversation history, in which case the + server will respond with an error. + """ + self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given({"type": "conversation.item.retrieve", "item_id": item_id, "event_id": event_id}), + ) + ) + + +class RealtimeOutputAudioBufferResource(BaseRealtimeConnectionResource): + def clear(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: + """**WebRTC Only:** Emit to cut off the current audio response. + + This will trigger the server to + stop generating audio and emit a `output_audio_buffer.cleared` event. This + event should be preceded by a `response.cancel` client event to stop the + generation of the current response. + [Learn more](https://platform.openai.com/docs/guides/realtime-conversations#client-and-server-events-for-audio-in-webrtc). + """ + self._connection.send( + cast(RealtimeClientEventParam, strip_not_given({"type": "output_audio_buffer.clear", "event_id": event_id})) + ) + + +class RealtimeTranscriptionSessionResource(BaseRealtimeConnectionResource): + def update( + self, *, session: RealtimeTranscriptionSessionCreateRequestParam, event_id: str | NotGiven = NOT_GIVEN + ) -> None: + """Send this event to update a transcription session.""" + self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given({"type": "transcription_session.update", "session": session, "event_id": event_id}), + ) + ) + + +class BaseAsyncRealtimeConnectionResource: + def __init__(self, connection: AsyncRealtimeConnection) -> None: + self._connection = connection + + +class AsyncRealtimeSessionResource(BaseAsyncRealtimeConnectionResource): + async def update(self, *, session: RealtimeSessionCreateRequestParam, event_id: str | NotGiven = NOT_GIVEN) -> None: + """ + Send this event to update the session’s default configuration. + The client may send this event at any time to update any field, + except for `voice`. However, note that once a session has been + initialized with a particular `model`, it can’t be changed to + another model using `session.update`. + + When the server receives a `session.update`, it will respond + with a `session.updated` event showing the full, effective configuration. + Only the fields that are present are updated. To clear a field like + `instructions`, pass an empty string. + """ + await self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given({"type": "session.update", "session": session, "event_id": event_id}), + ) + ) + + +class AsyncRealtimeResponseResource(BaseAsyncRealtimeConnectionResource): + async def create( + self, + *, + event_id: str | NotGiven = NOT_GIVEN, + response: response_create_event_param.Response | NotGiven = NOT_GIVEN, + ) -> None: + """ + This event instructs the server to create a Response, which means triggering + model inference. When in Server VAD mode, the server will create Responses + automatically. + + A Response will include at least one Item, and may have two, in which case + the second will be a function call. These Items will be appended to the + conversation history. + + The server will respond with a `response.created` event, events for Items + and content created, and finally a `response.done` event to indicate the + Response is complete. + + The `response.create` event includes inference configuration like + `instructions`, and `temperature`. These fields will override the Session's + configuration for this Response only. + """ + await self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given({"type": "response.create", "event_id": event_id, "response": response}), + ) + ) + + async def cancel(self, *, event_id: str | NotGiven = NOT_GIVEN, response_id: str | NotGiven = NOT_GIVEN) -> None: + """Send this event to cancel an in-progress response. + + The server will respond + with a `response.done` event with a status of `response.status=cancelled`. If + there is no response to cancel, the server will respond with an error. + """ + await self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given({"type": "response.cancel", "event_id": event_id, "response_id": response_id}), + ) + ) + + +class AsyncRealtimeInputAudioBufferResource(BaseAsyncRealtimeConnectionResource): + async def clear(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: + """Send this event to clear the audio bytes in the buffer. + + The server will + respond with an `input_audio_buffer.cleared` event. + """ + await self._connection.send( + cast(RealtimeClientEventParam, strip_not_given({"type": "input_audio_buffer.clear", "event_id": event_id})) + ) + + async def commit(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: + """ + Send this event to commit the user input audio buffer, which will create a + new user message item in the conversation. This event will produce an error + if the input audio buffer is empty. When in Server VAD mode, the client does + not need to send this event, the server will commit the audio buffer + automatically. + + Committing the input audio buffer will trigger input audio transcription + (if enabled in session configuration), but it will not create a response + from the model. The server will respond with an `input_audio_buffer.committed` + event. + """ + await self._connection.send( + cast(RealtimeClientEventParam, strip_not_given({"type": "input_audio_buffer.commit", "event_id": event_id})) + ) + + async def append(self, *, audio: str, event_id: str | NotGiven = NOT_GIVEN) -> None: + """Send this event to append audio bytes to the input audio buffer. + + The audio + buffer is temporary storage you can write to and later commit. In Server VAD + mode, the audio buffer is used to detect speech and the server will decide + when to commit. When Server VAD is disabled, you must commit the audio buffer + manually. + + The client may choose how much audio to place in each event up to a maximum + of 15 MiB, for example streaming smaller chunks from the client may allow the + VAD to be more responsive. Unlike made other client events, the server will + not send a confirmation response to this event. + """ + await self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given({"type": "input_audio_buffer.append", "audio": audio, "event_id": event_id}), + ) + ) + + +class AsyncRealtimeConversationResource(BaseAsyncRealtimeConnectionResource): + @cached_property + def item(self) -> AsyncRealtimeConversationItemResource: + return AsyncRealtimeConversationItemResource(self._connection) + + +class AsyncRealtimeConversationItemResource(BaseAsyncRealtimeConnectionResource): + async def delete(self, *, item_id: str, event_id: str | NotGiven = NOT_GIVEN) -> None: + """Send this event when you want to remove any item from the conversation + history. + + The server will respond with a `conversation.item.deleted` event, + unless the item does not exist in the conversation history, in which case the + server will respond with an error. + """ + await self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given({"type": "conversation.item.delete", "item_id": item_id, "event_id": event_id}), + ) + ) + + async def create( + self, + *, + item: ConversationItemParam, + event_id: str | NotGiven = NOT_GIVEN, + previous_item_id: str | NotGiven = NOT_GIVEN, + ) -> None: + """ + Add a new Item to the Conversation's context, including messages, function + calls, and function call responses. This event can be used both to populate a + "history" of the conversation and to add new items mid-stream, but has the + current limitation that it cannot populate assistant audio messages. + + If successful, the server will respond with a `conversation.item.created` + event, otherwise an `error` event will be sent. + """ + await self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given( + { + "type": "conversation.item.create", + "item": item, + "event_id": event_id, + "previous_item_id": previous_item_id, + } + ), + ) + ) + + async def truncate( + self, *, audio_end_ms: int, content_index: int, item_id: str, event_id: str | NotGiven = NOT_GIVEN + ) -> None: + """Send this event to truncate a previous assistant message’s audio. + + The server + will produce audio faster than realtime, so this event is useful when the user + interrupts to truncate audio that has already been sent to the client but not + yet played. This will synchronize the server's understanding of the audio with + the client's playback. + + Truncating audio will delete the server-side text transcript to ensure there + is not text in the context that hasn't been heard by the user. + + If successful, the server will respond with a `conversation.item.truncated` + event. + """ + await self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given( + { + "type": "conversation.item.truncate", + "audio_end_ms": audio_end_ms, + "content_index": content_index, + "item_id": item_id, + "event_id": event_id, + } + ), + ) + ) + + async def retrieve(self, *, item_id: str, event_id: str | NotGiven = NOT_GIVEN) -> None: + """ + Send this event when you want to retrieve the server's representation of a specific item in the conversation history. This is useful, for example, to inspect user audio after noise cancellation and VAD. + The server will respond with a `conversation.item.retrieved` event, + unless the item does not exist in the conversation history, in which case the + server will respond with an error. + """ + await self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given({"type": "conversation.item.retrieve", "item_id": item_id, "event_id": event_id}), + ) + ) + + +class AsyncRealtimeOutputAudioBufferResource(BaseAsyncRealtimeConnectionResource): + async def clear(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: + """**WebRTC Only:** Emit to cut off the current audio response. + + This will trigger the server to + stop generating audio and emit a `output_audio_buffer.cleared` event. This + event should be preceded by a `response.cancel` client event to stop the + generation of the current response. + [Learn more](https://platform.openai.com/docs/guides/realtime-conversations#client-and-server-events-for-audio-in-webrtc). + """ + await self._connection.send( + cast(RealtimeClientEventParam, strip_not_given({"type": "output_audio_buffer.clear", "event_id": event_id})) + ) + + +class AsyncRealtimeTranscriptionSessionResource(BaseAsyncRealtimeConnectionResource): + async def update( + self, *, session: RealtimeTranscriptionSessionCreateRequestParam, event_id: str | NotGiven = NOT_GIVEN + ) -> None: + """Send this event to update a transcription session.""" + await self._connection.send( + cast( + RealtimeClientEventParam, + strip_not_given({"type": "transcription_session.update", "session": session, "event_id": event_id}), + ) + ) diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index e04382a9ff..e459f55c61 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -260,7 +260,7 @@ def create( tools: An array of tools the model may call while generating a response. You can specify which tool to use by setting the `tool_choice` parameter. - The two categories of tools you can provide the model are: + We support the following categories of tools: - **Built-in tools**: Tools that are provided by OpenAI that extend the model's capabilities, like @@ -268,6 +268,9 @@ def create( [file search](https://platform.openai.com/docs/guides/tools-file-search). Learn more about [built-in tools](https://platform.openai.com/docs/guides/tools). + - **MCP Tools**: Integrations with third-party systems via custom MCP servers or + predefined connectors such as Google Drive and Notion. Learn more about + [MCP Tools](https://platform.openai.com/docs/guides/tools-connectors-mcp). - **Function calls (custom tools)**: Functions that are defined by you, enabling the model to call your own code with strongly typed arguments and outputs. Learn more about @@ -496,7 +499,7 @@ def create( tools: An array of tools the model may call while generating a response. You can specify which tool to use by setting the `tool_choice` parameter. - The two categories of tools you can provide the model are: + We support the following categories of tools: - **Built-in tools**: Tools that are provided by OpenAI that extend the model's capabilities, like @@ -504,6 +507,9 @@ def create( [file search](https://platform.openai.com/docs/guides/tools-file-search). Learn more about [built-in tools](https://platform.openai.com/docs/guides/tools). + - **MCP Tools**: Integrations with third-party systems via custom MCP servers or + predefined connectors such as Google Drive and Notion. Learn more about + [MCP Tools](https://platform.openai.com/docs/guides/tools-connectors-mcp). - **Function calls (custom tools)**: Functions that are defined by you, enabling the model to call your own code with strongly typed arguments and outputs. Learn more about @@ -732,7 +738,7 @@ def create( tools: An array of tools the model may call while generating a response. You can specify which tool to use by setting the `tool_choice` parameter. - The two categories of tools you can provide the model are: + We support the following categories of tools: - **Built-in tools**: Tools that are provided by OpenAI that extend the model's capabilities, like @@ -740,6 +746,9 @@ def create( [file search](https://platform.openai.com/docs/guides/tools-file-search). Learn more about [built-in tools](https://platform.openai.com/docs/guides/tools). + - **MCP Tools**: Integrations with third-party systems via custom MCP servers or + predefined connectors such as Google Drive and Notion. Learn more about + [MCP Tools](https://platform.openai.com/docs/guides/tools-connectors-mcp). - **Function calls (custom tools)**: Functions that are defined by you, enabling the model to call your own code with strongly typed arguments and outputs. Learn more about @@ -1682,7 +1691,7 @@ async def create( tools: An array of tools the model may call while generating a response. You can specify which tool to use by setting the `tool_choice` parameter. - The two categories of tools you can provide the model are: + We support the following categories of tools: - **Built-in tools**: Tools that are provided by OpenAI that extend the model's capabilities, like @@ -1690,6 +1699,9 @@ async def create( [file search](https://platform.openai.com/docs/guides/tools-file-search). Learn more about [built-in tools](https://platform.openai.com/docs/guides/tools). + - **MCP Tools**: Integrations with third-party systems via custom MCP servers or + predefined connectors such as Google Drive and Notion. Learn more about + [MCP Tools](https://platform.openai.com/docs/guides/tools-connectors-mcp). - **Function calls (custom tools)**: Functions that are defined by you, enabling the model to call your own code with strongly typed arguments and outputs. Learn more about @@ -1918,7 +1930,7 @@ async def create( tools: An array of tools the model may call while generating a response. You can specify which tool to use by setting the `tool_choice` parameter. - The two categories of tools you can provide the model are: + We support the following categories of tools: - **Built-in tools**: Tools that are provided by OpenAI that extend the model's capabilities, like @@ -1926,6 +1938,9 @@ async def create( [file search](https://platform.openai.com/docs/guides/tools-file-search). Learn more about [built-in tools](https://platform.openai.com/docs/guides/tools). + - **MCP Tools**: Integrations with third-party systems via custom MCP servers or + predefined connectors such as Google Drive and Notion. Learn more about + [MCP Tools](https://platform.openai.com/docs/guides/tools-connectors-mcp). - **Function calls (custom tools)**: Functions that are defined by you, enabling the model to call your own code with strongly typed arguments and outputs. Learn more about @@ -2154,7 +2169,7 @@ async def create( tools: An array of tools the model may call while generating a response. You can specify which tool to use by setting the `tool_choice` parameter. - The two categories of tools you can provide the model are: + We support the following categories of tools: - **Built-in tools**: Tools that are provided by OpenAI that extend the model's capabilities, like @@ -2162,6 +2177,9 @@ async def create( [file search](https://platform.openai.com/docs/guides/tools-file-search). Learn more about [built-in tools](https://platform.openai.com/docs/guides/tools). + - **MCP Tools**: Integrations with third-party systems via custom MCP servers or + predefined connectors such as Google Drive and Notion. Learn more about + [MCP Tools](https://platform.openai.com/docs/guides/tools-connectors-mcp). - **Function calls (custom tools)**: Functions that are defined by you, enabling the model to call your own code with strongly typed arguments and outputs. Learn more about diff --git a/src/openai/types/audio/speech_create_params.py b/src/openai/types/audio/speech_create_params.py index feeb68c68b..634d788191 100644 --- a/src/openai/types/audio/speech_create_params.py +++ b/src/openai/types/audio/speech_create_params.py @@ -20,7 +20,9 @@ class SpeechCreateParams(TypedDict, total=False): `tts-1`, `tts-1-hd` or `gpt-4o-mini-tts`. """ - voice: Required[Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"]]] + voice: Required[ + Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"]] + ] """The voice to use when generating the audio. Supported voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, `fable`, `onyx`, diff --git a/src/openai/types/chat/chat_completion_audio_param.py b/src/openai/types/chat/chat_completion_audio_param.py index dc68159c1e..b1576b41df 100644 --- a/src/openai/types/chat/chat_completion_audio_param.py +++ b/src/openai/types/chat/chat_completion_audio_param.py @@ -15,7 +15,9 @@ class ChatCompletionAudioParam(TypedDict, total=False): Must be one of `wav`, `mp3`, `flac`, `opus`, or `pcm16`. """ - voice: Required[Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"]]] + voice: Required[ + Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"]] + ] """The voice the model uses to respond. Supported voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, `fable`, `nova`, diff --git a/src/openai/types/realtime/__init__.py b/src/openai/types/realtime/__init__.py new file mode 100644 index 0000000000..b05f620619 --- /dev/null +++ b/src/openai/types/realtime/__init__.py @@ -0,0 +1,184 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .realtime_error import RealtimeError as RealtimeError +from .realtime_session import RealtimeSession as RealtimeSession +from .conversation_item import ConversationItem as ConversationItem +from .realtime_response import RealtimeResponse as RealtimeResponse +from .log_prob_properties import LogProbProperties as LogProbProperties +from .realtime_truncation import RealtimeTruncation as RealtimeTruncation +from .response_done_event import ResponseDoneEvent as ResponseDoneEvent +from .realtime_error_event import RealtimeErrorEvent as RealtimeErrorEvent +from .session_update_event import SessionUpdateEvent as SessionUpdateEvent +from .mcp_list_tools_failed import McpListToolsFailed as McpListToolsFailed +from .realtime_audio_config import RealtimeAudioConfig as RealtimeAudioConfig +from .realtime_client_event import RealtimeClientEvent as RealtimeClientEvent +from .realtime_server_event import RealtimeServerEvent as RealtimeServerEvent +from .realtime_tools_config import RealtimeToolsConfig as RealtimeToolsConfig +from .response_cancel_event import ResponseCancelEvent as ResponseCancelEvent +from .response_create_event import ResponseCreateEvent as ResponseCreateEvent +from .session_created_event import SessionCreatedEvent as SessionCreatedEvent +from .session_updated_event import SessionUpdatedEvent as SessionUpdatedEvent +from .conversation_item_done import ConversationItemDone as ConversationItemDone +from .realtime_mcp_tool_call import RealtimeMcpToolCall as RealtimeMcpToolCall +from .realtime_mcphttp_error import RealtimeMcphttpError as RealtimeMcphttpError +from .response_created_event import ResponseCreatedEvent as ResponseCreatedEvent +from .conversation_item_added import ConversationItemAdded as ConversationItemAdded +from .conversation_item_param import ConversationItemParam as ConversationItemParam +from .realtime_connect_params import RealtimeConnectParams as RealtimeConnectParams +from .realtime_mcp_list_tools import RealtimeMcpListTools as RealtimeMcpListTools +from .realtime_response_usage import RealtimeResponseUsage as RealtimeResponseUsage +from .realtime_tracing_config import RealtimeTracingConfig as RealtimeTracingConfig +from .mcp_list_tools_completed import McpListToolsCompleted as McpListToolsCompleted +from .realtime_response_status import RealtimeResponseStatus as RealtimeResponseStatus +from .response_mcp_call_failed import ResponseMcpCallFailed as ResponseMcpCallFailed +from .response_text_done_event import ResponseTextDoneEvent as ResponseTextDoneEvent +from .rate_limits_updated_event import RateLimitsUpdatedEvent as RateLimitsUpdatedEvent +from .realtime_truncation_param import RealtimeTruncationParam as RealtimeTruncationParam +from .response_audio_done_event import ResponseAudioDoneEvent as ResponseAudioDoneEvent +from .response_text_delta_event import ResponseTextDeltaEvent as ResponseTextDeltaEvent +from .conversation_created_event import ConversationCreatedEvent as ConversationCreatedEvent +from .mcp_list_tools_in_progress import McpListToolsInProgress as McpListToolsInProgress +from .response_audio_delta_event import ResponseAudioDeltaEvent as ResponseAudioDeltaEvent +from .session_update_event_param import SessionUpdateEventParam as SessionUpdateEventParam +from .client_secret_create_params import ClientSecretCreateParams as ClientSecretCreateParams +from .realtime_audio_config_param import RealtimeAudioConfigParam as RealtimeAudioConfigParam +from .realtime_client_event_param import RealtimeClientEventParam as RealtimeClientEventParam +from .realtime_mcp_protocol_error import RealtimeMcpProtocolError as RealtimeMcpProtocolError +from .realtime_tool_choice_config import RealtimeToolChoiceConfig as RealtimeToolChoiceConfig +from .realtime_tools_config_param import RealtimeToolsConfigParam as RealtimeToolsConfigParam +from .realtime_tools_config_union import RealtimeToolsConfigUnion as RealtimeToolsConfigUnion +from .response_cancel_event_param import ResponseCancelEventParam as ResponseCancelEventParam +from .response_create_event_param import ResponseCreateEventParam as ResponseCreateEventParam +from .response_mcp_call_completed import ResponseMcpCallCompleted as ResponseMcpCallCompleted +from .realtime_mcp_tool_call_param import RealtimeMcpToolCallParam as RealtimeMcpToolCallParam +from .realtime_mcphttp_error_param import RealtimeMcphttpErrorParam as RealtimeMcphttpErrorParam +from .transcription_session_update import TranscriptionSessionUpdate as TranscriptionSessionUpdate +from .client_secret_create_response import ClientSecretCreateResponse as ClientSecretCreateResponse +from .realtime_client_secret_config import RealtimeClientSecretConfig as RealtimeClientSecretConfig +from .realtime_mcp_approval_request import RealtimeMcpApprovalRequest as RealtimeMcpApprovalRequest +from .realtime_mcp_list_tools_param import RealtimeMcpListToolsParam as RealtimeMcpListToolsParam +from .realtime_tracing_config_param import RealtimeTracingConfigParam as RealtimeTracingConfigParam +from .response_mcp_call_in_progress import ResponseMcpCallInProgress as ResponseMcpCallInProgress +from .transcription_session_created import TranscriptionSessionCreated as TranscriptionSessionCreated +from .conversation_item_create_event import ConversationItemCreateEvent as ConversationItemCreateEvent +from .conversation_item_delete_event import ConversationItemDeleteEvent as ConversationItemDeleteEvent +from .input_audio_buffer_clear_event import InputAudioBufferClearEvent as InputAudioBufferClearEvent +from .realtime_mcp_approval_response import RealtimeMcpApprovalResponse as RealtimeMcpApprovalResponse +from .conversation_item_created_event import ConversationItemCreatedEvent as ConversationItemCreatedEvent +from .conversation_item_deleted_event import ConversationItemDeletedEvent as ConversationItemDeletedEvent +from .input_audio_buffer_append_event import InputAudioBufferAppendEvent as InputAudioBufferAppendEvent +from .input_audio_buffer_commit_event import InputAudioBufferCommitEvent as InputAudioBufferCommitEvent +from .output_audio_buffer_clear_event import OutputAudioBufferClearEvent as OutputAudioBufferClearEvent +from .realtime_session_create_request import RealtimeSessionCreateRequest as RealtimeSessionCreateRequest +from .response_output_item_done_event import ResponseOutputItemDoneEvent as ResponseOutputItemDoneEvent +from .conversation_item_retrieve_event import ConversationItemRetrieveEvent as ConversationItemRetrieveEvent +from .conversation_item_truncate_event import ConversationItemTruncateEvent as ConversationItemTruncateEvent +from .input_audio_buffer_cleared_event import InputAudioBufferClearedEvent as InputAudioBufferClearedEvent +from .realtime_session_create_response import RealtimeSessionCreateResponse as RealtimeSessionCreateResponse +from .response_content_part_done_event import ResponseContentPartDoneEvent as ResponseContentPartDoneEvent +from .response_mcp_call_arguments_done import ResponseMcpCallArgumentsDone as ResponseMcpCallArgumentsDone +from .response_output_item_added_event import ResponseOutputItemAddedEvent as ResponseOutputItemAddedEvent +from .conversation_item_truncated_event import ConversationItemTruncatedEvent as ConversationItemTruncatedEvent +from .realtime_mcp_protocol_error_param import RealtimeMcpProtocolErrorParam as RealtimeMcpProtocolErrorParam +from .realtime_mcp_tool_execution_error import RealtimeMcpToolExecutionError as RealtimeMcpToolExecutionError +from .realtime_tool_choice_config_param import RealtimeToolChoiceConfigParam as RealtimeToolChoiceConfigParam +from .realtime_tools_config_union_param import RealtimeToolsConfigUnionParam as RealtimeToolsConfigUnionParam +from .response_content_part_added_event import ResponseContentPartAddedEvent as ResponseContentPartAddedEvent +from .response_mcp_call_arguments_delta import ResponseMcpCallArgumentsDelta as ResponseMcpCallArgumentsDelta +from .input_audio_buffer_committed_event import InputAudioBufferCommittedEvent as InputAudioBufferCommittedEvent +from .transcription_session_update_param import TranscriptionSessionUpdateParam as TranscriptionSessionUpdateParam +from .realtime_client_secret_config_param import RealtimeClientSecretConfigParam as RealtimeClientSecretConfigParam +from .realtime_mcp_approval_request_param import RealtimeMcpApprovalRequestParam as RealtimeMcpApprovalRequestParam +from .transcription_session_updated_event import TranscriptionSessionUpdatedEvent as TranscriptionSessionUpdatedEvent +from .conversation_item_create_event_param import ConversationItemCreateEventParam as ConversationItemCreateEventParam +from .conversation_item_delete_event_param import ConversationItemDeleteEventParam as ConversationItemDeleteEventParam +from .input_audio_buffer_clear_event_param import InputAudioBufferClearEventParam as InputAudioBufferClearEventParam +from .input_audio_buffer_timeout_triggered import InputAudioBufferTimeoutTriggered as InputAudioBufferTimeoutTriggered +from .realtime_mcp_approval_response_param import RealtimeMcpApprovalResponseParam as RealtimeMcpApprovalResponseParam +from .response_audio_transcript_done_event import ResponseAudioTranscriptDoneEvent as ResponseAudioTranscriptDoneEvent +from .input_audio_buffer_append_event_param import InputAudioBufferAppendEventParam as InputAudioBufferAppendEventParam +from .input_audio_buffer_commit_event_param import InputAudioBufferCommitEventParam as InputAudioBufferCommitEventParam +from .output_audio_buffer_clear_event_param import OutputAudioBufferClearEventParam as OutputAudioBufferClearEventParam +from .realtime_session_create_request_param import ( + RealtimeSessionCreateRequestParam as RealtimeSessionCreateRequestParam, +) +from .response_audio_transcript_delta_event import ( + ResponseAudioTranscriptDeltaEvent as ResponseAudioTranscriptDeltaEvent, +) +from .conversation_item_retrieve_event_param import ( + ConversationItemRetrieveEventParam as ConversationItemRetrieveEventParam, +) +from .conversation_item_truncate_event_param import ( + ConversationItemTruncateEventParam as ConversationItemTruncateEventParam, +) +from .input_audio_buffer_speech_started_event import ( + InputAudioBufferSpeechStartedEvent as InputAudioBufferSpeechStartedEvent, +) +from .input_audio_buffer_speech_stopped_event import ( + InputAudioBufferSpeechStoppedEvent as InputAudioBufferSpeechStoppedEvent, +) +from .realtime_conversation_item_user_message import ( + RealtimeConversationItemUserMessage as RealtimeConversationItemUserMessage, +) +from .realtime_mcp_tool_execution_error_param import ( + RealtimeMcpToolExecutionErrorParam as RealtimeMcpToolExecutionErrorParam, +) +from .realtime_conversation_item_function_call import ( + RealtimeConversationItemFunctionCall as RealtimeConversationItemFunctionCall, +) +from .realtime_conversation_item_system_message import ( + RealtimeConversationItemSystemMessage as RealtimeConversationItemSystemMessage, +) +from .realtime_response_usage_input_token_details import ( + RealtimeResponseUsageInputTokenDetails as RealtimeResponseUsageInputTokenDetails, +) +from .response_function_call_arguments_done_event import ( + ResponseFunctionCallArgumentsDoneEvent as ResponseFunctionCallArgumentsDoneEvent, +) +from .realtime_conversation_item_assistant_message import ( + RealtimeConversationItemAssistantMessage as RealtimeConversationItemAssistantMessage, +) +from .realtime_response_usage_output_token_details import ( + RealtimeResponseUsageOutputTokenDetails as RealtimeResponseUsageOutputTokenDetails, +) +from .response_function_call_arguments_delta_event import ( + ResponseFunctionCallArgumentsDeltaEvent as ResponseFunctionCallArgumentsDeltaEvent, +) +from .realtime_conversation_item_user_message_param import ( + RealtimeConversationItemUserMessageParam as RealtimeConversationItemUserMessageParam, +) +from .realtime_transcription_session_create_request import ( + RealtimeTranscriptionSessionCreateRequest as RealtimeTranscriptionSessionCreateRequest, +) +from .realtime_conversation_item_function_call_param import ( + RealtimeConversationItemFunctionCallParam as RealtimeConversationItemFunctionCallParam, +) +from .realtime_conversation_item_function_call_output import ( + RealtimeConversationItemFunctionCallOutput as RealtimeConversationItemFunctionCallOutput, +) +from .realtime_conversation_item_system_message_param import ( + RealtimeConversationItemSystemMessageParam as RealtimeConversationItemSystemMessageParam, +) +from .realtime_conversation_item_assistant_message_param import ( + RealtimeConversationItemAssistantMessageParam as RealtimeConversationItemAssistantMessageParam, +) +from .conversation_item_input_audio_transcription_segment import ( + ConversationItemInputAudioTranscriptionSegment as ConversationItemInputAudioTranscriptionSegment, +) +from .realtime_transcription_session_create_request_param import ( + RealtimeTranscriptionSessionCreateRequestParam as RealtimeTranscriptionSessionCreateRequestParam, +) +from .realtime_conversation_item_function_call_output_param import ( + RealtimeConversationItemFunctionCallOutputParam as RealtimeConversationItemFunctionCallOutputParam, +) +from .conversation_item_input_audio_transcription_delta_event import ( + ConversationItemInputAudioTranscriptionDeltaEvent as ConversationItemInputAudioTranscriptionDeltaEvent, +) +from .conversation_item_input_audio_transcription_failed_event import ( + ConversationItemInputAudioTranscriptionFailedEvent as ConversationItemInputAudioTranscriptionFailedEvent, +) +from .conversation_item_input_audio_transcription_completed_event import ( + ConversationItemInputAudioTranscriptionCompletedEvent as ConversationItemInputAudioTranscriptionCompletedEvent, +) diff --git a/src/openai/types/realtime/client_secret_create_params.py b/src/openai/types/realtime/client_secret_create_params.py new file mode 100644 index 0000000000..696176e5a8 --- /dev/null +++ b/src/openai/types/realtime/client_secret_create_params.py @@ -0,0 +1,39 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import Literal, TypeAlias, TypedDict + +from .realtime_session_create_request_param import RealtimeSessionCreateRequestParam +from .realtime_transcription_session_create_request_param import RealtimeTranscriptionSessionCreateRequestParam + +__all__ = ["ClientSecretCreateParams", "ExpiresAfter", "Session"] + + +class ClientSecretCreateParams(TypedDict, total=False): + expires_after: ExpiresAfter + """Configuration for the ephemeral token expiration.""" + + session: Session + """Session configuration to use for the client secret. + + Choose either a realtime session or a transcription session. + """ + + +class ExpiresAfter(TypedDict, total=False): + anchor: Literal["created_at"] + """The anchor point for the ephemeral token expiration. + + Only `created_at` is currently supported. + """ + + seconds: int + """The number of seconds from the anchor point to the expiration. + + Select a value between `10` and `7200`. + """ + + +Session: TypeAlias = Union[RealtimeSessionCreateRequestParam, RealtimeTranscriptionSessionCreateRequestParam] diff --git a/src/openai/types/realtime/client_secret_create_response.py b/src/openai/types/realtime/client_secret_create_response.py new file mode 100644 index 0000000000..ea8b9f9ca1 --- /dev/null +++ b/src/openai/types/realtime/client_secret_create_response.py @@ -0,0 +1,110 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, TypeAlias + +from ..._models import BaseModel +from .realtime_session_create_response import RealtimeSessionCreateResponse + +__all__ = [ + "ClientSecretCreateResponse", + "Session", + "SessionRealtimeTranscriptionSessionCreateResponse", + "SessionRealtimeTranscriptionSessionCreateResponseAudio", + "SessionRealtimeTranscriptionSessionCreateResponseAudioInput", + "SessionRealtimeTranscriptionSessionCreateResponseAudioInputNoiseReduction", + "SessionRealtimeTranscriptionSessionCreateResponseAudioInputTranscription", + "SessionRealtimeTranscriptionSessionCreateResponseAudioInputTurnDetection", +] + + +class SessionRealtimeTranscriptionSessionCreateResponseAudioInputNoiseReduction(BaseModel): + type: Optional[Literal["near_field", "far_field"]] = None + + +class SessionRealtimeTranscriptionSessionCreateResponseAudioInputTranscription(BaseModel): + language: Optional[str] = None + """The language of the input audio. + + Supplying the input language in + [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) + format will improve accuracy and latency. + """ + + model: Optional[Literal["gpt-4o-transcribe", "gpt-4o-mini-transcribe", "whisper-1"]] = None + """The model to use for transcription. + + Can be `gpt-4o-transcribe`, `gpt-4o-mini-transcribe`, or `whisper-1`. + """ + + prompt: Optional[str] = None + """An optional text to guide the model's style or continue a previous audio + segment. + + The [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) + should match the audio language. + """ + + +class SessionRealtimeTranscriptionSessionCreateResponseAudioInputTurnDetection(BaseModel): + prefix_padding_ms: Optional[int] = None + + silence_duration_ms: Optional[int] = None + + threshold: Optional[float] = None + + type: Optional[str] = None + """Type of turn detection, only `server_vad` is currently supported.""" + + +class SessionRealtimeTranscriptionSessionCreateResponseAudioInput(BaseModel): + format: Optional[str] = None + """The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + + noise_reduction: Optional[SessionRealtimeTranscriptionSessionCreateResponseAudioInputNoiseReduction] = None + """Configuration for input audio noise reduction.""" + + transcription: Optional[SessionRealtimeTranscriptionSessionCreateResponseAudioInputTranscription] = None + """Configuration of the transcription model.""" + + turn_detection: Optional[SessionRealtimeTranscriptionSessionCreateResponseAudioInputTurnDetection] = None + """Configuration for turn detection.""" + + +class SessionRealtimeTranscriptionSessionCreateResponseAudio(BaseModel): + input: Optional[SessionRealtimeTranscriptionSessionCreateResponseAudioInput] = None + + +class SessionRealtimeTranscriptionSessionCreateResponse(BaseModel): + id: Optional[str] = None + """Unique identifier for the session that looks like `sess_1234567890abcdef`.""" + + audio: Optional[SessionRealtimeTranscriptionSessionCreateResponseAudio] = None + """Configuration for input audio for the session.""" + + expires_at: Optional[int] = None + """Expiration timestamp for the session, in seconds since epoch.""" + + include: Optional[List[Literal["item.input_audio_transcription.logprobs"]]] = None + """Additional fields to include in server outputs. + + - `item.input_audio_transcription.logprobs`: Include logprobs for input audio + transcription. + """ + + object: Optional[str] = None + """The object type. Always `realtime.transcription_session`.""" + + +Session: TypeAlias = Union[RealtimeSessionCreateResponse, SessionRealtimeTranscriptionSessionCreateResponse] + + +class ClientSecretCreateResponse(BaseModel): + expires_at: int + """Expiration timestamp for the client secret, in seconds since epoch.""" + + session: Session + """The session configuration for either a realtime or transcription session.""" + + value: str + """The generated client secret value.""" diff --git a/src/openai/types/realtime/conversation_created_event.py b/src/openai/types/realtime/conversation_created_event.py new file mode 100644 index 0000000000..6ec1dc8c85 --- /dev/null +++ b/src/openai/types/realtime/conversation_created_event.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ConversationCreatedEvent", "Conversation"] + + +class Conversation(BaseModel): + id: Optional[str] = None + """The unique ID of the conversation.""" + + object: Optional[Literal["realtime.conversation"]] = None + """The object type, must be `realtime.conversation`.""" + + +class ConversationCreatedEvent(BaseModel): + conversation: Conversation + """The conversation resource.""" + + event_id: str + """The unique ID of the server event.""" + + type: Literal["conversation.created"] + """The event type, must be `conversation.created`.""" diff --git a/src/openai/types/realtime/conversation_item.py b/src/openai/types/realtime/conversation_item.py new file mode 100644 index 0000000000..be021520a2 --- /dev/null +++ b/src/openai/types/realtime/conversation_item.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from typing_extensions import Annotated, TypeAlias + +from ..._utils import PropertyInfo +from .realtime_mcp_tool_call import RealtimeMcpToolCall +from .realtime_mcp_list_tools import RealtimeMcpListTools +from .realtime_mcp_approval_request import RealtimeMcpApprovalRequest +from .realtime_mcp_approval_response import RealtimeMcpApprovalResponse +from .realtime_conversation_item_user_message import RealtimeConversationItemUserMessage +from .realtime_conversation_item_function_call import RealtimeConversationItemFunctionCall +from .realtime_conversation_item_system_message import RealtimeConversationItemSystemMessage +from .realtime_conversation_item_assistant_message import RealtimeConversationItemAssistantMessage +from .realtime_conversation_item_function_call_output import RealtimeConversationItemFunctionCallOutput + +__all__ = ["ConversationItem"] + +ConversationItem: TypeAlias = Annotated[ + Union[ + RealtimeConversationItemSystemMessage, + RealtimeConversationItemUserMessage, + RealtimeConversationItemAssistantMessage, + RealtimeConversationItemFunctionCall, + RealtimeConversationItemFunctionCallOutput, + RealtimeMcpApprovalResponse, + RealtimeMcpListTools, + RealtimeMcpToolCall, + RealtimeMcpApprovalRequest, + ], + PropertyInfo(discriminator="type"), +] diff --git a/src/openai/types/realtime/conversation_item_added.py b/src/openai/types/realtime/conversation_item_added.py new file mode 100644 index 0000000000..ae9f6803e4 --- /dev/null +++ b/src/openai/types/realtime/conversation_item_added.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel +from .conversation_item import ConversationItem + +__all__ = ["ConversationItemAdded"] + + +class ConversationItemAdded(BaseModel): + event_id: str + """The unique ID of the server event.""" + + item: ConversationItem + """A single item within a Realtime conversation.""" + + type: Literal["conversation.item.added"] + """The event type, must be `conversation.item.added`.""" + + previous_item_id: Optional[str] = None + """The ID of the item that precedes this one, if any. + + This is used to maintain ordering when items are inserted. + """ diff --git a/src/openai/types/realtime/conversation_item_create_event.py b/src/openai/types/realtime/conversation_item_create_event.py new file mode 100644 index 0000000000..8fa2dfe08c --- /dev/null +++ b/src/openai/types/realtime/conversation_item_create_event.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel +from .conversation_item import ConversationItem + +__all__ = ["ConversationItemCreateEvent"] + + +class ConversationItemCreateEvent(BaseModel): + item: ConversationItem + """A single item within a Realtime conversation.""" + + type: Literal["conversation.item.create"] + """The event type, must be `conversation.item.create`.""" + + event_id: Optional[str] = None + """Optional client-generated ID used to identify this event.""" + + previous_item_id: Optional[str] = None + """The ID of the preceding item after which the new item will be inserted. + + If not set, the new item will be appended to the end of the conversation. If set + to `root`, the new item will be added to the beginning of the conversation. If + set to an existing ID, it allows an item to be inserted mid-conversation. If the + ID cannot be found, an error will be returned and the item will not be added. + """ diff --git a/src/openai/types/realtime/conversation_item_create_event_param.py b/src/openai/types/realtime/conversation_item_create_event_param.py new file mode 100644 index 0000000000..8530dc72cd --- /dev/null +++ b/src/openai/types/realtime/conversation_item_create_event_param.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +from .conversation_item_param import ConversationItemParam + +__all__ = ["ConversationItemCreateEventParam"] + + +class ConversationItemCreateEventParam(TypedDict, total=False): + item: Required[ConversationItemParam] + """A single item within a Realtime conversation.""" + + type: Required[Literal["conversation.item.create"]] + """The event type, must be `conversation.item.create`.""" + + event_id: str + """Optional client-generated ID used to identify this event.""" + + previous_item_id: str + """The ID of the preceding item after which the new item will be inserted. + + If not set, the new item will be appended to the end of the conversation. If set + to `root`, the new item will be added to the beginning of the conversation. If + set to an existing ID, it allows an item to be inserted mid-conversation. If the + ID cannot be found, an error will be returned and the item will not be added. + """ diff --git a/src/openai/types/realtime/conversation_item_created_event.py b/src/openai/types/realtime/conversation_item_created_event.py new file mode 100644 index 0000000000..13f24ad31a --- /dev/null +++ b/src/openai/types/realtime/conversation_item_created_event.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel +from .conversation_item import ConversationItem + +__all__ = ["ConversationItemCreatedEvent"] + + +class ConversationItemCreatedEvent(BaseModel): + event_id: str + """The unique ID of the server event.""" + + item: ConversationItem + """A single item within a Realtime conversation.""" + + type: Literal["conversation.item.created"] + """The event type, must be `conversation.item.created`.""" + + previous_item_id: Optional[str] = None + """ + The ID of the preceding item in the Conversation context, allows the client to + understand the order of the conversation. Can be `null` if the item has no + predecessor. + """ diff --git a/src/openai/types/realtime/conversation_item_delete_event.py b/src/openai/types/realtime/conversation_item_delete_event.py new file mode 100644 index 0000000000..3734f72e9d --- /dev/null +++ b/src/openai/types/realtime/conversation_item_delete_event.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ConversationItemDeleteEvent"] + + +class ConversationItemDeleteEvent(BaseModel): + item_id: str + """The ID of the item to delete.""" + + type: Literal["conversation.item.delete"] + """The event type, must be `conversation.item.delete`.""" + + event_id: Optional[str] = None + """Optional client-generated ID used to identify this event.""" diff --git a/src/openai/types/realtime/conversation_item_delete_event_param.py b/src/openai/types/realtime/conversation_item_delete_event_param.py new file mode 100644 index 0000000000..c3f88d6627 --- /dev/null +++ b/src/openai/types/realtime/conversation_item_delete_event_param.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ConversationItemDeleteEventParam"] + + +class ConversationItemDeleteEventParam(TypedDict, total=False): + item_id: Required[str] + """The ID of the item to delete.""" + + type: Required[Literal["conversation.item.delete"]] + """The event type, must be `conversation.item.delete`.""" + + event_id: str + """Optional client-generated ID used to identify this event.""" diff --git a/src/openai/types/realtime/conversation_item_deleted_event.py b/src/openai/types/realtime/conversation_item_deleted_event.py new file mode 100644 index 0000000000..cfe6fe85fc --- /dev/null +++ b/src/openai/types/realtime/conversation_item_deleted_event.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ConversationItemDeletedEvent"] + + +class ConversationItemDeletedEvent(BaseModel): + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the item that was deleted.""" + + type: Literal["conversation.item.deleted"] + """The event type, must be `conversation.item.deleted`.""" diff --git a/src/openai/types/realtime/conversation_item_done.py b/src/openai/types/realtime/conversation_item_done.py new file mode 100644 index 0000000000..a4c9b8a840 --- /dev/null +++ b/src/openai/types/realtime/conversation_item_done.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel +from .conversation_item import ConversationItem + +__all__ = ["ConversationItemDone"] + + +class ConversationItemDone(BaseModel): + event_id: str + """The unique ID of the server event.""" + + item: ConversationItem + """A single item within a Realtime conversation.""" + + type: Literal["conversation.item.done"] + """The event type, must be `conversation.item.done`.""" + + previous_item_id: Optional[str] = None + """The ID of the item that precedes this one, if any. + + This is used to maintain ordering when items are inserted. + """ diff --git a/src/openai/types/realtime/conversation_item_input_audio_transcription_completed_event.py b/src/openai/types/realtime/conversation_item_input_audio_transcription_completed_event.py new file mode 100644 index 0000000000..eda3f3bab6 --- /dev/null +++ b/src/openai/types/realtime/conversation_item_input_audio_transcription_completed_event.py @@ -0,0 +1,76 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, TypeAlias + +from ..._models import BaseModel +from .log_prob_properties import LogProbProperties + +__all__ = [ + "ConversationItemInputAudioTranscriptionCompletedEvent", + "Usage", + "UsageTranscriptTextUsageTokens", + "UsageTranscriptTextUsageTokensInputTokenDetails", + "UsageTranscriptTextUsageDuration", +] + + +class UsageTranscriptTextUsageTokensInputTokenDetails(BaseModel): + audio_tokens: Optional[int] = None + """Number of audio tokens billed for this request.""" + + text_tokens: Optional[int] = None + """Number of text tokens billed for this request.""" + + +class UsageTranscriptTextUsageTokens(BaseModel): + input_tokens: int + """Number of input tokens billed for this request.""" + + output_tokens: int + """Number of output tokens generated.""" + + total_tokens: int + """Total number of tokens used (input + output).""" + + type: Literal["tokens"] + """The type of the usage object. Always `tokens` for this variant.""" + + input_token_details: Optional[UsageTranscriptTextUsageTokensInputTokenDetails] = None + """Details about the input tokens billed for this request.""" + + +class UsageTranscriptTextUsageDuration(BaseModel): + seconds: float + """Duration of the input audio in seconds.""" + + type: Literal["duration"] + """The type of the usage object. Always `duration` for this variant.""" + + +Usage: TypeAlias = Union[UsageTranscriptTextUsageTokens, UsageTranscriptTextUsageDuration] + + +class ConversationItemInputAudioTranscriptionCompletedEvent(BaseModel): + content_index: int + """The index of the content part containing the audio.""" + + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the user message item containing the audio.""" + + transcript: str + """The transcribed text.""" + + type: Literal["conversation.item.input_audio_transcription.completed"] + """ + The event type, must be `conversation.item.input_audio_transcription.completed`. + """ + + usage: Usage + """Usage statistics for the transcription.""" + + logprobs: Optional[List[LogProbProperties]] = None + """The log probabilities of the transcription.""" diff --git a/src/openai/types/realtime/conversation_item_input_audio_transcription_delta_event.py b/src/openai/types/realtime/conversation_item_input_audio_transcription_delta_event.py new file mode 100644 index 0000000000..4e9528ccb0 --- /dev/null +++ b/src/openai/types/realtime/conversation_item_input_audio_transcription_delta_event.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel +from .log_prob_properties import LogProbProperties + +__all__ = ["ConversationItemInputAudioTranscriptionDeltaEvent"] + + +class ConversationItemInputAudioTranscriptionDeltaEvent(BaseModel): + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the item.""" + + type: Literal["conversation.item.input_audio_transcription.delta"] + """The event type, must be `conversation.item.input_audio_transcription.delta`.""" + + content_index: Optional[int] = None + """The index of the content part in the item's content array.""" + + delta: Optional[str] = None + """The text delta.""" + + logprobs: Optional[List[LogProbProperties]] = None + """The log probabilities of the transcription.""" diff --git a/src/openai/types/realtime/conversation_item_input_audio_transcription_failed_event.py b/src/openai/types/realtime/conversation_item_input_audio_transcription_failed_event.py new file mode 100644 index 0000000000..edb97bbf6f --- /dev/null +++ b/src/openai/types/realtime/conversation_item_input_audio_transcription_failed_event.py @@ -0,0 +1,39 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ConversationItemInputAudioTranscriptionFailedEvent", "Error"] + + +class Error(BaseModel): + code: Optional[str] = None + """Error code, if any.""" + + message: Optional[str] = None + """A human-readable error message.""" + + param: Optional[str] = None + """Parameter related to the error, if any.""" + + type: Optional[str] = None + """The type of error.""" + + +class ConversationItemInputAudioTranscriptionFailedEvent(BaseModel): + content_index: int + """The index of the content part containing the audio.""" + + error: Error + """Details of the transcription error.""" + + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the user message item.""" + + type: Literal["conversation.item.input_audio_transcription.failed"] + """The event type, must be `conversation.item.input_audio_transcription.failed`.""" diff --git a/src/openai/types/realtime/conversation_item_input_audio_transcription_segment.py b/src/openai/types/realtime/conversation_item_input_audio_transcription_segment.py new file mode 100644 index 0000000000..e2cbc9d299 --- /dev/null +++ b/src/openai/types/realtime/conversation_item_input_audio_transcription_segment.py @@ -0,0 +1,36 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ConversationItemInputAudioTranscriptionSegment"] + + +class ConversationItemInputAudioTranscriptionSegment(BaseModel): + id: str + """The segment identifier.""" + + content_index: int + """The index of the input audio content part within the item.""" + + end: float + """End time of the segment in seconds.""" + + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the item containing the input audio content.""" + + speaker: str + """The detected speaker label for this segment.""" + + start: float + """Start time of the segment in seconds.""" + + text: str + """The text for this segment.""" + + type: Literal["conversation.item.input_audio_transcription.segment"] + """The event type, must be `conversation.item.input_audio_transcription.segment`.""" diff --git a/src/openai/types/realtime/conversation_item_param.py b/src/openai/types/realtime/conversation_item_param.py new file mode 100644 index 0000000000..c8b442ecad --- /dev/null +++ b/src/openai/types/realtime/conversation_item_param.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import TypeAlias + +from .realtime_mcp_tool_call_param import RealtimeMcpToolCallParam +from .realtime_mcp_list_tools_param import RealtimeMcpListToolsParam +from .realtime_mcp_approval_request_param import RealtimeMcpApprovalRequestParam +from .realtime_mcp_approval_response_param import RealtimeMcpApprovalResponseParam +from .realtime_conversation_item_user_message_param import RealtimeConversationItemUserMessageParam +from .realtime_conversation_item_function_call_param import RealtimeConversationItemFunctionCallParam +from .realtime_conversation_item_system_message_param import RealtimeConversationItemSystemMessageParam +from .realtime_conversation_item_assistant_message_param import RealtimeConversationItemAssistantMessageParam +from .realtime_conversation_item_function_call_output_param import RealtimeConversationItemFunctionCallOutputParam + +__all__ = ["ConversationItemParam"] + +ConversationItemParam: TypeAlias = Union[ + RealtimeConversationItemSystemMessageParam, + RealtimeConversationItemUserMessageParam, + RealtimeConversationItemAssistantMessageParam, + RealtimeConversationItemFunctionCallParam, + RealtimeConversationItemFunctionCallOutputParam, + RealtimeMcpApprovalResponseParam, + RealtimeMcpListToolsParam, + RealtimeMcpToolCallParam, + RealtimeMcpApprovalRequestParam, +] diff --git a/src/openai/types/realtime/conversation_item_retrieve_event.py b/src/openai/types/realtime/conversation_item_retrieve_event.py new file mode 100644 index 0000000000..018c2ccc59 --- /dev/null +++ b/src/openai/types/realtime/conversation_item_retrieve_event.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ConversationItemRetrieveEvent"] + + +class ConversationItemRetrieveEvent(BaseModel): + item_id: str + """The ID of the item to retrieve.""" + + type: Literal["conversation.item.retrieve"] + """The event type, must be `conversation.item.retrieve`.""" + + event_id: Optional[str] = None + """Optional client-generated ID used to identify this event.""" diff --git a/src/openai/types/realtime/conversation_item_retrieve_event_param.py b/src/openai/types/realtime/conversation_item_retrieve_event_param.py new file mode 100644 index 0000000000..71b3ffa499 --- /dev/null +++ b/src/openai/types/realtime/conversation_item_retrieve_event_param.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ConversationItemRetrieveEventParam"] + + +class ConversationItemRetrieveEventParam(TypedDict, total=False): + item_id: Required[str] + """The ID of the item to retrieve.""" + + type: Required[Literal["conversation.item.retrieve"]] + """The event type, must be `conversation.item.retrieve`.""" + + event_id: str + """Optional client-generated ID used to identify this event.""" diff --git a/src/openai/types/realtime/conversation_item_truncate_event.py b/src/openai/types/realtime/conversation_item_truncate_event.py new file mode 100644 index 0000000000..63b591bfdb --- /dev/null +++ b/src/openai/types/realtime/conversation_item_truncate_event.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ConversationItemTruncateEvent"] + + +class ConversationItemTruncateEvent(BaseModel): + audio_end_ms: int + """Inclusive duration up to which audio is truncated, in milliseconds. + + If the audio_end_ms is greater than the actual audio duration, the server will + respond with an error. + """ + + content_index: int + """The index of the content part to truncate. Set this to 0.""" + + item_id: str + """The ID of the assistant message item to truncate. + + Only assistant message items can be truncated. + """ + + type: Literal["conversation.item.truncate"] + """The event type, must be `conversation.item.truncate`.""" + + event_id: Optional[str] = None + """Optional client-generated ID used to identify this event.""" diff --git a/src/openai/types/realtime/conversation_item_truncate_event_param.py b/src/openai/types/realtime/conversation_item_truncate_event_param.py new file mode 100644 index 0000000000..d3ad1e1e25 --- /dev/null +++ b/src/openai/types/realtime/conversation_item_truncate_event_param.py @@ -0,0 +1,31 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ConversationItemTruncateEventParam"] + + +class ConversationItemTruncateEventParam(TypedDict, total=False): + audio_end_ms: Required[int] + """Inclusive duration up to which audio is truncated, in milliseconds. + + If the audio_end_ms is greater than the actual audio duration, the server will + respond with an error. + """ + + content_index: Required[int] + """The index of the content part to truncate. Set this to 0.""" + + item_id: Required[str] + """The ID of the assistant message item to truncate. + + Only assistant message items can be truncated. + """ + + type: Required[Literal["conversation.item.truncate"]] + """The event type, must be `conversation.item.truncate`.""" + + event_id: str + """Optional client-generated ID used to identify this event.""" diff --git a/src/openai/types/realtime/conversation_item_truncated_event.py b/src/openai/types/realtime/conversation_item_truncated_event.py new file mode 100644 index 0000000000..f56cabc3d9 --- /dev/null +++ b/src/openai/types/realtime/conversation_item_truncated_event.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ConversationItemTruncatedEvent"] + + +class ConversationItemTruncatedEvent(BaseModel): + audio_end_ms: int + """The duration up to which the audio was truncated, in milliseconds.""" + + content_index: int + """The index of the content part that was truncated.""" + + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the assistant message item that was truncated.""" + + type: Literal["conversation.item.truncated"] + """The event type, must be `conversation.item.truncated`.""" diff --git a/src/openai/types/realtime/input_audio_buffer_append_event.py b/src/openai/types/realtime/input_audio_buffer_append_event.py new file mode 100644 index 0000000000..8562cf0af4 --- /dev/null +++ b/src/openai/types/realtime/input_audio_buffer_append_event.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["InputAudioBufferAppendEvent"] + + +class InputAudioBufferAppendEvent(BaseModel): + audio: str + """Base64-encoded audio bytes. + + This must be in the format specified by the `input_audio_format` field in the + session configuration. + """ + + type: Literal["input_audio_buffer.append"] + """The event type, must be `input_audio_buffer.append`.""" + + event_id: Optional[str] = None + """Optional client-generated ID used to identify this event.""" diff --git a/src/openai/types/realtime/input_audio_buffer_append_event_param.py b/src/openai/types/realtime/input_audio_buffer_append_event_param.py new file mode 100644 index 0000000000..3ad0bc737d --- /dev/null +++ b/src/openai/types/realtime/input_audio_buffer_append_event_param.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["InputAudioBufferAppendEventParam"] + + +class InputAudioBufferAppendEventParam(TypedDict, total=False): + audio: Required[str] + """Base64-encoded audio bytes. + + This must be in the format specified by the `input_audio_format` field in the + session configuration. + """ + + type: Required[Literal["input_audio_buffer.append"]] + """The event type, must be `input_audio_buffer.append`.""" + + event_id: str + """Optional client-generated ID used to identify this event.""" diff --git a/src/openai/types/realtime/input_audio_buffer_clear_event.py b/src/openai/types/realtime/input_audio_buffer_clear_event.py new file mode 100644 index 0000000000..9922ff3b32 --- /dev/null +++ b/src/openai/types/realtime/input_audio_buffer_clear_event.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["InputAudioBufferClearEvent"] + + +class InputAudioBufferClearEvent(BaseModel): + type: Literal["input_audio_buffer.clear"] + """The event type, must be `input_audio_buffer.clear`.""" + + event_id: Optional[str] = None + """Optional client-generated ID used to identify this event.""" diff --git a/src/openai/types/realtime/input_audio_buffer_clear_event_param.py b/src/openai/types/realtime/input_audio_buffer_clear_event_param.py new file mode 100644 index 0000000000..2bd6bc5a02 --- /dev/null +++ b/src/openai/types/realtime/input_audio_buffer_clear_event_param.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["InputAudioBufferClearEventParam"] + + +class InputAudioBufferClearEventParam(TypedDict, total=False): + type: Required[Literal["input_audio_buffer.clear"]] + """The event type, must be `input_audio_buffer.clear`.""" + + event_id: str + """Optional client-generated ID used to identify this event.""" diff --git a/src/openai/types/realtime/input_audio_buffer_cleared_event.py b/src/openai/types/realtime/input_audio_buffer_cleared_event.py new file mode 100644 index 0000000000..af71844f2f --- /dev/null +++ b/src/openai/types/realtime/input_audio_buffer_cleared_event.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["InputAudioBufferClearedEvent"] + + +class InputAudioBufferClearedEvent(BaseModel): + event_id: str + """The unique ID of the server event.""" + + type: Literal["input_audio_buffer.cleared"] + """The event type, must be `input_audio_buffer.cleared`.""" diff --git a/src/openai/types/realtime/input_audio_buffer_commit_event.py b/src/openai/types/realtime/input_audio_buffer_commit_event.py new file mode 100644 index 0000000000..125c3ba1e8 --- /dev/null +++ b/src/openai/types/realtime/input_audio_buffer_commit_event.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["InputAudioBufferCommitEvent"] + + +class InputAudioBufferCommitEvent(BaseModel): + type: Literal["input_audio_buffer.commit"] + """The event type, must be `input_audio_buffer.commit`.""" + + event_id: Optional[str] = None + """Optional client-generated ID used to identify this event.""" diff --git a/src/openai/types/realtime/input_audio_buffer_commit_event_param.py b/src/openai/types/realtime/input_audio_buffer_commit_event_param.py new file mode 100644 index 0000000000..c9c927ab98 --- /dev/null +++ b/src/openai/types/realtime/input_audio_buffer_commit_event_param.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["InputAudioBufferCommitEventParam"] + + +class InputAudioBufferCommitEventParam(TypedDict, total=False): + type: Required[Literal["input_audio_buffer.commit"]] + """The event type, must be `input_audio_buffer.commit`.""" + + event_id: str + """Optional client-generated ID used to identify this event.""" diff --git a/src/openai/types/realtime/input_audio_buffer_committed_event.py b/src/openai/types/realtime/input_audio_buffer_committed_event.py new file mode 100644 index 0000000000..5ed1b4ccc7 --- /dev/null +++ b/src/openai/types/realtime/input_audio_buffer_committed_event.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["InputAudioBufferCommittedEvent"] + + +class InputAudioBufferCommittedEvent(BaseModel): + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the user message item that will be created.""" + + type: Literal["input_audio_buffer.committed"] + """The event type, must be `input_audio_buffer.committed`.""" + + previous_item_id: Optional[str] = None + """ + The ID of the preceding item after which the new item will be inserted. Can be + `null` if the item has no predecessor. + """ diff --git a/src/openai/types/realtime/input_audio_buffer_speech_started_event.py b/src/openai/types/realtime/input_audio_buffer_speech_started_event.py new file mode 100644 index 0000000000..865205d786 --- /dev/null +++ b/src/openai/types/realtime/input_audio_buffer_speech_started_event.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["InputAudioBufferSpeechStartedEvent"] + + +class InputAudioBufferSpeechStartedEvent(BaseModel): + audio_start_ms: int + """ + Milliseconds from the start of all audio written to the buffer during the + session when speech was first detected. This will correspond to the beginning of + audio sent to the model, and thus includes the `prefix_padding_ms` configured in + the Session. + """ + + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the user message item that will be created when speech stops.""" + + type: Literal["input_audio_buffer.speech_started"] + """The event type, must be `input_audio_buffer.speech_started`.""" diff --git a/src/openai/types/realtime/input_audio_buffer_speech_stopped_event.py b/src/openai/types/realtime/input_audio_buffer_speech_stopped_event.py new file mode 100644 index 0000000000..6cb7845ff4 --- /dev/null +++ b/src/openai/types/realtime/input_audio_buffer_speech_stopped_event.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["InputAudioBufferSpeechStoppedEvent"] + + +class InputAudioBufferSpeechStoppedEvent(BaseModel): + audio_end_ms: int + """Milliseconds since the session started when speech stopped. + + This will correspond to the end of audio sent to the model, and thus includes + the `min_silence_duration_ms` configured in the Session. + """ + + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the user message item that will be created.""" + + type: Literal["input_audio_buffer.speech_stopped"] + """The event type, must be `input_audio_buffer.speech_stopped`.""" diff --git a/src/openai/types/realtime/input_audio_buffer_timeout_triggered.py b/src/openai/types/realtime/input_audio_buffer_timeout_triggered.py new file mode 100644 index 0000000000..ed592ac06b --- /dev/null +++ b/src/openai/types/realtime/input_audio_buffer_timeout_triggered.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["InputAudioBufferTimeoutTriggered"] + + +class InputAudioBufferTimeoutTriggered(BaseModel): + audio_end_ms: int + """Millisecond offset where speech ended within the buffered audio.""" + + audio_start_ms: int + """Millisecond offset where speech started within the buffered audio.""" + + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the item associated with this segment.""" + + type: Literal["input_audio_buffer.timeout_triggered"] + """The event type, must be `input_audio_buffer.timeout_triggered`.""" diff --git a/src/openai/types/realtime/log_prob_properties.py b/src/openai/types/realtime/log_prob_properties.py new file mode 100644 index 0000000000..92477d67d0 --- /dev/null +++ b/src/openai/types/realtime/log_prob_properties.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel + +__all__ = ["LogProbProperties"] + + +class LogProbProperties(BaseModel): + token: str + """The token that was used to generate the log probability.""" + + bytes: List[int] + """The bytes that were used to generate the log probability.""" + + logprob: float + """The log probability of the token.""" diff --git a/src/openai/types/realtime/mcp_list_tools_completed.py b/src/openai/types/realtime/mcp_list_tools_completed.py new file mode 100644 index 0000000000..941280f01a --- /dev/null +++ b/src/openai/types/realtime/mcp_list_tools_completed.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["McpListToolsCompleted"] + + +class McpListToolsCompleted(BaseModel): + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the MCP list tools item.""" + + type: Literal["mcp_list_tools.completed"] + """The event type, must be `mcp_list_tools.completed`.""" diff --git a/src/openai/types/realtime/mcp_list_tools_failed.py b/src/openai/types/realtime/mcp_list_tools_failed.py new file mode 100644 index 0000000000..892eda21bd --- /dev/null +++ b/src/openai/types/realtime/mcp_list_tools_failed.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["McpListToolsFailed"] + + +class McpListToolsFailed(BaseModel): + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the MCP list tools item.""" + + type: Literal["mcp_list_tools.failed"] + """The event type, must be `mcp_list_tools.failed`.""" diff --git a/src/openai/types/realtime/mcp_list_tools_in_progress.py b/src/openai/types/realtime/mcp_list_tools_in_progress.py new file mode 100644 index 0000000000..4254b5fd33 --- /dev/null +++ b/src/openai/types/realtime/mcp_list_tools_in_progress.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["McpListToolsInProgress"] + + +class McpListToolsInProgress(BaseModel): + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the MCP list tools item.""" + + type: Literal["mcp_list_tools.in_progress"] + """The event type, must be `mcp_list_tools.in_progress`.""" diff --git a/src/openai/types/realtime/output_audio_buffer_clear_event.py b/src/openai/types/realtime/output_audio_buffer_clear_event.py new file mode 100644 index 0000000000..b4c95039f3 --- /dev/null +++ b/src/openai/types/realtime/output_audio_buffer_clear_event.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["OutputAudioBufferClearEvent"] + + +class OutputAudioBufferClearEvent(BaseModel): + type: Literal["output_audio_buffer.clear"] + """The event type, must be `output_audio_buffer.clear`.""" + + event_id: Optional[str] = None + """The unique ID of the client event used for error handling.""" diff --git a/src/openai/types/realtime/output_audio_buffer_clear_event_param.py b/src/openai/types/realtime/output_audio_buffer_clear_event_param.py new file mode 100644 index 0000000000..a3205ebc6c --- /dev/null +++ b/src/openai/types/realtime/output_audio_buffer_clear_event_param.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["OutputAudioBufferClearEventParam"] + + +class OutputAudioBufferClearEventParam(TypedDict, total=False): + type: Required[Literal["output_audio_buffer.clear"]] + """The event type, must be `output_audio_buffer.clear`.""" + + event_id: str + """The unique ID of the client event used for error handling.""" diff --git a/src/openai/types/realtime/rate_limits_updated_event.py b/src/openai/types/realtime/rate_limits_updated_event.py new file mode 100644 index 0000000000..048a4028a1 --- /dev/null +++ b/src/openai/types/realtime/rate_limits_updated_event.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["RateLimitsUpdatedEvent", "RateLimit"] + + +class RateLimit(BaseModel): + limit: Optional[int] = None + """The maximum allowed value for the rate limit.""" + + name: Optional[Literal["requests", "tokens"]] = None + """The name of the rate limit (`requests`, `tokens`).""" + + remaining: Optional[int] = None + """The remaining value before the limit is reached.""" + + reset_seconds: Optional[float] = None + """Seconds until the rate limit resets.""" + + +class RateLimitsUpdatedEvent(BaseModel): + event_id: str + """The unique ID of the server event.""" + + rate_limits: List[RateLimit] + """List of rate limit information.""" + + type: Literal["rate_limits.updated"] + """The event type, must be `rate_limits.updated`.""" diff --git a/src/openai/types/realtime/realtime_audio_config.py b/src/openai/types/realtime/realtime_audio_config.py new file mode 100644 index 0000000000..7463c70038 --- /dev/null +++ b/src/openai/types/realtime/realtime_audio_config.py @@ -0,0 +1,184 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union, Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["RealtimeAudioConfig", "Input", "InputNoiseReduction", "InputTranscription", "InputTurnDetection", "Output"] + + +class InputNoiseReduction(BaseModel): + type: Optional[Literal["near_field", "far_field"]] = None + """Type of noise reduction. + + `near_field` is for close-talking microphones such as headphones, `far_field` is + for far-field microphones such as laptop or conference room microphones. + """ + + +class InputTranscription(BaseModel): + language: Optional[str] = None + """The language of the input audio. + + Supplying the input language in + [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) + format will improve accuracy and latency. + """ + + model: Optional[ + Literal[ + "whisper-1", + "gpt-4o-transcribe-latest", + "gpt-4o-mini-transcribe", + "gpt-4o-transcribe", + "gpt-4o-transcribe-diarize", + ] + ] = None + """The model to use for transcription. + + Current options are `whisper-1`, `gpt-4o-transcribe-latest`, + `gpt-4o-mini-transcribe`, `gpt-4o-transcribe`, and `gpt-4o-transcribe-diarize`. + """ + + prompt: Optional[str] = None + """ + An optional text to guide the model's style or continue a previous audio + segment. For `whisper-1`, the + [prompt is a list of keywords](https://platform.openai.com/docs/guides/speech-to-text#prompting). + For `gpt-4o-transcribe` models, the prompt is a free text string, for example + "expect words related to technology". + """ + + +class InputTurnDetection(BaseModel): + create_response: Optional[bool] = None + """ + Whether or not to automatically generate a response when a VAD stop event + occurs. + """ + + eagerness: Optional[Literal["low", "medium", "high", "auto"]] = None + """Used only for `semantic_vad` mode. + + The eagerness of the model to respond. `low` will wait longer for the user to + continue speaking, `high` will respond more quickly. `auto` is the default and + is equivalent to `medium`. + """ + + idle_timeout_ms: Optional[int] = None + """ + Optional idle timeout after which turn detection will auto-timeout when no + additional audio is received. + """ + + interrupt_response: Optional[bool] = None + """ + Whether or not to automatically interrupt any ongoing response with output to + the default conversation (i.e. `conversation` of `auto`) when a VAD start event + occurs. + """ + + prefix_padding_ms: Optional[int] = None + """Used only for `server_vad` mode. + + Amount of audio to include before the VAD detected speech (in milliseconds). + Defaults to 300ms. + """ + + silence_duration_ms: Optional[int] = None + """Used only for `server_vad` mode. + + Duration of silence to detect speech stop (in milliseconds). Defaults to 500ms. + With shorter values the model will respond more quickly, but may jump in on + short pauses from the user. + """ + + threshold: Optional[float] = None + """Used only for `server_vad` mode. + + Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A higher + threshold will require louder audio to activate the model, and thus might + perform better in noisy environments. + """ + + type: Optional[Literal["server_vad", "semantic_vad"]] = None + """Type of turn detection.""" + + +class Input(BaseModel): + format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None + """The format of input audio. + + Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, input audio must + be 16-bit PCM at a 24kHz sample rate, single channel (mono), and little-endian + byte order. + """ + + noise_reduction: Optional[InputNoiseReduction] = None + """Configuration for input audio noise reduction. + + This can be set to `null` to turn off. Noise reduction filters audio added to + the input audio buffer before it is sent to VAD and the model. Filtering the + audio can improve VAD and turn detection accuracy (reducing false positives) and + model performance by improving perception of the input audio. + """ + + transcription: Optional[InputTranscription] = None + """ + Configuration for input audio transcription, defaults to off and can be set to + `null` to turn off once on. Input audio transcription is not native to the + model, since the model consumes audio directly. Transcription runs + asynchronously through + [the /audio/transcriptions endpoint](https://platform.openai.com/docs/api-reference/audio/createTranscription) + and should be treated as guidance of input audio content rather than precisely + what the model heard. The client can optionally set the language and prompt for + transcription, these offer additional guidance to the transcription service. + """ + + turn_detection: Optional[InputTurnDetection] = None + """Configuration for turn detection, ether Server VAD or Semantic VAD. + + This can be set to `null` to turn off, in which case the client must manually + trigger model response. Server VAD means that the model will detect the start + and end of speech based on audio volume and respond at the end of user speech. + Semantic VAD is more advanced and uses a turn detection model (in conjunction + with VAD) to semantically estimate whether the user has finished speaking, then + dynamically sets a timeout based on this probability. For example, if user audio + trails off with "uhhm", the model will score a low probability of turn end and + wait longer for the user to continue speaking. This can be useful for more + natural conversations, but may have a higher latency. + """ + + +class Output(BaseModel): + format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None + """The format of output audio. + + Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, output audio is + sampled at a rate of 24kHz. + """ + + speed: Optional[float] = None + """The speed of the model's spoken response. + + 1.0 is the default speed. 0.25 is the minimum speed. 1.5 is the maximum speed. + This value can only be changed in between model turns, not while a response is + in progress. + """ + + voice: Union[ + str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"], None + ] = None + """The voice the model uses to respond. + + Voice cannot be changed during the session once the model has responded with + audio at least once. Current voice options are `alloy`, `ash`, `ballad`, + `coral`, `echo`, `sage`, `shimmer`, `verse`, `marin`, and `cedar`. + """ + + +class RealtimeAudioConfig(BaseModel): + input: Optional[Input] = None + + output: Optional[Output] = None diff --git a/src/openai/types/realtime/realtime_audio_config_param.py b/src/openai/types/realtime/realtime_audio_config_param.py new file mode 100644 index 0000000000..9f2e12e910 --- /dev/null +++ b/src/openai/types/realtime/realtime_audio_config_param.py @@ -0,0 +1,187 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Optional +from typing_extensions import Literal, TypedDict + +__all__ = [ + "RealtimeAudioConfigParam", + "Input", + "InputNoiseReduction", + "InputTranscription", + "InputTurnDetection", + "Output", +] + + +class InputNoiseReduction(TypedDict, total=False): + type: Literal["near_field", "far_field"] + """Type of noise reduction. + + `near_field` is for close-talking microphones such as headphones, `far_field` is + for far-field microphones such as laptop or conference room microphones. + """ + + +class InputTranscription(TypedDict, total=False): + language: str + """The language of the input audio. + + Supplying the input language in + [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) + format will improve accuracy and latency. + """ + + model: Literal[ + "whisper-1", + "gpt-4o-transcribe-latest", + "gpt-4o-mini-transcribe", + "gpt-4o-transcribe", + "gpt-4o-transcribe-diarize", + ] + """The model to use for transcription. + + Current options are `whisper-1`, `gpt-4o-transcribe-latest`, + `gpt-4o-mini-transcribe`, `gpt-4o-transcribe`, and `gpt-4o-transcribe-diarize`. + """ + + prompt: str + """ + An optional text to guide the model's style or continue a previous audio + segment. For `whisper-1`, the + [prompt is a list of keywords](https://platform.openai.com/docs/guides/speech-to-text#prompting). + For `gpt-4o-transcribe` models, the prompt is a free text string, for example + "expect words related to technology". + """ + + +class InputTurnDetection(TypedDict, total=False): + create_response: bool + """ + Whether or not to automatically generate a response when a VAD stop event + occurs. + """ + + eagerness: Literal["low", "medium", "high", "auto"] + """Used only for `semantic_vad` mode. + + The eagerness of the model to respond. `low` will wait longer for the user to + continue speaking, `high` will respond more quickly. `auto` is the default and + is equivalent to `medium`. + """ + + idle_timeout_ms: Optional[int] + """ + Optional idle timeout after which turn detection will auto-timeout when no + additional audio is received. + """ + + interrupt_response: bool + """ + Whether or not to automatically interrupt any ongoing response with output to + the default conversation (i.e. `conversation` of `auto`) when a VAD start event + occurs. + """ + + prefix_padding_ms: int + """Used only for `server_vad` mode. + + Amount of audio to include before the VAD detected speech (in milliseconds). + Defaults to 300ms. + """ + + silence_duration_ms: int + """Used only for `server_vad` mode. + + Duration of silence to detect speech stop (in milliseconds). Defaults to 500ms. + With shorter values the model will respond more quickly, but may jump in on + short pauses from the user. + """ + + threshold: float + """Used only for `server_vad` mode. + + Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A higher + threshold will require louder audio to activate the model, and thus might + perform better in noisy environments. + """ + + type: Literal["server_vad", "semantic_vad"] + """Type of turn detection.""" + + +class Input(TypedDict, total=False): + format: Literal["pcm16", "g711_ulaw", "g711_alaw"] + """The format of input audio. + + Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, input audio must + be 16-bit PCM at a 24kHz sample rate, single channel (mono), and little-endian + byte order. + """ + + noise_reduction: InputNoiseReduction + """Configuration for input audio noise reduction. + + This can be set to `null` to turn off. Noise reduction filters audio added to + the input audio buffer before it is sent to VAD and the model. Filtering the + audio can improve VAD and turn detection accuracy (reducing false positives) and + model performance by improving perception of the input audio. + """ + + transcription: InputTranscription + """ + Configuration for input audio transcription, defaults to off and can be set to + `null` to turn off once on. Input audio transcription is not native to the + model, since the model consumes audio directly. Transcription runs + asynchronously through + [the /audio/transcriptions endpoint](https://platform.openai.com/docs/api-reference/audio/createTranscription) + and should be treated as guidance of input audio content rather than precisely + what the model heard. The client can optionally set the language and prompt for + transcription, these offer additional guidance to the transcription service. + """ + + turn_detection: InputTurnDetection + """Configuration for turn detection, ether Server VAD or Semantic VAD. + + This can be set to `null` to turn off, in which case the client must manually + trigger model response. Server VAD means that the model will detect the start + and end of speech based on audio volume and respond at the end of user speech. + Semantic VAD is more advanced and uses a turn detection model (in conjunction + with VAD) to semantically estimate whether the user has finished speaking, then + dynamically sets a timeout based on this probability. For example, if user audio + trails off with "uhhm", the model will score a low probability of turn end and + wait longer for the user to continue speaking. This can be useful for more + natural conversations, but may have a higher latency. + """ + + +class Output(TypedDict, total=False): + format: Literal["pcm16", "g711_ulaw", "g711_alaw"] + """The format of output audio. + + Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, output audio is + sampled at a rate of 24kHz. + """ + + speed: float + """The speed of the model's spoken response. + + 1.0 is the default speed. 0.25 is the minimum speed. 1.5 is the maximum speed. + This value can only be changed in between model turns, not while a response is + in progress. + """ + + voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"]] + """The voice the model uses to respond. + + Voice cannot be changed during the session once the model has responded with + audio at least once. Current voice options are `alloy`, `ash`, `ballad`, + `coral`, `echo`, `sage`, `shimmer`, `verse`, `marin`, and `cedar`. + """ + + +class RealtimeAudioConfigParam(TypedDict, total=False): + input: Input + + output: Output diff --git a/src/openai/types/realtime/realtime_client_event.py b/src/openai/types/realtime/realtime_client_event.py new file mode 100644 index 0000000000..8c2c95e849 --- /dev/null +++ b/src/openai/types/realtime/realtime_client_event.py @@ -0,0 +1,38 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from typing_extensions import Annotated, TypeAlias + +from ..._utils import PropertyInfo +from .session_update_event import SessionUpdateEvent +from .response_cancel_event import ResponseCancelEvent +from .response_create_event import ResponseCreateEvent +from .transcription_session_update import TranscriptionSessionUpdate +from .conversation_item_create_event import ConversationItemCreateEvent +from .conversation_item_delete_event import ConversationItemDeleteEvent +from .input_audio_buffer_clear_event import InputAudioBufferClearEvent +from .input_audio_buffer_append_event import InputAudioBufferAppendEvent +from .input_audio_buffer_commit_event import InputAudioBufferCommitEvent +from .output_audio_buffer_clear_event import OutputAudioBufferClearEvent +from .conversation_item_retrieve_event import ConversationItemRetrieveEvent +from .conversation_item_truncate_event import ConversationItemTruncateEvent + +__all__ = ["RealtimeClientEvent"] + +RealtimeClientEvent: TypeAlias = Annotated[ + Union[ + ConversationItemCreateEvent, + ConversationItemDeleteEvent, + ConversationItemRetrieveEvent, + ConversationItemTruncateEvent, + InputAudioBufferAppendEvent, + InputAudioBufferClearEvent, + OutputAudioBufferClearEvent, + InputAudioBufferCommitEvent, + ResponseCancelEvent, + ResponseCreateEvent, + SessionUpdateEvent, + TranscriptionSessionUpdate, + ], + PropertyInfo(discriminator="type"), +] diff --git a/src/openai/types/realtime/realtime_client_event_param.py b/src/openai/types/realtime/realtime_client_event_param.py new file mode 100644 index 0000000000..8e042dd64b --- /dev/null +++ b/src/openai/types/realtime/realtime_client_event_param.py @@ -0,0 +1,36 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import TypeAlias + +from .session_update_event_param import SessionUpdateEventParam +from .response_cancel_event_param import ResponseCancelEventParam +from .response_create_event_param import ResponseCreateEventParam +from .transcription_session_update_param import TranscriptionSessionUpdateParam +from .conversation_item_create_event_param import ConversationItemCreateEventParam +from .conversation_item_delete_event_param import ConversationItemDeleteEventParam +from .input_audio_buffer_clear_event_param import InputAudioBufferClearEventParam +from .input_audio_buffer_append_event_param import InputAudioBufferAppendEventParam +from .input_audio_buffer_commit_event_param import InputAudioBufferCommitEventParam +from .output_audio_buffer_clear_event_param import OutputAudioBufferClearEventParam +from .conversation_item_retrieve_event_param import ConversationItemRetrieveEventParam +from .conversation_item_truncate_event_param import ConversationItemTruncateEventParam + +__all__ = ["RealtimeClientEventParam"] + +RealtimeClientEventParam: TypeAlias = Union[ + ConversationItemCreateEventParam, + ConversationItemDeleteEventParam, + ConversationItemRetrieveEventParam, + ConversationItemTruncateEventParam, + InputAudioBufferAppendEventParam, + InputAudioBufferClearEventParam, + OutputAudioBufferClearEventParam, + InputAudioBufferCommitEventParam, + ResponseCancelEventParam, + ResponseCreateEventParam, + SessionUpdateEventParam, + TranscriptionSessionUpdateParam, +] diff --git a/src/openai/types/realtime/realtime_client_secret_config.py b/src/openai/types/realtime/realtime_client_secret_config.py new file mode 100644 index 0000000000..29f8f57081 --- /dev/null +++ b/src/openai/types/realtime/realtime_client_secret_config.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["RealtimeClientSecretConfig", "ExpiresAfter"] + + +class ExpiresAfter(BaseModel): + anchor: Literal["created_at"] + """The anchor point for the ephemeral token expiration. + + Only `created_at` is currently supported. + """ + + seconds: Optional[int] = None + """The number of seconds from the anchor point to the expiration. + + Select a value between `10` and `7200`. + """ + + +class RealtimeClientSecretConfig(BaseModel): + expires_after: Optional[ExpiresAfter] = None + """Configuration for the ephemeral token expiration.""" diff --git a/src/openai/types/realtime/realtime_client_secret_config_param.py b/src/openai/types/realtime/realtime_client_secret_config_param.py new file mode 100644 index 0000000000..30a80134ee --- /dev/null +++ b/src/openai/types/realtime/realtime_client_secret_config_param.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["RealtimeClientSecretConfigParam", "ExpiresAfter"] + + +class ExpiresAfter(TypedDict, total=False): + anchor: Required[Literal["created_at"]] + """The anchor point for the ephemeral token expiration. + + Only `created_at` is currently supported. + """ + + seconds: int + """The number of seconds from the anchor point to the expiration. + + Select a value between `10` and `7200`. + """ + + +class RealtimeClientSecretConfigParam(TypedDict, total=False): + expires_after: ExpiresAfter + """Configuration for the ephemeral token expiration.""" diff --git a/src/openai/types/realtime/realtime_connect_params.py b/src/openai/types/realtime/realtime_connect_params.py new file mode 100644 index 0000000000..76474f3de4 --- /dev/null +++ b/src/openai/types/realtime/realtime_connect_params.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["RealtimeConnectParams"] + + +class RealtimeConnectParams(TypedDict, total=False): + model: Required[str] diff --git a/src/openai/types/realtime/realtime_conversation_item_assistant_message.py b/src/openai/types/realtime/realtime_conversation_item_assistant_message.py new file mode 100644 index 0000000000..d0f37745ea --- /dev/null +++ b/src/openai/types/realtime/realtime_conversation_item_assistant_message.py @@ -0,0 +1,36 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["RealtimeConversationItemAssistantMessage", "Content"] + + +class Content(BaseModel): + text: Optional[str] = None + """The text content.""" + + type: Optional[Literal["text"]] = None + """The content type. Always `text` for assistant messages.""" + + +class RealtimeConversationItemAssistantMessage(BaseModel): + content: List[Content] + """The content of the message.""" + + role: Literal["assistant"] + """The role of the message sender. Always `assistant`.""" + + type: Literal["message"] + """The type of the item. Always `message`.""" + + id: Optional[str] = None + """The unique ID of the item.""" + + object: Optional[Literal["realtime.item"]] = None + """Identifier for the API object being returned - always `realtime.item`.""" + + status: Optional[Literal["completed", "incomplete", "in_progress"]] = None + """The status of the item. Has no effect on the conversation.""" diff --git a/src/openai/types/realtime/realtime_conversation_item_assistant_message_param.py b/src/openai/types/realtime/realtime_conversation_item_assistant_message_param.py new file mode 100644 index 0000000000..cfbd9cd2cf --- /dev/null +++ b/src/openai/types/realtime/realtime_conversation_item_assistant_message_param.py @@ -0,0 +1,36 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["RealtimeConversationItemAssistantMessageParam", "Content"] + + +class Content(TypedDict, total=False): + text: str + """The text content.""" + + type: Literal["text"] + """The content type. Always `text` for assistant messages.""" + + +class RealtimeConversationItemAssistantMessageParam(TypedDict, total=False): + content: Required[Iterable[Content]] + """The content of the message.""" + + role: Required[Literal["assistant"]] + """The role of the message sender. Always `assistant`.""" + + type: Required[Literal["message"]] + """The type of the item. Always `message`.""" + + id: str + """The unique ID of the item.""" + + object: Literal["realtime.item"] + """Identifier for the API object being returned - always `realtime.item`.""" + + status: Literal["completed", "incomplete", "in_progress"] + """The status of the item. Has no effect on the conversation.""" diff --git a/src/openai/types/realtime/realtime_conversation_item_function_call.py b/src/openai/types/realtime/realtime_conversation_item_function_call.py new file mode 100644 index 0000000000..ce1c6d4cb2 --- /dev/null +++ b/src/openai/types/realtime/realtime_conversation_item_function_call.py @@ -0,0 +1,31 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["RealtimeConversationItemFunctionCall"] + + +class RealtimeConversationItemFunctionCall(BaseModel): + arguments: str + """The arguments of the function call.""" + + name: str + """The name of the function being called.""" + + type: Literal["function_call"] + """The type of the item. Always `function_call`.""" + + id: Optional[str] = None + """The unique ID of the item.""" + + call_id: Optional[str] = None + """The ID of the function call.""" + + object: Optional[Literal["realtime.item"]] = None + """Identifier for the API object being returned - always `realtime.item`.""" + + status: Optional[Literal["completed", "incomplete", "in_progress"]] = None + """The status of the item. Has no effect on the conversation.""" diff --git a/src/openai/types/realtime/realtime_conversation_item_function_call_output.py b/src/openai/types/realtime/realtime_conversation_item_function_call_output.py new file mode 100644 index 0000000000..cea840fdba --- /dev/null +++ b/src/openai/types/realtime/realtime_conversation_item_function_call_output.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["RealtimeConversationItemFunctionCallOutput"] + + +class RealtimeConversationItemFunctionCallOutput(BaseModel): + call_id: str + """The ID of the function call this output is for.""" + + output: str + """The output of the function call.""" + + type: Literal["function_call_output"] + """The type of the item. Always `function_call_output`.""" + + id: Optional[str] = None + """The unique ID of the item.""" + + object: Optional[Literal["realtime.item"]] = None + """Identifier for the API object being returned - always `realtime.item`.""" + + status: Optional[Literal["completed", "incomplete", "in_progress"]] = None + """The status of the item. Has no effect on the conversation.""" diff --git a/src/openai/types/realtime/realtime_conversation_item_function_call_output_param.py b/src/openai/types/realtime/realtime_conversation_item_function_call_output_param.py new file mode 100644 index 0000000000..a66c587fb6 --- /dev/null +++ b/src/openai/types/realtime/realtime_conversation_item_function_call_output_param.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["RealtimeConversationItemFunctionCallOutputParam"] + + +class RealtimeConversationItemFunctionCallOutputParam(TypedDict, total=False): + call_id: Required[str] + """The ID of the function call this output is for.""" + + output: Required[str] + """The output of the function call.""" + + type: Required[Literal["function_call_output"]] + """The type of the item. Always `function_call_output`.""" + + id: str + """The unique ID of the item.""" + + object: Literal["realtime.item"] + """Identifier for the API object being returned - always `realtime.item`.""" + + status: Literal["completed", "incomplete", "in_progress"] + """The status of the item. Has no effect on the conversation.""" diff --git a/src/openai/types/realtime/realtime_conversation_item_function_call_param.py b/src/openai/types/realtime/realtime_conversation_item_function_call_param.py new file mode 100644 index 0000000000..a4d6fb83ab --- /dev/null +++ b/src/openai/types/realtime/realtime_conversation_item_function_call_param.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["RealtimeConversationItemFunctionCallParam"] + + +class RealtimeConversationItemFunctionCallParam(TypedDict, total=False): + arguments: Required[str] + """The arguments of the function call.""" + + name: Required[str] + """The name of the function being called.""" + + type: Required[Literal["function_call"]] + """The type of the item. Always `function_call`.""" + + id: str + """The unique ID of the item.""" + + call_id: str + """The ID of the function call.""" + + object: Literal["realtime.item"] + """Identifier for the API object being returned - always `realtime.item`.""" + + status: Literal["completed", "incomplete", "in_progress"] + """The status of the item. Has no effect on the conversation.""" diff --git a/src/openai/types/realtime/realtime_conversation_item_system_message.py b/src/openai/types/realtime/realtime_conversation_item_system_message.py new file mode 100644 index 0000000000..abc67f6c5f --- /dev/null +++ b/src/openai/types/realtime/realtime_conversation_item_system_message.py @@ -0,0 +1,36 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["RealtimeConversationItemSystemMessage", "Content"] + + +class Content(BaseModel): + text: Optional[str] = None + """The text content.""" + + type: Optional[Literal["input_text"]] = None + """The content type. Always `input_text` for system messages.""" + + +class RealtimeConversationItemSystemMessage(BaseModel): + content: List[Content] + """The content of the message.""" + + role: Literal["system"] + """The role of the message sender. Always `system`.""" + + type: Literal["message"] + """The type of the item. Always `message`.""" + + id: Optional[str] = None + """The unique ID of the item.""" + + object: Optional[Literal["realtime.item"]] = None + """Identifier for the API object being returned - always `realtime.item`.""" + + status: Optional[Literal["completed", "incomplete", "in_progress"]] = None + """The status of the item. Has no effect on the conversation.""" diff --git a/src/openai/types/realtime/realtime_conversation_item_system_message_param.py b/src/openai/types/realtime/realtime_conversation_item_system_message_param.py new file mode 100644 index 0000000000..2a1c442738 --- /dev/null +++ b/src/openai/types/realtime/realtime_conversation_item_system_message_param.py @@ -0,0 +1,36 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["RealtimeConversationItemSystemMessageParam", "Content"] + + +class Content(TypedDict, total=False): + text: str + """The text content.""" + + type: Literal["input_text"] + """The content type. Always `input_text` for system messages.""" + + +class RealtimeConversationItemSystemMessageParam(TypedDict, total=False): + content: Required[Iterable[Content]] + """The content of the message.""" + + role: Required[Literal["system"]] + """The role of the message sender. Always `system`.""" + + type: Required[Literal["message"]] + """The type of the item. Always `message`.""" + + id: str + """The unique ID of the item.""" + + object: Literal["realtime.item"] + """Identifier for the API object being returned - always `realtime.item`.""" + + status: Literal["completed", "incomplete", "in_progress"] + """The status of the item. Has no effect on the conversation.""" diff --git a/src/openai/types/realtime/realtime_conversation_item_user_message.py b/src/openai/types/realtime/realtime_conversation_item_user_message.py new file mode 100644 index 0000000000..48a6c6ec0a --- /dev/null +++ b/src/openai/types/realtime/realtime_conversation_item_user_message.py @@ -0,0 +1,42 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["RealtimeConversationItemUserMessage", "Content"] + + +class Content(BaseModel): + audio: Optional[str] = None + """Base64-encoded audio bytes (for `input_audio`).""" + + text: Optional[str] = None + """The text content (for `input_text`).""" + + transcript: Optional[str] = None + """Transcript of the audio (for `input_audio`).""" + + type: Optional[Literal["input_text", "input_audio"]] = None + """The content type (`input_text` or `input_audio`).""" + + +class RealtimeConversationItemUserMessage(BaseModel): + content: List[Content] + """The content of the message.""" + + role: Literal["user"] + """The role of the message sender. Always `user`.""" + + type: Literal["message"] + """The type of the item. Always `message`.""" + + id: Optional[str] = None + """The unique ID of the item.""" + + object: Optional[Literal["realtime.item"]] = None + """Identifier for the API object being returned - always `realtime.item`.""" + + status: Optional[Literal["completed", "incomplete", "in_progress"]] = None + """The status of the item. Has no effect on the conversation.""" diff --git a/src/openai/types/realtime/realtime_conversation_item_user_message_param.py b/src/openai/types/realtime/realtime_conversation_item_user_message_param.py new file mode 100644 index 0000000000..cff64a66bf --- /dev/null +++ b/src/openai/types/realtime/realtime_conversation_item_user_message_param.py @@ -0,0 +1,42 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["RealtimeConversationItemUserMessageParam", "Content"] + + +class Content(TypedDict, total=False): + audio: str + """Base64-encoded audio bytes (for `input_audio`).""" + + text: str + """The text content (for `input_text`).""" + + transcript: str + """Transcript of the audio (for `input_audio`).""" + + type: Literal["input_text", "input_audio"] + """The content type (`input_text` or `input_audio`).""" + + +class RealtimeConversationItemUserMessageParam(TypedDict, total=False): + content: Required[Iterable[Content]] + """The content of the message.""" + + role: Required[Literal["user"]] + """The role of the message sender. Always `user`.""" + + type: Required[Literal["message"]] + """The type of the item. Always `message`.""" + + id: str + """The unique ID of the item.""" + + object: Literal["realtime.item"] + """Identifier for the API object being returned - always `realtime.item`.""" + + status: Literal["completed", "incomplete", "in_progress"] + """The status of the item. Has no effect on the conversation.""" diff --git a/src/openai/types/realtime/realtime_error.py b/src/openai/types/realtime/realtime_error.py new file mode 100644 index 0000000000..f1017d09e4 --- /dev/null +++ b/src/openai/types/realtime/realtime_error.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["RealtimeError"] + + +class RealtimeError(BaseModel): + message: str + """A human-readable error message.""" + + type: str + """The type of error (e.g., "invalid_request_error", "server_error").""" + + code: Optional[str] = None + """Error code, if any.""" + + event_id: Optional[str] = None + """The event_id of the client event that caused the error, if applicable.""" + + param: Optional[str] = None + """Parameter related to the error, if any.""" diff --git a/src/openai/types/realtime/realtime_error_event.py b/src/openai/types/realtime/realtime_error_event.py new file mode 100644 index 0000000000..8b501d6b21 --- /dev/null +++ b/src/openai/types/realtime/realtime_error_event.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel +from .realtime_error import RealtimeError + +__all__ = ["RealtimeErrorEvent"] + + +class RealtimeErrorEvent(BaseModel): + error: RealtimeError + """Details of the error.""" + + event_id: str + """The unique ID of the server event.""" + + type: Literal["error"] + """The event type, must be `error`.""" diff --git a/src/openai/types/realtime/realtime_mcp_approval_request.py b/src/openai/types/realtime/realtime_mcp_approval_request.py new file mode 100644 index 0000000000..bafc8d89d4 --- /dev/null +++ b/src/openai/types/realtime/realtime_mcp_approval_request.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["RealtimeMcpApprovalRequest"] + + +class RealtimeMcpApprovalRequest(BaseModel): + id: str + """The unique ID of the approval request.""" + + arguments: str + """A JSON string of arguments for the tool.""" + + name: str + """The name of the tool to run.""" + + server_label: str + """The label of the MCP server making the request.""" + + type: Literal["mcp_approval_request"] + """The type of the item. Always `mcp_approval_request`.""" diff --git a/src/openai/types/realtime/realtime_mcp_approval_request_param.py b/src/openai/types/realtime/realtime_mcp_approval_request_param.py new file mode 100644 index 0000000000..57c21a487f --- /dev/null +++ b/src/openai/types/realtime/realtime_mcp_approval_request_param.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["RealtimeMcpApprovalRequestParam"] + + +class RealtimeMcpApprovalRequestParam(TypedDict, total=False): + id: Required[str] + """The unique ID of the approval request.""" + + arguments: Required[str] + """A JSON string of arguments for the tool.""" + + name: Required[str] + """The name of the tool to run.""" + + server_label: Required[str] + """The label of the MCP server making the request.""" + + type: Required[Literal["mcp_approval_request"]] + """The type of the item. Always `mcp_approval_request`.""" diff --git a/src/openai/types/realtime/realtime_mcp_approval_response.py b/src/openai/types/realtime/realtime_mcp_approval_response.py new file mode 100644 index 0000000000..2cb03bc61a --- /dev/null +++ b/src/openai/types/realtime/realtime_mcp_approval_response.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["RealtimeMcpApprovalResponse"] + + +class RealtimeMcpApprovalResponse(BaseModel): + id: str + """The unique ID of the approval response.""" + + approval_request_id: str + """The ID of the approval request being answered.""" + + approve: bool + """Whether the request was approved.""" + + type: Literal["mcp_approval_response"] + """The type of the item. Always `mcp_approval_response`.""" + + reason: Optional[str] = None + """Optional reason for the decision.""" diff --git a/src/openai/types/realtime/realtime_mcp_approval_response_param.py b/src/openai/types/realtime/realtime_mcp_approval_response_param.py new file mode 100644 index 0000000000..19b6337004 --- /dev/null +++ b/src/openai/types/realtime/realtime_mcp_approval_response_param.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["RealtimeMcpApprovalResponseParam"] + + +class RealtimeMcpApprovalResponseParam(TypedDict, total=False): + id: Required[str] + """The unique ID of the approval response.""" + + approval_request_id: Required[str] + """The ID of the approval request being answered.""" + + approve: Required[bool] + """Whether the request was approved.""" + + type: Required[Literal["mcp_approval_response"]] + """The type of the item. Always `mcp_approval_response`.""" + + reason: Optional[str] + """Optional reason for the decision.""" diff --git a/src/openai/types/realtime/realtime_mcp_list_tools.py b/src/openai/types/realtime/realtime_mcp_list_tools.py new file mode 100644 index 0000000000..aeb58a1faf --- /dev/null +++ b/src/openai/types/realtime/realtime_mcp_list_tools.py @@ -0,0 +1,36 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["RealtimeMcpListTools", "Tool"] + + +class Tool(BaseModel): + input_schema: object + """The JSON schema describing the tool's input.""" + + name: str + """The name of the tool.""" + + annotations: Optional[object] = None + """Additional annotations about the tool.""" + + description: Optional[str] = None + """The description of the tool.""" + + +class RealtimeMcpListTools(BaseModel): + server_label: str + """The label of the MCP server.""" + + tools: List[Tool] + """The tools available on the server.""" + + type: Literal["mcp_list_tools"] + """The type of the item. Always `mcp_list_tools`.""" + + id: Optional[str] = None + """The unique ID of the list.""" diff --git a/src/openai/types/realtime/realtime_mcp_list_tools_param.py b/src/openai/types/realtime/realtime_mcp_list_tools_param.py new file mode 100644 index 0000000000..eb8605a061 --- /dev/null +++ b/src/openai/types/realtime/realtime_mcp_list_tools_param.py @@ -0,0 +1,36 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["RealtimeMcpListToolsParam", "Tool"] + + +class Tool(TypedDict, total=False): + input_schema: Required[object] + """The JSON schema describing the tool's input.""" + + name: Required[str] + """The name of the tool.""" + + annotations: Optional[object] + """Additional annotations about the tool.""" + + description: Optional[str] + """The description of the tool.""" + + +class RealtimeMcpListToolsParam(TypedDict, total=False): + server_label: Required[str] + """The label of the MCP server.""" + + tools: Required[Iterable[Tool]] + """The tools available on the server.""" + + type: Required[Literal["mcp_list_tools"]] + """The type of the item. Always `mcp_list_tools`.""" + + id: str + """The unique ID of the list.""" diff --git a/src/openai/types/realtime/realtime_mcp_protocol_error.py b/src/openai/types/realtime/realtime_mcp_protocol_error.py new file mode 100644 index 0000000000..2e7cfdffa3 --- /dev/null +++ b/src/openai/types/realtime/realtime_mcp_protocol_error.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["RealtimeMcpProtocolError"] + + +class RealtimeMcpProtocolError(BaseModel): + code: int + + message: str + + type: Literal["protocol_error"] diff --git a/src/openai/types/realtime/realtime_mcp_protocol_error_param.py b/src/openai/types/realtime/realtime_mcp_protocol_error_param.py new file mode 100644 index 0000000000..bebe3d379e --- /dev/null +++ b/src/openai/types/realtime/realtime_mcp_protocol_error_param.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["RealtimeMcpProtocolErrorParam"] + + +class RealtimeMcpProtocolErrorParam(TypedDict, total=False): + code: Required[int] + + message: Required[str] + + type: Required[Literal["protocol_error"]] diff --git a/src/openai/types/realtime/realtime_mcp_tool_call.py b/src/openai/types/realtime/realtime_mcp_tool_call.py new file mode 100644 index 0000000000..533175e55b --- /dev/null +++ b/src/openai/types/realtime/realtime_mcp_tool_call.py @@ -0,0 +1,43 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .realtime_mcphttp_error import RealtimeMcphttpError +from .realtime_mcp_protocol_error import RealtimeMcpProtocolError +from .realtime_mcp_tool_execution_error import RealtimeMcpToolExecutionError + +__all__ = ["RealtimeMcpToolCall", "Error"] + +Error: TypeAlias = Annotated[ + Union[RealtimeMcpProtocolError, RealtimeMcpToolExecutionError, RealtimeMcphttpError, None], + PropertyInfo(discriminator="type"), +] + + +class RealtimeMcpToolCall(BaseModel): + id: str + """The unique ID of the tool call.""" + + arguments: str + """A JSON string of the arguments passed to the tool.""" + + name: str + """The name of the tool that was run.""" + + server_label: str + """The label of the MCP server running the tool.""" + + type: Literal["mcp_tool_call"] + """The type of the item. Always `mcp_tool_call`.""" + + approval_request_id: Optional[str] = None + """The ID of an associated approval request, if any.""" + + error: Optional[Error] = None + """The error from the tool call, if any.""" + + output: Optional[str] = None + """The output from the tool call.""" diff --git a/src/openai/types/realtime/realtime_mcp_tool_call_param.py b/src/openai/types/realtime/realtime_mcp_tool_call_param.py new file mode 100644 index 0000000000..afdc9d1d17 --- /dev/null +++ b/src/openai/types/realtime/realtime_mcp_tool_call_param.py @@ -0,0 +1,40 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .realtime_mcphttp_error_param import RealtimeMcphttpErrorParam +from .realtime_mcp_protocol_error_param import RealtimeMcpProtocolErrorParam +from .realtime_mcp_tool_execution_error_param import RealtimeMcpToolExecutionErrorParam + +__all__ = ["RealtimeMcpToolCallParam", "Error"] + +Error: TypeAlias = Union[RealtimeMcpProtocolErrorParam, RealtimeMcpToolExecutionErrorParam, RealtimeMcphttpErrorParam] + + +class RealtimeMcpToolCallParam(TypedDict, total=False): + id: Required[str] + """The unique ID of the tool call.""" + + arguments: Required[str] + """A JSON string of the arguments passed to the tool.""" + + name: Required[str] + """The name of the tool that was run.""" + + server_label: Required[str] + """The label of the MCP server running the tool.""" + + type: Required[Literal["mcp_tool_call"]] + """The type of the item. Always `mcp_tool_call`.""" + + approval_request_id: Optional[str] + """The ID of an associated approval request, if any.""" + + error: Optional[Error] + """The error from the tool call, if any.""" + + output: Optional[str] + """The output from the tool call.""" diff --git a/src/openai/types/realtime/realtime_mcp_tool_execution_error.py b/src/openai/types/realtime/realtime_mcp_tool_execution_error.py new file mode 100644 index 0000000000..a2ed063129 --- /dev/null +++ b/src/openai/types/realtime/realtime_mcp_tool_execution_error.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["RealtimeMcpToolExecutionError"] + + +class RealtimeMcpToolExecutionError(BaseModel): + message: str + + type: Literal["tool_execution_error"] diff --git a/src/openai/types/realtime/realtime_mcp_tool_execution_error_param.py b/src/openai/types/realtime/realtime_mcp_tool_execution_error_param.py new file mode 100644 index 0000000000..619e11c305 --- /dev/null +++ b/src/openai/types/realtime/realtime_mcp_tool_execution_error_param.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["RealtimeMcpToolExecutionErrorParam"] + + +class RealtimeMcpToolExecutionErrorParam(TypedDict, total=False): + message: Required[str] + + type: Required[Literal["tool_execution_error"]] diff --git a/src/openai/types/realtime/realtime_mcphttp_error.py b/src/openai/types/realtime/realtime_mcphttp_error.py new file mode 100644 index 0000000000..53cff91e6e --- /dev/null +++ b/src/openai/types/realtime/realtime_mcphttp_error.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["RealtimeMcphttpError"] + + +class RealtimeMcphttpError(BaseModel): + code: int + + message: str + + type: Literal["http_error"] diff --git a/src/openai/types/realtime/realtime_mcphttp_error_param.py b/src/openai/types/realtime/realtime_mcphttp_error_param.py new file mode 100644 index 0000000000..2b80a6f0a4 --- /dev/null +++ b/src/openai/types/realtime/realtime_mcphttp_error_param.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["RealtimeMcphttpErrorParam"] + + +class RealtimeMcphttpErrorParam(TypedDict, total=False): + code: Required[int] + + message: Required[str] + + type: Required[Literal["http_error"]] diff --git a/src/openai/types/realtime/realtime_response.py b/src/openai/types/realtime/realtime_response.py new file mode 100644 index 0000000000..54f5999b81 --- /dev/null +++ b/src/openai/types/realtime/realtime_response.py @@ -0,0 +1,89 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal + +from ..._models import BaseModel +from ..shared.metadata import Metadata +from .conversation_item import ConversationItem +from .realtime_response_usage import RealtimeResponseUsage +from .realtime_response_status import RealtimeResponseStatus + +__all__ = ["RealtimeResponse"] + + +class RealtimeResponse(BaseModel): + id: Optional[str] = None + """The unique ID of the response.""" + + conversation_id: Optional[str] = None + """ + Which conversation the response is added to, determined by the `conversation` + field in the `response.create` event. If `auto`, the response will be added to + the default conversation and the value of `conversation_id` will be an id like + `conv_1234`. If `none`, the response will not be added to any conversation and + the value of `conversation_id` will be `null`. If responses are being triggered + by server VAD, the response will be added to the default conversation, thus the + `conversation_id` will be an id like `conv_1234`. + """ + + max_output_tokens: Union[int, Literal["inf"], None] = None + """ + Maximum number of output tokens for a single assistant response, inclusive of + tool calls, that was used in this response. + """ + + metadata: Optional[Metadata] = None + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + """ + + modalities: Optional[List[Literal["text", "audio"]]] = None + """The set of modalities the model used to respond. + + If there are multiple modalities, the model will pick one, for example if + `modalities` is `["text", "audio"]`, the model could be responding in either + text or audio. + """ + + object: Optional[Literal["realtime.response"]] = None + """The object type, must be `realtime.response`.""" + + output: Optional[List[ConversationItem]] = None + """The list of output items generated by the response.""" + + output_audio_format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None + """The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + + status: Optional[Literal["completed", "cancelled", "failed", "incomplete", "in_progress"]] = None + """ + The final status of the response (`completed`, `cancelled`, `failed`, or + `incomplete`, `in_progress`). + """ + + status_details: Optional[RealtimeResponseStatus] = None + """Additional details about the status.""" + + temperature: Optional[float] = None + """Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8.""" + + usage: Optional[RealtimeResponseUsage] = None + """Usage statistics for the Response, this will correspond to billing. + + A Realtime API session will maintain a conversation context and append new Items + to the Conversation, thus output from previous turns (text and audio tokens) + will become the input for later turns. + """ + + voice: Union[ + str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"], None + ] = None + """ + The voice the model used to respond. Current voice options are `alloy`, `ash`, + `ballad`, `coral`, `echo`, `sage`, `shimmer`, and `verse`. + """ diff --git a/src/openai/types/realtime/realtime_response_status.py b/src/openai/types/realtime/realtime_response_status.py new file mode 100644 index 0000000000..12999f61a1 --- /dev/null +++ b/src/openai/types/realtime/realtime_response_status.py @@ -0,0 +1,39 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["RealtimeResponseStatus", "Error"] + + +class Error(BaseModel): + code: Optional[str] = None + """Error code, if any.""" + + type: Optional[str] = None + """The type of error.""" + + +class RealtimeResponseStatus(BaseModel): + error: Optional[Error] = None + """ + A description of the error that caused the response to fail, populated when the + `status` is `failed`. + """ + + reason: Optional[Literal["turn_detected", "client_cancelled", "max_output_tokens", "content_filter"]] = None + """The reason the Response did not complete. + + For a `cancelled` Response, one of `turn_detected` (the server VAD detected a + new start of speech) or `client_cancelled` (the client sent a cancel event). For + an `incomplete` Response, one of `max_output_tokens` or `content_filter` (the + server-side safety filter activated and cut off the response). + """ + + type: Optional[Literal["completed", "cancelled", "incomplete", "failed"]] = None + """ + The type of error that caused the response to fail, corresponding with the + `status` field (`completed`, `cancelled`, `incomplete`, `failed`). + """ diff --git a/src/openai/types/realtime/realtime_response_usage.py b/src/openai/types/realtime/realtime_response_usage.py new file mode 100644 index 0000000000..dbce5f28c3 --- /dev/null +++ b/src/openai/types/realtime/realtime_response_usage.py @@ -0,0 +1,35 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel +from .realtime_response_usage_input_token_details import RealtimeResponseUsageInputTokenDetails +from .realtime_response_usage_output_token_details import RealtimeResponseUsageOutputTokenDetails + +__all__ = ["RealtimeResponseUsage"] + + +class RealtimeResponseUsage(BaseModel): + input_token_details: Optional[RealtimeResponseUsageInputTokenDetails] = None + """Details about the input tokens used in the Response.""" + + input_tokens: Optional[int] = None + """ + The number of input tokens used in the Response, including text and audio + tokens. + """ + + output_token_details: Optional[RealtimeResponseUsageOutputTokenDetails] = None + """Details about the output tokens used in the Response.""" + + output_tokens: Optional[int] = None + """ + The number of output tokens sent in the Response, including text and audio + tokens. + """ + + total_tokens: Optional[int] = None + """ + The total number of tokens in the Response including input and output text and + audio tokens. + """ diff --git a/src/openai/types/realtime/realtime_response_usage_input_token_details.py b/src/openai/types/realtime/realtime_response_usage_input_token_details.py new file mode 100644 index 0000000000..dfeead90ef --- /dev/null +++ b/src/openai/types/realtime/realtime_response_usage_input_token_details.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["RealtimeResponseUsageInputTokenDetails"] + + +class RealtimeResponseUsageInputTokenDetails(BaseModel): + audio_tokens: Optional[int] = None + """The number of audio tokens used in the Response.""" + + cached_tokens: Optional[int] = None + """The number of cached tokens used in the Response.""" + + text_tokens: Optional[int] = None + """The number of text tokens used in the Response.""" diff --git a/src/openai/types/realtime/realtime_response_usage_output_token_details.py b/src/openai/types/realtime/realtime_response_usage_output_token_details.py new file mode 100644 index 0000000000..dfa97a1f47 --- /dev/null +++ b/src/openai/types/realtime/realtime_response_usage_output_token_details.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["RealtimeResponseUsageOutputTokenDetails"] + + +class RealtimeResponseUsageOutputTokenDetails(BaseModel): + audio_tokens: Optional[int] = None + """The number of audio tokens used in the Response.""" + + text_tokens: Optional[int] = None + """The number of text tokens used in the Response.""" diff --git a/src/openai/types/realtime/realtime_server_event.py b/src/openai/types/realtime/realtime_server_event.py new file mode 100644 index 0000000000..8094bcfa96 --- /dev/null +++ b/src/openai/types/realtime/realtime_server_event.py @@ -0,0 +1,159 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .conversation_item import ConversationItem +from .response_done_event import ResponseDoneEvent +from .realtime_error_event import RealtimeErrorEvent +from .mcp_list_tools_failed import McpListToolsFailed +from .session_created_event import SessionCreatedEvent +from .session_updated_event import SessionUpdatedEvent +from .conversation_item_done import ConversationItemDone +from .response_created_event import ResponseCreatedEvent +from .conversation_item_added import ConversationItemAdded +from .mcp_list_tools_completed import McpListToolsCompleted +from .response_mcp_call_failed import ResponseMcpCallFailed +from .response_text_done_event import ResponseTextDoneEvent +from .rate_limits_updated_event import RateLimitsUpdatedEvent +from .response_audio_done_event import ResponseAudioDoneEvent +from .response_text_delta_event import ResponseTextDeltaEvent +from .conversation_created_event import ConversationCreatedEvent +from .mcp_list_tools_in_progress import McpListToolsInProgress +from .response_audio_delta_event import ResponseAudioDeltaEvent +from .response_mcp_call_completed import ResponseMcpCallCompleted +from .response_mcp_call_in_progress import ResponseMcpCallInProgress +from .transcription_session_created import TranscriptionSessionCreated +from .conversation_item_created_event import ConversationItemCreatedEvent +from .conversation_item_deleted_event import ConversationItemDeletedEvent +from .response_output_item_done_event import ResponseOutputItemDoneEvent +from .input_audio_buffer_cleared_event import InputAudioBufferClearedEvent +from .response_content_part_done_event import ResponseContentPartDoneEvent +from .response_mcp_call_arguments_done import ResponseMcpCallArgumentsDone +from .response_output_item_added_event import ResponseOutputItemAddedEvent +from .conversation_item_truncated_event import ConversationItemTruncatedEvent +from .response_content_part_added_event import ResponseContentPartAddedEvent +from .response_mcp_call_arguments_delta import ResponseMcpCallArgumentsDelta +from .input_audio_buffer_committed_event import InputAudioBufferCommittedEvent +from .transcription_session_updated_event import TranscriptionSessionUpdatedEvent +from .input_audio_buffer_timeout_triggered import InputAudioBufferTimeoutTriggered +from .response_audio_transcript_done_event import ResponseAudioTranscriptDoneEvent +from .response_audio_transcript_delta_event import ResponseAudioTranscriptDeltaEvent +from .input_audio_buffer_speech_started_event import InputAudioBufferSpeechStartedEvent +from .input_audio_buffer_speech_stopped_event import InputAudioBufferSpeechStoppedEvent +from .response_function_call_arguments_done_event import ResponseFunctionCallArgumentsDoneEvent +from .response_function_call_arguments_delta_event import ResponseFunctionCallArgumentsDeltaEvent +from .conversation_item_input_audio_transcription_segment import ConversationItemInputAudioTranscriptionSegment +from .conversation_item_input_audio_transcription_delta_event import ConversationItemInputAudioTranscriptionDeltaEvent +from .conversation_item_input_audio_transcription_failed_event import ConversationItemInputAudioTranscriptionFailedEvent +from .conversation_item_input_audio_transcription_completed_event import ( + ConversationItemInputAudioTranscriptionCompletedEvent, +) + +__all__ = [ + "RealtimeServerEvent", + "ConversationItemRetrieved", + "OutputAudioBufferStarted", + "OutputAudioBufferStopped", + "OutputAudioBufferCleared", +] + + +class ConversationItemRetrieved(BaseModel): + event_id: str + """The unique ID of the server event.""" + + item: ConversationItem + """A single item within a Realtime conversation.""" + + type: Literal["conversation.item.retrieved"] + """The event type, must be `conversation.item.retrieved`.""" + + +class OutputAudioBufferStarted(BaseModel): + event_id: str + """The unique ID of the server event.""" + + response_id: str + """The unique ID of the response that produced the audio.""" + + type: Literal["output_audio_buffer.started"] + """The event type, must be `output_audio_buffer.started`.""" + + +class OutputAudioBufferStopped(BaseModel): + event_id: str + """The unique ID of the server event.""" + + response_id: str + """The unique ID of the response that produced the audio.""" + + type: Literal["output_audio_buffer.stopped"] + """The event type, must be `output_audio_buffer.stopped`.""" + + +class OutputAudioBufferCleared(BaseModel): + event_id: str + """The unique ID of the server event.""" + + response_id: str + """The unique ID of the response that produced the audio.""" + + type: Literal["output_audio_buffer.cleared"] + """The event type, must be `output_audio_buffer.cleared`.""" + + +RealtimeServerEvent: TypeAlias = Annotated[ + Union[ + ConversationCreatedEvent, + ConversationItemCreatedEvent, + ConversationItemDeletedEvent, + ConversationItemInputAudioTranscriptionCompletedEvent, + ConversationItemInputAudioTranscriptionDeltaEvent, + ConversationItemInputAudioTranscriptionFailedEvent, + ConversationItemRetrieved, + ConversationItemTruncatedEvent, + RealtimeErrorEvent, + InputAudioBufferClearedEvent, + InputAudioBufferCommittedEvent, + InputAudioBufferSpeechStartedEvent, + InputAudioBufferSpeechStoppedEvent, + RateLimitsUpdatedEvent, + ResponseAudioDeltaEvent, + ResponseAudioDoneEvent, + ResponseAudioTranscriptDeltaEvent, + ResponseAudioTranscriptDoneEvent, + ResponseContentPartAddedEvent, + ResponseContentPartDoneEvent, + ResponseCreatedEvent, + ResponseDoneEvent, + ResponseFunctionCallArgumentsDeltaEvent, + ResponseFunctionCallArgumentsDoneEvent, + ResponseOutputItemAddedEvent, + ResponseOutputItemDoneEvent, + ResponseTextDeltaEvent, + ResponseTextDoneEvent, + SessionCreatedEvent, + SessionUpdatedEvent, + TranscriptionSessionUpdatedEvent, + TranscriptionSessionCreated, + OutputAudioBufferStarted, + OutputAudioBufferStopped, + OutputAudioBufferCleared, + ConversationItemAdded, + ConversationItemDone, + InputAudioBufferTimeoutTriggered, + ConversationItemInputAudioTranscriptionSegment, + McpListToolsInProgress, + McpListToolsCompleted, + McpListToolsFailed, + ResponseMcpCallArgumentsDelta, + ResponseMcpCallArgumentsDone, + ResponseMcpCallInProgress, + ResponseMcpCallCompleted, + ResponseMcpCallFailed, + ], + PropertyInfo(discriminator="type"), +] diff --git a/src/openai/types/realtime/realtime_session.py b/src/openai/types/realtime/realtime_session.py new file mode 100644 index 0000000000..43576ea73d --- /dev/null +++ b/src/openai/types/realtime/realtime_session.py @@ -0,0 +1,305 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, TypeAlias + +from ..._models import BaseModel +from ..responses.response_prompt import ResponsePrompt + +__all__ = [ + "RealtimeSession", + "InputAudioNoiseReduction", + "InputAudioTranscription", + "Tool", + "Tracing", + "TracingTracingConfiguration", + "TurnDetection", +] + + +class InputAudioNoiseReduction(BaseModel): + type: Optional[Literal["near_field", "far_field"]] = None + """Type of noise reduction. + + `near_field` is for close-talking microphones such as headphones, `far_field` is + for far-field microphones such as laptop or conference room microphones. + """ + + +class InputAudioTranscription(BaseModel): + language: Optional[str] = None + """The language of the input audio. + + Supplying the input language in + [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) + format will improve accuracy and latency. + """ + + model: Optional[str] = None + """ + The model to use for transcription, current options are `gpt-4o-transcribe`, + `gpt-4o-mini-transcribe`, and `whisper-1`. + """ + + prompt: Optional[str] = None + """ + An optional text to guide the model's style or continue a previous audio + segment. For `whisper-1`, the + [prompt is a list of keywords](https://platform.openai.com/docs/guides/speech-to-text#prompting). + For `gpt-4o-transcribe` models, the prompt is a free text string, for example + "expect words related to technology". + """ + + +class Tool(BaseModel): + description: Optional[str] = None + """ + The description of the function, including guidance on when and how to call it, + and guidance about what to tell the user when calling (if anything). + """ + + name: Optional[str] = None + """The name of the function.""" + + parameters: Optional[object] = None + """Parameters of the function in JSON Schema.""" + + type: Optional[Literal["function"]] = None + """The type of the tool, i.e. `function`.""" + + +class TracingTracingConfiguration(BaseModel): + group_id: Optional[str] = None + """ + The group id to attach to this trace to enable filtering and grouping in the + traces dashboard. + """ + + metadata: Optional[object] = None + """ + The arbitrary metadata to attach to this trace to enable filtering in the traces + dashboard. + """ + + workflow_name: Optional[str] = None + """The name of the workflow to attach to this trace. + + This is used to name the trace in the traces dashboard. + """ + + +Tracing: TypeAlias = Union[Literal["auto"], TracingTracingConfiguration, None] + + +class TurnDetection(BaseModel): + create_response: Optional[bool] = None + """ + Whether or not to automatically generate a response when a VAD stop event + occurs. + """ + + eagerness: Optional[Literal["low", "medium", "high", "auto"]] = None + """Used only for `semantic_vad` mode. + + The eagerness of the model to respond. `low` will wait longer for the user to + continue speaking, `high` will respond more quickly. `auto` is the default and + is equivalent to `medium`. + """ + + idle_timeout_ms: Optional[int] = None + """ + Optional idle timeout after which turn detection will auto-timeout when no + additional audio is received. + """ + + interrupt_response: Optional[bool] = None + """ + Whether or not to automatically interrupt any ongoing response with output to + the default conversation (i.e. `conversation` of `auto`) when a VAD start event + occurs. + """ + + prefix_padding_ms: Optional[int] = None + """Used only for `server_vad` mode. + + Amount of audio to include before the VAD detected speech (in milliseconds). + Defaults to 300ms. + """ + + silence_duration_ms: Optional[int] = None + """Used only for `server_vad` mode. + + Duration of silence to detect speech stop (in milliseconds). Defaults to 500ms. + With shorter values the model will respond more quickly, but may jump in on + short pauses from the user. + """ + + threshold: Optional[float] = None + """Used only for `server_vad` mode. + + Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A higher + threshold will require louder audio to activate the model, and thus might + perform better in noisy environments. + """ + + type: Optional[Literal["server_vad", "semantic_vad"]] = None + """Type of turn detection.""" + + +class RealtimeSession(BaseModel): + id: Optional[str] = None + """Unique identifier for the session that looks like `sess_1234567890abcdef`.""" + + expires_at: Optional[int] = None + """Expiration timestamp for the session, in seconds since epoch.""" + + include: Optional[List[Literal["item.input_audio_transcription.logprobs"]]] = None + """Additional fields to include in server outputs. + + - `item.input_audio_transcription.logprobs`: Include logprobs for input audio + transcription. + """ + + input_audio_format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None + """The format of input audio. + + Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, input audio must + be 16-bit PCM at a 24kHz sample rate, single channel (mono), and little-endian + byte order. + """ + + input_audio_noise_reduction: Optional[InputAudioNoiseReduction] = None + """Configuration for input audio noise reduction. + + This can be set to `null` to turn off. Noise reduction filters audio added to + the input audio buffer before it is sent to VAD and the model. Filtering the + audio can improve VAD and turn detection accuracy (reducing false positives) and + model performance by improving perception of the input audio. + """ + + input_audio_transcription: Optional[InputAudioTranscription] = None + """ + Configuration for input audio transcription, defaults to off and can be set to + `null` to turn off once on. Input audio transcription is not native to the + model, since the model consumes audio directly. Transcription runs + asynchronously through + [the /audio/transcriptions endpoint](https://platform.openai.com/docs/api-reference/audio/createTranscription) + and should be treated as guidance of input audio content rather than precisely + what the model heard. The client can optionally set the language and prompt for + transcription, these offer additional guidance to the transcription service. + """ + + instructions: Optional[str] = None + """The default system instructions (i.e. + + system message) prepended to model calls. This field allows the client to guide + the model on desired responses. The model can be instructed on response content + and format, (e.g. "be extremely succinct", "act friendly", "here are examples of + good responses") and on audio behavior (e.g. "talk quickly", "inject emotion + into your voice", "laugh frequently"). The instructions are not guaranteed to be + followed by the model, but they provide guidance to the model on the desired + behavior. + + Note that the server sets default instructions which will be used if this field + is not set and are visible in the `session.created` event at the start of the + session. + """ + + max_response_output_tokens: Union[int, Literal["inf"], None] = None + """ + Maximum number of output tokens for a single assistant response, inclusive of + tool calls. Provide an integer between 1 and 4096 to limit output tokens, or + `inf` for the maximum available tokens for a given model. Defaults to `inf`. + """ + + modalities: Optional[List[Literal["text", "audio"]]] = None + """The set of modalities the model can respond with. + + To disable audio, set this to ["text"]. + """ + + model: Optional[ + Literal[ + "gpt-4o-realtime-preview", + "gpt-4o-realtime-preview-2024-10-01", + "gpt-4o-realtime-preview-2024-12-17", + "gpt-4o-realtime-preview-2025-06-03", + "gpt-4o-mini-realtime-preview", + "gpt-4o-mini-realtime-preview-2024-12-17", + ] + ] = None + """The Realtime model used for this session.""" + + object: Optional[Literal["realtime.session"]] = None + """The object type. Always `realtime.session`.""" + + output_audio_format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None + """The format of output audio. + + Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, output audio is + sampled at a rate of 24kHz. + """ + + prompt: Optional[ResponsePrompt] = None + """Reference to a prompt template and its variables. + + [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). + """ + + speed: Optional[float] = None + """The speed of the model's spoken response. + + 1.0 is the default speed. 0.25 is the minimum speed. 1.5 is the maximum speed. + This value can only be changed in between model turns, not while a response is + in progress. + """ + + temperature: Optional[float] = None + """Sampling temperature for the model, limited to [0.6, 1.2]. + + For audio models a temperature of 0.8 is highly recommended for best + performance. + """ + + tool_choice: Optional[str] = None + """How the model chooses tools. + + Options are `auto`, `none`, `required`, or specify a function. + """ + + tools: Optional[List[Tool]] = None + """Tools (functions) available to the model.""" + + tracing: Optional[Tracing] = None + """Configuration options for tracing. + + Set to null to disable tracing. Once tracing is enabled for a session, the + configuration cannot be modified. + + `auto` will create a trace for the session with default values for the workflow + name, group id, and metadata. + """ + + turn_detection: Optional[TurnDetection] = None + """Configuration for turn detection, ether Server VAD or Semantic VAD. + + This can be set to `null` to turn off, in which case the client must manually + trigger model response. Server VAD means that the model will detect the start + and end of speech based on audio volume and respond at the end of user speech. + Semantic VAD is more advanced and uses a turn detection model (in conjunction + with VAD) to semantically estimate whether the user has finished speaking, then + dynamically sets a timeout based on this probability. For example, if user audio + trails off with "uhhm", the model will score a low probability of turn end and + wait longer for the user to continue speaking. This can be useful for more + natural conversations, but may have a higher latency. + """ + + voice: Union[ + str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"], None + ] = None + """The voice the model uses to respond. + + Voice cannot be changed during the session once the model has responded with + audio at least once. Current voice options are `alloy`, `ash`, `ballad`, + `coral`, `echo`, `sage`, `shimmer`, and `verse`. + """ diff --git a/src/openai/types/realtime/realtime_session_create_request.py b/src/openai/types/realtime/realtime_session_create_request.py new file mode 100644 index 0000000000..a8d0f99704 --- /dev/null +++ b/src/openai/types/realtime/realtime_session_create_request.py @@ -0,0 +1,116 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal + +from ..._models import BaseModel +from .realtime_truncation import RealtimeTruncation +from .realtime_audio_config import RealtimeAudioConfig +from .realtime_tools_config import RealtimeToolsConfig +from .realtime_tracing_config import RealtimeTracingConfig +from ..responses.response_prompt import ResponsePrompt +from .realtime_tool_choice_config import RealtimeToolChoiceConfig +from .realtime_client_secret_config import RealtimeClientSecretConfig + +__all__ = ["RealtimeSessionCreateRequest"] + + +class RealtimeSessionCreateRequest(BaseModel): + model: Union[ + str, + Literal[ + "gpt-4o-realtime", + "gpt-4o-mini-realtime", + "gpt-4o-realtime-preview", + "gpt-4o-realtime-preview-2024-10-01", + "gpt-4o-realtime-preview-2024-12-17", + "gpt-4o-realtime-preview-2025-06-03", + "gpt-4o-mini-realtime-preview", + "gpt-4o-mini-realtime-preview-2024-12-17", + ], + ] + """The Realtime model used for this session.""" + + type: Literal["realtime"] + """The type of session to create. Always `realtime` for the Realtime API.""" + + audio: Optional[RealtimeAudioConfig] = None + """Configuration for input and output audio.""" + + client_secret: Optional[RealtimeClientSecretConfig] = None + """Configuration options for the generated client secret.""" + + include: Optional[List[Literal["item.input_audio_transcription.logprobs"]]] = None + """Additional fields to include in server outputs. + + - `item.input_audio_transcription.logprobs`: Include logprobs for input audio + transcription. + """ + + instructions: Optional[str] = None + """The default system instructions (i.e. + + system message) prepended to model calls. This field allows the client to guide + the model on desired responses. The model can be instructed on response content + and format, (e.g. "be extremely succinct", "act friendly", "here are examples of + good responses") and on audio behavior (e.g. "talk quickly", "inject emotion + into your voice", "laugh frequently"). The instructions are not guaranteed to be + followed by the model, but they provide guidance to the model on the desired + behavior. + + Note that the server sets default instructions which will be used if this field + is not set and are visible in the `session.created` event at the start of the + session. + """ + + max_output_tokens: Union[int, Literal["inf"], None] = None + """ + Maximum number of output tokens for a single assistant response, inclusive of + tool calls. Provide an integer between 1 and 4096 to limit output tokens, or + `inf` for the maximum available tokens for a given model. Defaults to `inf`. + """ + + output_modalities: Optional[List[Literal["text", "audio"]]] = None + """The set of modalities the model can respond with. + + To disable audio, set this to ["text"]. + """ + + prompt: Optional[ResponsePrompt] = None + """Reference to a prompt template and its variables. + + [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). + """ + + temperature: Optional[float] = None + """Sampling temperature for the model, limited to [0.6, 1.2]. + + For audio models a temperature of 0.8 is highly recommended for best + performance. + """ + + tool_choice: Optional[RealtimeToolChoiceConfig] = None + """How the model chooses tools. + + Provide one of the string modes or force a specific function/MCP tool. + """ + + tools: Optional[RealtimeToolsConfig] = None + """Tools available to the model.""" + + tracing: Optional[RealtimeTracingConfig] = None + """Configuration options for tracing. + + Set to null to disable tracing. Once tracing is enabled for a session, the + configuration cannot be modified. + + `auto` will create a trace for the session with default values for the workflow + name, group id, and metadata. + """ + + truncation: Optional[RealtimeTruncation] = None + """ + Controls how the realtime conversation is truncated prior to model inference. + The default is `auto`. When set to `retention_ratio`, the server retains a + fraction of the conversation tokens prior to the instructions. + """ diff --git a/src/openai/types/realtime/realtime_session_create_request_param.py b/src/openai/types/realtime/realtime_session_create_request_param.py new file mode 100644 index 0000000000..2c5d1e0bee --- /dev/null +++ b/src/openai/types/realtime/realtime_session_create_request_param.py @@ -0,0 +1,119 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union, Optional +from typing_extensions import Literal, Required, TypedDict + +from .realtime_truncation_param import RealtimeTruncationParam +from .realtime_audio_config_param import RealtimeAudioConfigParam +from .realtime_tools_config_param import RealtimeToolsConfigParam +from .realtime_tracing_config_param import RealtimeTracingConfigParam +from ..responses.response_prompt_param import ResponsePromptParam +from .realtime_tool_choice_config_param import RealtimeToolChoiceConfigParam +from .realtime_client_secret_config_param import RealtimeClientSecretConfigParam + +__all__ = ["RealtimeSessionCreateRequestParam"] + + +class RealtimeSessionCreateRequestParam(TypedDict, total=False): + model: Required[ + Union[ + str, + Literal[ + "gpt-4o-realtime", + "gpt-4o-mini-realtime", + "gpt-4o-realtime-preview", + "gpt-4o-realtime-preview-2024-10-01", + "gpt-4o-realtime-preview-2024-12-17", + "gpt-4o-realtime-preview-2025-06-03", + "gpt-4o-mini-realtime-preview", + "gpt-4o-mini-realtime-preview-2024-12-17", + ], + ] + ] + """The Realtime model used for this session.""" + + type: Required[Literal["realtime"]] + """The type of session to create. Always `realtime` for the Realtime API.""" + + audio: RealtimeAudioConfigParam + """Configuration for input and output audio.""" + + client_secret: RealtimeClientSecretConfigParam + """Configuration options for the generated client secret.""" + + include: List[Literal["item.input_audio_transcription.logprobs"]] + """Additional fields to include in server outputs. + + - `item.input_audio_transcription.logprobs`: Include logprobs for input audio + transcription. + """ + + instructions: str + """The default system instructions (i.e. + + system message) prepended to model calls. This field allows the client to guide + the model on desired responses. The model can be instructed on response content + and format, (e.g. "be extremely succinct", "act friendly", "here are examples of + good responses") and on audio behavior (e.g. "talk quickly", "inject emotion + into your voice", "laugh frequently"). The instructions are not guaranteed to be + followed by the model, but they provide guidance to the model on the desired + behavior. + + Note that the server sets default instructions which will be used if this field + is not set and are visible in the `session.created` event at the start of the + session. + """ + + max_output_tokens: Union[int, Literal["inf"]] + """ + Maximum number of output tokens for a single assistant response, inclusive of + tool calls. Provide an integer between 1 and 4096 to limit output tokens, or + `inf` for the maximum available tokens for a given model. Defaults to `inf`. + """ + + output_modalities: List[Literal["text", "audio"]] + """The set of modalities the model can respond with. + + To disable audio, set this to ["text"]. + """ + + prompt: Optional[ResponsePromptParam] + """Reference to a prompt template and its variables. + + [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). + """ + + temperature: float + """Sampling temperature for the model, limited to [0.6, 1.2]. + + For audio models a temperature of 0.8 is highly recommended for best + performance. + """ + + tool_choice: RealtimeToolChoiceConfigParam + """How the model chooses tools. + + Provide one of the string modes or force a specific function/MCP tool. + """ + + tools: RealtimeToolsConfigParam + """Tools available to the model.""" + + tracing: Optional[RealtimeTracingConfigParam] + """Configuration options for tracing. + + Set to null to disable tracing. Once tracing is enabled for a session, the + configuration cannot be modified. + + `auto` will create a trace for the session with default values for the workflow + name, group id, and metadata. + """ + + truncation: RealtimeTruncationParam + """ + Controls how the realtime conversation is truncated prior to model inference. + The default is `auto`. When set to `retention_ratio`, the server retains a + fraction of the conversation tokens prior to the instructions. + """ diff --git a/src/openai/types/realtime/realtime_session_create_response.py b/src/openai/types/realtime/realtime_session_create_response.py new file mode 100644 index 0000000000..82fa426982 --- /dev/null +++ b/src/openai/types/realtime/realtime_session_create_response.py @@ -0,0 +1,222 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, TypeAlias + +from ..._models import BaseModel + +__all__ = [ + "RealtimeSessionCreateResponse", + "Audio", + "AudioInput", + "AudioInputNoiseReduction", + "AudioInputTranscription", + "AudioInputTurnDetection", + "AudioOutput", + "Tool", + "Tracing", + "TracingTracingConfiguration", + "TurnDetection", +] + + +class AudioInputNoiseReduction(BaseModel): + type: Optional[Literal["near_field", "far_field"]] = None + + +class AudioInputTranscription(BaseModel): + language: Optional[str] = None + """The language of the input audio.""" + + model: Optional[str] = None + """The model to use for transcription.""" + + prompt: Optional[str] = None + """Optional text to guide the model's style or continue a previous audio segment.""" + + +class AudioInputTurnDetection(BaseModel): + prefix_padding_ms: Optional[int] = None + + silence_duration_ms: Optional[int] = None + + threshold: Optional[float] = None + + type: Optional[str] = None + """Type of turn detection, only `server_vad` is currently supported.""" + + +class AudioInput(BaseModel): + format: Optional[str] = None + """The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + + noise_reduction: Optional[AudioInputNoiseReduction] = None + """Configuration for input audio noise reduction.""" + + transcription: Optional[AudioInputTranscription] = None + """Configuration for input audio transcription.""" + + turn_detection: Optional[AudioInputTurnDetection] = None + """Configuration for turn detection.""" + + +class AudioOutput(BaseModel): + format: Optional[str] = None + """The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + + speed: Optional[float] = None + + voice: Union[ + str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"], None + ] = None + + +class Audio(BaseModel): + input: Optional[AudioInput] = None + + output: Optional[AudioOutput] = None + + +class Tool(BaseModel): + description: Optional[str] = None + """ + The description of the function, including guidance on when and how to call it, + and guidance about what to tell the user when calling (if anything). + """ + + name: Optional[str] = None + """The name of the function.""" + + parameters: Optional[object] = None + """Parameters of the function in JSON Schema.""" + + type: Optional[Literal["function"]] = None + """The type of the tool, i.e. `function`.""" + + +class TracingTracingConfiguration(BaseModel): + group_id: Optional[str] = None + """ + The group id to attach to this trace to enable filtering and grouping in the + traces dashboard. + """ + + metadata: Optional[object] = None + """ + The arbitrary metadata to attach to this trace to enable filtering in the traces + dashboard. + """ + + workflow_name: Optional[str] = None + """The name of the workflow to attach to this trace. + + This is used to name the trace in the traces dashboard. + """ + + +Tracing: TypeAlias = Union[Literal["auto"], TracingTracingConfiguration] + + +class TurnDetection(BaseModel): + prefix_padding_ms: Optional[int] = None + """Amount of audio to include before the VAD detected speech (in milliseconds). + + Defaults to 300ms. + """ + + silence_duration_ms: Optional[int] = None + """Duration of silence to detect speech stop (in milliseconds). + + Defaults to 500ms. With shorter values the model will respond more quickly, but + may jump in on short pauses from the user. + """ + + threshold: Optional[float] = None + """Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. + + A higher threshold will require louder audio to activate the model, and thus + might perform better in noisy environments. + """ + + type: Optional[str] = None + """Type of turn detection, only `server_vad` is currently supported.""" + + +class RealtimeSessionCreateResponse(BaseModel): + id: Optional[str] = None + """Unique identifier for the session that looks like `sess_1234567890abcdef`.""" + + audio: Optional[Audio] = None + """Configuration for input and output audio for the session.""" + + expires_at: Optional[int] = None + """Expiration timestamp for the session, in seconds since epoch.""" + + include: Optional[List[Literal["item.input_audio_transcription.logprobs"]]] = None + """Additional fields to include in server outputs. + + - `item.input_audio_transcription.logprobs`: Include logprobs for input audio + transcription. + """ + + instructions: Optional[str] = None + """The default system instructions (i.e. + + system message) prepended to model calls. This field allows the client to guide + the model on desired responses. The model can be instructed on response content + and format, (e.g. "be extremely succinct", "act friendly", "here are examples of + good responses") and on audio behavior (e.g. "talk quickly", "inject emotion + into your voice", "laugh frequently"). The instructions are not guaranteed to be + followed by the model, but they provide guidance to the model on the desired + behavior. + + Note that the server sets default instructions which will be used if this field + is not set and are visible in the `session.created` event at the start of the + session. + """ + + max_output_tokens: Union[int, Literal["inf"], None] = None + """ + Maximum number of output tokens for a single assistant response, inclusive of + tool calls. Provide an integer between 1 and 4096 to limit output tokens, or + `inf` for the maximum available tokens for a given model. Defaults to `inf`. + """ + + model: Optional[str] = None + """The Realtime model used for this session.""" + + object: Optional[str] = None + """The object type. Always `realtime.session`.""" + + output_modalities: Optional[List[Literal["text", "audio"]]] = None + """The set of modalities the model can respond with. + + To disable audio, set this to ["text"]. + """ + + tool_choice: Optional[str] = None + """How the model chooses tools. + + Options are `auto`, `none`, `required`, or specify a function. + """ + + tools: Optional[List[Tool]] = None + """Tools (functions) available to the model.""" + + tracing: Optional[Tracing] = None + """Configuration options for tracing. + + Set to null to disable tracing. Once tracing is enabled for a session, the + configuration cannot be modified. + + `auto` will create a trace for the session with default values for the workflow + name, group id, and metadata. + """ + + turn_detection: Optional[TurnDetection] = None + """Configuration for turn detection. + + Can be set to `null` to turn off. Server VAD means that the model will detect + the start and end of speech based on audio volume and respond at the end of user + speech. + """ diff --git a/src/openai/types/realtime/realtime_tool_choice_config.py b/src/openai/types/realtime/realtime_tool_choice_config.py new file mode 100644 index 0000000000..f93c490004 --- /dev/null +++ b/src/openai/types/realtime/realtime_tool_choice_config.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from typing_extensions import TypeAlias + +from ..responses.tool_choice_mcp import ToolChoiceMcp +from ..responses.tool_choice_options import ToolChoiceOptions +from ..responses.tool_choice_function import ToolChoiceFunction + +__all__ = ["RealtimeToolChoiceConfig"] + +RealtimeToolChoiceConfig: TypeAlias = Union[ToolChoiceOptions, ToolChoiceFunction, ToolChoiceMcp] diff --git a/src/openai/types/realtime/realtime_tool_choice_config_param.py b/src/openai/types/realtime/realtime_tool_choice_config_param.py new file mode 100644 index 0000000000..af92f243b0 --- /dev/null +++ b/src/openai/types/realtime/realtime_tool_choice_config_param.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import TypeAlias + +from ..responses.tool_choice_options import ToolChoiceOptions +from ..responses.tool_choice_mcp_param import ToolChoiceMcpParam +from ..responses.tool_choice_function_param import ToolChoiceFunctionParam + +__all__ = ["RealtimeToolChoiceConfigParam"] + +RealtimeToolChoiceConfigParam: TypeAlias = Union[ToolChoiceOptions, ToolChoiceFunctionParam, ToolChoiceMcpParam] diff --git a/src/openai/types/realtime/realtime_tools_config.py b/src/openai/types/realtime/realtime_tools_config.py new file mode 100644 index 0000000000..b97599ab42 --- /dev/null +++ b/src/openai/types/realtime/realtime_tools_config.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .realtime_tools_config_union import RealtimeToolsConfigUnion + +__all__ = ["RealtimeToolsConfig"] + +RealtimeToolsConfig: TypeAlias = List[RealtimeToolsConfigUnion] diff --git a/src/openai/types/realtime/realtime_tools_config_param.py b/src/openai/types/realtime/realtime_tools_config_param.py new file mode 100644 index 0000000000..12af65c871 --- /dev/null +++ b/src/openai/types/realtime/realtime_tools_config_param.py @@ -0,0 +1,158 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +__all__ = [ + "RealtimeToolsConfigParam", + "RealtimeToolsConfigUnionParam", + "Function", + "Mcp", + "McpAllowedTools", + "McpAllowedToolsMcpToolFilter", + "McpRequireApproval", + "McpRequireApprovalMcpToolApprovalFilter", + "McpRequireApprovalMcpToolApprovalFilterAlways", + "McpRequireApprovalMcpToolApprovalFilterNever", +] + + +class Function(TypedDict, total=False): + description: str + """ + The description of the function, including guidance on when and how to call it, + and guidance about what to tell the user when calling (if anything). + """ + + name: str + """The name of the function.""" + + parameters: object + """Parameters of the function in JSON Schema.""" + + type: Literal["function"] + """The type of the tool, i.e. `function`.""" + + +class McpAllowedToolsMcpToolFilter(TypedDict, total=False): + read_only: bool + """Indicates whether or not a tool modifies data or is read-only. + + If an MCP server is + [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), + it will match this filter. + """ + + tool_names: List[str] + """List of allowed tool names.""" + + +McpAllowedTools: TypeAlias = Union[List[str], McpAllowedToolsMcpToolFilter] + + +class McpRequireApprovalMcpToolApprovalFilterAlways(TypedDict, total=False): + read_only: bool + """Indicates whether or not a tool modifies data or is read-only. + + If an MCP server is + [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), + it will match this filter. + """ + + tool_names: List[str] + """List of allowed tool names.""" + + +class McpRequireApprovalMcpToolApprovalFilterNever(TypedDict, total=False): + read_only: bool + """Indicates whether or not a tool modifies data or is read-only. + + If an MCP server is + [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), + it will match this filter. + """ + + tool_names: List[str] + """List of allowed tool names.""" + + +class McpRequireApprovalMcpToolApprovalFilter(TypedDict, total=False): + always: McpRequireApprovalMcpToolApprovalFilterAlways + """A filter object to specify which tools are allowed.""" + + never: McpRequireApprovalMcpToolApprovalFilterNever + """A filter object to specify which tools are allowed.""" + + +McpRequireApproval: TypeAlias = Union[McpRequireApprovalMcpToolApprovalFilter, Literal["always", "never"]] + + +class Mcp(TypedDict, total=False): + server_label: Required[str] + """A label for this MCP server, used to identify it in tool calls.""" + + type: Required[Literal["mcp"]] + """The type of the MCP tool. Always `mcp`.""" + + allowed_tools: Optional[McpAllowedTools] + """List of allowed tool names or a filter object.""" + + authorization: str + """ + An OAuth access token that can be used with a remote MCP server, either with a + custom MCP server URL or a service connector. Your application must handle the + OAuth authorization flow and provide the token here. + """ + + connector_id: Literal[ + "connector_dropbox", + "connector_gmail", + "connector_googlecalendar", + "connector_googledrive", + "connector_microsoftteams", + "connector_outlookcalendar", + "connector_outlookemail", + "connector_sharepoint", + ] + """Identifier for service connectors, like those available in ChatGPT. + + One of `server_url` or `connector_id` must be provided. Learn more about service + connectors + [here](https://platform.openai.com/docs/guides/tools-remote-mcp#connectors). + + Currently supported `connector_id` values are: + + - Dropbox: `connector_dropbox` + - Gmail: `connector_gmail` + - Google Calendar: `connector_googlecalendar` + - Google Drive: `connector_googledrive` + - Microsoft Teams: `connector_microsoftteams` + - Outlook Calendar: `connector_outlookcalendar` + - Outlook Email: `connector_outlookemail` + - SharePoint: `connector_sharepoint` + """ + + headers: Optional[Dict[str, str]] + """Optional HTTP headers to send to the MCP server. + + Use for authentication or other purposes. + """ + + require_approval: Optional[McpRequireApproval] + """Specify which of the MCP server's tools require approval.""" + + server_description: str + """Optional description of the MCP server, used to provide more context.""" + + server_url: str + """The URL for the MCP server. + + One of `server_url` or `connector_id` must be provided. + """ + + +RealtimeToolsConfigUnionParam: TypeAlias = Union[Function, Mcp] + +RealtimeToolsConfigParam: TypeAlias = List[RealtimeToolsConfigUnionParam] diff --git a/src/openai/types/realtime/realtime_tools_config_union.py b/src/openai/types/realtime/realtime_tools_config_union.py new file mode 100644 index 0000000000..16b1557743 --- /dev/null +++ b/src/openai/types/realtime/realtime_tools_config_union.py @@ -0,0 +1,158 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel + +__all__ = [ + "RealtimeToolsConfigUnion", + "Function", + "Mcp", + "McpAllowedTools", + "McpAllowedToolsMcpToolFilter", + "McpRequireApproval", + "McpRequireApprovalMcpToolApprovalFilter", + "McpRequireApprovalMcpToolApprovalFilterAlways", + "McpRequireApprovalMcpToolApprovalFilterNever", +] + + +class Function(BaseModel): + description: Optional[str] = None + """ + The description of the function, including guidance on when and how to call it, + and guidance about what to tell the user when calling (if anything). + """ + + name: Optional[str] = None + """The name of the function.""" + + parameters: Optional[object] = None + """Parameters of the function in JSON Schema.""" + + type: Optional[Literal["function"]] = None + """The type of the tool, i.e. `function`.""" + + +class McpAllowedToolsMcpToolFilter(BaseModel): + read_only: Optional[bool] = None + """Indicates whether or not a tool modifies data or is read-only. + + If an MCP server is + [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), + it will match this filter. + """ + + tool_names: Optional[List[str]] = None + """List of allowed tool names.""" + + +McpAllowedTools: TypeAlias = Union[List[str], McpAllowedToolsMcpToolFilter, None] + + +class McpRequireApprovalMcpToolApprovalFilterAlways(BaseModel): + read_only: Optional[bool] = None + """Indicates whether or not a tool modifies data or is read-only. + + If an MCP server is + [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), + it will match this filter. + """ + + tool_names: Optional[List[str]] = None + """List of allowed tool names.""" + + +class McpRequireApprovalMcpToolApprovalFilterNever(BaseModel): + read_only: Optional[bool] = None + """Indicates whether or not a tool modifies data or is read-only. + + If an MCP server is + [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), + it will match this filter. + """ + + tool_names: Optional[List[str]] = None + """List of allowed tool names.""" + + +class McpRequireApprovalMcpToolApprovalFilter(BaseModel): + always: Optional[McpRequireApprovalMcpToolApprovalFilterAlways] = None + """A filter object to specify which tools are allowed.""" + + never: Optional[McpRequireApprovalMcpToolApprovalFilterNever] = None + """A filter object to specify which tools are allowed.""" + + +McpRequireApproval: TypeAlias = Union[McpRequireApprovalMcpToolApprovalFilter, Literal["always", "never"], None] + + +class Mcp(BaseModel): + server_label: str + """A label for this MCP server, used to identify it in tool calls.""" + + type: Literal["mcp"] + """The type of the MCP tool. Always `mcp`.""" + + allowed_tools: Optional[McpAllowedTools] = None + """List of allowed tool names or a filter object.""" + + authorization: Optional[str] = None + """ + An OAuth access token that can be used with a remote MCP server, either with a + custom MCP server URL or a service connector. Your application must handle the + OAuth authorization flow and provide the token here. + """ + + connector_id: Optional[ + Literal[ + "connector_dropbox", + "connector_gmail", + "connector_googlecalendar", + "connector_googledrive", + "connector_microsoftteams", + "connector_outlookcalendar", + "connector_outlookemail", + "connector_sharepoint", + ] + ] = None + """Identifier for service connectors, like those available in ChatGPT. + + One of `server_url` or `connector_id` must be provided. Learn more about service + connectors + [here](https://platform.openai.com/docs/guides/tools-remote-mcp#connectors). + + Currently supported `connector_id` values are: + + - Dropbox: `connector_dropbox` + - Gmail: `connector_gmail` + - Google Calendar: `connector_googlecalendar` + - Google Drive: `connector_googledrive` + - Microsoft Teams: `connector_microsoftteams` + - Outlook Calendar: `connector_outlookcalendar` + - Outlook Email: `connector_outlookemail` + - SharePoint: `connector_sharepoint` + """ + + headers: Optional[Dict[str, str]] = None + """Optional HTTP headers to send to the MCP server. + + Use for authentication or other purposes. + """ + + require_approval: Optional[McpRequireApproval] = None + """Specify which of the MCP server's tools require approval.""" + + server_description: Optional[str] = None + """Optional description of the MCP server, used to provide more context.""" + + server_url: Optional[str] = None + """The URL for the MCP server. + + One of `server_url` or `connector_id` must be provided. + """ + + +RealtimeToolsConfigUnion: TypeAlias = Annotated[Union[Function, Mcp], PropertyInfo(discriminator="type")] diff --git a/src/openai/types/realtime/realtime_tools_config_union_param.py b/src/openai/types/realtime/realtime_tools_config_union_param.py new file mode 100644 index 0000000000..1b9f18536c --- /dev/null +++ b/src/openai/types/realtime/realtime_tools_config_union_param.py @@ -0,0 +1,155 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +__all__ = [ + "RealtimeToolsConfigUnionParam", + "Function", + "Mcp", + "McpAllowedTools", + "McpAllowedToolsMcpToolFilter", + "McpRequireApproval", + "McpRequireApprovalMcpToolApprovalFilter", + "McpRequireApprovalMcpToolApprovalFilterAlways", + "McpRequireApprovalMcpToolApprovalFilterNever", +] + + +class Function(TypedDict, total=False): + description: str + """ + The description of the function, including guidance on when and how to call it, + and guidance about what to tell the user when calling (if anything). + """ + + name: str + """The name of the function.""" + + parameters: object + """Parameters of the function in JSON Schema.""" + + type: Literal["function"] + """The type of the tool, i.e. `function`.""" + + +class McpAllowedToolsMcpToolFilter(TypedDict, total=False): + read_only: bool + """Indicates whether or not a tool modifies data or is read-only. + + If an MCP server is + [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), + it will match this filter. + """ + + tool_names: List[str] + """List of allowed tool names.""" + + +McpAllowedTools: TypeAlias = Union[List[str], McpAllowedToolsMcpToolFilter] + + +class McpRequireApprovalMcpToolApprovalFilterAlways(TypedDict, total=False): + read_only: bool + """Indicates whether or not a tool modifies data or is read-only. + + If an MCP server is + [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), + it will match this filter. + """ + + tool_names: List[str] + """List of allowed tool names.""" + + +class McpRequireApprovalMcpToolApprovalFilterNever(TypedDict, total=False): + read_only: bool + """Indicates whether or not a tool modifies data or is read-only. + + If an MCP server is + [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), + it will match this filter. + """ + + tool_names: List[str] + """List of allowed tool names.""" + + +class McpRequireApprovalMcpToolApprovalFilter(TypedDict, total=False): + always: McpRequireApprovalMcpToolApprovalFilterAlways + """A filter object to specify which tools are allowed.""" + + never: McpRequireApprovalMcpToolApprovalFilterNever + """A filter object to specify which tools are allowed.""" + + +McpRequireApproval: TypeAlias = Union[McpRequireApprovalMcpToolApprovalFilter, Literal["always", "never"]] + + +class Mcp(TypedDict, total=False): + server_label: Required[str] + """A label for this MCP server, used to identify it in tool calls.""" + + type: Required[Literal["mcp"]] + """The type of the MCP tool. Always `mcp`.""" + + allowed_tools: Optional[McpAllowedTools] + """List of allowed tool names or a filter object.""" + + authorization: str + """ + An OAuth access token that can be used with a remote MCP server, either with a + custom MCP server URL or a service connector. Your application must handle the + OAuth authorization flow and provide the token here. + """ + + connector_id: Literal[ + "connector_dropbox", + "connector_gmail", + "connector_googlecalendar", + "connector_googledrive", + "connector_microsoftteams", + "connector_outlookcalendar", + "connector_outlookemail", + "connector_sharepoint", + ] + """Identifier for service connectors, like those available in ChatGPT. + + One of `server_url` or `connector_id` must be provided. Learn more about service + connectors + [here](https://platform.openai.com/docs/guides/tools-remote-mcp#connectors). + + Currently supported `connector_id` values are: + + - Dropbox: `connector_dropbox` + - Gmail: `connector_gmail` + - Google Calendar: `connector_googlecalendar` + - Google Drive: `connector_googledrive` + - Microsoft Teams: `connector_microsoftteams` + - Outlook Calendar: `connector_outlookcalendar` + - Outlook Email: `connector_outlookemail` + - SharePoint: `connector_sharepoint` + """ + + headers: Optional[Dict[str, str]] + """Optional HTTP headers to send to the MCP server. + + Use for authentication or other purposes. + """ + + require_approval: Optional[McpRequireApproval] + """Specify which of the MCP server's tools require approval.""" + + server_description: str + """Optional description of the MCP server, used to provide more context.""" + + server_url: str + """The URL for the MCP server. + + One of `server_url` or `connector_id` must be provided. + """ + + +RealtimeToolsConfigUnionParam: TypeAlias = Union[Function, Mcp] diff --git a/src/openai/types/realtime/realtime_tracing_config.py b/src/openai/types/realtime/realtime_tracing_config.py new file mode 100644 index 0000000000..1de24d6e5f --- /dev/null +++ b/src/openai/types/realtime/realtime_tracing_config.py @@ -0,0 +1,31 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union, Optional +from typing_extensions import Literal, TypeAlias + +from ..._models import BaseModel + +__all__ = ["RealtimeTracingConfig", "TracingConfiguration"] + + +class TracingConfiguration(BaseModel): + group_id: Optional[str] = None + """ + The group id to attach to this trace to enable filtering and grouping in the + traces dashboard. + """ + + metadata: Optional[object] = None + """ + The arbitrary metadata to attach to this trace to enable filtering in the traces + dashboard. + """ + + workflow_name: Optional[str] = None + """The name of the workflow to attach to this trace. + + This is used to name the trace in the traces dashboard. + """ + + +RealtimeTracingConfig: TypeAlias = Union[Literal["auto"], TracingConfiguration, None] diff --git a/src/openai/types/realtime/realtime_tracing_config_param.py b/src/openai/types/realtime/realtime_tracing_config_param.py new file mode 100644 index 0000000000..3a35c6f7fa --- /dev/null +++ b/src/openai/types/realtime/realtime_tracing_config_param.py @@ -0,0 +1,31 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import Literal, TypeAlias, TypedDict + +__all__ = ["RealtimeTracingConfigParam", "TracingConfiguration"] + + +class TracingConfiguration(TypedDict, total=False): + group_id: str + """ + The group id to attach to this trace to enable filtering and grouping in the + traces dashboard. + """ + + metadata: object + """ + The arbitrary metadata to attach to this trace to enable filtering in the traces + dashboard. + """ + + workflow_name: str + """The name of the workflow to attach to this trace. + + This is used to name the trace in the traces dashboard. + """ + + +RealtimeTracingConfigParam: TypeAlias = Union[Literal["auto"], TracingConfiguration] diff --git a/src/openai/types/realtime/realtime_transcription_session_create_request.py b/src/openai/types/realtime/realtime_transcription_session_create_request.py new file mode 100644 index 0000000000..d67bc92708 --- /dev/null +++ b/src/openai/types/realtime/realtime_transcription_session_create_request.py @@ -0,0 +1,128 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = [ + "RealtimeTranscriptionSessionCreateRequest", + "InputAudioNoiseReduction", + "InputAudioTranscription", + "TurnDetection", +] + + +class InputAudioNoiseReduction(BaseModel): + type: Optional[Literal["near_field", "far_field"]] = None + """Type of noise reduction. + + `near_field` is for close-talking microphones such as headphones, `far_field` is + for far-field microphones such as laptop or conference room microphones. + """ + + +class InputAudioTranscription(BaseModel): + language: Optional[str] = None + """The language of the input audio. + + Supplying the input language in + [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) + format will improve accuracy and latency. + """ + + model: Optional[Literal["gpt-4o-transcribe", "gpt-4o-mini-transcribe", "whisper-1"]] = None + """ + The model to use for transcription, current options are `gpt-4o-transcribe`, + `gpt-4o-mini-transcribe`, and `whisper-1`. + """ + + prompt: Optional[str] = None + """ + An optional text to guide the model's style or continue a previous audio + segment. For `whisper-1`, the + [prompt is a list of keywords](https://platform.openai.com/docs/guides/speech-to-text#prompting). + For `gpt-4o-transcribe` models, the prompt is a free text string, for example + "expect words related to technology". + """ + + +class TurnDetection(BaseModel): + prefix_padding_ms: Optional[int] = None + """Amount of audio to include before the VAD detected speech (in milliseconds). + + Defaults to 300ms. + """ + + silence_duration_ms: Optional[int] = None + """Duration of silence to detect speech stop (in milliseconds). + + Defaults to 500ms. With shorter values the model will respond more quickly, but + may jump in on short pauses from the user. + """ + + threshold: Optional[float] = None + """Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. + + A higher threshold will require louder audio to activate the model, and thus + might perform better in noisy environments. + """ + + type: Optional[Literal["server_vad"]] = None + """Type of turn detection. + + Only `server_vad` is currently supported for transcription sessions. + """ + + +class RealtimeTranscriptionSessionCreateRequest(BaseModel): + model: Union[str, Literal["whisper-1", "gpt-4o-transcribe", "gpt-4o-mini-transcribe"]] + """ID of the model to use. + + The options are `gpt-4o-transcribe`, `gpt-4o-mini-transcribe`, and `whisper-1` + (which is powered by our open source Whisper V2 model). + """ + + type: Literal["transcription"] + """The type of session to create. + + Always `transcription` for transcription sessions. + """ + + include: Optional[List[Literal["item.input_audio_transcription.logprobs"]]] = None + """The set of items to include in the transcription. Current available items are: + + - `item.input_audio_transcription.logprobs` + """ + + input_audio_format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None + """The format of input audio. + + Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, input audio must + be 16-bit PCM at a 24kHz sample rate, single channel (mono), and little-endian + byte order. + """ + + input_audio_noise_reduction: Optional[InputAudioNoiseReduction] = None + """Configuration for input audio noise reduction. + + This can be set to `null` to turn off. Noise reduction filters audio added to + the input audio buffer before it is sent to VAD and the model. Filtering the + audio can improve VAD and turn detection accuracy (reducing false positives) and + model performance by improving perception of the input audio. + """ + + input_audio_transcription: Optional[InputAudioTranscription] = None + """Configuration for input audio transcription. + + The client can optionally set the language and prompt for transcription, these + offer additional guidance to the transcription service. + """ + + turn_detection: Optional[TurnDetection] = None + """Configuration for turn detection. + + Can be set to `null` to turn off. Server VAD means that the model will detect + the start and end of speech based on audio volume and respond at the end of user + speech. + """ diff --git a/src/openai/types/realtime/realtime_transcription_session_create_request_param.py b/src/openai/types/realtime/realtime_transcription_session_create_request_param.py new file mode 100644 index 0000000000..405f0c5f2c --- /dev/null +++ b/src/openai/types/realtime/realtime_transcription_session_create_request_param.py @@ -0,0 +1,128 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union +from typing_extensions import Literal, Required, TypedDict + +__all__ = [ + "RealtimeTranscriptionSessionCreateRequestParam", + "InputAudioNoiseReduction", + "InputAudioTranscription", + "TurnDetection", +] + + +class InputAudioNoiseReduction(TypedDict, total=False): + type: Literal["near_field", "far_field"] + """Type of noise reduction. + + `near_field` is for close-talking microphones such as headphones, `far_field` is + for far-field microphones such as laptop or conference room microphones. + """ + + +class InputAudioTranscription(TypedDict, total=False): + language: str + """The language of the input audio. + + Supplying the input language in + [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) + format will improve accuracy and latency. + """ + + model: Literal["gpt-4o-transcribe", "gpt-4o-mini-transcribe", "whisper-1"] + """ + The model to use for transcription, current options are `gpt-4o-transcribe`, + `gpt-4o-mini-transcribe`, and `whisper-1`. + """ + + prompt: str + """ + An optional text to guide the model's style or continue a previous audio + segment. For `whisper-1`, the + [prompt is a list of keywords](https://platform.openai.com/docs/guides/speech-to-text#prompting). + For `gpt-4o-transcribe` models, the prompt is a free text string, for example + "expect words related to technology". + """ + + +class TurnDetection(TypedDict, total=False): + prefix_padding_ms: int + """Amount of audio to include before the VAD detected speech (in milliseconds). + + Defaults to 300ms. + """ + + silence_duration_ms: int + """Duration of silence to detect speech stop (in milliseconds). + + Defaults to 500ms. With shorter values the model will respond more quickly, but + may jump in on short pauses from the user. + """ + + threshold: float + """Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. + + A higher threshold will require louder audio to activate the model, and thus + might perform better in noisy environments. + """ + + type: Literal["server_vad"] + """Type of turn detection. + + Only `server_vad` is currently supported for transcription sessions. + """ + + +class RealtimeTranscriptionSessionCreateRequestParam(TypedDict, total=False): + model: Required[Union[str, Literal["whisper-1", "gpt-4o-transcribe", "gpt-4o-mini-transcribe"]]] + """ID of the model to use. + + The options are `gpt-4o-transcribe`, `gpt-4o-mini-transcribe`, and `whisper-1` + (which is powered by our open source Whisper V2 model). + """ + + type: Required[Literal["transcription"]] + """The type of session to create. + + Always `transcription` for transcription sessions. + """ + + include: List[Literal["item.input_audio_transcription.logprobs"]] + """The set of items to include in the transcription. Current available items are: + + - `item.input_audio_transcription.logprobs` + """ + + input_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] + """The format of input audio. + + Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, input audio must + be 16-bit PCM at a 24kHz sample rate, single channel (mono), and little-endian + byte order. + """ + + input_audio_noise_reduction: InputAudioNoiseReduction + """Configuration for input audio noise reduction. + + This can be set to `null` to turn off. Noise reduction filters audio added to + the input audio buffer before it is sent to VAD and the model. Filtering the + audio can improve VAD and turn detection accuracy (reducing false positives) and + model performance by improving perception of the input audio. + """ + + input_audio_transcription: InputAudioTranscription + """Configuration for input audio transcription. + + The client can optionally set the language and prompt for transcription, these + offer additional guidance to the transcription service. + """ + + turn_detection: TurnDetection + """Configuration for turn detection. + + Can be set to `null` to turn off. Server VAD means that the model will detect + the start and end of speech based on audio volume and respond at the end of user + speech. + """ diff --git a/src/openai/types/realtime/realtime_truncation.py b/src/openai/types/realtime/realtime_truncation.py new file mode 100644 index 0000000000..4687e3da56 --- /dev/null +++ b/src/openai/types/realtime/realtime_truncation.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union, Optional +from typing_extensions import Literal, TypeAlias + +from ..._models import BaseModel + +__all__ = ["RealtimeTruncation", "RetentionRatioTruncation"] + + +class RetentionRatioTruncation(BaseModel): + retention_ratio: float + """Fraction of pre-instruction conversation tokens to retain (0.0 - 1.0).""" + + type: Literal["retention_ratio"] + """Use retention ratio truncation.""" + + post_instructions_token_limit: Optional[int] = None + """Optional cap on tokens allowed after the instructions.""" + + +RealtimeTruncation: TypeAlias = Union[Literal["auto", "disabled"], RetentionRatioTruncation] diff --git a/src/openai/types/realtime/realtime_truncation_param.py b/src/openai/types/realtime/realtime_truncation_param.py new file mode 100644 index 0000000000..edc88ea685 --- /dev/null +++ b/src/openai/types/realtime/realtime_truncation_param.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +__all__ = ["RealtimeTruncationParam", "RetentionRatioTruncation"] + + +class RetentionRatioTruncation(TypedDict, total=False): + retention_ratio: Required[float] + """Fraction of pre-instruction conversation tokens to retain (0.0 - 1.0).""" + + type: Required[Literal["retention_ratio"]] + """Use retention ratio truncation.""" + + post_instructions_token_limit: Optional[int] + """Optional cap on tokens allowed after the instructions.""" + + +RealtimeTruncationParam: TypeAlias = Union[Literal["auto", "disabled"], RetentionRatioTruncation] diff --git a/src/openai/types/realtime/response_audio_delta_event.py b/src/openai/types/realtime/response_audio_delta_event.py new file mode 100644 index 0000000000..d92c5462d0 --- /dev/null +++ b/src/openai/types/realtime/response_audio_delta_event.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseAudioDeltaEvent"] + + +class ResponseAudioDeltaEvent(BaseModel): + content_index: int + """The index of the content part in the item's content array.""" + + delta: str + """Base64-encoded audio data delta.""" + + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the item.""" + + output_index: int + """The index of the output item in the response.""" + + response_id: str + """The ID of the response.""" + + type: Literal["response.output_audio.delta"] + """The event type, must be `response.output_audio.delta`.""" diff --git a/src/openai/types/realtime/response_audio_done_event.py b/src/openai/types/realtime/response_audio_done_event.py new file mode 100644 index 0000000000..5ea0f07e36 --- /dev/null +++ b/src/openai/types/realtime/response_audio_done_event.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseAudioDoneEvent"] + + +class ResponseAudioDoneEvent(BaseModel): + content_index: int + """The index of the content part in the item's content array.""" + + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the item.""" + + output_index: int + """The index of the output item in the response.""" + + response_id: str + """The ID of the response.""" + + type: Literal["response.output_audio.done"] + """The event type, must be `response.output_audio.done`.""" diff --git a/src/openai/types/realtime/response_audio_transcript_delta_event.py b/src/openai/types/realtime/response_audio_transcript_delta_event.py new file mode 100644 index 0000000000..4dd5fecac0 --- /dev/null +++ b/src/openai/types/realtime/response_audio_transcript_delta_event.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseAudioTranscriptDeltaEvent"] + + +class ResponseAudioTranscriptDeltaEvent(BaseModel): + content_index: int + """The index of the content part in the item's content array.""" + + delta: str + """The transcript delta.""" + + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the item.""" + + output_index: int + """The index of the output item in the response.""" + + response_id: str + """The ID of the response.""" + + type: Literal["response.output_audio_transcript.delta"] + """The event type, must be `response.output_audio_transcript.delta`.""" diff --git a/src/openai/types/realtime/response_audio_transcript_done_event.py b/src/openai/types/realtime/response_audio_transcript_done_event.py new file mode 100644 index 0000000000..2de913d277 --- /dev/null +++ b/src/openai/types/realtime/response_audio_transcript_done_event.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseAudioTranscriptDoneEvent"] + + +class ResponseAudioTranscriptDoneEvent(BaseModel): + content_index: int + """The index of the content part in the item's content array.""" + + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the item.""" + + output_index: int + """The index of the output item in the response.""" + + response_id: str + """The ID of the response.""" + + transcript: str + """The final transcript of the audio.""" + + type: Literal["response.output_audio_transcript.done"] + """The event type, must be `response.output_audio_transcript.done`.""" diff --git a/src/openai/types/realtime/response_cancel_event.py b/src/openai/types/realtime/response_cancel_event.py new file mode 100644 index 0000000000..15dc141cbf --- /dev/null +++ b/src/openai/types/realtime/response_cancel_event.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseCancelEvent"] + + +class ResponseCancelEvent(BaseModel): + type: Literal["response.cancel"] + """The event type, must be `response.cancel`.""" + + event_id: Optional[str] = None + """Optional client-generated ID used to identify this event.""" + + response_id: Optional[str] = None + """ + A specific response ID to cancel - if not provided, will cancel an in-progress + response in the default conversation. + """ diff --git a/src/openai/types/realtime/response_cancel_event_param.py b/src/openai/types/realtime/response_cancel_event_param.py new file mode 100644 index 0000000000..f33740730a --- /dev/null +++ b/src/openai/types/realtime/response_cancel_event_param.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ResponseCancelEventParam"] + + +class ResponseCancelEventParam(TypedDict, total=False): + type: Required[Literal["response.cancel"]] + """The event type, must be `response.cancel`.""" + + event_id: str + """Optional client-generated ID used to identify this event.""" + + response_id: str + """ + A specific response ID to cancel - if not provided, will cancel an in-progress + response in the default conversation. + """ diff --git a/src/openai/types/realtime/response_content_part_added_event.py b/src/openai/types/realtime/response_content_part_added_event.py new file mode 100644 index 0000000000..aca965c3d8 --- /dev/null +++ b/src/openai/types/realtime/response_content_part_added_event.py @@ -0,0 +1,45 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseContentPartAddedEvent", "Part"] + + +class Part(BaseModel): + audio: Optional[str] = None + """Base64-encoded audio data (if type is "audio").""" + + text: Optional[str] = None + """The text content (if type is "text").""" + + transcript: Optional[str] = None + """The transcript of the audio (if type is "audio").""" + + type: Optional[Literal["text", "audio"]] = None + """The content type ("text", "audio").""" + + +class ResponseContentPartAddedEvent(BaseModel): + content_index: int + """The index of the content part in the item's content array.""" + + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the item to which the content part was added.""" + + output_index: int + """The index of the output item in the response.""" + + part: Part + """The content part that was added.""" + + response_id: str + """The ID of the response.""" + + type: Literal["response.content_part.added"] + """The event type, must be `response.content_part.added`.""" diff --git a/src/openai/types/realtime/response_content_part_done_event.py b/src/openai/types/realtime/response_content_part_done_event.py new file mode 100644 index 0000000000..59af808a90 --- /dev/null +++ b/src/openai/types/realtime/response_content_part_done_event.py @@ -0,0 +1,45 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseContentPartDoneEvent", "Part"] + + +class Part(BaseModel): + audio: Optional[str] = None + """Base64-encoded audio data (if type is "audio").""" + + text: Optional[str] = None + """The text content (if type is "text").""" + + transcript: Optional[str] = None + """The transcript of the audio (if type is "audio").""" + + type: Optional[Literal["text", "audio"]] = None + """The content type ("text", "audio").""" + + +class ResponseContentPartDoneEvent(BaseModel): + content_index: int + """The index of the content part in the item's content array.""" + + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the item.""" + + output_index: int + """The index of the output item in the response.""" + + part: Part + """The content part that is done.""" + + response_id: str + """The ID of the response.""" + + type: Literal["response.content_part.done"] + """The event type, must be `response.content_part.done`.""" diff --git a/src/openai/types/realtime/response_create_event.py b/src/openai/types/realtime/response_create_event.py new file mode 100644 index 0000000000..a37045eab1 --- /dev/null +++ b/src/openai/types/realtime/response_create_event.py @@ -0,0 +1,134 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, TypeAlias + +from ..._models import BaseModel +from ..shared.metadata import Metadata +from .conversation_item import ConversationItem +from ..responses.response_prompt import ResponsePrompt +from ..responses.tool_choice_mcp import ToolChoiceMcp +from ..responses.tool_choice_options import ToolChoiceOptions +from ..responses.tool_choice_function import ToolChoiceFunction + +__all__ = ["ResponseCreateEvent", "Response", "ResponseToolChoice", "ResponseTool"] + +ResponseToolChoice: TypeAlias = Union[ToolChoiceOptions, ToolChoiceFunction, ToolChoiceMcp] + + +class ResponseTool(BaseModel): + description: Optional[str] = None + """ + The description of the function, including guidance on when and how to call it, + and guidance about what to tell the user when calling (if anything). + """ + + name: Optional[str] = None + """The name of the function.""" + + parameters: Optional[object] = None + """Parameters of the function in JSON Schema.""" + + type: Optional[Literal["function"]] = None + """The type of the tool, i.e. `function`.""" + + +class Response(BaseModel): + conversation: Union[str, Literal["auto", "none"], None] = None + """Controls which conversation the response is added to. + + Currently supports `auto` and `none`, with `auto` as the default value. The + `auto` value means that the contents of the response will be added to the + default conversation. Set this to `none` to create an out-of-band response which + will not add items to default conversation. + """ + + input: Optional[List[ConversationItem]] = None + """Input items to include in the prompt for the model. + + Using this field creates a new context for this Response instead of using the + default conversation. An empty array `[]` will clear the context for this + Response. Note that this can include references to items from the default + conversation. + """ + + instructions: Optional[str] = None + """The default system instructions (i.e. + + system message) prepended to model calls. This field allows the client to guide + the model on desired responses. The model can be instructed on response content + and format, (e.g. "be extremely succinct", "act friendly", "here are examples of + good responses") and on audio behavior (e.g. "talk quickly", "inject emotion + into your voice", "laugh frequently"). The instructions are not guaranteed to be + followed by the model, but they provide guidance to the model on the desired + behavior. + + Note that the server sets default instructions which will be used if this field + is not set and are visible in the `session.created` event at the start of the + session. + """ + + max_output_tokens: Union[int, Literal["inf"], None] = None + """ + Maximum number of output tokens for a single assistant response, inclusive of + tool calls. Provide an integer between 1 and 4096 to limit output tokens, or + `inf` for the maximum available tokens for a given model. Defaults to `inf`. + """ + + metadata: Optional[Metadata] = None + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + """ + + modalities: Optional[List[Literal["text", "audio"]]] = None + """The set of modalities the model can respond with. + + To disable audio, set this to ["text"]. + """ + + output_audio_format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None + """The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + + prompt: Optional[ResponsePrompt] = None + """Reference to a prompt template and its variables. + + [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). + """ + + temperature: Optional[float] = None + """Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8.""" + + tool_choice: Optional[ResponseToolChoice] = None + """How the model chooses tools. + + Provide one of the string modes or force a specific function/MCP tool. + """ + + tools: Optional[List[ResponseTool]] = None + """Tools (functions) available to the model.""" + + voice: Union[ + str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"], None + ] = None + """The voice the model uses to respond. + + Voice cannot be changed during the session once the model has responded with + audio at least once. Current voice options are `alloy`, `ash`, `ballad`, + `coral`, `echo`, `sage`, `shimmer`, and `verse`. + """ + + +class ResponseCreateEvent(BaseModel): + type: Literal["response.create"] + """The event type, must be `response.create`.""" + + event_id: Optional[str] = None + """Optional client-generated ID used to identify this event.""" + + response: Optional[Response] = None + """Create a new Realtime response with these parameters""" diff --git a/src/openai/types/realtime/response_create_event_param.py b/src/openai/types/realtime/response_create_event_param.py new file mode 100644 index 0000000000..f941c4ca9c --- /dev/null +++ b/src/openai/types/realtime/response_create_event_param.py @@ -0,0 +1,133 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from ..shared_params.metadata import Metadata +from .conversation_item_param import ConversationItemParam +from ..responses.tool_choice_options import ToolChoiceOptions +from ..responses.response_prompt_param import ResponsePromptParam +from ..responses.tool_choice_mcp_param import ToolChoiceMcpParam +from ..responses.tool_choice_function_param import ToolChoiceFunctionParam + +__all__ = ["ResponseCreateEventParam", "Response", "ResponseToolChoice", "ResponseTool"] + +ResponseToolChoice: TypeAlias = Union[ToolChoiceOptions, ToolChoiceFunctionParam, ToolChoiceMcpParam] + + +class ResponseTool(TypedDict, total=False): + description: str + """ + The description of the function, including guidance on when and how to call it, + and guidance about what to tell the user when calling (if anything). + """ + + name: str + """The name of the function.""" + + parameters: object + """Parameters of the function in JSON Schema.""" + + type: Literal["function"] + """The type of the tool, i.e. `function`.""" + + +class Response(TypedDict, total=False): + conversation: Union[str, Literal["auto", "none"]] + """Controls which conversation the response is added to. + + Currently supports `auto` and `none`, with `auto` as the default value. The + `auto` value means that the contents of the response will be added to the + default conversation. Set this to `none` to create an out-of-band response which + will not add items to default conversation. + """ + + input: Iterable[ConversationItemParam] + """Input items to include in the prompt for the model. + + Using this field creates a new context for this Response instead of using the + default conversation. An empty array `[]` will clear the context for this + Response. Note that this can include references to items from the default + conversation. + """ + + instructions: str + """The default system instructions (i.e. + + system message) prepended to model calls. This field allows the client to guide + the model on desired responses. The model can be instructed on response content + and format, (e.g. "be extremely succinct", "act friendly", "here are examples of + good responses") and on audio behavior (e.g. "talk quickly", "inject emotion + into your voice", "laugh frequently"). The instructions are not guaranteed to be + followed by the model, but they provide guidance to the model on the desired + behavior. + + Note that the server sets default instructions which will be used if this field + is not set and are visible in the `session.created` event at the start of the + session. + """ + + max_output_tokens: Union[int, Literal["inf"]] + """ + Maximum number of output tokens for a single assistant response, inclusive of + tool calls. Provide an integer between 1 and 4096 to limit output tokens, or + `inf` for the maximum available tokens for a given model. Defaults to `inf`. + """ + + metadata: Optional[Metadata] + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + """ + + modalities: List[Literal["text", "audio"]] + """The set of modalities the model can respond with. + + To disable audio, set this to ["text"]. + """ + + output_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] + """The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + + prompt: Optional[ResponsePromptParam] + """Reference to a prompt template and its variables. + + [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). + """ + + temperature: float + """Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8.""" + + tool_choice: ResponseToolChoice + """How the model chooses tools. + + Provide one of the string modes or force a specific function/MCP tool. + """ + + tools: Iterable[ResponseTool] + """Tools (functions) available to the model.""" + + voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"]] + """The voice the model uses to respond. + + Voice cannot be changed during the session once the model has responded with + audio at least once. Current voice options are `alloy`, `ash`, `ballad`, + `coral`, `echo`, `sage`, `shimmer`, and `verse`. + """ + + +class ResponseCreateEventParam(TypedDict, total=False): + type: Required[Literal["response.create"]] + """The event type, must be `response.create`.""" + + event_id: str + """Optional client-generated ID used to identify this event.""" + + response: Response + """Create a new Realtime response with these parameters""" diff --git a/src/openai/types/realtime/response_created_event.py b/src/openai/types/realtime/response_created_event.py new file mode 100644 index 0000000000..996bf26f75 --- /dev/null +++ b/src/openai/types/realtime/response_created_event.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel +from .realtime_response import RealtimeResponse + +__all__ = ["ResponseCreatedEvent"] + + +class ResponseCreatedEvent(BaseModel): + event_id: str + """The unique ID of the server event.""" + + response: RealtimeResponse + """The response resource.""" + + type: Literal["response.created"] + """The event type, must be `response.created`.""" diff --git a/src/openai/types/realtime/response_done_event.py b/src/openai/types/realtime/response_done_event.py new file mode 100644 index 0000000000..ce9a4b9f1d --- /dev/null +++ b/src/openai/types/realtime/response_done_event.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel +from .realtime_response import RealtimeResponse + +__all__ = ["ResponseDoneEvent"] + + +class ResponseDoneEvent(BaseModel): + event_id: str + """The unique ID of the server event.""" + + response: RealtimeResponse + """The response resource.""" + + type: Literal["response.done"] + """The event type, must be `response.done`.""" diff --git a/src/openai/types/realtime/response_function_call_arguments_delta_event.py b/src/openai/types/realtime/response_function_call_arguments_delta_event.py new file mode 100644 index 0000000000..6d96e78b24 --- /dev/null +++ b/src/openai/types/realtime/response_function_call_arguments_delta_event.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseFunctionCallArgumentsDeltaEvent"] + + +class ResponseFunctionCallArgumentsDeltaEvent(BaseModel): + call_id: str + """The ID of the function call.""" + + delta: str + """The arguments delta as a JSON string.""" + + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the function call item.""" + + output_index: int + """The index of the output item in the response.""" + + response_id: str + """The ID of the response.""" + + type: Literal["response.function_call_arguments.delta"] + """The event type, must be `response.function_call_arguments.delta`.""" diff --git a/src/openai/types/realtime/response_function_call_arguments_done_event.py b/src/openai/types/realtime/response_function_call_arguments_done_event.py new file mode 100644 index 0000000000..be7fae9a1b --- /dev/null +++ b/src/openai/types/realtime/response_function_call_arguments_done_event.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseFunctionCallArgumentsDoneEvent"] + + +class ResponseFunctionCallArgumentsDoneEvent(BaseModel): + arguments: str + """The final arguments as a JSON string.""" + + call_id: str + """The ID of the function call.""" + + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the function call item.""" + + output_index: int + """The index of the output item in the response.""" + + response_id: str + """The ID of the response.""" + + type: Literal["response.function_call_arguments.done"] + """The event type, must be `response.function_call_arguments.done`.""" diff --git a/src/openai/types/realtime/response_mcp_call_arguments_delta.py b/src/openai/types/realtime/response_mcp_call_arguments_delta.py new file mode 100644 index 0000000000..0a02a1a578 --- /dev/null +++ b/src/openai/types/realtime/response_mcp_call_arguments_delta.py @@ -0,0 +1,31 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseMcpCallArgumentsDelta"] + + +class ResponseMcpCallArgumentsDelta(BaseModel): + delta: str + """The JSON-encoded arguments delta.""" + + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the MCP tool call item.""" + + output_index: int + """The index of the output item in the response.""" + + response_id: str + """The ID of the response.""" + + type: Literal["response.mcp_call_arguments.delta"] + """The event type, must be `response.mcp_call_arguments.delta`.""" + + obfuscation: Optional[str] = None + """If present, indicates the delta text was obfuscated.""" diff --git a/src/openai/types/realtime/response_mcp_call_arguments_done.py b/src/openai/types/realtime/response_mcp_call_arguments_done.py new file mode 100644 index 0000000000..5ec95f1728 --- /dev/null +++ b/src/openai/types/realtime/response_mcp_call_arguments_done.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseMcpCallArgumentsDone"] + + +class ResponseMcpCallArgumentsDone(BaseModel): + arguments: str + """The final JSON-encoded arguments string.""" + + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the MCP tool call item.""" + + output_index: int + """The index of the output item in the response.""" + + response_id: str + """The ID of the response.""" + + type: Literal["response.mcp_call_arguments.done"] + """The event type, must be `response.mcp_call_arguments.done`.""" diff --git a/src/openai/types/realtime/response_mcp_call_completed.py b/src/openai/types/realtime/response_mcp_call_completed.py new file mode 100644 index 0000000000..e3fcec21f0 --- /dev/null +++ b/src/openai/types/realtime/response_mcp_call_completed.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseMcpCallCompleted"] + + +class ResponseMcpCallCompleted(BaseModel): + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the MCP tool call item.""" + + output_index: int + """The index of the output item in the response.""" + + type: Literal["response.mcp_call.completed"] + """The event type, must be `response.mcp_call.completed`.""" diff --git a/src/openai/types/realtime/response_mcp_call_failed.py b/src/openai/types/realtime/response_mcp_call_failed.py new file mode 100644 index 0000000000..b7adc8c2a7 --- /dev/null +++ b/src/openai/types/realtime/response_mcp_call_failed.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseMcpCallFailed"] + + +class ResponseMcpCallFailed(BaseModel): + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the MCP tool call item.""" + + output_index: int + """The index of the output item in the response.""" + + type: Literal["response.mcp_call.failed"] + """The event type, must be `response.mcp_call.failed`.""" diff --git a/src/openai/types/realtime/response_mcp_call_in_progress.py b/src/openai/types/realtime/response_mcp_call_in_progress.py new file mode 100644 index 0000000000..d0fcc7615c --- /dev/null +++ b/src/openai/types/realtime/response_mcp_call_in_progress.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseMcpCallInProgress"] + + +class ResponseMcpCallInProgress(BaseModel): + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the MCP tool call item.""" + + output_index: int + """The index of the output item in the response.""" + + type: Literal["response.mcp_call.in_progress"] + """The event type, must be `response.mcp_call.in_progress`.""" diff --git a/src/openai/types/realtime/response_output_item_added_event.py b/src/openai/types/realtime/response_output_item_added_event.py new file mode 100644 index 0000000000..509dfcaeaf --- /dev/null +++ b/src/openai/types/realtime/response_output_item_added_event.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel +from .conversation_item import ConversationItem + +__all__ = ["ResponseOutputItemAddedEvent"] + + +class ResponseOutputItemAddedEvent(BaseModel): + event_id: str + """The unique ID of the server event.""" + + item: ConversationItem + """A single item within a Realtime conversation.""" + + output_index: int + """The index of the output item in the Response.""" + + response_id: str + """The ID of the Response to which the item belongs.""" + + type: Literal["response.output_item.added"] + """The event type, must be `response.output_item.added`.""" diff --git a/src/openai/types/realtime/response_output_item_done_event.py b/src/openai/types/realtime/response_output_item_done_event.py new file mode 100644 index 0000000000..800e4ae8ee --- /dev/null +++ b/src/openai/types/realtime/response_output_item_done_event.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel +from .conversation_item import ConversationItem + +__all__ = ["ResponseOutputItemDoneEvent"] + + +class ResponseOutputItemDoneEvent(BaseModel): + event_id: str + """The unique ID of the server event.""" + + item: ConversationItem + """A single item within a Realtime conversation.""" + + output_index: int + """The index of the output item in the Response.""" + + response_id: str + """The ID of the Response to which the item belongs.""" + + type: Literal["response.output_item.done"] + """The event type, must be `response.output_item.done`.""" diff --git a/src/openai/types/realtime/response_text_delta_event.py b/src/openai/types/realtime/response_text_delta_event.py new file mode 100644 index 0000000000..493348aa22 --- /dev/null +++ b/src/openai/types/realtime/response_text_delta_event.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseTextDeltaEvent"] + + +class ResponseTextDeltaEvent(BaseModel): + content_index: int + """The index of the content part in the item's content array.""" + + delta: str + """The text delta.""" + + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the item.""" + + output_index: int + """The index of the output item in the response.""" + + response_id: str + """The ID of the response.""" + + type: Literal["response.output_text.delta"] + """The event type, must be `response.output_text.delta`.""" diff --git a/src/openai/types/realtime/response_text_done_event.py b/src/openai/types/realtime/response_text_done_event.py new file mode 100644 index 0000000000..83c6cf0694 --- /dev/null +++ b/src/openai/types/realtime/response_text_done_event.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseTextDoneEvent"] + + +class ResponseTextDoneEvent(BaseModel): + content_index: int + """The index of the content part in the item's content array.""" + + event_id: str + """The unique ID of the server event.""" + + item_id: str + """The ID of the item.""" + + output_index: int + """The index of the output item in the response.""" + + response_id: str + """The ID of the response.""" + + text: str + """The final text content.""" + + type: Literal["response.output_text.done"] + """The event type, must be `response.output_text.done`.""" diff --git a/src/openai/types/realtime/session_created_event.py b/src/openai/types/realtime/session_created_event.py new file mode 100644 index 0000000000..51f75700f0 --- /dev/null +++ b/src/openai/types/realtime/session_created_event.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel +from .realtime_session import RealtimeSession + +__all__ = ["SessionCreatedEvent"] + + +class SessionCreatedEvent(BaseModel): + event_id: str + """The unique ID of the server event.""" + + session: RealtimeSession + """Realtime session object.""" + + type: Literal["session.created"] + """The event type, must be `session.created`.""" diff --git a/src/openai/types/realtime/session_update_event.py b/src/openai/types/realtime/session_update_event.py new file mode 100644 index 0000000000..00a4377f96 --- /dev/null +++ b/src/openai/types/realtime/session_update_event.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel +from .realtime_session_create_request import RealtimeSessionCreateRequest + +__all__ = ["SessionUpdateEvent"] + + +class SessionUpdateEvent(BaseModel): + session: RealtimeSessionCreateRequest + """Realtime session object configuration.""" + + type: Literal["session.update"] + """The event type, must be `session.update`.""" + + event_id: Optional[str] = None + """Optional client-generated ID used to identify this event.""" diff --git a/src/openai/types/realtime/session_update_event_param.py b/src/openai/types/realtime/session_update_event_param.py new file mode 100644 index 0000000000..79ff05f729 --- /dev/null +++ b/src/openai/types/realtime/session_update_event_param.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +from .realtime_session_create_request_param import RealtimeSessionCreateRequestParam + +__all__ = ["SessionUpdateEventParam"] + + +class SessionUpdateEventParam(TypedDict, total=False): + session: Required[RealtimeSessionCreateRequestParam] + """Realtime session object configuration.""" + + type: Required[Literal["session.update"]] + """The event type, must be `session.update`.""" + + event_id: str + """Optional client-generated ID used to identify this event.""" diff --git a/src/openai/types/realtime/session_updated_event.py b/src/openai/types/realtime/session_updated_event.py new file mode 100644 index 0000000000..b8a5972f6e --- /dev/null +++ b/src/openai/types/realtime/session_updated_event.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel +from .realtime_session import RealtimeSession + +__all__ = ["SessionUpdatedEvent"] + + +class SessionUpdatedEvent(BaseModel): + event_id: str + """The unique ID of the server event.""" + + session: RealtimeSession + """Realtime session object.""" + + type: Literal["session.updated"] + """The event type, must be `session.updated`.""" diff --git a/src/openai/types/realtime/transcription_session_created.py b/src/openai/types/realtime/transcription_session_created.py new file mode 100644 index 0000000000..1d34d152d7 --- /dev/null +++ b/src/openai/types/realtime/transcription_session_created.py @@ -0,0 +1,105 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = [ + "TranscriptionSessionCreated", + "Session", + "SessionAudio", + "SessionAudioInput", + "SessionAudioInputNoiseReduction", + "SessionAudioInputTranscription", + "SessionAudioInputTurnDetection", +] + + +class SessionAudioInputNoiseReduction(BaseModel): + type: Optional[Literal["near_field", "far_field"]] = None + + +class SessionAudioInputTranscription(BaseModel): + language: Optional[str] = None + """The language of the input audio. + + Supplying the input language in + [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) + format will improve accuracy and latency. + """ + + model: Optional[Literal["gpt-4o-transcribe", "gpt-4o-mini-transcribe", "whisper-1"]] = None + """The model to use for transcription. + + Can be `gpt-4o-transcribe`, `gpt-4o-mini-transcribe`, or `whisper-1`. + """ + + prompt: Optional[str] = None + """An optional text to guide the model's style or continue a previous audio + segment. + + The [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) + should match the audio language. + """ + + +class SessionAudioInputTurnDetection(BaseModel): + prefix_padding_ms: Optional[int] = None + + silence_duration_ms: Optional[int] = None + + threshold: Optional[float] = None + + type: Optional[str] = None + """Type of turn detection, only `server_vad` is currently supported.""" + + +class SessionAudioInput(BaseModel): + format: Optional[str] = None + """The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + + noise_reduction: Optional[SessionAudioInputNoiseReduction] = None + """Configuration for input audio noise reduction.""" + + transcription: Optional[SessionAudioInputTranscription] = None + """Configuration of the transcription model.""" + + turn_detection: Optional[SessionAudioInputTurnDetection] = None + """Configuration for turn detection.""" + + +class SessionAudio(BaseModel): + input: Optional[SessionAudioInput] = None + + +class Session(BaseModel): + id: Optional[str] = None + """Unique identifier for the session that looks like `sess_1234567890abcdef`.""" + + audio: Optional[SessionAudio] = None + """Configuration for input audio for the session.""" + + expires_at: Optional[int] = None + """Expiration timestamp for the session, in seconds since epoch.""" + + include: Optional[List[Literal["item.input_audio_transcription.logprobs"]]] = None + """Additional fields to include in server outputs. + + - `item.input_audio_transcription.logprobs`: Include logprobs for input audio + transcription. + """ + + object: Optional[str] = None + """The object type. Always `realtime.transcription_session`.""" + + +class TranscriptionSessionCreated(BaseModel): + event_id: str + """The unique ID of the server event.""" + + session: Session + """A Realtime transcription session configuration object.""" + + type: Literal["transcription_session.created"] + """The event type, must be `transcription_session.created`.""" diff --git a/src/openai/types/realtime/transcription_session_update.py b/src/openai/types/realtime/transcription_session_update.py new file mode 100644 index 0000000000..c8f5b9eb4a --- /dev/null +++ b/src/openai/types/realtime/transcription_session_update.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel +from .realtime_transcription_session_create_request import RealtimeTranscriptionSessionCreateRequest + +__all__ = ["TranscriptionSessionUpdate"] + + +class TranscriptionSessionUpdate(BaseModel): + session: RealtimeTranscriptionSessionCreateRequest + """Realtime transcription session object configuration.""" + + type: Literal["transcription_session.update"] + """The event type, must be `transcription_session.update`.""" + + event_id: Optional[str] = None + """Optional client-generated ID used to identify this event.""" diff --git a/src/openai/types/realtime/transcription_session_update_param.py b/src/openai/types/realtime/transcription_session_update_param.py new file mode 100644 index 0000000000..f2e66efaa0 --- /dev/null +++ b/src/openai/types/realtime/transcription_session_update_param.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +from .realtime_transcription_session_create_request_param import RealtimeTranscriptionSessionCreateRequestParam + +__all__ = ["TranscriptionSessionUpdateParam"] + + +class TranscriptionSessionUpdateParam(TypedDict, total=False): + session: Required[RealtimeTranscriptionSessionCreateRequestParam] + """Realtime transcription session object configuration.""" + + type: Required[Literal["transcription_session.update"]] + """The event type, must be `transcription_session.update`.""" + + event_id: str + """Optional client-generated ID used to identify this event.""" diff --git a/src/openai/types/realtime/transcription_session_updated_event.py b/src/openai/types/realtime/transcription_session_updated_event.py new file mode 100644 index 0000000000..9abd1d20be --- /dev/null +++ b/src/openai/types/realtime/transcription_session_updated_event.py @@ -0,0 +1,105 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = [ + "TranscriptionSessionUpdatedEvent", + "Session", + "SessionAudio", + "SessionAudioInput", + "SessionAudioInputNoiseReduction", + "SessionAudioInputTranscription", + "SessionAudioInputTurnDetection", +] + + +class SessionAudioInputNoiseReduction(BaseModel): + type: Optional[Literal["near_field", "far_field"]] = None + + +class SessionAudioInputTranscription(BaseModel): + language: Optional[str] = None + """The language of the input audio. + + Supplying the input language in + [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) + format will improve accuracy and latency. + """ + + model: Optional[Literal["gpt-4o-transcribe", "gpt-4o-mini-transcribe", "whisper-1"]] = None + """The model to use for transcription. + + Can be `gpt-4o-transcribe`, `gpt-4o-mini-transcribe`, or `whisper-1`. + """ + + prompt: Optional[str] = None + """An optional text to guide the model's style or continue a previous audio + segment. + + The [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) + should match the audio language. + """ + + +class SessionAudioInputTurnDetection(BaseModel): + prefix_padding_ms: Optional[int] = None + + silence_duration_ms: Optional[int] = None + + threshold: Optional[float] = None + + type: Optional[str] = None + """Type of turn detection, only `server_vad` is currently supported.""" + + +class SessionAudioInput(BaseModel): + format: Optional[str] = None + """The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + + noise_reduction: Optional[SessionAudioInputNoiseReduction] = None + """Configuration for input audio noise reduction.""" + + transcription: Optional[SessionAudioInputTranscription] = None + """Configuration of the transcription model.""" + + turn_detection: Optional[SessionAudioInputTurnDetection] = None + """Configuration for turn detection.""" + + +class SessionAudio(BaseModel): + input: Optional[SessionAudioInput] = None + + +class Session(BaseModel): + id: Optional[str] = None + """Unique identifier for the session that looks like `sess_1234567890abcdef`.""" + + audio: Optional[SessionAudio] = None + """Configuration for input audio for the session.""" + + expires_at: Optional[int] = None + """Expiration timestamp for the session, in seconds since epoch.""" + + include: Optional[List[Literal["item.input_audio_transcription.logprobs"]]] = None + """Additional fields to include in server outputs. + + - `item.input_audio_transcription.logprobs`: Include logprobs for input audio + transcription. + """ + + object: Optional[str] = None + """The object type. Always `realtime.transcription_session`.""" + + +class TranscriptionSessionUpdatedEvent(BaseModel): + event_id: str + """The unique ID of the server event.""" + + session: Session + """A Realtime transcription session configuration object.""" + + type: Literal["transcription_session.updated"] + """The event type, must be `transcription_session.updated`.""" diff --git a/src/openai/types/responses/__init__.py b/src/openai/types/responses/__init__.py index 7c574ed315..8047f3c4d1 100644 --- a/src/openai/types/responses/__init__.py +++ b/src/openai/types/responses/__init__.py @@ -59,6 +59,7 @@ from .response_output_refusal import ResponseOutputRefusal as ResponseOutputRefusal from .response_reasoning_item import ResponseReasoningItem as ResponseReasoningItem from .tool_choice_types_param import ToolChoiceTypesParam as ToolChoiceTypesParam +from .web_search_preview_tool import WebSearchPreviewTool as WebSearchPreviewTool from .easy_input_message_param import EasyInputMessageParam as EasyInputMessageParam from .response_completed_event import ResponseCompletedEvent as ResponseCompletedEvent from .response_retrieve_params import ResponseRetrieveParams as ResponseRetrieveParams @@ -90,6 +91,7 @@ from .response_output_message_param import ResponseOutputMessageParam as ResponseOutputMessageParam from .response_output_refusal_param import ResponseOutputRefusalParam as ResponseOutputRefusalParam from .response_reasoning_item_param import ResponseReasoningItemParam as ResponseReasoningItemParam +from .web_search_preview_tool_param import WebSearchPreviewToolParam as WebSearchPreviewToolParam from .response_file_search_tool_call import ResponseFileSearchToolCall as ResponseFileSearchToolCall from .response_mcp_call_failed_event import ResponseMcpCallFailedEvent as ResponseMcpCallFailedEvent from .response_custom_tool_call_param import ResponseCustomToolCallParam as ResponseCustomToolCallParam diff --git a/src/openai/types/responses/response.py b/src/openai/types/responses/response.py index ce9effd75e..9f6fd3e2d2 100644 --- a/src/openai/types/responses/response.py +++ b/src/openai/types/responses/response.py @@ -116,7 +116,7 @@ class Response(BaseModel): You can specify which tool to use by setting the `tool_choice` parameter. - The two categories of tools you can provide the model are: + We support the following categories of tools: - **Built-in tools**: Tools that are provided by OpenAI that extend the model's capabilities, like @@ -124,6 +124,9 @@ class Response(BaseModel): [file search](https://platform.openai.com/docs/guides/tools-file-search). Learn more about [built-in tools](https://platform.openai.com/docs/guides/tools). + - **MCP Tools**: Integrations with third-party systems via custom MCP servers or + predefined connectors such as Google Drive and Notion. Learn more about + [MCP Tools](https://platform.openai.com/docs/guides/tools-connectors-mcp). - **Function calls (custom tools)**: Functions that are defined by you, enabling the model to call your own code with strongly typed arguments and outputs. Learn more about diff --git a/src/openai/types/responses/response_create_params.py b/src/openai/types/responses/response_create_params.py index ff28c05816..eac249414a 100644 --- a/src/openai/types/responses/response_create_params.py +++ b/src/openai/types/responses/response_create_params.py @@ -216,7 +216,7 @@ class ResponseCreateParamsBase(TypedDict, total=False): You can specify which tool to use by setting the `tool_choice` parameter. - The two categories of tools you can provide the model are: + We support the following categories of tools: - **Built-in tools**: Tools that are provided by OpenAI that extend the model's capabilities, like @@ -224,6 +224,9 @@ class ResponseCreateParamsBase(TypedDict, total=False): [file search](https://platform.openai.com/docs/guides/tools-file-search). Learn more about [built-in tools](https://platform.openai.com/docs/guides/tools). + - **MCP Tools**: Integrations with third-party systems via custom MCP servers or + predefined connectors such as Google Drive and Notion. Learn more about + [MCP Tools](https://platform.openai.com/docs/guides/tools-connectors-mcp). - **Function calls (custom tools)**: Functions that are defined by you, enabling the model to call your own code with strongly typed arguments and outputs. Learn more about diff --git a/src/openai/types/responses/tool.py b/src/openai/types/responses/tool.py index 0fe7133804..594e09d729 100644 --- a/src/openai/types/responses/tool.py +++ b/src/openai/types/responses/tool.py @@ -3,19 +3,18 @@ from typing import Dict, List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias -from . import web_search_tool from ..._utils import PropertyInfo from ..._models import BaseModel from .custom_tool import CustomTool from .computer_tool import ComputerTool from .function_tool import FunctionTool +from .web_search_tool import WebSearchTool from .file_search_tool import FileSearchTool +from .web_search_preview_tool import WebSearchPreviewTool __all__ = [ "Tool", "WebSearchTool", - "WebSearchToolFilters", - "WebSearchToolUserLocation", "Mcp", "McpAllowedTools", "McpAllowedToolsMcpToolFilter", @@ -32,61 +31,6 @@ ] -class WebSearchToolFilters(BaseModel): - allowed_domains: Optional[List[str]] = None - """Allowed domains for the search. - - If not provided, all domains are allowed. Subdomains of the provided domains are - allowed as well. - - Example: `["pubmed.ncbi.nlm.nih.gov"]` - """ - - -class WebSearchToolUserLocation(BaseModel): - city: Optional[str] = None - """Free text input for the city of the user, e.g. `San Francisco`.""" - - country: Optional[str] = None - """ - The two-letter [ISO country code](https://en.wikipedia.org/wiki/ISO_3166-1) of - the user, e.g. `US`. - """ - - region: Optional[str] = None - """Free text input for the region of the user, e.g. `California`.""" - - timezone: Optional[str] = None - """ - The [IANA timezone](https://timeapi.io/documentation/iana-timezones) of the - user, e.g. `America/Los_Angeles`. - """ - - type: Optional[Literal["approximate"]] = None - """The type of location approximation. Always `approximate`.""" - - -class WebSearchTool(BaseModel): - type: Literal["web_search", "web_search_2025_08_26"] - """The type of the web search tool. - - One of `web_search` or `web_search_2025_08_26`. - """ - - filters: Optional[WebSearchToolFilters] = None - """Filters for the search.""" - - search_context_size: Optional[Literal["low", "medium", "high"]] = None - """High level guidance for the amount of context window space to use for the - search. - - One of `low`, `medium`, or `high`. `medium` is the default. - """ - - user_location: Optional[WebSearchToolUserLocation] = None - """The approximate location of the user.""" - - class McpAllowedToolsMcpToolFilter(BaseModel): read_only: Optional[bool] = None """Indicates whether or not a tool modifies data or is read-only. @@ -310,7 +254,7 @@ class LocalShell(BaseModel): ImageGeneration, LocalShell, CustomTool, - web_search_tool.WebSearchTool, + WebSearchPreviewTool, ], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/responses/tool_param.py b/src/openai/types/responses/tool_param.py index aff9359efa..def1f08094 100644 --- a/src/openai/types/responses/tool_param.py +++ b/src/openai/types/responses/tool_param.py @@ -11,12 +11,10 @@ from .function_tool_param import FunctionToolParam from .web_search_tool_param import WebSearchToolParam from .file_search_tool_param import FileSearchToolParam +from .web_search_preview_tool_param import WebSearchPreviewToolParam __all__ = [ "ToolParam", - "WebSearchTool", - "WebSearchToolFilters", - "WebSearchToolUserLocation", "Mcp", "McpAllowedTools", "McpAllowedToolsMcpToolFilter", @@ -33,61 +31,6 @@ ] -class WebSearchToolFilters(TypedDict, total=False): - allowed_domains: Optional[List[str]] - """Allowed domains for the search. - - If not provided, all domains are allowed. Subdomains of the provided domains are - allowed as well. - - Example: `["pubmed.ncbi.nlm.nih.gov"]` - """ - - -class WebSearchToolUserLocation(TypedDict, total=False): - city: Optional[str] - """Free text input for the city of the user, e.g. `San Francisco`.""" - - country: Optional[str] - """ - The two-letter [ISO country code](https://en.wikipedia.org/wiki/ISO_3166-1) of - the user, e.g. `US`. - """ - - region: Optional[str] - """Free text input for the region of the user, e.g. `California`.""" - - timezone: Optional[str] - """ - The [IANA timezone](https://timeapi.io/documentation/iana-timezones) of the - user, e.g. `America/Los_Angeles`. - """ - - type: Literal["approximate"] - """The type of location approximation. Always `approximate`.""" - - -class WebSearchTool(TypedDict, total=False): - type: Required[Literal["web_search", "web_search_2025_08_26"]] - """The type of the web search tool. - - One of `web_search` or `web_search_2025_08_26`. - """ - - filters: Optional[WebSearchToolFilters] - """Filters for the search.""" - - search_context_size: Literal["low", "medium", "high"] - """High level guidance for the amount of context window space to use for the - search. - - One of `low`, `medium`, or `high`. `medium` is the default. - """ - - user_location: Optional[WebSearchToolUserLocation] - """The approximate location of the user.""" - - class McpAllowedToolsMcpToolFilter(TypedDict, total=False): read_only: bool """Indicates whether or not a tool modifies data or is read-only. @@ -302,13 +245,13 @@ class LocalShell(TypedDict, total=False): FunctionToolParam, FileSearchToolParam, ComputerToolParam, - WebSearchTool, + WebSearchToolParam, Mcp, CodeInterpreter, ImageGeneration, LocalShell, CustomToolParam, - WebSearchToolParam, + WebSearchPreviewToolParam, ] diff --git a/src/openai/types/responses/web_search_preview_tool.py b/src/openai/types/responses/web_search_preview_tool.py new file mode 100644 index 0000000000..66d6a24679 --- /dev/null +++ b/src/openai/types/responses/web_search_preview_tool.py @@ -0,0 +1,49 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["WebSearchPreviewTool", "UserLocation"] + + +class UserLocation(BaseModel): + type: Literal["approximate"] + """The type of location approximation. Always `approximate`.""" + + city: Optional[str] = None + """Free text input for the city of the user, e.g. `San Francisco`.""" + + country: Optional[str] = None + """ + The two-letter [ISO country code](https://en.wikipedia.org/wiki/ISO_3166-1) of + the user, e.g. `US`. + """ + + region: Optional[str] = None + """Free text input for the region of the user, e.g. `California`.""" + + timezone: Optional[str] = None + """ + The [IANA timezone](https://timeapi.io/documentation/iana-timezones) of the + user, e.g. `America/Los_Angeles`. + """ + + +class WebSearchPreviewTool(BaseModel): + type: Literal["web_search_preview", "web_search_preview_2025_03_11"] + """The type of the web search tool. + + One of `web_search_preview` or `web_search_preview_2025_03_11`. + """ + + search_context_size: Optional[Literal["low", "medium", "high"]] = None + """High level guidance for the amount of context window space to use for the + search. + + One of `low`, `medium`, or `high`. `medium` is the default. + """ + + user_location: Optional[UserLocation] = None + """The user's location.""" diff --git a/src/openai/types/responses/web_search_preview_tool_param.py b/src/openai/types/responses/web_search_preview_tool_param.py new file mode 100644 index 0000000000..ec2173f8e8 --- /dev/null +++ b/src/openai/types/responses/web_search_preview_tool_param.py @@ -0,0 +1,49 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["WebSearchPreviewToolParam", "UserLocation"] + + +class UserLocation(TypedDict, total=False): + type: Required[Literal["approximate"]] + """The type of location approximation. Always `approximate`.""" + + city: Optional[str] + """Free text input for the city of the user, e.g. `San Francisco`.""" + + country: Optional[str] + """ + The two-letter [ISO country code](https://en.wikipedia.org/wiki/ISO_3166-1) of + the user, e.g. `US`. + """ + + region: Optional[str] + """Free text input for the region of the user, e.g. `California`.""" + + timezone: Optional[str] + """ + The [IANA timezone](https://timeapi.io/documentation/iana-timezones) of the + user, e.g. `America/Los_Angeles`. + """ + + +class WebSearchPreviewToolParam(TypedDict, total=False): + type: Required[Literal["web_search_preview", "web_search_preview_2025_03_11"]] + """The type of the web search tool. + + One of `web_search_preview` or `web_search_preview_2025_03_11`. + """ + + search_context_size: Literal["low", "medium", "high"] + """High level guidance for the amount of context window space to use for the + search. + + One of `low`, `medium`, or `high`. `medium` is the default. + """ + + user_location: Optional[UserLocation] + """The user's location.""" diff --git a/src/openai/types/responses/web_search_tool.py b/src/openai/types/responses/web_search_tool.py index a6bf951145..bde9600c87 100644 --- a/src/openai/types/responses/web_search_tool.py +++ b/src/openai/types/responses/web_search_tool.py @@ -1,17 +1,25 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional +from typing import List, Optional from typing_extensions import Literal from ..._models import BaseModel -__all__ = ["WebSearchTool", "UserLocation"] +__all__ = ["WebSearchTool", "Filters", "UserLocation"] -class UserLocation(BaseModel): - type: Literal["approximate"] - """The type of location approximation. Always `approximate`.""" +class Filters(BaseModel): + allowed_domains: Optional[List[str]] = None + """Allowed domains for the search. + + If not provided, all domains are allowed. Subdomains of the provided domains are + allowed as well. + + Example: `["pubmed.ncbi.nlm.nih.gov"]` + """ + +class UserLocation(BaseModel): city: Optional[str] = None """Free text input for the city of the user, e.g. `San Francisco`.""" @@ -30,14 +38,20 @@ class UserLocation(BaseModel): user, e.g. `America/Los_Angeles`. """ + type: Optional[Literal["approximate"]] = None + """The type of location approximation. Always `approximate`.""" + class WebSearchTool(BaseModel): - type: Literal["web_search_preview", "web_search_preview_2025_03_11"] + type: Literal["web_search", "web_search_2025_08_26"] """The type of the web search tool. - One of `web_search_preview` or `web_search_preview_2025_03_11`. + One of `web_search` or `web_search_2025_08_26`. """ + filters: Optional[Filters] = None + """Filters for the search.""" + search_context_size: Optional[Literal["low", "medium", "high"]] = None """High level guidance for the amount of context window space to use for the search. @@ -46,4 +60,4 @@ class WebSearchTool(BaseModel): """ user_location: Optional[UserLocation] = None - """The user's location.""" + """The approximate location of the user.""" diff --git a/src/openai/types/responses/web_search_tool_param.py b/src/openai/types/responses/web_search_tool_param.py index d0335c01a3..17a382456b 100644 --- a/src/openai/types/responses/web_search_tool_param.py +++ b/src/openai/types/responses/web_search_tool_param.py @@ -2,16 +2,24 @@ from __future__ import annotations -from typing import Optional +from typing import List, Optional from typing_extensions import Literal, Required, TypedDict -__all__ = ["WebSearchToolParam", "UserLocation"] +__all__ = ["WebSearchToolParam", "Filters", "UserLocation"] -class UserLocation(TypedDict, total=False): - type: Required[Literal["approximate"]] - """The type of location approximation. Always `approximate`.""" +class Filters(TypedDict, total=False): + allowed_domains: Optional[List[str]] + """Allowed domains for the search. + + If not provided, all domains are allowed. Subdomains of the provided domains are + allowed as well. + + Example: `["pubmed.ncbi.nlm.nih.gov"]` + """ + +class UserLocation(TypedDict, total=False): city: Optional[str] """Free text input for the city of the user, e.g. `San Francisco`.""" @@ -30,14 +38,20 @@ class UserLocation(TypedDict, total=False): user, e.g. `America/Los_Angeles`. """ + type: Literal["approximate"] + """The type of location approximation. Always `approximate`.""" + class WebSearchToolParam(TypedDict, total=False): - type: Required[Literal["web_search_preview", "web_search_preview_2025_03_11"]] + type: Required[Literal["web_search", "web_search_2025_08_26"]] """The type of the web search tool. - One of `web_search_preview` or `web_search_preview_2025_03_11`. + One of `web_search` or `web_search_2025_08_26`. """ + filters: Optional[Filters] + """Filters for the search.""" + search_context_size: Literal["low", "medium", "high"] """High level guidance for the amount of context window space to use for the search. @@ -46,4 +60,4 @@ class WebSearchToolParam(TypedDict, total=False): """ user_location: Optional[UserLocation] - """The user's location.""" + """The approximate location of the user.""" diff --git a/src/openai/types/webhooks/__init__.py b/src/openai/types/webhooks/__init__.py index 9caad38c82..8b9e55653b 100644 --- a/src/openai/types/webhooks/__init__.py +++ b/src/openai/types/webhooks/__init__.py @@ -15,6 +15,7 @@ from .response_completed_webhook_event import ResponseCompletedWebhookEvent as ResponseCompletedWebhookEvent from .response_incomplete_webhook_event import ResponseIncompleteWebhookEvent as ResponseIncompleteWebhookEvent from .fine_tuning_job_failed_webhook_event import FineTuningJobFailedWebhookEvent as FineTuningJobFailedWebhookEvent +from .realtime_call_incoming_webhook_event import RealtimeCallIncomingWebhookEvent as RealtimeCallIncomingWebhookEvent from .fine_tuning_job_cancelled_webhook_event import ( FineTuningJobCancelledWebhookEvent as FineTuningJobCancelledWebhookEvent, ) diff --git a/src/openai/types/webhooks/realtime_call_incoming_webhook_event.py b/src/openai/types/webhooks/realtime_call_incoming_webhook_event.py new file mode 100644 index 0000000000..a166a3471b --- /dev/null +++ b/src/openai/types/webhooks/realtime_call_incoming_webhook_event.py @@ -0,0 +1,41 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["RealtimeCallIncomingWebhookEvent", "Data", "DataSipHeader"] + + +class DataSipHeader(BaseModel): + name: str + """Name of the SIP Header.""" + + value: str + """Value of the SIP Header.""" + + +class Data(BaseModel): + call_id: str + """The unique ID of this call.""" + + sip_headers: List[DataSipHeader] + """Headers from the SIP Invite.""" + + +class RealtimeCallIncomingWebhookEvent(BaseModel): + id: str + """The unique ID of the event.""" + + created_at: int + """The Unix timestamp (in seconds) of when the model response was completed.""" + + data: Data + """Event data payload.""" + + type: Literal["realtime.call.incoming"] + """The type of the event. Always `realtime.call.incoming`.""" + + object: Optional[Literal["event"]] = None + """The object of the event. Always `event`.""" diff --git a/src/openai/types/webhooks/unwrap_webhook_event.py b/src/openai/types/webhooks/unwrap_webhook_event.py index 91091af32f..952383c049 100644 --- a/src/openai/types/webhooks/unwrap_webhook_event.py +++ b/src/openai/types/webhooks/unwrap_webhook_event.py @@ -16,6 +16,7 @@ from .response_completed_webhook_event import ResponseCompletedWebhookEvent from .response_incomplete_webhook_event import ResponseIncompleteWebhookEvent from .fine_tuning_job_failed_webhook_event import FineTuningJobFailedWebhookEvent +from .realtime_call_incoming_webhook_event import RealtimeCallIncomingWebhookEvent from .fine_tuning_job_cancelled_webhook_event import FineTuningJobCancelledWebhookEvent from .fine_tuning_job_succeeded_webhook_event import FineTuningJobSucceededWebhookEvent @@ -33,6 +34,7 @@ FineTuningJobCancelledWebhookEvent, FineTuningJobFailedWebhookEvent, FineTuningJobSucceededWebhookEvent, + RealtimeCallIncomingWebhookEvent, ResponseCancelledWebhookEvent, ResponseCompletedWebhookEvent, ResponseFailedWebhookEvent, diff --git a/tests/api_resources/beta/realtime/test_sessions.py b/tests/api_resources/beta/realtime/test_sessions.py deleted file mode 100644 index 3c55abf80c..0000000000 --- a/tests/api_resources/beta/realtime/test_sessions.py +++ /dev/null @@ -1,166 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from openai import OpenAI, AsyncOpenAI -from tests.utils import assert_matches_type -from openai.types.beta.realtime import SessionCreateResponse - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestSessions: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: OpenAI) -> None: - session = client.beta.realtime.sessions.create() - assert_matches_type(SessionCreateResponse, session, path=["response"]) - - @parametrize - def test_method_create_with_all_params(self, client: OpenAI) -> None: - session = client.beta.realtime.sessions.create( - client_secret={ - "expires_after": { - "anchor": "created_at", - "seconds": 0, - } - }, - input_audio_format="pcm16", - input_audio_noise_reduction={"type": "near_field"}, - input_audio_transcription={ - "language": "language", - "model": "model", - "prompt": "prompt", - }, - instructions="instructions", - max_response_output_tokens=0, - modalities=["text"], - model="gpt-4o-realtime-preview", - output_audio_format="pcm16", - speed=0.25, - temperature=0, - tool_choice="tool_choice", - tools=[ - { - "description": "description", - "name": "name", - "parameters": {}, - "type": "function", - } - ], - tracing="auto", - turn_detection={ - "create_response": True, - "eagerness": "low", - "interrupt_response": True, - "prefix_padding_ms": 0, - "silence_duration_ms": 0, - "threshold": 0, - "type": "server_vad", - }, - voice="ash", - ) - assert_matches_type(SessionCreateResponse, session, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: OpenAI) -> None: - response = client.beta.realtime.sessions.with_raw_response.create() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - session = response.parse() - assert_matches_type(SessionCreateResponse, session, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: OpenAI) -> None: - with client.beta.realtime.sessions.with_streaming_response.create() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - session = response.parse() - assert_matches_type(SessionCreateResponse, session, path=["response"]) - - assert cast(Any, response.is_closed) is True - - -class TestAsyncSessions: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncOpenAI) -> None: - session = await async_client.beta.realtime.sessions.create() - assert_matches_type(SessionCreateResponse, session, path=["response"]) - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: - session = await async_client.beta.realtime.sessions.create( - client_secret={ - "expires_after": { - "anchor": "created_at", - "seconds": 0, - } - }, - input_audio_format="pcm16", - input_audio_noise_reduction={"type": "near_field"}, - input_audio_transcription={ - "language": "language", - "model": "model", - "prompt": "prompt", - }, - instructions="instructions", - max_response_output_tokens=0, - modalities=["text"], - model="gpt-4o-realtime-preview", - output_audio_format="pcm16", - speed=0.25, - temperature=0, - tool_choice="tool_choice", - tools=[ - { - "description": "description", - "name": "name", - "parameters": {}, - "type": "function", - } - ], - tracing="auto", - turn_detection={ - "create_response": True, - "eagerness": "low", - "interrupt_response": True, - "prefix_padding_ms": 0, - "silence_duration_ms": 0, - "threshold": 0, - "type": "server_vad", - }, - voice="ash", - ) - assert_matches_type(SessionCreateResponse, session, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.realtime.sessions.with_raw_response.create() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - session = response.parse() - assert_matches_type(SessionCreateResponse, session, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.realtime.sessions.with_streaming_response.create() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - session = await response.parse() - assert_matches_type(SessionCreateResponse, session, path=["response"]) - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/beta/realtime/test_transcription_sessions.py b/tests/api_resources/beta/realtime/test_transcription_sessions.py deleted file mode 100644 index ac52489e74..0000000000 --- a/tests/api_resources/beta/realtime/test_transcription_sessions.py +++ /dev/null @@ -1,134 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from openai import OpenAI, AsyncOpenAI -from tests.utils import assert_matches_type -from openai.types.beta.realtime import TranscriptionSession - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestTranscriptionSessions: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: OpenAI) -> None: - transcription_session = client.beta.realtime.transcription_sessions.create() - assert_matches_type(TranscriptionSession, transcription_session, path=["response"]) - - @parametrize - def test_method_create_with_all_params(self, client: OpenAI) -> None: - transcription_session = client.beta.realtime.transcription_sessions.create( - client_secret={ - "expires_at": { - "anchor": "created_at", - "seconds": 0, - } - }, - include=["string"], - input_audio_format="pcm16", - input_audio_noise_reduction={"type": "near_field"}, - input_audio_transcription={ - "language": "language", - "model": "gpt-4o-transcribe", - "prompt": "prompt", - }, - modalities=["text"], - turn_detection={ - "create_response": True, - "eagerness": "low", - "interrupt_response": True, - "prefix_padding_ms": 0, - "silence_duration_ms": 0, - "threshold": 0, - "type": "server_vad", - }, - ) - assert_matches_type(TranscriptionSession, transcription_session, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: OpenAI) -> None: - response = client.beta.realtime.transcription_sessions.with_raw_response.create() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - transcription_session = response.parse() - assert_matches_type(TranscriptionSession, transcription_session, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: OpenAI) -> None: - with client.beta.realtime.transcription_sessions.with_streaming_response.create() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - transcription_session = response.parse() - assert_matches_type(TranscriptionSession, transcription_session, path=["response"]) - - assert cast(Any, response.is_closed) is True - - -class TestAsyncTranscriptionSessions: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncOpenAI) -> None: - transcription_session = await async_client.beta.realtime.transcription_sessions.create() - assert_matches_type(TranscriptionSession, transcription_session, path=["response"]) - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: - transcription_session = await async_client.beta.realtime.transcription_sessions.create( - client_secret={ - "expires_at": { - "anchor": "created_at", - "seconds": 0, - } - }, - include=["string"], - input_audio_format="pcm16", - input_audio_noise_reduction={"type": "near_field"}, - input_audio_transcription={ - "language": "language", - "model": "gpt-4o-transcribe", - "prompt": "prompt", - }, - modalities=["text"], - turn_detection={ - "create_response": True, - "eagerness": "low", - "interrupt_response": True, - "prefix_padding_ms": 0, - "silence_duration_ms": 0, - "threshold": 0, - "type": "server_vad", - }, - ) - assert_matches_type(TranscriptionSession, transcription_session, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.realtime.transcription_sessions.with_raw_response.create() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - transcription_session = response.parse() - assert_matches_type(TranscriptionSession, transcription_session, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.realtime.transcription_sessions.with_streaming_response.create() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - transcription_session = await response.parse() - assert_matches_type(TranscriptionSession, transcription_session, path=["response"]) - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/beta/test_realtime.py b/tests/api_resources/beta/test_realtime.py index 2b0c7f7d8d..8f752a0fd3 100644 --- a/tests/api_resources/beta/test_realtime.py +++ b/tests/api_resources/beta/test_realtime.py @@ -6,6 +6,8 @@ import pytest +# pyright: reportDeprecated=false + base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") diff --git a/tests/api_resources/beta/realtime/__init__.py b/tests/api_resources/realtime/__init__.py similarity index 100% rename from tests/api_resources/beta/realtime/__init__.py rename to tests/api_resources/realtime/__init__.py diff --git a/tests/api_resources/realtime/test_client_secrets.py b/tests/api_resources/realtime/test_client_secrets.py new file mode 100644 index 0000000000..c477268ee6 --- /dev/null +++ b/tests/api_resources/realtime/test_client_secrets.py @@ -0,0 +1,208 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.types.realtime import ClientSecretCreateResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestClientSecrets: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: OpenAI) -> None: + client_secret = client.realtime.client_secrets.create() + assert_matches_type(ClientSecretCreateResponse, client_secret, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: OpenAI) -> None: + client_secret = client.realtime.client_secrets.create( + expires_after={ + "anchor": "created_at", + "seconds": 10, + }, + session={ + "model": "string", + "type": "realtime", + "audio": { + "input": { + "format": "pcm16", + "noise_reduction": {"type": "near_field"}, + "transcription": { + "language": "language", + "model": "whisper-1", + "prompt": "prompt", + }, + "turn_detection": { + "create_response": True, + "eagerness": "low", + "idle_timeout_ms": 0, + "interrupt_response": True, + "prefix_padding_ms": 0, + "silence_duration_ms": 0, + "threshold": 0, + "type": "server_vad", + }, + }, + "output": { + "format": "pcm16", + "speed": 0.25, + "voice": "ash", + }, + }, + "client_secret": { + "expires_after": { + "anchor": "created_at", + "seconds": 0, + } + }, + "include": ["item.input_audio_transcription.logprobs"], + "instructions": "instructions", + "max_output_tokens": 0, + "output_modalities": ["text"], + "prompt": { + "id": "id", + "variables": {"foo": "string"}, + "version": "version", + }, + "temperature": 0, + "tool_choice": "none", + "tools": [ + { + "description": "description", + "name": "name", + "parameters": {}, + "type": "function", + } + ], + "tracing": "auto", + "truncation": "auto", + }, + ) + assert_matches_type(ClientSecretCreateResponse, client_secret, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: OpenAI) -> None: + response = client.realtime.client_secrets.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + client_secret = response.parse() + assert_matches_type(ClientSecretCreateResponse, client_secret, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: OpenAI) -> None: + with client.realtime.client_secrets.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + client_secret = response.parse() + assert_matches_type(ClientSecretCreateResponse, client_secret, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncClientSecrets: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncOpenAI) -> None: + client_secret = await async_client.realtime.client_secrets.create() + assert_matches_type(ClientSecretCreateResponse, client_secret, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: + client_secret = await async_client.realtime.client_secrets.create( + expires_after={ + "anchor": "created_at", + "seconds": 10, + }, + session={ + "model": "string", + "type": "realtime", + "audio": { + "input": { + "format": "pcm16", + "noise_reduction": {"type": "near_field"}, + "transcription": { + "language": "language", + "model": "whisper-1", + "prompt": "prompt", + }, + "turn_detection": { + "create_response": True, + "eagerness": "low", + "idle_timeout_ms": 0, + "interrupt_response": True, + "prefix_padding_ms": 0, + "silence_duration_ms": 0, + "threshold": 0, + "type": "server_vad", + }, + }, + "output": { + "format": "pcm16", + "speed": 0.25, + "voice": "ash", + }, + }, + "client_secret": { + "expires_after": { + "anchor": "created_at", + "seconds": 0, + } + }, + "include": ["item.input_audio_transcription.logprobs"], + "instructions": "instructions", + "max_output_tokens": 0, + "output_modalities": ["text"], + "prompt": { + "id": "id", + "variables": {"foo": "string"}, + "version": "version", + }, + "temperature": 0, + "tool_choice": "none", + "tools": [ + { + "description": "description", + "name": "name", + "parameters": {}, + "type": "function", + } + ], + "tracing": "auto", + "truncation": "auto", + }, + ) + assert_matches_type(ClientSecretCreateResponse, client_secret, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: + response = await async_client.realtime.client_secrets.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + client_secret = response.parse() + assert_matches_type(ClientSecretCreateResponse, client_secret, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: + async with async_client.realtime.client_secrets.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + client_secret = await response.parse() + assert_matches_type(ClientSecretCreateResponse, client_secret, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_realtime.py b/tests/api_resources/test_realtime.py new file mode 100644 index 0000000000..2b0c7f7d8d --- /dev/null +++ b/tests/api_resources/test_realtime.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os + +import pytest + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestRealtime: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + +class TestAsyncRealtime: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) From c382ea30742f9327ad2afc25c8febb148452694a Mon Sep 17 00:00:00 2001 From: David Meadows Date: Tue, 2 Sep 2025 09:49:33 -0400 Subject: [PATCH 470/769] chore(client): format imports --- tests/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/utils.py b/tests/utils.py index 7740ed3f7c..a07052140b 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -5,7 +5,7 @@ import inspect import traceback import contextlib -from typing import Any, TypeVar, Iterator, ForwardRef, Sequence, cast +from typing import Any, TypeVar, Iterator, Sequence, ForwardRef, cast from datetime import date, datetime from typing_extensions import Literal, get_args, get_origin, assert_type From 3e3c7a762098d30ebd30567a9853bd5917354987 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 2 Sep 2025 13:50:11 +0000 Subject: [PATCH 471/769] release: 1.103.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 23 +++++++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 98411f0f2b..0a5613fed8 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.102.0" + ".": "1.103.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 26ca1c5cb2..6595e5246b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,28 @@ # Changelog +## 1.103.0 (2025-09-02) + +Full Changelog: [v1.102.0...v1.103.0](https://github.com/openai/openai-python/compare/v1.102.0...v1.103.0) + +### Features + +* **api:** realtime API updates ([b7c2ddc](https://github.com/openai/openai-python/commit/b7c2ddc5e5dedda01015b3d0e14ea6eb68c282d3)) + + +### Bug Fixes + +* **responses:** add missing params to stream() method ([bfc0673](https://github.com/openai/openai-python/commit/bfc06732ffe3764cb95cef9f23b4b5c0d312826a)) + + +### Chores + +* bump `inline-snapshot` version to 0.28.0 ([#2590](https://github.com/openai/openai-python/issues/2590)) ([a6b0872](https://github.com/openai/openai-python/commit/a6b087226587d4cc4f59f1f09a595921b2823ef2)) +* **client:** format imports ([7ae3020](https://github.com/openai/openai-python/commit/7ae3020b3ca7de21e6e9a0a1c40908e655f6cad5)) +* **internal:** add Sequence related utils ([d3d72b9](https://github.com/openai/openai-python/commit/d3d72b9ce3c0885bf2b6934ac57d9e84f8653208)) +* **internal:** fix formatting ([3ab273f](https://github.com/openai/openai-python/commit/3ab273f21e601f088be7502b7bb5d249fc386d6a)) +* **internal:** minor formatting change ([478a348](https://github.com/openai/openai-python/commit/478a34881c968e9cab9d93ac2cf8da2fcb37c46c)) +* **internal:** update pyright exclude list ([66e440f](https://github.com/openai/openai-python/commit/66e440fac3ca388400392c64211450dedc491c11)) + ## 1.102.0 (2025-08-26) Full Changelog: [v1.101.0...v1.102.0](https://github.com/openai/openai-python/compare/v1.101.0...v1.102.0) diff --git a/pyproject.toml b/pyproject.toml index 2633918fc0..309b0f5544 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.102.0" +version = "1.103.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 b2d62263ff..313e60b0bf 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.102.0" # x-release-please-version +__version__ = "1.103.0" # x-release-please-version From 7da727a4a3eb35306c328e2c3207a1618ed1809f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 2 Sep 2025 15:11:31 +0000 Subject: [PATCH 472/769] feat(types): replace List[str] with SequenceNotStr in params --- src/openai/_utils/_transform.py | 6 ++++ .../resources/chat/completions/completions.py | 18 +++++----- src/openai/resources/completions.py | 36 +++++++++---------- src/openai/resources/containers/containers.py | 7 ++-- src/openai/resources/embeddings.py | 8 ++--- .../fine_tuning/checkpoints/permissions.py | 7 ++-- src/openai/resources/images.py | 20 +++++------ src/openai/resources/moderations.py | 8 ++--- src/openai/resources/uploads/uploads.py | 7 ++-- .../resources/vector_stores/file_batches.py | 8 ++--- .../resources/vector_stores/vector_stores.py | 12 +++---- .../types/beta/assistant_create_params.py | 9 ++--- .../types/beta/assistant_update_params.py | 7 ++-- .../beta/thread_create_and_run_params.py | 13 +++---- src/openai/types/beta/thread_create_params.py | 9 ++--- src/openai/types/beta/thread_update_params.py | 7 ++-- .../types/chat/completion_create_params.py | 3 +- src/openai/types/completion_create_params.py | 7 ++-- src/openai/types/container_create_params.py | 5 +-- src/openai/types/embedding_create_params.py | 5 +-- src/openai/types/eval_create_params.py | 7 ++-- src/openai/types/evals/run_create_params.py | 7 ++-- .../checkpoints/permission_create_params.py | 5 +-- .../types/fine_tuning/job_create_params.py | 5 +-- .../types/graders/label_model_grader_param.py | 7 ++-- src/openai/types/image_edit_params.py | 6 ++-- src/openai/types/moderation_create_params.py | 5 +-- .../realtime/realtime_tools_config_param.py | 10 +++--- .../realtime_tools_config_union_param.py | 12 ++++--- .../types/responses/file_search_tool_param.py | 5 +-- .../response_computer_tool_call_param.py | 6 ++-- .../response_file_search_tool_call_param.py | 6 ++-- .../responses/response_input_item_param.py | 5 +-- .../types/responses/response_input_param.py | 3 +- src/openai/types/responses/tool_param.py | 13 +++---- .../types/responses/web_search_tool_param.py | 6 ++-- src/openai/types/upload_complete_params.py | 5 +-- .../types/vector_store_create_params.py | 5 +-- .../types/vector_store_search_params.py | 5 +-- .../vector_stores/file_batch_create_params.py | 5 +-- 40 files changed, 183 insertions(+), 147 deletions(-) diff --git a/src/openai/_utils/_transform.py b/src/openai/_utils/_transform.py index 4fd49a1908..f5c41c09c4 100644 --- a/src/openai/_utils/_transform.py +++ b/src/openai/_utils/_transform.py @@ -16,6 +16,7 @@ lru_cache, is_mapping, is_iterable, + is_sequence, ) from .._files import is_base64_file_input from ._typing import ( @@ -24,6 +25,7 @@ extract_type_arg, is_iterable_type, is_required_type, + is_sequence_type, is_annotated_type, strip_annotated_type, ) @@ -184,6 +186,8 @@ def _transform_recursive( (is_list_type(stripped_type) and is_list(data)) # Iterable[T] or (is_iterable_type(stripped_type) and is_iterable(data) and not isinstance(data, str)) + # Sequence[T] + or (is_sequence_type(stripped_type) and is_sequence(data) and not isinstance(data, str)) ): # dicts are technically iterable, but it is an iterable on the keys of the dict and is not usually # intended as an iterable, so we don't transform it. @@ -346,6 +350,8 @@ async def _async_transform_recursive( (is_list_type(stripped_type) and is_list(data)) # Iterable[T] or (is_iterable_type(stripped_type) and is_iterable(data) and not isinstance(data, str)) + # Sequence[T] + or (is_sequence_type(stripped_type) and is_sequence(data) and not isinstance(data, str)) ): # dicts are technically iterable, but it is an iterable on the keys of the dict and is not usually # intended as an iterable, so we don't transform it. diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index 7e209ff0ee..14a755a50e 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -19,7 +19,7 @@ MessagesWithStreamingResponse, AsyncMessagesWithStreamingResponse, ) -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr from ...._utils import required_args, maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource @@ -260,7 +260,7 @@ def create( safety_identifier: str | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, + stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, @@ -549,7 +549,7 @@ def create( safety_identifier: str | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, + stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -837,7 +837,7 @@ def create( safety_identifier: str | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, + stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -1124,7 +1124,7 @@ def create( safety_identifier: str | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, + stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, @@ -1696,7 +1696,7 @@ async def create( safety_identifier: str | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, + stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, @@ -1985,7 +1985,7 @@ async def create( safety_identifier: str | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, + stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -2273,7 +2273,7 @@ async def create( safety_identifier: str | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, + stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -2560,7 +2560,7 @@ async def create( safety_identifier: str | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, + stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, diff --git a/src/openai/resources/completions.py b/src/openai/resources/completions.py index 43b923b9b9..97a84575ab 100644 --- a/src/openai/resources/completions.py +++ b/src/openai/resources/completions.py @@ -2,14 +2,14 @@ from __future__ import annotations -from typing import Dict, List, Union, Iterable, Optional +from typing import Dict, Union, Iterable, Optional from typing_extensions import Literal, overload import httpx from .. import _legacy_response from ..types import completion_create_params -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr from .._utils import required_args, maybe_transform, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource @@ -49,7 +49,7 @@ def create( self, *, model: Union[str, Literal["gpt-3.5-turbo-instruct", "davinci-002", "babbage-002"]], - prompt: Union[str, List[str], Iterable[int], Iterable[Iterable[int]], None], + prompt: Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]], None], best_of: Optional[int] | NotGiven = NOT_GIVEN, echo: Optional[bool] | NotGiven = NOT_GIVEN, frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, @@ -59,7 +59,7 @@ def create( n: Optional[int] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, + stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, suffix: Optional[str] | NotGiven = NOT_GIVEN, @@ -204,7 +204,7 @@ def create( self, *, model: Union[str, Literal["gpt-3.5-turbo-instruct", "davinci-002", "babbage-002"]], - prompt: Union[str, List[str], Iterable[int], Iterable[Iterable[int]], None], + prompt: Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]], None], stream: Literal[True], best_of: Optional[int] | NotGiven = NOT_GIVEN, echo: Optional[bool] | NotGiven = NOT_GIVEN, @@ -215,7 +215,7 @@ def create( n: Optional[int] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, + stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, suffix: Optional[str] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -359,7 +359,7 @@ def create( self, *, model: Union[str, Literal["gpt-3.5-turbo-instruct", "davinci-002", "babbage-002"]], - prompt: Union[str, List[str], Iterable[int], Iterable[Iterable[int]], None], + prompt: Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]], None], stream: bool, best_of: Optional[int] | NotGiven = NOT_GIVEN, echo: Optional[bool] | NotGiven = NOT_GIVEN, @@ -370,7 +370,7 @@ def create( n: Optional[int] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, + stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, suffix: Optional[str] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -514,7 +514,7 @@ def create( self, *, model: Union[str, Literal["gpt-3.5-turbo-instruct", "davinci-002", "babbage-002"]], - prompt: Union[str, List[str], Iterable[int], Iterable[Iterable[int]], None], + prompt: Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]], None], best_of: Optional[int] | NotGiven = NOT_GIVEN, echo: Optional[bool] | NotGiven = NOT_GIVEN, frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, @@ -524,7 +524,7 @@ def create( n: Optional[int] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, + stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, suffix: Optional[str] | NotGiven = NOT_GIVEN, @@ -599,7 +599,7 @@ async def create( self, *, model: Union[str, Literal["gpt-3.5-turbo-instruct", "davinci-002", "babbage-002"]], - prompt: Union[str, List[str], Iterable[int], Iterable[Iterable[int]], None], + prompt: Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]], None], best_of: Optional[int] | NotGiven = NOT_GIVEN, echo: Optional[bool] | NotGiven = NOT_GIVEN, frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, @@ -609,7 +609,7 @@ async def create( n: Optional[int] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, + stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, suffix: Optional[str] | NotGiven = NOT_GIVEN, @@ -754,7 +754,7 @@ async def create( self, *, model: Union[str, Literal["gpt-3.5-turbo-instruct", "davinci-002", "babbage-002"]], - prompt: Union[str, List[str], Iterable[int], Iterable[Iterable[int]], None], + prompt: Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]], None], stream: Literal[True], best_of: Optional[int] | NotGiven = NOT_GIVEN, echo: Optional[bool] | NotGiven = NOT_GIVEN, @@ -765,7 +765,7 @@ async def create( n: Optional[int] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, + stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, suffix: Optional[str] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -909,7 +909,7 @@ async def create( self, *, model: Union[str, Literal["gpt-3.5-turbo-instruct", "davinci-002", "babbage-002"]], - prompt: Union[str, List[str], Iterable[int], Iterable[Iterable[int]], None], + prompt: Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]], None], stream: bool, best_of: Optional[int] | NotGiven = NOT_GIVEN, echo: Optional[bool] | NotGiven = NOT_GIVEN, @@ -920,7 +920,7 @@ async def create( n: Optional[int] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, + stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, suffix: Optional[str] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -1064,7 +1064,7 @@ async def create( self, *, model: Union[str, Literal["gpt-3.5-turbo-instruct", "davinci-002", "babbage-002"]], - prompt: Union[str, List[str], Iterable[int], Iterable[Iterable[int]], None], + prompt: Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]], None], best_of: Optional[int] | NotGiven = NOT_GIVEN, echo: Optional[bool] | NotGiven = NOT_GIVEN, frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, @@ -1074,7 +1074,7 @@ async def create( n: Optional[int] | NotGiven = NOT_GIVEN, presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, + stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, suffix: Optional[str] | NotGiven = NOT_GIVEN, diff --git a/src/openai/resources/containers/containers.py b/src/openai/resources/containers/containers.py index 71e5e6b08d..30e9eff127 100644 --- a/src/openai/resources/containers/containers.py +++ b/src/openai/resources/containers/containers.py @@ -2,14 +2,13 @@ from __future__ import annotations -from typing import List from typing_extensions import Literal import httpx from ... import _legacy_response from ...types import container_list_params, container_create_params -from ..._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven +from ..._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven, SequenceNotStr from ..._utils import maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource @@ -60,7 +59,7 @@ def create( *, name: str, expires_after: container_create_params.ExpiresAfter | NotGiven = NOT_GIVEN, - file_ids: List[str] | NotGiven = NOT_GIVEN, + file_ids: SequenceNotStr[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -256,7 +255,7 @@ async def create( *, name: str, expires_after: container_create_params.ExpiresAfter | NotGiven = NOT_GIVEN, - file_ids: List[str] | NotGiven = NOT_GIVEN, + file_ids: SequenceNotStr[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, diff --git a/src/openai/resources/embeddings.py b/src/openai/resources/embeddings.py index 609f33f3b4..a8cf179850 100644 --- a/src/openai/resources/embeddings.py +++ b/src/openai/resources/embeddings.py @@ -4,14 +4,14 @@ import array import base64 -from typing import List, Union, Iterable, cast +from typing import Union, Iterable, cast from typing_extensions import Literal import httpx from .. import _legacy_response from ..types import embedding_create_params -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr from .._utils import is_given, maybe_transform from .._compat import cached_property from .._extras import numpy as np, has_numpy @@ -47,7 +47,7 @@ def with_streaming_response(self) -> EmbeddingsWithStreamingResponse: def create( self, *, - input: Union[str, List[str], Iterable[int], Iterable[Iterable[int]]], + input: Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]]], model: Union[str, EmbeddingModel], dimensions: int | NotGiven = NOT_GIVEN, encoding_format: Literal["float", "base64"] | NotGiven = NOT_GIVEN, @@ -166,7 +166,7 @@ def with_streaming_response(self) -> AsyncEmbeddingsWithStreamingResponse: async def create( self, *, - input: Union[str, List[str], Iterable[int], Iterable[Iterable[int]]], + input: Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]]], model: Union[str, EmbeddingModel], dimensions: int | NotGiven = NOT_GIVEN, encoding_format: Literal["float", "base64"] | NotGiven = NOT_GIVEN, diff --git a/src/openai/resources/fine_tuning/checkpoints/permissions.py b/src/openai/resources/fine_tuning/checkpoints/permissions.py index 547e42ecac..f8ae125941 100644 --- a/src/openai/resources/fine_tuning/checkpoints/permissions.py +++ b/src/openai/resources/fine_tuning/checkpoints/permissions.py @@ -2,13 +2,12 @@ from __future__ import annotations -from typing import List from typing_extensions import Literal import httpx from .... import _legacy_response -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr from ...._utils import maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource @@ -47,7 +46,7 @@ def create( self, fine_tuned_model_checkpoint: str, *, - project_ids: List[str], + project_ids: SequenceNotStr[str], # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -215,7 +214,7 @@ def create( self, fine_tuned_model_checkpoint: str, *, - project_ids: List[str], + project_ids: SequenceNotStr[str], # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, diff --git a/src/openai/resources/images.py b/src/openai/resources/images.py index c8eda8a76f..17ec264b6a 100644 --- a/src/openai/resources/images.py +++ b/src/openai/resources/images.py @@ -2,14 +2,14 @@ from __future__ import annotations -from typing import List, Union, Mapping, Optional, cast +from typing import Union, Mapping, Optional, cast from typing_extensions import Literal, overload import httpx from .. import _legacy_response from ..types import image_edit_params, image_generate_params, image_create_variation_params -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven, FileTypes +from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven, FileTypes, SequenceNotStr from .._utils import extract_files, required_args, maybe_transform, deepcopy_minimal, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource @@ -121,7 +121,7 @@ def create_variation( def edit( self, *, - image: Union[FileTypes, List[FileTypes]], + image: Union[FileTypes, SequenceNotStr[FileTypes]], prompt: str, background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, input_fidelity: Optional[Literal["high", "low"]] | NotGiven = NOT_GIVEN, @@ -234,7 +234,7 @@ def edit( def edit( self, *, - image: Union[FileTypes, List[FileTypes]], + image: Union[FileTypes, SequenceNotStr[FileTypes]], prompt: str, stream: Literal[True], background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, @@ -347,7 +347,7 @@ def edit( def edit( self, *, - image: Union[FileTypes, List[FileTypes]], + image: Union[FileTypes, SequenceNotStr[FileTypes]], prompt: str, stream: bool, background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, @@ -460,7 +460,7 @@ def edit( def edit( self, *, - image: Union[FileTypes, List[FileTypes]], + image: Union[FileTypes, SequenceNotStr[FileTypes]], prompt: str, background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, input_fidelity: Optional[Literal["high", "low"]] | NotGiven = NOT_GIVEN, @@ -1009,7 +1009,7 @@ async def create_variation( async def edit( self, *, - image: Union[FileTypes, List[FileTypes]], + image: Union[FileTypes, SequenceNotStr[FileTypes]], prompt: str, background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, input_fidelity: Optional[Literal["high", "low"]] | NotGiven = NOT_GIVEN, @@ -1122,7 +1122,7 @@ async def edit( async def edit( self, *, - image: Union[FileTypes, List[FileTypes]], + image: Union[FileTypes, SequenceNotStr[FileTypes]], prompt: str, stream: Literal[True], background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, @@ -1235,7 +1235,7 @@ async def edit( async def edit( self, *, - image: Union[FileTypes, List[FileTypes]], + image: Union[FileTypes, SequenceNotStr[FileTypes]], prompt: str, stream: bool, background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, @@ -1348,7 +1348,7 @@ async def edit( async def edit( self, *, - image: Union[FileTypes, List[FileTypes]], + image: Union[FileTypes, SequenceNotStr[FileTypes]], prompt: str, background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, input_fidelity: Optional[Literal["high", "low"]] | NotGiven = NOT_GIVEN, diff --git a/src/openai/resources/moderations.py b/src/openai/resources/moderations.py index f7a8b52c23..91c0df4358 100644 --- a/src/openai/resources/moderations.py +++ b/src/openai/resources/moderations.py @@ -2,13 +2,13 @@ from __future__ import annotations -from typing import List, Union, Iterable +from typing import Union, Iterable import httpx from .. import _legacy_response from ..types import moderation_create_params -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr from .._utils import maybe_transform, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource @@ -44,7 +44,7 @@ def with_streaming_response(self) -> ModerationsWithStreamingResponse: def create( self, *, - input: Union[str, List[str], Iterable[ModerationMultiModalInputParam]], + input: Union[str, SequenceNotStr[str], Iterable[ModerationMultiModalInputParam]], model: Union[str, ModerationModel] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -114,7 +114,7 @@ def with_streaming_response(self) -> AsyncModerationsWithStreamingResponse: async def create( self, *, - input: Union[str, List[str], Iterable[ModerationMultiModalInputParam]], + input: Union[str, SequenceNotStr[str], Iterable[ModerationMultiModalInputParam]], model: Union[str, ModerationModel] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. diff --git a/src/openai/resources/uploads/uploads.py b/src/openai/resources/uploads/uploads.py index 125a45e33c..c1dd4ec7c7 100644 --- a/src/openai/resources/uploads/uploads.py +++ b/src/openai/resources/uploads/uploads.py @@ -8,7 +8,6 @@ import builtins from typing import List, overload from pathlib import Path - import anyio import httpx @@ -22,7 +21,7 @@ AsyncPartsWithStreamingResponse, ) from ...types import FilePurpose, upload_create_params, upload_complete_params -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr from ..._utils import maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource @@ -281,7 +280,7 @@ def complete( self, upload_id: str, *, - part_ids: List[str], + part_ids: SequenceNotStr[str], md5: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -589,7 +588,7 @@ async def complete( self, upload_id: str, *, - part_ids: List[str], + part_ids: SequenceNotStr[str], md5: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. diff --git a/src/openai/resources/vector_stores/file_batches.py b/src/openai/resources/vector_stores/file_batches.py index 4dd4430b71..5c1470b3c3 100644 --- a/src/openai/resources/vector_stores/file_batches.py +++ b/src/openai/resources/vector_stores/file_batches.py @@ -3,7 +3,7 @@ from __future__ import annotations import asyncio -from typing import Dict, List, Iterable, Optional +from typing import Dict, Iterable, Optional from typing_extensions import Union, Literal from concurrent.futures import Future, ThreadPoolExecutor, as_completed @@ -12,7 +12,7 @@ from ... import _legacy_response from ...types import FileChunkingStrategyParam -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven, FileTypes +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven, FileTypes, SequenceNotStr from ..._utils import is_given, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource @@ -52,7 +52,7 @@ def create( self, vector_store_id: str, *, - file_ids: List[str], + file_ids: SequenceNotStr[str], attributes: Optional[Dict[str, Union[str, float, bool]]] | NotGiven = NOT_GIVEN, chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -389,7 +389,7 @@ async def create( self, vector_store_id: str, *, - file_ids: List[str], + file_ids: SequenceNotStr[str], attributes: Optional[Dict[str, Union[str, float, bool]]] | NotGiven = NOT_GIVEN, chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. diff --git a/src/openai/resources/vector_stores/vector_stores.py b/src/openai/resources/vector_stores/vector_stores.py index 9fc17b183b..4f211ea25a 100644 --- a/src/openai/resources/vector_stores/vector_stores.py +++ b/src/openai/resources/vector_stores/vector_stores.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import List, Union, Optional +from typing import Union, Optional from typing_extensions import Literal import httpx @@ -23,7 +23,7 @@ vector_store_search_params, vector_store_update_params, ) -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr from ..._utils import maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource @@ -80,7 +80,7 @@ def create( *, chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, expires_after: vector_store_create_params.ExpiresAfter | NotGiven = NOT_GIVEN, - file_ids: List[str] | NotGiven = NOT_GIVEN, + file_ids: SequenceNotStr[str] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, name: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -332,7 +332,7 @@ def search( self, vector_store_id: str, *, - query: Union[str, List[str]], + query: Union[str, SequenceNotStr[str]], filters: vector_store_search_params.Filters | NotGiven = NOT_GIVEN, max_num_results: int | NotGiven = NOT_GIVEN, ranking_options: vector_store_search_params.RankingOptions | NotGiven = NOT_GIVEN, @@ -425,7 +425,7 @@ async def create( *, chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, expires_after: vector_store_create_params.ExpiresAfter | NotGiven = NOT_GIVEN, - file_ids: List[str] | NotGiven = NOT_GIVEN, + file_ids: SequenceNotStr[str] | NotGiven = NOT_GIVEN, metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, name: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -677,7 +677,7 @@ def search( self, vector_store_id: str, *, - query: Union[str, List[str]], + query: Union[str, SequenceNotStr[str]], filters: vector_store_search_params.Filters | NotGiven = NOT_GIVEN, max_num_results: int | NotGiven = NOT_GIVEN, ranking_options: vector_store_search_params.RankingOptions | NotGiven = NOT_GIVEN, diff --git a/src/openai/types/beta/assistant_create_params.py b/src/openai/types/beta/assistant_create_params.py index 4b03dc0ea6..07f8f28f02 100644 --- a/src/openai/types/beta/assistant_create_params.py +++ b/src/openai/types/beta/assistant_create_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import List, Union, Iterable, Optional +from typing import Union, Iterable, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict +from ..._types import SequenceNotStr from ..shared.chat_model import ChatModel from .assistant_tool_param import AssistantToolParam from ..shared_params.metadata import Metadata @@ -123,7 +124,7 @@ class AssistantCreateParams(TypedDict, total=False): class ToolResourcesCodeInterpreter(TypedDict, total=False): - file_ids: List[str] + file_ids: SequenceNotStr[str] """ A list of [file](https://platform.openai.com/docs/api-reference/files) IDs made available to the `code_interpreter` tool. There can be a maximum of 20 files @@ -170,7 +171,7 @@ class ToolResourcesFileSearchVectorStore(TypedDict, total=False): If not set, will use the `auto` strategy. """ - file_ids: List[str] + file_ids: SequenceNotStr[str] """ A list of [file](https://platform.openai.com/docs/api-reference/files) IDs to add to the vector store. There can be a maximum of 10000 files in a vector @@ -189,7 +190,7 @@ class ToolResourcesFileSearchVectorStore(TypedDict, total=False): class ToolResourcesFileSearch(TypedDict, total=False): - vector_store_ids: List[str] + vector_store_ids: SequenceNotStr[str] """ The [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) diff --git a/src/openai/types/beta/assistant_update_params.py b/src/openai/types/beta/assistant_update_params.py index e032554db8..45d9f984b2 100644 --- a/src/openai/types/beta/assistant_update_params.py +++ b/src/openai/types/beta/assistant_update_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import List, Union, Iterable, Optional +from typing import Union, Iterable, Optional from typing_extensions import Literal, TypedDict +from ..._types import SequenceNotStr from .assistant_tool_param import AssistantToolParam from ..shared_params.metadata import Metadata from ..shared.reasoning_effort import ReasoningEffort @@ -158,7 +159,7 @@ class AssistantUpdateParams(TypedDict, total=False): class ToolResourcesCodeInterpreter(TypedDict, total=False): - file_ids: List[str] + file_ids: SequenceNotStr[str] """ Overrides the list of [file](https://platform.openai.com/docs/api-reference/files) IDs made available @@ -168,7 +169,7 @@ class ToolResourcesCodeInterpreter(TypedDict, total=False): class ToolResourcesFileSearch(TypedDict, total=False): - vector_store_ids: List[str] + vector_store_ids: SequenceNotStr[str] """ Overrides the [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) diff --git a/src/openai/types/beta/thread_create_and_run_params.py b/src/openai/types/beta/thread_create_and_run_params.py index ad148d693a..734e5e2a4e 100644 --- a/src/openai/types/beta/thread_create_and_run_params.py +++ b/src/openai/types/beta/thread_create_and_run_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import List, Union, Iterable, Optional +from typing import Union, Iterable, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict +from ..._types import SequenceNotStr from ..shared.chat_model import ChatModel from .assistant_tool_param import AssistantToolParam from ..shared_params.metadata import Metadata @@ -217,7 +218,7 @@ class ThreadMessage(TypedDict, total=False): class ThreadToolResourcesCodeInterpreter(TypedDict, total=False): - file_ids: List[str] + file_ids: SequenceNotStr[str] """ A list of [file](https://platform.openai.com/docs/api-reference/files) IDs made available to the `code_interpreter` tool. There can be a maximum of 20 files @@ -265,7 +266,7 @@ class ThreadToolResourcesFileSearchVectorStore(TypedDict, total=False): If not set, will use the `auto` strategy. """ - file_ids: List[str] + file_ids: SequenceNotStr[str] """ A list of [file](https://platform.openai.com/docs/api-reference/files) IDs to add to the vector store. There can be a maximum of 10000 files in a vector @@ -284,7 +285,7 @@ class ThreadToolResourcesFileSearchVectorStore(TypedDict, total=False): class ThreadToolResourcesFileSearch(TypedDict, total=False): - vector_store_ids: List[str] + vector_store_ids: SequenceNotStr[str] """ The [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) @@ -334,7 +335,7 @@ class Thread(TypedDict, total=False): class ToolResourcesCodeInterpreter(TypedDict, total=False): - file_ids: List[str] + file_ids: SequenceNotStr[str] """ A list of [file](https://platform.openai.com/docs/api-reference/files) IDs made available to the `code_interpreter` tool. There can be a maximum of 20 files @@ -343,7 +344,7 @@ class ToolResourcesCodeInterpreter(TypedDict, total=False): class ToolResourcesFileSearch(TypedDict, total=False): - vector_store_ids: List[str] + vector_store_ids: SequenceNotStr[str] """ The ID of the [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) diff --git a/src/openai/types/beta/thread_create_params.py b/src/openai/types/beta/thread_create_params.py index ec1ccf19a6..8fd9f38df7 100644 --- a/src/openai/types/beta/thread_create_params.py +++ b/src/openai/types/beta/thread_create_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import List, Union, Iterable, Optional +from typing import Union, Iterable, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict +from ..._types import SequenceNotStr from ..shared_params.metadata import Metadata from .code_interpreter_tool_param import CodeInterpreterToolParam from .threads.message_content_part_param import MessageContentPartParam @@ -96,7 +97,7 @@ class Message(TypedDict, total=False): class ToolResourcesCodeInterpreter(TypedDict, total=False): - file_ids: List[str] + file_ids: SequenceNotStr[str] """ A list of [file](https://platform.openai.com/docs/api-reference/files) IDs made available to the `code_interpreter` tool. There can be a maximum of 20 files @@ -143,7 +144,7 @@ class ToolResourcesFileSearchVectorStore(TypedDict, total=False): If not set, will use the `auto` strategy. """ - file_ids: List[str] + file_ids: SequenceNotStr[str] """ A list of [file](https://platform.openai.com/docs/api-reference/files) IDs to add to the vector store. There can be a maximum of 10000 files in a vector @@ -162,7 +163,7 @@ class ToolResourcesFileSearchVectorStore(TypedDict, total=False): class ToolResourcesFileSearch(TypedDict, total=False): - vector_store_ids: List[str] + vector_store_ids: SequenceNotStr[str] """ The [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) diff --git a/src/openai/types/beta/thread_update_params.py b/src/openai/types/beta/thread_update_params.py index b47ea8f3b0..464ea8d7eb 100644 --- a/src/openai/types/beta/thread_update_params.py +++ b/src/openai/types/beta/thread_update_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import List, Optional +from typing import Optional from typing_extensions import TypedDict +from ..._types import SequenceNotStr from ..shared_params.metadata import Metadata __all__ = ["ThreadUpdateParams", "ToolResources", "ToolResourcesCodeInterpreter", "ToolResourcesFileSearch"] @@ -31,7 +32,7 @@ class ThreadUpdateParams(TypedDict, total=False): class ToolResourcesCodeInterpreter(TypedDict, total=False): - file_ids: List[str] + file_ids: SequenceNotStr[str] """ A list of [file](https://platform.openai.com/docs/api-reference/files) IDs made available to the `code_interpreter` tool. There can be a maximum of 20 files @@ -40,7 +41,7 @@ class ToolResourcesCodeInterpreter(TypedDict, total=False): class ToolResourcesFileSearch(TypedDict, total=False): - vector_store_ids: List[str] + vector_store_ids: SequenceNotStr[str] """ The [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) diff --git a/src/openai/types/chat/completion_create_params.py b/src/openai/types/chat/completion_create_params.py index da37ee4c13..2ae81dfbc2 100644 --- a/src/openai/types/chat/completion_create_params.py +++ b/src/openai/types/chat/completion_create_params.py @@ -5,6 +5,7 @@ from typing import Dict, List, Union, Iterable, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict +from ..._types import SequenceNotStr from ..shared.chat_model import ChatModel from ..shared_params.metadata import Metadata from ..shared.reasoning_effort import ReasoningEffort @@ -243,7 +244,7 @@ class CompletionCreateParamsBase(TypedDict, total=False): parameter. """ - stop: Union[Optional[str], List[str], None] + stop: Union[Optional[str], SequenceNotStr[str], None] """Not supported with latest reasoning models `o3` and `o4-mini`. Up to 4 sequences where the API will stop generating further tokens. The diff --git a/src/openai/types/completion_create_params.py b/src/openai/types/completion_create_params.py index 6ae20cff83..f9beb9afc7 100644 --- a/src/openai/types/completion_create_params.py +++ b/src/openai/types/completion_create_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import Dict, List, Union, Iterable, Optional +from typing import Dict, Union, Iterable, Optional from typing_extensions import Literal, Required, TypedDict +from .._types import SequenceNotStr from .chat.chat_completion_stream_options_param import ChatCompletionStreamOptionsParam __all__ = ["CompletionCreateParamsBase", "CompletionCreateParamsNonStreaming", "CompletionCreateParamsStreaming"] @@ -21,7 +22,7 @@ class CompletionCreateParamsBase(TypedDict, total=False): them. """ - prompt: Required[Union[str, List[str], Iterable[int], Iterable[Iterable[int]], None]] + prompt: Required[Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]], None]] """ The prompt(s) to generate completions for, encoded as a string, array of strings, array of tokens, or array of token arrays. @@ -119,7 +120,7 @@ class CompletionCreateParamsBase(TypedDict, total=False): response parameter to monitor changes in the backend. """ - stop: Union[Optional[str], List[str], None] + stop: Union[Optional[str], SequenceNotStr[str], None] """Not supported with latest reasoning models `o3` and `o4-mini`. Up to 4 sequences where the API will stop generating further tokens. The diff --git a/src/openai/types/container_create_params.py b/src/openai/types/container_create_params.py index bd27334933..01a48ac410 100644 --- a/src/openai/types/container_create_params.py +++ b/src/openai/types/container_create_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import List from typing_extensions import Literal, Required, TypedDict +from .._types import SequenceNotStr + __all__ = ["ContainerCreateParams", "ExpiresAfter"] @@ -15,7 +16,7 @@ class ContainerCreateParams(TypedDict, total=False): expires_after: ExpiresAfter """Container expiration time in seconds relative to the 'anchor' time.""" - file_ids: List[str] + file_ids: SequenceNotStr[str] """IDs of files to copy to the container.""" diff --git a/src/openai/types/embedding_create_params.py b/src/openai/types/embedding_create_params.py index 94edce10a4..ab3e877964 100644 --- a/src/openai/types/embedding_create_params.py +++ b/src/openai/types/embedding_create_params.py @@ -2,16 +2,17 @@ from __future__ import annotations -from typing import List, Union, Iterable +from typing import Union, Iterable from typing_extensions import Literal, Required, TypedDict +from .._types import SequenceNotStr from .embedding_model import EmbeddingModel __all__ = ["EmbeddingCreateParams"] class EmbeddingCreateParams(TypedDict, total=False): - input: Required[Union[str, List[str], Iterable[int], Iterable[Iterable[int]]]] + input: Required[Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]]]] """Input text to embed, encoded as a string or array of tokens. To embed multiple inputs in a single request, pass an array of strings or array diff --git a/src/openai/types/eval_create_params.py b/src/openai/types/eval_create_params.py index 9674785701..016f705dd7 100644 --- a/src/openai/types/eval_create_params.py +++ b/src/openai/types/eval_create_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import Dict, List, Union, Iterable, Optional +from typing import Dict, Union, Iterable, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict +from .._types import SequenceNotStr from .shared_params.metadata import Metadata from .graders.python_grader_param import PythonGraderParam from .graders.score_model_grader_param import ScoreModelGraderParam @@ -159,7 +160,7 @@ class TestingCriterionLabelModel(TypedDict, total=False): May include variable references to the `item` namespace, ie {{item.name}}. """ - labels: Required[List[str]] + labels: Required[SequenceNotStr[str]] """The labels to classify to each item in the evaluation.""" model: Required[str] @@ -168,7 +169,7 @@ class TestingCriterionLabelModel(TypedDict, total=False): name: Required[str] """The name of the grader.""" - passing_labels: Required[List[str]] + passing_labels: Required[SequenceNotStr[str]] """The labels that indicate a passing result. Must be a subset of labels.""" type: Required[Literal["label_model"]] diff --git a/src/openai/types/evals/run_create_params.py b/src/openai/types/evals/run_create_params.py index 1622b00eb7..faf06a2f58 100644 --- a/src/openai/types/evals/run_create_params.py +++ b/src/openai/types/evals/run_create_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import Dict, List, Union, Iterable, Optional +from typing import Dict, Union, Iterable, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict +from ..._types import SequenceNotStr from ..responses.tool_param import ToolParam from ..shared_params.metadata import Metadata from ..shared.reasoning_effort import ReasoningEffort @@ -119,13 +120,13 @@ class DataSourceCreateEvalResponsesRunDataSourceSourceResponses(TypedDict, total temperature: Optional[float] """Sampling temperature. This is a query parameter used to select responses.""" - tools: Optional[List[str]] + tools: Optional[SequenceNotStr[str]] """List of tool names. This is a query parameter used to select responses.""" top_p: Optional[float] """Nucleus sampling parameter. This is a query parameter used to select responses.""" - users: Optional[List[str]] + users: Optional[SequenceNotStr[str]] """List of user identifiers. This is a query parameter used to select responses.""" diff --git a/src/openai/types/fine_tuning/checkpoints/permission_create_params.py b/src/openai/types/fine_tuning/checkpoints/permission_create_params.py index 92f98f21b9..e7cf4e4ee4 100644 --- a/src/openai/types/fine_tuning/checkpoints/permission_create_params.py +++ b/src/openai/types/fine_tuning/checkpoints/permission_create_params.py @@ -2,12 +2,13 @@ from __future__ import annotations -from typing import List from typing_extensions import Required, TypedDict +from ...._types import SequenceNotStr + __all__ = ["PermissionCreateParams"] class PermissionCreateParams(TypedDict, total=False): - project_ids: Required[List[str]] + project_ids: Required[SequenceNotStr[str]] """The project identifiers to grant access to.""" diff --git a/src/openai/types/fine_tuning/job_create_params.py b/src/openai/types/fine_tuning/job_create_params.py index 5514db1ed1..351d4e0e1b 100644 --- a/src/openai/types/fine_tuning/job_create_params.py +++ b/src/openai/types/fine_tuning/job_create_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import List, Union, Iterable, Optional +from typing import Union, Iterable, Optional from typing_extensions import Literal, Required, TypedDict +from ..._types import SequenceNotStr from .dpo_method_param import DpoMethodParam from ..shared_params.metadata import Metadata from .supervised_method_param import SupervisedMethodParam @@ -137,7 +138,7 @@ class IntegrationWandb(TypedDict, total=False): If not set, we will use the Job ID as the name. """ - tags: List[str] + tags: SequenceNotStr[str] """A list of tags to be attached to the newly created run. These tags are passed through directly to WandB. Some default tags are generated diff --git a/src/openai/types/graders/label_model_grader_param.py b/src/openai/types/graders/label_model_grader_param.py index 941c8a1bd0..57f7885872 100644 --- a/src/openai/types/graders/label_model_grader_param.py +++ b/src/openai/types/graders/label_model_grader_param.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import List, Union, Iterable +from typing import Union, Iterable from typing_extensions import Literal, Required, TypeAlias, TypedDict +from ..._types import SequenceNotStr from ..responses.response_input_text_param import ResponseInputTextParam __all__ = ["LabelModelGraderParam", "Input", "InputContent", "InputContentOutputText", "InputContentInputImage"] @@ -54,7 +55,7 @@ class Input(TypedDict, total=False): class LabelModelGraderParam(TypedDict, total=False): input: Required[Iterable[Input]] - labels: Required[List[str]] + labels: Required[SequenceNotStr[str]] """The labels to assign to each item in the evaluation.""" model: Required[str] @@ -63,7 +64,7 @@ class LabelModelGraderParam(TypedDict, total=False): name: Required[str] """The name of the grader.""" - passing_labels: Required[List[str]] + passing_labels: Required[SequenceNotStr[str]] """The labels that indicate a passing result. Must be a subset of labels.""" type: Required[Literal["label_model"]] diff --git a/src/openai/types/image_edit_params.py b/src/openai/types/image_edit_params.py index c0481012e4..065d9789fc 100644 --- a/src/openai/types/image_edit_params.py +++ b/src/openai/types/image_edit_params.py @@ -2,17 +2,17 @@ from __future__ import annotations -from typing import List, Union, Optional +from typing import Union, Optional from typing_extensions import Literal, Required, TypedDict -from .._types import FileTypes +from .._types import FileTypes, SequenceNotStr from .image_model import ImageModel __all__ = ["ImageEditParamsBase", "ImageEditParamsNonStreaming", "ImageEditParamsStreaming"] class ImageEditParamsBase(TypedDict, total=False): - image: Required[Union[FileTypes, List[FileTypes]]] + image: Required[Union[FileTypes, SequenceNotStr[FileTypes]]] """The image(s) to edit. Must be a supported image file or an array of images. For `gpt-image-1`, each image should be a `png`, `webp`, or `jpg` file less than diff --git a/src/openai/types/moderation_create_params.py b/src/openai/types/moderation_create_params.py index 3ea2f3cd88..65d9b7e561 100644 --- a/src/openai/types/moderation_create_params.py +++ b/src/openai/types/moderation_create_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import List, Union, Iterable +from typing import Union, Iterable from typing_extensions import Required, TypedDict +from .._types import SequenceNotStr from .moderation_model import ModerationModel from .moderation_multi_modal_input_param import ModerationMultiModalInputParam @@ -12,7 +13,7 @@ class ModerationCreateParams(TypedDict, total=False): - input: Required[Union[str, List[str], Iterable[ModerationMultiModalInputParam]]] + input: Required[Union[str, SequenceNotStr[str], Iterable[ModerationMultiModalInputParam]]] """Input (or inputs) to classify. Can be a single string, an array of strings, or an array of multi-modal input diff --git a/src/openai/types/realtime/realtime_tools_config_param.py b/src/openai/types/realtime/realtime_tools_config_param.py index 12af65c871..ea4b8c4d43 100644 --- a/src/openai/types/realtime/realtime_tools_config_param.py +++ b/src/openai/types/realtime/realtime_tools_config_param.py @@ -5,6 +5,8 @@ from typing import Dict, List, Union, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict +from ..._types import SequenceNotStr + __all__ = [ "RealtimeToolsConfigParam", "RealtimeToolsConfigUnionParam", @@ -45,11 +47,11 @@ class McpAllowedToolsMcpToolFilter(TypedDict, total=False): it will match this filter. """ - tool_names: List[str] + tool_names: SequenceNotStr[str] """List of allowed tool names.""" -McpAllowedTools: TypeAlias = Union[List[str], McpAllowedToolsMcpToolFilter] +McpAllowedTools: TypeAlias = Union[SequenceNotStr[str], McpAllowedToolsMcpToolFilter] class McpRequireApprovalMcpToolApprovalFilterAlways(TypedDict, total=False): @@ -61,7 +63,7 @@ class McpRequireApprovalMcpToolApprovalFilterAlways(TypedDict, total=False): it will match this filter. """ - tool_names: List[str] + tool_names: SequenceNotStr[str] """List of allowed tool names.""" @@ -74,7 +76,7 @@ class McpRequireApprovalMcpToolApprovalFilterNever(TypedDict, total=False): it will match this filter. """ - tool_names: List[str] + tool_names: SequenceNotStr[str] """List of allowed tool names.""" diff --git a/src/openai/types/realtime/realtime_tools_config_union_param.py b/src/openai/types/realtime/realtime_tools_config_union_param.py index 1b9f18536c..21b4d07752 100644 --- a/src/openai/types/realtime/realtime_tools_config_union_param.py +++ b/src/openai/types/realtime/realtime_tools_config_union_param.py @@ -2,9 +2,11 @@ from __future__ import annotations -from typing import Dict, List, Union, Optional +from typing import Dict, Union, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict +from ..._types import SequenceNotStr + __all__ = [ "RealtimeToolsConfigUnionParam", "Function", @@ -44,11 +46,11 @@ class McpAllowedToolsMcpToolFilter(TypedDict, total=False): it will match this filter. """ - tool_names: List[str] + tool_names: SequenceNotStr[str] """List of allowed tool names.""" -McpAllowedTools: TypeAlias = Union[List[str], McpAllowedToolsMcpToolFilter] +McpAllowedTools: TypeAlias = Union[SequenceNotStr[str], McpAllowedToolsMcpToolFilter] class McpRequireApprovalMcpToolApprovalFilterAlways(TypedDict, total=False): @@ -60,7 +62,7 @@ class McpRequireApprovalMcpToolApprovalFilterAlways(TypedDict, total=False): it will match this filter. """ - tool_names: List[str] + tool_names: SequenceNotStr[str] """List of allowed tool names.""" @@ -73,7 +75,7 @@ class McpRequireApprovalMcpToolApprovalFilterNever(TypedDict, total=False): it will match this filter. """ - tool_names: List[str] + tool_names: SequenceNotStr[str] """List of allowed tool names.""" diff --git a/src/openai/types/responses/file_search_tool_param.py b/src/openai/types/responses/file_search_tool_param.py index 2851fae460..c7641c1b86 100644 --- a/src/openai/types/responses/file_search_tool_param.py +++ b/src/openai/types/responses/file_search_tool_param.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import List, Union, Optional +from typing import Union, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict +from ..._types import SequenceNotStr from ..shared_params.compound_filter import CompoundFilter from ..shared_params.comparison_filter import ComparisonFilter @@ -29,7 +30,7 @@ class FileSearchToolParam(TypedDict, total=False): type: Required[Literal["file_search"]] """The type of the file search tool. Always `file_search`.""" - vector_store_ids: Required[List[str]] + vector_store_ids: Required[SequenceNotStr[str]] """The IDs of the vector stores to search.""" filters: Optional[Filters] diff --git a/src/openai/types/responses/response_computer_tool_call_param.py b/src/openai/types/responses/response_computer_tool_call_param.py index d4ef56ab5c..0be63db2fe 100644 --- a/src/openai/types/responses/response_computer_tool_call_param.py +++ b/src/openai/types/responses/response_computer_tool_call_param.py @@ -2,9 +2,11 @@ from __future__ import annotations -from typing import List, Union, Iterable +from typing import Union, Iterable from typing_extensions import Literal, Required, TypeAlias, TypedDict +from ..._types import SequenceNotStr + __all__ = [ "ResponseComputerToolCallParam", "Action", @@ -86,7 +88,7 @@ class ActionDrag(TypedDict, total=False): class ActionKeypress(TypedDict, total=False): - keys: Required[List[str]] + keys: Required[SequenceNotStr[str]] """The combination of keys the model is requesting to be pressed. This is an array of strings, each representing a key. diff --git a/src/openai/types/responses/response_file_search_tool_call_param.py b/src/openai/types/responses/response_file_search_tool_call_param.py index 9a4177cf81..4903dca4fb 100644 --- a/src/openai/types/responses/response_file_search_tool_call_param.py +++ b/src/openai/types/responses/response_file_search_tool_call_param.py @@ -2,9 +2,11 @@ from __future__ import annotations -from typing import Dict, List, Union, Iterable, Optional +from typing import Dict, Union, Iterable, Optional from typing_extensions import Literal, Required, TypedDict +from ..._types import SequenceNotStr + __all__ = ["ResponseFileSearchToolCallParam", "Result"] @@ -35,7 +37,7 @@ class ResponseFileSearchToolCallParam(TypedDict, total=False): id: Required[str] """The unique ID of the file search tool call.""" - queries: Required[List[str]] + queries: Required[SequenceNotStr[str]] """The queries used to search for files.""" status: Required[Literal["in_progress", "searching", "completed", "incomplete", "failed"]] diff --git a/src/openai/types/responses/response_input_item_param.py b/src/openai/types/responses/response_input_item_param.py index 0d5dbda85c..5ad83fc03a 100644 --- a/src/openai/types/responses/response_input_item_param.py +++ b/src/openai/types/responses/response_input_item_param.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import Dict, List, Union, Iterable, Optional +from typing import Dict, Union, Iterable, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict +from ..._types import SequenceNotStr from .easy_input_message_param import EasyInputMessageParam from .response_output_message_param import ResponseOutputMessageParam from .response_reasoning_item_param import ResponseReasoningItemParam @@ -135,7 +136,7 @@ class ImageGenerationCall(TypedDict, total=False): class LocalShellCallAction(TypedDict, total=False): - command: Required[List[str]] + command: Required[SequenceNotStr[str]] """The command to run.""" env: Required[Dict[str, str]] diff --git a/src/openai/types/responses/response_input_param.py b/src/openai/types/responses/response_input_param.py index 6ff36a4238..73eac62428 100644 --- a/src/openai/types/responses/response_input_param.py +++ b/src/openai/types/responses/response_input_param.py @@ -5,6 +5,7 @@ from typing import Dict, List, Union, Iterable, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict +from ..._types import SequenceNotStr from .easy_input_message_param import EasyInputMessageParam from .response_output_message_param import ResponseOutputMessageParam from .response_reasoning_item_param import ResponseReasoningItemParam @@ -136,7 +137,7 @@ class ImageGenerationCall(TypedDict, total=False): class LocalShellCallAction(TypedDict, total=False): - command: Required[List[str]] + command: Required[SequenceNotStr[str]] """The command to run.""" env: Required[Dict[str, str]] diff --git a/src/openai/types/responses/tool_param.py b/src/openai/types/responses/tool_param.py index def1f08094..fd916a2a81 100644 --- a/src/openai/types/responses/tool_param.py +++ b/src/openai/types/responses/tool_param.py @@ -2,10 +2,11 @@ from __future__ import annotations -from typing import Dict, List, Union, Optional +from typing import Dict, Union, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict from ..chat import ChatCompletionFunctionToolParam +from ..._types import SequenceNotStr from .custom_tool_param import CustomToolParam from .computer_tool_param import ComputerToolParam from .function_tool_param import FunctionToolParam @@ -40,11 +41,11 @@ class McpAllowedToolsMcpToolFilter(TypedDict, total=False): it will match this filter. """ - tool_names: List[str] + tool_names: SequenceNotStr[str] """List of allowed tool names.""" -McpAllowedTools: TypeAlias = Union[List[str], McpAllowedToolsMcpToolFilter] +McpAllowedTools: TypeAlias = Union[SequenceNotStr[str], McpAllowedToolsMcpToolFilter] class McpRequireApprovalMcpToolApprovalFilterAlways(TypedDict, total=False): @@ -56,7 +57,7 @@ class McpRequireApprovalMcpToolApprovalFilterAlways(TypedDict, total=False): it will match this filter. """ - tool_names: List[str] + tool_names: SequenceNotStr[str] """List of allowed tool names.""" @@ -69,7 +70,7 @@ class McpRequireApprovalMcpToolApprovalFilterNever(TypedDict, total=False): it will match this filter. """ - tool_names: List[str] + tool_names: SequenceNotStr[str] """List of allowed tool names.""" @@ -152,7 +153,7 @@ class CodeInterpreterContainerCodeInterpreterToolAuto(TypedDict, total=False): type: Required[Literal["auto"]] """Always `auto`.""" - file_ids: List[str] + file_ids: SequenceNotStr[str] """An optional list of uploaded files to make available to your code.""" diff --git a/src/openai/types/responses/web_search_tool_param.py b/src/openai/types/responses/web_search_tool_param.py index 17a382456b..7fa19e9c23 100644 --- a/src/openai/types/responses/web_search_tool_param.py +++ b/src/openai/types/responses/web_search_tool_param.py @@ -2,14 +2,16 @@ from __future__ import annotations -from typing import List, Optional +from typing import Optional from typing_extensions import Literal, Required, TypedDict +from ..._types import SequenceNotStr + __all__ = ["WebSearchToolParam", "Filters", "UserLocation"] class Filters(TypedDict, total=False): - allowed_domains: Optional[List[str]] + allowed_domains: Optional[SequenceNotStr[str]] """Allowed domains for the search. If not provided, all domains are allowed. Subdomains of the provided domains are diff --git a/src/openai/types/upload_complete_params.py b/src/openai/types/upload_complete_params.py index cce568d5c6..846a241dc7 100644 --- a/src/openai/types/upload_complete_params.py +++ b/src/openai/types/upload_complete_params.py @@ -2,14 +2,15 @@ from __future__ import annotations -from typing import List from typing_extensions import Required, TypedDict +from .._types import SequenceNotStr + __all__ = ["UploadCompleteParams"] class UploadCompleteParams(TypedDict, total=False): - part_ids: Required[List[str]] + part_ids: Required[SequenceNotStr[str]] """The ordered list of Part IDs.""" md5: str diff --git a/src/openai/types/vector_store_create_params.py b/src/openai/types/vector_store_create_params.py index 365d0936b1..945a9886a3 100644 --- a/src/openai/types/vector_store_create_params.py +++ b/src/openai/types/vector_store_create_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import List, Optional +from typing import Optional from typing_extensions import Literal, Required, TypedDict +from .._types import SequenceNotStr from .shared_params.metadata import Metadata from .file_chunking_strategy_param import FileChunkingStrategyParam @@ -22,7 +23,7 @@ class VectorStoreCreateParams(TypedDict, total=False): expires_after: ExpiresAfter """The expiration policy for a vector store.""" - file_ids: List[str] + file_ids: SequenceNotStr[str] """ A list of [File](https://platform.openai.com/docs/api-reference/files) IDs that the vector store should use. Useful for tools like `file_search` that can access diff --git a/src/openai/types/vector_store_search_params.py b/src/openai/types/vector_store_search_params.py index 973c49ff5a..8b7b13c4a1 100644 --- a/src/openai/types/vector_store_search_params.py +++ b/src/openai/types/vector_store_search_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import List, Union +from typing import Union from typing_extensions import Literal, Required, TypeAlias, TypedDict +from .._types import SequenceNotStr from .shared_params.compound_filter import CompoundFilter from .shared_params.comparison_filter import ComparisonFilter @@ -12,7 +13,7 @@ class VectorStoreSearchParams(TypedDict, total=False): - query: Required[Union[str, List[str]]] + query: Required[Union[str, SequenceNotStr[str]]] """A query string for a search""" filters: Filters diff --git a/src/openai/types/vector_stores/file_batch_create_params.py b/src/openai/types/vector_stores/file_batch_create_params.py index 1a470f757a..d8d7b44888 100644 --- a/src/openai/types/vector_stores/file_batch_create_params.py +++ b/src/openai/types/vector_stores/file_batch_create_params.py @@ -2,16 +2,17 @@ from __future__ import annotations -from typing import Dict, List, Union, Optional +from typing import Dict, Union, Optional from typing_extensions import Required, TypedDict +from ..._types import SequenceNotStr from ..file_chunking_strategy_param import FileChunkingStrategyParam __all__ = ["FileBatchCreateParams"] class FileBatchCreateParams(TypedDict, total=False): - file_ids: Required[List[str]] + file_ids: Required[SequenceNotStr[str]] """ A list of [File](https://platform.openai.com/docs/api-reference/files) IDs that the vector store should use. Useful for tools like `file_search` that can access From 56baf2d26179b670b560dedacbffcaf828e53a13 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Tue, 2 Sep 2025 16:20:22 +0100 Subject: [PATCH 473/769] chore: remove unused import --- src/openai/resources/uploads/uploads.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/openai/resources/uploads/uploads.py b/src/openai/resources/uploads/uploads.py index c1dd4ec7c7..8811bed48c 100644 --- a/src/openai/resources/uploads/uploads.py +++ b/src/openai/resources/uploads/uploads.py @@ -6,8 +6,9 @@ import os import logging import builtins -from typing import List, overload +from typing import overload from pathlib import Path + import anyio import httpx From 74d43eda0c295fbb931b589c02e078f50d92a82d Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Tue, 2 Sep 2025 17:46:20 +0100 Subject: [PATCH 474/769] fix(types): update some types to SequenceNotStr --- src/openai/resources/vector_stores/file_batches.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/openai/resources/vector_stores/file_batches.py b/src/openai/resources/vector_stores/file_batches.py index 5c1470b3c3..adf399d8de 100644 --- a/src/openai/resources/vector_stores/file_batches.py +++ b/src/openai/resources/vector_stores/file_batches.py @@ -186,7 +186,7 @@ def create_and_poll( self, vector_store_id: str, *, - file_ids: List[str], + file_ids: SequenceNotStr[str], poll_interval_ms: int | NotGiven = NOT_GIVEN, chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, ) -> VectorStoreFileBatch: @@ -320,7 +320,7 @@ def upload_and_poll( *, files: Iterable[FileTypes], max_concurrency: int = 5, - file_ids: List[str] = [], + file_ids: SequenceNotStr[str] = [], poll_interval_ms: int | NotGiven = NOT_GIVEN, chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, ) -> VectorStoreFileBatch: @@ -523,7 +523,7 @@ async def create_and_poll( self, vector_store_id: str, *, - file_ids: List[str], + file_ids: SequenceNotStr[str], poll_interval_ms: int | NotGiven = NOT_GIVEN, chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, ) -> VectorStoreFileBatch: @@ -657,7 +657,7 @@ async def upload_and_poll( *, files: Iterable[FileTypes], max_concurrency: int = 5, - file_ids: List[str] = [], + file_ids: SequenceNotStr[str] = [], poll_interval_ms: int | NotGiven = NOT_GIVEN, chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, ) -> VectorStoreFileBatch: From afe0aebc00323704eb0066e2f2df16d7ba9926f7 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Tue, 2 Sep 2025 17:48:04 +0100 Subject: [PATCH 475/769] fix(types): update more types to use SequenceNotStr --- src/openai/resources/chat/completions/completions.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index 14a755a50e..168cf04dbc 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -106,7 +106,7 @@ def parse( safety_identifier: str | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, + stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -1400,7 +1400,7 @@ def stream( safety_identifier: str | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, + stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -1542,7 +1542,7 @@ async def parse( safety_identifier: str | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, + stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -2836,7 +2836,7 @@ def stream( safety_identifier: str | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, + stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, store: Optional[bool] | NotGiven = NOT_GIVEN, stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, From f4458bc734db33f33a432fa62d8ef490e68d76db Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 2 Sep 2025 16:49:05 +0000 Subject: [PATCH 476/769] release: 1.104.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 19 +++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 0a5613fed8..2e568a21c7 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.103.0" + ".": "1.104.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 6595e5246b..6116a79d30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## 1.104.0 (2025-09-02) + +Full Changelog: [v1.103.0...v1.104.0](https://github.com/openai/openai-python/compare/v1.103.0...v1.104.0) + +### Features + +* **types:** replace List[str] with SequenceNotStr in params ([bc00bda](https://github.com/openai/openai-python/commit/bc00bda880a80089be8a1758c016266ca72dab2c)) + + +### Bug Fixes + +* **types:** update more types to use SequenceNotStr ([cff135c](https://github.com/openai/openai-python/commit/cff135cb7059ef1bf8f9b101a83529fc0cee37c4)) +* **types:** update some types to SequenceNotStr ([03f8b88](https://github.com/openai/openai-python/commit/03f8b88a0d428b74a7822e678a60d0ef106ea961)) + + +### Chores + +* remove unused import ([ac7795b](https://github.com/openai/openai-python/commit/ac7795b50d956ec5dc468302e8e3579a0467edcb)) + ## 1.103.0 (2025-09-02) Full Changelog: [v1.102.0...v1.103.0](https://github.com/openai/openai-python/compare/v1.102.0...v1.103.0) diff --git a/pyproject.toml b/pyproject.toml index 309b0f5544..08a04d08d1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.103.0" +version = "1.104.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 313e60b0bf..46e82bb627 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.103.0" # x-release-please-version +__version__ = "1.104.0" # x-release-please-version From 3c1f55439e0c6afe358a5e2d4ccfca9516b667af Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 2 Sep 2025 19:55:13 +0000 Subject: [PATCH 477/769] chore(api): manual updates for ResponseInputAudio --- .stats.yml | 4 ++-- src/openai/resources/responses/responses.py | 12 +++++----- src/openai/types/eval_create_params.py | 2 ++ ...create_eval_completions_run_data_source.py | 2 ++ ..._eval_completions_run_data_source_param.py | 2 ++ src/openai/types/evals/run_cancel_response.py | 2 ++ src/openai/types/evals/run_create_params.py | 2 ++ src/openai/types/evals/run_create_response.py | 2 ++ src/openai/types/evals/run_list_response.py | 2 ++ .../types/evals/run_retrieve_response.py | 2 ++ .../types/graders/label_model_grader.py | 5 ++++- .../types/graders/label_model_grader_param.py | 8 ++++++- .../types/graders/score_model_grader.py | 5 ++++- .../types/graders/score_model_grader_param.py | 8 ++++++- src/openai/types/responses/__init__.py | 2 ++ src/openai/types/responses/response.py | 2 +- .../types/responses/response_create_params.py | 2 +- .../types/responses/response_input_audio.py | 22 +++++++++++++++++++ .../responses/response_input_audio_param.py | 22 +++++++++++++++++++ .../types/responses/response_input_content.py | 4 +++- .../responses/response_input_content_param.py | 5 ++++- ...sponse_input_message_content_list_param.py | 5 ++++- 22 files changed, 105 insertions(+), 17 deletions(-) create mode 100644 src/openai/types/responses/response_input_audio.py create mode 100644 src/openai/types/responses/response_input_audio_param.py diff --git a/.stats.yml b/.stats.yml index ebe81d146e..41379b009a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 118 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-356b4364203ff36d7724074cd04f6e684253bfcc3c9d969122d730aa7bc51b46.yml -openapi_spec_hash: 4ab8e96f52699bc3d2b0c4432aa92af8 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-f312a661d9dd6b5d6d676e449c357f6414afd1fdaaf4d982d44ad86cba5c5f6e.yml +openapi_spec_hash: b62fd3d3fb98e37b1da0a2e22af51d40 config_hash: b854932c0ea24b400bdd64e4376936bd diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index e459f55c61..837d2b2211 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -269,7 +269,7 @@ def create( Learn more about [built-in tools](https://platform.openai.com/docs/guides/tools). - **MCP Tools**: Integrations with third-party systems via custom MCP servers or - predefined connectors such as Google Drive and Notion. Learn more about + predefined connectors such as Google Drive and SharePoint. Learn more about [MCP Tools](https://platform.openai.com/docs/guides/tools-connectors-mcp). - **Function calls (custom tools)**: Functions that are defined by you, enabling the model to call your own code with strongly typed arguments and outputs. @@ -508,7 +508,7 @@ def create( Learn more about [built-in tools](https://platform.openai.com/docs/guides/tools). - **MCP Tools**: Integrations with third-party systems via custom MCP servers or - predefined connectors such as Google Drive and Notion. Learn more about + predefined connectors such as Google Drive and SharePoint. Learn more about [MCP Tools](https://platform.openai.com/docs/guides/tools-connectors-mcp). - **Function calls (custom tools)**: Functions that are defined by you, enabling the model to call your own code with strongly typed arguments and outputs. @@ -747,7 +747,7 @@ def create( Learn more about [built-in tools](https://platform.openai.com/docs/guides/tools). - **MCP Tools**: Integrations with third-party systems via custom MCP servers or - predefined connectors such as Google Drive and Notion. Learn more about + predefined connectors such as Google Drive and SharePoint. Learn more about [MCP Tools](https://platform.openai.com/docs/guides/tools-connectors-mcp). - **Function calls (custom tools)**: Functions that are defined by you, enabling the model to call your own code with strongly typed arguments and outputs. @@ -1700,7 +1700,7 @@ async def create( Learn more about [built-in tools](https://platform.openai.com/docs/guides/tools). - **MCP Tools**: Integrations with third-party systems via custom MCP servers or - predefined connectors such as Google Drive and Notion. Learn more about + predefined connectors such as Google Drive and SharePoint. Learn more about [MCP Tools](https://platform.openai.com/docs/guides/tools-connectors-mcp). - **Function calls (custom tools)**: Functions that are defined by you, enabling the model to call your own code with strongly typed arguments and outputs. @@ -1939,7 +1939,7 @@ async def create( Learn more about [built-in tools](https://platform.openai.com/docs/guides/tools). - **MCP Tools**: Integrations with third-party systems via custom MCP servers or - predefined connectors such as Google Drive and Notion. Learn more about + predefined connectors such as Google Drive and SharePoint. Learn more about [MCP Tools](https://platform.openai.com/docs/guides/tools-connectors-mcp). - **Function calls (custom tools)**: Functions that are defined by you, enabling the model to call your own code with strongly typed arguments and outputs. @@ -2178,7 +2178,7 @@ async def create( Learn more about [built-in tools](https://platform.openai.com/docs/guides/tools). - **MCP Tools**: Integrations with third-party systems via custom MCP servers or - predefined connectors such as Google Drive and Notion. Learn more about + predefined connectors such as Google Drive and SharePoint. Learn more about [MCP Tools](https://platform.openai.com/docs/guides/tools-connectors-mcp). - **Function calls (custom tools)**: Functions that are defined by you, enabling the model to call your own code with strongly typed arguments and outputs. diff --git a/src/openai/types/eval_create_params.py b/src/openai/types/eval_create_params.py index 016f705dd7..eb7f86cd92 100644 --- a/src/openai/types/eval_create_params.py +++ b/src/openai/types/eval_create_params.py @@ -12,6 +12,7 @@ from .graders.string_check_grader_param import StringCheckGraderParam from .responses.response_input_text_param import ResponseInputTextParam from .graders.text_similarity_grader_param import TextSimilarityGraderParam +from .responses.response_input_audio_param import ResponseInputAudioParam __all__ = [ "EvalCreateParams", @@ -130,6 +131,7 @@ class TestingCriterionLabelModelInputEvalItemContentInputImage(TypedDict, total= ResponseInputTextParam, TestingCriterionLabelModelInputEvalItemContentOutputText, TestingCriterionLabelModelInputEvalItemContentInputImage, + ResponseInputAudioParam, Iterable[object], ] diff --git a/src/openai/types/evals/create_eval_completions_run_data_source.py b/src/openai/types/evals/create_eval_completions_run_data_source.py index efcab9adb8..edf70c8ad4 100644 --- a/src/openai/types/evals/create_eval_completions_run_data_source.py +++ b/src/openai/types/evals/create_eval_completions_run_data_source.py @@ -9,6 +9,7 @@ from ..shared.response_format_text import ResponseFormatText from ..responses.easy_input_message import EasyInputMessage from ..responses.response_input_text import ResponseInputText +from ..responses.response_input_audio import ResponseInputAudio from ..chat.chat_completion_function_tool import ChatCompletionFunctionTool from ..shared.response_format_json_object import ResponseFormatJSONObject from ..shared.response_format_json_schema import ResponseFormatJSONSchema @@ -114,6 +115,7 @@ class InputMessagesTemplateTemplateEvalItemContentInputImage(BaseModel): ResponseInputText, InputMessagesTemplateTemplateEvalItemContentOutputText, InputMessagesTemplateTemplateEvalItemContentInputImage, + ResponseInputAudio, List[object], ] diff --git a/src/openai/types/evals/create_eval_completions_run_data_source_param.py b/src/openai/types/evals/create_eval_completions_run_data_source_param.py index effa658452..c14360ac80 100644 --- a/src/openai/types/evals/create_eval_completions_run_data_source_param.py +++ b/src/openai/types/evals/create_eval_completions_run_data_source_param.py @@ -9,6 +9,7 @@ from ..responses.easy_input_message_param import EasyInputMessageParam from ..shared_params.response_format_text import ResponseFormatText from ..responses.response_input_text_param import ResponseInputTextParam +from ..responses.response_input_audio_param import ResponseInputAudioParam from ..chat.chat_completion_function_tool_param import ChatCompletionFunctionToolParam from ..shared_params.response_format_json_object import ResponseFormatJSONObject from ..shared_params.response_format_json_schema import ResponseFormatJSONSchema @@ -112,6 +113,7 @@ class InputMessagesTemplateTemplateEvalItemContentInputImage(TypedDict, total=Fa ResponseInputTextParam, InputMessagesTemplateTemplateEvalItemContentOutputText, InputMessagesTemplateTemplateEvalItemContentInputImage, + ResponseInputAudioParam, Iterable[object], ] diff --git a/src/openai/types/evals/run_cancel_response.py b/src/openai/types/evals/run_cancel_response.py index 7f4f4c9cc4..44f9cfc453 100644 --- a/src/openai/types/evals/run_cancel_response.py +++ b/src/openai/types/evals/run_cancel_response.py @@ -12,6 +12,7 @@ from ..shared.metadata import Metadata from ..shared.reasoning_effort import ReasoningEffort from ..responses.response_input_text import ResponseInputText +from ..responses.response_input_audio import ResponseInputAudio from .create_eval_jsonl_run_data_source import CreateEvalJSONLRunDataSource from ..responses.response_format_text_config import ResponseFormatTextConfig from .create_eval_completions_run_data_source import CreateEvalCompletionsRunDataSource @@ -158,6 +159,7 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage( ResponseInputText, DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText, DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage, + ResponseInputAudio, List[object], ] diff --git a/src/openai/types/evals/run_create_params.py b/src/openai/types/evals/run_create_params.py index faf06a2f58..ef9541ff0a 100644 --- a/src/openai/types/evals/run_create_params.py +++ b/src/openai/types/evals/run_create_params.py @@ -10,6 +10,7 @@ from ..shared_params.metadata import Metadata from ..shared.reasoning_effort import ReasoningEffort from ..responses.response_input_text_param import ResponseInputTextParam +from ..responses.response_input_audio_param import ResponseInputAudioParam from .create_eval_jsonl_run_data_source_param import CreateEvalJSONLRunDataSourceParam from ..responses.response_format_text_config_param import ResponseFormatTextConfigParam from .create_eval_completions_run_data_source_param import CreateEvalCompletionsRunDataSourceParam @@ -176,6 +177,7 @@ class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEva ResponseInputTextParam, DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentOutputText, DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentInputImage, + ResponseInputAudioParam, Iterable[object], ] diff --git a/src/openai/types/evals/run_create_response.py b/src/openai/types/evals/run_create_response.py index fba5321552..70641d6db8 100644 --- a/src/openai/types/evals/run_create_response.py +++ b/src/openai/types/evals/run_create_response.py @@ -12,6 +12,7 @@ from ..shared.metadata import Metadata from ..shared.reasoning_effort import ReasoningEffort from ..responses.response_input_text import ResponseInputText +from ..responses.response_input_audio import ResponseInputAudio from .create_eval_jsonl_run_data_source import CreateEvalJSONLRunDataSource from ..responses.response_format_text_config import ResponseFormatTextConfig from .create_eval_completions_run_data_source import CreateEvalCompletionsRunDataSource @@ -158,6 +159,7 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage( ResponseInputText, DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText, DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage, + ResponseInputAudio, List[object], ] diff --git a/src/openai/types/evals/run_list_response.py b/src/openai/types/evals/run_list_response.py index e9e445af5c..e31d570a84 100644 --- a/src/openai/types/evals/run_list_response.py +++ b/src/openai/types/evals/run_list_response.py @@ -12,6 +12,7 @@ from ..shared.metadata import Metadata from ..shared.reasoning_effort import ReasoningEffort from ..responses.response_input_text import ResponseInputText +from ..responses.response_input_audio import ResponseInputAudio from .create_eval_jsonl_run_data_source import CreateEvalJSONLRunDataSource from ..responses.response_format_text_config import ResponseFormatTextConfig from .create_eval_completions_run_data_source import CreateEvalCompletionsRunDataSource @@ -158,6 +159,7 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage( ResponseInputText, DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText, DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage, + ResponseInputAudio, List[object], ] diff --git a/src/openai/types/evals/run_retrieve_response.py b/src/openai/types/evals/run_retrieve_response.py index e13f1abe42..62213d3edd 100644 --- a/src/openai/types/evals/run_retrieve_response.py +++ b/src/openai/types/evals/run_retrieve_response.py @@ -12,6 +12,7 @@ from ..shared.metadata import Metadata from ..shared.reasoning_effort import ReasoningEffort from ..responses.response_input_text import ResponseInputText +from ..responses.response_input_audio import ResponseInputAudio from .create_eval_jsonl_run_data_source import CreateEvalJSONLRunDataSource from ..responses.response_format_text_config import ResponseFormatTextConfig from .create_eval_completions_run_data_source import CreateEvalCompletionsRunDataSource @@ -158,6 +159,7 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage( ResponseInputText, DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText, DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage, + ResponseInputAudio, List[object], ] diff --git a/src/openai/types/graders/label_model_grader.py b/src/openai/types/graders/label_model_grader.py index 76dbfb854a..0929349c24 100644 --- a/src/openai/types/graders/label_model_grader.py +++ b/src/openai/types/graders/label_model_grader.py @@ -5,6 +5,7 @@ from ..._models import BaseModel from ..responses.response_input_text import ResponseInputText +from ..responses.response_input_audio import ResponseInputAudio __all__ = ["LabelModelGrader", "Input", "InputContent", "InputContentOutputText", "InputContentInputImage"] @@ -31,7 +32,9 @@ class InputContentInputImage(BaseModel): """ -InputContent: TypeAlias = Union[str, ResponseInputText, InputContentOutputText, InputContentInputImage, List[object]] +InputContent: TypeAlias = Union[ + str, ResponseInputText, InputContentOutputText, InputContentInputImage, ResponseInputAudio, List[object] +] class Input(BaseModel): diff --git a/src/openai/types/graders/label_model_grader_param.py b/src/openai/types/graders/label_model_grader_param.py index 57f7885872..7bd6fdb4a7 100644 --- a/src/openai/types/graders/label_model_grader_param.py +++ b/src/openai/types/graders/label_model_grader_param.py @@ -7,6 +7,7 @@ from ..._types import SequenceNotStr from ..responses.response_input_text_param import ResponseInputTextParam +from ..responses.response_input_audio_param import ResponseInputAudioParam __all__ = ["LabelModelGraderParam", "Input", "InputContent", "InputContentOutputText", "InputContentInputImage"] @@ -34,7 +35,12 @@ class InputContentInputImage(TypedDict, total=False): InputContent: TypeAlias = Union[ - str, ResponseInputTextParam, InputContentOutputText, InputContentInputImage, Iterable[object] + str, + ResponseInputTextParam, + InputContentOutputText, + InputContentInputImage, + ResponseInputAudioParam, + Iterable[object], ] diff --git a/src/openai/types/graders/score_model_grader.py b/src/openai/types/graders/score_model_grader.py index e6af0ebcf7..fc221b8e41 100644 --- a/src/openai/types/graders/score_model_grader.py +++ b/src/openai/types/graders/score_model_grader.py @@ -5,6 +5,7 @@ from ..._models import BaseModel from ..responses.response_input_text import ResponseInputText +from ..responses.response_input_audio import ResponseInputAudio __all__ = ["ScoreModelGrader", "Input", "InputContent", "InputContentOutputText", "InputContentInputImage"] @@ -31,7 +32,9 @@ class InputContentInputImage(BaseModel): """ -InputContent: TypeAlias = Union[str, ResponseInputText, InputContentOutputText, InputContentInputImage, List[object]] +InputContent: TypeAlias = Union[ + str, ResponseInputText, InputContentOutputText, InputContentInputImage, ResponseInputAudio, List[object] +] class Input(BaseModel): diff --git a/src/openai/types/graders/score_model_grader_param.py b/src/openai/types/graders/score_model_grader_param.py index 47c9928076..15100bb74b 100644 --- a/src/openai/types/graders/score_model_grader_param.py +++ b/src/openai/types/graders/score_model_grader_param.py @@ -6,6 +6,7 @@ from typing_extensions import Literal, Required, TypeAlias, TypedDict from ..responses.response_input_text_param import ResponseInputTextParam +from ..responses.response_input_audio_param import ResponseInputAudioParam __all__ = ["ScoreModelGraderParam", "Input", "InputContent", "InputContentOutputText", "InputContentInputImage"] @@ -33,7 +34,12 @@ class InputContentInputImage(TypedDict, total=False): InputContent: TypeAlias = Union[ - str, ResponseInputTextParam, InputContentOutputText, InputContentInputImage, Iterable[object] + str, + ResponseInputTextParam, + InputContentOutputText, + InputContentInputImage, + ResponseInputAudioParam, + Iterable[object], ] diff --git a/src/openai/types/responses/__init__.py b/src/openai/types/responses/__init__.py index 8047f3c4d1..d59f0a74b8 100644 --- a/src/openai/types/responses/__init__.py +++ b/src/openai/types/responses/__init__.py @@ -38,6 +38,7 @@ from .tool_choice_allowed import ToolChoiceAllowed as ToolChoiceAllowed from .tool_choice_options import ToolChoiceOptions as ToolChoiceOptions from .response_error_event import ResponseErrorEvent as ResponseErrorEvent +from .response_input_audio import ResponseInputAudio as ResponseInputAudio from .response_input_image import ResponseInputImage as ResponseInputImage from .response_input_param import ResponseInputParam as ResponseInputParam from .response_output_item import ResponseOutputItem as ResponseOutputItem @@ -75,6 +76,7 @@ from .tool_choice_allowed_param import ToolChoiceAllowedParam as ToolChoiceAllowedParam from .response_audio_delta_event import ResponseAudioDeltaEvent as ResponseAudioDeltaEvent from .response_in_progress_event import ResponseInProgressEvent as ResponseInProgressEvent +from .response_input_audio_param import ResponseInputAudioParam as ResponseInputAudioParam from .response_input_image_param import ResponseInputImageParam as ResponseInputImageParam from .response_output_text_param import ResponseOutputTextParam as ResponseOutputTextParam from .response_text_config_param import ResponseTextConfigParam as ResponseTextConfigParam diff --git a/src/openai/types/responses/response.py b/src/openai/types/responses/response.py index 9f6fd3e2d2..163648ef3e 100644 --- a/src/openai/types/responses/response.py +++ b/src/openai/types/responses/response.py @@ -125,7 +125,7 @@ class Response(BaseModel): Learn more about [built-in tools](https://platform.openai.com/docs/guides/tools). - **MCP Tools**: Integrations with third-party systems via custom MCP servers or - predefined connectors such as Google Drive and Notion. Learn more about + predefined connectors such as Google Drive and SharePoint. Learn more about [MCP Tools](https://platform.openai.com/docs/guides/tools-connectors-mcp). - **Function calls (custom tools)**: Functions that are defined by you, enabling the model to call your own code with strongly typed arguments and outputs. diff --git a/src/openai/types/responses/response_create_params.py b/src/openai/types/responses/response_create_params.py index eac249414a..be687c0aff 100644 --- a/src/openai/types/responses/response_create_params.py +++ b/src/openai/types/responses/response_create_params.py @@ -225,7 +225,7 @@ class ResponseCreateParamsBase(TypedDict, total=False): Learn more about [built-in tools](https://platform.openai.com/docs/guides/tools). - **MCP Tools**: Integrations with third-party systems via custom MCP servers or - predefined connectors such as Google Drive and Notion. Learn more about + predefined connectors such as Google Drive and SharePoint. Learn more about [MCP Tools](https://platform.openai.com/docs/guides/tools-connectors-mcp). - **Function calls (custom tools)**: Functions that are defined by you, enabling the model to call your own code with strongly typed arguments and outputs. diff --git a/src/openai/types/responses/response_input_audio.py b/src/openai/types/responses/response_input_audio.py new file mode 100644 index 0000000000..9fef6de0fd --- /dev/null +++ b/src/openai/types/responses/response_input_audio.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseInputAudio", "InputAudio"] + + +class InputAudio(BaseModel): + data: str + """Base64-encoded audio data.""" + + format: Literal["mp3", "wav"] + """The format of the audio data. Currently supported formats are `mp3` and `wav`.""" + + +class ResponseInputAudio(BaseModel): + input_audio: InputAudio + + type: Literal["input_audio"] + """The type of the input item. Always `input_audio`.""" diff --git a/src/openai/types/responses/response_input_audio_param.py b/src/openai/types/responses/response_input_audio_param.py new file mode 100644 index 0000000000..f3fc913cca --- /dev/null +++ b/src/openai/types/responses/response_input_audio_param.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ResponseInputAudioParam", "InputAudio"] + + +class InputAudio(TypedDict, total=False): + data: Required[str] + """Base64-encoded audio data.""" + + format: Required[Literal["mp3", "wav"]] + """The format of the audio data. Currently supported formats are `mp3` and `wav`.""" + + +class ResponseInputAudioParam(TypedDict, total=False): + input_audio: Required[InputAudio] + + type: Required[Literal["input_audio"]] + """The type of the input item. Always `input_audio`.""" diff --git a/src/openai/types/responses/response_input_content.py b/src/openai/types/responses/response_input_content.py index 1726909a17..376b9ffce8 100644 --- a/src/openai/types/responses/response_input_content.py +++ b/src/openai/types/responses/response_input_content.py @@ -6,10 +6,12 @@ from ..._utils import PropertyInfo from .response_input_file import ResponseInputFile from .response_input_text import ResponseInputText +from .response_input_audio import ResponseInputAudio from .response_input_image import ResponseInputImage __all__ = ["ResponseInputContent"] ResponseInputContent: TypeAlias = Annotated[ - Union[ResponseInputText, ResponseInputImage, ResponseInputFile], PropertyInfo(discriminator="type") + Union[ResponseInputText, ResponseInputImage, ResponseInputFile, ResponseInputAudio], + PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/responses/response_input_content_param.py b/src/openai/types/responses/response_input_content_param.py index 7791cdfd8e..a95e026a53 100644 --- a/src/openai/types/responses/response_input_content_param.py +++ b/src/openai/types/responses/response_input_content_param.py @@ -7,8 +7,11 @@ from .response_input_file_param import ResponseInputFileParam from .response_input_text_param import ResponseInputTextParam +from .response_input_audio_param import ResponseInputAudioParam from .response_input_image_param import ResponseInputImageParam __all__ = ["ResponseInputContentParam"] -ResponseInputContentParam: TypeAlias = Union[ResponseInputTextParam, ResponseInputImageParam, ResponseInputFileParam] +ResponseInputContentParam: TypeAlias = Union[ + ResponseInputTextParam, ResponseInputImageParam, ResponseInputFileParam, ResponseInputAudioParam +] diff --git a/src/openai/types/responses/response_input_message_content_list_param.py b/src/openai/types/responses/response_input_message_content_list_param.py index 080613df0d..8e3778d15a 100644 --- a/src/openai/types/responses/response_input_message_content_list_param.py +++ b/src/openai/types/responses/response_input_message_content_list_param.py @@ -7,10 +7,13 @@ from .response_input_file_param import ResponseInputFileParam from .response_input_text_param import ResponseInputTextParam +from .response_input_audio_param import ResponseInputAudioParam from .response_input_image_param import ResponseInputImageParam __all__ = ["ResponseInputMessageContentListParam", "ResponseInputContentParam"] -ResponseInputContentParam: TypeAlias = Union[ResponseInputTextParam, ResponseInputImageParam, ResponseInputFileParam] +ResponseInputContentParam: TypeAlias = Union[ + ResponseInputTextParam, ResponseInputImageParam, ResponseInputFileParam, ResponseInputAudioParam +] ResponseInputMessageContentListParam: TypeAlias = List[ResponseInputContentParam] From fb152d967edb181c1a17827f31a4df10e416e255 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 2 Sep 2025 19:55:42 +0000 Subject: [PATCH 478/769] release: 1.104.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 2e568a21c7..8168399b9e 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.104.0" + ".": "1.104.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 6116a79d30..422e50ed9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.104.1 (2025-09-02) + +Full Changelog: [v1.104.0...v1.104.1](https://github.com/openai/openai-python/compare/v1.104.0...v1.104.1) + +### Chores + +* **api:** manual updates for ResponseInputAudio ([0db5061](https://github.com/openai/openai-python/commit/0db50619663656ba97bba30ab640bbb33683d196)) + ## 1.104.0 (2025-09-02) Full Changelog: [v1.103.0...v1.104.0](https://github.com/openai/openai-python/compare/v1.103.0...v1.104.0) diff --git a/pyproject.toml b/pyproject.toml index 08a04d08d1..313eb21ea3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.104.0" +version = "1.104.1" 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 46e82bb627..139d9a48ab 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.104.0" # x-release-please-version +__version__ = "1.104.1" # x-release-please-version From 5a6931dafdf73d9dbfce62c3a7c585b95daaf009 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Tue, 2 Sep 2025 22:36:22 +0100 Subject: [PATCH 479/769] fix(types): add aliases back for web search tool types --- src/openai/types/responses/tool.py | 3 +++ src/openai/types/responses/tool_param.py | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/src/openai/types/responses/tool.py b/src/openai/types/responses/tool.py index 594e09d729..482d4e75c1 100644 --- a/src/openai/types/responses/tool.py +++ b/src/openai/types/responses/tool.py @@ -3,6 +3,7 @@ from typing import Dict, List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias +from . import web_search_tool from ..._utils import PropertyInfo from ..._models import BaseModel from .custom_tool import CustomTool @@ -30,6 +31,8 @@ "LocalShell", ] +WebSearchToolFilters = web_search_tool.Filters +WebSearchToolUserLocation = web_search_tool.UserLocation class McpAllowedToolsMcpToolFilter(BaseModel): read_only: Optional[bool] = None diff --git a/src/openai/types/responses/tool_param.py b/src/openai/types/responses/tool_param.py index fd916a2a81..54bc271c0f 100644 --- a/src/openai/types/responses/tool_param.py +++ b/src/openai/types/responses/tool_param.py @@ -5,6 +5,7 @@ from typing import Dict, Union, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict +from . import web_search_tool_param from ..chat import ChatCompletionFunctionToolParam from ..._types import SequenceNotStr from .custom_tool_param import CustomToolParam @@ -31,6 +32,9 @@ "LocalShell", ] +WebSearchTool = web_search_tool_param.WebSearchToolParam +WebSearchToolFilters = web_search_tool_param.Filters +WebSearchToolUserLocation = web_search_tool_param.UserLocation class McpAllowedToolsMcpToolFilter(TypedDict, total=False): read_only: bool From a52463c93215a09f9a142e25c975935523d15c10 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 2 Sep 2025 21:39:13 +0000 Subject: [PATCH 480/769] release: 1.104.2 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 8168399b9e..a3896371d6 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.104.1" + ".": "1.104.2" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 422e50ed9c..754f25576a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.104.2 (2025-09-02) + +Full Changelog: [v1.104.1...v1.104.2](https://github.com/openai/openai-python/compare/v1.104.1...v1.104.2) + +### Bug Fixes + +* **types:** add aliases back for web search tool types ([2521cd8](https://github.com/openai/openai-python/commit/2521cd8445906e418dbae783b0d7c375ad91d49d)) + ## 1.104.1 (2025-09-02) Full Changelog: [v1.104.0...v1.104.1](https://github.com/openai/openai-python/compare/v1.104.0...v1.104.1) diff --git a/pyproject.toml b/pyproject.toml index 313eb21ea3..6860630f3f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.104.1" +version = "1.104.2" 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 139d9a48ab..4368a7e74c 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.104.1" # x-release-please-version +__version__ = "1.104.2" # x-release-please-version From 2c60d78b378465433b70bbe2a7d3f94c8eeaa0d5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 3 Sep 2025 14:10:24 +0000 Subject: [PATCH 481/769] feat(api): Add gpt-realtime models Adds gpt-realtime and gpt-realtime-2025-08-28 --- .stats.yml | 4 ++-- src/openai/types/realtime/realtime_session.py | 2 ++ src/openai/types/realtime/realtime_session_create_request.py | 2 ++ .../types/realtime/realtime_session_create_request_param.py | 2 ++ 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 41379b009a..c41be6ee57 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 118 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-f312a661d9dd6b5d6d676e449c357f6414afd1fdaaf4d982d44ad86cba5c5f6e.yml -openapi_spec_hash: b62fd3d3fb98e37b1da0a2e22af51d40 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-51afd6abbcb18c3086f62993f9379c18443b9e516cbc0548ddfb932e835657f8.yml +openapi_spec_hash: dae6afeaefa15cb8700c7a870531e06f config_hash: b854932c0ea24b400bdd64e4376936bd diff --git a/src/openai/types/realtime/realtime_session.py b/src/openai/types/realtime/realtime_session.py index 43576ea73d..fdb5e9419a 100644 --- a/src/openai/types/realtime/realtime_session.py +++ b/src/openai/types/realtime/realtime_session.py @@ -220,6 +220,8 @@ class RealtimeSession(BaseModel): model: Optional[ Literal[ + "gpt-realtime", + "gpt-realtime-2025-08-28", "gpt-4o-realtime-preview", "gpt-4o-realtime-preview-2024-10-01", "gpt-4o-realtime-preview-2024-12-17", diff --git a/src/openai/types/realtime/realtime_session_create_request.py b/src/openai/types/realtime/realtime_session_create_request.py index a8d0f99704..85205add50 100644 --- a/src/openai/types/realtime/realtime_session_create_request.py +++ b/src/openai/types/realtime/realtime_session_create_request.py @@ -19,6 +19,8 @@ class RealtimeSessionCreateRequest(BaseModel): model: Union[ str, Literal[ + "gpt-realtime", + "gpt-realtime-2025-08-28", "gpt-4o-realtime", "gpt-4o-mini-realtime", "gpt-4o-realtime-preview", diff --git a/src/openai/types/realtime/realtime_session_create_request_param.py b/src/openai/types/realtime/realtime_session_create_request_param.py index 2c5d1e0bee..8f962ca0e2 100644 --- a/src/openai/types/realtime/realtime_session_create_request_param.py +++ b/src/openai/types/realtime/realtime_session_create_request_param.py @@ -21,6 +21,8 @@ class RealtimeSessionCreateRequestParam(TypedDict, total=False): Union[ str, Literal[ + "gpt-realtime", + "gpt-realtime-2025-08-28", "gpt-4o-realtime", "gpt-4o-mini-realtime", "gpt-4o-realtime-preview", From 8672413735889e83e74e7e133b976fe6029843a5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 3 Sep 2025 14:10:58 +0000 Subject: [PATCH 482/769] release: 1.105.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index a3896371d6..1e15251d64 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.104.2" + ".": "1.105.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 754f25576a..3ed3bbe6ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.105.0 (2025-09-03) + +Full Changelog: [v1.104.2...v1.105.0](https://github.com/openai/openai-python/compare/v1.104.2...v1.105.0) + +### Features + +* **api:** Add gpt-realtime models ([8502041](https://github.com/openai/openai-python/commit/85020414808314df9cb42e020b11baff12f18f16)) + ## 1.104.2 (2025-09-02) Full Changelog: [v1.104.1...v1.104.2](https://github.com/openai/openai-python/compare/v1.104.1...v1.104.2) diff --git a/pyproject.toml b/pyproject.toml index 6860630f3f..587ca41e01 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.104.2" +version = "1.105.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 4368a7e74c..5509cd4d8e 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.104.2" # x-release-please-version +__version__ = "1.105.0" # x-release-please-version From 25d16be18bcd11e00a853e8f4af881c76098e0d0 Mon Sep 17 00:00:00 2001 From: "Johan Stenberg (MSFT)" Date: Wed, 3 Sep 2025 08:52:05 -0700 Subject: [PATCH 483/769] feat(client): support callable api_key (#2588) Co-authored-by: Krista Pratico --- src/openai/_client.py | 47 ++++-- src/openai/lib/azure.py | 24 +-- .../resources/beta/realtime/realtime.py | 2 + src/openai/resources/realtime/realtime.py | 2 + tests/test_client.py | 138 +++++++++++++++++- 5 files changed, 188 insertions(+), 25 deletions(-) diff --git a/src/openai/_client.py b/src/openai/_client.py index fe5ebac42a..2be32fe13f 100644 --- a/src/openai/_client.py +++ b/src/openai/_client.py @@ -3,7 +3,7 @@ from __future__ import annotations import os -from typing import TYPE_CHECKING, Any, Union, Mapping +from typing import TYPE_CHECKING, Any, Union, Mapping, Callable, Awaitable from typing_extensions import Self, override import httpx @@ -25,6 +25,7 @@ get_async_library, ) from ._compat import cached_property +from ._models import FinalRequestOptions from ._version import __version__ from ._streaming import Stream as Stream, AsyncStream as AsyncStream from ._exceptions import OpenAIError, APIStatusError @@ -96,7 +97,7 @@ class OpenAI(SyncAPIClient): def __init__( self, *, - api_key: str | None = None, + api_key: str | None | Callable[[], str] = None, organization: str | None = None, project: str | None = None, webhook_secret: str | None = None, @@ -134,7 +135,12 @@ def __init__( raise OpenAIError( "The api_key client option must be set either by passing api_key to the client or by setting the OPENAI_API_KEY environment variable" ) - self.api_key = api_key + if callable(api_key): + self.api_key = "" + self._api_key_provider: Callable[[], str] | None = api_key + else: + self.api_key = api_key + self._api_key_provider = None if organization is None: organization = os.environ.get("OPENAI_ORG_ID") @@ -295,6 +301,15 @@ def with_streaming_response(self) -> OpenAIWithStreamedResponse: def qs(self) -> Querystring: return Querystring(array_format="brackets") + def _refresh_api_key(self) -> None: + if self._api_key_provider: + self.api_key = self._api_key_provider() + + @override + def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOptions: + self._refresh_api_key() + return super()._prepare_options(options) + @property @override def auth_headers(self) -> dict[str, str]: @@ -318,7 +333,7 @@ def default_headers(self) -> dict[str, str | Omit]: def copy( self, *, - api_key: str | None = None, + api_key: str | Callable[[], str] | None = None, organization: str | None = None, project: str | None = None, webhook_secret: str | None = None, @@ -356,7 +371,7 @@ def copy( http_client = http_client or self._client return self.__class__( - api_key=api_key or self.api_key, + api_key=api_key or self._api_key_provider or self.api_key, organization=organization or self.organization, project=project or self.project, webhook_secret=webhook_secret or self.webhook_secret, @@ -427,7 +442,7 @@ class AsyncOpenAI(AsyncAPIClient): def __init__( self, *, - api_key: str | None = None, + api_key: str | Callable[[], Awaitable[str]] | None = None, organization: str | None = None, project: str | None = None, webhook_secret: str | None = None, @@ -465,7 +480,12 @@ def __init__( raise OpenAIError( "The api_key client option must be set either by passing api_key to the client or by setting the OPENAI_API_KEY environment variable" ) - self.api_key = api_key + if callable(api_key): + self.api_key = "" + self._api_key_provider: Callable[[], Awaitable[str]] | None = api_key + else: + self.api_key = api_key + self._api_key_provider = None if organization is None: organization = os.environ.get("OPENAI_ORG_ID") @@ -626,6 +646,15 @@ def with_streaming_response(self) -> AsyncOpenAIWithStreamedResponse: def qs(self) -> Querystring: return Querystring(array_format="brackets") + async def _refresh_api_key(self) -> None: + if self._api_key_provider: + self.api_key = await self._api_key_provider() + + @override + async def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOptions: + await self._refresh_api_key() + return await super()._prepare_options(options) + @property @override def auth_headers(self) -> dict[str, str]: @@ -649,7 +678,7 @@ def default_headers(self) -> dict[str, str | Omit]: def copy( self, *, - api_key: str | None = None, + api_key: str | Callable[[], Awaitable[str]] | None = None, organization: str | None = None, project: str | None = None, webhook_secret: str | None = None, @@ -687,7 +716,7 @@ def copy( http_client = http_client or self._client return self.__class__( - api_key=api_key or self.api_key, + api_key=api_key or self._api_key_provider or self.api_key, organization=organization or self.organization, project=project or self.project, webhook_secret=webhook_secret or self.webhook_secret, diff --git a/src/openai/lib/azure.py b/src/openai/lib/azure.py index a994e4256c..ad64707261 100644 --- a/src/openai/lib/azure.py +++ b/src/openai/lib/azure.py @@ -94,7 +94,7 @@ def __init__( azure_endpoint: str, azure_deployment: str | None = None, api_version: str | None = None, - api_key: str | None = None, + api_key: str | Callable[[], str] | None = None, azure_ad_token: str | None = None, azure_ad_token_provider: AzureADTokenProvider | None = None, organization: str | None = None, @@ -114,7 +114,7 @@ def __init__( *, azure_deployment: str | None = None, api_version: str | None = None, - api_key: str | None = None, + api_key: str | Callable[[], str] | None = None, azure_ad_token: str | None = None, azure_ad_token_provider: AzureADTokenProvider | None = None, organization: str | None = None, @@ -134,7 +134,7 @@ def __init__( *, base_url: str, api_version: str | None = None, - api_key: str | None = None, + api_key: str | Callable[[], str] | None = None, azure_ad_token: str | None = None, azure_ad_token_provider: AzureADTokenProvider | None = None, organization: str | None = None, @@ -154,7 +154,7 @@ def __init__( api_version: str | None = None, azure_endpoint: str | None = None, azure_deployment: str | None = None, - api_key: str | None = None, + api_key: str | Callable[[], str] | None = None, azure_ad_token: str | None = None, azure_ad_token_provider: AzureADTokenProvider | None = None, organization: str | None = None, @@ -258,7 +258,7 @@ def __init__( def copy( self, *, - api_key: str | None = None, + api_key: str | Callable[[], str] | None = None, organization: str | None = None, project: str | None = None, webhook_secret: str | None = None, @@ -345,7 +345,7 @@ def _configure_realtime(self, model: str, extra_query: Query) -> tuple[httpx.URL "api-version": self._api_version, "deployment": self._azure_deployment or model, } - if self.api_key != "": + if self.api_key and self.api_key != "": auth_headers = {"api-key": self.api_key} else: token = self._get_azure_ad_token() @@ -372,7 +372,7 @@ def __init__( azure_endpoint: str, azure_deployment: str | None = None, api_version: str | None = None, - api_key: str | None = None, + api_key: str | Callable[[], Awaitable[str]] | None = None, azure_ad_token: str | None = None, azure_ad_token_provider: AsyncAzureADTokenProvider | None = None, organization: str | None = None, @@ -393,7 +393,7 @@ def __init__( *, azure_deployment: str | None = None, api_version: str | None = None, - api_key: str | None = None, + api_key: str | Callable[[], Awaitable[str]] | None = None, azure_ad_token: str | None = None, azure_ad_token_provider: AsyncAzureADTokenProvider | None = None, organization: str | None = None, @@ -414,7 +414,7 @@ def __init__( *, base_url: str, api_version: str | None = None, - api_key: str | None = None, + api_key: str | Callable[[], Awaitable[str]] | None = None, azure_ad_token: str | None = None, azure_ad_token_provider: AsyncAzureADTokenProvider | None = None, organization: str | None = None, @@ -435,7 +435,7 @@ def __init__( azure_endpoint: str | None = None, azure_deployment: str | None = None, api_version: str | None = None, - api_key: str | None = None, + api_key: str | Callable[[], Awaitable[str]] | None = None, azure_ad_token: str | None = None, azure_ad_token_provider: AsyncAzureADTokenProvider | None = None, organization: str | None = None, @@ -539,7 +539,7 @@ def __init__( def copy( self, *, - api_key: str | None = None, + api_key: str | Callable[[], Awaitable[str]] | None = None, organization: str | None = None, project: str | None = None, webhook_secret: str | None = None, @@ -628,7 +628,7 @@ async def _configure_realtime(self, model: str, extra_query: Query) -> tuple[htt "api-version": self._api_version, "deployment": self._azure_deployment or model, } - if self.api_key != "": + if self.api_key and self.api_key != "": auth_headers = {"api-key": self.api_key} else: token = await self._get_azure_ad_token() diff --git a/src/openai/resources/beta/realtime/realtime.py b/src/openai/resources/beta/realtime/realtime.py index 7b99c7f6c4..4fa35963b6 100644 --- a/src/openai/resources/beta/realtime/realtime.py +++ b/src/openai/resources/beta/realtime/realtime.py @@ -358,6 +358,7 @@ async def __aenter__(self) -> AsyncRealtimeConnection: raise OpenAIError("You need to install `openai[realtime]` to use this method") from exc extra_query = self.__extra_query + await self.__client._refresh_api_key() auth_headers = self.__client.auth_headers if is_async_azure_client(self.__client): url, auth_headers = await self.__client._configure_realtime(self.__model, extra_query) @@ -540,6 +541,7 @@ def __enter__(self) -> RealtimeConnection: raise OpenAIError("You need to install `openai[realtime]` to use this method") from exc extra_query = self.__extra_query + self.__client._refresh_api_key() auth_headers = self.__client.auth_headers if is_azure_client(self.__client): url, auth_headers = self.__client._configure_realtime(self.__model, extra_query) diff --git a/src/openai/resources/realtime/realtime.py b/src/openai/resources/realtime/realtime.py index ebdfce86e3..2f5adf6548 100644 --- a/src/openai/resources/realtime/realtime.py +++ b/src/openai/resources/realtime/realtime.py @@ -326,6 +326,7 @@ async def __aenter__(self) -> AsyncRealtimeConnection: raise OpenAIError("You need to install `openai[realtime]` to use this method") from exc extra_query = self.__extra_query + await self.__client._refresh_api_key() auth_headers = self.__client.auth_headers if is_async_azure_client(self.__client): url, auth_headers = await self.__client._configure_realtime(self.__model, extra_query) @@ -507,6 +508,7 @@ def __enter__(self) -> RealtimeConnection: raise OpenAIError("You need to install `openai[realtime]` to use this method") from exc extra_query = self.__extra_query + self.__client._refresh_api_key() auth_headers = self.__client.auth_headers if is_azure_client(self.__client): url, auth_headers = self.__client._configure_realtime(self.__model, extra_query) diff --git a/tests/test_client.py b/tests/test_client.py index ccda50a7f0..e5300e55d7 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -11,7 +11,7 @@ import inspect import subprocess import tracemalloc -from typing import Any, Union, cast +from typing import Any, Union, Protocol, cast from textwrap import dedent from unittest import mock from typing_extensions import Literal @@ -41,6 +41,10 @@ api_key = "My API Key" +class MockRequestCall(Protocol): + request: httpx.Request + + def _get_params(client: BaseClient[Any, Any]) -> dict[str, str]: request = client._build_request(FinalRequestOptions(method="get", url="/foo")) url = httpx.URL(request.url) @@ -337,7 +341,9 @@ def test_default_headers_option(self) -> None: def test_validate_headers(self) -> None: client = OpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=True) - request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + options = client._prepare_options(FinalRequestOptions(method="get", url="/foo")) + request = client._build_request(options) + assert request.headers.get("Authorization") == f"Bearer {api_key}" with pytest.raises(OpenAIError): @@ -939,6 +945,62 @@ def test_follow_redirects_disabled(self, respx_mock: MockRouter) -> None: assert exc_info.value.response.status_code == 302 assert exc_info.value.response.headers["Location"] == f"{base_url}/redirected" + def test_api_key_before_after_refresh_provider(self) -> None: + client = OpenAI(base_url=base_url, api_key=lambda: "test_bearer_token") + + assert client.api_key == "" + assert "Authorization" not in client.auth_headers + + client._refresh_api_key() + + assert client.api_key == "test_bearer_token" + assert client.auth_headers.get("Authorization") == "Bearer test_bearer_token" + + def test_api_key_before_after_refresh_str(self) -> None: + client = OpenAI(base_url=base_url, api_key="test_api_key") + + assert client.auth_headers.get("Authorization") == "Bearer test_api_key" + client._refresh_api_key() + + assert client.auth_headers.get("Authorization") == "Bearer test_api_key" + + @pytest.mark.respx() + def test_api_key_refresh_on_retry(self, respx_mock: MockRouter) -> None: + respx_mock.post(base_url + "/chat/completions").mock( + side_effect=[ + httpx.Response(500, json={"error": "server error"}), + httpx.Response(200, json={"foo": "bar"}), + ] + ) + + counter = 0 + + def token_provider() -> str: + nonlocal counter + + counter += 1 + + if counter == 1: + return "first" + + return "second" + + client = OpenAI(base_url=base_url, api_key=token_provider) + client.chat.completions.create(messages=[], model="gpt-4") + + calls = cast("list[MockRequestCall]", respx_mock.calls) + assert len(calls) == 2 + + assert calls[0].request.headers.get("Authorization") == "Bearer first" + assert calls[1].request.headers.get("Authorization") == "Bearer second" + + def test_copy_auth(self) -> None: + client = OpenAI(base_url=base_url, api_key=lambda: "test_bearer_token_1").copy( + api_key=lambda: "test_bearer_token_2" + ) + client._refresh_api_key() + assert client.auth_headers == {"Authorization": "Bearer test_bearer_token_2"} + class TestAsyncOpenAI: client = AsyncOpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=True) @@ -1220,9 +1282,10 @@ def test_default_headers_option(self) -> None: assert request.headers.get("x-foo") == "stainless" assert request.headers.get("x-stainless-lang") == "my-overriding-header" - def test_validate_headers(self) -> None: + async def test_validate_headers(self) -> None: client = AsyncOpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=True) - request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + options = await client._prepare_options(FinalRequestOptions(method="get", url="/foo")) + request = client._build_request(options) assert request.headers.get("Authorization") == f"Bearer {api_key}" with pytest.raises(OpenAIError): @@ -1887,3 +1950,70 @@ async def test_follow_redirects_disabled(self, respx_mock: MockRouter) -> None: assert exc_info.value.response.status_code == 302 assert exc_info.value.response.headers["Location"] == f"{base_url}/redirected" + + @pytest.mark.asyncio + async def test_api_key_before_after_refresh_provider(self) -> None: + async def mock_api_key_provider(): + return "test_bearer_token" + + client = AsyncOpenAI(base_url=base_url, api_key=mock_api_key_provider) + + assert client.api_key == "" + assert "Authorization" not in client.auth_headers + + await client._refresh_api_key() + + assert client.api_key == "test_bearer_token" + assert client.auth_headers.get("Authorization") == "Bearer test_bearer_token" + + @pytest.mark.asyncio + async def test_api_key_before_after_refresh_str(self) -> None: + client = AsyncOpenAI(base_url=base_url, api_key="test_api_key") + + assert client.auth_headers.get("Authorization") == "Bearer test_api_key" + await client._refresh_api_key() + + assert client.auth_headers.get("Authorization") == "Bearer test_api_key" + + @pytest.mark.asyncio + @pytest.mark.respx() + async def test_bearer_token_refresh_async(self, respx_mock: MockRouter) -> None: + respx_mock.post(base_url + "/chat/completions").mock( + side_effect=[ + httpx.Response(500, json={"error": "server error"}), + httpx.Response(200, json={"foo": "bar"}), + ] + ) + + counter = 0 + + async def token_provider() -> str: + nonlocal counter + + counter += 1 + + if counter == 1: + return "first" + + return "second" + + client = AsyncOpenAI(base_url=base_url, api_key=token_provider) + await client.chat.completions.create(messages=[], model="gpt-4") + + calls = cast("list[MockRequestCall]", respx_mock.calls) + assert len(calls) == 2 + + assert calls[0].request.headers.get("Authorization") == "Bearer first" + assert calls[1].request.headers.get("Authorization") == "Bearer second" + + @pytest.mark.asyncio + async def test_copy_auth(self) -> None: + async def token_provider_1() -> str: + return "test_bearer_token_1" + + async def token_provider_2() -> str: + return "test_bearer_token_2" + + client = AsyncOpenAI(base_url=base_url, api_key=token_provider_1).copy(api_key=token_provider_2) + await client._refresh_api_key() + assert client.auth_headers == {"Authorization": "Bearer test_bearer_token_2"} From 2cf4ed5072f89103c674a61d22879b06a4c407f6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 3 Sep 2025 22:05:40 +0000 Subject: [PATCH 484/769] feat: improve future compat with pydantic v3 --- src/openai/_base_client.py | 6 +- src/openai/_compat.py | 108 +++++++++---------- src/openai/_models.py | 82 +++++++------- src/openai/_utils/__init__.py | 10 +- src/openai/_utils/_compat.py | 45 ++++++++ src/openai/_utils/_datetime_parse.py | 136 ++++++++++++++++++++++++ src/openai/_utils/_transform.py | 6 +- src/openai/_utils/_typing.py | 2 +- src/openai/_utils/_utils.py | 1 - src/openai/cli/_cli.py | 12 +-- src/openai/cli/_models.py | 8 +- src/openai/lib/_parsing/_completions.py | 4 +- src/openai/lib/_parsing/_responses.py | 4 +- src/openai/lib/_pydantic.py | 4 +- tests/lib/chat/test_completions.py | 6 +- tests/lib/test_pydantic.py | 8 +- tests/test_models.py | 48 ++++----- tests/test_transform.py | 16 +-- tests/test_utils/test_datetime_parse.py | 110 +++++++++++++++++++ tests/utils.py | 8 +- 20 files changed, 462 insertions(+), 162 deletions(-) create mode 100644 src/openai/_utils/_compat.py create mode 100644 src/openai/_utils/_datetime_parse.py create mode 100644 tests/test_utils/test_datetime_parse.py diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index f71e00f51f..d5f1ab0903 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -59,7 +59,7 @@ ModelBuilderProtocol, ) from ._utils import SensitiveHeadersFilter, is_dict, is_list, asyncify, is_given, lru_cache, is_mapping -from ._compat import PYDANTIC_V2, model_copy, model_dump +from ._compat import PYDANTIC_V1, model_copy, model_dump from ._models import GenericModel, FinalRequestOptions, validate_type, construct_type from ._response import ( APIResponse, @@ -234,7 +234,7 @@ def _set_private_attributes( model: Type[_T], options: FinalRequestOptions, ) -> None: - if PYDANTIC_V2 and getattr(self, "__pydantic_private__", None) is None: + if (not PYDANTIC_V1) and getattr(self, "__pydantic_private__", None) is None: self.__pydantic_private__ = {} self._model = model @@ -322,7 +322,7 @@ def _set_private_attributes( client: AsyncAPIClient, options: FinalRequestOptions, ) -> None: - if PYDANTIC_V2 and getattr(self, "__pydantic_private__", None) is None: + if (not PYDANTIC_V1) and getattr(self, "__pydantic_private__", None) is None: self.__pydantic_private__ = {} self._model = model diff --git a/src/openai/_compat.py b/src/openai/_compat.py index 87fc370765..73a1f3ea93 100644 --- a/src/openai/_compat.py +++ b/src/openai/_compat.py @@ -12,14 +12,13 @@ _T = TypeVar("_T") _ModelT = TypeVar("_ModelT", bound=pydantic.BaseModel) -# --------------- Pydantic v2 compatibility --------------- +# --------------- Pydantic v2, v3 compatibility --------------- # Pyright incorrectly reports some of our functions as overriding a method when they don't # pyright: reportIncompatibleMethodOverride=false -PYDANTIC_V2 = pydantic.VERSION.startswith("2.") +PYDANTIC_V1 = pydantic.VERSION.startswith("1.") -# v1 re-exports if TYPE_CHECKING: def parse_date(value: date | StrBytesIntFloat) -> date: # noqa: ARG001 @@ -44,90 +43,92 @@ def is_typeddict(type_: type[Any]) -> bool: # noqa: ARG001 ... else: - if PYDANTIC_V2: - from pydantic.v1.typing import ( + # v1 re-exports + if PYDANTIC_V1: + from pydantic.typing import ( get_args as get_args, is_union as is_union, get_origin as get_origin, is_typeddict as is_typeddict, is_literal_type as is_literal_type, ) - from pydantic.v1.datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime + from pydantic.datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime else: - from pydantic.typing import ( + from ._utils import ( get_args as get_args, is_union as is_union, get_origin as get_origin, + parse_date as parse_date, is_typeddict as is_typeddict, + parse_datetime as parse_datetime, is_literal_type as is_literal_type, ) - from pydantic.datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime # refactored config if TYPE_CHECKING: from pydantic import ConfigDict as ConfigDict else: - if PYDANTIC_V2: - from pydantic import ConfigDict - else: + if PYDANTIC_V1: # TODO: provide an error message here? ConfigDict = None + else: + from pydantic import ConfigDict as ConfigDict # renamed methods / properties def parse_obj(model: type[_ModelT], value: object) -> _ModelT: - if PYDANTIC_V2: - return model.model_validate(value) - else: + if PYDANTIC_V1: return cast(_ModelT, model.parse_obj(value)) # pyright: ignore[reportDeprecated, reportUnnecessaryCast] + else: + return model.model_validate(value) def field_is_required(field: FieldInfo) -> bool: - if PYDANTIC_V2: - return field.is_required() - return field.required # type: ignore + if PYDANTIC_V1: + return field.required # type: ignore + return field.is_required() def field_get_default(field: FieldInfo) -> Any: value = field.get_default() - if PYDANTIC_V2: - from pydantic_core import PydanticUndefined - - if value == PydanticUndefined: - return None + if PYDANTIC_V1: return value + from pydantic_core import PydanticUndefined + + if value == PydanticUndefined: + return None return value def field_outer_type(field: FieldInfo) -> Any: - if PYDANTIC_V2: - return field.annotation - return field.outer_type_ # type: ignore + if PYDANTIC_V1: + return field.outer_type_ # type: ignore + return field.annotation def get_model_config(model: type[pydantic.BaseModel]) -> Any: - if PYDANTIC_V2: - return model.model_config - return model.__config__ # type: ignore + if PYDANTIC_V1: + return model.__config__ # type: ignore + return model.model_config def get_model_fields(model: type[pydantic.BaseModel]) -> dict[str, FieldInfo]: - if PYDANTIC_V2: - return model.model_fields - return model.__fields__ # type: ignore + if PYDANTIC_V1: + return model.__fields__ # type: ignore + return model.model_fields def model_copy(model: _ModelT, *, deep: bool = False) -> _ModelT: - if PYDANTIC_V2: - return model.model_copy(deep=deep) - return model.copy(deep=deep) # type: ignore + if PYDANTIC_V1: + return model.copy(deep=deep) # type: ignore + return model.model_copy(deep=deep) def model_json(model: pydantic.BaseModel, *, indent: int | None = None) -> str: - if PYDANTIC_V2: - return model.model_dump_json(indent=indent) - return model.json(indent=indent) # type: ignore + if PYDANTIC_V1: + return model.json(indent=indent) # type: ignore + return model.model_dump_json(indent=indent) def model_dump( @@ -139,14 +140,14 @@ def model_dump( warnings: bool = True, mode: Literal["json", "python"] = "python", ) -> dict[str, Any]: - if PYDANTIC_V2 or hasattr(model, "model_dump"): + if (not PYDANTIC_V1) or hasattr(model, "model_dump"): return model.model_dump( mode=mode, exclude=exclude, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, # warnings are not supported in Pydantic v1 - warnings=warnings if PYDANTIC_V2 else True, + warnings=True if PYDANTIC_V1 else warnings, ) return cast( "dict[str, Any]", @@ -159,21 +160,21 @@ def model_dump( def model_parse(model: type[_ModelT], data: Any) -> _ModelT: - if PYDANTIC_V2: - return model.model_validate(data) - return model.parse_obj(data) # pyright: ignore[reportDeprecated] + if PYDANTIC_V1: + return model.parse_obj(data) # pyright: ignore[reportDeprecated] + return model.model_validate(data) def model_parse_json(model: type[_ModelT], data: str | bytes) -> _ModelT: - if PYDANTIC_V2: - return model.model_validate_json(data) - return model.parse_raw(data) # pyright: ignore[reportDeprecated] + if PYDANTIC_V1: + return model.parse_raw(data) # pyright: ignore[reportDeprecated] + return model.model_validate_json(data) def model_json_schema(model: type[_ModelT]) -> dict[str, Any]: - if PYDANTIC_V2: - return model.model_json_schema() - return model.schema() # pyright: ignore[reportDeprecated] + if PYDANTIC_V1: + return model.schema() # pyright: ignore[reportDeprecated] + return model.model_json_schema() # generic models @@ -182,17 +183,16 @@ def model_json_schema(model: type[_ModelT]) -> dict[str, Any]: class GenericModel(pydantic.BaseModel): ... else: - if PYDANTIC_V2: + if PYDANTIC_V1: + import pydantic.generics + + class GenericModel(pydantic.generics.GenericModel, pydantic.BaseModel): ... + else: # there no longer needs to be a distinction in v2 but # we still have to create our own subclass to avoid # inconsistent MRO ordering errors class GenericModel(pydantic.BaseModel): ... - else: - import pydantic.generics - - class GenericModel(pydantic.generics.GenericModel, pydantic.BaseModel): ... - # cached properties if TYPE_CHECKING: diff --git a/src/openai/_models.py b/src/openai/_models.py index 50eb0af751..8ee8612d1e 100644 --- a/src/openai/_models.py +++ b/src/openai/_models.py @@ -51,7 +51,7 @@ strip_annotated_type, ) from ._compat import ( - PYDANTIC_V2, + PYDANTIC_V1, ConfigDict, GenericModel as BaseGenericModel, get_args, @@ -84,11 +84,7 @@ class _ConfigProtocol(Protocol): class BaseModel(pydantic.BaseModel): - if PYDANTIC_V2: - model_config: ClassVar[ConfigDict] = ConfigDict( - extra="allow", defer_build=coerce_boolean(os.environ.get("DEFER_PYDANTIC_BUILD", "true")) - ) - else: + if PYDANTIC_V1: @property @override @@ -103,6 +99,10 @@ class Config(pydantic.BaseConfig): # pyright: ignore[reportDeprecated] def __repr_args__(self) -> ReprArgs: # we don't want these attributes to be included when something like `rich.print` is used return [arg for arg in super().__repr_args__() if arg[0] not in {"_request_id", "__exclude_fields__"}] + else: + model_config: ClassVar[ConfigDict] = ConfigDict( + extra="allow", defer_build=coerce_boolean(os.environ.get("DEFER_PYDANTIC_BUILD", "true")) + ) if TYPE_CHECKING: _request_id: Optional[str] = None @@ -240,25 +240,25 @@ def construct( # pyright: ignore[reportIncompatibleMethodOverride] if key not in model_fields: parsed = construct_type(value=value, type_=extra_field_type) if extra_field_type is not None else value - if PYDANTIC_V2: - _extra[key] = parsed - else: + if PYDANTIC_V1: _fields_set.add(key) fields_values[key] = parsed + else: + _extra[key] = parsed object.__setattr__(m, "__dict__", fields_values) - if PYDANTIC_V2: - # these properties are copied from Pydantic's `model_construct()` method - object.__setattr__(m, "__pydantic_private__", None) - object.__setattr__(m, "__pydantic_extra__", _extra) - object.__setattr__(m, "__pydantic_fields_set__", _fields_set) - else: + if PYDANTIC_V1: # init_private_attributes() does not exist in v2 m._init_private_attributes() # type: ignore # copied from Pydantic v1's `construct()` method object.__setattr__(m, "__fields_set__", _fields_set) + else: + # these properties are copied from Pydantic's `model_construct()` method + object.__setattr__(m, "__pydantic_private__", None) + object.__setattr__(m, "__pydantic_extra__", _extra) + object.__setattr__(m, "__pydantic_fields_set__", _fields_set) return m @@ -268,7 +268,7 @@ def construct( # pyright: ignore[reportIncompatibleMethodOverride] # although not in practice model_construct = construct - if not PYDANTIC_V2: + if PYDANTIC_V1: # we define aliases for some of the new pydantic v2 methods so # that we can just document these methods without having to specify # a specific pydantic version as some users may not know which @@ -388,10 +388,10 @@ def _construct_field(value: object, field: FieldInfo, key: str) -> object: if value is None: return field_get_default(field) - if PYDANTIC_V2: - type_ = field.annotation - else: + if PYDANTIC_V1: type_ = cast(type, field.outer_type_) # type: ignore + else: + type_ = field.annotation # type: ignore if type_ is None: raise RuntimeError(f"Unexpected field type is None for {key}") @@ -400,7 +400,7 @@ def _construct_field(value: object, field: FieldInfo, key: str) -> object: def _get_extra_fields_type(cls: type[pydantic.BaseModel]) -> type | None: - if not PYDANTIC_V2: + if PYDANTIC_V1: # TODO return None @@ -653,30 +653,30 @@ def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, for variant in get_args(union): variant = strip_annotated_type(variant) if is_basemodel_type(variant): - if PYDANTIC_V2: - field = _extract_field_schema_pv2(variant, discriminator_field_name) - if not field: + if PYDANTIC_V1: + field_info = cast("dict[str, FieldInfo]", variant.__fields__).get(discriminator_field_name) # pyright: ignore[reportDeprecated, reportUnnecessaryCast] + if not field_info: continue # Note: if one variant defines an alias then they all should - discriminator_alias = field.get("serialization_alias") - - field_schema = field["schema"] + discriminator_alias = field_info.alias - if field_schema["type"] == "literal": - for entry in cast("LiteralSchema", field_schema)["expected"]: + if (annotation := getattr(field_info, "annotation", None)) and is_literal_type(annotation): + for entry in get_args(annotation): if isinstance(entry, str): mapping[entry] = variant else: - field_info = cast("dict[str, FieldInfo]", variant.__fields__).get(discriminator_field_name) # pyright: ignore[reportDeprecated, reportUnnecessaryCast] - if not field_info: + field = _extract_field_schema_pv2(variant, discriminator_field_name) + if not field: continue # Note: if one variant defines an alias then they all should - discriminator_alias = field_info.alias + discriminator_alias = field.get("serialization_alias") - if (annotation := getattr(field_info, "annotation", None)) and is_literal_type(annotation): - for entry in get_args(annotation): + field_schema = field["schema"] + + if field_schema["type"] == "literal": + for entry in cast("LiteralSchema", field_schema)["expected"]: if isinstance(entry, str): mapping[entry] = variant @@ -735,7 +735,7 @@ def add_request_id(obj: BaseModel, request_id: str | None) -> None: # in Pydantic v1, using setattr like we do above causes the attribute # to be included when serializing the model which we don't want in this # case so we need to explicitly exclude it - if not PYDANTIC_V2: + if PYDANTIC_V1: try: exclude_fields = obj.__exclude_fields__ # type: ignore except AttributeError: @@ -754,7 +754,7 @@ class GenericModel(BaseGenericModel, BaseModel): pass -if PYDANTIC_V2: +if not PYDANTIC_V1: from pydantic import TypeAdapter as _TypeAdapter _CachedTypeAdapter = cast("TypeAdapter[object]", lru_cache(maxsize=None)(_TypeAdapter)) @@ -822,12 +822,12 @@ class FinalRequestOptions(pydantic.BaseModel): json_data: Union[Body, None] = None extra_json: Union[AnyMapping, None] = None - if PYDANTIC_V2: - model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True) - else: + if PYDANTIC_V1: class Config(pydantic.BaseConfig): # pyright: ignore[reportDeprecated] arbitrary_types_allowed: bool = True + else: + model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True) def get_max_retries(self, max_retries: int) -> int: if isinstance(self.max_retries, NotGiven): @@ -860,9 +860,9 @@ def construct( # type: ignore key: strip_not_given(value) for key, value in values.items() } - if PYDANTIC_V2: - return super().model_construct(_fields_set, **kwargs) - return cast(FinalRequestOptions, super().construct(_fields_set, **kwargs)) # pyright: ignore[reportDeprecated] + if PYDANTIC_V1: + return cast(FinalRequestOptions, super().construct(_fields_set, **kwargs)) # pyright: ignore[reportDeprecated] + return super().model_construct(_fields_set, **kwargs) if not TYPE_CHECKING: # type checkers incorrectly complain about this assignment diff --git a/src/openai/_utils/__init__.py b/src/openai/_utils/__init__.py index 6471aa4c0d..963c83b6d4 100644 --- a/src/openai/_utils/__init__.py +++ b/src/openai/_utils/__init__.py @@ -11,7 +11,6 @@ lru_cache as lru_cache, is_mapping as is_mapping, is_tuple_t as is_tuple_t, - parse_date as parse_date, is_iterable as is_iterable, is_sequence as is_sequence, coerce_float as coerce_float, @@ -24,7 +23,6 @@ coerce_boolean as coerce_boolean, coerce_integer as coerce_integer, file_from_path as file_from_path, - parse_datetime as parse_datetime, is_azure_client as is_azure_client, strip_not_given as strip_not_given, deepcopy_minimal as deepcopy_minimal, @@ -35,6 +33,13 @@ maybe_coerce_integer as maybe_coerce_integer, is_async_azure_client as is_async_azure_client, ) +from ._compat import ( + get_args as get_args, + is_union as is_union, + get_origin as get_origin, + is_typeddict as is_typeddict, + is_literal_type as is_literal_type, +) from ._typing import ( is_list_type as is_list_type, is_union_type as is_union_type, @@ -59,3 +64,4 @@ function_has_argument as function_has_argument, assert_signatures_in_sync as assert_signatures_in_sync, ) +from ._datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime diff --git a/src/openai/_utils/_compat.py b/src/openai/_utils/_compat.py new file mode 100644 index 0000000000..dd703233c5 --- /dev/null +++ b/src/openai/_utils/_compat.py @@ -0,0 +1,45 @@ +from __future__ import annotations + +import sys +import typing_extensions +from typing import Any, Type, Union, Literal, Optional +from datetime import date, datetime +from typing_extensions import get_args as _get_args, get_origin as _get_origin + +from .._types import StrBytesIntFloat +from ._datetime_parse import parse_date as _parse_date, parse_datetime as _parse_datetime + +_LITERAL_TYPES = {Literal, typing_extensions.Literal} + + +def get_args(tp: type[Any]) -> tuple[Any, ...]: + return _get_args(tp) + + +def get_origin(tp: type[Any]) -> type[Any] | None: + return _get_origin(tp) + + +def is_union(tp: Optional[Type[Any]]) -> bool: + if sys.version_info < (3, 10): + return tp is Union # type: ignore[comparison-overlap] + else: + import types + + return tp is Union or tp is types.UnionType + + +def is_typeddict(tp: Type[Any]) -> bool: + return typing_extensions.is_typeddict(tp) + + +def is_literal_type(tp: Type[Any]) -> bool: + return get_origin(tp) in _LITERAL_TYPES + + +def parse_date(value: Union[date, StrBytesIntFloat]) -> date: + return _parse_date(value) + + +def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: + return _parse_datetime(value) diff --git a/src/openai/_utils/_datetime_parse.py b/src/openai/_utils/_datetime_parse.py new file mode 100644 index 0000000000..7cb9d9e668 --- /dev/null +++ b/src/openai/_utils/_datetime_parse.py @@ -0,0 +1,136 @@ +""" +This file contains code from https://github.com/pydantic/pydantic/blob/main/pydantic/v1/datetime_parse.py +without the Pydantic v1 specific errors. +""" + +from __future__ import annotations + +import re +from typing import Dict, Union, Optional +from datetime import date, datetime, timezone, timedelta + +from .._types import StrBytesIntFloat + +date_expr = r"(?P\d{4})-(?P\d{1,2})-(?P\d{1,2})" +time_expr = ( + r"(?P\d{1,2}):(?P\d{1,2})" + r"(?::(?P\d{1,2})(?:\.(?P\d{1,6})\d{0,6})?)?" + r"(?PZ|[+-]\d{2}(?::?\d{2})?)?$" +) + +date_re = re.compile(f"{date_expr}$") +datetime_re = re.compile(f"{date_expr}[T ]{time_expr}") + + +EPOCH = datetime(1970, 1, 1) +# if greater than this, the number is in ms, if less than or equal it's in seconds +# (in seconds this is 11th October 2603, in ms it's 20th August 1970) +MS_WATERSHED = int(2e10) +# slightly more than datetime.max in ns - (datetime.max - EPOCH).total_seconds() * 1e9 +MAX_NUMBER = int(3e20) + + +def _get_numeric(value: StrBytesIntFloat, native_expected_type: str) -> Union[None, int, float]: + if isinstance(value, (int, float)): + return value + try: + return float(value) + except ValueError: + return None + except TypeError: + raise TypeError(f"invalid type; expected {native_expected_type}, string, bytes, int or float") from None + + +def _from_unix_seconds(seconds: Union[int, float]) -> datetime: + if seconds > MAX_NUMBER: + return datetime.max + elif seconds < -MAX_NUMBER: + return datetime.min + + while abs(seconds) > MS_WATERSHED: + seconds /= 1000 + dt = EPOCH + timedelta(seconds=seconds) + return dt.replace(tzinfo=timezone.utc) + + +def _parse_timezone(value: Optional[str]) -> Union[None, int, timezone]: + if value == "Z": + return timezone.utc + elif value is not None: + offset_mins = int(value[-2:]) if len(value) > 3 else 0 + offset = 60 * int(value[1:3]) + offset_mins + if value[0] == "-": + offset = -offset + return timezone(timedelta(minutes=offset)) + else: + return None + + +def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: + """ + Parse a datetime/int/float/string and return a datetime.datetime. + + This function supports time zone offsets. When the input contains one, + the output uses a timezone with a fixed offset from UTC. + + Raise ValueError if the input is well formatted but not a valid datetime. + Raise ValueError if the input isn't well formatted. + """ + if isinstance(value, datetime): + return value + + number = _get_numeric(value, "datetime") + if number is not None: + return _from_unix_seconds(number) + + if isinstance(value, bytes): + value = value.decode() + + assert not isinstance(value, (float, int)) + + match = datetime_re.match(value) + if match is None: + raise ValueError("invalid datetime format") + + kw = match.groupdict() + if kw["microsecond"]: + kw["microsecond"] = kw["microsecond"].ljust(6, "0") + + tzinfo = _parse_timezone(kw.pop("tzinfo")) + kw_: Dict[str, Union[None, int, timezone]] = {k: int(v) for k, v in kw.items() if v is not None} + kw_["tzinfo"] = tzinfo + + return datetime(**kw_) # type: ignore + + +def parse_date(value: Union[date, StrBytesIntFloat]) -> date: + """ + Parse a date/int/float/string and return a datetime.date. + + Raise ValueError if the input is well formatted but not a valid date. + Raise ValueError if the input isn't well formatted. + """ + if isinstance(value, date): + if isinstance(value, datetime): + return value.date() + else: + return value + + number = _get_numeric(value, "date") + if number is not None: + return _from_unix_seconds(number).date() + + if isinstance(value, bytes): + value = value.decode() + + assert not isinstance(value, (float, int)) + match = date_re.match(value) + if match is None: + raise ValueError("invalid date format") + + kw = {k: int(v) for k, v in match.groupdict().items()} + + try: + return date(**kw) + except ValueError: + raise ValueError("invalid date format") from None diff --git a/src/openai/_utils/_transform.py b/src/openai/_utils/_transform.py index f5c41c09c4..bc262ea339 100644 --- a/src/openai/_utils/_transform.py +++ b/src/openai/_utils/_transform.py @@ -19,6 +19,7 @@ is_sequence, ) from .._files import is_base64_file_input +from ._compat import get_origin, is_typeddict from ._typing import ( is_list_type, is_union_type, @@ -29,7 +30,6 @@ is_annotated_type, strip_annotated_type, ) -from .._compat import get_origin, model_dump, is_typeddict _T = TypeVar("_T") @@ -169,6 +169,8 @@ def _transform_recursive( Defaults to the same value as the `annotation` argument. """ + from .._compat import model_dump + if inner_type is None: inner_type = annotation @@ -333,6 +335,8 @@ async def _async_transform_recursive( Defaults to the same value as the `annotation` argument. """ + from .._compat import model_dump + if inner_type is None: inner_type = annotation diff --git a/src/openai/_utils/_typing.py b/src/openai/_utils/_typing.py index 845cd6b287..193109f3ad 100644 --- a/src/openai/_utils/_typing.py +++ b/src/openai/_utils/_typing.py @@ -15,7 +15,7 @@ from ._utils import lru_cache from .._types import InheritsGeneric -from .._compat import is_union as _is_union +from ._compat import is_union as _is_union def is_annotated_type(typ: type) -> bool: diff --git a/src/openai/_utils/_utils.py b/src/openai/_utils/_utils.py index 1e7d013b51..4a23c96c0a 100644 --- a/src/openai/_utils/_utils.py +++ b/src/openai/_utils/_utils.py @@ -23,7 +23,6 @@ import sniffio from .._types import NotGiven, FileTypes, NotGivenOr, HeadersLike -from .._compat import parse_date as parse_date, parse_datetime as parse_datetime _T = TypeVar("_T") _TupleT = TypeVar("_TupleT", bound=Tuple[object, ...]) diff --git a/src/openai/cli/_cli.py b/src/openai/cli/_cli.py index fd165f48ab..d31196da50 100644 --- a/src/openai/cli/_cli.py +++ b/src/openai/cli/_cli.py @@ -16,7 +16,7 @@ from ._api import register_commands from ._utils import can_use_http2 from ._errors import CLIError, display_error -from .._compat import PYDANTIC_V2, ConfigDict, model_parse +from .._compat import PYDANTIC_V1, ConfigDict, model_parse from .._models import BaseModel from .._exceptions import APIError @@ -28,14 +28,14 @@ class Arguments(BaseModel): - if PYDANTIC_V2: - model_config: ClassVar[ConfigDict] = ConfigDict( - extra="ignore", - ) - else: + if PYDANTIC_V1: class Config(pydantic.BaseConfig): # type: ignore extra: Any = pydantic.Extra.ignore # type: ignore + else: + model_config: ClassVar[ConfigDict] = ConfigDict( + extra="ignore", + ) verbosity: int version: Optional[str] = None diff --git a/src/openai/cli/_models.py b/src/openai/cli/_models.py index 5583db2609..a88608961b 100644 --- a/src/openai/cli/_models.py +++ b/src/openai/cli/_models.py @@ -4,14 +4,14 @@ import pydantic from .. import _models -from .._compat import PYDANTIC_V2, ConfigDict +from .._compat import PYDANTIC_V1, ConfigDict class BaseModel(_models.BaseModel): - if PYDANTIC_V2: - model_config: ClassVar[ConfigDict] = ConfigDict(extra="ignore", arbitrary_types_allowed=True) - else: + if PYDANTIC_V1: class Config(pydantic.BaseConfig): # type: ignore extra: Any = pydantic.Extra.ignore # type: ignore arbitrary_types_allowed: bool = True + else: + model_config: ClassVar[ConfigDict] = ConfigDict(extra="ignore", arbitrary_types_allowed=True) diff --git a/src/openai/lib/_parsing/_completions.py b/src/openai/lib/_parsing/_completions.py index fc0bd05e4d..4b8b78b70a 100644 --- a/src/openai/lib/_parsing/_completions.py +++ b/src/openai/lib/_parsing/_completions.py @@ -10,7 +10,7 @@ from .._tools import PydanticFunctionTool from ..._types import NOT_GIVEN, NotGiven from ..._utils import is_dict, is_given -from ..._compat import PYDANTIC_V2, model_parse_json +from ..._compat import PYDANTIC_V1, model_parse_json from ..._models import construct_type_unchecked from .._pydantic import is_basemodel_type, to_strict_json_schema, is_dataclass_like_type from ...types.chat import ( @@ -262,7 +262,7 @@ def _parse_content(response_format: type[ResponseFormatT], content: str) -> Resp return cast(ResponseFormatT, model_parse_json(response_format, content)) if is_dataclass_like_type(response_format): - if not PYDANTIC_V2: + if PYDANTIC_V1: raise TypeError(f"Non BaseModel types are only supported with Pydantic v2 - {response_format}") return pydantic.TypeAdapter(response_format).validate_json(content) diff --git a/src/openai/lib/_parsing/_responses.py b/src/openai/lib/_parsing/_responses.py index 2a30ac836c..b6ebde0e8e 100644 --- a/src/openai/lib/_parsing/_responses.py +++ b/src/openai/lib/_parsing/_responses.py @@ -9,7 +9,7 @@ from .._tools import ResponsesPydanticFunctionTool from ..._types import NotGiven from ..._utils import is_given -from ..._compat import PYDANTIC_V2, model_parse_json +from ..._compat import PYDANTIC_V1, model_parse_json from ..._models import construct_type_unchecked from .._pydantic import is_basemodel_type, is_dataclass_like_type from ._completions import solve_response_format_t, type_to_response_format_param @@ -138,7 +138,7 @@ def parse_text(text: str, text_format: type[TextFormatT] | NotGiven) -> TextForm return cast(TextFormatT, model_parse_json(text_format, text)) if is_dataclass_like_type(text_format): - if not PYDANTIC_V2: + if PYDANTIC_V1: raise TypeError(f"Non BaseModel types are only supported with Pydantic v2 - {text_format}") return pydantic.TypeAdapter(text_format).validate_json(text) diff --git a/src/openai/lib/_pydantic.py b/src/openai/lib/_pydantic.py index c2d73e5fc6..3cfe224cb1 100644 --- a/src/openai/lib/_pydantic.py +++ b/src/openai/lib/_pydantic.py @@ -8,7 +8,7 @@ from .._types import NOT_GIVEN from .._utils import is_dict as _is_dict, is_list -from .._compat import PYDANTIC_V2, model_json_schema +from .._compat import PYDANTIC_V1, model_json_schema _T = TypeVar("_T") @@ -16,7 +16,7 @@ def to_strict_json_schema(model: type[pydantic.BaseModel] | pydantic.TypeAdapter[Any]) -> dict[str, Any]: if inspect.isclass(model) and is_basemodel_type(model): schema = model_json_schema(model) - elif PYDANTIC_V2 and isinstance(model, pydantic.TypeAdapter): + elif (not PYDANTIC_V1) and isinstance(model, pydantic.TypeAdapter): schema = model.json_schema() else: raise TypeError(f"Non BaseModel types are only supported with Pydantic v2 - {model}") diff --git a/tests/lib/chat/test_completions.py b/tests/lib/chat/test_completions.py index f69bc09ca3..afad5a1391 100644 --- a/tests/lib/chat/test_completions.py +++ b/tests/lib/chat/test_completions.py @@ -12,7 +12,7 @@ import openai from openai import OpenAI, AsyncOpenAI from openai._utils import assert_signatures_in_sync -from openai._compat import PYDANTIC_V2 +from openai._compat import PYDANTIC_V1 from ..utils import print_obj from ...conftest import base_url @@ -245,7 +245,7 @@ class ColorDetection(BaseModel): color: Color hex_color_code: str = Field(description="The hex color code of the detected color") - if not PYDANTIC_V2: + if PYDANTIC_V1: ColorDetection.update_forward_refs(**locals()) # type: ignore completion = make_snapshot_request( @@ -368,7 +368,7 @@ class Location(BaseModel): @pytest.mark.respx(base_url=base_url) -@pytest.mark.skipif(not PYDANTIC_V2, reason="dataclasses only supported in v2") +@pytest.mark.skipif(PYDANTIC_V1, reason="dataclasses only supported in v2") def test_parse_pydantic_dataclass(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None: from pydantic.dataclasses import dataclass diff --git a/tests/lib/test_pydantic.py b/tests/lib/test_pydantic.py index 7e128b70c0..754a15151c 100644 --- a/tests/lib/test_pydantic.py +++ b/tests/lib/test_pydantic.py @@ -6,14 +6,14 @@ from inline_snapshot import snapshot import openai -from openai._compat import PYDANTIC_V2 +from openai._compat import PYDANTIC_V1 from openai.lib._pydantic import to_strict_json_schema from .schema_types.query import Query def test_most_types() -> None: - if PYDANTIC_V2: + if not PYDANTIC_V1: assert openai.pydantic_function_tool(Query)["function"] == snapshot( { "name": "Query", @@ -181,7 +181,7 @@ class ColorDetection(BaseModel): def test_enums() -> None: - if PYDANTIC_V2: + if not PYDANTIC_V1: assert openai.pydantic_function_tool(ColorDetection)["function"] == snapshot( { "name": "ColorDetection", @@ -253,7 +253,7 @@ class Universe(BaseModel): def test_nested_inline_ref_expansion() -> None: - if PYDANTIC_V2: + if not PYDANTIC_V1: assert to_strict_json_schema(Universe) == snapshot( { "title": "Universe", diff --git a/tests/test_models.py b/tests/test_models.py index 54a3a32048..410ec3bf4e 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -8,7 +8,7 @@ from pydantic import Field from openai._utils import PropertyInfo -from openai._compat import PYDANTIC_V2, parse_obj, model_dump, model_json +from openai._compat import PYDANTIC_V1, parse_obj, model_dump, model_json from openai._models import BaseModel, construct_type @@ -294,12 +294,12 @@ class Model(BaseModel): assert cast(bool, m.foo) is True m = Model.construct(foo={"name": 3}) - if PYDANTIC_V2: - assert isinstance(m.foo, Submodel1) - assert m.foo.name == 3 # type: ignore - else: + if PYDANTIC_V1: assert isinstance(m.foo, Submodel2) assert m.foo.name == "3" + else: + assert isinstance(m.foo, Submodel1) + assert m.foo.name == 3 # type: ignore def test_list_of_unions() -> None: @@ -426,10 +426,10 @@ class Model(BaseModel): expected = datetime(2019, 12, 27, 18, 11, 19, 117000, tzinfo=timezone.utc) - if PYDANTIC_V2: - expected_json = '{"created_at":"2019-12-27T18:11:19.117000Z"}' - else: + if PYDANTIC_V1: expected_json = '{"created_at": "2019-12-27T18:11:19.117000+00:00"}' + else: + expected_json = '{"created_at":"2019-12-27T18:11:19.117000Z"}' model = Model.construct(created_at="2019-12-27T18:11:19.117Z") assert model.created_at == expected @@ -531,7 +531,7 @@ class Model2(BaseModel): assert m4.to_dict(mode="python") == {"created_at": datetime.fromisoformat(time_str)} assert m4.to_dict(mode="json") == {"created_at": time_str} - if not PYDANTIC_V2: + if PYDANTIC_V1: with pytest.raises(ValueError, match="warnings is only supported in Pydantic v2"): m.to_dict(warnings=False) @@ -556,7 +556,7 @@ class Model(BaseModel): assert m3.model_dump() == {"foo": None} assert m3.model_dump(exclude_none=True) == {} - if not PYDANTIC_V2: + if PYDANTIC_V1: with pytest.raises(ValueError, match="round_trip is only supported in Pydantic v2"): m.model_dump(round_trip=True) @@ -580,10 +580,10 @@ class Model(BaseModel): assert json.loads(m.to_json()) == {"FOO": "hello"} assert json.loads(m.to_json(use_api_names=False)) == {"foo": "hello"} - if PYDANTIC_V2: - assert m.to_json(indent=None) == '{"FOO":"hello"}' - else: + if PYDANTIC_V1: assert m.to_json(indent=None) == '{"FOO": "hello"}' + else: + assert m.to_json(indent=None) == '{"FOO":"hello"}' m2 = Model() assert json.loads(m2.to_json()) == {} @@ -595,7 +595,7 @@ class Model(BaseModel): assert json.loads(m3.to_json()) == {"FOO": None} assert json.loads(m3.to_json(exclude_none=True)) == {} - if not PYDANTIC_V2: + if PYDANTIC_V1: with pytest.raises(ValueError, match="warnings is only supported in Pydantic v2"): m.to_json(warnings=False) @@ -622,7 +622,7 @@ class Model(BaseModel): assert json.loads(m3.model_dump_json()) == {"foo": None} assert json.loads(m3.model_dump_json(exclude_none=True)) == {} - if not PYDANTIC_V2: + if PYDANTIC_V1: with pytest.raises(ValueError, match="round_trip is only supported in Pydantic v2"): m.model_dump_json(round_trip=True) @@ -679,12 +679,12 @@ class B(BaseModel): ) assert isinstance(m, A) assert m.type == "a" - if PYDANTIC_V2: - assert m.data == 100 # type: ignore[comparison-overlap] - else: + if PYDANTIC_V1: # pydantic v1 automatically converts inputs to strings # if the expected type is a str assert m.data == "100" + else: + assert m.data == 100 # type: ignore[comparison-overlap] def test_discriminated_unions_unknown_variant() -> None: @@ -768,12 +768,12 @@ class B(BaseModel): ) assert isinstance(m, A) assert m.foo_type == "a" - if PYDANTIC_V2: - assert m.data == 100 # type: ignore[comparison-overlap] - else: + if PYDANTIC_V1: # pydantic v1 automatically converts inputs to strings # if the expected type is a str assert m.data == "100" + else: + assert m.data == 100 # type: ignore[comparison-overlap] def test_discriminated_unions_overlapping_discriminators_invalid_data() -> None: @@ -833,7 +833,7 @@ class B(BaseModel): assert UnionType.__discriminator__ is discriminator -@pytest.mark.skipif(not PYDANTIC_V2, reason="TypeAliasType is not supported in Pydantic v1") +@pytest.mark.skipif(PYDANTIC_V1, reason="TypeAliasType is not supported in Pydantic v1") def test_type_alias_type() -> None: Alias = TypeAliasType("Alias", str) # pyright: ignore @@ -849,7 +849,7 @@ class Model(BaseModel): assert m.union == "bar" -@pytest.mark.skipif(not PYDANTIC_V2, reason="TypeAliasType is not supported in Pydantic v1") +@pytest.mark.skipif(PYDANTIC_V1, reason="TypeAliasType is not supported in Pydantic v1") def test_field_named_cls() -> None: class Model(BaseModel): cls: str @@ -936,7 +936,7 @@ class Type2(BaseModel): assert isinstance(model.value, InnerType2) -@pytest.mark.skipif(not PYDANTIC_V2, reason="this is only supported in pydantic v2 for now") +@pytest.mark.skipif(PYDANTIC_V1, reason="this is only supported in pydantic v2 for now") def test_extra_properties() -> None: class Item(BaseModel): prop: int diff --git a/tests/test_transform.py b/tests/test_transform.py index 965f65f74f..036cfdfb06 100644 --- a/tests/test_transform.py +++ b/tests/test_transform.py @@ -15,7 +15,7 @@ parse_datetime, async_transform as _async_transform, ) -from openai._compat import PYDANTIC_V2 +from openai._compat import PYDANTIC_V1 from openai._models import BaseModel _T = TypeVar("_T") @@ -189,7 +189,7 @@ class DateModel(BaseModel): @pytest.mark.asyncio async def test_iso8601_format(use_async: bool) -> None: dt = datetime.fromisoformat("2023-02-23T14:16:36.337692+00:00") - tz = "Z" if PYDANTIC_V2 else "+00:00" + tz = "+00:00" if PYDANTIC_V1 else "Z" assert await transform({"foo": dt}, DatetimeDict, use_async) == {"foo": "2023-02-23T14:16:36.337692+00:00"} # type: ignore[comparison-overlap] assert await transform(DatetimeModel(foo=dt), Any, use_async) == {"foo": "2023-02-23T14:16:36.337692" + tz} # type: ignore[comparison-overlap] @@ -297,11 +297,11 @@ async def test_pydantic_unknown_field(use_async: bool) -> None: @pytest.mark.asyncio async def test_pydantic_mismatched_types(use_async: bool) -> None: model = MyModel.construct(foo=True) - if PYDANTIC_V2: + if PYDANTIC_V1: + params = await transform(model, Any, use_async) + else: with pytest.warns(UserWarning): params = await transform(model, Any, use_async) - else: - params = await transform(model, Any, use_async) assert cast(Any, params) == {"foo": True} @@ -309,11 +309,11 @@ async def test_pydantic_mismatched_types(use_async: bool) -> None: @pytest.mark.asyncio async def test_pydantic_mismatched_object_type(use_async: bool) -> None: model = MyModel.construct(foo=MyModel.construct(hello="world")) - if PYDANTIC_V2: + if PYDANTIC_V1: + params = await transform(model, Any, use_async) + else: with pytest.warns(UserWarning): params = await transform(model, Any, use_async) - else: - params = await transform(model, Any, use_async) assert cast(Any, params) == {"foo": {"hello": "world"}} diff --git a/tests/test_utils/test_datetime_parse.py b/tests/test_utils/test_datetime_parse.py new file mode 100644 index 0000000000..44c33a4ccb --- /dev/null +++ b/tests/test_utils/test_datetime_parse.py @@ -0,0 +1,110 @@ +""" +Copied from https://github.com/pydantic/pydantic/blob/v1.10.22/tests/test_datetime_parse.py +with modifications so it works without pydantic v1 imports. +""" + +from typing import Type, Union +from datetime import date, datetime, timezone, timedelta + +import pytest + +from openai._utils import parse_date, parse_datetime + + +def create_tz(minutes: int) -> timezone: + return timezone(timedelta(minutes=minutes)) + + +@pytest.mark.parametrize( + "value,result", + [ + # Valid inputs + ("1494012444.883309", date(2017, 5, 5)), + (b"1494012444.883309", date(2017, 5, 5)), + (1_494_012_444.883_309, date(2017, 5, 5)), + ("1494012444", date(2017, 5, 5)), + (1_494_012_444, date(2017, 5, 5)), + (0, date(1970, 1, 1)), + ("2012-04-23", date(2012, 4, 23)), + (b"2012-04-23", date(2012, 4, 23)), + ("2012-4-9", date(2012, 4, 9)), + (date(2012, 4, 9), date(2012, 4, 9)), + (datetime(2012, 4, 9, 12, 15), date(2012, 4, 9)), + # Invalid inputs + ("x20120423", ValueError), + ("2012-04-56", ValueError), + (19_999_999_999, date(2603, 10, 11)), # just before watershed + (20_000_000_001, date(1970, 8, 20)), # just after watershed + (1_549_316_052, date(2019, 2, 4)), # nowish in s + (1_549_316_052_104, date(2019, 2, 4)), # nowish in ms + (1_549_316_052_104_324, date(2019, 2, 4)), # nowish in μs + (1_549_316_052_104_324_096, date(2019, 2, 4)), # nowish in ns + ("infinity", date(9999, 12, 31)), + ("inf", date(9999, 12, 31)), + (float("inf"), date(9999, 12, 31)), + ("infinity ", date(9999, 12, 31)), + (int("1" + "0" * 100), date(9999, 12, 31)), + (1e1000, date(9999, 12, 31)), + ("-infinity", date(1, 1, 1)), + ("-inf", date(1, 1, 1)), + ("nan", ValueError), + ], +) +def test_date_parsing(value: Union[str, bytes, int, float], result: Union[date, Type[Exception]]) -> None: + if type(result) == type and issubclass(result, Exception): # pyright: ignore[reportUnnecessaryIsInstance] + with pytest.raises(result): + parse_date(value) + else: + assert parse_date(value) == result + + +@pytest.mark.parametrize( + "value,result", + [ + # Valid inputs + # values in seconds + ("1494012444.883309", datetime(2017, 5, 5, 19, 27, 24, 883_309, tzinfo=timezone.utc)), + (1_494_012_444.883_309, datetime(2017, 5, 5, 19, 27, 24, 883_309, tzinfo=timezone.utc)), + ("1494012444", datetime(2017, 5, 5, 19, 27, 24, tzinfo=timezone.utc)), + (b"1494012444", datetime(2017, 5, 5, 19, 27, 24, tzinfo=timezone.utc)), + (1_494_012_444, datetime(2017, 5, 5, 19, 27, 24, tzinfo=timezone.utc)), + # values in ms + ("1494012444000.883309", datetime(2017, 5, 5, 19, 27, 24, 883, tzinfo=timezone.utc)), + ("-1494012444000.883309", datetime(1922, 8, 29, 4, 32, 35, 999117, tzinfo=timezone.utc)), + (1_494_012_444_000, datetime(2017, 5, 5, 19, 27, 24, tzinfo=timezone.utc)), + ("2012-04-23T09:15:00", datetime(2012, 4, 23, 9, 15)), + ("2012-4-9 4:8:16", datetime(2012, 4, 9, 4, 8, 16)), + ("2012-04-23T09:15:00Z", datetime(2012, 4, 23, 9, 15, 0, 0, timezone.utc)), + ("2012-4-9 4:8:16-0320", datetime(2012, 4, 9, 4, 8, 16, 0, create_tz(-200))), + ("2012-04-23T10:20:30.400+02:30", datetime(2012, 4, 23, 10, 20, 30, 400_000, create_tz(150))), + ("2012-04-23T10:20:30.400+02", datetime(2012, 4, 23, 10, 20, 30, 400_000, create_tz(120))), + ("2012-04-23T10:20:30.400-02", datetime(2012, 4, 23, 10, 20, 30, 400_000, create_tz(-120))), + (b"2012-04-23T10:20:30.400-02", datetime(2012, 4, 23, 10, 20, 30, 400_000, create_tz(-120))), + (datetime(2017, 5, 5), datetime(2017, 5, 5)), + (0, datetime(1970, 1, 1, 0, 0, 0, tzinfo=timezone.utc)), + # Invalid inputs + ("x20120423091500", ValueError), + ("2012-04-56T09:15:90", ValueError), + ("2012-04-23T11:05:00-25:00", ValueError), + (19_999_999_999, datetime(2603, 10, 11, 11, 33, 19, tzinfo=timezone.utc)), # just before watershed + (20_000_000_001, datetime(1970, 8, 20, 11, 33, 20, 1000, tzinfo=timezone.utc)), # just after watershed + (1_549_316_052, datetime(2019, 2, 4, 21, 34, 12, 0, tzinfo=timezone.utc)), # nowish in s + (1_549_316_052_104, datetime(2019, 2, 4, 21, 34, 12, 104_000, tzinfo=timezone.utc)), # nowish in ms + (1_549_316_052_104_324, datetime(2019, 2, 4, 21, 34, 12, 104_324, tzinfo=timezone.utc)), # nowish in μs + (1_549_316_052_104_324_096, datetime(2019, 2, 4, 21, 34, 12, 104_324, tzinfo=timezone.utc)), # nowish in ns + ("infinity", datetime(9999, 12, 31, 23, 59, 59, 999999)), + ("inf", datetime(9999, 12, 31, 23, 59, 59, 999999)), + ("inf ", datetime(9999, 12, 31, 23, 59, 59, 999999)), + (1e50, datetime(9999, 12, 31, 23, 59, 59, 999999)), + (float("inf"), datetime(9999, 12, 31, 23, 59, 59, 999999)), + ("-infinity", datetime(1, 1, 1, 0, 0)), + ("-inf", datetime(1, 1, 1, 0, 0)), + ("nan", ValueError), + ], +) +def test_datetime_parsing(value: Union[str, bytes, int, float], result: Union[datetime, Type[Exception]]) -> None: + if type(result) == type and issubclass(result, Exception): # pyright: ignore[reportUnnecessaryIsInstance] + with pytest.raises(result): + parse_datetime(value) + else: + assert parse_datetime(value) == result diff --git a/tests/utils.py b/tests/utils.py index a07052140b..e03ed1a039 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -22,7 +22,7 @@ is_annotated_type, is_type_alias_type, ) -from openai._compat import PYDANTIC_V2, field_outer_type, get_model_fields +from openai._compat import PYDANTIC_V1, field_outer_type, get_model_fields from openai._models import BaseModel BaseModelT = TypeVar("BaseModelT", bound=BaseModel) @@ -35,12 +35,12 @@ def evaluate_forwardref(forwardref: ForwardRef, globalns: dict[str, Any]) -> typ def assert_matches_model(model: type[BaseModelT], value: BaseModelT, *, path: list[str]) -> bool: for name, field in get_model_fields(model).items(): field_value = getattr(value, name) - if PYDANTIC_V2: - allow_none = False - else: + if PYDANTIC_V1: # in v1 nullability was structured differently # https://docs.pydantic.dev/2.0/migration/#required-optional-and-nullable-fields allow_none = getattr(field, "allow_none", False) + else: + allow_none = False assert_matches_type( field_outer_type(field), From 2de8d7cde5565ec71851d8bc3a26f021cebab32c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 4 Sep 2025 13:34:31 +0000 Subject: [PATCH 485/769] release: 1.106.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 9 +++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 1e15251d64..3064ce9554 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.105.0" + ".": "1.106.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ed3bbe6ed..423ace20c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 1.106.0 (2025-09-04) + +Full Changelog: [v1.105.0...v1.106.0](https://github.com/openai/openai-python/compare/v1.105.0...v1.106.0) + +### Features + +* **client:** support callable api_key ([#2588](https://github.com/openai/openai-python/issues/2588)) ([e1bad01](https://github.com/openai/openai-python/commit/e1bad015b8a2b98bfee955a24bc931347a58efc1)) +* improve future compat with pydantic v3 ([6645d93](https://github.com/openai/openai-python/commit/6645d9317a240982928b92c2f4af0381db6edc09)) + ## 1.105.0 (2025-09-03) Full Changelog: [v1.104.2...v1.105.0](https://github.com/openai/openai-python/compare/v1.104.2...v1.105.0) diff --git a/pyproject.toml b/pyproject.toml index 587ca41e01..94d85b8442 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.105.0" +version = "1.106.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 5509cd4d8e..6a8d9a3e2d 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.105.0" # x-release-please-version +__version__ = "1.106.0" # x-release-please-version From c4f9d0b997e18614709752e030f85d9e8281b4e0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 4 Sep 2025 14:54:58 +0000 Subject: [PATCH 486/769] chore(internal): move mypy configurations to `pyproject.toml` file --- mypy.ini | 53 ------------------------------------------- pyproject.toml | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 53 deletions(-) delete mode 100644 mypy.ini diff --git a/mypy.ini b/mypy.ini deleted file mode 100644 index 660f1a086e..0000000000 --- a/mypy.ini +++ /dev/null @@ -1,53 +0,0 @@ -[mypy] -pretty = True -show_error_codes = True - -# Exclude _files.py and _logs.py because mypy isn't smart enough to apply -# the correct type narrowing and as this is an internal module -# it's fine to just use Pyright. -# -# We also exclude our `tests` as mypy doesn't always infer -# types correctly and Pyright will still catch any type errors. - -# realtime examples use inline `uv` script dependencies -# which means it can't be type checked -exclude = ^(src/openai/_files\.py|_dev/.*\.py|tests/.*|src/openai/_utils/_logs\.py|examples/realtime/audio_util\.py|examples/realtime/push_to_talk_app\.py)$ - -strict_equality = True -implicit_reexport = True -check_untyped_defs = True -no_implicit_optional = True - -warn_return_any = True -warn_unreachable = True -warn_unused_configs = True - -# Turn these options off as it could cause conflicts -# with the Pyright options. -warn_unused_ignores = False -warn_redundant_casts = False - -disallow_any_generics = True -disallow_untyped_defs = True -disallow_untyped_calls = True -disallow_subclassing_any = True -disallow_incomplete_defs = True -disallow_untyped_decorators = True -cache_fine_grained = True - -# By default, mypy reports an error if you assign a value to the result -# of a function call that doesn't return anything. We do this in our test -# cases: -# ``` -# result = ... -# assert result is None -# ``` -# Changing this codegen to make mypy happy would increase complexity -# and would not be worth it. -disable_error_code = func-returns-value,overload-cannot-match - -# https://github.com/python/mypy/issues/12162 -[mypy.overrides] -module = "black.files.*" -ignore_errors = true -ignore_missing_imports = true diff --git a/pyproject.toml b/pyproject.toml index 94d85b8442..c420bfa1e3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -179,6 +179,67 @@ reportOverlappingOverload = false reportImportCycles = false reportPrivateUsage = false +[tool.mypy] +pretty = true +show_error_codes = true + +# Exclude _files.py because mypy isn't smart enough to apply +# the correct type narrowing and as this is an internal module +# it's fine to just use Pyright. +# +# We also exclude our `tests` as mypy doesn't always infer +# types correctly and Pyright will still catch any type errors. +# +# realtime examples use inline `uv` script dependencies +# which means it can't be type checked +exclude = [ + 'src/openai/_files.py', + '_dev/.*.py', + 'tests/.*', + 'src/openai/_utils/_logs.py', + 'examples/realtime/audio_util.py', + 'examples/realtime/push_to_talk_app.py', +] + +strict_equality = true +implicit_reexport = true +check_untyped_defs = true +no_implicit_optional = true + +warn_return_any = true +warn_unreachable = true +warn_unused_configs = true + +# Turn these options off as it could cause conflicts +# with the Pyright options. +warn_unused_ignores = false +warn_redundant_casts = false + +disallow_any_generics = true +disallow_untyped_defs = true +disallow_untyped_calls = true +disallow_subclassing_any = true +disallow_incomplete_defs = true +disallow_untyped_decorators = true +cache_fine_grained = true + +# By default, mypy reports an error if you assign a value to the result +# of a function call that doesn't return anything. We do this in our test +# cases: +# ``` +# result = ... +# assert result is None +# ``` +# Changing this codegen to make mypy happy would increase complexity +# and would not be worth it. +disable_error_code = "func-returns-value,overload-cannot-match" + +# https://github.com/python/mypy/issues/12162 +[[tool.mypy.overrides]] +module = "black.files.*" +ignore_errors = true +ignore_missing_imports = true + [tool.ruff] line-length = 120 output-format = "grouped" From 2adf11112988e998fcf5adb805bae38501d22318 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 4 Sep 2025 14:55:32 +0000 Subject: [PATCH 487/769] release: 1.106.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 3064ce9554..f2761d4022 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.106.0" + ".": "1.106.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 423ace20c9..c0ad7d1490 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.106.1 (2025-09-04) + +Full Changelog: [v1.106.0...v1.106.1](https://github.com/openai/openai-python/compare/v1.106.0...v1.106.1) + +### Chores + +* **internal:** move mypy configurations to `pyproject.toml` file ([ca413a2](https://github.com/openai/openai-python/commit/ca413a277496c3b883b103ad1138a886e89ae15e)) + ## 1.106.0 (2025-09-04) Full Changelog: [v1.105.0...v1.106.0](https://github.com/openai/openai-python/compare/v1.105.0...v1.106.0) diff --git a/pyproject.toml b/pyproject.toml index c420bfa1e3..82aa72b045 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.106.0" +version = "1.106.1" 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 6a8d9a3e2d..33c16fef6a 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.106.0" # x-release-please-version +__version__ = "1.106.1" # x-release-please-version From 0296375f9cf45ed3786292a0c03bb52a2ca06b94 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 8 Sep 2025 15:24:53 -0400 Subject: [PATCH 488/769] release: 1.107.0 (#2613) * chore(internal): codegen related update * feat(api): ship the RealtimeGA API shape Updates types to use the GA shape for Realtime API * release: 1.107.0 --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- .stats.yml | 6 +- CHANGELOG.md | 13 + api.md | 25 +- pyproject.toml | 2 +- requirements-dev.lock | 2 +- src/openai/_version.py | 2 +- .../resources/realtime/client_secrets.py | 16 +- src/openai/resources/realtime/realtime.py | 129 +++--- src/openai/types/realtime/__init__.py | 65 +++- .../types/realtime/audio_transcription.py | 36 ++ .../realtime/audio_transcription_param.py | 33 ++ .../realtime/client_secret_create_params.py | 17 +- .../realtime/client_secret_create_response.py | 97 +---- ...put_audio_transcription_completed_event.py | 7 +- ...m_input_audio_transcription_delta_event.py | 11 +- .../conversation_item_truncate_event.py | 2 +- .../conversation_item_truncate_event_param.py | 2 +- src/openai/types/realtime/models.py | 25 ++ src/openai/types/realtime/models_param.py | 24 ++ .../types/realtime/noise_reduction_type.py | 7 + .../types/realtime/realtime_audio_config.py | 181 +-------- .../realtime/realtime_audio_config_input.py | 60 +++ .../realtime_audio_config_input_param.py | 61 +++ .../realtime/realtime_audio_config_output.py | 36 ++ .../realtime_audio_config_output_param.py | 35 ++ .../realtime/realtime_audio_config_param.py | 183 +-------- .../types/realtime/realtime_audio_formats.py | 30 ++ .../realtime/realtime_audio_formats_param.py | 29 ++ .../realtime_audio_input_turn_detection.py | 64 +++ ...altime_audio_input_turn_detection_param.py | 64 +++ .../realtime/realtime_client_secret_config.py | 27 -- .../realtime_client_secret_config_param.py | 26 -- ...ime_conversation_item_assistant_message.py | 30 +- ...nversation_item_assistant_message_param.py | 30 +- ...ealtime_conversation_item_function_call.py | 16 +- ..._conversation_item_function_call_output.py | 15 +- ...rsation_item_function_call_output_param.py | 15 +- ...e_conversation_item_function_call_param.py | 16 +- ...altime_conversation_item_system_message.py | 10 +- ..._conversation_item_system_message_param.py | 10 +- ...realtime_conversation_item_user_message.py | 39 +- ...me_conversation_item_user_message_param.py | 39 +- .../types/realtime/realtime_response.py | 59 +-- .../realtime_response_create_audio_output.py | 29 ++ ...time_response_create_audio_output_param.py | 28 ++ .../realtime_response_create_mcp_tool.py | 135 +++++++ ...realtime_response_create_mcp_tool_param.py | 135 +++++++ .../realtime_response_create_params.py | 98 +++++ .../realtime_response_create_params_param.py | 99 +++++ .../types/realtime/realtime_response_usage.py | 8 +- ...time_response_usage_input_token_details.py | 25 +- src/openai/types/realtime/realtime_session.py | 307 --------------- .../realtime_session_client_secret.py | 20 + .../realtime_session_create_request.py | 63 ++- .../realtime_session_create_request_param.py | 64 ++- .../realtime_session_create_response.py | 368 ++++++++++++++---- .../realtime/realtime_tools_config_param.py | 21 +- .../realtime/realtime_tools_config_union.py | 21 +- .../realtime_tools_config_union_param.py | 21 +- .../types/realtime/realtime_tracing_config.py | 8 +- .../realtime/realtime_tracing_config_param.py | 8 +- .../realtime_transcription_session_audio.py | 12 + ...ltime_transcription_session_audio_input.py | 62 +++ ...transcription_session_audio_input_param.py | 63 +++ ...tion_session_audio_input_turn_detection.py | 63 +++ ...ession_audio_input_turn_detection_param.py | 63 +++ ...ltime_transcription_session_audio_param.py | 13 + ...ime_transcription_session_client_secret.py | 20 + ...me_transcription_session_create_request.py | 119 +----- ...nscription_session_create_request_param.py | 118 +----- ...e_transcription_session_create_response.py | 41 ++ ...ption_session_input_audio_transcription.py | 36 ++ ...me_transcription_session_turn_detection.py | 32 ++ .../types/realtime/realtime_truncation.py | 20 +- .../realtime/realtime_truncation_param.py | 20 +- .../realtime_truncation_retention_ratio.py | 18 + ...altime_truncation_retention_ratio_param.py | 18 + .../types/realtime/response_create_event.py | 124 +----- .../realtime/response_create_event_param.py | 121 +----- .../types/realtime/session_created_event.py | 14 +- .../types/realtime/session_update_event.py | 23 +- .../realtime/session_update_event_param.py | 22 +- .../types/realtime/session_updated_event.py | 14 +- .../realtime/transcription_session_created.py | 99 +---- .../realtime/transcription_session_update.py | 86 +++- .../transcription_session_update_param.py | 85 +++- .../transcription_session_updated_event.py | 99 +---- .../realtime/test_client_secrets.py | 38 +- 89 files changed, 2603 insertions(+), 1896 deletions(-) create mode 100644 src/openai/types/realtime/audio_transcription.py create mode 100644 src/openai/types/realtime/audio_transcription_param.py create mode 100644 src/openai/types/realtime/models.py create mode 100644 src/openai/types/realtime/models_param.py create mode 100644 src/openai/types/realtime/noise_reduction_type.py create mode 100644 src/openai/types/realtime/realtime_audio_config_input.py create mode 100644 src/openai/types/realtime/realtime_audio_config_input_param.py create mode 100644 src/openai/types/realtime/realtime_audio_config_output.py create mode 100644 src/openai/types/realtime/realtime_audio_config_output_param.py create mode 100644 src/openai/types/realtime/realtime_audio_formats.py create mode 100644 src/openai/types/realtime/realtime_audio_formats_param.py create mode 100644 src/openai/types/realtime/realtime_audio_input_turn_detection.py create mode 100644 src/openai/types/realtime/realtime_audio_input_turn_detection_param.py delete mode 100644 src/openai/types/realtime/realtime_client_secret_config.py delete mode 100644 src/openai/types/realtime/realtime_client_secret_config_param.py create mode 100644 src/openai/types/realtime/realtime_response_create_audio_output.py create mode 100644 src/openai/types/realtime/realtime_response_create_audio_output_param.py create mode 100644 src/openai/types/realtime/realtime_response_create_mcp_tool.py create mode 100644 src/openai/types/realtime/realtime_response_create_mcp_tool_param.py create mode 100644 src/openai/types/realtime/realtime_response_create_params.py create mode 100644 src/openai/types/realtime/realtime_response_create_params_param.py delete mode 100644 src/openai/types/realtime/realtime_session.py create mode 100644 src/openai/types/realtime/realtime_session_client_secret.py create mode 100644 src/openai/types/realtime/realtime_transcription_session_audio.py create mode 100644 src/openai/types/realtime/realtime_transcription_session_audio_input.py create mode 100644 src/openai/types/realtime/realtime_transcription_session_audio_input_param.py create mode 100644 src/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection.py create mode 100644 src/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection_param.py create mode 100644 src/openai/types/realtime/realtime_transcription_session_audio_param.py create mode 100644 src/openai/types/realtime/realtime_transcription_session_client_secret.py create mode 100644 src/openai/types/realtime/realtime_transcription_session_create_response.py create mode 100644 src/openai/types/realtime/realtime_transcription_session_input_audio_transcription.py create mode 100644 src/openai/types/realtime/realtime_transcription_session_turn_detection.py create mode 100644 src/openai/types/realtime/realtime_truncation_retention_ratio.py create mode 100644 src/openai/types/realtime/realtime_truncation_retention_ratio_param.py diff --git a/.release-please-manifest.json b/.release-please-manifest.json index f2761d4022..12cec28d56 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.106.1" + ".": "1.107.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index c41be6ee57..36a3c7f587 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 118 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-51afd6abbcb18c3086f62993f9379c18443b9e516cbc0548ddfb932e835657f8.yml -openapi_spec_hash: dae6afeaefa15cb8700c7a870531e06f -config_hash: b854932c0ea24b400bdd64e4376936bd +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-7807ec6037efcee1af7decbfd3974a42b761fb6c6a71b4050fe43484d7fcbac4.yml +openapi_spec_hash: da6851e3891ad2659a50ed6a736fd32a +config_hash: 74d955cdc2377213f5268ea309090f6c diff --git a/CHANGELOG.md b/CHANGELOG.md index c0ad7d1490..76d5dcb2dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 1.107.0 (2025-09-08) + +Full Changelog: [v1.106.1...v1.107.0](https://github.com/openai/openai-python/compare/v1.106.1...v1.107.0) + +### Features + +* **api:** ship the RealtimeGA API shape ([dc319d8](https://github.com/openai/openai-python/commit/dc319d8bbb3a20108399c1d15f98e63bdd84eb5c)) + + +### Chores + +* **internal:** codegen related update ([b79b7ca](https://github.com/openai/openai-python/commit/b79b7ca3a72009a036db0a344b500f616ca0443f)) + ## 1.106.1 (2025-09-04) Full Changelog: [v1.106.0...v1.106.1](https://github.com/openai/openai-python/compare/v1.106.0...v1.106.1) diff --git a/api.md b/api.md index a8a95bd23e..7c947fffe1 100644 --- a/api.md +++ b/api.md @@ -863,6 +863,7 @@ Types: ```python from openai.types.realtime import ( + AudioTranscription, ConversationCreatedEvent, ConversationItem, ConversationItemAdded, @@ -891,11 +892,16 @@ from openai.types.realtime import ( McpListToolsCompleted, McpListToolsFailed, McpListToolsInProgress, + Models, + NoiseReductionType, OutputAudioBufferClearEvent, RateLimitsUpdatedEvent, RealtimeAudioConfig, + RealtimeAudioConfigInput, + RealtimeAudioConfigOutput, + RealtimeAudioFormats, + RealtimeAudioInputTurnDetection, RealtimeClientEvent, - RealtimeClientSecretConfig, RealtimeConversationItemAssistantMessage, RealtimeConversationItemFunctionCall, RealtimeConversationItemFunctionCallOutput, @@ -911,6 +917,9 @@ from openai.types.realtime import ( RealtimeMcpToolExecutionError, RealtimeMcphttpError, RealtimeResponse, + RealtimeResponseCreateAudioOutput, + RealtimeResponseCreateMcpTool, + RealtimeResponseCreateParams, RealtimeResponseStatus, RealtimeResponseUsage, RealtimeResponseUsageInputTokenDetails, @@ -922,8 +931,12 @@ from openai.types.realtime import ( RealtimeToolsConfig, RealtimeToolsConfigUnion, RealtimeTracingConfig, + RealtimeTranscriptionSessionAudio, + RealtimeTranscriptionSessionAudioInput, + RealtimeTranscriptionSessionAudioInputTurnDetection, RealtimeTranscriptionSessionCreateRequest, RealtimeTruncation, + RealtimeTruncationRetentionRatio, ResponseAudioDeltaEvent, ResponseAudioDoneEvent, ResponseAudioTranscriptDeltaEvent, @@ -959,7 +972,15 @@ from openai.types.realtime import ( Types: ```python -from openai.types.realtime import RealtimeSessionCreateResponse, ClientSecretCreateResponse +from openai.types.realtime import ( + RealtimeSessionClientSecret, + RealtimeSessionCreateResponse, + RealtimeTranscriptionSessionClientSecret, + RealtimeTranscriptionSessionCreateResponse, + RealtimeTranscriptionSessionInputAudioTranscription, + RealtimeTranscriptionSessionTurnDetection, + ClientSecretCreateResponse, +) ``` Methods: diff --git a/pyproject.toml b/pyproject.toml index 82aa72b045..5c3985cc7c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.106.1" +version = "1.107.0" description = "The official Python library for the openai API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/requirements-dev.lock b/requirements-dev.lock index 669378387d..7d690683e9 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -70,7 +70,7 @@ filelock==3.12.4 frozenlist==1.7.0 # via aiohttp # via aiosignal -griffe==1.13.0 +griffe==1.14.0 h11==0.16.0 # via httpcore httpcore==1.0.9 diff --git a/src/openai/_version.py b/src/openai/_version.py index 33c16fef6a..06826fc4de 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.106.1" # x-release-please-version +__version__ = "1.107.0" # x-release-please-version diff --git a/src/openai/resources/realtime/client_secrets.py b/src/openai/resources/realtime/client_secrets.py index ba0f9ee538..a79460746d 100644 --- a/src/openai/resources/realtime/client_secrets.py +++ b/src/openai/resources/realtime/client_secrets.py @@ -50,11 +50,13 @@ def create( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> ClientSecretCreateResponse: """ - Create a Realtime session and client secret for either realtime or - transcription. + Create a Realtime client secret with an associated session configuration. Args: - expires_after: Configuration for the ephemeral token expiration. + expires_after: Configuration for the client secret expiration. Expiration refers to the time + after which a client secret will no longer be valid for creating sessions. The + session itself may continue after that time once started. A secret can be used + to create multiple sessions until it expires. session: Session configuration to use for the client secret. Choose either a realtime session or a transcription session. @@ -116,11 +118,13 @@ async def create( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> ClientSecretCreateResponse: """ - Create a Realtime session and client secret for either realtime or - transcription. + Create a Realtime client secret with an associated session configuration. Args: - expires_after: Configuration for the ephemeral token expiration. + expires_after: Configuration for the client secret expiration. Expiration refers to the time + after which a client secret will no longer be valid for creating sessions. The + session itself may continue after that time once started. A secret can be used + to create multiple sessions until it expires. session: Session configuration to use for the client secret. Choose either a realtime session or a transcription session. diff --git a/src/openai/resources/realtime/realtime.py b/src/openai/resources/realtime/realtime.py index 2f5adf6548..81e6dc54f5 100644 --- a/src/openai/resources/realtime/realtime.py +++ b/src/openai/resources/realtime/realtime.py @@ -32,16 +32,13 @@ ClientSecretsWithStreamingResponse, AsyncClientSecretsWithStreamingResponse, ) -from ...types.realtime import response_create_event_param +from ...types.realtime import session_update_event_param, transcription_session_update_param from ...types.websocket_connection_options import WebsocketConnectionOptions from ...types.realtime.realtime_client_event import RealtimeClientEvent from ...types.realtime.realtime_server_event import RealtimeServerEvent from ...types.realtime.conversation_item_param import ConversationItemParam from ...types.realtime.realtime_client_event_param import RealtimeClientEventParam -from ...types.realtime.realtime_session_create_request_param import RealtimeSessionCreateRequestParam -from ...types.realtime.realtime_transcription_session_create_request_param import ( - RealtimeTranscriptionSessionCreateRequestParam, -) +from ...types.realtime.realtime_response_create_params_param import RealtimeResponseCreateParamsParam if TYPE_CHECKING: from websockets.sync.client import ClientConnection as WebsocketConnection @@ -564,18 +561,18 @@ def __init__(self, connection: RealtimeConnection) -> None: class RealtimeSessionResource(BaseRealtimeConnectionResource): - def update(self, *, session: RealtimeSessionCreateRequestParam, event_id: str | NotGiven = NOT_GIVEN) -> None: + def update(self, *, session: session_update_event_param.Session, event_id: str | NotGiven = NOT_GIVEN) -> None: """ - Send this event to update the session’s default configuration. - The client may send this event at any time to update any field, - except for `voice`. However, note that once a session has been - initialized with a particular `model`, it can’t be changed to - another model using `session.update`. + Send this event to update the session’s configuration. + The client may send this event at any time to update any field + except for `voice` and `model`. `voice` can be updated only if there have been no other + audio outputs yet. When the server receives a `session.update`, it will respond with a `session.updated` event showing the full, effective configuration. - Only the fields that are present are updated. To clear a field like - `instructions`, pass an empty string. + Only the fields that are present in the `session.update` are updated. To clear a field like + `instructions`, pass an empty string. To clear a field like `tools`, pass an empty array. + To clear a field like `turn_detection`, pass `null`. """ self._connection.send( cast( @@ -590,7 +587,7 @@ def create( self, *, event_id: str | NotGiven = NOT_GIVEN, - response: response_create_event_param.Response | NotGiven = NOT_GIVEN, + response: RealtimeResponseCreateParamsParam | NotGiven = NOT_GIVEN, ) -> None: """ This event instructs the server to create a Response, which means triggering @@ -599,15 +596,25 @@ def create( A Response will include at least one Item, and may have two, in which case the second will be a function call. These Items will be appended to the - conversation history. + conversation history by default. The server will respond with a `response.created` event, events for Items and content created, and finally a `response.done` event to indicate the Response is complete. The `response.create` event includes inference configuration like - `instructions`, and `temperature`. These fields will override the Session's + `instructions` and `tools`. If these are set, they will override the Session's configuration for this Response only. + + Responses can be created out-of-band of the default Conversation, meaning that they can + have arbitrary input, and it's possible to disable writing the output to the Conversation. + Only one Response can write to the default Conversation at a time, but otherwise multiple + Responses can be created in parallel. The `metadata` field is a good way to disambiguate + multiple simultaneous Responses. + + Clients can set `conversation` to `none` to create a Response that does not write to the default + Conversation. Arbitrary input can be provided with the `input` field, which is an array accepting + raw Items and references to existing Items. """ self._connection.send( cast( @@ -621,7 +628,9 @@ def cancel(self, *, event_id: str | NotGiven = NOT_GIVEN, response_id: str | Not The server will respond with a `response.done` event with a status of `response.status=cancelled`. If - there is no response to cancel, the server will respond with an error. + there is no response to cancel, the server will respond with an error. It's safe + to call `response.cancel` even if no response is in progress, an error will be + returned the session will remain unaffected. """ self._connection.send( cast( @@ -644,16 +653,9 @@ def clear(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: def commit(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: """ - Send this event to commit the user input audio buffer, which will create a - new user message item in the conversation. This event will produce an error - if the input audio buffer is empty. When in Server VAD mode, the client does - not need to send this event, the server will commit the audio buffer - automatically. + Send this event to commit the user input audio buffer, which will create a new user message item in the conversation. This event will produce an error if the input audio buffer is empty. When in Server VAD mode, the client does not need to send this event, the server will commit the audio buffer automatically. - Committing the input audio buffer will trigger input audio transcription - (if enabled in session configuration), but it will not create a response - from the model. The server will respond with an `input_audio_buffer.committed` - event. + Committing the input audio buffer will trigger input audio transcription (if enabled in session configuration), but it will not create a response from the model. The server will respond with an `input_audio_buffer.committed` event. """ self._connection.send( cast(RealtimeClientEventParam, strip_not_given({"type": "input_audio_buffer.commit", "event_id": event_id})) @@ -663,14 +665,17 @@ def append(self, *, audio: str, event_id: str | NotGiven = NOT_GIVEN) -> None: """Send this event to append audio bytes to the input audio buffer. The audio - buffer is temporary storage you can write to and later commit. In Server VAD - mode, the audio buffer is used to detect speech and the server will decide + buffer is temporary storage you can write to and later commit. A "commit" will create a new + user message item in the conversation history from the buffer content and clear the buffer. + Input audio transcription (if enabled) will be generated when the buffer is committed. + + If VAD is enabled the audio buffer is used to detect speech and the server will decide when to commit. When Server VAD is disabled, you must commit the audio buffer - manually. + manually. Input audio noise reduction operates on writes to the audio buffer. The client may choose how much audio to place in each event up to a maximum of 15 MiB, for example streaming smaller chunks from the client may allow the - VAD to be more responsive. Unlike made other client events, the server will + VAD to be more responsive. Unlike most other client events, the server will not send a confirmation response to this event. """ self._connection.send( @@ -797,7 +802,7 @@ def clear(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: class RealtimeTranscriptionSessionResource(BaseRealtimeConnectionResource): def update( - self, *, session: RealtimeTranscriptionSessionCreateRequestParam, event_id: str | NotGiven = NOT_GIVEN + self, *, session: transcription_session_update_param.Session, event_id: str | NotGiven = NOT_GIVEN ) -> None: """Send this event to update a transcription session.""" self._connection.send( @@ -814,18 +819,20 @@ def __init__(self, connection: AsyncRealtimeConnection) -> None: class AsyncRealtimeSessionResource(BaseAsyncRealtimeConnectionResource): - async def update(self, *, session: RealtimeSessionCreateRequestParam, event_id: str | NotGiven = NOT_GIVEN) -> None: + async def update( + self, *, session: session_update_event_param.Session, event_id: str | NotGiven = NOT_GIVEN + ) -> None: """ - Send this event to update the session’s default configuration. - The client may send this event at any time to update any field, - except for `voice`. However, note that once a session has been - initialized with a particular `model`, it can’t be changed to - another model using `session.update`. + Send this event to update the session’s configuration. + The client may send this event at any time to update any field + except for `voice` and `model`. `voice` can be updated only if there have been no other + audio outputs yet. When the server receives a `session.update`, it will respond with a `session.updated` event showing the full, effective configuration. - Only the fields that are present are updated. To clear a field like - `instructions`, pass an empty string. + Only the fields that are present in the `session.update` are updated. To clear a field like + `instructions`, pass an empty string. To clear a field like `tools`, pass an empty array. + To clear a field like `turn_detection`, pass `null`. """ await self._connection.send( cast( @@ -840,7 +847,7 @@ async def create( self, *, event_id: str | NotGiven = NOT_GIVEN, - response: response_create_event_param.Response | NotGiven = NOT_GIVEN, + response: RealtimeResponseCreateParamsParam | NotGiven = NOT_GIVEN, ) -> None: """ This event instructs the server to create a Response, which means triggering @@ -849,15 +856,25 @@ async def create( A Response will include at least one Item, and may have two, in which case the second will be a function call. These Items will be appended to the - conversation history. + conversation history by default. The server will respond with a `response.created` event, events for Items and content created, and finally a `response.done` event to indicate the Response is complete. The `response.create` event includes inference configuration like - `instructions`, and `temperature`. These fields will override the Session's + `instructions` and `tools`. If these are set, they will override the Session's configuration for this Response only. + + Responses can be created out-of-band of the default Conversation, meaning that they can + have arbitrary input, and it's possible to disable writing the output to the Conversation. + Only one Response can write to the default Conversation at a time, but otherwise multiple + Responses can be created in parallel. The `metadata` field is a good way to disambiguate + multiple simultaneous Responses. + + Clients can set `conversation` to `none` to create a Response that does not write to the default + Conversation. Arbitrary input can be provided with the `input` field, which is an array accepting + raw Items and references to existing Items. """ await self._connection.send( cast( @@ -871,7 +888,9 @@ async def cancel(self, *, event_id: str | NotGiven = NOT_GIVEN, response_id: str The server will respond with a `response.done` event with a status of `response.status=cancelled`. If - there is no response to cancel, the server will respond with an error. + there is no response to cancel, the server will respond with an error. It's safe + to call `response.cancel` even if no response is in progress, an error will be + returned the session will remain unaffected. """ await self._connection.send( cast( @@ -894,16 +913,9 @@ async def clear(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: async def commit(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: """ - Send this event to commit the user input audio buffer, which will create a - new user message item in the conversation. This event will produce an error - if the input audio buffer is empty. When in Server VAD mode, the client does - not need to send this event, the server will commit the audio buffer - automatically. + Send this event to commit the user input audio buffer, which will create a new user message item in the conversation. This event will produce an error if the input audio buffer is empty. When in Server VAD mode, the client does not need to send this event, the server will commit the audio buffer automatically. - Committing the input audio buffer will trigger input audio transcription - (if enabled in session configuration), but it will not create a response - from the model. The server will respond with an `input_audio_buffer.committed` - event. + Committing the input audio buffer will trigger input audio transcription (if enabled in session configuration), but it will not create a response from the model. The server will respond with an `input_audio_buffer.committed` event. """ await self._connection.send( cast(RealtimeClientEventParam, strip_not_given({"type": "input_audio_buffer.commit", "event_id": event_id})) @@ -913,14 +925,17 @@ async def append(self, *, audio: str, event_id: str | NotGiven = NOT_GIVEN) -> N """Send this event to append audio bytes to the input audio buffer. The audio - buffer is temporary storage you can write to and later commit. In Server VAD - mode, the audio buffer is used to detect speech and the server will decide + buffer is temporary storage you can write to and later commit. A "commit" will create a new + user message item in the conversation history from the buffer content and clear the buffer. + Input audio transcription (if enabled) will be generated when the buffer is committed. + + If VAD is enabled the audio buffer is used to detect speech and the server will decide when to commit. When Server VAD is disabled, you must commit the audio buffer - manually. + manually. Input audio noise reduction operates on writes to the audio buffer. The client may choose how much audio to place in each event up to a maximum of 15 MiB, for example streaming smaller chunks from the client may allow the - VAD to be more responsive. Unlike made other client events, the server will + VAD to be more responsive. Unlike most other client events, the server will not send a confirmation response to this event. """ await self._connection.send( @@ -1047,7 +1062,7 @@ async def clear(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: class AsyncRealtimeTranscriptionSessionResource(BaseAsyncRealtimeConnectionResource): async def update( - self, *, session: RealtimeTranscriptionSessionCreateRequestParam, event_id: str | NotGiven = NOT_GIVEN + self, *, session: transcription_session_update_param.Session, event_id: str | NotGiven = NOT_GIVEN ) -> None: """Send this event to update a transcription session.""" await self._connection.send( diff --git a/src/openai/types/realtime/__init__.py b/src/openai/types/realtime/__init__.py index b05f620619..6873ba6a2a 100644 --- a/src/openai/types/realtime/__init__.py +++ b/src/openai/types/realtime/__init__.py @@ -2,13 +2,16 @@ from __future__ import annotations +from .models import Models as Models +from .models_param import ModelsParam as ModelsParam from .realtime_error import RealtimeError as RealtimeError -from .realtime_session import RealtimeSession as RealtimeSession from .conversation_item import ConversationItem as ConversationItem from .realtime_response import RealtimeResponse as RealtimeResponse +from .audio_transcription import AudioTranscription as AudioTranscription from .log_prob_properties import LogProbProperties as LogProbProperties from .realtime_truncation import RealtimeTruncation as RealtimeTruncation from .response_done_event import ResponseDoneEvent as ResponseDoneEvent +from .noise_reduction_type import NoiseReductionType as NoiseReductionType from .realtime_error_event import RealtimeErrorEvent as RealtimeErrorEvent from .session_update_event import SessionUpdateEvent as SessionUpdateEvent from .mcp_list_tools_failed import McpListToolsFailed as McpListToolsFailed @@ -21,6 +24,7 @@ from .session_created_event import SessionCreatedEvent as SessionCreatedEvent from .session_updated_event import SessionUpdatedEvent as SessionUpdatedEvent from .conversation_item_done import ConversationItemDone as ConversationItemDone +from .realtime_audio_formats import RealtimeAudioFormats as RealtimeAudioFormats from .realtime_mcp_tool_call import RealtimeMcpToolCall as RealtimeMcpToolCall from .realtime_mcphttp_error import RealtimeMcphttpError as RealtimeMcphttpError from .response_created_event import ResponseCreatedEvent as ResponseCreatedEvent @@ -34,6 +38,7 @@ from .realtime_response_status import RealtimeResponseStatus as RealtimeResponseStatus from .response_mcp_call_failed import ResponseMcpCallFailed as ResponseMcpCallFailed from .response_text_done_event import ResponseTextDoneEvent as ResponseTextDoneEvent +from .audio_transcription_param import AudioTranscriptionParam as AudioTranscriptionParam from .rate_limits_updated_event import RateLimitsUpdatedEvent as RateLimitsUpdatedEvent from .realtime_truncation_param import RealtimeTruncationParam as RealtimeTruncationParam from .response_audio_done_event import ResponseAudioDoneEvent as ResponseAudioDoneEvent @@ -43,6 +48,7 @@ from .response_audio_delta_event import ResponseAudioDeltaEvent as ResponseAudioDeltaEvent from .session_update_event_param import SessionUpdateEventParam as SessionUpdateEventParam from .client_secret_create_params import ClientSecretCreateParams as ClientSecretCreateParams +from .realtime_audio_config_input import RealtimeAudioConfigInput as RealtimeAudioConfigInput from .realtime_audio_config_param import RealtimeAudioConfigParam as RealtimeAudioConfigParam from .realtime_client_event_param import RealtimeClientEventParam as RealtimeClientEventParam from .realtime_mcp_protocol_error import RealtimeMcpProtocolError as RealtimeMcpProtocolError @@ -52,11 +58,12 @@ from .response_cancel_event_param import ResponseCancelEventParam as ResponseCancelEventParam from .response_create_event_param import ResponseCreateEventParam as ResponseCreateEventParam from .response_mcp_call_completed import ResponseMcpCallCompleted as ResponseMcpCallCompleted +from .realtime_audio_config_output import RealtimeAudioConfigOutput as RealtimeAudioConfigOutput +from .realtime_audio_formats_param import RealtimeAudioFormatsParam as RealtimeAudioFormatsParam from .realtime_mcp_tool_call_param import RealtimeMcpToolCallParam as RealtimeMcpToolCallParam from .realtime_mcphttp_error_param import RealtimeMcphttpErrorParam as RealtimeMcphttpErrorParam from .transcription_session_update import TranscriptionSessionUpdate as TranscriptionSessionUpdate from .client_secret_create_response import ClientSecretCreateResponse as ClientSecretCreateResponse -from .realtime_client_secret_config import RealtimeClientSecretConfig as RealtimeClientSecretConfig from .realtime_mcp_approval_request import RealtimeMcpApprovalRequest as RealtimeMcpApprovalRequest from .realtime_mcp_list_tools_param import RealtimeMcpListToolsParam as RealtimeMcpListToolsParam from .realtime_tracing_config_param import RealtimeTracingConfigParam as RealtimeTracingConfigParam @@ -66,11 +73,13 @@ from .conversation_item_delete_event import ConversationItemDeleteEvent as ConversationItemDeleteEvent from .input_audio_buffer_clear_event import InputAudioBufferClearEvent as InputAudioBufferClearEvent from .realtime_mcp_approval_response import RealtimeMcpApprovalResponse as RealtimeMcpApprovalResponse +from .realtime_session_client_secret import RealtimeSessionClientSecret as RealtimeSessionClientSecret from .conversation_item_created_event import ConversationItemCreatedEvent as ConversationItemCreatedEvent from .conversation_item_deleted_event import ConversationItemDeletedEvent as ConversationItemDeletedEvent from .input_audio_buffer_append_event import InputAudioBufferAppendEvent as InputAudioBufferAppendEvent from .input_audio_buffer_commit_event import InputAudioBufferCommitEvent as InputAudioBufferCommitEvent from .output_audio_buffer_clear_event import OutputAudioBufferClearEvent as OutputAudioBufferClearEvent +from .realtime_response_create_params import RealtimeResponseCreateParams as RealtimeResponseCreateParams from .realtime_session_create_request import RealtimeSessionCreateRequest as RealtimeSessionCreateRequest from .response_output_item_done_event import ResponseOutputItemDoneEvent as ResponseOutputItemDoneEvent from .conversation_item_retrieve_event import ConversationItemRetrieveEvent as ConversationItemRetrieveEvent @@ -81,26 +90,37 @@ from .response_mcp_call_arguments_done import ResponseMcpCallArgumentsDone as ResponseMcpCallArgumentsDone from .response_output_item_added_event import ResponseOutputItemAddedEvent as ResponseOutputItemAddedEvent from .conversation_item_truncated_event import ConversationItemTruncatedEvent as ConversationItemTruncatedEvent +from .realtime_audio_config_input_param import RealtimeAudioConfigInputParam as RealtimeAudioConfigInputParam from .realtime_mcp_protocol_error_param import RealtimeMcpProtocolErrorParam as RealtimeMcpProtocolErrorParam from .realtime_mcp_tool_execution_error import RealtimeMcpToolExecutionError as RealtimeMcpToolExecutionError +from .realtime_response_create_mcp_tool import RealtimeResponseCreateMcpTool as RealtimeResponseCreateMcpTool from .realtime_tool_choice_config_param import RealtimeToolChoiceConfigParam as RealtimeToolChoiceConfigParam from .realtime_tools_config_union_param import RealtimeToolsConfigUnionParam as RealtimeToolsConfigUnionParam from .response_content_part_added_event import ResponseContentPartAddedEvent as ResponseContentPartAddedEvent from .response_mcp_call_arguments_delta import ResponseMcpCallArgumentsDelta as ResponseMcpCallArgumentsDelta from .input_audio_buffer_committed_event import InputAudioBufferCommittedEvent as InputAudioBufferCommittedEvent +from .realtime_audio_config_output_param import RealtimeAudioConfigOutputParam as RealtimeAudioConfigOutputParam from .transcription_session_update_param import TranscriptionSessionUpdateParam as TranscriptionSessionUpdateParam -from .realtime_client_secret_config_param import RealtimeClientSecretConfigParam as RealtimeClientSecretConfigParam +from .realtime_audio_input_turn_detection import RealtimeAudioInputTurnDetection as RealtimeAudioInputTurnDetection from .realtime_mcp_approval_request_param import RealtimeMcpApprovalRequestParam as RealtimeMcpApprovalRequestParam +from .realtime_truncation_retention_ratio import RealtimeTruncationRetentionRatio as RealtimeTruncationRetentionRatio from .transcription_session_updated_event import TranscriptionSessionUpdatedEvent as TranscriptionSessionUpdatedEvent from .conversation_item_create_event_param import ConversationItemCreateEventParam as ConversationItemCreateEventParam from .conversation_item_delete_event_param import ConversationItemDeleteEventParam as ConversationItemDeleteEventParam from .input_audio_buffer_clear_event_param import InputAudioBufferClearEventParam as InputAudioBufferClearEventParam from .input_audio_buffer_timeout_triggered import InputAudioBufferTimeoutTriggered as InputAudioBufferTimeoutTriggered from .realtime_mcp_approval_response_param import RealtimeMcpApprovalResponseParam as RealtimeMcpApprovalResponseParam +from .realtime_transcription_session_audio import RealtimeTranscriptionSessionAudio as RealtimeTranscriptionSessionAudio from .response_audio_transcript_done_event import ResponseAudioTranscriptDoneEvent as ResponseAudioTranscriptDoneEvent from .input_audio_buffer_append_event_param import InputAudioBufferAppendEventParam as InputAudioBufferAppendEventParam from .input_audio_buffer_commit_event_param import InputAudioBufferCommitEventParam as InputAudioBufferCommitEventParam from .output_audio_buffer_clear_event_param import OutputAudioBufferClearEventParam as OutputAudioBufferClearEventParam +from .realtime_response_create_audio_output import ( + RealtimeResponseCreateAudioOutput as RealtimeResponseCreateAudioOutput, +) +from .realtime_response_create_params_param import ( + RealtimeResponseCreateParamsParam as RealtimeResponseCreateParamsParam, +) from .realtime_session_create_request_param import ( RealtimeSessionCreateRequestParam as RealtimeSessionCreateRequestParam, ) @@ -125,12 +145,30 @@ from .realtime_mcp_tool_execution_error_param import ( RealtimeMcpToolExecutionErrorParam as RealtimeMcpToolExecutionErrorParam, ) +from .realtime_response_create_mcp_tool_param import ( + RealtimeResponseCreateMcpToolParam as RealtimeResponseCreateMcpToolParam, +) from .realtime_conversation_item_function_call import ( RealtimeConversationItemFunctionCall as RealtimeConversationItemFunctionCall, ) +from .realtime_audio_input_turn_detection_param import ( + RealtimeAudioInputTurnDetectionParam as RealtimeAudioInputTurnDetectionParam, +) from .realtime_conversation_item_system_message import ( RealtimeConversationItemSystemMessage as RealtimeConversationItemSystemMessage, ) +from .realtime_truncation_retention_ratio_param import ( + RealtimeTruncationRetentionRatioParam as RealtimeTruncationRetentionRatioParam, +) +from .realtime_transcription_session_audio_input import ( + RealtimeTranscriptionSessionAudioInput as RealtimeTranscriptionSessionAudioInput, +) +from .realtime_transcription_session_audio_param import ( + RealtimeTranscriptionSessionAudioParam as RealtimeTranscriptionSessionAudioParam, +) +from .realtime_response_create_audio_output_param import ( + RealtimeResponseCreateAudioOutputParam as RealtimeResponseCreateAudioOutputParam, +) from .realtime_response_usage_input_token_details import ( RealtimeResponseUsageInputTokenDetails as RealtimeResponseUsageInputTokenDetails, ) @@ -143,6 +181,9 @@ from .realtime_response_usage_output_token_details import ( RealtimeResponseUsageOutputTokenDetails as RealtimeResponseUsageOutputTokenDetails, ) +from .realtime_transcription_session_client_secret import ( + RealtimeTranscriptionSessionClientSecret as RealtimeTranscriptionSessionClientSecret, +) from .response_function_call_arguments_delta_event import ( ResponseFunctionCallArgumentsDeltaEvent as ResponseFunctionCallArgumentsDeltaEvent, ) @@ -152,15 +193,24 @@ from .realtime_transcription_session_create_request import ( RealtimeTranscriptionSessionCreateRequest as RealtimeTranscriptionSessionCreateRequest, ) +from .realtime_transcription_session_turn_detection import ( + RealtimeTranscriptionSessionTurnDetection as RealtimeTranscriptionSessionTurnDetection, +) from .realtime_conversation_item_function_call_param import ( RealtimeConversationItemFunctionCallParam as RealtimeConversationItemFunctionCallParam, ) +from .realtime_transcription_session_create_response import ( + RealtimeTranscriptionSessionCreateResponse as RealtimeTranscriptionSessionCreateResponse, +) from .realtime_conversation_item_function_call_output import ( RealtimeConversationItemFunctionCallOutput as RealtimeConversationItemFunctionCallOutput, ) from .realtime_conversation_item_system_message_param import ( RealtimeConversationItemSystemMessageParam as RealtimeConversationItemSystemMessageParam, ) +from .realtime_transcription_session_audio_input_param import ( + RealtimeTranscriptionSessionAudioInputParam as RealtimeTranscriptionSessionAudioInputParam, +) from .realtime_conversation_item_assistant_message_param import ( RealtimeConversationItemAssistantMessageParam as RealtimeConversationItemAssistantMessageParam, ) @@ -179,6 +229,15 @@ from .conversation_item_input_audio_transcription_failed_event import ( ConversationItemInputAudioTranscriptionFailedEvent as ConversationItemInputAudioTranscriptionFailedEvent, ) +from .realtime_transcription_session_input_audio_transcription import ( + RealtimeTranscriptionSessionInputAudioTranscription as RealtimeTranscriptionSessionInputAudioTranscription, +) +from .realtime_transcription_session_audio_input_turn_detection import ( + RealtimeTranscriptionSessionAudioInputTurnDetection as RealtimeTranscriptionSessionAudioInputTurnDetection, +) from .conversation_item_input_audio_transcription_completed_event import ( ConversationItemInputAudioTranscriptionCompletedEvent as ConversationItemInputAudioTranscriptionCompletedEvent, ) +from .realtime_transcription_session_audio_input_turn_detection_param import ( + RealtimeTranscriptionSessionAudioInputTurnDetectionParam as RealtimeTranscriptionSessionAudioInputTurnDetectionParam, +) diff --git a/src/openai/types/realtime/audio_transcription.py b/src/openai/types/realtime/audio_transcription.py new file mode 100644 index 0000000000..cf662b3aa2 --- /dev/null +++ b/src/openai/types/realtime/audio_transcription.py @@ -0,0 +1,36 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["AudioTranscription"] + + +class AudioTranscription(BaseModel): + language: Optional[str] = None + """The language of the input audio. + + Supplying the input language in + [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) + format will improve accuracy and latency. + """ + + model: Optional[Literal["whisper-1", "gpt-4o-transcribe-latest", "gpt-4o-mini-transcribe", "gpt-4o-transcribe"]] = ( + None + ) + """The model to use for transcription. + + Current options are `whisper-1`, `gpt-4o-transcribe-latest`, + `gpt-4o-mini-transcribe`, and `gpt-4o-transcribe`. + """ + + prompt: Optional[str] = None + """ + An optional text to guide the model's style or continue a previous audio + segment. For `whisper-1`, the + [prompt is a list of keywords](https://platform.openai.com/docs/guides/speech-to-text#prompting). + For `gpt-4o-transcribe` models, the prompt is a free text string, for example + "expect words related to technology". + """ diff --git a/src/openai/types/realtime/audio_transcription_param.py b/src/openai/types/realtime/audio_transcription_param.py new file mode 100644 index 0000000000..fb09f105b8 --- /dev/null +++ b/src/openai/types/realtime/audio_transcription_param.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["AudioTranscriptionParam"] + + +class AudioTranscriptionParam(TypedDict, total=False): + language: str + """The language of the input audio. + + Supplying the input language in + [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) + format will improve accuracy and latency. + """ + + model: Literal["whisper-1", "gpt-4o-transcribe-latest", "gpt-4o-mini-transcribe", "gpt-4o-transcribe"] + """The model to use for transcription. + + Current options are `whisper-1`, `gpt-4o-transcribe-latest`, + `gpt-4o-mini-transcribe`, and `gpt-4o-transcribe`. + """ + + prompt: str + """ + An optional text to guide the model's style or continue a previous audio + segment. For `whisper-1`, the + [prompt is a list of keywords](https://platform.openai.com/docs/guides/speech-to-text#prompting). + For `gpt-4o-transcribe` models, the prompt is a free text string, for example + "expect words related to technology". + """ diff --git a/src/openai/types/realtime/client_secret_create_params.py b/src/openai/types/realtime/client_secret_create_params.py index 696176e5a8..5f0b0d796f 100644 --- a/src/openai/types/realtime/client_secret_create_params.py +++ b/src/openai/types/realtime/client_secret_create_params.py @@ -13,7 +13,12 @@ class ClientSecretCreateParams(TypedDict, total=False): expires_after: ExpiresAfter - """Configuration for the ephemeral token expiration.""" + """Configuration for the client secret expiration. + + Expiration refers to the time after which a client secret will no longer be + valid for creating sessions. The session itself may continue after that time + once started. A secret can be used to create multiple sessions until it expires. + """ session: Session """Session configuration to use for the client secret. @@ -24,15 +29,17 @@ class ClientSecretCreateParams(TypedDict, total=False): class ExpiresAfter(TypedDict, total=False): anchor: Literal["created_at"] - """The anchor point for the ephemeral token expiration. - - Only `created_at` is currently supported. + """ + The anchor point for the client secret expiration, meaning that `seconds` will + be added to the `created_at` time of the client secret to produce an expiration + timestamp. Only `created_at` is currently supported. """ seconds: int """The number of seconds from the anchor point to the expiration. - Select a value between `10` and `7200`. + Select a value between `10` and `7200` (2 hours). This default to 600 seconds + (10 minutes) if not specified. """ diff --git a/src/openai/types/realtime/client_secret_create_response.py b/src/openai/types/realtime/client_secret_create_response.py index ea8b9f9ca1..8d61be3ab7 100644 --- a/src/openai/types/realtime/client_secret_create_response.py +++ b/src/openai/types/realtime/client_secret_create_response.py @@ -1,102 +1,15 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union, Optional -from typing_extensions import Literal, TypeAlias +from typing import Union +from typing_extensions import TypeAlias from ..._models import BaseModel from .realtime_session_create_response import RealtimeSessionCreateResponse +from .realtime_transcription_session_create_response import RealtimeTranscriptionSessionCreateResponse -__all__ = [ - "ClientSecretCreateResponse", - "Session", - "SessionRealtimeTranscriptionSessionCreateResponse", - "SessionRealtimeTranscriptionSessionCreateResponseAudio", - "SessionRealtimeTranscriptionSessionCreateResponseAudioInput", - "SessionRealtimeTranscriptionSessionCreateResponseAudioInputNoiseReduction", - "SessionRealtimeTranscriptionSessionCreateResponseAudioInputTranscription", - "SessionRealtimeTranscriptionSessionCreateResponseAudioInputTurnDetection", -] +__all__ = ["ClientSecretCreateResponse", "Session"] - -class SessionRealtimeTranscriptionSessionCreateResponseAudioInputNoiseReduction(BaseModel): - type: Optional[Literal["near_field", "far_field"]] = None - - -class SessionRealtimeTranscriptionSessionCreateResponseAudioInputTranscription(BaseModel): - language: Optional[str] = None - """The language of the input audio. - - Supplying the input language in - [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) - format will improve accuracy and latency. - """ - - model: Optional[Literal["gpt-4o-transcribe", "gpt-4o-mini-transcribe", "whisper-1"]] = None - """The model to use for transcription. - - Can be `gpt-4o-transcribe`, `gpt-4o-mini-transcribe`, or `whisper-1`. - """ - - prompt: Optional[str] = None - """An optional text to guide the model's style or continue a previous audio - segment. - - The [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) - should match the audio language. - """ - - -class SessionRealtimeTranscriptionSessionCreateResponseAudioInputTurnDetection(BaseModel): - prefix_padding_ms: Optional[int] = None - - silence_duration_ms: Optional[int] = None - - threshold: Optional[float] = None - - type: Optional[str] = None - """Type of turn detection, only `server_vad` is currently supported.""" - - -class SessionRealtimeTranscriptionSessionCreateResponseAudioInput(BaseModel): - format: Optional[str] = None - """The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" - - noise_reduction: Optional[SessionRealtimeTranscriptionSessionCreateResponseAudioInputNoiseReduction] = None - """Configuration for input audio noise reduction.""" - - transcription: Optional[SessionRealtimeTranscriptionSessionCreateResponseAudioInputTranscription] = None - """Configuration of the transcription model.""" - - turn_detection: Optional[SessionRealtimeTranscriptionSessionCreateResponseAudioInputTurnDetection] = None - """Configuration for turn detection.""" - - -class SessionRealtimeTranscriptionSessionCreateResponseAudio(BaseModel): - input: Optional[SessionRealtimeTranscriptionSessionCreateResponseAudioInput] = None - - -class SessionRealtimeTranscriptionSessionCreateResponse(BaseModel): - id: Optional[str] = None - """Unique identifier for the session that looks like `sess_1234567890abcdef`.""" - - audio: Optional[SessionRealtimeTranscriptionSessionCreateResponseAudio] = None - """Configuration for input audio for the session.""" - - expires_at: Optional[int] = None - """Expiration timestamp for the session, in seconds since epoch.""" - - include: Optional[List[Literal["item.input_audio_transcription.logprobs"]]] = None - """Additional fields to include in server outputs. - - - `item.input_audio_transcription.logprobs`: Include logprobs for input audio - transcription. - """ - - object: Optional[str] = None - """The object type. Always `realtime.transcription_session`.""" - - -Session: TypeAlias = Union[RealtimeSessionCreateResponse, SessionRealtimeTranscriptionSessionCreateResponse] +Session: TypeAlias = Union[RealtimeSessionCreateResponse, RealtimeTranscriptionSessionCreateResponse] class ClientSecretCreateResponse(BaseModel): diff --git a/src/openai/types/realtime/conversation_item_input_audio_transcription_completed_event.py b/src/openai/types/realtime/conversation_item_input_audio_transcription_completed_event.py index eda3f3bab6..09b20aa184 100644 --- a/src/openai/types/realtime/conversation_item_input_audio_transcription_completed_event.py +++ b/src/openai/types/realtime/conversation_item_input_audio_transcription_completed_event.py @@ -59,7 +59,7 @@ class ConversationItemInputAudioTranscriptionCompletedEvent(BaseModel): """The unique ID of the server event.""" item_id: str - """The ID of the user message item containing the audio.""" + """The ID of the item containing the audio that is being transcribed.""" transcript: str """The transcribed text.""" @@ -70,7 +70,10 @@ class ConversationItemInputAudioTranscriptionCompletedEvent(BaseModel): """ usage: Usage - """Usage statistics for the transcription.""" + """ + Usage statistics for the transcription, this is billed according to the ASR + model's pricing rather than the realtime model's pricing. + """ logprobs: Optional[List[LogProbProperties]] = None """The log probabilities of the transcription.""" diff --git a/src/openai/types/realtime/conversation_item_input_audio_transcription_delta_event.py b/src/openai/types/realtime/conversation_item_input_audio_transcription_delta_event.py index 4e9528ccb0..f49e6f636f 100644 --- a/src/openai/types/realtime/conversation_item_input_audio_transcription_delta_event.py +++ b/src/openai/types/realtime/conversation_item_input_audio_transcription_delta_event.py @@ -14,7 +14,7 @@ class ConversationItemInputAudioTranscriptionDeltaEvent(BaseModel): """The unique ID of the server event.""" item_id: str - """The ID of the item.""" + """The ID of the item containing the audio that is being transcribed.""" type: Literal["conversation.item.input_audio_transcription.delta"] """The event type, must be `conversation.item.input_audio_transcription.delta`.""" @@ -26,4 +26,11 @@ class ConversationItemInputAudioTranscriptionDeltaEvent(BaseModel): """The text delta.""" logprobs: Optional[List[LogProbProperties]] = None - """The log probabilities of the transcription.""" + """The log probabilities of the transcription. + + These can be enabled by configurating the session with + `"include": ["item.input_audio_transcription.logprobs"]`. Each entry in the + array corresponds a log probability of which token would be selected for this + chunk of transcription. This can help to identify if it was possible there were + multiple valid options for a given chunk of transcription. + """ diff --git a/src/openai/types/realtime/conversation_item_truncate_event.py b/src/openai/types/realtime/conversation_item_truncate_event.py index 63b591bfdb..d6c6779cc8 100644 --- a/src/openai/types/realtime/conversation_item_truncate_event.py +++ b/src/openai/types/realtime/conversation_item_truncate_event.py @@ -17,7 +17,7 @@ class ConversationItemTruncateEvent(BaseModel): """ content_index: int - """The index of the content part to truncate. Set this to 0.""" + """The index of the content part to truncate. Set this to `0`.""" item_id: str """The ID of the assistant message item to truncate. diff --git a/src/openai/types/realtime/conversation_item_truncate_event_param.py b/src/openai/types/realtime/conversation_item_truncate_event_param.py index d3ad1e1e25..f5ab13a419 100644 --- a/src/openai/types/realtime/conversation_item_truncate_event_param.py +++ b/src/openai/types/realtime/conversation_item_truncate_event_param.py @@ -16,7 +16,7 @@ class ConversationItemTruncateEventParam(TypedDict, total=False): """ content_index: Required[int] - """The index of the content part to truncate. Set this to 0.""" + """The index of the content part to truncate. Set this to `0`.""" item_id: Required[str] """The ID of the assistant message item to truncate. diff --git a/src/openai/types/realtime/models.py b/src/openai/types/realtime/models.py new file mode 100644 index 0000000000..d4827538a3 --- /dev/null +++ b/src/openai/types/realtime/models.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["Models"] + + +class Models(BaseModel): + description: Optional[str] = None + """ + The description of the function, including guidance on when and how to call it, + and guidance about what to tell the user when calling (if anything). + """ + + name: Optional[str] = None + """The name of the function.""" + + parameters: Optional[object] = None + """Parameters of the function in JSON Schema.""" + + type: Optional[Literal["function"]] = None + """The type of the tool, i.e. `function`.""" diff --git a/src/openai/types/realtime/models_param.py b/src/openai/types/realtime/models_param.py new file mode 100644 index 0000000000..1db2d7e464 --- /dev/null +++ b/src/openai/types/realtime/models_param.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["ModelsParam"] + + +class ModelsParam(TypedDict, total=False): + description: str + """ + The description of the function, including guidance on when and how to call it, + and guidance about what to tell the user when calling (if anything). + """ + + name: str + """The name of the function.""" + + parameters: object + """Parameters of the function in JSON Schema.""" + + type: Literal["function"] + """The type of the tool, i.e. `function`.""" diff --git a/src/openai/types/realtime/noise_reduction_type.py b/src/openai/types/realtime/noise_reduction_type.py new file mode 100644 index 0000000000..f4338991bb --- /dev/null +++ b/src/openai/types/realtime/noise_reduction_type.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["NoiseReductionType"] + +NoiseReductionType: TypeAlias = Literal["near_field", "far_field"] diff --git a/src/openai/types/realtime/realtime_audio_config.py b/src/openai/types/realtime/realtime_audio_config.py index 7463c70038..72d7cc59cc 100644 --- a/src/openai/types/realtime/realtime_audio_config.py +++ b/src/openai/types/realtime/realtime_audio_config.py @@ -1,184 +1,15 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Union, Optional -from typing_extensions import Literal +from typing import Optional from ..._models import BaseModel +from .realtime_audio_config_input import RealtimeAudioConfigInput +from .realtime_audio_config_output import RealtimeAudioConfigOutput -__all__ = ["RealtimeAudioConfig", "Input", "InputNoiseReduction", "InputTranscription", "InputTurnDetection", "Output"] - - -class InputNoiseReduction(BaseModel): - type: Optional[Literal["near_field", "far_field"]] = None - """Type of noise reduction. - - `near_field` is for close-talking microphones such as headphones, `far_field` is - for far-field microphones such as laptop or conference room microphones. - """ - - -class InputTranscription(BaseModel): - language: Optional[str] = None - """The language of the input audio. - - Supplying the input language in - [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) - format will improve accuracy and latency. - """ - - model: Optional[ - Literal[ - "whisper-1", - "gpt-4o-transcribe-latest", - "gpt-4o-mini-transcribe", - "gpt-4o-transcribe", - "gpt-4o-transcribe-diarize", - ] - ] = None - """The model to use for transcription. - - Current options are `whisper-1`, `gpt-4o-transcribe-latest`, - `gpt-4o-mini-transcribe`, `gpt-4o-transcribe`, and `gpt-4o-transcribe-diarize`. - """ - - prompt: Optional[str] = None - """ - An optional text to guide the model's style or continue a previous audio - segment. For `whisper-1`, the - [prompt is a list of keywords](https://platform.openai.com/docs/guides/speech-to-text#prompting). - For `gpt-4o-transcribe` models, the prompt is a free text string, for example - "expect words related to technology". - """ - - -class InputTurnDetection(BaseModel): - create_response: Optional[bool] = None - """ - Whether or not to automatically generate a response when a VAD stop event - occurs. - """ - - eagerness: Optional[Literal["low", "medium", "high", "auto"]] = None - """Used only for `semantic_vad` mode. - - The eagerness of the model to respond. `low` will wait longer for the user to - continue speaking, `high` will respond more quickly. `auto` is the default and - is equivalent to `medium`. - """ - - idle_timeout_ms: Optional[int] = None - """ - Optional idle timeout after which turn detection will auto-timeout when no - additional audio is received. - """ - - interrupt_response: Optional[bool] = None - """ - Whether or not to automatically interrupt any ongoing response with output to - the default conversation (i.e. `conversation` of `auto`) when a VAD start event - occurs. - """ - - prefix_padding_ms: Optional[int] = None - """Used only for `server_vad` mode. - - Amount of audio to include before the VAD detected speech (in milliseconds). - Defaults to 300ms. - """ - - silence_duration_ms: Optional[int] = None - """Used only for `server_vad` mode. - - Duration of silence to detect speech stop (in milliseconds). Defaults to 500ms. - With shorter values the model will respond more quickly, but may jump in on - short pauses from the user. - """ - - threshold: Optional[float] = None - """Used only for `server_vad` mode. - - Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A higher - threshold will require louder audio to activate the model, and thus might - perform better in noisy environments. - """ - - type: Optional[Literal["server_vad", "semantic_vad"]] = None - """Type of turn detection.""" - - -class Input(BaseModel): - format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None - """The format of input audio. - - Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, input audio must - be 16-bit PCM at a 24kHz sample rate, single channel (mono), and little-endian - byte order. - """ - - noise_reduction: Optional[InputNoiseReduction] = None - """Configuration for input audio noise reduction. - - This can be set to `null` to turn off. Noise reduction filters audio added to - the input audio buffer before it is sent to VAD and the model. Filtering the - audio can improve VAD and turn detection accuracy (reducing false positives) and - model performance by improving perception of the input audio. - """ - - transcription: Optional[InputTranscription] = None - """ - Configuration for input audio transcription, defaults to off and can be set to - `null` to turn off once on. Input audio transcription is not native to the - model, since the model consumes audio directly. Transcription runs - asynchronously through - [the /audio/transcriptions endpoint](https://platform.openai.com/docs/api-reference/audio/createTranscription) - and should be treated as guidance of input audio content rather than precisely - what the model heard. The client can optionally set the language and prompt for - transcription, these offer additional guidance to the transcription service. - """ - - turn_detection: Optional[InputTurnDetection] = None - """Configuration for turn detection, ether Server VAD or Semantic VAD. - - This can be set to `null` to turn off, in which case the client must manually - trigger model response. Server VAD means that the model will detect the start - and end of speech based on audio volume and respond at the end of user speech. - Semantic VAD is more advanced and uses a turn detection model (in conjunction - with VAD) to semantically estimate whether the user has finished speaking, then - dynamically sets a timeout based on this probability. For example, if user audio - trails off with "uhhm", the model will score a low probability of turn end and - wait longer for the user to continue speaking. This can be useful for more - natural conversations, but may have a higher latency. - """ - - -class Output(BaseModel): - format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None - """The format of output audio. - - Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, output audio is - sampled at a rate of 24kHz. - """ - - speed: Optional[float] = None - """The speed of the model's spoken response. - - 1.0 is the default speed. 0.25 is the minimum speed. 1.5 is the maximum speed. - This value can only be changed in between model turns, not while a response is - in progress. - """ - - voice: Union[ - str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"], None - ] = None - """The voice the model uses to respond. - - Voice cannot be changed during the session once the model has responded with - audio at least once. Current voice options are `alloy`, `ash`, `ballad`, - `coral`, `echo`, `sage`, `shimmer`, `verse`, `marin`, and `cedar`. - """ +__all__ = ["RealtimeAudioConfig"] class RealtimeAudioConfig(BaseModel): - input: Optional[Input] = None + input: Optional[RealtimeAudioConfigInput] = None - output: Optional[Output] = None + output: Optional[RealtimeAudioConfigOutput] = None diff --git a/src/openai/types/realtime/realtime_audio_config_input.py b/src/openai/types/realtime/realtime_audio_config_input.py new file mode 100644 index 0000000000..fd96e2a52d --- /dev/null +++ b/src/openai/types/realtime/realtime_audio_config_input.py @@ -0,0 +1,60 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel +from .audio_transcription import AudioTranscription +from .noise_reduction_type import NoiseReductionType +from .realtime_audio_formats import RealtimeAudioFormats +from .realtime_audio_input_turn_detection import RealtimeAudioInputTurnDetection + +__all__ = ["RealtimeAudioConfigInput", "NoiseReduction"] + + +class NoiseReduction(BaseModel): + type: Optional[NoiseReductionType] = None + """Type of noise reduction. + + `near_field` is for close-talking microphones such as headphones, `far_field` is + for far-field microphones such as laptop or conference room microphones. + """ + + +class RealtimeAudioConfigInput(BaseModel): + format: Optional[RealtimeAudioFormats] = None + """The format of the input audio.""" + + noise_reduction: Optional[NoiseReduction] = None + """Configuration for input audio noise reduction. + + This can be set to `null` to turn off. Noise reduction filters audio added to + the input audio buffer before it is sent to VAD and the model. Filtering the + audio can improve VAD and turn detection accuracy (reducing false positives) and + model performance by improving perception of the input audio. + """ + + transcription: Optional[AudioTranscription] = None + """ + Configuration for input audio transcription, defaults to off and can be set to + `null` to turn off once on. Input audio transcription is not native to the + model, since the model consumes audio directly. Transcription runs + asynchronously through + [the /audio/transcriptions endpoint](https://platform.openai.com/docs/api-reference/audio/createTranscription) + and should be treated as guidance of input audio content rather than precisely + what the model heard. The client can optionally set the language and prompt for + transcription, these offer additional guidance to the transcription service. + """ + + turn_detection: Optional[RealtimeAudioInputTurnDetection] = None + """Configuration for turn detection, ether Server VAD or Semantic VAD. + + This can be set to `null` to turn off, in which case the client must manually + trigger model response. Server VAD means that the model will detect the start + and end of speech based on audio volume and respond at the end of user speech. + Semantic VAD is more advanced and uses a turn detection model (in conjunction + with VAD) to semantically estimate whether the user has finished speaking, then + dynamically sets a timeout based on this probability. For example, if user audio + trails off with "uhhm", the model will score a low probability of turn end and + wait longer for the user to continue speaking. This can be useful for more + natural conversations, but may have a higher latency. + """ diff --git a/src/openai/types/realtime/realtime_audio_config_input_param.py b/src/openai/types/realtime/realtime_audio_config_input_param.py new file mode 100644 index 0000000000..1dfb439006 --- /dev/null +++ b/src/openai/types/realtime/realtime_audio_config_input_param.py @@ -0,0 +1,61 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +from .noise_reduction_type import NoiseReductionType +from .audio_transcription_param import AudioTranscriptionParam +from .realtime_audio_formats_param import RealtimeAudioFormatsParam +from .realtime_audio_input_turn_detection_param import RealtimeAudioInputTurnDetectionParam + +__all__ = ["RealtimeAudioConfigInputParam", "NoiseReduction"] + + +class NoiseReduction(TypedDict, total=False): + type: NoiseReductionType + """Type of noise reduction. + + `near_field` is for close-talking microphones such as headphones, `far_field` is + for far-field microphones such as laptop or conference room microphones. + """ + + +class RealtimeAudioConfigInputParam(TypedDict, total=False): + format: RealtimeAudioFormatsParam + """The format of the input audio.""" + + noise_reduction: NoiseReduction + """Configuration for input audio noise reduction. + + This can be set to `null` to turn off. Noise reduction filters audio added to + the input audio buffer before it is sent to VAD and the model. Filtering the + audio can improve VAD and turn detection accuracy (reducing false positives) and + model performance by improving perception of the input audio. + """ + + transcription: AudioTranscriptionParam + """ + Configuration for input audio transcription, defaults to off and can be set to + `null` to turn off once on. Input audio transcription is not native to the + model, since the model consumes audio directly. Transcription runs + asynchronously through + [the /audio/transcriptions endpoint](https://platform.openai.com/docs/api-reference/audio/createTranscription) + and should be treated as guidance of input audio content rather than precisely + what the model heard. The client can optionally set the language and prompt for + transcription, these offer additional guidance to the transcription service. + """ + + turn_detection: RealtimeAudioInputTurnDetectionParam + """Configuration for turn detection, ether Server VAD or Semantic VAD. + + This can be set to `null` to turn off, in which case the client must manually + trigger model response. Server VAD means that the model will detect the start + and end of speech based on audio volume and respond at the end of user speech. + Semantic VAD is more advanced and uses a turn detection model (in conjunction + with VAD) to semantically estimate whether the user has finished speaking, then + dynamically sets a timeout based on this probability. For example, if user audio + trails off with "uhhm", the model will score a low probability of turn end and + wait longer for the user to continue speaking. This can be useful for more + natural conversations, but may have a higher latency. + """ diff --git a/src/openai/types/realtime/realtime_audio_config_output.py b/src/openai/types/realtime/realtime_audio_config_output.py new file mode 100644 index 0000000000..a8af237c1d --- /dev/null +++ b/src/openai/types/realtime/realtime_audio_config_output.py @@ -0,0 +1,36 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union, Optional +from typing_extensions import Literal + +from ..._models import BaseModel +from .realtime_audio_formats import RealtimeAudioFormats + +__all__ = ["RealtimeAudioConfigOutput"] + + +class RealtimeAudioConfigOutput(BaseModel): + format: Optional[RealtimeAudioFormats] = None + """The format of the output audio.""" + + speed: Optional[float] = None + """ + The speed of the model's spoken response as a multiple of the original speed. + 1.0 is the default speed. 0.25 is the minimum speed. 1.5 is the maximum speed. + This value can only be changed in between model turns, not while a response is + in progress. + + This parameter is a post-processing adjustment to the audio after it is + generated, it's also possible to prompt the model to speak faster or slower. + """ + + voice: Union[ + str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"], None + ] = None + """The voice the model uses to respond. + + Voice cannot be changed during the session once the model has responded with + audio at least once. Current voice options are `alloy`, `ash`, `ballad`, + `coral`, `echo`, `sage`, `shimmer`, `verse`, `marin`, and `cedar`. We recommend + `marin` and `cedar` for best quality. + """ diff --git a/src/openai/types/realtime/realtime_audio_config_output_param.py b/src/openai/types/realtime/realtime_audio_config_output_param.py new file mode 100644 index 0000000000..8e887d3464 --- /dev/null +++ b/src/openai/types/realtime/realtime_audio_config_output_param.py @@ -0,0 +1,35 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import Literal, TypedDict + +from .realtime_audio_formats_param import RealtimeAudioFormatsParam + +__all__ = ["RealtimeAudioConfigOutputParam"] + + +class RealtimeAudioConfigOutputParam(TypedDict, total=False): + format: RealtimeAudioFormatsParam + """The format of the output audio.""" + + speed: float + """ + The speed of the model's spoken response as a multiple of the original speed. + 1.0 is the default speed. 0.25 is the minimum speed. 1.5 is the maximum speed. + This value can only be changed in between model turns, not while a response is + in progress. + + This parameter is a post-processing adjustment to the audio after it is + generated, it's also possible to prompt the model to speak faster or slower. + """ + + voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"]] + """The voice the model uses to respond. + + Voice cannot be changed during the session once the model has responded with + audio at least once. Current voice options are `alloy`, `ash`, `ballad`, + `coral`, `echo`, `sage`, `shimmer`, `verse`, `marin`, and `cedar`. We recommend + `marin` and `cedar` for best quality. + """ diff --git a/src/openai/types/realtime/realtime_audio_config_param.py b/src/openai/types/realtime/realtime_audio_config_param.py index 9f2e12e910..2c41de35ae 100644 --- a/src/openai/types/realtime/realtime_audio_config_param.py +++ b/src/openai/types/realtime/realtime_audio_config_param.py @@ -2,186 +2,15 @@ from __future__ import annotations -from typing import Union, Optional -from typing_extensions import Literal, TypedDict +from typing_extensions import TypedDict -__all__ = [ - "RealtimeAudioConfigParam", - "Input", - "InputNoiseReduction", - "InputTranscription", - "InputTurnDetection", - "Output", -] +from .realtime_audio_config_input_param import RealtimeAudioConfigInputParam +from .realtime_audio_config_output_param import RealtimeAudioConfigOutputParam - -class InputNoiseReduction(TypedDict, total=False): - type: Literal["near_field", "far_field"] - """Type of noise reduction. - - `near_field` is for close-talking microphones such as headphones, `far_field` is - for far-field microphones such as laptop or conference room microphones. - """ - - -class InputTranscription(TypedDict, total=False): - language: str - """The language of the input audio. - - Supplying the input language in - [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) - format will improve accuracy and latency. - """ - - model: Literal[ - "whisper-1", - "gpt-4o-transcribe-latest", - "gpt-4o-mini-transcribe", - "gpt-4o-transcribe", - "gpt-4o-transcribe-diarize", - ] - """The model to use for transcription. - - Current options are `whisper-1`, `gpt-4o-transcribe-latest`, - `gpt-4o-mini-transcribe`, `gpt-4o-transcribe`, and `gpt-4o-transcribe-diarize`. - """ - - prompt: str - """ - An optional text to guide the model's style or continue a previous audio - segment. For `whisper-1`, the - [prompt is a list of keywords](https://platform.openai.com/docs/guides/speech-to-text#prompting). - For `gpt-4o-transcribe` models, the prompt is a free text string, for example - "expect words related to technology". - """ - - -class InputTurnDetection(TypedDict, total=False): - create_response: bool - """ - Whether or not to automatically generate a response when a VAD stop event - occurs. - """ - - eagerness: Literal["low", "medium", "high", "auto"] - """Used only for `semantic_vad` mode. - - The eagerness of the model to respond. `low` will wait longer for the user to - continue speaking, `high` will respond more quickly. `auto` is the default and - is equivalent to `medium`. - """ - - idle_timeout_ms: Optional[int] - """ - Optional idle timeout after which turn detection will auto-timeout when no - additional audio is received. - """ - - interrupt_response: bool - """ - Whether or not to automatically interrupt any ongoing response with output to - the default conversation (i.e. `conversation` of `auto`) when a VAD start event - occurs. - """ - - prefix_padding_ms: int - """Used only for `server_vad` mode. - - Amount of audio to include before the VAD detected speech (in milliseconds). - Defaults to 300ms. - """ - - silence_duration_ms: int - """Used only for `server_vad` mode. - - Duration of silence to detect speech stop (in milliseconds). Defaults to 500ms. - With shorter values the model will respond more quickly, but may jump in on - short pauses from the user. - """ - - threshold: float - """Used only for `server_vad` mode. - - Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A higher - threshold will require louder audio to activate the model, and thus might - perform better in noisy environments. - """ - - type: Literal["server_vad", "semantic_vad"] - """Type of turn detection.""" - - -class Input(TypedDict, total=False): - format: Literal["pcm16", "g711_ulaw", "g711_alaw"] - """The format of input audio. - - Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, input audio must - be 16-bit PCM at a 24kHz sample rate, single channel (mono), and little-endian - byte order. - """ - - noise_reduction: InputNoiseReduction - """Configuration for input audio noise reduction. - - This can be set to `null` to turn off. Noise reduction filters audio added to - the input audio buffer before it is sent to VAD and the model. Filtering the - audio can improve VAD and turn detection accuracy (reducing false positives) and - model performance by improving perception of the input audio. - """ - - transcription: InputTranscription - """ - Configuration for input audio transcription, defaults to off and can be set to - `null` to turn off once on. Input audio transcription is not native to the - model, since the model consumes audio directly. Transcription runs - asynchronously through - [the /audio/transcriptions endpoint](https://platform.openai.com/docs/api-reference/audio/createTranscription) - and should be treated as guidance of input audio content rather than precisely - what the model heard. The client can optionally set the language and prompt for - transcription, these offer additional guidance to the transcription service. - """ - - turn_detection: InputTurnDetection - """Configuration for turn detection, ether Server VAD or Semantic VAD. - - This can be set to `null` to turn off, in which case the client must manually - trigger model response. Server VAD means that the model will detect the start - and end of speech based on audio volume and respond at the end of user speech. - Semantic VAD is more advanced and uses a turn detection model (in conjunction - with VAD) to semantically estimate whether the user has finished speaking, then - dynamically sets a timeout based on this probability. For example, if user audio - trails off with "uhhm", the model will score a low probability of turn end and - wait longer for the user to continue speaking. This can be useful for more - natural conversations, but may have a higher latency. - """ - - -class Output(TypedDict, total=False): - format: Literal["pcm16", "g711_ulaw", "g711_alaw"] - """The format of output audio. - - Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, output audio is - sampled at a rate of 24kHz. - """ - - speed: float - """The speed of the model's spoken response. - - 1.0 is the default speed. 0.25 is the minimum speed. 1.5 is the maximum speed. - This value can only be changed in between model turns, not while a response is - in progress. - """ - - voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"]] - """The voice the model uses to respond. - - Voice cannot be changed during the session once the model has responded with - audio at least once. Current voice options are `alloy`, `ash`, `ballad`, - `coral`, `echo`, `sage`, `shimmer`, `verse`, `marin`, and `cedar`. - """ +__all__ = ["RealtimeAudioConfigParam"] class RealtimeAudioConfigParam(TypedDict, total=False): - input: Input + input: RealtimeAudioConfigInputParam - output: Output + output: RealtimeAudioConfigOutputParam diff --git a/src/openai/types/realtime/realtime_audio_formats.py b/src/openai/types/realtime/realtime_audio_formats.py new file mode 100644 index 0000000000..10f91883b6 --- /dev/null +++ b/src/openai/types/realtime/realtime_audio_formats.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel + +__all__ = ["RealtimeAudioFormats", "AudioPCM", "AudioPCMU", "AudioPCMA"] + + +class AudioPCM(BaseModel): + rate: Optional[Literal[24000]] = None + """The sample rate of the audio. Always `24000`.""" + + type: Optional[Literal["audio/pcm"]] = None + """The audio format. Always `audio/pcm`.""" + + +class AudioPCMU(BaseModel): + type: Optional[Literal["audio/pcmu"]] = None + """The audio format. Always `audio/pcmu`.""" + + +class AudioPCMA(BaseModel): + type: Optional[Literal["audio/pcma"]] = None + """The audio format. Always `audio/pcma`.""" + + +RealtimeAudioFormats: TypeAlias = Annotated[Union[AudioPCM, AudioPCMU, AudioPCMA], PropertyInfo(discriminator="type")] diff --git a/src/openai/types/realtime/realtime_audio_formats_param.py b/src/openai/types/realtime/realtime_audio_formats_param.py new file mode 100644 index 0000000000..cf58577f38 --- /dev/null +++ b/src/openai/types/realtime/realtime_audio_formats_param.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import Literal, TypeAlias, TypedDict + +__all__ = ["RealtimeAudioFormatsParam", "AudioPCM", "AudioPCMU", "AudioPCMA"] + + +class AudioPCM(TypedDict, total=False): + rate: Literal[24000] + """The sample rate of the audio. Always `24000`.""" + + type: Literal["audio/pcm"] + """The audio format. Always `audio/pcm`.""" + + +class AudioPCMU(TypedDict, total=False): + type: Literal["audio/pcmu"] + """The audio format. Always `audio/pcmu`.""" + + +class AudioPCMA(TypedDict, total=False): + type: Literal["audio/pcma"] + """The audio format. Always `audio/pcma`.""" + + +RealtimeAudioFormatsParam: TypeAlias = Union[AudioPCM, AudioPCMU, AudioPCMA] diff --git a/src/openai/types/realtime/realtime_audio_input_turn_detection.py b/src/openai/types/realtime/realtime_audio_input_turn_detection.py new file mode 100644 index 0000000000..ea9423f6a1 --- /dev/null +++ b/src/openai/types/realtime/realtime_audio_input_turn_detection.py @@ -0,0 +1,64 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["RealtimeAudioInputTurnDetection"] + + +class RealtimeAudioInputTurnDetection(BaseModel): + create_response: Optional[bool] = None + """ + Whether or not to automatically generate a response when a VAD stop event + occurs. + """ + + eagerness: Optional[Literal["low", "medium", "high", "auto"]] = None + """Used only for `semantic_vad` mode. + + The eagerness of the model to respond. `low` will wait longer for the user to + continue speaking, `high` will respond more quickly. `auto` is the default and + is equivalent to `medium`. `low`, `medium`, and `high` have max timeouts of 8s, + 4s, and 2s respectively. + """ + + idle_timeout_ms: Optional[int] = None + """ + Optional idle timeout after which turn detection will auto-timeout when no + additional audio is received. + """ + + interrupt_response: Optional[bool] = None + """ + Whether or not to automatically interrupt any ongoing response with output to + the default conversation (i.e. `conversation` of `auto`) when a VAD start event + occurs. + """ + + prefix_padding_ms: Optional[int] = None + """Used only for `server_vad` mode. + + Amount of audio to include before the VAD detected speech (in milliseconds). + Defaults to 300ms. + """ + + silence_duration_ms: Optional[int] = None + """Used only for `server_vad` mode. + + Duration of silence to detect speech stop (in milliseconds). Defaults to 500ms. + With shorter values the model will respond more quickly, but may jump in on + short pauses from the user. + """ + + threshold: Optional[float] = None + """Used only for `server_vad` mode. + + Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A higher + threshold will require louder audio to activate the model, and thus might + perform better in noisy environments. + """ + + type: Optional[Literal["server_vad", "semantic_vad"]] = None + """Type of turn detection.""" diff --git a/src/openai/types/realtime/realtime_audio_input_turn_detection_param.py b/src/openai/types/realtime/realtime_audio_input_turn_detection_param.py new file mode 100644 index 0000000000..ec398f52e6 --- /dev/null +++ b/src/openai/types/realtime/realtime_audio_input_turn_detection_param.py @@ -0,0 +1,64 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, TypedDict + +__all__ = ["RealtimeAudioInputTurnDetectionParam"] + + +class RealtimeAudioInputTurnDetectionParam(TypedDict, total=False): + create_response: bool + """ + Whether or not to automatically generate a response when a VAD stop event + occurs. + """ + + eagerness: Literal["low", "medium", "high", "auto"] + """Used only for `semantic_vad` mode. + + The eagerness of the model to respond. `low` will wait longer for the user to + continue speaking, `high` will respond more quickly. `auto` is the default and + is equivalent to `medium`. `low`, `medium`, and `high` have max timeouts of 8s, + 4s, and 2s respectively. + """ + + idle_timeout_ms: Optional[int] + """ + Optional idle timeout after which turn detection will auto-timeout when no + additional audio is received. + """ + + interrupt_response: bool + """ + Whether or not to automatically interrupt any ongoing response with output to + the default conversation (i.e. `conversation` of `auto`) when a VAD start event + occurs. + """ + + prefix_padding_ms: int + """Used only for `server_vad` mode. + + Amount of audio to include before the VAD detected speech (in milliseconds). + Defaults to 300ms. + """ + + silence_duration_ms: int + """Used only for `server_vad` mode. + + Duration of silence to detect speech stop (in milliseconds). Defaults to 500ms. + With shorter values the model will respond more quickly, but may jump in on + short pauses from the user. + """ + + threshold: float + """Used only for `server_vad` mode. + + Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A higher + threshold will require louder audio to activate the model, and thus might + perform better in noisy environments. + """ + + type: Literal["server_vad", "semantic_vad"] + """Type of turn detection.""" diff --git a/src/openai/types/realtime/realtime_client_secret_config.py b/src/openai/types/realtime/realtime_client_secret_config.py deleted file mode 100644 index 29f8f57081..0000000000 --- a/src/openai/types/realtime/realtime_client_secret_config.py +++ /dev/null @@ -1,27 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["RealtimeClientSecretConfig", "ExpiresAfter"] - - -class ExpiresAfter(BaseModel): - anchor: Literal["created_at"] - """The anchor point for the ephemeral token expiration. - - Only `created_at` is currently supported. - """ - - seconds: Optional[int] = None - """The number of seconds from the anchor point to the expiration. - - Select a value between `10` and `7200`. - """ - - -class RealtimeClientSecretConfig(BaseModel): - expires_after: Optional[ExpiresAfter] = None - """Configuration for the ephemeral token expiration.""" diff --git a/src/openai/types/realtime/realtime_client_secret_config_param.py b/src/openai/types/realtime/realtime_client_secret_config_param.py deleted file mode 100644 index 30a80134ee..0000000000 --- a/src/openai/types/realtime/realtime_client_secret_config_param.py +++ /dev/null @@ -1,26 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["RealtimeClientSecretConfigParam", "ExpiresAfter"] - - -class ExpiresAfter(TypedDict, total=False): - anchor: Required[Literal["created_at"]] - """The anchor point for the ephemeral token expiration. - - Only `created_at` is currently supported. - """ - - seconds: int - """The number of seconds from the anchor point to the expiration. - - Select a value between `10` and `7200`. - """ - - -class RealtimeClientSecretConfigParam(TypedDict, total=False): - expires_after: ExpiresAfter - """Configuration for the ephemeral token expiration.""" diff --git a/src/openai/types/realtime/realtime_conversation_item_assistant_message.py b/src/openai/types/realtime/realtime_conversation_item_assistant_message.py index d0f37745ea..6b0f86ee32 100644 --- a/src/openai/types/realtime/realtime_conversation_item_assistant_message.py +++ b/src/openai/types/realtime/realtime_conversation_item_assistant_message.py @@ -9,11 +9,27 @@ class Content(BaseModel): + audio: Optional[str] = None + """ + Base64-encoded audio bytes, these will be parsed as the format specified in the + session output audio type configuration. This defaults to PCM 16-bit 24kHz mono + if not specified. + """ + text: Optional[str] = None """The text content.""" - type: Optional[Literal["text"]] = None - """The content type. Always `text` for assistant messages.""" + transcript: Optional[str] = None + """ + The transcript of the audio content, this will always be present if the output + type is `audio`. + """ + + type: Optional[Literal["output_text", "output_audio"]] = None + """ + The content type, `output_text` or `output_audio` depending on the session + `output_modalities` configuration. + """ class RealtimeConversationItemAssistantMessage(BaseModel): @@ -27,10 +43,16 @@ class RealtimeConversationItemAssistantMessage(BaseModel): """The type of the item. Always `message`.""" id: Optional[str] = None - """The unique ID of the item.""" + """The unique ID of the item. + + This may be provided by the client or generated by the server. + """ object: Optional[Literal["realtime.item"]] = None - """Identifier for the API object being returned - always `realtime.item`.""" + """Identifier for the API object being returned - always `realtime.item`. + + Optional when creating a new item. + """ status: Optional[Literal["completed", "incomplete", "in_progress"]] = None """The status of the item. Has no effect on the conversation.""" diff --git a/src/openai/types/realtime/realtime_conversation_item_assistant_message_param.py b/src/openai/types/realtime/realtime_conversation_item_assistant_message_param.py index cfbd9cd2cf..93699afba2 100644 --- a/src/openai/types/realtime/realtime_conversation_item_assistant_message_param.py +++ b/src/openai/types/realtime/realtime_conversation_item_assistant_message_param.py @@ -9,11 +9,27 @@ class Content(TypedDict, total=False): + audio: str + """ + Base64-encoded audio bytes, these will be parsed as the format specified in the + session output audio type configuration. This defaults to PCM 16-bit 24kHz mono + if not specified. + """ + text: str """The text content.""" - type: Literal["text"] - """The content type. Always `text` for assistant messages.""" + transcript: str + """ + The transcript of the audio content, this will always be present if the output + type is `audio`. + """ + + type: Literal["output_text", "output_audio"] + """ + The content type, `output_text` or `output_audio` depending on the session + `output_modalities` configuration. + """ class RealtimeConversationItemAssistantMessageParam(TypedDict, total=False): @@ -27,10 +43,16 @@ class RealtimeConversationItemAssistantMessageParam(TypedDict, total=False): """The type of the item. Always `message`.""" id: str - """The unique ID of the item.""" + """The unique ID of the item. + + This may be provided by the client or generated by the server. + """ object: Literal["realtime.item"] - """Identifier for the API object being returned - always `realtime.item`.""" + """Identifier for the API object being returned - always `realtime.item`. + + Optional when creating a new item. + """ status: Literal["completed", "incomplete", "in_progress"] """The status of the item. Has no effect on the conversation.""" diff --git a/src/openai/types/realtime/realtime_conversation_item_function_call.py b/src/openai/types/realtime/realtime_conversation_item_function_call.py index ce1c6d4cb2..279a2fcdc5 100644 --- a/src/openai/types/realtime/realtime_conversation_item_function_call.py +++ b/src/openai/types/realtime/realtime_conversation_item_function_call.py @@ -10,7 +10,11 @@ class RealtimeConversationItemFunctionCall(BaseModel): arguments: str - """The arguments of the function call.""" + """The arguments of the function call. + + This is a JSON-encoded string representing the arguments passed to the function, + for example `{"arg1": "value1", "arg2": 42}`. + """ name: str """The name of the function being called.""" @@ -19,13 +23,19 @@ class RealtimeConversationItemFunctionCall(BaseModel): """The type of the item. Always `function_call`.""" id: Optional[str] = None - """The unique ID of the item.""" + """The unique ID of the item. + + This may be provided by the client or generated by the server. + """ call_id: Optional[str] = None """The ID of the function call.""" object: Optional[Literal["realtime.item"]] = None - """Identifier for the API object being returned - always `realtime.item`.""" + """Identifier for the API object being returned - always `realtime.item`. + + Optional when creating a new item. + """ status: Optional[Literal["completed", "incomplete", "in_progress"]] = None """The status of the item. Has no effect on the conversation.""" diff --git a/src/openai/types/realtime/realtime_conversation_item_function_call_output.py b/src/openai/types/realtime/realtime_conversation_item_function_call_output.py index cea840fdba..4b6b15d0ad 100644 --- a/src/openai/types/realtime/realtime_conversation_item_function_call_output.py +++ b/src/openai/types/realtime/realtime_conversation_item_function_call_output.py @@ -13,16 +13,25 @@ class RealtimeConversationItemFunctionCallOutput(BaseModel): """The ID of the function call this output is for.""" output: str - """The output of the function call.""" + """ + The output of the function call, this is free text and can contain any + information or simply be empty. + """ type: Literal["function_call_output"] """The type of the item. Always `function_call_output`.""" id: Optional[str] = None - """The unique ID of the item.""" + """The unique ID of the item. + + This may be provided by the client or generated by the server. + """ object: Optional[Literal["realtime.item"]] = None - """Identifier for the API object being returned - always `realtime.item`.""" + """Identifier for the API object being returned - always `realtime.item`. + + Optional when creating a new item. + """ status: Optional[Literal["completed", "incomplete", "in_progress"]] = None """The status of the item. Has no effect on the conversation.""" diff --git a/src/openai/types/realtime/realtime_conversation_item_function_call_output_param.py b/src/openai/types/realtime/realtime_conversation_item_function_call_output_param.py index a66c587fb6..56d62da563 100644 --- a/src/openai/types/realtime/realtime_conversation_item_function_call_output_param.py +++ b/src/openai/types/realtime/realtime_conversation_item_function_call_output_param.py @@ -12,16 +12,25 @@ class RealtimeConversationItemFunctionCallOutputParam(TypedDict, total=False): """The ID of the function call this output is for.""" output: Required[str] - """The output of the function call.""" + """ + The output of the function call, this is free text and can contain any + information or simply be empty. + """ type: Required[Literal["function_call_output"]] """The type of the item. Always `function_call_output`.""" id: str - """The unique ID of the item.""" + """The unique ID of the item. + + This may be provided by the client or generated by the server. + """ object: Literal["realtime.item"] - """Identifier for the API object being returned - always `realtime.item`.""" + """Identifier for the API object being returned - always `realtime.item`. + + Optional when creating a new item. + """ status: Literal["completed", "incomplete", "in_progress"] """The status of the item. Has no effect on the conversation.""" diff --git a/src/openai/types/realtime/realtime_conversation_item_function_call_param.py b/src/openai/types/realtime/realtime_conversation_item_function_call_param.py index a4d6fb83ab..36a16a27b3 100644 --- a/src/openai/types/realtime/realtime_conversation_item_function_call_param.py +++ b/src/openai/types/realtime/realtime_conversation_item_function_call_param.py @@ -9,7 +9,11 @@ class RealtimeConversationItemFunctionCallParam(TypedDict, total=False): arguments: Required[str] - """The arguments of the function call.""" + """The arguments of the function call. + + This is a JSON-encoded string representing the arguments passed to the function, + for example `{"arg1": "value1", "arg2": 42}`. + """ name: Required[str] """The name of the function being called.""" @@ -18,13 +22,19 @@ class RealtimeConversationItemFunctionCallParam(TypedDict, total=False): """The type of the item. Always `function_call`.""" id: str - """The unique ID of the item.""" + """The unique ID of the item. + + This may be provided by the client or generated by the server. + """ call_id: str """The ID of the function call.""" object: Literal["realtime.item"] - """Identifier for the API object being returned - always `realtime.item`.""" + """Identifier for the API object being returned - always `realtime.item`. + + Optional when creating a new item. + """ status: Literal["completed", "incomplete", "in_progress"] """The status of the item. Has no effect on the conversation.""" diff --git a/src/openai/types/realtime/realtime_conversation_item_system_message.py b/src/openai/types/realtime/realtime_conversation_item_system_message.py index abc67f6c5f..7dac5c9fe2 100644 --- a/src/openai/types/realtime/realtime_conversation_item_system_message.py +++ b/src/openai/types/realtime/realtime_conversation_item_system_message.py @@ -27,10 +27,16 @@ class RealtimeConversationItemSystemMessage(BaseModel): """The type of the item. Always `message`.""" id: Optional[str] = None - """The unique ID of the item.""" + """The unique ID of the item. + + This may be provided by the client or generated by the server. + """ object: Optional[Literal["realtime.item"]] = None - """Identifier for the API object being returned - always `realtime.item`.""" + """Identifier for the API object being returned - always `realtime.item`. + + Optional when creating a new item. + """ status: Optional[Literal["completed", "incomplete", "in_progress"]] = None """The status of the item. Has no effect on the conversation.""" diff --git a/src/openai/types/realtime/realtime_conversation_item_system_message_param.py b/src/openai/types/realtime/realtime_conversation_item_system_message_param.py index 2a1c442738..a2790fcf67 100644 --- a/src/openai/types/realtime/realtime_conversation_item_system_message_param.py +++ b/src/openai/types/realtime/realtime_conversation_item_system_message_param.py @@ -27,10 +27,16 @@ class RealtimeConversationItemSystemMessageParam(TypedDict, total=False): """The type of the item. Always `message`.""" id: str - """The unique ID of the item.""" + """The unique ID of the item. + + This may be provided by the client or generated by the server. + """ object: Literal["realtime.item"] - """Identifier for the API object being returned - always `realtime.item`.""" + """Identifier for the API object being returned - always `realtime.item`. + + Optional when creating a new item. + """ status: Literal["completed", "incomplete", "in_progress"] """The status of the item. Has no effect on the conversation.""" diff --git a/src/openai/types/realtime/realtime_conversation_item_user_message.py b/src/openai/types/realtime/realtime_conversation_item_user_message.py index 48a6c6ec0a..30d9bb10e3 100644 --- a/src/openai/types/realtime/realtime_conversation_item_user_message.py +++ b/src/openai/types/realtime/realtime_conversation_item_user_message.py @@ -10,16 +10,37 @@ class Content(BaseModel): audio: Optional[str] = None - """Base64-encoded audio bytes (for `input_audio`).""" + """ + Base64-encoded audio bytes (for `input_audio`), these will be parsed as the + format specified in the session input audio type configuration. This defaults to + PCM 16-bit 24kHz mono if not specified. + """ + + detail: Optional[Literal["auto", "low", "high"]] = None + """The detail level of the image (for `input_image`). + + `auto` will default to `high`. + """ + + image_url: Optional[str] = None + """Base64-encoded image bytes (for `input_image`) as a data URI. + + For example `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...`. Supported + formats are PNG and JPEG. + """ text: Optional[str] = None """The text content (for `input_text`).""" transcript: Optional[str] = None - """Transcript of the audio (for `input_audio`).""" + """Transcript of the audio (for `input_audio`). - type: Optional[Literal["input_text", "input_audio"]] = None - """The content type (`input_text` or `input_audio`).""" + This is not sent to the model, but will be attached to the message item for + reference. + """ + + type: Optional[Literal["input_text", "input_audio", "input_image"]] = None + """The content type (`input_text`, `input_audio`, or `input_image`).""" class RealtimeConversationItemUserMessage(BaseModel): @@ -33,10 +54,16 @@ class RealtimeConversationItemUserMessage(BaseModel): """The type of the item. Always `message`.""" id: Optional[str] = None - """The unique ID of the item.""" + """The unique ID of the item. + + This may be provided by the client or generated by the server. + """ object: Optional[Literal["realtime.item"]] = None - """Identifier for the API object being returned - always `realtime.item`.""" + """Identifier for the API object being returned - always `realtime.item`. + + Optional when creating a new item. + """ status: Optional[Literal["completed", "incomplete", "in_progress"]] = None """The status of the item. Has no effect on the conversation.""" diff --git a/src/openai/types/realtime/realtime_conversation_item_user_message_param.py b/src/openai/types/realtime/realtime_conversation_item_user_message_param.py index cff64a66bf..7d3b9bc137 100644 --- a/src/openai/types/realtime/realtime_conversation_item_user_message_param.py +++ b/src/openai/types/realtime/realtime_conversation_item_user_message_param.py @@ -10,16 +10,37 @@ class Content(TypedDict, total=False): audio: str - """Base64-encoded audio bytes (for `input_audio`).""" + """ + Base64-encoded audio bytes (for `input_audio`), these will be parsed as the + format specified in the session input audio type configuration. This defaults to + PCM 16-bit 24kHz mono if not specified. + """ + + detail: Literal["auto", "low", "high"] + """The detail level of the image (for `input_image`). + + `auto` will default to `high`. + """ + + image_url: str + """Base64-encoded image bytes (for `input_image`) as a data URI. + + For example `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...`. Supported + formats are PNG and JPEG. + """ text: str """The text content (for `input_text`).""" transcript: str - """Transcript of the audio (for `input_audio`).""" + """Transcript of the audio (for `input_audio`). - type: Literal["input_text", "input_audio"] - """The content type (`input_text` or `input_audio`).""" + This is not sent to the model, but will be attached to the message item for + reference. + """ + + type: Literal["input_text", "input_audio", "input_image"] + """The content type (`input_text`, `input_audio`, or `input_image`).""" class RealtimeConversationItemUserMessageParam(TypedDict, total=False): @@ -33,10 +54,16 @@ class RealtimeConversationItemUserMessageParam(TypedDict, total=False): """The type of the item. Always `message`.""" id: str - """The unique ID of the item.""" + """The unique ID of the item. + + This may be provided by the client or generated by the server. + """ object: Literal["realtime.item"] - """Identifier for the API object being returned - always `realtime.item`.""" + """Identifier for the API object being returned - always `realtime.item`. + + Optional when creating a new item. + """ status: Literal["completed", "incomplete", "in_progress"] """The status of the item. Has no effect on the conversation.""" diff --git a/src/openai/types/realtime/realtime_response.py b/src/openai/types/realtime/realtime_response.py index 54f5999b81..92d75491c0 100644 --- a/src/openai/types/realtime/realtime_response.py +++ b/src/openai/types/realtime/realtime_response.py @@ -6,15 +6,39 @@ from ..._models import BaseModel from ..shared.metadata import Metadata from .conversation_item import ConversationItem +from .realtime_audio_formats import RealtimeAudioFormats from .realtime_response_usage import RealtimeResponseUsage from .realtime_response_status import RealtimeResponseStatus -__all__ = ["RealtimeResponse"] +__all__ = ["RealtimeResponse", "Audio", "AudioOutput"] + + +class AudioOutput(BaseModel): + format: Optional[RealtimeAudioFormats] = None + """The format of the output audio.""" + + voice: Union[ + str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"], None + ] = None + """The voice the model uses to respond. + + Voice cannot be changed during the session once the model has responded with + audio at least once. Current voice options are `alloy`, `ash`, `ballad`, + `coral`, `echo`, `sage`, `shimmer`, `verse`, `marin`, and `cedar`. We recommend + `marin` and `cedar` for best quality. + """ + + +class Audio(BaseModel): + output: Optional[AudioOutput] = None class RealtimeResponse(BaseModel): id: Optional[str] = None - """The unique ID of the response.""" + """The unique ID of the response, will look like `resp_1234`.""" + + audio: Optional[Audio] = None + """Configuration for audio output.""" conversation_id: Optional[str] = None """ @@ -23,8 +47,7 @@ class RealtimeResponse(BaseModel): the default conversation and the value of `conversation_id` will be an id like `conv_1234`. If `none`, the response will not be added to any conversation and the value of `conversation_id` will be `null`. If responses are being triggered - by server VAD, the response will be added to the default conversation, thus the - `conversation_id` will be an id like `conv_1234`. + automatically by VAD the response will be added to the default conversation """ max_output_tokens: Union[int, Literal["inf"], None] = None @@ -43,22 +66,19 @@ class RealtimeResponse(BaseModel): a maximum length of 512 characters. """ - modalities: Optional[List[Literal["text", "audio"]]] = None - """The set of modalities the model used to respond. - - If there are multiple modalities, the model will pick one, for example if - `modalities` is `["text", "audio"]`, the model could be responding in either - text or audio. - """ - object: Optional[Literal["realtime.response"]] = None """The object type, must be `realtime.response`.""" output: Optional[List[ConversationItem]] = None """The list of output items generated by the response.""" - output_audio_format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None - """The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + output_modalities: Optional[List[Literal["text", "audio"]]] = None + """ + The set of modalities the model used to respond, currently the only possible + values are `[\"audio\"]`, `[\"text\"]`. Audio output always include a text + transcript. Setting the output to mode `text` will disable audio output from the + model. + """ status: Optional[Literal["completed", "cancelled", "failed", "incomplete", "in_progress"]] = None """ @@ -69,9 +89,6 @@ class RealtimeResponse(BaseModel): status_details: Optional[RealtimeResponseStatus] = None """Additional details about the status.""" - temperature: Optional[float] = None - """Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8.""" - usage: Optional[RealtimeResponseUsage] = None """Usage statistics for the Response, this will correspond to billing. @@ -79,11 +96,3 @@ class RealtimeResponse(BaseModel): to the Conversation, thus output from previous turns (text and audio tokens) will become the input for later turns. """ - - voice: Union[ - str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"], None - ] = None - """ - The voice the model used to respond. Current voice options are `alloy`, `ash`, - `ballad`, `coral`, `echo`, `sage`, `shimmer`, and `verse`. - """ diff --git a/src/openai/types/realtime/realtime_response_create_audio_output.py b/src/openai/types/realtime/realtime_response_create_audio_output.py new file mode 100644 index 0000000000..48a5d67e20 --- /dev/null +++ b/src/openai/types/realtime/realtime_response_create_audio_output.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union, Optional +from typing_extensions import Literal + +from ..._models import BaseModel +from .realtime_audio_formats import RealtimeAudioFormats + +__all__ = ["RealtimeResponseCreateAudioOutput", "Output"] + + +class Output(BaseModel): + format: Optional[RealtimeAudioFormats] = None + """The format of the output audio.""" + + voice: Union[ + str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"], None + ] = None + """The voice the model uses to respond. + + Voice cannot be changed during the session once the model has responded with + audio at least once. Current voice options are `alloy`, `ash`, `ballad`, + `coral`, `echo`, `sage`, `shimmer`, `verse`, `marin`, and `cedar`. We recommend + `marin` and `cedar` for best quality. + """ + + +class RealtimeResponseCreateAudioOutput(BaseModel): + output: Optional[Output] = None diff --git a/src/openai/types/realtime/realtime_response_create_audio_output_param.py b/src/openai/types/realtime/realtime_response_create_audio_output_param.py new file mode 100644 index 0000000000..9aa6d28835 --- /dev/null +++ b/src/openai/types/realtime/realtime_response_create_audio_output_param.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import Literal, TypedDict + +from .realtime_audio_formats_param import RealtimeAudioFormatsParam + +__all__ = ["RealtimeResponseCreateAudioOutputParam", "Output"] + + +class Output(TypedDict, total=False): + format: RealtimeAudioFormatsParam + """The format of the output audio.""" + + voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"]] + """The voice the model uses to respond. + + Voice cannot be changed during the session once the model has responded with + audio at least once. Current voice options are `alloy`, `ash`, `ballad`, + `coral`, `echo`, `sage`, `shimmer`, `verse`, `marin`, and `cedar`. We recommend + `marin` and `cedar` for best quality. + """ + + +class RealtimeResponseCreateAudioOutputParam(TypedDict, total=False): + output: Output diff --git a/src/openai/types/realtime/realtime_response_create_mcp_tool.py b/src/openai/types/realtime/realtime_response_create_mcp_tool.py new file mode 100644 index 0000000000..119b4a455d --- /dev/null +++ b/src/openai/types/realtime/realtime_response_create_mcp_tool.py @@ -0,0 +1,135 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, TypeAlias + +from ..._models import BaseModel + +__all__ = [ + "RealtimeResponseCreateMcpTool", + "AllowedTools", + "AllowedToolsMcpToolFilter", + "RequireApproval", + "RequireApprovalMcpToolApprovalFilter", + "RequireApprovalMcpToolApprovalFilterAlways", + "RequireApprovalMcpToolApprovalFilterNever", +] + + +class AllowedToolsMcpToolFilter(BaseModel): + read_only: Optional[bool] = None + """Indicates whether or not a tool modifies data or is read-only. + + If an MCP server is + [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), + it will match this filter. + """ + + tool_names: Optional[List[str]] = None + """List of allowed tool names.""" + + +AllowedTools: TypeAlias = Union[List[str], AllowedToolsMcpToolFilter, None] + + +class RequireApprovalMcpToolApprovalFilterAlways(BaseModel): + read_only: Optional[bool] = None + """Indicates whether or not a tool modifies data or is read-only. + + If an MCP server is + [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), + it will match this filter. + """ + + tool_names: Optional[List[str]] = None + """List of allowed tool names.""" + + +class RequireApprovalMcpToolApprovalFilterNever(BaseModel): + read_only: Optional[bool] = None + """Indicates whether or not a tool modifies data or is read-only. + + If an MCP server is + [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), + it will match this filter. + """ + + tool_names: Optional[List[str]] = None + """List of allowed tool names.""" + + +class RequireApprovalMcpToolApprovalFilter(BaseModel): + always: Optional[RequireApprovalMcpToolApprovalFilterAlways] = None + """A filter object to specify which tools are allowed.""" + + never: Optional[RequireApprovalMcpToolApprovalFilterNever] = None + """A filter object to specify which tools are allowed.""" + + +RequireApproval: TypeAlias = Union[RequireApprovalMcpToolApprovalFilter, Literal["always", "never"], None] + + +class RealtimeResponseCreateMcpTool(BaseModel): + server_label: str + """A label for this MCP server, used to identify it in tool calls.""" + + type: Literal["mcp"] + """The type of the MCP tool. Always `mcp`.""" + + allowed_tools: Optional[AllowedTools] = None + """List of allowed tool names or a filter object.""" + + authorization: Optional[str] = None + """ + An OAuth access token that can be used with a remote MCP server, either with a + custom MCP server URL or a service connector. Your application must handle the + OAuth authorization flow and provide the token here. + """ + + connector_id: Optional[ + Literal[ + "connector_dropbox", + "connector_gmail", + "connector_googlecalendar", + "connector_googledrive", + "connector_microsoftteams", + "connector_outlookcalendar", + "connector_outlookemail", + "connector_sharepoint", + ] + ] = None + """Identifier for service connectors, like those available in ChatGPT. + + One of `server_url` or `connector_id` must be provided. Learn more about service + connectors + [here](https://platform.openai.com/docs/guides/tools-remote-mcp#connectors). + + Currently supported `connector_id` values are: + + - Dropbox: `connector_dropbox` + - Gmail: `connector_gmail` + - Google Calendar: `connector_googlecalendar` + - Google Drive: `connector_googledrive` + - Microsoft Teams: `connector_microsoftteams` + - Outlook Calendar: `connector_outlookcalendar` + - Outlook Email: `connector_outlookemail` + - SharePoint: `connector_sharepoint` + """ + + headers: Optional[Dict[str, str]] = None + """Optional HTTP headers to send to the MCP server. + + Use for authentication or other purposes. + """ + + require_approval: Optional[RequireApproval] = None + """Specify which of the MCP server's tools require approval.""" + + server_description: Optional[str] = None + """Optional description of the MCP server, used to provide more context.""" + + server_url: Optional[str] = None + """The URL for the MCP server. + + One of `server_url` or `connector_id` must be provided. + """ diff --git a/src/openai/types/realtime/realtime_response_create_mcp_tool_param.py b/src/openai/types/realtime/realtime_response_create_mcp_tool_param.py new file mode 100644 index 0000000000..3b9cf047c1 --- /dev/null +++ b/src/openai/types/realtime/realtime_response_create_mcp_tool_param.py @@ -0,0 +1,135 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from ..._types import SequenceNotStr + +__all__ = [ + "RealtimeResponseCreateMcpToolParam", + "AllowedTools", + "AllowedToolsMcpToolFilter", + "RequireApproval", + "RequireApprovalMcpToolApprovalFilter", + "RequireApprovalMcpToolApprovalFilterAlways", + "RequireApprovalMcpToolApprovalFilterNever", +] + + +class AllowedToolsMcpToolFilter(TypedDict, total=False): + read_only: bool + """Indicates whether or not a tool modifies data or is read-only. + + If an MCP server is + [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), + it will match this filter. + """ + + tool_names: SequenceNotStr[str] + """List of allowed tool names.""" + + +AllowedTools: TypeAlias = Union[SequenceNotStr[str], AllowedToolsMcpToolFilter] + + +class RequireApprovalMcpToolApprovalFilterAlways(TypedDict, total=False): + read_only: bool + """Indicates whether or not a tool modifies data or is read-only. + + If an MCP server is + [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), + it will match this filter. + """ + + tool_names: SequenceNotStr[str] + """List of allowed tool names.""" + + +class RequireApprovalMcpToolApprovalFilterNever(TypedDict, total=False): + read_only: bool + """Indicates whether or not a tool modifies data or is read-only. + + If an MCP server is + [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), + it will match this filter. + """ + + tool_names: SequenceNotStr[str] + """List of allowed tool names.""" + + +class RequireApprovalMcpToolApprovalFilter(TypedDict, total=False): + always: RequireApprovalMcpToolApprovalFilterAlways + """A filter object to specify which tools are allowed.""" + + never: RequireApprovalMcpToolApprovalFilterNever + """A filter object to specify which tools are allowed.""" + + +RequireApproval: TypeAlias = Union[RequireApprovalMcpToolApprovalFilter, Literal["always", "never"]] + + +class RealtimeResponseCreateMcpToolParam(TypedDict, total=False): + server_label: Required[str] + """A label for this MCP server, used to identify it in tool calls.""" + + type: Required[Literal["mcp"]] + """The type of the MCP tool. Always `mcp`.""" + + allowed_tools: Optional[AllowedTools] + """List of allowed tool names or a filter object.""" + + authorization: str + """ + An OAuth access token that can be used with a remote MCP server, either with a + custom MCP server URL or a service connector. Your application must handle the + OAuth authorization flow and provide the token here. + """ + + connector_id: Literal[ + "connector_dropbox", + "connector_gmail", + "connector_googlecalendar", + "connector_googledrive", + "connector_microsoftteams", + "connector_outlookcalendar", + "connector_outlookemail", + "connector_sharepoint", + ] + """Identifier for service connectors, like those available in ChatGPT. + + One of `server_url` or `connector_id` must be provided. Learn more about service + connectors + [here](https://platform.openai.com/docs/guides/tools-remote-mcp#connectors). + + Currently supported `connector_id` values are: + + - Dropbox: `connector_dropbox` + - Gmail: `connector_gmail` + - Google Calendar: `connector_googlecalendar` + - Google Drive: `connector_googledrive` + - Microsoft Teams: `connector_microsoftteams` + - Outlook Calendar: `connector_outlookcalendar` + - Outlook Email: `connector_outlookemail` + - SharePoint: `connector_sharepoint` + """ + + headers: Optional[Dict[str, str]] + """Optional HTTP headers to send to the MCP server. + + Use for authentication or other purposes. + """ + + require_approval: Optional[RequireApproval] + """Specify which of the MCP server's tools require approval.""" + + server_description: str + """Optional description of the MCP server, used to provide more context.""" + + server_url: str + """The URL for the MCP server. + + One of `server_url` or `connector_id` must be provided. + """ diff --git a/src/openai/types/realtime/realtime_response_create_params.py b/src/openai/types/realtime/realtime_response_create_params.py new file mode 100644 index 0000000000..3b5a8907a1 --- /dev/null +++ b/src/openai/types/realtime/realtime_response_create_params.py @@ -0,0 +1,98 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, TypeAlias + +from .models import Models +from ..._models import BaseModel +from ..shared.metadata import Metadata +from .conversation_item import ConversationItem +from ..responses.response_prompt import ResponsePrompt +from ..responses.tool_choice_mcp import ToolChoiceMcp +from ..responses.tool_choice_options import ToolChoiceOptions +from ..responses.tool_choice_function import ToolChoiceFunction +from .realtime_response_create_mcp_tool import RealtimeResponseCreateMcpTool +from .realtime_response_create_audio_output import RealtimeResponseCreateAudioOutput + +__all__ = ["RealtimeResponseCreateParams", "ToolChoice", "Tool"] + +ToolChoice: TypeAlias = Union[ToolChoiceOptions, ToolChoiceFunction, ToolChoiceMcp] + +Tool: TypeAlias = Union[Models, RealtimeResponseCreateMcpTool] + + +class RealtimeResponseCreateParams(BaseModel): + audio: Optional[RealtimeResponseCreateAudioOutput] = None + """Configuration for audio input and output.""" + + conversation: Union[str, Literal["auto", "none"], None] = None + """Controls which conversation the response is added to. + + Currently supports `auto` and `none`, with `auto` as the default value. The + `auto` value means that the contents of the response will be added to the + default conversation. Set this to `none` to create an out-of-band response which + will not add items to default conversation. + """ + + input: Optional[List[ConversationItem]] = None + """Input items to include in the prompt for the model. + + Using this field creates a new context for this Response instead of using the + default conversation. An empty array `[]` will clear the context for this + Response. Note that this can include references to items that previously + appeared in the session using their id. + """ + + instructions: Optional[str] = None + """The default system instructions (i.e. + + system message) prepended to model calls. This field allows the client to guide + the model on desired responses. The model can be instructed on response content + and format, (e.g. "be extremely succinct", "act friendly", "here are examples of + good responses") and on audio behavior (e.g. "talk quickly", "inject emotion + into your voice", "laugh frequently"). The instructions are not guaranteed to be + followed by the model, but they provide guidance to the model on the desired + behavior. Note that the server sets default instructions which will be used if + this field is not set and are visible in the `session.created` event at the + start of the session. + """ + + max_output_tokens: Union[int, Literal["inf"], None] = None + """ + Maximum number of output tokens for a single assistant response, inclusive of + tool calls. Provide an integer between 1 and 4096 to limit output tokens, or + `inf` for the maximum available tokens for a given model. Defaults to `inf`. + """ + + metadata: Optional[Metadata] = None + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + """ + + output_modalities: Optional[List[Literal["text", "audio"]]] = None + """ + The set of modalities the model used to respond, currently the only possible + values are `[\"audio\"]`, `[\"text\"]`. Audio output always include a text + transcript. Setting the output to mode `text` will disable audio output from the + model. + """ + + prompt: Optional[ResponsePrompt] = None + """Reference to a prompt template and its variables. + + [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). + """ + + tool_choice: Optional[ToolChoice] = None + """How the model chooses tools. + + Provide one of the string modes or force a specific function/MCP tool. + """ + + tools: Optional[List[Tool]] = None + """Tools available to the model.""" diff --git a/src/openai/types/realtime/realtime_response_create_params_param.py b/src/openai/types/realtime/realtime_response_create_params_param.py new file mode 100644 index 0000000000..6800d36a31 --- /dev/null +++ b/src/openai/types/realtime/realtime_response_create_params_param.py @@ -0,0 +1,99 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union, Iterable, Optional +from typing_extensions import Literal, TypeAlias, TypedDict + +from .models_param import ModelsParam +from ..shared_params.metadata import Metadata +from .conversation_item_param import ConversationItemParam +from ..responses.tool_choice_options import ToolChoiceOptions +from ..responses.response_prompt_param import ResponsePromptParam +from ..responses.tool_choice_mcp_param import ToolChoiceMcpParam +from ..responses.tool_choice_function_param import ToolChoiceFunctionParam +from .realtime_response_create_mcp_tool_param import RealtimeResponseCreateMcpToolParam +from .realtime_response_create_audio_output_param import RealtimeResponseCreateAudioOutputParam + +__all__ = ["RealtimeResponseCreateParamsParam", "ToolChoice", "Tool"] + +ToolChoice: TypeAlias = Union[ToolChoiceOptions, ToolChoiceFunctionParam, ToolChoiceMcpParam] + +Tool: TypeAlias = Union[ModelsParam, RealtimeResponseCreateMcpToolParam] + + +class RealtimeResponseCreateParamsParam(TypedDict, total=False): + audio: RealtimeResponseCreateAudioOutputParam + """Configuration for audio input and output.""" + + conversation: Union[str, Literal["auto", "none"]] + """Controls which conversation the response is added to. + + Currently supports `auto` and `none`, with `auto` as the default value. The + `auto` value means that the contents of the response will be added to the + default conversation. Set this to `none` to create an out-of-band response which + will not add items to default conversation. + """ + + input: Iterable[ConversationItemParam] + """Input items to include in the prompt for the model. + + Using this field creates a new context for this Response instead of using the + default conversation. An empty array `[]` will clear the context for this + Response. Note that this can include references to items that previously + appeared in the session using their id. + """ + + instructions: str + """The default system instructions (i.e. + + system message) prepended to model calls. This field allows the client to guide + the model on desired responses. The model can be instructed on response content + and format, (e.g. "be extremely succinct", "act friendly", "here are examples of + good responses") and on audio behavior (e.g. "talk quickly", "inject emotion + into your voice", "laugh frequently"). The instructions are not guaranteed to be + followed by the model, but they provide guidance to the model on the desired + behavior. Note that the server sets default instructions which will be used if + this field is not set and are visible in the `session.created` event at the + start of the session. + """ + + max_output_tokens: Union[int, Literal["inf"]] + """ + Maximum number of output tokens for a single assistant response, inclusive of + tool calls. Provide an integer between 1 and 4096 to limit output tokens, or + `inf` for the maximum available tokens for a given model. Defaults to `inf`. + """ + + metadata: Optional[Metadata] + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + """ + + output_modalities: List[Literal["text", "audio"]] + """ + The set of modalities the model used to respond, currently the only possible + values are `[\"audio\"]`, `[\"text\"]`. Audio output always include a text + transcript. Setting the output to mode `text` will disable audio output from the + model. + """ + + prompt: Optional[ResponsePromptParam] + """Reference to a prompt template and its variables. + + [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). + """ + + tool_choice: ToolChoice + """How the model chooses tools. + + Provide one of the string modes or force a specific function/MCP tool. + """ + + tools: Iterable[Tool] + """Tools available to the model.""" diff --git a/src/openai/types/realtime/realtime_response_usage.py b/src/openai/types/realtime/realtime_response_usage.py index dbce5f28c3..fb8893b346 100644 --- a/src/openai/types/realtime/realtime_response_usage.py +++ b/src/openai/types/realtime/realtime_response_usage.py @@ -11,7 +11,13 @@ class RealtimeResponseUsage(BaseModel): input_token_details: Optional[RealtimeResponseUsageInputTokenDetails] = None - """Details about the input tokens used in the Response.""" + """Details about the input tokens used in the Response. + + Cached tokens are tokens from previous turns in the conversation that are + included as context for the current response. Cached tokens here are counted as + a subset of input tokens, meaning input tokens will include cached and uncached + tokens. + """ input_tokens: Optional[int] = None """ diff --git a/src/openai/types/realtime/realtime_response_usage_input_token_details.py b/src/openai/types/realtime/realtime_response_usage_input_token_details.py index dfeead90ef..e14a74a84e 100644 --- a/src/openai/types/realtime/realtime_response_usage_input_token_details.py +++ b/src/openai/types/realtime/realtime_response_usage_input_token_details.py @@ -4,15 +4,32 @@ from ..._models import BaseModel -__all__ = ["RealtimeResponseUsageInputTokenDetails"] +__all__ = ["RealtimeResponseUsageInputTokenDetails", "CachedTokensDetails"] + + +class CachedTokensDetails(BaseModel): + audio_tokens: Optional[int] = None + """The number of cached audio tokens used as input for the Response.""" + + image_tokens: Optional[int] = None + """The number of cached image tokens used as input for the Response.""" + + text_tokens: Optional[int] = None + """The number of cached text tokens used as input for the Response.""" class RealtimeResponseUsageInputTokenDetails(BaseModel): audio_tokens: Optional[int] = None - """The number of audio tokens used in the Response.""" + """The number of audio tokens used as input for the Response.""" cached_tokens: Optional[int] = None - """The number of cached tokens used in the Response.""" + """The number of cached tokens used as input for the Response.""" + + cached_tokens_details: Optional[CachedTokensDetails] = None + """Details about the cached tokens used as input for the Response.""" + + image_tokens: Optional[int] = None + """The number of image tokens used as input for the Response.""" text_tokens: Optional[int] = None - """The number of text tokens used in the Response.""" + """The number of text tokens used as input for the Response.""" diff --git a/src/openai/types/realtime/realtime_session.py b/src/openai/types/realtime/realtime_session.py deleted file mode 100644 index fdb5e9419a..0000000000 --- a/src/openai/types/realtime/realtime_session.py +++ /dev/null @@ -1,307 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal, TypeAlias - -from ..._models import BaseModel -from ..responses.response_prompt import ResponsePrompt - -__all__ = [ - "RealtimeSession", - "InputAudioNoiseReduction", - "InputAudioTranscription", - "Tool", - "Tracing", - "TracingTracingConfiguration", - "TurnDetection", -] - - -class InputAudioNoiseReduction(BaseModel): - type: Optional[Literal["near_field", "far_field"]] = None - """Type of noise reduction. - - `near_field` is for close-talking microphones such as headphones, `far_field` is - for far-field microphones such as laptop or conference room microphones. - """ - - -class InputAudioTranscription(BaseModel): - language: Optional[str] = None - """The language of the input audio. - - Supplying the input language in - [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) - format will improve accuracy and latency. - """ - - model: Optional[str] = None - """ - The model to use for transcription, current options are `gpt-4o-transcribe`, - `gpt-4o-mini-transcribe`, and `whisper-1`. - """ - - prompt: Optional[str] = None - """ - An optional text to guide the model's style or continue a previous audio - segment. For `whisper-1`, the - [prompt is a list of keywords](https://platform.openai.com/docs/guides/speech-to-text#prompting). - For `gpt-4o-transcribe` models, the prompt is a free text string, for example - "expect words related to technology". - """ - - -class Tool(BaseModel): - description: Optional[str] = None - """ - The description of the function, including guidance on when and how to call it, - and guidance about what to tell the user when calling (if anything). - """ - - name: Optional[str] = None - """The name of the function.""" - - parameters: Optional[object] = None - """Parameters of the function in JSON Schema.""" - - type: Optional[Literal["function"]] = None - """The type of the tool, i.e. `function`.""" - - -class TracingTracingConfiguration(BaseModel): - group_id: Optional[str] = None - """ - The group id to attach to this trace to enable filtering and grouping in the - traces dashboard. - """ - - metadata: Optional[object] = None - """ - The arbitrary metadata to attach to this trace to enable filtering in the traces - dashboard. - """ - - workflow_name: Optional[str] = None - """The name of the workflow to attach to this trace. - - This is used to name the trace in the traces dashboard. - """ - - -Tracing: TypeAlias = Union[Literal["auto"], TracingTracingConfiguration, None] - - -class TurnDetection(BaseModel): - create_response: Optional[bool] = None - """ - Whether or not to automatically generate a response when a VAD stop event - occurs. - """ - - eagerness: Optional[Literal["low", "medium", "high", "auto"]] = None - """Used only for `semantic_vad` mode. - - The eagerness of the model to respond. `low` will wait longer for the user to - continue speaking, `high` will respond more quickly. `auto` is the default and - is equivalent to `medium`. - """ - - idle_timeout_ms: Optional[int] = None - """ - Optional idle timeout after which turn detection will auto-timeout when no - additional audio is received. - """ - - interrupt_response: Optional[bool] = None - """ - Whether or not to automatically interrupt any ongoing response with output to - the default conversation (i.e. `conversation` of `auto`) when a VAD start event - occurs. - """ - - prefix_padding_ms: Optional[int] = None - """Used only for `server_vad` mode. - - Amount of audio to include before the VAD detected speech (in milliseconds). - Defaults to 300ms. - """ - - silence_duration_ms: Optional[int] = None - """Used only for `server_vad` mode. - - Duration of silence to detect speech stop (in milliseconds). Defaults to 500ms. - With shorter values the model will respond more quickly, but may jump in on - short pauses from the user. - """ - - threshold: Optional[float] = None - """Used only for `server_vad` mode. - - Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A higher - threshold will require louder audio to activate the model, and thus might - perform better in noisy environments. - """ - - type: Optional[Literal["server_vad", "semantic_vad"]] = None - """Type of turn detection.""" - - -class RealtimeSession(BaseModel): - id: Optional[str] = None - """Unique identifier for the session that looks like `sess_1234567890abcdef`.""" - - expires_at: Optional[int] = None - """Expiration timestamp for the session, in seconds since epoch.""" - - include: Optional[List[Literal["item.input_audio_transcription.logprobs"]]] = None - """Additional fields to include in server outputs. - - - `item.input_audio_transcription.logprobs`: Include logprobs for input audio - transcription. - """ - - input_audio_format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None - """The format of input audio. - - Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, input audio must - be 16-bit PCM at a 24kHz sample rate, single channel (mono), and little-endian - byte order. - """ - - input_audio_noise_reduction: Optional[InputAudioNoiseReduction] = None - """Configuration for input audio noise reduction. - - This can be set to `null` to turn off. Noise reduction filters audio added to - the input audio buffer before it is sent to VAD and the model. Filtering the - audio can improve VAD and turn detection accuracy (reducing false positives) and - model performance by improving perception of the input audio. - """ - - input_audio_transcription: Optional[InputAudioTranscription] = None - """ - Configuration for input audio transcription, defaults to off and can be set to - `null` to turn off once on. Input audio transcription is not native to the - model, since the model consumes audio directly. Transcription runs - asynchronously through - [the /audio/transcriptions endpoint](https://platform.openai.com/docs/api-reference/audio/createTranscription) - and should be treated as guidance of input audio content rather than precisely - what the model heard. The client can optionally set the language and prompt for - transcription, these offer additional guidance to the transcription service. - """ - - instructions: Optional[str] = None - """The default system instructions (i.e. - - system message) prepended to model calls. This field allows the client to guide - the model on desired responses. The model can be instructed on response content - and format, (e.g. "be extremely succinct", "act friendly", "here are examples of - good responses") and on audio behavior (e.g. "talk quickly", "inject emotion - into your voice", "laugh frequently"). The instructions are not guaranteed to be - followed by the model, but they provide guidance to the model on the desired - behavior. - - Note that the server sets default instructions which will be used if this field - is not set and are visible in the `session.created` event at the start of the - session. - """ - - max_response_output_tokens: Union[int, Literal["inf"], None] = None - """ - Maximum number of output tokens for a single assistant response, inclusive of - tool calls. Provide an integer between 1 and 4096 to limit output tokens, or - `inf` for the maximum available tokens for a given model. Defaults to `inf`. - """ - - modalities: Optional[List[Literal["text", "audio"]]] = None - """The set of modalities the model can respond with. - - To disable audio, set this to ["text"]. - """ - - model: Optional[ - Literal[ - "gpt-realtime", - "gpt-realtime-2025-08-28", - "gpt-4o-realtime-preview", - "gpt-4o-realtime-preview-2024-10-01", - "gpt-4o-realtime-preview-2024-12-17", - "gpt-4o-realtime-preview-2025-06-03", - "gpt-4o-mini-realtime-preview", - "gpt-4o-mini-realtime-preview-2024-12-17", - ] - ] = None - """The Realtime model used for this session.""" - - object: Optional[Literal["realtime.session"]] = None - """The object type. Always `realtime.session`.""" - - output_audio_format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None - """The format of output audio. - - Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, output audio is - sampled at a rate of 24kHz. - """ - - prompt: Optional[ResponsePrompt] = None - """Reference to a prompt template and its variables. - - [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). - """ - - speed: Optional[float] = None - """The speed of the model's spoken response. - - 1.0 is the default speed. 0.25 is the minimum speed. 1.5 is the maximum speed. - This value can only be changed in between model turns, not while a response is - in progress. - """ - - temperature: Optional[float] = None - """Sampling temperature for the model, limited to [0.6, 1.2]. - - For audio models a temperature of 0.8 is highly recommended for best - performance. - """ - - tool_choice: Optional[str] = None - """How the model chooses tools. - - Options are `auto`, `none`, `required`, or specify a function. - """ - - tools: Optional[List[Tool]] = None - """Tools (functions) available to the model.""" - - tracing: Optional[Tracing] = None - """Configuration options for tracing. - - Set to null to disable tracing. Once tracing is enabled for a session, the - configuration cannot be modified. - - `auto` will create a trace for the session with default values for the workflow - name, group id, and metadata. - """ - - turn_detection: Optional[TurnDetection] = None - """Configuration for turn detection, ether Server VAD or Semantic VAD. - - This can be set to `null` to turn off, in which case the client must manually - trigger model response. Server VAD means that the model will detect the start - and end of speech based on audio volume and respond at the end of user speech. - Semantic VAD is more advanced and uses a turn detection model (in conjunction - with VAD) to semantically estimate whether the user has finished speaking, then - dynamically sets a timeout based on this probability. For example, if user audio - trails off with "uhhm", the model will score a low probability of turn end and - wait longer for the user to continue speaking. This can be useful for more - natural conversations, but may have a higher latency. - """ - - voice: Union[ - str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"], None - ] = None - """The voice the model uses to respond. - - Voice cannot be changed during the session once the model has responded with - audio at least once. Current voice options are `alloy`, `ash`, `ballad`, - `coral`, `echo`, `sage`, `shimmer`, and `verse`. - """ diff --git a/src/openai/types/realtime/realtime_session_client_secret.py b/src/openai/types/realtime/realtime_session_client_secret.py new file mode 100644 index 0000000000..a4998802bb --- /dev/null +++ b/src/openai/types/realtime/realtime_session_client_secret.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["RealtimeSessionClientSecret"] + + +class RealtimeSessionClientSecret(BaseModel): + expires_at: int + """Timestamp for when the token expires. + + Currently, all tokens expire after one minute. + """ + + value: str + """ + Ephemeral key usable in client environments to authenticate connections to the + Realtime API. Use this in client-side environments rather than a standard API + token, which should only be used server-side. + """ diff --git a/src/openai/types/realtime/realtime_session_create_request.py b/src/openai/types/realtime/realtime_session_create_request.py index 85205add50..578bc43821 100644 --- a/src/openai/types/realtime/realtime_session_create_request.py +++ b/src/openai/types/realtime/realtime_session_create_request.py @@ -10,43 +10,22 @@ from .realtime_tracing_config import RealtimeTracingConfig from ..responses.response_prompt import ResponsePrompt from .realtime_tool_choice_config import RealtimeToolChoiceConfig -from .realtime_client_secret_config import RealtimeClientSecretConfig __all__ = ["RealtimeSessionCreateRequest"] class RealtimeSessionCreateRequest(BaseModel): - model: Union[ - str, - Literal[ - "gpt-realtime", - "gpt-realtime-2025-08-28", - "gpt-4o-realtime", - "gpt-4o-mini-realtime", - "gpt-4o-realtime-preview", - "gpt-4o-realtime-preview-2024-10-01", - "gpt-4o-realtime-preview-2024-12-17", - "gpt-4o-realtime-preview-2025-06-03", - "gpt-4o-mini-realtime-preview", - "gpt-4o-mini-realtime-preview-2024-12-17", - ], - ] - """The Realtime model used for this session.""" - type: Literal["realtime"] """The type of session to create. Always `realtime` for the Realtime API.""" audio: Optional[RealtimeAudioConfig] = None """Configuration for input and output audio.""" - client_secret: Optional[RealtimeClientSecretConfig] = None - """Configuration options for the generated client secret.""" - include: Optional[List[Literal["item.input_audio_transcription.logprobs"]]] = None """Additional fields to include in server outputs. - - `item.input_audio_transcription.logprobs`: Include logprobs for input audio - transcription. + `item.input_audio_transcription.logprobs`: Include logprobs for input audio + transcription. """ instructions: Optional[str] = None @@ -72,10 +51,28 @@ class RealtimeSessionCreateRequest(BaseModel): `inf` for the maximum available tokens for a given model. Defaults to `inf`. """ + model: Union[ + str, + Literal[ + "gpt-realtime", + "gpt-realtime-2025-08-28", + "gpt-4o-realtime-preview", + "gpt-4o-realtime-preview-2024-10-01", + "gpt-4o-realtime-preview-2024-12-17", + "gpt-4o-realtime-preview-2025-06-03", + "gpt-4o-mini-realtime-preview", + "gpt-4o-mini-realtime-preview-2024-12-17", + ], + None, + ] = None + """The Realtime model used for this session.""" + output_modalities: Optional[List[Literal["text", "audio"]]] = None """The set of modalities the model can respond with. - To disable audio, set this to ["text"]. + It defaults to `["audio"]`, indicating that the model will respond with audio + plus a transcript. `["text"]` can be used to make the model respond with text + only. It is not possible to request both `text` and `audio` at the same time. """ prompt: Optional[ResponsePrompt] = None @@ -84,13 +81,6 @@ class RealtimeSessionCreateRequest(BaseModel): [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). """ - temperature: Optional[float] = None - """Sampling temperature for the model, limited to [0.6, 1.2]. - - For audio models a temperature of 0.8 is highly recommended for best - performance. - """ - tool_choice: Optional[RealtimeToolChoiceConfig] = None """How the model chooses tools. @@ -101,10 +91,10 @@ class RealtimeSessionCreateRequest(BaseModel): """Tools available to the model.""" tracing: Optional[RealtimeTracingConfig] = None - """Configuration options for tracing. - - Set to null to disable tracing. Once tracing is enabled for a session, the - configuration cannot be modified. + """ + Realtime API can write session traces to the + [Traces Dashboard](/logs?api=traces). Set to null to disable tracing. Once + tracing is enabled for a session, the configuration cannot be modified. `auto` will create a trace for the session with default values for the workflow name, group id, and metadata. @@ -113,6 +103,5 @@ class RealtimeSessionCreateRequest(BaseModel): truncation: Optional[RealtimeTruncation] = None """ Controls how the realtime conversation is truncated prior to model inference. - The default is `auto`. When set to `retention_ratio`, the server retains a - fraction of the conversation tokens prior to the instructions. + The default is `auto`. """ diff --git a/src/openai/types/realtime/realtime_session_create_request_param.py b/src/openai/types/realtime/realtime_session_create_request_param.py index 8f962ca0e2..5f7819fa61 100644 --- a/src/openai/types/realtime/realtime_session_create_request_param.py +++ b/src/openai/types/realtime/realtime_session_create_request_param.py @@ -11,45 +11,22 @@ from .realtime_tracing_config_param import RealtimeTracingConfigParam from ..responses.response_prompt_param import ResponsePromptParam from .realtime_tool_choice_config_param import RealtimeToolChoiceConfigParam -from .realtime_client_secret_config_param import RealtimeClientSecretConfigParam __all__ = ["RealtimeSessionCreateRequestParam"] class RealtimeSessionCreateRequestParam(TypedDict, total=False): - model: Required[ - Union[ - str, - Literal[ - "gpt-realtime", - "gpt-realtime-2025-08-28", - "gpt-4o-realtime", - "gpt-4o-mini-realtime", - "gpt-4o-realtime-preview", - "gpt-4o-realtime-preview-2024-10-01", - "gpt-4o-realtime-preview-2024-12-17", - "gpt-4o-realtime-preview-2025-06-03", - "gpt-4o-mini-realtime-preview", - "gpt-4o-mini-realtime-preview-2024-12-17", - ], - ] - ] - """The Realtime model used for this session.""" - type: Required[Literal["realtime"]] """The type of session to create. Always `realtime` for the Realtime API.""" audio: RealtimeAudioConfigParam """Configuration for input and output audio.""" - client_secret: RealtimeClientSecretConfigParam - """Configuration options for the generated client secret.""" - include: List[Literal["item.input_audio_transcription.logprobs"]] """Additional fields to include in server outputs. - - `item.input_audio_transcription.logprobs`: Include logprobs for input audio - transcription. + `item.input_audio_transcription.logprobs`: Include logprobs for input audio + transcription. """ instructions: str @@ -75,10 +52,27 @@ class RealtimeSessionCreateRequestParam(TypedDict, total=False): `inf` for the maximum available tokens for a given model. Defaults to `inf`. """ + model: Union[ + str, + Literal[ + "gpt-realtime", + "gpt-realtime-2025-08-28", + "gpt-4o-realtime-preview", + "gpt-4o-realtime-preview-2024-10-01", + "gpt-4o-realtime-preview-2024-12-17", + "gpt-4o-realtime-preview-2025-06-03", + "gpt-4o-mini-realtime-preview", + "gpt-4o-mini-realtime-preview-2024-12-17", + ], + ] + """The Realtime model used for this session.""" + output_modalities: List[Literal["text", "audio"]] """The set of modalities the model can respond with. - To disable audio, set this to ["text"]. + It defaults to `["audio"]`, indicating that the model will respond with audio + plus a transcript. `["text"]` can be used to make the model respond with text + only. It is not possible to request both `text` and `audio` at the same time. """ prompt: Optional[ResponsePromptParam] @@ -87,13 +81,6 @@ class RealtimeSessionCreateRequestParam(TypedDict, total=False): [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). """ - temperature: float - """Sampling temperature for the model, limited to [0.6, 1.2]. - - For audio models a temperature of 0.8 is highly recommended for best - performance. - """ - tool_choice: RealtimeToolChoiceConfigParam """How the model chooses tools. @@ -104,10 +91,10 @@ class RealtimeSessionCreateRequestParam(TypedDict, total=False): """Tools available to the model.""" tracing: Optional[RealtimeTracingConfigParam] - """Configuration options for tracing. - - Set to null to disable tracing. Once tracing is enabled for a session, the - configuration cannot be modified. + """ + Realtime API can write session traces to the + [Traces Dashboard](/logs?api=traces). Set to null to disable tracing. Once + tracing is enabled for a session, the configuration cannot be modified. `auto` will create a trace for the session with default values for the workflow name, group id, and metadata. @@ -116,6 +103,5 @@ class RealtimeSessionCreateRequestParam(TypedDict, total=False): truncation: RealtimeTruncationParam """ Controls how the realtime conversation is truncated prior to model inference. - The default is `auto`. When set to `retention_ratio`, the server retains a - fraction of the conversation tokens prior to the instructions. + The default is `auto`. """ diff --git a/src/openai/types/realtime/realtime_session_create_response.py b/src/openai/types/realtime/realtime_session_create_response.py index 82fa426982..9c10b84588 100644 --- a/src/openai/types/realtime/realtime_session_create_response.py +++ b/src/openai/types/realtime/realtime_session_create_response.py @@ -1,74 +1,171 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union, Optional +from typing import Dict, List, Union, Optional from typing_extensions import Literal, TypeAlias +from .models import Models from ..._models import BaseModel +from .audio_transcription import AudioTranscription +from .realtime_truncation import RealtimeTruncation +from .noise_reduction_type import NoiseReductionType +from .realtime_audio_formats import RealtimeAudioFormats +from ..responses.response_prompt import ResponsePrompt +from ..responses.tool_choice_mcp import ToolChoiceMcp +from ..responses.tool_choice_options import ToolChoiceOptions +from .realtime_session_client_secret import RealtimeSessionClientSecret +from ..responses.tool_choice_function import ToolChoiceFunction __all__ = [ "RealtimeSessionCreateResponse", "Audio", "AudioInput", "AudioInputNoiseReduction", - "AudioInputTranscription", "AudioInputTurnDetection", "AudioOutput", + "ToolChoice", "Tool", + "ToolMcpTool", + "ToolMcpToolAllowedTools", + "ToolMcpToolAllowedToolsMcpToolFilter", + "ToolMcpToolRequireApproval", + "ToolMcpToolRequireApprovalMcpToolApprovalFilter", + "ToolMcpToolRequireApprovalMcpToolApprovalFilterAlways", + "ToolMcpToolRequireApprovalMcpToolApprovalFilterNever", "Tracing", "TracingTracingConfiguration", - "TurnDetection", ] class AudioInputNoiseReduction(BaseModel): - type: Optional[Literal["near_field", "far_field"]] = None + type: Optional[NoiseReductionType] = None + """Type of noise reduction. + `near_field` is for close-talking microphones such as headphones, `far_field` is + for far-field microphones such as laptop or conference room microphones. + """ -class AudioInputTranscription(BaseModel): - language: Optional[str] = None - """The language of the input audio.""" - model: Optional[str] = None - """The model to use for transcription.""" +class AudioInputTurnDetection(BaseModel): + create_response: Optional[bool] = None + """ + Whether or not to automatically generate a response when a VAD stop event + occurs. + """ - prompt: Optional[str] = None - """Optional text to guide the model's style or continue a previous audio segment.""" + eagerness: Optional[Literal["low", "medium", "high", "auto"]] = None + """Used only for `semantic_vad` mode. + The eagerness of the model to respond. `low` will wait longer for the user to + continue speaking, `high` will respond more quickly. `auto` is the default and + is equivalent to `medium`. `low`, `medium`, and `high` have max timeouts of 8s, + 4s, and 2s respectively. + """ + + idle_timeout_ms: Optional[int] = None + """ + Optional idle timeout after which turn detection will auto-timeout when no + additional audio is received. + """ + + interrupt_response: Optional[bool] = None + """ + Whether or not to automatically interrupt any ongoing response with output to + the default conversation (i.e. `conversation` of `auto`) when a VAD start event + occurs. + """ -class AudioInputTurnDetection(BaseModel): prefix_padding_ms: Optional[int] = None + """Used only for `server_vad` mode. + + Amount of audio to include before the VAD detected speech (in milliseconds). + Defaults to 300ms. + """ silence_duration_ms: Optional[int] = None + """Used only for `server_vad` mode. + + Duration of silence to detect speech stop (in milliseconds). Defaults to 500ms. + With shorter values the model will respond more quickly, but may jump in on + short pauses from the user. + """ threshold: Optional[float] = None + """Used only for `server_vad` mode. - type: Optional[str] = None - """Type of turn detection, only `server_vad` is currently supported.""" + Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A higher + threshold will require louder audio to activate the model, and thus might + perform better in noisy environments. + """ + + type: Optional[Literal["server_vad", "semantic_vad"]] = None + """Type of turn detection.""" class AudioInput(BaseModel): - format: Optional[str] = None - """The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + format: Optional[RealtimeAudioFormats] = None + """The format of the input audio.""" noise_reduction: Optional[AudioInputNoiseReduction] = None - """Configuration for input audio noise reduction.""" + """Configuration for input audio noise reduction. - transcription: Optional[AudioInputTranscription] = None - """Configuration for input audio transcription.""" + This can be set to `null` to turn off. Noise reduction filters audio added to + the input audio buffer before it is sent to VAD and the model. Filtering the + audio can improve VAD and turn detection accuracy (reducing false positives) and + model performance by improving perception of the input audio. + """ + + transcription: Optional[AudioTranscription] = None + """ + Configuration for input audio transcription, defaults to off and can be set to + `null` to turn off once on. Input audio transcription is not native to the + model, since the model consumes audio directly. Transcription runs + asynchronously through + [the /audio/transcriptions endpoint](https://platform.openai.com/docs/api-reference/audio/createTranscription) + and should be treated as guidance of input audio content rather than precisely + what the model heard. The client can optionally set the language and prompt for + transcription, these offer additional guidance to the transcription service. + """ turn_detection: Optional[AudioInputTurnDetection] = None - """Configuration for turn detection.""" + """Configuration for turn detection, ether Server VAD or Semantic VAD. + + This can be set to `null` to turn off, in which case the client must manually + trigger model response. Server VAD means that the model will detect the start + and end of speech based on audio volume and respond at the end of user speech. + Semantic VAD is more advanced and uses a turn detection model (in conjunction + with VAD) to semantically estimate whether the user has finished speaking, then + dynamically sets a timeout based on this probability. For example, if user audio + trails off with "uhhm", the model will score a low probability of turn end and + wait longer for the user to continue speaking. This can be useful for more + natural conversations, but may have a higher latency. + """ class AudioOutput(BaseModel): - format: Optional[str] = None - """The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + format: Optional[RealtimeAudioFormats] = None + """The format of the output audio.""" speed: Optional[float] = None + """ + The speed of the model's spoken response as a multiple of the original speed. + 1.0 is the default speed. 0.25 is the minimum speed. 1.5 is the maximum speed. + This value can only be changed in between model turns, not while a response is + in progress. + + This parameter is a post-processing adjustment to the audio after it is + generated, it's also possible to prompt the model to speak faster or slower. + """ voice: Union[ str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"], None ] = None + """The voice the model uses to respond. + + Voice cannot be changed during the session once the model has responded with + audio at least once. Current voice options are `alloy`, `ash`, `ballad`, + `coral`, `echo`, `sage`, `shimmer`, `verse`, `marin`, and `cedar`. We recommend + `marin` and `cedar` for best quality. + """ class Audio(BaseModel): @@ -77,86 +174,168 @@ class Audio(BaseModel): output: Optional[AudioOutput] = None -class Tool(BaseModel): - description: Optional[str] = None - """ - The description of the function, including guidance on when and how to call it, - and guidance about what to tell the user when calling (if anything). +ToolChoice: TypeAlias = Union[ToolChoiceOptions, ToolChoiceFunction, ToolChoiceMcp] + + +class ToolMcpToolAllowedToolsMcpToolFilter(BaseModel): + read_only: Optional[bool] = None + """Indicates whether or not a tool modifies data or is read-only. + + If an MCP server is + [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), + it will match this filter. """ - name: Optional[str] = None - """The name of the function.""" + tool_names: Optional[List[str]] = None + """List of allowed tool names.""" - parameters: Optional[object] = None - """Parameters of the function in JSON Schema.""" - type: Optional[Literal["function"]] = None - """The type of the tool, i.e. `function`.""" +ToolMcpToolAllowedTools: TypeAlias = Union[List[str], ToolMcpToolAllowedToolsMcpToolFilter, None] -class TracingTracingConfiguration(BaseModel): - group_id: Optional[str] = None +class ToolMcpToolRequireApprovalMcpToolApprovalFilterAlways(BaseModel): + read_only: Optional[bool] = None + """Indicates whether or not a tool modifies data or is read-only. + + If an MCP server is + [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), + it will match this filter. """ - The group id to attach to this trace to enable filtering and grouping in the - traces dashboard. + + tool_names: Optional[List[str]] = None + """List of allowed tool names.""" + + +class ToolMcpToolRequireApprovalMcpToolApprovalFilterNever(BaseModel): + read_only: Optional[bool] = None + """Indicates whether or not a tool modifies data or is read-only. + + If an MCP server is + [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), + it will match this filter. """ - metadata: Optional[object] = None + tool_names: Optional[List[str]] = None + """List of allowed tool names.""" + + +class ToolMcpToolRequireApprovalMcpToolApprovalFilter(BaseModel): + always: Optional[ToolMcpToolRequireApprovalMcpToolApprovalFilterAlways] = None + """A filter object to specify which tools are allowed.""" + + never: Optional[ToolMcpToolRequireApprovalMcpToolApprovalFilterNever] = None + """A filter object to specify which tools are allowed.""" + + +ToolMcpToolRequireApproval: TypeAlias = Union[ + ToolMcpToolRequireApprovalMcpToolApprovalFilter, Literal["always", "never"], None +] + + +class ToolMcpTool(BaseModel): + server_label: str + """A label for this MCP server, used to identify it in tool calls.""" + + type: Literal["mcp"] + """The type of the MCP tool. Always `mcp`.""" + + allowed_tools: Optional[ToolMcpToolAllowedTools] = None + """List of allowed tool names or a filter object.""" + + authorization: Optional[str] = None """ - The arbitrary metadata to attach to this trace to enable filtering in the traces - dashboard. + An OAuth access token that can be used with a remote MCP server, either with a + custom MCP server URL or a service connector. Your application must handle the + OAuth authorization flow and provide the token here. """ - workflow_name: Optional[str] = None - """The name of the workflow to attach to this trace. - - This is used to name the trace in the traces dashboard. + connector_id: Optional[ + Literal[ + "connector_dropbox", + "connector_gmail", + "connector_googlecalendar", + "connector_googledrive", + "connector_microsoftteams", + "connector_outlookcalendar", + "connector_outlookemail", + "connector_sharepoint", + ] + ] = None + """Identifier for service connectors, like those available in ChatGPT. + + One of `server_url` or `connector_id` must be provided. Learn more about service + connectors + [here](https://platform.openai.com/docs/guides/tools-remote-mcp#connectors). + + Currently supported `connector_id` values are: + + - Dropbox: `connector_dropbox` + - Gmail: `connector_gmail` + - Google Calendar: `connector_googlecalendar` + - Google Drive: `connector_googledrive` + - Microsoft Teams: `connector_microsoftteams` + - Outlook Calendar: `connector_outlookcalendar` + - Outlook Email: `connector_outlookemail` + - SharePoint: `connector_sharepoint` """ + headers: Optional[Dict[str, str]] = None + """Optional HTTP headers to send to the MCP server. + + Use for authentication or other purposes. + """ -Tracing: TypeAlias = Union[Literal["auto"], TracingTracingConfiguration] + require_approval: Optional[ToolMcpToolRequireApproval] = None + """Specify which of the MCP server's tools require approval.""" + server_description: Optional[str] = None + """Optional description of the MCP server, used to provide more context.""" -class TurnDetection(BaseModel): - prefix_padding_ms: Optional[int] = None - """Amount of audio to include before the VAD detected speech (in milliseconds). + server_url: Optional[str] = None + """The URL for the MCP server. - Defaults to 300ms. + One of `server_url` or `connector_id` must be provided. """ - silence_duration_ms: Optional[int] = None - """Duration of silence to detect speech stop (in milliseconds). - Defaults to 500ms. With shorter values the model will respond more quickly, but - may jump in on short pauses from the user. +Tool: TypeAlias = Union[Models, ToolMcpTool] + + +class TracingTracingConfiguration(BaseModel): + group_id: Optional[str] = None + """ + The group id to attach to this trace to enable filtering and grouping in the + Traces Dashboard. """ - threshold: Optional[float] = None - """Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. + metadata: Optional[object] = None + """ + The arbitrary metadata to attach to this trace to enable filtering in the Traces + Dashboard. + """ - A higher threshold will require louder audio to activate the model, and thus - might perform better in noisy environments. + workflow_name: Optional[str] = None + """The name of the workflow to attach to this trace. + + This is used to name the trace in the Traces Dashboard. """ - type: Optional[str] = None - """Type of turn detection, only `server_vad` is currently supported.""" +Tracing: TypeAlias = Union[Literal["auto"], TracingTracingConfiguration, None] -class RealtimeSessionCreateResponse(BaseModel): - id: Optional[str] = None - """Unique identifier for the session that looks like `sess_1234567890abcdef`.""" +class RealtimeSessionCreateResponse(BaseModel): audio: Optional[Audio] = None - """Configuration for input and output audio for the session.""" + """Configuration for input and output audio.""" - expires_at: Optional[int] = None - """Expiration timestamp for the session, in seconds since epoch.""" + client_secret: Optional[RealtimeSessionClientSecret] = None + """Ephemeral key returned by the API.""" include: Optional[List[Literal["item.input_audio_transcription.logprobs"]]] = None """Additional fields to include in server outputs. - - `item.input_audio_transcription.logprobs`: Include logprobs for input audio - transcription. + `item.input_audio_transcription.logprobs`: Include logprobs for input audio + transcription. """ instructions: Optional[str] = None @@ -182,41 +361,60 @@ class RealtimeSessionCreateResponse(BaseModel): `inf` for the maximum available tokens for a given model. Defaults to `inf`. """ - model: Optional[str] = None + model: Union[ + str, + Literal[ + "gpt-realtime", + "gpt-realtime-2025-08-28", + "gpt-4o-realtime-preview", + "gpt-4o-realtime-preview-2024-10-01", + "gpt-4o-realtime-preview-2024-12-17", + "gpt-4o-realtime-preview-2025-06-03", + "gpt-4o-mini-realtime-preview", + "gpt-4o-mini-realtime-preview-2024-12-17", + ], + None, + ] = None """The Realtime model used for this session.""" - object: Optional[str] = None - """The object type. Always `realtime.session`.""" - output_modalities: Optional[List[Literal["text", "audio"]]] = None """The set of modalities the model can respond with. - To disable audio, set this to ["text"]. + It defaults to `["audio"]`, indicating that the model will respond with audio + plus a transcript. `["text"]` can be used to make the model respond with text + only. It is not possible to request both `text` and `audio` at the same time. + """ + + prompt: Optional[ResponsePrompt] = None + """Reference to a prompt template and its variables. + + [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). """ - tool_choice: Optional[str] = None + tool_choice: Optional[ToolChoice] = None """How the model chooses tools. - Options are `auto`, `none`, `required`, or specify a function. + Provide one of the string modes or force a specific function/MCP tool. """ tools: Optional[List[Tool]] = None - """Tools (functions) available to the model.""" + """Tools available to the model.""" tracing: Optional[Tracing] = None - """Configuration options for tracing. - - Set to null to disable tracing. Once tracing is enabled for a session, the - configuration cannot be modified. + """ + Realtime API can write session traces to the + [Traces Dashboard](/logs?api=traces). Set to null to disable tracing. Once + tracing is enabled for a session, the configuration cannot be modified. `auto` will create a trace for the session with default values for the workflow name, group id, and metadata. """ - turn_detection: Optional[TurnDetection] = None - """Configuration for turn detection. - - Can be set to `null` to turn off. Server VAD means that the model will detect - the start and end of speech based on audio volume and respond at the end of user - speech. + truncation: Optional[RealtimeTruncation] = None """ + Controls how the realtime conversation is truncated prior to model inference. + The default is `auto`. + """ + + type: Optional[Literal["realtime"]] = None + """The type of session to create. Always `realtime` for the Realtime API.""" diff --git a/src/openai/types/realtime/realtime_tools_config_param.py b/src/openai/types/realtime/realtime_tools_config_param.py index ea4b8c4d43..700b548fe2 100644 --- a/src/openai/types/realtime/realtime_tools_config_param.py +++ b/src/openai/types/realtime/realtime_tools_config_param.py @@ -6,11 +6,11 @@ from typing_extensions import Literal, Required, TypeAlias, TypedDict from ..._types import SequenceNotStr +from .models_param import ModelsParam __all__ = [ "RealtimeToolsConfigParam", "RealtimeToolsConfigUnionParam", - "Function", "Mcp", "McpAllowedTools", "McpAllowedToolsMcpToolFilter", @@ -21,23 +21,6 @@ ] -class Function(TypedDict, total=False): - description: str - """ - The description of the function, including guidance on when and how to call it, - and guidance about what to tell the user when calling (if anything). - """ - - name: str - """The name of the function.""" - - parameters: object - """Parameters of the function in JSON Schema.""" - - type: Literal["function"] - """The type of the tool, i.e. `function`.""" - - class McpAllowedToolsMcpToolFilter(TypedDict, total=False): read_only: bool """Indicates whether or not a tool modifies data or is read-only. @@ -155,6 +138,6 @@ class Mcp(TypedDict, total=False): """ -RealtimeToolsConfigUnionParam: TypeAlias = Union[Function, Mcp] +RealtimeToolsConfigUnionParam: TypeAlias = Union[ModelsParam, Mcp] RealtimeToolsConfigParam: TypeAlias = List[RealtimeToolsConfigUnionParam] diff --git a/src/openai/types/realtime/realtime_tools_config_union.py b/src/openai/types/realtime/realtime_tools_config_union.py index 16b1557743..8a064d78d4 100644 --- a/src/openai/types/realtime/realtime_tools_config_union.py +++ b/src/openai/types/realtime/realtime_tools_config_union.py @@ -3,12 +3,12 @@ from typing import Dict, List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias +from .models import Models from ..._utils import PropertyInfo from ..._models import BaseModel __all__ = [ "RealtimeToolsConfigUnion", - "Function", "Mcp", "McpAllowedTools", "McpAllowedToolsMcpToolFilter", @@ -19,23 +19,6 @@ ] -class Function(BaseModel): - description: Optional[str] = None - """ - The description of the function, including guidance on when and how to call it, - and guidance about what to tell the user when calling (if anything). - """ - - name: Optional[str] = None - """The name of the function.""" - - parameters: Optional[object] = None - """Parameters of the function in JSON Schema.""" - - type: Optional[Literal["function"]] = None - """The type of the tool, i.e. `function`.""" - - class McpAllowedToolsMcpToolFilter(BaseModel): read_only: Optional[bool] = None """Indicates whether or not a tool modifies data or is read-only. @@ -155,4 +138,4 @@ class Mcp(BaseModel): """ -RealtimeToolsConfigUnion: TypeAlias = Annotated[Union[Function, Mcp], PropertyInfo(discriminator="type")] +RealtimeToolsConfigUnion: TypeAlias = Annotated[Union[Models, Mcp], PropertyInfo(discriminator="type")] diff --git a/src/openai/types/realtime/realtime_tools_config_union_param.py b/src/openai/types/realtime/realtime_tools_config_union_param.py index 21b4d07752..179ad040d9 100644 --- a/src/openai/types/realtime/realtime_tools_config_union_param.py +++ b/src/openai/types/realtime/realtime_tools_config_union_param.py @@ -6,10 +6,10 @@ from typing_extensions import Literal, Required, TypeAlias, TypedDict from ..._types import SequenceNotStr +from .models_param import ModelsParam __all__ = [ "RealtimeToolsConfigUnionParam", - "Function", "Mcp", "McpAllowedTools", "McpAllowedToolsMcpToolFilter", @@ -20,23 +20,6 @@ ] -class Function(TypedDict, total=False): - description: str - """ - The description of the function, including guidance on when and how to call it, - and guidance about what to tell the user when calling (if anything). - """ - - name: str - """The name of the function.""" - - parameters: object - """Parameters of the function in JSON Schema.""" - - type: Literal["function"] - """The type of the tool, i.e. `function`.""" - - class McpAllowedToolsMcpToolFilter(TypedDict, total=False): read_only: bool """Indicates whether or not a tool modifies data or is read-only. @@ -154,4 +137,4 @@ class Mcp(TypedDict, total=False): """ -RealtimeToolsConfigUnionParam: TypeAlias = Union[Function, Mcp] +RealtimeToolsConfigUnionParam: TypeAlias = Union[ModelsParam, Mcp] diff --git a/src/openai/types/realtime/realtime_tracing_config.py b/src/openai/types/realtime/realtime_tracing_config.py index 1de24d6e5f..1c46de7928 100644 --- a/src/openai/types/realtime/realtime_tracing_config.py +++ b/src/openai/types/realtime/realtime_tracing_config.py @@ -12,19 +12,19 @@ class TracingConfiguration(BaseModel): group_id: Optional[str] = None """ The group id to attach to this trace to enable filtering and grouping in the - traces dashboard. + Traces Dashboard. """ metadata: Optional[object] = None """ - The arbitrary metadata to attach to this trace to enable filtering in the traces - dashboard. + The arbitrary metadata to attach to this trace to enable filtering in the Traces + Dashboard. """ workflow_name: Optional[str] = None """The name of the workflow to attach to this trace. - This is used to name the trace in the traces dashboard. + This is used to name the trace in the Traces Dashboard. """ diff --git a/src/openai/types/realtime/realtime_tracing_config_param.py b/src/openai/types/realtime/realtime_tracing_config_param.py index 3a35c6f7fa..fd9e266244 100644 --- a/src/openai/types/realtime/realtime_tracing_config_param.py +++ b/src/openai/types/realtime/realtime_tracing_config_param.py @@ -12,19 +12,19 @@ class TracingConfiguration(TypedDict, total=False): group_id: str """ The group id to attach to this trace to enable filtering and grouping in the - traces dashboard. + Traces Dashboard. """ metadata: object """ - The arbitrary metadata to attach to this trace to enable filtering in the traces - dashboard. + The arbitrary metadata to attach to this trace to enable filtering in the Traces + Dashboard. """ workflow_name: str """The name of the workflow to attach to this trace. - This is used to name the trace in the traces dashboard. + This is used to name the trace in the Traces Dashboard. """ diff --git a/src/openai/types/realtime/realtime_transcription_session_audio.py b/src/openai/types/realtime/realtime_transcription_session_audio.py new file mode 100644 index 0000000000..a5506947f1 --- /dev/null +++ b/src/openai/types/realtime/realtime_transcription_session_audio.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel +from .realtime_transcription_session_audio_input import RealtimeTranscriptionSessionAudioInput + +__all__ = ["RealtimeTranscriptionSessionAudio"] + + +class RealtimeTranscriptionSessionAudio(BaseModel): + input: Optional[RealtimeTranscriptionSessionAudioInput] = None diff --git a/src/openai/types/realtime/realtime_transcription_session_audio_input.py b/src/openai/types/realtime/realtime_transcription_session_audio_input.py new file mode 100644 index 0000000000..0ae92959aa --- /dev/null +++ b/src/openai/types/realtime/realtime_transcription_session_audio_input.py @@ -0,0 +1,62 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel +from .audio_transcription import AudioTranscription +from .noise_reduction_type import NoiseReductionType +from .realtime_audio_formats import RealtimeAudioFormats +from .realtime_transcription_session_audio_input_turn_detection import ( + RealtimeTranscriptionSessionAudioInputTurnDetection, +) + +__all__ = ["RealtimeTranscriptionSessionAudioInput", "NoiseReduction"] + + +class NoiseReduction(BaseModel): + type: Optional[NoiseReductionType] = None + """Type of noise reduction. + + `near_field` is for close-talking microphones such as headphones, `far_field` is + for far-field microphones such as laptop or conference room microphones. + """ + + +class RealtimeTranscriptionSessionAudioInput(BaseModel): + format: Optional[RealtimeAudioFormats] = None + """The PCM audio format. Only a 24kHz sample rate is supported.""" + + noise_reduction: Optional[NoiseReduction] = None + """Configuration for input audio noise reduction. + + This can be set to `null` to turn off. Noise reduction filters audio added to + the input audio buffer before it is sent to VAD and the model. Filtering the + audio can improve VAD and turn detection accuracy (reducing false positives) and + model performance by improving perception of the input audio. + """ + + transcription: Optional[AudioTranscription] = None + """ + Configuration for input audio transcription, defaults to off and can be set to + `null` to turn off once on. Input audio transcription is not native to the + model, since the model consumes audio directly. Transcription runs + asynchronously through + [the /audio/transcriptions endpoint](https://platform.openai.com/docs/api-reference/audio/createTranscription) + and should be treated as guidance of input audio content rather than precisely + what the model heard. The client can optionally set the language and prompt for + transcription, these offer additional guidance to the transcription service. + """ + + turn_detection: Optional[RealtimeTranscriptionSessionAudioInputTurnDetection] = None + """Configuration for turn detection, ether Server VAD or Semantic VAD. + + This can be set to `null` to turn off, in which case the client must manually + trigger model response. Server VAD means that the model will detect the start + and end of speech based on audio volume and respond at the end of user speech. + Semantic VAD is more advanced and uses a turn detection model (in conjunction + with VAD) to semantically estimate whether the user has finished speaking, then + dynamically sets a timeout based on this probability. For example, if user audio + trails off with "uhhm", the model will score a low probability of turn end and + wait longer for the user to continue speaking. This can be useful for more + natural conversations, but may have a higher latency. + """ diff --git a/src/openai/types/realtime/realtime_transcription_session_audio_input_param.py b/src/openai/types/realtime/realtime_transcription_session_audio_input_param.py new file mode 100644 index 0000000000..a8263789dc --- /dev/null +++ b/src/openai/types/realtime/realtime_transcription_session_audio_input_param.py @@ -0,0 +1,63 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +from .noise_reduction_type import NoiseReductionType +from .audio_transcription_param import AudioTranscriptionParam +from .realtime_audio_formats_param import RealtimeAudioFormatsParam +from .realtime_transcription_session_audio_input_turn_detection_param import ( + RealtimeTranscriptionSessionAudioInputTurnDetectionParam, +) + +__all__ = ["RealtimeTranscriptionSessionAudioInputParam", "NoiseReduction"] + + +class NoiseReduction(TypedDict, total=False): + type: NoiseReductionType + """Type of noise reduction. + + `near_field` is for close-talking microphones such as headphones, `far_field` is + for far-field microphones such as laptop or conference room microphones. + """ + + +class RealtimeTranscriptionSessionAudioInputParam(TypedDict, total=False): + format: RealtimeAudioFormatsParam + """The PCM audio format. Only a 24kHz sample rate is supported.""" + + noise_reduction: NoiseReduction + """Configuration for input audio noise reduction. + + This can be set to `null` to turn off. Noise reduction filters audio added to + the input audio buffer before it is sent to VAD and the model. Filtering the + audio can improve VAD and turn detection accuracy (reducing false positives) and + model performance by improving perception of the input audio. + """ + + transcription: AudioTranscriptionParam + """ + Configuration for input audio transcription, defaults to off and can be set to + `null` to turn off once on. Input audio transcription is not native to the + model, since the model consumes audio directly. Transcription runs + asynchronously through + [the /audio/transcriptions endpoint](https://platform.openai.com/docs/api-reference/audio/createTranscription) + and should be treated as guidance of input audio content rather than precisely + what the model heard. The client can optionally set the language and prompt for + transcription, these offer additional guidance to the transcription service. + """ + + turn_detection: RealtimeTranscriptionSessionAudioInputTurnDetectionParam + """Configuration for turn detection, ether Server VAD or Semantic VAD. + + This can be set to `null` to turn off, in which case the client must manually + trigger model response. Server VAD means that the model will detect the start + and end of speech based on audio volume and respond at the end of user speech. + Semantic VAD is more advanced and uses a turn detection model (in conjunction + with VAD) to semantically estimate whether the user has finished speaking, then + dynamically sets a timeout based on this probability. For example, if user audio + trails off with "uhhm", the model will score a low probability of turn end and + wait longer for the user to continue speaking. This can be useful for more + natural conversations, but may have a higher latency. + """ diff --git a/src/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection.py b/src/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection.py new file mode 100644 index 0000000000..0cac36f7a3 --- /dev/null +++ b/src/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection.py @@ -0,0 +1,63 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["RealtimeTranscriptionSessionAudioInputTurnDetection"] + + +class RealtimeTranscriptionSessionAudioInputTurnDetection(BaseModel): + create_response: Optional[bool] = None + """ + Whether or not to automatically generate a response when a VAD stop event + occurs. + """ + + eagerness: Optional[Literal["low", "medium", "high", "auto"]] = None + """Used only for `semantic_vad` mode. + + The eagerness of the model to respond. `low` will wait longer for the user to + continue speaking, `high` will respond more quickly. `auto` is the default and + is equivalent to `medium`. + """ + + idle_timeout_ms: Optional[int] = None + """ + Optional idle timeout after which turn detection will auto-timeout when no + additional audio is received. + """ + + interrupt_response: Optional[bool] = None + """ + Whether or not to automatically interrupt any ongoing response with output to + the default conversation (i.e. `conversation` of `auto`) when a VAD start event + occurs. + """ + + prefix_padding_ms: Optional[int] = None + """Used only for `server_vad` mode. + + Amount of audio to include before the VAD detected speech (in milliseconds). + Defaults to 300ms. + """ + + silence_duration_ms: Optional[int] = None + """Used only for `server_vad` mode. + + Duration of silence to detect speech stop (in milliseconds). Defaults to 500ms. + With shorter values the model will respond more quickly, but may jump in on + short pauses from the user. + """ + + threshold: Optional[float] = None + """Used only for `server_vad` mode. + + Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A higher + threshold will require louder audio to activate the model, and thus might + perform better in noisy environments. + """ + + type: Optional[Literal["server_vad", "semantic_vad"]] = None + """Type of turn detection.""" diff --git a/src/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection_param.py b/src/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection_param.py new file mode 100644 index 0000000000..e76dc9a8fe --- /dev/null +++ b/src/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection_param.py @@ -0,0 +1,63 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, TypedDict + +__all__ = ["RealtimeTranscriptionSessionAudioInputTurnDetectionParam"] + + +class RealtimeTranscriptionSessionAudioInputTurnDetectionParam(TypedDict, total=False): + create_response: bool + """ + Whether or not to automatically generate a response when a VAD stop event + occurs. + """ + + eagerness: Literal["low", "medium", "high", "auto"] + """Used only for `semantic_vad` mode. + + The eagerness of the model to respond. `low` will wait longer for the user to + continue speaking, `high` will respond more quickly. `auto` is the default and + is equivalent to `medium`. + """ + + idle_timeout_ms: Optional[int] + """ + Optional idle timeout after which turn detection will auto-timeout when no + additional audio is received. + """ + + interrupt_response: bool + """ + Whether or not to automatically interrupt any ongoing response with output to + the default conversation (i.e. `conversation` of `auto`) when a VAD start event + occurs. + """ + + prefix_padding_ms: int + """Used only for `server_vad` mode. + + Amount of audio to include before the VAD detected speech (in milliseconds). + Defaults to 300ms. + """ + + silence_duration_ms: int + """Used only for `server_vad` mode. + + Duration of silence to detect speech stop (in milliseconds). Defaults to 500ms. + With shorter values the model will respond more quickly, but may jump in on + short pauses from the user. + """ + + threshold: float + """Used only for `server_vad` mode. + + Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A higher + threshold will require louder audio to activate the model, and thus might + perform better in noisy environments. + """ + + type: Literal["server_vad", "semantic_vad"] + """Type of turn detection.""" diff --git a/src/openai/types/realtime/realtime_transcription_session_audio_param.py b/src/openai/types/realtime/realtime_transcription_session_audio_param.py new file mode 100644 index 0000000000..1503a606d3 --- /dev/null +++ b/src/openai/types/realtime/realtime_transcription_session_audio_param.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +from .realtime_transcription_session_audio_input_param import RealtimeTranscriptionSessionAudioInputParam + +__all__ = ["RealtimeTranscriptionSessionAudioParam"] + + +class RealtimeTranscriptionSessionAudioParam(TypedDict, total=False): + input: RealtimeTranscriptionSessionAudioInputParam diff --git a/src/openai/types/realtime/realtime_transcription_session_client_secret.py b/src/openai/types/realtime/realtime_transcription_session_client_secret.py new file mode 100644 index 0000000000..0cfde4c0a2 --- /dev/null +++ b/src/openai/types/realtime/realtime_transcription_session_client_secret.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["RealtimeTranscriptionSessionClientSecret"] + + +class RealtimeTranscriptionSessionClientSecret(BaseModel): + expires_at: int + """Timestamp for when the token expires. + + Currently, all tokens expire after one minute. + """ + + value: str + """ + Ephemeral key usable in client environments to authenticate connections to the + Realtime API. Use this in client-side environments rather than a standard API + token, which should only be used server-side. + """ diff --git a/src/openai/types/realtime/realtime_transcription_session_create_request.py b/src/openai/types/realtime/realtime_transcription_session_create_request.py index d67bc92708..102f2b14fb 100644 --- a/src/openai/types/realtime/realtime_transcription_session_create_request.py +++ b/src/openai/types/realtime/realtime_transcription_session_create_request.py @@ -1,128 +1,27 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union, Optional +from typing import List, Optional from typing_extensions import Literal from ..._models import BaseModel +from .realtime_transcription_session_audio import RealtimeTranscriptionSessionAudio -__all__ = [ - "RealtimeTranscriptionSessionCreateRequest", - "InputAudioNoiseReduction", - "InputAudioTranscription", - "TurnDetection", -] - - -class InputAudioNoiseReduction(BaseModel): - type: Optional[Literal["near_field", "far_field"]] = None - """Type of noise reduction. - - `near_field` is for close-talking microphones such as headphones, `far_field` is - for far-field microphones such as laptop or conference room microphones. - """ - - -class InputAudioTranscription(BaseModel): - language: Optional[str] = None - """The language of the input audio. - - Supplying the input language in - [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) - format will improve accuracy and latency. - """ - - model: Optional[Literal["gpt-4o-transcribe", "gpt-4o-mini-transcribe", "whisper-1"]] = None - """ - The model to use for transcription, current options are `gpt-4o-transcribe`, - `gpt-4o-mini-transcribe`, and `whisper-1`. - """ - - prompt: Optional[str] = None - """ - An optional text to guide the model's style or continue a previous audio - segment. For `whisper-1`, the - [prompt is a list of keywords](https://platform.openai.com/docs/guides/speech-to-text#prompting). - For `gpt-4o-transcribe` models, the prompt is a free text string, for example - "expect words related to technology". - """ - - -class TurnDetection(BaseModel): - prefix_padding_ms: Optional[int] = None - """Amount of audio to include before the VAD detected speech (in milliseconds). - - Defaults to 300ms. - """ - - silence_duration_ms: Optional[int] = None - """Duration of silence to detect speech stop (in milliseconds). - - Defaults to 500ms. With shorter values the model will respond more quickly, but - may jump in on short pauses from the user. - """ - - threshold: Optional[float] = None - """Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. - - A higher threshold will require louder audio to activate the model, and thus - might perform better in noisy environments. - """ - - type: Optional[Literal["server_vad"]] = None - """Type of turn detection. - - Only `server_vad` is currently supported for transcription sessions. - """ +__all__ = ["RealtimeTranscriptionSessionCreateRequest"] class RealtimeTranscriptionSessionCreateRequest(BaseModel): - model: Union[str, Literal["whisper-1", "gpt-4o-transcribe", "gpt-4o-mini-transcribe"]] - """ID of the model to use. - - The options are `gpt-4o-transcribe`, `gpt-4o-mini-transcribe`, and `whisper-1` - (which is powered by our open source Whisper V2 model). - """ - type: Literal["transcription"] """The type of session to create. Always `transcription` for transcription sessions. """ - include: Optional[List[Literal["item.input_audio_transcription.logprobs"]]] = None - """The set of items to include in the transcription. Current available items are: - - - `item.input_audio_transcription.logprobs` - """ + audio: Optional[RealtimeTranscriptionSessionAudio] = None + """Configuration for input and output audio.""" - input_audio_format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None - """The format of input audio. - - Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, input audio must - be 16-bit PCM at a 24kHz sample rate, single channel (mono), and little-endian - byte order. - """ - - input_audio_noise_reduction: Optional[InputAudioNoiseReduction] = None - """Configuration for input audio noise reduction. - - This can be set to `null` to turn off. Noise reduction filters audio added to - the input audio buffer before it is sent to VAD and the model. Filtering the - audio can improve VAD and turn detection accuracy (reducing false positives) and - model performance by improving perception of the input audio. - """ - - input_audio_transcription: Optional[InputAudioTranscription] = None - """Configuration for input audio transcription. - - The client can optionally set the language and prompt for transcription, these - offer additional guidance to the transcription service. - """ - - turn_detection: Optional[TurnDetection] = None - """Configuration for turn detection. + include: Optional[List[Literal["item.input_audio_transcription.logprobs"]]] = None + """Additional fields to include in server outputs. - Can be set to `null` to turn off. Server VAD means that the model will detect - the start and end of speech based on audio volume and respond at the end of user - speech. + `item.input_audio_transcription.logprobs`: Include logprobs for input audio + transcription. """ diff --git a/src/openai/types/realtime/realtime_transcription_session_create_request_param.py b/src/openai/types/realtime/realtime_transcription_session_create_request_param.py index 405f0c5f2c..80cbe2d414 100644 --- a/src/openai/types/realtime/realtime_transcription_session_create_request_param.py +++ b/src/openai/types/realtime/realtime_transcription_session_create_request_param.py @@ -2,127 +2,27 @@ from __future__ import annotations -from typing import List, Union +from typing import List from typing_extensions import Literal, Required, TypedDict -__all__ = [ - "RealtimeTranscriptionSessionCreateRequestParam", - "InputAudioNoiseReduction", - "InputAudioTranscription", - "TurnDetection", -] +from .realtime_transcription_session_audio_param import RealtimeTranscriptionSessionAudioParam - -class InputAudioNoiseReduction(TypedDict, total=False): - type: Literal["near_field", "far_field"] - """Type of noise reduction. - - `near_field` is for close-talking microphones such as headphones, `far_field` is - for far-field microphones such as laptop or conference room microphones. - """ - - -class InputAudioTranscription(TypedDict, total=False): - language: str - """The language of the input audio. - - Supplying the input language in - [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) - format will improve accuracy and latency. - """ - - model: Literal["gpt-4o-transcribe", "gpt-4o-mini-transcribe", "whisper-1"] - """ - The model to use for transcription, current options are `gpt-4o-transcribe`, - `gpt-4o-mini-transcribe`, and `whisper-1`. - """ - - prompt: str - """ - An optional text to guide the model's style or continue a previous audio - segment. For `whisper-1`, the - [prompt is a list of keywords](https://platform.openai.com/docs/guides/speech-to-text#prompting). - For `gpt-4o-transcribe` models, the prompt is a free text string, for example - "expect words related to technology". - """ - - -class TurnDetection(TypedDict, total=False): - prefix_padding_ms: int - """Amount of audio to include before the VAD detected speech (in milliseconds). - - Defaults to 300ms. - """ - - silence_duration_ms: int - """Duration of silence to detect speech stop (in milliseconds). - - Defaults to 500ms. With shorter values the model will respond more quickly, but - may jump in on short pauses from the user. - """ - - threshold: float - """Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. - - A higher threshold will require louder audio to activate the model, and thus - might perform better in noisy environments. - """ - - type: Literal["server_vad"] - """Type of turn detection. - - Only `server_vad` is currently supported for transcription sessions. - """ +__all__ = ["RealtimeTranscriptionSessionCreateRequestParam"] class RealtimeTranscriptionSessionCreateRequestParam(TypedDict, total=False): - model: Required[Union[str, Literal["whisper-1", "gpt-4o-transcribe", "gpt-4o-mini-transcribe"]]] - """ID of the model to use. - - The options are `gpt-4o-transcribe`, `gpt-4o-mini-transcribe`, and `whisper-1` - (which is powered by our open source Whisper V2 model). - """ - type: Required[Literal["transcription"]] """The type of session to create. Always `transcription` for transcription sessions. """ - include: List[Literal["item.input_audio_transcription.logprobs"]] - """The set of items to include in the transcription. Current available items are: - - - `item.input_audio_transcription.logprobs` - """ + audio: RealtimeTranscriptionSessionAudioParam + """Configuration for input and output audio.""" - input_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] - """The format of input audio. - - Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, input audio must - be 16-bit PCM at a 24kHz sample rate, single channel (mono), and little-endian - byte order. - """ - - input_audio_noise_reduction: InputAudioNoiseReduction - """Configuration for input audio noise reduction. - - This can be set to `null` to turn off. Noise reduction filters audio added to - the input audio buffer before it is sent to VAD and the model. Filtering the - audio can improve VAD and turn detection accuracy (reducing false positives) and - model performance by improving perception of the input audio. - """ - - input_audio_transcription: InputAudioTranscription - """Configuration for input audio transcription. - - The client can optionally set the language and prompt for transcription, these - offer additional guidance to the transcription service. - """ - - turn_detection: TurnDetection - """Configuration for turn detection. + include: List[Literal["item.input_audio_transcription.logprobs"]] + """Additional fields to include in server outputs. - Can be set to `null` to turn off. Server VAD means that the model will detect - the start and end of speech based on audio volume and respond at the end of user - speech. + `item.input_audio_transcription.logprobs`: Include logprobs for input audio + transcription. """ diff --git a/src/openai/types/realtime/realtime_transcription_session_create_response.py b/src/openai/types/realtime/realtime_transcription_session_create_response.py new file mode 100644 index 0000000000..a08538aa8f --- /dev/null +++ b/src/openai/types/realtime/realtime_transcription_session_create_response.py @@ -0,0 +1,41 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel +from .realtime_transcription_session_client_secret import RealtimeTranscriptionSessionClientSecret +from .realtime_transcription_session_turn_detection import RealtimeTranscriptionSessionTurnDetection +from .realtime_transcription_session_input_audio_transcription import ( + RealtimeTranscriptionSessionInputAudioTranscription, +) + +__all__ = ["RealtimeTranscriptionSessionCreateResponse"] + + +class RealtimeTranscriptionSessionCreateResponse(BaseModel): + client_secret: RealtimeTranscriptionSessionClientSecret + """Ephemeral key returned by the API. + + Only present when the session is created on the server via REST API. + """ + + input_audio_format: Optional[str] = None + """The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" + + input_audio_transcription: Optional[RealtimeTranscriptionSessionInputAudioTranscription] = None + """Configuration of the transcription model.""" + + modalities: Optional[List[Literal["text", "audio"]]] = None + """The set of modalities the model can respond with. + + To disable audio, set this to ["text"]. + """ + + turn_detection: Optional[RealtimeTranscriptionSessionTurnDetection] = None + """Configuration for turn detection. + + Can be set to `null` to turn off. Server VAD means that the model will detect + the start and end of speech based on audio volume and respond at the end of user + speech. + """ diff --git a/src/openai/types/realtime/realtime_transcription_session_input_audio_transcription.py b/src/openai/types/realtime/realtime_transcription_session_input_audio_transcription.py new file mode 100644 index 0000000000..52254bed33 --- /dev/null +++ b/src/openai/types/realtime/realtime_transcription_session_input_audio_transcription.py @@ -0,0 +1,36 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["RealtimeTranscriptionSessionInputAudioTranscription"] + + +class RealtimeTranscriptionSessionInputAudioTranscription(BaseModel): + language: Optional[str] = None + """The language of the input audio. + + Supplying the input language in + [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) + format will improve accuracy and latency. + """ + + model: Optional[Literal["whisper-1", "gpt-4o-transcribe-latest", "gpt-4o-mini-transcribe", "gpt-4o-transcribe"]] = ( + None + ) + """The model to use for transcription. + + Current options are `whisper-1`, `gpt-4o-transcribe-latest`, + `gpt-4o-mini-transcribe`, and `gpt-4o-transcribe`. + """ + + prompt: Optional[str] = None + """ + An optional text to guide the model's style or continue a previous audio + segment. For `whisper-1`, the + [prompt is a list of keywords](https://platform.openai.com/docs/guides/speech-to-text#prompting). + For `gpt-4o-transcribe` models, the prompt is a free text string, for example + "expect words related to technology". + """ diff --git a/src/openai/types/realtime/realtime_transcription_session_turn_detection.py b/src/openai/types/realtime/realtime_transcription_session_turn_detection.py new file mode 100644 index 0000000000..f5da31ce77 --- /dev/null +++ b/src/openai/types/realtime/realtime_transcription_session_turn_detection.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["RealtimeTranscriptionSessionTurnDetection"] + + +class RealtimeTranscriptionSessionTurnDetection(BaseModel): + prefix_padding_ms: Optional[int] = None + """Amount of audio to include before the VAD detected speech (in milliseconds). + + Defaults to 300ms. + """ + + silence_duration_ms: Optional[int] = None + """Duration of silence to detect speech stop (in milliseconds). + + Defaults to 500ms. With shorter values the model will respond more quickly, but + may jump in on short pauses from the user. + """ + + threshold: Optional[float] = None + """Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. + + A higher threshold will require louder audio to activate the model, and thus + might perform better in noisy environments. + """ + + type: Optional[str] = None + """Type of turn detection, only `server_vad` is currently supported.""" diff --git a/src/openai/types/realtime/realtime_truncation.py b/src/openai/types/realtime/realtime_truncation.py index 4687e3da56..515f869071 100644 --- a/src/openai/types/realtime/realtime_truncation.py +++ b/src/openai/types/realtime/realtime_truncation.py @@ -1,22 +1,10 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Union, Optional +from typing import Union from typing_extensions import Literal, TypeAlias -from ..._models import BaseModel +from .realtime_truncation_retention_ratio import RealtimeTruncationRetentionRatio -__all__ = ["RealtimeTruncation", "RetentionRatioTruncation"] +__all__ = ["RealtimeTruncation"] - -class RetentionRatioTruncation(BaseModel): - retention_ratio: float - """Fraction of pre-instruction conversation tokens to retain (0.0 - 1.0).""" - - type: Literal["retention_ratio"] - """Use retention ratio truncation.""" - - post_instructions_token_limit: Optional[int] = None - """Optional cap on tokens allowed after the instructions.""" - - -RealtimeTruncation: TypeAlias = Union[Literal["auto", "disabled"], RetentionRatioTruncation] +RealtimeTruncation: TypeAlias = Union[Literal["auto", "disabled"], RealtimeTruncationRetentionRatio] diff --git a/src/openai/types/realtime/realtime_truncation_param.py b/src/openai/types/realtime/realtime_truncation_param.py index edc88ea685..5e42b27418 100644 --- a/src/openai/types/realtime/realtime_truncation_param.py +++ b/src/openai/types/realtime/realtime_truncation_param.py @@ -2,21 +2,11 @@ from __future__ import annotations -from typing import Union, Optional -from typing_extensions import Literal, Required, TypeAlias, TypedDict +from typing import Union +from typing_extensions import Literal, TypeAlias -__all__ = ["RealtimeTruncationParam", "RetentionRatioTruncation"] +from .realtime_truncation_retention_ratio_param import RealtimeTruncationRetentionRatioParam +__all__ = ["RealtimeTruncationParam"] -class RetentionRatioTruncation(TypedDict, total=False): - retention_ratio: Required[float] - """Fraction of pre-instruction conversation tokens to retain (0.0 - 1.0).""" - - type: Required[Literal["retention_ratio"]] - """Use retention ratio truncation.""" - - post_instructions_token_limit: Optional[int] - """Optional cap on tokens allowed after the instructions.""" - - -RealtimeTruncationParam: TypeAlias = Union[Literal["auto", "disabled"], RetentionRatioTruncation] +RealtimeTruncationParam: TypeAlias = Union[Literal["auto", "disabled"], RealtimeTruncationRetentionRatioParam] diff --git a/src/openai/types/realtime/realtime_truncation_retention_ratio.py b/src/openai/types/realtime/realtime_truncation_retention_ratio.py new file mode 100644 index 0000000000..b40427244e --- /dev/null +++ b/src/openai/types/realtime/realtime_truncation_retention_ratio.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["RealtimeTruncationRetentionRatio"] + + +class RealtimeTruncationRetentionRatio(BaseModel): + retention_ratio: float + """ + Fraction of post-instruction conversation tokens to retain (0.0 - 1.0) when the + conversation exceeds the input token limit. + """ + + type: Literal["retention_ratio"] + """Use retention ratio truncation.""" diff --git a/src/openai/types/realtime/realtime_truncation_retention_ratio_param.py b/src/openai/types/realtime/realtime_truncation_retention_ratio_param.py new file mode 100644 index 0000000000..b65d65666a --- /dev/null +++ b/src/openai/types/realtime/realtime_truncation_retention_ratio_param.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["RealtimeTruncationRetentionRatioParam"] + + +class RealtimeTruncationRetentionRatioParam(TypedDict, total=False): + retention_ratio: Required[float] + """ + Fraction of post-instruction conversation tokens to retain (0.0 - 1.0) when the + conversation exceeds the input token limit. + """ + + type: Required[Literal["retention_ratio"]] + """Use retention ratio truncation.""" diff --git a/src/openai/types/realtime/response_create_event.py b/src/openai/types/realtime/response_create_event.py index a37045eab1..75a08ee460 100644 --- a/src/openai/types/realtime/response_create_event.py +++ b/src/openai/types/realtime/response_create_event.py @@ -1,126 +1,12 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union, Optional -from typing_extensions import Literal, TypeAlias +from typing import Optional +from typing_extensions import Literal from ..._models import BaseModel -from ..shared.metadata import Metadata -from .conversation_item import ConversationItem -from ..responses.response_prompt import ResponsePrompt -from ..responses.tool_choice_mcp import ToolChoiceMcp -from ..responses.tool_choice_options import ToolChoiceOptions -from ..responses.tool_choice_function import ToolChoiceFunction +from .realtime_response_create_params import RealtimeResponseCreateParams -__all__ = ["ResponseCreateEvent", "Response", "ResponseToolChoice", "ResponseTool"] - -ResponseToolChoice: TypeAlias = Union[ToolChoiceOptions, ToolChoiceFunction, ToolChoiceMcp] - - -class ResponseTool(BaseModel): - description: Optional[str] = None - """ - The description of the function, including guidance on when and how to call it, - and guidance about what to tell the user when calling (if anything). - """ - - name: Optional[str] = None - """The name of the function.""" - - parameters: Optional[object] = None - """Parameters of the function in JSON Schema.""" - - type: Optional[Literal["function"]] = None - """The type of the tool, i.e. `function`.""" - - -class Response(BaseModel): - conversation: Union[str, Literal["auto", "none"], None] = None - """Controls which conversation the response is added to. - - Currently supports `auto` and `none`, with `auto` as the default value. The - `auto` value means that the contents of the response will be added to the - default conversation. Set this to `none` to create an out-of-band response which - will not add items to default conversation. - """ - - input: Optional[List[ConversationItem]] = None - """Input items to include in the prompt for the model. - - Using this field creates a new context for this Response instead of using the - default conversation. An empty array `[]` will clear the context for this - Response. Note that this can include references to items from the default - conversation. - """ - - instructions: Optional[str] = None - """The default system instructions (i.e. - - system message) prepended to model calls. This field allows the client to guide - the model on desired responses. The model can be instructed on response content - and format, (e.g. "be extremely succinct", "act friendly", "here are examples of - good responses") and on audio behavior (e.g. "talk quickly", "inject emotion - into your voice", "laugh frequently"). The instructions are not guaranteed to be - followed by the model, but they provide guidance to the model on the desired - behavior. - - Note that the server sets default instructions which will be used if this field - is not set and are visible in the `session.created` event at the start of the - session. - """ - - max_output_tokens: Union[int, Literal["inf"], None] = None - """ - Maximum number of output tokens for a single assistant response, inclusive of - tool calls. Provide an integer between 1 and 4096 to limit output tokens, or - `inf` for the maximum available tokens for a given model. Defaults to `inf`. - """ - - metadata: Optional[Metadata] = None - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - modalities: Optional[List[Literal["text", "audio"]]] = None - """The set of modalities the model can respond with. - - To disable audio, set this to ["text"]. - """ - - output_audio_format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None - """The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" - - prompt: Optional[ResponsePrompt] = None - """Reference to a prompt template and its variables. - - [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). - """ - - temperature: Optional[float] = None - """Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8.""" - - tool_choice: Optional[ResponseToolChoice] = None - """How the model chooses tools. - - Provide one of the string modes or force a specific function/MCP tool. - """ - - tools: Optional[List[ResponseTool]] = None - """Tools (functions) available to the model.""" - - voice: Union[ - str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"], None - ] = None - """The voice the model uses to respond. - - Voice cannot be changed during the session once the model has responded with - audio at least once. Current voice options are `alloy`, `ash`, `ballad`, - `coral`, `echo`, `sage`, `shimmer`, and `verse`. - """ +__all__ = ["ResponseCreateEvent"] class ResponseCreateEvent(BaseModel): @@ -130,5 +16,5 @@ class ResponseCreateEvent(BaseModel): event_id: Optional[str] = None """Optional client-generated ID used to identify this event.""" - response: Optional[Response] = None + response: Optional[RealtimeResponseCreateParams] = None """Create a new Realtime response with these parameters""" diff --git a/src/openai/types/realtime/response_create_event_param.py b/src/openai/types/realtime/response_create_event_param.py index f941c4ca9c..e5dd46d9b6 100644 --- a/src/openai/types/realtime/response_create_event_param.py +++ b/src/openai/types/realtime/response_create_event_param.py @@ -2,124 +2,11 @@ from __future__ import annotations -from typing import List, Union, Iterable, Optional -from typing_extensions import Literal, Required, TypeAlias, TypedDict +from typing_extensions import Literal, Required, TypedDict -from ..shared_params.metadata import Metadata -from .conversation_item_param import ConversationItemParam -from ..responses.tool_choice_options import ToolChoiceOptions -from ..responses.response_prompt_param import ResponsePromptParam -from ..responses.tool_choice_mcp_param import ToolChoiceMcpParam -from ..responses.tool_choice_function_param import ToolChoiceFunctionParam +from .realtime_response_create_params_param import RealtimeResponseCreateParamsParam -__all__ = ["ResponseCreateEventParam", "Response", "ResponseToolChoice", "ResponseTool"] - -ResponseToolChoice: TypeAlias = Union[ToolChoiceOptions, ToolChoiceFunctionParam, ToolChoiceMcpParam] - - -class ResponseTool(TypedDict, total=False): - description: str - """ - The description of the function, including guidance on when and how to call it, - and guidance about what to tell the user when calling (if anything). - """ - - name: str - """The name of the function.""" - - parameters: object - """Parameters of the function in JSON Schema.""" - - type: Literal["function"] - """The type of the tool, i.e. `function`.""" - - -class Response(TypedDict, total=False): - conversation: Union[str, Literal["auto", "none"]] - """Controls which conversation the response is added to. - - Currently supports `auto` and `none`, with `auto` as the default value. The - `auto` value means that the contents of the response will be added to the - default conversation. Set this to `none` to create an out-of-band response which - will not add items to default conversation. - """ - - input: Iterable[ConversationItemParam] - """Input items to include in the prompt for the model. - - Using this field creates a new context for this Response instead of using the - default conversation. An empty array `[]` will clear the context for this - Response. Note that this can include references to items from the default - conversation. - """ - - instructions: str - """The default system instructions (i.e. - - system message) prepended to model calls. This field allows the client to guide - the model on desired responses. The model can be instructed on response content - and format, (e.g. "be extremely succinct", "act friendly", "here are examples of - good responses") and on audio behavior (e.g. "talk quickly", "inject emotion - into your voice", "laugh frequently"). The instructions are not guaranteed to be - followed by the model, but they provide guidance to the model on the desired - behavior. - - Note that the server sets default instructions which will be used if this field - is not set and are visible in the `session.created` event at the start of the - session. - """ - - max_output_tokens: Union[int, Literal["inf"]] - """ - Maximum number of output tokens for a single assistant response, inclusive of - tool calls. Provide an integer between 1 and 4096 to limit output tokens, or - `inf` for the maximum available tokens for a given model. Defaults to `inf`. - """ - - metadata: Optional[Metadata] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - modalities: List[Literal["text", "audio"]] - """The set of modalities the model can respond with. - - To disable audio, set this to ["text"]. - """ - - output_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] - """The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" - - prompt: Optional[ResponsePromptParam] - """Reference to a prompt template and its variables. - - [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). - """ - - temperature: float - """Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8.""" - - tool_choice: ResponseToolChoice - """How the model chooses tools. - - Provide one of the string modes or force a specific function/MCP tool. - """ - - tools: Iterable[ResponseTool] - """Tools (functions) available to the model.""" - - voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"]] - """The voice the model uses to respond. - - Voice cannot be changed during the session once the model has responded with - audio at least once. Current voice options are `alloy`, `ash`, `ballad`, - `coral`, `echo`, `sage`, `shimmer`, and `verse`. - """ +__all__ = ["ResponseCreateEventParam"] class ResponseCreateEventParam(TypedDict, total=False): @@ -129,5 +16,5 @@ class ResponseCreateEventParam(TypedDict, total=False): event_id: str """Optional client-generated ID used to identify this event.""" - response: Response + response: RealtimeResponseCreateParamsParam """Create a new Realtime response with these parameters""" diff --git a/src/openai/types/realtime/session_created_event.py b/src/openai/types/realtime/session_created_event.py index 51f75700f0..b5caad35d7 100644 --- a/src/openai/types/realtime/session_created_event.py +++ b/src/openai/types/realtime/session_created_event.py @@ -1,19 +1,23 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing_extensions import Literal +from typing import Union +from typing_extensions import Literal, TypeAlias from ..._models import BaseModel -from .realtime_session import RealtimeSession +from .realtime_session_create_request import RealtimeSessionCreateRequest +from .realtime_transcription_session_create_request import RealtimeTranscriptionSessionCreateRequest -__all__ = ["SessionCreatedEvent"] +__all__ = ["SessionCreatedEvent", "Session"] + +Session: TypeAlias = Union[RealtimeSessionCreateRequest, RealtimeTranscriptionSessionCreateRequest] class SessionCreatedEvent(BaseModel): event_id: str """The unique ID of the server event.""" - session: RealtimeSession - """Realtime session object.""" + session: Session + """The session configuration.""" type: Literal["session.created"] """The event type, must be `session.created`.""" diff --git a/src/openai/types/realtime/session_update_event.py b/src/openai/types/realtime/session_update_event.py index 00a4377f96..2e226162c4 100644 --- a/src/openai/types/realtime/session_update_event.py +++ b/src/openai/types/realtime/session_update_event.py @@ -1,20 +1,31 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional -from typing_extensions import Literal +from typing import Union, Optional +from typing_extensions import Literal, TypeAlias from ..._models import BaseModel from .realtime_session_create_request import RealtimeSessionCreateRequest +from .realtime_transcription_session_create_request import RealtimeTranscriptionSessionCreateRequest -__all__ = ["SessionUpdateEvent"] +__all__ = ["SessionUpdateEvent", "Session"] + +Session: TypeAlias = Union[RealtimeSessionCreateRequest, RealtimeTranscriptionSessionCreateRequest] class SessionUpdateEvent(BaseModel): - session: RealtimeSessionCreateRequest - """Realtime session object configuration.""" + session: Session + """Update the Realtime session. + + Choose either a realtime session or a transcription session. + """ type: Literal["session.update"] """The event type, must be `session.update`.""" event_id: Optional[str] = None - """Optional client-generated ID used to identify this event.""" + """Optional client-generated ID used to identify this event. + + This is an arbitrary string that a client may assign. It will be passed back if + there is an error with the event, but the corresponding `session.updated` event + will not include it. + """ diff --git a/src/openai/types/realtime/session_update_event_param.py b/src/openai/types/realtime/session_update_event_param.py index 79ff05f729..5962361431 100644 --- a/src/openai/types/realtime/session_update_event_param.py +++ b/src/openai/types/realtime/session_update_event_param.py @@ -2,19 +2,31 @@ from __future__ import annotations -from typing_extensions import Literal, Required, TypedDict +from typing import Union +from typing_extensions import Literal, Required, TypeAlias, TypedDict from .realtime_session_create_request_param import RealtimeSessionCreateRequestParam +from .realtime_transcription_session_create_request_param import RealtimeTranscriptionSessionCreateRequestParam -__all__ = ["SessionUpdateEventParam"] +__all__ = ["SessionUpdateEventParam", "Session"] + +Session: TypeAlias = Union[RealtimeSessionCreateRequestParam, RealtimeTranscriptionSessionCreateRequestParam] class SessionUpdateEventParam(TypedDict, total=False): - session: Required[RealtimeSessionCreateRequestParam] - """Realtime session object configuration.""" + session: Required[Session] + """Update the Realtime session. + + Choose either a realtime session or a transcription session. + """ type: Required[Literal["session.update"]] """The event type, must be `session.update`.""" event_id: str - """Optional client-generated ID used to identify this event.""" + """Optional client-generated ID used to identify this event. + + This is an arbitrary string that a client may assign. It will be passed back if + there is an error with the event, but the corresponding `session.updated` event + will not include it. + """ diff --git a/src/openai/types/realtime/session_updated_event.py b/src/openai/types/realtime/session_updated_event.py index b8a5972f6e..eb7ee0332d 100644 --- a/src/openai/types/realtime/session_updated_event.py +++ b/src/openai/types/realtime/session_updated_event.py @@ -1,19 +1,23 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing_extensions import Literal +from typing import Union +from typing_extensions import Literal, TypeAlias from ..._models import BaseModel -from .realtime_session import RealtimeSession +from .realtime_session_create_request import RealtimeSessionCreateRequest +from .realtime_transcription_session_create_request import RealtimeTranscriptionSessionCreateRequest -__all__ = ["SessionUpdatedEvent"] +__all__ = ["SessionUpdatedEvent", "Session"] + +Session: TypeAlias = Union[RealtimeSessionCreateRequest, RealtimeTranscriptionSessionCreateRequest] class SessionUpdatedEvent(BaseModel): event_id: str """The unique ID of the server event.""" - session: RealtimeSession - """Realtime session object.""" + session: Session + """The session configuration.""" type: Literal["session.updated"] """The event type, must be `session.updated`.""" diff --git a/src/openai/types/realtime/transcription_session_created.py b/src/openai/types/realtime/transcription_session_created.py index 1d34d152d7..c358c5e8b0 100644 --- a/src/openai/types/realtime/transcription_session_created.py +++ b/src/openai/types/realtime/transcription_session_created.py @@ -1,105 +1,24 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Optional from typing_extensions import Literal from ..._models import BaseModel +from .realtime_transcription_session_create_response import RealtimeTranscriptionSessionCreateResponse -__all__ = [ - "TranscriptionSessionCreated", - "Session", - "SessionAudio", - "SessionAudioInput", - "SessionAudioInputNoiseReduction", - "SessionAudioInputTranscription", - "SessionAudioInputTurnDetection", -] - - -class SessionAudioInputNoiseReduction(BaseModel): - type: Optional[Literal["near_field", "far_field"]] = None - - -class SessionAudioInputTranscription(BaseModel): - language: Optional[str] = None - """The language of the input audio. - - Supplying the input language in - [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) - format will improve accuracy and latency. - """ - - model: Optional[Literal["gpt-4o-transcribe", "gpt-4o-mini-transcribe", "whisper-1"]] = None - """The model to use for transcription. - - Can be `gpt-4o-transcribe`, `gpt-4o-mini-transcribe`, or `whisper-1`. - """ - - prompt: Optional[str] = None - """An optional text to guide the model's style or continue a previous audio - segment. - - The [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) - should match the audio language. - """ - - -class SessionAudioInputTurnDetection(BaseModel): - prefix_padding_ms: Optional[int] = None - - silence_duration_ms: Optional[int] = None - - threshold: Optional[float] = None - - type: Optional[str] = None - """Type of turn detection, only `server_vad` is currently supported.""" - - -class SessionAudioInput(BaseModel): - format: Optional[str] = None - """The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" - - noise_reduction: Optional[SessionAudioInputNoiseReduction] = None - """Configuration for input audio noise reduction.""" - - transcription: Optional[SessionAudioInputTranscription] = None - """Configuration of the transcription model.""" - - turn_detection: Optional[SessionAudioInputTurnDetection] = None - """Configuration for turn detection.""" - - -class SessionAudio(BaseModel): - input: Optional[SessionAudioInput] = None - - -class Session(BaseModel): - id: Optional[str] = None - """Unique identifier for the session that looks like `sess_1234567890abcdef`.""" - - audio: Optional[SessionAudio] = None - """Configuration for input audio for the session.""" - - expires_at: Optional[int] = None - """Expiration timestamp for the session, in seconds since epoch.""" - - include: Optional[List[Literal["item.input_audio_transcription.logprobs"]]] = None - """Additional fields to include in server outputs. - - - `item.input_audio_transcription.logprobs`: Include logprobs for input audio - transcription. - """ - - object: Optional[str] = None - """The object type. Always `realtime.transcription_session`.""" +__all__ = ["TranscriptionSessionCreated"] class TranscriptionSessionCreated(BaseModel): event_id: str """The unique ID of the server event.""" - session: Session - """A Realtime transcription session configuration object.""" + session: RealtimeTranscriptionSessionCreateResponse + """A new Realtime transcription session configuration. + + When a session is created on the server via REST API, the session object also + contains an ephemeral key. Default TTL for keys is 10 minutes. This property is + not present when a session is updated via the WebSocket API. + """ type: Literal["transcription_session.created"] """The event type, must be `transcription_session.created`.""" diff --git a/src/openai/types/realtime/transcription_session_update.py b/src/openai/types/realtime/transcription_session_update.py index c8f5b9eb4a..0faff9cb57 100644 --- a/src/openai/types/realtime/transcription_session_update.py +++ b/src/openai/types/realtime/transcription_session_update.py @@ -1,16 +1,94 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional +from typing import List, Optional from typing_extensions import Literal from ..._models import BaseModel -from .realtime_transcription_session_create_request import RealtimeTranscriptionSessionCreateRequest +from .audio_transcription import AudioTranscription +from .noise_reduction_type import NoiseReductionType -__all__ = ["TranscriptionSessionUpdate"] +__all__ = ["TranscriptionSessionUpdate", "Session", "SessionInputAudioNoiseReduction", "SessionTurnDetection"] + + +class SessionInputAudioNoiseReduction(BaseModel): + type: Optional[NoiseReductionType] = None + """Type of noise reduction. + + `near_field` is for close-talking microphones such as headphones, `far_field` is + for far-field microphones such as laptop or conference room microphones. + """ + + +class SessionTurnDetection(BaseModel): + prefix_padding_ms: Optional[int] = None + """Amount of audio to include before the VAD detected speech (in milliseconds). + + Defaults to 300ms. + """ + + silence_duration_ms: Optional[int] = None + """Duration of silence to detect speech stop (in milliseconds). + + Defaults to 500ms. With shorter values the model will respond more quickly, but + may jump in on short pauses from the user. + """ + + threshold: Optional[float] = None + """Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. + + A higher threshold will require louder audio to activate the model, and thus + might perform better in noisy environments. + """ + + type: Optional[Literal["server_vad"]] = None + """Type of turn detection. + + Only `server_vad` is currently supported for transcription sessions. + """ + + +class Session(BaseModel): + include: Optional[List[Literal["item.input_audio_transcription.logprobs"]]] = None + """The set of items to include in the transcription. + + Current available items are: `item.input_audio_transcription.logprobs` + """ + + input_audio_format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None + """The format of input audio. + + Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, input audio must + be 16-bit PCM at a 24kHz sample rate, single channel (mono), and little-endian + byte order. + """ + + input_audio_noise_reduction: Optional[SessionInputAudioNoiseReduction] = None + """Configuration for input audio noise reduction. + + This can be set to `null` to turn off. Noise reduction filters audio added to + the input audio buffer before it is sent to VAD and the model. Filtering the + audio can improve VAD and turn detection accuracy (reducing false positives) and + model performance by improving perception of the input audio. + """ + + input_audio_transcription: Optional[AudioTranscription] = None + """Configuration for input audio transcription. + + The client can optionally set the language and prompt for transcription, these + offer additional guidance to the transcription service. + """ + + turn_detection: Optional[SessionTurnDetection] = None + """Configuration for turn detection. + + Can be set to `null` to turn off. Server VAD means that the model will detect + the start and end of speech based on audio volume and respond at the end of user + speech. + """ class TranscriptionSessionUpdate(BaseModel): - session: RealtimeTranscriptionSessionCreateRequest + session: Session """Realtime transcription session object configuration.""" type: Literal["transcription_session.update"] diff --git a/src/openai/types/realtime/transcription_session_update_param.py b/src/openai/types/realtime/transcription_session_update_param.py index f2e66efaa0..55c67798b6 100644 --- a/src/openai/types/realtime/transcription_session_update_param.py +++ b/src/openai/types/realtime/transcription_session_update_param.py @@ -2,15 +2,94 @@ from __future__ import annotations +from typing import List from typing_extensions import Literal, Required, TypedDict -from .realtime_transcription_session_create_request_param import RealtimeTranscriptionSessionCreateRequestParam +from .noise_reduction_type import NoiseReductionType +from .audio_transcription_param import AudioTranscriptionParam -__all__ = ["TranscriptionSessionUpdateParam"] +__all__ = ["TranscriptionSessionUpdateParam", "Session", "SessionInputAudioNoiseReduction", "SessionTurnDetection"] + + +class SessionInputAudioNoiseReduction(TypedDict, total=False): + type: NoiseReductionType + """Type of noise reduction. + + `near_field` is for close-talking microphones such as headphones, `far_field` is + for far-field microphones such as laptop or conference room microphones. + """ + + +class SessionTurnDetection(TypedDict, total=False): + prefix_padding_ms: int + """Amount of audio to include before the VAD detected speech (in milliseconds). + + Defaults to 300ms. + """ + + silence_duration_ms: int + """Duration of silence to detect speech stop (in milliseconds). + + Defaults to 500ms. With shorter values the model will respond more quickly, but + may jump in on short pauses from the user. + """ + + threshold: float + """Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. + + A higher threshold will require louder audio to activate the model, and thus + might perform better in noisy environments. + """ + + type: Literal["server_vad"] + """Type of turn detection. + + Only `server_vad` is currently supported for transcription sessions. + """ + + +class Session(TypedDict, total=False): + include: List[Literal["item.input_audio_transcription.logprobs"]] + """The set of items to include in the transcription. + + Current available items are: `item.input_audio_transcription.logprobs` + """ + + input_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] + """The format of input audio. + + Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, input audio must + be 16-bit PCM at a 24kHz sample rate, single channel (mono), and little-endian + byte order. + """ + + input_audio_noise_reduction: SessionInputAudioNoiseReduction + """Configuration for input audio noise reduction. + + This can be set to `null` to turn off. Noise reduction filters audio added to + the input audio buffer before it is sent to VAD and the model. Filtering the + audio can improve VAD and turn detection accuracy (reducing false positives) and + model performance by improving perception of the input audio. + """ + + input_audio_transcription: AudioTranscriptionParam + """Configuration for input audio transcription. + + The client can optionally set the language and prompt for transcription, these + offer additional guidance to the transcription service. + """ + + turn_detection: SessionTurnDetection + """Configuration for turn detection. + + Can be set to `null` to turn off. Server VAD means that the model will detect + the start and end of speech based on audio volume and respond at the end of user + speech. + """ class TranscriptionSessionUpdateParam(TypedDict, total=False): - session: Required[RealtimeTranscriptionSessionCreateRequestParam] + session: Required[Session] """Realtime transcription session object configuration.""" type: Required[Literal["transcription_session.update"]] diff --git a/src/openai/types/realtime/transcription_session_updated_event.py b/src/openai/types/realtime/transcription_session_updated_event.py index 9abd1d20be..f6a52a12f3 100644 --- a/src/openai/types/realtime/transcription_session_updated_event.py +++ b/src/openai/types/realtime/transcription_session_updated_event.py @@ -1,105 +1,24 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Optional from typing_extensions import Literal from ..._models import BaseModel +from .realtime_transcription_session_create_response import RealtimeTranscriptionSessionCreateResponse -__all__ = [ - "TranscriptionSessionUpdatedEvent", - "Session", - "SessionAudio", - "SessionAudioInput", - "SessionAudioInputNoiseReduction", - "SessionAudioInputTranscription", - "SessionAudioInputTurnDetection", -] - - -class SessionAudioInputNoiseReduction(BaseModel): - type: Optional[Literal["near_field", "far_field"]] = None - - -class SessionAudioInputTranscription(BaseModel): - language: Optional[str] = None - """The language of the input audio. - - Supplying the input language in - [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) - format will improve accuracy and latency. - """ - - model: Optional[Literal["gpt-4o-transcribe", "gpt-4o-mini-transcribe", "whisper-1"]] = None - """The model to use for transcription. - - Can be `gpt-4o-transcribe`, `gpt-4o-mini-transcribe`, or `whisper-1`. - """ - - prompt: Optional[str] = None - """An optional text to guide the model's style or continue a previous audio - segment. - - The [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) - should match the audio language. - """ - - -class SessionAudioInputTurnDetection(BaseModel): - prefix_padding_ms: Optional[int] = None - - silence_duration_ms: Optional[int] = None - - threshold: Optional[float] = None - - type: Optional[str] = None - """Type of turn detection, only `server_vad` is currently supported.""" - - -class SessionAudioInput(BaseModel): - format: Optional[str] = None - """The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" - - noise_reduction: Optional[SessionAudioInputNoiseReduction] = None - """Configuration for input audio noise reduction.""" - - transcription: Optional[SessionAudioInputTranscription] = None - """Configuration of the transcription model.""" - - turn_detection: Optional[SessionAudioInputTurnDetection] = None - """Configuration for turn detection.""" - - -class SessionAudio(BaseModel): - input: Optional[SessionAudioInput] = None - - -class Session(BaseModel): - id: Optional[str] = None - """Unique identifier for the session that looks like `sess_1234567890abcdef`.""" - - audio: Optional[SessionAudio] = None - """Configuration for input audio for the session.""" - - expires_at: Optional[int] = None - """Expiration timestamp for the session, in seconds since epoch.""" - - include: Optional[List[Literal["item.input_audio_transcription.logprobs"]]] = None - """Additional fields to include in server outputs. - - - `item.input_audio_transcription.logprobs`: Include logprobs for input audio - transcription. - """ - - object: Optional[str] = None - """The object type. Always `realtime.transcription_session`.""" +__all__ = ["TranscriptionSessionUpdatedEvent"] class TranscriptionSessionUpdatedEvent(BaseModel): event_id: str """The unique ID of the server event.""" - session: Session - """A Realtime transcription session configuration object.""" + session: RealtimeTranscriptionSessionCreateResponse + """A new Realtime transcription session configuration. + + When a session is created on the server via REST API, the session object also + contains an ephemeral key. Default TTL for keys is 10 minutes. This property is + not present when a session is updated via the WebSocket API. + """ type: Literal["transcription_session.updated"] """The event type, must be `transcription_session.updated`.""" diff --git a/tests/api_resources/realtime/test_client_secrets.py b/tests/api_resources/realtime/test_client_secrets.py index c477268ee6..b7bb0e5aa7 100644 --- a/tests/api_resources/realtime/test_client_secrets.py +++ b/tests/api_resources/realtime/test_client_secrets.py @@ -30,11 +30,13 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: "seconds": 10, }, session={ - "model": "string", "type": "realtime", "audio": { "input": { - "format": "pcm16", + "format": { + "rate": 24000, + "type": "audio/pcm", + }, "noise_reduction": {"type": "near_field"}, "transcription": { "language": "language", @@ -53,27 +55,24 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: }, }, "output": { - "format": "pcm16", + "format": { + "rate": 24000, + "type": "audio/pcm", + }, "speed": 0.25, "voice": "ash", }, }, - "client_secret": { - "expires_after": { - "anchor": "created_at", - "seconds": 0, - } - }, "include": ["item.input_audio_transcription.logprobs"], "instructions": "instructions", "max_output_tokens": 0, + "model": "string", "output_modalities": ["text"], "prompt": { "id": "id", "variables": {"foo": "string"}, "version": "version", }, - "temperature": 0, "tool_choice": "none", "tools": [ { @@ -128,11 +127,13 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> "seconds": 10, }, session={ - "model": "string", "type": "realtime", "audio": { "input": { - "format": "pcm16", + "format": { + "rate": 24000, + "type": "audio/pcm", + }, "noise_reduction": {"type": "near_field"}, "transcription": { "language": "language", @@ -151,27 +152,24 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> }, }, "output": { - "format": "pcm16", + "format": { + "rate": 24000, + "type": "audio/pcm", + }, "speed": 0.25, "voice": "ash", }, }, - "client_secret": { - "expires_after": { - "anchor": "created_at", - "seconds": 0, - } - }, "include": ["item.input_audio_transcription.logprobs"], "instructions": "instructions", "max_output_tokens": 0, + "model": "string", "output_modalities": ["text"], "prompt": { "id": "id", "variables": {"foo": "string"}, "version": "version", }, - "temperature": 0, "tool_choice": "none", "tools": [ { From 847ff0b83841d9262ba0d9c4fdf46f0478004ad0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 10 Sep 2025 11:03:41 -0400 Subject: [PATCH 489/769] release: 1.107.1 (#2619) * chore(api): fix realtime GA types * release: 1.107.1 --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- .stats.yml | 6 +- CHANGELOG.md | 8 ++ api.md | 5 +- pyproject.toml | 2 +- src/openai/_version.py | 2 +- src/openai/resources/realtime/realtime.py | 38 +------ src/openai/types/realtime/__init__.py | 14 +-- .../realtime/client_secret_create_response.py | 7 +- .../realtime_audio_input_turn_detection.py | 2 +- ...altime_audio_input_turn_detection_param.py | 2 +- .../types/realtime/realtime_client_event.py | 2 - .../realtime/realtime_client_event_param.py | 2 - .../{models.py => realtime_function_tool.py} | 4 +- ...ram.py => realtime_function_tool_param.py} | 4 +- .../realtime_response_create_params.py | 4 +- .../realtime_response_create_params_param.py | 4 +- .../types/realtime/realtime_server_event.py | 4 - .../realtime_session_create_response.py | 18 ++-- .../realtime/realtime_tools_config_param.py | 4 +- .../realtime/realtime_tools_config_union.py | 4 +- .../realtime_tools_config_union_param.py | 4 +- ...ime_transcription_session_client_secret.py | 20 ---- ...e_transcription_session_create_response.py | 61 ++++++++---- ...ption_session_input_audio_transcription.py | 36 ------- .../realtime/transcription_session_created.py | 24 ----- .../realtime/transcription_session_update.py | 98 ------------------ .../transcription_session_update_param.py | 99 ------------------- .../transcription_session_updated_event.py | 24 ----- 29 files changed, 94 insertions(+), 410 deletions(-) rename src/openai/types/realtime/{models.py => realtime_function_tool.py} (89%) rename src/openai/types/realtime/{models_param.py => realtime_function_tool_param.py} (85%) delete mode 100644 src/openai/types/realtime/realtime_transcription_session_client_secret.py delete mode 100644 src/openai/types/realtime/realtime_transcription_session_input_audio_transcription.py delete mode 100644 src/openai/types/realtime/transcription_session_created.py delete mode 100644 src/openai/types/realtime/transcription_session_update.py delete mode 100644 src/openai/types/realtime/transcription_session_update_param.py delete mode 100644 src/openai/types/realtime/transcription_session_updated_event.py diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 12cec28d56..25880b2e7b 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.107.0" + ".": "1.107.1" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 36a3c7f587..2aa16be875 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 118 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-7807ec6037efcee1af7decbfd3974a42b761fb6c6a71b4050fe43484d7fcbac4.yml -openapi_spec_hash: da6851e3891ad2659a50ed6a736fd32a -config_hash: 74d955cdc2377213f5268ea309090f6c +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-16cb18bed32bae8c5840fb39a1bf664026cc40463ad0c487dcb0df1bd3d72db0.yml +openapi_spec_hash: 4cb51b22f98dee1a90bc7add82d1d132 +config_hash: 930dac3aa861344867e4ac84f037b5df diff --git a/CHANGELOG.md b/CHANGELOG.md index 76d5dcb2dd..19eab7da7e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.107.1 (2025-09-10) + +Full Changelog: [v1.107.0...v1.107.1](https://github.com/openai/openai-python/compare/v1.107.0...v1.107.1) + +### Chores + +* **api:** fix realtime GA types ([570fc5a](https://github.com/openai/openai-python/commit/570fc5a28ada665fd658b24675361680cfeb086f)) + ## 1.107.0 (2025-09-08) Full Changelog: [v1.106.1...v1.107.0](https://github.com/openai/openai-python/compare/v1.106.1...v1.107.0) diff --git a/api.md b/api.md index 7c947fffe1..73b8427387 100644 --- a/api.md +++ b/api.md @@ -892,7 +892,6 @@ from openai.types.realtime import ( McpListToolsCompleted, McpListToolsFailed, McpListToolsInProgress, - Models, NoiseReductionType, OutputAudioBufferClearEvent, RateLimitsUpdatedEvent, @@ -909,6 +908,7 @@ from openai.types.realtime import ( RealtimeConversationItemUserMessage, RealtimeError, RealtimeErrorEvent, + RealtimeFunctionTool, RealtimeMcpApprovalRequest, RealtimeMcpApprovalResponse, RealtimeMcpListTools, @@ -961,7 +961,6 @@ from openai.types.realtime import ( SessionCreatedEvent, SessionUpdateEvent, SessionUpdatedEvent, - TranscriptionSessionCreated, TranscriptionSessionUpdate, TranscriptionSessionUpdatedEvent, ) @@ -975,9 +974,7 @@ Types: from openai.types.realtime import ( RealtimeSessionClientSecret, RealtimeSessionCreateResponse, - RealtimeTranscriptionSessionClientSecret, RealtimeTranscriptionSessionCreateResponse, - RealtimeTranscriptionSessionInputAudioTranscription, RealtimeTranscriptionSessionTurnDetection, ClientSecretCreateResponse, ) diff --git a/pyproject.toml b/pyproject.toml index 5c3985cc7c..326dc5a004 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.107.0" +version = "1.107.1" 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 06826fc4de..f337b21cd5 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.107.0" # x-release-please-version +__version__ = "1.107.1" # x-release-please-version diff --git a/src/openai/resources/realtime/realtime.py b/src/openai/resources/realtime/realtime.py index 81e6dc54f5..64fca72915 100644 --- a/src/openai/resources/realtime/realtime.py +++ b/src/openai/resources/realtime/realtime.py @@ -32,7 +32,7 @@ ClientSecretsWithStreamingResponse, AsyncClientSecretsWithStreamingResponse, ) -from ...types.realtime import session_update_event_param, transcription_session_update_param +from ...types.realtime import session_update_event_param from ...types.websocket_connection_options import WebsocketConnectionOptions from ...types.realtime.realtime_client_event import RealtimeClientEvent from ...types.realtime.realtime_server_event import RealtimeServerEvent @@ -199,7 +199,6 @@ class AsyncRealtimeConnection: input_audio_buffer: AsyncRealtimeInputAudioBufferResource conversation: AsyncRealtimeConversationResource output_audio_buffer: AsyncRealtimeOutputAudioBufferResource - transcription_session: AsyncRealtimeTranscriptionSessionResource _connection: AsyncWebsocketConnection @@ -211,7 +210,6 @@ def __init__(self, connection: AsyncWebsocketConnection) -> None: self.input_audio_buffer = AsyncRealtimeInputAudioBufferResource(self) self.conversation = AsyncRealtimeConversationResource(self) self.output_audio_buffer = AsyncRealtimeOutputAudioBufferResource(self) - self.transcription_session = AsyncRealtimeTranscriptionSessionResource(self) async def __aiter__(self) -> AsyncIterator[RealtimeServerEvent]: """ @@ -381,7 +379,6 @@ class RealtimeConnection: input_audio_buffer: RealtimeInputAudioBufferResource conversation: RealtimeConversationResource output_audio_buffer: RealtimeOutputAudioBufferResource - transcription_session: RealtimeTranscriptionSessionResource _connection: WebsocketConnection @@ -393,7 +390,6 @@ def __init__(self, connection: WebsocketConnection) -> None: self.input_audio_buffer = RealtimeInputAudioBufferResource(self) self.conversation = RealtimeConversationResource(self) self.output_audio_buffer = RealtimeOutputAudioBufferResource(self) - self.transcription_session = RealtimeTranscriptionSessionResource(self) def __iter__(self) -> Iterator[RealtimeServerEvent]: """ @@ -565,8 +561,7 @@ def update(self, *, session: session_update_event_param.Session, event_id: str | """ Send this event to update the session’s configuration. The client may send this event at any time to update any field - except for `voice` and `model`. `voice` can be updated only if there have been no other - audio outputs yet. + except for `voice` and `model`. `voice` can be updated only if there have been no other audio outputs yet. When the server receives a `session.update`, it will respond with a `session.updated` event showing the full, effective configuration. @@ -800,19 +795,6 @@ def clear(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: ) -class RealtimeTranscriptionSessionResource(BaseRealtimeConnectionResource): - def update( - self, *, session: transcription_session_update_param.Session, event_id: str | NotGiven = NOT_GIVEN - ) -> None: - """Send this event to update a transcription session.""" - self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given({"type": "transcription_session.update", "session": session, "event_id": event_id}), - ) - ) - - class BaseAsyncRealtimeConnectionResource: def __init__(self, connection: AsyncRealtimeConnection) -> None: self._connection = connection @@ -825,8 +807,7 @@ async def update( """ Send this event to update the session’s configuration. The client may send this event at any time to update any field - except for `voice` and `model`. `voice` can be updated only if there have been no other - audio outputs yet. + except for `voice` and `model`. `voice` can be updated only if there have been no other audio outputs yet. When the server receives a `session.update`, it will respond with a `session.updated` event showing the full, effective configuration. @@ -1058,16 +1039,3 @@ async def clear(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: await self._connection.send( cast(RealtimeClientEventParam, strip_not_given({"type": "output_audio_buffer.clear", "event_id": event_id})) ) - - -class AsyncRealtimeTranscriptionSessionResource(BaseAsyncRealtimeConnectionResource): - async def update( - self, *, session: transcription_session_update_param.Session, event_id: str | NotGiven = NOT_GIVEN - ) -> None: - """Send this event to update a transcription session.""" - await self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given({"type": "transcription_session.update", "session": session, "event_id": event_id}), - ) - ) diff --git a/src/openai/types/realtime/__init__.py b/src/openai/types/realtime/__init__.py index 6873ba6a2a..2d947c8a2f 100644 --- a/src/openai/types/realtime/__init__.py +++ b/src/openai/types/realtime/__init__.py @@ -2,8 +2,6 @@ from __future__ import annotations -from .models import Models as Models -from .models_param import ModelsParam as ModelsParam from .realtime_error import RealtimeError as RealtimeError from .conversation_item import ConversationItem as ConversationItem from .realtime_response import RealtimeResponse as RealtimeResponse @@ -25,6 +23,7 @@ from .session_updated_event import SessionUpdatedEvent as SessionUpdatedEvent from .conversation_item_done import ConversationItemDone as ConversationItemDone from .realtime_audio_formats import RealtimeAudioFormats as RealtimeAudioFormats +from .realtime_function_tool import RealtimeFunctionTool as RealtimeFunctionTool from .realtime_mcp_tool_call import RealtimeMcpToolCall as RealtimeMcpToolCall from .realtime_mcphttp_error import RealtimeMcphttpError as RealtimeMcphttpError from .response_created_event import ResponseCreatedEvent as ResponseCreatedEvent @@ -60,15 +59,14 @@ from .response_mcp_call_completed import ResponseMcpCallCompleted as ResponseMcpCallCompleted from .realtime_audio_config_output import RealtimeAudioConfigOutput as RealtimeAudioConfigOutput from .realtime_audio_formats_param import RealtimeAudioFormatsParam as RealtimeAudioFormatsParam +from .realtime_function_tool_param import RealtimeFunctionToolParam as RealtimeFunctionToolParam from .realtime_mcp_tool_call_param import RealtimeMcpToolCallParam as RealtimeMcpToolCallParam from .realtime_mcphttp_error_param import RealtimeMcphttpErrorParam as RealtimeMcphttpErrorParam -from .transcription_session_update import TranscriptionSessionUpdate as TranscriptionSessionUpdate from .client_secret_create_response import ClientSecretCreateResponse as ClientSecretCreateResponse from .realtime_mcp_approval_request import RealtimeMcpApprovalRequest as RealtimeMcpApprovalRequest from .realtime_mcp_list_tools_param import RealtimeMcpListToolsParam as RealtimeMcpListToolsParam from .realtime_tracing_config_param import RealtimeTracingConfigParam as RealtimeTracingConfigParam from .response_mcp_call_in_progress import ResponseMcpCallInProgress as ResponseMcpCallInProgress -from .transcription_session_created import TranscriptionSessionCreated as TranscriptionSessionCreated from .conversation_item_create_event import ConversationItemCreateEvent as ConversationItemCreateEvent from .conversation_item_delete_event import ConversationItemDeleteEvent as ConversationItemDeleteEvent from .input_audio_buffer_clear_event import InputAudioBufferClearEvent as InputAudioBufferClearEvent @@ -100,11 +98,9 @@ from .response_mcp_call_arguments_delta import ResponseMcpCallArgumentsDelta as ResponseMcpCallArgumentsDelta from .input_audio_buffer_committed_event import InputAudioBufferCommittedEvent as InputAudioBufferCommittedEvent from .realtime_audio_config_output_param import RealtimeAudioConfigOutputParam as RealtimeAudioConfigOutputParam -from .transcription_session_update_param import TranscriptionSessionUpdateParam as TranscriptionSessionUpdateParam from .realtime_audio_input_turn_detection import RealtimeAudioInputTurnDetection as RealtimeAudioInputTurnDetection from .realtime_mcp_approval_request_param import RealtimeMcpApprovalRequestParam as RealtimeMcpApprovalRequestParam from .realtime_truncation_retention_ratio import RealtimeTruncationRetentionRatio as RealtimeTruncationRetentionRatio -from .transcription_session_updated_event import TranscriptionSessionUpdatedEvent as TranscriptionSessionUpdatedEvent from .conversation_item_create_event_param import ConversationItemCreateEventParam as ConversationItemCreateEventParam from .conversation_item_delete_event_param import ConversationItemDeleteEventParam as ConversationItemDeleteEventParam from .input_audio_buffer_clear_event_param import InputAudioBufferClearEventParam as InputAudioBufferClearEventParam @@ -181,9 +177,6 @@ from .realtime_response_usage_output_token_details import ( RealtimeResponseUsageOutputTokenDetails as RealtimeResponseUsageOutputTokenDetails, ) -from .realtime_transcription_session_client_secret import ( - RealtimeTranscriptionSessionClientSecret as RealtimeTranscriptionSessionClientSecret, -) from .response_function_call_arguments_delta_event import ( ResponseFunctionCallArgumentsDeltaEvent as ResponseFunctionCallArgumentsDeltaEvent, ) @@ -229,9 +222,6 @@ from .conversation_item_input_audio_transcription_failed_event import ( ConversationItemInputAudioTranscriptionFailedEvent as ConversationItemInputAudioTranscriptionFailedEvent, ) -from .realtime_transcription_session_input_audio_transcription import ( - RealtimeTranscriptionSessionInputAudioTranscription as RealtimeTranscriptionSessionInputAudioTranscription, -) from .realtime_transcription_session_audio_input_turn_detection import ( RealtimeTranscriptionSessionAudioInputTurnDetection as RealtimeTranscriptionSessionAudioInputTurnDetection, ) diff --git a/src/openai/types/realtime/client_secret_create_response.py b/src/openai/types/realtime/client_secret_create_response.py index 8d61be3ab7..2aed66a25b 100644 --- a/src/openai/types/realtime/client_secret_create_response.py +++ b/src/openai/types/realtime/client_secret_create_response.py @@ -1,15 +1,18 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from typing import Union -from typing_extensions import TypeAlias +from typing_extensions import Annotated, TypeAlias +from ..._utils import PropertyInfo from ..._models import BaseModel from .realtime_session_create_response import RealtimeSessionCreateResponse from .realtime_transcription_session_create_response import RealtimeTranscriptionSessionCreateResponse __all__ = ["ClientSecretCreateResponse", "Session"] -Session: TypeAlias = Union[RealtimeSessionCreateResponse, RealtimeTranscriptionSessionCreateResponse] +Session: TypeAlias = Annotated[ + Union[RealtimeSessionCreateResponse, RealtimeTranscriptionSessionCreateResponse], PropertyInfo(discriminator="type") +] class ClientSecretCreateResponse(BaseModel): diff --git a/src/openai/types/realtime/realtime_audio_input_turn_detection.py b/src/openai/types/realtime/realtime_audio_input_turn_detection.py index ea9423f6a1..1c736ab2b7 100644 --- a/src/openai/types/realtime/realtime_audio_input_turn_detection.py +++ b/src/openai/types/realtime/realtime_audio_input_turn_detection.py @@ -27,7 +27,7 @@ class RealtimeAudioInputTurnDetection(BaseModel): idle_timeout_ms: Optional[int] = None """ Optional idle timeout after which turn detection will auto-timeout when no - additional audio is received. + additional audio is received and emits a `timeout_triggered` event. """ interrupt_response: Optional[bool] = None diff --git a/src/openai/types/realtime/realtime_audio_input_turn_detection_param.py b/src/openai/types/realtime/realtime_audio_input_turn_detection_param.py index ec398f52e6..79cabec708 100644 --- a/src/openai/types/realtime/realtime_audio_input_turn_detection_param.py +++ b/src/openai/types/realtime/realtime_audio_input_turn_detection_param.py @@ -27,7 +27,7 @@ class RealtimeAudioInputTurnDetectionParam(TypedDict, total=False): idle_timeout_ms: Optional[int] """ Optional idle timeout after which turn detection will auto-timeout when no - additional audio is received. + additional audio is received and emits a `timeout_triggered` event. """ interrupt_response: bool diff --git a/src/openai/types/realtime/realtime_client_event.py b/src/openai/types/realtime/realtime_client_event.py index 8c2c95e849..3b1c348daa 100644 --- a/src/openai/types/realtime/realtime_client_event.py +++ b/src/openai/types/realtime/realtime_client_event.py @@ -7,7 +7,6 @@ from .session_update_event import SessionUpdateEvent from .response_cancel_event import ResponseCancelEvent from .response_create_event import ResponseCreateEvent -from .transcription_session_update import TranscriptionSessionUpdate from .conversation_item_create_event import ConversationItemCreateEvent from .conversation_item_delete_event import ConversationItemDeleteEvent from .input_audio_buffer_clear_event import InputAudioBufferClearEvent @@ -32,7 +31,6 @@ ResponseCancelEvent, ResponseCreateEvent, SessionUpdateEvent, - TranscriptionSessionUpdate, ], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/realtime/realtime_client_event_param.py b/src/openai/types/realtime/realtime_client_event_param.py index 8e042dd64b..cda5766e2a 100644 --- a/src/openai/types/realtime/realtime_client_event_param.py +++ b/src/openai/types/realtime/realtime_client_event_param.py @@ -8,7 +8,6 @@ from .session_update_event_param import SessionUpdateEventParam from .response_cancel_event_param import ResponseCancelEventParam from .response_create_event_param import ResponseCreateEventParam -from .transcription_session_update_param import TranscriptionSessionUpdateParam from .conversation_item_create_event_param import ConversationItemCreateEventParam from .conversation_item_delete_event_param import ConversationItemDeleteEventParam from .input_audio_buffer_clear_event_param import InputAudioBufferClearEventParam @@ -32,5 +31,4 @@ ResponseCancelEventParam, ResponseCreateEventParam, SessionUpdateEventParam, - TranscriptionSessionUpdateParam, ] diff --git a/src/openai/types/realtime/models.py b/src/openai/types/realtime/realtime_function_tool.py similarity index 89% rename from src/openai/types/realtime/models.py rename to src/openai/types/realtime/realtime_function_tool.py index d4827538a3..48dbf9929d 100644 --- a/src/openai/types/realtime/models.py +++ b/src/openai/types/realtime/realtime_function_tool.py @@ -5,10 +5,10 @@ from ..._models import BaseModel -__all__ = ["Models"] +__all__ = ["RealtimeFunctionTool"] -class Models(BaseModel): +class RealtimeFunctionTool(BaseModel): description: Optional[str] = None """ The description of the function, including guidance on when and how to call it, diff --git a/src/openai/types/realtime/models_param.py b/src/openai/types/realtime/realtime_function_tool_param.py similarity index 85% rename from src/openai/types/realtime/models_param.py rename to src/openai/types/realtime/realtime_function_tool_param.py index 1db2d7e464..f42e3e497c 100644 --- a/src/openai/types/realtime/models_param.py +++ b/src/openai/types/realtime/realtime_function_tool_param.py @@ -4,10 +4,10 @@ from typing_extensions import Literal, TypedDict -__all__ = ["ModelsParam"] +__all__ = ["RealtimeFunctionToolParam"] -class ModelsParam(TypedDict, total=False): +class RealtimeFunctionToolParam(TypedDict, total=False): description: str """ The description of the function, including guidance on when and how to call it, diff --git a/src/openai/types/realtime/realtime_response_create_params.py b/src/openai/types/realtime/realtime_response_create_params.py index 3b5a8907a1..4dfd1fd386 100644 --- a/src/openai/types/realtime/realtime_response_create_params.py +++ b/src/openai/types/realtime/realtime_response_create_params.py @@ -3,10 +3,10 @@ from typing import List, Union, Optional from typing_extensions import Literal, TypeAlias -from .models import Models from ..._models import BaseModel from ..shared.metadata import Metadata from .conversation_item import ConversationItem +from .realtime_function_tool import RealtimeFunctionTool from ..responses.response_prompt import ResponsePrompt from ..responses.tool_choice_mcp import ToolChoiceMcp from ..responses.tool_choice_options import ToolChoiceOptions @@ -18,7 +18,7 @@ ToolChoice: TypeAlias = Union[ToolChoiceOptions, ToolChoiceFunction, ToolChoiceMcp] -Tool: TypeAlias = Union[Models, RealtimeResponseCreateMcpTool] +Tool: TypeAlias = Union[RealtimeFunctionTool, RealtimeResponseCreateMcpTool] class RealtimeResponseCreateParams(BaseModel): diff --git a/src/openai/types/realtime/realtime_response_create_params_param.py b/src/openai/types/realtime/realtime_response_create_params_param.py index 6800d36a31..eceffcccb7 100644 --- a/src/openai/types/realtime/realtime_response_create_params_param.py +++ b/src/openai/types/realtime/realtime_response_create_params_param.py @@ -5,9 +5,9 @@ from typing import List, Union, Iterable, Optional from typing_extensions import Literal, TypeAlias, TypedDict -from .models_param import ModelsParam from ..shared_params.metadata import Metadata from .conversation_item_param import ConversationItemParam +from .realtime_function_tool_param import RealtimeFunctionToolParam from ..responses.tool_choice_options import ToolChoiceOptions from ..responses.response_prompt_param import ResponsePromptParam from ..responses.tool_choice_mcp_param import ToolChoiceMcpParam @@ -19,7 +19,7 @@ ToolChoice: TypeAlias = Union[ToolChoiceOptions, ToolChoiceFunctionParam, ToolChoiceMcpParam] -Tool: TypeAlias = Union[ModelsParam, RealtimeResponseCreateMcpToolParam] +Tool: TypeAlias = Union[RealtimeFunctionToolParam, RealtimeResponseCreateMcpToolParam] class RealtimeResponseCreateParamsParam(TypedDict, total=False): diff --git a/src/openai/types/realtime/realtime_server_event.py b/src/openai/types/realtime/realtime_server_event.py index 8094bcfa96..1605b81a97 100644 --- a/src/openai/types/realtime/realtime_server_event.py +++ b/src/openai/types/realtime/realtime_server_event.py @@ -25,7 +25,6 @@ from .response_audio_delta_event import ResponseAudioDeltaEvent from .response_mcp_call_completed import ResponseMcpCallCompleted from .response_mcp_call_in_progress import ResponseMcpCallInProgress -from .transcription_session_created import TranscriptionSessionCreated from .conversation_item_created_event import ConversationItemCreatedEvent from .conversation_item_deleted_event import ConversationItemDeletedEvent from .response_output_item_done_event import ResponseOutputItemDoneEvent @@ -37,7 +36,6 @@ from .response_content_part_added_event import ResponseContentPartAddedEvent from .response_mcp_call_arguments_delta import ResponseMcpCallArgumentsDelta from .input_audio_buffer_committed_event import InputAudioBufferCommittedEvent -from .transcription_session_updated_event import TranscriptionSessionUpdatedEvent from .input_audio_buffer_timeout_triggered import InputAudioBufferTimeoutTriggered from .response_audio_transcript_done_event import ResponseAudioTranscriptDoneEvent from .response_audio_transcript_delta_event import ResponseAudioTranscriptDeltaEvent @@ -137,8 +135,6 @@ class OutputAudioBufferCleared(BaseModel): ResponseTextDoneEvent, SessionCreatedEvent, SessionUpdatedEvent, - TranscriptionSessionUpdatedEvent, - TranscriptionSessionCreated, OutputAudioBufferStarted, OutputAudioBufferStopped, OutputAudioBufferCleared, diff --git a/src/openai/types/realtime/realtime_session_create_response.py b/src/openai/types/realtime/realtime_session_create_response.py index 9c10b84588..7779f07a6e 100644 --- a/src/openai/types/realtime/realtime_session_create_response.py +++ b/src/openai/types/realtime/realtime_session_create_response.py @@ -3,12 +3,12 @@ from typing import Dict, List, Union, Optional from typing_extensions import Literal, TypeAlias -from .models import Models from ..._models import BaseModel from .audio_transcription import AudioTranscription from .realtime_truncation import RealtimeTruncation from .noise_reduction_type import NoiseReductionType from .realtime_audio_formats import RealtimeAudioFormats +from .realtime_function_tool import RealtimeFunctionTool from ..responses.response_prompt import ResponsePrompt from ..responses.tool_choice_mcp import ToolChoiceMcp from ..responses.tool_choice_options import ToolChoiceOptions @@ -64,7 +64,7 @@ class AudioInputTurnDetection(BaseModel): idle_timeout_ms: Optional[int] = None """ Optional idle timeout after which turn detection will auto-timeout when no - additional audio is received. + additional audio is received and emits a `timeout_triggered` event. """ interrupt_response: Optional[bool] = None @@ -298,7 +298,7 @@ class ToolMcpTool(BaseModel): """ -Tool: TypeAlias = Union[Models, ToolMcpTool] +Tool: TypeAlias = Union[RealtimeFunctionTool, ToolMcpTool] class TracingTracingConfiguration(BaseModel): @@ -325,12 +325,15 @@ class TracingTracingConfiguration(BaseModel): class RealtimeSessionCreateResponse(BaseModel): + client_secret: RealtimeSessionClientSecret + """Ephemeral key returned by the API.""" + + type: Literal["realtime"] + """The type of session to create. Always `realtime` for the Realtime API.""" + audio: Optional[Audio] = None """Configuration for input and output audio.""" - client_secret: Optional[RealtimeSessionClientSecret] = None - """Ephemeral key returned by the API.""" - include: Optional[List[Literal["item.input_audio_transcription.logprobs"]]] = None """Additional fields to include in server outputs. @@ -415,6 +418,3 @@ class RealtimeSessionCreateResponse(BaseModel): Controls how the realtime conversation is truncated prior to model inference. The default is `auto`. """ - - type: Optional[Literal["realtime"]] = None - """The type of session to create. Always `realtime` for the Realtime API.""" diff --git a/src/openai/types/realtime/realtime_tools_config_param.py b/src/openai/types/realtime/realtime_tools_config_param.py index 700b548fe2..630fc74691 100644 --- a/src/openai/types/realtime/realtime_tools_config_param.py +++ b/src/openai/types/realtime/realtime_tools_config_param.py @@ -6,7 +6,7 @@ from typing_extensions import Literal, Required, TypeAlias, TypedDict from ..._types import SequenceNotStr -from .models_param import ModelsParam +from .realtime_function_tool_param import RealtimeFunctionToolParam __all__ = [ "RealtimeToolsConfigParam", @@ -138,6 +138,6 @@ class Mcp(TypedDict, total=False): """ -RealtimeToolsConfigUnionParam: TypeAlias = Union[ModelsParam, Mcp] +RealtimeToolsConfigUnionParam: TypeAlias = Union[RealtimeFunctionToolParam, Mcp] RealtimeToolsConfigParam: TypeAlias = List[RealtimeToolsConfigUnionParam] diff --git a/src/openai/types/realtime/realtime_tools_config_union.py b/src/openai/types/realtime/realtime_tools_config_union.py index 8a064d78d4..e7126ed60d 100644 --- a/src/openai/types/realtime/realtime_tools_config_union.py +++ b/src/openai/types/realtime/realtime_tools_config_union.py @@ -3,9 +3,9 @@ from typing import Dict, List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias -from .models import Models from ..._utils import PropertyInfo from ..._models import BaseModel +from .realtime_function_tool import RealtimeFunctionTool __all__ = [ "RealtimeToolsConfigUnion", @@ -138,4 +138,4 @@ class Mcp(BaseModel): """ -RealtimeToolsConfigUnion: TypeAlias = Annotated[Union[Models, Mcp], PropertyInfo(discriminator="type")] +RealtimeToolsConfigUnion: TypeAlias = Annotated[Union[RealtimeFunctionTool, Mcp], PropertyInfo(discriminator="type")] diff --git a/src/openai/types/realtime/realtime_tools_config_union_param.py b/src/openai/types/realtime/realtime_tools_config_union_param.py index 179ad040d9..9ee58fdbe6 100644 --- a/src/openai/types/realtime/realtime_tools_config_union_param.py +++ b/src/openai/types/realtime/realtime_tools_config_union_param.py @@ -6,7 +6,7 @@ from typing_extensions import Literal, Required, TypeAlias, TypedDict from ..._types import SequenceNotStr -from .models_param import ModelsParam +from .realtime_function_tool_param import RealtimeFunctionToolParam __all__ = [ "RealtimeToolsConfigUnionParam", @@ -137,4 +137,4 @@ class Mcp(TypedDict, total=False): """ -RealtimeToolsConfigUnionParam: TypeAlias = Union[ModelsParam, Mcp] +RealtimeToolsConfigUnionParam: TypeAlias = Union[RealtimeFunctionToolParam, Mcp] diff --git a/src/openai/types/realtime/realtime_transcription_session_client_secret.py b/src/openai/types/realtime/realtime_transcription_session_client_secret.py deleted file mode 100644 index 0cfde4c0a2..0000000000 --- a/src/openai/types/realtime/realtime_transcription_session_client_secret.py +++ /dev/null @@ -1,20 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel - -__all__ = ["RealtimeTranscriptionSessionClientSecret"] - - -class RealtimeTranscriptionSessionClientSecret(BaseModel): - expires_at: int - """Timestamp for when the token expires. - - Currently, all tokens expire after one minute. - """ - - value: str - """ - Ephemeral key usable in client environments to authenticate connections to the - Realtime API. Use this in client-side environments rather than a standard API - token, which should only be used server-side. - """ diff --git a/src/openai/types/realtime/realtime_transcription_session_create_response.py b/src/openai/types/realtime/realtime_transcription_session_create_response.py index a08538aa8f..301af1ac3f 100644 --- a/src/openai/types/realtime/realtime_transcription_session_create_response.py +++ b/src/openai/types/realtime/realtime_transcription_session_create_response.py @@ -4,33 +4,32 @@ from typing_extensions import Literal from ..._models import BaseModel -from .realtime_transcription_session_client_secret import RealtimeTranscriptionSessionClientSecret +from .audio_transcription import AudioTranscription +from .noise_reduction_type import NoiseReductionType +from .realtime_audio_formats import RealtimeAudioFormats from .realtime_transcription_session_turn_detection import RealtimeTranscriptionSessionTurnDetection -from .realtime_transcription_session_input_audio_transcription import ( - RealtimeTranscriptionSessionInputAudioTranscription, -) -__all__ = ["RealtimeTranscriptionSessionCreateResponse"] +__all__ = ["RealtimeTranscriptionSessionCreateResponse", "Audio", "AudioInput", "AudioInputNoiseReduction"] -class RealtimeTranscriptionSessionCreateResponse(BaseModel): - client_secret: RealtimeTranscriptionSessionClientSecret - """Ephemeral key returned by the API. +class AudioInputNoiseReduction(BaseModel): + type: Optional[NoiseReductionType] = None + """Type of noise reduction. - Only present when the session is created on the server via REST API. + `near_field` is for close-talking microphones such as headphones, `far_field` is + for far-field microphones such as laptop or conference room microphones. """ - input_audio_format: Optional[str] = None - """The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" - input_audio_transcription: Optional[RealtimeTranscriptionSessionInputAudioTranscription] = None - """Configuration of the transcription model.""" +class AudioInput(BaseModel): + format: Optional[RealtimeAudioFormats] = None + """The PCM audio format. Only a 24kHz sample rate is supported.""" - modalities: Optional[List[Literal["text", "audio"]]] = None - """The set of modalities the model can respond with. + noise_reduction: Optional[AudioInputNoiseReduction] = None + """Configuration for input audio noise reduction.""" - To disable audio, set this to ["text"]. - """ + transcription: Optional[AudioTranscription] = None + """Configuration of the transcription model.""" turn_detection: Optional[RealtimeTranscriptionSessionTurnDetection] = None """Configuration for turn detection. @@ -39,3 +38,31 @@ class RealtimeTranscriptionSessionCreateResponse(BaseModel): the start and end of speech based on audio volume and respond at the end of user speech. """ + + +class Audio(BaseModel): + input: Optional[AudioInput] = None + + +class RealtimeTranscriptionSessionCreateResponse(BaseModel): + id: str + """Unique identifier for the session that looks like `sess_1234567890abcdef`.""" + + object: str + """The object type. Always `realtime.transcription_session`.""" + + type: Literal["transcription"] + """The type of session. Always `transcription` for transcription sessions.""" + + audio: Optional[Audio] = None + """Configuration for input audio for the session.""" + + expires_at: Optional[int] = None + """Expiration timestamp for the session, in seconds since epoch.""" + + include: Optional[List[Literal["item.input_audio_transcription.logprobs"]]] = None + """Additional fields to include in server outputs. + + - `item.input_audio_transcription.logprobs`: Include logprobs for input audio + transcription. + """ diff --git a/src/openai/types/realtime/realtime_transcription_session_input_audio_transcription.py b/src/openai/types/realtime/realtime_transcription_session_input_audio_transcription.py deleted file mode 100644 index 52254bed33..0000000000 --- a/src/openai/types/realtime/realtime_transcription_session_input_audio_transcription.py +++ /dev/null @@ -1,36 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["RealtimeTranscriptionSessionInputAudioTranscription"] - - -class RealtimeTranscriptionSessionInputAudioTranscription(BaseModel): - language: Optional[str] = None - """The language of the input audio. - - Supplying the input language in - [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) - format will improve accuracy and latency. - """ - - model: Optional[Literal["whisper-1", "gpt-4o-transcribe-latest", "gpt-4o-mini-transcribe", "gpt-4o-transcribe"]] = ( - None - ) - """The model to use for transcription. - - Current options are `whisper-1`, `gpt-4o-transcribe-latest`, - `gpt-4o-mini-transcribe`, and `gpt-4o-transcribe`. - """ - - prompt: Optional[str] = None - """ - An optional text to guide the model's style or continue a previous audio - segment. For `whisper-1`, the - [prompt is a list of keywords](https://platform.openai.com/docs/guides/speech-to-text#prompting). - For `gpt-4o-transcribe` models, the prompt is a free text string, for example - "expect words related to technology". - """ diff --git a/src/openai/types/realtime/transcription_session_created.py b/src/openai/types/realtime/transcription_session_created.py deleted file mode 100644 index c358c5e8b0..0000000000 --- a/src/openai/types/realtime/transcription_session_created.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel -from .realtime_transcription_session_create_response import RealtimeTranscriptionSessionCreateResponse - -__all__ = ["TranscriptionSessionCreated"] - - -class TranscriptionSessionCreated(BaseModel): - event_id: str - """The unique ID of the server event.""" - - session: RealtimeTranscriptionSessionCreateResponse - """A new Realtime transcription session configuration. - - When a session is created on the server via REST API, the session object also - contains an ephemeral key. Default TTL for keys is 10 minutes. This property is - not present when a session is updated via the WebSocket API. - """ - - type: Literal["transcription_session.created"] - """The event type, must be `transcription_session.created`.""" diff --git a/src/openai/types/realtime/transcription_session_update.py b/src/openai/types/realtime/transcription_session_update.py deleted file mode 100644 index 0faff9cb57..0000000000 --- a/src/openai/types/realtime/transcription_session_update.py +++ /dev/null @@ -1,98 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ..._models import BaseModel -from .audio_transcription import AudioTranscription -from .noise_reduction_type import NoiseReductionType - -__all__ = ["TranscriptionSessionUpdate", "Session", "SessionInputAudioNoiseReduction", "SessionTurnDetection"] - - -class SessionInputAudioNoiseReduction(BaseModel): - type: Optional[NoiseReductionType] = None - """Type of noise reduction. - - `near_field` is for close-talking microphones such as headphones, `far_field` is - for far-field microphones such as laptop or conference room microphones. - """ - - -class SessionTurnDetection(BaseModel): - prefix_padding_ms: Optional[int] = None - """Amount of audio to include before the VAD detected speech (in milliseconds). - - Defaults to 300ms. - """ - - silence_duration_ms: Optional[int] = None - """Duration of silence to detect speech stop (in milliseconds). - - Defaults to 500ms. With shorter values the model will respond more quickly, but - may jump in on short pauses from the user. - """ - - threshold: Optional[float] = None - """Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. - - A higher threshold will require louder audio to activate the model, and thus - might perform better in noisy environments. - """ - - type: Optional[Literal["server_vad"]] = None - """Type of turn detection. - - Only `server_vad` is currently supported for transcription sessions. - """ - - -class Session(BaseModel): - include: Optional[List[Literal["item.input_audio_transcription.logprobs"]]] = None - """The set of items to include in the transcription. - - Current available items are: `item.input_audio_transcription.logprobs` - """ - - input_audio_format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None - """The format of input audio. - - Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, input audio must - be 16-bit PCM at a 24kHz sample rate, single channel (mono), and little-endian - byte order. - """ - - input_audio_noise_reduction: Optional[SessionInputAudioNoiseReduction] = None - """Configuration for input audio noise reduction. - - This can be set to `null` to turn off. Noise reduction filters audio added to - the input audio buffer before it is sent to VAD and the model. Filtering the - audio can improve VAD and turn detection accuracy (reducing false positives) and - model performance by improving perception of the input audio. - """ - - input_audio_transcription: Optional[AudioTranscription] = None - """Configuration for input audio transcription. - - The client can optionally set the language and prompt for transcription, these - offer additional guidance to the transcription service. - """ - - turn_detection: Optional[SessionTurnDetection] = None - """Configuration for turn detection. - - Can be set to `null` to turn off. Server VAD means that the model will detect - the start and end of speech based on audio volume and respond at the end of user - speech. - """ - - -class TranscriptionSessionUpdate(BaseModel): - session: Session - """Realtime transcription session object configuration.""" - - type: Literal["transcription_session.update"] - """The event type, must be `transcription_session.update`.""" - - event_id: Optional[str] = None - """Optional client-generated ID used to identify this event.""" diff --git a/src/openai/types/realtime/transcription_session_update_param.py b/src/openai/types/realtime/transcription_session_update_param.py deleted file mode 100644 index 55c67798b6..0000000000 --- a/src/openai/types/realtime/transcription_session_update_param.py +++ /dev/null @@ -1,99 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List -from typing_extensions import Literal, Required, TypedDict - -from .noise_reduction_type import NoiseReductionType -from .audio_transcription_param import AudioTranscriptionParam - -__all__ = ["TranscriptionSessionUpdateParam", "Session", "SessionInputAudioNoiseReduction", "SessionTurnDetection"] - - -class SessionInputAudioNoiseReduction(TypedDict, total=False): - type: NoiseReductionType - """Type of noise reduction. - - `near_field` is for close-talking microphones such as headphones, `far_field` is - for far-field microphones such as laptop or conference room microphones. - """ - - -class SessionTurnDetection(TypedDict, total=False): - prefix_padding_ms: int - """Amount of audio to include before the VAD detected speech (in milliseconds). - - Defaults to 300ms. - """ - - silence_duration_ms: int - """Duration of silence to detect speech stop (in milliseconds). - - Defaults to 500ms. With shorter values the model will respond more quickly, but - may jump in on short pauses from the user. - """ - - threshold: float - """Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. - - A higher threshold will require louder audio to activate the model, and thus - might perform better in noisy environments. - """ - - type: Literal["server_vad"] - """Type of turn detection. - - Only `server_vad` is currently supported for transcription sessions. - """ - - -class Session(TypedDict, total=False): - include: List[Literal["item.input_audio_transcription.logprobs"]] - """The set of items to include in the transcription. - - Current available items are: `item.input_audio_transcription.logprobs` - """ - - input_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] - """The format of input audio. - - Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, input audio must - be 16-bit PCM at a 24kHz sample rate, single channel (mono), and little-endian - byte order. - """ - - input_audio_noise_reduction: SessionInputAudioNoiseReduction - """Configuration for input audio noise reduction. - - This can be set to `null` to turn off. Noise reduction filters audio added to - the input audio buffer before it is sent to VAD and the model. Filtering the - audio can improve VAD and turn detection accuracy (reducing false positives) and - model performance by improving perception of the input audio. - """ - - input_audio_transcription: AudioTranscriptionParam - """Configuration for input audio transcription. - - The client can optionally set the language and prompt for transcription, these - offer additional guidance to the transcription service. - """ - - turn_detection: SessionTurnDetection - """Configuration for turn detection. - - Can be set to `null` to turn off. Server VAD means that the model will detect - the start and end of speech based on audio volume and respond at the end of user - speech. - """ - - -class TranscriptionSessionUpdateParam(TypedDict, total=False): - session: Required[Session] - """Realtime transcription session object configuration.""" - - type: Required[Literal["transcription_session.update"]] - """The event type, must be `transcription_session.update`.""" - - event_id: str - """Optional client-generated ID used to identify this event.""" diff --git a/src/openai/types/realtime/transcription_session_updated_event.py b/src/openai/types/realtime/transcription_session_updated_event.py deleted file mode 100644 index f6a52a12f3..0000000000 --- a/src/openai/types/realtime/transcription_session_updated_event.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel -from .realtime_transcription_session_create_response import RealtimeTranscriptionSessionCreateResponse - -__all__ = ["TranscriptionSessionUpdatedEvent"] - - -class TranscriptionSessionUpdatedEvent(BaseModel): - event_id: str - """The unique ID of the server event.""" - - session: RealtimeTranscriptionSessionCreateResponse - """A new Realtime transcription session configuration. - - When a session is created on the server via REST API, the session object also - contains an ephemeral key. Default TTL for keys is 10 minutes. This property is - not present when a session is updated via the WebSocket API. - """ - - type: Literal["transcription_session.updated"] - """The event type, must be `transcription_session.updated`.""" From 4756247cee3d9548397b26a29109e76cc9522379 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 12 Sep 2025 15:51:27 -0400 Subject: [PATCH 490/769] release: 1.107.2 (#2624) * chore(api): Minor docs and type updates for realtime * codegen metadata * chore(tests): simplify `get_platform` test `nest_asyncio` is archived and broken on some platforms so it's not worth keeping in our test suite. * release: 1.107.2 --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- .stats.yml | 4 +- CHANGELOG.md | 9 +++ pyproject.toml | 2 +- requirements-dev.lock | 3 +- src/openai/_version.py | 2 +- src/openai/resources/responses/responses.py | 48 ++++++------ .../input_audio_buffer_timeout_triggered.py | 10 ++- .../realtime/realtime_audio_config_input.py | 7 +- .../realtime_audio_config_input_param.py | 10 ++- .../realtime_audio_input_turn_detection.py | 68 ++++++++++++----- ...altime_audio_input_turn_detection_param.py | 65 +++++++++++----- .../realtime_session_create_response.py | 74 ++++++++++++++----- ...ltime_transcription_session_audio_input.py | 7 +- ...transcription_session_audio_input_param.py | 10 ++- ...tion_session_audio_input_turn_detection.py | 67 +++++++++++++---- ...ession_audio_input_turn_detection_param.py | 64 ++++++++++++---- src/openai/types/responses/response.py | 8 +- .../types/responses/response_create_params.py | 8 +- .../realtime/test_client_secrets.py | 10 +-- tests/test_client.py | 53 ++----------- 21 files changed, 344 insertions(+), 187 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 25880b2e7b..32e0d8892c 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.107.1" + ".": "1.107.2" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 2aa16be875..e389718967 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 118 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-16cb18bed32bae8c5840fb39a1bf664026cc40463ad0c487dcb0df1bd3d72db0.yml -openapi_spec_hash: 4cb51b22f98dee1a90bc7add82d1d132 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-94b1e3cb0bdc616ff0c2f267c33dadd95f133b1f64e647aab6c64afb292b2793.yml +openapi_spec_hash: 2395319ac9befd59b6536ae7f9564a05 config_hash: 930dac3aa861344867e4ac84f037b5df diff --git a/CHANGELOG.md b/CHANGELOG.md index 19eab7da7e..31ccac5195 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 1.107.2 (2025-09-12) + +Full Changelog: [v1.107.1...v1.107.2](https://github.com/openai/openai-python/compare/v1.107.1...v1.107.2) + +### Chores + +* **api:** Minor docs and type updates for realtime ([ab6a10d](https://github.com/openai/openai-python/commit/ab6a10da4ed7e6386695b6f5f29149d4870f85c9)) +* **tests:** simplify `get_platform` test ([01f03e0](https://github.com/openai/openai-python/commit/01f03e0ad1f9ab3f2ed8b7c13d652263c6d06378)) + ## 1.107.1 (2025-09-10) Full Changelog: [v1.107.0...v1.107.1](https://github.com/openai/openai-python/compare/v1.107.0...v1.107.1) diff --git a/pyproject.toml b/pyproject.toml index 326dc5a004..7cb1ef4f76 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.107.1" +version = "1.107.2" description = "The official Python library for the openai API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/requirements-dev.lock b/requirements-dev.lock index 7d690683e9..eaf136f7e6 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -70,7 +70,7 @@ filelock==3.12.4 frozenlist==1.7.0 # via aiohttp # via aiosignal -griffe==1.14.0 +griffe==1.13.0 h11==0.16.0 # via httpcore httpcore==1.0.9 @@ -108,7 +108,6 @@ multidict==6.5.0 mypy==1.14.1 mypy-extensions==1.0.0 # via mypy -nest-asyncio==1.6.0 nodeenv==1.8.0 # via pyright nox==2023.4.22 diff --git a/src/openai/_version.py b/src/openai/_version.py index f337b21cd5..70f9958885 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.107.1" # x-release-please-version +__version__ = "1.107.2" # x-release-please-version diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 837d2b2211..8acdb10b51 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -288,10 +288,10 @@ def create( truncation: The truncation strategy to use for the model response. - - `auto`: If the context of this response and previous ones exceeds the model's - context window size, the model will truncate the response to fit the context - window by dropping input items in the middle of the conversation. - - `disabled` (default): If a model response will exceed the context window size + - `auto`: If the input to this Response exceeds the model's context window size, + the model will truncate the response to fit the context window by dropping + items from the beginning of the conversation. + - `disabled` (default): If the input size will exceed the context window size for a model, the request will fail with a 400 error. user: This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use @@ -527,10 +527,10 @@ def create( truncation: The truncation strategy to use for the model response. - - `auto`: If the context of this response and previous ones exceeds the model's - context window size, the model will truncate the response to fit the context - window by dropping input items in the middle of the conversation. - - `disabled` (default): If a model response will exceed the context window size + - `auto`: If the input to this Response exceeds the model's context window size, + the model will truncate the response to fit the context window by dropping + items from the beginning of the conversation. + - `disabled` (default): If the input size will exceed the context window size for a model, the request will fail with a 400 error. user: This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use @@ -766,10 +766,10 @@ def create( truncation: The truncation strategy to use for the model response. - - `auto`: If the context of this response and previous ones exceeds the model's - context window size, the model will truncate the response to fit the context - window by dropping input items in the middle of the conversation. - - `disabled` (default): If a model response will exceed the context window size + - `auto`: If the input to this Response exceeds the model's context window size, + the model will truncate the response to fit the context window by dropping + items from the beginning of the conversation. + - `disabled` (default): If the input size will exceed the context window size for a model, the request will fail with a 400 error. user: This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use @@ -1719,10 +1719,10 @@ async def create( truncation: The truncation strategy to use for the model response. - - `auto`: If the context of this response and previous ones exceeds the model's - context window size, the model will truncate the response to fit the context - window by dropping input items in the middle of the conversation. - - `disabled` (default): If a model response will exceed the context window size + - `auto`: If the input to this Response exceeds the model's context window size, + the model will truncate the response to fit the context window by dropping + items from the beginning of the conversation. + - `disabled` (default): If the input size will exceed the context window size for a model, the request will fail with a 400 error. user: This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use @@ -1958,10 +1958,10 @@ async def create( truncation: The truncation strategy to use for the model response. - - `auto`: If the context of this response and previous ones exceeds the model's - context window size, the model will truncate the response to fit the context - window by dropping input items in the middle of the conversation. - - `disabled` (default): If a model response will exceed the context window size + - `auto`: If the input to this Response exceeds the model's context window size, + the model will truncate the response to fit the context window by dropping + items from the beginning of the conversation. + - `disabled` (default): If the input size will exceed the context window size for a model, the request will fail with a 400 error. user: This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use @@ -2197,10 +2197,10 @@ async def create( truncation: The truncation strategy to use for the model response. - - `auto`: If the context of this response and previous ones exceeds the model's - context window size, the model will truncate the response to fit the context - window by dropping input items in the middle of the conversation. - - `disabled` (default): If a model response will exceed the context window size + - `auto`: If the input to this Response exceeds the model's context window size, + the model will truncate the response to fit the context window by dropping + items from the beginning of the conversation. + - `disabled` (default): If the input size will exceed the context window size for a model, the request will fail with a 400 error. user: This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use diff --git a/src/openai/types/realtime/input_audio_buffer_timeout_triggered.py b/src/openai/types/realtime/input_audio_buffer_timeout_triggered.py index ed592ac06b..5c5dc5cfa6 100644 --- a/src/openai/types/realtime/input_audio_buffer_timeout_triggered.py +++ b/src/openai/types/realtime/input_audio_buffer_timeout_triggered.py @@ -9,10 +9,16 @@ class InputAudioBufferTimeoutTriggered(BaseModel): audio_end_ms: int - """Millisecond offset where speech ended within the buffered audio.""" + """ + Millisecond offset of audio written to the input audio buffer at the time the + timeout was triggered. + """ audio_start_ms: int - """Millisecond offset where speech started within the buffered audio.""" + """ + Millisecond offset of audio written to the input audio buffer that was after the + playback time of the last model response. + """ event_id: str """The unique ID of the server event.""" diff --git a/src/openai/types/realtime/realtime_audio_config_input.py b/src/openai/types/realtime/realtime_audio_config_input.py index fd96e2a52d..cfcb7f22d4 100644 --- a/src/openai/types/realtime/realtime_audio_config_input.py +++ b/src/openai/types/realtime/realtime_audio_config_input.py @@ -49,8 +49,11 @@ class RealtimeAudioConfigInput(BaseModel): """Configuration for turn detection, ether Server VAD or Semantic VAD. This can be set to `null` to turn off, in which case the client must manually - trigger model response. Server VAD means that the model will detect the start - and end of speech based on audio volume and respond at the end of user speech. + trigger model response. + + Server VAD means that the model will detect the start and end of speech based on + audio volume and respond at the end of user speech. + Semantic VAD is more advanced and uses a turn detection model (in conjunction with VAD) to semantically estimate whether the user has finished speaking, then dynamically sets a timeout based on this probability. For example, if user audio diff --git a/src/openai/types/realtime/realtime_audio_config_input_param.py b/src/openai/types/realtime/realtime_audio_config_input_param.py index 1dfb439006..730f46cfec 100644 --- a/src/openai/types/realtime/realtime_audio_config_input_param.py +++ b/src/openai/types/realtime/realtime_audio_config_input_param.py @@ -2,6 +2,7 @@ from __future__ import annotations +from typing import Optional from typing_extensions import TypedDict from .noise_reduction_type import NoiseReductionType @@ -46,12 +47,15 @@ class RealtimeAudioConfigInputParam(TypedDict, total=False): transcription, these offer additional guidance to the transcription service. """ - turn_detection: RealtimeAudioInputTurnDetectionParam + turn_detection: Optional[RealtimeAudioInputTurnDetectionParam] """Configuration for turn detection, ether Server VAD or Semantic VAD. This can be set to `null` to turn off, in which case the client must manually - trigger model response. Server VAD means that the model will detect the start - and end of speech based on audio volume and respond at the end of user speech. + trigger model response. + + Server VAD means that the model will detect the start and end of speech based on + audio volume and respond at the end of user speech. + Semantic VAD is more advanced and uses a turn detection model (in conjunction with VAD) to semantically estimate whether the user has finished speaking, then dynamically sets a timeout based on this probability. For example, if user audio diff --git a/src/openai/types/realtime/realtime_audio_input_turn_detection.py b/src/openai/types/realtime/realtime_audio_input_turn_detection.py index 1c736ab2b7..d3f4e00316 100644 --- a/src/openai/types/realtime/realtime_audio_input_turn_detection.py +++ b/src/openai/types/realtime/realtime_audio_input_turn_detection.py @@ -1,33 +1,38 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional -from typing_extensions import Literal +from typing import Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias +from ..._utils import PropertyInfo from ..._models import BaseModel -__all__ = ["RealtimeAudioInputTurnDetection"] +__all__ = ["RealtimeAudioInputTurnDetection", "ServerVad", "SemanticVad"] -class RealtimeAudioInputTurnDetection(BaseModel): +class ServerVad(BaseModel): + type: Literal["server_vad"] + """Type of turn detection, `server_vad` to turn on simple Server VAD.""" + create_response: Optional[bool] = None """ Whether or not to automatically generate a response when a VAD stop event occurs. """ - eagerness: Optional[Literal["low", "medium", "high", "auto"]] = None - """Used only for `semantic_vad` mode. + idle_timeout_ms: Optional[int] = None + """Optional timeout after which a model response will be triggered automatically. - The eagerness of the model to respond. `low` will wait longer for the user to - continue speaking, `high` will respond more quickly. `auto` is the default and - is equivalent to `medium`. `low`, `medium`, and `high` have max timeouts of 8s, - 4s, and 2s respectively. - """ + This is useful for situations in which a long pause from the user is unexpected, + such as a phone call. The model will effectively prompt the user to continue the + conversation based on the current context. - idle_timeout_ms: Optional[int] = None - """ - Optional idle timeout after which turn detection will auto-timeout when no - additional audio is received and emits a `timeout_triggered` event. + The timeout value will be applied after the last model response's audio has + finished playing, i.e. it's set to the `response.done` time plus audio playback + duration. + + An `input_audio_buffer.timeout_triggered` event (plus events associated with the + Response) will be emitted when the timeout is reached. Idle timeout is currently + only supported for `server_vad` mode. """ interrupt_response: Optional[bool] = None @@ -60,5 +65,34 @@ class RealtimeAudioInputTurnDetection(BaseModel): perform better in noisy environments. """ - type: Optional[Literal["server_vad", "semantic_vad"]] = None - """Type of turn detection.""" + +class SemanticVad(BaseModel): + type: Literal["semantic_vad"] + """Type of turn detection, `semantic_vad` to turn on Semantic VAD.""" + + create_response: Optional[bool] = None + """ + Whether or not to automatically generate a response when a VAD stop event + occurs. + """ + + eagerness: Optional[Literal["low", "medium", "high", "auto"]] = None + """Used only for `semantic_vad` mode. + + The eagerness of the model to respond. `low` will wait longer for the user to + continue speaking, `high` will respond more quickly. `auto` is the default and + is equivalent to `medium`. `low`, `medium`, and `high` have max timeouts of 8s, + 4s, and 2s respectively. + """ + + interrupt_response: Optional[bool] = None + """ + Whether or not to automatically interrupt any ongoing response with output to + the default conversation (i.e. `conversation` of `auto`) when a VAD start event + occurs. + """ + + +RealtimeAudioInputTurnDetection: TypeAlias = Annotated[ + Union[ServerVad, SemanticVad, None], PropertyInfo(discriminator="type") +] diff --git a/src/openai/types/realtime/realtime_audio_input_turn_detection_param.py b/src/openai/types/realtime/realtime_audio_input_turn_detection_param.py index 79cabec708..09b8cfd159 100644 --- a/src/openai/types/realtime/realtime_audio_input_turn_detection_param.py +++ b/src/openai/types/realtime/realtime_audio_input_turn_detection_param.py @@ -2,32 +2,36 @@ from __future__ import annotations -from typing import Optional -from typing_extensions import Literal, TypedDict +from typing import Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict -__all__ = ["RealtimeAudioInputTurnDetectionParam"] +__all__ = ["RealtimeAudioInputTurnDetectionParam", "ServerVad", "SemanticVad"] -class RealtimeAudioInputTurnDetectionParam(TypedDict, total=False): +class ServerVad(TypedDict, total=False): + type: Required[Literal["server_vad"]] + """Type of turn detection, `server_vad` to turn on simple Server VAD.""" + create_response: bool """ Whether or not to automatically generate a response when a VAD stop event occurs. """ - eagerness: Literal["low", "medium", "high", "auto"] - """Used only for `semantic_vad` mode. + idle_timeout_ms: Optional[int] + """Optional timeout after which a model response will be triggered automatically. - The eagerness of the model to respond. `low` will wait longer for the user to - continue speaking, `high` will respond more quickly. `auto` is the default and - is equivalent to `medium`. `low`, `medium`, and `high` have max timeouts of 8s, - 4s, and 2s respectively. - """ + This is useful for situations in which a long pause from the user is unexpected, + such as a phone call. The model will effectively prompt the user to continue the + conversation based on the current context. - idle_timeout_ms: Optional[int] - """ - Optional idle timeout after which turn detection will auto-timeout when no - additional audio is received and emits a `timeout_triggered` event. + The timeout value will be applied after the last model response's audio has + finished playing, i.e. it's set to the `response.done` time plus audio playback + duration. + + An `input_audio_buffer.timeout_triggered` event (plus events associated with the + Response) will be emitted when the timeout is reached. Idle timeout is currently + only supported for `server_vad` mode. """ interrupt_response: bool @@ -60,5 +64,32 @@ class RealtimeAudioInputTurnDetectionParam(TypedDict, total=False): perform better in noisy environments. """ - type: Literal["server_vad", "semantic_vad"] - """Type of turn detection.""" + +class SemanticVad(TypedDict, total=False): + type: Required[Literal["semantic_vad"]] + """Type of turn detection, `semantic_vad` to turn on Semantic VAD.""" + + create_response: bool + """ + Whether or not to automatically generate a response when a VAD stop event + occurs. + """ + + eagerness: Literal["low", "medium", "high", "auto"] + """Used only for `semantic_vad` mode. + + The eagerness of the model to respond. `low` will wait longer for the user to + continue speaking, `high` will respond more quickly. `auto` is the default and + is equivalent to `medium`. `low`, `medium`, and `high` have max timeouts of 8s, + 4s, and 2s respectively. + """ + + interrupt_response: bool + """ + Whether or not to automatically interrupt any ongoing response with output to + the default conversation (i.e. `conversation` of `auto`) when a VAD start event + occurs. + """ + + +RealtimeAudioInputTurnDetectionParam: TypeAlias = Union[ServerVad, SemanticVad] diff --git a/src/openai/types/realtime/realtime_session_create_response.py b/src/openai/types/realtime/realtime_session_create_response.py index 7779f07a6e..8d7bfd6d8e 100644 --- a/src/openai/types/realtime/realtime_session_create_response.py +++ b/src/openai/types/realtime/realtime_session_create_response.py @@ -1,8 +1,9 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from typing import Dict, List, Union, Optional -from typing_extensions import Literal, TypeAlias +from typing_extensions import Literal, Annotated, TypeAlias +from ..._utils import PropertyInfo from ..._models import BaseModel from .audio_transcription import AudioTranscription from .realtime_truncation import RealtimeTruncation @@ -21,6 +22,8 @@ "AudioInput", "AudioInputNoiseReduction", "AudioInputTurnDetection", + "AudioInputTurnDetectionServerVad", + "AudioInputTurnDetectionSemanticVad", "AudioOutput", "ToolChoice", "Tool", @@ -45,26 +48,30 @@ class AudioInputNoiseReduction(BaseModel): """ -class AudioInputTurnDetection(BaseModel): +class AudioInputTurnDetectionServerVad(BaseModel): + type: Literal["server_vad"] + """Type of turn detection, `server_vad` to turn on simple Server VAD.""" + create_response: Optional[bool] = None """ Whether or not to automatically generate a response when a VAD stop event occurs. """ - eagerness: Optional[Literal["low", "medium", "high", "auto"]] = None - """Used only for `semantic_vad` mode. + idle_timeout_ms: Optional[int] = None + """Optional timeout after which a model response will be triggered automatically. - The eagerness of the model to respond. `low` will wait longer for the user to - continue speaking, `high` will respond more quickly. `auto` is the default and - is equivalent to `medium`. `low`, `medium`, and `high` have max timeouts of 8s, - 4s, and 2s respectively. - """ + This is useful for situations in which a long pause from the user is unexpected, + such as a phone call. The model will effectively prompt the user to continue the + conversation based on the current context. - idle_timeout_ms: Optional[int] = None - """ - Optional idle timeout after which turn detection will auto-timeout when no - additional audio is received and emits a `timeout_triggered` event. + The timeout value will be applied after the last model response's audio has + finished playing, i.e. it's set to the `response.done` time plus audio playback + duration. + + An `input_audio_buffer.timeout_triggered` event (plus events associated with the + Response) will be emitted when the timeout is reached. Idle timeout is currently + only supported for `server_vad` mode. """ interrupt_response: Optional[bool] = None @@ -97,8 +104,38 @@ class AudioInputTurnDetection(BaseModel): perform better in noisy environments. """ - type: Optional[Literal["server_vad", "semantic_vad"]] = None - """Type of turn detection.""" + +class AudioInputTurnDetectionSemanticVad(BaseModel): + type: Literal["semantic_vad"] + """Type of turn detection, `semantic_vad` to turn on Semantic VAD.""" + + create_response: Optional[bool] = None + """ + Whether or not to automatically generate a response when a VAD stop event + occurs. + """ + + eagerness: Optional[Literal["low", "medium", "high", "auto"]] = None + """Used only for `semantic_vad` mode. + + The eagerness of the model to respond. `low` will wait longer for the user to + continue speaking, `high` will respond more quickly. `auto` is the default and + is equivalent to `medium`. `low`, `medium`, and `high` have max timeouts of 8s, + 4s, and 2s respectively. + """ + + interrupt_response: Optional[bool] = None + """ + Whether or not to automatically interrupt any ongoing response with output to + the default conversation (i.e. `conversation` of `auto`) when a VAD start event + occurs. + """ + + +AudioInputTurnDetection: TypeAlias = Annotated[ + Union[AudioInputTurnDetectionServerVad, AudioInputTurnDetectionSemanticVad, None], + PropertyInfo(discriminator="type"), +] class AudioInput(BaseModel): @@ -130,8 +167,11 @@ class AudioInput(BaseModel): """Configuration for turn detection, ether Server VAD or Semantic VAD. This can be set to `null` to turn off, in which case the client must manually - trigger model response. Server VAD means that the model will detect the start - and end of speech based on audio volume and respond at the end of user speech. + trigger model response. + + Server VAD means that the model will detect the start and end of speech based on + audio volume and respond at the end of user speech. + Semantic VAD is more advanced and uses a turn detection model (in conjunction with VAD) to semantically estimate whether the user has finished speaking, then dynamically sets a timeout based on this probability. For example, if user audio diff --git a/src/openai/types/realtime/realtime_transcription_session_audio_input.py b/src/openai/types/realtime/realtime_transcription_session_audio_input.py index 0ae92959aa..efc321cbeb 100644 --- a/src/openai/types/realtime/realtime_transcription_session_audio_input.py +++ b/src/openai/types/realtime/realtime_transcription_session_audio_input.py @@ -51,8 +51,11 @@ class RealtimeTranscriptionSessionAudioInput(BaseModel): """Configuration for turn detection, ether Server VAD or Semantic VAD. This can be set to `null` to turn off, in which case the client must manually - trigger model response. Server VAD means that the model will detect the start - and end of speech based on audio volume and respond at the end of user speech. + trigger model response. + + Server VAD means that the model will detect the start and end of speech based on + audio volume and respond at the end of user speech. + Semantic VAD is more advanced and uses a turn detection model (in conjunction with VAD) to semantically estimate whether the user has finished speaking, then dynamically sets a timeout based on this probability. For example, if user audio diff --git a/src/openai/types/realtime/realtime_transcription_session_audio_input_param.py b/src/openai/types/realtime/realtime_transcription_session_audio_input_param.py index a8263789dc..c9153b68a4 100644 --- a/src/openai/types/realtime/realtime_transcription_session_audio_input_param.py +++ b/src/openai/types/realtime/realtime_transcription_session_audio_input_param.py @@ -2,6 +2,7 @@ from __future__ import annotations +from typing import Optional from typing_extensions import TypedDict from .noise_reduction_type import NoiseReductionType @@ -48,12 +49,15 @@ class RealtimeTranscriptionSessionAudioInputParam(TypedDict, total=False): transcription, these offer additional guidance to the transcription service. """ - turn_detection: RealtimeTranscriptionSessionAudioInputTurnDetectionParam + turn_detection: Optional[RealtimeTranscriptionSessionAudioInputTurnDetectionParam] """Configuration for turn detection, ether Server VAD or Semantic VAD. This can be set to `null` to turn off, in which case the client must manually - trigger model response. Server VAD means that the model will detect the start - and end of speech based on audio volume and respond at the end of user speech. + trigger model response. + + Server VAD means that the model will detect the start and end of speech based on + audio volume and respond at the end of user speech. + Semantic VAD is more advanced and uses a turn detection model (in conjunction with VAD) to semantically estimate whether the user has finished speaking, then dynamically sets a timeout based on this probability. For example, if user audio diff --git a/src/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection.py b/src/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection.py index 0cac36f7a3..7dc7a8f302 100644 --- a/src/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection.py +++ b/src/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection.py @@ -1,32 +1,38 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional -from typing_extensions import Literal +from typing import Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias +from ..._utils import PropertyInfo from ..._models import BaseModel -__all__ = ["RealtimeTranscriptionSessionAudioInputTurnDetection"] +__all__ = ["RealtimeTranscriptionSessionAudioInputTurnDetection", "ServerVad", "SemanticVad"] -class RealtimeTranscriptionSessionAudioInputTurnDetection(BaseModel): +class ServerVad(BaseModel): + type: Literal["server_vad"] + """Type of turn detection, `server_vad` to turn on simple Server VAD.""" + create_response: Optional[bool] = None """ Whether or not to automatically generate a response when a VAD stop event occurs. """ - eagerness: Optional[Literal["low", "medium", "high", "auto"]] = None - """Used only for `semantic_vad` mode. + idle_timeout_ms: Optional[int] = None + """Optional timeout after which a model response will be triggered automatically. - The eagerness of the model to respond. `low` will wait longer for the user to - continue speaking, `high` will respond more quickly. `auto` is the default and - is equivalent to `medium`. - """ + This is useful for situations in which a long pause from the user is unexpected, + such as a phone call. The model will effectively prompt the user to continue the + conversation based on the current context. - idle_timeout_ms: Optional[int] = None - """ - Optional idle timeout after which turn detection will auto-timeout when no - additional audio is received. + The timeout value will be applied after the last model response's audio has + finished playing, i.e. it's set to the `response.done` time plus audio playback + duration. + + An `input_audio_buffer.timeout_triggered` event (plus events associated with the + Response) will be emitted when the timeout is reached. Idle timeout is currently + only supported for `server_vad` mode. """ interrupt_response: Optional[bool] = None @@ -59,5 +65,34 @@ class RealtimeTranscriptionSessionAudioInputTurnDetection(BaseModel): perform better in noisy environments. """ - type: Optional[Literal["server_vad", "semantic_vad"]] = None - """Type of turn detection.""" + +class SemanticVad(BaseModel): + type: Literal["semantic_vad"] + """Type of turn detection, `semantic_vad` to turn on Semantic VAD.""" + + create_response: Optional[bool] = None + """ + Whether or not to automatically generate a response when a VAD stop event + occurs. + """ + + eagerness: Optional[Literal["low", "medium", "high", "auto"]] = None + """Used only for `semantic_vad` mode. + + The eagerness of the model to respond. `low` will wait longer for the user to + continue speaking, `high` will respond more quickly. `auto` is the default and + is equivalent to `medium`. `low`, `medium`, and `high` have max timeouts of 8s, + 4s, and 2s respectively. + """ + + interrupt_response: Optional[bool] = None + """ + Whether or not to automatically interrupt any ongoing response with output to + the default conversation (i.e. `conversation` of `auto`) when a VAD start event + occurs. + """ + + +RealtimeTranscriptionSessionAudioInputTurnDetection: TypeAlias = Annotated[ + Union[ServerVad, SemanticVad, None], PropertyInfo(discriminator="type") +] diff --git a/src/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection_param.py b/src/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection_param.py index e76dc9a8fe..d899b8c5c1 100644 --- a/src/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection_param.py +++ b/src/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection_param.py @@ -2,31 +2,36 @@ from __future__ import annotations -from typing import Optional -from typing_extensions import Literal, TypedDict +from typing import Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict -__all__ = ["RealtimeTranscriptionSessionAudioInputTurnDetectionParam"] +__all__ = ["RealtimeTranscriptionSessionAudioInputTurnDetectionParam", "ServerVad", "SemanticVad"] -class RealtimeTranscriptionSessionAudioInputTurnDetectionParam(TypedDict, total=False): +class ServerVad(TypedDict, total=False): + type: Required[Literal["server_vad"]] + """Type of turn detection, `server_vad` to turn on simple Server VAD.""" + create_response: bool """ Whether or not to automatically generate a response when a VAD stop event occurs. """ - eagerness: Literal["low", "medium", "high", "auto"] - """Used only for `semantic_vad` mode. + idle_timeout_ms: Optional[int] + """Optional timeout after which a model response will be triggered automatically. - The eagerness of the model to respond. `low` will wait longer for the user to - continue speaking, `high` will respond more quickly. `auto` is the default and - is equivalent to `medium`. - """ + This is useful for situations in which a long pause from the user is unexpected, + such as a phone call. The model will effectively prompt the user to continue the + conversation based on the current context. - idle_timeout_ms: Optional[int] - """ - Optional idle timeout after which turn detection will auto-timeout when no - additional audio is received. + The timeout value will be applied after the last model response's audio has + finished playing, i.e. it's set to the `response.done` time plus audio playback + duration. + + An `input_audio_buffer.timeout_triggered` event (plus events associated with the + Response) will be emitted when the timeout is reached. Idle timeout is currently + only supported for `server_vad` mode. """ interrupt_response: bool @@ -59,5 +64,32 @@ class RealtimeTranscriptionSessionAudioInputTurnDetectionParam(TypedDict, total= perform better in noisy environments. """ - type: Literal["server_vad", "semantic_vad"] - """Type of turn detection.""" + +class SemanticVad(TypedDict, total=False): + type: Required[Literal["semantic_vad"]] + """Type of turn detection, `semantic_vad` to turn on Semantic VAD.""" + + create_response: bool + """ + Whether or not to automatically generate a response when a VAD stop event + occurs. + """ + + eagerness: Literal["low", "medium", "high", "auto"] + """Used only for `semantic_vad` mode. + + The eagerness of the model to respond. `low` will wait longer for the user to + continue speaking, `high` will respond more quickly. `auto` is the default and + is equivalent to `medium`. `low`, `medium`, and `high` have max timeouts of 8s, + 4s, and 2s respectively. + """ + + interrupt_response: bool + """ + Whether or not to automatically interrupt any ongoing response with output to + the default conversation (i.e. `conversation` of `auto`) when a VAD start event + occurs. + """ + + +RealtimeTranscriptionSessionAudioInputTurnDetectionParam: TypeAlias = Union[ServerVad, SemanticVad] diff --git a/src/openai/types/responses/response.py b/src/openai/types/responses/response.py index 163648ef3e..423b6f20f1 100644 --- a/src/openai/types/responses/response.py +++ b/src/openai/types/responses/response.py @@ -252,10 +252,10 @@ class Response(BaseModel): truncation: Optional[Literal["auto", "disabled"]] = None """The truncation strategy to use for the model response. - - `auto`: If the context of this response and previous ones exceeds the model's - context window size, the model will truncate the response to fit the context - window by dropping input items in the middle of the conversation. - - `disabled` (default): If a model response will exceed the context window size + - `auto`: If the input to this Response exceeds the model's context window size, + the model will truncate the response to fit the context window by dropping + items from the beginning of the conversation. + - `disabled` (default): If the input size will exceed the context window size for a model, the request will fail with a 400 error. """ diff --git a/src/openai/types/responses/response_create_params.py b/src/openai/types/responses/response_create_params.py index be687c0aff..af0d5e7483 100644 --- a/src/openai/types/responses/response_create_params.py +++ b/src/openai/types/responses/response_create_params.py @@ -252,10 +252,10 @@ class ResponseCreateParamsBase(TypedDict, total=False): truncation: Optional[Literal["auto", "disabled"]] """The truncation strategy to use for the model response. - - `auto`: If the context of this response and previous ones exceeds the model's - context window size, the model will truncate the response to fit the context - window by dropping input items in the middle of the conversation. - - `disabled` (default): If a model response will exceed the context window size + - `auto`: If the input to this Response exceeds the model's context window size, + the model will truncate the response to fit the context window by dropping + items from the beginning of the conversation. + - `disabled` (default): If the input size will exceed the context window size for a model, the request will fail with a 400 error. """ diff --git a/tests/api_resources/realtime/test_client_secrets.py b/tests/api_resources/realtime/test_client_secrets.py index b7bb0e5aa7..cd15b4be52 100644 --- a/tests/api_resources/realtime/test_client_secrets.py +++ b/tests/api_resources/realtime/test_client_secrets.py @@ -44,14 +44,13 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: "prompt": "prompt", }, "turn_detection": { + "type": "server_vad", "create_response": True, - "eagerness": "low", - "idle_timeout_ms": 0, + "idle_timeout_ms": 5000, "interrupt_response": True, "prefix_padding_ms": 0, "silence_duration_ms": 0, "threshold": 0, - "type": "server_vad", }, }, "output": { @@ -141,14 +140,13 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> "prompt": "prompt", }, "turn_detection": { + "type": "server_vad", "create_response": True, - "eagerness": "low", - "idle_timeout_ms": 0, + "idle_timeout_ms": 5000, "interrupt_response": True, "prefix_padding_ms": 0, "silence_duration_ms": 0, "threshold": 0, - "type": "server_vad", }, }, "output": { diff --git a/tests/test_client.py b/tests/test_client.py index e5300e55d7..3287e0e706 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -6,13 +6,10 @@ import os import sys import json -import time import asyncio import inspect -import subprocess import tracemalloc from typing import Any, Union, Protocol, cast -from textwrap import dedent from unittest import mock from typing_extensions import Literal @@ -23,6 +20,7 @@ from openai import OpenAI, AsyncOpenAI, APIResponseValidationError from openai._types import Omit +from openai._utils import asyncify from openai._models import BaseModel, FinalRequestOptions from openai._streaming import Stream, AsyncStream from openai._exceptions import OpenAIError, APIStatusError, APITimeoutError, APIResponseValidationError @@ -30,8 +28,10 @@ DEFAULT_TIMEOUT, HTTPX_DEFAULT_TIMEOUT, BaseClient, + OtherPlatform, DefaultHttpxClient, DefaultAsyncHttpxClient, + get_platform, make_request_options, ) @@ -1857,50 +1857,9 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: assert response.retries_taken == failures_before_success assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success - def test_get_platform(self) -> None: - # A previous implementation of asyncify could leave threads unterminated when - # used with nest_asyncio. - # - # Since nest_asyncio.apply() is global and cannot be un-applied, this - # test is run in a separate process to avoid affecting other tests. - test_code = dedent(""" - import asyncio - import nest_asyncio - import threading - - from openai._utils import asyncify - from openai._base_client import get_platform - - async def test_main() -> None: - result = await asyncify(get_platform)() - print(result) - for thread in threading.enumerate(): - print(thread.name) - - nest_asyncio.apply() - asyncio.run(test_main()) - """) - with subprocess.Popen( - [sys.executable, "-c", test_code], - text=True, - ) as process: - timeout = 10 # seconds - - start_time = time.monotonic() - while True: - return_code = process.poll() - if return_code is not None: - if return_code != 0: - raise AssertionError("calling get_platform using asyncify resulted in a non-zero exit code") - - # success - break - - if time.monotonic() - start_time > timeout: - process.kill() - raise AssertionError("calling get_platform using asyncify resulted in a hung process") - - time.sleep(0.1) + async def test_get_platform(self) -> None: + platform = await asyncify(get_platform)() + assert isinstance(platform, (str, OtherPlatform)) async def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None: # Test that the proxy environment variables are set correctly From 514de0fe148bc44bed09491b97eeec44d8071c81 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 19:52:16 +0000 Subject: [PATCH 491/769] chore(api): docs and spec refactoring --- .stats.yml | 6 +++--- .../resources/chat/completions/completions.py | 16 ++++++++++------ .../resources/conversations/conversations.py | 16 ++++++++++++---- .../types/audio/transcription_create_params.py | 12 ++++++------ .../chat_completion_assistant_message_param.py | 4 ++-- src/openai/types/chat/completion_list_params.py | 8 ++++++-- .../conversations/conversation_create_params.py | 7 +++++-- src/openai/types/evals/run_cancel_response.py | 9 ++++++--- src/openai/types/evals/run_create_params.py | 9 ++++++--- src/openai/types/evals/run_create_response.py | 9 ++++++--- src/openai/types/evals/run_list_response.py | 9 ++++++--- src/openai/types/evals/run_retrieve_response.py | 9 ++++++--- .../realtime/realtime_response_create_params.py | 4 ++-- .../realtime_response_create_params_param.py | 4 ++-- .../realtime/realtime_session_create_request.py | 4 ++-- .../realtime_session_create_request_param.py | 4 ++-- .../realtime/realtime_session_create_response.py | 4 ++-- src/openai/types/responses/response.py | 4 ++-- .../response_code_interpreter_tool_call.py | 6 +++--- .../response_code_interpreter_tool_call_param.py | 6 +++--- .../types/responses/response_create_params.py | 4 ++-- 21 files changed, 94 insertions(+), 60 deletions(-) diff --git a/.stats.yml b/.stats.yml index e389718967..905a02c44a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 118 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-94b1e3cb0bdc616ff0c2f267c33dadd95f133b1f64e647aab6c64afb292b2793.yml -openapi_spec_hash: 2395319ac9befd59b6536ae7f9564a05 -config_hash: 930dac3aa861344867e4ac84f037b5df +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-d30ff992a48873c1466c49f3c01f2ec8933faebff23424748f8d056065b1bcef.yml +openapi_spec_hash: e933ec43b46f45c348adb78840e5808d +config_hash: bf45940f0a7805b4ec2017eecdd36893 diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index 168cf04dbc..f29792a207 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -1300,10 +1300,12 @@ def list( limit: Number of Chat Completions to retrieve. - metadata: - A list of metadata keys to filter the Chat Completions by. Example: + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. - `metadata[key1]=value1&metadata[key2]=value2` + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. model: The model used to generate the Chat Completions. @@ -2736,10 +2738,12 @@ def list( limit: Number of Chat Completions to retrieve. - metadata: - A list of metadata keys to filter the Chat Completions by. Example: + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. - `metadata[key1]=value1&metadata[key2]=value2` + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. model: The model used to generate the Chat Completions. diff --git a/src/openai/resources/conversations/conversations.py b/src/openai/resources/conversations/conversations.py index 802620e6ad..c0239d402c 100644 --- a/src/openai/resources/conversations/conversations.py +++ b/src/openai/resources/conversations/conversations.py @@ -73,8 +73,12 @@ def create( items: Initial items to include in the conversation context. You may add up to 20 items at a time. - metadata: Set of 16 key-value pairs that can be attached to an object. Useful for storing - additional information about the object in a structured format. + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. extra_headers: Send extra headers @@ -250,8 +254,12 @@ async def create( items: Initial items to include in the conversation context. You may add up to 20 items at a time. - metadata: Set of 16 key-value pairs that can be attached to an object. Useful for storing - additional information about the object in a structured format. + metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful + for storing additional information about the object in a structured format, and + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. extra_headers: Send extra headers diff --git a/src/openai/types/audio/transcription_create_params.py b/src/openai/types/audio/transcription_create_params.py index 8271b054ab..f7abcced87 100644 --- a/src/openai/types/audio/transcription_create_params.py +++ b/src/openai/types/audio/transcription_create_params.py @@ -43,12 +43,12 @@ class TranscriptionCreateParamsBase(TypedDict, total=False): """ include: List[TranscriptionInclude] - """Additional information to include in the transcription response. - - `logprobs` will return the log probabilities of the tokens in the response to - understand the model's confidence in the transcription. `logprobs` only works - with response_format set to `json` and only with the models `gpt-4o-transcribe` - and `gpt-4o-mini-transcribe`. + """ + Additional information to include in the transcription response. `logprobs` will + return the log probabilities of the tokens in the response to understand the + model's confidence in the transcription. `logprobs` only works with + response_format set to `json` and only with the models `gpt-4o-transcribe` and + `gpt-4o-mini-transcribe`. """ language: str diff --git a/src/openai/types/chat/chat_completion_assistant_message_param.py b/src/openai/types/chat/chat_completion_assistant_message_param.py index 212d933e9b..1a08a959db 100644 --- a/src/openai/types/chat/chat_completion_assistant_message_param.py +++ b/src/openai/types/chat/chat_completion_assistant_message_param.py @@ -38,8 +38,8 @@ class ChatCompletionAssistantMessageParam(TypedDict, total=False): """The role of the messages author, in this case `assistant`.""" audio: Optional[Audio] - """Data about a previous audio response from the model. - + """ + Data about a previous audio response from the model. [Learn more](https://platform.openai.com/docs/guides/audio). """ diff --git a/src/openai/types/chat/completion_list_params.py b/src/openai/types/chat/completion_list_params.py index d93da834a3..32bd3f5c0a 100644 --- a/src/openai/types/chat/completion_list_params.py +++ b/src/openai/types/chat/completion_list_params.py @@ -18,9 +18,13 @@ class CompletionListParams(TypedDict, total=False): """Number of Chat Completions to retrieve.""" metadata: Optional[Metadata] - """A list of metadata keys to filter the Chat Completions by. Example: + """Set of 16 key-value pairs that can be attached to an object. - `metadata[key1]=value1&metadata[key2]=value2` + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. """ model: str diff --git a/src/openai/types/conversations/conversation_create_params.py b/src/openai/types/conversations/conversation_create_params.py index 7ad3f8ae2d..0d84f503bd 100644 --- a/src/openai/types/conversations/conversation_create_params.py +++ b/src/openai/types/conversations/conversation_create_params.py @@ -21,6 +21,9 @@ class ConversationCreateParams(TypedDict, total=False): metadata: Optional[Metadata] """Set of 16 key-value pairs that can be attached to an object. - Useful for storing additional information about the object in a structured - format. + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. """ diff --git a/src/openai/types/evals/run_cancel_response.py b/src/openai/types/evals/run_cancel_response.py index 44f9cfc453..8f43494e68 100644 --- a/src/openai/types/evals/run_cancel_response.py +++ b/src/openai/types/evals/run_cancel_response.py @@ -100,9 +100,12 @@ class DataSourceResponsesSourceResponses(BaseModel): """ reasoning_effort: Optional[ReasoningEffort] = None - """Optional reasoning effort parameter. - - This is a query parameter used to select responses. + """ + Constrains effort on reasoning for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently + supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning + effort can result in faster responses and fewer tokens used on reasoning in a + response. """ temperature: Optional[float] = None diff --git a/src/openai/types/evals/run_create_params.py b/src/openai/types/evals/run_create_params.py index ef9541ff0a..35813c8901 100644 --- a/src/openai/types/evals/run_create_params.py +++ b/src/openai/types/evals/run_create_params.py @@ -113,9 +113,12 @@ class DataSourceCreateEvalResponsesRunDataSourceSourceResponses(TypedDict, total """ reasoning_effort: Optional[ReasoningEffort] - """Optional reasoning effort parameter. - - This is a query parameter used to select responses. + """ + Constrains effort on reasoning for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently + supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning + effort can result in faster responses and fewer tokens used on reasoning in a + response. """ temperature: Optional[float] diff --git a/src/openai/types/evals/run_create_response.py b/src/openai/types/evals/run_create_response.py index 70641d6db8..c842a5ad2f 100644 --- a/src/openai/types/evals/run_create_response.py +++ b/src/openai/types/evals/run_create_response.py @@ -100,9 +100,12 @@ class DataSourceResponsesSourceResponses(BaseModel): """ reasoning_effort: Optional[ReasoningEffort] = None - """Optional reasoning effort parameter. - - This is a query parameter used to select responses. + """ + Constrains effort on reasoning for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently + supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning + effort can result in faster responses and fewer tokens used on reasoning in a + response. """ temperature: Optional[float] = None diff --git a/src/openai/types/evals/run_list_response.py b/src/openai/types/evals/run_list_response.py index e31d570a84..5a5c2efbb3 100644 --- a/src/openai/types/evals/run_list_response.py +++ b/src/openai/types/evals/run_list_response.py @@ -100,9 +100,12 @@ class DataSourceResponsesSourceResponses(BaseModel): """ reasoning_effort: Optional[ReasoningEffort] = None - """Optional reasoning effort parameter. - - This is a query parameter used to select responses. + """ + Constrains effort on reasoning for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently + supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning + effort can result in faster responses and fewer tokens used on reasoning in a + response. """ temperature: Optional[float] = None diff --git a/src/openai/types/evals/run_retrieve_response.py b/src/openai/types/evals/run_retrieve_response.py index 62213d3edd..f341296875 100644 --- a/src/openai/types/evals/run_retrieve_response.py +++ b/src/openai/types/evals/run_retrieve_response.py @@ -100,9 +100,12 @@ class DataSourceResponsesSourceResponses(BaseModel): """ reasoning_effort: Optional[ReasoningEffort] = None - """Optional reasoning effort parameter. - - This is a query parameter used to select responses. + """ + Constrains effort on reasoning for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently + supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning + effort can result in faster responses and fewer tokens used on reasoning in a + response. """ temperature: Optional[float] = None diff --git a/src/openai/types/realtime/realtime_response_create_params.py b/src/openai/types/realtime/realtime_response_create_params.py index 4dfd1fd386..e8486220bf 100644 --- a/src/openai/types/realtime/realtime_response_create_params.py +++ b/src/openai/types/realtime/realtime_response_create_params.py @@ -83,8 +83,8 @@ class RealtimeResponseCreateParams(BaseModel): """ prompt: Optional[ResponsePrompt] = None - """Reference to a prompt template and its variables. - + """ + Reference to a prompt template and its variables. [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). """ diff --git a/src/openai/types/realtime/realtime_response_create_params_param.py b/src/openai/types/realtime/realtime_response_create_params_param.py index eceffcccb7..116384bd82 100644 --- a/src/openai/types/realtime/realtime_response_create_params_param.py +++ b/src/openai/types/realtime/realtime_response_create_params_param.py @@ -84,8 +84,8 @@ class RealtimeResponseCreateParamsParam(TypedDict, total=False): """ prompt: Optional[ResponsePromptParam] - """Reference to a prompt template and its variables. - + """ + Reference to a prompt template and its variables. [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). """ diff --git a/src/openai/types/realtime/realtime_session_create_request.py b/src/openai/types/realtime/realtime_session_create_request.py index 578bc43821..755dbe8638 100644 --- a/src/openai/types/realtime/realtime_session_create_request.py +++ b/src/openai/types/realtime/realtime_session_create_request.py @@ -76,8 +76,8 @@ class RealtimeSessionCreateRequest(BaseModel): """ prompt: Optional[ResponsePrompt] = None - """Reference to a prompt template and its variables. - + """ + Reference to a prompt template and its variables. [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). """ diff --git a/src/openai/types/realtime/realtime_session_create_request_param.py b/src/openai/types/realtime/realtime_session_create_request_param.py index 5f7819fa61..cd4ef71ba2 100644 --- a/src/openai/types/realtime/realtime_session_create_request_param.py +++ b/src/openai/types/realtime/realtime_session_create_request_param.py @@ -76,8 +76,8 @@ class RealtimeSessionCreateRequestParam(TypedDict, total=False): """ prompt: Optional[ResponsePromptParam] - """Reference to a prompt template and its variables. - + """ + Reference to a prompt template and its variables. [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). """ diff --git a/src/openai/types/realtime/realtime_session_create_response.py b/src/openai/types/realtime/realtime_session_create_response.py index 8d7bfd6d8e..2d6912d072 100644 --- a/src/openai/types/realtime/realtime_session_create_response.py +++ b/src/openai/types/realtime/realtime_session_create_response.py @@ -429,8 +429,8 @@ class RealtimeSessionCreateResponse(BaseModel): """ prompt: Optional[ResponsePrompt] = None - """Reference to a prompt template and its variables. - + """ + Reference to a prompt template and its variables. [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). """ diff --git a/src/openai/types/responses/response.py b/src/openai/types/responses/response.py index 423b6f20f1..a1133a41f5 100644 --- a/src/openai/types/responses/response.py +++ b/src/openai/types/responses/response.py @@ -180,8 +180,8 @@ class Response(BaseModel): """ prompt: Optional[ResponsePrompt] = None - """Reference to a prompt template and its variables. - + """ + Reference to a prompt template and its variables. [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). """ diff --git a/src/openai/types/responses/response_code_interpreter_tool_call.py b/src/openai/types/responses/response_code_interpreter_tool_call.py index 257937118b..ed720ecd42 100644 --- a/src/openai/types/responses/response_code_interpreter_tool_call.py +++ b/src/openai/types/responses/response_code_interpreter_tool_call.py @@ -39,9 +39,9 @@ class ResponseCodeInterpreterToolCall(BaseModel): """The ID of the container used to run the code.""" outputs: Optional[List[Output]] = None - """The outputs generated by the code interpreter, such as logs or images. - - Can be null if no outputs are available. + """ + The outputs generated by the code interpreter, such as logs or images. Can be + null if no outputs are available. """ status: Literal["in_progress", "completed", "incomplete", "interpreting", "failed"] diff --git a/src/openai/types/responses/response_code_interpreter_tool_call_param.py b/src/openai/types/responses/response_code_interpreter_tool_call_param.py index 435091001f..78b90ca87e 100644 --- a/src/openai/types/responses/response_code_interpreter_tool_call_param.py +++ b/src/openai/types/responses/response_code_interpreter_tool_call_param.py @@ -38,9 +38,9 @@ class ResponseCodeInterpreterToolCallParam(TypedDict, total=False): """The ID of the container used to run the code.""" outputs: Required[Optional[Iterable[Output]]] - """The outputs generated by the code interpreter, such as logs or images. - - Can be null if no outputs are available. + """ + The outputs generated by the code interpreter, such as logs or images. Can be + null if no outputs are available. """ status: Required[Literal["in_progress", "completed", "incomplete", "interpreting", "failed"]] diff --git a/src/openai/types/responses/response_create_params.py b/src/openai/types/responses/response_create_params.py index af0d5e7483..ba5c45ffee 100644 --- a/src/openai/types/responses/response_create_params.py +++ b/src/openai/types/responses/response_create_params.py @@ -134,8 +134,8 @@ class ResponseCreateParamsBase(TypedDict, total=False): """ prompt: Optional[ResponsePromptParam] - """Reference to a prompt template and its variables. - + """ + Reference to a prompt template and its variables. [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). """ From 0b4bc5049f31f9d03b773d6919064e007b378778 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 19:52:49 +0000 Subject: [PATCH 492/769] release: 1.107.3 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 9 +++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 32e0d8892c..3b81c9b87e 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.107.2" + ".": "1.107.3" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 31ccac5195..b9314bd48a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 1.107.3 (2025-09-15) + +Full Changelog: [v1.107.2...v1.107.3](https://github.com/openai/openai-python/compare/v1.107.2...v1.107.3) + +### Chores + +* **api:** docs and spec refactoring ([9bab5da](https://github.com/openai/openai-python/commit/9bab5da1802c3575c58e73ed1470dd5fa61fd1d2)) +* **tests:** simplify `get_platform` test ([0b1f6a2](https://github.com/openai/openai-python/commit/0b1f6a28d5a59e10873264e976d2e332903eef29)) + ## 1.107.2 (2025-09-12) Full Changelog: [v1.107.1...v1.107.2](https://github.com/openai/openai-python/compare/v1.107.1...v1.107.2) diff --git a/pyproject.toml b/pyproject.toml index 7cb1ef4f76..190542e6dc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.107.2" +version = "1.107.3" 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 70f9958885..aa7660d137 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.107.2" # x-release-please-version +__version__ = "1.107.3" # x-release-please-version From 0d85ca08c83a408abf3f03b46189e6bf39f68ac6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 17 Sep 2025 18:02:28 -0400 Subject: [PATCH 493/769] release: 1.108.0 (#2635) * chore(internal): update pydantic dependency * feat(api): type updates for conversations, reasoning_effort and results for evals * release: 1.108.0 --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- .stats.yml | 6 +-- CHANGELOG.md | 13 +++++++ api.md | 15 +++----- pyproject.toml | 2 +- requirements-dev.lock | 10 +++-- requirements.lock | 11 ++++-- src/openai/_models.py | 14 +++++-- src/openai/_version.py | 2 +- src/openai/types/conversations/__init__.py | 10 ++--- .../container_file_citation_body.py | 27 -------------- .../types/conversations/file_citation_body.py | 21 ----------- .../types/conversations/input_file_content.py | 19 +--------- .../conversations/input_file_content_param.py | 7 ++++ .../conversations/input_image_content.py | 25 +------------ .../input_image_content_param.py | 7 ++++ .../types/conversations/input_text_content.py | 12 +----- .../conversations/input_text_content_param.py | 7 ++++ src/openai/types/conversations/lob_prob.py | 18 --------- src/openai/types/conversations/message.py | 20 +++++----- .../conversations/output_text_content.py | 29 ++------------- .../output_text_content_param.py | 7 ++++ .../types/conversations/refusal_content.py | 12 +----- .../conversations/refusal_content_param.py | 7 ++++ .../types/conversations/top_log_prob.py | 15 -------- .../types/conversations/url_citation_body.py | 24 ------------ ...create_eval_completions_run_data_source.py | 10 +++++ ..._eval_completions_run_data_source_param.py | 10 +++++ src/openai/types/evals/run_cancel_response.py | 9 +++++ src/openai/types/evals/run_create_params.py | 9 +++++ src/openai/types/evals/run_create_response.py | 9 +++++ src/openai/types/evals/run_list_response.py | 9 +++++ .../types/evals/run_retrieve_response.py | 9 +++++ .../evals/runs/output_item_list_response.py | 35 +++++++++++++++--- .../runs/output_item_retrieve_response.py | 35 +++++++++++++++--- .../types/graders/score_model_grader.py | 35 +++++++++++++++++- .../types/graders/score_model_grader_param.py | 37 +++++++++++++++++-- 37 files changed, 301 insertions(+), 248 deletions(-) delete mode 100644 src/openai/types/conversations/container_file_citation_body.py delete mode 100644 src/openai/types/conversations/file_citation_body.py create mode 100644 src/openai/types/conversations/input_file_content_param.py create mode 100644 src/openai/types/conversations/input_image_content_param.py create mode 100644 src/openai/types/conversations/input_text_content_param.py delete mode 100644 src/openai/types/conversations/lob_prob.py create mode 100644 src/openai/types/conversations/output_text_content_param.py create mode 100644 src/openai/types/conversations/refusal_content_param.py delete mode 100644 src/openai/types/conversations/top_log_prob.py delete mode 100644 src/openai/types/conversations/url_citation_body.py diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 3b81c9b87e..102fa47016 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.107.3" + ".": "1.108.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 905a02c44a..2dd0aef46a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 118 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-d30ff992a48873c1466c49f3c01f2ec8933faebff23424748f8d056065b1bcef.yml -openapi_spec_hash: e933ec43b46f45c348adb78840e5808d -config_hash: bf45940f0a7805b4ec2017eecdd36893 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-380330a93b5d010391ca3b36ea193c5353b0dfdf2ddd02789ef84a84ce427e82.yml +openapi_spec_hash: 859703234259ecdd2a3c6f4de88eb504 +config_hash: b619b45c1e7facf819f902dee8fa4f97 diff --git a/CHANGELOG.md b/CHANGELOG.md index b9314bd48a..1e35189611 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 1.108.0 (2025-09-17) + +Full Changelog: [v1.107.3...v1.108.0](https://github.com/openai/openai-python/compare/v1.107.3...v1.108.0) + +### Features + +* **api:** type updates for conversations, reasoning_effort and results for evals ([c2ee28c](https://github.com/openai/openai-python/commit/c2ee28c1b77eed98766fbb01cf1ad2ee240f412e)) + + +### Chores + +* **internal:** update pydantic dependency ([369d10a](https://github.com/openai/openai-python/commit/369d10a40dfe744f6bfc10c99eb1f58176500120)) + ## 1.107.3 (2025-09-15) Full Changelog: [v1.107.2...v1.107.3](https://github.com/openai/openai-python/compare/v1.107.2...v1.107.3) diff --git a/api.md b/api.md index 73b8427387..6bbb47f78c 100644 --- a/api.md +++ b/api.md @@ -991,22 +991,17 @@ Types: ```python from openai.types.conversations import ( ComputerScreenshotContent, - ContainerFileCitationBody, Conversation, ConversationDeleted, ConversationDeletedResource, - FileCitationBody, - InputFileContent, - InputImageContent, - InputTextContent, - LobProb, Message, - OutputTextContent, - RefusalContent, SummaryTextContent, TextContent, - TopLogProb, - URLCitationBody, + InputTextContent, + OutputTextContent, + RefusalContent, + InputImageContent, + InputFileContent, ) ``` diff --git a/pyproject.toml b/pyproject.toml index 190542e6dc..058b7cda6c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.107.3" +version = "1.108.0" description = "The official Python library for the openai API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/requirements-dev.lock b/requirements-dev.lock index eaf136f7e6..0bd1c2c70f 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -108,6 +108,7 @@ multidict==6.5.0 mypy==1.14.1 mypy-extensions==1.0.0 # via mypy +nest-asyncio==1.6.0 nodeenv==1.8.0 # via pyright nox==2023.4.22 @@ -133,11 +134,11 @@ portalocker==2.10.1 propcache==0.3.2 # via aiohttp # via yarl -pycparser==2.22 +pycparser==2.23 # via cffi -pydantic==2.10.3 +pydantic==2.11.9 # via openai -pydantic-core==2.27.1 +pydantic-core==2.33.2 # via pydantic pygments==2.18.0 # via pytest @@ -199,6 +200,9 @@ typing-extensions==4.12.2 # via pydantic # via pydantic-core # via pyright + # via typing-inspection +typing-inspection==0.4.1 + # via pydantic tzdata==2024.1 # via pandas urllib3==2.2.1 diff --git a/requirements.lock b/requirements.lock index 3b6ece87e2..a2b6845942 100644 --- a/requirements.lock +++ b/requirements.lock @@ -67,11 +67,11 @@ pandas-stubs==2.2.2.240807 propcache==0.3.2 # via aiohttp # via yarl -pycparser==2.22 +pycparser==2.23 # via cffi -pydantic==2.10.3 +pydantic==2.11.9 # via openai -pydantic-core==2.27.1 +pydantic-core==2.33.2 # via pydantic python-dateutil==2.9.0.post0 # via pandas @@ -93,7 +93,10 @@ typing-extensions==4.12.2 # via openai # via pydantic # via pydantic-core -tzdata==2024.1 + # via typing-inspection +typing-inspection==0.4.1 + # via pydantic +tzdata==2025.2 # via pandas websockets==15.0.1 # via openai diff --git a/src/openai/_models.py b/src/openai/_models.py index 8ee8612d1e..af71a91850 100644 --- a/src/openai/_models.py +++ b/src/openai/_models.py @@ -281,7 +281,7 @@ def model_dump( mode: Literal["json", "python"] | str = "python", include: IncEx | None = None, exclude: IncEx | None = None, - by_alias: bool = False, + by_alias: bool | None = None, exclude_unset: bool = False, exclude_defaults: bool = False, exclude_none: bool = False, @@ -289,6 +289,7 @@ def model_dump( warnings: bool | Literal["none", "warn", "error"] = True, context: dict[str, Any] | None = None, serialize_as_any: bool = False, + fallback: Callable[[Any], Any] | None = None, ) -> dict[str, Any]: """Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump @@ -320,10 +321,12 @@ def model_dump( raise ValueError("context is only supported in Pydantic v2") if serialize_as_any != False: raise ValueError("serialize_as_any is only supported in Pydantic v2") + if fallback is not None: + raise ValueError("fallback is only supported in Pydantic v2") dumped = super().dict( # pyright: ignore[reportDeprecated] include=include, exclude=exclude, - by_alias=by_alias, + by_alias=by_alias if by_alias is not None else False, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, exclude_none=exclude_none, @@ -338,13 +341,14 @@ def model_dump_json( indent: int | None = None, include: IncEx | None = None, exclude: IncEx | None = None, - by_alias: bool = False, + by_alias: bool | None = None, exclude_unset: bool = False, exclude_defaults: bool = False, exclude_none: bool = False, round_trip: bool = False, warnings: bool | Literal["none", "warn", "error"] = True, context: dict[str, Any] | None = None, + fallback: Callable[[Any], Any] | None = None, serialize_as_any: bool = False, ) -> str: """Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump_json @@ -373,11 +377,13 @@ def model_dump_json( raise ValueError("context is only supported in Pydantic v2") if serialize_as_any != False: raise ValueError("serialize_as_any is only supported in Pydantic v2") + if fallback is not None: + raise ValueError("fallback is only supported in Pydantic v2") return super().json( # type: ignore[reportDeprecated] indent=indent, include=include, exclude=exclude, - by_alias=by_alias, + by_alias=by_alias if by_alias is not None else False, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, exclude_none=exclude_none, diff --git a/src/openai/_version.py b/src/openai/_version.py index aa7660d137..7030fe068c 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.107.3" # x-release-please-version +__version__ = "1.108.0" # x-release-please-version diff --git a/src/openai/types/conversations/__init__.py b/src/openai/types/conversations/__init__.py index 538966db4f..9dec848737 100644 --- a/src/openai/types/conversations/__init__.py +++ b/src/openai/types/conversations/__init__.py @@ -3,15 +3,11 @@ from __future__ import annotations from .message import Message as Message -from .lob_prob import LobProb as LobProb from .conversation import Conversation as Conversation from .text_content import TextContent as TextContent -from .top_log_prob import TopLogProb as TopLogProb from .refusal_content import RefusalContent as RefusalContent from .item_list_params import ItemListParams as ItemListParams from .conversation_item import ConversationItem as ConversationItem -from .url_citation_body import URLCitationBody as URLCitationBody -from .file_citation_body import FileCitationBody as FileCitationBody from .input_file_content import InputFileContent as InputFileContent from .input_text_content import InputTextContent as InputTextContent from .item_create_params import ItemCreateParams as ItemCreateParams @@ -19,9 +15,13 @@ from .output_text_content import OutputTextContent as OutputTextContent from .item_retrieve_params import ItemRetrieveParams as ItemRetrieveParams from .summary_text_content import SummaryTextContent as SummaryTextContent +from .refusal_content_param import RefusalContentParam as RefusalContentParam from .conversation_item_list import ConversationItemList as ConversationItemList +from .input_file_content_param import InputFileContentParam as InputFileContentParam +from .input_text_content_param import InputTextContentParam as InputTextContentParam +from .input_image_content_param import InputImageContentParam as InputImageContentParam +from .output_text_content_param import OutputTextContentParam as OutputTextContentParam from .conversation_create_params import ConversationCreateParams as ConversationCreateParams from .conversation_update_params import ConversationUpdateParams as ConversationUpdateParams from .computer_screenshot_content import ComputerScreenshotContent as ComputerScreenshotContent -from .container_file_citation_body import ContainerFileCitationBody as ContainerFileCitationBody from .conversation_deleted_resource import ConversationDeletedResource as ConversationDeletedResource diff --git a/src/openai/types/conversations/container_file_citation_body.py b/src/openai/types/conversations/container_file_citation_body.py deleted file mode 100644 index ea460df2e2..0000000000 --- a/src/openai/types/conversations/container_file_citation_body.py +++ /dev/null @@ -1,27 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ContainerFileCitationBody"] - - -class ContainerFileCitationBody(BaseModel): - container_id: str - """The ID of the container file.""" - - end_index: int - """The index of the last character of the container file citation in the message.""" - - file_id: str - """The ID of the file.""" - - filename: str - """The filename of the container file cited.""" - - start_index: int - """The index of the first character of the container file citation in the message.""" - - type: Literal["container_file_citation"] - """The type of the container file citation. Always `container_file_citation`.""" diff --git a/src/openai/types/conversations/file_citation_body.py b/src/openai/types/conversations/file_citation_body.py deleted file mode 100644 index ea90ae381d..0000000000 --- a/src/openai/types/conversations/file_citation_body.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["FileCitationBody"] - - -class FileCitationBody(BaseModel): - file_id: str - """The ID of the file.""" - - filename: str - """The filename of the file cited.""" - - index: int - """The index of the file in the list of files.""" - - type: Literal["file_citation"] - """The type of the file citation. Always `file_citation`.""" diff --git a/src/openai/types/conversations/input_file_content.py b/src/openai/types/conversations/input_file_content.py index 6aef7a89d9..ca555d85fc 100644 --- a/src/openai/types/conversations/input_file_content.py +++ b/src/openai/types/conversations/input_file_content.py @@ -1,22 +1,7 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel +from ..responses.response_input_file import ResponseInputFile __all__ = ["InputFileContent"] - -class InputFileContent(BaseModel): - file_id: Optional[str] = None - """The ID of the file to be sent to the model.""" - - type: Literal["input_file"] - """The type of the input item. Always `input_file`.""" - - file_url: Optional[str] = None - """The URL of the file to be sent to the model.""" - - filename: Optional[str] = None - """The name of the file to be sent to the model.""" +InputFileContent = ResponseInputFile diff --git a/src/openai/types/conversations/input_file_content_param.py b/src/openai/types/conversations/input_file_content_param.py new file mode 100644 index 0000000000..1ed8b8b9d1 --- /dev/null +++ b/src/openai/types/conversations/input_file_content_param.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from ..responses.response_input_file_param import ResponseInputFileParam + +InputFileContentParam = ResponseInputFileParam diff --git a/src/openai/types/conversations/input_image_content.py b/src/openai/types/conversations/input_image_content.py index f2587e0adc..4304323c3a 100644 --- a/src/openai/types/conversations/input_image_content.py +++ b/src/openai/types/conversations/input_image_content.py @@ -1,28 +1,7 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel +from ..responses.response_input_image import ResponseInputImage __all__ = ["InputImageContent"] - -class InputImageContent(BaseModel): - detail: Literal["low", "high", "auto"] - """The detail level of the image to be sent to the model. - - One of `high`, `low`, or `auto`. Defaults to `auto`. - """ - - file_id: Optional[str] = None - """The ID of the file to be sent to the model.""" - - image_url: Optional[str] = None - """The URL of the image to be sent to the model. - - A fully qualified URL or base64 encoded image in a data URL. - """ - - type: Literal["input_image"] - """The type of the input item. Always `input_image`.""" +InputImageContent = ResponseInputImage diff --git a/src/openai/types/conversations/input_image_content_param.py b/src/openai/types/conversations/input_image_content_param.py new file mode 100644 index 0000000000..a0ef9f545c --- /dev/null +++ b/src/openai/types/conversations/input_image_content_param.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from ..responses.response_input_image_param import ResponseInputImageParam + +InputImageContentParam = ResponseInputImageParam diff --git a/src/openai/types/conversations/input_text_content.py b/src/openai/types/conversations/input_text_content.py index 5e2daebdc5..cab8b26cb1 100644 --- a/src/openai/types/conversations/input_text_content.py +++ b/src/openai/types/conversations/input_text_content.py @@ -1,15 +1,7 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing_extensions import Literal - -from ..._models import BaseModel +from ..responses.response_input_text import ResponseInputText __all__ = ["InputTextContent"] - -class InputTextContent(BaseModel): - text: str - """The text input to the model.""" - - type: Literal["input_text"] - """The type of the input item. Always `input_text`.""" +InputTextContent = ResponseInputText diff --git a/src/openai/types/conversations/input_text_content_param.py b/src/openai/types/conversations/input_text_content_param.py new file mode 100644 index 0000000000..b1fd9a5f1c --- /dev/null +++ b/src/openai/types/conversations/input_text_content_param.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from ..responses.response_input_text_param import ResponseInputTextParam + +InputTextContentParam = ResponseInputTextParam diff --git a/src/openai/types/conversations/lob_prob.py b/src/openai/types/conversations/lob_prob.py deleted file mode 100644 index f7dcd62a5e..0000000000 --- a/src/openai/types/conversations/lob_prob.py +++ /dev/null @@ -1,18 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List - -from ..._models import BaseModel -from .top_log_prob import TopLogProb - -__all__ = ["LobProb"] - - -class LobProb(BaseModel): - token: str - - bytes: List[int] - - logprob: float - - top_logprobs: List[TopLogProb] diff --git a/src/openai/types/conversations/message.py b/src/openai/types/conversations/message.py index a070cf2869..95e03c5c00 100644 --- a/src/openai/types/conversations/message.py +++ b/src/openai/types/conversations/message.py @@ -6,26 +6,26 @@ from ..._utils import PropertyInfo from ..._models import BaseModel from .text_content import TextContent -from .refusal_content import RefusalContent -from .input_file_content import InputFileContent -from .input_text_content import InputTextContent -from .input_image_content import InputImageContent -from .output_text_content import OutputTextContent from .summary_text_content import SummaryTextContent from .computer_screenshot_content import ComputerScreenshotContent +from ..responses.response_input_file import ResponseInputFile +from ..responses.response_input_text import ResponseInputText +from ..responses.response_input_image import ResponseInputImage +from ..responses.response_output_text import ResponseOutputText +from ..responses.response_output_refusal import ResponseOutputRefusal __all__ = ["Message", "Content"] Content: TypeAlias = Annotated[ Union[ - InputTextContent, - OutputTextContent, + ResponseInputText, + ResponseOutputText, TextContent, SummaryTextContent, - RefusalContent, - InputImageContent, + ResponseOutputRefusal, + ResponseInputImage, ComputerScreenshotContent, - InputFileContent, + ResponseInputFile, ], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/conversations/output_text_content.py b/src/openai/types/conversations/output_text_content.py index 2ffee76526..cfe9307d74 100644 --- a/src/openai/types/conversations/output_text_content.py +++ b/src/openai/types/conversations/output_text_content.py @@ -1,30 +1,7 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias +from ..responses.response_output_text import ResponseOutputText -from ..._utils import PropertyInfo -from .lob_prob import LobProb -from ..._models import BaseModel -from .url_citation_body import URLCitationBody -from .file_citation_body import FileCitationBody -from .container_file_citation_body import ContainerFileCitationBody +__all__ = ["OutputTextContent"] -__all__ = ["OutputTextContent", "Annotation"] - -Annotation: TypeAlias = Annotated[ - Union[FileCitationBody, URLCitationBody, ContainerFileCitationBody], PropertyInfo(discriminator="type") -] - - -class OutputTextContent(BaseModel): - annotations: List[Annotation] - """The annotations of the text output.""" - - text: str - """The text output from the model.""" - - type: Literal["output_text"] - """The type of the output text. Always `output_text`.""" - - logprobs: Optional[List[LobProb]] = None +OutputTextContent = ResponseOutputText diff --git a/src/openai/types/conversations/output_text_content_param.py b/src/openai/types/conversations/output_text_content_param.py new file mode 100644 index 0000000000..dc3e2026f6 --- /dev/null +++ b/src/openai/types/conversations/output_text_content_param.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from ..responses.response_output_text_param import ResponseOutputTextParam + +OutputTextContentParam = ResponseOutputTextParam diff --git a/src/openai/types/conversations/refusal_content.py b/src/openai/types/conversations/refusal_content.py index 3c8bd5e35f..6206c267dc 100644 --- a/src/openai/types/conversations/refusal_content.py +++ b/src/openai/types/conversations/refusal_content.py @@ -1,15 +1,7 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing_extensions import Literal - -from ..._models import BaseModel +from ..responses.response_output_refusal import ResponseOutputRefusal __all__ = ["RefusalContent"] - -class RefusalContent(BaseModel): - refusal: str - """The refusal explanation from the model.""" - - type: Literal["refusal"] - """The type of the refusal. Always `refusal`.""" +RefusalContent = ResponseOutputRefusal diff --git a/src/openai/types/conversations/refusal_content_param.py b/src/openai/types/conversations/refusal_content_param.py new file mode 100644 index 0000000000..9b83da5f2d --- /dev/null +++ b/src/openai/types/conversations/refusal_content_param.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from ..responses.response_output_refusal_param import ResponseOutputRefusalParam + +RefusalContentParam = ResponseOutputRefusalParam diff --git a/src/openai/types/conversations/top_log_prob.py b/src/openai/types/conversations/top_log_prob.py deleted file mode 100644 index fafca756ae..0000000000 --- a/src/openai/types/conversations/top_log_prob.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List - -from ..._models import BaseModel - -__all__ = ["TopLogProb"] - - -class TopLogProb(BaseModel): - token: str - - bytes: List[int] - - logprob: float diff --git a/src/openai/types/conversations/url_citation_body.py b/src/openai/types/conversations/url_citation_body.py deleted file mode 100644 index 1becb44bc0..0000000000 --- a/src/openai/types/conversations/url_citation_body.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["URLCitationBody"] - - -class URLCitationBody(BaseModel): - end_index: int - """The index of the last character of the URL citation in the message.""" - - start_index: int - """The index of the first character of the URL citation in the message.""" - - title: str - """The title of the web resource.""" - - type: Literal["url_citation"] - """The type of the URL citation. Always `url_citation`.""" - - url: str - """The URL of the web resource.""" diff --git a/src/openai/types/evals/create_eval_completions_run_data_source.py b/src/openai/types/evals/create_eval_completions_run_data_source.py index edf70c8ad4..74323a735e 100644 --- a/src/openai/types/evals/create_eval_completions_run_data_source.py +++ b/src/openai/types/evals/create_eval_completions_run_data_source.py @@ -6,6 +6,7 @@ from ..._utils import PropertyInfo from ..._models import BaseModel from ..shared.metadata import Metadata +from ..shared.reasoning_effort import ReasoningEffort from ..shared.response_format_text import ResponseFormatText from ..responses.easy_input_message import EasyInputMessage from ..responses.response_input_text import ResponseInputText @@ -167,6 +168,15 @@ class SamplingParams(BaseModel): max_completion_tokens: Optional[int] = None """The maximum number of tokens in the generated output.""" + reasoning_effort: Optional[ReasoningEffort] = None + """ + Constrains effort on reasoning for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently + supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning + effort can result in faster responses and fewer tokens used on reasoning in a + response. + """ + response_format: Optional[SamplingParamsResponseFormat] = None """An object specifying the format that the model must output. diff --git a/src/openai/types/evals/create_eval_completions_run_data_source_param.py b/src/openai/types/evals/create_eval_completions_run_data_source_param.py index c14360ac80..4e9c1fdeb8 100644 --- a/src/openai/types/evals/create_eval_completions_run_data_source_param.py +++ b/src/openai/types/evals/create_eval_completions_run_data_source_param.py @@ -6,6 +6,7 @@ from typing_extensions import Literal, Required, TypeAlias, TypedDict from ..shared_params.metadata import Metadata +from ..shared.reasoning_effort import ReasoningEffort from ..responses.easy_input_message_param import EasyInputMessageParam from ..shared_params.response_format_text import ResponseFormatText from ..responses.response_input_text_param import ResponseInputTextParam @@ -163,6 +164,15 @@ class SamplingParams(TypedDict, total=False): max_completion_tokens: int """The maximum number of tokens in the generated output.""" + reasoning_effort: Optional[ReasoningEffort] + """ + Constrains effort on reasoning for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently + supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning + effort can result in faster responses and fewer tokens used on reasoning in a + response. + """ + response_format: SamplingParamsResponseFormat """An object specifying the format that the model must output. diff --git a/src/openai/types/evals/run_cancel_response.py b/src/openai/types/evals/run_cancel_response.py index 8f43494e68..d04d4ff657 100644 --- a/src/openai/types/evals/run_cancel_response.py +++ b/src/openai/types/evals/run_cancel_response.py @@ -234,6 +234,15 @@ class DataSourceResponsesSamplingParams(BaseModel): max_completion_tokens: Optional[int] = None """The maximum number of tokens in the generated output.""" + reasoning_effort: Optional[ReasoningEffort] = None + """ + Constrains effort on reasoning for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently + supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning + effort can result in faster responses and fewer tokens used on reasoning in a + response. + """ + seed: Optional[int] = None """A seed value to initialize the randomness, during sampling.""" diff --git a/src/openai/types/evals/run_create_params.py b/src/openai/types/evals/run_create_params.py index 35813c8901..6ff897b5de 100644 --- a/src/openai/types/evals/run_create_params.py +++ b/src/openai/types/evals/run_create_params.py @@ -252,6 +252,15 @@ class DataSourceCreateEvalResponsesRunDataSourceSamplingParams(TypedDict, total= max_completion_tokens: int """The maximum number of tokens in the generated output.""" + reasoning_effort: Optional[ReasoningEffort] + """ + Constrains effort on reasoning for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently + supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning + effort can result in faster responses and fewer tokens used on reasoning in a + response. + """ + seed: int """A seed value to initialize the randomness, during sampling.""" diff --git a/src/openai/types/evals/run_create_response.py b/src/openai/types/evals/run_create_response.py index c842a5ad2f..defa275c8c 100644 --- a/src/openai/types/evals/run_create_response.py +++ b/src/openai/types/evals/run_create_response.py @@ -234,6 +234,15 @@ class DataSourceResponsesSamplingParams(BaseModel): max_completion_tokens: Optional[int] = None """The maximum number of tokens in the generated output.""" + reasoning_effort: Optional[ReasoningEffort] = None + """ + Constrains effort on reasoning for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently + supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning + effort can result in faster responses and fewer tokens used on reasoning in a + response. + """ + seed: Optional[int] = None """A seed value to initialize the randomness, during sampling.""" diff --git a/src/openai/types/evals/run_list_response.py b/src/openai/types/evals/run_list_response.py index 5a5c2efbb3..7fe0e55ace 100644 --- a/src/openai/types/evals/run_list_response.py +++ b/src/openai/types/evals/run_list_response.py @@ -234,6 +234,15 @@ class DataSourceResponsesSamplingParams(BaseModel): max_completion_tokens: Optional[int] = None """The maximum number of tokens in the generated output.""" + reasoning_effort: Optional[ReasoningEffort] = None + """ + Constrains effort on reasoning for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently + supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning + effort can result in faster responses and fewer tokens used on reasoning in a + response. + """ + seed: Optional[int] = None """A seed value to initialize the randomness, during sampling.""" diff --git a/src/openai/types/evals/run_retrieve_response.py b/src/openai/types/evals/run_retrieve_response.py index f341296875..a50520f17d 100644 --- a/src/openai/types/evals/run_retrieve_response.py +++ b/src/openai/types/evals/run_retrieve_response.py @@ -234,6 +234,15 @@ class DataSourceResponsesSamplingParams(BaseModel): max_completion_tokens: Optional[int] = None """The maximum number of tokens in the generated output.""" + reasoning_effort: Optional[ReasoningEffort] = None + """ + Constrains effort on reasoning for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently + supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning + effort can result in faster responses and fewer tokens used on reasoning in a + response. + """ + seed: Optional[int] = None """A seed value to initialize the randomness, during sampling.""" diff --git a/src/openai/types/evals/runs/output_item_list_response.py b/src/openai/types/evals/runs/output_item_list_response.py index 72b1049f7b..f774518f3c 100644 --- a/src/openai/types/evals/runs/output_item_list_response.py +++ b/src/openai/types/evals/runs/output_item_list_response.py @@ -1,13 +1,38 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import builtins -from typing import Dict, List, Optional +from typing import TYPE_CHECKING, Dict, List, Optional from typing_extensions import Literal +from pydantic import Field as FieldInfo + from ...._models import BaseModel from ..eval_api_error import EvalAPIError -__all__ = ["OutputItemListResponse", "Sample", "SampleInput", "SampleOutput", "SampleUsage"] +__all__ = ["OutputItemListResponse", "Result", "Sample", "SampleInput", "SampleOutput", "SampleUsage"] + + +class Result(BaseModel): + name: str + """The name of the grader.""" + + passed: bool + """Whether the grader considered the output a pass.""" + + score: float + """The numeric score produced by the grader.""" + + sample: Optional[Dict[str, object]] = None + """Optional sample or intermediate data produced by the grader.""" + + type: Optional[str] = None + """The grader type (for example, "string-check-grader").""" + + __pydantic_extra__: Dict[str, object] = FieldInfo(init=False) # pyright: ignore[reportIncompatibleVariableOverride] + if TYPE_CHECKING: + # Stub to indicate that arbitrary properties are accepted. + # To access properties that are not valid identifiers you can use `getattr`, e.g. + # `getattr(obj, '$type')` + def __getattr__(self, attr: str) -> object: ... class SampleInput(BaseModel): @@ -91,8 +116,8 @@ class OutputItemListResponse(BaseModel): object: Literal["eval.run.output_item"] """The type of the object. Always "eval.run.output_item".""" - results: List[Dict[str, builtins.object]] - """A list of results from the evaluation run.""" + results: List[Result] + """A list of grader results for this output item.""" run_id: str """The identifier of the evaluation run associated with this output item.""" diff --git a/src/openai/types/evals/runs/output_item_retrieve_response.py b/src/openai/types/evals/runs/output_item_retrieve_response.py index 63aab5565f..d66435bd4f 100644 --- a/src/openai/types/evals/runs/output_item_retrieve_response.py +++ b/src/openai/types/evals/runs/output_item_retrieve_response.py @@ -1,13 +1,38 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import builtins -from typing import Dict, List, Optional +from typing import TYPE_CHECKING, Dict, List, Optional from typing_extensions import Literal +from pydantic import Field as FieldInfo + from ...._models import BaseModel from ..eval_api_error import EvalAPIError -__all__ = ["OutputItemRetrieveResponse", "Sample", "SampleInput", "SampleOutput", "SampleUsage"] +__all__ = ["OutputItemRetrieveResponse", "Result", "Sample", "SampleInput", "SampleOutput", "SampleUsage"] + + +class Result(BaseModel): + name: str + """The name of the grader.""" + + passed: bool + """Whether the grader considered the output a pass.""" + + score: float + """The numeric score produced by the grader.""" + + sample: Optional[Dict[str, object]] = None + """Optional sample or intermediate data produced by the grader.""" + + type: Optional[str] = None + """The grader type (for example, "string-check-grader").""" + + __pydantic_extra__: Dict[str, object] = FieldInfo(init=False) # pyright: ignore[reportIncompatibleVariableOverride] + if TYPE_CHECKING: + # Stub to indicate that arbitrary properties are accepted. + # To access properties that are not valid identifiers you can use `getattr`, e.g. + # `getattr(obj, '$type')` + def __getattr__(self, attr: str) -> object: ... class SampleInput(BaseModel): @@ -91,8 +116,8 @@ class OutputItemRetrieveResponse(BaseModel): object: Literal["eval.run.output_item"] """The type of the object. Always "eval.run.output_item".""" - results: List[Dict[str, builtins.object]] - """A list of results from the evaluation run.""" + results: List[Result] + """A list of grader results for this output item.""" run_id: str """The identifier of the evaluation run associated with this output item.""" diff --git a/src/openai/types/graders/score_model_grader.py b/src/openai/types/graders/score_model_grader.py index fc221b8e41..908c6f91d3 100644 --- a/src/openai/types/graders/score_model_grader.py +++ b/src/openai/types/graders/score_model_grader.py @@ -4,10 +4,18 @@ from typing_extensions import Literal, TypeAlias from ..._models import BaseModel +from ..shared.reasoning_effort import ReasoningEffort from ..responses.response_input_text import ResponseInputText from ..responses.response_input_audio import ResponseInputAudio -__all__ = ["ScoreModelGrader", "Input", "InputContent", "InputContentOutputText", "InputContentInputImage"] +__all__ = [ + "ScoreModelGrader", + "Input", + "InputContent", + "InputContentOutputText", + "InputContentInputImage", + "SamplingParams", +] class InputContentOutputText(BaseModel): @@ -51,6 +59,29 @@ class Input(BaseModel): """The type of the message input. Always `message`.""" +class SamplingParams(BaseModel): + max_completions_tokens: Optional[int] = None + """The maximum number of tokens the grader model may generate in its response.""" + + reasoning_effort: Optional[ReasoningEffort] = None + """ + Constrains effort on reasoning for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently + supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning + effort can result in faster responses and fewer tokens used on reasoning in a + response. + """ + + seed: Optional[int] = None + """A seed value to initialize the randomness, during sampling.""" + + temperature: Optional[float] = None + """A higher temperature increases randomness in the outputs.""" + + top_p: Optional[float] = None + """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" + + class ScoreModelGrader(BaseModel): input: List[Input] """The input text. This may include template strings.""" @@ -67,5 +98,5 @@ class ScoreModelGrader(BaseModel): range: Optional[List[float]] = None """The range of the score. Defaults to `[0, 1]`.""" - sampling_params: Optional[object] = None + sampling_params: Optional[SamplingParams] = None """The sampling parameters for the model.""" diff --git a/src/openai/types/graders/score_model_grader_param.py b/src/openai/types/graders/score_model_grader_param.py index 15100bb74b..743944e099 100644 --- a/src/openai/types/graders/score_model_grader_param.py +++ b/src/openai/types/graders/score_model_grader_param.py @@ -2,13 +2,21 @@ from __future__ import annotations -from typing import Union, Iterable +from typing import Union, Iterable, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict +from ..shared.reasoning_effort import ReasoningEffort from ..responses.response_input_text_param import ResponseInputTextParam from ..responses.response_input_audio_param import ResponseInputAudioParam -__all__ = ["ScoreModelGraderParam", "Input", "InputContent", "InputContentOutputText", "InputContentInputImage"] +__all__ = [ + "ScoreModelGraderParam", + "Input", + "InputContent", + "InputContentOutputText", + "InputContentInputImage", + "SamplingParams", +] class InputContentOutputText(TypedDict, total=False): @@ -57,6 +65,29 @@ class Input(TypedDict, total=False): """The type of the message input. Always `message`.""" +class SamplingParams(TypedDict, total=False): + max_completions_tokens: Optional[int] + """The maximum number of tokens the grader model may generate in its response.""" + + reasoning_effort: Optional[ReasoningEffort] + """ + Constrains effort on reasoning for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently + supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning + effort can result in faster responses and fewer tokens used on reasoning in a + response. + """ + + seed: Optional[int] + """A seed value to initialize the randomness, during sampling.""" + + temperature: Optional[float] + """A higher temperature increases randomness in the outputs.""" + + top_p: Optional[float] + """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" + + class ScoreModelGraderParam(TypedDict, total=False): input: Required[Iterable[Input]] """The input text. This may include template strings.""" @@ -73,5 +104,5 @@ class ScoreModelGraderParam(TypedDict, total=False): range: Iterable[float] """The range of the score. Defaults to `[0, 1]`.""" - sampling_params: object + sampling_params: SamplingParams """The sampling parameters for the model.""" From 82602884b61ef2f407f4c5f4fcae7d07243897be Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 18 Sep 2025 14:56:20 +0000 Subject: [PATCH 494/769] chore(types): change optional parameter type from NotGiven to Omit --- src/openai/__init__.py | 4 +- src/openai/_base_client.py | 18 +- src/openai/_client.py | 16 +- src/openai/_qs.py | 14 +- src/openai/_types.py | 31 +- src/openai/_utils/_transform.py | 4 +- src/openai/_utils/_utils.py | 8 +- src/openai/cli/_api/audio.py | 12 +- src/openai/cli/_api/completions.py | 26 +- src/openai/cli/_api/fine_tuning/jobs.py | 25 +- src/openai/cli/_api/image.py | 16 +- src/openai/lib/_parsing/_completions.py | 34 +- src/openai/lib/_parsing/_responses.py | 10 +- src/openai/lib/streaming/chat/_completions.py | 28 +- .../lib/streaming/responses/_responses.py | 24 +- src/openai/resources/audio/speech.py | 22 +- src/openai/resources/audio/transcriptions.py | 196 ++-- src/openai/resources/audio/translations.py | 62 +- src/openai/resources/batches.py | 34 +- src/openai/resources/beta/assistants.py | 122 +-- src/openai/resources/beta/threads/messages.py | 54 +- .../resources/beta/threads/runs/runs.py | 786 +++++++-------- .../resources/beta/threads/runs/steps.py | 34 +- src/openai/resources/beta/threads/threads.py | 514 +++++----- .../resources/chat/completions/completions.py | 814 ++++++++-------- .../resources/chat/completions/messages.py | 18 +- src/openai/resources/completions.py | 266 +++--- src/openai/resources/containers/containers.py | 38 +- .../resources/containers/files/content.py | 6 +- .../resources/containers/files/files.py | 38 +- .../resources/conversations/conversations.py | 26 +- src/openai/resources/conversations/items.py | 42 +- src/openai/resources/embeddings.py | 18 +- src/openai/resources/evals/evals.py | 54 +- .../resources/evals/runs/output_items.py | 26 +- src/openai/resources/evals/runs/runs.py | 46 +- src/openai/resources/files.py | 46 +- .../resources/fine_tuning/alpha/graders.py | 14 +- .../fine_tuning/checkpoints/permissions.py | 30 +- .../resources/fine_tuning/jobs/checkpoints.py | 14 +- src/openai/resources/fine_tuning/jobs/jobs.py | 78 +- src/openai/resources/images.py | 466 +++++---- src/openai/resources/models.py | 14 +- src/openai/resources/moderations.py | 10 +- .../resources/realtime/client_secrets.py | 14 +- src/openai/resources/realtime/realtime.py | 66 +- src/openai/resources/responses/input_items.py | 22 +- src/openai/resources/responses/responses.py | 898 +++++++++--------- src/openai/resources/uploads/parts.py | 6 +- src/openai/resources/uploads/uploads.py | 34 +- .../resources/vector_stores/file_batches.py | 66 +- src/openai/resources/vector_stores/files.py | 86 +- .../resources/vector_stores/vector_stores.py | 90 +- src/openai/types/responses/tool.py | 1 + src/openai/types/responses/tool_param.py | 1 + tests/test_transform.py | 11 +- 56 files changed, 2723 insertions(+), 2730 deletions(-) diff --git a/src/openai/__init__.py b/src/openai/__init__.py index a03b49e0c4..bd01da628d 100644 --- a/src/openai/__init__.py +++ b/src/openai/__init__.py @@ -7,7 +7,7 @@ from typing_extensions import override from . import types -from ._types import NOT_GIVEN, Omit, NoneType, NotGiven, Transport, ProxiesTypes +from ._types import NOT_GIVEN, Omit, NoneType, NotGiven, Transport, ProxiesTypes, omit, not_given from ._utils import file_from_path from ._client import Client, OpenAI, Stream, Timeout, Transport, AsyncClient, AsyncOpenAI, AsyncStream, RequestOptions from ._models import BaseModel @@ -46,7 +46,9 @@ "ProxiesTypes", "NotGiven", "NOT_GIVEN", + "not_given", "Omit", + "omit", "OpenAIError", "APIError", "APIStatusError", diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index d5f1ab0903..58490e4430 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -42,7 +42,6 @@ from ._qs import Querystring from ._files import to_httpx_files, async_to_httpx_files from ._types import ( - NOT_GIVEN, Body, Omit, Query, @@ -57,6 +56,7 @@ RequestOptions, HttpxRequestFiles, ModelBuilderProtocol, + not_given, ) from ._utils import SensitiveHeadersFilter, is_dict, is_list, asyncify, is_given, lru_cache, is_mapping from ._compat import PYDANTIC_V1, model_copy, model_dump @@ -147,9 +147,9 @@ def __init__( def __init__( self, *, - url: URL | NotGiven = NOT_GIVEN, - json: Body | NotGiven = NOT_GIVEN, - params: Query | NotGiven = NOT_GIVEN, + url: URL | NotGiven = not_given, + json: Body | NotGiven = not_given, + params: Query | NotGiven = not_given, ) -> None: self.url = url self.json = json @@ -597,7 +597,7 @@ def _maybe_override_cast_to(self, cast_to: type[ResponseT], options: FinalReques # we internally support defining a temporary header to override the # default `cast_to` type for use with `.with_raw_response` and `.with_streaming_response` # see _response.py for implementation details - override_cast_to = headers.pop(OVERRIDE_CAST_TO_HEADER, NOT_GIVEN) + override_cast_to = headers.pop(OVERRIDE_CAST_TO_HEADER, not_given) if is_given(override_cast_to): options.headers = headers return cast(Type[ResponseT], override_cast_to) @@ -827,7 +827,7 @@ def __init__( version: str, base_url: str | URL, max_retries: int = DEFAULT_MAX_RETRIES, - timeout: float | Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | Timeout | None | NotGiven = not_given, http_client: httpx.Client | None = None, custom_headers: Mapping[str, str] | None = None, custom_query: Mapping[str, object] | None = None, @@ -1373,7 +1373,7 @@ def __init__( base_url: str | URL, _strict_response_validation: bool, max_retries: int = DEFAULT_MAX_RETRIES, - timeout: float | Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | Timeout | None | NotGiven = not_given, http_client: httpx.AsyncClient | None = None, custom_headers: Mapping[str, str] | None = None, custom_query: Mapping[str, object] | None = None, @@ -1850,8 +1850,8 @@ def make_request_options( extra_query: Query | None = None, extra_body: Body | None = None, idempotency_key: str | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - post_parser: PostParser | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + post_parser: PostParser | NotGiven = not_given, ) -> RequestOptions: """Create a dict of type RequestOptions without keys of NotGiven values.""" options: RequestOptions = {} diff --git a/src/openai/_client.py b/src/openai/_client.py index 2be32fe13f..1485029ddd 100644 --- a/src/openai/_client.py +++ b/src/openai/_client.py @@ -3,7 +3,7 @@ from __future__ import annotations import os -from typing import TYPE_CHECKING, Any, Union, Mapping, Callable, Awaitable +from typing import TYPE_CHECKING, Any, Mapping, Callable, Awaitable from typing_extensions import Self, override import httpx @@ -11,13 +11,13 @@ from . import _exceptions from ._qs import Querystring from ._types import ( - NOT_GIVEN, Omit, Timeout, NotGiven, Transport, ProxiesTypes, RequestOptions, + not_given, ) from ._utils import ( is_given, @@ -103,7 +103,7 @@ def __init__( webhook_secret: str | None = None, base_url: str | httpx.URL | None = None, websocket_base_url: str | httpx.URL | None = None, - timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN, + timeout: float | Timeout | None | NotGiven = not_given, max_retries: int = DEFAULT_MAX_RETRIES, default_headers: Mapping[str, str] | None = None, default_query: Mapping[str, object] | None = None, @@ -339,9 +339,9 @@ def copy( webhook_secret: str | None = None, websocket_base_url: str | httpx.URL | None = None, base_url: str | httpx.URL | None = None, - timeout: float | Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | Timeout | None | NotGiven = not_given, http_client: httpx.Client | None = None, - max_retries: int | NotGiven = NOT_GIVEN, + max_retries: int | NotGiven = not_given, default_headers: Mapping[str, str] | None = None, set_default_headers: Mapping[str, str] | None = None, default_query: Mapping[str, object] | None = None, @@ -448,7 +448,7 @@ def __init__( webhook_secret: str | None = None, base_url: str | httpx.URL | None = None, websocket_base_url: str | httpx.URL | None = None, - timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN, + timeout: float | Timeout | None | NotGiven = not_given, max_retries: int = DEFAULT_MAX_RETRIES, default_headers: Mapping[str, str] | None = None, default_query: Mapping[str, object] | None = None, @@ -684,9 +684,9 @@ def copy( webhook_secret: str | None = None, websocket_base_url: str | httpx.URL | None = None, base_url: str | httpx.URL | None = None, - timeout: float | Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | Timeout | None | NotGiven = not_given, http_client: httpx.AsyncClient | None = None, - max_retries: int | NotGiven = NOT_GIVEN, + max_retries: int | NotGiven = not_given, default_headers: Mapping[str, str] | None = None, set_default_headers: Mapping[str, str] | None = None, default_query: Mapping[str, object] | None = None, diff --git a/src/openai/_qs.py b/src/openai/_qs.py index 274320ca5e..ada6fd3f72 100644 --- a/src/openai/_qs.py +++ b/src/openai/_qs.py @@ -4,7 +4,7 @@ from urllib.parse import parse_qs, urlencode from typing_extensions import Literal, get_args -from ._types import NOT_GIVEN, NotGiven, NotGivenOr +from ._types import NotGiven, not_given from ._utils import flatten _T = TypeVar("_T") @@ -41,8 +41,8 @@ def stringify( self, params: Params, *, - array_format: NotGivenOr[ArrayFormat] = NOT_GIVEN, - nested_format: NotGivenOr[NestedFormat] = NOT_GIVEN, + array_format: ArrayFormat | NotGiven = not_given, + nested_format: NestedFormat | NotGiven = not_given, ) -> str: return urlencode( self.stringify_items( @@ -56,8 +56,8 @@ def stringify_items( self, params: Params, *, - array_format: NotGivenOr[ArrayFormat] = NOT_GIVEN, - nested_format: NotGivenOr[NestedFormat] = NOT_GIVEN, + array_format: ArrayFormat | NotGiven = not_given, + nested_format: NestedFormat | NotGiven = not_given, ) -> list[tuple[str, str]]: opts = Options( qs=self, @@ -143,8 +143,8 @@ def __init__( self, qs: Querystring = _qs, *, - array_format: NotGivenOr[ArrayFormat] = NOT_GIVEN, - nested_format: NotGivenOr[NestedFormat] = NOT_GIVEN, + array_format: ArrayFormat | NotGiven = not_given, + nested_format: NestedFormat | NotGiven = not_given, ) -> None: self.array_format = qs.array_format if isinstance(array_format, NotGiven) else array_format self.nested_format = qs.nested_format if isinstance(nested_format, NotGiven) else nested_format diff --git a/src/openai/_types.py b/src/openai/_types.py index 0e8ffa12aa..2387d7e01c 100644 --- a/src/openai/_types.py +++ b/src/openai/_types.py @@ -118,18 +118,21 @@ class RequestOptions(TypedDict, total=False): # Sentinel class used until PEP 0661 is accepted class NotGiven: """ - A sentinel singleton class used to distinguish omitted keyword arguments - from those passed in with the value None (which may have different behavior). + For parameters with a meaningful None value, we need to distinguish between + the user explicitly passing None, and the user not passing the parameter at + all. + + User code shouldn't need to use not_given directly. For example: ```py - def get(timeout: Union[int, NotGiven, None] = NotGiven()) -> Response: ... + def create(timeout: Timeout | None | NotGiven = not_given): ... - get(timeout=1) # 1s timeout - get(timeout=None) # No timeout - get() # Default timeout behavior, which may not be statically known at the method definition. + create(timeout=1) # 1s timeout + create(timeout=None) # No timeout + create() # Default timeout behavior ``` """ @@ -141,13 +144,14 @@ def __repr__(self) -> str: return "NOT_GIVEN" -NotGivenOr = Union[_T, NotGiven] +not_given = NotGiven() +# for backwards compatibility: NOT_GIVEN = NotGiven() class Omit: - """In certain situations you need to be able to represent a case where a default value has - to be explicitly removed and `None` is not an appropriate substitute, for example: + """ + To explicitly omit something from being sent in a request, use `omit`. ```py # as the default `Content-Type` header is `application/json` that will be sent @@ -157,8 +161,8 @@ class Omit: # to look something like: 'multipart/form-data; boundary=0d8382fcf5f8c3be01ca2e11002d2983' client.post(..., headers={"Content-Type": "multipart/form-data"}) - # instead you can remove the default `application/json` header by passing Omit - client.post(..., headers={"Content-Type": Omit()}) + # instead you can remove the default `application/json` header by passing omit + client.post(..., headers={"Content-Type": omit}) ``` """ @@ -166,6 +170,11 @@ def __bool__(self) -> Literal[False]: return False +omit = Omit() + +Omittable = Union[_T, Omit] + + @runtime_checkable class ModelBuilderProtocol(Protocol): @classmethod diff --git a/src/openai/_utils/_transform.py b/src/openai/_utils/_transform.py index bc262ea339..414f38c340 100644 --- a/src/openai/_utils/_transform.py +++ b/src/openai/_utils/_transform.py @@ -268,7 +268,7 @@ def _transform_typeddict( annotations = get_type_hints(expected_type, include_extras=True) for key, value in data.items(): if not is_given(value): - # we don't need to include `NotGiven` values here as they'll + # we don't need to include omitted values here as they'll # be stripped out before the request is sent anyway continue @@ -434,7 +434,7 @@ async def _async_transform_typeddict( annotations = get_type_hints(expected_type, include_extras=True) for key, value in data.items(): if not is_given(value): - # we don't need to include `NotGiven` values here as they'll + # we don't need to include omitted values here as they'll # be stripped out before the request is sent anyway continue diff --git a/src/openai/_utils/_utils.py b/src/openai/_utils/_utils.py index 4a23c96c0a..cddf2c8da4 100644 --- a/src/openai/_utils/_utils.py +++ b/src/openai/_utils/_utils.py @@ -22,7 +22,7 @@ import sniffio -from .._types import NotGiven, FileTypes, NotGivenOr, HeadersLike +from .._types import Omit, NotGiven, FileTypes, HeadersLike _T = TypeVar("_T") _TupleT = TypeVar("_TupleT", bound=Tuple[object, ...]) @@ -67,7 +67,7 @@ def _extract_items( try: key = path[index] except IndexError: - if isinstance(obj, NotGiven): + if not is_given(obj): # no value was provided - we can safely ignore return [] @@ -130,8 +130,8 @@ def _extract_items( return [] -def is_given(obj: NotGivenOr[_T]) -> TypeGuard[_T]: - return not isinstance(obj, NotGiven) +def is_given(obj: _T | NotGiven | Omit) -> TypeGuard[_T]: + return not isinstance(obj, NotGiven) and not isinstance(obj, Omit) # Type safe methods for narrowing types with TypeVars. diff --git a/src/openai/cli/_api/audio.py b/src/openai/cli/_api/audio.py index 269c67df28..e7c3734e75 100644 --- a/src/openai/cli/_api/audio.py +++ b/src/openai/cli/_api/audio.py @@ -5,7 +5,7 @@ from argparse import ArgumentParser from .._utils import get_client, print_model -from ..._types import NOT_GIVEN +from ..._types import omit from .._models import BaseModel from .._progress import BufferReader from ...types.audio import Transcription @@ -72,9 +72,9 @@ def transcribe(args: CLITranscribeArgs) -> None: get_client().audio.transcriptions.create( file=(args.file, buffer_reader), model=args.model, - language=args.language or NOT_GIVEN, - temperature=args.temperature or NOT_GIVEN, - prompt=args.prompt or NOT_GIVEN, + language=args.language or omit, + temperature=args.temperature or omit, + prompt=args.prompt or omit, # casts required because the API is typed for enums # but we don't want to validate that here for forwards-compat response_format=cast(Any, args.response_format), @@ -95,8 +95,8 @@ def translate(args: CLITranslationArgs) -> None: get_client().audio.translations.create( file=(args.file, buffer_reader), model=args.model, - temperature=args.temperature or NOT_GIVEN, - prompt=args.prompt or NOT_GIVEN, + temperature=args.temperature or omit, + prompt=args.prompt or omit, # casts required because the API is typed for enums # but we don't want to validate that here for forwards-compat response_format=cast(Any, args.response_format), diff --git a/src/openai/cli/_api/completions.py b/src/openai/cli/_api/completions.py index cbdb35bf3a..b22ecde9ef 100644 --- a/src/openai/cli/_api/completions.py +++ b/src/openai/cli/_api/completions.py @@ -8,7 +8,7 @@ from openai.types.completion import Completion from .._utils import get_client -from ..._types import NOT_GIVEN, NotGivenOr +from ..._types import Omittable, omit from ..._utils import is_given from .._errors import CLIError from .._models import BaseModel @@ -95,18 +95,18 @@ class CLICompletionCreateArgs(BaseModel): stream: bool = False prompt: Optional[str] = None - n: NotGivenOr[int] = NOT_GIVEN - stop: NotGivenOr[str] = NOT_GIVEN - user: NotGivenOr[str] = NOT_GIVEN - echo: NotGivenOr[bool] = NOT_GIVEN - suffix: NotGivenOr[str] = NOT_GIVEN - best_of: NotGivenOr[int] = NOT_GIVEN - top_p: NotGivenOr[float] = NOT_GIVEN - logprobs: NotGivenOr[int] = NOT_GIVEN - max_tokens: NotGivenOr[int] = NOT_GIVEN - temperature: NotGivenOr[float] = NOT_GIVEN - presence_penalty: NotGivenOr[float] = NOT_GIVEN - frequency_penalty: NotGivenOr[float] = NOT_GIVEN + n: Omittable[int] = omit + stop: Omittable[str] = omit + user: Omittable[str] = omit + echo: Omittable[bool] = omit + suffix: Omittable[str] = omit + best_of: Omittable[int] = omit + top_p: Omittable[float] = omit + logprobs: Omittable[int] = omit + max_tokens: Omittable[int] = omit + temperature: Omittable[float] = omit + presence_penalty: Omittable[float] = omit + frequency_penalty: Omittable[float] = omit class CLICompletions: diff --git a/src/openai/cli/_api/fine_tuning/jobs.py b/src/openai/cli/_api/fine_tuning/jobs.py index 806fa0f788..a4e429108a 100644 --- a/src/openai/cli/_api/fine_tuning/jobs.py +++ b/src/openai/cli/_api/fine_tuning/jobs.py @@ -5,7 +5,8 @@ from argparse import ArgumentParser from ..._utils import get_client, print_model -from ...._types import NOT_GIVEN, NotGivenOr +from ...._types import Omittable, omit +from ...._utils import is_given from ..._models import BaseModel from ....pagination import SyncCursorPage from ....types.fine_tuning import ( @@ -105,9 +106,9 @@ def register(subparser: _SubParsersAction[ArgumentParser]) -> None: class CLIFineTuningJobsCreateArgs(BaseModel): model: str training_file: str - hyperparameters: NotGivenOr[str] = NOT_GIVEN - suffix: NotGivenOr[str] = NOT_GIVEN - validation_file: NotGivenOr[str] = NOT_GIVEN + hyperparameters: Omittable[str] = omit + suffix: Omittable[str] = omit + validation_file: Omittable[str] = omit class CLIFineTuningJobsRetrieveArgs(BaseModel): @@ -115,8 +116,8 @@ class CLIFineTuningJobsRetrieveArgs(BaseModel): class CLIFineTuningJobsListArgs(BaseModel): - after: NotGivenOr[str] = NOT_GIVEN - limit: NotGivenOr[int] = NOT_GIVEN + after: Omittable[str] = omit + limit: Omittable[int] = omit class CLIFineTuningJobsCancelArgs(BaseModel): @@ -125,14 +126,14 @@ class CLIFineTuningJobsCancelArgs(BaseModel): class CLIFineTuningJobsListEventsArgs(BaseModel): id: str - after: NotGivenOr[str] = NOT_GIVEN - limit: NotGivenOr[int] = NOT_GIVEN + after: Omittable[str] = omit + limit: Omittable[int] = omit class CLIFineTuningJobs: @staticmethod def create(args: CLIFineTuningJobsCreateArgs) -> None: - hyperparameters = json.loads(str(args.hyperparameters)) if args.hyperparameters is not NOT_GIVEN else NOT_GIVEN + hyperparameters = json.loads(str(args.hyperparameters)) if is_given(args.hyperparameters) else omit fine_tuning_job: FineTuningJob = get_client().fine_tuning.jobs.create( model=args.model, training_file=args.training_file, @@ -150,7 +151,7 @@ def retrieve(args: CLIFineTuningJobsRetrieveArgs) -> None: @staticmethod def list(args: CLIFineTuningJobsListArgs) -> None: fine_tuning_jobs: SyncCursorPage[FineTuningJob] = get_client().fine_tuning.jobs.list( - after=args.after or NOT_GIVEN, limit=args.limit or NOT_GIVEN + after=args.after or omit, limit=args.limit or omit ) print_model(fine_tuning_jobs) @@ -163,7 +164,7 @@ def cancel(args: CLIFineTuningJobsCancelArgs) -> None: def list_events(args: CLIFineTuningJobsListEventsArgs) -> None: fine_tuning_job_events: SyncCursorPage[FineTuningJobEvent] = get_client().fine_tuning.jobs.list_events( fine_tuning_job_id=args.id, - after=args.after or NOT_GIVEN, - limit=args.limit or NOT_GIVEN, + after=args.after or omit, + limit=args.limit or omit, ) print_model(fine_tuning_job_events) diff --git a/src/openai/cli/_api/image.py b/src/openai/cli/_api/image.py index 3e2a0a90f1..1d0cf810c1 100644 --- a/src/openai/cli/_api/image.py +++ b/src/openai/cli/_api/image.py @@ -4,7 +4,7 @@ from argparse import ArgumentParser from .._utils import get_client, print_model -from ..._types import NOT_GIVEN, NotGiven, NotGivenOr +from ..._types import Omit, Omittable, omit from .._models import BaseModel from .._progress import BufferReader @@ -63,7 +63,7 @@ class CLIImageCreateArgs(BaseModel): num_images: int size: str response_format: str - model: NotGivenOr[str] = NOT_GIVEN + model: Omittable[str] = omit class CLIImageCreateVariationArgs(BaseModel): @@ -71,7 +71,7 @@ class CLIImageCreateVariationArgs(BaseModel): num_images: int size: str response_format: str - model: NotGivenOr[str] = NOT_GIVEN + model: Omittable[str] = omit class CLIImageEditArgs(BaseModel): @@ -80,8 +80,8 @@ class CLIImageEditArgs(BaseModel): size: str response_format: str prompt: str - mask: NotGivenOr[str] = NOT_GIVEN - model: NotGivenOr[str] = NOT_GIVEN + mask: Omittable[str] = omit + model: Omittable[str] = omit class CLIImage: @@ -119,8 +119,8 @@ def edit(args: CLIImageEditArgs) -> None: with open(args.image, "rb") as file_reader: buffer_reader = BufferReader(file_reader.read(), desc="Image upload progress") - if isinstance(args.mask, NotGiven): - mask: NotGivenOr[BufferReader] = NOT_GIVEN + if isinstance(args.mask, Omit): + mask: Omittable[BufferReader] = omit else: with open(args.mask, "rb") as file_reader: mask = BufferReader(file_reader.read(), desc="Mask progress") @@ -130,7 +130,7 @@ def edit(args: CLIImageEditArgs) -> None: prompt=args.prompt, image=("image", buffer_reader), n=args.num_images, - mask=("mask", mask) if not isinstance(mask, NotGiven) else mask, + mask=("mask", mask) if not isinstance(mask, Omit) else mask, # casts required because the API is typed for enums # but we don't want to validate that here for forwards-compat size=cast(Any, args.size), diff --git a/src/openai/lib/_parsing/_completions.py b/src/openai/lib/_parsing/_completions.py index 4b8b78b70a..7903732a4a 100644 --- a/src/openai/lib/_parsing/_completions.py +++ b/src/openai/lib/_parsing/_completions.py @@ -8,7 +8,7 @@ import pydantic from .._tools import PydanticFunctionTool -from ..._types import NOT_GIVEN, NotGiven +from ..._types import Omit, omit from ..._utils import is_dict, is_given from ..._compat import PYDANTIC_V1, model_parse_json from ..._models import construct_type_unchecked @@ -53,20 +53,20 @@ def is_strict_chat_completion_tool_param( def select_strict_chat_completion_tools( - tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, -) -> Iterable[ChatCompletionFunctionToolParam] | NotGiven: + tools: Iterable[ChatCompletionToolUnionParam] | Omit = omit, +) -> Iterable[ChatCompletionFunctionToolParam] | Omit: """Select only the strict ChatCompletionFunctionToolParams from the given tools.""" if not is_given(tools): - return NOT_GIVEN + return omit return [t for t in tools if is_strict_chat_completion_tool_param(t)] def validate_input_tools( - tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, -) -> Iterable[ChatCompletionFunctionToolParam] | NotGiven: + tools: Iterable[ChatCompletionToolUnionParam] | Omit = omit, +) -> Iterable[ChatCompletionFunctionToolParam] | Omit: if not is_given(tools): - return NOT_GIVEN + return omit for tool in tools: if tool["type"] != "function": @@ -85,8 +85,8 @@ def validate_input_tools( def parse_chat_completion( *, - response_format: type[ResponseFormatT] | completion_create_params.ResponseFormat | NotGiven, - input_tools: Iterable[ChatCompletionToolUnionParam] | NotGiven, + response_format: type[ResponseFormatT] | completion_create_params.ResponseFormat | Omit, + input_tools: Iterable[ChatCompletionToolUnionParam] | Omit, chat_completion: ChatCompletion | ParsedChatCompletion[object], ) -> ParsedChatCompletion[ResponseFormatT]: if is_given(input_tools): @@ -192,7 +192,7 @@ def parse_function_tool_arguments( def maybe_parse_content( *, - response_format: type[ResponseFormatT] | ResponseFormatParam | NotGiven, + response_format: type[ResponseFormatT] | ResponseFormatParam | Omit, message: ChatCompletionMessage | ParsedChatCompletionMessage[object], ) -> ResponseFormatT | None: if has_rich_response_format(response_format) and message.content and not message.refusal: @@ -202,7 +202,7 @@ def maybe_parse_content( def solve_response_format_t( - response_format: type[ResponseFormatT] | ResponseFormatParam | NotGiven, + response_format: type[ResponseFormatT] | ResponseFormatParam | Omit, ) -> type[ResponseFormatT]: """Return the runtime type for the given response format. @@ -217,8 +217,8 @@ def solve_response_format_t( def has_parseable_input( *, - response_format: type | ResponseFormatParam | NotGiven, - input_tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, + response_format: type | ResponseFormatParam | Omit, + input_tools: Iterable[ChatCompletionToolUnionParam] | Omit = omit, ) -> bool: if has_rich_response_format(response_format): return True @@ -231,7 +231,7 @@ def has_parseable_input( def has_rich_response_format( - response_format: type[ResponseFormatT] | ResponseFormatParam | NotGiven, + response_format: type[ResponseFormatT] | ResponseFormatParam | Omit, ) -> TypeGuard[type[ResponseFormatT]]: if not is_given(response_format): return False @@ -271,10 +271,10 @@ def _parse_content(response_format: type[ResponseFormatT], content: str) -> Resp def type_to_response_format_param( - response_format: type | completion_create_params.ResponseFormat | NotGiven, -) -> ResponseFormatParam | NotGiven: + response_format: type | completion_create_params.ResponseFormat | Omit, +) -> ResponseFormatParam | Omit: if not is_given(response_format): - return NOT_GIVEN + return omit if is_response_format_param(response_format): return response_format diff --git a/src/openai/lib/_parsing/_responses.py b/src/openai/lib/_parsing/_responses.py index b6ebde0e8e..8a1bf3cf2c 100644 --- a/src/openai/lib/_parsing/_responses.py +++ b/src/openai/lib/_parsing/_responses.py @@ -7,7 +7,7 @@ import pydantic from .._tools import ResponsesPydanticFunctionTool -from ..._types import NotGiven +from ..._types import Omit from ..._utils import is_given from ..._compat import PYDANTIC_V1, model_parse_json from ..._models import construct_type_unchecked @@ -52,8 +52,8 @@ def type_to_text_format_param(type_: type) -> ResponseFormatTextConfigParam: def parse_response( *, - text_format: type[TextFormatT] | NotGiven, - input_tools: Iterable[ToolParam] | NotGiven | None, + text_format: type[TextFormatT] | Omit, + input_tools: Iterable[ToolParam] | Omit | None, response: Response | ParsedResponse[object], ) -> ParsedResponse[TextFormatT]: solved_t = solve_response_format_t(text_format) @@ -130,7 +130,7 @@ def parse_response( ) -def parse_text(text: str, text_format: type[TextFormatT] | NotGiven) -> TextFormatT | None: +def parse_text(text: str, text_format: type[TextFormatT] | Omit) -> TextFormatT | None: if not is_given(text_format): return None @@ -156,7 +156,7 @@ def get_input_tool_by_name(*, input_tools: Iterable[ToolParam], name: str) -> Fu def parse_function_tool_arguments( *, - input_tools: Iterable[ToolParam] | NotGiven | None, + input_tools: Iterable[ToolParam] | Omit | None, function_call: ParsedResponseFunctionToolCall | ResponseFunctionToolCall, ) -> object: if input_tools is None or not is_given(input_tools): diff --git a/src/openai/lib/streaming/chat/_completions.py b/src/openai/lib/streaming/chat/_completions.py index 52a6a550b2..c4610e2120 100644 --- a/src/openai/lib/streaming/chat/_completions.py +++ b/src/openai/lib/streaming/chat/_completions.py @@ -23,7 +23,7 @@ FunctionToolCallArgumentsDeltaEvent, ) from .._deltas import accumulate_delta -from ...._types import NOT_GIVEN, IncEx, NotGiven +from ...._types import Omit, IncEx, omit from ...._utils import is_given, consume_sync_iterator, consume_async_iterator from ...._compat import model_dump from ...._models import build, construct_type @@ -57,8 +57,8 @@ def __init__( self, *, raw_stream: Stream[ChatCompletionChunk], - response_format: type[ResponseFormatT] | ResponseFormatParam | NotGiven, - input_tools: Iterable[ChatCompletionToolUnionParam] | NotGiven, + response_format: type[ResponseFormatT] | ResponseFormatParam | Omit, + input_tools: Iterable[ChatCompletionToolUnionParam] | Omit, ) -> None: self._raw_stream = raw_stream self._response = raw_stream.response @@ -138,8 +138,8 @@ def __init__( self, api_request: Callable[[], Stream[ChatCompletionChunk]], *, - response_format: type[ResponseFormatT] | ResponseFormatParam | NotGiven, - input_tools: Iterable[ChatCompletionToolUnionParam] | NotGiven, + response_format: type[ResponseFormatT] | ResponseFormatParam | Omit, + input_tools: Iterable[ChatCompletionToolUnionParam] | Omit, ) -> None: self.__stream: ChatCompletionStream[ResponseFormatT] | None = None self.__api_request = api_request @@ -180,8 +180,8 @@ def __init__( self, *, raw_stream: AsyncStream[ChatCompletionChunk], - response_format: type[ResponseFormatT] | ResponseFormatParam | NotGiven, - input_tools: Iterable[ChatCompletionToolUnionParam] | NotGiven, + response_format: type[ResponseFormatT] | ResponseFormatParam | Omit, + input_tools: Iterable[ChatCompletionToolUnionParam] | Omit, ) -> None: self._raw_stream = raw_stream self._response = raw_stream.response @@ -261,8 +261,8 @@ def __init__( self, api_request: Awaitable[AsyncStream[ChatCompletionChunk]], *, - response_format: type[ResponseFormatT] | ResponseFormatParam | NotGiven, - input_tools: Iterable[ChatCompletionToolUnionParam] | NotGiven, + response_format: type[ResponseFormatT] | ResponseFormatParam | Omit, + input_tools: Iterable[ChatCompletionToolUnionParam] | Omit, ) -> None: self.__stream: AsyncChatCompletionStream[ResponseFormatT] | None = None self.__api_request = api_request @@ -314,15 +314,15 @@ class ChatCompletionStreamState(Generic[ResponseFormatT]): def __init__( self, *, - input_tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, - response_format: type[ResponseFormatT] | ResponseFormatParam | NotGiven = NOT_GIVEN, + input_tools: Iterable[ChatCompletionToolUnionParam] | Omit = omit, + response_format: type[ResponseFormatT] | ResponseFormatParam | Omit = omit, ) -> None: self.__current_completion_snapshot: ParsedChatCompletionSnapshot | None = None self.__choice_event_states: list[ChoiceEventState] = [] self._input_tools = [tool for tool in input_tools] if is_given(input_tools) else [] self._response_format = response_format - self._rich_response_format: type | NotGiven = response_format if inspect.isclass(response_format) else NOT_GIVEN + self._rich_response_format: type | Omit = response_format if inspect.isclass(response_format) else omit def get_final_completion(self) -> ParsedChatCompletion[ResponseFormatT]: """Parse the final completion object. @@ -599,7 +599,7 @@ def get_done_events( *, choice_chunk: ChoiceChunk, choice_snapshot: ParsedChoiceSnapshot, - response_format: type[ResponseFormatT] | ResponseFormatParam | NotGiven, + response_format: type[ResponseFormatT] | ResponseFormatParam | Omit, ) -> list[ChatCompletionStreamEvent[ResponseFormatT]]: events_to_fire: list[ChatCompletionStreamEvent[ResponseFormatT]] = [] @@ -639,7 +639,7 @@ def _content_done_events( self, *, choice_snapshot: ParsedChoiceSnapshot, - response_format: type[ResponseFormatT] | ResponseFormatParam | NotGiven, + response_format: type[ResponseFormatT] | ResponseFormatParam | Omit, ) -> list[ChatCompletionStreamEvent[ResponseFormatT]]: events_to_fire: list[ChatCompletionStreamEvent[ResponseFormatT]] = [] diff --git a/src/openai/lib/streaming/responses/_responses.py b/src/openai/lib/streaming/responses/_responses.py index d45664de45..6975a9260d 100644 --- a/src/openai/lib/streaming/responses/_responses.py +++ b/src/openai/lib/streaming/responses/_responses.py @@ -13,7 +13,7 @@ ResponseTextDeltaEvent, ResponseFunctionCallArgumentsDeltaEvent, ) -from ...._types import NOT_GIVEN, NotGiven +from ...._types import Omit, omit from ...._utils import is_given, consume_sync_iterator, consume_async_iterator from ...._models import build, construct_type_unchecked from ...._streaming import Stream, AsyncStream @@ -32,8 +32,8 @@ def __init__( self, *, raw_stream: Stream[RawResponseStreamEvent], - text_format: type[TextFormatT] | NotGiven, - input_tools: Iterable[ToolParam] | NotGiven, + text_format: type[TextFormatT] | Omit, + input_tools: Iterable[ToolParam] | Omit, starting_after: int | None, ) -> None: self._raw_stream = raw_stream @@ -97,8 +97,8 @@ def __init__( self, api_request: Callable[[], Stream[RawResponseStreamEvent]], *, - text_format: type[TextFormatT] | NotGiven, - input_tools: Iterable[ToolParam] | NotGiven, + text_format: type[TextFormatT] | Omit, + input_tools: Iterable[ToolParam] | Omit, starting_after: int | None, ) -> None: self.__stream: ResponseStream[TextFormatT] | None = None @@ -134,8 +134,8 @@ def __init__( self, *, raw_stream: AsyncStream[RawResponseStreamEvent], - text_format: type[TextFormatT] | NotGiven, - input_tools: Iterable[ToolParam] | NotGiven, + text_format: type[TextFormatT] | Omit, + input_tools: Iterable[ToolParam] | Omit, starting_after: int | None, ) -> None: self._raw_stream = raw_stream @@ -199,8 +199,8 @@ def __init__( self, api_request: Awaitable[AsyncStream[RawResponseStreamEvent]], *, - text_format: type[TextFormatT] | NotGiven, - input_tools: Iterable[ToolParam] | NotGiven, + text_format: type[TextFormatT] | Omit, + input_tools: Iterable[ToolParam] | Omit, starting_after: int | None, ) -> None: self.__stream: AsyncResponseStream[TextFormatT] | None = None @@ -235,14 +235,14 @@ class ResponseStreamState(Generic[TextFormatT]): def __init__( self, *, - input_tools: Iterable[ToolParam] | NotGiven, - text_format: type[TextFormatT] | NotGiven, + input_tools: Iterable[ToolParam] | Omit, + text_format: type[TextFormatT] | Omit, ) -> None: self.__current_snapshot: ParsedResponseSnapshot | None = None self._completed_response: ParsedResponse[TextFormatT] | None = None self._input_tools = [tool for tool in input_tools] if is_given(input_tools) else [] self._text_format = text_format - self._rich_text_format: type | NotGiven = text_format if inspect.isclass(text_format) else NOT_GIVEN + self._rich_text_format: type | Omit = text_format if inspect.isclass(text_format) else omit def handle_event(self, event: RawResponseStreamEvent) -> List[ResponseStreamEvent[TextFormatT]]: self.__current_snapshot = snapshot = self.accumulate_event(event) diff --git a/src/openai/resources/audio/speech.py b/src/openai/resources/audio/speech.py index 64ce5eec49..992fb5971a 100644 --- a/src/openai/resources/audio/speech.py +++ b/src/openai/resources/audio/speech.py @@ -8,7 +8,7 @@ import httpx from ... import _legacy_response -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given from ..._utils import maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource @@ -53,16 +53,16 @@ def create( voice: Union[ str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"] ], - instructions: str | NotGiven = NOT_GIVEN, - response_format: Literal["mp3", "opus", "aac", "flac", "wav", "pcm"] | NotGiven = NOT_GIVEN, - speed: float | NotGiven = NOT_GIVEN, - stream_format: Literal["sse", "audio"] | NotGiven = NOT_GIVEN, + instructions: str | Omit = omit, + response_format: Literal["mp3", "opus", "aac", "flac", "wav", "pcm"] | Omit = omit, + speed: float | Omit = omit, + stream_format: Literal["sse", "audio"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> _legacy_response.HttpxBinaryResponseContent: """ Generates audio from the input text. @@ -149,16 +149,16 @@ async def create( voice: Union[ str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"] ], - instructions: str | NotGiven = NOT_GIVEN, - response_format: Literal["mp3", "opus", "aac", "flac", "wav", "pcm"] | NotGiven = NOT_GIVEN, - speed: float | NotGiven = NOT_GIVEN, - stream_format: Literal["sse", "audio"] | NotGiven = NOT_GIVEN, + instructions: str | Omit = omit, + response_format: Literal["mp3", "opus", "aac", "flac", "wav", "pcm"] | Omit = omit, + speed: float | Omit = omit, + stream_format: Literal["sse", "audio"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> _legacy_response.HttpxBinaryResponseContent: """ Generates audio from the input text. diff --git a/src/openai/resources/audio/transcriptions.py b/src/openai/resources/audio/transcriptions.py index 208f6e8b05..1fe8866562 100644 --- a/src/openai/resources/audio/transcriptions.py +++ b/src/openai/resources/audio/transcriptions.py @@ -10,7 +10,7 @@ from ... import _legacy_response from ...types import AudioResponseFormat -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven, FileTypes +from ..._types import Body, Omit, Query, Headers, NotGiven, FileTypes, omit, not_given from ..._utils import extract_files, required_args, maybe_transform, deepcopy_minimal, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource @@ -57,19 +57,19 @@ def create( *, file: FileTypes, model: Union[str, AudioModel], - chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | NotGiven = NOT_GIVEN, - include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, - response_format: Union[Literal["json"], NotGiven] = NOT_GIVEN, - language: str | NotGiven = NOT_GIVEN, - prompt: str | NotGiven = NOT_GIVEN, - temperature: float | NotGiven = NOT_GIVEN, - timestamp_granularities: List[Literal["word", "segment"]] | NotGiven = NOT_GIVEN, + chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | Omit = omit, + include: List[TranscriptionInclude] | Omit = omit, + response_format: Union[Literal["json"], Omit] = omit, + language: str | Omit = omit, + prompt: str | Omit = omit, + temperature: float | Omit = omit, + timestamp_granularities: List[Literal["word", "segment"]] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Transcription: ... @overload @@ -78,19 +78,19 @@ def create( *, file: FileTypes, model: Union[str, AudioModel], - chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | NotGiven = NOT_GIVEN, - include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, + chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | Omit = omit, + include: List[TranscriptionInclude] | Omit = omit, response_format: Literal["verbose_json"], - language: str | NotGiven = NOT_GIVEN, - prompt: str | NotGiven = NOT_GIVEN, - temperature: float | NotGiven = NOT_GIVEN, - timestamp_granularities: List[Literal["word", "segment"]] | NotGiven = NOT_GIVEN, + language: str | Omit = omit, + prompt: str | Omit = omit, + temperature: float | Omit = omit, + timestamp_granularities: List[Literal["word", "segment"]] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TranscriptionVerbose: ... @overload @@ -99,19 +99,19 @@ def create( *, file: FileTypes, model: Union[str, AudioModel], - chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | NotGiven = NOT_GIVEN, + chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | Omit = omit, response_format: Literal["text", "srt", "vtt"], - include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, - language: str | NotGiven = NOT_GIVEN, - prompt: str | NotGiven = NOT_GIVEN, - temperature: float | NotGiven = NOT_GIVEN, - timestamp_granularities: List[Literal["word", "segment"]] | NotGiven = NOT_GIVEN, + include: List[TranscriptionInclude] | Omit = omit, + language: str | Omit = omit, + prompt: str | Omit = omit, + temperature: float | Omit = omit, + timestamp_granularities: List[Literal["word", "segment"]] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> str: ... @overload @@ -121,19 +121,19 @@ def create( file: FileTypes, model: Union[str, AudioModel], stream: Literal[True], - chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | NotGiven = NOT_GIVEN, - include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, - language: str | NotGiven = NOT_GIVEN, - prompt: str | NotGiven = NOT_GIVEN, - response_format: Union[AudioResponseFormat, NotGiven] = NOT_GIVEN, - temperature: float | NotGiven = NOT_GIVEN, - timestamp_granularities: List[Literal["word", "segment"]] | NotGiven = NOT_GIVEN, + chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | Omit = omit, + include: List[TranscriptionInclude] | Omit = omit, + language: str | Omit = omit, + prompt: str | Omit = omit, + response_format: Union[AudioResponseFormat, Omit] = omit, + temperature: float | Omit = omit, + timestamp_granularities: List[Literal["word", "segment"]] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Stream[TranscriptionStreamEvent]: """ Transcribes audio into the input language. @@ -209,19 +209,19 @@ def create( file: FileTypes, model: Union[str, AudioModel], stream: bool, - chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | NotGiven = NOT_GIVEN, - include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, - language: str | NotGiven = NOT_GIVEN, - prompt: str | NotGiven = NOT_GIVEN, - response_format: Union[AudioResponseFormat, NotGiven] = NOT_GIVEN, - temperature: float | NotGiven = NOT_GIVEN, - timestamp_granularities: List[Literal["word", "segment"]] | NotGiven = NOT_GIVEN, + chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | Omit = omit, + include: List[TranscriptionInclude] | Omit = omit, + language: str | Omit = omit, + prompt: str | Omit = omit, + response_format: Union[AudioResponseFormat, Omit] = omit, + temperature: float | Omit = omit, + timestamp_granularities: List[Literal["word", "segment"]] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TranscriptionCreateResponse | Stream[TranscriptionStreamEvent]: """ Transcribes audio into the input language. @@ -296,20 +296,20 @@ def create( *, file: FileTypes, model: Union[str, AudioModel], - chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | NotGiven = NOT_GIVEN, - include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, - language: str | NotGiven = NOT_GIVEN, - prompt: str | NotGiven = NOT_GIVEN, - response_format: Union[AudioResponseFormat, NotGiven] = NOT_GIVEN, - stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, - temperature: float | NotGiven = NOT_GIVEN, - timestamp_granularities: List[Literal["word", "segment"]] | NotGiven = NOT_GIVEN, + chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | Omit = omit, + include: List[TranscriptionInclude] | Omit = omit, + language: str | Omit = omit, + prompt: str | Omit = omit, + response_format: Union[AudioResponseFormat, Omit] = omit, + stream: Optional[Literal[False]] | Literal[True] | Omit = omit, + temperature: float | Omit = omit, + timestamp_granularities: List[Literal["word", "segment"]] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> str | Transcription | TranscriptionVerbose | Stream[TranscriptionStreamEvent]: body = deepcopy_minimal( { @@ -374,20 +374,20 @@ async def create( *, file: FileTypes, model: Union[str, AudioModel], - chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | NotGiven = NOT_GIVEN, - include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, - language: str | NotGiven = NOT_GIVEN, - prompt: str | NotGiven = NOT_GIVEN, - response_format: Union[Literal["json"], NotGiven] = NOT_GIVEN, - stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, - temperature: float | NotGiven = NOT_GIVEN, - timestamp_granularities: List[Literal["word", "segment"]] | NotGiven = NOT_GIVEN, + chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | Omit = omit, + include: List[TranscriptionInclude] | Omit = omit, + language: str | Omit = omit, + prompt: str | Omit = omit, + response_format: Union[Literal["json"], Omit] = omit, + stream: Optional[Literal[False]] | Omit = omit, + temperature: float | Omit = omit, + timestamp_granularities: List[Literal["word", "segment"]] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TranscriptionCreateResponse: """ Transcribes audio into the input language. @@ -457,19 +457,19 @@ async def create( *, file: FileTypes, model: Union[str, AudioModel], - chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | NotGiven = NOT_GIVEN, - include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, + chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | Omit = omit, + include: List[TranscriptionInclude] | Omit = omit, response_format: Literal["verbose_json"], - language: str | NotGiven = NOT_GIVEN, - prompt: str | NotGiven = NOT_GIVEN, - temperature: float | NotGiven = NOT_GIVEN, - timestamp_granularities: List[Literal["word", "segment"]] | NotGiven = NOT_GIVEN, + language: str | Omit = omit, + prompt: str | Omit = omit, + temperature: float | Omit = omit, + timestamp_granularities: List[Literal["word", "segment"]] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TranscriptionVerbose: ... @overload @@ -478,19 +478,19 @@ async def create( *, file: FileTypes, model: Union[str, AudioModel], - chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | NotGiven = NOT_GIVEN, - include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, + chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | Omit = omit, + include: List[TranscriptionInclude] | Omit = omit, response_format: Literal["text", "srt", "vtt"], - language: str | NotGiven = NOT_GIVEN, - prompt: str | NotGiven = NOT_GIVEN, - temperature: float | NotGiven = NOT_GIVEN, - timestamp_granularities: List[Literal["word", "segment"]] | NotGiven = NOT_GIVEN, + language: str | Omit = omit, + prompt: str | Omit = omit, + temperature: float | Omit = omit, + timestamp_granularities: List[Literal["word", "segment"]] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> str: ... @overload @@ -500,19 +500,19 @@ async def create( file: FileTypes, model: Union[str, AudioModel], stream: Literal[True], - chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | NotGiven = NOT_GIVEN, - include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, - language: str | NotGiven = NOT_GIVEN, - prompt: str | NotGiven = NOT_GIVEN, - response_format: Union[AudioResponseFormat, NotGiven] = NOT_GIVEN, - temperature: float | NotGiven = NOT_GIVEN, - timestamp_granularities: List[Literal["word", "segment"]] | NotGiven = NOT_GIVEN, + chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | Omit = omit, + include: List[TranscriptionInclude] | Omit = omit, + language: str | Omit = omit, + prompt: str | Omit = omit, + response_format: Union[AudioResponseFormat, Omit] = omit, + temperature: float | Omit = omit, + timestamp_granularities: List[Literal["word", "segment"]] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncStream[TranscriptionStreamEvent]: """ Transcribes audio into the input language. @@ -588,19 +588,19 @@ async def create( file: FileTypes, model: Union[str, AudioModel], stream: bool, - chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | NotGiven = NOT_GIVEN, - include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, - language: str | NotGiven = NOT_GIVEN, - prompt: str | NotGiven = NOT_GIVEN, - response_format: Union[AudioResponseFormat, NotGiven] = NOT_GIVEN, - temperature: float | NotGiven = NOT_GIVEN, - timestamp_granularities: List[Literal["word", "segment"]] | NotGiven = NOT_GIVEN, + chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | Omit = omit, + include: List[TranscriptionInclude] | Omit = omit, + language: str | Omit = omit, + prompt: str | Omit = omit, + response_format: Union[AudioResponseFormat, Omit] = omit, + temperature: float | Omit = omit, + timestamp_granularities: List[Literal["word", "segment"]] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TranscriptionCreateResponse | AsyncStream[TranscriptionStreamEvent]: """ Transcribes audio into the input language. @@ -675,20 +675,20 @@ async def create( *, file: FileTypes, model: Union[str, AudioModel], - chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | NotGiven = NOT_GIVEN, - include: List[TranscriptionInclude] | NotGiven = NOT_GIVEN, - language: str | NotGiven = NOT_GIVEN, - prompt: str | NotGiven = NOT_GIVEN, - response_format: Union[AudioResponseFormat, NotGiven] = NOT_GIVEN, - stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, - temperature: float | NotGiven = NOT_GIVEN, - timestamp_granularities: List[Literal["word", "segment"]] | NotGiven = NOT_GIVEN, + chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | Omit = omit, + include: List[TranscriptionInclude] | Omit = omit, + language: str | Omit = omit, + prompt: str | Omit = omit, + response_format: Union[AudioResponseFormat, Omit] = omit, + stream: Optional[Literal[False]] | Literal[True] | Omit = omit, + temperature: float | Omit = omit, + timestamp_granularities: List[Literal["word", "segment"]] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Transcription | TranscriptionVerbose | str | AsyncStream[TranscriptionStreamEvent]: body = deepcopy_minimal( { @@ -764,9 +764,9 @@ def __init__(self, transcriptions: AsyncTranscriptions) -> None: def _get_response_format_type( - response_format: Literal["json", "text", "srt", "verbose_json", "vtt"] | NotGiven, + response_format: Literal["json", "text", "srt", "verbose_json", "vtt"] | Omit, ) -> type[Transcription | TranscriptionVerbose | str]: - if isinstance(response_format, NotGiven) or response_format is None: # pyright: ignore[reportUnnecessaryComparison] + if isinstance(response_format, Omit) or response_format is None: # pyright: ignore[reportUnnecessaryComparison] return Transcription if response_format == "json": diff --git a/src/openai/resources/audio/translations.py b/src/openai/resources/audio/translations.py index 28b577ce2e..a4f844db13 100644 --- a/src/openai/resources/audio/translations.py +++ b/src/openai/resources/audio/translations.py @@ -9,7 +9,7 @@ import httpx from ... import _legacy_response -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven, FileTypes +from ..._types import Body, Omit, Query, Headers, NotGiven, FileTypes, omit, not_given from ..._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource @@ -52,15 +52,15 @@ def create( *, file: FileTypes, model: Union[str, AudioModel], - response_format: Union[Literal["json"], NotGiven] = NOT_GIVEN, - prompt: str | NotGiven = NOT_GIVEN, - temperature: float | NotGiven = NOT_GIVEN, + response_format: Union[Literal["json"], Omit] = omit, + prompt: str | Omit = omit, + temperature: float | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Translation: ... @overload @@ -70,14 +70,14 @@ def create( file: FileTypes, model: Union[str, AudioModel], response_format: Literal["verbose_json"], - prompt: str | NotGiven = NOT_GIVEN, - temperature: float | NotGiven = NOT_GIVEN, + prompt: str | Omit = omit, + temperature: float | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TranslationVerbose: ... @overload @@ -87,14 +87,14 @@ def create( file: FileTypes, model: Union[str, AudioModel], response_format: Literal["text", "srt", "vtt"], - prompt: str | NotGiven = NOT_GIVEN, - temperature: float | NotGiven = NOT_GIVEN, + prompt: str | Omit = omit, + temperature: float | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> str: ... def create( @@ -102,15 +102,15 @@ def create( *, file: FileTypes, model: Union[str, AudioModel], - prompt: str | NotGiven = NOT_GIVEN, - response_format: Union[Literal["json", "text", "srt", "verbose_json", "vtt"], NotGiven] = NOT_GIVEN, - temperature: float | NotGiven = NOT_GIVEN, + prompt: str | Omit = omit, + response_format: Union[Literal["json", "text", "srt", "verbose_json", "vtt"], Omit] = omit, + temperature: float | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Translation | TranslationVerbose | str: """ Translates audio into English. @@ -195,15 +195,15 @@ async def create( *, file: FileTypes, model: Union[str, AudioModel], - response_format: Union[Literal["json"], NotGiven] = NOT_GIVEN, - prompt: str | NotGiven = NOT_GIVEN, - temperature: float | NotGiven = NOT_GIVEN, + response_format: Union[Literal["json"], Omit] = omit, + prompt: str | Omit = omit, + temperature: float | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Translation: ... @overload @@ -213,14 +213,14 @@ async def create( file: FileTypes, model: Union[str, AudioModel], response_format: Literal["verbose_json"], - prompt: str | NotGiven = NOT_GIVEN, - temperature: float | NotGiven = NOT_GIVEN, + prompt: str | Omit = omit, + temperature: float | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TranslationVerbose: ... @overload @@ -230,14 +230,14 @@ async def create( file: FileTypes, model: Union[str, AudioModel], response_format: Literal["text", "srt", "vtt"], - prompt: str | NotGiven = NOT_GIVEN, - temperature: float | NotGiven = NOT_GIVEN, + prompt: str | Omit = omit, + temperature: float | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> str: ... async def create( @@ -245,15 +245,15 @@ async def create( *, file: FileTypes, model: Union[str, AudioModel], - prompt: str | NotGiven = NOT_GIVEN, - response_format: Union[AudioResponseFormat, NotGiven] = NOT_GIVEN, - temperature: float | NotGiven = NOT_GIVEN, + prompt: str | Omit = omit, + response_format: Union[AudioResponseFormat, Omit] = omit, + temperature: float | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Translation | TranslationVerbose | str: """ Translates audio into English. @@ -349,9 +349,9 @@ def __init__(self, translations: AsyncTranslations) -> None: def _get_response_format_type( - response_format: Literal["json", "text", "srt", "verbose_json", "vtt"] | NotGiven, + response_format: Literal["json", "text", "srt", "verbose_json", "vtt"] | Omit, ) -> type[Translation | TranslationVerbose | str]: - if isinstance(response_format, NotGiven) or response_format is None: # pyright: ignore[reportUnnecessaryComparison] + if isinstance(response_format, Omit) or response_format is None: # pyright: ignore[reportUnnecessaryComparison] return Translation if response_format == "json": diff --git a/src/openai/resources/batches.py b/src/openai/resources/batches.py index 2340bd2e32..afc7fa6eb9 100644 --- a/src/openai/resources/batches.py +++ b/src/openai/resources/batches.py @@ -9,7 +9,7 @@ from .. import _legacy_response from ..types import batch_list_params, batch_create_params -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given from .._utils import maybe_transform, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource @@ -48,14 +48,14 @@ def create( completion_window: Literal["24h"], endpoint: Literal["/v1/responses", "/v1/chat/completions", "/v1/embeddings", "/v1/completions"], input_file_id: str, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - output_expires_after: batch_create_params.OutputExpiresAfter | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | Omit = omit, + output_expires_after: batch_create_params.OutputExpiresAfter | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Batch: """ Creates and executes a batch from an uploaded file of requests @@ -124,7 +124,7 @@ def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Batch: """ Retrieves a batch. @@ -151,14 +151,14 @@ def retrieve( def list( self, *, - after: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + limit: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncCursorPage[Batch]: """List your organization's batches. @@ -209,7 +209,7 @@ def cancel( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Batch: """Cancels an in-progress batch. @@ -263,14 +263,14 @@ async def create( completion_window: Literal["24h"], endpoint: Literal["/v1/responses", "/v1/chat/completions", "/v1/embeddings", "/v1/completions"], input_file_id: str, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - output_expires_after: batch_create_params.OutputExpiresAfter | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | Omit = omit, + output_expires_after: batch_create_params.OutputExpiresAfter | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Batch: """ Creates and executes a batch from an uploaded file of requests @@ -339,7 +339,7 @@ async def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Batch: """ Retrieves a batch. @@ -366,14 +366,14 @@ async def retrieve( def list( self, *, - after: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + limit: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[Batch, AsyncCursorPage[Batch]]: """List your organization's batches. @@ -424,7 +424,7 @@ async def cancel( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Batch: """Cancels an in-progress batch. diff --git a/src/openai/resources/beta/assistants.py b/src/openai/resources/beta/assistants.py index fe0c99c88a..ddac9a79cb 100644 --- a/src/openai/resources/beta/assistants.py +++ b/src/openai/resources/beta/assistants.py @@ -8,7 +8,7 @@ import httpx from ... import _legacy_response -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given from ..._utils import maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource @@ -55,22 +55,22 @@ def create( self, *, model: Union[str, ChatModel], - description: Optional[str] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - name: Optional[str] | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | 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, - tools: Iterable[AssistantToolParam] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, + description: Optional[str] | Omit = omit, + instructions: Optional[str] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + name: Optional[str] | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_resources: Optional[assistant_create_params.ToolResources] | Omit = omit, + tools: Iterable[AssistantToolParam] | Omit = omit, + top_p: Optional[float] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Assistant: """ Create an assistant with a model and instructions. @@ -184,7 +184,7 @@ def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Assistant: """ Retrieves an assistant. @@ -213,9 +213,9 @@ def update( self, assistant_id: str, *, - description: Optional[str] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + description: Optional[str] | Omit = omit, + instructions: Optional[str] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, model: Union[ str, Literal[ @@ -263,20 +263,20 @@ def update( "gpt-3.5-turbo-16k-0613", ], ] - | NotGiven = NOT_GIVEN, - name: Optional[str] | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | 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, - tools: Iterable[AssistantToolParam] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, + | Omit = omit, + name: Optional[str] | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_resources: Optional[assistant_update_params.ToolResources] | Omit = omit, + tools: Iterable[AssistantToolParam] | Omit = omit, + top_p: Optional[float] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Assistant: """Modifies an assistant. @@ -387,16 +387,16 @@ def update( def list( self, *, - after: str | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + before: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncCursorPage[Assistant]: """Returns a list of assistants. @@ -458,7 +458,7 @@ def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AssistantDeleted: """ Delete an assistant. @@ -508,22 +508,22 @@ async def create( self, *, model: Union[str, ChatModel], - description: Optional[str] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - name: Optional[str] | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | 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, - tools: Iterable[AssistantToolParam] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, + description: Optional[str] | Omit = omit, + instructions: Optional[str] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + name: Optional[str] | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_resources: Optional[assistant_create_params.ToolResources] | Omit = omit, + tools: Iterable[AssistantToolParam] | Omit = omit, + top_p: Optional[float] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Assistant: """ Create an assistant with a model and instructions. @@ -637,7 +637,7 @@ async def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Assistant: """ Retrieves an assistant. @@ -666,9 +666,9 @@ async def update( self, assistant_id: str, *, - description: Optional[str] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + description: Optional[str] | Omit = omit, + instructions: Optional[str] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, model: Union[ str, Literal[ @@ -716,20 +716,20 @@ async def update( "gpt-3.5-turbo-16k-0613", ], ] - | NotGiven = NOT_GIVEN, - name: Optional[str] | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | 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, - tools: Iterable[AssistantToolParam] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, + | Omit = omit, + name: Optional[str] | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_resources: Optional[assistant_update_params.ToolResources] | Omit = omit, + tools: Iterable[AssistantToolParam] | Omit = omit, + top_p: Optional[float] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Assistant: """Modifies an assistant. @@ -840,16 +840,16 @@ async def update( def list( self, *, - after: str | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + before: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[Assistant, AsyncCursorPage[Assistant]]: """Returns a list of assistants. @@ -911,7 +911,7 @@ async def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AssistantDeleted: """ Delete an assistant. diff --git a/src/openai/resources/beta/threads/messages.py b/src/openai/resources/beta/threads/messages.py index 8903ff0316..d94ecca9a2 100644 --- a/src/openai/resources/beta/threads/messages.py +++ b/src/openai/resources/beta/threads/messages.py @@ -9,7 +9,7 @@ import httpx from .... import _legacy_response -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given from ...._utils import maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource @@ -55,14 +55,14 @@ def create( *, content: Union[str, Iterable[MessageContentPartParam]], role: Literal["user", "assistant"], - attachments: Optional[Iterable[message_create_params.Attachment]] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + attachments: Optional[Iterable[message_create_params.Attachment]] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Message: """ Create a message. @@ -126,7 +126,7 @@ def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Message: """ Retrieve a message. @@ -159,13 +159,13 @@ def update( message_id: str, *, thread_id: str, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Message: """ Modifies a message. @@ -205,17 +205,17 @@ def list( self, thread_id: str, *, - after: str | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, - run_id: str | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + before: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + run_id: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncCursorPage[Message]: """ Returns a list of messages for a given thread. @@ -283,7 +283,7 @@ def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MessageDeleted: """ Deletes a message. @@ -338,14 +338,14 @@ async def create( *, content: Union[str, Iterable[MessageContentPartParam]], role: Literal["user", "assistant"], - attachments: Optional[Iterable[message_create_params.Attachment]] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + attachments: Optional[Iterable[message_create_params.Attachment]] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Message: """ Create a message. @@ -409,7 +409,7 @@ async def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Message: """ Retrieve a message. @@ -442,13 +442,13 @@ async def update( message_id: str, *, thread_id: str, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Message: """ Modifies a message. @@ -488,17 +488,17 @@ def list( self, thread_id: str, *, - after: str | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, - run_id: str | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + before: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + run_id: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[Message, AsyncCursorPage[Message]]: """ Returns a list of messages for a given thread. @@ -566,7 +566,7 @@ async def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MessageDeleted: """ Deletes a message. diff --git a/src/openai/resources/beta/threads/runs/runs.py b/src/openai/resources/beta/threads/runs/runs.py index e97d519a40..ec2dfa84cd 100644 --- a/src/openai/resources/beta/threads/runs/runs.py +++ b/src/openai/resources/beta/threads/runs/runs.py @@ -18,7 +18,7 @@ StepsWithStreamingResponse, AsyncStepsWithStreamingResponse, ) -from ....._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ....._types import NOT_GIVEN, Body, Omit, Query, Headers, NotGiven, omit, not_given from ....._utils import ( is_given, required_args, @@ -89,29 +89,29 @@ def create( thread_id: str, *, assistant_id: str, - include: List[RunStepInclude] | NotGiven = NOT_GIVEN, - additional_instructions: Optional[str] | NotGiven = NOT_GIVEN, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, - stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + include: List[RunStepInclude] | Omit = omit, + additional_instructions: Optional[str] | Omit = omit, + additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + stream: Optional[Literal[False]] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Run: """ Create a run. @@ -240,28 +240,28 @@ def create( *, assistant_id: str, stream: Literal[True], - include: List[RunStepInclude] | NotGiven = NOT_GIVEN, - additional_instructions: Optional[str] | NotGiven = NOT_GIVEN, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + include: List[RunStepInclude] | Omit = omit, + additional_instructions: Optional[str] | Omit = omit, + additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Stream[AssistantStreamEvent]: """ Create a run. @@ -390,28 +390,28 @@ def create( *, assistant_id: str, stream: bool, - include: List[RunStepInclude] | NotGiven = NOT_GIVEN, - additional_instructions: Optional[str] | NotGiven = NOT_GIVEN, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + include: List[RunStepInclude] | Omit = omit, + additional_instructions: Optional[str] | Omit = omit, + additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Run | Stream[AssistantStreamEvent]: """ Create a run. @@ -539,29 +539,29 @@ def create( thread_id: str, *, assistant_id: str, - include: List[RunStepInclude] | NotGiven = NOT_GIVEN, - additional_instructions: Optional[str] | NotGiven = NOT_GIVEN, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | 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, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + include: List[RunStepInclude] | Omit = omit, + additional_instructions: Optional[str] | Omit = omit, + additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + stream: Optional[Literal[False]] | Literal[True] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Run | Stream[AssistantStreamEvent]: if not thread_id: raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") @@ -613,7 +613,7 @@ def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Run: """ Retrieves a run. @@ -646,13 +646,13 @@ def update( run_id: str, *, thread_id: str, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Run: """ Modifies a run. @@ -692,16 +692,16 @@ def list( self, thread_id: str, *, - after: str | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + before: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncCursorPage[Run]: """ Returns a list of runs belonging to a thread. @@ -766,7 +766,7 @@ def cancel( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Run: """ Cancels a run that is `in_progress`. @@ -798,23 +798,23 @@ def create_and_poll( self, *, assistant_id: str, - include: List[RunStepInclude] | NotGiven = NOT_GIVEN, - additional_instructions: Optional[str] | NotGiven = NOT_GIVEN, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, - poll_interval_ms: int | NotGiven = NOT_GIVEN, + include: List[RunStepInclude] | Omit = omit, + additional_instructions: Optional[str] | Omit = omit, + additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, + poll_interval_ms: int | Omit = omit, thread_id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -870,21 +870,21 @@ def create_and_stream( self, *, assistant_id: str, - additional_instructions: Optional[str] | NotGiven = NOT_GIVEN, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + additional_instructions: Optional[str] | Omit = omit, + additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, thread_id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -902,21 +902,21 @@ def create_and_stream( self, *, assistant_id: str, - additional_instructions: Optional[str] | NotGiven = NOT_GIVEN, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + additional_instructions: Optional[str] | Omit = omit, + additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, thread_id: str, event_handler: AssistantEventHandlerT, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -934,21 +934,21 @@ def create_and_stream( self, *, assistant_id: str, - additional_instructions: Optional[str] | NotGiven = NOT_GIVEN, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + additional_instructions: Optional[str] | Omit = omit, + additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, thread_id: str, event_handler: AssistantEventHandlerT | None = None, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -1010,8 +1010,8 @@ def poll( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - poll_interval_ms: int | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + poll_interval_ms: int | Omit = omit, ) -> Run: """ A helper to poll a run status until it reaches a terminal state. More @@ -1054,22 +1054,22 @@ def stream( self, *, assistant_id: str, - include: List[RunStepInclude] | NotGiven = NOT_GIVEN, - additional_instructions: Optional[str] | NotGiven = NOT_GIVEN, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + include: List[RunStepInclude] | Omit = omit, + additional_instructions: Optional[str] | Omit = omit, + additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, thread_id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -1087,22 +1087,22 @@ def stream( self, *, assistant_id: str, - include: List[RunStepInclude] | NotGiven = NOT_GIVEN, - additional_instructions: Optional[str] | NotGiven = NOT_GIVEN, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + include: List[RunStepInclude] | Omit = omit, + additional_instructions: Optional[str] | Omit = omit, + additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, thread_id: str, event_handler: AssistantEventHandlerT, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -1120,22 +1120,22 @@ def stream( self, *, assistant_id: str, - include: List[RunStepInclude] | NotGiven = NOT_GIVEN, - additional_instructions: Optional[str] | NotGiven = NOT_GIVEN, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + include: List[RunStepInclude] | Omit = omit, + additional_instructions: Optional[str] | Omit = omit, + additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, thread_id: str, event_handler: AssistantEventHandlerT | None = None, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -1201,13 +1201,13 @@ def submit_tool_outputs( *, thread_id: str, tool_outputs: Iterable[run_submit_tool_outputs_params.ToolOutput], - stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, + stream: Optional[Literal[False]] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Run: """ When a run has the `status: "requires_action"` and `required_action.type` is @@ -1246,7 +1246,7 @@ def submit_tool_outputs( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Stream[AssistantStreamEvent]: """ When a run has the `status: "requires_action"` and `required_action.type` is @@ -1285,7 +1285,7 @@ def submit_tool_outputs( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Run | Stream[AssistantStreamEvent]: """ When a run has the `status: "requires_action"` and `required_action.type` is @@ -1319,13 +1319,13 @@ def submit_tool_outputs( *, thread_id: str, tool_outputs: Iterable[run_submit_tool_outputs_params.ToolOutput], - stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, + stream: Optional[Literal[False]] | Literal[True] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Run | Stream[AssistantStreamEvent]: if not thread_id: raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") @@ -1358,7 +1358,7 @@ def submit_tool_outputs_and_poll( tool_outputs: Iterable[run_submit_tool_outputs_params.ToolOutput], run_id: str, thread_id: str, - poll_interval_ms: int | NotGiven = NOT_GIVEN, + poll_interval_ms: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1519,29 +1519,29 @@ async def create( thread_id: str, *, assistant_id: str, - include: List[RunStepInclude] | NotGiven = NOT_GIVEN, - additional_instructions: Optional[str] | NotGiven = NOT_GIVEN, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, - stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + include: List[RunStepInclude] | Omit = omit, + additional_instructions: Optional[str] | Omit = omit, + additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + stream: Optional[Literal[False]] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Run: """ Create a run. @@ -1670,28 +1670,28 @@ async def create( *, assistant_id: str, stream: Literal[True], - include: List[RunStepInclude] | NotGiven = NOT_GIVEN, - additional_instructions: Optional[str] | NotGiven = NOT_GIVEN, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + include: List[RunStepInclude] | Omit = omit, + additional_instructions: Optional[str] | Omit = omit, + additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncStream[AssistantStreamEvent]: """ Create a run. @@ -1820,28 +1820,28 @@ async def create( *, assistant_id: str, stream: bool, - include: List[RunStepInclude] | NotGiven = NOT_GIVEN, - additional_instructions: Optional[str] | NotGiven = NOT_GIVEN, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + include: List[RunStepInclude] | Omit = omit, + additional_instructions: Optional[str] | Omit = omit, + additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Run | AsyncStream[AssistantStreamEvent]: """ Create a run. @@ -1970,29 +1970,29 @@ async def create( thread_id: str, *, assistant_id: str, - include: List[RunStepInclude] | NotGiven = NOT_GIVEN, - additional_instructions: Optional[str] | NotGiven = NOT_GIVEN, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | 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, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + include: List[RunStepInclude] | Omit = omit, + additional_instructions: Optional[str] | Omit = omit, + additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + stream: Optional[Literal[False]] | Literal[True] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Run | AsyncStream[AssistantStreamEvent]: if not thread_id: raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") @@ -2044,7 +2044,7 @@ async def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Run: """ Retrieves a run. @@ -2077,13 +2077,13 @@ async def update( run_id: str, *, thread_id: str, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Run: """ Modifies a run. @@ -2123,16 +2123,16 @@ def list( self, thread_id: str, *, - after: str | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + before: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[Run, AsyncCursorPage[Run]]: """ Returns a list of runs belonging to a thread. @@ -2197,7 +2197,7 @@ async def cancel( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Run: """ Cancels a run that is `in_progress`. @@ -2229,23 +2229,23 @@ async def create_and_poll( self, *, assistant_id: str, - include: List[RunStepInclude] | NotGiven = NOT_GIVEN, - additional_instructions: Optional[str] | NotGiven = NOT_GIVEN, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, - poll_interval_ms: int | NotGiven = NOT_GIVEN, + include: List[RunStepInclude] | Omit = omit, + additional_instructions: Optional[str] | Omit = omit, + additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, + poll_interval_ms: int | Omit = omit, thread_id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -2301,20 +2301,20 @@ def create_and_stream( self, *, assistant_id: str, - additional_instructions: Optional[str] | NotGiven = NOT_GIVEN, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + additional_instructions: Optional[str] | Omit = omit, + additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, thread_id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -2332,20 +2332,20 @@ def create_and_stream( self, *, assistant_id: str, - additional_instructions: Optional[str] | NotGiven = NOT_GIVEN, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + additional_instructions: Optional[str] | Omit = omit, + additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, thread_id: str, event_handler: AsyncAssistantEventHandlerT, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -2363,20 +2363,20 @@ def create_and_stream( self, *, assistant_id: str, - additional_instructions: Optional[str] | NotGiven = NOT_GIVEN, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + additional_instructions: Optional[str] | Omit = omit, + additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, thread_id: str, event_handler: AsyncAssistantEventHandlerT | None = None, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -2439,8 +2439,8 @@ async def poll( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - poll_interval_ms: int | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + poll_interval_ms: int | Omit = omit, ) -> Run: """ A helper to poll a run status until it reaches a terminal state. More @@ -2483,21 +2483,21 @@ def stream( self, *, assistant_id: str, - additional_instructions: Optional[str] | NotGiven = NOT_GIVEN, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + additional_instructions: Optional[str] | Omit = omit, + additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, thread_id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -2515,22 +2515,22 @@ def stream( self, *, assistant_id: str, - include: List[RunStepInclude] | NotGiven = NOT_GIVEN, - additional_instructions: Optional[str] | NotGiven = NOT_GIVEN, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + include: List[RunStepInclude] | Omit = omit, + additional_instructions: Optional[str] | Omit = omit, + additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, thread_id: str, event_handler: AsyncAssistantEventHandlerT, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -2548,22 +2548,22 @@ def stream( self, *, assistant_id: str, - include: List[RunStepInclude] | NotGiven = NOT_GIVEN, - additional_instructions: Optional[str] | NotGiven = NOT_GIVEN, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + include: List[RunStepInclude] | Omit = omit, + additional_instructions: Optional[str] | Omit = omit, + additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, thread_id: str, event_handler: AsyncAssistantEventHandlerT | None = None, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -2631,13 +2631,13 @@ async def submit_tool_outputs( *, thread_id: str, tool_outputs: Iterable[run_submit_tool_outputs_params.ToolOutput], - stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, + stream: Optional[Literal[False]] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Run: """ When a run has the `status: "requires_action"` and `required_action.type` is @@ -2676,7 +2676,7 @@ async def submit_tool_outputs( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncStream[AssistantStreamEvent]: """ When a run has the `status: "requires_action"` and `required_action.type` is @@ -2715,7 +2715,7 @@ async def submit_tool_outputs( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Run | AsyncStream[AssistantStreamEvent]: """ When a run has the `status: "requires_action"` and `required_action.type` is @@ -2749,13 +2749,13 @@ async def submit_tool_outputs( *, thread_id: str, tool_outputs: Iterable[run_submit_tool_outputs_params.ToolOutput], - stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, + stream: Optional[Literal[False]] | Literal[True] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Run | AsyncStream[AssistantStreamEvent]: if not thread_id: raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") @@ -2788,7 +2788,7 @@ async def submit_tool_outputs_and_poll( tool_outputs: Iterable[run_submit_tool_outputs_params.ToolOutput], run_id: str, thread_id: str, - poll_interval_ms: int | NotGiven = NOT_GIVEN, + poll_interval_ms: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, diff --git a/src/openai/resources/beta/threads/runs/steps.py b/src/openai/resources/beta/threads/runs/steps.py index 8e34210bd7..254a94435c 100644 --- a/src/openai/resources/beta/threads/runs/steps.py +++ b/src/openai/resources/beta/threads/runs/steps.py @@ -9,7 +9,7 @@ import httpx from ..... import _legacy_response -from ....._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given from ....._utils import maybe_transform, async_maybe_transform from ....._compat import cached_property from ....._resource import SyncAPIResource, AsyncAPIResource @@ -50,13 +50,13 @@ def retrieve( *, thread_id: str, run_id: str, - include: List[RunStepInclude] | NotGiven = NOT_GIVEN, + include: List[RunStepInclude] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> RunStep: """ Retrieves a run step. @@ -103,17 +103,17 @@ def list( run_id: str, *, thread_id: str, - after: str | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - include: List[RunStepInclude] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + before: str | Omit = omit, + include: List[RunStepInclude] | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncCursorPage[RunStep]: """ Returns a list of run steps belonging to a run. @@ -206,13 +206,13 @@ async def retrieve( *, thread_id: str, run_id: str, - include: List[RunStepInclude] | NotGiven = NOT_GIVEN, + include: List[RunStepInclude] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> RunStep: """ Retrieves a run step. @@ -259,17 +259,17 @@ def list( run_id: str, *, thread_id: str, - after: str | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - include: List[RunStepInclude] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + before: str | Omit = omit, + include: List[RunStepInclude] | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[RunStep, AsyncCursorPage[RunStep]]: """ Returns a list of run steps belonging to a run. diff --git a/src/openai/resources/beta/threads/threads.py b/src/openai/resources/beta/threads/threads.py index 7121851cab..681d3c2933 100644 --- a/src/openai/resources/beta/threads/threads.py +++ b/src/openai/resources/beta/threads/threads.py @@ -18,7 +18,7 @@ MessagesWithStreamingResponse, AsyncMessagesWithStreamingResponse, ) -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._types import NOT_GIVEN, Body, Omit, Query, Headers, NotGiven, omit, not_given from ...._utils import required_args, maybe_transform, async_maybe_transform from .runs.runs import ( Runs, @@ -91,15 +91,15 @@ def with_streaming_response(self) -> ThreadsWithStreamingResponse: def create( self, *, - messages: Iterable[thread_create_params.Message] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - tool_resources: Optional[thread_create_params.ToolResources] | NotGiven = NOT_GIVEN, + messages: Iterable[thread_create_params.Message] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + tool_resources: Optional[thread_create_params.ToolResources] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Thread: """ Create a thread. @@ -155,7 +155,7 @@ def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Thread: """ Retrieves a thread. @@ -185,14 +185,14 @@ def update( self, thread_id: str, *, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - tool_resources: Optional[thread_update_params.ToolResources] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | Omit = omit, + tool_resources: Optional[thread_update_params.ToolResources] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Thread: """ Modifies a thread. @@ -246,7 +246,7 @@ def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ThreadDeleted: """ Delete a thread. @@ -277,27 +277,27 @@ def create_and_run( self, *, assistant_id: str, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, - stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - thread: thread_create_and_run_params.Thread | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + stream: Optional[Literal[False]] | Omit = omit, + temperature: Optional[float] | Omit = omit, + thread: thread_create_and_run_params.Thread | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tool_resources: Optional[thread_create_and_run_params.ToolResources] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Run: """ Create a thread and run it in one request. @@ -412,26 +412,26 @@ def create_and_run( *, assistant_id: str, stream: Literal[True], - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - thread: thread_create_and_run_params.Thread | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + thread: thread_create_and_run_params.Thread | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tool_resources: Optional[thread_create_and_run_params.ToolResources] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Stream[AssistantStreamEvent]: """ Create a thread and run it in one request. @@ -546,26 +546,26 @@ def create_and_run( *, assistant_id: str, stream: bool, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - thread: thread_create_and_run_params.Thread | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + thread: thread_create_and_run_params.Thread | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tool_resources: Optional[thread_create_and_run_params.ToolResources] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Run | Stream[AssistantStreamEvent]: """ Create a thread and run it in one request. @@ -680,27 +680,27 @@ def create_and_run( self, *, assistant_id: str, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | 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, - thread: thread_create_and_run_params.Thread | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + stream: Optional[Literal[False]] | Literal[True] | Omit = omit, + temperature: Optional[float] | Omit = omit, + thread: thread_create_and_run_params.Thread | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tool_resources: Optional[thread_create_and_run_params.ToolResources] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Run | Stream[AssistantStreamEvent]: extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( @@ -740,21 +740,21 @@ def create_and_run_poll( self, *, assistant_id: str, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - thread: thread_create_and_run_params.Thread | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, - poll_interval_ms: int | NotGiven = NOT_GIVEN, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + thread: thread_create_and_run_params.Thread | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tool_resources: Optional[thread_create_and_run_params.ToolResources] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | Omit = omit, + poll_interval_ms: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -796,20 +796,20 @@ def create_and_run_stream( self, *, assistant_id: str, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - thread: thread_create_and_run_params.Thread | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + thread: thread_create_and_run_params.Thread | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tool_resources: Optional[thread_create_and_run_params.ToolResources] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -825,20 +825,20 @@ def create_and_run_stream( self, *, assistant_id: str, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - thread: thread_create_and_run_params.Thread | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + thread: thread_create_and_run_params.Thread | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tool_resources: Optional[thread_create_and_run_params.ToolResources] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | Omit = omit, event_handler: AssistantEventHandlerT, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -854,20 +854,20 @@ def create_and_run_stream( self, *, assistant_id: str, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - thread: thread_create_and_run_params.Thread | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + thread: thread_create_and_run_params.Thread | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tool_resources: Optional[thread_create_and_run_params.ToolResources] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | Omit = omit, event_handler: AssistantEventHandlerT | None = None, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -949,15 +949,15 @@ def with_streaming_response(self) -> AsyncThreadsWithStreamingResponse: async def create( self, *, - messages: Iterable[thread_create_params.Message] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - tool_resources: Optional[thread_create_params.ToolResources] | NotGiven = NOT_GIVEN, + messages: Iterable[thread_create_params.Message] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + tool_resources: Optional[thread_create_params.ToolResources] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Thread: """ Create a thread. @@ -1013,7 +1013,7 @@ async def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Thread: """ Retrieves a thread. @@ -1043,14 +1043,14 @@ async def update( self, thread_id: str, *, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - tool_resources: Optional[thread_update_params.ToolResources] | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | Omit = omit, + tool_resources: Optional[thread_update_params.ToolResources] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Thread: """ Modifies a thread. @@ -1104,7 +1104,7 @@ async def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ThreadDeleted: """ Delete a thread. @@ -1135,27 +1135,27 @@ async def create_and_run( self, *, assistant_id: str, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, - stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - thread: thread_create_and_run_params.Thread | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + stream: Optional[Literal[False]] | Omit = omit, + temperature: Optional[float] | Omit = omit, + thread: thread_create_and_run_params.Thread | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tool_resources: Optional[thread_create_and_run_params.ToolResources] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Run: """ Create a thread and run it in one request. @@ -1270,26 +1270,26 @@ async def create_and_run( *, assistant_id: str, stream: Literal[True], - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - thread: thread_create_and_run_params.Thread | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + thread: thread_create_and_run_params.Thread | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tool_resources: Optional[thread_create_and_run_params.ToolResources] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncStream[AssistantStreamEvent]: """ Create a thread and run it in one request. @@ -1404,26 +1404,26 @@ async def create_and_run( *, assistant_id: str, stream: bool, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - thread: thread_create_and_run_params.Thread | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + thread: thread_create_and_run_params.Thread | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tool_resources: Optional[thread_create_and_run_params.ToolResources] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Run | AsyncStream[AssistantStreamEvent]: """ Create a thread and run it in one request. @@ -1538,27 +1538,27 @@ async def create_and_run( self, *, assistant_id: str, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | 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, - thread: thread_create_and_run_params.Thread | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + stream: Optional[Literal[False]] | Literal[True] | Omit = omit, + temperature: Optional[float] | Omit = omit, + thread: thread_create_and_run_params.Thread | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tool_resources: Optional[thread_create_and_run_params.ToolResources] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Run | AsyncStream[AssistantStreamEvent]: extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( @@ -1598,21 +1598,21 @@ async def create_and_run_poll( self, *, assistant_id: str, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - thread: thread_create_and_run_params.Thread | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, - poll_interval_ms: int | NotGiven = NOT_GIVEN, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + thread: thread_create_and_run_params.Thread | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tool_resources: Optional[thread_create_and_run_params.ToolResources] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | Omit = omit, + poll_interval_ms: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1656,20 +1656,20 @@ def create_and_run_stream( self, *, assistant_id: str, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - thread: thread_create_and_run_params.Thread | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + thread: thread_create_and_run_params.Thread | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tool_resources: Optional[thread_create_and_run_params.ToolResources] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1685,20 +1685,20 @@ def create_and_run_stream( self, *, assistant_id: str, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - thread: thread_create_and_run_params.Thread | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + thread: thread_create_and_run_params.Thread | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tool_resources: Optional[thread_create_and_run_params.ToolResources] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | Omit = omit, event_handler: AsyncAssistantEventHandlerT, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -1714,20 +1714,20 @@ def create_and_run_stream( self, *, assistant_id: str, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_prompt_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: Union[str, ChatModel, None] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - response_format: Optional[AssistantResponseFormatOptionParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - thread: thread_create_and_run_params.Thread | NotGiven = NOT_GIVEN, - tool_choice: Optional[AssistantToolChoiceOptionParam] | NotGiven = NOT_GIVEN, - tool_resources: Optional[thread_create_and_run_params.ToolResources] | NotGiven = NOT_GIVEN, - tools: Optional[Iterable[AssistantToolParam]] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | NotGiven = NOT_GIVEN, + instructions: Optional[str] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_prompt_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: Union[str, ChatModel, None] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + thread: thread_create_and_run_params.Thread | Omit = omit, + tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, + tool_resources: Optional[thread_create_and_run_params.ToolResources] | Omit = omit, + tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | Omit = omit, event_handler: AsyncAssistantEventHandlerT | None = None, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index f29792a207..329634ba43 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -19,7 +19,7 @@ MessagesWithStreamingResponse, AsyncMessagesWithStreamingResponse, ) -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr +from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given from ...._utils import required_args, maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource @@ -86,43 +86,43 @@ def parse( *, messages: Iterable[ChatCompletionMessageParam], model: Union[str, ChatModel], - audio: Optional[ChatCompletionAudioParam] | NotGiven = NOT_GIVEN, - response_format: type[ResponseFormatT] | NotGiven = NOT_GIVEN, - frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, - function_call: completion_create_params.FunctionCall | NotGiven = NOT_GIVEN, - functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, - logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, - logprobs: Optional[bool] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - modalities: Optional[List[Literal["text", "audio"]]] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, - presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - prompt_cache_key: str | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - safety_identifier: str | NotGiven = NOT_GIVEN, - seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, - tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, - top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, - verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, - web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, + audio: Optional[ChatCompletionAudioParam] | Omit = omit, + response_format: type[ResponseFormatT] | Omit = omit, + frequency_penalty: Optional[float] | Omit = omit, + function_call: completion_create_params.FunctionCall | Omit = omit, + functions: Iterable[completion_create_params.Function] | Omit = omit, + logit_bias: Optional[Dict[str, int]] | Omit = omit, + logprobs: Optional[bool] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, + n: Optional[int] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, + presence_penalty: Optional[float] | Omit = omit, + prompt_cache_key: str | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + safety_identifier: str | Omit = omit, + seed: Optional[int] | Omit = omit, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, + stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, + store: Optional[bool] | Omit = omit, + stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_choice: ChatCompletionToolChoiceOptionParam | Omit = omit, + tools: Iterable[ChatCompletionToolUnionParam] | Omit = omit, + top_logprobs: Optional[int] | Omit = omit, + top_p: Optional[float] | Omit = omit, + user: str | Omit = omit, + verbosity: Optional[Literal["low", "medium", "high"]] | Omit = omit, + web_search_options: completion_create_params.WebSearchOptions | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ParsedChatCompletion[ResponseFormatT]: """Wrapper over the `client.chat.completions.create()` method that provides richer integrations with Python specific types & returns a `ParsedChatCompletion` object, which is a subclass of the standard `ChatCompletion` class. @@ -240,44 +240,44 @@ def create( *, messages: Iterable[ChatCompletionMessageParam], model: Union[str, ChatModel], - audio: Optional[ChatCompletionAudioParam] | NotGiven = NOT_GIVEN, - frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, - function_call: completion_create_params.FunctionCall | NotGiven = NOT_GIVEN, - functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, - logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, - logprobs: Optional[bool] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - modalities: Optional[List[Literal["text", "audio"]]] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, - presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - prompt_cache_key: str | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, - safety_identifier: str | NotGiven = NOT_GIVEN, - seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, - stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, - tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, - top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, - verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, - web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, + audio: Optional[ChatCompletionAudioParam] | Omit = omit, + frequency_penalty: Optional[float] | Omit = omit, + function_call: completion_create_params.FunctionCall | Omit = omit, + functions: Iterable[completion_create_params.Function] | Omit = omit, + logit_bias: Optional[Dict[str, int]] | Omit = omit, + logprobs: Optional[bool] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, + n: Optional[int] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, + presence_penalty: Optional[float] | Omit = omit, + prompt_cache_key: str | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + response_format: completion_create_params.ResponseFormat | Omit = omit, + safety_identifier: str | Omit = omit, + seed: Optional[int] | Omit = omit, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, + stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, + store: Optional[bool] | Omit = omit, + stream: Optional[Literal[False]] | Omit = omit, + stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_choice: ChatCompletionToolChoiceOptionParam | Omit = omit, + tools: Iterable[ChatCompletionToolUnionParam] | Omit = omit, + top_logprobs: Optional[int] | Omit = omit, + top_p: Optional[float] | Omit = omit, + user: str | Omit = omit, + verbosity: Optional[Literal["low", "medium", "high"]] | Omit = omit, + web_search_options: completion_create_params.WebSearchOptions | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ChatCompletion: """ **Starting a new project?** We recommend trying @@ -529,43 +529,43 @@ def create( messages: Iterable[ChatCompletionMessageParam], model: Union[str, ChatModel], stream: Literal[True], - audio: Optional[ChatCompletionAudioParam] | NotGiven = NOT_GIVEN, - frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, - function_call: completion_create_params.FunctionCall | NotGiven = NOT_GIVEN, - functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, - logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, - logprobs: Optional[bool] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - modalities: Optional[List[Literal["text", "audio"]]] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, - presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - prompt_cache_key: str | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, - safety_identifier: str | NotGiven = NOT_GIVEN, - seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, - tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, - top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, - verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, - web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, + audio: Optional[ChatCompletionAudioParam] | Omit = omit, + frequency_penalty: Optional[float] | Omit = omit, + function_call: completion_create_params.FunctionCall | Omit = omit, + functions: Iterable[completion_create_params.Function] | Omit = omit, + logit_bias: Optional[Dict[str, int]] | Omit = omit, + logprobs: Optional[bool] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, + n: Optional[int] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, + presence_penalty: Optional[float] | Omit = omit, + prompt_cache_key: str | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + response_format: completion_create_params.ResponseFormat | Omit = omit, + safety_identifier: str | Omit = omit, + seed: Optional[int] | Omit = omit, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, + stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, + store: Optional[bool] | Omit = omit, + stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_choice: ChatCompletionToolChoiceOptionParam | Omit = omit, + tools: Iterable[ChatCompletionToolUnionParam] | Omit = omit, + top_logprobs: Optional[int] | Omit = omit, + top_p: Optional[float] | Omit = omit, + user: str | Omit = omit, + verbosity: Optional[Literal["low", "medium", "high"]] | Omit = omit, + web_search_options: completion_create_params.WebSearchOptions | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Stream[ChatCompletionChunk]: """ **Starting a new project?** We recommend trying @@ -817,43 +817,43 @@ def create( messages: Iterable[ChatCompletionMessageParam], model: Union[str, ChatModel], stream: bool, - audio: Optional[ChatCompletionAudioParam] | NotGiven = NOT_GIVEN, - frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, - function_call: completion_create_params.FunctionCall | NotGiven = NOT_GIVEN, - functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, - logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, - logprobs: Optional[bool] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - modalities: Optional[List[Literal["text", "audio"]]] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, - presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - prompt_cache_key: str | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, - safety_identifier: str | NotGiven = NOT_GIVEN, - seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, - tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, - top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, - verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, - web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, + audio: Optional[ChatCompletionAudioParam] | Omit = omit, + frequency_penalty: Optional[float] | Omit = omit, + function_call: completion_create_params.FunctionCall | Omit = omit, + functions: Iterable[completion_create_params.Function] | Omit = omit, + logit_bias: Optional[Dict[str, int]] | Omit = omit, + logprobs: Optional[bool] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, + n: Optional[int] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, + presence_penalty: Optional[float] | Omit = omit, + prompt_cache_key: str | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + response_format: completion_create_params.ResponseFormat | Omit = omit, + safety_identifier: str | Omit = omit, + seed: Optional[int] | Omit = omit, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, + stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, + store: Optional[bool] | Omit = omit, + stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_choice: ChatCompletionToolChoiceOptionParam | Omit = omit, + tools: Iterable[ChatCompletionToolUnionParam] | Omit = omit, + top_logprobs: Optional[int] | Omit = omit, + top_p: Optional[float] | Omit = omit, + user: str | Omit = omit, + verbosity: Optional[Literal["low", "medium", "high"]] | Omit = omit, + web_search_options: completion_create_params.WebSearchOptions | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ChatCompletion | Stream[ChatCompletionChunk]: """ **Starting a new project?** We recommend trying @@ -1104,44 +1104,44 @@ def create( *, messages: Iterable[ChatCompletionMessageParam], model: Union[str, ChatModel], - audio: Optional[ChatCompletionAudioParam] | NotGiven = NOT_GIVEN, - frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, - function_call: completion_create_params.FunctionCall | NotGiven = NOT_GIVEN, - functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, - logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, - logprobs: Optional[bool] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - modalities: Optional[List[Literal["text", "audio"]]] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, - presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - prompt_cache_key: str | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, - safety_identifier: str | NotGiven = NOT_GIVEN, - seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, - stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, - tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, - top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, - verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, - web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, + audio: Optional[ChatCompletionAudioParam] | Omit = omit, + frequency_penalty: Optional[float] | Omit = omit, + function_call: completion_create_params.FunctionCall | Omit = omit, + functions: Iterable[completion_create_params.Function] | Omit = omit, + logit_bias: Optional[Dict[str, int]] | Omit = omit, + logprobs: Optional[bool] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, + n: Optional[int] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, + presence_penalty: Optional[float] | Omit = omit, + prompt_cache_key: str | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + response_format: completion_create_params.ResponseFormat | Omit = omit, + safety_identifier: str | Omit = omit, + seed: Optional[int] | Omit = omit, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, + stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, + store: Optional[bool] | Omit = omit, + stream: Optional[Literal[False]] | Literal[True] | Omit = omit, + stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_choice: ChatCompletionToolChoiceOptionParam | Omit = omit, + tools: Iterable[ChatCompletionToolUnionParam] | Omit = omit, + top_logprobs: Optional[int] | Omit = omit, + top_p: Optional[float] | Omit = omit, + user: str | Omit = omit, + verbosity: Optional[Literal["low", "medium", "high"]] | Omit = omit, + web_search_options: completion_create_params.WebSearchOptions | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ChatCompletion | Stream[ChatCompletionChunk]: validate_response_format(response_format) return self._post( @@ -1204,7 +1204,7 @@ def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ChatCompletion: """Get a stored chat completion. @@ -1240,7 +1240,7 @@ def update( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ChatCompletion: """Modify a stored chat completion. @@ -1278,17 +1278,17 @@ def update( def list( self, *, - after: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: str | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + limit: int | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: str | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncCursorPage[ChatCompletion]: """List stored Chat Completions. @@ -1351,7 +1351,7 @@ def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ChatCompletionDeleted: """Delete a stored chat completion. @@ -1382,43 +1382,43 @@ def stream( *, messages: Iterable[ChatCompletionMessageParam], model: Union[str, ChatModel], - audio: Optional[ChatCompletionAudioParam] | NotGiven = NOT_GIVEN, - response_format: completion_create_params.ResponseFormat | type[ResponseFormatT] | NotGiven = NOT_GIVEN, - frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, - function_call: completion_create_params.FunctionCall | NotGiven = NOT_GIVEN, - functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, - logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, - logprobs: Optional[bool] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - modalities: Optional[List[Literal["text", "audio"]]] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, - presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - prompt_cache_key: str | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - safety_identifier: str | NotGiven = NOT_GIVEN, - seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, - tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, - top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, - verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, - web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, + audio: Optional[ChatCompletionAudioParam] | Omit = omit, + response_format: completion_create_params.ResponseFormat | type[ResponseFormatT] | Omit = omit, + frequency_penalty: Optional[float] | Omit = omit, + function_call: completion_create_params.FunctionCall | Omit = omit, + functions: Iterable[completion_create_params.Function] | Omit = omit, + logit_bias: Optional[Dict[str, int]] | Omit = omit, + logprobs: Optional[bool] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, + n: Optional[int] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, + presence_penalty: Optional[float] | Omit = omit, + prompt_cache_key: str | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + safety_identifier: str | Omit = omit, + seed: Optional[int] | Omit = omit, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, + stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, + store: Optional[bool] | Omit = omit, + stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_choice: ChatCompletionToolChoiceOptionParam | Omit = omit, + tools: Iterable[ChatCompletionToolUnionParam] | Omit = omit, + top_logprobs: Optional[int] | Omit = omit, + top_p: Optional[float] | Omit = omit, + user: str | Omit = omit, + verbosity: Optional[Literal["low", "medium", "high"]] | Omit = omit, + web_search_options: completion_create_params.WebSearchOptions | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ChatCompletionStreamManager[ResponseFormatT]: """Wrapper over the `client.chat.completions.create(stream=True)` method that provides a more granular event API and automatic accumulation of each delta. @@ -1524,43 +1524,43 @@ async def parse( *, messages: Iterable[ChatCompletionMessageParam], model: Union[str, ChatModel], - audio: Optional[ChatCompletionAudioParam] | NotGiven = NOT_GIVEN, - response_format: type[ResponseFormatT] | NotGiven = NOT_GIVEN, - frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, - function_call: completion_create_params.FunctionCall | NotGiven = NOT_GIVEN, - functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, - logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, - logprobs: Optional[bool] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - modalities: Optional[List[Literal["text", "audio"]]] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, - presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - prompt_cache_key: str | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - safety_identifier: str | NotGiven = NOT_GIVEN, - seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, - tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, - top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, - verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, - web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, + audio: Optional[ChatCompletionAudioParam] | Omit = omit, + response_format: type[ResponseFormatT] | Omit = omit, + frequency_penalty: Optional[float] | Omit = omit, + function_call: completion_create_params.FunctionCall | Omit = omit, + functions: Iterable[completion_create_params.Function] | Omit = omit, + logit_bias: Optional[Dict[str, int]] | Omit = omit, + logprobs: Optional[bool] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, + n: Optional[int] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, + presence_penalty: Optional[float] | Omit = omit, + prompt_cache_key: str | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + safety_identifier: str | Omit = omit, + seed: Optional[int] | Omit = omit, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, + stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, + store: Optional[bool] | Omit = omit, + stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_choice: ChatCompletionToolChoiceOptionParam | Omit = omit, + tools: Iterable[ChatCompletionToolUnionParam] | Omit = omit, + top_logprobs: Optional[int] | Omit = omit, + top_p: Optional[float] | Omit = omit, + user: str | Omit = omit, + verbosity: Optional[Literal["low", "medium", "high"]] | Omit = omit, + web_search_options: completion_create_params.WebSearchOptions | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ParsedChatCompletion[ResponseFormatT]: """Wrapper over the `client.chat.completions.create()` method that provides richer integrations with Python specific types & returns a `ParsedChatCompletion` object, which is a subclass of the standard `ChatCompletion` class. @@ -1678,44 +1678,44 @@ async def create( *, messages: Iterable[ChatCompletionMessageParam], model: Union[str, ChatModel], - audio: Optional[ChatCompletionAudioParam] | NotGiven = NOT_GIVEN, - frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, - function_call: completion_create_params.FunctionCall | NotGiven = NOT_GIVEN, - functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, - logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, - logprobs: Optional[bool] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - modalities: Optional[List[Literal["text", "audio"]]] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, - presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - prompt_cache_key: str | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, - safety_identifier: str | NotGiven = NOT_GIVEN, - seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, - stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, - tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, - top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, - verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, - web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, + audio: Optional[ChatCompletionAudioParam] | Omit = omit, + frequency_penalty: Optional[float] | Omit = omit, + function_call: completion_create_params.FunctionCall | Omit = omit, + functions: Iterable[completion_create_params.Function] | Omit = omit, + logit_bias: Optional[Dict[str, int]] | Omit = omit, + logprobs: Optional[bool] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, + n: Optional[int] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, + presence_penalty: Optional[float] | Omit = omit, + prompt_cache_key: str | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + response_format: completion_create_params.ResponseFormat | Omit = omit, + safety_identifier: str | Omit = omit, + seed: Optional[int] | Omit = omit, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, + stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, + store: Optional[bool] | Omit = omit, + stream: Optional[Literal[False]] | Omit = omit, + stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_choice: ChatCompletionToolChoiceOptionParam | Omit = omit, + tools: Iterable[ChatCompletionToolUnionParam] | Omit = omit, + top_logprobs: Optional[int] | Omit = omit, + top_p: Optional[float] | Omit = omit, + user: str | Omit = omit, + verbosity: Optional[Literal["low", "medium", "high"]] | Omit = omit, + web_search_options: completion_create_params.WebSearchOptions | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ChatCompletion: """ **Starting a new project?** We recommend trying @@ -1967,43 +1967,43 @@ async def create( messages: Iterable[ChatCompletionMessageParam], model: Union[str, ChatModel], stream: Literal[True], - audio: Optional[ChatCompletionAudioParam] | NotGiven = NOT_GIVEN, - frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, - function_call: completion_create_params.FunctionCall | NotGiven = NOT_GIVEN, - functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, - logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, - logprobs: Optional[bool] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - modalities: Optional[List[Literal["text", "audio"]]] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, - presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - prompt_cache_key: str | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, - safety_identifier: str | NotGiven = NOT_GIVEN, - seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, - tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, - top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, - verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, - web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, + audio: Optional[ChatCompletionAudioParam] | Omit = omit, + frequency_penalty: Optional[float] | Omit = omit, + function_call: completion_create_params.FunctionCall | Omit = omit, + functions: Iterable[completion_create_params.Function] | Omit = omit, + logit_bias: Optional[Dict[str, int]] | Omit = omit, + logprobs: Optional[bool] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, + n: Optional[int] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, + presence_penalty: Optional[float] | Omit = omit, + prompt_cache_key: str | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + response_format: completion_create_params.ResponseFormat | Omit = omit, + safety_identifier: str | Omit = omit, + seed: Optional[int] | Omit = omit, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, + stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, + store: Optional[bool] | Omit = omit, + stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_choice: ChatCompletionToolChoiceOptionParam | Omit = omit, + tools: Iterable[ChatCompletionToolUnionParam] | Omit = omit, + top_logprobs: Optional[int] | Omit = omit, + top_p: Optional[float] | Omit = omit, + user: str | Omit = omit, + verbosity: Optional[Literal["low", "medium", "high"]] | Omit = omit, + web_search_options: completion_create_params.WebSearchOptions | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncStream[ChatCompletionChunk]: """ **Starting a new project?** We recommend trying @@ -2255,43 +2255,43 @@ async def create( messages: Iterable[ChatCompletionMessageParam], model: Union[str, ChatModel], stream: bool, - audio: Optional[ChatCompletionAudioParam] | NotGiven = NOT_GIVEN, - frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, - function_call: completion_create_params.FunctionCall | NotGiven = NOT_GIVEN, - functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, - logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, - logprobs: Optional[bool] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - modalities: Optional[List[Literal["text", "audio"]]] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, - presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - prompt_cache_key: str | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, - safety_identifier: str | NotGiven = NOT_GIVEN, - seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, - tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, - top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, - verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, - web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, + audio: Optional[ChatCompletionAudioParam] | Omit = omit, + frequency_penalty: Optional[float] | Omit = omit, + function_call: completion_create_params.FunctionCall | Omit = omit, + functions: Iterable[completion_create_params.Function] | Omit = omit, + logit_bias: Optional[Dict[str, int]] | Omit = omit, + logprobs: Optional[bool] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, + n: Optional[int] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, + presence_penalty: Optional[float] | Omit = omit, + prompt_cache_key: str | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + response_format: completion_create_params.ResponseFormat | Omit = omit, + safety_identifier: str | Omit = omit, + seed: Optional[int] | Omit = omit, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, + stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, + store: Optional[bool] | Omit = omit, + stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_choice: ChatCompletionToolChoiceOptionParam | Omit = omit, + tools: Iterable[ChatCompletionToolUnionParam] | Omit = omit, + top_logprobs: Optional[int] | Omit = omit, + top_p: Optional[float] | Omit = omit, + user: str | Omit = omit, + verbosity: Optional[Literal["low", "medium", "high"]] | Omit = omit, + web_search_options: completion_create_params.WebSearchOptions | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ChatCompletion | AsyncStream[ChatCompletionChunk]: """ **Starting a new project?** We recommend trying @@ -2542,44 +2542,44 @@ async def create( *, messages: Iterable[ChatCompletionMessageParam], model: Union[str, ChatModel], - audio: Optional[ChatCompletionAudioParam] | NotGiven = NOT_GIVEN, - frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, - function_call: completion_create_params.FunctionCall | NotGiven = NOT_GIVEN, - functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, - logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, - logprobs: Optional[bool] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - modalities: Optional[List[Literal["text", "audio"]]] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, - presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - prompt_cache_key: str | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - response_format: completion_create_params.ResponseFormat | NotGiven = NOT_GIVEN, - safety_identifier: str | NotGiven = NOT_GIVEN, - seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, - stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, - tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, - top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, - verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, - web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, + audio: Optional[ChatCompletionAudioParam] | Omit = omit, + frequency_penalty: Optional[float] | Omit = omit, + function_call: completion_create_params.FunctionCall | Omit = omit, + functions: Iterable[completion_create_params.Function] | Omit = omit, + logit_bias: Optional[Dict[str, int]] | Omit = omit, + logprobs: Optional[bool] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, + n: Optional[int] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, + presence_penalty: Optional[float] | Omit = omit, + prompt_cache_key: str | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + response_format: completion_create_params.ResponseFormat | Omit = omit, + safety_identifier: str | Omit = omit, + seed: Optional[int] | Omit = omit, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, + stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, + store: Optional[bool] | Omit = omit, + stream: Optional[Literal[False]] | Literal[True] | Omit = omit, + stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_choice: ChatCompletionToolChoiceOptionParam | Omit = omit, + tools: Iterable[ChatCompletionToolUnionParam] | Omit = omit, + top_logprobs: Optional[int] | Omit = omit, + top_p: Optional[float] | Omit = omit, + user: str | Omit = omit, + verbosity: Optional[Literal["low", "medium", "high"]] | Omit = omit, + web_search_options: completion_create_params.WebSearchOptions | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ChatCompletion | AsyncStream[ChatCompletionChunk]: validate_response_format(response_format) return await self._post( @@ -2642,7 +2642,7 @@ async def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ChatCompletion: """Get a stored chat completion. @@ -2678,7 +2678,7 @@ async def update( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ChatCompletion: """Modify a stored chat completion. @@ -2716,17 +2716,17 @@ async def update( def list( self, *, - after: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: str | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + limit: int | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: str | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[ChatCompletion, AsyncCursorPage[ChatCompletion]]: """List stored Chat Completions. @@ -2789,7 +2789,7 @@ async def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ChatCompletionDeleted: """Delete a stored chat completion. @@ -2820,43 +2820,43 @@ def stream( *, messages: Iterable[ChatCompletionMessageParam], model: Union[str, ChatModel], - audio: Optional[ChatCompletionAudioParam] | NotGiven = NOT_GIVEN, - response_format: completion_create_params.ResponseFormat | type[ResponseFormatT] | NotGiven = NOT_GIVEN, - frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, - function_call: completion_create_params.FunctionCall | NotGiven = NOT_GIVEN, - functions: Iterable[completion_create_params.Function] | NotGiven = NOT_GIVEN, - logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, - logprobs: Optional[bool] | NotGiven = NOT_GIVEN, - max_completion_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - modalities: Optional[List[Literal["text", "audio"]]] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - parallel_tool_calls: bool | NotGiven = NOT_GIVEN, - prediction: Optional[ChatCompletionPredictionContentParam] | NotGiven = NOT_GIVEN, - presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - prompt_cache_key: str | NotGiven = NOT_GIVEN, - reasoning_effort: Optional[ReasoningEffort] | NotGiven = NOT_GIVEN, - safety_identifier: str | NotGiven = NOT_GIVEN, - seed: Optional[int] | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - tool_choice: ChatCompletionToolChoiceOptionParam | NotGiven = NOT_GIVEN, - tools: Iterable[ChatCompletionToolUnionParam] | NotGiven = NOT_GIVEN, - top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, - verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, - web_search_options: completion_create_params.WebSearchOptions | NotGiven = NOT_GIVEN, + audio: Optional[ChatCompletionAudioParam] | Omit = omit, + response_format: completion_create_params.ResponseFormat | type[ResponseFormatT] | Omit = omit, + frequency_penalty: Optional[float] | Omit = omit, + function_call: completion_create_params.FunctionCall | Omit = omit, + functions: Iterable[completion_create_params.Function] | Omit = omit, + logit_bias: Optional[Dict[str, int]] | Omit = omit, + logprobs: Optional[bool] | Omit = omit, + max_completion_tokens: Optional[int] | Omit = omit, + max_tokens: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, + n: Optional[int] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, + prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, + presence_penalty: Optional[float] | Omit = omit, + prompt_cache_key: str | Omit = omit, + reasoning_effort: Optional[ReasoningEffort] | Omit = omit, + safety_identifier: str | Omit = omit, + seed: Optional[int] | Omit = omit, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, + stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, + store: Optional[bool] | Omit = omit, + stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, + temperature: Optional[float] | Omit = omit, + tool_choice: ChatCompletionToolChoiceOptionParam | Omit = omit, + tools: Iterable[ChatCompletionToolUnionParam] | Omit = omit, + top_logprobs: Optional[int] | Omit = omit, + top_p: Optional[float] | Omit = omit, + user: str | Omit = omit, + verbosity: Optional[Literal["low", "medium", "high"]] | Omit = omit, + web_search_options: completion_create_params.WebSearchOptions | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncChatCompletionStreamManager[ResponseFormatT]: """Wrapper over the `client.chat.completions.create(stream=True)` method that provides a more granular event API and automatic accumulation of each delta. diff --git a/src/openai/resources/chat/completions/messages.py b/src/openai/resources/chat/completions/messages.py index fac15fba8b..3d6dc79cd6 100644 --- a/src/openai/resources/chat/completions/messages.py +++ b/src/openai/resources/chat/completions/messages.py @@ -7,7 +7,7 @@ import httpx from .... import _legacy_response -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given from ...._utils import maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource @@ -44,15 +44,15 @@ def list( self, completion_id: str, *, - after: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncCursorPage[ChatCompletionStoreMessage]: """Get the messages in a stored chat completion. @@ -122,15 +122,15 @@ def list( self, completion_id: str, *, - after: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[ChatCompletionStoreMessage, AsyncCursorPage[ChatCompletionStoreMessage]]: """Get the messages in a stored chat completion. diff --git a/src/openai/resources/completions.py b/src/openai/resources/completions.py index 97a84575ab..2f2284a622 100644 --- a/src/openai/resources/completions.py +++ b/src/openai/resources/completions.py @@ -9,7 +9,7 @@ from .. import _legacy_response from ..types import completion_create_params -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr +from .._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given from .._utils import required_args, maybe_transform, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource @@ -50,28 +50,28 @@ def create( *, model: Union[str, Literal["gpt-3.5-turbo-instruct", "davinci-002", "babbage-002"]], prompt: Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]], None], - best_of: Optional[int] | NotGiven = NOT_GIVEN, - echo: Optional[bool] | NotGiven = NOT_GIVEN, - frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, - logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, - logprobs: Optional[int] | NotGiven = NOT_GIVEN, - max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - seed: Optional[int] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, - stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, - stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, - suffix: Optional[str] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + best_of: Optional[int] | Omit = omit, + echo: Optional[bool] | Omit = omit, + frequency_penalty: Optional[float] | Omit = omit, + logit_bias: Optional[Dict[str, int]] | Omit = omit, + logprobs: Optional[int] | Omit = omit, + max_tokens: Optional[int] | Omit = omit, + n: Optional[int] | Omit = omit, + presence_penalty: Optional[float] | Omit = omit, + seed: Optional[int] | Omit = omit, + stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, + stream: Optional[Literal[False]] | Omit = omit, + stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, + suffix: Optional[str] | Omit = omit, + temperature: Optional[float] | Omit = omit, + top_p: Optional[float] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Completion: """ Creates a completion for the provided prompt and parameters. @@ -206,27 +206,27 @@ def create( model: Union[str, Literal["gpt-3.5-turbo-instruct", "davinci-002", "babbage-002"]], prompt: Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]], None], stream: Literal[True], - best_of: Optional[int] | NotGiven = NOT_GIVEN, - echo: Optional[bool] | NotGiven = NOT_GIVEN, - frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, - logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, - logprobs: Optional[int] | NotGiven = NOT_GIVEN, - max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - seed: Optional[int] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, - stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, - suffix: Optional[str] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + best_of: Optional[int] | Omit = omit, + echo: Optional[bool] | Omit = omit, + frequency_penalty: Optional[float] | Omit = omit, + logit_bias: Optional[Dict[str, int]] | Omit = omit, + logprobs: Optional[int] | Omit = omit, + max_tokens: Optional[int] | Omit = omit, + n: Optional[int] | Omit = omit, + presence_penalty: Optional[float] | Omit = omit, + seed: Optional[int] | Omit = omit, + stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, + stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, + suffix: Optional[str] | Omit = omit, + temperature: Optional[float] | Omit = omit, + top_p: Optional[float] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Stream[Completion]: """ Creates a completion for the provided prompt and parameters. @@ -361,27 +361,27 @@ def create( model: Union[str, Literal["gpt-3.5-turbo-instruct", "davinci-002", "babbage-002"]], prompt: Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]], None], stream: bool, - best_of: Optional[int] | NotGiven = NOT_GIVEN, - echo: Optional[bool] | NotGiven = NOT_GIVEN, - frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, - logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, - logprobs: Optional[int] | NotGiven = NOT_GIVEN, - max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - seed: Optional[int] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, - stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, - suffix: Optional[str] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + best_of: Optional[int] | Omit = omit, + echo: Optional[bool] | Omit = omit, + frequency_penalty: Optional[float] | Omit = omit, + logit_bias: Optional[Dict[str, int]] | Omit = omit, + logprobs: Optional[int] | Omit = omit, + max_tokens: Optional[int] | Omit = omit, + n: Optional[int] | Omit = omit, + presence_penalty: Optional[float] | Omit = omit, + seed: Optional[int] | Omit = omit, + stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, + stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, + suffix: Optional[str] | Omit = omit, + temperature: Optional[float] | Omit = omit, + top_p: Optional[float] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Completion | Stream[Completion]: """ Creates a completion for the provided prompt and parameters. @@ -515,28 +515,28 @@ def create( *, model: Union[str, Literal["gpt-3.5-turbo-instruct", "davinci-002", "babbage-002"]], prompt: Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]], None], - best_of: Optional[int] | NotGiven = NOT_GIVEN, - echo: Optional[bool] | NotGiven = NOT_GIVEN, - frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, - logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, - logprobs: Optional[int] | NotGiven = NOT_GIVEN, - max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - seed: Optional[int] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, - stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, - stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, - suffix: Optional[str] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + best_of: Optional[int] | Omit = omit, + echo: Optional[bool] | Omit = omit, + frequency_penalty: Optional[float] | Omit = omit, + logit_bias: Optional[Dict[str, int]] | Omit = omit, + logprobs: Optional[int] | Omit = omit, + max_tokens: Optional[int] | Omit = omit, + n: Optional[int] | Omit = omit, + presence_penalty: Optional[float] | Omit = omit, + seed: Optional[int] | Omit = omit, + stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, + stream: Optional[Literal[False]] | Literal[True] | Omit = omit, + stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, + suffix: Optional[str] | Omit = omit, + temperature: Optional[float] | Omit = omit, + top_p: Optional[float] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Completion | Stream[Completion]: return self._post( "/completions", @@ -600,28 +600,28 @@ async def create( *, model: Union[str, Literal["gpt-3.5-turbo-instruct", "davinci-002", "babbage-002"]], prompt: Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]], None], - best_of: Optional[int] | NotGiven = NOT_GIVEN, - echo: Optional[bool] | NotGiven = NOT_GIVEN, - frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, - logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, - logprobs: Optional[int] | NotGiven = NOT_GIVEN, - max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - seed: Optional[int] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, - stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, - stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, - suffix: Optional[str] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + best_of: Optional[int] | Omit = omit, + echo: Optional[bool] | Omit = omit, + frequency_penalty: Optional[float] | Omit = omit, + logit_bias: Optional[Dict[str, int]] | Omit = omit, + logprobs: Optional[int] | Omit = omit, + max_tokens: Optional[int] | Omit = omit, + n: Optional[int] | Omit = omit, + presence_penalty: Optional[float] | Omit = omit, + seed: Optional[int] | Omit = omit, + stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, + stream: Optional[Literal[False]] | Omit = omit, + stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, + suffix: Optional[str] | Omit = omit, + temperature: Optional[float] | Omit = omit, + top_p: Optional[float] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Completion: """ Creates a completion for the provided prompt and parameters. @@ -756,27 +756,27 @@ async def create( model: Union[str, Literal["gpt-3.5-turbo-instruct", "davinci-002", "babbage-002"]], prompt: Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]], None], stream: Literal[True], - best_of: Optional[int] | NotGiven = NOT_GIVEN, - echo: Optional[bool] | NotGiven = NOT_GIVEN, - frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, - logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, - logprobs: Optional[int] | NotGiven = NOT_GIVEN, - max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - seed: Optional[int] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, - stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, - suffix: Optional[str] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + best_of: Optional[int] | Omit = omit, + echo: Optional[bool] | Omit = omit, + frequency_penalty: Optional[float] | Omit = omit, + logit_bias: Optional[Dict[str, int]] | Omit = omit, + logprobs: Optional[int] | Omit = omit, + max_tokens: Optional[int] | Omit = omit, + n: Optional[int] | Omit = omit, + presence_penalty: Optional[float] | Omit = omit, + seed: Optional[int] | Omit = omit, + stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, + stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, + suffix: Optional[str] | Omit = omit, + temperature: Optional[float] | Omit = omit, + top_p: Optional[float] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncStream[Completion]: """ Creates a completion for the provided prompt and parameters. @@ -911,27 +911,27 @@ async def create( model: Union[str, Literal["gpt-3.5-turbo-instruct", "davinci-002", "babbage-002"]], prompt: Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]], None], stream: bool, - best_of: Optional[int] | NotGiven = NOT_GIVEN, - echo: Optional[bool] | NotGiven = NOT_GIVEN, - frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, - logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, - logprobs: Optional[int] | NotGiven = NOT_GIVEN, - max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - seed: Optional[int] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, - stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, - suffix: Optional[str] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + best_of: Optional[int] | Omit = omit, + echo: Optional[bool] | Omit = omit, + frequency_penalty: Optional[float] | Omit = omit, + logit_bias: Optional[Dict[str, int]] | Omit = omit, + logprobs: Optional[int] | Omit = omit, + max_tokens: Optional[int] | Omit = omit, + n: Optional[int] | Omit = omit, + presence_penalty: Optional[float] | Omit = omit, + seed: Optional[int] | Omit = omit, + stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, + stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, + suffix: Optional[str] | Omit = omit, + temperature: Optional[float] | Omit = omit, + top_p: Optional[float] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Completion | AsyncStream[Completion]: """ Creates a completion for the provided prompt and parameters. @@ -1065,28 +1065,28 @@ async def create( *, model: Union[str, Literal["gpt-3.5-turbo-instruct", "davinci-002", "babbage-002"]], prompt: Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]], None], - best_of: Optional[int] | NotGiven = NOT_GIVEN, - echo: Optional[bool] | NotGiven = NOT_GIVEN, - frequency_penalty: Optional[float] | NotGiven = NOT_GIVEN, - logit_bias: Optional[Dict[str, int]] | NotGiven = NOT_GIVEN, - logprobs: Optional[int] | NotGiven = NOT_GIVEN, - max_tokens: Optional[int] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, - seed: Optional[int] | NotGiven = NOT_GIVEN, - stop: Union[Optional[str], SequenceNotStr[str], None] | NotGiven = NOT_GIVEN, - stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, - stream_options: Optional[ChatCompletionStreamOptionsParam] | NotGiven = NOT_GIVEN, - suffix: Optional[str] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + best_of: Optional[int] | Omit = omit, + echo: Optional[bool] | Omit = omit, + frequency_penalty: Optional[float] | Omit = omit, + logit_bias: Optional[Dict[str, int]] | Omit = omit, + logprobs: Optional[int] | Omit = omit, + max_tokens: Optional[int] | Omit = omit, + n: Optional[int] | Omit = omit, + presence_penalty: Optional[float] | Omit = omit, + seed: Optional[int] | Omit = omit, + stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, + stream: Optional[Literal[False]] | Literal[True] | Omit = omit, + stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, + suffix: Optional[str] | Omit = omit, + temperature: Optional[float] | Omit = omit, + top_p: Optional[float] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Completion | AsyncStream[Completion]: return await self._post( "/completions", diff --git a/src/openai/resources/containers/containers.py b/src/openai/resources/containers/containers.py index 30e9eff127..dcdc3e1a3e 100644 --- a/src/openai/resources/containers/containers.py +++ b/src/openai/resources/containers/containers.py @@ -8,7 +8,7 @@ from ... import _legacy_response from ...types import container_list_params, container_create_params -from ..._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven, SequenceNotStr +from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given from ..._utils import maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource @@ -58,14 +58,14 @@ def create( self, *, name: str, - expires_after: container_create_params.ExpiresAfter | NotGiven = NOT_GIVEN, - file_ids: SequenceNotStr[str] | NotGiven = NOT_GIVEN, + expires_after: container_create_params.ExpiresAfter | Omit = omit, + file_ids: SequenceNotStr[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ContainerCreateResponse: """ Create Container @@ -110,7 +110,7 @@ def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ContainerRetrieveResponse: """ Retrieve Container @@ -137,15 +137,15 @@ def retrieve( def list( self, *, - after: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncCursorPage[ContainerListResponse]: """List Containers @@ -200,7 +200,7 @@ def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: """ Delete Container @@ -254,14 +254,14 @@ async def create( self, *, name: str, - expires_after: container_create_params.ExpiresAfter | NotGiven = NOT_GIVEN, - file_ids: SequenceNotStr[str] | NotGiven = NOT_GIVEN, + expires_after: container_create_params.ExpiresAfter | Omit = omit, + file_ids: SequenceNotStr[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ContainerCreateResponse: """ Create Container @@ -306,7 +306,7 @@ async def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ContainerRetrieveResponse: """ Retrieve Container @@ -333,15 +333,15 @@ async def retrieve( def list( self, *, - after: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[ContainerListResponse, AsyncCursorPage[ContainerListResponse]]: """List Containers @@ -396,7 +396,7 @@ async def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: """ Delete Container diff --git a/src/openai/resources/containers/files/content.py b/src/openai/resources/containers/files/content.py index a200383407..a3dbd0e8c7 100644 --- a/src/openai/resources/containers/files/content.py +++ b/src/openai/resources/containers/files/content.py @@ -5,7 +5,7 @@ import httpx from .... import _legacy_response -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._types import Body, Query, Headers, NotGiven, not_given from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import ( @@ -49,7 +49,7 @@ def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> _legacy_response.HttpxBinaryResponseContent: """ Retrieve Container File Content @@ -107,7 +107,7 @@ async def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> _legacy_response.HttpxBinaryResponseContent: """ Retrieve Container File Content diff --git a/src/openai/resources/containers/files/files.py b/src/openai/resources/containers/files/files.py index 624398b97b..a472cfc9f3 100644 --- a/src/openai/resources/containers/files/files.py +++ b/src/openai/resources/containers/files/files.py @@ -16,7 +16,7 @@ ContentWithStreamingResponse, AsyncContentWithStreamingResponse, ) -from ...._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven, FileTypes +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, FileTypes, omit, not_given from ...._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource @@ -59,14 +59,14 @@ def create( self, container_id: str, *, - file: FileTypes | NotGiven = NOT_GIVEN, - file_id: str | NotGiven = NOT_GIVEN, + file: FileTypes | Omit = omit, + file_id: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> FileCreateResponse: """ Create a Container File @@ -120,7 +120,7 @@ def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> FileRetrieveResponse: """ Retrieve Container File @@ -150,15 +150,15 @@ def list( self, container_id: str, *, - after: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncCursorPage[FileListResponse]: """List Container files @@ -216,7 +216,7 @@ def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: """ Delete Container File @@ -272,14 +272,14 @@ async def create( self, container_id: str, *, - file: FileTypes | NotGiven = NOT_GIVEN, - file_id: str | NotGiven = NOT_GIVEN, + file: FileTypes | Omit = omit, + file_id: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> FileCreateResponse: """ Create a Container File @@ -333,7 +333,7 @@ async def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> FileRetrieveResponse: """ Retrieve Container File @@ -363,15 +363,15 @@ def list( self, container_id: str, *, - after: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[FileListResponse, AsyncCursorPage[FileListResponse]]: """List Container files @@ -429,7 +429,7 @@ async def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: """ Delete Container File diff --git a/src/openai/resources/conversations/conversations.py b/src/openai/resources/conversations/conversations.py index c0239d402c..4b942eb014 100644 --- a/src/openai/resources/conversations/conversations.py +++ b/src/openai/resources/conversations/conversations.py @@ -15,7 +15,7 @@ ItemsWithStreamingResponse, AsyncItemsWithStreamingResponse, ) -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given from ..._utils import maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource @@ -57,14 +57,14 @@ def with_streaming_response(self) -> ConversationsWithStreamingResponse: def create( self, *, - items: Optional[Iterable[ResponseInputItemParam]] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + items: Optional[Iterable[ResponseInputItemParam]] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Conversation: """ Create a conversation. @@ -112,7 +112,7 @@ def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Conversation: """ Get a conversation with the given ID. @@ -146,7 +146,7 @@ def update( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Conversation: """ Update a conversation's metadata with the given ID. @@ -186,7 +186,7 @@ def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ConversationDeletedResource: """ Delete a conversation with the given ID. @@ -238,14 +238,14 @@ def with_streaming_response(self) -> AsyncConversationsWithStreamingResponse: async def create( self, *, - items: Optional[Iterable[ResponseInputItemParam]] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, + items: Optional[Iterable[ResponseInputItemParam]] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Conversation: """ Create a conversation. @@ -293,7 +293,7 @@ async def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Conversation: """ Get a conversation with the given ID. @@ -327,7 +327,7 @@ async def update( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Conversation: """ Update a conversation's metadata with the given ID. @@ -369,7 +369,7 @@ async def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ConversationDeletedResource: """ Delete a conversation with the given ID. diff --git a/src/openai/resources/conversations/items.py b/src/openai/resources/conversations/items.py index 01811f956b..3dba144849 100644 --- a/src/openai/resources/conversations/items.py +++ b/src/openai/resources/conversations/items.py @@ -8,7 +8,7 @@ import httpx from ... import _legacy_response -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given from ..._utils import maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource @@ -50,13 +50,13 @@ def create( conversation_id: str, *, items: Iterable[ResponseInputItemParam], - include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + include: List[ResponseIncludable] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ConversationItemList: """ Create items in a conversation with the given ID. @@ -96,13 +96,13 @@ def retrieve( item_id: str, *, conversation_id: str, - include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + include: List[ResponseIncludable] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ConversationItem: """ Get a single item from a conversation with the given IDs. @@ -143,16 +143,16 @@ def list( self, conversation_id: str, *, - after: str | NotGiven = NOT_GIVEN, - include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + include: List[ResponseIncludable] | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncConversationCursorPage[ConversationItem]: """ List all items for a conversation with the given ID. @@ -228,7 +228,7 @@ def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Conversation: """ Delete an item from a conversation with the given IDs. @@ -280,13 +280,13 @@ async def create( conversation_id: str, *, items: Iterable[ResponseInputItemParam], - include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + include: List[ResponseIncludable] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ConversationItemList: """ Create items in a conversation with the given ID. @@ -326,13 +326,13 @@ async def retrieve( item_id: str, *, conversation_id: str, - include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, + include: List[ResponseIncludable] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ConversationItem: """ Get a single item from a conversation with the given IDs. @@ -373,16 +373,16 @@ def list( self, conversation_id: str, *, - after: str | NotGiven = NOT_GIVEN, - include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + include: List[ResponseIncludable] | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[ConversationItem, AsyncConversationCursorPage[ConversationItem]]: """ List all items for a conversation with the given ID. @@ -458,7 +458,7 @@ async def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Conversation: """ Delete an item from a conversation with the given IDs. diff --git a/src/openai/resources/embeddings.py b/src/openai/resources/embeddings.py index a8cf179850..5dc3dfa9b3 100644 --- a/src/openai/resources/embeddings.py +++ b/src/openai/resources/embeddings.py @@ -11,7 +11,7 @@ from .. import _legacy_response from ..types import embedding_create_params -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr +from .._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given from .._utils import is_given, maybe_transform from .._compat import cached_property from .._extras import numpy as np, has_numpy @@ -49,15 +49,15 @@ def create( *, input: Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]]], model: Union[str, EmbeddingModel], - dimensions: int | NotGiven = NOT_GIVEN, - encoding_format: Literal["float", "base64"] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + dimensions: int | Omit = omit, + encoding_format: Literal["float", "base64"] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> CreateEmbeddingResponse: """ Creates an embedding vector representing the input text. @@ -168,15 +168,15 @@ async def create( *, input: Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]]], model: Union[str, EmbeddingModel], - dimensions: int | NotGiven = NOT_GIVEN, - encoding_format: Literal["float", "base64"] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + dimensions: int | Omit = omit, + encoding_format: Literal["float", "base64"] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> CreateEmbeddingResponse: """ Creates an embedding vector representing the input text. diff --git a/src/openai/resources/evals/evals.py b/src/openai/resources/evals/evals.py index 7aba192c51..40c4a3e9a3 100644 --- a/src/openai/resources/evals/evals.py +++ b/src/openai/resources/evals/evals.py @@ -9,7 +9,7 @@ from ... import _legacy_response from ...types import eval_list_params, eval_create_params, eval_update_params -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given from ..._utils import maybe_transform, async_maybe_transform from ..._compat import cached_property from .runs.runs import ( @@ -63,14 +63,14 @@ def create( *, data_source_config: eval_create_params.DataSourceConfig, testing_criteria: Iterable[eval_create_params.TestingCriterion], - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - name: str | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | Omit = omit, + name: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> EvalCreateResponse: """ Create the structure of an evaluation that can be used to test a model's @@ -132,7 +132,7 @@ def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> EvalRetrieveResponse: """ Get an evaluation by ID. @@ -160,14 +160,14 @@ def update( self, eval_id: str, *, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - name: str | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | Omit = omit, + name: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> EvalUpdateResponse: """ Update certain properties of an evaluation. @@ -210,16 +210,16 @@ def update( def list( self, *, - after: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, - order_by: Literal["created_at", "updated_at"] | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + order_by: Literal["created_at", "updated_at"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncCursorPage[EvalListResponse]: """ List evaluations for a project. @@ -273,7 +273,7 @@ def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> EvalDeleteResponse: """ Delete an evaluation. @@ -327,14 +327,14 @@ async def create( *, data_source_config: eval_create_params.DataSourceConfig, testing_criteria: Iterable[eval_create_params.TestingCriterion], - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - name: str | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | Omit = omit, + name: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> EvalCreateResponse: """ Create the structure of an evaluation that can be used to test a model's @@ -396,7 +396,7 @@ async def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> EvalRetrieveResponse: """ Get an evaluation by ID. @@ -424,14 +424,14 @@ async def update( self, eval_id: str, *, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - name: str | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | Omit = omit, + name: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> EvalUpdateResponse: """ Update certain properties of an evaluation. @@ -474,16 +474,16 @@ async def update( def list( self, *, - after: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, - order_by: Literal["created_at", "updated_at"] | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + order_by: Literal["created_at", "updated_at"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[EvalListResponse, AsyncCursorPage[EvalListResponse]]: """ List evaluations for a project. @@ -537,7 +537,7 @@ async def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> EvalDeleteResponse: """ Delete an evaluation. diff --git a/src/openai/resources/evals/runs/output_items.py b/src/openai/resources/evals/runs/output_items.py index 8fd0fdea92..c2dee72122 100644 --- a/src/openai/resources/evals/runs/output_items.py +++ b/src/openai/resources/evals/runs/output_items.py @@ -7,7 +7,7 @@ import httpx from .... import _legacy_response -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given from ...._utils import maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource @@ -52,7 +52,7 @@ def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> OutputItemRetrieveResponse: """ Get an evaluation run output item by ID. @@ -85,16 +85,16 @@ def list( run_id: str, *, eval_id: str, - after: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, - status: Literal["fail", "pass"] | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + status: Literal["fail", "pass"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncCursorPage[OutputItemListResponse]: """ Get a list of output items for an evaluation run. @@ -175,7 +175,7 @@ async def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> OutputItemRetrieveResponse: """ Get an evaluation run output item by ID. @@ -208,16 +208,16 @@ def list( run_id: str, *, eval_id: str, - after: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, - status: Literal["fail", "pass"] | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + status: Literal["fail", "pass"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[OutputItemListResponse, AsyncCursorPage[OutputItemListResponse]]: """ Get a list of output items for an evaluation run. diff --git a/src/openai/resources/evals/runs/runs.py b/src/openai/resources/evals/runs/runs.py index 7efc61292c..b747b198f8 100644 --- a/src/openai/resources/evals/runs/runs.py +++ b/src/openai/resources/evals/runs/runs.py @@ -8,7 +8,7 @@ import httpx from .... import _legacy_response -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given from ...._utils import maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource @@ -63,14 +63,14 @@ def create( eval_id: str, *, data_source: run_create_params.DataSource, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - name: str | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | Omit = omit, + name: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> RunCreateResponse: """ Kicks off a new run for a given evaluation, specifying the data source, and what @@ -125,7 +125,7 @@ def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> RunRetrieveResponse: """ Get an evaluation run by ID. @@ -155,16 +155,16 @@ def list( self, eval_id: str, *, - after: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, - status: Literal["queued", "in_progress", "completed", "canceled", "failed"] | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + status: Literal["queued", "in_progress", "completed", "canceled", "failed"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncCursorPage[RunListResponse]: """ Get a list of runs for an evaluation. @@ -221,7 +221,7 @@ def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> RunDeleteResponse: """ Delete an eval run. @@ -257,7 +257,7 @@ def cancel( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> RunCancelResponse: """ Cancel an ongoing evaluation run. @@ -313,14 +313,14 @@ async def create( eval_id: str, *, data_source: run_create_params.DataSource, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - name: str | NotGiven = NOT_GIVEN, + metadata: Optional[Metadata] | Omit = omit, + name: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> RunCreateResponse: """ Kicks off a new run for a given evaluation, specifying the data source, and what @@ -375,7 +375,7 @@ async def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> RunRetrieveResponse: """ Get an evaluation run by ID. @@ -405,16 +405,16 @@ def list( self, eval_id: str, *, - after: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, - status: Literal["queued", "in_progress", "completed", "canceled", "failed"] | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + status: Literal["queued", "in_progress", "completed", "canceled", "failed"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[RunListResponse, AsyncCursorPage[RunListResponse]]: """ Get a list of runs for an evaluation. @@ -471,7 +471,7 @@ async def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> RunDeleteResponse: """ Delete an eval run. @@ -507,7 +507,7 @@ async def cancel( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> RunCancelResponse: """ Cancel an ongoing evaluation run. diff --git a/src/openai/resources/files.py b/src/openai/resources/files.py index 963c3c0a9f..77bb2d613c 100644 --- a/src/openai/resources/files.py +++ b/src/openai/resources/files.py @@ -11,7 +11,7 @@ from .. import _legacy_response from ..types import FilePurpose, file_list_params, file_create_params -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven, FileTypes +from .._types import Body, Omit, Query, Headers, NotGiven, FileTypes, omit, not_given from .._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource @@ -57,13 +57,13 @@ def create( *, file: FileTypes, purpose: FilePurpose, - expires_after: file_create_params.ExpiresAfter | NotGiven = NOT_GIVEN, + expires_after: file_create_params.ExpiresAfter | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> FileObject: """Upload a file that can be used across various endpoints. @@ -139,7 +139,7 @@ def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> FileObject: """ Returns information about a specific file. @@ -166,16 +166,16 @@ def retrieve( def list( self, *, - after: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, - purpose: str | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + purpose: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncCursorPage[FileObject]: """Returns a list of files. @@ -233,7 +233,7 @@ def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> FileDeleted: """ Delete a file. @@ -266,7 +266,7 @@ def content( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> _legacy_response.HttpxBinaryResponseContent: """ Returns the contents of the specified file. @@ -301,7 +301,7 @@ def retrieve_content( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> str: """ Returns the contents of the specified file. @@ -374,13 +374,13 @@ async def create( *, file: FileTypes, purpose: FilePurpose, - expires_after: file_create_params.ExpiresAfter | NotGiven = NOT_GIVEN, + expires_after: file_create_params.ExpiresAfter | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> FileObject: """Upload a file that can be used across various endpoints. @@ -456,7 +456,7 @@ async def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> FileObject: """ Returns information about a specific file. @@ -483,16 +483,16 @@ async def retrieve( def list( self, *, - after: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, - purpose: str | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + purpose: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[FileObject, AsyncCursorPage[FileObject]]: """Returns a list of files. @@ -550,7 +550,7 @@ async def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> FileDeleted: """ Delete a file. @@ -583,7 +583,7 @@ async def content( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> _legacy_response.HttpxBinaryResponseContent: """ Returns the contents of the specified file. @@ -618,7 +618,7 @@ async def retrieve_content( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> str: """ Returns the contents of the specified file. diff --git a/src/openai/resources/fine_tuning/alpha/graders.py b/src/openai/resources/fine_tuning/alpha/graders.py index 387e6c72ff..e7a9b925ea 100644 --- a/src/openai/resources/fine_tuning/alpha/graders.py +++ b/src/openai/resources/fine_tuning/alpha/graders.py @@ -5,7 +5,7 @@ import httpx from .... import _legacy_response -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given from ...._utils import maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource @@ -43,13 +43,13 @@ def run( *, grader: grader_run_params.Grader, model_sample: str, - item: object | NotGiven = NOT_GIVEN, + item: object | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> GraderRunResponse: """ Run a grader. @@ -100,7 +100,7 @@ def validate( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> GraderValidateResponse: """ Validate a grader. @@ -151,13 +151,13 @@ async def run( *, grader: grader_run_params.Grader, model_sample: str, - item: object | NotGiven = NOT_GIVEN, + item: object | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> GraderRunResponse: """ Run a grader. @@ -208,7 +208,7 @@ async def validate( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> GraderValidateResponse: """ Validate a grader. diff --git a/src/openai/resources/fine_tuning/checkpoints/permissions.py b/src/openai/resources/fine_tuning/checkpoints/permissions.py index f8ae125941..e7f55b82d9 100644 --- a/src/openai/resources/fine_tuning/checkpoints/permissions.py +++ b/src/openai/resources/fine_tuning/checkpoints/permissions.py @@ -7,7 +7,7 @@ import httpx from .... import _legacy_response -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr +from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given from ...._utils import maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource @@ -52,7 +52,7 @@ def create( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncPage[PermissionCreateResponse]: """ **NOTE:** Calling this endpoint requires an [admin API key](../admin-api-keys). @@ -90,16 +90,16 @@ def retrieve( self, fine_tuned_model_checkpoint: str, *, - after: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - order: Literal["ascending", "descending"] | NotGiven = NOT_GIVEN, - project_id: str | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["ascending", "descending"] | Omit = omit, + project_id: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> PermissionRetrieveResponse: """ **NOTE:** This endpoint requires an [admin API key](../admin-api-keys). @@ -158,7 +158,7 @@ def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> PermissionDeleteResponse: """ **NOTE:** This endpoint requires an [admin API key](../admin-api-keys). @@ -220,7 +220,7 @@ def create( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[PermissionCreateResponse, AsyncPage[PermissionCreateResponse]]: """ **NOTE:** Calling this endpoint requires an [admin API key](../admin-api-keys). @@ -258,16 +258,16 @@ async def retrieve( self, fine_tuned_model_checkpoint: str, *, - after: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - order: Literal["ascending", "descending"] | NotGiven = NOT_GIVEN, - project_id: str | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["ascending", "descending"] | Omit = omit, + project_id: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> PermissionRetrieveResponse: """ **NOTE:** This endpoint requires an [admin API key](../admin-api-keys). @@ -326,7 +326,7 @@ async def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> PermissionDeleteResponse: """ **NOTE:** This endpoint requires an [admin API key](../admin-api-keys). diff --git a/src/openai/resources/fine_tuning/jobs/checkpoints.py b/src/openai/resources/fine_tuning/jobs/checkpoints.py index f86462e513..f65856f0c6 100644 --- a/src/openai/resources/fine_tuning/jobs/checkpoints.py +++ b/src/openai/resources/fine_tuning/jobs/checkpoints.py @@ -5,7 +5,7 @@ import httpx from .... import _legacy_response -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given from ...._utils import maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource @@ -45,14 +45,14 @@ def list( self, fine_tuning_job_id: str, *, - after: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + limit: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncCursorPage[FineTuningJobCheckpoint]: """ List checkpoints for a fine-tuning job. @@ -116,14 +116,14 @@ def list( self, fine_tuning_job_id: str, *, - after: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + limit: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[FineTuningJobCheckpoint, AsyncCursorPage[FineTuningJobCheckpoint]]: """ List checkpoints for a fine-tuning job. diff --git a/src/openai/resources/fine_tuning/jobs/jobs.py b/src/openai/resources/fine_tuning/jobs/jobs.py index ee21cdd280..b292e057cf 100644 --- a/src/openai/resources/fine_tuning/jobs/jobs.py +++ b/src/openai/resources/fine_tuning/jobs/jobs.py @@ -8,7 +8,7 @@ import httpx from .... import _legacy_response -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given from ...._utils import maybe_transform, async_maybe_transform from ...._compat import cached_property from .checkpoints import ( @@ -63,19 +63,19 @@ def create( *, model: Union[str, Literal["babbage-002", "davinci-002", "gpt-3.5-turbo", "gpt-4o-mini"]], training_file: str, - hyperparameters: job_create_params.Hyperparameters | NotGiven = NOT_GIVEN, - integrations: Optional[Iterable[job_create_params.Integration]] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - method: job_create_params.Method | NotGiven = NOT_GIVEN, - seed: Optional[int] | NotGiven = NOT_GIVEN, - suffix: Optional[str] | NotGiven = NOT_GIVEN, - validation_file: Optional[str] | NotGiven = NOT_GIVEN, + hyperparameters: job_create_params.Hyperparameters | Omit = omit, + integrations: Optional[Iterable[job_create_params.Integration]] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + method: job_create_params.Method | Omit = omit, + seed: Optional[int] | Omit = omit, + suffix: Optional[str] | Omit = omit, + validation_file: Optional[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> FineTuningJob: """ Creates a fine-tuning job which begins the process of creating a new model from @@ -186,7 +186,7 @@ def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> FineTuningJob: """ Get info about a fine-tuning job. @@ -215,15 +215,15 @@ def retrieve( def list( self, *, - after: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + limit: int | Omit = omit, + metadata: Optional[Dict[str, str]] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncCursorPage[FineTuningJob]: """ List your organization's fine-tuning jobs @@ -273,7 +273,7 @@ def cancel( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> FineTuningJob: """ Immediately cancel a fine-tune job. @@ -301,14 +301,14 @@ def list_events( self, fine_tuning_job_id: str, *, - after: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + limit: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncCursorPage[FineTuningJobEvent]: """ Get status updates for a fine-tuning job. @@ -356,7 +356,7 @@ def pause( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> FineTuningJob: """ Pause a fine-tune job. @@ -389,7 +389,7 @@ def resume( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> FineTuningJob: """ Resume a fine-tune job. @@ -443,19 +443,19 @@ async def create( *, model: Union[str, Literal["babbage-002", "davinci-002", "gpt-3.5-turbo", "gpt-4o-mini"]], training_file: str, - hyperparameters: job_create_params.Hyperparameters | NotGiven = NOT_GIVEN, - integrations: Optional[Iterable[job_create_params.Integration]] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - method: job_create_params.Method | NotGiven = NOT_GIVEN, - seed: Optional[int] | NotGiven = NOT_GIVEN, - suffix: Optional[str] | NotGiven = NOT_GIVEN, - validation_file: Optional[str] | NotGiven = NOT_GIVEN, + hyperparameters: job_create_params.Hyperparameters | Omit = omit, + integrations: Optional[Iterable[job_create_params.Integration]] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + method: job_create_params.Method | Omit = omit, + seed: Optional[int] | Omit = omit, + suffix: Optional[str] | Omit = omit, + validation_file: Optional[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> FineTuningJob: """ Creates a fine-tuning job which begins the process of creating a new model from @@ -566,7 +566,7 @@ async def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> FineTuningJob: """ Get info about a fine-tuning job. @@ -595,15 +595,15 @@ async def retrieve( def list( self, *, - after: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + limit: int | Omit = omit, + metadata: Optional[Dict[str, str]] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[FineTuningJob, AsyncCursorPage[FineTuningJob]]: """ List your organization's fine-tuning jobs @@ -653,7 +653,7 @@ async def cancel( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> FineTuningJob: """ Immediately cancel a fine-tune job. @@ -681,14 +681,14 @@ def list_events( self, fine_tuning_job_id: str, *, - after: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + limit: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[FineTuningJobEvent, AsyncCursorPage[FineTuningJobEvent]]: """ Get status updates for a fine-tuning job. @@ -736,7 +736,7 @@ async def pause( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> FineTuningJob: """ Pause a fine-tune job. @@ -769,7 +769,7 @@ async def resume( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> FineTuningJob: """ Resume a fine-tune job. diff --git a/src/openai/resources/images.py b/src/openai/resources/images.py index 17ec264b6a..aae26bab64 100644 --- a/src/openai/resources/images.py +++ b/src/openai/resources/images.py @@ -9,7 +9,7 @@ from .. import _legacy_response from ..types import image_edit_params, image_generate_params, image_create_variation_params -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven, FileTypes, SequenceNotStr +from .._types import Body, Omit, Query, Headers, NotGiven, FileTypes, SequenceNotStr, omit, not_given from .._utils import extract_files, required_args, maybe_transform, deepcopy_minimal, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource @@ -48,17 +48,17 @@ def create_variation( self, *, image: FileTypes, - model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, - size: Optional[Literal["256x256", "512x512", "1024x1024"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + model: Union[str, ImageModel, None] | Omit = omit, + n: Optional[int] | Omit = omit, + response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, + size: Optional[Literal["256x256", "512x512", "1024x1024"]] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ImagesResponse: """Creates a variation of a given image. @@ -123,26 +123,25 @@ def edit( *, image: Union[FileTypes, SequenceNotStr[FileTypes]], prompt: str, - background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, - input_fidelity: Optional[Literal["high", "low"]] | NotGiven = NOT_GIVEN, - mask: FileTypes | NotGiven = NOT_GIVEN, - model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - output_compression: Optional[int] | NotGiven = NOT_GIVEN, - output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, - partial_images: Optional[int] | NotGiven = NOT_GIVEN, - quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, - response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, - size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] - | NotGiven = NOT_GIVEN, - stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + background: Optional[Literal["transparent", "opaque", "auto"]] | Omit = omit, + input_fidelity: Optional[Literal["high", "low"]] | Omit = omit, + mask: FileTypes | Omit = omit, + model: Union[str, ImageModel, None] | Omit = omit, + n: Optional[int] | Omit = omit, + output_compression: Optional[int] | Omit = omit, + output_format: Optional[Literal["png", "jpeg", "webp"]] | Omit = omit, + partial_images: Optional[int] | Omit = omit, + quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | Omit = omit, + response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, + size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] | Omit = omit, + stream: Optional[Literal[False]] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ImagesResponse: """Creates an edited or extended image given one or more source images and a prompt. @@ -237,25 +236,24 @@ def edit( image: Union[FileTypes, SequenceNotStr[FileTypes]], prompt: str, stream: Literal[True], - background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, - input_fidelity: Optional[Literal["high", "low"]] | NotGiven = NOT_GIVEN, - mask: FileTypes | NotGiven = NOT_GIVEN, - model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - output_compression: Optional[int] | NotGiven = NOT_GIVEN, - output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, - partial_images: Optional[int] | NotGiven = NOT_GIVEN, - quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, - response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, - size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] - | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + background: Optional[Literal["transparent", "opaque", "auto"]] | Omit = omit, + input_fidelity: Optional[Literal["high", "low"]] | Omit = omit, + mask: FileTypes | Omit = omit, + model: Union[str, ImageModel, None] | Omit = omit, + n: Optional[int] | Omit = omit, + output_compression: Optional[int] | Omit = omit, + output_format: Optional[Literal["png", "jpeg", "webp"]] | Omit = omit, + partial_images: Optional[int] | Omit = omit, + quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | Omit = omit, + response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, + size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Stream[ImageEditStreamEvent]: """Creates an edited or extended image given one or more source images and a prompt. @@ -350,25 +348,24 @@ def edit( image: Union[FileTypes, SequenceNotStr[FileTypes]], prompt: str, stream: bool, - background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, - input_fidelity: Optional[Literal["high", "low"]] | NotGiven = NOT_GIVEN, - mask: FileTypes | NotGiven = NOT_GIVEN, - model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - output_compression: Optional[int] | NotGiven = NOT_GIVEN, - output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, - partial_images: Optional[int] | NotGiven = NOT_GIVEN, - quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, - response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, - size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] - | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + background: Optional[Literal["transparent", "opaque", "auto"]] | Omit = omit, + input_fidelity: Optional[Literal["high", "low"]] | Omit = omit, + mask: FileTypes | Omit = omit, + model: Union[str, ImageModel, None] | Omit = omit, + n: Optional[int] | Omit = omit, + output_compression: Optional[int] | Omit = omit, + output_format: Optional[Literal["png", "jpeg", "webp"]] | Omit = omit, + partial_images: Optional[int] | Omit = omit, + quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | Omit = omit, + response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, + size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ImagesResponse | Stream[ImageEditStreamEvent]: """Creates an edited or extended image given one or more source images and a prompt. @@ -462,26 +459,25 @@ def edit( *, image: Union[FileTypes, SequenceNotStr[FileTypes]], prompt: str, - background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, - input_fidelity: Optional[Literal["high", "low"]] | NotGiven = NOT_GIVEN, - mask: FileTypes | NotGiven = NOT_GIVEN, - model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - output_compression: Optional[int] | NotGiven = NOT_GIVEN, - output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, - partial_images: Optional[int] | NotGiven = NOT_GIVEN, - quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, - response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, - size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] - | NotGiven = NOT_GIVEN, - stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + background: Optional[Literal["transparent", "opaque", "auto"]] | Omit = omit, + input_fidelity: Optional[Literal["high", "low"]] | Omit = omit, + mask: FileTypes | Omit = omit, + model: Union[str, ImageModel, None] | Omit = omit, + n: Optional[int] | Omit = omit, + output_compression: Optional[int] | Omit = omit, + output_format: Optional[Literal["png", "jpeg", "webp"]] | Omit = omit, + partial_images: Optional[int] | Omit = omit, + quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | Omit = omit, + response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, + size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] | Omit = omit, + stream: Optional[Literal[False]] | Literal[True] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ImagesResponse | Stream[ImageEditStreamEvent]: body = deepcopy_minimal( { @@ -527,28 +523,28 @@ def generate( self, *, prompt: str, - background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, - model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, - moderation: Optional[Literal["low", "auto"]] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - output_compression: Optional[int] | NotGiven = NOT_GIVEN, - output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, - partial_images: Optional[int] | NotGiven = NOT_GIVEN, - quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, - response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, + background: Optional[Literal["transparent", "opaque", "auto"]] | Omit = omit, + model: Union[str, ImageModel, None] | Omit = omit, + moderation: Optional[Literal["low", "auto"]] | Omit = omit, + n: Optional[int] | Omit = omit, + output_compression: Optional[int] | Omit = omit, + output_format: Optional[Literal["png", "jpeg", "webp"]] | Omit = omit, + partial_images: Optional[int] | Omit = omit, + quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | Omit = omit, + response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, size: Optional[ Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] ] - | NotGiven = NOT_GIVEN, - stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, - style: Optional[Literal["vivid", "natural"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + | Omit = omit, + stream: Optional[Literal[False]] | Omit = omit, + style: Optional[Literal["vivid", "natural"]] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ImagesResponse: """ Creates an image given a prompt. @@ -638,27 +634,27 @@ def generate( *, prompt: str, stream: Literal[True], - background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, - model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, - moderation: Optional[Literal["low", "auto"]] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - output_compression: Optional[int] | NotGiven = NOT_GIVEN, - output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, - partial_images: Optional[int] | NotGiven = NOT_GIVEN, - quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, - response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, + background: Optional[Literal["transparent", "opaque", "auto"]] | Omit = omit, + model: Union[str, ImageModel, None] | Omit = omit, + moderation: Optional[Literal["low", "auto"]] | Omit = omit, + n: Optional[int] | Omit = omit, + output_compression: Optional[int] | Omit = omit, + output_format: Optional[Literal["png", "jpeg", "webp"]] | Omit = omit, + partial_images: Optional[int] | Omit = omit, + quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | Omit = omit, + response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, size: Optional[ Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] ] - | NotGiven = NOT_GIVEN, - style: Optional[Literal["vivid", "natural"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + | Omit = omit, + style: Optional[Literal["vivid", "natural"]] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Stream[ImageGenStreamEvent]: """ Creates an image given a prompt. @@ -748,27 +744,27 @@ def generate( *, prompt: str, stream: bool, - background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, - model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, - moderation: Optional[Literal["low", "auto"]] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - output_compression: Optional[int] | NotGiven = NOT_GIVEN, - output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, - partial_images: Optional[int] | NotGiven = NOT_GIVEN, - quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, - response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, + background: Optional[Literal["transparent", "opaque", "auto"]] | Omit = omit, + model: Union[str, ImageModel, None] | Omit = omit, + moderation: Optional[Literal["low", "auto"]] | Omit = omit, + n: Optional[int] | Omit = omit, + output_compression: Optional[int] | Omit = omit, + output_format: Optional[Literal["png", "jpeg", "webp"]] | Omit = omit, + partial_images: Optional[int] | Omit = omit, + quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | Omit = omit, + response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, size: Optional[ Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] ] - | NotGiven = NOT_GIVEN, - style: Optional[Literal["vivid", "natural"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + | Omit = omit, + style: Optional[Literal["vivid", "natural"]] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ImagesResponse | Stream[ImageGenStreamEvent]: """ Creates an image given a prompt. @@ -857,28 +853,28 @@ def generate( self, *, prompt: str, - background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, - model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, - moderation: Optional[Literal["low", "auto"]] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - output_compression: Optional[int] | NotGiven = NOT_GIVEN, - output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, - partial_images: Optional[int] | NotGiven = NOT_GIVEN, - quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, - response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, + background: Optional[Literal["transparent", "opaque", "auto"]] | Omit = omit, + model: Union[str, ImageModel, None] | Omit = omit, + moderation: Optional[Literal["low", "auto"]] | Omit = omit, + n: Optional[int] | Omit = omit, + output_compression: Optional[int] | Omit = omit, + output_format: Optional[Literal["png", "jpeg", "webp"]] | Omit = omit, + partial_images: Optional[int] | Omit = omit, + quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | Omit = omit, + response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, size: Optional[ Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] ] - | NotGiven = NOT_GIVEN, - stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, - style: Optional[Literal["vivid", "natural"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + | Omit = omit, + stream: Optional[Literal[False]] | Literal[True] | Omit = omit, + style: Optional[Literal["vivid", "natural"]] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ImagesResponse | Stream[ImageGenStreamEvent]: return self._post( "/images/generations", @@ -936,17 +932,17 @@ async def create_variation( self, *, image: FileTypes, - model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, - size: Optional[Literal["256x256", "512x512", "1024x1024"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + model: Union[str, ImageModel, None] | Omit = omit, + n: Optional[int] | Omit = omit, + response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, + size: Optional[Literal["256x256", "512x512", "1024x1024"]] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ImagesResponse: """Creates a variation of a given image. @@ -1011,26 +1007,25 @@ async def edit( *, image: Union[FileTypes, SequenceNotStr[FileTypes]], prompt: str, - background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, - input_fidelity: Optional[Literal["high", "low"]] | NotGiven = NOT_GIVEN, - mask: FileTypes | NotGiven = NOT_GIVEN, - model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - output_compression: Optional[int] | NotGiven = NOT_GIVEN, - output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, - partial_images: Optional[int] | NotGiven = NOT_GIVEN, - quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, - response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, - size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] - | NotGiven = NOT_GIVEN, - stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + background: Optional[Literal["transparent", "opaque", "auto"]] | Omit = omit, + input_fidelity: Optional[Literal["high", "low"]] | Omit = omit, + mask: FileTypes | Omit = omit, + model: Union[str, ImageModel, None] | Omit = omit, + n: Optional[int] | Omit = omit, + output_compression: Optional[int] | Omit = omit, + output_format: Optional[Literal["png", "jpeg", "webp"]] | Omit = omit, + partial_images: Optional[int] | Omit = omit, + quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | Omit = omit, + response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, + size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] | Omit = omit, + stream: Optional[Literal[False]] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ImagesResponse: """Creates an edited or extended image given one or more source images and a prompt. @@ -1125,25 +1120,24 @@ async def edit( image: Union[FileTypes, SequenceNotStr[FileTypes]], prompt: str, stream: Literal[True], - background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, - input_fidelity: Optional[Literal["high", "low"]] | NotGiven = NOT_GIVEN, - mask: FileTypes | NotGiven = NOT_GIVEN, - model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - output_compression: Optional[int] | NotGiven = NOT_GIVEN, - output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, - partial_images: Optional[int] | NotGiven = NOT_GIVEN, - quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, - response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, - size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] - | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + background: Optional[Literal["transparent", "opaque", "auto"]] | Omit = omit, + input_fidelity: Optional[Literal["high", "low"]] | Omit = omit, + mask: FileTypes | Omit = omit, + model: Union[str, ImageModel, None] | Omit = omit, + n: Optional[int] | Omit = omit, + output_compression: Optional[int] | Omit = omit, + output_format: Optional[Literal["png", "jpeg", "webp"]] | Omit = omit, + partial_images: Optional[int] | Omit = omit, + quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | Omit = omit, + response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, + size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncStream[ImageEditStreamEvent]: """Creates an edited or extended image given one or more source images and a prompt. @@ -1238,25 +1232,24 @@ async def edit( image: Union[FileTypes, SequenceNotStr[FileTypes]], prompt: str, stream: bool, - background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, - input_fidelity: Optional[Literal["high", "low"]] | NotGiven = NOT_GIVEN, - mask: FileTypes | NotGiven = NOT_GIVEN, - model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - output_compression: Optional[int] | NotGiven = NOT_GIVEN, - output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, - partial_images: Optional[int] | NotGiven = NOT_GIVEN, - quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, - response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, - size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] - | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + background: Optional[Literal["transparent", "opaque", "auto"]] | Omit = omit, + input_fidelity: Optional[Literal["high", "low"]] | Omit = omit, + mask: FileTypes | Omit = omit, + model: Union[str, ImageModel, None] | Omit = omit, + n: Optional[int] | Omit = omit, + output_compression: Optional[int] | Omit = omit, + output_format: Optional[Literal["png", "jpeg", "webp"]] | Omit = omit, + partial_images: Optional[int] | Omit = omit, + quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | Omit = omit, + response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, + size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ImagesResponse | AsyncStream[ImageEditStreamEvent]: """Creates an edited or extended image given one or more source images and a prompt. @@ -1350,26 +1343,25 @@ async def edit( *, image: Union[FileTypes, SequenceNotStr[FileTypes]], prompt: str, - background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, - input_fidelity: Optional[Literal["high", "low"]] | NotGiven = NOT_GIVEN, - mask: FileTypes | NotGiven = NOT_GIVEN, - model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - output_compression: Optional[int] | NotGiven = NOT_GIVEN, - output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, - partial_images: Optional[int] | NotGiven = NOT_GIVEN, - quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, - response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, - size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] - | NotGiven = NOT_GIVEN, - stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + background: Optional[Literal["transparent", "opaque", "auto"]] | Omit = omit, + input_fidelity: Optional[Literal["high", "low"]] | Omit = omit, + mask: FileTypes | Omit = omit, + model: Union[str, ImageModel, None] | Omit = omit, + n: Optional[int] | Omit = omit, + output_compression: Optional[int] | Omit = omit, + output_format: Optional[Literal["png", "jpeg", "webp"]] | Omit = omit, + partial_images: Optional[int] | Omit = omit, + quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | Omit = omit, + response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, + size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] | Omit = omit, + stream: Optional[Literal[False]] | Literal[True] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ImagesResponse | AsyncStream[ImageEditStreamEvent]: body = deepcopy_minimal( { @@ -1415,28 +1407,28 @@ async def generate( self, *, prompt: str, - background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, - model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, - moderation: Optional[Literal["low", "auto"]] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - output_compression: Optional[int] | NotGiven = NOT_GIVEN, - output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, - partial_images: Optional[int] | NotGiven = NOT_GIVEN, - quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, - response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, + background: Optional[Literal["transparent", "opaque", "auto"]] | Omit = omit, + model: Union[str, ImageModel, None] | Omit = omit, + moderation: Optional[Literal["low", "auto"]] | Omit = omit, + n: Optional[int] | Omit = omit, + output_compression: Optional[int] | Omit = omit, + output_format: Optional[Literal["png", "jpeg", "webp"]] | Omit = omit, + partial_images: Optional[int] | Omit = omit, + quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | Omit = omit, + response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, size: Optional[ Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] ] - | NotGiven = NOT_GIVEN, - stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, - style: Optional[Literal["vivid", "natural"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + | Omit = omit, + stream: Optional[Literal[False]] | Omit = omit, + style: Optional[Literal["vivid", "natural"]] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ImagesResponse: """ Creates an image given a prompt. @@ -1526,27 +1518,27 @@ async def generate( *, prompt: str, stream: Literal[True], - background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, - model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, - moderation: Optional[Literal["low", "auto"]] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - output_compression: Optional[int] | NotGiven = NOT_GIVEN, - output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, - partial_images: Optional[int] | NotGiven = NOT_GIVEN, - quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, - response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, + background: Optional[Literal["transparent", "opaque", "auto"]] | Omit = omit, + model: Union[str, ImageModel, None] | Omit = omit, + moderation: Optional[Literal["low", "auto"]] | Omit = omit, + n: Optional[int] | Omit = omit, + output_compression: Optional[int] | Omit = omit, + output_format: Optional[Literal["png", "jpeg", "webp"]] | Omit = omit, + partial_images: Optional[int] | Omit = omit, + quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | Omit = omit, + response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, size: Optional[ Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] ] - | NotGiven = NOT_GIVEN, - style: Optional[Literal["vivid", "natural"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + | Omit = omit, + style: Optional[Literal["vivid", "natural"]] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncStream[ImageGenStreamEvent]: """ Creates an image given a prompt. @@ -1636,27 +1628,27 @@ async def generate( *, prompt: str, stream: bool, - background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, - model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, - moderation: Optional[Literal["low", "auto"]] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - output_compression: Optional[int] | NotGiven = NOT_GIVEN, - output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, - partial_images: Optional[int] | NotGiven = NOT_GIVEN, - quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, - response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, + background: Optional[Literal["transparent", "opaque", "auto"]] | Omit = omit, + model: Union[str, ImageModel, None] | Omit = omit, + moderation: Optional[Literal["low", "auto"]] | Omit = omit, + n: Optional[int] | Omit = omit, + output_compression: Optional[int] | Omit = omit, + output_format: Optional[Literal["png", "jpeg", "webp"]] | Omit = omit, + partial_images: Optional[int] | Omit = omit, + quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | Omit = omit, + response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, size: Optional[ Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] ] - | NotGiven = NOT_GIVEN, - style: Optional[Literal["vivid", "natural"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + | Omit = omit, + style: Optional[Literal["vivid", "natural"]] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ImagesResponse | AsyncStream[ImageGenStreamEvent]: """ Creates an image given a prompt. @@ -1745,28 +1737,28 @@ async def generate( self, *, prompt: str, - background: Optional[Literal["transparent", "opaque", "auto"]] | NotGiven = NOT_GIVEN, - model: Union[str, ImageModel, None] | NotGiven = NOT_GIVEN, - moderation: Optional[Literal["low", "auto"]] | NotGiven = NOT_GIVEN, - n: Optional[int] | NotGiven = NOT_GIVEN, - output_compression: Optional[int] | NotGiven = NOT_GIVEN, - output_format: Optional[Literal["png", "jpeg", "webp"]] | NotGiven = NOT_GIVEN, - partial_images: Optional[int] | NotGiven = NOT_GIVEN, - quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | NotGiven = NOT_GIVEN, - response_format: Optional[Literal["url", "b64_json"]] | NotGiven = NOT_GIVEN, + background: Optional[Literal["transparent", "opaque", "auto"]] | Omit = omit, + model: Union[str, ImageModel, None] | Omit = omit, + moderation: Optional[Literal["low", "auto"]] | Omit = omit, + n: Optional[int] | Omit = omit, + output_compression: Optional[int] | Omit = omit, + output_format: Optional[Literal["png", "jpeg", "webp"]] | Omit = omit, + partial_images: Optional[int] | Omit = omit, + quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | Omit = omit, + response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, size: Optional[ Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] ] - | NotGiven = NOT_GIVEN, - stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, - style: Optional[Literal["vivid", "natural"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + | Omit = omit, + stream: Optional[Literal[False]] | Literal[True] | Omit = omit, + style: Optional[Literal["vivid", "natural"]] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ImagesResponse | AsyncStream[ImageGenStreamEvent]: return await self._post( "/images/generations", diff --git a/src/openai/resources/models.py b/src/openai/resources/models.py index a9693a6b0a..a8f7691055 100644 --- a/src/openai/resources/models.py +++ b/src/openai/resources/models.py @@ -5,7 +5,7 @@ import httpx from .. import _legacy_response -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from .._types import Body, Query, Headers, NotGiven, not_given from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -49,7 +49,7 @@ def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Model: """ Retrieves a model instance, providing basic information about the model such as @@ -82,7 +82,7 @@ def list( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncPage[Model]: """ Lists the currently available models, and provides basic information about each @@ -106,7 +106,7 @@ def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ModelDeleted: """Delete a fine-tuned model. @@ -162,7 +162,7 @@ async def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Model: """ Retrieves a model instance, providing basic information about the model such as @@ -195,7 +195,7 @@ def list( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[Model, AsyncPage[Model]]: """ Lists the currently available models, and provides basic information about each @@ -219,7 +219,7 @@ async def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ModelDeleted: """Delete a fine-tuned model. diff --git a/src/openai/resources/moderations.py b/src/openai/resources/moderations.py index 91c0df4358..5f378f71e7 100644 --- a/src/openai/resources/moderations.py +++ b/src/openai/resources/moderations.py @@ -8,7 +8,7 @@ from .. import _legacy_response from ..types import moderation_create_params -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr +from .._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given from .._utils import maybe_transform, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource @@ -45,13 +45,13 @@ def create( self, *, input: Union[str, SequenceNotStr[str], Iterable[ModerationMultiModalInputParam]], - model: Union[str, ModerationModel] | NotGiven = NOT_GIVEN, + model: Union[str, ModerationModel] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ModerationCreateResponse: """Classifies if text and/or image inputs are potentially harmful. @@ -115,13 +115,13 @@ async def create( self, *, input: Union[str, SequenceNotStr[str], Iterable[ModerationMultiModalInputParam]], - model: Union[str, ModerationModel] | NotGiven = NOT_GIVEN, + model: Union[str, ModerationModel] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ModerationCreateResponse: """Classifies if text and/or image inputs are potentially harmful. diff --git a/src/openai/resources/realtime/client_secrets.py b/src/openai/resources/realtime/client_secrets.py index a79460746d..5ceba7bef1 100644 --- a/src/openai/resources/realtime/client_secrets.py +++ b/src/openai/resources/realtime/client_secrets.py @@ -5,7 +5,7 @@ import httpx from ... import _legacy_response -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given from ..._utils import maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource @@ -40,14 +40,14 @@ def with_streaming_response(self) -> ClientSecretsWithStreamingResponse: def create( self, *, - expires_after: client_secret_create_params.ExpiresAfter | NotGiven = NOT_GIVEN, - session: client_secret_create_params.Session | NotGiven = NOT_GIVEN, + expires_after: client_secret_create_params.ExpiresAfter | Omit = omit, + session: client_secret_create_params.Session | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ClientSecretCreateResponse: """ Create a Realtime client secret with an associated session configuration. @@ -108,14 +108,14 @@ def with_streaming_response(self) -> AsyncClientSecretsWithStreamingResponse: async def create( self, *, - expires_after: client_secret_create_params.ExpiresAfter | NotGiven = NOT_GIVEN, - session: client_secret_create_params.Session | NotGiven = NOT_GIVEN, + expires_after: client_secret_create_params.ExpiresAfter | Omit = omit, + session: client_secret_create_params.Session | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ClientSecretCreateResponse: """ Create a Realtime client secret with an associated session configuration. diff --git a/src/openai/resources/realtime/realtime.py b/src/openai/resources/realtime/realtime.py index 64fca72915..9d61fa25e0 100644 --- a/src/openai/resources/realtime/realtime.py +++ b/src/openai/resources/realtime/realtime.py @@ -11,7 +11,7 @@ import httpx from pydantic import BaseModel -from ..._types import NOT_GIVEN, Query, Headers, NotGiven +from ..._types import Omit, Query, Headers, omit from ..._utils import ( is_azure_client, maybe_transform, @@ -557,7 +557,7 @@ def __init__(self, connection: RealtimeConnection) -> None: class RealtimeSessionResource(BaseRealtimeConnectionResource): - def update(self, *, session: session_update_event_param.Session, event_id: str | NotGiven = NOT_GIVEN) -> None: + def update(self, *, session: session_update_event_param.Session, event_id: str | Omit = omit) -> None: """ Send this event to update the session’s configuration. The client may send this event at any time to update any field @@ -578,12 +578,7 @@ def update(self, *, session: session_update_event_param.Session, event_id: str | class RealtimeResponseResource(BaseRealtimeConnectionResource): - def create( - self, - *, - event_id: str | NotGiven = NOT_GIVEN, - response: RealtimeResponseCreateParamsParam | NotGiven = NOT_GIVEN, - ) -> None: + def create(self, *, event_id: str | Omit = omit, response: RealtimeResponseCreateParamsParam | Omit = omit) -> None: """ This event instructs the server to create a Response, which means triggering model inference. When in Server VAD mode, the server will create Responses @@ -618,7 +613,7 @@ def create( ) ) - def cancel(self, *, event_id: str | NotGiven = NOT_GIVEN, response_id: str | NotGiven = NOT_GIVEN) -> None: + def cancel(self, *, event_id: str | Omit = omit, response_id: str | Omit = omit) -> None: """Send this event to cancel an in-progress response. The server will respond @@ -636,7 +631,7 @@ def cancel(self, *, event_id: str | NotGiven = NOT_GIVEN, response_id: str | Not class RealtimeInputAudioBufferResource(BaseRealtimeConnectionResource): - def clear(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: + def clear(self, *, event_id: str | Omit = omit) -> None: """Send this event to clear the audio bytes in the buffer. The server will @@ -646,7 +641,7 @@ def clear(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: cast(RealtimeClientEventParam, strip_not_given({"type": "input_audio_buffer.clear", "event_id": event_id})) ) - def commit(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: + def commit(self, *, event_id: str | Omit = omit) -> None: """ Send this event to commit the user input audio buffer, which will create a new user message item in the conversation. This event will produce an error if the input audio buffer is empty. When in Server VAD mode, the client does not need to send this event, the server will commit the audio buffer automatically. @@ -656,7 +651,7 @@ def commit(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: cast(RealtimeClientEventParam, strip_not_given({"type": "input_audio_buffer.commit", "event_id": event_id})) ) - def append(self, *, audio: str, event_id: str | NotGiven = NOT_GIVEN) -> None: + def append(self, *, audio: str, event_id: str | Omit = omit) -> None: """Send this event to append audio bytes to the input audio buffer. The audio @@ -688,7 +683,7 @@ def item(self) -> RealtimeConversationItemResource: class RealtimeConversationItemResource(BaseRealtimeConnectionResource): - def delete(self, *, item_id: str, event_id: str | NotGiven = NOT_GIVEN) -> None: + def delete(self, *, item_id: str, event_id: str | Omit = omit) -> None: """Send this event when you want to remove any item from the conversation history. @@ -704,11 +699,7 @@ def delete(self, *, item_id: str, event_id: str | NotGiven = NOT_GIVEN) -> None: ) def create( - self, - *, - item: ConversationItemParam, - event_id: str | NotGiven = NOT_GIVEN, - previous_item_id: str | NotGiven = NOT_GIVEN, + self, *, item: ConversationItemParam, event_id: str | Omit = omit, previous_item_id: str | Omit = omit ) -> None: """ Add a new Item to the Conversation's context, including messages, function @@ -733,9 +724,7 @@ def create( ) ) - def truncate( - self, *, audio_end_ms: int, content_index: int, item_id: str, event_id: str | NotGiven = NOT_GIVEN - ) -> None: + def truncate(self, *, audio_end_ms: int, content_index: int, item_id: str, event_id: str | Omit = omit) -> None: """Send this event to truncate a previous assistant message’s audio. The server @@ -765,7 +754,7 @@ def truncate( ) ) - def retrieve(self, *, item_id: str, event_id: str | NotGiven = NOT_GIVEN) -> None: + def retrieve(self, *, item_id: str, event_id: str | Omit = omit) -> None: """ Send this event when you want to retrieve the server's representation of a specific item in the conversation history. This is useful, for example, to inspect user audio after noise cancellation and VAD. The server will respond with a `conversation.item.retrieved` event, @@ -781,7 +770,7 @@ def retrieve(self, *, item_id: str, event_id: str | NotGiven = NOT_GIVEN) -> Non class RealtimeOutputAudioBufferResource(BaseRealtimeConnectionResource): - def clear(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: + def clear(self, *, event_id: str | Omit = omit) -> None: """**WebRTC Only:** Emit to cut off the current audio response. This will trigger the server to @@ -801,9 +790,7 @@ def __init__(self, connection: AsyncRealtimeConnection) -> None: class AsyncRealtimeSessionResource(BaseAsyncRealtimeConnectionResource): - async def update( - self, *, session: session_update_event_param.Session, event_id: str | NotGiven = NOT_GIVEN - ) -> None: + async def update(self, *, session: session_update_event_param.Session, event_id: str | Omit = omit) -> None: """ Send this event to update the session’s configuration. The client may send this event at any time to update any field @@ -825,10 +812,7 @@ async def update( class AsyncRealtimeResponseResource(BaseAsyncRealtimeConnectionResource): async def create( - self, - *, - event_id: str | NotGiven = NOT_GIVEN, - response: RealtimeResponseCreateParamsParam | NotGiven = NOT_GIVEN, + self, *, event_id: str | Omit = omit, response: RealtimeResponseCreateParamsParam | Omit = omit ) -> None: """ This event instructs the server to create a Response, which means triggering @@ -864,7 +848,7 @@ async def create( ) ) - async def cancel(self, *, event_id: str | NotGiven = NOT_GIVEN, response_id: str | NotGiven = NOT_GIVEN) -> None: + async def cancel(self, *, event_id: str | Omit = omit, response_id: str | Omit = omit) -> None: """Send this event to cancel an in-progress response. The server will respond @@ -882,7 +866,7 @@ async def cancel(self, *, event_id: str | NotGiven = NOT_GIVEN, response_id: str class AsyncRealtimeInputAudioBufferResource(BaseAsyncRealtimeConnectionResource): - async def clear(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: + async def clear(self, *, event_id: str | Omit = omit) -> None: """Send this event to clear the audio bytes in the buffer. The server will @@ -892,7 +876,7 @@ async def clear(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: cast(RealtimeClientEventParam, strip_not_given({"type": "input_audio_buffer.clear", "event_id": event_id})) ) - async def commit(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: + async def commit(self, *, event_id: str | Omit = omit) -> None: """ Send this event to commit the user input audio buffer, which will create a new user message item in the conversation. This event will produce an error if the input audio buffer is empty. When in Server VAD mode, the client does not need to send this event, the server will commit the audio buffer automatically. @@ -902,7 +886,7 @@ async def commit(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: cast(RealtimeClientEventParam, strip_not_given({"type": "input_audio_buffer.commit", "event_id": event_id})) ) - async def append(self, *, audio: str, event_id: str | NotGiven = NOT_GIVEN) -> None: + async def append(self, *, audio: str, event_id: str | Omit = omit) -> None: """Send this event to append audio bytes to the input audio buffer. The audio @@ -934,7 +918,7 @@ def item(self) -> AsyncRealtimeConversationItemResource: class AsyncRealtimeConversationItemResource(BaseAsyncRealtimeConnectionResource): - async def delete(self, *, item_id: str, event_id: str | NotGiven = NOT_GIVEN) -> None: + async def delete(self, *, item_id: str, event_id: str | Omit = omit) -> None: """Send this event when you want to remove any item from the conversation history. @@ -950,11 +934,7 @@ async def delete(self, *, item_id: str, event_id: str | NotGiven = NOT_GIVEN) -> ) async def create( - self, - *, - item: ConversationItemParam, - event_id: str | NotGiven = NOT_GIVEN, - previous_item_id: str | NotGiven = NOT_GIVEN, + self, *, item: ConversationItemParam, event_id: str | Omit = omit, previous_item_id: str | Omit = omit ) -> None: """ Add a new Item to the Conversation's context, including messages, function @@ -980,7 +960,7 @@ async def create( ) async def truncate( - self, *, audio_end_ms: int, content_index: int, item_id: str, event_id: str | NotGiven = NOT_GIVEN + self, *, audio_end_ms: int, content_index: int, item_id: str, event_id: str | Omit = omit ) -> None: """Send this event to truncate a previous assistant message’s audio. @@ -1011,7 +991,7 @@ async def truncate( ) ) - async def retrieve(self, *, item_id: str, event_id: str | NotGiven = NOT_GIVEN) -> None: + async def retrieve(self, *, item_id: str, event_id: str | Omit = omit) -> None: """ Send this event when you want to retrieve the server's representation of a specific item in the conversation history. This is useful, for example, to inspect user audio after noise cancellation and VAD. The server will respond with a `conversation.item.retrieved` event, @@ -1027,7 +1007,7 @@ async def retrieve(self, *, item_id: str, event_id: str | NotGiven = NOT_GIVEN) class AsyncRealtimeOutputAudioBufferResource(BaseAsyncRealtimeConnectionResource): - async def clear(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: + async def clear(self, *, event_id: str | Omit = omit) -> None: """**WebRTC Only:** Emit to cut off the current audio response. This will trigger the server to diff --git a/src/openai/resources/responses/input_items.py b/src/openai/resources/responses/input_items.py index 9f3ef637ce..3311bfe10a 100644 --- a/src/openai/resources/responses/input_items.py +++ b/src/openai/resources/responses/input_items.py @@ -8,7 +8,7 @@ import httpx from ... import _legacy_response -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given from ..._utils import maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource @@ -46,16 +46,16 @@ def list( self, response_id: str, *, - after: str | NotGiven = NOT_GIVEN, - include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + include: List[ResponseIncludable] | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncCursorPage[ResponseItem]: """ Returns a list of input items for a given response. @@ -130,16 +130,16 @@ def list( self, response_id: str, *, - after: str | NotGiven = NOT_GIVEN, - include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + include: List[ResponseIncludable] | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[ResponseItem, AsyncCursorPage[ResponseItem]]: """ Returns a list of input items for a given response. diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 8acdb10b51..0a89d0c18e 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -9,7 +9,7 @@ import httpx from ... import _legacy_response -from ..._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven +from ..._types import NOT_GIVEN, Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given from ..._utils import is_given, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource @@ -75,39 +75,39 @@ def with_streaming_response(self) -> ResponsesWithStreamingResponse: def create( self, *, - background: Optional[bool] | NotGiven = NOT_GIVEN, - conversation: Optional[response_create_params.Conversation] | NotGiven = NOT_GIVEN, - include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, - input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_tool_calls: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: ResponsesModel | NotGiven = NOT_GIVEN, - parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, - previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, - prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, - prompt_cache_key: str | NotGiven = NOT_GIVEN, - reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - safety_identifier: str | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, - stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, - tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, - tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, - top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + background: Optional[bool] | Omit = omit, + conversation: Optional[response_create_params.Conversation] | Omit = omit, + include: Optional[List[ResponseIncludable]] | Omit = omit, + input: Union[str, ResponseInputParam] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_output_tokens: Optional[int] | Omit = omit, + max_tool_calls: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: ResponsesModel | Omit = omit, + parallel_tool_calls: Optional[bool] | Omit = omit, + previous_response_id: Optional[str] | Omit = omit, + prompt: Optional[ResponsePromptParam] | Omit = omit, + prompt_cache_key: str | Omit = omit, + reasoning: Optional[Reasoning] | Omit = omit, + safety_identifier: str | Omit = omit, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, + store: Optional[bool] | Omit = omit, + stream: Optional[Literal[False]] | Omit = omit, + stream_options: Optional[response_create_params.StreamOptions] | Omit = omit, + temperature: Optional[float] | Omit = omit, + text: ResponseTextConfigParam | Omit = omit, + tool_choice: response_create_params.ToolChoice | Omit = omit, + tools: Iterable[ToolParam] | Omit = omit, + top_logprobs: Optional[int] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation: Optional[Literal["auto", "disabled"]] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Response: """Creates a model response. @@ -315,38 +315,38 @@ def create( self, *, stream: Literal[True], - background: Optional[bool] | NotGiven = NOT_GIVEN, - conversation: Optional[response_create_params.Conversation] | NotGiven = NOT_GIVEN, - include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, - input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_tool_calls: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: ResponsesModel | NotGiven = NOT_GIVEN, - parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, - previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, - prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, - prompt_cache_key: str | NotGiven = NOT_GIVEN, - reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - safety_identifier: str | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, - tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, - tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, - top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + background: Optional[bool] | Omit = omit, + conversation: Optional[response_create_params.Conversation] | Omit = omit, + include: Optional[List[ResponseIncludable]] | Omit = omit, + input: Union[str, ResponseInputParam] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_output_tokens: Optional[int] | Omit = omit, + max_tool_calls: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: ResponsesModel | Omit = omit, + parallel_tool_calls: Optional[bool] | Omit = omit, + previous_response_id: Optional[str] | Omit = omit, + prompt: Optional[ResponsePromptParam] | Omit = omit, + prompt_cache_key: str | Omit = omit, + reasoning: Optional[Reasoning] | Omit = omit, + safety_identifier: str | Omit = omit, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, + store: Optional[bool] | Omit = omit, + stream_options: Optional[response_create_params.StreamOptions] | Omit = omit, + temperature: Optional[float] | Omit = omit, + text: ResponseTextConfigParam | Omit = omit, + tool_choice: response_create_params.ToolChoice | Omit = omit, + tools: Iterable[ToolParam] | Omit = omit, + top_logprobs: Optional[int] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation: Optional[Literal["auto", "disabled"]] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Stream[ResponseStreamEvent]: """Creates a model response. @@ -554,38 +554,38 @@ def create( self, *, stream: bool, - background: Optional[bool] | NotGiven = NOT_GIVEN, - conversation: Optional[response_create_params.Conversation] | NotGiven = NOT_GIVEN, - include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, - input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_tool_calls: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: ResponsesModel | NotGiven = NOT_GIVEN, - parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, - previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, - prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, - prompt_cache_key: str | NotGiven = NOT_GIVEN, - reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - safety_identifier: str | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, - tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, - tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, - top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + background: Optional[bool] | Omit = omit, + conversation: Optional[response_create_params.Conversation] | Omit = omit, + include: Optional[List[ResponseIncludable]] | Omit = omit, + input: Union[str, ResponseInputParam] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_output_tokens: Optional[int] | Omit = omit, + max_tool_calls: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: ResponsesModel | Omit = omit, + parallel_tool_calls: Optional[bool] | Omit = omit, + previous_response_id: Optional[str] | Omit = omit, + prompt: Optional[ResponsePromptParam] | Omit = omit, + prompt_cache_key: str | Omit = omit, + reasoning: Optional[Reasoning] | Omit = omit, + safety_identifier: str | Omit = omit, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, + store: Optional[bool] | Omit = omit, + stream_options: Optional[response_create_params.StreamOptions] | Omit = omit, + temperature: Optional[float] | Omit = omit, + text: ResponseTextConfigParam | Omit = omit, + tool_choice: response_create_params.ToolChoice | Omit = omit, + tools: Iterable[ToolParam] | Omit = omit, + top_logprobs: Optional[int] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation: Optional[Literal["auto", "disabled"]] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Response | Stream[ResponseStreamEvent]: """Creates a model response. @@ -791,39 +791,39 @@ def create( def create( self, *, - background: Optional[bool] | NotGiven = NOT_GIVEN, - conversation: Optional[response_create_params.Conversation] | NotGiven = NOT_GIVEN, - include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, - input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_tool_calls: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: ResponsesModel | NotGiven = NOT_GIVEN, - parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, - previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, - prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, - prompt_cache_key: str | NotGiven = NOT_GIVEN, - reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - safety_identifier: str | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, - stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, - tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, - tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, - top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + background: Optional[bool] | Omit = omit, + conversation: Optional[response_create_params.Conversation] | Omit = omit, + include: Optional[List[ResponseIncludable]] | Omit = omit, + input: Union[str, ResponseInputParam] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_output_tokens: Optional[int] | Omit = omit, + max_tool_calls: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: ResponsesModel | Omit = omit, + parallel_tool_calls: Optional[bool] | Omit = omit, + previous_response_id: Optional[str] | Omit = omit, + prompt: Optional[ResponsePromptParam] | Omit = omit, + prompt_cache_key: str | Omit = omit, + reasoning: Optional[Reasoning] | Omit = omit, + safety_identifier: str | Omit = omit, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, + store: Optional[bool] | Omit = omit, + stream: Optional[Literal[False]] | Literal[True] | Omit = omit, + stream_options: Optional[response_create_params.StreamOptions] | Omit = omit, + temperature: Optional[float] | Omit = omit, + text: ResponseTextConfigParam | Omit = omit, + tool_choice: response_create_params.ToolChoice | Omit = omit, + tools: Iterable[ToolParam] | Omit = omit, + top_logprobs: Optional[int] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation: Optional[Literal["auto", "disabled"]] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Response | Stream[ResponseStreamEvent]: return self._post( "/responses", @@ -874,9 +874,9 @@ def stream( self, *, response_id: str, - text_format: type[TextFormatT] | NotGiven = NOT_GIVEN, - starting_after: int | NotGiven = NOT_GIVEN, - tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, + text_format: type[TextFormatT] | Omit = omit, + starting_after: int | Omit = omit, + tools: Iterable[ParseableToolParam] | Omit = omit, # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, @@ -890,31 +890,31 @@ def stream( *, input: Union[str, ResponseInputParam], model: ResponsesModel, - background: Optional[bool] | NotGiven = NOT_GIVEN, - text_format: type[TextFormatT] | NotGiven = NOT_GIVEN, - tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, - conversation: Optional[response_create_params.Conversation] | NotGiven = NOT_GIVEN, - include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_tool_calls: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, - previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, - prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, - prompt_cache_key: str | NotGiven = NOT_GIVEN, - reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - safety_identifier: str | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, - tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, - top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + background: Optional[bool] | Omit = omit, + text_format: type[TextFormatT] | Omit = omit, + tools: Iterable[ParseableToolParam] | Omit = omit, + conversation: Optional[response_create_params.Conversation] | Omit = omit, + include: Optional[List[ResponseIncludable]] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_output_tokens: Optional[int] | Omit = omit, + max_tool_calls: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + parallel_tool_calls: Optional[bool] | Omit = omit, + previous_response_id: Optional[str] | Omit = omit, + prompt: Optional[ResponsePromptParam] | Omit = omit, + prompt_cache_key: str | Omit = omit, + reasoning: Optional[Reasoning] | Omit = omit, + safety_identifier: str | Omit = omit, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, + store: Optional[bool] | Omit = omit, + stream_options: Optional[response_create_params.StreamOptions] | Omit = omit, + temperature: Optional[float] | Omit = omit, + text: ResponseTextConfigParam | Omit = omit, + tool_choice: response_create_params.ToolChoice | Omit = omit, + top_logprobs: Optional[int] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation: Optional[Literal["auto", "disabled"]] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -926,35 +926,35 @@ def stream( def stream( self, *, - response_id: str | NotGiven = NOT_GIVEN, - input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, - model: ResponsesModel | NotGiven = NOT_GIVEN, - background: Optional[bool] | NotGiven = NOT_GIVEN, - text_format: type[TextFormatT] | NotGiven = NOT_GIVEN, - tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, - conversation: Optional[response_create_params.Conversation] | NotGiven = NOT_GIVEN, - include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_tool_calls: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, - previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, - prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, - prompt_cache_key: str | NotGiven = NOT_GIVEN, - reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - safety_identifier: str | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, - tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, - top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, - starting_after: int | NotGiven = NOT_GIVEN, + response_id: str | Omit = omit, + input: Union[str, ResponseInputParam] | Omit = omit, + model: ResponsesModel | Omit = omit, + background: Optional[bool] | Omit = omit, + text_format: type[TextFormatT] | Omit = omit, + tools: Iterable[ParseableToolParam] | Omit = omit, + conversation: Optional[response_create_params.Conversation] | Omit = omit, + include: Optional[List[ResponseIncludable]] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_output_tokens: Optional[int] | Omit = omit, + max_tool_calls: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + parallel_tool_calls: Optional[bool] | Omit = omit, + previous_response_id: Optional[str] | Omit = omit, + prompt: Optional[ResponsePromptParam] | Omit = omit, + prompt_cache_key: str | Omit = omit, + reasoning: Optional[Reasoning] | Omit = omit, + safety_identifier: str | Omit = omit, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, + store: Optional[bool] | Omit = omit, + stream_options: Optional[response_create_params.StreamOptions] | Omit = omit, + temperature: Optional[float] | Omit = omit, + text: ResponseTextConfigParam | Omit = omit, + tool_choice: response_create_params.ToolChoice | Omit = omit, + top_logprobs: Optional[int] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation: Optional[Literal["auto", "disabled"]] | Omit = omit, + user: str | Omit = omit, + starting_after: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1061,7 +1061,7 @@ def stream( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, - starting_after=NOT_GIVEN, + starting_after=omit, timeout=timeout, ), text_format=text_format, @@ -1072,35 +1072,35 @@ def stream( def parse( self, *, - text_format: type[TextFormatT] | NotGiven = NOT_GIVEN, - background: Optional[bool] | NotGiven = NOT_GIVEN, - conversation: Optional[response_create_params.Conversation] | NotGiven = NOT_GIVEN, - include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, - input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_tool_calls: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: ResponsesModel | NotGiven = NOT_GIVEN, - parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, - previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, - prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, - prompt_cache_key: str | NotGiven = NOT_GIVEN, - reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - safety_identifier: str | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, - stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, - tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, - tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, - top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, - verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, + text_format: type[TextFormatT] | Omit = omit, + background: Optional[bool] | Omit = omit, + conversation: Optional[response_create_params.Conversation] | Omit = omit, + include: Optional[List[ResponseIncludable]] | Omit = omit, + input: Union[str, ResponseInputParam] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_output_tokens: Optional[int] | Omit = omit, + max_tool_calls: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: ResponsesModel | Omit = omit, + parallel_tool_calls: Optional[bool] | Omit = omit, + previous_response_id: Optional[str] | Omit = omit, + prompt: Optional[ResponsePromptParam] | Omit = omit, + prompt_cache_key: str | Omit = omit, + reasoning: Optional[Reasoning] | Omit = omit, + safety_identifier: str | Omit = omit, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, + store: Optional[bool] | Omit = omit, + stream: Optional[Literal[False]] | Literal[True] | Omit = omit, + stream_options: Optional[response_create_params.StreamOptions] | Omit = omit, + temperature: Optional[float] | Omit = omit, + text: ResponseTextConfigParam | Omit = omit, + tool_choice: response_create_params.ToolChoice | Omit = omit, + tools: Iterable[ParseableToolParam] | Omit = omit, + top_logprobs: Optional[int] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation: Optional[Literal["auto", "disabled"]] | Omit = omit, + user: str | Omit = omit, + verbosity: Optional[Literal["low", "medium", "high"]] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1178,16 +1178,16 @@ def retrieve( self, response_id: str, *, - include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, - include_obfuscation: bool | NotGiven = NOT_GIVEN, - starting_after: int | NotGiven = NOT_GIVEN, - stream: Literal[False] | NotGiven = NOT_GIVEN, + include: List[ResponseIncludable] | Omit = omit, + include_obfuscation: bool | Omit = omit, + starting_after: int | Omit = omit, + stream: Literal[False] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Response: ... @overload @@ -1196,8 +1196,8 @@ def retrieve( response_id: str, *, stream: Literal[True], - include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, - starting_after: int | NotGiven = NOT_GIVEN, + include: List[ResponseIncludable] | Omit = omit, + starting_after: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1212,8 +1212,8 @@ def retrieve( response_id: str, *, stream: bool, - include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, - starting_after: int | NotGiven = NOT_GIVEN, + include: List[ResponseIncludable] | Omit = omit, + starting_after: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1228,8 +1228,8 @@ def retrieve( response_id: str, *, stream: bool = False, - include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, - starting_after: int | NotGiven = NOT_GIVEN, + include: List[ResponseIncludable] | Omit = omit, + starting_after: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1276,15 +1276,15 @@ def retrieve( response_id: str, *, stream: Literal[True], - include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, - include_obfuscation: bool | NotGiven = NOT_GIVEN, - starting_after: int | NotGiven = NOT_GIVEN, + include: List[ResponseIncludable] | Omit = omit, + include_obfuscation: bool | Omit = omit, + starting_after: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Stream[ResponseStreamEvent]: """ Retrieves a model response with the given ID. @@ -1325,15 +1325,15 @@ def retrieve( response_id: str, *, stream: bool, - include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, - include_obfuscation: bool | NotGiven = NOT_GIVEN, - starting_after: int | NotGiven = NOT_GIVEN, + include: List[ResponseIncludable] | Omit = omit, + include_obfuscation: bool | Omit = omit, + starting_after: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Response | Stream[ResponseStreamEvent]: """ Retrieves a model response with the given ID. @@ -1372,16 +1372,16 @@ def retrieve( self, response_id: str, *, - include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, - include_obfuscation: bool | NotGiven = NOT_GIVEN, - starting_after: int | NotGiven = NOT_GIVEN, - stream: Literal[False] | Literal[True] | NotGiven = NOT_GIVEN, + include: List[ResponseIncludable] | Omit = omit, + include_obfuscation: bool | Omit = omit, + starting_after: int | Omit = omit, + stream: Literal[False] | Literal[True] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Response | Stream[ResponseStreamEvent]: if not response_id: raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") @@ -1416,7 +1416,7 @@ def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: """ Deletes a model response with the given ID. @@ -1450,7 +1450,7 @@ def cancel( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Response: """Cancels a model response with the given ID. @@ -1506,39 +1506,39 @@ def with_streaming_response(self) -> AsyncResponsesWithStreamingResponse: async def create( self, *, - background: Optional[bool] | NotGiven = NOT_GIVEN, - conversation: Optional[response_create_params.Conversation] | NotGiven = NOT_GIVEN, - include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, - input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_tool_calls: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: ResponsesModel | NotGiven = NOT_GIVEN, - parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, - previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, - prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, - prompt_cache_key: str | NotGiven = NOT_GIVEN, - reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - safety_identifier: str | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, - stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, - tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, - tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, - top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + background: Optional[bool] | Omit = omit, + conversation: Optional[response_create_params.Conversation] | Omit = omit, + include: Optional[List[ResponseIncludable]] | Omit = omit, + input: Union[str, ResponseInputParam] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_output_tokens: Optional[int] | Omit = omit, + max_tool_calls: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: ResponsesModel | Omit = omit, + parallel_tool_calls: Optional[bool] | Omit = omit, + previous_response_id: Optional[str] | Omit = omit, + prompt: Optional[ResponsePromptParam] | Omit = omit, + prompt_cache_key: str | Omit = omit, + reasoning: Optional[Reasoning] | Omit = omit, + safety_identifier: str | Omit = omit, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, + store: Optional[bool] | Omit = omit, + stream: Optional[Literal[False]] | Omit = omit, + stream_options: Optional[response_create_params.StreamOptions] | Omit = omit, + temperature: Optional[float] | Omit = omit, + text: ResponseTextConfigParam | Omit = omit, + tool_choice: response_create_params.ToolChoice | Omit = omit, + tools: Iterable[ToolParam] | Omit = omit, + top_logprobs: Optional[int] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation: Optional[Literal["auto", "disabled"]] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Response: """Creates a model response. @@ -1746,38 +1746,38 @@ async def create( self, *, stream: Literal[True], - background: Optional[bool] | NotGiven = NOT_GIVEN, - conversation: Optional[response_create_params.Conversation] | NotGiven = NOT_GIVEN, - include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, - input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_tool_calls: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: ResponsesModel | NotGiven = NOT_GIVEN, - parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, - previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, - prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, - prompt_cache_key: str | NotGiven = NOT_GIVEN, - reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - safety_identifier: str | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, - tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, - tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, - top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + background: Optional[bool] | Omit = omit, + conversation: Optional[response_create_params.Conversation] | Omit = omit, + include: Optional[List[ResponseIncludable]] | Omit = omit, + input: Union[str, ResponseInputParam] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_output_tokens: Optional[int] | Omit = omit, + max_tool_calls: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: ResponsesModel | Omit = omit, + parallel_tool_calls: Optional[bool] | Omit = omit, + previous_response_id: Optional[str] | Omit = omit, + prompt: Optional[ResponsePromptParam] | Omit = omit, + prompt_cache_key: str | Omit = omit, + reasoning: Optional[Reasoning] | Omit = omit, + safety_identifier: str | Omit = omit, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, + store: Optional[bool] | Omit = omit, + stream_options: Optional[response_create_params.StreamOptions] | Omit = omit, + temperature: Optional[float] | Omit = omit, + text: ResponseTextConfigParam | Omit = omit, + tool_choice: response_create_params.ToolChoice | Omit = omit, + tools: Iterable[ToolParam] | Omit = omit, + top_logprobs: Optional[int] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation: Optional[Literal["auto", "disabled"]] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncStream[ResponseStreamEvent]: """Creates a model response. @@ -1985,38 +1985,38 @@ async def create( self, *, stream: bool, - background: Optional[bool] | NotGiven = NOT_GIVEN, - conversation: Optional[response_create_params.Conversation] | NotGiven = NOT_GIVEN, - include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, - input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_tool_calls: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: ResponsesModel | NotGiven = NOT_GIVEN, - parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, - previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, - prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, - prompt_cache_key: str | NotGiven = NOT_GIVEN, - reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - safety_identifier: str | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, - tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, - tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, - top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + background: Optional[bool] | Omit = omit, + conversation: Optional[response_create_params.Conversation] | Omit = omit, + include: Optional[List[ResponseIncludable]] | Omit = omit, + input: Union[str, ResponseInputParam] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_output_tokens: Optional[int] | Omit = omit, + max_tool_calls: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: ResponsesModel | Omit = omit, + parallel_tool_calls: Optional[bool] | Omit = omit, + previous_response_id: Optional[str] | Omit = omit, + prompt: Optional[ResponsePromptParam] | Omit = omit, + prompt_cache_key: str | Omit = omit, + reasoning: Optional[Reasoning] | Omit = omit, + safety_identifier: str | Omit = omit, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, + store: Optional[bool] | Omit = omit, + stream_options: Optional[response_create_params.StreamOptions] | Omit = omit, + temperature: Optional[float] | Omit = omit, + text: ResponseTextConfigParam | Omit = omit, + tool_choice: response_create_params.ToolChoice | Omit = omit, + tools: Iterable[ToolParam] | Omit = omit, + top_logprobs: Optional[int] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation: Optional[Literal["auto", "disabled"]] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Response | AsyncStream[ResponseStreamEvent]: """Creates a model response. @@ -2222,39 +2222,39 @@ async def create( async def create( self, *, - background: Optional[bool] | NotGiven = NOT_GIVEN, - conversation: Optional[response_create_params.Conversation] | NotGiven = NOT_GIVEN, - include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, - input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_tool_calls: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: ResponsesModel | NotGiven = NOT_GIVEN, - parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, - previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, - prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, - prompt_cache_key: str | NotGiven = NOT_GIVEN, - reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - safety_identifier: str | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, - stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, - tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, - tools: Iterable[ToolParam] | NotGiven = NOT_GIVEN, - top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + background: Optional[bool] | Omit = omit, + conversation: Optional[response_create_params.Conversation] | Omit = omit, + include: Optional[List[ResponseIncludable]] | Omit = omit, + input: Union[str, ResponseInputParam] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_output_tokens: Optional[int] | Omit = omit, + max_tool_calls: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: ResponsesModel | Omit = omit, + parallel_tool_calls: Optional[bool] | Omit = omit, + previous_response_id: Optional[str] | Omit = omit, + prompt: Optional[ResponsePromptParam] | Omit = omit, + prompt_cache_key: str | Omit = omit, + reasoning: Optional[Reasoning] | Omit = omit, + safety_identifier: str | Omit = omit, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, + store: Optional[bool] | Omit = omit, + stream: Optional[Literal[False]] | Literal[True] | Omit = omit, + stream_options: Optional[response_create_params.StreamOptions] | Omit = omit, + temperature: Optional[float] | Omit = omit, + text: ResponseTextConfigParam | Omit = omit, + tool_choice: response_create_params.ToolChoice | Omit = omit, + tools: Iterable[ToolParam] | Omit = omit, + top_logprobs: Optional[int] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation: Optional[Literal["auto", "disabled"]] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Response | AsyncStream[ResponseStreamEvent]: return await self._post( "/responses", @@ -2305,9 +2305,9 @@ def stream( self, *, response_id: str, - text_format: type[TextFormatT] | NotGiven = NOT_GIVEN, - starting_after: int | NotGiven = NOT_GIVEN, - tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, + text_format: type[TextFormatT] | Omit = omit, + starting_after: int | Omit = omit, + tools: Iterable[ParseableToolParam] | Omit = omit, # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, @@ -2321,31 +2321,31 @@ def stream( *, input: Union[str, ResponseInputParam], model: ResponsesModel, - background: Optional[bool] | NotGiven = NOT_GIVEN, - text_format: type[TextFormatT] | NotGiven = NOT_GIVEN, - tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, - conversation: Optional[response_create_params.Conversation] | NotGiven = NOT_GIVEN, - include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_tool_calls: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, - previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, - prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, - prompt_cache_key: str | NotGiven = NOT_GIVEN, - reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - safety_identifier: str | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, - tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, - top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, + background: Optional[bool] | Omit = omit, + text_format: type[TextFormatT] | Omit = omit, + tools: Iterable[ParseableToolParam] | Omit = omit, + conversation: Optional[response_create_params.Conversation] | Omit = omit, + include: Optional[List[ResponseIncludable]] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_output_tokens: Optional[int] | Omit = omit, + max_tool_calls: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + parallel_tool_calls: Optional[bool] | Omit = omit, + previous_response_id: Optional[str] | Omit = omit, + prompt: Optional[ResponsePromptParam] | Omit = omit, + prompt_cache_key: str | Omit = omit, + reasoning: Optional[Reasoning] | Omit = omit, + safety_identifier: str | Omit = omit, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, + store: Optional[bool] | Omit = omit, + stream_options: Optional[response_create_params.StreamOptions] | Omit = omit, + temperature: Optional[float] | Omit = omit, + text: ResponseTextConfigParam | Omit = omit, + tool_choice: response_create_params.ToolChoice | Omit = omit, + top_logprobs: Optional[int] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation: Optional[Literal["auto", "disabled"]] | Omit = omit, + user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -2357,35 +2357,35 @@ def stream( def stream( self, *, - response_id: str | NotGiven = NOT_GIVEN, - input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, - model: ResponsesModel | NotGiven = NOT_GIVEN, - background: Optional[bool] | NotGiven = NOT_GIVEN, - text_format: type[TextFormatT] | NotGiven = NOT_GIVEN, - tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, - conversation: Optional[response_create_params.Conversation] | NotGiven = NOT_GIVEN, - include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_tool_calls: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, - previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, - prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, - prompt_cache_key: str | NotGiven = NOT_GIVEN, - reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - safety_identifier: str | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, - tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, - top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, - starting_after: int | NotGiven = NOT_GIVEN, + response_id: str | Omit = omit, + input: Union[str, ResponseInputParam] | Omit = omit, + model: ResponsesModel | Omit = omit, + background: Optional[bool] | Omit = omit, + text_format: type[TextFormatT] | Omit = omit, + tools: Iterable[ParseableToolParam] | Omit = omit, + conversation: Optional[response_create_params.Conversation] | Omit = omit, + include: Optional[List[ResponseIncludable]] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_output_tokens: Optional[int] | Omit = omit, + max_tool_calls: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + parallel_tool_calls: Optional[bool] | Omit = omit, + previous_response_id: Optional[str] | Omit = omit, + prompt: Optional[ResponsePromptParam] | Omit = omit, + prompt_cache_key: str | Omit = omit, + reasoning: Optional[Reasoning] | Omit = omit, + safety_identifier: str | Omit = omit, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, + store: Optional[bool] | Omit = omit, + stream_options: Optional[response_create_params.StreamOptions] | Omit = omit, + temperature: Optional[float] | Omit = omit, + text: ResponseTextConfigParam | Omit = omit, + tool_choice: response_create_params.ToolChoice | Omit = omit, + top_logprobs: Optional[int] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation: Optional[Literal["auto", "disabled"]] | Omit = omit, + user: str | Omit = omit, + starting_after: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -2486,7 +2486,7 @@ def stream( starting_after=None, ) else: - if isinstance(response_id, NotGiven): + if isinstance(response_id, Omit): raise ValueError("response_id must be provided when streaming an existing response") api_request = self.retrieve( @@ -2508,35 +2508,35 @@ def stream( async def parse( self, *, - text_format: type[TextFormatT] | NotGiven = NOT_GIVEN, - background: Optional[bool] | NotGiven = NOT_GIVEN, - conversation: Optional[response_create_params.Conversation] | NotGiven = NOT_GIVEN, - include: Optional[List[ResponseIncludable]] | NotGiven = NOT_GIVEN, - input: Union[str, ResponseInputParam] | NotGiven = NOT_GIVEN, - instructions: Optional[str] | NotGiven = NOT_GIVEN, - max_output_tokens: Optional[int] | NotGiven = NOT_GIVEN, - max_tool_calls: Optional[int] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - model: ResponsesModel | NotGiven = NOT_GIVEN, - parallel_tool_calls: Optional[bool] | NotGiven = NOT_GIVEN, - previous_response_id: Optional[str] | NotGiven = NOT_GIVEN, - prompt: Optional[ResponsePromptParam] | NotGiven = NOT_GIVEN, - prompt_cache_key: str | NotGiven = NOT_GIVEN, - reasoning: Optional[Reasoning] | NotGiven = NOT_GIVEN, - safety_identifier: str | NotGiven = NOT_GIVEN, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | NotGiven = NOT_GIVEN, - store: Optional[bool] | NotGiven = NOT_GIVEN, - stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, - stream_options: Optional[response_create_params.StreamOptions] | NotGiven = NOT_GIVEN, - temperature: Optional[float] | NotGiven = NOT_GIVEN, - text: ResponseTextConfigParam | NotGiven = NOT_GIVEN, - tool_choice: response_create_params.ToolChoice | NotGiven = NOT_GIVEN, - tools: Iterable[ParseableToolParam] | NotGiven = NOT_GIVEN, - top_logprobs: Optional[int] | NotGiven = NOT_GIVEN, - top_p: Optional[float] | NotGiven = NOT_GIVEN, - truncation: Optional[Literal["auto", "disabled"]] | NotGiven = NOT_GIVEN, - user: str | NotGiven = NOT_GIVEN, - verbosity: Optional[Literal["low", "medium", "high"]] | NotGiven = NOT_GIVEN, + text_format: type[TextFormatT] | Omit = omit, + background: Optional[bool] | Omit = omit, + conversation: Optional[response_create_params.Conversation] | Omit = omit, + include: Optional[List[ResponseIncludable]] | Omit = omit, + input: Union[str, ResponseInputParam] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_output_tokens: Optional[int] | Omit = omit, + max_tool_calls: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: ResponsesModel | Omit = omit, + parallel_tool_calls: Optional[bool] | Omit = omit, + previous_response_id: Optional[str] | Omit = omit, + prompt: Optional[ResponsePromptParam] | Omit = omit, + prompt_cache_key: str | Omit = omit, + reasoning: Optional[Reasoning] | Omit = omit, + safety_identifier: str | Omit = omit, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, + store: Optional[bool] | Omit = omit, + stream: Optional[Literal[False]] | Literal[True] | Omit = omit, + stream_options: Optional[response_create_params.StreamOptions] | Omit = omit, + temperature: Optional[float] | Omit = omit, + text: ResponseTextConfigParam | Omit = omit, + tool_choice: response_create_params.ToolChoice | Omit = omit, + tools: Iterable[ParseableToolParam] | Omit = omit, + top_logprobs: Optional[int] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation: Optional[Literal["auto", "disabled"]] | Omit = omit, + user: str | Omit = omit, + verbosity: Optional[Literal["low", "medium", "high"]] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -2614,16 +2614,16 @@ async def retrieve( self, response_id: str, *, - include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, - include_obfuscation: bool | NotGiven = NOT_GIVEN, - starting_after: int | NotGiven = NOT_GIVEN, - stream: Literal[False] | NotGiven = NOT_GIVEN, + include: List[ResponseIncludable] | Omit = omit, + include_obfuscation: bool | Omit = omit, + starting_after: int | Omit = omit, + stream: Literal[False] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Response: ... @overload @@ -2632,8 +2632,8 @@ async def retrieve( response_id: str, *, stream: Literal[True], - include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, - starting_after: int | NotGiven = NOT_GIVEN, + include: List[ResponseIncludable] | Omit = omit, + starting_after: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -2648,8 +2648,8 @@ async def retrieve( response_id: str, *, stream: bool, - include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, - starting_after: int | NotGiven = NOT_GIVEN, + include: List[ResponseIncludable] | Omit = omit, + starting_after: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -2664,8 +2664,8 @@ async def retrieve( response_id: str, *, stream: bool = False, - include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, - starting_after: int | NotGiven = NOT_GIVEN, + include: List[ResponseIncludable] | Omit = omit, + starting_after: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -2712,15 +2712,15 @@ async def retrieve( response_id: str, *, stream: Literal[True], - include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, - include_obfuscation: bool | NotGiven = NOT_GIVEN, - starting_after: int | NotGiven = NOT_GIVEN, + include: List[ResponseIncludable] | Omit = omit, + include_obfuscation: bool | Omit = omit, + starting_after: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncStream[ResponseStreamEvent]: """ Retrieves a model response with the given ID. @@ -2761,15 +2761,15 @@ async def retrieve( response_id: str, *, stream: bool, - include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, - include_obfuscation: bool | NotGiven = NOT_GIVEN, - starting_after: int | NotGiven = NOT_GIVEN, + include: List[ResponseIncludable] | Omit = omit, + include_obfuscation: bool | Omit = omit, + starting_after: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Response | AsyncStream[ResponseStreamEvent]: """ Retrieves a model response with the given ID. @@ -2808,16 +2808,16 @@ async def retrieve( self, response_id: str, *, - include: List[ResponseIncludable] | NotGiven = NOT_GIVEN, - include_obfuscation: bool | NotGiven = NOT_GIVEN, - starting_after: int | NotGiven = NOT_GIVEN, - stream: Literal[False] | Literal[True] | NotGiven = NOT_GIVEN, + include: List[ResponseIncludable] | Omit = omit, + include_obfuscation: bool | Omit = omit, + starting_after: int | Omit = omit, + stream: Literal[False] | Literal[True] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Response | AsyncStream[ResponseStreamEvent]: if not response_id: raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") @@ -2852,7 +2852,7 @@ async def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: """ Deletes a model response with the given ID. @@ -2886,7 +2886,7 @@ async def cancel( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Response: """Cancels a model response with the given ID. @@ -3008,9 +3008,9 @@ def input_items(self) -> AsyncInputItemsWithStreamingResponse: return AsyncInputItemsWithStreamingResponse(self._responses.input_items) -def _make_tools(tools: Iterable[ParseableToolParam] | NotGiven) -> List[ToolParam] | NotGiven: +def _make_tools(tools: Iterable[ParseableToolParam] | Omit) -> List[ToolParam] | Omit: if not is_given(tools): - return NOT_GIVEN + return omit converted_tools: List[ToolParam] = [] for tool in tools: diff --git a/src/openai/resources/uploads/parts.py b/src/openai/resources/uploads/parts.py index a32f4eb1d2..73eabd4083 100644 --- a/src/openai/resources/uploads/parts.py +++ b/src/openai/resources/uploads/parts.py @@ -7,7 +7,7 @@ import httpx from ... import _legacy_response -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven, FileTypes +from ..._types import Body, Query, Headers, NotGiven, FileTypes, not_given from ..._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource @@ -49,7 +49,7 @@ def create( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> UploadPart: """ Adds a @@ -124,7 +124,7 @@ async def create( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> UploadPart: """ Adds a diff --git a/src/openai/resources/uploads/uploads.py b/src/openai/resources/uploads/uploads.py index 8811bed48c..8953256f2a 100644 --- a/src/openai/resources/uploads/uploads.py +++ b/src/openai/resources/uploads/uploads.py @@ -22,7 +22,7 @@ AsyncPartsWithStreamingResponse, ) from ...types import FilePurpose, upload_create_params, upload_complete_params -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr +from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given from ..._utils import maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource @@ -73,7 +73,7 @@ def upload_file_chunked( purpose: FilePurpose, bytes: int | None = None, part_size: int | None = None, - md5: str | NotGiven = NOT_GIVEN, + md5: str | Omit = omit, ) -> Upload: """Splits a file into multiple 64MB parts and uploads them sequentially.""" @@ -87,7 +87,7 @@ def upload_file_chunked( mime_type: str, purpose: FilePurpose, part_size: int | None = None, - md5: str | NotGiven = NOT_GIVEN, + md5: str | Omit = omit, ) -> Upload: """Splits an in-memory file into multiple 64MB parts and uploads them sequentially.""" @@ -100,7 +100,7 @@ def upload_file_chunked( filename: str | None = None, bytes: int | None = None, part_size: int | None = None, - md5: str | NotGiven = NOT_GIVEN, + md5: str | Omit = omit, ) -> Upload: """Splits the given file into multiple parts and uploads them sequentially. @@ -170,13 +170,13 @@ def create( filename: str, mime_type: str, purpose: FilePurpose, - expires_after: upload_create_params.ExpiresAfter | NotGiven = NOT_GIVEN, + expires_after: upload_create_params.ExpiresAfter | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Upload: """ Creates an intermediate @@ -252,7 +252,7 @@ def cancel( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Upload: """Cancels the Upload. @@ -282,13 +282,13 @@ def complete( upload_id: str, *, part_ids: SequenceNotStr[str], - md5: str | NotGiven = NOT_GIVEN, + md5: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Upload: """ Completes the @@ -370,7 +370,7 @@ async def upload_file_chunked( purpose: FilePurpose, bytes: int | None = None, part_size: int | None = None, - md5: str | NotGiven = NOT_GIVEN, + md5: str | Omit = omit, ) -> Upload: """Splits a file into multiple 64MB parts and uploads them sequentially.""" @@ -384,7 +384,7 @@ async def upload_file_chunked( mime_type: str, purpose: FilePurpose, part_size: int | None = None, - md5: str | NotGiven = NOT_GIVEN, + md5: str | Omit = omit, ) -> Upload: """Splits an in-memory file into multiple 64MB parts and uploads them sequentially.""" @@ -397,7 +397,7 @@ async def upload_file_chunked( filename: str | None = None, bytes: int | None = None, part_size: int | None = None, - md5: str | NotGiven = NOT_GIVEN, + md5: str | Omit = omit, ) -> Upload: """Splits the given file into multiple parts and uploads them sequentially. @@ -478,13 +478,13 @@ async def create( filename: str, mime_type: str, purpose: FilePurpose, - expires_after: upload_create_params.ExpiresAfter | NotGiven = NOT_GIVEN, + expires_after: upload_create_params.ExpiresAfter | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Upload: """ Creates an intermediate @@ -560,7 +560,7 @@ async def cancel( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Upload: """Cancels the Upload. @@ -590,13 +590,13 @@ async def complete( upload_id: str, *, part_ids: SequenceNotStr[str], - md5: str | NotGiven = NOT_GIVEN, + md5: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Upload: """ Completes the diff --git a/src/openai/resources/vector_stores/file_batches.py b/src/openai/resources/vector_stores/file_batches.py index adf399d8de..0f989821de 100644 --- a/src/openai/resources/vector_stores/file_batches.py +++ b/src/openai/resources/vector_stores/file_batches.py @@ -12,7 +12,7 @@ from ... import _legacy_response from ...types import FileChunkingStrategyParam -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven, FileTypes, SequenceNotStr +from ..._types import Body, Omit, Query, Headers, NotGiven, FileTypes, SequenceNotStr, omit, not_given from ..._utils import is_given, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource @@ -53,14 +53,14 @@ def create( vector_store_id: str, *, file_ids: SequenceNotStr[str], - attributes: Optional[Dict[str, Union[str, float, bool]]] | NotGiven = NOT_GIVEN, - chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, + attributes: Optional[Dict[str, Union[str, float, bool]]] | Omit = omit, + chunking_strategy: FileChunkingStrategyParam | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> VectorStoreFileBatch: """ Create a vector store file batch. @@ -116,7 +116,7 @@ def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> VectorStoreFileBatch: """ Retrieves a vector store file batch. @@ -153,7 +153,7 @@ def cancel( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> VectorStoreFileBatch: """Cancel a vector store file batch. @@ -187,8 +187,8 @@ def create_and_poll( vector_store_id: str, *, file_ids: SequenceNotStr[str], - poll_interval_ms: int | NotGiven = NOT_GIVEN, - chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, + poll_interval_ms: int | Omit = omit, + chunking_strategy: FileChunkingStrategyParam | Omit = omit, ) -> VectorStoreFileBatch: """Create a vector store batch and poll until all files have been processed.""" batch = self.create( @@ -208,17 +208,17 @@ def list_files( batch_id: str, *, vector_store_id: str, - after: str | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - filter: Literal["in_progress", "completed", "failed", "cancelled"] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + before: str | Omit = omit, + filter: Literal["in_progress", "completed", "failed", "cancelled"] | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncCursorPage[VectorStoreFile]: """ Returns a list of vector store files in a batch. @@ -282,7 +282,7 @@ def poll( batch_id: str, *, vector_store_id: str, - poll_interval_ms: int | NotGiven = NOT_GIVEN, + poll_interval_ms: int | Omit = omit, ) -> VectorStoreFileBatch: """Wait for the given file batch to be processed. @@ -321,8 +321,8 @@ def upload_and_poll( files: Iterable[FileTypes], max_concurrency: int = 5, file_ids: SequenceNotStr[str] = [], - poll_interval_ms: int | NotGiven = NOT_GIVEN, - chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, + poll_interval_ms: int | Omit = omit, + chunking_strategy: FileChunkingStrategyParam | Omit = omit, ) -> VectorStoreFileBatch: """Uploads the given files concurrently and then creates a vector store file batch. @@ -390,14 +390,14 @@ async def create( vector_store_id: str, *, file_ids: SequenceNotStr[str], - attributes: Optional[Dict[str, Union[str, float, bool]]] | NotGiven = NOT_GIVEN, - chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, + attributes: Optional[Dict[str, Union[str, float, bool]]] | Omit = omit, + chunking_strategy: FileChunkingStrategyParam | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> VectorStoreFileBatch: """ Create a vector store file batch. @@ -453,7 +453,7 @@ async def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> VectorStoreFileBatch: """ Retrieves a vector store file batch. @@ -490,7 +490,7 @@ async def cancel( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> VectorStoreFileBatch: """Cancel a vector store file batch. @@ -524,8 +524,8 @@ async def create_and_poll( vector_store_id: str, *, file_ids: SequenceNotStr[str], - poll_interval_ms: int | NotGiven = NOT_GIVEN, - chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, + poll_interval_ms: int | Omit = omit, + chunking_strategy: FileChunkingStrategyParam | Omit = omit, ) -> VectorStoreFileBatch: """Create a vector store batch and poll until all files have been processed.""" batch = await self.create( @@ -545,17 +545,17 @@ def list_files( batch_id: str, *, vector_store_id: str, - after: str | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - filter: Literal["in_progress", "completed", "failed", "cancelled"] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + before: str | Omit = omit, + filter: Literal["in_progress", "completed", "failed", "cancelled"] | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[VectorStoreFile, AsyncCursorPage[VectorStoreFile]]: """ Returns a list of vector store files in a batch. @@ -619,7 +619,7 @@ async def poll( batch_id: str, *, vector_store_id: str, - poll_interval_ms: int | NotGiven = NOT_GIVEN, + poll_interval_ms: int | Omit = omit, ) -> VectorStoreFileBatch: """Wait for the given file batch to be processed. @@ -658,8 +658,8 @@ async def upload_and_poll( files: Iterable[FileTypes], max_concurrency: int = 5, file_ids: SequenceNotStr[str] = [], - poll_interval_ms: int | NotGiven = NOT_GIVEN, - chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, + poll_interval_ms: int | Omit = omit, + chunking_strategy: FileChunkingStrategyParam | Omit = omit, ) -> VectorStoreFileBatch: """Uploads the given files concurrently and then creates a vector store file batch. diff --git a/src/openai/resources/vector_stores/files.py b/src/openai/resources/vector_stores/files.py index 2c90bb7a1f..d2eb4e16ed 100644 --- a/src/openai/resources/vector_stores/files.py +++ b/src/openai/resources/vector_stores/files.py @@ -9,7 +9,7 @@ from ... import _legacy_response from ...types import FileChunkingStrategyParam -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven, FileTypes +from ..._types import Body, Omit, Query, Headers, NotGiven, FileTypes, omit, not_given from ..._utils import is_given, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource @@ -50,14 +50,14 @@ def create( vector_store_id: str, *, file_id: str, - attributes: Optional[Dict[str, Union[str, float, bool]]] | NotGiven = NOT_GIVEN, - chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, + attributes: Optional[Dict[str, Union[str, float, bool]]] | Omit = omit, + chunking_strategy: FileChunkingStrategyParam | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> VectorStoreFile: """ Create a vector store file by attaching a @@ -115,7 +115,7 @@ def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> VectorStoreFile: """ Retrieves a vector store file. @@ -153,7 +153,7 @@ def update( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> VectorStoreFile: """ Update attributes on a vector store file. @@ -191,17 +191,17 @@ def list( self, vector_store_id: str, *, - after: str | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - filter: Literal["in_progress", "completed", "failed", "cancelled"] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + before: str | Omit = omit, + filter: Literal["in_progress", "completed", "failed", "cancelled"] | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncCursorPage[VectorStoreFile]: """ Returns a list of vector store files. @@ -268,7 +268,7 @@ def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> VectorStoreFileDeleted: """Delete a vector store file. @@ -304,9 +304,9 @@ def create_and_poll( file_id: str, *, vector_store_id: str, - attributes: Optional[Dict[str, Union[str, float, bool]]] | NotGiven = NOT_GIVEN, - poll_interval_ms: int | NotGiven = NOT_GIVEN, - chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, + attributes: Optional[Dict[str, Union[str, float, bool]]] | Omit = omit, + poll_interval_ms: int | Omit = omit, + chunking_strategy: FileChunkingStrategyParam | Omit = omit, ) -> VectorStoreFile: """Attach a file to the given vector store and wait for it to be processed.""" self.create( @@ -324,7 +324,7 @@ def poll( file_id: str, *, vector_store_id: str, - poll_interval_ms: int | NotGiven = NOT_GIVEN, + poll_interval_ms: int | Omit = omit, ) -> VectorStoreFile: """Wait for the vector store file to finish processing. @@ -365,7 +365,7 @@ def upload( *, vector_store_id: str, file: FileTypes, - chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, + chunking_strategy: FileChunkingStrategyParam | Omit = omit, ) -> VectorStoreFile: """Upload a file to the `files` API and then attach it to the given vector store. @@ -380,9 +380,9 @@ def upload_and_poll( *, vector_store_id: str, file: FileTypes, - attributes: Optional[Dict[str, Union[str, float, bool]]] | NotGiven = NOT_GIVEN, - poll_interval_ms: int | NotGiven = NOT_GIVEN, - chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, + attributes: Optional[Dict[str, Union[str, float, bool]]] | Omit = omit, + poll_interval_ms: int | Omit = omit, + chunking_strategy: FileChunkingStrategyParam | Omit = omit, ) -> VectorStoreFile: """Add a file to a vector store and poll until processing is complete.""" file_obj = self._client.files.create(file=file, purpose="assistants") @@ -404,7 +404,7 @@ def content( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncPage[FileContentResponse]: """ Retrieve the parsed contents of a vector store file. @@ -458,14 +458,14 @@ async def create( vector_store_id: str, *, file_id: str, - attributes: Optional[Dict[str, Union[str, float, bool]]] | NotGiven = NOT_GIVEN, - chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, + attributes: Optional[Dict[str, Union[str, float, bool]]] | Omit = omit, + chunking_strategy: FileChunkingStrategyParam | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> VectorStoreFile: """ Create a vector store file by attaching a @@ -523,7 +523,7 @@ async def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> VectorStoreFile: """ Retrieves a vector store file. @@ -561,7 +561,7 @@ async def update( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> VectorStoreFile: """ Update attributes on a vector store file. @@ -599,17 +599,17 @@ def list( self, vector_store_id: str, *, - after: str | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - filter: Literal["in_progress", "completed", "failed", "cancelled"] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + before: str | Omit = omit, + filter: Literal["in_progress", "completed", "failed", "cancelled"] | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[VectorStoreFile, AsyncCursorPage[VectorStoreFile]]: """ Returns a list of vector store files. @@ -676,7 +676,7 @@ async def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> VectorStoreFileDeleted: """Delete a vector store file. @@ -712,9 +712,9 @@ async def create_and_poll( file_id: str, *, vector_store_id: str, - attributes: Optional[Dict[str, Union[str, float, bool]]] | NotGiven = NOT_GIVEN, - poll_interval_ms: int | NotGiven = NOT_GIVEN, - chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, + attributes: Optional[Dict[str, Union[str, float, bool]]] | Omit = omit, + poll_interval_ms: int | Omit = omit, + chunking_strategy: FileChunkingStrategyParam | Omit = omit, ) -> VectorStoreFile: """Attach a file to the given vector store and wait for it to be processed.""" await self.create( @@ -732,7 +732,7 @@ async def poll( file_id: str, *, vector_store_id: str, - poll_interval_ms: int | NotGiven = NOT_GIVEN, + poll_interval_ms: int | Omit = omit, ) -> VectorStoreFile: """Wait for the vector store file to finish processing. @@ -773,7 +773,7 @@ async def upload( *, vector_store_id: str, file: FileTypes, - chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, + chunking_strategy: FileChunkingStrategyParam | Omit = omit, ) -> VectorStoreFile: """Upload a file to the `files` API and then attach it to the given vector store. @@ -790,9 +790,9 @@ async def upload_and_poll( *, vector_store_id: str, file: FileTypes, - attributes: Optional[Dict[str, Union[str, float, bool]]] | NotGiven = NOT_GIVEN, - poll_interval_ms: int | NotGiven = NOT_GIVEN, - chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, + attributes: Optional[Dict[str, Union[str, float, bool]]] | Omit = omit, + poll_interval_ms: int | Omit = omit, + chunking_strategy: FileChunkingStrategyParam | Omit = omit, ) -> VectorStoreFile: """Add a file to a vector store and poll until processing is complete.""" file_obj = await self._client.files.create(file=file, purpose="assistants") @@ -814,7 +814,7 @@ def content( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[FileContentResponse, AsyncPage[FileContentResponse]]: """ Retrieve the parsed contents of a vector store file. diff --git a/src/openai/resources/vector_stores/vector_stores.py b/src/openai/resources/vector_stores/vector_stores.py index 4f211ea25a..39548936c8 100644 --- a/src/openai/resources/vector_stores/vector_stores.py +++ b/src/openai/resources/vector_stores/vector_stores.py @@ -23,7 +23,7 @@ vector_store_search_params, vector_store_update_params, ) -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr +from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given from ..._utils import maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource @@ -78,17 +78,17 @@ def with_streaming_response(self) -> VectorStoresWithStreamingResponse: def create( self, *, - chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, - expires_after: vector_store_create_params.ExpiresAfter | NotGiven = NOT_GIVEN, - file_ids: SequenceNotStr[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - name: str | NotGiven = NOT_GIVEN, + chunking_strategy: FileChunkingStrategyParam | Omit = omit, + expires_after: vector_store_create_params.ExpiresAfter | Omit = omit, + file_ids: SequenceNotStr[str] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + name: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> VectorStore: """ Create a vector store. @@ -148,7 +148,7 @@ def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> VectorStore: """ Retrieves a vector store. @@ -177,15 +177,15 @@ def update( self, vector_store_id: str, *, - expires_after: Optional[vector_store_update_params.ExpiresAfter] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - name: Optional[str] | NotGiven = NOT_GIVEN, + expires_after: Optional[vector_store_update_params.ExpiresAfter] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + name: Optional[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> VectorStore: """ Modifies a vector store. @@ -232,16 +232,16 @@ def update( def list( self, *, - after: str | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + before: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncCursorPage[VectorStore]: """Returns a list of vector stores. @@ -303,7 +303,7 @@ def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> VectorStoreDeleted: """ Delete a vector store. @@ -333,16 +333,16 @@ def search( vector_store_id: str, *, query: Union[str, SequenceNotStr[str]], - filters: vector_store_search_params.Filters | NotGiven = NOT_GIVEN, - max_num_results: int | NotGiven = NOT_GIVEN, - ranking_options: vector_store_search_params.RankingOptions | NotGiven = NOT_GIVEN, - rewrite_query: bool | NotGiven = NOT_GIVEN, + filters: vector_store_search_params.Filters | Omit = omit, + max_num_results: int | Omit = omit, + ranking_options: vector_store_search_params.RankingOptions | Omit = omit, + rewrite_query: bool | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncPage[VectorStoreSearchResponse]: """ Search a vector store for relevant chunks based on a query and file attributes @@ -423,17 +423,17 @@ def with_streaming_response(self) -> AsyncVectorStoresWithStreamingResponse: async def create( self, *, - chunking_strategy: FileChunkingStrategyParam | NotGiven = NOT_GIVEN, - expires_after: vector_store_create_params.ExpiresAfter | NotGiven = NOT_GIVEN, - file_ids: SequenceNotStr[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - name: str | NotGiven = NOT_GIVEN, + chunking_strategy: FileChunkingStrategyParam | Omit = omit, + expires_after: vector_store_create_params.ExpiresAfter | Omit = omit, + file_ids: SequenceNotStr[str] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + name: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> VectorStore: """ Create a vector store. @@ -493,7 +493,7 @@ async def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> VectorStore: """ Retrieves a vector store. @@ -522,15 +522,15 @@ async def update( self, vector_store_id: str, *, - expires_after: Optional[vector_store_update_params.ExpiresAfter] | NotGiven = NOT_GIVEN, - metadata: Optional[Metadata] | NotGiven = NOT_GIVEN, - name: Optional[str] | NotGiven = NOT_GIVEN, + expires_after: Optional[vector_store_update_params.ExpiresAfter] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + name: Optional[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> VectorStore: """ Modifies a vector store. @@ -577,16 +577,16 @@ async def update( def list( self, *, - after: str | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + before: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[VectorStore, AsyncCursorPage[VectorStore]]: """Returns a list of vector stores. @@ -648,7 +648,7 @@ async def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> VectorStoreDeleted: """ Delete a vector store. @@ -678,16 +678,16 @@ def search( vector_store_id: str, *, query: Union[str, SequenceNotStr[str]], - filters: vector_store_search_params.Filters | NotGiven = NOT_GIVEN, - max_num_results: int | NotGiven = NOT_GIVEN, - ranking_options: vector_store_search_params.RankingOptions | NotGiven = NOT_GIVEN, - rewrite_query: bool | NotGiven = NOT_GIVEN, + filters: vector_store_search_params.Filters | Omit = omit, + max_num_results: int | Omit = omit, + ranking_options: vector_store_search_params.RankingOptions | Omit = omit, + rewrite_query: bool | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[VectorStoreSearchResponse, AsyncPage[VectorStoreSearchResponse]]: """ Search a vector store for relevant chunks based on a query and file attributes diff --git a/src/openai/types/responses/tool.py b/src/openai/types/responses/tool.py index 482d4e75c1..8dd2bd5981 100644 --- a/src/openai/types/responses/tool.py +++ b/src/openai/types/responses/tool.py @@ -34,6 +34,7 @@ WebSearchToolFilters = web_search_tool.Filters WebSearchToolUserLocation = web_search_tool.UserLocation + class McpAllowedToolsMcpToolFilter(BaseModel): read_only: Optional[bool] = None """Indicates whether or not a tool modifies data or is read-only. diff --git a/src/openai/types/responses/tool_param.py b/src/openai/types/responses/tool_param.py index 54bc271c0f..e84abc4390 100644 --- a/src/openai/types/responses/tool_param.py +++ b/src/openai/types/responses/tool_param.py @@ -36,6 +36,7 @@ WebSearchToolFilters = web_search_tool_param.Filters WebSearchToolUserLocation = web_search_tool_param.UserLocation + class McpAllowedToolsMcpToolFilter(TypedDict, total=False): read_only: bool """Indicates whether or not a tool modifies data or is read-only. diff --git a/tests/test_transform.py b/tests/test_transform.py index 036cfdfb06..bece75dfc7 100644 --- a/tests/test_transform.py +++ b/tests/test_transform.py @@ -8,7 +8,7 @@ import pytest -from openai._types import NOT_GIVEN, Base64FileInput +from openai._types import Base64FileInput, omit, not_given from openai._utils import ( PropertyInfo, transform as _transform, @@ -450,4 +450,11 @@ async def test_transform_skipping(use_async: bool) -> None: @pytest.mark.asyncio async def test_strips_notgiven(use_async: bool) -> None: assert await transform({"foo_bar": "bar"}, Foo1, use_async) == {"fooBar": "bar"} - assert await transform({"foo_bar": NOT_GIVEN}, Foo1, use_async) == {} + assert await transform({"foo_bar": not_given}, Foo1, use_async) == {} + + +@parametrize +@pytest.mark.asyncio +async def test_strips_omit(use_async: bool) -> None: + assert await transform({"foo_bar": "bar"}, Foo1, use_async) == {"fooBar": "bar"} + assert await transform({"foo_bar": omit}, Foo1, use_async) == {} From d296d85884cac05917a2776cc22c632027e8eb05 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 19 Sep 2025 05:03:36 +0000 Subject: [PATCH 495/769] feat(api): add reasoning_text --- .stats.yml | 6 +++--- src/openai/types/conversations/message.py | 12 +++++++++++- .../types/conversations/summary_text_content.py | 2 ++ .../response_content_part_added_event.py | 15 +++++++++++++-- .../responses/response_content_part_done_event.py | 15 +++++++++++++-- .../types/responses/response_reasoning_item.py | 4 ++-- .../responses/response_reasoning_item_param.py | 4 ++-- 7 files changed, 46 insertions(+), 12 deletions(-) diff --git a/.stats.yml b/.stats.yml index 2dd0aef46a..c961e232cf 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 118 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-380330a93b5d010391ca3b36ea193c5353b0dfdf2ddd02789ef84a84ce427e82.yml -openapi_spec_hash: 859703234259ecdd2a3c6f4de88eb504 -config_hash: b619b45c1e7facf819f902dee8fa4f97 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-ea23db36b0899cc715f56d0098956069b2d92880f448adff3a4ac1bb53cb2cec.yml +openapi_spec_hash: 36f76ea31297c9593bcfae453f6255cc +config_hash: 666d6bb4b564f0d9d431124b5d1a0665 diff --git a/src/openai/types/conversations/message.py b/src/openai/types/conversations/message.py index 95e03c5c00..dbf5a14680 100644 --- a/src/openai/types/conversations/message.py +++ b/src/openai/types/conversations/message.py @@ -14,7 +14,16 @@ from ..responses.response_output_text import ResponseOutputText from ..responses.response_output_refusal import ResponseOutputRefusal -__all__ = ["Message", "Content"] +__all__ = ["Message", "Content", "ContentReasoningText"] + + +class ContentReasoningText(BaseModel): + text: str + """The reasoning text from the model.""" + + type: Literal["reasoning_text"] + """The type of the reasoning text. Always `reasoning_text`.""" + Content: TypeAlias = Annotated[ Union[ @@ -22,6 +31,7 @@ ResponseOutputText, TextContent, SummaryTextContent, + ContentReasoningText, ResponseOutputRefusal, ResponseInputImage, ComputerScreenshotContent, diff --git a/src/openai/types/conversations/summary_text_content.py b/src/openai/types/conversations/summary_text_content.py index 047769ed67..d357b15725 100644 --- a/src/openai/types/conversations/summary_text_content.py +++ b/src/openai/types/conversations/summary_text_content.py @@ -9,5 +9,7 @@ class SummaryTextContent(BaseModel): text: str + """A summary of the reasoning output from the model so far.""" type: Literal["summary_text"] + """The type of the object. Always `summary_text`.""" diff --git a/src/openai/types/responses/response_content_part_added_event.py b/src/openai/types/responses/response_content_part_added_event.py index 11e0ac7c92..c78e80d1c4 100644 --- a/src/openai/types/responses/response_content_part_added_event.py +++ b/src/openai/types/responses/response_content_part_added_event.py @@ -8,9 +8,20 @@ from .response_output_text import ResponseOutputText from .response_output_refusal import ResponseOutputRefusal -__all__ = ["ResponseContentPartAddedEvent", "Part"] +__all__ = ["ResponseContentPartAddedEvent", "Part", "PartReasoningText"] -Part: TypeAlias = Annotated[Union[ResponseOutputText, ResponseOutputRefusal], PropertyInfo(discriminator="type")] + +class PartReasoningText(BaseModel): + text: str + """The reasoning text from the model.""" + + type: Literal["reasoning_text"] + """The type of the reasoning text. Always `reasoning_text`.""" + + +Part: TypeAlias = Annotated[ + Union[ResponseOutputText, ResponseOutputRefusal, PartReasoningText], PropertyInfo(discriminator="type") +] class ResponseContentPartAddedEvent(BaseModel): diff --git a/src/openai/types/responses/response_content_part_done_event.py b/src/openai/types/responses/response_content_part_done_event.py index e1b411bb45..732f2303ef 100644 --- a/src/openai/types/responses/response_content_part_done_event.py +++ b/src/openai/types/responses/response_content_part_done_event.py @@ -8,9 +8,20 @@ from .response_output_text import ResponseOutputText from .response_output_refusal import ResponseOutputRefusal -__all__ = ["ResponseContentPartDoneEvent", "Part"] +__all__ = ["ResponseContentPartDoneEvent", "Part", "PartReasoningText"] -Part: TypeAlias = Annotated[Union[ResponseOutputText, ResponseOutputRefusal], PropertyInfo(discriminator="type")] + +class PartReasoningText(BaseModel): + text: str + """The reasoning text from the model.""" + + type: Literal["reasoning_text"] + """The type of the reasoning text. Always `reasoning_text`.""" + + +Part: TypeAlias = Annotated[ + Union[ResponseOutputText, ResponseOutputRefusal, PartReasoningText], PropertyInfo(discriminator="type") +] class ResponseContentPartDoneEvent(BaseModel): diff --git a/src/openai/types/responses/response_reasoning_item.py b/src/openai/types/responses/response_reasoning_item.py index e5cb094e62..fc582cf7c5 100644 --- a/src/openai/types/responses/response_reasoning_item.py +++ b/src/openai/types/responses/response_reasoning_item.py @@ -18,10 +18,10 @@ class Summary(BaseModel): class Content(BaseModel): text: str - """Reasoning text output from the model.""" + """The reasoning text from the model.""" type: Literal["reasoning_text"] - """The type of the object. Always `reasoning_text`.""" + """The type of the reasoning text. Always `reasoning_text`.""" class ResponseReasoningItem(BaseModel): diff --git a/src/openai/types/responses/response_reasoning_item_param.py b/src/openai/types/responses/response_reasoning_item_param.py index 042b6c05db..56e88ba28d 100644 --- a/src/openai/types/responses/response_reasoning_item_param.py +++ b/src/openai/types/responses/response_reasoning_item_param.py @@ -18,10 +18,10 @@ class Summary(TypedDict, total=False): class Content(TypedDict, total=False): text: Required[str] - """Reasoning text output from the model.""" + """The reasoning text from the model.""" type: Required[Literal["reasoning_text"]] - """The type of the object. Always `reasoning_text`.""" + """The type of the reasoning text. Always `reasoning_text`.""" class ResponseReasoningItemParam(TypedDict, total=False): From 71dedfad6716c241744d3bd856370e8c59e75500 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 19 Sep 2025 05:04:29 +0000 Subject: [PATCH 496/769] release: 1.108.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 102fa47016..118bf88182 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.108.0" + ".": "1.108.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e35189611..897ba0d1bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 1.108.1 (2025-09-19) + +Full Changelog: [v1.108.0...v1.108.1](https://github.com/openai/openai-python/compare/v1.108.0...v1.108.1) + +### Features + +* **api:** add reasoning_text ([18d8e12](https://github.com/openai/openai-python/commit/18d8e12061d1fd4e09d24986ff6e38c5063013e9)) + + +### Chores + +* **types:** change optional parameter type from NotGiven to Omit ([acc190a](https://github.com/openai/openai-python/commit/acc190a29526e64db6074e7f21aca800423c128c)) + ## 1.108.0 (2025-09-17) Full Changelog: [v1.107.3...v1.108.0](https://github.com/openai/openai-python/compare/v1.107.3...v1.108.0) diff --git a/pyproject.toml b/pyproject.toml index 058b7cda6c..5adf4a2a8c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.108.0" +version = "1.108.1" 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 7030fe068c..8ba4e8e168 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.108.0" # x-release-please-version +__version__ = "1.108.1" # x-release-please-version From 9272e61afa41b1e8223fdccc4935f55e7b72d11b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 19 Sep 2025 17:41:05 +0000 Subject: [PATCH 497/769] chore: do not install brew dependencies in ./scripts/bootstrap by default --- scripts/bootstrap | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/scripts/bootstrap b/scripts/bootstrap index 9910ec05fc..953993addb 100755 --- a/scripts/bootstrap +++ b/scripts/bootstrap @@ -4,10 +4,18 @@ set -e cd "$(dirname "$0")/.." -if ! command -v rye >/dev/null 2>&1 && [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ]; then +if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "$SKIP_BREW" != "1" ] && [ -t 0 ]; then brew bundle check >/dev/null 2>&1 || { - echo "==> Installing Homebrew dependencies…" - brew bundle + echo -n "==> Install Homebrew dependencies? (y/N): " + read -r response + case "$response" in + [yY][eE][sS]|[yY]) + brew bundle + ;; + *) + ;; + esac + echo } fi From bfed4af9be93e911111299c34da1baf324cbea99 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sun, 21 Sep 2025 05:33:13 +0000 Subject: [PATCH 498/769] fix(api): fix mcp tool name --- .stats.yml | 4 ++-- src/openai/types/realtime/realtime_mcp_tool_call.py | 4 ++-- src/openai/types/realtime/realtime_mcp_tool_call_param.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.stats.yml b/.stats.yml index c961e232cf..66c059ae58 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 118 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-ea23db36b0899cc715f56d0098956069b2d92880f448adff3a4ac1bb53cb2cec.yml -openapi_spec_hash: 36f76ea31297c9593bcfae453f6255cc +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-65d42621b731238ad4e59a35a705fc0608b17f53a14d047e66ce480c793da26b.yml +openapi_spec_hash: d7ca86b2507600cbd5ed197cf31263c2 config_hash: 666d6bb4b564f0d9d431124b5d1a0665 diff --git a/src/openai/types/realtime/realtime_mcp_tool_call.py b/src/openai/types/realtime/realtime_mcp_tool_call.py index 533175e55b..019aee25c0 100644 --- a/src/openai/types/realtime/realtime_mcp_tool_call.py +++ b/src/openai/types/realtime/realtime_mcp_tool_call.py @@ -30,8 +30,8 @@ class RealtimeMcpToolCall(BaseModel): server_label: str """The label of the MCP server running the tool.""" - type: Literal["mcp_tool_call"] - """The type of the item. Always `mcp_tool_call`.""" + type: Literal["mcp_call"] + """The type of the item. Always `mcp_call`.""" approval_request_id: Optional[str] = None """The ID of an associated approval request, if any.""" diff --git a/src/openai/types/realtime/realtime_mcp_tool_call_param.py b/src/openai/types/realtime/realtime_mcp_tool_call_param.py index afdc9d1d17..0ba16d3dc1 100644 --- a/src/openai/types/realtime/realtime_mcp_tool_call_param.py +++ b/src/openai/types/realtime/realtime_mcp_tool_call_param.py @@ -27,8 +27,8 @@ class RealtimeMcpToolCallParam(TypedDict, total=False): server_label: Required[str] """The label of the MCP server running the tool.""" - type: Required[Literal["mcp_tool_call"]] - """The type of the item. Always `mcp_tool_call`.""" + type: Required[Literal["mcp_call"]] + """The type of the item. Always `mcp_call`.""" approval_request_id: Optional[str] """The ID of an associated approval request, if any.""" From 3a3cabb7e140f0a462e4e3aa4f9f2902bb7a2a92 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 19:25:50 +0000 Subject: [PATCH 499/769] chore: improve example values --- tests/api_resources/conversations/test_items.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/api_resources/conversations/test_items.py b/tests/api_resources/conversations/test_items.py index c308160543..0df88dc199 100644 --- a/tests/api_resources/conversations/test_items.py +++ b/tests/api_resources/conversations/test_items.py @@ -30,6 +30,7 @@ def test_method_create(self, client: OpenAI) -> None: { "content": "string", "role": "user", + "type": "message", } ], ) @@ -58,6 +59,7 @@ def test_raw_response_create(self, client: OpenAI) -> None: { "content": "string", "role": "user", + "type": "message", } ], ) @@ -75,6 +77,7 @@ def test_streaming_response_create(self, client: OpenAI) -> None: { "content": "string", "role": "user", + "type": "message", } ], ) as response: @@ -95,6 +98,7 @@ def test_path_params_create(self, client: OpenAI) -> None: { "content": "string", "role": "user", + "type": "message", } ], ) @@ -267,6 +271,7 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None: { "content": "string", "role": "user", + "type": "message", } ], ) @@ -295,6 +300,7 @@ async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: { "content": "string", "role": "user", + "type": "message", } ], ) @@ -312,6 +318,7 @@ async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> Non { "content": "string", "role": "user", + "type": "message", } ], ) as response: @@ -332,6 +339,7 @@ async def test_path_params_create(self, async_client: AsyncOpenAI) -> None: { "content": "string", "role": "user", + "type": "message", } ], ) From 58add648f119140bf108931371e0811601e977c3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 23:20:40 +0000 Subject: [PATCH 500/769] chore(api): openapi updates for conversations --- .stats.yml | 4 +- .../resources/conversations/conversations.py | 38 ++++++++++--------- .../conversation_create_params.py | 6 +-- .../conversation_update_params.py | 13 ++++--- 4 files changed, 34 insertions(+), 27 deletions(-) diff --git a/.stats.yml b/.stats.yml index 66c059ae58..062111e2c4 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 118 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-65d42621b731238ad4e59a35a705fc0608b17f53a14d047e66ce480c793da26b.yml -openapi_spec_hash: d7ca86b2507600cbd5ed197cf31263c2 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-937fcfac8cbab692796cd9822b37e48a311e2220a8b103106ded0ee92a0b9484.yml +openapi_spec_hash: 74a0c58b5b8c4e06792d79b685e02a01 config_hash: 666d6bb4b564f0d9d431124b5d1a0665 diff --git a/src/openai/resources/conversations/conversations.py b/src/openai/resources/conversations/conversations.py index 4b942eb014..da037a4e22 100644 --- a/src/openai/resources/conversations/conversations.py +++ b/src/openai/resources/conversations/conversations.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict, Iterable, Optional +from typing import Iterable, Optional import httpx @@ -115,7 +115,7 @@ def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Conversation: """ - Get a conversation with the given ID. + Get a conversation Args: extra_headers: Send extra headers @@ -140,7 +140,7 @@ def update( self, conversation_id: str, *, - metadata: Dict[str, str], + metadata: Optional[Metadata], # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -149,14 +149,15 @@ def update( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Conversation: """ - Update a conversation's metadata with the given ID. + Update a conversation Args: metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. Keys are strings with a maximum - length of 64 characters. Values are strings with a maximum length of 512 - characters. + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. extra_headers: Send extra headers @@ -188,8 +189,9 @@ def delete( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ConversationDeletedResource: - """ - Delete a conversation with the given ID. + """Delete a conversation. + + Items in the conversation will not be deleted. Args: extra_headers: Send extra headers @@ -296,7 +298,7 @@ async def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Conversation: """ - Get a conversation with the given ID. + Get a conversation Args: extra_headers: Send extra headers @@ -321,7 +323,7 @@ async def update( self, conversation_id: str, *, - metadata: Dict[str, str], + metadata: Optional[Metadata], # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -330,14 +332,15 @@ async def update( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Conversation: """ - Update a conversation's metadata with the given ID. + Update a conversation Args: metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. Keys are strings with a maximum - length of 64 characters. Values are strings with a maximum length of 512 - characters. + querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. extra_headers: Send extra headers @@ -371,8 +374,9 @@ async def delete( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ConversationDeletedResource: - """ - Delete a conversation with the given ID. + """Delete a conversation. + + Items in the conversation will not be deleted. Args: extra_headers: Send extra headers diff --git a/src/openai/types/conversations/conversation_create_params.py b/src/openai/types/conversations/conversation_create_params.py index 0d84f503bd..5f38d2aca7 100644 --- a/src/openai/types/conversations/conversation_create_params.py +++ b/src/openai/types/conversations/conversation_create_params.py @@ -13,9 +13,9 @@ class ConversationCreateParams(TypedDict, total=False): items: Optional[Iterable[ResponseInputItemParam]] - """ - Initial items to include in the conversation context. You may add up to 20 items - at a time. + """Initial items to include in the conversation context. + + You may add up to 20 items at a time. """ metadata: Optional[Metadata] diff --git a/src/openai/types/conversations/conversation_update_params.py b/src/openai/types/conversations/conversation_update_params.py index f2aa42d833..1f0dd09e50 100644 --- a/src/openai/types/conversations/conversation_update_params.py +++ b/src/openai/types/conversations/conversation_update_params.py @@ -2,18 +2,21 @@ from __future__ import annotations -from typing import Dict +from typing import Optional from typing_extensions import Required, TypedDict +from ..shared_params.metadata import Metadata + __all__ = ["ConversationUpdateParams"] class ConversationUpdateParams(TypedDict, total=False): - metadata: Required[Dict[str, str]] + metadata: Required[Optional[Metadata]] """Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. Keys are - strings with a maximum length of 64 characters. Values are strings with a - maximum length of 512 characters. + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. """ From 02af9aacd14805cbca21078d32a311758360f134 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 23:21:08 +0000 Subject: [PATCH 501/769] release: 1.108.2 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 15 +++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 118bf88182..e66e9ab9f4 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.108.1" + ".": "1.108.2" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 897ba0d1bc..34d2e24899 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## 1.108.2 (2025-09-22) + +Full Changelog: [v1.108.1...v1.108.2](https://github.com/openai/openai-python/compare/v1.108.1...v1.108.2) + +### Bug Fixes + +* **api:** fix mcp tool name ([fd1c673](https://github.com/openai/openai-python/commit/fd1c673fa8d5581b38c69c37aa4fd1fd251259a2)) + + +### Chores + +* **api:** openapi updates for conversations ([3224f6f](https://github.com/openai/openai-python/commit/3224f6f9b4221b954a8f63de66bcaab389164ee5)) +* do not install brew dependencies in ./scripts/bootstrap by default ([6764b00](https://github.com/openai/openai-python/commit/6764b00bcb8aeab41e73d2fcaf6c7a18ea9f7909)) +* improve example values ([20b58e1](https://github.com/openai/openai-python/commit/20b58e164f9f28b9fc562968263fa3eacc6f5c7c)) + ## 1.108.1 (2025-09-19) Full Changelog: [v1.108.0...v1.108.1](https://github.com/openai/openai-python/compare/v1.108.0...v1.108.1) diff --git a/pyproject.toml b/pyproject.toml index 5adf4a2a8c..01d7c4e4a2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.108.1" +version = "1.108.2" 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 8ba4e8e168..a266f4ecdb 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.108.1" # x-release-please-version +__version__ = "1.108.2" # x-release-please-version From c523e639bb0b041562aa2a1b511ddf032e4a719a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 23 Sep 2025 16:55:28 +0000 Subject: [PATCH 502/769] feat(api): gpt-5-codex --- .stats.yml | 4 ++-- src/openai/types/shared/all_models.py | 1 + src/openai/types/shared/responses_model.py | 1 + src/openai/types/shared_params/responses_model.py | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 062111e2c4..48863a6e93 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 118 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-937fcfac8cbab692796cd9822b37e48a311e2220a8b103106ded0ee92a0b9484.yml -openapi_spec_hash: 74a0c58b5b8c4e06792d79b685e02a01 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-410219ea680089f02bb55163c673919703f946c3d6ad7ff5d6f607121d5287d5.yml +openapi_spec_hash: 2b3eee95d3f6796c7a61dfddf694a59a config_hash: 666d6bb4b564f0d9d431124b5d1a0665 diff --git a/src/openai/types/shared/all_models.py b/src/openai/types/shared/all_models.py index 828f3b5669..76ca1ffd29 100644 --- a/src/openai/types/shared/all_models.py +++ b/src/openai/types/shared/all_models.py @@ -21,5 +21,6 @@ "o4-mini-deep-research-2025-06-26", "computer-use-preview", "computer-use-preview-2025-03-11", + "gpt-5-codex", ], ] diff --git a/src/openai/types/shared/responses_model.py b/src/openai/types/shared/responses_model.py index 4d35356806..4fbdce8db9 100644 --- a/src/openai/types/shared/responses_model.py +++ b/src/openai/types/shared/responses_model.py @@ -21,5 +21,6 @@ "o4-mini-deep-research-2025-06-26", "computer-use-preview", "computer-use-preview-2025-03-11", + "gpt-5-codex", ], ] diff --git a/src/openai/types/shared_params/responses_model.py b/src/openai/types/shared_params/responses_model.py index adfcecf1e5..2feaa22b67 100644 --- a/src/openai/types/shared_params/responses_model.py +++ b/src/openai/types/shared_params/responses_model.py @@ -23,5 +23,6 @@ "o4-mini-deep-research-2025-06-26", "computer-use-preview", "computer-use-preview-2025-03-11", + "gpt-5-codex", ], ] From 9c4b995682f664c629d681c975496a99c793c06d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 23 Sep 2025 16:55:58 +0000 Subject: [PATCH 503/769] release: 1.109.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index e66e9ab9f4..529006a8d5 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.108.2" + ".": "1.109.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 34d2e24899..15e8f62701 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.109.0 (2025-09-23) + +Full Changelog: [v1.108.2...v1.109.0](https://github.com/openai/openai-python/compare/v1.108.2...v1.109.0) + +### Features + +* **api:** gpt-5-codex ([34502b5](https://github.com/openai/openai-python/commit/34502b5a175f8a10ea8694fcea38fe7308de89ef)) + ## 1.108.2 (2025-09-22) Full Changelog: [v1.108.1...v1.108.2](https://github.com/openai/openai-python/compare/v1.108.1...v1.108.2) diff --git a/pyproject.toml b/pyproject.toml index 01d7c4e4a2..26dfbcf443 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.108.2" +version = "1.109.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 a266f4ecdb..16f48fb404 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.108.2" # x-release-please-version +__version__ = "1.109.0" # x-release-please-version From edb8e106bf41937e1da9644250945665bc7a4caa Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 24 Sep 2025 10:05:32 +0000 Subject: [PATCH 504/769] fix(compat): compat with `pydantic<2.8.0` when using additional fields --- src/openai/types/evals/runs/output_item_list_response.py | 7 ++++++- .../types/evals/runs/output_item_retrieve_response.py | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/openai/types/evals/runs/output_item_list_response.py b/src/openai/types/evals/runs/output_item_list_response.py index f774518f3c..e88c21766f 100644 --- a/src/openai/types/evals/runs/output_item_list_response.py +++ b/src/openai/types/evals/runs/output_item_list_response.py @@ -27,12 +27,17 @@ class Result(BaseModel): type: Optional[str] = None """The grader type (for example, "string-check-grader").""" - __pydantic_extra__: Dict[str, object] = FieldInfo(init=False) # pyright: ignore[reportIncompatibleVariableOverride] if TYPE_CHECKING: + # Some versions of Pydantic <2.8.0 have a bug and don’t allow assigning a + # value to this field, so for compatibility we avoid doing it at runtime. + __pydantic_extra__: Dict[str, object] = FieldInfo(init=False) # pyright: ignore[reportIncompatibleVariableOverride] + # Stub to indicate that arbitrary properties are accepted. # To access properties that are not valid identifiers you can use `getattr`, e.g. # `getattr(obj, '$type')` def __getattr__(self, attr: str) -> object: ... + else: + __pydantic_extra__: Dict[str, object] class SampleInput(BaseModel): diff --git a/src/openai/types/evals/runs/output_item_retrieve_response.py b/src/openai/types/evals/runs/output_item_retrieve_response.py index d66435bd4f..c728629b41 100644 --- a/src/openai/types/evals/runs/output_item_retrieve_response.py +++ b/src/openai/types/evals/runs/output_item_retrieve_response.py @@ -27,12 +27,17 @@ class Result(BaseModel): type: Optional[str] = None """The grader type (for example, "string-check-grader").""" - __pydantic_extra__: Dict[str, object] = FieldInfo(init=False) # pyright: ignore[reportIncompatibleVariableOverride] if TYPE_CHECKING: + # Some versions of Pydantic <2.8.0 have a bug and don’t allow assigning a + # value to this field, so for compatibility we avoid doing it at runtime. + __pydantic_extra__: Dict[str, object] = FieldInfo(init=False) # pyright: ignore[reportIncompatibleVariableOverride] + # Stub to indicate that arbitrary properties are accepted. # To access properties that are not valid identifiers you can use `getattr`, e.g. # `getattr(obj, '$type')` def __getattr__(self, attr: str) -> object: ... + else: + __pydantic_extra__: Dict[str, object] class SampleInput(BaseModel): From a1493f92a7cd4399d57046aadc943aeadda5b8e7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 24 Sep 2025 10:06:05 +0000 Subject: [PATCH 505/769] release: 1.109.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 529006a8d5..9e6e24e53d 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.109.0" + ".": "1.109.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 15e8f62701..24aced9a9d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.109.1 (2025-09-24) + +Full Changelog: [v1.109.0...v1.109.1](https://github.com/openai/openai-python/compare/v1.109.0...v1.109.1) + +### Bug Fixes + +* **compat:** compat with `pydantic<2.8.0` when using additional fields ([5d95ecf](https://github.com/openai/openai-python/commit/5d95ecf7abd65f3e4e273be14c80f9b4cd91ffe8)) + ## 1.109.0 (2025-09-23) Full Changelog: [v1.108.2...v1.109.0](https://github.com/openai/openai-python/compare/v1.108.2...v1.109.0) diff --git a/pyproject.toml b/pyproject.toml index 26dfbcf443..b89b4e25bd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.109.0" +version = "1.109.1" 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 16f48fb404..53c9794d8f 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.109.0" # x-release-please-version +__version__ = "1.109.1" # x-release-please-version From 8b333e66c602c3e8244324c38442f21a92d214ed Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 30 Sep 2025 07:36:50 +0000 Subject: [PATCH 506/769] feat(api): Support images and files for function call outputs in responses, BatchUsage This release introduces a major version change to reflect a breaking modification in the `ResponseFunctionToolCallOutputItem` and `ResponseCustomToolCallOutput` schemas. Specifically, the `output` field, which previously accepted only a `string` value, has been expanded to support multiple structured types: ``` Before: output: string After: output: string | Array ``` This change allows custom tool calls to return images, files, and rich text content in addition to plain strings, aligning `ResponseCustomToolCallOutput` with the broader `ResponseInput` type system. Because this alters the type and shape of the field, it may break existing callsites that only accept strings. BREAKING CHANGE: `ResponseFunctionToolCallOutputItem.output` and `ResponseCustomToolCallOutput.output` now return `string | Array` instead of `string` only. This may break existing callsites that assume `output` is always a string. --- .stats.yml | 6 ++-- api.md | 7 +++- src/openai/types/__init__.py | 1 + src/openai/types/batch.py | 17 +++++++++ src/openai/types/batch_usage.py | 35 +++++++++++++++++++ src/openai/types/responses/__init__.py | 16 +++++++++ .../response_custom_tool_call_output.py | 21 ++++++++--- .../response_custom_tool_call_output_param.py | 18 +++++++--- ...onse_function_call_arguments_done_event.py | 3 ++ .../response_function_call_output_item.py | 16 +++++++++ ...response_function_call_output_item_list.py | 10 ++++++ ...se_function_call_output_item_list_param.py | 18 ++++++++++ ...esponse_function_call_output_item_param.py | 16 +++++++++ ...response_function_tool_call_output_item.py | 21 ++++++++--- .../responses/response_input_file_content.py | 25 +++++++++++++ .../response_input_file_content_param.py | 25 +++++++++++++ .../responses/response_input_image_content.py | 28 +++++++++++++++ .../response_input_image_content_param.py | 28 +++++++++++++++ .../types/responses/response_input_item.py | 5 +-- .../responses/response_input_item_param.py | 5 +-- .../types/responses/response_input_param.py | 5 +-- .../responses/response_input_text_content.py | 15 ++++++++ .../response_input_text_content_param.py | 15 ++++++++ 23 files changed, 332 insertions(+), 24 deletions(-) create mode 100644 src/openai/types/batch_usage.py create mode 100644 src/openai/types/responses/response_function_call_output_item.py create mode 100644 src/openai/types/responses/response_function_call_output_item_list.py create mode 100644 src/openai/types/responses/response_function_call_output_item_list_param.py create mode 100644 src/openai/types/responses/response_function_call_output_item_param.py create mode 100644 src/openai/types/responses/response_input_file_content.py create mode 100644 src/openai/types/responses/response_input_file_content_param.py create mode 100644 src/openai/types/responses/response_input_image_content.py create mode 100644 src/openai/types/responses/response_input_image_content_param.py create mode 100644 src/openai/types/responses/response_input_text_content.py create mode 100644 src/openai/types/responses/response_input_text_content_param.py diff --git a/.stats.yml b/.stats.yml index 48863a6e93..10c939b22c 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 118 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-410219ea680089f02bb55163c673919703f946c3d6ad7ff5d6f607121d5287d5.yml -openapi_spec_hash: 2b3eee95d3f6796c7a61dfddf694a59a -config_hash: 666d6bb4b564f0d9d431124b5d1a0665 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-49233088b5e73dbb96bf7af27be3d4547632e3db1c2b00f14184900613325bbc.yml +openapi_spec_hash: b34f14b141d5019244112901c5c7c2d8 +config_hash: 94e9ba08201c3d1ca46e093e6a0138fa diff --git a/api.md b/api.md index 6bbb47f78c..1c80bd6e5f 100644 --- a/api.md +++ b/api.md @@ -687,7 +687,7 @@ Methods: Types: ```python -from openai.types import Batch, BatchError, BatchRequestCounts +from openai.types import Batch, BatchError, BatchRequestCounts, BatchUsage ``` Methods: @@ -769,6 +769,8 @@ from openai.types.responses import ( ResponseFormatTextJSONSchemaConfig, ResponseFunctionCallArgumentsDeltaEvent, ResponseFunctionCallArgumentsDoneEvent, + ResponseFunctionCallOutputItem, + ResponseFunctionCallOutputItemList, ResponseFunctionToolCall, ResponseFunctionToolCallItem, ResponseFunctionToolCallOutputItem, @@ -784,11 +786,14 @@ from openai.types.responses import ( ResponseInputAudio, ResponseInputContent, ResponseInputFile, + ResponseInputFileContent, ResponseInputImage, + ResponseInputImageContent, ResponseInputItem, ResponseInputMessageContentList, ResponseInputMessageItem, ResponseInputText, + ResponseInputTextContent, ResponseItem, ResponseMcpCallArgumentsDeltaEvent, ResponseMcpCallArgumentsDoneEvent, diff --git a/src/openai/types/__init__.py b/src/openai/types/__init__.py index 1844f71ba7..87e4520461 100644 --- a/src/openai/types/__init__.py +++ b/src/openai/types/__init__.py @@ -31,6 +31,7 @@ from .moderation import Moderation as Moderation from .audio_model import AudioModel as AudioModel from .batch_error import BatchError as BatchError +from .batch_usage import BatchUsage as BatchUsage from .file_object import FileObject as FileObject from .image_model import ImageModel as ImageModel from .file_content import FileContent as FileContent diff --git a/src/openai/types/batch.py b/src/openai/types/batch.py index 35de90ac85..ece0513b35 100644 --- a/src/openai/types/batch.py +++ b/src/openai/types/batch.py @@ -5,6 +5,7 @@ from .._models import BaseModel from .batch_error import BatchError +from .batch_usage import BatchUsage from .shared.metadata import Metadata from .batch_request_counts import BatchRequestCounts @@ -80,8 +81,24 @@ class Batch(BaseModel): a maximum length of 512 characters. """ + model: Optional[str] = None + """Model ID used to process the batch, like `gpt-5-2025-08-07`. + + OpenAI offers a wide range of models with different capabilities, performance + characteristics, and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + """ + output_file_id: Optional[str] = None """The ID of the file containing the outputs of successfully executed requests.""" request_counts: Optional[BatchRequestCounts] = None """The request counts for different statuses within the batch.""" + + usage: Optional[BatchUsage] = None + """ + Represents token usage details including input tokens, output tokens, a + breakdown of output tokens, and the total tokens used. Only populated on batches + created after September 7, 2025. + """ diff --git a/src/openai/types/batch_usage.py b/src/openai/types/batch_usage.py new file mode 100644 index 0000000000..578f64a5e2 --- /dev/null +++ b/src/openai/types/batch_usage.py @@ -0,0 +1,35 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .._models import BaseModel + +__all__ = ["BatchUsage", "InputTokensDetails", "OutputTokensDetails"] + + +class InputTokensDetails(BaseModel): + cached_tokens: int + """The number of tokens that were retrieved from the cache. + + [More on prompt caching](https://platform.openai.com/docs/guides/prompt-caching). + """ + + +class OutputTokensDetails(BaseModel): + reasoning_tokens: int + """The number of reasoning tokens.""" + + +class BatchUsage(BaseModel): + input_tokens: int + """The number of input tokens.""" + + input_tokens_details: InputTokensDetails + """A detailed breakdown of the input tokens.""" + + output_tokens: int + """The number of output tokens.""" + + output_tokens_details: OutputTokensDetails + """A detailed breakdown of the output tokens.""" + + total_tokens: int + """The total number of tokens used.""" diff --git a/src/openai/types/responses/__init__.py b/src/openai/types/responses/__init__.py index d59f0a74b8..458118741b 100644 --- a/src/openai/types/responses/__init__.py +++ b/src/openai/types/responses/__init__.py @@ -85,10 +85,13 @@ from .response_conversation_param import ResponseConversationParam as ResponseConversationParam from .response_format_text_config import ResponseFormatTextConfig as ResponseFormatTextConfig from .response_function_tool_call import ResponseFunctionToolCall as ResponseFunctionToolCall +from .response_input_file_content import ResponseInputFileContent as ResponseInputFileContent from .response_input_message_item import ResponseInputMessageItem as ResponseInputMessageItem +from .response_input_text_content import ResponseInputTextContent as ResponseInputTextContent from .response_refusal_done_event import ResponseRefusalDoneEvent as ResponseRefusalDoneEvent from .response_function_web_search import ResponseFunctionWebSearch as ResponseFunctionWebSearch from .response_input_content_param import ResponseInputContentParam as ResponseInputContentParam +from .response_input_image_content import ResponseInputImageContent as ResponseInputImageContent from .response_refusal_delta_event import ResponseRefusalDeltaEvent as ResponseRefusalDeltaEvent from .response_output_message_param import ResponseOutputMessageParam as ResponseOutputMessageParam from .response_output_refusal_param import ResponseOutputRefusalParam as ResponseOutputRefusalParam @@ -106,8 +109,12 @@ from .response_content_part_added_event import ResponseContentPartAddedEvent as ResponseContentPartAddedEvent from .response_format_text_config_param import ResponseFormatTextConfigParam as ResponseFormatTextConfigParam from .response_function_tool_call_param import ResponseFunctionToolCallParam as ResponseFunctionToolCallParam +from .response_input_file_content_param import ResponseInputFileContentParam as ResponseInputFileContentParam +from .response_input_text_content_param import ResponseInputTextContentParam as ResponseInputTextContentParam from .response_mcp_call_completed_event import ResponseMcpCallCompletedEvent as ResponseMcpCallCompletedEvent +from .response_function_call_output_item import ResponseFunctionCallOutputItem as ResponseFunctionCallOutputItem from .response_function_web_search_param import ResponseFunctionWebSearchParam as ResponseFunctionWebSearchParam +from .response_input_image_content_param import ResponseInputImageContentParam as ResponseInputImageContentParam from .response_reasoning_text_done_event import ResponseReasoningTextDoneEvent as ResponseReasoningTextDoneEvent from .response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall as ResponseCodeInterpreterToolCall from .response_input_message_content_list import ResponseInputMessageContentList as ResponseInputMessageContentList @@ -131,6 +138,9 @@ from .response_format_text_json_schema_config import ( ResponseFormatTextJSONSchemaConfig as ResponseFormatTextJSONSchemaConfig, ) +from .response_function_call_output_item_list import ( + ResponseFunctionCallOutputItemList as ResponseFunctionCallOutputItemList, +) from .response_function_tool_call_output_item import ( ResponseFunctionToolCallOutputItem as ResponseFunctionToolCallOutputItem, ) @@ -143,6 +153,9 @@ from .response_mcp_list_tools_completed_event import ( ResponseMcpListToolsCompletedEvent as ResponseMcpListToolsCompletedEvent, ) +from .response_function_call_output_item_param import ( + ResponseFunctionCallOutputItemParam as ResponseFunctionCallOutputItemParam, +) from .response_image_gen_call_generating_event import ( ResponseImageGenCallGeneratingEvent as ResponseImageGenCallGeneratingEvent, ) @@ -212,6 +225,9 @@ from .response_format_text_json_schema_config_param import ( ResponseFormatTextJSONSchemaConfigParam as ResponseFormatTextJSONSchemaConfigParam, ) +from .response_function_call_output_item_list_param import ( + ResponseFunctionCallOutputItemListParam as ResponseFunctionCallOutputItemListParam, +) from .response_code_interpreter_call_code_done_event import ( ResponseCodeInterpreterCallCodeDoneEvent as ResponseCodeInterpreterCallCodeDoneEvent, ) diff --git a/src/openai/types/responses/response_custom_tool_call_output.py b/src/openai/types/responses/response_custom_tool_call_output.py index a2b4cc3000..9db9e7e5cf 100644 --- a/src/openai/types/responses/response_custom_tool_call_output.py +++ b/src/openai/types/responses/response_custom_tool_call_output.py @@ -1,19 +1,30 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional -from typing_extensions import Literal +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias +from ..._utils import PropertyInfo from ..._models import BaseModel +from .response_input_file import ResponseInputFile +from .response_input_text import ResponseInputText +from .response_input_image import ResponseInputImage -__all__ = ["ResponseCustomToolCallOutput"] +__all__ = ["ResponseCustomToolCallOutput", "OutputOutputContentList"] + +OutputOutputContentList: TypeAlias = Annotated[ + Union[ResponseInputText, ResponseInputImage, ResponseInputFile], PropertyInfo(discriminator="type") +] class ResponseCustomToolCallOutput(BaseModel): call_id: str """The call ID, used to map this custom tool call output to a custom tool call.""" - output: str - """The output from the custom tool call generated by your code.""" + output: Union[str, List[OutputOutputContentList]] + """ + The output from the custom tool call generated by your code. Can be a string or + an list of output content. + """ type: Literal["custom_tool_call_output"] """The type of the custom tool call output. Always `custom_tool_call_output`.""" diff --git a/src/openai/types/responses/response_custom_tool_call_output_param.py b/src/openai/types/responses/response_custom_tool_call_output_param.py index d52c525467..e967a37cff 100644 --- a/src/openai/types/responses/response_custom_tool_call_output_param.py +++ b/src/openai/types/responses/response_custom_tool_call_output_param.py @@ -2,17 +2,27 @@ from __future__ import annotations -from typing_extensions import Literal, Required, TypedDict +from typing import Union, Iterable +from typing_extensions import Literal, Required, TypeAlias, TypedDict -__all__ = ["ResponseCustomToolCallOutputParam"] +from .response_input_file_param import ResponseInputFileParam +from .response_input_text_param import ResponseInputTextParam +from .response_input_image_param import ResponseInputImageParam + +__all__ = ["ResponseCustomToolCallOutputParam", "OutputOutputContentList"] + +OutputOutputContentList: TypeAlias = Union[ResponseInputTextParam, ResponseInputImageParam, ResponseInputFileParam] class ResponseCustomToolCallOutputParam(TypedDict, total=False): call_id: Required[str] """The call ID, used to map this custom tool call output to a custom tool call.""" - output: Required[str] - """The output from the custom tool call generated by your code.""" + output: Required[Union[str, Iterable[OutputOutputContentList]]] + """ + The output from the custom tool call generated by your code. Can be a string or + an list of output content. + """ type: Required[Literal["custom_tool_call_output"]] """The type of the custom tool call output. Always `custom_tool_call_output`.""" diff --git a/src/openai/types/responses/response_function_call_arguments_done_event.py b/src/openai/types/responses/response_function_call_arguments_done_event.py index 875e7a6875..4ee5ed7fe1 100644 --- a/src/openai/types/responses/response_function_call_arguments_done_event.py +++ b/src/openai/types/responses/response_function_call_arguments_done_event.py @@ -14,6 +14,9 @@ class ResponseFunctionCallArgumentsDoneEvent(BaseModel): item_id: str """The ID of the item.""" + name: str + """The name of the function that was called.""" + output_index: int """The index of the output item.""" diff --git a/src/openai/types/responses/response_function_call_output_item.py b/src/openai/types/responses/response_function_call_output_item.py new file mode 100644 index 0000000000..41898f9eda --- /dev/null +++ b/src/openai/types/responses/response_function_call_output_item.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from typing_extensions import Annotated, TypeAlias + +from ..._utils import PropertyInfo +from .response_input_file_content import ResponseInputFileContent +from .response_input_text_content import ResponseInputTextContent +from .response_input_image_content import ResponseInputImageContent + +__all__ = ["ResponseFunctionCallOutputItem"] + +ResponseFunctionCallOutputItem: TypeAlias = Annotated[ + Union[ResponseInputTextContent, ResponseInputImageContent, ResponseInputFileContent], + PropertyInfo(discriminator="type"), +] diff --git a/src/openai/types/responses/response_function_call_output_item_list.py b/src/openai/types/responses/response_function_call_output_item_list.py new file mode 100644 index 0000000000..13db577160 --- /dev/null +++ b/src/openai/types/responses/response_function_call_output_item_list.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .response_function_call_output_item import ResponseFunctionCallOutputItem + +__all__ = ["ResponseFunctionCallOutputItemList"] + +ResponseFunctionCallOutputItemList: TypeAlias = List[ResponseFunctionCallOutputItem] diff --git a/src/openai/types/responses/response_function_call_output_item_list_param.py b/src/openai/types/responses/response_function_call_output_item_list_param.py new file mode 100644 index 0000000000..8c286d3cf0 --- /dev/null +++ b/src/openai/types/responses/response_function_call_output_item_list_param.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union +from typing_extensions import TypeAlias + +from .response_input_file_content_param import ResponseInputFileContentParam +from .response_input_text_content_param import ResponseInputTextContentParam +from .response_input_image_content_param import ResponseInputImageContentParam + +__all__ = ["ResponseFunctionCallOutputItemListParam", "ResponseFunctionCallOutputItemParam"] + +ResponseFunctionCallOutputItemParam: TypeAlias = Union[ + ResponseInputTextContentParam, ResponseInputImageContentParam, ResponseInputFileContentParam +] + +ResponseFunctionCallOutputItemListParam: TypeAlias = List[ResponseFunctionCallOutputItemParam] diff --git a/src/openai/types/responses/response_function_call_output_item_param.py b/src/openai/types/responses/response_function_call_output_item_param.py new file mode 100644 index 0000000000..2a703cac1e --- /dev/null +++ b/src/openai/types/responses/response_function_call_output_item_param.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import TypeAlias + +from .response_input_file_content_param import ResponseInputFileContentParam +from .response_input_text_content_param import ResponseInputTextContentParam +from .response_input_image_content_param import ResponseInputImageContentParam + +__all__ = ["ResponseFunctionCallOutputItemParam"] + +ResponseFunctionCallOutputItemParam: TypeAlias = Union[ + ResponseInputTextContentParam, ResponseInputImageContentParam, ResponseInputFileContentParam +] diff --git a/src/openai/types/responses/response_function_tool_call_output_item.py b/src/openai/types/responses/response_function_tool_call_output_item.py index 4c8c41a6fe..1a2c848cb3 100644 --- a/src/openai/types/responses/response_function_tool_call_output_item.py +++ b/src/openai/types/responses/response_function_tool_call_output_item.py @@ -1,11 +1,19 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional -from typing_extensions import Literal +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias +from ..._utils import PropertyInfo from ..._models import BaseModel +from .response_input_file import ResponseInputFile +from .response_input_text import ResponseInputText +from .response_input_image import ResponseInputImage -__all__ = ["ResponseFunctionToolCallOutputItem"] +__all__ = ["ResponseFunctionToolCallOutputItem", "OutputOutputContentList"] + +OutputOutputContentList: TypeAlias = Annotated[ + Union[ResponseInputText, ResponseInputImage, ResponseInputFile], PropertyInfo(discriminator="type") +] class ResponseFunctionToolCallOutputItem(BaseModel): @@ -15,8 +23,11 @@ class ResponseFunctionToolCallOutputItem(BaseModel): call_id: str """The unique ID of the function tool call generated by the model.""" - output: str - """A JSON string of the output of the function tool call.""" + output: Union[str, List[OutputOutputContentList]] + """ + The output from the function call generated by your code. Can be a string or an + list of output content. + """ type: Literal["function_call_output"] """The type of the function tool call output. Always `function_call_output`.""" diff --git a/src/openai/types/responses/response_input_file_content.py b/src/openai/types/responses/response_input_file_content.py new file mode 100644 index 0000000000..d832bb0e26 --- /dev/null +++ b/src/openai/types/responses/response_input_file_content.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseInputFileContent"] + + +class ResponseInputFileContent(BaseModel): + type: Literal["input_file"] + """The type of the input item. Always `input_file`.""" + + file_data: Optional[str] = None + """The base64-encoded data of the file to be sent to the model.""" + + file_id: Optional[str] = None + """The ID of the file to be sent to the model.""" + + file_url: Optional[str] = None + """The URL of the file to be sent to the model.""" + + filename: Optional[str] = None + """The name of the file to be sent to the model.""" diff --git a/src/openai/types/responses/response_input_file_content_param.py b/src/openai/types/responses/response_input_file_content_param.py new file mode 100644 index 0000000000..71f7b3a281 --- /dev/null +++ b/src/openai/types/responses/response_input_file_content_param.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ResponseInputFileContentParam"] + + +class ResponseInputFileContentParam(TypedDict, total=False): + type: Required[Literal["input_file"]] + """The type of the input item. Always `input_file`.""" + + file_data: Optional[str] + """The base64-encoded data of the file to be sent to the model.""" + + file_id: Optional[str] + """The ID of the file to be sent to the model.""" + + file_url: Optional[str] + """The URL of the file to be sent to the model.""" + + filename: Optional[str] + """The name of the file to be sent to the model.""" diff --git a/src/openai/types/responses/response_input_image_content.py b/src/openai/types/responses/response_input_image_content.py new file mode 100644 index 0000000000..fb90cb57eb --- /dev/null +++ b/src/openai/types/responses/response_input_image_content.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseInputImageContent"] + + +class ResponseInputImageContent(BaseModel): + type: Literal["input_image"] + """The type of the input item. Always `input_image`.""" + + detail: Optional[Literal["low", "high", "auto"]] = None + """The detail level of the image to be sent to the model. + + One of `high`, `low`, or `auto`. Defaults to `auto`. + """ + + file_id: Optional[str] = None + """The ID of the file to be sent to the model.""" + + image_url: Optional[str] = None + """The URL of the image to be sent to the model. + + A fully qualified URL or base64 encoded image in a data URL. + """ diff --git a/src/openai/types/responses/response_input_image_content_param.py b/src/openai/types/responses/response_input_image_content_param.py new file mode 100644 index 0000000000..c51509a3f3 --- /dev/null +++ b/src/openai/types/responses/response_input_image_content_param.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ResponseInputImageContentParam"] + + +class ResponseInputImageContentParam(TypedDict, total=False): + type: Required[Literal["input_image"]] + """The type of the input item. Always `input_image`.""" + + detail: Optional[Literal["low", "high", "auto"]] + """The detail level of the image to be sent to the model. + + One of `high`, `low`, or `auto`. Defaults to `auto`. + """ + + file_id: Optional[str] + """The ID of the file to be sent to the model.""" + + image_url: Optional[str] + """The URL of the image to be sent to the model. + + A fully qualified URL or base64 encoded image in a data URL. + """ diff --git a/src/openai/types/responses/response_input_item.py b/src/openai/types/responses/response_input_item.py index d2b454fd2c..b8358cbee1 100644 --- a/src/openai/types/responses/response_input_item.py +++ b/src/openai/types/responses/response_input_item.py @@ -16,6 +16,7 @@ from .response_custom_tool_call_output import ResponseCustomToolCallOutput from .response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall from .response_input_message_content_list import ResponseInputMessageContentList +from .response_function_call_output_item_list import ResponseFunctionCallOutputItemList from .response_computer_tool_call_output_screenshot import ResponseComputerToolCallOutputScreenshot __all__ = [ @@ -100,8 +101,8 @@ class FunctionCallOutput(BaseModel): call_id: str """The unique ID of the function tool call generated by the model.""" - output: str - """A JSON string of the output of the function tool call.""" + output: Union[str, ResponseFunctionCallOutputItemList] + """Text, image, or file output of the function tool call.""" type: Literal["function_call_output"] """The type of the function tool call output. Always `function_call_output`.""" diff --git a/src/openai/types/responses/response_input_item_param.py b/src/openai/types/responses/response_input_item_param.py index 5ad83fc03a..13832cc3f2 100644 --- a/src/openai/types/responses/response_input_item_param.py +++ b/src/openai/types/responses/response_input_item_param.py @@ -17,6 +17,7 @@ from .response_custom_tool_call_output_param import ResponseCustomToolCallOutputParam from .response_code_interpreter_tool_call_param import ResponseCodeInterpreterToolCallParam from .response_input_message_content_list_param import ResponseInputMessageContentListParam +from .response_function_call_output_item_list_param import ResponseFunctionCallOutputItemListParam from .response_computer_tool_call_output_screenshot_param import ResponseComputerToolCallOutputScreenshotParam __all__ = [ @@ -101,8 +102,8 @@ class FunctionCallOutput(TypedDict, total=False): call_id: Required[str] """The unique ID of the function tool call generated by the model.""" - output: Required[str] - """A JSON string of the output of the function tool call.""" + output: Required[Union[str, ResponseFunctionCallOutputItemListParam]] + """Text, image, or file output of the function tool call.""" type: Required[Literal["function_call_output"]] """The type of the function tool call output. Always `function_call_output`.""" diff --git a/src/openai/types/responses/response_input_param.py b/src/openai/types/responses/response_input_param.py index 73eac62428..aa1f639e9c 100644 --- a/src/openai/types/responses/response_input_param.py +++ b/src/openai/types/responses/response_input_param.py @@ -17,6 +17,7 @@ from .response_custom_tool_call_output_param import ResponseCustomToolCallOutputParam from .response_code_interpreter_tool_call_param import ResponseCodeInterpreterToolCallParam from .response_input_message_content_list_param import ResponseInputMessageContentListParam +from .response_function_call_output_item_list_param import ResponseFunctionCallOutputItemListParam from .response_computer_tool_call_output_screenshot_param import ResponseComputerToolCallOutputScreenshotParam __all__ = [ @@ -102,8 +103,8 @@ class FunctionCallOutput(TypedDict, total=False): call_id: Required[str] """The unique ID of the function tool call generated by the model.""" - output: Required[str] - """A JSON string of the output of the function tool call.""" + output: Required[Union[str, ResponseFunctionCallOutputItemListParam]] + """Text, image, or file output of the function tool call.""" type: Required[Literal["function_call_output"]] """The type of the function tool call output. Always `function_call_output`.""" diff --git a/src/openai/types/responses/response_input_text_content.py b/src/openai/types/responses/response_input_text_content.py new file mode 100644 index 0000000000..2cce849855 --- /dev/null +++ b/src/openai/types/responses/response_input_text_content.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseInputTextContent"] + + +class ResponseInputTextContent(BaseModel): + text: str + """The text input to the model.""" + + type: Literal["input_text"] + """The type of the input item. Always `input_text`.""" diff --git a/src/openai/types/responses/response_input_text_content_param.py b/src/openai/types/responses/response_input_text_content_param.py new file mode 100644 index 0000000000..85b57df2bd --- /dev/null +++ b/src/openai/types/responses/response_input_text_content_param.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ResponseInputTextContentParam"] + + +class ResponseInputTextContentParam(TypedDict, total=False): + text: Required[str] + """The text input to the model.""" + + type: Required[Literal["input_text"]] + """The type of the input item. Always `input_text`.""" From 70650697e6d2dddc841e0e44515e35829ee3637a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 30 Sep 2025 07:37:22 +0000 Subject: [PATCH 507/769] release: 2.0.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 12 ++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 9e6e24e53d..65f558e71b 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.109.1" + ".": "2.0.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 24aced9a9d..0e71b12205 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## 2.0.0 (2025-09-30) + +Full Changelog: [v1.109.1...v2.0.0](https://github.com/openai/openai-python/compare/v1.109.1...v2.0.0) + +### ⚠ BREAKING CHANGES + +* **api:** `ResponseFunctionToolCallOutputItem.output` and `ResponseCustomToolCallOutput.output` now return `string | Array` instead of `string` only. This may break existing callsites that assume `output` is always a string. + +### Features + +* **api:** Support images and files for function call outputs in responses, BatchUsage ([4105376](https://github.com/openai/openai-python/commit/4105376a60293581371fd5635b805b717d24aa19)) + ## 1.109.1 (2025-09-24) Full Changelog: [v1.109.0...v1.109.1](https://github.com/openai/openai-python/compare/v1.109.0...v1.109.1) diff --git a/pyproject.toml b/pyproject.toml index b89b4e25bd..aadde38c02 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.109.1" +version = "2.0.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 53c9794d8f..d34c028c6a 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.109.1" # x-release-please-version +__version__ = "2.0.0" # x-release-please-version From d1e24895c537ea2d3aa00179dc05f8b512be7e8c Mon Sep 17 00:00:00 2001 From: Alex Gamble Date: Wed, 1 Oct 2025 14:23:44 +0100 Subject: [PATCH 508/769] [realtime] Add gpt-realtime models to beta SDK interface --- src/openai/resources/beta/realtime/sessions.py | 4 ++++ src/openai/types/beta/realtime/session.py | 2 ++ src/openai/types/beta/realtime/session_create_params.py | 2 ++ src/openai/types/beta/realtime/session_update_event.py | 2 ++ src/openai/types/beta/realtime/session_update_event_param.py | 2 ++ 5 files changed, 12 insertions(+) diff --git a/src/openai/resources/beta/realtime/sessions.py b/src/openai/resources/beta/realtime/sessions.py index eaddb384ce..9b85e02d17 100644 --- a/src/openai/resources/beta/realtime/sessions.py +++ b/src/openai/resources/beta/realtime/sessions.py @@ -51,6 +51,8 @@ def create( max_response_output_tokens: Union[int, Literal["inf"]] | NotGiven = NOT_GIVEN, modalities: List[Literal["text", "audio"]] | NotGiven = NOT_GIVEN, model: Literal[ + "gpt-realtime", + "gpt-realtime-2025-08-28", "gpt-4o-realtime-preview", "gpt-4o-realtime-preview-2024-10-01", "gpt-4o-realtime-preview-2024-12-17", @@ -233,6 +235,8 @@ async def create( max_response_output_tokens: Union[int, Literal["inf"]] | NotGiven = NOT_GIVEN, modalities: List[Literal["text", "audio"]] | NotGiven = NOT_GIVEN, model: Literal[ + "gpt-realtime", + "gpt-realtime-2025-08-28", "gpt-4o-realtime-preview", "gpt-4o-realtime-preview-2024-10-01", "gpt-4o-realtime-preview-2024-12-17", diff --git a/src/openai/types/beta/realtime/session.py b/src/openai/types/beta/realtime/session.py index f478a92fbb..2e099a2e98 100644 --- a/src/openai/types/beta/realtime/session.py +++ b/src/openai/types/beta/realtime/session.py @@ -203,6 +203,8 @@ class Session(BaseModel): model: Optional[ Literal[ + "gpt-realtime", + "gpt-realtime-2025-08-28", "gpt-4o-realtime-preview", "gpt-4o-realtime-preview-2024-10-01", "gpt-4o-realtime-preview-2024-12-17", diff --git a/src/openai/types/beta/realtime/session_create_params.py b/src/openai/types/beta/realtime/session_create_params.py index 8a477f9843..38465a56c3 100644 --- a/src/openai/types/beta/realtime/session_create_params.py +++ b/src/openai/types/beta/realtime/session_create_params.py @@ -81,6 +81,8 @@ class SessionCreateParams(TypedDict, total=False): """ model: Literal[ + "gpt-realtime", + "gpt-realtime-2025-08-28", "gpt-4o-realtime-preview", "gpt-4o-realtime-preview-2024-10-01", "gpt-4o-realtime-preview-2024-12-17", diff --git a/src/openai/types/beta/realtime/session_update_event.py b/src/openai/types/beta/realtime/session_update_event.py index 11929ab376..78d2e4bb18 100644 --- a/src/openai/types/beta/realtime/session_update_event.py +++ b/src/openai/types/beta/realtime/session_update_event.py @@ -225,6 +225,8 @@ class Session(BaseModel): model: Optional[ Literal[ + "gpt-realtime", + "gpt-realtime-2025-08-28", "gpt-4o-realtime-preview", "gpt-4o-realtime-preview-2024-10-01", "gpt-4o-realtime-preview-2024-12-17", diff --git a/src/openai/types/beta/realtime/session_update_event_param.py b/src/openai/types/beta/realtime/session_update_event_param.py index e939f4cc79..c58b202a71 100644 --- a/src/openai/types/beta/realtime/session_update_event_param.py +++ b/src/openai/types/beta/realtime/session_update_event_param.py @@ -224,6 +224,8 @@ class Session(TypedDict, total=False): """ model: Literal[ + "gpt-realtime", + "gpt-realtime-2025-08-28", "gpt-4o-realtime-preview", "gpt-4o-realtime-preview-2024-10-01", "gpt-4o-realtime-preview-2024-12-17", From d5e79998b0017e77ca48b470c70ed7679693fd91 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 1 Oct 2025 19:45:25 +0000 Subject: [PATCH 509/769] fix(api): add status, approval_request_id to MCP tool call --- .stats.yml | 6 +++--- src/openai/types/conversations/conversation_item.py | 13 +++++++++++++ src/openai/types/responses/response_input_item.py | 13 +++++++++++++ .../types/responses/response_input_item_param.py | 13 +++++++++++++ src/openai/types/responses/response_input_param.py | 13 +++++++++++++ src/openai/types/responses/response_item.py | 13 +++++++++++++ src/openai/types/responses/response_output_item.py | 13 +++++++++++++ 7 files changed, 81 insertions(+), 3 deletions(-) diff --git a/.stats.yml b/.stats.yml index 10c939b22c..27f2ffc6db 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 118 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-49233088b5e73dbb96bf7af27be3d4547632e3db1c2b00f14184900613325bbc.yml -openapi_spec_hash: b34f14b141d5019244112901c5c7c2d8 -config_hash: 94e9ba08201c3d1ca46e093e6a0138fa +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-e205b1f2da6a1f2caa229efa9ede63f2d3d2fedeeb2dd6ed3d880bafdcb0ab88.yml +openapi_spec_hash: c8aee2469a749f6a838b40c57e4b7b06 +config_hash: 45dcba51451ba532959c020a0ddbf23c diff --git a/src/openai/types/conversations/conversation_item.py b/src/openai/types/conversations/conversation_item.py index a7cd355f36..9e9fb40033 100644 --- a/src/openai/types/conversations/conversation_item.py +++ b/src/openai/types/conversations/conversation_item.py @@ -177,12 +177,25 @@ class McpCall(BaseModel): type: Literal["mcp_call"] """The type of the item. Always `mcp_call`.""" + approval_request_id: Optional[str] = None + """ + Unique identifier for the MCP tool call approval request. Include this value in + a subsequent `mcp_approval_response` input to approve or reject the + corresponding tool call. + """ + error: Optional[str] = None """The error from the tool call, if any.""" output: Optional[str] = None """The output from the tool call.""" + status: Optional[Literal["in_progress", "completed", "incomplete", "calling", "failed"]] = None + """The status of the tool call. + + One of `in_progress`, `completed`, `incomplete`, `calling`, or `failed`. + """ + ConversationItem: TypeAlias = Annotated[ Union[ diff --git a/src/openai/types/responses/response_input_item.py b/src/openai/types/responses/response_input_item.py index b8358cbee1..0a487b8bef 100644 --- a/src/openai/types/responses/response_input_item.py +++ b/src/openai/types/responses/response_input_item.py @@ -267,12 +267,25 @@ class McpCall(BaseModel): type: Literal["mcp_call"] """The type of the item. Always `mcp_call`.""" + approval_request_id: Optional[str] = None + """ + Unique identifier for the MCP tool call approval request. Include this value in + a subsequent `mcp_approval_response` input to approve or reject the + corresponding tool call. + """ + error: Optional[str] = None """The error from the tool call, if any.""" output: Optional[str] = None """The output from the tool call.""" + status: Optional[Literal["in_progress", "completed", "incomplete", "calling", "failed"]] = None + """The status of the tool call. + + One of `in_progress`, `completed`, `incomplete`, `calling`, or `failed`. + """ + class ItemReference(BaseModel): id: str diff --git a/src/openai/types/responses/response_input_item_param.py b/src/openai/types/responses/response_input_item_param.py index 13832cc3f2..115147dc4b 100644 --- a/src/openai/types/responses/response_input_item_param.py +++ b/src/openai/types/responses/response_input_item_param.py @@ -268,12 +268,25 @@ class McpCall(TypedDict, total=False): type: Required[Literal["mcp_call"]] """The type of the item. Always `mcp_call`.""" + approval_request_id: Optional[str] + """ + Unique identifier for the MCP tool call approval request. Include this value in + a subsequent `mcp_approval_response` input to approve or reject the + corresponding tool call. + """ + error: Optional[str] """The error from the tool call, if any.""" output: Optional[str] """The output from the tool call.""" + status: Literal["in_progress", "completed", "incomplete", "calling", "failed"] + """The status of the tool call. + + One of `in_progress`, `completed`, `incomplete`, `calling`, or `failed`. + """ + class ItemReference(TypedDict, total=False): id: Required[str] diff --git a/src/openai/types/responses/response_input_param.py b/src/openai/types/responses/response_input_param.py index aa1f639e9c..9a999c7252 100644 --- a/src/openai/types/responses/response_input_param.py +++ b/src/openai/types/responses/response_input_param.py @@ -269,12 +269,25 @@ class McpCall(TypedDict, total=False): type: Required[Literal["mcp_call"]] """The type of the item. Always `mcp_call`.""" + approval_request_id: Optional[str] + """ + Unique identifier for the MCP tool call approval request. Include this value in + a subsequent `mcp_approval_response` input to approve or reject the + corresponding tool call. + """ + error: Optional[str] """The error from the tool call, if any.""" output: Optional[str] """The output from the tool call.""" + status: Literal["in_progress", "completed", "incomplete", "calling", "failed"] + """The status of the tool call. + + One of `in_progress`, `completed`, `incomplete`, `calling`, or `failed`. + """ + class ItemReference(TypedDict, total=False): id: Required[str] diff --git a/src/openai/types/responses/response_item.py b/src/openai/types/responses/response_item.py index cba89390ed..bdd2523baf 100644 --- a/src/openai/types/responses/response_item.py +++ b/src/openai/types/responses/response_item.py @@ -175,12 +175,25 @@ class McpCall(BaseModel): type: Literal["mcp_call"] """The type of the item. Always `mcp_call`.""" + approval_request_id: Optional[str] = None + """ + Unique identifier for the MCP tool call approval request. Include this value in + a subsequent `mcp_approval_response` input to approve or reject the + corresponding tool call. + """ + error: Optional[str] = None """The error from the tool call, if any.""" output: Optional[str] = None """The output from the tool call.""" + status: Optional[Literal["in_progress", "completed", "incomplete", "calling", "failed"]] = None + """The status of the tool call. + + One of `in_progress`, `completed`, `incomplete`, `calling`, or `failed`. + """ + ResponseItem: TypeAlias = Annotated[ Union[ diff --git a/src/openai/types/responses/response_output_item.py b/src/openai/types/responses/response_output_item.py index 2d3ee7b64e..e33d59cefe 100644 --- a/src/openai/types/responses/response_output_item.py +++ b/src/openai/types/responses/response_output_item.py @@ -93,12 +93,25 @@ class McpCall(BaseModel): type: Literal["mcp_call"] """The type of the item. Always `mcp_call`.""" + approval_request_id: Optional[str] = None + """ + Unique identifier for the MCP tool call approval request. Include this value in + a subsequent `mcp_approval_response` input to approve or reject the + corresponding tool call. + """ + error: Optional[str] = None """The error from the tool call, if any.""" output: Optional[str] = None """The output from the tool call.""" + status: Optional[Literal["in_progress", "completed", "incomplete", "calling", "failed"]] = None + """The status of the tool call. + + One of `in_progress`, `completed`, `incomplete`, `calling`, or `failed`. + """ + class McpListToolsTool(BaseModel): input_schema: object From 75a3aa490a6bf8e91ec98df12590980a680ac77a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 1 Oct 2025 19:45:55 +0000 Subject: [PATCH 510/769] release: 2.0.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 65f558e71b..cf7239890c 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.0.0" + ".": "2.0.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e71b12205..fcb9926c29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 2.0.1 (2025-10-01) + +Full Changelog: [v2.0.0...v2.0.1](https://github.com/openai/openai-python/compare/v2.0.0...v2.0.1) + +### Bug Fixes + +* **api:** add status, approval_request_id to MCP tool call ([2a02255](https://github.com/openai/openai-python/commit/2a022553f83b636defcfda3b1c6f4b12d901357b)) + ## 2.0.0 (2025-09-30) Full Changelog: [v1.109.1...v2.0.0](https://github.com/openai/openai-python/compare/v1.109.1...v2.0.0) diff --git a/pyproject.toml b/pyproject.toml index aadde38c02..a83bca2dcd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.0.0" +version = "2.0.1" 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 d34c028c6a..f20794ac19 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__ = "2.0.0" # x-release-please-version +__version__ = "2.0.1" # x-release-please-version From 86aaa1de28cdc4b186baf440b370684a05e8ae95 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 2 Oct 2025 20:13:26 +0000 Subject: [PATCH 511/769] feat(api): add support for realtime calls --- .stats.yml | 8 +- api.md | 10 + src/openai/lib/_realtime.py | 92 +++ src/openai/resources/realtime/__init__.py | 14 + src/openai/resources/realtime/calls.py | 734 ++++++++++++++++++ src/openai/resources/realtime/realtime.py | 70 +- src/openai/types/realtime/__init__.py | 4 + .../types/realtime/call_accept_params.py | 107 +++ .../types/realtime/call_create_params.py | 17 + .../types/realtime/call_refer_params.py | 15 + .../types/realtime/call_reject_params.py | 15 + .../types/realtime/realtime_connect_params.py | 6 +- tests/api_resources/realtime/test_calls.py | 692 +++++++++++++++++ 13 files changed, 1770 insertions(+), 14 deletions(-) create mode 100644 src/openai/lib/_realtime.py create mode 100644 src/openai/resources/realtime/calls.py create mode 100644 src/openai/types/realtime/call_accept_params.py create mode 100644 src/openai/types/realtime/call_create_params.py create mode 100644 src/openai/types/realtime/call_refer_params.py create mode 100644 src/openai/types/realtime/call_reject_params.py create mode 100644 tests/api_resources/realtime/test_calls.py diff --git a/.stats.yml b/.stats.yml index 27f2ffc6db..d974760a99 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 118 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-e205b1f2da6a1f2caa229efa9ede63f2d3d2fedeeb2dd6ed3d880bafdcb0ab88.yml -openapi_spec_hash: c8aee2469a749f6a838b40c57e4b7b06 -config_hash: 45dcba51451ba532959c020a0ddbf23c +configured_endpoints: 123 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-fadefdc7c7e30df47c09df323669b242ff90ee08e51f304175ace5274e0aab49.yml +openapi_spec_hash: 6d20f639d9ff8a097a34962da6218231 +config_hash: 902654e60f5d659f2bfcfd903e17c46d diff --git a/api.md b/api.md index 1c80bd6e5f..d5331803ce 100644 --- a/api.md +++ b/api.md @@ -989,6 +989,16 @@ Methods: - client.realtime.client_secrets.create(\*\*params) -> ClientSecretCreateResponse +## Calls + +Methods: + +- client.realtime.calls.create(\*\*params) -> HttpxBinaryResponseContent +- client.realtime.calls.accept(call_id, \*\*params) -> None +- client.realtime.calls.hangup(call_id) -> None +- client.realtime.calls.refer(call_id, \*\*params) -> None +- client.realtime.calls.reject(call_id, \*\*params) -> None + # Conversations Types: diff --git a/src/openai/lib/_realtime.py b/src/openai/lib/_realtime.py new file mode 100644 index 0000000000..999d1e4463 --- /dev/null +++ b/src/openai/lib/_realtime.py @@ -0,0 +1,92 @@ +from __future__ import annotations + +import json +from typing_extensions import override + +import httpx + +from openai import _legacy_response +from openai._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from openai._utils import maybe_transform, async_maybe_transform +from openai._base_client import make_request_options +from openai.resources.realtime.calls import Calls, AsyncCalls +from openai.types.realtime.realtime_session_create_request_param import RealtimeSessionCreateRequestParam + +__all__ = ["_Calls", "_AsyncCalls"] + + +# Custom code to override the `create` method to have correct behavior with +# application/sdp and multipart/form-data. +# Ideally we can cutover to the generated code this overrides eventually and remove this. +class _Calls(Calls): + @override + def create( + self, + *, + sdp: str, + session: RealtimeSessionCreateRequestParam | Omit = omit, + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> _legacy_response.HttpxBinaryResponseContent: + if session is omit: + extra_headers = {"Accept": "application/sdp", "Content-Type": "application/sdp", **(extra_headers or {})} + return self._post( + "/realtime/calls", + body=sdp.encode("utf-8"), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, timeout=timeout), + cast_to=_legacy_response.HttpxBinaryResponseContent, + ) + + extra_headers = {"Accept": "application/sdp", "Content-Type": "multipart/form-data", **(extra_headers or {})} + session_payload = maybe_transform(session, RealtimeSessionCreateRequestParam) + files = [ + ("sdp", (None, sdp.encode("utf-8"), "application/sdp")), + ("session", (None, json.dumps(session_payload).encode("utf-8"), "application/json")), + ] + return self._post( + "/realtime/calls", + files=files, + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=_legacy_response.HttpxBinaryResponseContent, + ) + + +class _AsyncCalls(AsyncCalls): + @override + async def create( + self, + *, + sdp: str, + session: RealtimeSessionCreateRequestParam | Omit = omit, + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> _legacy_response.HttpxBinaryResponseContent: + if session is omit: + extra_headers = {"Accept": "application/sdp", "Content-Type": "application/sdp", **(extra_headers or {})} + return await self._post( + "/realtime/calls", + body=sdp.encode("utf-8"), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, timeout=timeout), + cast_to=_legacy_response.HttpxBinaryResponseContent, + ) + + extra_headers = {"Accept": "application/sdp", "Content-Type": "multipart/form-data", **(extra_headers or {})} + session_payload = await async_maybe_transform(session, RealtimeSessionCreateRequestParam) + files = [ + ("sdp", (None, sdp.encode("utf-8"), "application/sdp")), + ("session", (None, json.dumps(session_payload).encode("utf-8"), "application/json")), + ] + return await self._post( + "/realtime/calls", + files=files, + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=_legacy_response.HttpxBinaryResponseContent, + ) diff --git a/src/openai/resources/realtime/__init__.py b/src/openai/resources/realtime/__init__.py index 7a41de8648..c11841017f 100644 --- a/src/openai/resources/realtime/__init__.py +++ b/src/openai/resources/realtime/__init__.py @@ -1,5 +1,13 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from .calls import ( + Calls, + AsyncCalls, + CallsWithRawResponse, + AsyncCallsWithRawResponse, + CallsWithStreamingResponse, + AsyncCallsWithStreamingResponse, +) from .realtime import ( Realtime, AsyncRealtime, @@ -24,6 +32,12 @@ "AsyncClientSecretsWithRawResponse", "ClientSecretsWithStreamingResponse", "AsyncClientSecretsWithStreamingResponse", + "Calls", + "AsyncCalls", + "CallsWithRawResponse", + "AsyncCallsWithRawResponse", + "CallsWithStreamingResponse", + "AsyncCallsWithStreamingResponse", "Realtime", "AsyncRealtime", "RealtimeWithRawResponse", diff --git a/src/openai/resources/realtime/calls.py b/src/openai/resources/realtime/calls.py new file mode 100644 index 0000000000..7dcea6b5cf --- /dev/null +++ b/src/openai/resources/realtime/calls.py @@ -0,0 +1,734 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union, Optional +from typing_extensions import Literal + +import httpx + +from ... import _legacy_response +from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + StreamedBinaryAPIResponse, + AsyncStreamedBinaryAPIResponse, + to_streamed_response_wrapper, + async_to_streamed_response_wrapper, + to_custom_streamed_response_wrapper, + async_to_custom_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.realtime import ( + call_refer_params, + call_accept_params, + call_create_params, + call_reject_params, +) +from ...types.responses.response_prompt_param import ResponsePromptParam +from ...types.realtime.realtime_truncation_param import RealtimeTruncationParam +from ...types.realtime.realtime_audio_config_param import RealtimeAudioConfigParam +from ...types.realtime.realtime_tools_config_param import RealtimeToolsConfigParam +from ...types.realtime.realtime_tracing_config_param import RealtimeTracingConfigParam +from ...types.realtime.realtime_tool_choice_config_param import RealtimeToolChoiceConfigParam +from ...types.realtime.realtime_session_create_request_param import RealtimeSessionCreateRequestParam + +__all__ = ["Calls", "AsyncCalls"] + + +class Calls(SyncAPIResource): + @cached_property + def with_raw_response(self) -> CallsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return CallsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> CallsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return CallsWithStreamingResponse(self) + + def create( + self, + *, + sdp: str, + session: RealtimeSessionCreateRequestParam | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> _legacy_response.HttpxBinaryResponseContent: + """ + Create a new Realtime API call over WebRTC and receive the SDP answer needed to + complete the peer connection. + + Args: + sdp: WebRTC Session Description Protocol (SDP) offer generated by the caller. + + session: Realtime session object configuration. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "application/sdp", **(extra_headers or {})} + return self._post( + "/realtime/calls", + body=maybe_transform( + { + "sdp": sdp, + "session": session, + }, + call_create_params.CallCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=_legacy_response.HttpxBinaryResponseContent, + ) + + def accept( + self, + call_id: str, + *, + type: Literal["realtime"], + audio: RealtimeAudioConfigParam | Omit = omit, + include: List[Literal["item.input_audio_transcription.logprobs"]] | Omit = omit, + instructions: str | Omit = omit, + max_output_tokens: Union[int, Literal["inf"]] | Omit = omit, + model: Union[ + str, + Literal[ + "gpt-realtime", + "gpt-realtime-2025-08-28", + "gpt-4o-realtime-preview", + "gpt-4o-realtime-preview-2024-10-01", + "gpt-4o-realtime-preview-2024-12-17", + "gpt-4o-realtime-preview-2025-06-03", + "gpt-4o-mini-realtime-preview", + "gpt-4o-mini-realtime-preview-2024-12-17", + ], + ] + | Omit = omit, + output_modalities: List[Literal["text", "audio"]] | Omit = omit, + prompt: Optional[ResponsePromptParam] | Omit = omit, + tool_choice: RealtimeToolChoiceConfigParam | Omit = omit, + tools: RealtimeToolsConfigParam | Omit = omit, + tracing: Optional[RealtimeTracingConfigParam] | Omit = omit, + truncation: RealtimeTruncationParam | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Accept an incoming SIP call and configure the realtime session that will handle + it. + + Args: + type: The type of session to create. Always `realtime` for the Realtime API. + + audio: Configuration for input and output audio. + + include: Additional fields to include in server outputs. + + `item.input_audio_transcription.logprobs`: Include logprobs for input audio + transcription. + + instructions: The default system instructions (i.e. system message) prepended to model calls. + This field allows the client to guide the model on desired responses. The model + can be instructed on response content and format, (e.g. "be extremely succinct", + "act friendly", "here are examples of good responses") and on audio behavior + (e.g. "talk quickly", "inject emotion into your voice", "laugh frequently"). The + instructions are not guaranteed to be followed by the model, but they provide + guidance to the model on the desired behavior. + + Note that the server sets default instructions which will be used if this field + is not set and are visible in the `session.created` event at the start of the + session. + + max_output_tokens: Maximum number of output tokens for a single assistant response, inclusive of + tool calls. Provide an integer between 1 and 4096 to limit output tokens, or + `inf` for the maximum available tokens for a given model. Defaults to `inf`. + + model: The Realtime model used for this session. + + output_modalities: The set of modalities the model can respond with. It defaults to `["audio"]`, + indicating that the model will respond with audio plus a transcript. `["text"]` + can be used to make the model respond with text only. It is not possible to + request both `text` and `audio` at the same time. + + prompt: Reference to a prompt template and its variables. + [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). + + tool_choice: How the model chooses tools. Provide one of the string modes or force a specific + function/MCP tool. + + tools: Tools available to the model. + + tracing: Realtime API can write session traces to the + [Traces Dashboard](/logs?api=traces). Set to null to disable tracing. Once + tracing is enabled for a session, the configuration cannot be modified. + + `auto` will create a trace for the session with default values for the workflow + name, group id, and metadata. + + truncation: Controls how the realtime conversation is truncated prior to model inference. + The default is `auto`. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not call_id: + raise ValueError(f"Expected a non-empty value for `call_id` but received {call_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + f"/realtime/calls/{call_id}/accept", + body=maybe_transform( + { + "type": type, + "audio": audio, + "include": include, + "instructions": instructions, + "max_output_tokens": max_output_tokens, + "model": model, + "output_modalities": output_modalities, + "prompt": prompt, + "tool_choice": tool_choice, + "tools": tools, + "tracing": tracing, + "truncation": truncation, + }, + call_accept_params.CallAcceptParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def hangup( + self, + call_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + End an active Realtime API call, whether it was initiated over SIP or WebRTC. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not call_id: + raise ValueError(f"Expected a non-empty value for `call_id` but received {call_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + f"/realtime/calls/{call_id}/hangup", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def refer( + self, + call_id: str, + *, + target_uri: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Transfer an active SIP call to a new destination using the SIP REFER verb. + + Args: + target_uri: URI that should appear in the SIP Refer-To header. Supports values like + `tel:+14155550123` or `sip:agent@example.com`. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not call_id: + raise ValueError(f"Expected a non-empty value for `call_id` but received {call_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + f"/realtime/calls/{call_id}/refer", + body=maybe_transform({"target_uri": target_uri}, call_refer_params.CallReferParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def reject( + self, + call_id: str, + *, + status_code: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Decline an incoming SIP call by returning a SIP status code to the caller. + + Args: + status_code: SIP response code to send back to the caller. Defaults to `603` (Decline) when + omitted. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not call_id: + raise ValueError(f"Expected a non-empty value for `call_id` but received {call_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + f"/realtime/calls/{call_id}/reject", + body=maybe_transform({"status_code": status_code}, call_reject_params.CallRejectParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncCalls(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncCallsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncCallsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncCallsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncCallsWithStreamingResponse(self) + + async def create( + self, + *, + sdp: str, + session: RealtimeSessionCreateRequestParam | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> _legacy_response.HttpxBinaryResponseContent: + """ + Create a new Realtime API call over WebRTC and receive the SDP answer needed to + complete the peer connection. + + Args: + sdp: WebRTC Session Description Protocol (SDP) offer generated by the caller. + + session: Realtime session object configuration. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "application/sdp", **(extra_headers or {})} + return await self._post( + "/realtime/calls", + body=await async_maybe_transform( + { + "sdp": sdp, + "session": session, + }, + call_create_params.CallCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=_legacy_response.HttpxBinaryResponseContent, + ) + + async def accept( + self, + call_id: str, + *, + type: Literal["realtime"], + audio: RealtimeAudioConfigParam | Omit = omit, + include: List[Literal["item.input_audio_transcription.logprobs"]] | Omit = omit, + instructions: str | Omit = omit, + max_output_tokens: Union[int, Literal["inf"]] | Omit = omit, + model: Union[ + str, + Literal[ + "gpt-realtime", + "gpt-realtime-2025-08-28", + "gpt-4o-realtime-preview", + "gpt-4o-realtime-preview-2024-10-01", + "gpt-4o-realtime-preview-2024-12-17", + "gpt-4o-realtime-preview-2025-06-03", + "gpt-4o-mini-realtime-preview", + "gpt-4o-mini-realtime-preview-2024-12-17", + ], + ] + | Omit = omit, + output_modalities: List[Literal["text", "audio"]] | Omit = omit, + prompt: Optional[ResponsePromptParam] | Omit = omit, + tool_choice: RealtimeToolChoiceConfigParam | Omit = omit, + tools: RealtimeToolsConfigParam | Omit = omit, + tracing: Optional[RealtimeTracingConfigParam] | Omit = omit, + truncation: RealtimeTruncationParam | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Accept an incoming SIP call and configure the realtime session that will handle + it. + + Args: + type: The type of session to create. Always `realtime` for the Realtime API. + + audio: Configuration for input and output audio. + + include: Additional fields to include in server outputs. + + `item.input_audio_transcription.logprobs`: Include logprobs for input audio + transcription. + + instructions: The default system instructions (i.e. system message) prepended to model calls. + This field allows the client to guide the model on desired responses. The model + can be instructed on response content and format, (e.g. "be extremely succinct", + "act friendly", "here are examples of good responses") and on audio behavior + (e.g. "talk quickly", "inject emotion into your voice", "laugh frequently"). The + instructions are not guaranteed to be followed by the model, but they provide + guidance to the model on the desired behavior. + + Note that the server sets default instructions which will be used if this field + is not set and are visible in the `session.created` event at the start of the + session. + + max_output_tokens: Maximum number of output tokens for a single assistant response, inclusive of + tool calls. Provide an integer between 1 and 4096 to limit output tokens, or + `inf` for the maximum available tokens for a given model. Defaults to `inf`. + + model: The Realtime model used for this session. + + output_modalities: The set of modalities the model can respond with. It defaults to `["audio"]`, + indicating that the model will respond with audio plus a transcript. `["text"]` + can be used to make the model respond with text only. It is not possible to + request both `text` and `audio` at the same time. + + prompt: Reference to a prompt template and its variables. + [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). + + tool_choice: How the model chooses tools. Provide one of the string modes or force a specific + function/MCP tool. + + tools: Tools available to the model. + + tracing: Realtime API can write session traces to the + [Traces Dashboard](/logs?api=traces). Set to null to disable tracing. Once + tracing is enabled for a session, the configuration cannot be modified. + + `auto` will create a trace for the session with default values for the workflow + name, group id, and metadata. + + truncation: Controls how the realtime conversation is truncated prior to model inference. + The default is `auto`. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not call_id: + raise ValueError(f"Expected a non-empty value for `call_id` but received {call_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + f"/realtime/calls/{call_id}/accept", + body=await async_maybe_transform( + { + "type": type, + "audio": audio, + "include": include, + "instructions": instructions, + "max_output_tokens": max_output_tokens, + "model": model, + "output_modalities": output_modalities, + "prompt": prompt, + "tool_choice": tool_choice, + "tools": tools, + "tracing": tracing, + "truncation": truncation, + }, + call_accept_params.CallAcceptParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def hangup( + self, + call_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + End an active Realtime API call, whether it was initiated over SIP or WebRTC. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not call_id: + raise ValueError(f"Expected a non-empty value for `call_id` but received {call_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + f"/realtime/calls/{call_id}/hangup", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def refer( + self, + call_id: str, + *, + target_uri: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Transfer an active SIP call to a new destination using the SIP REFER verb. + + Args: + target_uri: URI that should appear in the SIP Refer-To header. Supports values like + `tel:+14155550123` or `sip:agent@example.com`. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not call_id: + raise ValueError(f"Expected a non-empty value for `call_id` but received {call_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + f"/realtime/calls/{call_id}/refer", + body=await async_maybe_transform({"target_uri": target_uri}, call_refer_params.CallReferParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def reject( + self, + call_id: str, + *, + status_code: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Decline an incoming SIP call by returning a SIP status code to the caller. + + Args: + status_code: SIP response code to send back to the caller. Defaults to `603` (Decline) when + omitted. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not call_id: + raise ValueError(f"Expected a non-empty value for `call_id` but received {call_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + f"/realtime/calls/{call_id}/reject", + body=await async_maybe_transform({"status_code": status_code}, call_reject_params.CallRejectParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class CallsWithRawResponse: + def __init__(self, calls: Calls) -> None: + self._calls = calls + + self.create = _legacy_response.to_raw_response_wrapper( + calls.create, + ) + self.accept = _legacy_response.to_raw_response_wrapper( + calls.accept, + ) + self.hangup = _legacy_response.to_raw_response_wrapper( + calls.hangup, + ) + self.refer = _legacy_response.to_raw_response_wrapper( + calls.refer, + ) + self.reject = _legacy_response.to_raw_response_wrapper( + calls.reject, + ) + + +class AsyncCallsWithRawResponse: + def __init__(self, calls: AsyncCalls) -> None: + self._calls = calls + + self.create = _legacy_response.async_to_raw_response_wrapper( + calls.create, + ) + self.accept = _legacy_response.async_to_raw_response_wrapper( + calls.accept, + ) + self.hangup = _legacy_response.async_to_raw_response_wrapper( + calls.hangup, + ) + self.refer = _legacy_response.async_to_raw_response_wrapper( + calls.refer, + ) + self.reject = _legacy_response.async_to_raw_response_wrapper( + calls.reject, + ) + + +class CallsWithStreamingResponse: + def __init__(self, calls: Calls) -> None: + self._calls = calls + + self.create = to_custom_streamed_response_wrapper( + calls.create, + StreamedBinaryAPIResponse, + ) + self.accept = to_streamed_response_wrapper( + calls.accept, + ) + self.hangup = to_streamed_response_wrapper( + calls.hangup, + ) + self.refer = to_streamed_response_wrapper( + calls.refer, + ) + self.reject = to_streamed_response_wrapper( + calls.reject, + ) + + +class AsyncCallsWithStreamingResponse: + def __init__(self, calls: AsyncCalls) -> None: + self._calls = calls + + self.create = async_to_custom_streamed_response_wrapper( + calls.create, + AsyncStreamedBinaryAPIResponse, + ) + self.accept = async_to_streamed_response_wrapper( + calls.accept, + ) + self.hangup = async_to_streamed_response_wrapper( + calls.hangup, + ) + self.refer = async_to_streamed_response_wrapper( + calls.refer, + ) + self.reject = async_to_streamed_response_wrapper( + calls.reject, + ) diff --git a/src/openai/resources/realtime/realtime.py b/src/openai/resources/realtime/realtime.py index 9d61fa25e0..7b4486d502 100644 --- a/src/openai/resources/realtime/realtime.py +++ b/src/openai/resources/realtime/realtime.py @@ -11,6 +11,14 @@ import httpx from pydantic import BaseModel +from .calls import ( + Calls, + AsyncCalls, + CallsWithRawResponse, + AsyncCallsWithRawResponse, + CallsWithStreamingResponse, + AsyncCallsWithStreamingResponse, +) from ..._types import Omit, Query, Headers, omit from ..._utils import ( is_azure_client, @@ -56,6 +64,11 @@ class Realtime(SyncAPIResource): def client_secrets(self) -> ClientSecrets: return ClientSecrets(self._client) + @cached_property + def calls(self) -> Calls: + from ...lib._realtime import _Calls + return _Calls(self._client) + @cached_property def with_raw_response(self) -> RealtimeWithRawResponse: """ @@ -78,7 +91,8 @@ def with_streaming_response(self) -> RealtimeWithStreamingResponse: def connect( self, *, - model: str, + call_id: str | Omit = omit, + model: str | Omit = omit, extra_query: Query = {}, extra_headers: Headers = {}, websocket_connection_options: WebsocketConnectionOptions = {}, @@ -99,6 +113,7 @@ def connect( extra_query=extra_query, extra_headers=extra_headers, websocket_connection_options=websocket_connection_options, + call_id=call_id, model=model, ) @@ -108,6 +123,11 @@ class AsyncRealtime(AsyncAPIResource): def client_secrets(self) -> AsyncClientSecrets: return AsyncClientSecrets(self._client) + @cached_property + def calls(self) -> AsyncCalls: + from ...lib._realtime import _AsyncCalls + return _AsyncCalls(self._client) + @cached_property def with_raw_response(self) -> AsyncRealtimeWithRawResponse: """ @@ -130,7 +150,8 @@ def with_streaming_response(self) -> AsyncRealtimeWithStreamingResponse: def connect( self, *, - model: str, + call_id: str | Omit = omit, + model: str | Omit = omit, extra_query: Query = {}, extra_headers: Headers = {}, websocket_connection_options: WebsocketConnectionOptions = {}, @@ -151,6 +172,7 @@ def connect( extra_query=extra_query, extra_headers=extra_headers, websocket_connection_options=websocket_connection_options, + call_id=call_id, model=model, ) @@ -163,6 +185,10 @@ def __init__(self, realtime: Realtime) -> None: def client_secrets(self) -> ClientSecretsWithRawResponse: return ClientSecretsWithRawResponse(self._realtime.client_secrets) + @cached_property + def calls(self) -> CallsWithRawResponse: + return CallsWithRawResponse(self._realtime.calls) + class AsyncRealtimeWithRawResponse: def __init__(self, realtime: AsyncRealtime) -> None: @@ -172,6 +198,10 @@ def __init__(self, realtime: AsyncRealtime) -> None: def client_secrets(self) -> AsyncClientSecretsWithRawResponse: return AsyncClientSecretsWithRawResponse(self._realtime.client_secrets) + @cached_property + def calls(self) -> AsyncCallsWithRawResponse: + return AsyncCallsWithRawResponse(self._realtime.calls) + class RealtimeWithStreamingResponse: def __init__(self, realtime: Realtime) -> None: @@ -181,6 +211,10 @@ def __init__(self, realtime: Realtime) -> None: def client_secrets(self) -> ClientSecretsWithStreamingResponse: return ClientSecretsWithStreamingResponse(self._realtime.client_secrets) + @cached_property + def calls(self) -> CallsWithStreamingResponse: + return CallsWithStreamingResponse(self._realtime.calls) + class AsyncRealtimeWithStreamingResponse: def __init__(self, realtime: AsyncRealtime) -> None: @@ -190,6 +224,10 @@ def __init__(self, realtime: AsyncRealtime) -> None: def client_secrets(self) -> AsyncClientSecretsWithStreamingResponse: return AsyncClientSecretsWithStreamingResponse(self._realtime.client_secrets) + @cached_property + def calls(self) -> AsyncCallsWithStreamingResponse: + return AsyncCallsWithStreamingResponse(self._realtime.calls) + class AsyncRealtimeConnection: """Represents a live websocket connection to the Realtime API""" @@ -290,12 +328,14 @@ def __init__( self, *, client: AsyncOpenAI, - model: str, + call_id: str | Omit = omit, + model: str | Omit = omit, extra_query: Query, extra_headers: Headers, websocket_connection_options: WebsocketConnectionOptions, ) -> None: self.__client = client + self.__call_id = call_id self.__model = model self.__connection: AsyncRealtimeConnection | None = None self.__extra_query = extra_query @@ -323,13 +363,19 @@ async def __aenter__(self) -> AsyncRealtimeConnection: extra_query = self.__extra_query await self.__client._refresh_api_key() auth_headers = self.__client.auth_headers + if self.__call_id is not omit: + extra_query = {**extra_query, "call_id": self.__call_id} if is_async_azure_client(self.__client): - url, auth_headers = await self.__client._configure_realtime(self.__model, extra_query) + model = self.__model + if not model: + raise OpenAIError("`model` is required for Azure Realtime API") + else: + url, auth_headers = await self.__client._configure_realtime(model, extra_query) else: url = self._prepare_url().copy_with( params={ **self.__client.base_url.params, - "model": self.__model, + **({"model": self.__model} if self.__model is not omit else {}), **extra_query, }, ) @@ -470,12 +516,14 @@ def __init__( self, *, client: OpenAI, - model: str, + call_id: str | Omit = omit, + model: str | Omit = omit, extra_query: Query, extra_headers: Headers, websocket_connection_options: WebsocketConnectionOptions, ) -> None: self.__client = client + self.__call_id = call_id self.__model = model self.__connection: RealtimeConnection | None = None self.__extra_query = extra_query @@ -503,13 +551,19 @@ def __enter__(self) -> RealtimeConnection: extra_query = self.__extra_query self.__client._refresh_api_key() auth_headers = self.__client.auth_headers + if self.__call_id is not omit: + extra_query = {**extra_query, "call_id": self.__call_id} if is_azure_client(self.__client): - url, auth_headers = self.__client._configure_realtime(self.__model, extra_query) + model = self.__model + if not model: + raise OpenAIError("`model` is required for Azure Realtime API") + else: + url, auth_headers = self.__client._configure_realtime(model, extra_query) else: url = self._prepare_url().copy_with( params={ **self.__client.base_url.params, - "model": self.__model, + **({"model": self.__model} if self.__model is not omit else {}), **extra_query, }, ) diff --git a/src/openai/types/realtime/__init__.py b/src/openai/types/realtime/__init__.py index 2d947c8a2f..83e81a034a 100644 --- a/src/openai/types/realtime/__init__.py +++ b/src/openai/types/realtime/__init__.py @@ -3,8 +3,12 @@ from __future__ import annotations from .realtime_error import RealtimeError as RealtimeError +from .call_refer_params import CallReferParams as CallReferParams from .conversation_item import ConversationItem as ConversationItem from .realtime_response import RealtimeResponse as RealtimeResponse +from .call_accept_params import CallAcceptParams as CallAcceptParams +from .call_create_params import CallCreateParams as CallCreateParams +from .call_reject_params import CallRejectParams as CallRejectParams from .audio_transcription import AudioTranscription as AudioTranscription from .log_prob_properties import LogProbProperties as LogProbProperties from .realtime_truncation import RealtimeTruncation as RealtimeTruncation diff --git a/src/openai/types/realtime/call_accept_params.py b/src/openai/types/realtime/call_accept_params.py new file mode 100644 index 0000000000..1780572e89 --- /dev/null +++ b/src/openai/types/realtime/call_accept_params.py @@ -0,0 +1,107 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union, Optional +from typing_extensions import Literal, Required, TypedDict + +from .realtime_truncation_param import RealtimeTruncationParam +from .realtime_audio_config_param import RealtimeAudioConfigParam +from .realtime_tools_config_param import RealtimeToolsConfigParam +from .realtime_tracing_config_param import RealtimeTracingConfigParam +from ..responses.response_prompt_param import ResponsePromptParam +from .realtime_tool_choice_config_param import RealtimeToolChoiceConfigParam + +__all__ = ["CallAcceptParams"] + + +class CallAcceptParams(TypedDict, total=False): + type: Required[Literal["realtime"]] + """The type of session to create. Always `realtime` for the Realtime API.""" + + audio: RealtimeAudioConfigParam + """Configuration for input and output audio.""" + + include: List[Literal["item.input_audio_transcription.logprobs"]] + """Additional fields to include in server outputs. + + `item.input_audio_transcription.logprobs`: Include logprobs for input audio + transcription. + """ + + instructions: str + """The default system instructions (i.e. + + system message) prepended to model calls. This field allows the client to guide + the model on desired responses. The model can be instructed on response content + and format, (e.g. "be extremely succinct", "act friendly", "here are examples of + good responses") and on audio behavior (e.g. "talk quickly", "inject emotion + into your voice", "laugh frequently"). The instructions are not guaranteed to be + followed by the model, but they provide guidance to the model on the desired + behavior. + + Note that the server sets default instructions which will be used if this field + is not set and are visible in the `session.created` event at the start of the + session. + """ + + max_output_tokens: Union[int, Literal["inf"]] + """ + Maximum number of output tokens for a single assistant response, inclusive of + tool calls. Provide an integer between 1 and 4096 to limit output tokens, or + `inf` for the maximum available tokens for a given model. Defaults to `inf`. + """ + + model: Union[ + str, + Literal[ + "gpt-realtime", + "gpt-realtime-2025-08-28", + "gpt-4o-realtime-preview", + "gpt-4o-realtime-preview-2024-10-01", + "gpt-4o-realtime-preview-2024-12-17", + "gpt-4o-realtime-preview-2025-06-03", + "gpt-4o-mini-realtime-preview", + "gpt-4o-mini-realtime-preview-2024-12-17", + ], + ] + """The Realtime model used for this session.""" + + output_modalities: List[Literal["text", "audio"]] + """The set of modalities the model can respond with. + + It defaults to `["audio"]`, indicating that the model will respond with audio + plus a transcript. `["text"]` can be used to make the model respond with text + only. It is not possible to request both `text` and `audio` at the same time. + """ + + prompt: Optional[ResponsePromptParam] + """ + Reference to a prompt template and its variables. + [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). + """ + + tool_choice: RealtimeToolChoiceConfigParam + """How the model chooses tools. + + Provide one of the string modes or force a specific function/MCP tool. + """ + + tools: RealtimeToolsConfigParam + """Tools available to the model.""" + + tracing: Optional[RealtimeTracingConfigParam] + """ + Realtime API can write session traces to the + [Traces Dashboard](/logs?api=traces). Set to null to disable tracing. Once + tracing is enabled for a session, the configuration cannot be modified. + + `auto` will create a trace for the session with default values for the workflow + name, group id, and metadata. + """ + + truncation: RealtimeTruncationParam + """ + Controls how the realtime conversation is truncated prior to model inference. + The default is `auto`. + """ diff --git a/src/openai/types/realtime/call_create_params.py b/src/openai/types/realtime/call_create_params.py new file mode 100644 index 0000000000..a378092a66 --- /dev/null +++ b/src/openai/types/realtime/call_create_params.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +from .realtime_session_create_request_param import RealtimeSessionCreateRequestParam + +__all__ = ["CallCreateParams"] + + +class CallCreateParams(TypedDict, total=False): + sdp: Required[str] + """WebRTC Session Description Protocol (SDP) offer generated by the caller.""" + + session: RealtimeSessionCreateRequestParam + """Realtime session object configuration.""" diff --git a/src/openai/types/realtime/call_refer_params.py b/src/openai/types/realtime/call_refer_params.py new file mode 100644 index 0000000000..3d8623855b --- /dev/null +++ b/src/openai/types/realtime/call_refer_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["CallReferParams"] + + +class CallReferParams(TypedDict, total=False): + target_uri: Required[str] + """URI that should appear in the SIP Refer-To header. + + Supports values like `tel:+14155550123` or `sip:agent@example.com`. + """ diff --git a/src/openai/types/realtime/call_reject_params.py b/src/openai/types/realtime/call_reject_params.py new file mode 100644 index 0000000000..f12222cded --- /dev/null +++ b/src/openai/types/realtime/call_reject_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["CallRejectParams"] + + +class CallRejectParams(TypedDict, total=False): + status_code: int + """SIP response code to send back to the caller. + + Defaults to `603` (Decline) when omitted. + """ diff --git a/src/openai/types/realtime/realtime_connect_params.py b/src/openai/types/realtime/realtime_connect_params.py index 76474f3de4..950f36212f 100644 --- a/src/openai/types/realtime/realtime_connect_params.py +++ b/src/openai/types/realtime/realtime_connect_params.py @@ -2,10 +2,12 @@ from __future__ import annotations -from typing_extensions import Required, TypedDict +from typing_extensions import TypedDict __all__ = ["RealtimeConnectParams"] class RealtimeConnectParams(TypedDict, total=False): - model: Required[str] + call_id: str + + model: str diff --git a/tests/api_resources/realtime/test_calls.py b/tests/api_resources/realtime/test_calls.py new file mode 100644 index 0000000000..5495a58a4e --- /dev/null +++ b/tests/api_resources/realtime/test_calls.py @@ -0,0 +1,692 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import httpx +import pytest +from respx import MockRouter + +import openai._legacy_response as _legacy_response +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type + +# pyright: reportDeprecated=false + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestCalls: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_method_create(self, client: OpenAI, respx_mock: MockRouter) -> None: + respx_mock.post("/realtime/calls").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + call = client.realtime.calls.create( + sdp="sdp", + ) + assert isinstance(call, _legacy_response.HttpxBinaryResponseContent) + assert call.json() == {"foo": "bar"} + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_method_create_with_all_params(self, client: OpenAI, respx_mock: MockRouter) -> None: + respx_mock.post("/realtime/calls").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + call = client.realtime.calls.create( + sdp="sdp", + session={ + "type": "realtime", + "audio": { + "input": { + "format": { + "rate": 24000, + "type": "audio/pcm", + }, + "noise_reduction": {"type": "near_field"}, + "transcription": { + "language": "language", + "model": "whisper-1", + "prompt": "prompt", + }, + "turn_detection": { + "type": "server_vad", + "create_response": True, + "idle_timeout_ms": 5000, + "interrupt_response": True, + "prefix_padding_ms": 0, + "silence_duration_ms": 0, + "threshold": 0, + }, + }, + "output": { + "format": { + "rate": 24000, + "type": "audio/pcm", + }, + "speed": 0.25, + "voice": "ash", + }, + }, + "include": ["item.input_audio_transcription.logprobs"], + "instructions": "instructions", + "max_output_tokens": 0, + "model": "string", + "output_modalities": ["text"], + "prompt": { + "id": "id", + "variables": {"foo": "string"}, + "version": "version", + }, + "tool_choice": "none", + "tools": [ + { + "description": "description", + "name": "name", + "parameters": {}, + "type": "function", + } + ], + "tracing": "auto", + "truncation": "auto", + }, + ) + assert isinstance(call, _legacy_response.HttpxBinaryResponseContent) + assert call.json() == {"foo": "bar"} + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_raw_response_create(self, client: OpenAI, respx_mock: MockRouter) -> None: + respx_mock.post("/realtime/calls").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + + response = client.realtime.calls.with_raw_response.create( + sdp="sdp", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + call = response.parse() + assert_matches_type(_legacy_response.HttpxBinaryResponseContent, call, path=["response"]) + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_streaming_response_create(self, client: OpenAI, respx_mock: MockRouter) -> None: + respx_mock.post("/realtime/calls").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + with client.realtime.calls.with_streaming_response.create( + sdp="sdp", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + call = response.parse() + assert_matches_type(bytes, call, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_accept(self, client: OpenAI) -> None: + call = client.realtime.calls.accept( + call_id="call_id", + type="realtime", + ) + assert call is None + + @parametrize + def test_method_accept_with_all_params(self, client: OpenAI) -> None: + call = client.realtime.calls.accept( + call_id="call_id", + type="realtime", + audio={ + "input": { + "format": { + "rate": 24000, + "type": "audio/pcm", + }, + "noise_reduction": {"type": "near_field"}, + "transcription": { + "language": "language", + "model": "whisper-1", + "prompt": "prompt", + }, + "turn_detection": { + "type": "server_vad", + "create_response": True, + "idle_timeout_ms": 5000, + "interrupt_response": True, + "prefix_padding_ms": 0, + "silence_duration_ms": 0, + "threshold": 0, + }, + }, + "output": { + "format": { + "rate": 24000, + "type": "audio/pcm", + }, + "speed": 0.25, + "voice": "ash", + }, + }, + include=["item.input_audio_transcription.logprobs"], + instructions="instructions", + max_output_tokens=0, + model="string", + output_modalities=["text"], + prompt={ + "id": "id", + "variables": {"foo": "string"}, + "version": "version", + }, + tool_choice="none", + tools=[ + { + "description": "description", + "name": "name", + "parameters": {}, + "type": "function", + } + ], + tracing="auto", + truncation="auto", + ) + assert call is None + + @parametrize + def test_raw_response_accept(self, client: OpenAI) -> None: + response = client.realtime.calls.with_raw_response.accept( + call_id="call_id", + type="realtime", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + call = response.parse() + assert call is None + + @parametrize + def test_streaming_response_accept(self, client: OpenAI) -> None: + with client.realtime.calls.with_streaming_response.accept( + call_id="call_id", + type="realtime", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + call = response.parse() + assert call is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_accept(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `call_id` but received ''"): + client.realtime.calls.with_raw_response.accept( + call_id="", + type="realtime", + ) + + @parametrize + def test_method_hangup(self, client: OpenAI) -> None: + call = client.realtime.calls.hangup( + "call_id", + ) + assert call is None + + @parametrize + def test_raw_response_hangup(self, client: OpenAI) -> None: + response = client.realtime.calls.with_raw_response.hangup( + "call_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + call = response.parse() + assert call is None + + @parametrize + def test_streaming_response_hangup(self, client: OpenAI) -> None: + with client.realtime.calls.with_streaming_response.hangup( + "call_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + call = response.parse() + assert call is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_hangup(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `call_id` but received ''"): + client.realtime.calls.with_raw_response.hangup( + "", + ) + + @parametrize + def test_method_refer(self, client: OpenAI) -> None: + call = client.realtime.calls.refer( + call_id="call_id", + target_uri="tel:+14155550123", + ) + assert call is None + + @parametrize + def test_raw_response_refer(self, client: OpenAI) -> None: + response = client.realtime.calls.with_raw_response.refer( + call_id="call_id", + target_uri="tel:+14155550123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + call = response.parse() + assert call is None + + @parametrize + def test_streaming_response_refer(self, client: OpenAI) -> None: + with client.realtime.calls.with_streaming_response.refer( + call_id="call_id", + target_uri="tel:+14155550123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + call = response.parse() + assert call is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_refer(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `call_id` but received ''"): + client.realtime.calls.with_raw_response.refer( + call_id="", + target_uri="tel:+14155550123", + ) + + @parametrize + def test_method_reject(self, client: OpenAI) -> None: + call = client.realtime.calls.reject( + call_id="call_id", + ) + assert call is None + + @parametrize + def test_method_reject_with_all_params(self, client: OpenAI) -> None: + call = client.realtime.calls.reject( + call_id="call_id", + status_code=486, + ) + assert call is None + + @parametrize + def test_raw_response_reject(self, client: OpenAI) -> None: + response = client.realtime.calls.with_raw_response.reject( + call_id="call_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + call = response.parse() + assert call is None + + @parametrize + def test_streaming_response_reject(self, client: OpenAI) -> None: + with client.realtime.calls.with_streaming_response.reject( + call_id="call_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + call = response.parse() + assert call is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_reject(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `call_id` but received ''"): + client.realtime.calls.with_raw_response.reject( + call_id="", + ) + + +class TestAsyncCalls: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_method_create(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None: + respx_mock.post("/realtime/calls").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + call = await async_client.realtime.calls.create( + sdp="sdp", + ) + assert isinstance(call, _legacy_response.HttpxBinaryResponseContent) + assert call.json() == {"foo": "bar"} + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_method_create_with_all_params(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None: + respx_mock.post("/realtime/calls").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + call = await async_client.realtime.calls.create( + sdp="sdp", + session={ + "type": "realtime", + "audio": { + "input": { + "format": { + "rate": 24000, + "type": "audio/pcm", + }, + "noise_reduction": {"type": "near_field"}, + "transcription": { + "language": "language", + "model": "whisper-1", + "prompt": "prompt", + }, + "turn_detection": { + "type": "server_vad", + "create_response": True, + "idle_timeout_ms": 5000, + "interrupt_response": True, + "prefix_padding_ms": 0, + "silence_duration_ms": 0, + "threshold": 0, + }, + }, + "output": { + "format": { + "rate": 24000, + "type": "audio/pcm", + }, + "speed": 0.25, + "voice": "ash", + }, + }, + "include": ["item.input_audio_transcription.logprobs"], + "instructions": "instructions", + "max_output_tokens": 0, + "model": "string", + "output_modalities": ["text"], + "prompt": { + "id": "id", + "variables": {"foo": "string"}, + "version": "version", + }, + "tool_choice": "none", + "tools": [ + { + "description": "description", + "name": "name", + "parameters": {}, + "type": "function", + } + ], + "tracing": "auto", + "truncation": "auto", + }, + ) + assert isinstance(call, _legacy_response.HttpxBinaryResponseContent) + assert call.json() == {"foo": "bar"} + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_raw_response_create(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None: + respx_mock.post("/realtime/calls").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + + response = await async_client.realtime.calls.with_raw_response.create( + sdp="sdp", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + call = response.parse() + assert_matches_type(_legacy_response.HttpxBinaryResponseContent, call, path=["response"]) + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_streaming_response_create(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None: + respx_mock.post("/realtime/calls").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + async with async_client.realtime.calls.with_streaming_response.create( + sdp="sdp", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + call = await response.parse() + assert_matches_type(bytes, call, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_accept(self, async_client: AsyncOpenAI) -> None: + call = await async_client.realtime.calls.accept( + call_id="call_id", + type="realtime", + ) + assert call is None + + @parametrize + async def test_method_accept_with_all_params(self, async_client: AsyncOpenAI) -> None: + call = await async_client.realtime.calls.accept( + call_id="call_id", + type="realtime", + audio={ + "input": { + "format": { + "rate": 24000, + "type": "audio/pcm", + }, + "noise_reduction": {"type": "near_field"}, + "transcription": { + "language": "language", + "model": "whisper-1", + "prompt": "prompt", + }, + "turn_detection": { + "type": "server_vad", + "create_response": True, + "idle_timeout_ms": 5000, + "interrupt_response": True, + "prefix_padding_ms": 0, + "silence_duration_ms": 0, + "threshold": 0, + }, + }, + "output": { + "format": { + "rate": 24000, + "type": "audio/pcm", + }, + "speed": 0.25, + "voice": "ash", + }, + }, + include=["item.input_audio_transcription.logprobs"], + instructions="instructions", + max_output_tokens=0, + model="string", + output_modalities=["text"], + prompt={ + "id": "id", + "variables": {"foo": "string"}, + "version": "version", + }, + tool_choice="none", + tools=[ + { + "description": "description", + "name": "name", + "parameters": {}, + "type": "function", + } + ], + tracing="auto", + truncation="auto", + ) + assert call is None + + @parametrize + async def test_raw_response_accept(self, async_client: AsyncOpenAI) -> None: + response = await async_client.realtime.calls.with_raw_response.accept( + call_id="call_id", + type="realtime", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + call = response.parse() + assert call is None + + @parametrize + async def test_streaming_response_accept(self, async_client: AsyncOpenAI) -> None: + async with async_client.realtime.calls.with_streaming_response.accept( + call_id="call_id", + type="realtime", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + call = await response.parse() + assert call is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_accept(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `call_id` but received ''"): + await async_client.realtime.calls.with_raw_response.accept( + call_id="", + type="realtime", + ) + + @parametrize + async def test_method_hangup(self, async_client: AsyncOpenAI) -> None: + call = await async_client.realtime.calls.hangup( + "call_id", + ) + assert call is None + + @parametrize + async def test_raw_response_hangup(self, async_client: AsyncOpenAI) -> None: + response = await async_client.realtime.calls.with_raw_response.hangup( + "call_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + call = response.parse() + assert call is None + + @parametrize + async def test_streaming_response_hangup(self, async_client: AsyncOpenAI) -> None: + async with async_client.realtime.calls.with_streaming_response.hangup( + "call_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + call = await response.parse() + assert call is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_hangup(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `call_id` but received ''"): + await async_client.realtime.calls.with_raw_response.hangup( + "", + ) + + @parametrize + async def test_method_refer(self, async_client: AsyncOpenAI) -> None: + call = await async_client.realtime.calls.refer( + call_id="call_id", + target_uri="tel:+14155550123", + ) + assert call is None + + @parametrize + async def test_raw_response_refer(self, async_client: AsyncOpenAI) -> None: + response = await async_client.realtime.calls.with_raw_response.refer( + call_id="call_id", + target_uri="tel:+14155550123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + call = response.parse() + assert call is None + + @parametrize + async def test_streaming_response_refer(self, async_client: AsyncOpenAI) -> None: + async with async_client.realtime.calls.with_streaming_response.refer( + call_id="call_id", + target_uri="tel:+14155550123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + call = await response.parse() + assert call is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_refer(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `call_id` but received ''"): + await async_client.realtime.calls.with_raw_response.refer( + call_id="", + target_uri="tel:+14155550123", + ) + + @parametrize + async def test_method_reject(self, async_client: AsyncOpenAI) -> None: + call = await async_client.realtime.calls.reject( + call_id="call_id", + ) + assert call is None + + @parametrize + async def test_method_reject_with_all_params(self, async_client: AsyncOpenAI) -> None: + call = await async_client.realtime.calls.reject( + call_id="call_id", + status_code=486, + ) + assert call is None + + @parametrize + async def test_raw_response_reject(self, async_client: AsyncOpenAI) -> None: + response = await async_client.realtime.calls.with_raw_response.reject( + call_id="call_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + call = response.parse() + assert call is None + + @parametrize + async def test_streaming_response_reject(self, async_client: AsyncOpenAI) -> None: + async with async_client.realtime.calls.with_streaming_response.reject( + call_id="call_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + call = await response.parse() + assert call is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_reject(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `call_id` but received ''"): + await async_client.realtime.calls.with_raw_response.reject( + call_id="", + ) From 53f7a74ca4af71fed7f61d6a73c5e597a99898ac Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 2 Oct 2025 20:13:57 +0000 Subject: [PATCH 512/769] release: 2.1.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index cf7239890c..656a2ef17d 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.0.1" + ".": "2.1.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index fcb9926c29..76d700f05e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 2.1.0 (2025-10-02) + +Full Changelog: [v2.0.1...v2.1.0](https://github.com/openai/openai-python/compare/v2.0.1...v2.1.0) + +### Features + +* **api:** add support for realtime calls ([7f7925b](https://github.com/openai/openai-python/commit/7f7925b4074ecbf879714698000e10fa0519d51a)) + ## 2.0.1 (2025-10-01) Full Changelog: [v2.0.0...v2.0.1](https://github.com/openai/openai-python/compare/v2.0.0...v2.0.1) diff --git a/pyproject.toml b/pyproject.toml index a83bca2dcd..d8deac4e61 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.0.1" +version = "2.1.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 f20794ac19..2860526ced 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__ = "2.0.1" # x-release-please-version +__version__ = "2.1.0" # x-release-please-version From 9ada2c74f3f5865a2bfb19afce885cc98ad6a4b3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 17:49:02 +0000 Subject: [PATCH 513/769] feat(api): dev day 2025 launches DevDay 2025 launches including videos and chatkit beta --- .stats.yml | 8 +- api.md | 26 + examples/video.py | 22 + helpers.md | 1 + src/openai/__init__.py | 1 + src/openai/_client.py | 38 + src/openai/_module_client.py | 8 + src/openai/resources/__init__.py | 14 + src/openai/resources/beta/__init__.py | 14 + src/openai/resources/beta/beta.py | 38 +- src/openai/resources/beta/chatkit/__init__.py | 47 + src/openai/resources/beta/chatkit/chatkit.py | 259 ++++++ src/openai/resources/beta/chatkit/sessions.py | 301 +++++++ src/openai/resources/beta/chatkit/threads.py | 521 +++++++++++ src/openai/resources/images.py | 18 +- src/openai/resources/realtime/calls.py | 8 + src/openai/resources/realtime/realtime.py | 6 +- src/openai/resources/videos.py | 847 ++++++++++++++++++ src/openai/types/__init__.py | 10 + src/openai/types/beta/__init__.py | 5 + src/openai/types/beta/chatkit/__init__.py | 32 + src/openai/types/beta/chatkit/chat_session.py | 43 + .../chat_session_automatic_thread_titling.py | 10 + .../chat_session_chatkit_configuration.py | 19 + ...hat_session_chatkit_configuration_param.py | 59 ++ .../chat_session_expires_after_param.py | 15 + .../beta/chatkit/chat_session_file_upload.py | 18 + .../beta/chatkit/chat_session_history.py | 18 + .../beta/chatkit/chat_session_rate_limits.py | 10 + .../chatkit/chat_session_rate_limits_param.py | 12 + .../types/beta/chatkit/chat_session_status.py | 7 + .../chatkit/chat_session_workflow_param.py | 34 + .../types/beta/chatkit/chatkit_attachment.py | 25 + .../chatkit/chatkit_response_output_text.py | 62 ++ .../types/beta/chatkit/chatkit_thread.py | 56 ++ .../chatkit_thread_assistant_message_item.py | 29 + .../beta/chatkit/chatkit_thread_item_list.py | 144 +++ .../chatkit_thread_user_message_item.py | 77 ++ .../types/beta/chatkit/chatkit_widget_item.py | 27 + .../beta/chatkit/session_create_params.py | 35 + .../beta/chatkit/thread_delete_response.py | 18 + .../beta/chatkit/thread_list_items_params.py | 27 + .../types/beta/chatkit/thread_list_params.py | 33 + .../types/beta/chatkit_upload_file_params.py | 17 + .../beta/chatkit_upload_file_response.py | 12 + src/openai/types/beta/chatkit_workflow.py | 32 + src/openai/types/beta/file_part.py | 28 + src/openai/types/beta/image_part.py | 31 + src/openai/types/image_edit_params.py | 13 +- src/openai/types/image_generate_params.py | 10 +- src/openai/types/image_model.py | 2 +- .../types/realtime/call_accept_params.py | 4 + .../realtime_session_create_request.py | 4 + .../realtime_session_create_request_param.py | 4 + .../realtime_session_create_response.py | 4 + src/openai/types/responses/tool.py | 5 +- src/openai/types/responses/tool_param.py | 5 +- src/openai/types/shared/all_models.py | 2 + src/openai/types/shared/responses_model.py | 2 + .../types/shared_params/responses_model.py | 2 + src/openai/types/video.py | 50 ++ src/openai/types/video_create_error.py | 11 + src/openai/types/video_create_params.py | 29 + src/openai/types/video_delete_response.py | 18 + .../types/video_download_content_params.py | 12 + src/openai/types/video_list_params.py | 21 + src/openai/types/video_model.py | 7 + src/openai/types/video_remix_params.py | 12 + src/openai/types/video_seconds.py | 7 + src/openai/types/video_size.py | 7 + tests/api_resources/beta/chatkit/__init__.py | 1 + .../beta/chatkit/test_sessions.py | 230 +++++ .../beta/chatkit/test_threads.py | 348 +++++++ tests/api_resources/beta/test_chatkit.py | 86 ++ tests/api_resources/test_videos.py | 551 ++++++++++++ 75 files changed, 4527 insertions(+), 42 deletions(-) create mode 100644 examples/video.py create mode 100644 src/openai/resources/beta/chatkit/__init__.py create mode 100644 src/openai/resources/beta/chatkit/chatkit.py create mode 100644 src/openai/resources/beta/chatkit/sessions.py create mode 100644 src/openai/resources/beta/chatkit/threads.py create mode 100644 src/openai/resources/videos.py create mode 100644 src/openai/types/beta/chatkit/__init__.py create mode 100644 src/openai/types/beta/chatkit/chat_session.py create mode 100644 src/openai/types/beta/chatkit/chat_session_automatic_thread_titling.py create mode 100644 src/openai/types/beta/chatkit/chat_session_chatkit_configuration.py create mode 100644 src/openai/types/beta/chatkit/chat_session_chatkit_configuration_param.py create mode 100644 src/openai/types/beta/chatkit/chat_session_expires_after_param.py create mode 100644 src/openai/types/beta/chatkit/chat_session_file_upload.py create mode 100644 src/openai/types/beta/chatkit/chat_session_history.py create mode 100644 src/openai/types/beta/chatkit/chat_session_rate_limits.py create mode 100644 src/openai/types/beta/chatkit/chat_session_rate_limits_param.py create mode 100644 src/openai/types/beta/chatkit/chat_session_status.py create mode 100644 src/openai/types/beta/chatkit/chat_session_workflow_param.py create mode 100644 src/openai/types/beta/chatkit/chatkit_attachment.py create mode 100644 src/openai/types/beta/chatkit/chatkit_response_output_text.py create mode 100644 src/openai/types/beta/chatkit/chatkit_thread.py create mode 100644 src/openai/types/beta/chatkit/chatkit_thread_assistant_message_item.py create mode 100644 src/openai/types/beta/chatkit/chatkit_thread_item_list.py create mode 100644 src/openai/types/beta/chatkit/chatkit_thread_user_message_item.py create mode 100644 src/openai/types/beta/chatkit/chatkit_widget_item.py create mode 100644 src/openai/types/beta/chatkit/session_create_params.py create mode 100644 src/openai/types/beta/chatkit/thread_delete_response.py create mode 100644 src/openai/types/beta/chatkit/thread_list_items_params.py create mode 100644 src/openai/types/beta/chatkit/thread_list_params.py create mode 100644 src/openai/types/beta/chatkit_upload_file_params.py create mode 100644 src/openai/types/beta/chatkit_upload_file_response.py create mode 100644 src/openai/types/beta/chatkit_workflow.py create mode 100644 src/openai/types/beta/file_part.py create mode 100644 src/openai/types/beta/image_part.py create mode 100644 src/openai/types/video.py create mode 100644 src/openai/types/video_create_error.py create mode 100644 src/openai/types/video_create_params.py create mode 100644 src/openai/types/video_delete_response.py create mode 100644 src/openai/types/video_download_content_params.py create mode 100644 src/openai/types/video_list_params.py create mode 100644 src/openai/types/video_model.py create mode 100644 src/openai/types/video_remix_params.py create mode 100644 src/openai/types/video_seconds.py create mode 100644 src/openai/types/video_size.py create mode 100644 tests/api_resources/beta/chatkit/__init__.py create mode 100644 tests/api_resources/beta/chatkit/test_sessions.py create mode 100644 tests/api_resources/beta/chatkit/test_threads.py create mode 100644 tests/api_resources/beta/test_chatkit.py create mode 100644 tests/api_resources/test_videos.py diff --git a/.stats.yml b/.stats.yml index d974760a99..2dc7422e7e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 123 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-fadefdc7c7e30df47c09df323669b242ff90ee08e51f304175ace5274e0aab49.yml -openapi_spec_hash: 6d20f639d9ff8a097a34962da6218231 -config_hash: 902654e60f5d659f2bfcfd903e17c46d +configured_endpoints: 136 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-d64cf80d2ebddf175c5578f68226a3d5bbd3f7fd8d62ccac2205f3fc05a355ee.yml +openapi_spec_hash: d51e0d60d0c536f210b597a211bc5af0 +config_hash: e7c42016df9c6bd7bd6ff15101b9bc9b diff --git a/api.md b/api.md index d5331803ce..1c170ccdd8 100644 --- a/api.md +++ b/api.md @@ -1139,3 +1139,29 @@ Methods: Methods: - client.containers.files.content.retrieve(file_id, \*, container_id) -> HttpxBinaryResponseContent + +# Videos + +Types: + +```python +from openai.types import ( + Video, + VideoCreateError, + VideoModel, + VideoSeconds, + VideoSize, + VideoDeleteResponse, +) +``` + +Methods: + +- client.videos.create(\*\*params) -> Video +- client.videos.retrieve(video_id) -> Video +- client.videos.list(\*\*params) -> SyncConversationCursorPage[Video] +- client.videos.delete(video_id) -> VideoDeleteResponse +- client.videos.download_content(video_id, \*\*params) -> HttpxBinaryResponseContent +- client.videos.remix(video_id, \*\*params) -> Video +- client.videos.create_and_poll(\*args) -> Video + diff --git a/examples/video.py b/examples/video.py new file mode 100644 index 0000000000..ee89e64697 --- /dev/null +++ b/examples/video.py @@ -0,0 +1,22 @@ +#!/usr/bin/env -S poetry run python + +import asyncio + +from openai import AsyncOpenAI + +client = AsyncOpenAI() + + +async def main() -> None: + video = await client.videos.create_and_poll( + model="sora-2", + prompt="A video of the words 'Thank you' in sparkling letters", + ) + + if video.status == "completed": + print("Video successfully completed: ", video) + else: + print("Video creation failed. Status: ", video.status) + + +asyncio.run(main()) diff --git a/helpers.md b/helpers.md index 21ad8ac2fb..89ff4498cf 100644 --- a/helpers.md +++ b/helpers.md @@ -514,4 +514,5 @@ client.beta.vector_stores.files.upload_and_poll(...) client.beta.vector_stores.files.create_and_poll(...) client.beta.vector_stores.file_batches.create_and_poll(...) client.beta.vector_stores.file_batches.upload_and_poll(...) +client.videos.create_and_poll(...) ``` diff --git a/src/openai/__init__.py b/src/openai/__init__.py index bd01da628d..e7411b3886 100644 --- a/src/openai/__init__.py +++ b/src/openai/__init__.py @@ -379,6 +379,7 @@ def _reset_client() -> None: # type: ignore[reportUnusedFunction] files as files, images as images, models as models, + videos as videos, batches as batches, uploads as uploads, realtime as realtime, diff --git a/src/openai/_client.py b/src/openai/_client.py index 1485029ddd..a3b01b2ce6 100644 --- a/src/openai/_client.py +++ b/src/openai/_client.py @@ -44,6 +44,7 @@ files, images, models, + videos, batches, uploads, realtime, @@ -59,6 +60,7 @@ from .resources.files import Files, AsyncFiles from .resources.images import Images, AsyncImages from .resources.models import Models, AsyncModels + from .resources.videos import Videos, AsyncVideos from .resources.batches import Batches, AsyncBatches from .resources.webhooks import Webhooks, AsyncWebhooks from .resources.beta.beta import Beta, AsyncBeta @@ -288,6 +290,12 @@ def containers(self) -> Containers: return Containers(self) + @cached_property + def videos(self) -> Videos: + from .resources.videos import Videos + + return Videos(self) + @cached_property def with_raw_response(self) -> OpenAIWithRawResponse: return OpenAIWithRawResponse(self) @@ -633,6 +641,12 @@ def containers(self) -> AsyncContainers: return AsyncContainers(self) + @cached_property + def videos(self) -> AsyncVideos: + from .resources.videos import AsyncVideos + + return AsyncVideos(self) + @cached_property def with_raw_response(self) -> AsyncOpenAIWithRawResponse: return AsyncOpenAIWithRawResponse(self) @@ -883,6 +897,12 @@ def containers(self) -> containers.ContainersWithRawResponse: return ContainersWithRawResponse(self._client.containers) + @cached_property + def videos(self) -> videos.VideosWithRawResponse: + from .resources.videos import VideosWithRawResponse + + return VideosWithRawResponse(self._client.videos) + class AsyncOpenAIWithRawResponse: _client: AsyncOpenAI @@ -998,6 +1018,12 @@ def containers(self) -> containers.AsyncContainersWithRawResponse: return AsyncContainersWithRawResponse(self._client.containers) + @cached_property + def videos(self) -> videos.AsyncVideosWithRawResponse: + from .resources.videos import AsyncVideosWithRawResponse + + return AsyncVideosWithRawResponse(self._client.videos) + class OpenAIWithStreamedResponse: _client: OpenAI @@ -1113,6 +1139,12 @@ def containers(self) -> containers.ContainersWithStreamingResponse: return ContainersWithStreamingResponse(self._client.containers) + @cached_property + def videos(self) -> videos.VideosWithStreamingResponse: + from .resources.videos import VideosWithStreamingResponse + + return VideosWithStreamingResponse(self._client.videos) + class AsyncOpenAIWithStreamedResponse: _client: AsyncOpenAI @@ -1228,6 +1260,12 @@ def containers(self) -> containers.AsyncContainersWithStreamingResponse: return AsyncContainersWithStreamingResponse(self._client.containers) + @cached_property + def videos(self) -> videos.AsyncVideosWithStreamingResponse: + from .resources.videos import AsyncVideosWithStreamingResponse + + return AsyncVideosWithStreamingResponse(self._client.videos) + Client = OpenAI diff --git a/src/openai/_module_client.py b/src/openai/_module_client.py index 4ecc28420a..d0d721887b 100644 --- a/src/openai/_module_client.py +++ b/src/openai/_module_client.py @@ -9,6 +9,7 @@ from .resources.files import Files from .resources.images import Images from .resources.models import Models + from .resources.videos import Videos from .resources.batches import Batches from .resources.webhooks import Webhooks from .resources.beta.beta import Beta @@ -72,6 +73,12 @@ def __load__(self) -> Models: return _load_client().models +class VideosProxy(LazyProxy["Videos"]): + @override + def __load__(self) -> Videos: + return _load_client().videos + + class BatchesProxy(LazyProxy["Batches"]): @override def __load__(self) -> Batches: @@ -151,6 +158,7 @@ def __load__(self) -> Conversations: evals: Evals = EvalsProxy().__as_proxied__() images: Images = ImagesProxy().__as_proxied__() models: Models = ModelsProxy().__as_proxied__() +videos: Videos = VideosProxy().__as_proxied__() batches: Batches = BatchesProxy().__as_proxied__() uploads: Uploads = UploadsProxy().__as_proxied__() webhooks: Webhooks = WebhooksProxy().__as_proxied__() diff --git a/src/openai/resources/__init__.py b/src/openai/resources/__init__.py index 82c9f037d9..b793fbc7b0 100644 --- a/src/openai/resources/__init__.py +++ b/src/openai/resources/__init__.py @@ -56,6 +56,14 @@ ModelsWithStreamingResponse, AsyncModelsWithStreamingResponse, ) +from .videos import ( + Videos, + AsyncVideos, + VideosWithRawResponse, + AsyncVideosWithRawResponse, + VideosWithStreamingResponse, + AsyncVideosWithStreamingResponse, +) from .batches import ( Batches, AsyncBatches, @@ -212,4 +220,10 @@ "AsyncContainersWithRawResponse", "ContainersWithStreamingResponse", "AsyncContainersWithStreamingResponse", + "Videos", + "AsyncVideos", + "VideosWithRawResponse", + "AsyncVideosWithRawResponse", + "VideosWithStreamingResponse", + "AsyncVideosWithStreamingResponse", ] diff --git a/src/openai/resources/beta/__init__.py b/src/openai/resources/beta/__init__.py index 87fea25267..6d6f538670 100644 --- a/src/openai/resources/beta/__init__.py +++ b/src/openai/resources/beta/__init__.py @@ -8,6 +8,14 @@ BetaWithStreamingResponse, AsyncBetaWithStreamingResponse, ) +from .chatkit import ( + ChatKit, + AsyncChatKit, + ChatKitWithRawResponse, + AsyncChatKitWithRawResponse, + ChatKitWithStreamingResponse, + AsyncChatKitWithStreamingResponse, +) from .threads import ( Threads, AsyncThreads, @@ -26,6 +34,12 @@ ) __all__ = [ + "ChatKit", + "AsyncChatKit", + "ChatKitWithRawResponse", + "AsyncChatKitWithRawResponse", + "ChatKitWithStreamingResponse", + "AsyncChatKitWithStreamingResponse", "Assistants", "AsyncAssistants", "AssistantsWithRawResponse", diff --git a/src/openai/resources/beta/beta.py b/src/openai/resources/beta/beta.py index 9084c477e9..81a6e7aa93 100644 --- a/src/openai/resources/beta/beta.py +++ b/src/openai/resources/beta/beta.py @@ -12,6 +12,14 @@ AsyncAssistantsWithStreamingResponse, ) from ..._resource import SyncAPIResource, AsyncAPIResource +from .chatkit.chatkit import ( + ChatKit, + AsyncChatKit, + ChatKitWithRawResponse, + AsyncChatKitWithRawResponse, + ChatKitWithStreamingResponse, + AsyncChatKitWithStreamingResponse, +) from .threads.threads import ( Threads, AsyncThreads, @@ -31,14 +39,7 @@ class Beta(SyncAPIResource): @cached_property - def chat(self) -> Chat: - return Chat(self._client) - - @cached_property - def realtime(self) -> Realtime: - return Realtime(self._client) - @cached_property def assistants(self) -> Assistants: return Assistants(self._client) @@ -68,14 +69,7 @@ def with_streaming_response(self) -> BetaWithStreamingResponse: class AsyncBeta(AsyncAPIResource): @cached_property - def chat(self) -> AsyncChat: - return AsyncChat(self._client) - @cached_property - def realtime(self) -> AsyncRealtime: - return AsyncRealtime(self._client) - - @cached_property def assistants(self) -> AsyncAssistants: return AsyncAssistants(self._client) @@ -107,6 +101,10 @@ class BetaWithRawResponse: def __init__(self, beta: Beta) -> None: self._beta = beta + @cached_property + def chatkit(self) -> ChatKitWithRawResponse: + return ChatKitWithRawResponse(self._beta.chatkit) + @cached_property def assistants(self) -> AssistantsWithRawResponse: return AssistantsWithRawResponse(self._beta.assistants) @@ -120,6 +118,10 @@ class AsyncBetaWithRawResponse: def __init__(self, beta: AsyncBeta) -> None: self._beta = beta + @cached_property + def chatkit(self) -> AsyncChatKitWithRawResponse: + return AsyncChatKitWithRawResponse(self._beta.chatkit) + @cached_property def assistants(self) -> AsyncAssistantsWithRawResponse: return AsyncAssistantsWithRawResponse(self._beta.assistants) @@ -133,6 +135,10 @@ class BetaWithStreamingResponse: def __init__(self, beta: Beta) -> None: self._beta = beta + @cached_property + def chatkit(self) -> ChatKitWithStreamingResponse: + return ChatKitWithStreamingResponse(self._beta.chatkit) + @cached_property def assistants(self) -> AssistantsWithStreamingResponse: return AssistantsWithStreamingResponse(self._beta.assistants) @@ -146,6 +152,10 @@ class AsyncBetaWithStreamingResponse: def __init__(self, beta: AsyncBeta) -> None: self._beta = beta + @cached_property + def chatkit(self) -> AsyncChatKitWithStreamingResponse: + return AsyncChatKitWithStreamingResponse(self._beta.chatkit) + @cached_property def assistants(self) -> AsyncAssistantsWithStreamingResponse: return AsyncAssistantsWithStreamingResponse(self._beta.assistants) diff --git a/src/openai/resources/beta/chatkit/__init__.py b/src/openai/resources/beta/chatkit/__init__.py new file mode 100644 index 0000000000..05f24d6238 --- /dev/null +++ b/src/openai/resources/beta/chatkit/__init__.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .chatkit import ( + ChatKit, + AsyncChatKit, + ChatKitWithRawResponse, + AsyncChatKitWithRawResponse, + ChatKitWithStreamingResponse, + AsyncChatKitWithStreamingResponse, +) +from .threads import ( + Threads, + AsyncThreads, + ThreadsWithRawResponse, + AsyncThreadsWithRawResponse, + ThreadsWithStreamingResponse, + AsyncThreadsWithStreamingResponse, +) +from .sessions import ( + Sessions, + AsyncSessions, + SessionsWithRawResponse, + AsyncSessionsWithRawResponse, + SessionsWithStreamingResponse, + AsyncSessionsWithStreamingResponse, +) + +__all__ = [ + "Sessions", + "AsyncSessions", + "SessionsWithRawResponse", + "AsyncSessionsWithRawResponse", + "SessionsWithStreamingResponse", + "AsyncSessionsWithStreamingResponse", + "Threads", + "AsyncThreads", + "ThreadsWithRawResponse", + "AsyncThreadsWithRawResponse", + "ThreadsWithStreamingResponse", + "AsyncThreadsWithStreamingResponse", + "ChatKit", + "AsyncChatKit", + "ChatKitWithRawResponse", + "AsyncChatKitWithRawResponse", + "ChatKitWithStreamingResponse", + "AsyncChatKitWithStreamingResponse", +] diff --git a/src/openai/resources/beta/chatkit/chatkit.py b/src/openai/resources/beta/chatkit/chatkit.py new file mode 100644 index 0000000000..2d090cf396 --- /dev/null +++ b/src/openai/resources/beta/chatkit/chatkit.py @@ -0,0 +1,259 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Any, Mapping, cast + +import httpx + +from .... import _legacy_response +from .threads import ( + Threads, + AsyncThreads, + ThreadsWithRawResponse, + AsyncThreadsWithRawResponse, + ThreadsWithStreamingResponse, + AsyncThreadsWithStreamingResponse, +) +from .sessions import ( + Sessions, + AsyncSessions, + SessionsWithRawResponse, + AsyncSessionsWithRawResponse, + SessionsWithStreamingResponse, + AsyncSessionsWithStreamingResponse, +) +from ...._types import Body, Query, Headers, NotGiven, FileTypes, not_given +from ...._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ....types.beta import chatkit_upload_file_params +from ...._base_client import make_request_options +from ....types.beta.chatkit_upload_file_response import ChatKitUploadFileResponse + +__all__ = ["ChatKit", "AsyncChatKit"] + + +class ChatKit(SyncAPIResource): + @cached_property + def sessions(self) -> Sessions: + return Sessions(self._client) + + @cached_property + def threads(self) -> Threads: + return Threads(self._client) + + @cached_property + def with_raw_response(self) -> ChatKitWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return ChatKitWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ChatKitWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return ChatKitWithStreamingResponse(self) + + def upload_file( + self, + *, + file: FileTypes, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ChatKitUploadFileResponse: + """ + Upload a ChatKit file + + Args: + file: Binary file contents to store with the ChatKit session. Supports PDFs and PNG, + JPG, JPEG, GIF, or WEBP images. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} + body = deepcopy_minimal({"file": file}) + files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) + if files: + # It should be noted that the actual Content-Type header that will be + # sent to the server will contain a `boundary` parameter, e.g. + # multipart/form-data; boundary=---abc-- + extra_headers["Content-Type"] = "multipart/form-data" + return cast( + ChatKitUploadFileResponse, + self._post( + "/chatkit/files", + body=maybe_transform(body, chatkit_upload_file_params.ChatKitUploadFileParams), + files=files, + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=cast( + Any, ChatKitUploadFileResponse + ), # Union types cannot be passed in as arguments in the type system + ), + ) + + +class AsyncChatKit(AsyncAPIResource): + @cached_property + def sessions(self) -> AsyncSessions: + return AsyncSessions(self._client) + + @cached_property + def threads(self) -> AsyncThreads: + return AsyncThreads(self._client) + + @cached_property + def with_raw_response(self) -> AsyncChatKitWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncChatKitWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncChatKitWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncChatKitWithStreamingResponse(self) + + async def upload_file( + self, + *, + file: FileTypes, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ChatKitUploadFileResponse: + """ + Upload a ChatKit file + + Args: + file: Binary file contents to store with the ChatKit session. Supports PDFs and PNG, + JPG, JPEG, GIF, or WEBP images. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} + body = deepcopy_minimal({"file": file}) + files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) + if files: + # It should be noted that the actual Content-Type header that will be + # sent to the server will contain a `boundary` parameter, e.g. + # multipart/form-data; boundary=---abc-- + extra_headers["Content-Type"] = "multipart/form-data" + return cast( + ChatKitUploadFileResponse, + await self._post( + "/chatkit/files", + body=await async_maybe_transform(body, chatkit_upload_file_params.ChatKitUploadFileParams), + files=files, + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=cast( + Any, ChatKitUploadFileResponse + ), # Union types cannot be passed in as arguments in the type system + ), + ) + + +class ChatKitWithRawResponse: + def __init__(self, chatkit: ChatKit) -> None: + self._chatkit = chatkit + + self.upload_file = _legacy_response.to_raw_response_wrapper( + chatkit.upload_file, + ) + + @cached_property + def sessions(self) -> SessionsWithRawResponse: + return SessionsWithRawResponse(self._chatkit.sessions) + + @cached_property + def threads(self) -> ThreadsWithRawResponse: + return ThreadsWithRawResponse(self._chatkit.threads) + + +class AsyncChatKitWithRawResponse: + def __init__(self, chatkit: AsyncChatKit) -> None: + self._chatkit = chatkit + + self.upload_file = _legacy_response.async_to_raw_response_wrapper( + chatkit.upload_file, + ) + + @cached_property + def sessions(self) -> AsyncSessionsWithRawResponse: + return AsyncSessionsWithRawResponse(self._chatkit.sessions) + + @cached_property + def threads(self) -> AsyncThreadsWithRawResponse: + return AsyncThreadsWithRawResponse(self._chatkit.threads) + + +class ChatKitWithStreamingResponse: + def __init__(self, chatkit: ChatKit) -> None: + self._chatkit = chatkit + + self.upload_file = to_streamed_response_wrapper( + chatkit.upload_file, + ) + + @cached_property + def sessions(self) -> SessionsWithStreamingResponse: + return SessionsWithStreamingResponse(self._chatkit.sessions) + + @cached_property + def threads(self) -> ThreadsWithStreamingResponse: + return ThreadsWithStreamingResponse(self._chatkit.threads) + + +class AsyncChatKitWithStreamingResponse: + def __init__(self, chatkit: AsyncChatKit) -> None: + self._chatkit = chatkit + + self.upload_file = async_to_streamed_response_wrapper( + chatkit.upload_file, + ) + + @cached_property + def sessions(self) -> AsyncSessionsWithStreamingResponse: + return AsyncSessionsWithStreamingResponse(self._chatkit.sessions) + + @cached_property + def threads(self) -> AsyncThreadsWithStreamingResponse: + return AsyncThreadsWithStreamingResponse(self._chatkit.threads) diff --git a/src/openai/resources/beta/chatkit/sessions.py b/src/openai/resources/beta/chatkit/sessions.py new file mode 100644 index 0000000000..a814f1058e --- /dev/null +++ b/src/openai/resources/beta/chatkit/sessions.py @@ -0,0 +1,301 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from .... import _legacy_response +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ...._base_client import make_request_options +from ....types.beta.chatkit import ( + ChatSessionWorkflowParam, + ChatSessionRateLimitsParam, + ChatSessionExpiresAfterParam, + ChatSessionChatKitConfigurationParam, + session_create_params, +) +from ....types.beta.chatkit.chat_session import ChatSession +from ....types.beta.chatkit.chat_session_workflow_param import ChatSessionWorkflowParam +from ....types.beta.chatkit.chat_session_rate_limits_param import ChatSessionRateLimitsParam +from ....types.beta.chatkit.chat_session_expires_after_param import ChatSessionExpiresAfterParam +from ....types.beta.chatkit.chat_session_chatkit_configuration_param import ChatSessionChatKitConfigurationParam + +__all__ = ["Sessions", "AsyncSessions"] + + +class Sessions(SyncAPIResource): + @cached_property + def with_raw_response(self) -> SessionsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return SessionsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> SessionsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return SessionsWithStreamingResponse(self) + + def create( + self, + *, + user: str, + workflow: ChatSessionWorkflowParam, + chatkit_configuration: ChatSessionChatKitConfigurationParam | Omit = omit, + expires_after: ChatSessionExpiresAfterParam | Omit = omit, + rate_limits: ChatSessionRateLimitsParam | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ChatSession: + """ + Create a ChatKit session + + Args: + user: A free-form string that identifies your end user; ensures this Session can + access other objects that have the same `user` scope. + + workflow: Workflow that powers the session. + + chatkit_configuration: Optional overrides for ChatKit runtime configuration features + + expires_after: Optional override for session expiration timing in seconds from creation. + Defaults to 10 minutes. + + rate_limits: Optional override for per-minute request limits. When omitted, defaults to 10. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} + return self._post( + "/chatkit/sessions", + body=maybe_transform( + { + "user": user, + "workflow": workflow, + "chatkit_configuration": chatkit_configuration, + "expires_after": expires_after, + "rate_limits": rate_limits, + }, + session_create_params.SessionCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ChatSession, + ) + + def cancel( + self, + session_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ChatSession: + """ + Cancel a ChatKit session + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not session_id: + raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") + extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} + return self._post( + f"/chatkit/sessions/{session_id}/cancel", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ChatSession, + ) + + +class AsyncSessions(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncSessionsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncSessionsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncSessionsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncSessionsWithStreamingResponse(self) + + async def create( + self, + *, + user: str, + workflow: ChatSessionWorkflowParam, + chatkit_configuration: ChatSessionChatKitConfigurationParam | Omit = omit, + expires_after: ChatSessionExpiresAfterParam | Omit = omit, + rate_limits: ChatSessionRateLimitsParam | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ChatSession: + """ + Create a ChatKit session + + Args: + user: A free-form string that identifies your end user; ensures this Session can + access other objects that have the same `user` scope. + + workflow: Workflow that powers the session. + + chatkit_configuration: Optional overrides for ChatKit runtime configuration features + + expires_after: Optional override for session expiration timing in seconds from creation. + Defaults to 10 minutes. + + rate_limits: Optional override for per-minute request limits. When omitted, defaults to 10. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} + return await self._post( + "/chatkit/sessions", + body=await async_maybe_transform( + { + "user": user, + "workflow": workflow, + "chatkit_configuration": chatkit_configuration, + "expires_after": expires_after, + "rate_limits": rate_limits, + }, + session_create_params.SessionCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ChatSession, + ) + + async def cancel( + self, + session_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ChatSession: + """ + Cancel a ChatKit session + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not session_id: + raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") + extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} + return await self._post( + f"/chatkit/sessions/{session_id}/cancel", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ChatSession, + ) + + +class SessionsWithRawResponse: + def __init__(self, sessions: Sessions) -> None: + self._sessions = sessions + + self.create = _legacy_response.to_raw_response_wrapper( + sessions.create, + ) + self.cancel = _legacy_response.to_raw_response_wrapper( + sessions.cancel, + ) + + +class AsyncSessionsWithRawResponse: + def __init__(self, sessions: AsyncSessions) -> None: + self._sessions = sessions + + self.create = _legacy_response.async_to_raw_response_wrapper( + sessions.create, + ) + self.cancel = _legacy_response.async_to_raw_response_wrapper( + sessions.cancel, + ) + + +class SessionsWithStreamingResponse: + def __init__(self, sessions: Sessions) -> None: + self._sessions = sessions + + self.create = to_streamed_response_wrapper( + sessions.create, + ) + self.cancel = to_streamed_response_wrapper( + sessions.cancel, + ) + + +class AsyncSessionsWithStreamingResponse: + def __init__(self, sessions: AsyncSessions) -> None: + self._sessions = sessions + + self.create = async_to_streamed_response_wrapper( + sessions.create, + ) + self.cancel = async_to_streamed_response_wrapper( + sessions.cancel, + ) diff --git a/src/openai/resources/beta/chatkit/threads.py b/src/openai/resources/beta/chatkit/threads.py new file mode 100644 index 0000000000..37cd57295a --- /dev/null +++ b/src/openai/resources/beta/chatkit/threads.py @@ -0,0 +1,521 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Any, cast +from typing_extensions import Literal + +import httpx + +from .... import _legacy_response +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ...._utils import maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ....pagination import SyncConversationCursorPage, AsyncConversationCursorPage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.beta.chatkit import thread_list_params, thread_list_items_params +from ....types.beta.chatkit.chatkit_thread import ChatKitThread +from ....types.beta.chatkit.thread_delete_response import ThreadDeleteResponse +from ....types.beta.chatkit.chatkit_thread_item_list import Data + +__all__ = ["Threads", "AsyncThreads"] + + +class Threads(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ThreadsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return ThreadsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ThreadsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return ThreadsWithStreamingResponse(self) + + def retrieve( + self, + thread_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ChatKitThread: + """ + Retrieve a ChatKit thread + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not thread_id: + raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") + extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} + return self._get( + f"/chatkit/threads/{thread_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ChatKitThread, + ) + + def list( + self, + *, + after: str | Omit = omit, + before: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + user: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncConversationCursorPage[ChatKitThread]: + """ + List ChatKit threads + + Args: + after: List items created after this thread item ID. Defaults to null for the first + page. + + before: List items created before this thread item ID. Defaults to null for the newest + results. + + limit: Maximum number of thread items to return. Defaults to 20. + + order: Sort order for results by creation time. Defaults to `desc`. + + user: Filter threads that belong to this user identifier. Defaults to null to return + all users. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} + return self._get_api_list( + "/chatkit/threads", + page=SyncConversationCursorPage[ChatKitThread], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "before": before, + "limit": limit, + "order": order, + "user": user, + }, + thread_list_params.ThreadListParams, + ), + ), + model=ChatKitThread, + ) + + def delete( + self, + thread_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ThreadDeleteResponse: + """ + Delete a ChatKit thread + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not thread_id: + raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") + extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} + return self._delete( + f"/chatkit/threads/{thread_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ThreadDeleteResponse, + ) + + def list_items( + self, + thread_id: str, + *, + after: str | Omit = omit, + before: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncConversationCursorPage[Data]: + """ + List ChatKit thread items + + Args: + after: List items created after this thread item ID. Defaults to null for the first + page. + + before: List items created before this thread item ID. Defaults to null for the newest + results. + + limit: Maximum number of thread items to return. Defaults to 20. + + order: Sort order for results by creation time. Defaults to `desc`. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not thread_id: + raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") + extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} + return self._get_api_list( + f"/chatkit/threads/{thread_id}/items", + page=SyncConversationCursorPage[Data], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "before": before, + "limit": limit, + "order": order, + }, + thread_list_items_params.ThreadListItemsParams, + ), + ), + model=cast(Any, Data), # Union types cannot be passed in as arguments in the type system + ) + + +class AsyncThreads(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncThreadsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncThreadsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncThreadsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncThreadsWithStreamingResponse(self) + + async def retrieve( + self, + thread_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ChatKitThread: + """ + Retrieve a ChatKit thread + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not thread_id: + raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") + extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} + return await self._get( + f"/chatkit/threads/{thread_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ChatKitThread, + ) + + def list( + self, + *, + after: str | Omit = omit, + before: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + user: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[ChatKitThread, AsyncConversationCursorPage[ChatKitThread]]: + """ + List ChatKit threads + + Args: + after: List items created after this thread item ID. Defaults to null for the first + page. + + before: List items created before this thread item ID. Defaults to null for the newest + results. + + limit: Maximum number of thread items to return. Defaults to 20. + + order: Sort order for results by creation time. Defaults to `desc`. + + user: Filter threads that belong to this user identifier. Defaults to null to return + all users. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} + return self._get_api_list( + "/chatkit/threads", + page=AsyncConversationCursorPage[ChatKitThread], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "before": before, + "limit": limit, + "order": order, + "user": user, + }, + thread_list_params.ThreadListParams, + ), + ), + model=ChatKitThread, + ) + + async def delete( + self, + thread_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ThreadDeleteResponse: + """ + Delete a ChatKit thread + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not thread_id: + raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") + extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} + return await self._delete( + f"/chatkit/threads/{thread_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ThreadDeleteResponse, + ) + + def list_items( + self, + thread_id: str, + *, + after: str | Omit = omit, + before: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Data, AsyncConversationCursorPage[Data]]: + """ + List ChatKit thread items + + Args: + after: List items created after this thread item ID. Defaults to null for the first + page. + + before: List items created before this thread item ID. Defaults to null for the newest + results. + + limit: Maximum number of thread items to return. Defaults to 20. + + order: Sort order for results by creation time. Defaults to `desc`. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not thread_id: + raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") + extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} + return self._get_api_list( + f"/chatkit/threads/{thread_id}/items", + page=AsyncConversationCursorPage[Data], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "before": before, + "limit": limit, + "order": order, + }, + thread_list_items_params.ThreadListItemsParams, + ), + ), + model=cast(Any, Data), # Union types cannot be passed in as arguments in the type system + ) + + +class ThreadsWithRawResponse: + def __init__(self, threads: Threads) -> None: + self._threads = threads + + self.retrieve = _legacy_response.to_raw_response_wrapper( + threads.retrieve, + ) + self.list = _legacy_response.to_raw_response_wrapper( + threads.list, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + threads.delete, + ) + self.list_items = _legacy_response.to_raw_response_wrapper( + threads.list_items, + ) + + +class AsyncThreadsWithRawResponse: + def __init__(self, threads: AsyncThreads) -> None: + self._threads = threads + + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + threads.retrieve, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + threads.list, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + threads.delete, + ) + self.list_items = _legacy_response.async_to_raw_response_wrapper( + threads.list_items, + ) + + +class ThreadsWithStreamingResponse: + def __init__(self, threads: Threads) -> None: + self._threads = threads + + self.retrieve = to_streamed_response_wrapper( + threads.retrieve, + ) + self.list = to_streamed_response_wrapper( + threads.list, + ) + self.delete = to_streamed_response_wrapper( + threads.delete, + ) + self.list_items = to_streamed_response_wrapper( + threads.list_items, + ) + + +class AsyncThreadsWithStreamingResponse: + def __init__(self, threads: AsyncThreads) -> None: + self._threads = threads + + self.retrieve = async_to_streamed_response_wrapper( + threads.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + threads.list, + ) + self.delete = async_to_streamed_response_wrapper( + threads.delete, + ) + self.list_items = async_to_streamed_response_wrapper( + threads.list_items, + ) diff --git a/src/openai/resources/images.py b/src/openai/resources/images.py index aae26bab64..265be6f743 100644 --- a/src/openai/resources/images.py +++ b/src/openai/resources/images.py @@ -170,7 +170,8 @@ def edit( input_fidelity: Control how much effort the model will exert to match the style and features, especially facial features, of input images. This parameter is only supported - for `gpt-image-1`. Supports `high` and `low`. Defaults to `low`. + for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and + `low`. Defaults to `low`. mask: An additional image whose fully transparent areas (e.g. where alpha is zero) indicate where `image` should be edited. If there are multiple images provided, @@ -286,7 +287,8 @@ def edit( input_fidelity: Control how much effort the model will exert to match the style and features, especially facial features, of input images. This parameter is only supported - for `gpt-image-1`. Supports `high` and `low`. Defaults to `low`. + for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and + `low`. Defaults to `low`. mask: An additional image whose fully transparent areas (e.g. where alpha is zero) indicate where `image` should be edited. If there are multiple images provided, @@ -398,7 +400,8 @@ def edit( input_fidelity: Control how much effort the model will exert to match the style and features, especially facial features, of input images. This parameter is only supported - for `gpt-image-1`. Supports `high` and `low`. Defaults to `low`. + for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and + `low`. Defaults to `low`. mask: An additional image whose fully transparent areas (e.g. where alpha is zero) indicate where `image` should be edited. If there are multiple images provided, @@ -1054,7 +1057,8 @@ async def edit( input_fidelity: Control how much effort the model will exert to match the style and features, especially facial features, of input images. This parameter is only supported - for `gpt-image-1`. Supports `high` and `low`. Defaults to `low`. + for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and + `low`. Defaults to `low`. mask: An additional image whose fully transparent areas (e.g. where alpha is zero) indicate where `image` should be edited. If there are multiple images provided, @@ -1170,7 +1174,8 @@ async def edit( input_fidelity: Control how much effort the model will exert to match the style and features, especially facial features, of input images. This parameter is only supported - for `gpt-image-1`. Supports `high` and `low`. Defaults to `low`. + for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and + `low`. Defaults to `low`. mask: An additional image whose fully transparent areas (e.g. where alpha is zero) indicate where `image` should be edited. If there are multiple images provided, @@ -1282,7 +1287,8 @@ async def edit( input_fidelity: Control how much effort the model will exert to match the style and features, especially facial features, of input images. This parameter is only supported - for `gpt-image-1`. Supports `high` and `low`. Defaults to `low`. + for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and + `low`. Defaults to `low`. mask: An additional image whose fully transparent areas (e.g. where alpha is zero) indicate where `image` should be edited. If there are multiple images provided, diff --git a/src/openai/resources/realtime/calls.py b/src/openai/resources/realtime/calls.py index 7dcea6b5cf..a8c4761717 100644 --- a/src/openai/resources/realtime/calls.py +++ b/src/openai/resources/realtime/calls.py @@ -123,6 +123,10 @@ def accept( "gpt-4o-realtime-preview-2025-06-03", "gpt-4o-mini-realtime-preview", "gpt-4o-mini-realtime-preview-2024-12-17", + "gpt-realtime-mini", + "gpt-realtime-mini-2025-10-06", + "gpt-audio-mini", + "gpt-audio-mini-2025-10-06", ], ] | Omit = omit, @@ -428,6 +432,10 @@ async def accept( "gpt-4o-realtime-preview-2025-06-03", "gpt-4o-mini-realtime-preview", "gpt-4o-mini-realtime-preview-2024-12-17", + "gpt-realtime-mini", + "gpt-realtime-mini-2025-10-06", + "gpt-audio-mini", + "gpt-audio-mini-2025-10-06", ], ] | Omit = omit, diff --git a/src/openai/resources/realtime/realtime.py b/src/openai/resources/realtime/realtime.py index 7b4486d502..bd4e1d9644 100644 --- a/src/openai/resources/realtime/realtime.py +++ b/src/openai/resources/realtime/realtime.py @@ -363,13 +363,14 @@ async def __aenter__(self) -> AsyncRealtimeConnection: extra_query = self.__extra_query await self.__client._refresh_api_key() auth_headers = self.__client.auth_headers + extra_query = self.__extra_query if self.__call_id is not omit: extra_query = {**extra_query, "call_id": self.__call_id} if is_async_azure_client(self.__client): model = self.__model if not model: raise OpenAIError("`model` is required for Azure Realtime API") - else: + else: url, auth_headers = await self.__client._configure_realtime(model, extra_query) else: url = self._prepare_url().copy_with( @@ -551,13 +552,14 @@ def __enter__(self) -> RealtimeConnection: extra_query = self.__extra_query self.__client._refresh_api_key() auth_headers = self.__client.auth_headers + extra_query = self.__extra_query if self.__call_id is not omit: extra_query = {**extra_query, "call_id": self.__call_id} if is_azure_client(self.__client): model = self.__model if not model: raise OpenAIError("`model` is required for Azure Realtime API") - else: + else: url, auth_headers = self.__client._configure_realtime(model, extra_query) else: url = self._prepare_url().copy_with( diff --git a/src/openai/resources/videos.py b/src/openai/resources/videos.py new file mode 100644 index 0000000000..4df5f02004 --- /dev/null +++ b/src/openai/resources/videos.py @@ -0,0 +1,847 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import TYPE_CHECKING, Mapping, cast +from typing_extensions import Literal, assert_never + +import httpx + +from .. import _legacy_response +from ..types import ( + VideoSize, + VideoModel, + VideoSeconds, + video_list_params, + video_remix_params, + video_create_params, + video_download_content_params, +) +from .._types import Body, Omit, Query, Headers, NotGiven, FileTypes, omit, not_given +from .._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform +from .._compat import cached_property +from .._resource import SyncAPIResource, AsyncAPIResource +from .._response import ( + StreamedBinaryAPIResponse, + AsyncStreamedBinaryAPIResponse, + to_streamed_response_wrapper, + async_to_streamed_response_wrapper, + to_custom_streamed_response_wrapper, + async_to_custom_streamed_response_wrapper, +) +from ..pagination import SyncConversationCursorPage, AsyncConversationCursorPage +from ..types.video import Video +from .._base_client import AsyncPaginator, make_request_options +from .._utils._utils import is_given +from ..types.video_size import VideoSize +from ..types.video_model import VideoModel +from ..types.video_seconds import VideoSeconds +from ..types.video_delete_response import VideoDeleteResponse + +__all__ = ["Videos", "AsyncVideos"] + + +class Videos(SyncAPIResource): + @cached_property + def with_raw_response(self) -> VideosWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return VideosWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> VideosWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return VideosWithStreamingResponse(self) + + def create( + self, + *, + prompt: str, + input_reference: FileTypes | Omit = omit, + model: VideoModel | Omit = omit, + seconds: VideoSeconds | Omit = omit, + size: VideoSize | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Video: + """ + Create a video + + Args: + prompt: Text prompt that describes the video to generate. + + input_reference: Optional image reference that guides generation. + + model: The video generation model to use. Defaults to `sora-2`. + + seconds: Clip duration in seconds. Defaults to 4 seconds. + + size: Output resolution formatted as width x height. Defaults to 720x1280. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + body = deepcopy_minimal( + { + "prompt": prompt, + "input_reference": input_reference, + "model": model, + "seconds": seconds, + "size": size, + } + ) + files = extract_files(cast(Mapping[str, object], body), paths=[["input_reference"]]) + if files: + # It should be noted that the actual Content-Type header that will be + # sent to the server will contain a `boundary` parameter, e.g. + # multipart/form-data; boundary=---abc-- + extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} + return self._post( + "/videos", + body=maybe_transform(body, video_create_params.VideoCreateParams), + files=files, + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Video, + ) + + def create_and_poll( + self, + *, + prompt: str, + input_reference: FileTypes | Omit = omit, + model: VideoModel | Omit = omit, + seconds: VideoSeconds | Omit = omit, + size: VideoSize | Omit = omit, + poll_interval_ms: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Video: + """Create a video and wait for it to be processed.""" + video = self.create( + model=model, + prompt=prompt, + input_reference=input_reference, + seconds=seconds, + size=size, + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + ) + + return self.poll( + video.id, + poll_interval_ms=poll_interval_ms, + ) + + def poll( + self, + video_id: str, + *, + poll_interval_ms: int | Omit = omit, + ) -> Video: + """Wait for the vector store file to finish processing. + + Note: this will return even if the file failed to process, you need to check + file.last_error and file.status to handle these cases + """ + headers: dict[str, str] = {"X-Stainless-Poll-Helper": "true"} + if is_given(poll_interval_ms): + headers["X-Stainless-Custom-Poll-Interval"] = str(poll_interval_ms) + + while True: + response = self.with_raw_response.retrieve( + video_id, + extra_headers=headers, + ) + + video = response.parse() + if video.status == "in_progress" or video.status == "queued": + if not is_given(poll_interval_ms): + from_header = response.headers.get("openai-poll-after-ms") + if from_header is not None: + poll_interval_ms = int(from_header) + else: + poll_interval_ms = 1000 + + self._sleep(poll_interval_ms / 1000) + elif video.status == "completed" or video.status == "failed": + return video + else: + if TYPE_CHECKING: # type: ignore[unreachable] + assert_never(video.status) + else: + return video + + def retrieve( + self, + video_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Video: + """ + Retrieve a video + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not video_id: + raise ValueError(f"Expected a non-empty value for `video_id` but received {video_id!r}") + return self._get( + f"/videos/{video_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Video, + ) + + def list( + self, + *, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncConversationCursorPage[Video]: + """ + List videos + + Args: + after: Identifier for the last item from the previous pagination request + + limit: Number of items to retrieve + + order: Sort order of results by timestamp. Use `asc` for ascending order or `desc` for + descending order. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/videos", + page=SyncConversationCursorPage[Video], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + video_list_params.VideoListParams, + ), + ), + model=Video, + ) + + def delete( + self, + video_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> VideoDeleteResponse: + """ + Delete a video + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not video_id: + raise ValueError(f"Expected a non-empty value for `video_id` but received {video_id!r}") + return self._delete( + f"/videos/{video_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=VideoDeleteResponse, + ) + + def download_content( + self, + video_id: str, + *, + variant: Literal["video", "thumbnail", "spritesheet"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> _legacy_response.HttpxBinaryResponseContent: + """Download video content + + Args: + variant: Which downloadable asset to return. + + Defaults to the MP4 video. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not video_id: + raise ValueError(f"Expected a non-empty value for `video_id` but received {video_id!r}") + extra_headers = {"Accept": "application/binary", **(extra_headers or {})} + return self._get( + f"/videos/{video_id}/content", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"variant": variant}, video_download_content_params.VideoDownloadContentParams), + ), + cast_to=_legacy_response.HttpxBinaryResponseContent, + ) + + def remix( + self, + video_id: str, + *, + prompt: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Video: + """ + Create a video remix + + Args: + prompt: Updated text prompt that directs the remix generation. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not video_id: + raise ValueError(f"Expected a non-empty value for `video_id` but received {video_id!r}") + return self._post( + f"/videos/{video_id}/remix", + body=maybe_transform({"prompt": prompt}, video_remix_params.VideoRemixParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Video, + ) + + +class AsyncVideos(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncVideosWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncVideosWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncVideosWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncVideosWithStreamingResponse(self) + + async def create( + self, + *, + prompt: str, + input_reference: FileTypes | Omit = omit, + model: VideoModel | Omit = omit, + seconds: VideoSeconds | Omit = omit, + size: VideoSize | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Video: + """ + Create a video + + Args: + prompt: Text prompt that describes the video to generate. + + input_reference: Optional image reference that guides generation. + + model: The video generation model to use. Defaults to `sora-2`. + + seconds: Clip duration in seconds. Defaults to 4 seconds. + + size: Output resolution formatted as width x height. Defaults to 720x1280. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + body = deepcopy_minimal( + { + "prompt": prompt, + "input_reference": input_reference, + "model": model, + "seconds": seconds, + "size": size, + } + ) + files = extract_files(cast(Mapping[str, object], body), paths=[["input_reference"]]) + if files: + # It should be noted that the actual Content-Type header that will be + # sent to the server will contain a `boundary` parameter, e.g. + # multipart/form-data; boundary=---abc-- + extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} + return await self._post( + "/videos", + body=await async_maybe_transform(body, video_create_params.VideoCreateParams), + files=files, + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Video, + ) + + async def create_and_poll( + self, + *, + prompt: str, + input_reference: FileTypes | Omit = omit, + model: VideoModel | Omit = omit, + seconds: VideoSeconds | Omit = omit, + size: VideoSize | Omit = omit, + poll_interval_ms: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Video: + """Create a video and wait for it to be processed.""" + video = await self.create( + model=model, + prompt=prompt, + input_reference=input_reference, + seconds=seconds, + size=size, + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + ) + + return await self.poll( + video.id, + poll_interval_ms=poll_interval_ms, + ) + + async def poll( + self, + video_id: str, + *, + poll_interval_ms: int | Omit = omit, + ) -> Video: + """Wait for the vector store file to finish processing. + + Note: this will return even if the file failed to process, you need to check + file.last_error and file.status to handle these cases + """ + headers: dict[str, str] = {"X-Stainless-Poll-Helper": "true"} + if is_given(poll_interval_ms): + headers["X-Stainless-Custom-Poll-Interval"] = str(poll_interval_ms) + + while True: + response = await self.with_raw_response.retrieve( + video_id, + extra_headers=headers, + ) + + video = response.parse() + if video.status == "in_progress" or video.status == "queued": + if not is_given(poll_interval_ms): + from_header = response.headers.get("openai-poll-after-ms") + if from_header is not None: + poll_interval_ms = int(from_header) + else: + poll_interval_ms = 1000 + + await self._sleep(poll_interval_ms / 1000) + elif video.status == "completed" or video.status == "failed": + return video + else: + if TYPE_CHECKING: # type: ignore[unreachable] + assert_never(video.status) + else: + return video + + async def retrieve( + self, + video_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Video: + """ + Retrieve a video + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not video_id: + raise ValueError(f"Expected a non-empty value for `video_id` but received {video_id!r}") + return await self._get( + f"/videos/{video_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Video, + ) + + def list( + self, + *, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Video, AsyncConversationCursorPage[Video]]: + """ + List videos + + Args: + after: Identifier for the last item from the previous pagination request + + limit: Number of items to retrieve + + order: Sort order of results by timestamp. Use `asc` for ascending order or `desc` for + descending order. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/videos", + page=AsyncConversationCursorPage[Video], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + video_list_params.VideoListParams, + ), + ), + model=Video, + ) + + async def delete( + self, + video_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> VideoDeleteResponse: + """ + Delete a video + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not video_id: + raise ValueError(f"Expected a non-empty value for `video_id` but received {video_id!r}") + return await self._delete( + f"/videos/{video_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=VideoDeleteResponse, + ) + + async def download_content( + self, + video_id: str, + *, + variant: Literal["video", "thumbnail", "spritesheet"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> _legacy_response.HttpxBinaryResponseContent: + """Download video content + + Args: + variant: Which downloadable asset to return. + + Defaults to the MP4 video. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not video_id: + raise ValueError(f"Expected a non-empty value for `video_id` but received {video_id!r}") + extra_headers = {"Accept": "application/binary", **(extra_headers or {})} + return await self._get( + f"/videos/{video_id}/content", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"variant": variant}, video_download_content_params.VideoDownloadContentParams + ), + ), + cast_to=_legacy_response.HttpxBinaryResponseContent, + ) + + async def remix( + self, + video_id: str, + *, + prompt: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Video: + """ + Create a video remix + + Args: + prompt: Updated text prompt that directs the remix generation. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not video_id: + raise ValueError(f"Expected a non-empty value for `video_id` but received {video_id!r}") + return await self._post( + f"/videos/{video_id}/remix", + body=await async_maybe_transform({"prompt": prompt}, video_remix_params.VideoRemixParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Video, + ) + + +class VideosWithRawResponse: + def __init__(self, videos: Videos) -> None: + self._videos = videos + + self.create = _legacy_response.to_raw_response_wrapper( + videos.create, + ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + videos.retrieve, + ) + self.list = _legacy_response.to_raw_response_wrapper( + videos.list, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + videos.delete, + ) + self.download_content = _legacy_response.to_raw_response_wrapper( + videos.download_content, + ) + self.remix = _legacy_response.to_raw_response_wrapper( + videos.remix, + ) + + +class AsyncVideosWithRawResponse: + def __init__(self, videos: AsyncVideos) -> None: + self._videos = videos + + self.create = _legacy_response.async_to_raw_response_wrapper( + videos.create, + ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + videos.retrieve, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + videos.list, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + videos.delete, + ) + self.download_content = _legacy_response.async_to_raw_response_wrapper( + videos.download_content, + ) + self.remix = _legacy_response.async_to_raw_response_wrapper( + videos.remix, + ) + + +class VideosWithStreamingResponse: + def __init__(self, videos: Videos) -> None: + self._videos = videos + + self.create = to_streamed_response_wrapper( + videos.create, + ) + self.retrieve = to_streamed_response_wrapper( + videos.retrieve, + ) + self.list = to_streamed_response_wrapper( + videos.list, + ) + self.delete = to_streamed_response_wrapper( + videos.delete, + ) + self.download_content = to_custom_streamed_response_wrapper( + videos.download_content, + StreamedBinaryAPIResponse, + ) + self.remix = to_streamed_response_wrapper( + videos.remix, + ) + + +class AsyncVideosWithStreamingResponse: + def __init__(self, videos: AsyncVideos) -> None: + self._videos = videos + + self.create = async_to_streamed_response_wrapper( + videos.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + videos.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + videos.list, + ) + self.delete = async_to_streamed_response_wrapper( + videos.delete, + ) + self.download_content = async_to_custom_streamed_response_wrapper( + videos.download_content, + AsyncStreamedBinaryAPIResponse, + ) + self.remix = async_to_streamed_response_wrapper( + videos.remix, + ) diff --git a/src/openai/types/__init__.py b/src/openai/types/__init__.py index 87e4520461..a98ca16ee9 100644 --- a/src/openai/types/__init__.py +++ b/src/openai/types/__init__.py @@ -5,6 +5,7 @@ from .batch import Batch as Batch from .image import Image as Image from .model import Model as Model +from .video import Video as Video from .shared import ( Metadata as Metadata, AllModels as AllModels, @@ -29,16 +30,19 @@ from .chat_model import ChatModel as ChatModel from .completion import Completion as Completion from .moderation import Moderation as Moderation +from .video_size import VideoSize as VideoSize from .audio_model import AudioModel as AudioModel from .batch_error import BatchError as BatchError from .batch_usage import BatchUsage as BatchUsage from .file_object import FileObject as FileObject from .image_model import ImageModel as ImageModel +from .video_model import VideoModel as VideoModel from .file_content import FileContent as FileContent from .file_deleted import FileDeleted as FileDeleted from .file_purpose import FilePurpose as FilePurpose from .vector_store import VectorStore as VectorStore from .model_deleted import ModelDeleted as ModelDeleted +from .video_seconds import VideoSeconds as VideoSeconds from .embedding_model import EmbeddingModel as EmbeddingModel from .images_response import ImagesResponse as ImagesResponse from .completion_usage import CompletionUsage as CompletionUsage @@ -48,11 +52,15 @@ from .batch_list_params import BatchListParams as BatchListParams from .completion_choice import CompletionChoice as CompletionChoice from .image_edit_params import ImageEditParams as ImageEditParams +from .video_list_params import VideoListParams as VideoListParams from .eval_create_params import EvalCreateParams as EvalCreateParams from .eval_list_response import EvalListResponse as EvalListResponse from .eval_update_params import EvalUpdateParams as EvalUpdateParams from .file_create_params import FileCreateParams as FileCreateParams +from .video_create_error import VideoCreateError as VideoCreateError +from .video_remix_params import VideoRemixParams as VideoRemixParams from .batch_create_params import BatchCreateParams as BatchCreateParams +from .video_create_params import VideoCreateParams as VideoCreateParams from .batch_request_counts import BatchRequestCounts as BatchRequestCounts from .eval_create_response import EvalCreateResponse as EvalCreateResponse from .eval_delete_response import EvalDeleteResponse as EvalDeleteResponse @@ -62,6 +70,7 @@ from .audio_response_format import AudioResponseFormat as AudioResponseFormat from .container_list_params import ContainerListParams as ContainerListParams from .image_generate_params import ImageGenerateParams as ImageGenerateParams +from .video_delete_response import VideoDeleteResponse as VideoDeleteResponse from .eval_retrieve_response import EvalRetrieveResponse as EvalRetrieveResponse from .file_chunking_strategy import FileChunkingStrategy as FileChunkingStrategy from .image_gen_stream_event import ImageGenStreamEvent as ImageGenStreamEvent @@ -89,6 +98,7 @@ from .image_create_variation_params import ImageCreateVariationParams as ImageCreateVariationParams from .image_gen_partial_image_event import ImageGenPartialImageEvent as ImageGenPartialImageEvent from .static_file_chunking_strategy import StaticFileChunkingStrategy as StaticFileChunkingStrategy +from .video_download_content_params import VideoDownloadContentParams as VideoDownloadContentParams from .eval_custom_data_source_config import EvalCustomDataSourceConfig as EvalCustomDataSourceConfig from .image_edit_partial_image_event import ImageEditPartialImageEvent as ImageEditPartialImageEvent from .moderation_image_url_input_param import ModerationImageURLInputParam as ModerationImageURLInputParam diff --git a/src/openai/types/beta/__init__.py b/src/openai/types/beta/__init__.py index 5ba3eadf3c..9ef6283864 100644 --- a/src/openai/types/beta/__init__.py +++ b/src/openai/types/beta/__init__.py @@ -4,9 +4,12 @@ from .thread import Thread as Thread from .assistant import Assistant as Assistant +from .file_part import FilePart as FilePart +from .image_part import ImagePart as ImagePart from .function_tool import FunctionTool as FunctionTool from .assistant_tool import AssistantTool as AssistantTool from .thread_deleted import ThreadDeleted as ThreadDeleted +from .chatkit_workflow import ChatKitWorkflow as ChatKitWorkflow from .file_search_tool import FileSearchTool as FileSearchTool from .assistant_deleted import AssistantDeleted as AssistantDeleted from .function_tool_param import FunctionToolParam as FunctionToolParam @@ -20,9 +23,11 @@ from .file_search_tool_param import FileSearchToolParam as FileSearchToolParam from .assistant_create_params import AssistantCreateParams as AssistantCreateParams from .assistant_update_params import AssistantUpdateParams as AssistantUpdateParams +from .chatkit_upload_file_params import ChatKitUploadFileParams as ChatKitUploadFileParams from .assistant_tool_choice_param import AssistantToolChoiceParam as AssistantToolChoiceParam from .code_interpreter_tool_param import CodeInterpreterToolParam as CodeInterpreterToolParam from .assistant_tool_choice_option import AssistantToolChoiceOption as AssistantToolChoiceOption +from .chatkit_upload_file_response import ChatKitUploadFileResponse as ChatKitUploadFileResponse from .thread_create_and_run_params import ThreadCreateAndRunParams as ThreadCreateAndRunParams from .assistant_tool_choice_function import AssistantToolChoiceFunction as AssistantToolChoiceFunction from .assistant_response_format_option import AssistantResponseFormatOption as AssistantResponseFormatOption diff --git a/src/openai/types/beta/chatkit/__init__.py b/src/openai/types/beta/chatkit/__init__.py new file mode 100644 index 0000000000..eafed9dd99 --- /dev/null +++ b/src/openai/types/beta/chatkit/__init__.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .chat_session import ChatSession as ChatSession +from .chatkit_thread import ChatKitThread as ChatKitThread +from .chatkit_attachment import ChatKitAttachment as ChatKitAttachment +from .thread_list_params import ThreadListParams as ThreadListParams +from .chat_session_status import ChatSessionStatus as ChatSessionStatus +from .chatkit_widget_item import ChatKitWidgetItem as ChatKitWidgetItem +from .chat_session_history import ChatSessionHistory as ChatSessionHistory +from .session_create_params import SessionCreateParams as SessionCreateParams +from .thread_delete_response import ThreadDeleteResponse as ThreadDeleteResponse +from .chat_session_file_upload import ChatSessionFileUpload as ChatSessionFileUpload +from .chat_session_rate_limits import ChatSessionRateLimits as ChatSessionRateLimits +from .chatkit_thread_item_list import ChatKitThreadItemList as ChatKitThreadItemList +from .thread_list_items_params import ThreadListItemsParams as ThreadListItemsParams +from .chat_session_workflow_param import ChatSessionWorkflowParam as ChatSessionWorkflowParam +from .chatkit_response_output_text import ChatKitResponseOutputText as ChatKitResponseOutputText +from .chat_session_rate_limits_param import ChatSessionRateLimitsParam as ChatSessionRateLimitsParam +from .chat_session_expires_after_param import ChatSessionExpiresAfterParam as ChatSessionExpiresAfterParam +from .chatkit_thread_user_message_item import ChatKitThreadUserMessageItem as ChatKitThreadUserMessageItem +from .chat_session_chatkit_configuration import ChatSessionChatKitConfiguration as ChatSessionChatKitConfiguration +from .chat_session_automatic_thread_titling import ( + ChatSessionAutomaticThreadTitling as ChatSessionAutomaticThreadTitling, +) +from .chatkit_thread_assistant_message_item import ( + ChatKitThreadAssistantMessageItem as ChatKitThreadAssistantMessageItem, +) +from .chat_session_chatkit_configuration_param import ( + ChatSessionChatKitConfigurationParam as ChatSessionChatKitConfigurationParam, +) diff --git a/src/openai/types/beta/chatkit/chat_session.py b/src/openai/types/beta/chatkit/chat_session.py new file mode 100644 index 0000000000..82baea211c --- /dev/null +++ b/src/openai/types/beta/chatkit/chat_session.py @@ -0,0 +1,43 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel +from ..chatkit_workflow import ChatKitWorkflow +from .chat_session_status import ChatSessionStatus +from .chat_session_rate_limits import ChatSessionRateLimits +from .chat_session_chatkit_configuration import ChatSessionChatKitConfiguration + +__all__ = ["ChatSession"] + + +class ChatSession(BaseModel): + id: str + """Identifier for the ChatKit session.""" + + chatkit_configuration: ChatSessionChatKitConfiguration + """Resolved ChatKit feature configuration for the session.""" + + client_secret: str + """Ephemeral client secret that authenticates session requests.""" + + expires_at: int + """Unix timestamp (in seconds) for when the session expires.""" + + max_requests_per_1_minute: int + """Convenience copy of the per-minute request limit.""" + + object: Literal["chatkit.session"] + """Type discriminator that is always `chatkit.session`.""" + + rate_limits: ChatSessionRateLimits + """Resolved rate limit values.""" + + status: ChatSessionStatus + """Current lifecycle state of the session.""" + + user: str + """User identifier associated with the session.""" + + workflow: ChatKitWorkflow + """Workflow metadata for the session.""" diff --git a/src/openai/types/beta/chatkit/chat_session_automatic_thread_titling.py b/src/openai/types/beta/chatkit/chat_session_automatic_thread_titling.py new file mode 100644 index 0000000000..4fa96a4433 --- /dev/null +++ b/src/openai/types/beta/chatkit/chat_session_automatic_thread_titling.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ...._models import BaseModel + +__all__ = ["ChatSessionAutomaticThreadTitling"] + + +class ChatSessionAutomaticThreadTitling(BaseModel): + enabled: bool + """Whether automatic thread titling is enabled.""" diff --git a/src/openai/types/beta/chatkit/chat_session_chatkit_configuration.py b/src/openai/types/beta/chatkit/chat_session_chatkit_configuration.py new file mode 100644 index 0000000000..6205b172cf --- /dev/null +++ b/src/openai/types/beta/chatkit/chat_session_chatkit_configuration.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ...._models import BaseModel +from .chat_session_history import ChatSessionHistory +from .chat_session_file_upload import ChatSessionFileUpload +from .chat_session_automatic_thread_titling import ChatSessionAutomaticThreadTitling + +__all__ = ["ChatSessionChatKitConfiguration"] + + +class ChatSessionChatKitConfiguration(BaseModel): + automatic_thread_titling: ChatSessionAutomaticThreadTitling + """Automatic thread titling preferences.""" + + file_upload: ChatSessionFileUpload + """Upload settings for the session.""" + + history: ChatSessionHistory + """History retention configuration.""" diff --git a/src/openai/types/beta/chatkit/chat_session_chatkit_configuration_param.py b/src/openai/types/beta/chatkit/chat_session_chatkit_configuration_param.py new file mode 100644 index 0000000000..0a5ae80a76 --- /dev/null +++ b/src/openai/types/beta/chatkit/chat_session_chatkit_configuration_param.py @@ -0,0 +1,59 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["ChatSessionChatKitConfigurationParam", "AutomaticThreadTitling", "FileUpload", "History"] + + +class AutomaticThreadTitling(TypedDict, total=False): + enabled: bool + """Enable automatic thread title generation. Defaults to true.""" + + +class FileUpload(TypedDict, total=False): + enabled: bool + """Enable uploads for this session. Defaults to false.""" + + max_file_size: int + """Maximum size in megabytes for each uploaded file. + + Defaults to 512 MB, which is the maximum allowable size. + """ + + max_files: int + """Maximum number of files that can be uploaded to the session. Defaults to 10.""" + + +class History(TypedDict, total=False): + enabled: bool + """Enables chat users to access previous ChatKit threads. Defaults to true.""" + + recent_threads: int + """Number of recent ChatKit threads users have access to. + + Defaults to unlimited when unset. + """ + + +class ChatSessionChatKitConfigurationParam(TypedDict, total=False): + automatic_thread_titling: AutomaticThreadTitling + """Configuration for automatic thread titling. + + When omitted, automatic thread titling is enabled by default. + """ + + file_upload: FileUpload + """Configuration for upload enablement and limits. + + When omitted, uploads are disabled by default (max_files 10, max_file_size 512 + MB). + """ + + history: History + """Configuration for chat history retention. + + When omitted, history is enabled by default with no limit on recent_threads + (null). + """ diff --git a/src/openai/types/beta/chatkit/chat_session_expires_after_param.py b/src/openai/types/beta/chatkit/chat_session_expires_after_param.py new file mode 100644 index 0000000000..ceb5a984c5 --- /dev/null +++ b/src/openai/types/beta/chatkit/chat_session_expires_after_param.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ChatSessionExpiresAfterParam"] + + +class ChatSessionExpiresAfterParam(TypedDict, total=False): + anchor: Required[Literal["created_at"]] + """Base timestamp used to calculate expiration. Currently fixed to `created_at`.""" + + seconds: Required[int] + """Number of seconds after the anchor when the session expires.""" diff --git a/src/openai/types/beta/chatkit/chat_session_file_upload.py b/src/openai/types/beta/chatkit/chat_session_file_upload.py new file mode 100644 index 0000000000..c63c7a0149 --- /dev/null +++ b/src/openai/types/beta/chatkit/chat_session_file_upload.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ...._models import BaseModel + +__all__ = ["ChatSessionFileUpload"] + + +class ChatSessionFileUpload(BaseModel): + enabled: bool + """Indicates if uploads are enabled for the session.""" + + max_file_size: Optional[int] = None + """Maximum upload size in megabytes.""" + + max_files: Optional[int] = None + """Maximum number of uploads allowed during the session.""" diff --git a/src/openai/types/beta/chatkit/chat_session_history.py b/src/openai/types/beta/chatkit/chat_session_history.py new file mode 100644 index 0000000000..66ebe00877 --- /dev/null +++ b/src/openai/types/beta/chatkit/chat_session_history.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ...._models import BaseModel + +__all__ = ["ChatSessionHistory"] + + +class ChatSessionHistory(BaseModel): + enabled: bool + """Indicates if chat history is persisted for the session.""" + + recent_threads: Optional[int] = None + """Number of prior threads surfaced in history views. + + Defaults to null when all history is retained. + """ diff --git a/src/openai/types/beta/chatkit/chat_session_rate_limits.py b/src/openai/types/beta/chatkit/chat_session_rate_limits.py new file mode 100644 index 0000000000..392225e347 --- /dev/null +++ b/src/openai/types/beta/chatkit/chat_session_rate_limits.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ...._models import BaseModel + +__all__ = ["ChatSessionRateLimits"] + + +class ChatSessionRateLimits(BaseModel): + max_requests_per_1_minute: int + """Maximum allowed requests per one-minute window.""" diff --git a/src/openai/types/beta/chatkit/chat_session_rate_limits_param.py b/src/openai/types/beta/chatkit/chat_session_rate_limits_param.py new file mode 100644 index 0000000000..7894c06484 --- /dev/null +++ b/src/openai/types/beta/chatkit/chat_session_rate_limits_param.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["ChatSessionRateLimitsParam"] + + +class ChatSessionRateLimitsParam(TypedDict, total=False): + max_requests_per_1_minute: int + """Maximum number of requests allowed per minute for the session. Defaults to 10.""" diff --git a/src/openai/types/beta/chatkit/chat_session_status.py b/src/openai/types/beta/chatkit/chat_session_status.py new file mode 100644 index 0000000000..a483099c6c --- /dev/null +++ b/src/openai/types/beta/chatkit/chat_session_status.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["ChatSessionStatus"] + +ChatSessionStatus: TypeAlias = Literal["active", "expired", "cancelled"] diff --git a/src/openai/types/beta/chatkit/chat_session_workflow_param.py b/src/openai/types/beta/chatkit/chat_session_workflow_param.py new file mode 100644 index 0000000000..5542922102 --- /dev/null +++ b/src/openai/types/beta/chatkit/chat_session_workflow_param.py @@ -0,0 +1,34 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union +from typing_extensions import Required, TypedDict + +__all__ = ["ChatSessionWorkflowParam", "Tracing"] + + +class Tracing(TypedDict, total=False): + enabled: bool + """Whether tracing is enabled during the session. Defaults to true.""" + + +class ChatSessionWorkflowParam(TypedDict, total=False): + id: Required[str] + """Identifier for the workflow invoked by the session.""" + + state_variables: Dict[str, Union[str, bool, float]] + """State variables forwarded to the workflow. + + Keys may be up to 64 characters, values must be primitive types, and the map + defaults to an empty object. + """ + + tracing: Tracing + """Optional tracing overrides for the workflow invocation. + + When omitted, tracing is enabled by default. + """ + + version: str + """Specific workflow version to run. Defaults to the latest deployed version.""" diff --git a/src/openai/types/beta/chatkit/chatkit_attachment.py b/src/openai/types/beta/chatkit/chatkit_attachment.py new file mode 100644 index 0000000000..8d8ad3e128 --- /dev/null +++ b/src/openai/types/beta/chatkit/chatkit_attachment.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["ChatKitAttachment"] + + +class ChatKitAttachment(BaseModel): + id: str + """Identifier for the attachment.""" + + mime_type: str + """MIME type of the attachment.""" + + name: str + """Original display name for the attachment.""" + + preview_url: Optional[str] = None + """Preview URL for rendering the attachment inline.""" + + type: Literal["image", "file"] + """Attachment discriminator.""" diff --git a/src/openai/types/beta/chatkit/chatkit_response_output_text.py b/src/openai/types/beta/chatkit/chatkit_response_output_text.py new file mode 100644 index 0000000000..116b797ec2 --- /dev/null +++ b/src/openai/types/beta/chatkit/chatkit_response_output_text.py @@ -0,0 +1,62 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union +from typing_extensions import Literal, Annotated, TypeAlias + +from ...._utils import PropertyInfo +from ...._models import BaseModel + +__all__ = [ + "ChatKitResponseOutputText", + "Annotation", + "AnnotationFile", + "AnnotationFileSource", + "AnnotationURL", + "AnnotationURLSource", +] + + +class AnnotationFileSource(BaseModel): + filename: str + """Filename referenced by the annotation.""" + + type: Literal["file"] + """Type discriminator that is always `file`.""" + + +class AnnotationFile(BaseModel): + source: AnnotationFileSource + """File attachment referenced by the annotation.""" + + type: Literal["file"] + """Type discriminator that is always `file` for this annotation.""" + + +class AnnotationURLSource(BaseModel): + type: Literal["url"] + """Type discriminator that is always `url`.""" + + url: str + """URL referenced by the annotation.""" + + +class AnnotationURL(BaseModel): + source: AnnotationURLSource + """URL referenced by the annotation.""" + + type: Literal["url"] + """Type discriminator that is always `url` for this annotation.""" + + +Annotation: TypeAlias = Annotated[Union[AnnotationFile, AnnotationURL], PropertyInfo(discriminator="type")] + + +class ChatKitResponseOutputText(BaseModel): + annotations: List[Annotation] + """Ordered list of annotations attached to the response text.""" + + text: str + """Assistant generated text.""" + + type: Literal["output_text"] + """Type discriminator that is always `output_text`.""" diff --git a/src/openai/types/beta/chatkit/chatkit_thread.py b/src/openai/types/beta/chatkit/chatkit_thread.py new file mode 100644 index 0000000000..abd1a9ea01 --- /dev/null +++ b/src/openai/types/beta/chatkit/chatkit_thread.py @@ -0,0 +1,56 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ...._utils import PropertyInfo +from ...._models import BaseModel + +__all__ = ["ChatKitThread", "Status", "StatusActive", "StatusLocked", "StatusClosed"] + + +class StatusActive(BaseModel): + type: Literal["active"] + """Status discriminator that is always `active`.""" + + +class StatusLocked(BaseModel): + reason: Optional[str] = None + """Reason that the thread was locked. Defaults to null when no reason is recorded.""" + + type: Literal["locked"] + """Status discriminator that is always `locked`.""" + + +class StatusClosed(BaseModel): + reason: Optional[str] = None + """Reason that the thread was closed. Defaults to null when no reason is recorded.""" + + type: Literal["closed"] + """Status discriminator that is always `closed`.""" + + +Status: TypeAlias = Annotated[Union[StatusActive, StatusLocked, StatusClosed], PropertyInfo(discriminator="type")] + + +class ChatKitThread(BaseModel): + id: str + """Identifier of the thread.""" + + created_at: int + """Unix timestamp (in seconds) for when the thread was created.""" + + object: Literal["chatkit.thread"] + """Type discriminator that is always `chatkit.thread`.""" + + status: Status + """Current status for the thread. Defaults to `active` for newly created threads.""" + + title: Optional[str] = None + """Optional human-readable title for the thread. + + Defaults to null when no title has been generated. + """ + + user: str + """Free-form string that identifies your end user who owns the thread.""" diff --git a/src/openai/types/beta/chatkit/chatkit_thread_assistant_message_item.py b/src/openai/types/beta/chatkit/chatkit_thread_assistant_message_item.py new file mode 100644 index 0000000000..f4afd053b6 --- /dev/null +++ b/src/openai/types/beta/chatkit/chatkit_thread_assistant_message_item.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import Literal + +from ...._models import BaseModel +from .chatkit_response_output_text import ChatKitResponseOutputText + +__all__ = ["ChatKitThreadAssistantMessageItem"] + + +class ChatKitThreadAssistantMessageItem(BaseModel): + id: str + """Identifier of the thread item.""" + + content: List[ChatKitResponseOutputText] + """Ordered assistant response segments.""" + + created_at: int + """Unix timestamp (in seconds) for when the item was created.""" + + object: Literal["chatkit.thread_item"] + """Type discriminator that is always `chatkit.thread_item`.""" + + thread_id: str + """Identifier of the parent thread.""" + + type: Literal["chatkit.assistant_message"] + """Type discriminator that is always `chatkit.assistant_message`.""" diff --git a/src/openai/types/beta/chatkit/chatkit_thread_item_list.py b/src/openai/types/beta/chatkit/chatkit_thread_item_list.py new file mode 100644 index 0000000000..173bd15055 --- /dev/null +++ b/src/openai/types/beta/chatkit/chatkit_thread_item_list.py @@ -0,0 +1,144 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ...._utils import PropertyInfo +from ...._models import BaseModel +from .chatkit_widget_item import ChatKitWidgetItem +from .chatkit_thread_user_message_item import ChatKitThreadUserMessageItem +from .chatkit_thread_assistant_message_item import ChatKitThreadAssistantMessageItem + +__all__ = [ + "ChatKitThreadItemList", + "Data", + "DataChatKitClientToolCall", + "DataChatKitTask", + "DataChatKitTaskGroup", + "DataChatKitTaskGroupTask", +] + + +class DataChatKitClientToolCall(BaseModel): + id: str + """Identifier of the thread item.""" + + arguments: str + """JSON-encoded arguments that were sent to the tool.""" + + call_id: str + """Identifier for the client tool call.""" + + created_at: int + """Unix timestamp (in seconds) for when the item was created.""" + + name: str + """Tool name that was invoked.""" + + object: Literal["chatkit.thread_item"] + """Type discriminator that is always `chatkit.thread_item`.""" + + output: Optional[str] = None + """JSON-encoded output captured from the tool. + + Defaults to null while execution is in progress. + """ + + status: Literal["in_progress", "completed"] + """Execution status for the tool call.""" + + thread_id: str + """Identifier of the parent thread.""" + + type: Literal["chatkit.client_tool_call"] + """Type discriminator that is always `chatkit.client_tool_call`.""" + + +class DataChatKitTask(BaseModel): + id: str + """Identifier of the thread item.""" + + created_at: int + """Unix timestamp (in seconds) for when the item was created.""" + + heading: Optional[str] = None + """Optional heading for the task. Defaults to null when not provided.""" + + object: Literal["chatkit.thread_item"] + """Type discriminator that is always `chatkit.thread_item`.""" + + summary: Optional[str] = None + """Optional summary that describes the task. Defaults to null when omitted.""" + + task_type: Literal["custom", "thought"] + """Subtype for the task.""" + + thread_id: str + """Identifier of the parent thread.""" + + type: Literal["chatkit.task"] + """Type discriminator that is always `chatkit.task`.""" + + +class DataChatKitTaskGroupTask(BaseModel): + heading: Optional[str] = None + """Optional heading for the grouped task. Defaults to null when not provided.""" + + summary: Optional[str] = None + """Optional summary that describes the grouped task. + + Defaults to null when omitted. + """ + + type: Literal["custom", "thought"] + """Subtype for the grouped task.""" + + +class DataChatKitTaskGroup(BaseModel): + id: str + """Identifier of the thread item.""" + + created_at: int + """Unix timestamp (in seconds) for when the item was created.""" + + object: Literal["chatkit.thread_item"] + """Type discriminator that is always `chatkit.thread_item`.""" + + tasks: List[DataChatKitTaskGroupTask] + """Tasks included in the group.""" + + thread_id: str + """Identifier of the parent thread.""" + + type: Literal["chatkit.task_group"] + """Type discriminator that is always `chatkit.task_group`.""" + + +Data: TypeAlias = Annotated[ + Union[ + ChatKitThreadUserMessageItem, + ChatKitThreadAssistantMessageItem, + ChatKitWidgetItem, + DataChatKitClientToolCall, + DataChatKitTask, + DataChatKitTaskGroup, + ], + PropertyInfo(discriminator="type"), +] + + +class ChatKitThreadItemList(BaseModel): + data: List[Data] + """A list of items""" + + first_id: Optional[str] = None + """The ID of the first item in the list.""" + + has_more: bool + """Whether there are more items available.""" + + last_id: Optional[str] = None + """The ID of the last item in the list.""" + + object: Literal["list"] + """The type of object returned, must be `list`.""" diff --git a/src/openai/types/beta/chatkit/chatkit_thread_user_message_item.py b/src/openai/types/beta/chatkit/chatkit_thread_user_message_item.py new file mode 100644 index 0000000000..233d07232f --- /dev/null +++ b/src/openai/types/beta/chatkit/chatkit_thread_user_message_item.py @@ -0,0 +1,77 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ...._utils import PropertyInfo +from ...._models import BaseModel +from .chatkit_attachment import ChatKitAttachment + +__all__ = [ + "ChatKitThreadUserMessageItem", + "Content", + "ContentInputText", + "ContentQuotedText", + "InferenceOptions", + "InferenceOptionsToolChoice", +] + + +class ContentInputText(BaseModel): + text: str + """Plain-text content supplied by the user.""" + + type: Literal["input_text"] + """Type discriminator that is always `input_text`.""" + + +class ContentQuotedText(BaseModel): + text: str + """Quoted text content.""" + + type: Literal["quoted_text"] + """Type discriminator that is always `quoted_text`.""" + + +Content: TypeAlias = Annotated[Union[ContentInputText, ContentQuotedText], PropertyInfo(discriminator="type")] + + +class InferenceOptionsToolChoice(BaseModel): + id: str + """Identifier of the requested tool.""" + + +class InferenceOptions(BaseModel): + model: Optional[str] = None + """Model name that generated the response. + + Defaults to null when using the session default. + """ + + tool_choice: Optional[InferenceOptionsToolChoice] = None + """Preferred tool to invoke. Defaults to null when ChatKit should auto-select.""" + + +class ChatKitThreadUserMessageItem(BaseModel): + id: str + """Identifier of the thread item.""" + + attachments: List[ChatKitAttachment] + """Attachments associated with the user message. Defaults to an empty list.""" + + content: List[Content] + """Ordered content elements supplied by the user.""" + + created_at: int + """Unix timestamp (in seconds) for when the item was created.""" + + inference_options: Optional[InferenceOptions] = None + """Inference overrides applied to the message. Defaults to null when unset.""" + + object: Literal["chatkit.thread_item"] + """Type discriminator that is always `chatkit.thread_item`.""" + + thread_id: str + """Identifier of the parent thread.""" + + type: Literal["chatkit.user_message"] diff --git a/src/openai/types/beta/chatkit/chatkit_widget_item.py b/src/openai/types/beta/chatkit/chatkit_widget_item.py new file mode 100644 index 0000000000..c7f182259a --- /dev/null +++ b/src/openai/types/beta/chatkit/chatkit_widget_item.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["ChatKitWidgetItem"] + + +class ChatKitWidgetItem(BaseModel): + id: str + """Identifier of the thread item.""" + + created_at: int + """Unix timestamp (in seconds) for when the item was created.""" + + object: Literal["chatkit.thread_item"] + """Type discriminator that is always `chatkit.thread_item`.""" + + thread_id: str + """Identifier of the parent thread.""" + + type: Literal["chatkit.widget"] + """Type discriminator that is always `chatkit.widget`.""" + + widget: str + """Serialized widget payload rendered in the UI.""" diff --git a/src/openai/types/beta/chatkit/session_create_params.py b/src/openai/types/beta/chatkit/session_create_params.py new file mode 100644 index 0000000000..1803d18cf6 --- /dev/null +++ b/src/openai/types/beta/chatkit/session_create_params.py @@ -0,0 +1,35 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +from .chat_session_workflow_param import ChatSessionWorkflowParam +from .chat_session_rate_limits_param import ChatSessionRateLimitsParam +from .chat_session_expires_after_param import ChatSessionExpiresAfterParam +from .chat_session_chatkit_configuration_param import ChatSessionChatKitConfigurationParam + +__all__ = ["SessionCreateParams"] + + +class SessionCreateParams(TypedDict, total=False): + user: Required[str] + """ + A free-form string that identifies your end user; ensures this Session can + access other objects that have the same `user` scope. + """ + + workflow: Required[ChatSessionWorkflowParam] + """Workflow that powers the session.""" + + chatkit_configuration: ChatSessionChatKitConfigurationParam + """Optional overrides for ChatKit runtime configuration features""" + + expires_after: ChatSessionExpiresAfterParam + """Optional override for session expiration timing in seconds from creation. + + Defaults to 10 minutes. + """ + + rate_limits: ChatSessionRateLimitsParam + """Optional override for per-minute request limits. When omitted, defaults to 10.""" diff --git a/src/openai/types/beta/chatkit/thread_delete_response.py b/src/openai/types/beta/chatkit/thread_delete_response.py new file mode 100644 index 0000000000..03fdec9c2c --- /dev/null +++ b/src/openai/types/beta/chatkit/thread_delete_response.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["ThreadDeleteResponse"] + + +class ThreadDeleteResponse(BaseModel): + id: str + """Identifier of the deleted thread.""" + + deleted: bool + """Indicates that the thread has been deleted.""" + + object: Literal["chatkit.thread.deleted"] + """Type discriminator that is always `chatkit.thread.deleted`.""" diff --git a/src/openai/types/beta/chatkit/thread_list_items_params.py b/src/openai/types/beta/chatkit/thread_list_items_params.py new file mode 100644 index 0000000000..95c959d719 --- /dev/null +++ b/src/openai/types/beta/chatkit/thread_list_items_params.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["ThreadListItemsParams"] + + +class ThreadListItemsParams(TypedDict, total=False): + after: str + """List items created after this thread item ID. + + Defaults to null for the first page. + """ + + before: str + """List items created before this thread item ID. + + Defaults to null for the newest results. + """ + + limit: int + """Maximum number of thread items to return. Defaults to 20.""" + + order: Literal["asc", "desc"] + """Sort order for results by creation time. Defaults to `desc`.""" diff --git a/src/openai/types/beta/chatkit/thread_list_params.py b/src/openai/types/beta/chatkit/thread_list_params.py new file mode 100644 index 0000000000..bb759c7ea3 --- /dev/null +++ b/src/openai/types/beta/chatkit/thread_list_params.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["ThreadListParams"] + + +class ThreadListParams(TypedDict, total=False): + after: str + """List items created after this thread item ID. + + Defaults to null for the first page. + """ + + before: str + """List items created before this thread item ID. + + Defaults to null for the newest results. + """ + + limit: int + """Maximum number of thread items to return. Defaults to 20.""" + + order: Literal["asc", "desc"] + """Sort order for results by creation time. Defaults to `desc`.""" + + user: str + """Filter threads that belong to this user identifier. + + Defaults to null to return all users. + """ diff --git a/src/openai/types/beta/chatkit_upload_file_params.py b/src/openai/types/beta/chatkit_upload_file_params.py new file mode 100644 index 0000000000..87dc993664 --- /dev/null +++ b/src/openai/types/beta/chatkit_upload_file_params.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +from ..._types import FileTypes + +__all__ = ["ChatKitUploadFileParams"] + + +class ChatKitUploadFileParams(TypedDict, total=False): + file: Required[FileTypes] + """Binary file contents to store with the ChatKit session. + + Supports PDFs and PNG, JPG, JPEG, GIF, or WEBP images. + """ diff --git a/src/openai/types/beta/chatkit_upload_file_response.py b/src/openai/types/beta/chatkit_upload_file_response.py new file mode 100644 index 0000000000..9527df76fb --- /dev/null +++ b/src/openai/types/beta/chatkit_upload_file_response.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from typing_extensions import Annotated, TypeAlias + +from ..._utils import PropertyInfo +from .file_part import FilePart +from .image_part import ImagePart + +__all__ = ["ChatKitUploadFileResponse"] + +ChatKitUploadFileResponse: TypeAlias = Annotated[Union[FilePart, ImagePart], PropertyInfo(discriminator="type")] diff --git a/src/openai/types/beta/chatkit_workflow.py b/src/openai/types/beta/chatkit_workflow.py new file mode 100644 index 0000000000..00fbcf41ce --- /dev/null +++ b/src/openai/types/beta/chatkit_workflow.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Union, Optional + +from ..._models import BaseModel + +__all__ = ["ChatKitWorkflow", "Tracing"] + + +class Tracing(BaseModel): + enabled: bool + """Indicates whether tracing is enabled.""" + + +class ChatKitWorkflow(BaseModel): + id: str + """Identifier of the workflow backing the session.""" + + state_variables: Optional[Dict[str, Union[str, bool, float]]] = None + """State variable key-value pairs applied when invoking the workflow. + + Defaults to null when no overrides were provided. + """ + + tracing: Tracing + """Tracing settings applied to the workflow.""" + + version: Optional[str] = None + """Specific workflow version used for the session. + + Defaults to null when using the latest deployment. + """ diff --git a/src/openai/types/beta/file_part.py b/src/openai/types/beta/file_part.py new file mode 100644 index 0000000000..cf60bddc99 --- /dev/null +++ b/src/openai/types/beta/file_part.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["FilePart"] + + +class FilePart(BaseModel): + id: str + """Unique identifier for the uploaded file.""" + + mime_type: Optional[str] = None + """MIME type reported for the uploaded file. Defaults to null when unknown.""" + + name: Optional[str] = None + """Original filename supplied by the uploader. Defaults to null when unnamed.""" + + type: Literal["file"] + """Type discriminator that is always `file`.""" + + upload_url: Optional[str] = None + """Signed URL for downloading the uploaded file. + + Defaults to null when no download link is available. + """ diff --git a/src/openai/types/beta/image_part.py b/src/openai/types/beta/image_part.py new file mode 100644 index 0000000000..4c06b4730b --- /dev/null +++ b/src/openai/types/beta/image_part.py @@ -0,0 +1,31 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ImagePart"] + + +class ImagePart(BaseModel): + id: str + """Unique identifier for the uploaded image.""" + + mime_type: str + """MIME type of the uploaded image.""" + + name: Optional[str] = None + """Original filename for the uploaded image. Defaults to null when unnamed.""" + + preview_url: str + """Preview URL that can be rendered inline for the image.""" + + type: Literal["image"] + """Type discriminator that is always `image`.""" + + upload_url: Optional[str] = None + """Signed URL for downloading the uploaded image. + + Defaults to null when no download link is available. + """ diff --git a/src/openai/types/image_edit_params.py b/src/openai/types/image_edit_params.py index 065d9789fc..2a8fab0f20 100644 --- a/src/openai/types/image_edit_params.py +++ b/src/openai/types/image_edit_params.py @@ -30,11 +30,11 @@ class ImageEditParamsBase(TypedDict, total=False): """ background: Optional[Literal["transparent", "opaque", "auto"]] - """Allows to set transparency for the background of the generated image(s). - - This parameter is only supported for `gpt-image-1`. Must be one of - `transparent`, `opaque` or `auto` (default value). When `auto` is used, the - model will automatically determine the best background for the image. + """ + Allows to set transparency for the background of the generated image(s). This + parameter is only supported for `gpt-image-1`. Must be one of `transparent`, + `opaque` or `auto` (default value). When `auto` is used, the model will + automatically determine the best background for the image. If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. @@ -44,7 +44,8 @@ class ImageEditParamsBase(TypedDict, total=False): """ Control how much effort the model will exert to match the style and features, especially facial features, of input images. This parameter is only supported - for `gpt-image-1`. Supports `high` and `low`. Defaults to `low`. + for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and + `low`. Defaults to `low`. """ mask: FileTypes diff --git a/src/openai/types/image_generate_params.py b/src/openai/types/image_generate_params.py index e9e9292cc2..3270ca1d6e 100644 --- a/src/openai/types/image_generate_params.py +++ b/src/openai/types/image_generate_params.py @@ -19,11 +19,11 @@ class ImageGenerateParamsBase(TypedDict, total=False): """ background: Optional[Literal["transparent", "opaque", "auto"]] - """Allows to set transparency for the background of the generated image(s). - - This parameter is only supported for `gpt-image-1`. Must be one of - `transparent`, `opaque` or `auto` (default value). When `auto` is used, the - model will automatically determine the best background for the image. + """ + Allows to set transparency for the background of the generated image(s). This + parameter is only supported for `gpt-image-1`. Must be one of `transparent`, + `opaque` or `auto` (default value). When `auto` is used, the model will + automatically determine the best background for the image. If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. diff --git a/src/openai/types/image_model.py b/src/openai/types/image_model.py index 7fed69ed82..22b1281fa9 100644 --- a/src/openai/types/image_model.py +++ b/src/openai/types/image_model.py @@ -4,4 +4,4 @@ __all__ = ["ImageModel"] -ImageModel: TypeAlias = Literal["dall-e-2", "dall-e-3", "gpt-image-1"] +ImageModel: TypeAlias = Literal["dall-e-2", "dall-e-3", "gpt-image-1", "gpt-image-1-mini"] diff --git a/src/openai/types/realtime/call_accept_params.py b/src/openai/types/realtime/call_accept_params.py index 1780572e89..0cfb01e7cf 100644 --- a/src/openai/types/realtime/call_accept_params.py +++ b/src/openai/types/realtime/call_accept_params.py @@ -63,6 +63,10 @@ class CallAcceptParams(TypedDict, total=False): "gpt-4o-realtime-preview-2025-06-03", "gpt-4o-mini-realtime-preview", "gpt-4o-mini-realtime-preview-2024-12-17", + "gpt-realtime-mini", + "gpt-realtime-mini-2025-10-06", + "gpt-audio-mini", + "gpt-audio-mini-2025-10-06", ], ] """The Realtime model used for this session.""" diff --git a/src/openai/types/realtime/realtime_session_create_request.py b/src/openai/types/realtime/realtime_session_create_request.py index 755dbe8638..bc205bd3b5 100644 --- a/src/openai/types/realtime/realtime_session_create_request.py +++ b/src/openai/types/realtime/realtime_session_create_request.py @@ -62,6 +62,10 @@ class RealtimeSessionCreateRequest(BaseModel): "gpt-4o-realtime-preview-2025-06-03", "gpt-4o-mini-realtime-preview", "gpt-4o-mini-realtime-preview-2024-12-17", + "gpt-realtime-mini", + "gpt-realtime-mini-2025-10-06", + "gpt-audio-mini", + "gpt-audio-mini-2025-10-06", ], None, ] = None diff --git a/src/openai/types/realtime/realtime_session_create_request_param.py b/src/openai/types/realtime/realtime_session_create_request_param.py index cd4ef71ba2..d1fa2b35d2 100644 --- a/src/openai/types/realtime/realtime_session_create_request_param.py +++ b/src/openai/types/realtime/realtime_session_create_request_param.py @@ -63,6 +63,10 @@ class RealtimeSessionCreateRequestParam(TypedDict, total=False): "gpt-4o-realtime-preview-2025-06-03", "gpt-4o-mini-realtime-preview", "gpt-4o-mini-realtime-preview-2024-12-17", + "gpt-realtime-mini", + "gpt-realtime-mini-2025-10-06", + "gpt-audio-mini", + "gpt-audio-mini-2025-10-06", ], ] """The Realtime model used for this session.""" diff --git a/src/openai/types/realtime/realtime_session_create_response.py b/src/openai/types/realtime/realtime_session_create_response.py index 2d6912d072..bb6b94e900 100644 --- a/src/openai/types/realtime/realtime_session_create_response.py +++ b/src/openai/types/realtime/realtime_session_create_response.py @@ -415,6 +415,10 @@ class RealtimeSessionCreateResponse(BaseModel): "gpt-4o-realtime-preview-2025-06-03", "gpt-4o-mini-realtime-preview", "gpt-4o-mini-realtime-preview-2024-12-17", + "gpt-realtime-mini", + "gpt-realtime-mini-2025-10-06", + "gpt-audio-mini", + "gpt-audio-mini-2025-10-06", ], None, ] = None diff --git a/src/openai/types/responses/tool.py b/src/openai/types/responses/tool.py index 8dd2bd5981..6239b818c9 100644 --- a/src/openai/types/responses/tool.py +++ b/src/openai/types/responses/tool.py @@ -199,7 +199,8 @@ class ImageGeneration(BaseModel): """ Control how much effort the model will exert to match the style and features, especially facial features, of input images. This parameter is only supported - for `gpt-image-1`. Supports `high` and `low`. Defaults to `low`. + for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and + `low`. Defaults to `low`. """ input_image_mask: Optional[ImageGenerationInputImageMask] = None @@ -208,7 +209,7 @@ class ImageGeneration(BaseModel): Contains `image_url` (string, optional) and `file_id` (string, optional). """ - model: Optional[Literal["gpt-image-1"]] = None + model: Optional[Literal["gpt-image-1", "gpt-image-1-mini"]] = None """The image generation model to use. Default: `gpt-image-1`.""" moderation: Optional[Literal["auto", "low"]] = None diff --git a/src/openai/types/responses/tool_param.py b/src/openai/types/responses/tool_param.py index e84abc4390..ff4ac2b953 100644 --- a/src/openai/types/responses/tool_param.py +++ b/src/openai/types/responses/tool_param.py @@ -199,7 +199,8 @@ class ImageGeneration(TypedDict, total=False): """ Control how much effort the model will exert to match the style and features, especially facial features, of input images. This parameter is only supported - for `gpt-image-1`. Supports `high` and `low`. Defaults to `low`. + for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and + `low`. Defaults to `low`. """ input_image_mask: ImageGenerationInputImageMask @@ -208,7 +209,7 @@ class ImageGeneration(TypedDict, total=False): Contains `image_url` (string, optional) and `file_id` (string, optional). """ - model: Literal["gpt-image-1"] + model: Literal["gpt-image-1", "gpt-image-1-mini"] """The image generation model to use. Default: `gpt-image-1`.""" moderation: Literal["auto", "low"] diff --git a/src/openai/types/shared/all_models.py b/src/openai/types/shared/all_models.py index 76ca1ffd29..3e0b09e2d1 100644 --- a/src/openai/types/shared/all_models.py +++ b/src/openai/types/shared/all_models.py @@ -22,5 +22,7 @@ "computer-use-preview", "computer-use-preview-2025-03-11", "gpt-5-codex", + "gpt-5-pro", + "gpt-5-pro-2025-10-06", ], ] diff --git a/src/openai/types/shared/responses_model.py b/src/openai/types/shared/responses_model.py index 4fbdce8db9..432cb82afd 100644 --- a/src/openai/types/shared/responses_model.py +++ b/src/openai/types/shared/responses_model.py @@ -22,5 +22,7 @@ "computer-use-preview", "computer-use-preview-2025-03-11", "gpt-5-codex", + "gpt-5-pro", + "gpt-5-pro-2025-10-06", ], ] diff --git a/src/openai/types/shared_params/responses_model.py b/src/openai/types/shared_params/responses_model.py index 2feaa22b67..fe34eb0f62 100644 --- a/src/openai/types/shared_params/responses_model.py +++ b/src/openai/types/shared_params/responses_model.py @@ -24,5 +24,7 @@ "computer-use-preview", "computer-use-preview-2025-03-11", "gpt-5-codex", + "gpt-5-pro", + "gpt-5-pro-2025-10-06", ], ] diff --git a/src/openai/types/video.py b/src/openai/types/video.py new file mode 100644 index 0000000000..2c804f75b8 --- /dev/null +++ b/src/openai/types/video.py @@ -0,0 +1,50 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from .._models import BaseModel +from .video_size import VideoSize +from .video_model import VideoModel +from .video_seconds import VideoSeconds +from .video_create_error import VideoCreateError + +__all__ = ["Video"] + + +class Video(BaseModel): + id: str + """Unique identifier for the video job.""" + + completed_at: Optional[int] = None + """Unix timestamp (seconds) for when the job completed, if finished.""" + + created_at: int + """Unix timestamp (seconds) for when the job was created.""" + + error: Optional[VideoCreateError] = None + """Error payload that explains why generation failed, if applicable.""" + + expires_at: Optional[int] = None + """Unix timestamp (seconds) for when the downloadable assets expire, if set.""" + + model: VideoModel + """The video generation model that produced the job.""" + + object: Literal["video"] + """The object type, which is always `video`.""" + + progress: int + """Approximate completion percentage for the generation task.""" + + remixed_from_video_id: Optional[str] = None + """Identifier of the source video if this video is a remix.""" + + seconds: VideoSeconds + """Duration of the generated clip in seconds.""" + + size: VideoSize + """The resolution of the generated video.""" + + status: Literal["queued", "in_progress", "completed", "failed"] + """Current lifecycle status of the video job.""" diff --git a/src/openai/types/video_create_error.py b/src/openai/types/video_create_error.py new file mode 100644 index 0000000000..ae328b78ea --- /dev/null +++ b/src/openai/types/video_create_error.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .._models import BaseModel + +__all__ = ["VideoCreateError"] + + +class VideoCreateError(BaseModel): + code: str + + message: str diff --git a/src/openai/types/video_create_params.py b/src/openai/types/video_create_params.py new file mode 100644 index 0000000000..527d62d193 --- /dev/null +++ b/src/openai/types/video_create_params.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +from .._types import FileTypes +from .video_size import VideoSize +from .video_model import VideoModel +from .video_seconds import VideoSeconds + +__all__ = ["VideoCreateParams"] + + +class VideoCreateParams(TypedDict, total=False): + prompt: Required[str] + """Text prompt that describes the video to generate.""" + + input_reference: FileTypes + """Optional image reference that guides generation.""" + + model: VideoModel + """The video generation model to use. Defaults to `sora-2`.""" + + seconds: VideoSeconds + """Clip duration in seconds. Defaults to 4 seconds.""" + + size: VideoSize + """Output resolution formatted as width x height. Defaults to 720x1280.""" diff --git a/src/openai/types/video_delete_response.py b/src/openai/types/video_delete_response.py new file mode 100644 index 0000000000..e2673ffe2b --- /dev/null +++ b/src/openai/types/video_delete_response.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["VideoDeleteResponse"] + + +class VideoDeleteResponse(BaseModel): + id: str + """Identifier of the deleted video.""" + + deleted: bool + """Indicates that the video resource was deleted.""" + + object: Literal["video.deleted"] + """The object type that signals the deletion response.""" diff --git a/src/openai/types/video_download_content_params.py b/src/openai/types/video_download_content_params.py new file mode 100644 index 0000000000..8c113d6715 --- /dev/null +++ b/src/openai/types/video_download_content_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["VideoDownloadContentParams"] + + +class VideoDownloadContentParams(TypedDict, total=False): + variant: Literal["video", "thumbnail", "spritesheet"] + """Which downloadable asset to return. Defaults to the MP4 video.""" diff --git a/src/openai/types/video_list_params.py b/src/openai/types/video_list_params.py new file mode 100644 index 0000000000..bf55ba7fa2 --- /dev/null +++ b/src/openai/types/video_list_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["VideoListParams"] + + +class VideoListParams(TypedDict, total=False): + after: str + """Identifier for the last item from the previous pagination request""" + + limit: int + """Number of items to retrieve""" + + order: Literal["asc", "desc"] + """Sort order of results by timestamp. + + Use `asc` for ascending order or `desc` for descending order. + """ diff --git a/src/openai/types/video_model.py b/src/openai/types/video_model.py new file mode 100644 index 0000000000..0b0835fca4 --- /dev/null +++ b/src/openai/types/video_model.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["VideoModel"] + +VideoModel: TypeAlias = Literal["sora-2", "sora-2-pro"] diff --git a/src/openai/types/video_remix_params.py b/src/openai/types/video_remix_params.py new file mode 100644 index 0000000000..15388d6172 --- /dev/null +++ b/src/openai/types/video_remix_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["VideoRemixParams"] + + +class VideoRemixParams(TypedDict, total=False): + prompt: Required[str] + """Updated text prompt that directs the remix generation.""" diff --git a/src/openai/types/video_seconds.py b/src/openai/types/video_seconds.py new file mode 100644 index 0000000000..e50d37dc51 --- /dev/null +++ b/src/openai/types/video_seconds.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["VideoSeconds"] + +VideoSeconds: TypeAlias = Literal["4", "8", "12"] diff --git a/src/openai/types/video_size.py b/src/openai/types/video_size.py new file mode 100644 index 0000000000..215ac8815a --- /dev/null +++ b/src/openai/types/video_size.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["VideoSize"] + +VideoSize: TypeAlias = Literal["720x1280", "1280x720", "1024x1792", "1792x1024"] diff --git a/tests/api_resources/beta/chatkit/__init__.py b/tests/api_resources/beta/chatkit/__init__.py new file mode 100644 index 0000000000..fd8019a9a1 --- /dev/null +++ b/tests/api_resources/beta/chatkit/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/beta/chatkit/test_sessions.py b/tests/api_resources/beta/chatkit/test_sessions.py new file mode 100644 index 0000000000..c94e4c92ae --- /dev/null +++ b/tests/api_resources/beta/chatkit/test_sessions.py @@ -0,0 +1,230 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.types.beta.chatkit import ( + ChatSession, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestSessions: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: OpenAI) -> None: + session = client.beta.chatkit.sessions.create( + user="x", + workflow={"id": "id"}, + ) + assert_matches_type(ChatSession, session, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: OpenAI) -> None: + session = client.beta.chatkit.sessions.create( + user="x", + workflow={ + "id": "id", + "state_variables": {"foo": "string"}, + "tracing": {"enabled": True}, + "version": "version", + }, + chatkit_configuration={ + "automatic_thread_titling": {"enabled": True}, + "file_upload": { + "enabled": True, + "max_file_size": 1, + "max_files": 1, + }, + "history": { + "enabled": True, + "recent_threads": 1, + }, + }, + expires_after={ + "anchor": "created_at", + "seconds": 1, + }, + rate_limits={"max_requests_per_1_minute": 1}, + ) + assert_matches_type(ChatSession, session, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: OpenAI) -> None: + response = client.beta.chatkit.sessions.with_raw_response.create( + user="x", + workflow={"id": "id"}, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + session = response.parse() + assert_matches_type(ChatSession, session, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: OpenAI) -> None: + with client.beta.chatkit.sessions.with_streaming_response.create( + user="x", + workflow={"id": "id"}, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + session = response.parse() + assert_matches_type(ChatSession, session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_cancel(self, client: OpenAI) -> None: + session = client.beta.chatkit.sessions.cancel( + "cksess_123", + ) + assert_matches_type(ChatSession, session, path=["response"]) + + @parametrize + def test_raw_response_cancel(self, client: OpenAI) -> None: + response = client.beta.chatkit.sessions.with_raw_response.cancel( + "cksess_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + session = response.parse() + assert_matches_type(ChatSession, session, path=["response"]) + + @parametrize + def test_streaming_response_cancel(self, client: OpenAI) -> None: + with client.beta.chatkit.sessions.with_streaming_response.cancel( + "cksess_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + session = response.parse() + assert_matches_type(ChatSession, session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_cancel(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `session_id` but received ''"): + client.beta.chatkit.sessions.with_raw_response.cancel( + "", + ) + + +class TestAsyncSessions: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncOpenAI) -> None: + session = await async_client.beta.chatkit.sessions.create( + user="x", + workflow={"id": "id"}, + ) + assert_matches_type(ChatSession, session, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: + session = await async_client.beta.chatkit.sessions.create( + user="x", + workflow={ + "id": "id", + "state_variables": {"foo": "string"}, + "tracing": {"enabled": True}, + "version": "version", + }, + chatkit_configuration={ + "automatic_thread_titling": {"enabled": True}, + "file_upload": { + "enabled": True, + "max_file_size": 1, + "max_files": 1, + }, + "history": { + "enabled": True, + "recent_threads": 1, + }, + }, + expires_after={ + "anchor": "created_at", + "seconds": 1, + }, + rate_limits={"max_requests_per_1_minute": 1}, + ) + assert_matches_type(ChatSession, session, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: + response = await async_client.beta.chatkit.sessions.with_raw_response.create( + user="x", + workflow={"id": "id"}, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + session = response.parse() + assert_matches_type(ChatSession, session, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: + async with async_client.beta.chatkit.sessions.with_streaming_response.create( + user="x", + workflow={"id": "id"}, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + session = await response.parse() + assert_matches_type(ChatSession, session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_cancel(self, async_client: AsyncOpenAI) -> None: + session = await async_client.beta.chatkit.sessions.cancel( + "cksess_123", + ) + assert_matches_type(ChatSession, session, path=["response"]) + + @parametrize + async def test_raw_response_cancel(self, async_client: AsyncOpenAI) -> None: + response = await async_client.beta.chatkit.sessions.with_raw_response.cancel( + "cksess_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + session = response.parse() + assert_matches_type(ChatSession, session, path=["response"]) + + @parametrize + async def test_streaming_response_cancel(self, async_client: AsyncOpenAI) -> None: + async with async_client.beta.chatkit.sessions.with_streaming_response.cancel( + "cksess_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + session = await response.parse() + assert_matches_type(ChatSession, session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_cancel(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `session_id` but received ''"): + await async_client.beta.chatkit.sessions.with_raw_response.cancel( + "", + ) diff --git a/tests/api_resources/beta/chatkit/test_threads.py b/tests/api_resources/beta/chatkit/test_threads.py new file mode 100644 index 0000000000..6395b72b2f --- /dev/null +++ b/tests/api_resources/beta/chatkit/test_threads.py @@ -0,0 +1,348 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.pagination import SyncConversationCursorPage, AsyncConversationCursorPage +from openai.types.beta.chatkit import ChatKitThread, ThreadDeleteResponse +from openai.types.beta.chatkit.chatkit_thread_item_list import Data + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestThreads: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + thread = client.beta.chatkit.threads.retrieve( + "cthr_123", + ) + assert_matches_type(ChatKitThread, thread, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.beta.chatkit.threads.with_raw_response.retrieve( + "cthr_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + thread = response.parse() + assert_matches_type(ChatKitThread, thread, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.beta.chatkit.threads.with_streaming_response.retrieve( + "cthr_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + thread = response.parse() + assert_matches_type(ChatKitThread, thread, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + client.beta.chatkit.threads.with_raw_response.retrieve( + "", + ) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + thread = client.beta.chatkit.threads.list() + assert_matches_type(SyncConversationCursorPage[ChatKitThread], thread, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + thread = client.beta.chatkit.threads.list( + after="after", + before="before", + limit=0, + order="asc", + user="x", + ) + assert_matches_type(SyncConversationCursorPage[ChatKitThread], thread, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.beta.chatkit.threads.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + thread = response.parse() + assert_matches_type(SyncConversationCursorPage[ChatKitThread], thread, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.beta.chatkit.threads.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + thread = response.parse() + assert_matches_type(SyncConversationCursorPage[ChatKitThread], thread, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: OpenAI) -> None: + thread = client.beta.chatkit.threads.delete( + "cthr_123", + ) + assert_matches_type(ThreadDeleteResponse, thread, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: OpenAI) -> None: + response = client.beta.chatkit.threads.with_raw_response.delete( + "cthr_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + thread = response.parse() + assert_matches_type(ThreadDeleteResponse, thread, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: OpenAI) -> None: + with client.beta.chatkit.threads.with_streaming_response.delete( + "cthr_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + thread = response.parse() + assert_matches_type(ThreadDeleteResponse, thread, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + client.beta.chatkit.threads.with_raw_response.delete( + "", + ) + + @parametrize + def test_method_list_items(self, client: OpenAI) -> None: + thread = client.beta.chatkit.threads.list_items( + thread_id="cthr_123", + ) + assert_matches_type(SyncConversationCursorPage[Data], thread, path=["response"]) + + @parametrize + def test_method_list_items_with_all_params(self, client: OpenAI) -> None: + thread = client.beta.chatkit.threads.list_items( + thread_id="cthr_123", + after="after", + before="before", + limit=0, + order="asc", + ) + assert_matches_type(SyncConversationCursorPage[Data], thread, path=["response"]) + + @parametrize + def test_raw_response_list_items(self, client: OpenAI) -> None: + response = client.beta.chatkit.threads.with_raw_response.list_items( + thread_id="cthr_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + thread = response.parse() + assert_matches_type(SyncConversationCursorPage[Data], thread, path=["response"]) + + @parametrize + def test_streaming_response_list_items(self, client: OpenAI) -> None: + with client.beta.chatkit.threads.with_streaming_response.list_items( + thread_id="cthr_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + thread = response.parse() + assert_matches_type(SyncConversationCursorPage[Data], thread, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list_items(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + client.beta.chatkit.threads.with_raw_response.list_items( + thread_id="", + ) + + +class TestAsyncThreads: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + thread = await async_client.beta.chatkit.threads.retrieve( + "cthr_123", + ) + assert_matches_type(ChatKitThread, thread, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.beta.chatkit.threads.with_raw_response.retrieve( + "cthr_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + thread = response.parse() + assert_matches_type(ChatKitThread, thread, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.beta.chatkit.threads.with_streaming_response.retrieve( + "cthr_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + thread = await response.parse() + assert_matches_type(ChatKitThread, thread, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + await async_client.beta.chatkit.threads.with_raw_response.retrieve( + "", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + thread = await async_client.beta.chatkit.threads.list() + assert_matches_type(AsyncConversationCursorPage[ChatKitThread], thread, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + thread = await async_client.beta.chatkit.threads.list( + after="after", + before="before", + limit=0, + order="asc", + user="x", + ) + assert_matches_type(AsyncConversationCursorPage[ChatKitThread], thread, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.beta.chatkit.threads.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + thread = response.parse() + assert_matches_type(AsyncConversationCursorPage[ChatKitThread], thread, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.beta.chatkit.threads.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + thread = await response.parse() + assert_matches_type(AsyncConversationCursorPage[ChatKitThread], thread, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncOpenAI) -> None: + thread = await async_client.beta.chatkit.threads.delete( + "cthr_123", + ) + assert_matches_type(ThreadDeleteResponse, thread, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: + response = await async_client.beta.chatkit.threads.with_raw_response.delete( + "cthr_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + thread = response.parse() + assert_matches_type(ThreadDeleteResponse, thread, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: + async with async_client.beta.chatkit.threads.with_streaming_response.delete( + "cthr_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + thread = await response.parse() + assert_matches_type(ThreadDeleteResponse, thread, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + await async_client.beta.chatkit.threads.with_raw_response.delete( + "", + ) + + @parametrize + async def test_method_list_items(self, async_client: AsyncOpenAI) -> None: + thread = await async_client.beta.chatkit.threads.list_items( + thread_id="cthr_123", + ) + assert_matches_type(AsyncConversationCursorPage[Data], thread, path=["response"]) + + @parametrize + async def test_method_list_items_with_all_params(self, async_client: AsyncOpenAI) -> None: + thread = await async_client.beta.chatkit.threads.list_items( + thread_id="cthr_123", + after="after", + before="before", + limit=0, + order="asc", + ) + assert_matches_type(AsyncConversationCursorPage[Data], thread, path=["response"]) + + @parametrize + async def test_raw_response_list_items(self, async_client: AsyncOpenAI) -> None: + response = await async_client.beta.chatkit.threads.with_raw_response.list_items( + thread_id="cthr_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + thread = response.parse() + assert_matches_type(AsyncConversationCursorPage[Data], thread, path=["response"]) + + @parametrize + async def test_streaming_response_list_items(self, async_client: AsyncOpenAI) -> None: + async with async_client.beta.chatkit.threads.with_streaming_response.list_items( + thread_id="cthr_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + thread = await response.parse() + assert_matches_type(AsyncConversationCursorPage[Data], thread, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list_items(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `thread_id` but received ''"): + await async_client.beta.chatkit.threads.with_raw_response.list_items( + thread_id="", + ) diff --git a/tests/api_resources/beta/test_chatkit.py b/tests/api_resources/beta/test_chatkit.py new file mode 100644 index 0000000000..b05be0ece5 --- /dev/null +++ b/tests/api_resources/beta/test_chatkit.py @@ -0,0 +1,86 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.types.beta import ChatKitUploadFileResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestChatKit: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_upload_file(self, client: OpenAI) -> None: + chatkit = client.beta.chatkit.upload_file( + file=b"raw file contents", + ) + assert_matches_type(ChatKitUploadFileResponse, chatkit, path=["response"]) + + @parametrize + def test_raw_response_upload_file(self, client: OpenAI) -> None: + response = client.beta.chatkit.with_raw_response.upload_file( + file=b"raw file contents", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + chatkit = response.parse() + assert_matches_type(ChatKitUploadFileResponse, chatkit, path=["response"]) + + @parametrize + def test_streaming_response_upload_file(self, client: OpenAI) -> None: + with client.beta.chatkit.with_streaming_response.upload_file( + file=b"raw file contents", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + chatkit = response.parse() + assert_matches_type(ChatKitUploadFileResponse, chatkit, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncChatKit: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_upload_file(self, async_client: AsyncOpenAI) -> None: + chatkit = await async_client.beta.chatkit.upload_file( + file=b"raw file contents", + ) + assert_matches_type(ChatKitUploadFileResponse, chatkit, path=["response"]) + + @parametrize + async def test_raw_response_upload_file(self, async_client: AsyncOpenAI) -> None: + response = await async_client.beta.chatkit.with_raw_response.upload_file( + file=b"raw file contents", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + chatkit = response.parse() + assert_matches_type(ChatKitUploadFileResponse, chatkit, path=["response"]) + + @parametrize + async def test_streaming_response_upload_file(self, async_client: AsyncOpenAI) -> None: + async with async_client.beta.chatkit.with_streaming_response.upload_file( + file=b"raw file contents", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + chatkit = await response.parse() + assert_matches_type(ChatKitUploadFileResponse, chatkit, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_videos.py b/tests/api_resources/test_videos.py new file mode 100644 index 0000000000..623cfc2153 --- /dev/null +++ b/tests/api_resources/test_videos.py @@ -0,0 +1,551 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import httpx +import pytest +from respx import MockRouter + +import openai._legacy_response as _legacy_response +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.types import ( + Video, + VideoDeleteResponse, +) +from openai._utils import assert_signatures_in_sync +from openai.pagination import SyncConversationCursorPage, AsyncConversationCursorPage + +# pyright: reportDeprecated=false + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestVideos: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: OpenAI) -> None: + video = client.videos.create( + prompt="x", + ) + assert_matches_type(Video, video, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: OpenAI) -> None: + video = client.videos.create( + prompt="x", + input_reference=b"raw file contents", + model="sora-2", + seconds="4", + size="720x1280", + ) + assert_matches_type(Video, video, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: OpenAI) -> None: + response = client.videos.with_raw_response.create( + prompt="x", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = response.parse() + assert_matches_type(Video, video, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: OpenAI) -> None: + with client.videos.with_streaming_response.create( + prompt="x", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = response.parse() + assert_matches_type(Video, video, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + video = client.videos.retrieve( + "video_123", + ) + assert_matches_type(Video, video, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.videos.with_raw_response.retrieve( + "video_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = response.parse() + assert_matches_type(Video, video, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.videos.with_streaming_response.retrieve( + "video_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = response.parse() + assert_matches_type(Video, video, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `video_id` but received ''"): + client.videos.with_raw_response.retrieve( + "", + ) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + video = client.videos.list() + assert_matches_type(SyncConversationCursorPage[Video], video, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + video = client.videos.list( + after="after", + limit=0, + order="asc", + ) + assert_matches_type(SyncConversationCursorPage[Video], video, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.videos.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = response.parse() + assert_matches_type(SyncConversationCursorPage[Video], video, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.videos.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = response.parse() + assert_matches_type(SyncConversationCursorPage[Video], video, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: OpenAI) -> None: + video = client.videos.delete( + "video_123", + ) + assert_matches_type(VideoDeleteResponse, video, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: OpenAI) -> None: + response = client.videos.with_raw_response.delete( + "video_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = response.parse() + assert_matches_type(VideoDeleteResponse, video, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: OpenAI) -> None: + with client.videos.with_streaming_response.delete( + "video_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = response.parse() + assert_matches_type(VideoDeleteResponse, video, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `video_id` but received ''"): + client.videos.with_raw_response.delete( + "", + ) + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_method_download_content(self, client: OpenAI, respx_mock: MockRouter) -> None: + respx_mock.get("/videos/video_123/content").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + video = client.videos.download_content( + video_id="video_123", + ) + assert isinstance(video, _legacy_response.HttpxBinaryResponseContent) + assert video.json() == {"foo": "bar"} + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_method_download_content_with_all_params(self, client: OpenAI, respx_mock: MockRouter) -> None: + respx_mock.get("/videos/video_123/content").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + video = client.videos.download_content( + video_id="video_123", + variant="video", + ) + assert isinstance(video, _legacy_response.HttpxBinaryResponseContent) + assert video.json() == {"foo": "bar"} + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_raw_response_download_content(self, client: OpenAI, respx_mock: MockRouter) -> None: + respx_mock.get("/videos/video_123/content").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + + response = client.videos.with_raw_response.download_content( + video_id="video_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = response.parse() + assert_matches_type(_legacy_response.HttpxBinaryResponseContent, video, path=["response"]) + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_streaming_response_download_content(self, client: OpenAI, respx_mock: MockRouter) -> None: + respx_mock.get("/videos/video_123/content").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + with client.videos.with_streaming_response.download_content( + video_id="video_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = response.parse() + assert_matches_type(bytes, video, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_path_params_download_content(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `video_id` but received ''"): + client.videos.with_raw_response.download_content( + video_id="", + ) + + @parametrize + def test_method_remix(self, client: OpenAI) -> None: + video = client.videos.remix( + video_id="video_123", + prompt="x", + ) + assert_matches_type(Video, video, path=["response"]) + + @parametrize + def test_raw_response_remix(self, client: OpenAI) -> None: + response = client.videos.with_raw_response.remix( + video_id="video_123", + prompt="x", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = response.parse() + assert_matches_type(Video, video, path=["response"]) + + @parametrize + def test_streaming_response_remix(self, client: OpenAI) -> None: + with client.videos.with_streaming_response.remix( + video_id="video_123", + prompt="x", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = response.parse() + assert_matches_type(Video, video, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_remix(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `video_id` but received ''"): + client.videos.with_raw_response.remix( + video_id="", + prompt="x", + ) + + +class TestAsyncVideos: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncOpenAI) -> None: + video = await async_client.videos.create( + prompt="x", + ) + assert_matches_type(Video, video, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: + video = await async_client.videos.create( + prompt="x", + input_reference=b"raw file contents", + model="sora-2", + seconds="4", + size="720x1280", + ) + assert_matches_type(Video, video, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: + response = await async_client.videos.with_raw_response.create( + prompt="x", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = response.parse() + assert_matches_type(Video, video, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: + async with async_client.videos.with_streaming_response.create( + prompt="x", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = await response.parse() + assert_matches_type(Video, video, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + video = await async_client.videos.retrieve( + "video_123", + ) + assert_matches_type(Video, video, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.videos.with_raw_response.retrieve( + "video_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = response.parse() + assert_matches_type(Video, video, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.videos.with_streaming_response.retrieve( + "video_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = await response.parse() + assert_matches_type(Video, video, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `video_id` but received ''"): + await async_client.videos.with_raw_response.retrieve( + "", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + video = await async_client.videos.list() + assert_matches_type(AsyncConversationCursorPage[Video], video, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + video = await async_client.videos.list( + after="after", + limit=0, + order="asc", + ) + assert_matches_type(AsyncConversationCursorPage[Video], video, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.videos.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = response.parse() + assert_matches_type(AsyncConversationCursorPage[Video], video, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.videos.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = await response.parse() + assert_matches_type(AsyncConversationCursorPage[Video], video, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncOpenAI) -> None: + video = await async_client.videos.delete( + "video_123", + ) + assert_matches_type(VideoDeleteResponse, video, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: + response = await async_client.videos.with_raw_response.delete( + "video_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = response.parse() + assert_matches_type(VideoDeleteResponse, video, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: + async with async_client.videos.with_streaming_response.delete( + "video_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = await response.parse() + assert_matches_type(VideoDeleteResponse, video, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `video_id` but received ''"): + await async_client.videos.with_raw_response.delete( + "", + ) + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_method_download_content(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None: + respx_mock.get("/videos/video_123/content").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + video = await async_client.videos.download_content( + video_id="video_123", + ) + assert isinstance(video, _legacy_response.HttpxBinaryResponseContent) + assert video.json() == {"foo": "bar"} + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_method_download_content_with_all_params( + self, async_client: AsyncOpenAI, respx_mock: MockRouter + ) -> None: + respx_mock.get("/videos/video_123/content").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + video = await async_client.videos.download_content( + video_id="video_123", + variant="video", + ) + assert isinstance(video, _legacy_response.HttpxBinaryResponseContent) + assert video.json() == {"foo": "bar"} + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_raw_response_download_content(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None: + respx_mock.get("/videos/video_123/content").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + + response = await async_client.videos.with_raw_response.download_content( + video_id="video_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = response.parse() + assert_matches_type(_legacy_response.HttpxBinaryResponseContent, video, path=["response"]) + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_streaming_response_download_content(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None: + respx_mock.get("/videos/video_123/content").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + async with async_client.videos.with_streaming_response.download_content( + video_id="video_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = await response.parse() + assert_matches_type(bytes, video, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_path_params_download_content(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `video_id` but received ''"): + await async_client.videos.with_raw_response.download_content( + video_id="", + ) + + @parametrize + async def test_method_remix(self, async_client: AsyncOpenAI) -> None: + video = await async_client.videos.remix( + video_id="video_123", + prompt="x", + ) + assert_matches_type(Video, video, path=["response"]) + + @parametrize + async def test_raw_response_remix(self, async_client: AsyncOpenAI) -> None: + response = await async_client.videos.with_raw_response.remix( + video_id="video_123", + prompt="x", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = response.parse() + assert_matches_type(Video, video, path=["response"]) + + @parametrize + async def test_streaming_response_remix(self, async_client: AsyncOpenAI) -> None: + async with async_client.videos.with_streaming_response.remix( + video_id="video_123", + prompt="x", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = await response.parse() + assert_matches_type(Video, video, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_remix(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `video_id` but received ''"): + await async_client.videos.with_raw_response.remix( + video_id="", + prompt="x", + ) + + +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +def test_create_and_poll_method_in_sync(sync: bool, client: OpenAI, async_client: AsyncOpenAI) -> None: + checking_client: OpenAI | AsyncOpenAI = client if sync else async_client + + assert_signatures_in_sync( + checking_client.videos.create, + checking_client.videos.create_and_poll, + exclude_params={"extra_headers", "extra_query", "extra_body", "timeout"}, + ) From 8082367a4d06b4c59b06ff417d458a5b22670d07 Mon Sep 17 00:00:00 2001 From: David Meadows Date: Mon, 6 Oct 2025 13:56:31 -0400 Subject: [PATCH 514/769] fix(client): add chatkit to beta resource --- src/openai/resources/beta/beta.py | 11 ++++++----- src/openai/resources/realtime/realtime.py | 2 ++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/openai/resources/beta/beta.py b/src/openai/resources/beta/beta.py index 81a6e7aa93..edf30be005 100644 --- a/src/openai/resources/beta/beta.py +++ b/src/openai/resources/beta/beta.py @@ -28,18 +28,16 @@ ThreadsWithStreamingResponse, AsyncThreadsWithStreamingResponse, ) -from ...resources.chat import Chat, AsyncChat -from .realtime.realtime import ( - Realtime, - AsyncRealtime, -) __all__ = ["Beta", "AsyncBeta"] class Beta(SyncAPIResource): @cached_property + def chatkit(self) -> ChatKit: + return ChatKit(self._client) + @cached_property def assistants(self) -> Assistants: return Assistants(self._client) @@ -69,7 +67,10 @@ def with_streaming_response(self) -> BetaWithStreamingResponse: class AsyncBeta(AsyncAPIResource): @cached_property + def chatkit(self) -> AsyncChatKit: + return AsyncChatKit(self._client) + @cached_property def assistants(self) -> AsyncAssistants: return AsyncAssistants(self._client) diff --git a/src/openai/resources/realtime/realtime.py b/src/openai/resources/realtime/realtime.py index bd4e1d9644..6e69258616 100644 --- a/src/openai/resources/realtime/realtime.py +++ b/src/openai/resources/realtime/realtime.py @@ -67,6 +67,7 @@ def client_secrets(self) -> ClientSecrets: @cached_property def calls(self) -> Calls: from ...lib._realtime import _Calls + return _Calls(self._client) @cached_property @@ -126,6 +127,7 @@ def client_secrets(self) -> AsyncClientSecrets: @cached_property def calls(self) -> AsyncCalls: from ...lib._realtime import _AsyncCalls + return _AsyncCalls(self._client) @cached_property From ea3dcf88b10f780b71076c42bab902250e857106 Mon Sep 17 00:00:00 2001 From: Alex Chang Date: Mon, 6 Oct 2025 11:03:41 -0700 Subject: [PATCH 515/769] [fix] readd realtime and chat --- src/openai/resources/beta/beta.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/openai/resources/beta/beta.py b/src/openai/resources/beta/beta.py index edf30be005..5ee3639db1 100644 --- a/src/openai/resources/beta/beta.py +++ b/src/openai/resources/beta/beta.py @@ -28,11 +28,24 @@ ThreadsWithStreamingResponse, AsyncThreadsWithStreamingResponse, ) +from ...resources.chat import Chat, AsyncChat +from .realtime.realtime import ( + Realtime, + AsyncRealtime, +) __all__ = ["Beta", "AsyncBeta"] class Beta(SyncAPIResource): + @cached_property + def chat(self) -> Chat: + return Chat(self._client) + + @cached_property + def realtime(self) -> Realtime: + return Realtime(self._client) + @cached_property def chatkit(self) -> ChatKit: return ChatKit(self._client) @@ -66,6 +79,14 @@ def with_streaming_response(self) -> BetaWithStreamingResponse: class AsyncBeta(AsyncAPIResource): + @cached_property + def chat(self) -> AsyncChat: + return AsyncChat(self._client) + + @cached_property + def realtime(self) -> AsyncRealtime: + return AsyncRealtime(self._client) + @cached_property def chatkit(self) -> AsyncChatKit: return AsyncChatKit(self._client) From d69edeb39e6a9cc8d9822a2838b10ab4102b4cc6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 18:04:19 +0000 Subject: [PATCH 516/769] release: 2.2.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 656a2ef17d..bfc26f9c4e 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.1.0" + ".": "2.2.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 76d700f05e..336c6601a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 2.2.0 (2025-10-06) + +Full Changelog: [v2.1.0...v2.2.0](https://github.com/openai/openai-python/compare/v2.1.0...v2.2.0) + +### Features + +* **api:** dev day 2025 launches ([38ac009](https://github.com/openai/openai-python/commit/38ac0093ebb3419b1e2280d0dc2d26c74a2bbbec)) + + +### Bug Fixes + +* **client:** add chatkit to beta resource ([de3e561](https://github.com/openai/openai-python/commit/de3e5619d0a85b17906a9416039ef309e820dc0f)) + ## 2.1.0 (2025-10-02) Full Changelog: [v2.0.1...v2.1.0](https://github.com/openai/openai-python/compare/v2.0.1...v2.1.0) diff --git a/pyproject.toml b/pyproject.toml index d8deac4e61..7e9f9bd1ee 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.1.0" +version = "2.2.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 2860526ced..2fdb2912ef 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__ = "2.1.0" # x-release-please-version +__version__ = "2.2.0" # x-release-please-version From 85a91ade618e7c97f382014c26aeac55a431258f Mon Sep 17 00:00:00 2001 From: giovx Date: Wed, 8 Oct 2025 11:30:46 +0200 Subject: [PATCH 517/769] chore(package): bump jiter to >=0.10.0 to support Python 3.14 (#2618) Co-authored-by: Robert Craigie --- pyproject.toml | 2 +- requirements-dev.lock | 2 +- requirements.lock | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 7e9f9bd1ee..bb5eb7cf41 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,7 +15,7 @@ dependencies = [ "distro>=1.7.0, <2", "sniffio", "tqdm > 4", - "jiter>=0.4.0, <1", + "jiter>=0.10.0, <1", ] requires-python = ">= 3.8" classifiers = [ diff --git a/requirements-dev.lock b/requirements-dev.lock index 0bd1c2c70f..e2446f2222 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -91,7 +91,7 @@ importlib-metadata==7.0.0 iniconfig==2.0.0 # via pytest inline-snapshot==0.28.0 -jiter==0.5.0 +jiter==0.11.0 # via openai markdown-it-py==3.0.0 # via rich diff --git a/requirements.lock b/requirements.lock index a2b6845942..aaca0834db 100644 --- a/requirements.lock +++ b/requirements.lock @@ -51,7 +51,7 @@ idna==3.4 # via anyio # via httpx # via yarl -jiter==0.6.1 +jiter==0.11.0 # via openai multidict==6.5.0 # via aiohttp From 044878859cf1257f0d0c6704e0568986e2d0686c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 10 Oct 2025 01:09:07 +0000 Subject: [PATCH 518/769] feat(api): comparison filter in/not in --- .stats.yml | 6 +++--- src/openai/resources/beta/assistants.py | 12 ++++++++++++ src/openai/resources/beta/threads/runs/runs.py | 18 ++++++++++++++++++ .../resources/chat/completions/completions.py | 18 ++++++++++++++++++ src/openai/resources/files.py | 4 ++-- .../types/beta/assistant_create_params.py | 3 +++ .../types/beta/assistant_update_params.py | 3 +++ .../types/beta/threads/run_create_params.py | 3 +++ .../types/chat/completion_create_params.py | 3 +++ .../create_eval_completions_run_data_source.py | 3 +++ ...e_eval_completions_run_data_source_param.py | 3 +++ src/openai/types/evals/run_cancel_response.py | 6 ++++++ src/openai/types/evals/run_create_params.py | 6 ++++++ src/openai/types/evals/run_create_response.py | 6 ++++++ src/openai/types/evals/run_list_response.py | 6 ++++++ .../types/evals/run_retrieve_response.py | 6 ++++++ src/openai/types/graders/score_model_grader.py | 3 +++ .../types/graders/score_model_grader_param.py | 3 +++ src/openai/types/shared/comparison_filter.py | 10 +++++++--- src/openai/types/shared/reasoning.py | 3 +++ .../types/shared_params/comparison_filter.py | 10 ++++++++-- src/openai/types/shared_params/reasoning.py | 3 +++ .../types/vector_stores/vector_store_file.py | 2 +- 23 files changed, 129 insertions(+), 11 deletions(-) diff --git a/.stats.yml b/.stats.yml index 2dc7422e7e..b5d9915ab8 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 136 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-d64cf80d2ebddf175c5578f68226a3d5bbd3f7fd8d62ccac2205f3fc05a355ee.yml -openapi_spec_hash: d51e0d60d0c536f210b597a211bc5af0 -config_hash: e7c42016df9c6bd7bd6ff15101b9bc9b +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-e66e85fb7f72477256dca1acb6b23396989d381c5c1b318de564195436bcb93f.yml +openapi_spec_hash: 0a4bbb5aa0ae532a072bd6b3854e70b1 +config_hash: 89bf7bb3a1f9439ffc6ea0e7dc57ba9b diff --git a/src/openai/resources/beta/assistants.py b/src/openai/resources/beta/assistants.py index ddac9a79cb..a958c0caa1 100644 --- a/src/openai/resources/beta/assistants.py +++ b/src/openai/resources/beta/assistants.py @@ -102,6 +102,9 @@ def create( effort can result in faster responses and fewer tokens used on reasoning in a response. + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. + 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 +312,9 @@ def update( effort can result in faster responses and fewer tokens used on reasoning in a response. + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. + 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), @@ -555,6 +561,9 @@ async def create( effort can result in faster responses and fewer tokens used on reasoning in a response. + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. + 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), @@ -762,6 +771,9 @@ async def update( effort can result in faster responses and fewer tokens used on reasoning in a response. + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. + 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), diff --git a/src/openai/resources/beta/threads/runs/runs.py b/src/openai/resources/beta/threads/runs/runs.py index ec2dfa84cd..2753f5817e 100644 --- a/src/openai/resources/beta/threads/runs/runs.py +++ b/src/openai/resources/beta/threads/runs/runs.py @@ -173,6 +173,9 @@ def create( effort can result in faster responses and fewer tokens used on reasoning in a response. + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. + 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), @@ -327,6 +330,9 @@ def create( effort can result in faster responses and fewer tokens used on reasoning in a response. + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. + 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), @@ -477,6 +483,9 @@ def create( effort can result in faster responses and fewer tokens used on reasoning in a response. + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. + 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), @@ -1603,6 +1612,9 @@ async def create( effort can result in faster responses and fewer tokens used on reasoning in a response. + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. + 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), @@ -1757,6 +1769,9 @@ async def create( effort can result in faster responses and fewer tokens used on reasoning in a response. + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. + 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), @@ -1907,6 +1922,9 @@ async def create( effort can result in faster responses and fewer tokens used on reasoning in a response. + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. + 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), diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index 329634ba43..4b73c69ae9 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -407,6 +407,9 @@ def create( effort can result in faster responses and fewer tokens used on reasoning in a response. + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. + response_format: An object specifying the format that the model must output. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured @@ -704,6 +707,9 @@ def create( effort can result in faster responses and fewer tokens used on reasoning in a response. + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. + response_format: An object specifying the format that the model must output. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured @@ -992,6 +998,9 @@ def create( effort can result in faster responses and fewer tokens used on reasoning in a response. + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. + response_format: An object specifying the format that the model must output. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured @@ -1845,6 +1854,9 @@ async def create( effort can result in faster responses and fewer tokens used on reasoning in a response. + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. + response_format: An object specifying the format that the model must output. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured @@ -2142,6 +2154,9 @@ async def create( effort can result in faster responses and fewer tokens used on reasoning in a response. + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. + response_format: An object specifying the format that the model must output. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured @@ -2430,6 +2445,9 @@ async def create( effort can result in faster responses and fewer tokens used on reasoning in a response. + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. + response_format: An object specifying the format that the model must output. Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured diff --git a/src/openai/resources/files.py b/src/openai/resources/files.py index 77bb2d613c..bb9ad43b1b 100644 --- a/src/openai/resources/files.py +++ b/src/openai/resources/files.py @@ -236,7 +236,7 @@ def delete( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> FileDeleted: """ - Delete a file. + Delete a file and remove it from all vector stores. Args: extra_headers: Send extra headers @@ -553,7 +553,7 @@ async def delete( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> FileDeleted: """ - Delete a file. + Delete a file and remove it from all vector stores. Args: extra_headers: Send extra headers diff --git a/src/openai/types/beta/assistant_create_params.py b/src/openai/types/beta/assistant_create_params.py index 07f8f28f02..6fb1551fa5 100644 --- a/src/openai/types/beta/assistant_create_params.py +++ b/src/openai/types/beta/assistant_create_params.py @@ -65,6 +65,9 @@ class AssistantCreateParams(TypedDict, total=False): supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response. + + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. """ response_format: Optional[AssistantResponseFormatOptionParam] diff --git a/src/openai/types/beta/assistant_update_params.py b/src/openai/types/beta/assistant_update_params.py index 45d9f984b2..6d20b8e01f 100644 --- a/src/openai/types/beta/assistant_update_params.py +++ b/src/openai/types/beta/assistant_update_params.py @@ -100,6 +100,9 @@ class AssistantUpdateParams(TypedDict, total=False): supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response. + + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. """ response_format: Optional[AssistantResponseFormatOptionParam] diff --git a/src/openai/types/beta/threads/run_create_params.py b/src/openai/types/beta/threads/run_create_params.py index cfd272f5ad..3190c8b308 100644 --- a/src/openai/types/beta/threads/run_create_params.py +++ b/src/openai/types/beta/threads/run_create_params.py @@ -114,6 +114,9 @@ class RunCreateParamsBase(TypedDict, total=False): supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response. + + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. """ response_format: Optional[AssistantResponseFormatOptionParam] diff --git a/src/openai/types/chat/completion_create_params.py b/src/openai/types/chat/completion_create_params.py index 2ae81dfbc2..8b0fdd04b3 100644 --- a/src/openai/types/chat/completion_create_params.py +++ b/src/openai/types/chat/completion_create_params.py @@ -192,6 +192,9 @@ class CompletionCreateParamsBase(TypedDict, total=False): supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response. + + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. """ response_format: ResponseFormat diff --git a/src/openai/types/evals/create_eval_completions_run_data_source.py b/src/openai/types/evals/create_eval_completions_run_data_source.py index 74323a735e..a9f2fd0858 100644 --- a/src/openai/types/evals/create_eval_completions_run_data_source.py +++ b/src/openai/types/evals/create_eval_completions_run_data_source.py @@ -175,6 +175,9 @@ class SamplingParams(BaseModel): supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response. + + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. """ response_format: Optional[SamplingParamsResponseFormat] = None diff --git a/src/openai/types/evals/create_eval_completions_run_data_source_param.py b/src/openai/types/evals/create_eval_completions_run_data_source_param.py index 4e9c1fdeb8..e682e2db5e 100644 --- a/src/openai/types/evals/create_eval_completions_run_data_source_param.py +++ b/src/openai/types/evals/create_eval_completions_run_data_source_param.py @@ -171,6 +171,9 @@ class SamplingParams(TypedDict, total=False): supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response. + + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. """ response_format: SamplingParamsResponseFormat diff --git a/src/openai/types/evals/run_cancel_response.py b/src/openai/types/evals/run_cancel_response.py index d04d4ff657..084dd6ce5c 100644 --- a/src/openai/types/evals/run_cancel_response.py +++ b/src/openai/types/evals/run_cancel_response.py @@ -106,6 +106,9 @@ class DataSourceResponsesSourceResponses(BaseModel): supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response. + + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. """ temperature: Optional[float] = None @@ -241,6 +244,9 @@ class DataSourceResponsesSamplingParams(BaseModel): supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response. + + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. """ seed: Optional[int] = None diff --git a/src/openai/types/evals/run_create_params.py b/src/openai/types/evals/run_create_params.py index 6ff897b5de..f114fae6a4 100644 --- a/src/openai/types/evals/run_create_params.py +++ b/src/openai/types/evals/run_create_params.py @@ -119,6 +119,9 @@ class DataSourceCreateEvalResponsesRunDataSourceSourceResponses(TypedDict, total supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response. + + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. """ temperature: Optional[float] @@ -259,6 +262,9 @@ class DataSourceCreateEvalResponsesRunDataSourceSamplingParams(TypedDict, total= supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response. + + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. """ seed: int diff --git a/src/openai/types/evals/run_create_response.py b/src/openai/types/evals/run_create_response.py index defa275c8c..1343335e0d 100644 --- a/src/openai/types/evals/run_create_response.py +++ b/src/openai/types/evals/run_create_response.py @@ -106,6 +106,9 @@ class DataSourceResponsesSourceResponses(BaseModel): supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response. + + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. """ temperature: Optional[float] = None @@ -241,6 +244,9 @@ class DataSourceResponsesSamplingParams(BaseModel): supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response. + + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. """ seed: Optional[int] = None diff --git a/src/openai/types/evals/run_list_response.py b/src/openai/types/evals/run_list_response.py index 7fe0e55ace..7c32ce54a2 100644 --- a/src/openai/types/evals/run_list_response.py +++ b/src/openai/types/evals/run_list_response.py @@ -106,6 +106,9 @@ class DataSourceResponsesSourceResponses(BaseModel): supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response. + + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. """ temperature: Optional[float] = None @@ -241,6 +244,9 @@ class DataSourceResponsesSamplingParams(BaseModel): supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response. + + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. """ seed: Optional[int] = None diff --git a/src/openai/types/evals/run_retrieve_response.py b/src/openai/types/evals/run_retrieve_response.py index a50520f17d..f1212c1671 100644 --- a/src/openai/types/evals/run_retrieve_response.py +++ b/src/openai/types/evals/run_retrieve_response.py @@ -106,6 +106,9 @@ class DataSourceResponsesSourceResponses(BaseModel): supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response. + + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. """ temperature: Optional[float] = None @@ -241,6 +244,9 @@ class DataSourceResponsesSamplingParams(BaseModel): supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response. + + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. """ seed: Optional[int] = None diff --git a/src/openai/types/graders/score_model_grader.py b/src/openai/types/graders/score_model_grader.py index 908c6f91d3..35e2dc1468 100644 --- a/src/openai/types/graders/score_model_grader.py +++ b/src/openai/types/graders/score_model_grader.py @@ -70,6 +70,9 @@ class SamplingParams(BaseModel): supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response. + + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. """ seed: Optional[int] = None diff --git a/src/openai/types/graders/score_model_grader_param.py b/src/openai/types/graders/score_model_grader_param.py index 743944e099..168feeae13 100644 --- a/src/openai/types/graders/score_model_grader_param.py +++ b/src/openai/types/graders/score_model_grader_param.py @@ -76,6 +76,9 @@ class SamplingParams(TypedDict, total=False): supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response. + + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. """ seed: Optional[int] diff --git a/src/openai/types/shared/comparison_filter.py b/src/openai/types/shared/comparison_filter.py index 2ec2651ff2..33415ca4f9 100644 --- a/src/openai/types/shared/comparison_filter.py +++ b/src/openai/types/shared/comparison_filter.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Union +from typing import List, Union from typing_extensions import Literal from ..._models import BaseModel @@ -13,7 +13,9 @@ class ComparisonFilter(BaseModel): """The key to compare against the value.""" type: Literal["eq", "ne", "gt", "gte", "lt", "lte"] - """Specifies the comparison operator: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`. + """ + Specifies the comparison operator: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `in`, + `nin`. - `eq`: equals - `ne`: not equal @@ -21,9 +23,11 @@ class ComparisonFilter(BaseModel): - `gte`: greater than or equal - `lt`: less than - `lte`: less than or equal + - `in`: in + - `nin`: not in """ - value: Union[str, float, bool] + value: Union[str, float, bool, List[Union[str, float]]] """ The value to compare against the attribute key; supports string, number, or boolean types. diff --git a/src/openai/types/shared/reasoning.py b/src/openai/types/shared/reasoning.py index 24ce301526..2cf34eb9ae 100644 --- a/src/openai/types/shared/reasoning.py +++ b/src/openai/types/shared/reasoning.py @@ -17,6 +17,9 @@ class Reasoning(BaseModel): supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response. + + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. """ generate_summary: Optional[Literal["auto", "concise", "detailed"]] = None diff --git a/src/openai/types/shared_params/comparison_filter.py b/src/openai/types/shared_params/comparison_filter.py index 38edd315ed..1c40729c19 100644 --- a/src/openai/types/shared_params/comparison_filter.py +++ b/src/openai/types/shared_params/comparison_filter.py @@ -5,6 +5,8 @@ from typing import Union from typing_extensions import Literal, Required, TypedDict +from ..._types import SequenceNotStr + __all__ = ["ComparisonFilter"] @@ -13,7 +15,9 @@ class ComparisonFilter(TypedDict, total=False): """The key to compare against the value.""" type: Required[Literal["eq", "ne", "gt", "gte", "lt", "lte"]] - """Specifies the comparison operator: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`. + """ + Specifies the comparison operator: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `in`, + `nin`. - `eq`: equals - `ne`: not equal @@ -21,9 +25,11 @@ class ComparisonFilter(TypedDict, total=False): - `gte`: greater than or equal - `lt`: less than - `lte`: less than or equal + - `in`: in + - `nin`: not in """ - value: Required[Union[str, float, bool]] + value: Required[Union[str, float, bool, SequenceNotStr[Union[str, float]]]] """ The value to compare against the attribute key; supports string, number, or boolean types. diff --git a/src/openai/types/shared_params/reasoning.py b/src/openai/types/shared_params/reasoning.py index 7eab2c76f7..d5461a4eaa 100644 --- a/src/openai/types/shared_params/reasoning.py +++ b/src/openai/types/shared_params/reasoning.py @@ -18,6 +18,9 @@ class Reasoning(TypedDict, total=False): supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response. + + Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning + effort. """ generate_summary: Optional[Literal["auto", "concise", "detailed"]] diff --git a/src/openai/types/vector_stores/vector_store_file.py b/src/openai/types/vector_stores/vector_store_file.py index b59a61dfb0..001584dfd7 100644 --- a/src/openai/types/vector_stores/vector_store_file.py +++ b/src/openai/types/vector_stores/vector_store_file.py @@ -11,7 +11,7 @@ class LastError(BaseModel): code: Literal["server_error", "unsupported_file", "invalid_file"] - """One of `server_error` or `rate_limit_exceeded`.""" + """One of `server_error`, `unsupported_file`, or `invalid_file`.""" message: str """A human-readable description of the error.""" From e5f93f5daee9f3fc7646833ac235b1693f192a56 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 10 Oct 2025 01:10:06 +0000 Subject: [PATCH 519/769] release: 2.3.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index bfc26f9c4e..75ec52fc91 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.2.0" + ".": "2.3.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 336c6601a2..66eec00fea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 2.3.0 (2025-10-10) + +Full Changelog: [v2.2.0...v2.3.0](https://github.com/openai/openai-python/compare/v2.2.0...v2.3.0) + +### Features + +* **api:** comparison filter in/not in ([aa49f62](https://github.com/openai/openai-python/commit/aa49f626a6ea9d77ad008badfb3741e16232d62f)) + + +### Chores + +* **package:** bump jiter to >=0.10.0 to support Python 3.14 ([#2618](https://github.com/openai/openai-python/issues/2618)) ([aa445ca](https://github.com/openai/openai-python/commit/aa445cab5c93c6908697fe98e73e16963330b141)) + ## 2.2.0 (2025-10-06) Full Changelog: [v2.1.0...v2.2.0](https://github.com/openai/openai-python/compare/v2.1.0...v2.2.0) diff --git a/pyproject.toml b/pyproject.toml index bb5eb7cf41..7197505229 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.2.0" +version = "2.3.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 2fdb2912ef..f202a6d61c 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__ = "2.2.0" # x-release-please-version +__version__ = "2.3.0" # x-release-please-version From b20a9e7b813a12b22202987f512d913433b07fcf Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 10 Oct 2025 08:49:48 +0000 Subject: [PATCH 520/769] chore(internal): detect missing future annotations with ruff --- pyproject.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 7197505229..0f773e5fa4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -256,6 +256,8 @@ select = [ "B", # remove unused imports "F401", + # check for missing future annotations + "FA102", # bare except statements "E722", # unused arguments @@ -278,6 +280,8 @@ unfixable = [ "T203", ] +extend-safe-fixes = ["FA102"] + [tool.ruff.lint.flake8-tidy-imports.banned-api] "functools.lru_cache".msg = "This function does not retain type information for the wrapped function's arguments; The `lru_cache` function from `_utils` should be used instead" From d5c64434b7b1a500e074913cd87d8a6c09f1c13e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 15 Oct 2025 20:10:15 +0000 Subject: [PATCH 521/769] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index b5d9915ab8..f6f2dd4705 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 136 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-e66e85fb7f72477256dca1acb6b23396989d381c5c1b318de564195436bcb93f.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-242fe01994cc3c6c2b1a76d8e1eaa832303fa870e4e40de4a2303ac5ce17369a.yml openapi_spec_hash: 0a4bbb5aa0ae532a072bd6b3854e70b1 -config_hash: 89bf7bb3a1f9439ffc6ea0e7dc57ba9b +config_hash: c6362759d174c1ff65e656b1cfb5efdb From 8cdfd0650ef548178939607eb39adf5df4af5b7d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 16 Oct 2025 14:46:54 +0000 Subject: [PATCH 522/769] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index f6f2dd4705..8bd7c486ba 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 136 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-242fe01994cc3c6c2b1a76d8e1eaa832303fa870e4e40de4a2303ac5ce17369a.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-11d308a9ef78ad01aa11c880a084a3982276800d7994db3f454aa515474977d7.yml openapi_spec_hash: 0a4bbb5aa0ae532a072bd6b3854e70b1 -config_hash: c6362759d174c1ff65e656b1cfb5efdb +config_hash: f0940d0906846178759ef7128e4cb98e From 25cbb74f835206c497df2772205c7b2225951989 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 16 Oct 2025 14:55:31 +0000 Subject: [PATCH 523/769] feat(api): Add support for gpt-4o-transcribe-diarize on audio/transcriptions endpoint --- .stats.yml | 6 +- api.md | 3 + src/openai/resources/audio/transcriptions.py | 278 +++++++++++++++--- src/openai/resources/audio/translations.py | 8 +- .../resources/vector_stores/vector_stores.py | 10 + src/openai/types/audio/__init__.py | 3 + .../audio/transcription_create_params.py | 41 ++- .../audio/transcription_create_response.py | 3 +- .../types/audio/transcription_diarized.py | 63 ++++ .../audio/transcription_diarized_segment.py | 32 ++ .../types/audio/transcription_stream_event.py | 4 +- .../audio/transcription_text_delta_event.py | 6 + .../audio/transcription_text_segment_event.py | 27 ++ src/openai/types/audio_model.py | 2 +- src/openai/types/audio_response_format.py | 2 +- .../types/realtime/audio_transcription.py | 15 +- .../realtime/audio_transcription_param.py | 11 +- .../types/vector_store_create_params.py | 6 + .../audio/test_transcriptions.py | 8 + tests/api_resources/test_vector_stores.py | 2 + tests/lib/test_audio.py | 26 +- 21 files changed, 475 insertions(+), 81 deletions(-) create mode 100644 src/openai/types/audio/transcription_diarized.py create mode 100644 src/openai/types/audio/transcription_diarized_segment.py create mode 100644 src/openai/types/audio/transcription_text_segment_event.py diff --git a/.stats.yml b/.stats.yml index 8bd7c486ba..d0ff2b0dc2 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 136 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-11d308a9ef78ad01aa11c880a084a3982276800d7994db3f454aa515474977d7.yml -openapi_spec_hash: 0a4bbb5aa0ae532a072bd6b3854e70b1 -config_hash: f0940d0906846178759ef7128e4cb98e +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-104cced8f4c7436a76eea02e26307828166405ccfb296faffb008b72772c11a7.yml +openapi_spec_hash: fdc03ed84a65a31b80da909255e53924 +config_hash: 03b48e9b8c7231a902403210dbd7dfa0 diff --git a/api.md b/api.md index 1c170ccdd8..7eb296318f 100644 --- a/api.md +++ b/api.md @@ -171,11 +171,14 @@ Types: ```python from openai.types.audio import ( Transcription, + TranscriptionDiarized, + TranscriptionDiarizedSegment, TranscriptionInclude, TranscriptionSegment, TranscriptionStreamEvent, TranscriptionTextDeltaEvent, TranscriptionTextDoneEvent, + TranscriptionTextSegmentEvent, TranscriptionVerbose, TranscriptionWord, TranscriptionCreateResponse, diff --git a/src/openai/resources/audio/transcriptions.py b/src/openai/resources/audio/transcriptions.py index 1fe8866562..52e44bffb7 100644 --- a/src/openai/resources/audio/transcriptions.py +++ b/src/openai/resources/audio/transcriptions.py @@ -9,8 +9,17 @@ import httpx from ... import _legacy_response -from ...types import AudioResponseFormat -from ..._types import Body, Omit, Query, Headers, NotGiven, FileTypes, omit, not_given +from ..._types import ( + Body, + Omit, + Query, + Headers, + NotGiven, + FileTypes, + SequenceNotStr, + omit, + not_given, +) from ..._utils import extract_files, required_args, maybe_transform, deepcopy_minimal, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource @@ -23,6 +32,7 @@ from ...types.audio_response_format import AudioResponseFormat from ...types.audio.transcription_include import TranscriptionInclude from ...types.audio.transcription_verbose import TranscriptionVerbose +from ...types.audio.transcription_diarized import TranscriptionDiarized from ...types.audio.transcription_stream_event import TranscriptionStreamEvent from ...types.audio.transcription_create_response import TranscriptionCreateResponse @@ -93,6 +103,66 @@ def create( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TranscriptionVerbose: ... + model's confidence in the transcription. `logprobs` only works with + response_format set to `json` and only with the models `gpt-4o-transcribe` and + `gpt-4o-mini-transcribe`. This field is not supported when using + `gpt-4o-transcribe-diarize`. + + known_speaker_names: Optional list of speaker names that correspond to the audio samples provided in + `known_speaker_references[]`. Each entry should be a short identifier (for + example `customer` or `agent`). Up to 4 speakers are supported. + + known_speaker_references: Optional list of audio samples (as + [data URLs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs)) + that contain known speaker references matching `known_speaker_names[]`. Each + sample must be between 2 and 10 seconds, and can use any of the same input audio + formats supported by `file`. + + language: The language of the input audio. Supplying the input language in + [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) + format will improve accuracy and latency. + + prompt: An optional text to guide the model's style or continue a previous audio + segment. The + [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) + should match the audio language. This field is not supported when using + `gpt-4o-transcribe-diarize`. + + response_format: The format of the output, in one of these options: `json`, `text`, `srt`, + `verbose_json`, `vtt`, or `diarized_json`. For `gpt-4o-transcribe` and + `gpt-4o-mini-transcribe`, the only supported format is `json`. For + `gpt-4o-transcribe-diarize`, the supported formats are `json`, `text`, and + `diarized_json`, with `diarized_json` required to receive speaker annotations. + + stream: If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section of the Speech-to-Text guide](https://platform.openai.com/docs/guides/speech-to-text?lang=curl#streaming-transcriptions) + for more information. + + Note: Streaming is not supported for the `whisper-1` model and will be ignored. + + temperature: The sampling temperature, between 0 and 1. Higher values like 0.8 will make the + output more random, while lower values like 0.2 will make it more focused and + deterministic. If set to 0, the model will use + [log probability](https://en.wikipedia.org/wiki/Log_probability) to + automatically increase the temperature until certain thresholds are hit. + + timestamp_granularities: The timestamp granularities to populate for this transcription. + `response_format` must be set `verbose_json` to use timestamp granularities. + Either or both of these options are supported: `word`, or `segment`. Note: There + is no additional latency for segment timestamps, but generating word timestamps + incurs additional latency. This option is not available for + `gpt-4o-transcribe-diarize`. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + ) -> Transcription: ... + @overload def create( self, @@ -114,6 +184,27 @@ def create( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> str: ... + @overload + def create( + self, + *, + file: FileTypes, + model: Union[str, AudioModel], + chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | Omit = omit, + response_format: Literal["diarized_json"], + known_speaker_names: SequenceNotStr[str] | Omit = omit, + known_speaker_references: SequenceNotStr[str] | Omit = omit, + language: str | Omit = omit, + temperature: float | Omit = omit, + timestamp_granularities: List[Literal["word", "segment"]] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TranscriptionDiarized: ... + @overload def create( self, @@ -123,6 +214,8 @@ def create( stream: Literal[True], chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | Omit = omit, include: List[TranscriptionInclude] | Omit = omit, + known_speaker_names: SequenceNotStr[str] | Omit = omit, + known_speaker_references: SequenceNotStr[str] | Omit = omit, language: str | Omit = omit, prompt: str | Omit = omit, response_format: Union[AudioResponseFormat, Omit] = omit, @@ -144,8 +237,8 @@ def create( flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. model: ID of the model to use. The options are `gpt-4o-transcribe`, - `gpt-4o-mini-transcribe`, and `whisper-1` (which is powered by our open source - Whisper V2 model). + `gpt-4o-mini-transcribe`, `whisper-1` (which is powered by our open source + Whisper V2 model), and `gpt-4o-transcribe-diarize`. stream: If set to true, the model response data will be streamed to the client as it is generated using @@ -160,12 +253,25 @@ def create( first normalizes loudness and then uses voice activity detection (VAD) to choose boundaries. `server_vad` object can be provided to tweak VAD detection parameters manually. If unset, the audio is transcribed as a single block. + Required when using `gpt-4o-transcribe-diarize` for inputs longer than 30 + seconds. include: Additional information to include in the transcription response. `logprobs` will return the log probabilities of the tokens in the response to understand the model's confidence in the transcription. `logprobs` only works with response_format set to `json` and only with the models `gpt-4o-transcribe` and - `gpt-4o-mini-transcribe`. + `gpt-4o-mini-transcribe`. This field is not supported when using + `gpt-4o-transcribe-diarize`. + + known_speaker_names: Optional list of speaker names that correspond to the audio samples provided in + `known_speaker_references[]`. Each entry should be a short identifier (for + example `customer` or `agent`). Up to 4 speakers are supported. + + known_speaker_references: Optional list of audio samples (as + [data URLs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs)) + that contain known speaker references matching `known_speaker_names[]`. Each + sample must be between 2 and 10 seconds, and can use any of the same input audio + formats supported by `file`. language: The language of the input audio. Supplying the input language in [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) @@ -174,11 +280,14 @@ def create( prompt: An optional text to guide the model's style or continue a previous audio segment. The [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) - should match the audio language. + should match the audio language. This field is not supported when using + `gpt-4o-transcribe-diarize`. response_format: The format of the output, in one of these options: `json`, `text`, `srt`, - `verbose_json`, or `vtt`. For `gpt-4o-transcribe` and `gpt-4o-mini-transcribe`, - the only supported format is `json`. + `verbose_json`, `vtt`, or `diarized_json`. For `gpt-4o-transcribe` and + `gpt-4o-mini-transcribe`, the only supported format is `json`. For + `gpt-4o-transcribe-diarize`, the supported formats are `json`, `text`, and + `diarized_json`, with `diarized_json` required to receive speaker annotations. temperature: The sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and @@ -190,7 +299,8 @@ def create( `response_format` must be set `verbose_json` to use timestamp granularities. Either or both of these options are supported: `word`, or `segment`. Note: There is no additional latency for segment timestamps, but generating word timestamps - incurs additional latency. + incurs additional latency. This option is not available for + `gpt-4o-transcribe-diarize`. extra_headers: Send extra headers @@ -211,6 +321,8 @@ def create( stream: bool, chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | Omit = omit, include: List[TranscriptionInclude] | Omit = omit, + known_speaker_names: SequenceNotStr[str] | Omit = omit, + known_speaker_references: SequenceNotStr[str] | Omit = omit, language: str | Omit = omit, prompt: str | Omit = omit, response_format: Union[AudioResponseFormat, Omit] = omit, @@ -232,8 +344,8 @@ def create( flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. model: ID of the model to use. The options are `gpt-4o-transcribe`, - `gpt-4o-mini-transcribe`, and `whisper-1` (which is powered by our open source - Whisper V2 model). + `gpt-4o-mini-transcribe`, `whisper-1` (which is powered by our open source + Whisper V2 model), and `gpt-4o-transcribe-diarize`. stream: If set to true, the model response data will be streamed to the client as it is generated using @@ -248,12 +360,25 @@ def create( first normalizes loudness and then uses voice activity detection (VAD) to choose boundaries. `server_vad` object can be provided to tweak VAD detection parameters manually. If unset, the audio is transcribed as a single block. + Required when using `gpt-4o-transcribe-diarize` for inputs longer than 30 + seconds. include: Additional information to include in the transcription response. `logprobs` will return the log probabilities of the tokens in the response to understand the model's confidence in the transcription. `logprobs` only works with response_format set to `json` and only with the models `gpt-4o-transcribe` and - `gpt-4o-mini-transcribe`. + `gpt-4o-mini-transcribe`. This field is not supported when using + `gpt-4o-transcribe-diarize`. + + known_speaker_names: Optional list of speaker names that correspond to the audio samples provided in + `known_speaker_references[]`. Each entry should be a short identifier (for + example `customer` or `agent`). Up to 4 speakers are supported. + + known_speaker_references: Optional list of audio samples (as + [data URLs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs)) + that contain known speaker references matching `known_speaker_names[]`. Each + sample must be between 2 and 10 seconds, and can use any of the same input audio + formats supported by `file`. language: The language of the input audio. Supplying the input language in [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) @@ -262,11 +387,14 @@ def create( prompt: An optional text to guide the model's style or continue a previous audio segment. The [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) - should match the audio language. + should match the audio language. This field is not supported when using + `gpt-4o-transcribe-diarize`. response_format: The format of the output, in one of these options: `json`, `text`, `srt`, - `verbose_json`, or `vtt`. For `gpt-4o-transcribe` and `gpt-4o-mini-transcribe`, - the only supported format is `json`. + `verbose_json`, `vtt`, or `diarized_json`. For `gpt-4o-transcribe` and + `gpt-4o-mini-transcribe`, the only supported format is `json`. For + `gpt-4o-transcribe-diarize`, the supported formats are `json`, `text`, and + `diarized_json`, with `diarized_json` required to receive speaker annotations. temperature: The sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and @@ -278,7 +406,8 @@ def create( `response_format` must be set `verbose_json` to use timestamp granularities. Either or both of these options are supported: `word`, or `segment`. Note: There is no additional latency for segment timestamps, but generating word timestamps - incurs additional latency. + incurs additional latency. This option is not available for + `gpt-4o-transcribe-diarize`. extra_headers: Send extra headers @@ -298,6 +427,8 @@ def create( model: Union[str, AudioModel], chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | Omit = omit, include: List[TranscriptionInclude] | Omit = omit, + known_speaker_names: SequenceNotStr[str] | Omit = omit, + known_speaker_references: SequenceNotStr[str] | Omit = omit, language: str | Omit = omit, prompt: str | Omit = omit, response_format: Union[AudioResponseFormat, Omit] = omit, @@ -310,13 +441,15 @@ def create( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> str | Transcription | TranscriptionVerbose | Stream[TranscriptionStreamEvent]: + ) -> str | Transcription | TranscriptionDiarized | TranscriptionVerbose | Stream[TranscriptionStreamEvent]: body = deepcopy_minimal( { "file": file, "model": model, "chunking_strategy": chunking_strategy, "include": include, + "known_speaker_names": known_speaker_names, + "known_speaker_references": known_speaker_references, "language": language, "prompt": prompt, "response_format": response_format, @@ -376,6 +509,8 @@ async def create( model: Union[str, AudioModel], chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | Omit = omit, include: List[TranscriptionInclude] | Omit = omit, + known_speaker_names: SequenceNotStr[str] | Omit = omit, + known_speaker_references: SequenceNotStr[str] | Omit = omit, language: str | Omit = omit, prompt: str | Omit = omit, response_format: Union[Literal["json"], Omit] = omit, @@ -398,19 +533,32 @@ async def create( flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. model: ID of the model to use. The options are `gpt-4o-transcribe`, - `gpt-4o-mini-transcribe`, and `whisper-1` (which is powered by our open source - Whisper V2 model). + `gpt-4o-mini-transcribe`, `whisper-1` (which is powered by our open source + Whisper V2 model), and `gpt-4o-transcribe-diarize`. chunking_strategy: Controls how the audio is cut into chunks. When set to `"auto"`, the server first normalizes loudness and then uses voice activity detection (VAD) to choose boundaries. `server_vad` object can be provided to tweak VAD detection parameters manually. If unset, the audio is transcribed as a single block. + Required when using `gpt-4o-transcribe-diarize` for inputs longer than 30 + seconds. include: Additional information to include in the transcription response. `logprobs` will return the log probabilities of the tokens in the response to understand the model's confidence in the transcription. `logprobs` only works with response_format set to `json` and only with the models `gpt-4o-transcribe` and - `gpt-4o-mini-transcribe`. + `gpt-4o-mini-transcribe`. This field is not supported when using + `gpt-4o-transcribe-diarize`. + + known_speaker_names: Optional list of speaker names that correspond to the audio samples provided in + `known_speaker_references[]`. Each entry should be a short identifier (for + example `customer` or `agent`). Up to 4 speakers are supported. + + known_speaker_references: Optional list of audio samples (as + [data URLs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs)) + that contain known speaker references matching `known_speaker_names[]`. Each + sample must be between 2 and 10 seconds, and can use any of the same input audio + formats supported by `file`. language: The language of the input audio. Supplying the input language in [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) @@ -419,11 +567,14 @@ async def create( prompt: An optional text to guide the model's style or continue a previous audio segment. The [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) - should match the audio language. + should match the audio language. This field is not supported when using + `gpt-4o-transcribe-diarize`. response_format: The format of the output, in one of these options: `json`, `text`, `srt`, - `verbose_json`, or `vtt`. For `gpt-4o-transcribe` and `gpt-4o-mini-transcribe`, - the only supported format is `json`. + `verbose_json`, `vtt`, or `diarized_json`. For `gpt-4o-transcribe` and + `gpt-4o-mini-transcribe`, the only supported format is `json`. For + `gpt-4o-transcribe-diarize`, the supported formats are `json`, `text`, and + `diarized_json`, with `diarized_json` required to receive speaker annotations. stream: If set to true, the model response data will be streamed to the client as it is generated using @@ -444,7 +595,8 @@ async def create( `response_format` must be set `verbose_json` to use timestamp granularities. Either or both of these options are supported: `word`, or `segment`. Note: There is no additional latency for segment timestamps, but generating word timestamps - incurs additional latency. + incurs additional latency. This option is not available for + `gpt-4o-transcribe-diarize`. extra_headers: Send extra headers @@ -502,6 +654,8 @@ async def create( stream: Literal[True], chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | Omit = omit, include: List[TranscriptionInclude] | Omit = omit, + known_speaker_names: SequenceNotStr[str] | Omit = omit, + known_speaker_references: SequenceNotStr[str] | Omit = omit, language: str | Omit = omit, prompt: str | Omit = omit, response_format: Union[AudioResponseFormat, Omit] = omit, @@ -523,8 +677,8 @@ async def create( flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. model: ID of the model to use. The options are `gpt-4o-transcribe`, - `gpt-4o-mini-transcribe`, and `whisper-1` (which is powered by our open source - Whisper V2 model). + `gpt-4o-mini-transcribe`, `whisper-1` (which is powered by our open source + Whisper V2 model), and `gpt-4o-transcribe-diarize`. stream: If set to true, the model response data will be streamed to the client as it is generated using @@ -539,12 +693,25 @@ async def create( first normalizes loudness and then uses voice activity detection (VAD) to choose boundaries. `server_vad` object can be provided to tweak VAD detection parameters manually. If unset, the audio is transcribed as a single block. + Required when using `gpt-4o-transcribe-diarize` for inputs longer than 30 + seconds. include: Additional information to include in the transcription response. `logprobs` will return the log probabilities of the tokens in the response to understand the model's confidence in the transcription. `logprobs` only works with response_format set to `json` and only with the models `gpt-4o-transcribe` and - `gpt-4o-mini-transcribe`. + `gpt-4o-mini-transcribe`. This field is not supported when using + `gpt-4o-transcribe-diarize`. + + known_speaker_names: Optional list of speaker names that correspond to the audio samples provided in + `known_speaker_references[]`. Each entry should be a short identifier (for + example `customer` or `agent`). Up to 4 speakers are supported. + + known_speaker_references: Optional list of audio samples (as + [data URLs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs)) + that contain known speaker references matching `known_speaker_names[]`. Each + sample must be between 2 and 10 seconds, and can use any of the same input audio + formats supported by `file`. language: The language of the input audio. Supplying the input language in [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) @@ -553,11 +720,14 @@ async def create( prompt: An optional text to guide the model's style or continue a previous audio segment. The [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) - should match the audio language. + should match the audio language. This field is not supported when using + `gpt-4o-transcribe-diarize`. response_format: The format of the output, in one of these options: `json`, `text`, `srt`, - `verbose_json`, or `vtt`. For `gpt-4o-transcribe` and `gpt-4o-mini-transcribe`, - the only supported format is `json`. + `verbose_json`, `vtt`, or `diarized_json`. For `gpt-4o-transcribe` and + `gpt-4o-mini-transcribe`, the only supported format is `json`. For + `gpt-4o-transcribe-diarize`, the supported formats are `json`, `text`, and + `diarized_json`, with `diarized_json` required to receive speaker annotations. temperature: The sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and @@ -569,7 +739,8 @@ async def create( `response_format` must be set `verbose_json` to use timestamp granularities. Either or both of these options are supported: `word`, or `segment`. Note: There is no additional latency for segment timestamps, but generating word timestamps - incurs additional latency. + incurs additional latency. This option is not available for + `gpt-4o-transcribe-diarize`. extra_headers: Send extra headers @@ -590,6 +761,8 @@ async def create( stream: bool, chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | Omit = omit, include: List[TranscriptionInclude] | Omit = omit, + known_speaker_names: SequenceNotStr[str] | Omit = omit, + known_speaker_references: SequenceNotStr[str] | Omit = omit, language: str | Omit = omit, prompt: str | Omit = omit, response_format: Union[AudioResponseFormat, Omit] = omit, @@ -611,8 +784,8 @@ async def create( flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. model: ID of the model to use. The options are `gpt-4o-transcribe`, - `gpt-4o-mini-transcribe`, and `whisper-1` (which is powered by our open source - Whisper V2 model). + `gpt-4o-mini-transcribe`, `whisper-1` (which is powered by our open source + Whisper V2 model), and `gpt-4o-transcribe-diarize`. stream: If set to true, the model response data will be streamed to the client as it is generated using @@ -627,12 +800,25 @@ async def create( first normalizes loudness and then uses voice activity detection (VAD) to choose boundaries. `server_vad` object can be provided to tweak VAD detection parameters manually. If unset, the audio is transcribed as a single block. + Required when using `gpt-4o-transcribe-diarize` for inputs longer than 30 + seconds. include: Additional information to include in the transcription response. `logprobs` will return the log probabilities of the tokens in the response to understand the model's confidence in the transcription. `logprobs` only works with response_format set to `json` and only with the models `gpt-4o-transcribe` and - `gpt-4o-mini-transcribe`. + `gpt-4o-mini-transcribe`. This field is not supported when using + `gpt-4o-transcribe-diarize`. + + known_speaker_names: Optional list of speaker names that correspond to the audio samples provided in + `known_speaker_references[]`. Each entry should be a short identifier (for + example `customer` or `agent`). Up to 4 speakers are supported. + + known_speaker_references: Optional list of audio samples (as + [data URLs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs)) + that contain known speaker references matching `known_speaker_names[]`. Each + sample must be between 2 and 10 seconds, and can use any of the same input audio + formats supported by `file`. language: The language of the input audio. Supplying the input language in [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) @@ -641,11 +827,14 @@ async def create( prompt: An optional text to guide the model's style or continue a previous audio segment. The [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) - should match the audio language. + should match the audio language. This field is not supported when using + `gpt-4o-transcribe-diarize`. response_format: The format of the output, in one of these options: `json`, `text`, `srt`, - `verbose_json`, or `vtt`. For `gpt-4o-transcribe` and `gpt-4o-mini-transcribe`, - the only supported format is `json`. + `verbose_json`, `vtt`, or `diarized_json`. For `gpt-4o-transcribe` and + `gpt-4o-mini-transcribe`, the only supported format is `json`. For + `gpt-4o-transcribe-diarize`, the supported formats are `json`, `text`, and + `diarized_json`, with `diarized_json` required to receive speaker annotations. temperature: The sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and @@ -657,7 +846,8 @@ async def create( `response_format` must be set `verbose_json` to use timestamp granularities. Either or both of these options are supported: `word`, or `segment`. Note: There is no additional latency for segment timestamps, but generating word timestamps - incurs additional latency. + incurs additional latency. This option is not available for + `gpt-4o-transcribe-diarize`. extra_headers: Send extra headers @@ -677,6 +867,8 @@ async def create( model: Union[str, AudioModel], chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | Omit = omit, include: List[TranscriptionInclude] | Omit = omit, + known_speaker_names: SequenceNotStr[str] | Omit = omit, + known_speaker_references: SequenceNotStr[str] | Omit = omit, language: str | Omit = omit, prompt: str | Omit = omit, response_format: Union[AudioResponseFormat, Omit] = omit, @@ -689,13 +881,15 @@ async def create( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Transcription | TranscriptionVerbose | str | AsyncStream[TranscriptionStreamEvent]: + ) -> Transcription | TranscriptionVerbose | TranscriptionDiarized | str | AsyncStream[TranscriptionStreamEvent]: body = deepcopy_minimal( { "file": file, "model": model, "chunking_strategy": chunking_strategy, "include": include, + "known_speaker_names": known_speaker_names, + "known_speaker_references": known_speaker_references, "language": language, "prompt": prompt, "response_format": response_format, @@ -764,8 +958,8 @@ def __init__(self, transcriptions: AsyncTranscriptions) -> None: def _get_response_format_type( - response_format: Literal["json", "text", "srt", "verbose_json", "vtt"] | Omit, -) -> type[Transcription | TranscriptionVerbose | str]: + response_format: AudioResponseFormat | Omit, +) -> type[Transcription | TranscriptionVerbose | TranscriptionDiarized | str]: if isinstance(response_format, Omit) or response_format is None: # pyright: ignore[reportUnnecessaryComparison] return Transcription @@ -773,6 +967,8 @@ def _get_response_format_type( return Transcription elif response_format == "verbose_json": return TranscriptionVerbose + elif response_format == "diarized_json": + return TranscriptionDiarized elif response_format == "srt" or response_format == "text" or response_format == "vtt": return str elif TYPE_CHECKING: # type: ignore[unreachable] diff --git a/src/openai/resources/audio/translations.py b/src/openai/resources/audio/translations.py index a4f844db13..310f901fb3 100644 --- a/src/openai/resources/audio/translations.py +++ b/src/openai/resources/audio/translations.py @@ -349,7 +349,7 @@ def __init__(self, translations: AsyncTranslations) -> None: def _get_response_format_type( - response_format: Literal["json", "text", "srt", "verbose_json", "vtt"] | Omit, + response_format: AudioResponseFormat | Omit, ) -> type[Translation | TranslationVerbose | str]: if isinstance(response_format, Omit) or response_format is None: # pyright: ignore[reportUnnecessaryComparison] return Translation @@ -360,8 +360,8 @@ def _get_response_format_type( return TranslationVerbose elif response_format == "srt" or response_format == "text" or response_format == "vtt": return str - elif TYPE_CHECKING: # type: ignore[unreachable] + elif TYPE_CHECKING and response_format != "diarized_json": # type: ignore[unreachable] assert_never(response_format) else: - log.warn("Unexpected audio response format: %s", response_format) - return Transcription + log.warning("Unexpected audio response format: %s", response_format) + return Translation diff --git a/src/openai/resources/vector_stores/vector_stores.py b/src/openai/resources/vector_stores/vector_stores.py index 39548936c8..490e3e7fdb 100644 --- a/src/openai/resources/vector_stores/vector_stores.py +++ b/src/openai/resources/vector_stores/vector_stores.py @@ -79,6 +79,7 @@ def create( self, *, chunking_strategy: FileChunkingStrategyParam | Omit = omit, + description: str | Omit = omit, expires_after: vector_store_create_params.ExpiresAfter | Omit = omit, file_ids: SequenceNotStr[str] | Omit = omit, metadata: Optional[Metadata] | Omit = omit, @@ -97,6 +98,9 @@ def create( chunking_strategy: The chunking strategy used to chunk the file(s). If not set, will use the `auto` strategy. Only applicable if `file_ids` is non-empty. + description: A description for the vector store. Can be used to describe the vector store's + purpose. + expires_after: The expiration policy for a vector store. file_ids: A list of [File](https://platform.openai.com/docs/api-reference/files) IDs that @@ -126,6 +130,7 @@ def create( body=maybe_transform( { "chunking_strategy": chunking_strategy, + "description": description, "expires_after": expires_after, "file_ids": file_ids, "metadata": metadata, @@ -424,6 +429,7 @@ async def create( self, *, chunking_strategy: FileChunkingStrategyParam | Omit = omit, + description: str | Omit = omit, expires_after: vector_store_create_params.ExpiresAfter | Omit = omit, file_ids: SequenceNotStr[str] | Omit = omit, metadata: Optional[Metadata] | Omit = omit, @@ -442,6 +448,9 @@ async def create( chunking_strategy: The chunking strategy used to chunk the file(s). If not set, will use the `auto` strategy. Only applicable if `file_ids` is non-empty. + description: A description for the vector store. Can be used to describe the vector store's + purpose. + expires_after: The expiration policy for a vector store. file_ids: A list of [File](https://platform.openai.com/docs/api-reference/files) IDs that @@ -471,6 +480,7 @@ async def create( body=await async_maybe_transform( { "chunking_strategy": chunking_strategy, + "description": description, "expires_after": expires_after, "file_ids": file_ids, "metadata": metadata, diff --git a/src/openai/types/audio/__init__.py b/src/openai/types/audio/__init__.py index 396944ee47..2ff2b8185d 100644 --- a/src/openai/types/audio/__init__.py +++ b/src/openai/types/audio/__init__.py @@ -11,10 +11,13 @@ from .transcription_include import TranscriptionInclude as TranscriptionInclude from .transcription_segment import TranscriptionSegment as TranscriptionSegment from .transcription_verbose import TranscriptionVerbose as TranscriptionVerbose +from .transcription_diarized import TranscriptionDiarized as TranscriptionDiarized from .translation_create_params import TranslationCreateParams as TranslationCreateParams from .transcription_stream_event import TranscriptionStreamEvent as TranscriptionStreamEvent from .transcription_create_params import TranscriptionCreateParams as TranscriptionCreateParams from .translation_create_response import TranslationCreateResponse as TranslationCreateResponse from .transcription_create_response import TranscriptionCreateResponse as TranscriptionCreateResponse from .transcription_text_done_event import TranscriptionTextDoneEvent as TranscriptionTextDoneEvent +from .transcription_diarized_segment import TranscriptionDiarizedSegment as TranscriptionDiarizedSegment from .transcription_text_delta_event import TranscriptionTextDeltaEvent as TranscriptionTextDeltaEvent +from .transcription_text_segment_event import TranscriptionTextSegmentEvent as TranscriptionTextSegmentEvent diff --git a/src/openai/types/audio/transcription_create_params.py b/src/openai/types/audio/transcription_create_params.py index f7abcced87..adaef9f5fe 100644 --- a/src/openai/types/audio/transcription_create_params.py +++ b/src/openai/types/audio/transcription_create_params.py @@ -5,7 +5,7 @@ from typing import List, Union, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict -from ..._types import FileTypes +from ..._types import FileTypes, SequenceNotStr from ..audio_model import AudioModel from .transcription_include import TranscriptionInclude from ..audio_response_format import AudioResponseFormat @@ -29,8 +29,9 @@ class TranscriptionCreateParamsBase(TypedDict, total=False): model: Required[Union[str, AudioModel]] """ID of the model to use. - The options are `gpt-4o-transcribe`, `gpt-4o-mini-transcribe`, and `whisper-1` - (which is powered by our open source Whisper V2 model). + The options are `gpt-4o-transcribe`, `gpt-4o-mini-transcribe`, `whisper-1` + (which is powered by our open source Whisper V2 model), and + `gpt-4o-transcribe-diarize`. """ chunking_strategy: Optional[ChunkingStrategy] @@ -39,7 +40,8 @@ class TranscriptionCreateParamsBase(TypedDict, total=False): When set to `"auto"`, the server first normalizes loudness and then uses voice activity detection (VAD) to choose boundaries. `server_vad` object can be provided to tweak VAD detection parameters manually. If unset, the audio is - transcribed as a single block. + transcribed as a single block. Required when using `gpt-4o-transcribe-diarize` + for inputs longer than 30 seconds. """ include: List[TranscriptionInclude] @@ -48,7 +50,24 @@ class TranscriptionCreateParamsBase(TypedDict, total=False): return the log probabilities of the tokens in the response to understand the model's confidence in the transcription. `logprobs` only works with response_format set to `json` and only with the models `gpt-4o-transcribe` and - `gpt-4o-mini-transcribe`. + `gpt-4o-mini-transcribe`. This field is not supported when using + `gpt-4o-transcribe-diarize`. + """ + + known_speaker_names: SequenceNotStr[str] + """ + Optional list of speaker names that correspond to the audio samples provided in + `known_speaker_references[]`. Each entry should be a short identifier (for + example `customer` or `agent`). Up to 4 speakers are supported. + """ + + known_speaker_references: SequenceNotStr[str] + """ + Optional list of audio samples (as + [data URLs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs)) + that contain known speaker references matching `known_speaker_names[]`. Each + sample must be between 2 and 10 seconds, and can use any of the same input audio + formats supported by `file`. """ language: str @@ -64,14 +83,17 @@ class TranscriptionCreateParamsBase(TypedDict, total=False): segment. The [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) - should match the audio language. + should match the audio language. This field is not supported when using + `gpt-4o-transcribe-diarize`. """ response_format: AudioResponseFormat """ The format of the output, in one of these options: `json`, `text`, `srt`, - `verbose_json`, or `vtt`. For `gpt-4o-transcribe` and `gpt-4o-mini-transcribe`, - the only supported format is `json`. + `verbose_json`, `vtt`, or `diarized_json`. For `gpt-4o-transcribe` and + `gpt-4o-mini-transcribe`, the only supported format is `json`. For + `gpt-4o-transcribe-diarize`, the supported formats are `json`, `text`, and + `diarized_json`, with `diarized_json` required to receive speaker annotations. """ temperature: float @@ -89,7 +111,8 @@ class TranscriptionCreateParamsBase(TypedDict, total=False): `response_format` must be set `verbose_json` to use timestamp granularities. Either or both of these options are supported: `word`, or `segment`. Note: There is no additional latency for segment timestamps, but generating word timestamps - incurs additional latency. + incurs additional latency. This option is not available for + `gpt-4o-transcribe-diarize`. """ diff --git a/src/openai/types/audio/transcription_create_response.py b/src/openai/types/audio/transcription_create_response.py index 2f7bed8114..5717a3e701 100644 --- a/src/openai/types/audio/transcription_create_response.py +++ b/src/openai/types/audio/transcription_create_response.py @@ -5,7 +5,8 @@ from .transcription import Transcription from .transcription_verbose import TranscriptionVerbose +from .transcription_diarized import TranscriptionDiarized __all__ = ["TranscriptionCreateResponse"] -TranscriptionCreateResponse: TypeAlias = Union[Transcription, TranscriptionVerbose] +TranscriptionCreateResponse: TypeAlias = Union[Transcription, TranscriptionDiarized, TranscriptionVerbose] diff --git a/src/openai/types/audio/transcription_diarized.py b/src/openai/types/audio/transcription_diarized.py new file mode 100644 index 0000000000..b7dd2b8ebb --- /dev/null +++ b/src/openai/types/audio/transcription_diarized.py @@ -0,0 +1,63 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .transcription_diarized_segment import TranscriptionDiarizedSegment + +__all__ = ["TranscriptionDiarized", "Usage", "UsageTokens", "UsageTokensInputTokenDetails", "UsageDuration"] + + +class UsageTokensInputTokenDetails(BaseModel): + audio_tokens: Optional[int] = None + """Number of audio tokens billed for this request.""" + + text_tokens: Optional[int] = None + """Number of text tokens billed for this request.""" + + +class UsageTokens(BaseModel): + input_tokens: int + """Number of input tokens billed for this request.""" + + output_tokens: int + """Number of output tokens generated.""" + + total_tokens: int + """Total number of tokens used (input + output).""" + + type: Literal["tokens"] + """The type of the usage object. Always `tokens` for this variant.""" + + input_token_details: Optional[UsageTokensInputTokenDetails] = None + """Details about the input tokens billed for this request.""" + + +class UsageDuration(BaseModel): + seconds: float + """Duration of the input audio in seconds.""" + + type: Literal["duration"] + """The type of the usage object. Always `duration` for this variant.""" + + +Usage: TypeAlias = Annotated[Union[UsageTokens, UsageDuration], PropertyInfo(discriminator="type")] + + +class TranscriptionDiarized(BaseModel): + duration: float + """Duration of the input audio in seconds.""" + + segments: List[TranscriptionDiarizedSegment] + """Segments of the transcript annotated with timestamps and speaker labels.""" + + task: Literal["transcribe"] + """The type of task that was run. Always `transcribe`.""" + + text: str + """The concatenated transcript text for the entire audio input.""" + + usage: Optional[Usage] = None + """Token or duration usage statistics for the request.""" diff --git a/src/openai/types/audio/transcription_diarized_segment.py b/src/openai/types/audio/transcription_diarized_segment.py new file mode 100644 index 0000000000..fe87bb4fb8 --- /dev/null +++ b/src/openai/types/audio/transcription_diarized_segment.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["TranscriptionDiarizedSegment"] + + +class TranscriptionDiarizedSegment(BaseModel): + id: str + """Unique identifier for the segment.""" + + end: float + """End timestamp of the segment in seconds.""" + + speaker: str + """Speaker label for this segment. + + When known speakers are provided, the label matches `known_speaker_names[]`. + Otherwise speakers are labeled sequentially using capital letters (`A`, `B`, + ...). + """ + + start: float + """Start timestamp of the segment in seconds.""" + + text: str + """Transcript text for this segment.""" + + type: Literal["transcript.text.segment"] + """The type of the segment. Always `transcript.text.segment`.""" diff --git a/src/openai/types/audio/transcription_stream_event.py b/src/openai/types/audio/transcription_stream_event.py index 757077a280..77d3a3aeec 100644 --- a/src/openai/types/audio/transcription_stream_event.py +++ b/src/openai/types/audio/transcription_stream_event.py @@ -6,9 +6,11 @@ from ..._utils import PropertyInfo from .transcription_text_done_event import TranscriptionTextDoneEvent from .transcription_text_delta_event import TranscriptionTextDeltaEvent +from .transcription_text_segment_event import TranscriptionTextSegmentEvent __all__ = ["TranscriptionStreamEvent"] TranscriptionStreamEvent: TypeAlias = Annotated[ - Union[TranscriptionTextDeltaEvent, TranscriptionTextDoneEvent], PropertyInfo(discriminator="type") + Union[TranscriptionTextSegmentEvent, TranscriptionTextDeltaEvent, TranscriptionTextDoneEvent], + PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/audio/transcription_text_delta_event.py b/src/openai/types/audio/transcription_text_delta_event.py index 36c52f0623..363b6a6335 100644 --- a/src/openai/types/audio/transcription_text_delta_event.py +++ b/src/openai/types/audio/transcription_text_delta_event.py @@ -33,3 +33,9 @@ class TranscriptionTextDeltaEvent(BaseModel): [create a transcription](https://platform.openai.com/docs/api-reference/audio/create-transcription) with the `include[]` parameter set to `logprobs`. """ + + segment_id: Optional[str] = None + """Identifier of the diarized segment that this delta belongs to. + + Only present when using `gpt-4o-transcribe-diarize`. + """ diff --git a/src/openai/types/audio/transcription_text_segment_event.py b/src/openai/types/audio/transcription_text_segment_event.py new file mode 100644 index 0000000000..d4f7664578 --- /dev/null +++ b/src/openai/types/audio/transcription_text_segment_event.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["TranscriptionTextSegmentEvent"] + + +class TranscriptionTextSegmentEvent(BaseModel): + id: str + """Unique identifier for the segment.""" + + end: float + """End timestamp of the segment in seconds.""" + + speaker: str + """Speaker label for this segment.""" + + start: float + """Start timestamp of the segment in seconds.""" + + text: str + """Transcript text for this segment.""" + + type: Literal["transcript.text.segment"] + """The type of the event. Always `transcript.text.segment`.""" diff --git a/src/openai/types/audio_model.py b/src/openai/types/audio_model.py index 4d14d60181..68031a2198 100644 --- a/src/openai/types/audio_model.py +++ b/src/openai/types/audio_model.py @@ -4,4 +4,4 @@ __all__ = ["AudioModel"] -AudioModel: TypeAlias = Literal["whisper-1", "gpt-4o-transcribe", "gpt-4o-mini-transcribe"] +AudioModel: TypeAlias = Literal["whisper-1", "gpt-4o-transcribe", "gpt-4o-mini-transcribe", "gpt-4o-transcribe-diarize"] diff --git a/src/openai/types/audio_response_format.py b/src/openai/types/audio_response_format.py index f8c8d45945..1897aaf6ed 100644 --- a/src/openai/types/audio_response_format.py +++ b/src/openai/types/audio_response_format.py @@ -4,4 +4,4 @@ __all__ = ["AudioResponseFormat"] -AudioResponseFormat: TypeAlias = Literal["json", "text", "srt", "verbose_json", "vtt"] +AudioResponseFormat: TypeAlias = Literal["json", "text", "srt", "verbose_json", "vtt", "diarized_json"] diff --git a/src/openai/types/realtime/audio_transcription.py b/src/openai/types/realtime/audio_transcription.py index cf662b3aa2..3e5c8e0cb4 100644 --- a/src/openai/types/realtime/audio_transcription.py +++ b/src/openai/types/realtime/audio_transcription.py @@ -17,13 +17,14 @@ class AudioTranscription(BaseModel): format will improve accuracy and latency. """ - model: Optional[Literal["whisper-1", "gpt-4o-transcribe-latest", "gpt-4o-mini-transcribe", "gpt-4o-transcribe"]] = ( - None - ) + model: Optional[ + Literal["whisper-1", "gpt-4o-mini-transcribe", "gpt-4o-transcribe", "gpt-4o-transcribe-diarize"] + ] = None """The model to use for transcription. - Current options are `whisper-1`, `gpt-4o-transcribe-latest`, - `gpt-4o-mini-transcribe`, and `gpt-4o-transcribe`. + Current options are `whisper-1`, `gpt-4o-mini-transcribe`, `gpt-4o-transcribe`, + and `gpt-4o-transcribe-diarize`. Use `gpt-4o-transcribe-diarize` when you need + diarization with speaker labels. """ prompt: Optional[str] = None @@ -31,6 +32,6 @@ class AudioTranscription(BaseModel): An optional text to guide the model's style or continue a previous audio segment. For `whisper-1`, the [prompt is a list of keywords](https://platform.openai.com/docs/guides/speech-to-text#prompting). - For `gpt-4o-transcribe` models, the prompt is a free text string, for example - "expect words related to technology". + For `gpt-4o-transcribe` models (excluding `gpt-4o-transcribe-diarize`), the + prompt is a free text string, for example "expect words related to technology". """ diff --git a/src/openai/types/realtime/audio_transcription_param.py b/src/openai/types/realtime/audio_transcription_param.py index fb09f105b8..3b65e42c8f 100644 --- a/src/openai/types/realtime/audio_transcription_param.py +++ b/src/openai/types/realtime/audio_transcription_param.py @@ -16,11 +16,12 @@ class AudioTranscriptionParam(TypedDict, total=False): format will improve accuracy and latency. """ - model: Literal["whisper-1", "gpt-4o-transcribe-latest", "gpt-4o-mini-transcribe", "gpt-4o-transcribe"] + model: Literal["whisper-1", "gpt-4o-mini-transcribe", "gpt-4o-transcribe", "gpt-4o-transcribe-diarize"] """The model to use for transcription. - Current options are `whisper-1`, `gpt-4o-transcribe-latest`, - `gpt-4o-mini-transcribe`, and `gpt-4o-transcribe`. + Current options are `whisper-1`, `gpt-4o-mini-transcribe`, `gpt-4o-transcribe`, + and `gpt-4o-transcribe-diarize`. Use `gpt-4o-transcribe-diarize` when you need + diarization with speaker labels. """ prompt: str @@ -28,6 +29,6 @@ class AudioTranscriptionParam(TypedDict, total=False): An optional text to guide the model's style or continue a previous audio segment. For `whisper-1`, the [prompt is a list of keywords](https://platform.openai.com/docs/guides/speech-to-text#prompting). - For `gpt-4o-transcribe` models, the prompt is a free text string, for example - "expect words related to technology". + For `gpt-4o-transcribe` models (excluding `gpt-4o-transcribe-diarize`), the + prompt is a free text string, for example "expect words related to technology". """ diff --git a/src/openai/types/vector_store_create_params.py b/src/openai/types/vector_store_create_params.py index 945a9886a3..f373a6ed28 100644 --- a/src/openai/types/vector_store_create_params.py +++ b/src/openai/types/vector_store_create_params.py @@ -20,6 +20,12 @@ class VectorStoreCreateParams(TypedDict, total=False): non-empty. """ + description: str + """A description for the vector store. + + Can be used to describe the vector store's purpose. + """ + expires_after: ExpiresAfter """The expiration policy for a vector store.""" diff --git a/tests/api_resources/audio/test_transcriptions.py b/tests/api_resources/audio/test_transcriptions.py index 11cbe2349c..b5eaa4be1f 100644 --- a/tests/api_resources/audio/test_transcriptions.py +++ b/tests/api_resources/audio/test_transcriptions.py @@ -32,6 +32,8 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: model="gpt-4o-transcribe", chunking_strategy="auto", include=["logprobs"], + known_speaker_names=["string"], + known_speaker_references=["string"], language="language", prompt="prompt", response_format="json", @@ -84,6 +86,8 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: stream=True, chunking_strategy="auto", include=["logprobs"], + known_speaker_names=["string"], + known_speaker_references=["string"], language="language", prompt="prompt", response_format="json", @@ -140,6 +144,8 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn model="gpt-4o-transcribe", chunking_strategy="auto", include=["logprobs"], + known_speaker_names=["string"], + known_speaker_references=["string"], language="language", prompt="prompt", response_format="json", @@ -192,6 +198,8 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn stream=True, chunking_strategy="auto", include=["logprobs"], + known_speaker_names=["string"], + known_speaker_references=["string"], language="language", prompt="prompt", response_format="json", diff --git a/tests/api_resources/test_vector_stores.py b/tests/api_resources/test_vector_stores.py index dffd2b1d07..cce9c52cea 100644 --- a/tests/api_resources/test_vector_stores.py +++ b/tests/api_resources/test_vector_stores.py @@ -31,6 +31,7 @@ def test_method_create(self, client: OpenAI) -> None: def test_method_create_with_all_params(self, client: OpenAI) -> None: vector_store = client.vector_stores.create( chunking_strategy={"type": "auto"}, + description="description", expires_after={ "anchor": "last_active_at", "days": 1, @@ -299,6 +300,7 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None: async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: vector_store = await async_client.vector_stores.create( chunking_strategy={"type": "auto"}, + description="description", expires_after={ "anchor": "last_active_at", "days": 1, diff --git a/tests/lib/test_audio.py b/tests/lib/test_audio.py index ff8dba4714..93ed3a33b2 100644 --- a/tests/lib/test_audio.py +++ b/tests/lib/test_audio.py @@ -44,7 +44,8 @@ def test_translation_create_overloads_in_sync(sync: bool, client: OpenAI, async_ elif is_literal_type(typ): overload_response_formats.update(get_args(typ)) - src_response_formats: set[str] = set(get_args(AudioResponseFormat)) + # 'diarized_json' applies only to transcriptions, not translations. + src_response_formats: set[str] = set(get_args(AudioResponseFormat)) - {"diarized_json"} diff = src_response_formats.difference(overload_response_formats) assert len(diff) == 0, f"some response format options don't have overloads" @@ -57,18 +58,27 @@ def test_transcription_create_overloads_in_sync(sync: bool, client: OpenAI, asyn overload_response_formats: set[str] = set() for i, overload in enumerate(typing_extensions.get_overloads(fn)): - assert_signatures_in_sync( - fn, - overload, - exclude_params={"response_format", "stream"}, - description=f" for overload {i}", - ) - sig = inspect.signature(overload) typ = evaluate_forwardref( sig.parameters["response_format"].annotation, globalns=sys.modules[fn.__module__].__dict__, ) + + exclude_params = {"response_format", "stream"} + # known_speaker_names and known_speaker_references are only supported by diarized_json + if not (is_literal_type(typ) and set(get_args(typ)) == {"diarized_json"}): + exclude_params.update({"known_speaker_names", "known_speaker_references"}) + + # diarized_json does not support these parameters + if is_literal_type(typ) and set(get_args(typ)) == {"diarized_json"}: + exclude_params.update({"include", "prompt", "timestamp_granularities"}) + + assert_signatures_in_sync( + fn, + overload, + exclude_params=exclude_params, + description=f" for overload {i}", + ) if is_union_type(typ): for arg in get_args(typ): if not is_literal_type(arg): From e043d7b164c9ee9b34f7029606f08ed60d2d47db Mon Sep 17 00:00:00 2001 From: Alex Chang Date: Thu, 16 Oct 2025 11:08:09 -0400 Subject: [PATCH 524/769] chore: fix dangling comment --- src/openai/resources/audio/transcriptions.py | 60 -------------------- 1 file changed, 60 deletions(-) diff --git a/src/openai/resources/audio/transcriptions.py b/src/openai/resources/audio/transcriptions.py index 52e44bffb7..30ef39deec 100644 --- a/src/openai/resources/audio/transcriptions.py +++ b/src/openai/resources/audio/transcriptions.py @@ -103,66 +103,6 @@ def create( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TranscriptionVerbose: ... - model's confidence in the transcription. `logprobs` only works with - response_format set to `json` and only with the models `gpt-4o-transcribe` and - `gpt-4o-mini-transcribe`. This field is not supported when using - `gpt-4o-transcribe-diarize`. - - known_speaker_names: Optional list of speaker names that correspond to the audio samples provided in - `known_speaker_references[]`. Each entry should be a short identifier (for - example `customer` or `agent`). Up to 4 speakers are supported. - - known_speaker_references: Optional list of audio samples (as - [data URLs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs)) - that contain known speaker references matching `known_speaker_names[]`. Each - sample must be between 2 and 10 seconds, and can use any of the same input audio - formats supported by `file`. - - language: The language of the input audio. Supplying the input language in - [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) - format will improve accuracy and latency. - - prompt: An optional text to guide the model's style or continue a previous audio - segment. The - [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) - should match the audio language. This field is not supported when using - `gpt-4o-transcribe-diarize`. - - response_format: The format of the output, in one of these options: `json`, `text`, `srt`, - `verbose_json`, `vtt`, or `diarized_json`. For `gpt-4o-transcribe` and - `gpt-4o-mini-transcribe`, the only supported format is `json`. For - `gpt-4o-transcribe-diarize`, the supported formats are `json`, `text`, and - `diarized_json`, with `diarized_json` required to receive speaker annotations. - - stream: If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section of the Speech-to-Text guide](https://platform.openai.com/docs/guides/speech-to-text?lang=curl#streaming-transcriptions) - for more information. - - Note: Streaming is not supported for the `whisper-1` model and will be ignored. - - temperature: The sampling temperature, between 0 and 1. Higher values like 0.8 will make the - output more random, while lower values like 0.2 will make it more focused and - deterministic. If set to 0, the model will use - [log probability](https://en.wikipedia.org/wiki/Log_probability) to - automatically increase the temperature until certain thresholds are hit. - - timestamp_granularities: The timestamp granularities to populate for this transcription. - `response_format` must be set `verbose_json` to use timestamp granularities. - Either or both of these options are supported: `word`, or `segment`. Note: There - is no additional latency for segment timestamps, but generating word timestamps - incurs additional latency. This option is not available for - `gpt-4o-transcribe-diarize`. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - ) -> Transcription: ... - @overload def create( self, From ebf32212f7bf5bec6b24cc2276ac0d9a28dd63bb Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 16 Oct 2025 15:08:49 +0000 Subject: [PATCH 525/769] release: 2.4.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 14 ++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 75ec52fc91..b44b287037 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.3.0" + ".": "2.4.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 66eec00fea..30f898c23b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## 2.4.0 (2025-10-16) + +Full Changelog: [v2.3.0...v2.4.0](https://github.com/openai/openai-python/compare/v2.3.0...v2.4.0) + +### Features + +* **api:** Add support for gpt-4o-transcribe-diarize on audio/transcriptions endpoint ([bdbe9b8](https://github.com/openai/openai-python/commit/bdbe9b8f440209afa2979db4a9eda9579b3d2550)) + + +### Chores + +* fix dangling comment ([da14e99](https://github.com/openai/openai-python/commit/da14e9960608f7ade6f5cdf91967830c8a6c1657)) +* **internal:** detect missing future annotations with ruff ([2672b8f](https://github.com/openai/openai-python/commit/2672b8f0726300f7c62c356f25545ef0b3c0bb2e)) + ## 2.3.0 (2025-10-10) Full Changelog: [v2.2.0...v2.3.0](https://github.com/openai/openai-python/compare/v2.2.0...v2.3.0) diff --git a/pyproject.toml b/pyproject.toml index 0f773e5fa4..43de9882f2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.3.0" +version = "2.4.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 f202a6d61c..e09654e09d 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__ = "2.3.0" # x-release-please-version +__version__ = "2.4.0" # x-release-please-version From 513ae76253cccdf9d0a9122b32cf0adb8d26f792 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 17 Oct 2025 14:13:47 -0400 Subject: [PATCH 526/769] release: 2.5.0 (#2694) * chore: bump `httpx-aiohttp` version to 0.1.9 * feat(api): api update * codegen metadata * codegen metadata * release: 2.5.0 --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- .stats.yml | 8 +- CHANGELOG.md | 13 ++ pyproject.toml | 4 +- requirements-dev.lock | 2 +- requirements.lock | 2 +- src/openai/_version.py | 2 +- src/openai/resources/beta/chatkit/chatkit.py | 125 ------------------ src/openai/types/beta/__init__.py | 4 - .../types/beta/chatkit_upload_file_params.py | 17 --- .../beta/chatkit_upload_file_response.py | 12 -- src/openai/types/beta/file_part.py | 28 ---- src/openai/types/beta/image_part.py | 31 ----- tests/api_resources/beta/test_chatkit.py | 86 ------------ 14 files changed, 23 insertions(+), 313 deletions(-) delete mode 100644 src/openai/types/beta/chatkit_upload_file_params.py delete mode 100644 src/openai/types/beta/chatkit_upload_file_response.py delete mode 100644 src/openai/types/beta/file_part.py delete mode 100644 src/openai/types/beta/image_part.py delete mode 100644 tests/api_resources/beta/test_chatkit.py diff --git a/.release-please-manifest.json b/.release-please-manifest.json index b44b287037..4dedeaebc3 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.4.0" + ".": "2.5.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index d0ff2b0dc2..b15622eba0 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 136 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-104cced8f4c7436a76eea02e26307828166405ccfb296faffb008b72772c11a7.yml -openapi_spec_hash: fdc03ed84a65a31b80da909255e53924 -config_hash: 03b48e9b8c7231a902403210dbd7dfa0 +configured_endpoints: 135 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-f59befea071ed7729cbb7bce219e7f837eccfdb57e01698514e6a0bd6052ff60.yml +openapi_spec_hash: 49da48619d37932b2e257c532078b2bb +config_hash: 1af83449a09a3b4f276444dbcdd3eb67 diff --git a/CHANGELOG.md b/CHANGELOG.md index 30f898c23b..3f79fb75fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 2.5.0 (2025-10-17) + +Full Changelog: [v2.4.0...v2.5.0](https://github.com/openai/openai-python/compare/v2.4.0...v2.5.0) + +### Features + +* **api:** api update ([8b280d5](https://github.com/openai/openai-python/commit/8b280d57d6d361bc3a032e030158f6859c445291)) + + +### Chores + +* bump `httpx-aiohttp` version to 0.1.9 ([67f2f0a](https://github.com/openai/openai-python/commit/67f2f0afe51dab9d5899fe18b1a4e86b2c774d10)) + ## 2.4.0 (2025-10-16) Full Changelog: [v2.3.0...v2.4.0](https://github.com/openai/openai-python/compare/v2.3.0...v2.4.0) diff --git a/pyproject.toml b/pyproject.toml index 43de9882f2..a2f0ab7176 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.4.0" +version = "2.5.0" description = "The official Python library for the openai API" dynamic = ["readme"] license = "Apache-2.0" @@ -44,7 +44,7 @@ Repository = "https://github.com/openai/openai-python" openai = "openai.cli:main" [project.optional-dependencies] -aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.8"] +aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.9"] realtime = ["websockets >= 13, < 16"] datalib = ["numpy >= 1", "pandas >= 1.2.3", "pandas-stubs >= 1.1.0.11"] voice_helpers = ["sounddevice>=0.5.1", "numpy>=2.0.2"] diff --git a/requirements-dev.lock b/requirements-dev.lock index e2446f2222..b454537b96 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -79,7 +79,7 @@ httpx==0.28.1 # via httpx-aiohttp # via openai # via respx -httpx-aiohttp==0.1.8 +httpx-aiohttp==0.1.9 # via openai idna==3.4 # via anyio diff --git a/requirements.lock b/requirements.lock index aaca0834db..b047cb3f88 100644 --- a/requirements.lock +++ b/requirements.lock @@ -45,7 +45,7 @@ httpcore==1.0.9 httpx==0.28.1 # via httpx-aiohttp # via openai -httpx-aiohttp==0.1.8 +httpx-aiohttp==0.1.9 # via openai idna==3.4 # via anyio diff --git a/src/openai/_version.py b/src/openai/_version.py index e09654e09d..0d92388b98 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__ = "2.4.0" # x-release-please-version +__version__ = "2.5.0" # x-release-please-version diff --git a/src/openai/resources/beta/chatkit/chatkit.py b/src/openai/resources/beta/chatkit/chatkit.py index 2d090cf396..5a10a39c7b 100644 --- a/src/openai/resources/beta/chatkit/chatkit.py +++ b/src/openai/resources/beta/chatkit/chatkit.py @@ -2,11 +2,6 @@ from __future__ import annotations -from typing import Any, Mapping, cast - -import httpx - -from .... import _legacy_response from .threads import ( Threads, AsyncThreads, @@ -23,14 +18,8 @@ SessionsWithStreamingResponse, AsyncSessionsWithStreamingResponse, ) -from ...._types import Body, Query, Headers, NotGiven, FileTypes, not_given -from ...._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ....types.beta import chatkit_upload_file_params -from ...._base_client import make_request_options -from ....types.beta.chatkit_upload_file_response import ChatKitUploadFileResponse __all__ = ["ChatKit", "AsyncChatKit"] @@ -63,55 +52,6 @@ def with_streaming_response(self) -> ChatKitWithStreamingResponse: """ return ChatKitWithStreamingResponse(self) - def upload_file( - self, - *, - file: FileTypes, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ChatKitUploadFileResponse: - """ - Upload a ChatKit file - - Args: - file: Binary file contents to store with the ChatKit session. Supports PDFs and PNG, - JPG, JPEG, GIF, or WEBP images. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} - body = deepcopy_minimal({"file": file}) - files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) - if files: - # It should be noted that the actual Content-Type header that will be - # sent to the server will contain a `boundary` parameter, e.g. - # multipart/form-data; boundary=---abc-- - extra_headers["Content-Type"] = "multipart/form-data" - return cast( - ChatKitUploadFileResponse, - self._post( - "/chatkit/files", - body=maybe_transform(body, chatkit_upload_file_params.ChatKitUploadFileParams), - files=files, - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=cast( - Any, ChatKitUploadFileResponse - ), # Union types cannot be passed in as arguments in the type system - ), - ) - class AsyncChatKit(AsyncAPIResource): @cached_property @@ -141,64 +81,11 @@ def with_streaming_response(self) -> AsyncChatKitWithStreamingResponse: """ return AsyncChatKitWithStreamingResponse(self) - async def upload_file( - self, - *, - file: FileTypes, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ChatKitUploadFileResponse: - """ - Upload a ChatKit file - - Args: - file: Binary file contents to store with the ChatKit session. Supports PDFs and PNG, - JPG, JPEG, GIF, or WEBP images. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} - body = deepcopy_minimal({"file": file}) - files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) - if files: - # It should be noted that the actual Content-Type header that will be - # sent to the server will contain a `boundary` parameter, e.g. - # multipart/form-data; boundary=---abc-- - extra_headers["Content-Type"] = "multipart/form-data" - return cast( - ChatKitUploadFileResponse, - await self._post( - "/chatkit/files", - body=await async_maybe_transform(body, chatkit_upload_file_params.ChatKitUploadFileParams), - files=files, - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=cast( - Any, ChatKitUploadFileResponse - ), # Union types cannot be passed in as arguments in the type system - ), - ) - class ChatKitWithRawResponse: def __init__(self, chatkit: ChatKit) -> None: self._chatkit = chatkit - self.upload_file = _legacy_response.to_raw_response_wrapper( - chatkit.upload_file, - ) - @cached_property def sessions(self) -> SessionsWithRawResponse: return SessionsWithRawResponse(self._chatkit.sessions) @@ -212,10 +99,6 @@ class AsyncChatKitWithRawResponse: def __init__(self, chatkit: AsyncChatKit) -> None: self._chatkit = chatkit - self.upload_file = _legacy_response.async_to_raw_response_wrapper( - chatkit.upload_file, - ) - @cached_property def sessions(self) -> AsyncSessionsWithRawResponse: return AsyncSessionsWithRawResponse(self._chatkit.sessions) @@ -229,10 +112,6 @@ class ChatKitWithStreamingResponse: def __init__(self, chatkit: ChatKit) -> None: self._chatkit = chatkit - self.upload_file = to_streamed_response_wrapper( - chatkit.upload_file, - ) - @cached_property def sessions(self) -> SessionsWithStreamingResponse: return SessionsWithStreamingResponse(self._chatkit.sessions) @@ -246,10 +125,6 @@ class AsyncChatKitWithStreamingResponse: def __init__(self, chatkit: AsyncChatKit) -> None: self._chatkit = chatkit - self.upload_file = async_to_streamed_response_wrapper( - chatkit.upload_file, - ) - @cached_property def sessions(self) -> AsyncSessionsWithStreamingResponse: return AsyncSessionsWithStreamingResponse(self._chatkit.sessions) diff --git a/src/openai/types/beta/__init__.py b/src/openai/types/beta/__init__.py index 9ef6283864..deb2369677 100644 --- a/src/openai/types/beta/__init__.py +++ b/src/openai/types/beta/__init__.py @@ -4,8 +4,6 @@ from .thread import Thread as Thread from .assistant import Assistant as Assistant -from .file_part import FilePart as FilePart -from .image_part import ImagePart as ImagePart from .function_tool import FunctionTool as FunctionTool from .assistant_tool import AssistantTool as AssistantTool from .thread_deleted import ThreadDeleted as ThreadDeleted @@ -23,11 +21,9 @@ from .file_search_tool_param import FileSearchToolParam as FileSearchToolParam from .assistant_create_params import AssistantCreateParams as AssistantCreateParams from .assistant_update_params import AssistantUpdateParams as AssistantUpdateParams -from .chatkit_upload_file_params import ChatKitUploadFileParams as ChatKitUploadFileParams from .assistant_tool_choice_param import AssistantToolChoiceParam as AssistantToolChoiceParam from .code_interpreter_tool_param import CodeInterpreterToolParam as CodeInterpreterToolParam from .assistant_tool_choice_option import AssistantToolChoiceOption as AssistantToolChoiceOption -from .chatkit_upload_file_response import ChatKitUploadFileResponse as ChatKitUploadFileResponse from .thread_create_and_run_params import ThreadCreateAndRunParams as ThreadCreateAndRunParams from .assistant_tool_choice_function import AssistantToolChoiceFunction as AssistantToolChoiceFunction from .assistant_response_format_option import AssistantResponseFormatOption as AssistantResponseFormatOption diff --git a/src/openai/types/beta/chatkit_upload_file_params.py b/src/openai/types/beta/chatkit_upload_file_params.py deleted file mode 100644 index 87dc993664..0000000000 --- a/src/openai/types/beta/chatkit_upload_file_params.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -from ..._types import FileTypes - -__all__ = ["ChatKitUploadFileParams"] - - -class ChatKitUploadFileParams(TypedDict, total=False): - file: Required[FileTypes] - """Binary file contents to store with the ChatKit session. - - Supports PDFs and PNG, JPG, JPEG, GIF, or WEBP images. - """ diff --git a/src/openai/types/beta/chatkit_upload_file_response.py b/src/openai/types/beta/chatkit_upload_file_response.py deleted file mode 100644 index 9527df76fb..0000000000 --- a/src/openai/types/beta/chatkit_upload_file_response.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Annotated, TypeAlias - -from ..._utils import PropertyInfo -from .file_part import FilePart -from .image_part import ImagePart - -__all__ = ["ChatKitUploadFileResponse"] - -ChatKitUploadFileResponse: TypeAlias = Annotated[Union[FilePart, ImagePart], PropertyInfo(discriminator="type")] diff --git a/src/openai/types/beta/file_part.py b/src/openai/types/beta/file_part.py deleted file mode 100644 index cf60bddc99..0000000000 --- a/src/openai/types/beta/file_part.py +++ /dev/null @@ -1,28 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["FilePart"] - - -class FilePart(BaseModel): - id: str - """Unique identifier for the uploaded file.""" - - mime_type: Optional[str] = None - """MIME type reported for the uploaded file. Defaults to null when unknown.""" - - name: Optional[str] = None - """Original filename supplied by the uploader. Defaults to null when unnamed.""" - - type: Literal["file"] - """Type discriminator that is always `file`.""" - - upload_url: Optional[str] = None - """Signed URL for downloading the uploaded file. - - Defaults to null when no download link is available. - """ diff --git a/src/openai/types/beta/image_part.py b/src/openai/types/beta/image_part.py deleted file mode 100644 index 4c06b4730b..0000000000 --- a/src/openai/types/beta/image_part.py +++ /dev/null @@ -1,31 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ImagePart"] - - -class ImagePart(BaseModel): - id: str - """Unique identifier for the uploaded image.""" - - mime_type: str - """MIME type of the uploaded image.""" - - name: Optional[str] = None - """Original filename for the uploaded image. Defaults to null when unnamed.""" - - preview_url: str - """Preview URL that can be rendered inline for the image.""" - - type: Literal["image"] - """Type discriminator that is always `image`.""" - - upload_url: Optional[str] = None - """Signed URL for downloading the uploaded image. - - Defaults to null when no download link is available. - """ diff --git a/tests/api_resources/beta/test_chatkit.py b/tests/api_resources/beta/test_chatkit.py deleted file mode 100644 index b05be0ece5..0000000000 --- a/tests/api_resources/beta/test_chatkit.py +++ /dev/null @@ -1,86 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from openai import OpenAI, AsyncOpenAI -from tests.utils import assert_matches_type -from openai.types.beta import ChatKitUploadFileResponse - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestChatKit: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_upload_file(self, client: OpenAI) -> None: - chatkit = client.beta.chatkit.upload_file( - file=b"raw file contents", - ) - assert_matches_type(ChatKitUploadFileResponse, chatkit, path=["response"]) - - @parametrize - def test_raw_response_upload_file(self, client: OpenAI) -> None: - response = client.beta.chatkit.with_raw_response.upload_file( - file=b"raw file contents", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - chatkit = response.parse() - assert_matches_type(ChatKitUploadFileResponse, chatkit, path=["response"]) - - @parametrize - def test_streaming_response_upload_file(self, client: OpenAI) -> None: - with client.beta.chatkit.with_streaming_response.upload_file( - file=b"raw file contents", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - chatkit = response.parse() - assert_matches_type(ChatKitUploadFileResponse, chatkit, path=["response"]) - - assert cast(Any, response.is_closed) is True - - -class TestAsyncChatKit: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_upload_file(self, async_client: AsyncOpenAI) -> None: - chatkit = await async_client.beta.chatkit.upload_file( - file=b"raw file contents", - ) - assert_matches_type(ChatKitUploadFileResponse, chatkit, path=["response"]) - - @parametrize - async def test_raw_response_upload_file(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.chatkit.with_raw_response.upload_file( - file=b"raw file contents", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - chatkit = response.parse() - assert_matches_type(ChatKitUploadFileResponse, chatkit, path=["response"]) - - @parametrize - async def test_streaming_response_upload_file(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.chatkit.with_streaming_response.upload_file( - file=b"raw file contents", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - chatkit = await response.parse() - assert_matches_type(ChatKitUploadFileResponse, chatkit, path=["response"]) - - assert cast(Any, response.is_closed) is True From 0a5ad3e89de194c7142a24857c86e6b852e4e2e8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 17 Oct 2025 21:31:29 +0000 Subject: [PATCH 527/769] fix(api): internal openapi updates --- .stats.yml | 6 ++-- src/openai/resources/images.py | 30 ++++--------------- .../response_code_interpreter_tool_call.py | 4 +-- ...sponse_code_interpreter_tool_call_param.py | 4 +-- .../responses/response_computer_tool_call.py | 11 +++---- ...response_computer_tool_call_output_item.py | 4 +-- .../response_computer_tool_call_param.py | 11 +++---- .../types/responses/response_includable.py | 8 +++-- .../api_resources/conversations/test_items.py | 12 ++++---- .../responses/test_input_items.py | 4 +-- tests/api_resources/test_responses.py | 16 +++++----- 11 files changed, 44 insertions(+), 66 deletions(-) diff --git a/.stats.yml b/.stats.yml index b15622eba0..9cef71c261 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 135 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-f59befea071ed7729cbb7bce219e7f837eccfdb57e01698514e6a0bd6052ff60.yml -openapi_spec_hash: 49da48619d37932b2e257c532078b2bb -config_hash: 1af83449a09a3b4f276444dbcdd3eb67 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-b062c33330de7e3bbf992fd4f0799afd868c30a66c39418dd2c62f4add3b45b6.yml +openapi_spec_hash: fe067f5b1c0e93799b5ea7fde3c4b1b3 +config_hash: 4b6f471b24d659514b86b736c90a0c0a diff --git a/src/openai/resources/images.py b/src/openai/resources/images.py index 265be6f743..9bb332230f 100644 --- a/src/openai/resources/images.py +++ b/src/openai/resources/images.py @@ -168,10 +168,7 @@ def edit( If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. - input_fidelity: Control how much effort the model will exert to match the style and features, - especially facial features, of input images. This parameter is only supported - for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and - `low`. Defaults to `low`. + input_fidelity: Control how much effort the model will exert to match the style and features, especially facial features, of input images. This parameter is only supported for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and `low`. Defaults to `low`. mask: An additional image whose fully transparent areas (e.g. where alpha is zero) indicate where `image` should be edited. If there are multiple images provided, @@ -285,10 +282,7 @@ def edit( If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. - input_fidelity: Control how much effort the model will exert to match the style and features, - especially facial features, of input images. This parameter is only supported - for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and - `low`. Defaults to `low`. + input_fidelity: Control how much effort the model will exert to match the style and features, especially facial features, of input images. This parameter is only supported for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and `low`. Defaults to `low`. mask: An additional image whose fully transparent areas (e.g. where alpha is zero) indicate where `image` should be edited. If there are multiple images provided, @@ -398,10 +392,7 @@ def edit( If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. - input_fidelity: Control how much effort the model will exert to match the style and features, - especially facial features, of input images. This parameter is only supported - for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and - `low`. Defaults to `low`. + input_fidelity: Control how much effort the model will exert to match the style and features, especially facial features, of input images. This parameter is only supported for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and `low`. Defaults to `low`. mask: An additional image whose fully transparent areas (e.g. where alpha is zero) indicate where `image` should be edited. If there are multiple images provided, @@ -1055,10 +1046,7 @@ async def edit( If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. - input_fidelity: Control how much effort the model will exert to match the style and features, - especially facial features, of input images. This parameter is only supported - for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and - `low`. Defaults to `low`. + input_fidelity: Control how much effort the model will exert to match the style and features, especially facial features, of input images. This parameter is only supported for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and `low`. Defaults to `low`. mask: An additional image whose fully transparent areas (e.g. where alpha is zero) indicate where `image` should be edited. If there are multiple images provided, @@ -1172,10 +1160,7 @@ async def edit( If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. - input_fidelity: Control how much effort the model will exert to match the style and features, - especially facial features, of input images. This parameter is only supported - for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and - `low`. Defaults to `low`. + input_fidelity: Control how much effort the model will exert to match the style and features, especially facial features, of input images. This parameter is only supported for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and `low`. Defaults to `low`. mask: An additional image whose fully transparent areas (e.g. where alpha is zero) indicate where `image` should be edited. If there are multiple images provided, @@ -1285,10 +1270,7 @@ async def edit( If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. - input_fidelity: Control how much effort the model will exert to match the style and features, - especially facial features, of input images. This parameter is only supported - for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and - `low`. Defaults to `low`. + input_fidelity: Control how much effort the model will exert to match the style and features, especially facial features, of input images. This parameter is only supported for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and `low`. Defaults to `low`. mask: An additional image whose fully transparent areas (e.g. where alpha is zero) indicate where `image` should be edited. If there are multiple images provided, diff --git a/src/openai/types/responses/response_code_interpreter_tool_call.py b/src/openai/types/responses/response_code_interpreter_tool_call.py index ed720ecd42..b651581520 100644 --- a/src/openai/types/responses/response_code_interpreter_tool_call.py +++ b/src/openai/types/responses/response_code_interpreter_tool_call.py @@ -14,12 +14,12 @@ class OutputLogs(BaseModel): """The logs output from the code interpreter.""" type: Literal["logs"] - """The type of the output. Always 'logs'.""" + """The type of the output. Always `logs`.""" class OutputImage(BaseModel): type: Literal["image"] - """The type of the output. Always 'image'.""" + """The type of the output. Always `image`.""" url: str """The URL of the image output from the code interpreter.""" diff --git a/src/openai/types/responses/response_code_interpreter_tool_call_param.py b/src/openai/types/responses/response_code_interpreter_tool_call_param.py index 78b90ca87e..d402b872a4 100644 --- a/src/openai/types/responses/response_code_interpreter_tool_call_param.py +++ b/src/openai/types/responses/response_code_interpreter_tool_call_param.py @@ -13,12 +13,12 @@ class OutputLogs(TypedDict, total=False): """The logs output from the code interpreter.""" type: Required[Literal["logs"]] - """The type of the output. Always 'logs'.""" + """The type of the output. Always `logs`.""" class OutputImage(TypedDict, total=False): type: Required[Literal["image"]] - """The type of the output. Always 'image'.""" + """The type of the output. Always `image`.""" url: Required[str] """The URL of the image output from the code interpreter.""" diff --git a/src/openai/types/responses/response_computer_tool_call.py b/src/openai/types/responses/response_computer_tool_call.py index 994837567a..f1476fa0fb 100644 --- a/src/openai/types/responses/response_computer_tool_call.py +++ b/src/openai/types/responses/response_computer_tool_call.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union +from typing import List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias from ..._utils import PropertyInfo @@ -31,10 +31,7 @@ class ActionClick(BaseModel): """ type: Literal["click"] - """Specifies the event type. - - For a click action, this property is always set to `click`. - """ + """Specifies the event type. For a click action, this property is always `click`.""" x: int """The x-coordinate where the click occurred.""" @@ -181,10 +178,10 @@ class PendingSafetyCheck(BaseModel): id: str """The ID of the pending safety check.""" - code: str + code: Optional[str] = None """The type of the pending safety check.""" - message: str + message: Optional[str] = None """Details about the pending safety check.""" diff --git a/src/openai/types/responses/response_computer_tool_call_output_item.py b/src/openai/types/responses/response_computer_tool_call_output_item.py index a2dd68f579..e1ac358cc6 100644 --- a/src/openai/types/responses/response_computer_tool_call_output_item.py +++ b/src/openai/types/responses/response_computer_tool_call_output_item.py @@ -13,10 +13,10 @@ class AcknowledgedSafetyCheck(BaseModel): id: str """The ID of the pending safety check.""" - code: str + code: Optional[str] = None """The type of the pending safety check.""" - message: str + message: Optional[str] = None """Details about the pending safety check.""" diff --git a/src/openai/types/responses/response_computer_tool_call_param.py b/src/openai/types/responses/response_computer_tool_call_param.py index 0be63db2fe..228f76bac9 100644 --- a/src/openai/types/responses/response_computer_tool_call_param.py +++ b/src/openai/types/responses/response_computer_tool_call_param.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Union, Iterable +from typing import Union, Iterable, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict from ..._types import SequenceNotStr @@ -32,10 +32,7 @@ class ActionClick(TypedDict, total=False): """ type: Required[Literal["click"]] - """Specifies the event type. - - For a click action, this property is always set to `click`. - """ + """Specifies the event type. For a click action, this property is always `click`.""" x: Required[int] """The x-coordinate where the click occurred.""" @@ -179,10 +176,10 @@ class PendingSafetyCheck(TypedDict, total=False): id: Required[str] """The ID of the pending safety check.""" - code: Required[str] + code: Optional[str] """The type of the pending safety check.""" - message: Required[str] + message: Optional[str] """Details about the pending safety check.""" diff --git a/src/openai/types/responses/response_includable.py b/src/openai/types/responses/response_includable.py index c17a02560f..675c83405a 100644 --- a/src/openai/types/responses/response_includable.py +++ b/src/openai/types/responses/response_includable.py @@ -5,10 +5,12 @@ __all__ = ["ResponseIncludable"] ResponseIncludable: TypeAlias = Literal[ - "code_interpreter_call.outputs", - "computer_call_output.output.image_url", "file_search_call.results", + "web_search_call.results", + "web_search_call.action.sources", "message.input_image.image_url", - "message.output_text.logprobs", + "computer_call_output.output.image_url", + "code_interpreter_call.outputs", "reasoning.encrypted_content", + "message.output_text.logprobs", ] diff --git a/tests/api_resources/conversations/test_items.py b/tests/api_resources/conversations/test_items.py index 0df88dc199..0503301f16 100644 --- a/tests/api_resources/conversations/test_items.py +++ b/tests/api_resources/conversations/test_items.py @@ -47,7 +47,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: "type": "message", } ], - include=["code_interpreter_call.outputs"], + include=["file_search_call.results"], ) assert_matches_type(ConversationItemList, item, path=["response"]) @@ -116,7 +116,7 @@ def test_method_retrieve_with_all_params(self, client: OpenAI) -> None: item = client.conversations.items.retrieve( item_id="msg_abc", conversation_id="conv_123", - include=["code_interpreter_call.outputs"], + include=["file_search_call.results"], ) assert_matches_type(ConversationItem, item, path=["response"]) @@ -172,7 +172,7 @@ def test_method_list_with_all_params(self, client: OpenAI) -> None: item = client.conversations.items.list( conversation_id="conv_123", after="after", - include=["code_interpreter_call.outputs"], + include=["file_search_call.results"], limit=0, order="asc", ) @@ -288,7 +288,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> "type": "message", } ], - include=["code_interpreter_call.outputs"], + include=["file_search_call.results"], ) assert_matches_type(ConversationItemList, item, path=["response"]) @@ -357,7 +357,7 @@ async def test_method_retrieve_with_all_params(self, async_client: AsyncOpenAI) item = await async_client.conversations.items.retrieve( item_id="msg_abc", conversation_id="conv_123", - include=["code_interpreter_call.outputs"], + include=["file_search_call.results"], ) assert_matches_type(ConversationItem, item, path=["response"]) @@ -413,7 +413,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> N item = await async_client.conversations.items.list( conversation_id="conv_123", after="after", - include=["code_interpreter_call.outputs"], + include=["file_search_call.results"], limit=0, order="asc", ) diff --git a/tests/api_resources/responses/test_input_items.py b/tests/api_resources/responses/test_input_items.py index eda20c9a0b..ed6fddf33a 100644 --- a/tests/api_resources/responses/test_input_items.py +++ b/tests/api_resources/responses/test_input_items.py @@ -30,7 +30,7 @@ def test_method_list_with_all_params(self, client: OpenAI) -> None: input_item = client.responses.input_items.list( response_id="response_id", after="after", - include=["code_interpreter_call.outputs"], + include=["file_search_call.results"], limit=0, order="asc", ) @@ -85,7 +85,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> N input_item = await async_client.responses.input_items.list( response_id="response_id", after="after", - include=["code_interpreter_call.outputs"], + include=["file_search_call.results"], limit=0, order="asc", ) diff --git a/tests/api_resources/test_responses.py b/tests/api_resources/test_responses.py index 0cc20e926b..a329aa4d9e 100644 --- a/tests/api_resources/test_responses.py +++ b/tests/api_resources/test_responses.py @@ -30,7 +30,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: response = client.responses.create( background=True, conversation="string", - include=["code_interpreter_call.outputs"], + include=["file_search_call.results"], input="string", instructions="instructions", max_output_tokens=0, @@ -110,7 +110,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: stream=True, background=True, conversation="string", - include=["code_interpreter_call.outputs"], + include=["file_search_call.results"], input="string", instructions="instructions", max_output_tokens=0, @@ -190,7 +190,7 @@ def test_method_retrieve_overload_1(self, client: OpenAI) -> None: def test_method_retrieve_with_all_params_overload_1(self, client: OpenAI) -> None: response = client.responses.retrieve( response_id="resp_677efb5139a88190b512bc3fef8e535d", - include=["code_interpreter_call.outputs"], + include=["file_search_call.results"], include_obfuscation=True, starting_after=0, stream=False, @@ -241,7 +241,7 @@ def test_method_retrieve_with_all_params_overload_2(self, client: OpenAI) -> Non response_stream = client.responses.retrieve( response_id="resp_677efb5139a88190b512bc3fef8e535d", stream=True, - include=["code_interpreter_call.outputs"], + include=["file_search_call.results"], include_obfuscation=True, starting_after=0, ) @@ -383,7 +383,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn response = await async_client.responses.create( background=True, conversation="string", - include=["code_interpreter_call.outputs"], + include=["file_search_call.results"], input="string", instructions="instructions", max_output_tokens=0, @@ -463,7 +463,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn stream=True, background=True, conversation="string", - include=["code_interpreter_call.outputs"], + include=["file_search_call.results"], input="string", instructions="instructions", max_output_tokens=0, @@ -543,7 +543,7 @@ async def test_method_retrieve_overload_1(self, async_client: AsyncOpenAI) -> No async def test_method_retrieve_with_all_params_overload_1(self, async_client: AsyncOpenAI) -> None: response = await async_client.responses.retrieve( response_id="resp_677efb5139a88190b512bc3fef8e535d", - include=["code_interpreter_call.outputs"], + include=["file_search_call.results"], include_obfuscation=True, starting_after=0, stream=False, @@ -594,7 +594,7 @@ async def test_method_retrieve_with_all_params_overload_2(self, async_client: As response_stream = await async_client.responses.retrieve( response_id="resp_677efb5139a88190b512bc3fef8e535d", stream=True, - include=["code_interpreter_call.outputs"], + include=["file_search_call.results"], include_obfuscation=True, starting_after=0, ) From 62a184d7634588fe3d8b9900071b079db6db92ac Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 16:44:45 +0000 Subject: [PATCH 528/769] feat(api): Add responses.input_tokens.count --- .stats.yml | 8 +- api.md | 12 + examples/responses_input_tokens.py | 54 +++ src/openai/resources/responses/__init__.py | 14 + .../resources/responses/input_tokens.py | 309 ++++++++++++++++++ src/openai/resources/responses/responses.py | 32 ++ src/openai/types/responses/__init__.py | 2 + .../responses/input_token_count_params.py | 138 ++++++++ .../responses/input_token_count_response.py | 13 + .../responses/test_input_tokens.py | 138 ++++++++ 10 files changed, 716 insertions(+), 4 deletions(-) create mode 100644 examples/responses_input_tokens.py create mode 100644 src/openai/resources/responses/input_tokens.py create mode 100644 src/openai/types/responses/input_token_count_params.py create mode 100644 src/openai/types/responses/input_token_count_response.py create mode 100644 tests/api_resources/responses/test_input_tokens.py diff --git a/.stats.yml b/.stats.yml index 9cef71c261..48649a27d0 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 135 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-b062c33330de7e3bbf992fd4f0799afd868c30a66c39418dd2c62f4add3b45b6.yml -openapi_spec_hash: fe067f5b1c0e93799b5ea7fde3c4b1b3 -config_hash: 4b6f471b24d659514b86b736c90a0c0a +configured_endpoints: 136 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-812a10f8fb54c584efc914422b574cb3f43dc238b5733b13f6a0b2308b7d9910.yml +openapi_spec_hash: 0222041ba12a5ff6b94924a834fa91a2 +config_hash: 50ee3382a63c021a9f821a935950e926 diff --git a/api.md b/api.md index 7eb296318f..96642c01ad 100644 --- a/api.md +++ b/api.md @@ -865,6 +865,18 @@ Methods: - client.responses.input_items.list(response_id, \*\*params) -> SyncCursorPage[ResponseItem] +## InputTokens + +Types: + +```python +from openai.types.responses import InputTokenCountResponse +``` + +Methods: + +- client.responses.input_tokens.count(\*\*params) -> InputTokenCountResponse + # Realtime Types: diff --git a/examples/responses_input_tokens.py b/examples/responses_input_tokens.py new file mode 100644 index 0000000000..39809b928f --- /dev/null +++ b/examples/responses_input_tokens.py @@ -0,0 +1,54 @@ +from typing import List + +from openai import OpenAI +from openai.types.responses.tool_param import ToolParam +from openai.types.responses.response_input_item_param import ResponseInputItemParam + + +def main() -> None: + client = OpenAI() + tools: List[ToolParam] = [ + { + "type": "function", + "name": "get_current_weather", + "description": "Get current weather in a given location", + "parameters": { + "type": "object", + "properties": { + "location": { + "type": "string", + "description": "City and state, e.g. San Francisco, CA", + }, + "unit": { + "type": "string", + "enum": ["c", "f"], + "description": "Temperature unit to use", + }, + }, + "required": ["location", "unit"], + "additionalProperties": False, + }, + "strict": True, + } + ] + + input_items: List[ResponseInputItemParam] = [ + { + "type": "message", + "role": "user", + "content": [{"type": "input_text", "text": "What's the weather in San Francisco today?"}], + } + ] + + response = client.responses.input_tokens.count( + model="gpt-5", + instructions="You are a concise assistant.", + input=input_items, + tools=tools, + tool_choice={"type": "function", "name": "get_current_weather"}, + ) + print(f"input tokens: {response.input_tokens}") + + +if __name__ == "__main__": + main() diff --git a/src/openai/resources/responses/__init__.py b/src/openai/resources/responses/__init__.py index ad19218b01..51d318ad8d 100644 --- a/src/openai/resources/responses/__init__.py +++ b/src/openai/resources/responses/__init__.py @@ -16,6 +16,14 @@ InputItemsWithStreamingResponse, AsyncInputItemsWithStreamingResponse, ) +from .input_tokens import ( + InputTokens, + AsyncInputTokens, + InputTokensWithRawResponse, + AsyncInputTokensWithRawResponse, + InputTokensWithStreamingResponse, + AsyncInputTokensWithStreamingResponse, +) __all__ = [ "InputItems", @@ -24,6 +32,12 @@ "AsyncInputItemsWithRawResponse", "InputItemsWithStreamingResponse", "AsyncInputItemsWithStreamingResponse", + "InputTokens", + "AsyncInputTokens", + "InputTokensWithRawResponse", + "AsyncInputTokensWithRawResponse", + "InputTokensWithStreamingResponse", + "AsyncInputTokensWithStreamingResponse", "Responses", "AsyncResponses", "ResponsesWithRawResponse", diff --git a/src/openai/resources/responses/input_tokens.py b/src/openai/resources/responses/input_tokens.py new file mode 100644 index 0000000000..0f47955fe4 --- /dev/null +++ b/src/openai/resources/responses/input_tokens.py @@ -0,0 +1,309 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable, Optional +from typing_extensions import Literal + +import httpx + +from ... import _legacy_response +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ..._base_client import make_request_options +from ...types.responses import input_token_count_params +from ...types.responses.tool_param import ToolParam +from ...types.shared_params.reasoning import Reasoning +from ...types.responses.response_input_item_param import ResponseInputItemParam +from ...types.responses.input_token_count_response import InputTokenCountResponse + +__all__ = ["InputTokens", "AsyncInputTokens"] + + +class InputTokens(SyncAPIResource): + @cached_property + def with_raw_response(self) -> InputTokensWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return InputTokensWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> InputTokensWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return InputTokensWithStreamingResponse(self) + + def count( + self, + *, + conversation: Optional[input_token_count_params.Conversation] | Omit = omit, + input: Union[str, Iterable[ResponseInputItemParam], None] | Omit = omit, + instructions: Optional[str] | Omit = omit, + model: Optional[str] | Omit = omit, + parallel_tool_calls: Optional[bool] | Omit = omit, + previous_response_id: Optional[str] | Omit = omit, + reasoning: Optional[Reasoning] | Omit = omit, + text: Optional[input_token_count_params.Text] | Omit = omit, + tool_choice: Optional[input_token_count_params.ToolChoice] | Omit = omit, + tools: Optional[Iterable[ToolParam]] | Omit = omit, + truncation: Literal["auto", "disabled"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InputTokenCountResponse: + """ + Get input token counts + + Args: + conversation: The conversation that this response belongs to. Items from this conversation are + prepended to `input_items` for this response request. Input items and output + items from this response are automatically added to this conversation after this + response completes. + + input: Text, image, or file inputs to the model, used to generate a response + + instructions: A system (or developer) message inserted into the model's context. When used + along with `previous_response_id`, the instructions from a previous response + will not be carried over to the next response. This makes it simple to swap out + system (or developer) messages in new responses. + + model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a + wide range of models with different capabilities, performance characteristics, + and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + + parallel_tool_calls: Whether to allow the model to run tool calls in parallel. + + previous_response_id: The unique ID of the previous response to the model. Use this to create + multi-turn conversations. Learn more about + [conversation state](https://platform.openai.com/docs/guides/conversation-state). + Cannot be used in conjunction with `conversation`. + + reasoning: **gpt-5 and o-series models only** Configuration options for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). + + text: Configuration options for a text response from the model. Can be plain text or + structured JSON data. Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + + tool_choice: How the model should select which tool (or tools) to use when generating a + response. See the `tools` parameter to see how to specify which tools the model + can call. + + tools: An array of tools the model may call while generating a response. You can + specify which tool to use by setting the `tool_choice` parameter. + + truncation: The truncation strategy to use for the model response. - `auto`: If the input to + this Response exceeds the model's context window size, the model will truncate + the response to fit the context window by dropping items from the beginning of + the conversation. - `disabled` (default): If the input size will exceed the + context window size for a model, the request will fail with a 400 error. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/responses/input_tokens", + body=maybe_transform( + { + "conversation": conversation, + "input": input, + "instructions": instructions, + "model": model, + "parallel_tool_calls": parallel_tool_calls, + "previous_response_id": previous_response_id, + "reasoning": reasoning, + "text": text, + "tool_choice": tool_choice, + "tools": tools, + "truncation": truncation, + }, + input_token_count_params.InputTokenCountParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InputTokenCountResponse, + ) + + +class AsyncInputTokens(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncInputTokensWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncInputTokensWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncInputTokensWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncInputTokensWithStreamingResponse(self) + + async def count( + self, + *, + conversation: Optional[input_token_count_params.Conversation] | Omit = omit, + input: Union[str, Iterable[ResponseInputItemParam], None] | Omit = omit, + instructions: Optional[str] | Omit = omit, + model: Optional[str] | Omit = omit, + parallel_tool_calls: Optional[bool] | Omit = omit, + previous_response_id: Optional[str] | Omit = omit, + reasoning: Optional[Reasoning] | Omit = omit, + text: Optional[input_token_count_params.Text] | Omit = omit, + tool_choice: Optional[input_token_count_params.ToolChoice] | Omit = omit, + tools: Optional[Iterable[ToolParam]] | Omit = omit, + truncation: Literal["auto", "disabled"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InputTokenCountResponse: + """ + Get input token counts + + Args: + conversation: The conversation that this response belongs to. Items from this conversation are + prepended to `input_items` for this response request. Input items and output + items from this response are automatically added to this conversation after this + response completes. + + input: Text, image, or file inputs to the model, used to generate a response + + instructions: A system (or developer) message inserted into the model's context. When used + along with `previous_response_id`, the instructions from a previous response + will not be carried over to the next response. This makes it simple to swap out + system (or developer) messages in new responses. + + model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a + wide range of models with different capabilities, performance characteristics, + and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + + parallel_tool_calls: Whether to allow the model to run tool calls in parallel. + + previous_response_id: The unique ID of the previous response to the model. Use this to create + multi-turn conversations. Learn more about + [conversation state](https://platform.openai.com/docs/guides/conversation-state). + Cannot be used in conjunction with `conversation`. + + reasoning: **gpt-5 and o-series models only** Configuration options for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). + + text: Configuration options for a text response from the model. Can be plain text or + structured JSON data. Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + + tool_choice: How the model should select which tool (or tools) to use when generating a + response. See the `tools` parameter to see how to specify which tools the model + can call. + + tools: An array of tools the model may call while generating a response. You can + specify which tool to use by setting the `tool_choice` parameter. + + truncation: The truncation strategy to use for the model response. - `auto`: If the input to + this Response exceeds the model's context window size, the model will truncate + the response to fit the context window by dropping items from the beginning of + the conversation. - `disabled` (default): If the input size will exceed the + context window size for a model, the request will fail with a 400 error. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/responses/input_tokens", + body=await async_maybe_transform( + { + "conversation": conversation, + "input": input, + "instructions": instructions, + "model": model, + "parallel_tool_calls": parallel_tool_calls, + "previous_response_id": previous_response_id, + "reasoning": reasoning, + "text": text, + "tool_choice": tool_choice, + "tools": tools, + "truncation": truncation, + }, + input_token_count_params.InputTokenCountParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InputTokenCountResponse, + ) + + +class InputTokensWithRawResponse: + def __init__(self, input_tokens: InputTokens) -> None: + self._input_tokens = input_tokens + + self.count = _legacy_response.to_raw_response_wrapper( + input_tokens.count, + ) + + +class AsyncInputTokensWithRawResponse: + def __init__(self, input_tokens: AsyncInputTokens) -> None: + self._input_tokens = input_tokens + + self.count = _legacy_response.async_to_raw_response_wrapper( + input_tokens.count, + ) + + +class InputTokensWithStreamingResponse: + def __init__(self, input_tokens: InputTokens) -> None: + self._input_tokens = input_tokens + + self.count = to_streamed_response_wrapper( + input_tokens.count, + ) + + +class AsyncInputTokensWithStreamingResponse: + def __init__(self, input_tokens: AsyncInputTokens) -> None: + self._input_tokens = input_tokens + + self.count = async_to_streamed_response_wrapper( + input_tokens.count, + ) diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 0a89d0c18e..439cf8d3ad 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -24,6 +24,14 @@ ) from ..._streaming import Stream, AsyncStream from ...lib._tools import PydanticFunctionTool, ResponsesPydanticFunctionTool +from .input_tokens import ( + InputTokens, + AsyncInputTokens, + InputTokensWithRawResponse, + AsyncInputTokensWithRawResponse, + InputTokensWithStreamingResponse, + AsyncInputTokensWithStreamingResponse, +) from ..._base_client import make_request_options from ...types.responses import response_create_params, response_retrieve_params from ...lib._parsing._responses import ( @@ -52,6 +60,10 @@ class Responses(SyncAPIResource): def input_items(self) -> InputItems: return InputItems(self._client) + @cached_property + def input_tokens(self) -> InputTokens: + return InputTokens(self._client) + @cached_property def with_raw_response(self) -> ResponsesWithRawResponse: """ @@ -1483,6 +1495,10 @@ class AsyncResponses(AsyncAPIResource): def input_items(self) -> AsyncInputItems: return AsyncInputItems(self._client) + @cached_property + def input_tokens(self) -> AsyncInputTokens: + return AsyncInputTokens(self._client) + @cached_property def with_raw_response(self) -> AsyncResponsesWithRawResponse: """ @@ -2938,6 +2954,10 @@ def __init__(self, responses: Responses) -> None: def input_items(self) -> InputItemsWithRawResponse: return InputItemsWithRawResponse(self._responses.input_items) + @cached_property + def input_tokens(self) -> InputTokensWithRawResponse: + return InputTokensWithRawResponse(self._responses.input_tokens) + class AsyncResponsesWithRawResponse: def __init__(self, responses: AsyncResponses) -> None: @@ -2963,6 +2983,10 @@ def __init__(self, responses: AsyncResponses) -> None: def input_items(self) -> AsyncInputItemsWithRawResponse: return AsyncInputItemsWithRawResponse(self._responses.input_items) + @cached_property + def input_tokens(self) -> AsyncInputTokensWithRawResponse: + return AsyncInputTokensWithRawResponse(self._responses.input_tokens) + class ResponsesWithStreamingResponse: def __init__(self, responses: Responses) -> None: @@ -2985,6 +3009,10 @@ def __init__(self, responses: Responses) -> None: def input_items(self) -> InputItemsWithStreamingResponse: return InputItemsWithStreamingResponse(self._responses.input_items) + @cached_property + def input_tokens(self) -> InputTokensWithStreamingResponse: + return InputTokensWithStreamingResponse(self._responses.input_tokens) + class AsyncResponsesWithStreamingResponse: def __init__(self, responses: AsyncResponses) -> None: @@ -3007,6 +3035,10 @@ def __init__(self, responses: AsyncResponses) -> None: def input_items(self) -> AsyncInputItemsWithStreamingResponse: return AsyncInputItemsWithStreamingResponse(self._responses.input_items) + @cached_property + def input_tokens(self) -> AsyncInputTokensWithStreamingResponse: + return AsyncInputTokensWithStreamingResponse(self._responses.input_tokens) + def _make_tools(tools: Iterable[ParseableToolParam] | Omit) -> List[ToolParam] | Omit: if not is_given(tools): diff --git a/src/openai/types/responses/__init__.py b/src/openai/types/responses/__init__.py index 458118741b..fd70836e50 100644 --- a/src/openai/types/responses/__init__.py +++ b/src/openai/types/responses/__init__.py @@ -62,6 +62,7 @@ from .tool_choice_types_param import ToolChoiceTypesParam as ToolChoiceTypesParam from .web_search_preview_tool import WebSearchPreviewTool as WebSearchPreviewTool from .easy_input_message_param import EasyInputMessageParam as EasyInputMessageParam +from .input_token_count_params import InputTokenCountParams as InputTokenCountParams from .response_completed_event import ResponseCompletedEvent as ResponseCompletedEvent from .response_retrieve_params import ResponseRetrieveParams as ResponseRetrieveParams from .response_text_done_event import ResponseTextDoneEvent as ResponseTextDoneEvent @@ -74,6 +75,7 @@ from .response_input_text_param import ResponseInputTextParam as ResponseInputTextParam from .response_text_delta_event import ResponseTextDeltaEvent as ResponseTextDeltaEvent from .tool_choice_allowed_param import ToolChoiceAllowedParam as ToolChoiceAllowedParam +from .input_token_count_response import InputTokenCountResponse as InputTokenCountResponse from .response_audio_delta_event import ResponseAudioDeltaEvent as ResponseAudioDeltaEvent from .response_in_progress_event import ResponseInProgressEvent as ResponseInProgressEvent from .response_input_audio_param import ResponseInputAudioParam as ResponseInputAudioParam diff --git a/src/openai/types/responses/input_token_count_params.py b/src/openai/types/responses/input_token_count_params.py new file mode 100644 index 0000000000..d442a2d171 --- /dev/null +++ b/src/openai/types/responses/input_token_count_params.py @@ -0,0 +1,138 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable, Optional +from typing_extensions import Literal, TypeAlias, TypedDict + +from .tool_param import ToolParam +from .tool_choice_options import ToolChoiceOptions +from .tool_choice_mcp_param import ToolChoiceMcpParam +from .tool_choice_types_param import ToolChoiceTypesParam +from ..shared_params.reasoning import Reasoning +from .tool_choice_custom_param import ToolChoiceCustomParam +from .response_input_item_param import ResponseInputItemParam +from .tool_choice_allowed_param import ToolChoiceAllowedParam +from .tool_choice_function_param import ToolChoiceFunctionParam +from .response_conversation_param import ResponseConversationParam +from .response_format_text_config_param import ResponseFormatTextConfigParam + +__all__ = ["InputTokenCountParams", "Conversation", "Text", "ToolChoice"] + + +class InputTokenCountParams(TypedDict, total=False): + conversation: Optional[Conversation] + """The conversation that this response belongs to. + + Items from this conversation are prepended to `input_items` for this response + request. Input items and output items from this response are automatically added + to this conversation after this response completes. + """ + + input: Union[str, Iterable[ResponseInputItemParam], None] + """Text, image, or file inputs to the model, used to generate a response""" + + instructions: Optional[str] + """ + A system (or developer) message inserted into the model's context. When used + along with `previous_response_id`, the instructions from a previous response + will not be carried over to the next response. This makes it simple to swap out + system (or developer) messages in new responses. + """ + + model: Optional[str] + """Model ID used to generate the response, like `gpt-4o` or `o3`. + + OpenAI offers a wide range of models with different capabilities, performance + characteristics, and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + """ + + parallel_tool_calls: Optional[bool] + """Whether to allow the model to run tool calls in parallel.""" + + previous_response_id: Optional[str] + """The unique ID of the previous response to the model. + + Use this to create multi-turn conversations. Learn more about + [conversation state](https://platform.openai.com/docs/guides/conversation-state). + Cannot be used in conjunction with `conversation`. + """ + + reasoning: Optional[Reasoning] + """ + **gpt-5 and o-series models only** Configuration options for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). + """ + + text: Optional[Text] + """Configuration options for a text response from the model. + + Can be plain text or structured JSON data. Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + """ + + tool_choice: Optional[ToolChoice] + """ + How the model should select which tool (or tools) to use when generating a + response. See the `tools` parameter to see how to specify which tools the model + can call. + """ + + tools: Optional[Iterable[ToolParam]] + """An array of tools the model may call while generating a response. + + You can specify which tool to use by setting the `tool_choice` parameter. + """ + + truncation: Literal["auto", "disabled"] + """The truncation strategy to use for the model response. + + - `auto`: If the input to this Response exceeds the model's context window size, + the model will truncate the response to fit the context window by dropping + items from the beginning of the conversation. - `disabled` (default): If the + input size will exceed the context window size for a model, the request will + fail with a 400 error. + """ + + +Conversation: TypeAlias = Union[str, ResponseConversationParam] + + +class Text(TypedDict, total=False): + format: ResponseFormatTextConfigParam + """An object specifying the format that the model must output. + + Configuring `{ "type": "json_schema" }` enables Structured Outputs, which + ensures the model will match your supplied JSON schema. Learn more in the + [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). + + The default format is `{ "type": "text" }` with no additional options. + + **Not recommended for gpt-4o and newer models:** + + Setting to `{ "type": "json_object" }` enables the older JSON mode, which + ensures the message the model generates is valid JSON. Using `json_schema` is + preferred for models that support it. + """ + + verbosity: Optional[Literal["low", "medium", "high"]] + """Constrains the verbosity of the model's response. + + Lower values will result in more concise responses, while higher values will + result in more verbose responses. Currently supported values are `low`, + `medium`, and `high`. + """ + + +ToolChoice: TypeAlias = Union[ + ToolChoiceOptions, + ToolChoiceAllowedParam, + ToolChoiceTypesParam, + ToolChoiceFunctionParam, + ToolChoiceMcpParam, + ToolChoiceCustomParam, +] diff --git a/src/openai/types/responses/input_token_count_response.py b/src/openai/types/responses/input_token_count_response.py new file mode 100644 index 0000000000..30ddfc1217 --- /dev/null +++ b/src/openai/types/responses/input_token_count_response.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["InputTokenCountResponse"] + + +class InputTokenCountResponse(BaseModel): + input_tokens: int + + object: Literal["response.input_tokens"] diff --git a/tests/api_resources/responses/test_input_tokens.py b/tests/api_resources/responses/test_input_tokens.py new file mode 100644 index 0000000000..54ba2d25c2 --- /dev/null +++ b/tests/api_resources/responses/test_input_tokens.py @@ -0,0 +1,138 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.types.responses import InputTokenCountResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestInputTokens: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_count(self, client: OpenAI) -> None: + input_token = client.responses.input_tokens.count() + assert_matches_type(InputTokenCountResponse, input_token, path=["response"]) + + @parametrize + def test_method_count_with_all_params(self, client: OpenAI) -> None: + input_token = client.responses.input_tokens.count( + conversation="string", + input="string", + instructions="instructions", + model="model", + parallel_tool_calls=True, + previous_response_id="resp_123", + reasoning={ + "effort": "minimal", + "generate_summary": "auto", + "summary": "auto", + }, + text={ + "format": {"type": "text"}, + "verbosity": "low", + }, + tool_choice="none", + tools=[ + { + "name": "name", + "parameters": {"foo": "bar"}, + "strict": True, + "type": "function", + "description": "description", + } + ], + truncation="auto", + ) + assert_matches_type(InputTokenCountResponse, input_token, path=["response"]) + + @parametrize + def test_raw_response_count(self, client: OpenAI) -> None: + response = client.responses.input_tokens.with_raw_response.count() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + input_token = response.parse() + assert_matches_type(InputTokenCountResponse, input_token, path=["response"]) + + @parametrize + def test_streaming_response_count(self, client: OpenAI) -> None: + with client.responses.input_tokens.with_streaming_response.count() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + input_token = response.parse() + assert_matches_type(InputTokenCountResponse, input_token, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncInputTokens: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_count(self, async_client: AsyncOpenAI) -> None: + input_token = await async_client.responses.input_tokens.count() + assert_matches_type(InputTokenCountResponse, input_token, path=["response"]) + + @parametrize + async def test_method_count_with_all_params(self, async_client: AsyncOpenAI) -> None: + input_token = await async_client.responses.input_tokens.count( + conversation="string", + input="string", + instructions="instructions", + model="model", + parallel_tool_calls=True, + previous_response_id="resp_123", + reasoning={ + "effort": "minimal", + "generate_summary": "auto", + "summary": "auto", + }, + text={ + "format": {"type": "text"}, + "verbosity": "low", + }, + tool_choice="none", + tools=[ + { + "name": "name", + "parameters": {"foo": "bar"}, + "strict": True, + "type": "function", + "description": "description", + } + ], + truncation="auto", + ) + assert_matches_type(InputTokenCountResponse, input_token, path=["response"]) + + @parametrize + async def test_raw_response_count(self, async_client: AsyncOpenAI) -> None: + response = await async_client.responses.input_tokens.with_raw_response.count() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + input_token = response.parse() + assert_matches_type(InputTokenCountResponse, input_token, path=["response"]) + + @parametrize + async def test_streaming_response_count(self, async_client: AsyncOpenAI) -> None: + async with async_client.responses.input_tokens.with_streaming_response.count() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + input_token = await response.parse() + assert_matches_type(InputTokenCountResponse, input_token, path=["response"]) + + assert cast(Any, response.is_closed) is True From dff16b5e9964bf85157eb41181255ed5dde8dda4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 16:45:52 +0000 Subject: [PATCH 529/769] release: 2.6.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 4dedeaebc3..511dd5165c 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.5.0" + ".": "2.6.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f79fb75fe..1ac76520f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 2.6.0 (2025-10-20) + +Full Changelog: [v2.5.0...v2.6.0](https://github.com/openai/openai-python/compare/v2.5.0...v2.6.0) + +### Features + +* **api:** Add responses.input_tokens.count ([6dd09e2](https://github.com/openai/openai-python/commit/6dd09e2829f385f72b28620888d91a4493c96772)) + + +### Bug Fixes + +* **api:** internal openapi updates ([caabd7c](https://github.com/openai/openai-python/commit/caabd7c81f0f557f66dc0089af460185a5816c11)) + ## 2.5.0 (2025-10-17) Full Changelog: [v2.4.0...v2.5.0](https://github.com/openai/openai-python/compare/v2.4.0...v2.5.0) diff --git a/pyproject.toml b/pyproject.toml index a2f0ab7176..bcf990f3c0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.5.0" +version = "2.6.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 0d92388b98..7183b0287b 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__ = "2.5.0" # x-release-please-version +__version__ = "2.6.0" # x-release-please-version From e01f14b2acacfb8d74a308c7878632833a44561e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 19:43:07 +0000 Subject: [PATCH 530/769] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 48649a27d0..acef7ba4ff 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 136 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-812a10f8fb54c584efc914422b574cb3f43dc238b5733b13f6a0b2308b7d9910.yml -openapi_spec_hash: 0222041ba12a5ff6b94924a834fa91a2 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-a4bb37d110a22c2888f53e21281434686a6fffa3e672a40f2503ad9bd2759063.yml +openapi_spec_hash: 2d59eefb494dff4eea8c3d008c7e2070 config_hash: 50ee3382a63c021a9f821a935950e926 From 8dcfe8b259868c7d5b5384cdc7bfe1d51e320f68 Mon Sep 17 00:00:00 2001 From: David Meadows Date: Fri, 17 Oct 2025 14:18:38 -0400 Subject: [PATCH 531/769] copy over translations non-streaming + json def from async --- src/openai/resources/audio/transcriptions.py | 66 +++++++++++++++++++- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/src/openai/resources/audio/transcriptions.py b/src/openai/resources/audio/transcriptions.py index 30ef39deec..056e15eca6 100644 --- a/src/openai/resources/audio/transcriptions.py +++ b/src/openai/resources/audio/transcriptions.py @@ -69,9 +69,10 @@ def create( model: Union[str, AudioModel], chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | Omit = omit, include: List[TranscriptionInclude] | Omit = omit, - response_format: Union[Literal["json"], Omit] = omit, language: str | Omit = omit, prompt: str | Omit = omit, + response_format: Union[Literal["json"], Omit] = omit, + stream: Optional[Literal[False]] | Omit = omit, temperature: float | Omit = omit, timestamp_granularities: List[Literal["word", "segment"]] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -80,7 +81,68 @@ def create( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Transcription: ... + ) -> TranscriptionCreateResponse: + """ + Transcribes audio into the input language. + + Args: + file: + The audio file object (not file name) to transcribe, in one of these formats: + flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. + + model: ID of the model to use. The options are `gpt-4o-transcribe`, + `gpt-4o-mini-transcribe`, and `whisper-1` (which is powered by our open source + Whisper V2 model). + + chunking_strategy: Controls how the audio is cut into chunks. When set to `"auto"`, the server + first normalizes loudness and then uses voice activity detection (VAD) to choose + boundaries. `server_vad` object can be provided to tweak VAD detection + parameters manually. If unset, the audio is transcribed as a single block. + + include: Additional information to include in the transcription response. `logprobs` will + return the log probabilities of the tokens in the response to understand the + model's confidence in the transcription. `logprobs` only works with + response_format set to `json` and only with the models `gpt-4o-transcribe` and + `gpt-4o-mini-transcribe`. + + language: The language of the input audio. Supplying the input language in + [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) + format will improve accuracy and latency. + + prompt: An optional text to guide the model's style or continue a previous audio + segment. The + [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) + should match the audio language. + + response_format: The format of the output, in one of these options: `json`, `text`, `srt`, + `verbose_json`, or `vtt`. For `gpt-4o-transcribe` and `gpt-4o-mini-transcribe`, + the only supported format is `json`. + + stream: If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section of the Speech-to-Text guide](https://platform.openai.com/docs/guides/speech-to-text?lang=curl#streaming-transcriptions) + for more information. + + Note: Streaming is not supported for the `whisper-1` model and will be ignored. + + temperature: The sampling temperature, between 0 and 1. Higher values like 0.8 will make the + output more random, while lower values like 0.2 will make it more focused and + deterministic. If set to 0, the model will use + [log probability](https://en.wikipedia.org/wiki/Log_probability) to + automatically increase the temperature until certain thresholds are hit. + + timestamp_granularities: The timestamp granularities to populate for this transcription. + `response_format` must be set `verbose_json` to use timestamp granularities. + Either or both of these options are supported: `word`, or `segment`. Note: There + is no additional latency for segment timestamps, but generating word timestamps + incurs additional latency. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + """ @overload def create( From f05eec91fe6dcfefb9ccadfeb6cf2154d77714fe Mon Sep 17 00:00:00 2001 From: David Meadows Date: Fri, 17 Oct 2025 14:33:26 -0400 Subject: [PATCH 532/769] revert change to response type --- src/openai/resources/audio/transcriptions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openai/resources/audio/transcriptions.py b/src/openai/resources/audio/transcriptions.py index 056e15eca6..a5c86146d4 100644 --- a/src/openai/resources/audio/transcriptions.py +++ b/src/openai/resources/audio/transcriptions.py @@ -81,7 +81,7 @@ def create( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> TranscriptionCreateResponse: + ) -> Transcription: """ Transcribes audio into the input language. From 663e89602cb5957e9dd584514a9b06f0d3f5385a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 21 Oct 2025 22:33:48 +0000 Subject: [PATCH 533/769] fix(api): docs updates --- .stats.yml | 4 +- src/openai/resources/files.py | 54 ++++++++++----------- src/openai/types/shared/reasoning.py | 2 + src/openai/types/shared_params/reasoning.py | 2 + 4 files changed, 32 insertions(+), 30 deletions(-) diff --git a/.stats.yml b/.stats.yml index acef7ba4ff..b4309cd4c3 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 136 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-a4bb37d110a22c2888f53e21281434686a6fffa3e672a40f2503ad9bd2759063.yml -openapi_spec_hash: 2d59eefb494dff4eea8c3d008c7e2070 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-a3c45d9bd3bb25bf4eaa49b7fb473a00038293dec659ffaa44f624ded884abf4.yml +openapi_spec_hash: 9c20aaf786a0700dabd13d9865481c9e config_hash: 50ee3382a63c021a9f821a935950e926 diff --git a/src/openai/resources/files.py b/src/openai/resources/files.py index bb9ad43b1b..cc117e7f15 100644 --- a/src/openai/resources/files.py +++ b/src/openai/resources/files.py @@ -71,20 +71,19 @@ def create( up to 512 MB, and the size of all files uploaded by one organization can be up to 1 TB. - The Assistants API supports files up to 2 million tokens and of specific file - types. See the - [Assistants Tools guide](https://platform.openai.com/docs/assistants/tools) for - details. - - The Fine-tuning API only supports `.jsonl` files. The input also has certain - required formats for fine-tuning - [chat](https://platform.openai.com/docs/api-reference/fine-tuning/chat-input) or - [completions](https://platform.openai.com/docs/api-reference/fine-tuning/completions-input) - models. - - The Batch API only supports `.jsonl` files up to 200 MB in size. The input also - has a specific required - [format](https://platform.openai.com/docs/api-reference/batch/request-input). + - The Assistants API supports files up to 2 million tokens and of specific file + types. See the + [Assistants Tools guide](https://platform.openai.com/docs/assistants/tools) + for details. + - The Fine-tuning API only supports `.jsonl` files. The input also has certain + required formats for fine-tuning + [chat](https://platform.openai.com/docs/api-reference/fine-tuning/chat-input) + or + [completions](https://platform.openai.com/docs/api-reference/fine-tuning/completions-input) + models. + - The Batch API only supports `.jsonl` files up to 200 MB in size. The input + also has a specific required + [format](https://platform.openai.com/docs/api-reference/batch/request-input). Please [contact us](https://help.openai.com/) if you need to increase these storage limits. @@ -388,20 +387,19 @@ async def create( up to 512 MB, and the size of all files uploaded by one organization can be up to 1 TB. - The Assistants API supports files up to 2 million tokens and of specific file - types. See the - [Assistants Tools guide](https://platform.openai.com/docs/assistants/tools) for - details. - - The Fine-tuning API only supports `.jsonl` files. The input also has certain - required formats for fine-tuning - [chat](https://platform.openai.com/docs/api-reference/fine-tuning/chat-input) or - [completions](https://platform.openai.com/docs/api-reference/fine-tuning/completions-input) - models. - - The Batch API only supports `.jsonl` files up to 200 MB in size. The input also - has a specific required - [format](https://platform.openai.com/docs/api-reference/batch/request-input). + - The Assistants API supports files up to 2 million tokens and of specific file + types. See the + [Assistants Tools guide](https://platform.openai.com/docs/assistants/tools) + for details. + - The Fine-tuning API only supports `.jsonl` files. The input also has certain + required formats for fine-tuning + [chat](https://platform.openai.com/docs/api-reference/fine-tuning/chat-input) + or + [completions](https://platform.openai.com/docs/api-reference/fine-tuning/completions-input) + models. + - The Batch API only supports `.jsonl` files up to 200 MB in size. The input + also has a specific required + [format](https://platform.openai.com/docs/api-reference/batch/request-input). Please [contact us](https://help.openai.com/) if you need to increase these storage limits. diff --git a/src/openai/types/shared/reasoning.py b/src/openai/types/shared/reasoning.py index 2cf34eb9ae..6ea2fe82bf 100644 --- a/src/openai/types/shared/reasoning.py +++ b/src/openai/types/shared/reasoning.py @@ -35,4 +35,6 @@ class Reasoning(BaseModel): This can be useful for debugging and understanding the model's reasoning process. One of `auto`, `concise`, or `detailed`. + + `concise` is only supported for `computer-use-preview` models. """ diff --git a/src/openai/types/shared_params/reasoning.py b/src/openai/types/shared_params/reasoning.py index d5461a4eaa..5c1eff683f 100644 --- a/src/openai/types/shared_params/reasoning.py +++ b/src/openai/types/shared_params/reasoning.py @@ -36,4 +36,6 @@ class Reasoning(TypedDict, total=False): This can be useful for debugging and understanding the model's reasoning process. One of `auto`, `concise`, or `detailed`. + + `concise` is only supported for `computer-use-preview` models. """ From 4e8856576211064b09c0cc4a1ed35b82b169abe2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 24 Oct 2025 05:04:02 +0000 Subject: [PATCH 534/769] release: 2.6.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 511dd5165c..2f8909f197 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.6.0" + ".": "2.6.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ac76520f3..0ce541566d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 2.6.1 (2025-10-24) + +Full Changelog: [v2.6.0...v2.6.1](https://github.com/openai/openai-python/compare/v2.6.0...v2.6.1) + +### Bug Fixes + +* **api:** docs updates ([d01a0c9](https://github.com/openai/openai-python/commit/d01a0c96ecb94c78b7e16546790c573704b7515b)) + + +### Chores + +* **client:** clean up custom translations code ([cfb9e25](https://github.com/openai/openai-python/commit/cfb9e25855b8eb020abe02cdd99566adf474e821)) + ## 2.6.0 (2025-10-20) Full Changelog: [v2.5.0...v2.6.0](https://github.com/openai/openai-python/compare/v2.5.0...v2.6.0) diff --git a/pyproject.toml b/pyproject.toml index bcf990f3c0..e96101b51c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.6.0" +version = "2.6.1" 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 7183b0287b..b0fe817996 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__ = "2.6.0" # x-release-please-version +__version__ = "2.6.1" # x-release-please-version From b16bf4eb46cce0a2414086fd14f2e6a7497e8754 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 28 Oct 2025 00:54:12 +0000 Subject: [PATCH 535/769] feat(api): remove InputAudio from ResponseInputContent Removes the type `InputAudio` from `ResponseInputContent`. This parameter was non-functional and has now been removed. Please note that this is not a feature removal; it was never supported by the Responses API. While this is technically a backward-incompatible change due to the type removal, it reflects the intended behavior and has no functional impact. --- .stats.yml | 4 ++-- src/openai/types/responses/response_input_content.py | 4 +--- src/openai/types/responses/response_input_content_param.py | 5 +---- .../responses/response_input_message_content_list_param.py | 5 +---- 4 files changed, 5 insertions(+), 13 deletions(-) diff --git a/.stats.yml b/.stats.yml index b4309cd4c3..bc4e084f99 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 136 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-a3c45d9bd3bb25bf4eaa49b7fb473a00038293dec659ffaa44f624ded884abf4.yml -openapi_spec_hash: 9c20aaf786a0700dabd13d9865481c9e +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-f68f718cd45ac3f9336603601bccc38a718af44d0b26601031de3d0a71b7ce2f.yml +openapi_spec_hash: 1560717860bba4105936647dde8f618d config_hash: 50ee3382a63c021a9f821a935950e926 diff --git a/src/openai/types/responses/response_input_content.py b/src/openai/types/responses/response_input_content.py index 376b9ffce8..1726909a17 100644 --- a/src/openai/types/responses/response_input_content.py +++ b/src/openai/types/responses/response_input_content.py @@ -6,12 +6,10 @@ from ..._utils import PropertyInfo from .response_input_file import ResponseInputFile from .response_input_text import ResponseInputText -from .response_input_audio import ResponseInputAudio from .response_input_image import ResponseInputImage __all__ = ["ResponseInputContent"] ResponseInputContent: TypeAlias = Annotated[ - Union[ResponseInputText, ResponseInputImage, ResponseInputFile, ResponseInputAudio], - PropertyInfo(discriminator="type"), + Union[ResponseInputText, ResponseInputImage, ResponseInputFile], PropertyInfo(discriminator="type") ] diff --git a/src/openai/types/responses/response_input_content_param.py b/src/openai/types/responses/response_input_content_param.py index a95e026a53..7791cdfd8e 100644 --- a/src/openai/types/responses/response_input_content_param.py +++ b/src/openai/types/responses/response_input_content_param.py @@ -7,11 +7,8 @@ from .response_input_file_param import ResponseInputFileParam from .response_input_text_param import ResponseInputTextParam -from .response_input_audio_param import ResponseInputAudioParam from .response_input_image_param import ResponseInputImageParam __all__ = ["ResponseInputContentParam"] -ResponseInputContentParam: TypeAlias = Union[ - ResponseInputTextParam, ResponseInputImageParam, ResponseInputFileParam, ResponseInputAudioParam -] +ResponseInputContentParam: TypeAlias = Union[ResponseInputTextParam, ResponseInputImageParam, ResponseInputFileParam] diff --git a/src/openai/types/responses/response_input_message_content_list_param.py b/src/openai/types/responses/response_input_message_content_list_param.py index 8e3778d15a..080613df0d 100644 --- a/src/openai/types/responses/response_input_message_content_list_param.py +++ b/src/openai/types/responses/response_input_message_content_list_param.py @@ -7,13 +7,10 @@ from .response_input_file_param import ResponseInputFileParam from .response_input_text_param import ResponseInputTextParam -from .response_input_audio_param import ResponseInputAudioParam from .response_input_image_param import ResponseInputImageParam __all__ = ["ResponseInputMessageContentListParam", "ResponseInputContentParam"] -ResponseInputContentParam: TypeAlias = Union[ - ResponseInputTextParam, ResponseInputImageParam, ResponseInputFileParam, ResponseInputAudioParam -] +ResponseInputContentParam: TypeAlias = Union[ResponseInputTextParam, ResponseInputImageParam, ResponseInputFileParam] ResponseInputMessageContentListParam: TypeAlias = List[ResponseInputContentParam] From 6132922c6d5d67708f3e6f1d09ddc85cff7ad32c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 29 Oct 2025 10:42:58 +0000 Subject: [PATCH 536/769] fix(client): close streams without requiring full consumption --- src/openai/_streaming.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/openai/_streaming.py b/src/openai/_streaming.py index f586de74ff..05c284a2be 100644 --- a/src/openai/_streaming.py +++ b/src/openai/_streaming.py @@ -96,9 +96,8 @@ def __stream__(self) -> Iterator[_T]: yield process_data(data=data, cast_to=cast_to, response=response) - # Ensure the entire stream is consumed - for _sse in iterator: - ... + # As we might not fully consume the response stream, we need to close it explicitly + response.close() def __enter__(self) -> Self: return self @@ -198,9 +197,8 @@ async def __stream__(self) -> AsyncIterator[_T]: yield process_data(data=data, cast_to=cast_to, response=response) - # Ensure the entire stream is consumed - async for _sse in iterator: - ... + # As we might not fully consume the response stream, we need to close it explicitly + await response.aclose() async def __aenter__(self) -> Self: return self From 35cb4e9bb6df5f9b746d818e80f7bafe72b30dfd Mon Sep 17 00:00:00 2001 From: Dan Martins Date: Wed, 29 Oct 2025 08:53:08 -0400 Subject: [PATCH 537/769] fix(readme): update realtime examples (#2714) --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9311b477a3..21f79312a1 100644 --- a/README.md +++ b/README.md @@ -244,7 +244,9 @@ async def main(): client = AsyncOpenAI() async with client.realtime.connect(model="gpt-realtime") as connection: - await connection.session.update(session={'modalities': ['text']}) + await connection.session.update( + session={"type": "realtime", "output_modalities": ["text"]} + ) await connection.conversation.item.create( item={ @@ -256,10 +258,10 @@ async def main(): await connection.response.create() async for event in connection: - if event.type == 'response.text.delta': + if event.type == "response.output_text.delta": print(event.delta, flush=True, end="") - elif event.type == 'response.text.done': + elif event.type == "response.output_text.done": print() elif event.type == "response.done": From 214d13284e95e3223dcc0fd954c8e9c93db5b89a Mon Sep 17 00:00:00 2001 From: Showmick Das Date: Thu, 30 Oct 2025 05:52:29 -0400 Subject: [PATCH 538/769] fix(uploads): avoid file handle leak --- src/openai/resources/uploads/uploads.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/openai/resources/uploads/uploads.py b/src/openai/resources/uploads/uploads.py index 8953256f2a..e8c047bd4f 100644 --- a/src/openai/resources/uploads/uploads.py +++ b/src/openai/resources/uploads/uploads.py @@ -157,9 +157,8 @@ def upload_file_chunked( part = self.parts.create(upload_id=upload.id, data=data) log.info("Uploaded part %s for upload %s", part.id, upload.id) part_ids.append(part.id) - except Exception: + finally: buf.close() - raise return self.complete(upload_id=upload.id, part_ids=part_ids, md5=md5) @@ -465,9 +464,8 @@ async def upload_file_chunked( part = await self.parts.create(upload_id=upload.id, data=data) log.info("Uploaded part %s for upload %s", part.id, upload.id) part_ids.append(part.id) - except Exception: + finally: buf.close() - raise return await self.complete(upload_id=upload.id, part_ids=part_ids, md5=md5) From 5327844316860adc1ca534e6001d163d0e23fd79 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 30 Oct 2025 11:05:12 +0000 Subject: [PATCH 539/769] chore(internal/tests): avoid race condition with implicit client cleanup --- tests/test_client.py | 372 +++++++++++++++++++++++-------------------- 1 file changed, 202 insertions(+), 170 deletions(-) diff --git a/tests/test_client.py b/tests/test_client.py index 3287e0e706..e8d62f17f7 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -64,51 +64,49 @@ def _get_open_connections(client: OpenAI | AsyncOpenAI) -> int: class TestOpenAI: - client = OpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=True) - @pytest.mark.respx(base_url=base_url) - def test_raw_response(self, respx_mock: MockRouter) -> None: + def test_raw_response(self, respx_mock: MockRouter, client: OpenAI) -> None: respx_mock.post("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - response = self.client.post("/foo", cast_to=httpx.Response) + response = client.post("/foo", cast_to=httpx.Response) assert response.status_code == 200 assert isinstance(response, httpx.Response) assert response.json() == {"foo": "bar"} @pytest.mark.respx(base_url=base_url) - def test_raw_response_for_binary(self, respx_mock: MockRouter) -> None: + def test_raw_response_for_binary(self, respx_mock: MockRouter, client: OpenAI) -> None: respx_mock.post("/foo").mock( return_value=httpx.Response(200, headers={"Content-Type": "application/binary"}, content='{"foo": "bar"}') ) - response = self.client.post("/foo", cast_to=httpx.Response) + response = client.post("/foo", cast_to=httpx.Response) assert response.status_code == 200 assert isinstance(response, httpx.Response) assert response.json() == {"foo": "bar"} - def test_copy(self) -> None: - copied = self.client.copy() - assert id(copied) != id(self.client) + def test_copy(self, client: OpenAI) -> None: + copied = client.copy() + assert id(copied) != id(client) - copied = self.client.copy(api_key="another My API Key") + copied = client.copy(api_key="another My API Key") assert copied.api_key == "another My API Key" - assert self.client.api_key == "My API Key" + assert client.api_key == "My API Key" - def test_copy_default_options(self) -> None: + def test_copy_default_options(self, client: OpenAI) -> None: # options that have a default are overridden correctly - copied = self.client.copy(max_retries=7) + copied = client.copy(max_retries=7) assert copied.max_retries == 7 - assert self.client.max_retries == 2 + assert client.max_retries == 2 copied2 = copied.copy(max_retries=6) assert copied2.max_retries == 6 assert copied.max_retries == 7 # timeout - assert isinstance(self.client.timeout, httpx.Timeout) - copied = self.client.copy(timeout=None) + assert isinstance(client.timeout, httpx.Timeout) + copied = client.copy(timeout=None) assert copied.timeout is None - assert isinstance(self.client.timeout, httpx.Timeout) + assert isinstance(client.timeout, httpx.Timeout) def test_copy_default_headers(self) -> None: client = OpenAI( @@ -143,6 +141,7 @@ def test_copy_default_headers(self) -> None: match="`default_headers` and `set_default_headers` arguments are mutually exclusive", ): client.copy(set_default_headers={}, default_headers={"X-Foo": "Bar"}) + client.close() def test_copy_default_query(self) -> None: client = OpenAI( @@ -180,13 +179,15 @@ def test_copy_default_query(self) -> None: ): client.copy(set_default_query={}, default_query={"foo": "Bar"}) - def test_copy_signature(self) -> None: + client.close() + + def test_copy_signature(self, client: OpenAI) -> None: # ensure the same parameters that can be passed to the client are defined in the `.copy()` method init_signature = inspect.signature( # mypy doesn't like that we access the `__init__` property. - self.client.__init__, # type: ignore[misc] + client.__init__, # type: ignore[misc] ) - copy_signature = inspect.signature(self.client.copy) + copy_signature = inspect.signature(client.copy) exclude_params = {"transport", "proxies", "_strict_response_validation"} for name in init_signature.parameters.keys(): @@ -197,12 +198,12 @@ def test_copy_signature(self) -> None: assert copy_param is not None, f"copy() signature is missing the {name} param" @pytest.mark.skipif(sys.version_info >= (3, 10), reason="fails because of a memory leak that started from 3.12") - def test_copy_build_request(self) -> None: + def test_copy_build_request(self, client: OpenAI) -> None: options = FinalRequestOptions(method="get", url="/foo") def build_request(options: FinalRequestOptions) -> None: - client = self.client.copy() - client._build_request(options) + client_copy = client.copy() + client_copy._build_request(options) # ensure that the machinery is warmed up before tracing starts. build_request(options) @@ -259,14 +260,12 @@ def add_leak(leaks: list[tracemalloc.StatisticDiff], diff: tracemalloc.Statistic print(frame) raise AssertionError() - def test_request_timeout(self) -> None: - request = self.client._build_request(FinalRequestOptions(method="get", url="/foo")) + def test_request_timeout(self, client: OpenAI) -> None: + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == DEFAULT_TIMEOUT - request = self.client._build_request( - FinalRequestOptions(method="get", url="/foo", timeout=httpx.Timeout(100.0)) - ) + request = client._build_request(FinalRequestOptions(method="get", url="/foo", timeout=httpx.Timeout(100.0))) timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == httpx.Timeout(100.0) @@ -277,6 +276,8 @@ def test_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == httpx.Timeout(0) + client.close() + def test_http_client_timeout_option(self) -> None: # custom timeout given to the httpx client should be used with httpx.Client(timeout=None) as http_client: @@ -288,6 +289,8 @@ def test_http_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == httpx.Timeout(None) + client.close() + # no timeout given to the httpx client should not use the httpx default with httpx.Client() as http_client: client = OpenAI( @@ -298,6 +301,8 @@ def test_http_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == DEFAULT_TIMEOUT + client.close() + # explicitly passing the default timeout currently results in it being ignored with httpx.Client(timeout=HTTPX_DEFAULT_TIMEOUT) as http_client: client = OpenAI( @@ -308,6 +313,8 @@ def test_http_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == DEFAULT_TIMEOUT # our default + client.close() + async def test_invalid_http_client(self) -> None: with pytest.raises(TypeError, match="Invalid `http_client` arg"): async with httpx.AsyncClient() as http_client: @@ -319,14 +326,14 @@ async def test_invalid_http_client(self) -> None: ) def test_default_headers_option(self) -> None: - client = OpenAI( + test_client = OpenAI( base_url=base_url, api_key=api_key, _strict_response_validation=True, default_headers={"X-Foo": "bar"} ) - request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + request = test_client._build_request(FinalRequestOptions(method="get", url="/foo")) assert request.headers.get("x-foo") == "bar" assert request.headers.get("x-stainless-lang") == "python" - client2 = OpenAI( + test_client2 = OpenAI( base_url=base_url, api_key=api_key, _strict_response_validation=True, @@ -335,10 +342,13 @@ def test_default_headers_option(self) -> None: "X-Stainless-Lang": "my-overriding-header", }, ) - request = client2._build_request(FinalRequestOptions(method="get", url="/foo")) + request = test_client2._build_request(FinalRequestOptions(method="get", url="/foo")) assert request.headers.get("x-foo") == "stainless" assert request.headers.get("x-stainless-lang") == "my-overriding-header" + test_client.close() + test_client2.close() + def test_validate_headers(self) -> None: client = OpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=True) options = client._prepare_options(FinalRequestOptions(method="get", url="/foo")) @@ -369,8 +379,10 @@ def test_default_query_option(self) -> None: url = httpx.URL(request.url) assert dict(url.params) == {"foo": "baz", "query_param": "overridden"} - def test_request_extra_json(self) -> None: - request = self.client._build_request( + client.close() + + def test_request_extra_json(self, client: OpenAI) -> None: + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -381,7 +393,7 @@ def test_request_extra_json(self) -> None: data = json.loads(request.content.decode("utf-8")) assert data == {"foo": "bar", "baz": False} - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -392,7 +404,7 @@ def test_request_extra_json(self) -> None: assert data == {"baz": False} # `extra_json` takes priority over `json_data` when keys clash - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -403,8 +415,8 @@ def test_request_extra_json(self) -> None: data = json.loads(request.content.decode("utf-8")) assert data == {"foo": "bar", "baz": None} - def test_request_extra_headers(self) -> None: - request = self.client._build_request( + def test_request_extra_headers(self, client: OpenAI) -> None: + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -414,7 +426,7 @@ def test_request_extra_headers(self) -> None: assert request.headers.get("X-Foo") == "Foo" # `extra_headers` takes priority over `default_headers` when keys clash - request = self.client.with_options(default_headers={"X-Bar": "true"})._build_request( + request = client.with_options(default_headers={"X-Bar": "true"})._build_request( FinalRequestOptions( method="post", url="/foo", @@ -425,8 +437,8 @@ def test_request_extra_headers(self) -> None: ) assert request.headers.get("X-Bar") == "false" - def test_request_extra_query(self) -> None: - request = self.client._build_request( + def test_request_extra_query(self, client: OpenAI) -> None: + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -439,7 +451,7 @@ def test_request_extra_query(self) -> None: assert params == {"my_query_param": "Foo"} # if both `query` and `extra_query` are given, they are merged - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -453,7 +465,7 @@ def test_request_extra_query(self) -> None: assert params == {"bar": "1", "foo": "2"} # `extra_query` takes priority over `query` when keys clash - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -496,7 +508,7 @@ def test_multipart_repeating_array(self, client: OpenAI) -> None: ] @pytest.mark.respx(base_url=base_url) - def test_basic_union_response(self, respx_mock: MockRouter) -> None: + def test_basic_union_response(self, respx_mock: MockRouter, client: OpenAI) -> None: class Model1(BaseModel): name: str @@ -505,12 +517,12 @@ class Model2(BaseModel): respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - response = self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + response = client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) assert isinstance(response, Model2) assert response.foo == "bar" @pytest.mark.respx(base_url=base_url) - def test_union_response_different_types(self, respx_mock: MockRouter) -> None: + def test_union_response_different_types(self, respx_mock: MockRouter, client: OpenAI) -> None: """Union of objects with the same field name using a different type""" class Model1(BaseModel): @@ -521,18 +533,18 @@ class Model2(BaseModel): respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - response = self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + response = client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) assert isinstance(response, Model2) assert response.foo == "bar" respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": 1})) - response = self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + response = client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) assert isinstance(response, Model1) assert response.foo == 1 @pytest.mark.respx(base_url=base_url) - def test_non_application_json_content_type_for_json_data(self, respx_mock: MockRouter) -> None: + def test_non_application_json_content_type_for_json_data(self, respx_mock: MockRouter, client: OpenAI) -> None: """ Response that sets Content-Type to something other than application/json but returns json data """ @@ -548,7 +560,7 @@ class Model(BaseModel): ) ) - response = self.client.get("/foo", cast_to=Model) + response = client.get("/foo", cast_to=Model) assert isinstance(response, Model) assert response.foo == 2 @@ -560,6 +572,8 @@ def test_base_url_setter(self) -> None: assert client.base_url == "https://example.com/from_setter/" + client.close() + def test_base_url_env(self) -> None: with update_env(OPENAI_BASE_URL="http://localhost:5000/from/env"): client = OpenAI(api_key=api_key, _strict_response_validation=True) @@ -587,6 +601,7 @@ def test_base_url_trailing_slash(self, client: OpenAI) -> None: ), ) assert request.url == "http://localhost:5000/custom/path/foo" + client.close() @pytest.mark.parametrize( "client", @@ -610,6 +625,7 @@ def test_base_url_no_trailing_slash(self, client: OpenAI) -> None: ), ) assert request.url == "http://localhost:5000/custom/path/foo" + client.close() @pytest.mark.parametrize( "client", @@ -633,35 +649,36 @@ def test_absolute_request_url(self, client: OpenAI) -> None: ), ) assert request.url == "https://myapi.com/foo" + client.close() def test_copied_client_does_not_close_http(self) -> None: - client = OpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=True) - assert not client.is_closed() + test_client = OpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=True) + assert not test_client.is_closed() - copied = client.copy() - assert copied is not client + copied = test_client.copy() + assert copied is not test_client del copied - assert not client.is_closed() + assert not test_client.is_closed() def test_client_context_manager(self) -> None: - client = OpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=True) - with client as c2: - assert c2 is client + test_client = OpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=True) + with test_client as c2: + assert c2 is test_client assert not c2.is_closed() - assert not client.is_closed() - assert client.is_closed() + assert not test_client.is_closed() + assert test_client.is_closed() @pytest.mark.respx(base_url=base_url) - def test_client_response_validation_error(self, respx_mock: MockRouter) -> None: + def test_client_response_validation_error(self, respx_mock: MockRouter, client: OpenAI) -> None: class Model(BaseModel): foo: str respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": {"invalid": True}})) with pytest.raises(APIResponseValidationError) as exc: - self.client.get("/foo", cast_to=Model) + client.get("/foo", cast_to=Model) assert isinstance(exc.value.__cause__, ValidationError) @@ -670,13 +687,13 @@ def test_client_max_retries_validation(self) -> None: OpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=True, max_retries=cast(Any, None)) @pytest.mark.respx(base_url=base_url) - def test_default_stream_cls(self, respx_mock: MockRouter) -> None: + def test_default_stream_cls(self, respx_mock: MockRouter, client: OpenAI) -> None: class Model(BaseModel): name: str respx_mock.post("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - stream = self.client.post("/foo", cast_to=Model, stream=True, stream_cls=Stream[Model]) + stream = client.post("/foo", cast_to=Model, stream=True, stream_cls=Stream[Model]) assert isinstance(stream, Stream) stream.response.close() @@ -692,11 +709,14 @@ class Model(BaseModel): with pytest.raises(APIResponseValidationError): strict_client.get("/foo", cast_to=Model) - client = OpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=False) + non_strict_client = OpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=False) - response = client.get("/foo", cast_to=Model) + response = non_strict_client.get("/foo", cast_to=Model) assert isinstance(response, str) # type: ignore[unreachable] + strict_client.close() + non_strict_client.close() + @pytest.mark.parametrize( "remaining_retries,retry_after,timeout", [ @@ -719,9 +739,9 @@ class Model(BaseModel): ], ) @mock.patch("time.time", mock.MagicMock(return_value=1696004797)) - def test_parse_retry_after_header(self, remaining_retries: int, retry_after: str, timeout: float) -> None: - client = OpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=True) - + def test_parse_retry_after_header( + self, remaining_retries: int, retry_after: str, timeout: float, client: OpenAI + ) -> None: headers = httpx.Headers({"retry-after": retry_after}) options = FinalRequestOptions(method="get", url="/foo", max_retries=3) calculated = client._calculate_retry_timeout(remaining_retries, options, headers) @@ -743,7 +763,7 @@ def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter, clien model="gpt-4o", ).__enter__() - assert _get_open_connections(self.client) == 0 + assert _get_open_connections(client) == 0 @mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) @@ -760,7 +780,7 @@ def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter, client ], model="gpt-4o", ).__enter__() - assert _get_open_connections(self.client) == 0 + assert _get_open_connections(client) == 0 @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @@ -919,28 +939,26 @@ def test_default_client_creation(self) -> None: ) @pytest.mark.respx(base_url=base_url) - def test_follow_redirects(self, respx_mock: MockRouter) -> None: + def test_follow_redirects(self, respx_mock: MockRouter, client: OpenAI) -> None: # Test that the default follow_redirects=True allows following redirects respx_mock.post("/redirect").mock( return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) ) respx_mock.get("/redirected").mock(return_value=httpx.Response(200, json={"status": "ok"})) - response = self.client.post("/redirect", body={"key": "value"}, cast_to=httpx.Response) + response = client.post("/redirect", body={"key": "value"}, cast_to=httpx.Response) assert response.status_code == 200 assert response.json() == {"status": "ok"} @pytest.mark.respx(base_url=base_url) - def test_follow_redirects_disabled(self, respx_mock: MockRouter) -> None: + def test_follow_redirects_disabled(self, respx_mock: MockRouter, client: OpenAI) -> None: # Test that follow_redirects=False prevents following redirects respx_mock.post("/redirect").mock( return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) ) with pytest.raises(APIStatusError) as exc_info: - self.client.post( - "/redirect", body={"key": "value"}, options={"follow_redirects": False}, cast_to=httpx.Response - ) + client.post("/redirect", body={"key": "value"}, options={"follow_redirects": False}, cast_to=httpx.Response) assert exc_info.value.response.status_code == 302 assert exc_info.value.response.headers["Location"] == f"{base_url}/redirected" @@ -1003,55 +1021,51 @@ def test_copy_auth(self) -> None: class TestAsyncOpenAI: - client = AsyncOpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=True) - @pytest.mark.respx(base_url=base_url) - @pytest.mark.asyncio - async def test_raw_response(self, respx_mock: MockRouter) -> None: + async def test_raw_response(self, respx_mock: MockRouter, async_client: AsyncOpenAI) -> None: respx_mock.post("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - response = await self.client.post("/foo", cast_to=httpx.Response) + response = await async_client.post("/foo", cast_to=httpx.Response) assert response.status_code == 200 assert isinstance(response, httpx.Response) assert response.json() == {"foo": "bar"} @pytest.mark.respx(base_url=base_url) - @pytest.mark.asyncio - async def test_raw_response_for_binary(self, respx_mock: MockRouter) -> None: + async def test_raw_response_for_binary(self, respx_mock: MockRouter, async_client: AsyncOpenAI) -> None: respx_mock.post("/foo").mock( return_value=httpx.Response(200, headers={"Content-Type": "application/binary"}, content='{"foo": "bar"}') ) - response = await self.client.post("/foo", cast_to=httpx.Response) + response = await async_client.post("/foo", cast_to=httpx.Response) assert response.status_code == 200 assert isinstance(response, httpx.Response) assert response.json() == {"foo": "bar"} - def test_copy(self) -> None: - copied = self.client.copy() - assert id(copied) != id(self.client) + def test_copy(self, async_client: AsyncOpenAI) -> None: + copied = async_client.copy() + assert id(copied) != id(async_client) - copied = self.client.copy(api_key="another My API Key") + copied = async_client.copy(api_key="another My API Key") assert copied.api_key == "another My API Key" - assert self.client.api_key == "My API Key" + assert async_client.api_key == "My API Key" - def test_copy_default_options(self) -> None: + def test_copy_default_options(self, async_client: AsyncOpenAI) -> None: # options that have a default are overridden correctly - copied = self.client.copy(max_retries=7) + copied = async_client.copy(max_retries=7) assert copied.max_retries == 7 - assert self.client.max_retries == 2 + assert async_client.max_retries == 2 copied2 = copied.copy(max_retries=6) assert copied2.max_retries == 6 assert copied.max_retries == 7 # timeout - assert isinstance(self.client.timeout, httpx.Timeout) - copied = self.client.copy(timeout=None) + assert isinstance(async_client.timeout, httpx.Timeout) + copied = async_client.copy(timeout=None) assert copied.timeout is None - assert isinstance(self.client.timeout, httpx.Timeout) + assert isinstance(async_client.timeout, httpx.Timeout) - def test_copy_default_headers(self) -> None: + async def test_copy_default_headers(self) -> None: client = AsyncOpenAI( base_url=base_url, api_key=api_key, _strict_response_validation=True, default_headers={"X-Foo": "bar"} ) @@ -1084,8 +1098,9 @@ def test_copy_default_headers(self) -> None: match="`default_headers` and `set_default_headers` arguments are mutually exclusive", ): client.copy(set_default_headers={}, default_headers={"X-Foo": "Bar"}) + await client.close() - def test_copy_default_query(self) -> None: + async def test_copy_default_query(self) -> None: client = AsyncOpenAI( base_url=base_url, api_key=api_key, _strict_response_validation=True, default_query={"foo": "bar"} ) @@ -1121,13 +1136,15 @@ def test_copy_default_query(self) -> None: ): client.copy(set_default_query={}, default_query={"foo": "Bar"}) - def test_copy_signature(self) -> None: + await client.close() + + def test_copy_signature(self, async_client: AsyncOpenAI) -> None: # ensure the same parameters that can be passed to the client are defined in the `.copy()` method init_signature = inspect.signature( # mypy doesn't like that we access the `__init__` property. - self.client.__init__, # type: ignore[misc] + async_client.__init__, # type: ignore[misc] ) - copy_signature = inspect.signature(self.client.copy) + copy_signature = inspect.signature(async_client.copy) exclude_params = {"transport", "proxies", "_strict_response_validation"} for name in init_signature.parameters.keys(): @@ -1138,12 +1155,12 @@ def test_copy_signature(self) -> None: assert copy_param is not None, f"copy() signature is missing the {name} param" @pytest.mark.skipif(sys.version_info >= (3, 10), reason="fails because of a memory leak that started from 3.12") - def test_copy_build_request(self) -> None: + def test_copy_build_request(self, async_client: AsyncOpenAI) -> None: options = FinalRequestOptions(method="get", url="/foo") def build_request(options: FinalRequestOptions) -> None: - client = self.client.copy() - client._build_request(options) + client_copy = async_client.copy() + client_copy._build_request(options) # ensure that the machinery is warmed up before tracing starts. build_request(options) @@ -1200,12 +1217,12 @@ def add_leak(leaks: list[tracemalloc.StatisticDiff], diff: tracemalloc.Statistic print(frame) raise AssertionError() - async def test_request_timeout(self) -> None: - request = self.client._build_request(FinalRequestOptions(method="get", url="/foo")) + async def test_request_timeout(self, async_client: AsyncOpenAI) -> None: + request = async_client._build_request(FinalRequestOptions(method="get", url="/foo")) timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == DEFAULT_TIMEOUT - request = self.client._build_request( + request = async_client._build_request( FinalRequestOptions(method="get", url="/foo", timeout=httpx.Timeout(100.0)) ) timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore @@ -1220,6 +1237,8 @@ async def test_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == httpx.Timeout(0) + await client.close() + async def test_http_client_timeout_option(self) -> None: # custom timeout given to the httpx client should be used async with httpx.AsyncClient(timeout=None) as http_client: @@ -1231,6 +1250,8 @@ async def test_http_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == httpx.Timeout(None) + await client.close() + # no timeout given to the httpx client should not use the httpx default async with httpx.AsyncClient() as http_client: client = AsyncOpenAI( @@ -1241,6 +1262,8 @@ async def test_http_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == DEFAULT_TIMEOUT + await client.close() + # explicitly passing the default timeout currently results in it being ignored async with httpx.AsyncClient(timeout=HTTPX_DEFAULT_TIMEOUT) as http_client: client = AsyncOpenAI( @@ -1251,6 +1274,8 @@ async def test_http_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == DEFAULT_TIMEOUT # our default + await client.close() + def test_invalid_http_client(self) -> None: with pytest.raises(TypeError, match="Invalid `http_client` arg"): with httpx.Client() as http_client: @@ -1261,15 +1286,15 @@ def test_invalid_http_client(self) -> None: http_client=cast(Any, http_client), ) - def test_default_headers_option(self) -> None: - client = AsyncOpenAI( + async def test_default_headers_option(self) -> None: + test_client = AsyncOpenAI( base_url=base_url, api_key=api_key, _strict_response_validation=True, default_headers={"X-Foo": "bar"} ) - request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + request = test_client._build_request(FinalRequestOptions(method="get", url="/foo")) assert request.headers.get("x-foo") == "bar" assert request.headers.get("x-stainless-lang") == "python" - client2 = AsyncOpenAI( + test_client2 = AsyncOpenAI( base_url=base_url, api_key=api_key, _strict_response_validation=True, @@ -1278,10 +1303,13 @@ def test_default_headers_option(self) -> None: "X-Stainless-Lang": "my-overriding-header", }, ) - request = client2._build_request(FinalRequestOptions(method="get", url="/foo")) + request = test_client2._build_request(FinalRequestOptions(method="get", url="/foo")) assert request.headers.get("x-foo") == "stainless" assert request.headers.get("x-stainless-lang") == "my-overriding-header" + await test_client.close() + await test_client2.close() + async def test_validate_headers(self) -> None: client = AsyncOpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=True) options = await client._prepare_options(FinalRequestOptions(method="get", url="/foo")) @@ -1293,7 +1321,7 @@ async def test_validate_headers(self) -> None: client2 = AsyncOpenAI(base_url=base_url, api_key=None, _strict_response_validation=True) _ = client2 - def test_default_query_option(self) -> None: + async def test_default_query_option(self) -> None: client = AsyncOpenAI( base_url=base_url, api_key=api_key, _strict_response_validation=True, default_query={"query_param": "bar"} ) @@ -1311,8 +1339,10 @@ def test_default_query_option(self) -> None: url = httpx.URL(request.url) assert dict(url.params) == {"foo": "baz", "query_param": "overridden"} - def test_request_extra_json(self) -> None: - request = self.client._build_request( + await client.close() + + def test_request_extra_json(self, client: OpenAI) -> None: + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1323,7 +1353,7 @@ def test_request_extra_json(self) -> None: data = json.loads(request.content.decode("utf-8")) assert data == {"foo": "bar", "baz": False} - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1334,7 +1364,7 @@ def test_request_extra_json(self) -> None: assert data == {"baz": False} # `extra_json` takes priority over `json_data` when keys clash - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1345,8 +1375,8 @@ def test_request_extra_json(self) -> None: data = json.loads(request.content.decode("utf-8")) assert data == {"foo": "bar", "baz": None} - def test_request_extra_headers(self) -> None: - request = self.client._build_request( + def test_request_extra_headers(self, client: OpenAI) -> None: + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1356,7 +1386,7 @@ def test_request_extra_headers(self) -> None: assert request.headers.get("X-Foo") == "Foo" # `extra_headers` takes priority over `default_headers` when keys clash - request = self.client.with_options(default_headers={"X-Bar": "true"})._build_request( + request = client.with_options(default_headers={"X-Bar": "true"})._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1367,8 +1397,8 @@ def test_request_extra_headers(self) -> None: ) assert request.headers.get("X-Bar") == "false" - def test_request_extra_query(self) -> None: - request = self.client._build_request( + def test_request_extra_query(self, client: OpenAI) -> None: + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1381,7 +1411,7 @@ def test_request_extra_query(self) -> None: assert params == {"my_query_param": "Foo"} # if both `query` and `extra_query` are given, they are merged - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1395,7 +1425,7 @@ def test_request_extra_query(self) -> None: assert params == {"bar": "1", "foo": "2"} # `extra_query` takes priority over `query` when keys clash - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1438,7 +1468,7 @@ def test_multipart_repeating_array(self, async_client: AsyncOpenAI) -> None: ] @pytest.mark.respx(base_url=base_url) - async def test_basic_union_response(self, respx_mock: MockRouter) -> None: + async def test_basic_union_response(self, respx_mock: MockRouter, async_client: AsyncOpenAI) -> None: class Model1(BaseModel): name: str @@ -1447,12 +1477,12 @@ class Model2(BaseModel): respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - response = await self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + response = await async_client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) assert isinstance(response, Model2) assert response.foo == "bar" @pytest.mark.respx(base_url=base_url) - async def test_union_response_different_types(self, respx_mock: MockRouter) -> None: + async def test_union_response_different_types(self, respx_mock: MockRouter, async_client: AsyncOpenAI) -> None: """Union of objects with the same field name using a different type""" class Model1(BaseModel): @@ -1463,18 +1493,20 @@ class Model2(BaseModel): respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - response = await self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + response = await async_client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) assert isinstance(response, Model2) assert response.foo == "bar" respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": 1})) - response = await self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + response = await async_client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) assert isinstance(response, Model1) assert response.foo == 1 @pytest.mark.respx(base_url=base_url) - async def test_non_application_json_content_type_for_json_data(self, respx_mock: MockRouter) -> None: + async def test_non_application_json_content_type_for_json_data( + self, respx_mock: MockRouter, async_client: AsyncOpenAI + ) -> None: """ Response that sets Content-Type to something other than application/json but returns json data """ @@ -1490,11 +1522,11 @@ class Model(BaseModel): ) ) - response = await self.client.get("/foo", cast_to=Model) + response = await async_client.get("/foo", cast_to=Model) assert isinstance(response, Model) assert response.foo == 2 - def test_base_url_setter(self) -> None: + async def test_base_url_setter(self) -> None: client = AsyncOpenAI( base_url="https://example.com/from_init", api_key=api_key, _strict_response_validation=True ) @@ -1504,7 +1536,9 @@ def test_base_url_setter(self) -> None: assert client.base_url == "https://example.com/from_setter/" - def test_base_url_env(self) -> None: + await client.close() + + async def test_base_url_env(self) -> None: with update_env(OPENAI_BASE_URL="http://localhost:5000/from/env"): client = AsyncOpenAI(api_key=api_key, _strict_response_validation=True) assert client.base_url == "http://localhost:5000/from/env/" @@ -1524,7 +1558,7 @@ def test_base_url_env(self) -> None: ], ids=["standard", "custom http client"], ) - def test_base_url_trailing_slash(self, client: AsyncOpenAI) -> None: + async def test_base_url_trailing_slash(self, client: AsyncOpenAI) -> None: request = client._build_request( FinalRequestOptions( method="post", @@ -1533,6 +1567,7 @@ def test_base_url_trailing_slash(self, client: AsyncOpenAI) -> None: ), ) assert request.url == "http://localhost:5000/custom/path/foo" + await client.close() @pytest.mark.parametrize( "client", @@ -1549,7 +1584,7 @@ def test_base_url_trailing_slash(self, client: AsyncOpenAI) -> None: ], ids=["standard", "custom http client"], ) - def test_base_url_no_trailing_slash(self, client: AsyncOpenAI) -> None: + async def test_base_url_no_trailing_slash(self, client: AsyncOpenAI) -> None: request = client._build_request( FinalRequestOptions( method="post", @@ -1558,6 +1593,7 @@ def test_base_url_no_trailing_slash(self, client: AsyncOpenAI) -> None: ), ) assert request.url == "http://localhost:5000/custom/path/foo" + await client.close() @pytest.mark.parametrize( "client", @@ -1574,7 +1610,7 @@ def test_base_url_no_trailing_slash(self, client: AsyncOpenAI) -> None: ], ids=["standard", "custom http client"], ) - def test_absolute_request_url(self, client: AsyncOpenAI) -> None: + async def test_absolute_request_url(self, client: AsyncOpenAI) -> None: request = client._build_request( FinalRequestOptions( method="post", @@ -1583,37 +1619,37 @@ def test_absolute_request_url(self, client: AsyncOpenAI) -> None: ), ) assert request.url == "https://myapi.com/foo" + await client.close() async def test_copied_client_does_not_close_http(self) -> None: - client = AsyncOpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=True) - assert not client.is_closed() + test_client = AsyncOpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=True) + assert not test_client.is_closed() - copied = client.copy() - assert copied is not client + copied = test_client.copy() + assert copied is not test_client del copied await asyncio.sleep(0.2) - assert not client.is_closed() + assert not test_client.is_closed() async def test_client_context_manager(self) -> None: - client = AsyncOpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=True) - async with client as c2: - assert c2 is client + test_client = AsyncOpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=True) + async with test_client as c2: + assert c2 is test_client assert not c2.is_closed() - assert not client.is_closed() - assert client.is_closed() + assert not test_client.is_closed() + assert test_client.is_closed() @pytest.mark.respx(base_url=base_url) - @pytest.mark.asyncio - async def test_client_response_validation_error(self, respx_mock: MockRouter) -> None: + async def test_client_response_validation_error(self, respx_mock: MockRouter, async_client: AsyncOpenAI) -> None: class Model(BaseModel): foo: str respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": {"invalid": True}})) with pytest.raises(APIResponseValidationError) as exc: - await self.client.get("/foo", cast_to=Model) + await async_client.get("/foo", cast_to=Model) assert isinstance(exc.value.__cause__, ValidationError) @@ -1624,19 +1660,17 @@ async def test_client_max_retries_validation(self) -> None: ) @pytest.mark.respx(base_url=base_url) - @pytest.mark.asyncio - async def test_default_stream_cls(self, respx_mock: MockRouter) -> None: + async def test_default_stream_cls(self, respx_mock: MockRouter, async_client: AsyncOpenAI) -> None: class Model(BaseModel): name: str respx_mock.post("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - stream = await self.client.post("/foo", cast_to=Model, stream=True, stream_cls=AsyncStream[Model]) + stream = await async_client.post("/foo", cast_to=Model, stream=True, stream_cls=AsyncStream[Model]) assert isinstance(stream, AsyncStream) await stream.response.aclose() @pytest.mark.respx(base_url=base_url) - @pytest.mark.asyncio async def test_received_text_for_expected_json(self, respx_mock: MockRouter) -> None: class Model(BaseModel): name: str @@ -1648,11 +1682,14 @@ class Model(BaseModel): with pytest.raises(APIResponseValidationError): await strict_client.get("/foo", cast_to=Model) - client = AsyncOpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=False) + non_strict_client = AsyncOpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=False) - response = await client.get("/foo", cast_to=Model) + response = await non_strict_client.get("/foo", cast_to=Model) assert isinstance(response, str) # type: ignore[unreachable] + await strict_client.close() + await non_strict_client.close() + @pytest.mark.parametrize( "remaining_retries,retry_after,timeout", [ @@ -1675,13 +1712,12 @@ class Model(BaseModel): ], ) @mock.patch("time.time", mock.MagicMock(return_value=1696004797)) - @pytest.mark.asyncio - async def test_parse_retry_after_header(self, remaining_retries: int, retry_after: str, timeout: float) -> None: - client = AsyncOpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=True) - + async def test_parse_retry_after_header( + self, remaining_retries: int, retry_after: str, timeout: float, async_client: AsyncOpenAI + ) -> None: headers = httpx.Headers({"retry-after": retry_after}) options = FinalRequestOptions(method="get", url="/foo", max_retries=3) - calculated = client._calculate_retry_timeout(remaining_retries, options, headers) + calculated = async_client._calculate_retry_timeout(remaining_retries, options, headers) assert calculated == pytest.approx(timeout, 0.5 * 0.875) # pyright: ignore[reportUnknownMemberType] @mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @@ -1700,7 +1736,7 @@ async def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter, model="gpt-4o", ).__aenter__() - assert _get_open_connections(self.client) == 0 + assert _get_open_connections(async_client) == 0 @mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) @@ -1717,12 +1753,11 @@ async def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter, ], model="gpt-4o", ).__aenter__() - assert _get_open_connections(self.client) == 0 + assert _get_open_connections(async_client) == 0 @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - @pytest.mark.asyncio @pytest.mark.parametrize("failure_mode", ["status", "exception"]) async def test_retries_taken( self, @@ -1762,7 +1797,6 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - @pytest.mark.asyncio async def test_omit_retry_count_header( self, async_client: AsyncOpenAI, failures_before_success: int, respx_mock: MockRouter ) -> None: @@ -1795,7 +1829,6 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - @pytest.mark.asyncio async def test_overwrite_retry_count_header( self, async_client: AsyncOpenAI, failures_before_success: int, respx_mock: MockRouter ) -> None: @@ -1828,7 +1861,6 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - @pytest.mark.asyncio async def test_retries_taken_new_response_class( self, async_client: AsyncOpenAI, failures_before_success: int, respx_mock: MockRouter ) -> None: @@ -1884,26 +1916,26 @@ async def test_default_client_creation(self) -> None: ) @pytest.mark.respx(base_url=base_url) - async def test_follow_redirects(self, respx_mock: MockRouter) -> None: + async def test_follow_redirects(self, respx_mock: MockRouter, async_client: AsyncOpenAI) -> None: # Test that the default follow_redirects=True allows following redirects respx_mock.post("/redirect").mock( return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) ) respx_mock.get("/redirected").mock(return_value=httpx.Response(200, json={"status": "ok"})) - response = await self.client.post("/redirect", body={"key": "value"}, cast_to=httpx.Response) + response = await async_client.post("/redirect", body={"key": "value"}, cast_to=httpx.Response) assert response.status_code == 200 assert response.json() == {"status": "ok"} @pytest.mark.respx(base_url=base_url) - async def test_follow_redirects_disabled(self, respx_mock: MockRouter) -> None: + async def test_follow_redirects_disabled(self, respx_mock: MockRouter, async_client: AsyncOpenAI) -> None: # Test that follow_redirects=False prevents following redirects respx_mock.post("/redirect").mock( return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) ) with pytest.raises(APIStatusError) as exc_info: - await self.client.post( + await async_client.post( "/redirect", body={"key": "value"}, options={"follow_redirects": False}, cast_to=httpx.Response ) From 0393d909fc4f45237350747a2cc28162bc7126de Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 3 Nov 2025 16:14:32 +0000 Subject: [PATCH 540/769] chore(internal): grammar fix (it's -> its) --- src/openai/_utils/_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openai/_utils/_utils.py b/src/openai/_utils/_utils.py index cddf2c8da4..90494748cc 100644 --- a/src/openai/_utils/_utils.py +++ b/src/openai/_utils/_utils.py @@ -137,7 +137,7 @@ def is_given(obj: _T | NotGiven | Omit) -> TypeGuard[_T]: # Type safe methods for narrowing types with TypeVars. # The default narrowing for isinstance(obj, dict) is dict[unknown, unknown], # however this cause Pyright to rightfully report errors. As we know we don't -# care about the contained types we can safely use `object` in it's place. +# care about the contained types we can safely use `object` in its place. # # There are two separate functions defined, `is_*` and `is_*_t` for different use cases. # `is_*` is for when you're dealing with an unknown input From ed9e2ddc5316b5c5cd972b2d9dadde910557fd61 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 3 Nov 2025 23:07:04 +0000 Subject: [PATCH 541/769] feat(api): Realtime API token_limits, Hybrid searching ranking options --- .stats.yml | 6 +-- src/openai/resources/images.py | 30 +++++++++++--- src/openai/resources/realtime/calls.py | 30 ++++++++++++-- .../resources/vector_stores/file_batches.py | 40 +++++++++++++------ .../types/realtime/call_accept_params.py | 15 ++++++- .../realtime_session_create_request.py | 15 ++++++- .../realtime_session_create_request_param.py | 15 ++++++- .../realtime_session_create_response.py | 15 ++++++- .../realtime_truncation_retention_ratio.py | 26 ++++++++++-- ...altime_truncation_retention_ratio_param.py | 25 ++++++++++-- .../types/responses/file_search_tool.py | 16 +++++++- .../types/responses/file_search_tool_param.py | 16 +++++++- .../types/responses/response_output_text.py | 6 +-- .../responses/response_output_text_param.py | 4 +- src/openai/types/responses/tool.py | 2 + src/openai/types/responses/tool_param.py | 2 + .../vector_stores/file_batch_create_params.py | 40 +++++++++++++++++-- src/openai/types/video.py | 3 ++ .../vector_stores/test_file_batches.py | 26 +++++++----- 19 files changed, 273 insertions(+), 59 deletions(-) diff --git a/.stats.yml b/.stats.yml index bc4e084f99..d59fe71ee4 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 136 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-f68f718cd45ac3f9336603601bccc38a718af44d0b26601031de3d0a71b7ce2f.yml -openapi_spec_hash: 1560717860bba4105936647dde8f618d -config_hash: 50ee3382a63c021a9f821a935950e926 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-3c5d1593d7c6f2b38a7d78d7906041465ee9d6e9022f0651e1da194654488108.yml +openapi_spec_hash: 0a4d8ad2469823ce24a3fd94f23f1c2b +config_hash: 032995825500a503a76da119f5354905 diff --git a/src/openai/resources/images.py b/src/openai/resources/images.py index 9bb332230f..265be6f743 100644 --- a/src/openai/resources/images.py +++ b/src/openai/resources/images.py @@ -168,7 +168,10 @@ def edit( If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. - input_fidelity: Control how much effort the model will exert to match the style and features, especially facial features, of input images. This parameter is only supported for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and `low`. Defaults to `low`. + input_fidelity: Control how much effort the model will exert to match the style and features, + especially facial features, of input images. This parameter is only supported + for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and + `low`. Defaults to `low`. mask: An additional image whose fully transparent areas (e.g. where alpha is zero) indicate where `image` should be edited. If there are multiple images provided, @@ -282,7 +285,10 @@ def edit( If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. - input_fidelity: Control how much effort the model will exert to match the style and features, especially facial features, of input images. This parameter is only supported for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and `low`. Defaults to `low`. + input_fidelity: Control how much effort the model will exert to match the style and features, + especially facial features, of input images. This parameter is only supported + for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and + `low`. Defaults to `low`. mask: An additional image whose fully transparent areas (e.g. where alpha is zero) indicate where `image` should be edited. If there are multiple images provided, @@ -392,7 +398,10 @@ def edit( If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. - input_fidelity: Control how much effort the model will exert to match the style and features, especially facial features, of input images. This parameter is only supported for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and `low`. Defaults to `low`. + input_fidelity: Control how much effort the model will exert to match the style and features, + especially facial features, of input images. This parameter is only supported + for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and + `low`. Defaults to `low`. mask: An additional image whose fully transparent areas (e.g. where alpha is zero) indicate where `image` should be edited. If there are multiple images provided, @@ -1046,7 +1055,10 @@ async def edit( If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. - input_fidelity: Control how much effort the model will exert to match the style and features, especially facial features, of input images. This parameter is only supported for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and `low`. Defaults to `low`. + input_fidelity: Control how much effort the model will exert to match the style and features, + especially facial features, of input images. This parameter is only supported + for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and + `low`. Defaults to `low`. mask: An additional image whose fully transparent areas (e.g. where alpha is zero) indicate where `image` should be edited. If there are multiple images provided, @@ -1160,7 +1172,10 @@ async def edit( If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. - input_fidelity: Control how much effort the model will exert to match the style and features, especially facial features, of input images. This parameter is only supported for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and `low`. Defaults to `low`. + input_fidelity: Control how much effort the model will exert to match the style and features, + especially facial features, of input images. This parameter is only supported + for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and + `low`. Defaults to `low`. mask: An additional image whose fully transparent areas (e.g. where alpha is zero) indicate where `image` should be edited. If there are multiple images provided, @@ -1270,7 +1285,10 @@ async def edit( If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. - input_fidelity: Control how much effort the model will exert to match the style and features, especially facial features, of input images. This parameter is only supported for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and `low`. Defaults to `low`. + input_fidelity: Control how much effort the model will exert to match the style and features, + especially facial features, of input images. This parameter is only supported + for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and + `low`. Defaults to `low`. mask: An additional image whose fully transparent areas (e.g. where alpha is zero) indicate where `image` should be edited. If there are multiple images provided, diff --git a/src/openai/resources/realtime/calls.py b/src/openai/resources/realtime/calls.py index a8c4761717..7d2c92fe86 100644 --- a/src/openai/resources/realtime/calls.py +++ b/src/openai/resources/realtime/calls.py @@ -195,8 +195,19 @@ def accept( `auto` will create a trace for the session with default values for the workflow name, group id, and metadata. - truncation: Controls how the realtime conversation is truncated prior to model inference. - The default is `auto`. + truncation: When the number of tokens in a conversation exceeds the model's input token + limit, the conversation be truncated, meaning messages (starting from the + oldest) will not be included in the model's context. A 32k context model with + 4,096 max output tokens can only include 28,224 tokens in the context before + truncation occurs. Clients can configure truncation behavior to truncate with a + lower max token limit, which is an effective way to control token usage and + cost. Truncation will reduce the number of cached tokens on the next turn + (busting the cache), since messages are dropped from the beginning of the + context. However, clients can also configure truncation to retain messages up to + a fraction of the maximum context size, which will reduce the need for future + truncations and thus improve the cache rate. Truncation can be disabled + entirely, which means the server will never truncate but would instead return an + error if the conversation exceeds the model's input token limit. extra_headers: Send extra headers @@ -504,8 +515,19 @@ async def accept( `auto` will create a trace for the session with default values for the workflow name, group id, and metadata. - truncation: Controls how the realtime conversation is truncated prior to model inference. - The default is `auto`. + truncation: When the number of tokens in a conversation exceeds the model's input token + limit, the conversation be truncated, meaning messages (starting from the + oldest) will not be included in the model's context. A 32k context model with + 4,096 max output tokens can only include 28,224 tokens in the context before + truncation occurs. Clients can configure truncation behavior to truncate with a + lower max token limit, which is an effective way to control token usage and + cost. Truncation will reduce the number of cached tokens on the next turn + (busting the cache), since messages are dropped from the beginning of the + context. However, clients can also configure truncation to retain messages up to + a fraction of the maximum context size, which will reduce the need for future + truncations and thus improve the cache rate. Truncation can be disabled + entirely, which means the server will never truncate but would instead return an + error if the conversation exceeds the model's input token limit. extra_headers: Send extra headers diff --git a/src/openai/resources/vector_stores/file_batches.py b/src/openai/resources/vector_stores/file_batches.py index 0f989821de..d31fb59bec 100644 --- a/src/openai/resources/vector_stores/file_batches.py +++ b/src/openai/resources/vector_stores/file_batches.py @@ -52,9 +52,10 @@ def create( self, vector_store_id: str, *, - file_ids: SequenceNotStr[str], attributes: Optional[Dict[str, Union[str, float, bool]]] | Omit = omit, chunking_strategy: FileChunkingStrategyParam | Omit = omit, + file_ids: SequenceNotStr[str] | Omit = omit, + files: Iterable[file_batch_create_params.File] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -66,10 +67,6 @@ def create( Create a vector store file batch. Args: - file_ids: A list of [File](https://platform.openai.com/docs/api-reference/files) IDs that - the vector store should use. Useful for tools like `file_search` that can access - files. - attributes: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format, and querying for objects via API or the dashboard. Keys are strings with a maximum @@ -79,6 +76,16 @@ def create( chunking_strategy: The chunking strategy used to chunk the file(s). If not set, will use the `auto` strategy. Only applicable if `file_ids` is non-empty. + file_ids: A list of [File](https://platform.openai.com/docs/api-reference/files) IDs that + the vector store should use. Useful for tools like `file_search` that can access + files. If `attributes` or `chunking_strategy` are provided, they will be applied + to all files in the batch. Mutually exclusive with `files`. + + files: A list of objects that each include a `file_id` plus optional `attributes` or + `chunking_strategy`. Use this when you need to override metadata for specific + files. The global `attributes` or `chunking_strategy` will be ignored and must + be specified for each file. Mutually exclusive with `file_ids`. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -94,9 +101,10 @@ def create( f"/vector_stores/{vector_store_id}/file_batches", body=maybe_transform( { - "file_ids": file_ids, "attributes": attributes, "chunking_strategy": chunking_strategy, + "file_ids": file_ids, + "files": files, }, file_batch_create_params.FileBatchCreateParams, ), @@ -389,9 +397,10 @@ async def create( self, vector_store_id: str, *, - file_ids: SequenceNotStr[str], attributes: Optional[Dict[str, Union[str, float, bool]]] | Omit = omit, chunking_strategy: FileChunkingStrategyParam | Omit = omit, + file_ids: SequenceNotStr[str] | Omit = omit, + files: Iterable[file_batch_create_params.File] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -403,10 +412,6 @@ async def create( Create a vector store file batch. Args: - file_ids: A list of [File](https://platform.openai.com/docs/api-reference/files) IDs that - the vector store should use. Useful for tools like `file_search` that can access - files. - attributes: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format, and querying for objects via API or the dashboard. Keys are strings with a maximum @@ -416,6 +421,16 @@ async def create( chunking_strategy: The chunking strategy used to chunk the file(s). If not set, will use the `auto` strategy. Only applicable if `file_ids` is non-empty. + file_ids: A list of [File](https://platform.openai.com/docs/api-reference/files) IDs that + the vector store should use. Useful for tools like `file_search` that can access + files. If `attributes` or `chunking_strategy` are provided, they will be applied + to all files in the batch. Mutually exclusive with `files`. + + files: A list of objects that each include a `file_id` plus optional `attributes` or + `chunking_strategy`. Use this when you need to override metadata for specific + files. The global `attributes` or `chunking_strategy` will be ignored and must + be specified for each file. Mutually exclusive with `file_ids`. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -431,9 +446,10 @@ async def create( f"/vector_stores/{vector_store_id}/file_batches", body=await async_maybe_transform( { - "file_ids": file_ids, "attributes": attributes, "chunking_strategy": chunking_strategy, + "file_ids": file_ids, + "files": files, }, file_batch_create_params.FileBatchCreateParams, ), diff --git a/src/openai/types/realtime/call_accept_params.py b/src/openai/types/realtime/call_accept_params.py index 0cfb01e7cf..d6fc92b8e5 100644 --- a/src/openai/types/realtime/call_accept_params.py +++ b/src/openai/types/realtime/call_accept_params.py @@ -106,6 +106,17 @@ class CallAcceptParams(TypedDict, total=False): truncation: RealtimeTruncationParam """ - Controls how the realtime conversation is truncated prior to model inference. - The default is `auto`. + When the number of tokens in a conversation exceeds the model's input token + limit, the conversation be truncated, meaning messages (starting from the + oldest) will not be included in the model's context. A 32k context model with + 4,096 max output tokens can only include 28,224 tokens in the context before + truncation occurs. Clients can configure truncation behavior to truncate with a + lower max token limit, which is an effective way to control token usage and + cost. Truncation will reduce the number of cached tokens on the next turn + (busting the cache), since messages are dropped from the beginning of the + context. However, clients can also configure truncation to retain messages up to + a fraction of the maximum context size, which will reduce the need for future + truncations and thus improve the cache rate. Truncation can be disabled + entirely, which means the server will never truncate but would instead return an + error if the conversation exceeds the model's input token limit. """ diff --git a/src/openai/types/realtime/realtime_session_create_request.py b/src/openai/types/realtime/realtime_session_create_request.py index bc205bd3b5..016ae45b67 100644 --- a/src/openai/types/realtime/realtime_session_create_request.py +++ b/src/openai/types/realtime/realtime_session_create_request.py @@ -106,6 +106,17 @@ class RealtimeSessionCreateRequest(BaseModel): truncation: Optional[RealtimeTruncation] = None """ - Controls how the realtime conversation is truncated prior to model inference. - The default is `auto`. + When the number of tokens in a conversation exceeds the model's input token + limit, the conversation be truncated, meaning messages (starting from the + oldest) will not be included in the model's context. A 32k context model with + 4,096 max output tokens can only include 28,224 tokens in the context before + truncation occurs. Clients can configure truncation behavior to truncate with a + lower max token limit, which is an effective way to control token usage and + cost. Truncation will reduce the number of cached tokens on the next turn + (busting the cache), since messages are dropped from the beginning of the + context. However, clients can also configure truncation to retain messages up to + a fraction of the maximum context size, which will reduce the need for future + truncations and thus improve the cache rate. Truncation can be disabled + entirely, which means the server will never truncate but would instead return an + error if the conversation exceeds the model's input token limit. """ diff --git a/src/openai/types/realtime/realtime_session_create_request_param.py b/src/openai/types/realtime/realtime_session_create_request_param.py index d1fa2b35d2..8c3998c1ca 100644 --- a/src/openai/types/realtime/realtime_session_create_request_param.py +++ b/src/openai/types/realtime/realtime_session_create_request_param.py @@ -106,6 +106,17 @@ class RealtimeSessionCreateRequestParam(TypedDict, total=False): truncation: RealtimeTruncationParam """ - Controls how the realtime conversation is truncated prior to model inference. - The default is `auto`. + When the number of tokens in a conversation exceeds the model's input token + limit, the conversation be truncated, meaning messages (starting from the + oldest) will not be included in the model's context. A 32k context model with + 4,096 max output tokens can only include 28,224 tokens in the context before + truncation occurs. Clients can configure truncation behavior to truncate with a + lower max token limit, which is an effective way to control token usage and + cost. Truncation will reduce the number of cached tokens on the next turn + (busting the cache), since messages are dropped from the beginning of the + context. However, clients can also configure truncation to retain messages up to + a fraction of the maximum context size, which will reduce the need for future + truncations and thus improve the cache rate. Truncation can be disabled + entirely, which means the server will never truncate but would instead return an + error if the conversation exceeds the model's input token limit. """ diff --git a/src/openai/types/realtime/realtime_session_create_response.py b/src/openai/types/realtime/realtime_session_create_response.py index bb6b94e900..c1336cd6e4 100644 --- a/src/openai/types/realtime/realtime_session_create_response.py +++ b/src/openai/types/realtime/realtime_session_create_response.py @@ -459,6 +459,17 @@ class RealtimeSessionCreateResponse(BaseModel): truncation: Optional[RealtimeTruncation] = None """ - Controls how the realtime conversation is truncated prior to model inference. - The default is `auto`. + When the number of tokens in a conversation exceeds the model's input token + limit, the conversation be truncated, meaning messages (starting from the + oldest) will not be included in the model's context. A 32k context model with + 4,096 max output tokens can only include 28,224 tokens in the context before + truncation occurs. Clients can configure truncation behavior to truncate with a + lower max token limit, which is an effective way to control token usage and + cost. Truncation will reduce the number of cached tokens on the next turn + (busting the cache), since messages are dropped from the beginning of the + context. However, clients can also configure truncation to retain messages up to + a fraction of the maximum context size, which will reduce the need for future + truncations and thus improve the cache rate. Truncation can be disabled + entirely, which means the server will never truncate but would instead return an + error if the conversation exceeds the model's input token limit. """ diff --git a/src/openai/types/realtime/realtime_truncation_retention_ratio.py b/src/openai/types/realtime/realtime_truncation_retention_ratio.py index b40427244e..e19ed64831 100644 --- a/src/openai/types/realtime/realtime_truncation_retention_ratio.py +++ b/src/openai/types/realtime/realtime_truncation_retention_ratio.py @@ -1,18 +1,38 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from typing import Optional from typing_extensions import Literal from ..._models import BaseModel -__all__ = ["RealtimeTruncationRetentionRatio"] +__all__ = ["RealtimeTruncationRetentionRatio", "TokenLimits"] + + +class TokenLimits(BaseModel): + post_instructions: Optional[int] = None + """ + Maximum tokens allowed in the conversation after instructions (which including + tool definitions). For example, setting this to 5,000 would mean that truncation + would occur when the conversation exceeds 5,000 tokens after instructions. This + cannot be higher than the model's context window size minus the maximum output + tokens. + """ class RealtimeTruncationRetentionRatio(BaseModel): retention_ratio: float """ - Fraction of post-instruction conversation tokens to retain (0.0 - 1.0) when the - conversation exceeds the input token limit. + Fraction of post-instruction conversation tokens to retain (`0.0` - `1.0`) when + the conversation exceeds the input token limit. Setting this to `0.8` means that + messages will be dropped until 80% of the maximum allowed tokens are used. This + helps reduce the frequency of truncations and improve cache rates. """ type: Literal["retention_ratio"] """Use retention ratio truncation.""" + + token_limits: Optional[TokenLimits] = None + """Optional custom token limits for this truncation strategy. + + If not provided, the model's default token limits will be used. + """ diff --git a/src/openai/types/realtime/realtime_truncation_retention_ratio_param.py b/src/openai/types/realtime/realtime_truncation_retention_ratio_param.py index b65d65666a..4ea80fe4ce 100644 --- a/src/openai/types/realtime/realtime_truncation_retention_ratio_param.py +++ b/src/openai/types/realtime/realtime_truncation_retention_ratio_param.py @@ -4,15 +4,34 @@ from typing_extensions import Literal, Required, TypedDict -__all__ = ["RealtimeTruncationRetentionRatioParam"] +__all__ = ["RealtimeTruncationRetentionRatioParam", "TokenLimits"] + + +class TokenLimits(TypedDict, total=False): + post_instructions: int + """ + Maximum tokens allowed in the conversation after instructions (which including + tool definitions). For example, setting this to 5,000 would mean that truncation + would occur when the conversation exceeds 5,000 tokens after instructions. This + cannot be higher than the model's context window size minus the maximum output + tokens. + """ class RealtimeTruncationRetentionRatioParam(TypedDict, total=False): retention_ratio: Required[float] """ - Fraction of post-instruction conversation tokens to retain (0.0 - 1.0) when the - conversation exceeds the input token limit. + Fraction of post-instruction conversation tokens to retain (`0.0` - `1.0`) when + the conversation exceeds the input token limit. Setting this to `0.8` means that + messages will be dropped until 80% of the maximum allowed tokens are used. This + helps reduce the frequency of truncations and improve cache rates. """ type: Required[Literal["retention_ratio"]] """Use retention ratio truncation.""" + + token_limits: TokenLimits + """Optional custom token limits for this truncation strategy. + + If not provided, the model's default token limits will be used. + """ diff --git a/src/openai/types/responses/file_search_tool.py b/src/openai/types/responses/file_search_tool.py index dbdd8cffab..d0d08a323f 100644 --- a/src/openai/types/responses/file_search_tool.py +++ b/src/openai/types/responses/file_search_tool.py @@ -7,12 +7,26 @@ from ..shared.compound_filter import CompoundFilter from ..shared.comparison_filter import ComparisonFilter -__all__ = ["FileSearchTool", "Filters", "RankingOptions"] +__all__ = ["FileSearchTool", "Filters", "RankingOptions", "RankingOptionsHybridSearch"] Filters: TypeAlias = Union[ComparisonFilter, CompoundFilter, None] +class RankingOptionsHybridSearch(BaseModel): + embedding_weight: float + """The weight of the embedding in the reciprocal ranking fusion.""" + + text_weight: float + """The weight of the text in the reciprocal ranking fusion.""" + + class RankingOptions(BaseModel): + hybrid_search: Optional[RankingOptionsHybridSearch] = None + """ + Weights that control how reciprocal rank fusion balances semantic embedding + matches versus sparse keyword matches when hybrid search is enabled. + """ + ranker: Optional[Literal["auto", "default-2024-11-15"]] = None """The ranker to use for the file search.""" diff --git a/src/openai/types/responses/file_search_tool_param.py b/src/openai/types/responses/file_search_tool_param.py index c7641c1b86..b37a669ebd 100644 --- a/src/openai/types/responses/file_search_tool_param.py +++ b/src/openai/types/responses/file_search_tool_param.py @@ -9,12 +9,26 @@ from ..shared_params.compound_filter import CompoundFilter from ..shared_params.comparison_filter import ComparisonFilter -__all__ = ["FileSearchToolParam", "Filters", "RankingOptions"] +__all__ = ["FileSearchToolParam", "Filters", "RankingOptions", "RankingOptionsHybridSearch"] Filters: TypeAlias = Union[ComparisonFilter, CompoundFilter] +class RankingOptionsHybridSearch(TypedDict, total=False): + embedding_weight: Required[float] + """The weight of the embedding in the reciprocal ranking fusion.""" + + text_weight: Required[float] + """The weight of the text in the reciprocal ranking fusion.""" + + class RankingOptions(TypedDict, total=False): + hybrid_search: RankingOptionsHybridSearch + """ + Weights that control how reciprocal rank fusion balances semantic embedding + matches versus sparse keyword matches when hybrid search is enabled. + """ + ranker: Literal["auto", "default-2024-11-15"] """The ranker to use for the file search.""" diff --git a/src/openai/types/responses/response_output_text.py b/src/openai/types/responses/response_output_text.py index aa97b629f0..fc579cd894 100644 --- a/src/openai/types/responses/response_output_text.py +++ b/src/openai/types/responses/response_output_text.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union, Optional +from typing import List, Union from typing_extensions import Literal, Annotated, TypeAlias from ..._utils import PropertyInfo @@ -108,10 +108,10 @@ class ResponseOutputText(BaseModel): annotations: List[Annotation] """The annotations of the text output.""" + logprobs: List[Logprob] + text: str """The text output from the model.""" type: Literal["output_text"] """The type of the output text. Always `output_text`.""" - - logprobs: Optional[List[Logprob]] = None diff --git a/src/openai/types/responses/response_output_text_param.py b/src/openai/types/responses/response_output_text_param.py index 63d2d394a8..445a308a5b 100644 --- a/src/openai/types/responses/response_output_text_param.py +++ b/src/openai/types/responses/response_output_text_param.py @@ -106,10 +106,10 @@ class ResponseOutputTextParam(TypedDict, total=False): annotations: Required[Iterable[Annotation]] """The annotations of the text output.""" + logprobs: Required[Iterable[Logprob]] + text: Required[str] """The text output from the model.""" type: Required[Literal["output_text"]] """The type of the output text. Always `output_text`.""" - - logprobs: Iterable[Logprob] diff --git a/src/openai/types/responses/tool.py b/src/openai/types/responses/tool.py index 6239b818c9..b29fede0c9 100644 --- a/src/openai/types/responses/tool.py +++ b/src/openai/types/responses/tool.py @@ -161,6 +161,8 @@ class CodeInterpreterContainerCodeInterpreterToolAuto(BaseModel): file_ids: Optional[List[str]] = None """An optional list of uploaded files to make available to your code.""" + memory_limit: Optional[Literal["1g", "4g", "16g", "64g"]] = None + CodeInterpreterContainer: TypeAlias = Union[str, CodeInterpreterContainerCodeInterpreterToolAuto] diff --git a/src/openai/types/responses/tool_param.py b/src/openai/types/responses/tool_param.py index ff4ac2b953..dd1ea0bd54 100644 --- a/src/openai/types/responses/tool_param.py +++ b/src/openai/types/responses/tool_param.py @@ -161,6 +161,8 @@ class CodeInterpreterContainerCodeInterpreterToolAuto(TypedDict, total=False): file_ids: SequenceNotStr[str] """An optional list of uploaded files to make available to your code.""" + memory_limit: Optional[Literal["1g", "4g", "16g", "64g"]] + CodeInterpreterContainer: TypeAlias = Union[str, CodeInterpreterContainerCodeInterpreterToolAuto] diff --git a/src/openai/types/vector_stores/file_batch_create_params.py b/src/openai/types/vector_stores/file_batch_create_params.py index d8d7b44888..2ab98a83ab 100644 --- a/src/openai/types/vector_stores/file_batch_create_params.py +++ b/src/openai/types/vector_stores/file_batch_create_params.py @@ -2,20 +2,54 @@ from __future__ import annotations -from typing import Dict, Union, Optional +from typing import Dict, Union, Iterable, Optional from typing_extensions import Required, TypedDict from ..._types import SequenceNotStr from ..file_chunking_strategy_param import FileChunkingStrategyParam -__all__ = ["FileBatchCreateParams"] +__all__ = ["FileBatchCreateParams", "File"] class FileBatchCreateParams(TypedDict, total=False): - file_ids: Required[SequenceNotStr[str]] + attributes: Optional[Dict[str, Union[str, float, bool]]] + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. Keys are + strings with a maximum length of 64 characters. Values are strings with a + maximum length of 512 characters, booleans, or numbers. + """ + + chunking_strategy: FileChunkingStrategyParam + """The chunking strategy used to chunk the file(s). + + If not set, will use the `auto` strategy. Only applicable if `file_ids` is + non-empty. + """ + + file_ids: SequenceNotStr[str] """ A list of [File](https://platform.openai.com/docs/api-reference/files) IDs that the vector store should use. Useful for tools like `file_search` that can access + files. If `attributes` or `chunking_strategy` are provided, they will be applied + to all files in the batch. Mutually exclusive with `files`. + """ + + files: Iterable[File] + """ + A list of objects that each include a `file_id` plus optional `attributes` or + `chunking_strategy`. Use this when you need to override metadata for specific + files. The global `attributes` or `chunking_strategy` will be ignored and must + be specified for each file. Mutually exclusive with `file_ids`. + """ + + +class File(TypedDict, total=False): + file_id: Required[str] + """ + A [File](https://platform.openai.com/docs/api-reference/files) ID that the + vector store should use. Useful for tools like `file_search` that can access files. """ diff --git a/src/openai/types/video.py b/src/openai/types/video.py index 2c804f75b8..22ee3a11f7 100644 --- a/src/openai/types/video.py +++ b/src/openai/types/video.py @@ -37,6 +37,9 @@ class Video(BaseModel): progress: int """Approximate completion percentage for the generation task.""" + prompt: Optional[str] = None + """The prompt that was used to generate the video.""" + remixed_from_video_id: Optional[str] = None """Identifier of the source video if this video is a remix.""" diff --git a/tests/api_resources/vector_stores/test_file_batches.py b/tests/api_resources/vector_stores/test_file_batches.py index ac678ce912..abbefc20e9 100644 --- a/tests/api_resources/vector_stores/test_file_batches.py +++ b/tests/api_resources/vector_stores/test_file_batches.py @@ -25,7 +25,6 @@ class TestFileBatches: def test_method_create(self, client: OpenAI) -> None: file_batch = client.vector_stores.file_batches.create( vector_store_id="vs_abc123", - file_ids=["string"], ) assert_matches_type(VectorStoreFileBatch, file_batch, path=["response"]) @@ -33,9 +32,16 @@ def test_method_create(self, client: OpenAI) -> None: def test_method_create_with_all_params(self, client: OpenAI) -> None: file_batch = client.vector_stores.file_batches.create( vector_store_id="vs_abc123", - file_ids=["string"], attributes={"foo": "string"}, chunking_strategy={"type": "auto"}, + file_ids=["string"], + files=[ + { + "file_id": "file_id", + "attributes": {"foo": "string"}, + "chunking_strategy": {"type": "auto"}, + } + ], ) assert_matches_type(VectorStoreFileBatch, file_batch, path=["response"]) @@ -43,7 +49,6 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: def test_raw_response_create(self, client: OpenAI) -> None: response = client.vector_stores.file_batches.with_raw_response.create( vector_store_id="vs_abc123", - file_ids=["string"], ) assert response.is_closed is True @@ -55,7 +60,6 @@ def test_raw_response_create(self, client: OpenAI) -> None: def test_streaming_response_create(self, client: OpenAI) -> None: with client.vector_stores.file_batches.with_streaming_response.create( vector_store_id="vs_abc123", - file_ids=["string"], ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -70,7 +74,6 @@ def test_path_params_create(self, client: OpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): client.vector_stores.file_batches.with_raw_response.create( vector_store_id="", - file_ids=["string"], ) @parametrize @@ -240,7 +243,6 @@ class TestAsyncFileBatches: async def test_method_create(self, async_client: AsyncOpenAI) -> None: file_batch = await async_client.vector_stores.file_batches.create( vector_store_id="vs_abc123", - file_ids=["string"], ) assert_matches_type(VectorStoreFileBatch, file_batch, path=["response"]) @@ -248,9 +250,16 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None: async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: file_batch = await async_client.vector_stores.file_batches.create( vector_store_id="vs_abc123", - file_ids=["string"], attributes={"foo": "string"}, chunking_strategy={"type": "auto"}, + file_ids=["string"], + files=[ + { + "file_id": "file_id", + "attributes": {"foo": "string"}, + "chunking_strategy": {"type": "auto"}, + } + ], ) assert_matches_type(VectorStoreFileBatch, file_batch, path=["response"]) @@ -258,7 +267,6 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: response = await async_client.vector_stores.file_batches.with_raw_response.create( vector_store_id="vs_abc123", - file_ids=["string"], ) assert response.is_closed is True @@ -270,7 +278,6 @@ async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: async with async_client.vector_stores.file_batches.with_streaming_response.create( vector_store_id="vs_abc123", - file_ids=["string"], ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -285,7 +292,6 @@ async def test_path_params_create(self, async_client: AsyncOpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `vector_store_id` but received ''"): await async_client.vector_stores.file_batches.with_raw_response.create( vector_store_id="", - file_ids=["string"], ) @parametrize From c82714c765a51a33ce64e8f0c646c47462796e1c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 3 Nov 2025 23:07:37 +0000 Subject: [PATCH 542/769] release: 2.7.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 2f8909f197..d1328ca9c9 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.6.1" + ".": "2.7.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ce541566d..516368cfed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,27 @@ # Changelog +## 2.7.0 (2025-11-03) + +Full Changelog: [v2.6.1...v2.7.0](https://github.com/openai/openai-python/compare/v2.6.1...v2.7.0) + +### Features + +* **api:** Realtime API token_limits, Hybrid searching ranking options ([5b43992](https://github.com/openai/openai-python/commit/5b4399219d7ed326411aec524d25ef2b8e3152fc)) +* **api:** remove InputAudio from ResponseInputContent ([bd70a33](https://github.com/openai/openai-python/commit/bd70a33234741fa68c185105e4f53cc0275a2a50)) + + +### Bug Fixes + +* **client:** close streams without requiring full consumption ([d8bb7d6](https://github.com/openai/openai-python/commit/d8bb7d6d728c5481de4198eebe668b67803ae14a)) +* **readme:** update realtime examples ([#2714](https://github.com/openai/openai-python/issues/2714)) ([d0370a8](https://github.com/openai/openai-python/commit/d0370a8d61fc2f710a34d8aad48f649a9683106d)) +* **uploads:** avoid file handle leak ([4f1b691](https://github.com/openai/openai-python/commit/4f1b691ab4db41aebd397ec41942b43fb0f0743c)) + + +### Chores + +* **internal/tests:** avoid race condition with implicit client cleanup ([933d23b](https://github.com/openai/openai-python/commit/933d23bd8d7809c77e0796becfe052167d44d40a)) +* **internal:** grammar fix (it's -> its) ([f7e9e9e](https://github.com/openai/openai-python/commit/f7e9e9e4f43039f19a41375a6d2b2bdc2264dad7)) + ## 2.6.1 (2025-10-24) Full Changelog: [v2.6.0...v2.6.1](https://github.com/openai/openai-python/compare/v2.6.0...v2.6.1) diff --git a/pyproject.toml b/pyproject.toml index e96101b51c..8ff272e18e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.6.1" +version = "2.7.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 b0fe817996..0963c9c373 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__ = "2.6.1" # x-release-please-version +__version__ = "2.7.0" # x-release-please-version From e2d25ef236eefe7e34d86bdfd831bc7068cb8510 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 4 Nov 2025 06:02:50 +0000 Subject: [PATCH 543/769] fix(api): fix nullability of logprobs Makes ResponseOutputText.logprobs nullable, matching with 2.6.1. While this is always present in the server response, this inadvertently affected params and some constructors --- .stats.yml | 4 ++-- src/openai/types/responses/response_output_text.py | 6 +++--- src/openai/types/responses/response_output_text_param.py | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.stats.yml b/.stats.yml index d59fe71ee4..2588839c5a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 136 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-3c5d1593d7c6f2b38a7d78d7906041465ee9d6e9022f0651e1da194654488108.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-eeba8addf3a5f412e5ce8d22031e60c61650cee3f5d9e587a2533f6818a249ea.yml openapi_spec_hash: 0a4d8ad2469823ce24a3fd94f23f1c2b -config_hash: 032995825500a503a76da119f5354905 +config_hash: 0bb1941a78ece0b610a2fbba7d74a84c diff --git a/src/openai/types/responses/response_output_text.py b/src/openai/types/responses/response_output_text.py index fc579cd894..aa97b629f0 100644 --- a/src/openai/types/responses/response_output_text.py +++ b/src/openai/types/responses/response_output_text.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union +from typing import List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias from ..._utils import PropertyInfo @@ -108,10 +108,10 @@ class ResponseOutputText(BaseModel): annotations: List[Annotation] """The annotations of the text output.""" - logprobs: List[Logprob] - text: str """The text output from the model.""" type: Literal["output_text"] """The type of the output text. Always `output_text`.""" + + logprobs: Optional[List[Logprob]] = None diff --git a/src/openai/types/responses/response_output_text_param.py b/src/openai/types/responses/response_output_text_param.py index 445a308a5b..63d2d394a8 100644 --- a/src/openai/types/responses/response_output_text_param.py +++ b/src/openai/types/responses/response_output_text_param.py @@ -106,10 +106,10 @@ class ResponseOutputTextParam(TypedDict, total=False): annotations: Required[Iterable[Annotation]] """The annotations of the text output.""" - logprobs: Required[Iterable[Logprob]] - text: Required[str] """The text output from the model.""" type: Required[Literal["output_text"]] """The type of the output text. Always `output_text`.""" + + logprobs: Iterable[Logprob] From 6574bcd612771186995074846253caa0ff1ba517 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 4 Nov 2025 06:03:21 +0000 Subject: [PATCH 544/769] release: 2.7.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index d1328ca9c9..0a163d740c 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.7.0" + ".": "2.7.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 516368cfed..d0b673d0f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 2.7.1 (2025-11-04) + +Full Changelog: [v2.7.0...v2.7.1](https://github.com/openai/openai-python/compare/v2.7.0...v2.7.1) + +### Bug Fixes + +* **api:** fix nullability of logprobs ([373b7f6](https://github.com/openai/openai-python/commit/373b7f6e4255dfef3ccd92520011e8ba44e8b7f0)) + ## 2.7.0 (2025-11-03) Full Changelog: [v2.6.1...v2.7.0](https://github.com/openai/openai-python/compare/v2.6.1...v2.7.0) diff --git a/pyproject.toml b/pyproject.toml index 8ff272e18e..a4850a0f49 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.7.0" +version = "2.7.1" 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 0963c9c373..9fb4c23dba 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__ = "2.7.0" # x-release-please-version +__version__ = "2.7.1" # x-release-please-version From 3f52ac842f9fc20d9729b71523a09f10374f97b9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 10 Nov 2025 11:28:54 +0000 Subject: [PATCH 545/769] chore(package): drop Python 3.8 support --- README.md | 4 ++-- pyproject.toml | 5 ++--- src/openai/_utils/_sync.py | 34 +++------------------------------- 3 files changed, 7 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 21f79312a1..470707e1f3 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![PyPI version](https://img.shields.io/pypi/v/openai.svg?label=pypi%20(stable))](https://pypi.org/project/openai/) -The OpenAI Python library provides convenient access to the OpenAI REST API from any Python 3.8+ +The OpenAI Python library provides convenient access to the OpenAI REST API from any Python 3.9+ application. The library includes type definitions for all request params and response fields, and offers both synchronous and asynchronous clients powered by [httpx](https://github.com/encode/httpx). @@ -854,7 +854,7 @@ print(openai.__version__) ## Requirements -Python 3.8 or higher. +Python 3.9 or higher. ## Contributing diff --git a/pyproject.toml b/pyproject.toml index a4850a0f49..bbc00e2d0c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,11 +17,10 @@ dependencies = [ "tqdm > 4", "jiter>=0.10.0, <1", ] -requires-python = ">= 3.8" +requires-python = ">= 3.9" classifiers = [ "Typing :: Typed", "Intended Audience :: Developers", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", @@ -159,7 +158,7 @@ format-command="ruff format --stdin-filename {filename}" # there are a couple of flags that are still disabled by # default in strict mode as they are experimental and niche. typeCheckingMode = "strict" -pythonVersion = "3.8" +pythonVersion = "3.9" exclude = [ "_dev", diff --git a/src/openai/_utils/_sync.py b/src/openai/_utils/_sync.py index ad7ec71b76..f6027c183d 100644 --- a/src/openai/_utils/_sync.py +++ b/src/openai/_utils/_sync.py @@ -1,10 +1,8 @@ from __future__ import annotations -import sys import asyncio import functools -import contextvars -from typing import Any, TypeVar, Callable, Awaitable +from typing import TypeVar, Callable, Awaitable from typing_extensions import ParamSpec import anyio @@ -15,34 +13,11 @@ T_ParamSpec = ParamSpec("T_ParamSpec") -if sys.version_info >= (3, 9): - _asyncio_to_thread = asyncio.to_thread -else: - # backport of https://docs.python.org/3/library/asyncio-task.html#asyncio.to_thread - # for Python 3.8 support - async def _asyncio_to_thread( - func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs - ) -> Any: - """Asynchronously run function *func* in a separate thread. - - Any *args and **kwargs supplied for this function are directly passed - to *func*. Also, the current :class:`contextvars.Context` is propagated, - allowing context variables from the main thread to be accessed in the - separate thread. - - Returns a coroutine that can be awaited to get the eventual result of *func*. - """ - loop = asyncio.events.get_running_loop() - ctx = contextvars.copy_context() - func_call = functools.partial(ctx.run, func, *args, **kwargs) - return await loop.run_in_executor(None, func_call) - - async def to_thread( func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs ) -> T_Retval: if sniffio.current_async_library() == "asyncio": - return await _asyncio_to_thread(func, *args, **kwargs) + return await asyncio.to_thread(func, *args, **kwargs) return await anyio.to_thread.run_sync( functools.partial(func, *args, **kwargs), @@ -53,10 +28,7 @@ async def to_thread( def asyncify(function: Callable[T_ParamSpec, T_Retval]) -> Callable[T_ParamSpec, Awaitable[T_Retval]]: """ Take a blocking function and create an async one that receives the same - positional and keyword arguments. For python version 3.9 and above, it uses - asyncio.to_thread to run the function in a separate thread. For python version - 3.8, it uses locally defined copy of the asyncio.to_thread function which was - introduced in python 3.9. + positional and keyword arguments. Usage: From 080587bda94771e54f39171067c165db597b950f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 10 Nov 2025 13:35:58 +0000 Subject: [PATCH 546/769] fix: compat with Python 3.14 --- src/openai/_models.py | 11 ++++++++--- tests/test_models.py | 8 ++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/openai/_models.py b/src/openai/_models.py index af71a91850..0f091058d2 100644 --- a/src/openai/_models.py +++ b/src/openai/_models.py @@ -2,6 +2,7 @@ import os import inspect +import weakref from typing import TYPE_CHECKING, Any, Type, Tuple, Union, Generic, TypeVar, Callable, Optional, cast from datetime import date, datetime from typing_extensions import ( @@ -598,6 +599,9 @@ class CachedDiscriminatorType(Protocol): __discriminator__: DiscriminatorDetails +DISCRIMINATOR_CACHE: weakref.WeakKeyDictionary[type, DiscriminatorDetails] = weakref.WeakKeyDictionary() + + class DiscriminatorDetails: field_name: str """The name of the discriminator field in the variant class, e.g. @@ -640,8 +644,9 @@ def __init__( def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, ...]) -> DiscriminatorDetails | None: - if isinstance(union, CachedDiscriminatorType): - return union.__discriminator__ + cached = DISCRIMINATOR_CACHE.get(union) + if cached is not None: + return cached discriminator_field_name: str | None = None @@ -694,7 +699,7 @@ def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, discriminator_field=discriminator_field_name, discriminator_alias=discriminator_alias, ) - cast(CachedDiscriminatorType, union).__discriminator__ = details + DISCRIMINATOR_CACHE.setdefault(union, details) return details diff --git a/tests/test_models.py b/tests/test_models.py index 410ec3bf4e..588869ee35 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -9,7 +9,7 @@ from openai._utils import PropertyInfo from openai._compat import PYDANTIC_V1, parse_obj, model_dump, model_json -from openai._models import BaseModel, construct_type +from openai._models import DISCRIMINATOR_CACHE, BaseModel, construct_type class BasicModel(BaseModel): @@ -809,7 +809,7 @@ class B(BaseModel): UnionType = cast(Any, Union[A, B]) - assert not hasattr(UnionType, "__discriminator__") + assert not DISCRIMINATOR_CACHE.get(UnionType) m = construct_type( value={"type": "b", "data": "foo"}, type_=cast(Any, Annotated[UnionType, PropertyInfo(discriminator="type")]) @@ -818,7 +818,7 @@ class B(BaseModel): assert m.type == "b" assert m.data == "foo" # type: ignore[comparison-overlap] - discriminator = UnionType.__discriminator__ + discriminator = DISCRIMINATOR_CACHE.get(UnionType) assert discriminator is not None m = construct_type( @@ -830,7 +830,7 @@ class B(BaseModel): # if the discriminator details object stays the same between invocations then # we hit the cache - assert UnionType.__discriminator__ is discriminator + assert DISCRIMINATOR_CACHE.get(UnionType) is discriminator @pytest.mark.skipif(PYDANTIC_V1, reason="TypeAliasType is not supported in Pydantic v1") From 650be393dedf2a4550092817c2b82c1d04d6e9dc Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 10 Nov 2025 13:36:34 +0000 Subject: [PATCH 547/769] release: 2.7.2 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 0a163d740c..e3ec769daf 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.7.1" + ".": "2.7.2" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index d0b673d0f7..03dfa94242 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 2.7.2 (2025-11-10) + +Full Changelog: [v2.7.1...v2.7.2](https://github.com/openai/openai-python/compare/v2.7.1...v2.7.2) + +### Bug Fixes + +* compat with Python 3.14 ([15a7ec8](https://github.com/openai/openai-python/commit/15a7ec8a753d7f57d525fca60c547fd5331cb214)) + + +### Chores + +* **package:** drop Python 3.8 support ([afc14f2](https://github.com/openai/openai-python/commit/afc14f2e42e7a8174f2ff1a5672829b808a716bf)) + ## 2.7.1 (2025-11-04) Full Changelog: [v2.7.0...v2.7.1](https://github.com/openai/openai-python/compare/v2.7.0...v2.7.1) diff --git a/pyproject.toml b/pyproject.toml index bbc00e2d0c..ca13765a98 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.7.1" +version = "2.7.2" 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 9fb4c23dba..6c0fcb3469 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__ = "2.7.1" # x-release-please-version +__version__ = "2.7.2" # x-release-please-version From 22317c6eb1b34428f21b801ecbb856f1625774a2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 11 Nov 2025 14:40:03 +0000 Subject: [PATCH 548/769] fix(compat): update signatures of `model_dump` and `model_dump_json` for Pydantic v1 --- src/openai/_models.py | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/src/openai/_models.py b/src/openai/_models.py index 0f091058d2..fac59c2cb8 100644 --- a/src/openai/_models.py +++ b/src/openai/_models.py @@ -282,15 +282,16 @@ def model_dump( mode: Literal["json", "python"] | str = "python", include: IncEx | None = None, exclude: IncEx | None = None, + context: Any | None = None, by_alias: bool | None = None, exclude_unset: bool = False, exclude_defaults: bool = False, exclude_none: bool = False, + exclude_computed_fields: bool = False, round_trip: bool = False, warnings: bool | Literal["none", "warn", "error"] = True, - context: dict[str, Any] | None = None, - serialize_as_any: bool = False, fallback: Callable[[Any], Any] | None = None, + serialize_as_any: bool = False, ) -> dict[str, Any]: """Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump @@ -298,16 +299,24 @@ def model_dump( Args: mode: The mode in which `to_python` should run. - If mode is 'json', the dictionary will only contain JSON serializable types. - If mode is 'python', the dictionary may contain any Python objects. - include: A list of fields to include in the output. - exclude: A list of fields to exclude from the output. + If mode is 'json', the output will only contain JSON serializable types. + If mode is 'python', the output may contain non-JSON-serializable Python objects. + include: A set of fields to include in the output. + exclude: A set of fields to exclude from the output. + context: Additional context to pass to the serializer. by_alias: Whether to use the field's alias in the dictionary key if defined. - exclude_unset: Whether to exclude fields that are unset or None from the output. - exclude_defaults: Whether to exclude fields that are set to their default value from the output. - exclude_none: Whether to exclude fields that have a value of `None` from the output. - round_trip: Whether to enable serialization and deserialization round-trip support. - warnings: Whether to log warnings when invalid fields are encountered. + exclude_unset: Whether to exclude fields that have not been explicitly set. + exclude_defaults: Whether to exclude fields that are set to their default value. + exclude_none: Whether to exclude fields that have a value of `None`. + exclude_computed_fields: Whether to exclude computed fields. + While this can be useful for round-tripping, it is usually recommended to use the dedicated + `round_trip` parameter instead. + round_trip: If True, dumped values should be valid as input for non-idempotent types such as Json[T]. + warnings: How to handle serialization errors. False/"none" ignores them, True/"warn" logs errors, + "error" raises a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError]. + fallback: A function to call when an unknown value is encountered. If not provided, + a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] error is raised. + serialize_as_any: Whether to serialize fields with duck-typing serialization behavior. Returns: A dictionary representation of the model. @@ -324,6 +333,8 @@ def model_dump( raise ValueError("serialize_as_any is only supported in Pydantic v2") if fallback is not None: raise ValueError("fallback is only supported in Pydantic v2") + if exclude_computed_fields != False: + raise ValueError("exclude_computed_fields is only supported in Pydantic v2") dumped = super().dict( # pyright: ignore[reportDeprecated] include=include, exclude=exclude, @@ -340,15 +351,17 @@ def model_dump_json( self, *, indent: int | None = None, + ensure_ascii: bool = False, include: IncEx | None = None, exclude: IncEx | None = None, + context: Any | None = None, by_alias: bool | None = None, exclude_unset: bool = False, exclude_defaults: bool = False, exclude_none: bool = False, + exclude_computed_fields: bool = False, round_trip: bool = False, warnings: bool | Literal["none", "warn", "error"] = True, - context: dict[str, Any] | None = None, fallback: Callable[[Any], Any] | None = None, serialize_as_any: bool = False, ) -> str: @@ -380,6 +393,10 @@ def model_dump_json( raise ValueError("serialize_as_any is only supported in Pydantic v2") if fallback is not None: raise ValueError("fallback is only supported in Pydantic v2") + if ensure_ascii != False: + raise ValueError("ensure_ascii is only supported in Pydantic v2") + if exclude_computed_fields != False: + raise ValueError("exclude_computed_fields is only supported in Pydantic v2") return super().json( # type: ignore[reportDeprecated] indent=indent, include=include, From 139b376ef9a186285e3bca891ebcdf57efc1ca75 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 12 Nov 2025 19:47:02 +0000 Subject: [PATCH 549/769] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 2588839c5a..25f1a92629 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 136 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-eeba8addf3a5f412e5ce8d22031e60c61650cee3f5d9e587a2533f6818a249ea.yml openapi_spec_hash: 0a4d8ad2469823ce24a3fd94f23f1c2b -config_hash: 0bb1941a78ece0b610a2fbba7d74a84c +config_hash: 630eea84bb3067d25640419af058ed56 From ac534dcd13fe1178c0d7e95f0cef3dbdcd647418 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 13 Nov 2025 18:10:43 +0000 Subject: [PATCH 550/769] feat(api): gpt 5.1 --- .stats.yml | 6 +- api.md | 9 + src/openai/lib/_parsing/_responses.py | 4 + src/openai/resources/batches.py | 22 ++- src/openai/resources/beta/assistants.py | 58 ++++--- .../resources/beta/threads/runs/runs.py | 86 ++++++---- .../resources/chat/completions/completions.py | 132 +++++++++++---- src/openai/resources/responses/responses.py | 52 ++++++ src/openai/types/batch_create_params.py | 12 +- .../types/beta/assistant_create_params.py | 16 +- .../types/beta/assistant_update_params.py | 16 +- .../types/beta/threads/run_create_params.py | 16 +- .../types/chat/completion_create_params.py | 24 ++- .../types/conversations/conversation_item.py | 8 + ...create_eval_completions_run_data_source.py | 16 +- ..._eval_completions_run_data_source_param.py | 16 +- src/openai/types/evals/run_cancel_response.py | 32 ++-- src/openai/types/evals/run_create_params.py | 32 ++-- src/openai/types/evals/run_create_response.py | 32 ++-- src/openai/types/evals/run_list_response.py | 32 ++-- .../types/evals/run_retrieve_response.py | 32 ++-- .../types/graders/score_model_grader.py | 16 +- .../types/graders/score_model_grader_param.py | 16 +- src/openai/types/responses/__init__.py | 20 +++ .../types/responses/apply_patch_tool.py | 12 ++ .../types/responses/apply_patch_tool_param.py | 12 ++ .../types/responses/function_shell_tool.py | 12 ++ .../responses/function_shell_tool_param.py | 12 ++ .../responses/input_token_count_params.py | 4 + src/openai/types/responses/parsed_response.py | 8 + src/openai/types/responses/response.py | 19 ++- .../response_apply_patch_tool_call.py | 76 +++++++++ .../response_apply_patch_tool_call_output.py | 31 ++++ .../types/responses/response_create_params.py | 12 ++ ...onse_function_shell_call_output_content.py | 36 ++++ ...unction_shell_call_output_content_param.py | 35 ++++ .../response_function_shell_tool_call.py | 44 +++++ ...esponse_function_shell_tool_call_output.py | 70 ++++++++ .../types/responses/response_input_item.py | 159 ++++++++++++++++++ .../responses/response_input_item_param.py | 158 +++++++++++++++++ .../types/responses/response_input_param.py | 158 +++++++++++++++++ src/openai/types/responses/response_item.py | 8 + .../types/responses/response_output_item.py | 8 + src/openai/types/responses/tool.py | 4 + .../responses/tool_choice_apply_patch.py | 12 ++ .../tool_choice_apply_patch_param.py | 12 ++ .../types/responses/tool_choice_shell.py | 12 ++ .../responses/tool_choice_shell_param.py | 12 ++ src/openai/types/responses/tool_param.py | 4 + src/openai/types/shared/chat_model.py | 5 + src/openai/types/shared/reasoning.py | 16 +- src/openai/types/shared/reasoning_effort.py | 2 +- src/openai/types/shared_params/chat_model.py | 5 + src/openai/types/shared_params/reasoning.py | 16 +- .../types/shared_params/reasoning_effort.py | 2 +- tests/api_resources/beta/test_assistants.py | 8 +- tests/api_resources/beta/threads/test_runs.py | 8 +- tests/api_resources/chat/test_completions.py | 12 +- .../responses/test_input_tokens.py | 4 +- tests/api_resources/test_responses.py | 12 +- 60 files changed, 1486 insertions(+), 239 deletions(-) create mode 100644 src/openai/types/responses/apply_patch_tool.py create mode 100644 src/openai/types/responses/apply_patch_tool_param.py create mode 100644 src/openai/types/responses/function_shell_tool.py create mode 100644 src/openai/types/responses/function_shell_tool_param.py create mode 100644 src/openai/types/responses/response_apply_patch_tool_call.py create mode 100644 src/openai/types/responses/response_apply_patch_tool_call_output.py create mode 100644 src/openai/types/responses/response_function_shell_call_output_content.py create mode 100644 src/openai/types/responses/response_function_shell_call_output_content_param.py create mode 100644 src/openai/types/responses/response_function_shell_tool_call.py create mode 100644 src/openai/types/responses/response_function_shell_tool_call_output.py create mode 100644 src/openai/types/responses/tool_choice_apply_patch.py create mode 100644 src/openai/types/responses/tool_choice_apply_patch_param.py create mode 100644 src/openai/types/responses/tool_choice_shell.py create mode 100644 src/openai/types/responses/tool_choice_shell_param.py diff --git a/.stats.yml b/.stats.yml index 25f1a92629..b44bda286e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 136 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-eeba8addf3a5f412e5ce8d22031e60c61650cee3f5d9e587a2533f6818a249ea.yml -openapi_spec_hash: 0a4d8ad2469823ce24a3fd94f23f1c2b -config_hash: 630eea84bb3067d25640419af058ed56 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-ca24bc4d8125b5153514ce643c4e3220f25971b7d67ca384d56d493c72c0d977.yml +openapi_spec_hash: c6f048c7b3d29f4de48fde0e845ba33f +config_hash: b876221dfb213df9f0a999e75d38a65e diff --git a/api.md b/api.md index 96642c01ad..28ee551af3 100644 --- a/api.md +++ b/api.md @@ -732,12 +732,16 @@ Types: ```python from openai.types.responses import ( + ApplyPatchTool, ComputerTool, CustomTool, EasyInputMessage, FileSearchTool, + FunctionShellTool, FunctionTool, Response, + ResponseApplyPatchToolCall, + ResponseApplyPatchToolCallOutput, ResponseAudioDeltaEvent, ResponseAudioDoneEvent, ResponseAudioTranscriptDeltaEvent, @@ -774,6 +778,9 @@ from openai.types.responses import ( ResponseFunctionCallArgumentsDoneEvent, ResponseFunctionCallOutputItem, ResponseFunctionCallOutputItemList, + ResponseFunctionShellCallOutputContent, + ResponseFunctionShellToolCall, + ResponseFunctionShellToolCallOutput, ResponseFunctionToolCall, ResponseFunctionToolCallItem, ResponseFunctionToolCallOutputItem, @@ -836,10 +843,12 @@ from openai.types.responses import ( ResponseWebSearchCallSearchingEvent, Tool, ToolChoiceAllowed, + ToolChoiceApplyPatch, ToolChoiceCustom, ToolChoiceFunction, ToolChoiceMcp, ToolChoiceOptions, + ToolChoiceShell, ToolChoiceTypes, WebSearchPreviewTool, WebSearchTool, diff --git a/src/openai/lib/_parsing/_responses.py b/src/openai/lib/_parsing/_responses.py index 8a1bf3cf2c..4d7b0b6224 100644 --- a/src/openai/lib/_parsing/_responses.py +++ b/src/openai/lib/_parsing/_responses.py @@ -108,6 +108,10 @@ def parse_response( or output.type == "image_generation_call" or output.type == "code_interpreter_call" or output.type == "local_shell_call" + or output.type == "shell_call" + or output.type == "shell_call_output" + or output.type == "apply_patch_call" + or output.type == "apply_patch_call_output" or output.type == "mcp_list_tools" or output.type == "exec" or output.type == "custom_tool_call" diff --git a/src/openai/resources/batches.py b/src/openai/resources/batches.py index afc7fa6eb9..80400839e4 100644 --- a/src/openai/resources/batches.py +++ b/src/openai/resources/batches.py @@ -46,7 +46,9 @@ def create( self, *, completion_window: Literal["24h"], - endpoint: Literal["/v1/responses", "/v1/chat/completions", "/v1/embeddings", "/v1/completions"], + endpoint: Literal[ + "/v1/responses", "/v1/chat/completions", "/v1/embeddings", "/v1/completions", "/v1/moderations" + ], input_file_id: str, metadata: Optional[Metadata] | Omit = omit, output_expires_after: batch_create_params.OutputExpiresAfter | Omit = omit, @@ -65,9 +67,10 @@ def create( is supported. endpoint: The endpoint to be used for all requests in the batch. Currently - `/v1/responses`, `/v1/chat/completions`, `/v1/embeddings`, and `/v1/completions` - are supported. Note that `/v1/embeddings` batches are also restricted to a - maximum of 50,000 embedding inputs across all requests in the batch. + `/v1/responses`, `/v1/chat/completions`, `/v1/embeddings`, `/v1/completions`, + and `/v1/moderations` are supported. Note that `/v1/embeddings` batches are also + restricted to a maximum of 50,000 embedding inputs across all requests in the + batch. input_file_id: The ID of an uploaded file that contains requests for the new batch. @@ -261,7 +264,9 @@ async def create( self, *, completion_window: Literal["24h"], - endpoint: Literal["/v1/responses", "/v1/chat/completions", "/v1/embeddings", "/v1/completions"], + endpoint: Literal[ + "/v1/responses", "/v1/chat/completions", "/v1/embeddings", "/v1/completions", "/v1/moderations" + ], input_file_id: str, metadata: Optional[Metadata] | Omit = omit, output_expires_after: batch_create_params.OutputExpiresAfter | Omit = omit, @@ -280,9 +285,10 @@ async def create( is supported. endpoint: The endpoint to be used for all requests in the batch. Currently - `/v1/responses`, `/v1/chat/completions`, `/v1/embeddings`, and `/v1/completions` - are supported. Note that `/v1/embeddings` batches are also restricted to a - maximum of 50,000 embedding inputs across all requests in the batch. + `/v1/responses`, `/v1/chat/completions`, `/v1/embeddings`, `/v1/completions`, + and `/v1/moderations` are supported. Note that `/v1/embeddings` batches are also + restricted to a maximum of 50,000 embedding inputs across all requests in the + batch. input_file_id: The ID of an uploaded file that contains requests for the new batch. diff --git a/src/openai/resources/beta/assistants.py b/src/openai/resources/beta/assistants.py index a958c0caa1..e4ec1dca11 100644 --- a/src/openai/resources/beta/assistants.py +++ b/src/openai/resources/beta/assistants.py @@ -98,12 +98,16 @@ def create( reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), @@ -308,12 +312,16 @@ def update( reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), @@ -557,12 +565,16 @@ async def create( reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), @@ -767,12 +779,16 @@ async def update( reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. - - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. + + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), diff --git a/src/openai/resources/beta/threads/runs/runs.py b/src/openai/resources/beta/threads/runs/runs.py index 2753f5817e..d7445d52b5 100644 --- a/src/openai/resources/beta/threads/runs/runs.py +++ b/src/openai/resources/beta/threads/runs/runs.py @@ -169,12 +169,16 @@ def create( reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), @@ -326,12 +330,16 @@ def create( reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), @@ -479,12 +487,16 @@ def create( reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), @@ -1608,12 +1620,16 @@ async def create( reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), @@ -1765,12 +1781,16 @@ async def create( reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), @@ -1918,12 +1938,16 @@ async def create( reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. - - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. + + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index 4b73c69ae9..c205011d10 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -102,6 +102,7 @@ def parse( prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, presence_penalty: Optional[float] | Omit = omit, prompt_cache_key: str | Omit = omit, + prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, reasoning_effort: Optional[ReasoningEffort] | Omit = omit, safety_identifier: str | Omit = omit, seed: Optional[int] | Omit = omit, @@ -201,6 +202,7 @@ def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseForma "prediction": prediction, "presence_penalty": presence_penalty, "prompt_cache_key": prompt_cache_key, + "prompt_cache_retention": prompt_cache_retention, "reasoning_effort": reasoning_effort, "response_format": _type_to_response_format(response_format), "safety_identifier": safety_identifier, @@ -255,6 +257,7 @@ def create( prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, presence_penalty: Optional[float] | Omit = omit, prompt_cache_key: str | Omit = omit, + prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, reasoning_effort: Optional[ReasoningEffort] | Omit = omit, response_format: completion_create_params.ResponseFormat | Omit = omit, safety_identifier: str | Omit = omit, @@ -401,14 +404,23 @@ def create( hit rates. Replaces the `user` field. [Learn more](https://platform.openai.com/docs/guides/prompt-caching). + prompt_cache_retention: The retention policy for the prompt cache. Set to `24h` to enable extended + prompt caching, which keeps cached prefixes active for longer, up to a maximum + of 24 hours. + [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). + reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. response_format: An object specifying the format that the model must output. @@ -547,6 +559,7 @@ def create( prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, presence_penalty: Optional[float] | Omit = omit, prompt_cache_key: str | Omit = omit, + prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, reasoning_effort: Optional[ReasoningEffort] | Omit = omit, response_format: completion_create_params.ResponseFormat | Omit = omit, safety_identifier: str | Omit = omit, @@ -701,14 +714,23 @@ def create( hit rates. Replaces the `user` field. [Learn more](https://platform.openai.com/docs/guides/prompt-caching). + prompt_cache_retention: The retention policy for the prompt cache. Set to `24h` to enable extended + prompt caching, which keeps cached prefixes active for longer, up to a maximum + of 24 hours. + [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). + reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. response_format: An object specifying the format that the model must output. @@ -838,6 +860,7 @@ def create( prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, presence_penalty: Optional[float] | Omit = omit, prompt_cache_key: str | Omit = omit, + prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, reasoning_effort: Optional[ReasoningEffort] | Omit = omit, response_format: completion_create_params.ResponseFormat | Omit = omit, safety_identifier: str | Omit = omit, @@ -992,14 +1015,23 @@ def create( hit rates. Replaces the `user` field. [Learn more](https://platform.openai.com/docs/guides/prompt-caching). + prompt_cache_retention: The retention policy for the prompt cache. Set to `24h` to enable extended + prompt caching, which keeps cached prefixes active for longer, up to a maximum + of 24 hours. + [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). + reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. response_format: An object specifying the format that the model must output. @@ -1128,6 +1160,7 @@ def create( prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, presence_penalty: Optional[float] | Omit = omit, prompt_cache_key: str | Omit = omit, + prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, reasoning_effort: Optional[ReasoningEffort] | Omit = omit, response_format: completion_create_params.ResponseFormat | Omit = omit, safety_identifier: str | Omit = omit, @@ -1174,6 +1207,7 @@ def create( "prediction": prediction, "presence_penalty": presence_penalty, "prompt_cache_key": prompt_cache_key, + "prompt_cache_retention": prompt_cache_retention, "reasoning_effort": reasoning_effort, "response_format": response_format, "safety_identifier": safety_identifier, @@ -1407,6 +1441,7 @@ def stream( prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, presence_penalty: Optional[float] | Omit = omit, prompt_cache_key: str | Omit = omit, + prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, reasoning_effort: Optional[ReasoningEffort] | Omit = omit, safety_identifier: str | Omit = omit, seed: Optional[int] | Omit = omit, @@ -1477,6 +1512,7 @@ def stream( prediction=prediction, presence_penalty=presence_penalty, prompt_cache_key=prompt_cache_key, + prompt_cache_retention=prompt_cache_retention, reasoning_effort=reasoning_effort, safety_identifier=safety_identifier, seed=seed, @@ -1549,6 +1585,7 @@ async def parse( prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, presence_penalty: Optional[float] | Omit = omit, prompt_cache_key: str | Omit = omit, + prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, reasoning_effort: Optional[ReasoningEffort] | Omit = omit, safety_identifier: str | Omit = omit, seed: Optional[int] | Omit = omit, @@ -1648,6 +1685,7 @@ def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseForma "prediction": prediction, "presence_penalty": presence_penalty, "prompt_cache_key": prompt_cache_key, + "prompt_cache_retention": prompt_cache_retention, "reasoning_effort": reasoning_effort, "response_format": _type_to_response_format(response_format), "safety_identifier": safety_identifier, @@ -1702,6 +1740,7 @@ async def create( prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, presence_penalty: Optional[float] | Omit = omit, prompt_cache_key: str | Omit = omit, + prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, reasoning_effort: Optional[ReasoningEffort] | Omit = omit, response_format: completion_create_params.ResponseFormat | Omit = omit, safety_identifier: str | Omit = omit, @@ -1848,14 +1887,23 @@ async def create( hit rates. Replaces the `user` field. [Learn more](https://platform.openai.com/docs/guides/prompt-caching). + prompt_cache_retention: The retention policy for the prompt cache. Set to `24h` to enable extended + prompt caching, which keeps cached prefixes active for longer, up to a maximum + of 24 hours. + [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). + reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. response_format: An object specifying the format that the model must output. @@ -1994,6 +2042,7 @@ async def create( prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, presence_penalty: Optional[float] | Omit = omit, prompt_cache_key: str | Omit = omit, + prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, reasoning_effort: Optional[ReasoningEffort] | Omit = omit, response_format: completion_create_params.ResponseFormat | Omit = omit, safety_identifier: str | Omit = omit, @@ -2148,14 +2197,23 @@ async def create( hit rates. Replaces the `user` field. [Learn more](https://platform.openai.com/docs/guides/prompt-caching). + prompt_cache_retention: The retention policy for the prompt cache. Set to `24h` to enable extended + prompt caching, which keeps cached prefixes active for longer, up to a maximum + of 24 hours. + [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). + reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. response_format: An object specifying the format that the model must output. @@ -2285,6 +2343,7 @@ async def create( prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, presence_penalty: Optional[float] | Omit = omit, prompt_cache_key: str | Omit = omit, + prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, reasoning_effort: Optional[ReasoningEffort] | Omit = omit, response_format: completion_create_params.ResponseFormat | Omit = omit, safety_identifier: str | Omit = omit, @@ -2439,14 +2498,23 @@ async def create( hit rates. Replaces the `user` field. [Learn more](https://platform.openai.com/docs/guides/prompt-caching). + prompt_cache_retention: The retention policy for the prompt cache. Set to `24h` to enable extended + prompt caching, which keeps cached prefixes active for longer, up to a maximum + of 24 hours. + [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). + reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. response_format: An object specifying the format that the model must output. @@ -2575,6 +2643,7 @@ async def create( prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, presence_penalty: Optional[float] | Omit = omit, prompt_cache_key: str | Omit = omit, + prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, reasoning_effort: Optional[ReasoningEffort] | Omit = omit, response_format: completion_create_params.ResponseFormat | Omit = omit, safety_identifier: str | Omit = omit, @@ -2621,6 +2690,7 @@ async def create( "prediction": prediction, "presence_penalty": presence_penalty, "prompt_cache_key": prompt_cache_key, + "prompt_cache_retention": prompt_cache_retention, "reasoning_effort": reasoning_effort, "response_format": response_format, "safety_identifier": safety_identifier, @@ -2854,6 +2924,7 @@ def stream( prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, presence_penalty: Optional[float] | Omit = omit, prompt_cache_key: str | Omit = omit, + prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, reasoning_effort: Optional[ReasoningEffort] | Omit = omit, safety_identifier: str | Omit = omit, seed: Optional[int] | Omit = omit, @@ -2925,6 +2996,7 @@ def stream( prediction=prediction, presence_penalty=presence_penalty, prompt_cache_key=prompt_cache_key, + prompt_cache_retention=prompt_cache_retention, reasoning_effort=reasoning_effort, safety_identifier=safety_identifier, seed=seed, diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 439cf8d3ad..dcf87ba07c 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -100,6 +100,7 @@ def create( previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, prompt_cache_key: str | Omit = omit, + prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, reasoning: Optional[Reasoning] | Omit = omit, safety_identifier: str | Omit = omit, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, @@ -215,6 +216,11 @@ def create( hit rates. Replaces the `user` field. [Learn more](https://platform.openai.com/docs/guides/prompt-caching). + prompt_cache_retention: The retention policy for the prompt cache. Set to `24h` to enable extended + prompt caching, which keeps cached prefixes active for longer, up to a maximum + of 24 hours. + [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). + reasoning: **gpt-5 and o-series models only** Configuration options for @@ -340,6 +346,7 @@ def create( previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, prompt_cache_key: str | Omit = omit, + prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, reasoning: Optional[Reasoning] | Omit = omit, safety_identifier: str | Omit = omit, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, @@ -461,6 +468,11 @@ def create( hit rates. Replaces the `user` field. [Learn more](https://platform.openai.com/docs/guides/prompt-caching). + prompt_cache_retention: The retention policy for the prompt cache. Set to `24h` to enable extended + prompt caching, which keeps cached prefixes active for longer, up to a maximum + of 24 hours. + [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). + reasoning: **gpt-5 and o-series models only** Configuration options for @@ -579,6 +591,7 @@ def create( previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, prompt_cache_key: str | Omit = omit, + prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, reasoning: Optional[Reasoning] | Omit = omit, safety_identifier: str | Omit = omit, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, @@ -700,6 +713,11 @@ def create( hit rates. Replaces the `user` field. [Learn more](https://platform.openai.com/docs/guides/prompt-caching). + prompt_cache_retention: The retention policy for the prompt cache. Set to `24h` to enable extended + prompt caching, which keeps cached prefixes active for longer, up to a maximum + of 24 hours. + [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). + reasoning: **gpt-5 and o-series models only** Configuration options for @@ -816,6 +834,7 @@ def create( previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, prompt_cache_key: str | Omit = omit, + prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, reasoning: Optional[Reasoning] | Omit = omit, safety_identifier: str | Omit = omit, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, @@ -854,6 +873,7 @@ def create( "previous_response_id": previous_response_id, "prompt": prompt, "prompt_cache_key": prompt_cache_key, + "prompt_cache_retention": prompt_cache_retention, "reasoning": reasoning, "safety_identifier": safety_identifier, "service_tier": service_tier, @@ -915,6 +935,7 @@ def stream( previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, prompt_cache_key: str | Omit = omit, + prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, reasoning: Optional[Reasoning] | Omit = omit, safety_identifier: str | Omit = omit, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, @@ -954,6 +975,7 @@ def stream( previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, prompt_cache_key: str | Omit = omit, + prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, reasoning: Optional[Reasoning] | Omit = omit, safety_identifier: str | Omit = omit, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, @@ -987,6 +1009,7 @@ def stream( "previous_response_id": previous_response_id, "prompt": prompt, "prompt_cache_key": prompt_cache_key, + "prompt_cache_retention": prompt_cache_retention, "reasoning": reasoning, "safety_identifier": safety_identifier, "service_tier": service_tier, @@ -1040,6 +1063,7 @@ def stream( previous_response_id=previous_response_id, prompt=prompt, prompt_cache_key=prompt_cache_key, + prompt_cache_retention=prompt_cache_retention, store=store, stream_options=stream_options, stream=True, @@ -1098,6 +1122,7 @@ def parse( previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, prompt_cache_key: str | Omit = omit, + prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, reasoning: Optional[Reasoning] | Omit = omit, safety_identifier: str | Omit = omit, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, @@ -1155,6 +1180,7 @@ def parser(raw_response: Response) -> ParsedResponse[TextFormatT]: "previous_response_id": previous_response_id, "prompt": prompt, "prompt_cache_key": prompt_cache_key, + "prompt_cache_retention": prompt_cache_retention, "reasoning": reasoning, "safety_identifier": safety_identifier, "service_tier": service_tier, @@ -1535,6 +1561,7 @@ async def create( previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, prompt_cache_key: str | Omit = omit, + prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, reasoning: Optional[Reasoning] | Omit = omit, safety_identifier: str | Omit = omit, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, @@ -1650,6 +1677,11 @@ async def create( hit rates. Replaces the `user` field. [Learn more](https://platform.openai.com/docs/guides/prompt-caching). + prompt_cache_retention: The retention policy for the prompt cache. Set to `24h` to enable extended + prompt caching, which keeps cached prefixes active for longer, up to a maximum + of 24 hours. + [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). + reasoning: **gpt-5 and o-series models only** Configuration options for @@ -1775,6 +1807,7 @@ async def create( previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, prompt_cache_key: str | Omit = omit, + prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, reasoning: Optional[Reasoning] | Omit = omit, safety_identifier: str | Omit = omit, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, @@ -1896,6 +1929,11 @@ async def create( hit rates. Replaces the `user` field. [Learn more](https://platform.openai.com/docs/guides/prompt-caching). + prompt_cache_retention: The retention policy for the prompt cache. Set to `24h` to enable extended + prompt caching, which keeps cached prefixes active for longer, up to a maximum + of 24 hours. + [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). + reasoning: **gpt-5 and o-series models only** Configuration options for @@ -2014,6 +2052,7 @@ async def create( previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, prompt_cache_key: str | Omit = omit, + prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, reasoning: Optional[Reasoning] | Omit = omit, safety_identifier: str | Omit = omit, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, @@ -2135,6 +2174,11 @@ async def create( hit rates. Replaces the `user` field. [Learn more](https://platform.openai.com/docs/guides/prompt-caching). + prompt_cache_retention: The retention policy for the prompt cache. Set to `24h` to enable extended + prompt caching, which keeps cached prefixes active for longer, up to a maximum + of 24 hours. + [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). + reasoning: **gpt-5 and o-series models only** Configuration options for @@ -2251,6 +2295,7 @@ async def create( previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, prompt_cache_key: str | Omit = omit, + prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, reasoning: Optional[Reasoning] | Omit = omit, safety_identifier: str | Omit = omit, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, @@ -2289,6 +2334,7 @@ async def create( "previous_response_id": previous_response_id, "prompt": prompt, "prompt_cache_key": prompt_cache_key, + "prompt_cache_retention": prompt_cache_retention, "reasoning": reasoning, "safety_identifier": safety_identifier, "service_tier": service_tier, @@ -2350,6 +2396,7 @@ def stream( previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, prompt_cache_key: str | Omit = omit, + prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, reasoning: Optional[Reasoning] | Omit = omit, safety_identifier: str | Omit = omit, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, @@ -2389,6 +2436,7 @@ def stream( previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, prompt_cache_key: str | Omit = omit, + prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, reasoning: Optional[Reasoning] | Omit = omit, safety_identifier: str | Omit = omit, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, @@ -2422,6 +2470,7 @@ def stream( "previous_response_id": previous_response_id, "prompt": prompt, "prompt_cache_key": prompt_cache_key, + "prompt_cache_retention": prompt_cache_retention, "reasoning": reasoning, "safety_identifier": safety_identifier, "service_tier": service_tier, @@ -2476,6 +2525,7 @@ def stream( previous_response_id=previous_response_id, prompt=prompt, prompt_cache_key=prompt_cache_key, + prompt_cache_retention=prompt_cache_retention, store=store, stream_options=stream_options, temperature=temperature, @@ -2538,6 +2588,7 @@ async def parse( previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, prompt_cache_key: str | Omit = omit, + prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, reasoning: Optional[Reasoning] | Omit = omit, safety_identifier: str | Omit = omit, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, @@ -2595,6 +2646,7 @@ def parser(raw_response: Response) -> ParsedResponse[TextFormatT]: "previous_response_id": previous_response_id, "prompt": prompt, "prompt_cache_key": prompt_cache_key, + "prompt_cache_retention": prompt_cache_retention, "reasoning": reasoning, "safety_identifier": safety_identifier, "service_tier": service_tier, diff --git a/src/openai/types/batch_create_params.py b/src/openai/types/batch_create_params.py index c0f9034d5e..c182a87e7f 100644 --- a/src/openai/types/batch_create_params.py +++ b/src/openai/types/batch_create_params.py @@ -17,13 +17,15 @@ class BatchCreateParams(TypedDict, total=False): Currently only `24h` is supported. """ - endpoint: Required[Literal["/v1/responses", "/v1/chat/completions", "/v1/embeddings", "/v1/completions"]] + endpoint: Required[ + Literal["/v1/responses", "/v1/chat/completions", "/v1/embeddings", "/v1/completions", "/v1/moderations"] + ] """The endpoint to be used for all requests in the batch. - Currently `/v1/responses`, `/v1/chat/completions`, `/v1/embeddings`, and - `/v1/completions` are supported. Note that `/v1/embeddings` batches are also - restricted to a maximum of 50,000 embedding inputs across all requests in the - batch. + Currently `/v1/responses`, `/v1/chat/completions`, `/v1/embeddings`, + `/v1/completions`, and `/v1/moderations` are supported. Note that + `/v1/embeddings` batches are also restricted to a maximum of 50,000 embedding + inputs across all requests in the batch. """ input_file_id: Required[str] diff --git a/src/openai/types/beta/assistant_create_params.py b/src/openai/types/beta/assistant_create_params.py index 6fb1551fa5..009b0f49e3 100644 --- a/src/openai/types/beta/assistant_create_params.py +++ b/src/openai/types/beta/assistant_create_params.py @@ -62,12 +62,16 @@ class AssistantCreateParams(TypedDict, total=False): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. - - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. + + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. """ response_format: Optional[AssistantResponseFormatOptionParam] diff --git a/src/openai/types/beta/assistant_update_params.py b/src/openai/types/beta/assistant_update_params.py index 6d20b8e01f..432116ad52 100644 --- a/src/openai/types/beta/assistant_update_params.py +++ b/src/openai/types/beta/assistant_update_params.py @@ -97,12 +97,16 @@ class AssistantUpdateParams(TypedDict, total=False): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. - - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. + + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. """ response_format: Optional[AssistantResponseFormatOptionParam] diff --git a/src/openai/types/beta/threads/run_create_params.py b/src/openai/types/beta/threads/run_create_params.py index 3190c8b308..74786d7d5c 100644 --- a/src/openai/types/beta/threads/run_create_params.py +++ b/src/openai/types/beta/threads/run_create_params.py @@ -111,12 +111,16 @@ class RunCreateParamsBase(TypedDict, total=False): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. - - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. + + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. """ response_format: Optional[AssistantResponseFormatOptionParam] diff --git a/src/openai/types/chat/completion_create_params.py b/src/openai/types/chat/completion_create_params.py index 8b0fdd04b3..e02c06cbb0 100644 --- a/src/openai/types/chat/completion_create_params.py +++ b/src/openai/types/chat/completion_create_params.py @@ -185,16 +185,28 @@ class CompletionCreateParamsBase(TypedDict, total=False): [Learn more](https://platform.openai.com/docs/guides/prompt-caching). """ + prompt_cache_retention: Optional[Literal["in-memory", "24h"]] + """The retention policy for the prompt cache. + + Set to `24h` to enable extended prompt caching, which keeps cached prefixes + active for longer, up to a maximum of 24 hours. + [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). + """ + reasoning_effort: Optional[ReasoningEffort] """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. - - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. + + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. """ response_format: ResponseFormat diff --git a/src/openai/types/conversations/conversation_item.py b/src/openai/types/conversations/conversation_item.py index 9e9fb40033..052d09ce77 100644 --- a/src/openai/types/conversations/conversation_item.py +++ b/src/openai/types/conversations/conversation_item.py @@ -10,12 +10,16 @@ from ..responses.response_custom_tool_call import ResponseCustomToolCall from ..responses.response_computer_tool_call import ResponseComputerToolCall from ..responses.response_function_web_search import ResponseFunctionWebSearch +from ..responses.response_apply_patch_tool_call import ResponseApplyPatchToolCall from ..responses.response_file_search_tool_call import ResponseFileSearchToolCall from ..responses.response_custom_tool_call_output import ResponseCustomToolCallOutput from ..responses.response_function_tool_call_item import ResponseFunctionToolCallItem +from ..responses.response_function_shell_tool_call import ResponseFunctionShellToolCall from ..responses.response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall +from ..responses.response_apply_patch_tool_call_output import ResponseApplyPatchToolCallOutput from ..responses.response_computer_tool_call_output_item import ResponseComputerToolCallOutputItem from ..responses.response_function_tool_call_output_item import ResponseFunctionToolCallOutputItem +from ..responses.response_function_shell_tool_call_output import ResponseFunctionShellToolCallOutput __all__ = [ "ConversationItem", @@ -211,6 +215,10 @@ class McpCall(BaseModel): ResponseCodeInterpreterToolCall, LocalShellCall, LocalShellCallOutput, + ResponseFunctionShellToolCall, + ResponseFunctionShellToolCallOutput, + ResponseApplyPatchToolCall, + ResponseApplyPatchToolCallOutput, McpListTools, McpApprovalRequest, McpApprovalResponse, diff --git a/src/openai/types/evals/create_eval_completions_run_data_source.py b/src/openai/types/evals/create_eval_completions_run_data_source.py index a9f2fd0858..742c27a775 100644 --- a/src/openai/types/evals/create_eval_completions_run_data_source.py +++ b/src/openai/types/evals/create_eval_completions_run_data_source.py @@ -172,12 +172,16 @@ class SamplingParams(BaseModel): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. - - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. + + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. """ response_format: Optional[SamplingParamsResponseFormat] = None diff --git a/src/openai/types/evals/create_eval_completions_run_data_source_param.py b/src/openai/types/evals/create_eval_completions_run_data_source_param.py index e682e2db5e..18cd5018b1 100644 --- a/src/openai/types/evals/create_eval_completions_run_data_source_param.py +++ b/src/openai/types/evals/create_eval_completions_run_data_source_param.py @@ -168,12 +168,16 @@ class SamplingParams(TypedDict, total=False): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. - - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. + + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. """ response_format: SamplingParamsResponseFormat diff --git a/src/openai/types/evals/run_cancel_response.py b/src/openai/types/evals/run_cancel_response.py index 084dd6ce5c..b18598b20e 100644 --- a/src/openai/types/evals/run_cancel_response.py +++ b/src/openai/types/evals/run_cancel_response.py @@ -103,12 +103,16 @@ class DataSourceResponsesSourceResponses(BaseModel): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. - - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. + + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. """ temperature: Optional[float] = None @@ -241,12 +245,16 @@ class DataSourceResponsesSamplingParams(BaseModel): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. - - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. + + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. """ seed: Optional[int] = None diff --git a/src/openai/types/evals/run_create_params.py b/src/openai/types/evals/run_create_params.py index f114fae6a4..a50433f06d 100644 --- a/src/openai/types/evals/run_create_params.py +++ b/src/openai/types/evals/run_create_params.py @@ -116,12 +116,16 @@ class DataSourceCreateEvalResponsesRunDataSourceSourceResponses(TypedDict, total """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. - - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. + + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. """ temperature: Optional[float] @@ -259,12 +263,16 @@ class DataSourceCreateEvalResponsesRunDataSourceSamplingParams(TypedDict, total= """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. - - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. + + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. """ seed: int diff --git a/src/openai/types/evals/run_create_response.py b/src/openai/types/evals/run_create_response.py index 1343335e0d..41dac615c7 100644 --- a/src/openai/types/evals/run_create_response.py +++ b/src/openai/types/evals/run_create_response.py @@ -103,12 +103,16 @@ class DataSourceResponsesSourceResponses(BaseModel): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. - - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. + + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. """ temperature: Optional[float] = None @@ -241,12 +245,16 @@ class DataSourceResponsesSamplingParams(BaseModel): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. - - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. + + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. """ seed: Optional[int] = None diff --git a/src/openai/types/evals/run_list_response.py b/src/openai/types/evals/run_list_response.py index 7c32ce54a2..61bff95447 100644 --- a/src/openai/types/evals/run_list_response.py +++ b/src/openai/types/evals/run_list_response.py @@ -103,12 +103,16 @@ class DataSourceResponsesSourceResponses(BaseModel): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. - - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. + + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. """ temperature: Optional[float] = None @@ -241,12 +245,16 @@ class DataSourceResponsesSamplingParams(BaseModel): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. - - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. + + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. """ seed: Optional[int] = None diff --git a/src/openai/types/evals/run_retrieve_response.py b/src/openai/types/evals/run_retrieve_response.py index f1212c1671..651d7423a9 100644 --- a/src/openai/types/evals/run_retrieve_response.py +++ b/src/openai/types/evals/run_retrieve_response.py @@ -103,12 +103,16 @@ class DataSourceResponsesSourceResponses(BaseModel): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. - - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. + + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. """ temperature: Optional[float] = None @@ -241,12 +245,16 @@ class DataSourceResponsesSamplingParams(BaseModel): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. - - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. + + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. """ seed: Optional[int] = None diff --git a/src/openai/types/graders/score_model_grader.py b/src/openai/types/graders/score_model_grader.py index 35e2dc1468..84686a9642 100644 --- a/src/openai/types/graders/score_model_grader.py +++ b/src/openai/types/graders/score_model_grader.py @@ -67,12 +67,16 @@ class SamplingParams(BaseModel): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. - - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. + + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. """ seed: Optional[int] = None diff --git a/src/openai/types/graders/score_model_grader_param.py b/src/openai/types/graders/score_model_grader_param.py index 168feeae13..aec7a95ad4 100644 --- a/src/openai/types/graders/score_model_grader_param.py +++ b/src/openai/types/graders/score_model_grader_param.py @@ -73,12 +73,16 @@ class SamplingParams(TypedDict, total=False): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. - - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. + + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. """ seed: Optional[int] diff --git a/src/openai/types/responses/__init__.py b/src/openai/types/responses/__init__.py index fd70836e50..e707141d9a 100644 --- a/src/openai/types/responses/__init__.py +++ b/src/openai/types/responses/__init__.py @@ -23,13 +23,16 @@ from .response_status import ResponseStatus as ResponseStatus from .tool_choice_mcp import ToolChoiceMcp as ToolChoiceMcp from .web_search_tool import WebSearchTool as WebSearchTool +from .apply_patch_tool import ApplyPatchTool as ApplyPatchTool from .file_search_tool import FileSearchTool as FileSearchTool from .custom_tool_param import CustomToolParam as CustomToolParam +from .tool_choice_shell import ToolChoiceShell as ToolChoiceShell from .tool_choice_types import ToolChoiceTypes as ToolChoiceTypes from .easy_input_message import EasyInputMessage as EasyInputMessage from .response_item_list import ResponseItemList as ResponseItemList from .tool_choice_custom import ToolChoiceCustom as ToolChoiceCustom from .computer_tool_param import ComputerToolParam as ComputerToolParam +from .function_shell_tool import FunctionShellTool as FunctionShellTool from .function_tool_param import FunctionToolParam as FunctionToolParam from .response_includable import ResponseIncludable as ResponseIncludable from .response_input_file import ResponseInputFile as ResponseInputFile @@ -51,6 +54,7 @@ from .response_stream_event import ResponseStreamEvent as ResponseStreamEvent from .tool_choice_mcp_param import ToolChoiceMcpParam as ToolChoiceMcpParam from .web_search_tool_param import WebSearchToolParam as WebSearchToolParam +from .apply_patch_tool_param import ApplyPatchToolParam as ApplyPatchToolParam from .file_search_tool_param import FileSearchToolParam as FileSearchToolParam from .input_item_list_params import InputItemListParams as InputItemListParams from .response_create_params import ResponseCreateParams as ResponseCreateParams @@ -59,6 +63,8 @@ from .response_output_message import ResponseOutputMessage as ResponseOutputMessage from .response_output_refusal import ResponseOutputRefusal as ResponseOutputRefusal from .response_reasoning_item import ResponseReasoningItem as ResponseReasoningItem +from .tool_choice_apply_patch import ToolChoiceApplyPatch as ToolChoiceApplyPatch +from .tool_choice_shell_param import ToolChoiceShellParam as ToolChoiceShellParam from .tool_choice_types_param import ToolChoiceTypesParam as ToolChoiceTypesParam from .web_search_preview_tool import WebSearchPreviewTool as WebSearchPreviewTool from .easy_input_message_param import EasyInputMessageParam as EasyInputMessageParam @@ -67,6 +73,7 @@ from .response_retrieve_params import ResponseRetrieveParams as ResponseRetrieveParams from .response_text_done_event import ResponseTextDoneEvent as ResponseTextDoneEvent from .tool_choice_custom_param import ToolChoiceCustomParam as ToolChoiceCustomParam +from .function_shell_tool_param import FunctionShellToolParam as FunctionShellToolParam from .response_audio_done_event import ResponseAudioDoneEvent as ResponseAudioDoneEvent from .response_custom_tool_call import ResponseCustomToolCall as ResponseCustomToolCall from .response_incomplete_event import ResponseIncompleteEvent as ResponseIncompleteEvent @@ -98,7 +105,9 @@ from .response_output_message_param import ResponseOutputMessageParam as ResponseOutputMessageParam from .response_output_refusal_param import ResponseOutputRefusalParam as ResponseOutputRefusalParam from .response_reasoning_item_param import ResponseReasoningItemParam as ResponseReasoningItemParam +from .tool_choice_apply_patch_param import ToolChoiceApplyPatchParam as ToolChoiceApplyPatchParam from .web_search_preview_tool_param import WebSearchPreviewToolParam as WebSearchPreviewToolParam +from .response_apply_patch_tool_call import ResponseApplyPatchToolCall as ResponseApplyPatchToolCall from .response_file_search_tool_call import ResponseFileSearchToolCall as ResponseFileSearchToolCall from .response_mcp_call_failed_event import ResponseMcpCallFailedEvent as ResponseMcpCallFailedEvent from .response_custom_tool_call_param import ResponseCustomToolCallParam as ResponseCustomToolCallParam @@ -110,6 +119,7 @@ from .response_computer_tool_call_param import ResponseComputerToolCallParam as ResponseComputerToolCallParam from .response_content_part_added_event import ResponseContentPartAddedEvent as ResponseContentPartAddedEvent from .response_format_text_config_param import ResponseFormatTextConfigParam as ResponseFormatTextConfigParam +from .response_function_shell_tool_call import ResponseFunctionShellToolCall as ResponseFunctionShellToolCall from .response_function_tool_call_param import ResponseFunctionToolCallParam as ResponseFunctionToolCallParam from .response_input_file_content_param import ResponseInputFileContentParam as ResponseInputFileContentParam from .response_input_text_content_param import ResponseInputTextContentParam as ResponseInputTextContentParam @@ -125,6 +135,7 @@ from .response_audio_transcript_done_event import ResponseAudioTranscriptDoneEvent as ResponseAudioTranscriptDoneEvent from .response_file_search_tool_call_param import ResponseFileSearchToolCallParam as ResponseFileSearchToolCallParam from .response_mcp_list_tools_failed_event import ResponseMcpListToolsFailedEvent as ResponseMcpListToolsFailedEvent +from .response_apply_patch_tool_call_output import ResponseApplyPatchToolCallOutput as ResponseApplyPatchToolCallOutput from .response_audio_transcript_delta_event import ( ResponseAudioTranscriptDeltaEvent as ResponseAudioTranscriptDeltaEvent, ) @@ -158,6 +169,9 @@ from .response_function_call_output_item_param import ( ResponseFunctionCallOutputItemParam as ResponseFunctionCallOutputItemParam, ) +from .response_function_shell_tool_call_output import ( + ResponseFunctionShellToolCallOutput as ResponseFunctionShellToolCallOutput, +) from .response_image_gen_call_generating_event import ( ResponseImageGenCallGeneratingEvent as ResponseImageGenCallGeneratingEvent, ) @@ -206,6 +220,9 @@ from .response_function_call_arguments_done_event import ( ResponseFunctionCallArgumentsDoneEvent as ResponseFunctionCallArgumentsDoneEvent, ) +from .response_function_shell_call_output_content import ( + ResponseFunctionShellCallOutputContent as ResponseFunctionShellCallOutputContent, +) from .response_image_gen_call_partial_image_event import ( ResponseImageGenCallPartialImageEvent as ResponseImageGenCallPartialImageEvent, ) @@ -245,6 +262,9 @@ from .response_code_interpreter_call_interpreting_event import ( ResponseCodeInterpreterCallInterpretingEvent as ResponseCodeInterpreterCallInterpretingEvent, ) +from .response_function_shell_call_output_content_param import ( + ResponseFunctionShellCallOutputContentParam as ResponseFunctionShellCallOutputContentParam, +) from .response_computer_tool_call_output_screenshot_param import ( ResponseComputerToolCallOutputScreenshotParam as ResponseComputerToolCallOutputScreenshotParam, ) diff --git a/src/openai/types/responses/apply_patch_tool.py b/src/openai/types/responses/apply_patch_tool.py new file mode 100644 index 0000000000..07706ce239 --- /dev/null +++ b/src/openai/types/responses/apply_patch_tool.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ApplyPatchTool"] + + +class ApplyPatchTool(BaseModel): + type: Literal["apply_patch"] + """The type of the tool. Always `apply_patch`.""" diff --git a/src/openai/types/responses/apply_patch_tool_param.py b/src/openai/types/responses/apply_patch_tool_param.py new file mode 100644 index 0000000000..93d15f0b1f --- /dev/null +++ b/src/openai/types/responses/apply_patch_tool_param.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ApplyPatchToolParam"] + + +class ApplyPatchToolParam(TypedDict, total=False): + type: Required[Literal["apply_patch"]] + """The type of the tool. Always `apply_patch`.""" diff --git a/src/openai/types/responses/function_shell_tool.py b/src/openai/types/responses/function_shell_tool.py new file mode 100644 index 0000000000..1784b6c2f1 --- /dev/null +++ b/src/openai/types/responses/function_shell_tool.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["FunctionShellTool"] + + +class FunctionShellTool(BaseModel): + type: Literal["shell"] + """The type of the shell tool. Always `shell`.""" diff --git a/src/openai/types/responses/function_shell_tool_param.py b/src/openai/types/responses/function_shell_tool_param.py new file mode 100644 index 0000000000..cee7ba23c9 --- /dev/null +++ b/src/openai/types/responses/function_shell_tool_param.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["FunctionShellToolParam"] + + +class FunctionShellToolParam(TypedDict, total=False): + type: Required[Literal["shell"]] + """The type of the shell tool. Always `shell`.""" diff --git a/src/openai/types/responses/input_token_count_params.py b/src/openai/types/responses/input_token_count_params.py index d442a2d171..296d0718d8 100644 --- a/src/openai/types/responses/input_token_count_params.py +++ b/src/openai/types/responses/input_token_count_params.py @@ -8,6 +8,7 @@ from .tool_param import ToolParam from .tool_choice_options import ToolChoiceOptions from .tool_choice_mcp_param import ToolChoiceMcpParam +from .tool_choice_shell_param import ToolChoiceShellParam from .tool_choice_types_param import ToolChoiceTypesParam from ..shared_params.reasoning import Reasoning from .tool_choice_custom_param import ToolChoiceCustomParam @@ -15,6 +16,7 @@ from .tool_choice_allowed_param import ToolChoiceAllowedParam from .tool_choice_function_param import ToolChoiceFunctionParam from .response_conversation_param import ResponseConversationParam +from .tool_choice_apply_patch_param import ToolChoiceApplyPatchParam from .response_format_text_config_param import ResponseFormatTextConfigParam __all__ = ["InputTokenCountParams", "Conversation", "Text", "ToolChoice"] @@ -135,4 +137,6 @@ class Text(TypedDict, total=False): ToolChoiceFunctionParam, ToolChoiceMcpParam, ToolChoiceCustomParam, + ToolChoiceApplyPatchParam, + ToolChoiceShellParam, ] diff --git a/src/openai/types/responses/parsed_response.py b/src/openai/types/responses/parsed_response.py index 1d9db361dd..c120f4641d 100644 --- a/src/openai/types/responses/parsed_response.py +++ b/src/openai/types/responses/parsed_response.py @@ -23,8 +23,12 @@ from .response_computer_tool_call import ResponseComputerToolCall from .response_function_tool_call import ResponseFunctionToolCall from .response_function_web_search import ResponseFunctionWebSearch +from .response_apply_patch_tool_call import ResponseApplyPatchToolCall from .response_file_search_tool_call import ResponseFileSearchToolCall +from .response_function_shell_tool_call import ResponseFunctionShellToolCall from .response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall +from .response_apply_patch_tool_call_output import ResponseApplyPatchToolCallOutput +from .response_function_shell_tool_call_output import ResponseFunctionShellToolCallOutput __all__ = ["ParsedResponse", "ParsedResponseOutputMessage", "ParsedResponseOutputText"] @@ -75,6 +79,10 @@ class ParsedResponseFunctionToolCall(ResponseFunctionToolCall): McpListTools, ResponseCodeInterpreterToolCall, ResponseCustomToolCall, + ResponseFunctionShellToolCall, + ResponseFunctionShellToolCallOutput, + ResponseApplyPatchToolCall, + ResponseApplyPatchToolCallOutput, ], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/responses/response.py b/src/openai/types/responses/response.py index a1133a41f5..cdd143f1cb 100644 --- a/src/openai/types/responses/response.py +++ b/src/openai/types/responses/response.py @@ -12,6 +12,7 @@ from .tool_choice_mcp import ToolChoiceMcp from ..shared.metadata import Metadata from ..shared.reasoning import Reasoning +from .tool_choice_shell import ToolChoiceShell from .tool_choice_types import ToolChoiceTypes from .tool_choice_custom import ToolChoiceCustom from .response_input_item import ResponseInputItem @@ -21,6 +22,7 @@ from .response_text_config import ResponseTextConfig from .tool_choice_function import ToolChoiceFunction from ..shared.responses_model import ResponsesModel +from .tool_choice_apply_patch import ToolChoiceApplyPatch __all__ = ["Response", "IncompleteDetails", "ToolChoice", "Conversation"] @@ -31,7 +33,14 @@ class IncompleteDetails(BaseModel): ToolChoice: TypeAlias = Union[ - ToolChoiceOptions, ToolChoiceAllowed, ToolChoiceTypes, ToolChoiceFunction, ToolChoiceMcp, ToolChoiceCustom + ToolChoiceOptions, + ToolChoiceAllowed, + ToolChoiceTypes, + ToolChoiceFunction, + ToolChoiceMcp, + ToolChoiceCustom, + ToolChoiceApplyPatch, + ToolChoiceShell, ] @@ -192,6 +201,14 @@ class Response(BaseModel): [Learn more](https://platform.openai.com/docs/guides/prompt-caching). """ + prompt_cache_retention: Optional[Literal["in-memory", "24h"]] = None + """The retention policy for the prompt cache. + + Set to `24h` to enable extended prompt caching, which keeps cached prefixes + active for longer, up to a maximum of 24 hours. + [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). + """ + reasoning: Optional[Reasoning] = None """**gpt-5 and o-series models only** diff --git a/src/openai/types/responses/response_apply_patch_tool_call.py b/src/openai/types/responses/response_apply_patch_tool_call.py new file mode 100644 index 0000000000..78eb8c8339 --- /dev/null +++ b/src/openai/types/responses/response_apply_patch_tool_call.py @@ -0,0 +1,76 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel + +__all__ = [ + "ResponseApplyPatchToolCall", + "Operation", + "OperationCreateFile", + "OperationDeleteFile", + "OperationUpdateFile", +] + + +class OperationCreateFile(BaseModel): + diff: str + """Diff to apply.""" + + path: str + """Path of the file to create.""" + + type: Literal["create_file"] + """Create a new file with the provided diff.""" + + +class OperationDeleteFile(BaseModel): + path: str + """Path of the file to delete.""" + + type: Literal["delete_file"] + """Delete the specified file.""" + + +class OperationUpdateFile(BaseModel): + diff: str + """Diff to apply.""" + + path: str + """Path of the file to update.""" + + type: Literal["update_file"] + """Update an existing file with the provided diff.""" + + +Operation: TypeAlias = Annotated[ + Union[OperationCreateFile, OperationDeleteFile, OperationUpdateFile], PropertyInfo(discriminator="type") +] + + +class ResponseApplyPatchToolCall(BaseModel): + id: str + """The unique ID of the apply patch tool call. + + Populated when this item is returned via API. + """ + + call_id: str + """The unique ID of the apply patch tool call generated by the model.""" + + status: Literal["in_progress", "completed"] + """The status of the apply patch tool call. One of `in_progress` or `completed`.""" + + type: Literal["apply_patch_call"] + """The type of the item. Always `apply_patch_call`.""" + + created_by: Optional[str] = None + """The ID of the entity that created this tool call.""" + + operation: Optional[Operation] = None + """ + One of the create_file, delete_file, or update_file operations applied via + apply_patch. + """ diff --git a/src/openai/types/responses/response_apply_patch_tool_call_output.py b/src/openai/types/responses/response_apply_patch_tool_call_output.py new file mode 100644 index 0000000000..7aee5fae9c --- /dev/null +++ b/src/openai/types/responses/response_apply_patch_tool_call_output.py @@ -0,0 +1,31 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseApplyPatchToolCallOutput"] + + +class ResponseApplyPatchToolCallOutput(BaseModel): + id: str + """The unique ID of the apply patch tool call output. + + Populated when this item is returned via API. + """ + + call_id: str + """The unique ID of the apply patch tool call generated by the model.""" + + output: Optional[str] = None + """Optional textual output returned by the apply patch tool.""" + + status: Literal["completed", "failed"] + """The status of the apply patch tool call output. One of `completed` or `failed`.""" + + type: Literal["apply_patch_call_output"] + """The type of the item. Always `apply_patch_call_output`.""" + + created_by: Optional[str] = None + """The ID of the entity that created this tool call output.""" diff --git a/src/openai/types/responses/response_create_params.py b/src/openai/types/responses/response_create_params.py index ba5c45ffee..64888ac62d 100644 --- a/src/openai/types/responses/response_create_params.py +++ b/src/openai/types/responses/response_create_params.py @@ -12,6 +12,7 @@ from .response_prompt_param import ResponsePromptParam from .tool_choice_mcp_param import ToolChoiceMcpParam from ..shared_params.metadata import Metadata +from .tool_choice_shell_param import ToolChoiceShellParam from .tool_choice_types_param import ToolChoiceTypesParam from ..shared_params.reasoning import Reasoning from .tool_choice_custom_param import ToolChoiceCustomParam @@ -19,6 +20,7 @@ from .response_text_config_param import ResponseTextConfigParam from .tool_choice_function_param import ToolChoiceFunctionParam from .response_conversation_param import ResponseConversationParam +from .tool_choice_apply_patch_param import ToolChoiceApplyPatchParam from ..shared_params.responses_model import ResponsesModel __all__ = [ @@ -146,6 +148,14 @@ class ResponseCreateParamsBase(TypedDict, total=False): [Learn more](https://platform.openai.com/docs/guides/prompt-caching). """ + prompt_cache_retention: Optional[Literal["in-memory", "24h"]] + """The retention policy for the prompt cache. + + Set to `24h` to enable extended prompt caching, which keeps cached prefixes + active for longer, up to a maximum of 24 hours. + [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). + """ + reasoning: Optional[Reasoning] """**gpt-5 and o-series models only** @@ -292,6 +302,8 @@ class StreamOptions(TypedDict, total=False): ToolChoiceFunctionParam, ToolChoiceMcpParam, ToolChoiceCustomParam, + ToolChoiceApplyPatchParam, + ToolChoiceShellParam, ] diff --git a/src/openai/types/responses/response_function_shell_call_output_content.py b/src/openai/types/responses/response_function_shell_call_output_content.py new file mode 100644 index 0000000000..1429ce9724 --- /dev/null +++ b/src/openai/types/responses/response_function_shell_call_output_content.py @@ -0,0 +1,36 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel + +__all__ = ["ResponseFunctionShellCallOutputContent", "Outcome", "OutcomeTimeout", "OutcomeExit"] + + +class OutcomeTimeout(BaseModel): + type: Literal["timeout"] + """The outcome type. Always `timeout`.""" + + +class OutcomeExit(BaseModel): + exit_code: int + """The exit code returned by the shell process.""" + + type: Literal["exit"] + """The outcome type. Always `exit`.""" + + +Outcome: TypeAlias = Annotated[Union[OutcomeTimeout, OutcomeExit], PropertyInfo(discriminator="type")] + + +class ResponseFunctionShellCallOutputContent(BaseModel): + outcome: Outcome + """The exit or timeout outcome associated with this chunk.""" + + stderr: str + """Captured stderr output for this chunk of the shell call.""" + + stdout: str + """Captured stdout output for this chunk of the shell call.""" diff --git a/src/openai/types/responses/response_function_shell_call_output_content_param.py b/src/openai/types/responses/response_function_shell_call_output_content_param.py new file mode 100644 index 0000000000..6395541cf5 --- /dev/null +++ b/src/openai/types/responses/response_function_shell_call_output_content_param.py @@ -0,0 +1,35 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +__all__ = ["ResponseFunctionShellCallOutputContentParam", "Outcome", "OutcomeTimeout", "OutcomeExit"] + + +class OutcomeTimeout(TypedDict, total=False): + type: Required[Literal["timeout"]] + """The outcome type. Always `timeout`.""" + + +class OutcomeExit(TypedDict, total=False): + exit_code: Required[int] + """The exit code returned by the shell process.""" + + type: Required[Literal["exit"]] + """The outcome type. Always `exit`.""" + + +Outcome: TypeAlias = Union[OutcomeTimeout, OutcomeExit] + + +class ResponseFunctionShellCallOutputContentParam(TypedDict, total=False): + outcome: Required[Outcome] + """The exit or timeout outcome associated with this chunk.""" + + stderr: Required[str] + """Captured stderr output for this chunk of the shell call.""" + + stdout: Required[str] + """Captured stdout output for this chunk of the shell call.""" diff --git a/src/openai/types/responses/response_function_shell_tool_call.py b/src/openai/types/responses/response_function_shell_tool_call.py new file mode 100644 index 0000000000..be0a5bcff8 --- /dev/null +++ b/src/openai/types/responses/response_function_shell_tool_call.py @@ -0,0 +1,44 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseFunctionShellToolCall", "Action"] + + +class Action(BaseModel): + commands: List[str] + + max_output_length: Optional[int] = None + """Optional maximum number of characters to return from each command.""" + + timeout_ms: Optional[int] = None + """Optional timeout in milliseconds for the commands.""" + + +class ResponseFunctionShellToolCall(BaseModel): + id: str + """The unique ID of the function shell tool call. + + Populated when this item is returned via API. + """ + + action: Action + """The shell commands and limits that describe how to run the tool call.""" + + call_id: str + """The unique ID of the function shell tool call generated by the model.""" + + status: Literal["in_progress", "completed", "incomplete"] + """The status of the shell call. + + One of `in_progress`, `completed`, or `incomplete`. + """ + + type: Literal["shell_call"] + """The type of the item. Always `shell_call`.""" + + created_by: Optional[str] = None + """The ID of the entity that created this tool call.""" diff --git a/src/openai/types/responses/response_function_shell_tool_call_output.py b/src/openai/types/responses/response_function_shell_tool_call_output.py new file mode 100644 index 0000000000..e74927df41 --- /dev/null +++ b/src/openai/types/responses/response_function_shell_tool_call_output.py @@ -0,0 +1,70 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel + +__all__ = [ + "ResponseFunctionShellToolCallOutput", + "Output", + "OutputOutcome", + "OutputOutcomeTimeout", + "OutputOutcomeExit", +] + + +class OutputOutcomeTimeout(BaseModel): + type: Literal["timeout"] + """The outcome type. Always `timeout`.""" + + +class OutputOutcomeExit(BaseModel): + exit_code: int + """Exit code from the shell process.""" + + type: Literal["exit"] + """The outcome type. Always `exit`.""" + + +OutputOutcome: TypeAlias = Annotated[Union[OutputOutcomeTimeout, OutputOutcomeExit], PropertyInfo(discriminator="type")] + + +class Output(BaseModel): + outcome: OutputOutcome + """ + Represents either an exit outcome (with an exit code) or a timeout outcome for a + shell call output chunk. + """ + + stderr: str + + stdout: str + + created_by: Optional[str] = None + + +class ResponseFunctionShellToolCallOutput(BaseModel): + id: str + """The unique ID of the shell call output. + + Populated when this item is returned via API. + """ + + call_id: str + """The unique ID of the shell tool call generated by the model.""" + + max_output_length: Optional[int] = None + """The maximum length of the shell command output. + + This is generated by the model and should be passed back with the raw output. + """ + + output: List[Output] + """An array of shell call output contents""" + + type: Literal["shell_call_output"] + """The type of the shell call output. Always `shell_call_output`.""" + + created_by: Optional[str] = None diff --git a/src/openai/types/responses/response_input_item.py b/src/openai/types/responses/response_input_item.py index 0a487b8bef..eaf5396087 100644 --- a/src/openai/types/responses/response_input_item.py +++ b/src/openai/types/responses/response_input_item.py @@ -17,6 +17,7 @@ from .response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall from .response_input_message_content_list import ResponseInputMessageContentList from .response_function_call_output_item_list import ResponseFunctionCallOutputItemList +from .response_function_shell_call_output_content import ResponseFunctionShellCallOutputContent from .response_computer_tool_call_output_screenshot import ResponseComputerToolCallOutputScreenshot __all__ = [ @@ -29,6 +30,15 @@ "LocalShellCall", "LocalShellCallAction", "LocalShellCallOutput", + "ShellCall", + "ShellCallAction", + "ShellCallOutput", + "ApplyPatchCall", + "ApplyPatchCallOperation", + "ApplyPatchCallOperationCreateFile", + "ApplyPatchCallOperationDeleteFile", + "ApplyPatchCallOperationUpdateFile", + "ApplyPatchCallOutput", "McpListTools", "McpListToolsTool", "McpApprovalRequest", @@ -186,6 +196,151 @@ class LocalShellCallOutput(BaseModel): """The status of the item. One of `in_progress`, `completed`, or `incomplete`.""" +class ShellCallAction(BaseModel): + commands: List[str] + """Ordered shell commands for the execution environment to run.""" + + max_output_length: Optional[int] = None + """ + Maximum number of UTF-8 characters to capture from combined stdout and stderr + output. + """ + + timeout_ms: Optional[int] = None + """Maximum wall-clock time in milliseconds to allow the shell commands to run.""" + + +class ShellCall(BaseModel): + action: ShellCallAction + """The shell commands and limits that describe how to run the tool call.""" + + call_id: str + """The unique ID of the function shell tool call generated by the model.""" + + type: Literal["shell_call"] + """The type of the item. Always `function_shell_call`.""" + + id: Optional[str] = None + """The unique ID of the function shell tool call. + + Populated when this item is returned via API. + """ + + status: Optional[Literal["in_progress", "completed", "incomplete"]] = None + """The status of the shell call. + + One of `in_progress`, `completed`, or `incomplete`. + """ + + +class ShellCallOutput(BaseModel): + call_id: str + """The unique ID of the function shell tool call generated by the model.""" + + output: List[ResponseFunctionShellCallOutputContent] + """ + Captured chunks of stdout and stderr output, along with their associated + outcomes. + """ + + type: Literal["shell_call_output"] + """The type of the item. Always `function_shell_call_output`.""" + + id: Optional[str] = None + """The unique ID of the function shell tool call output. + + Populated when this item is returned via API. + """ + + max_output_length: Optional[int] = None + """ + The maximum number of UTF-8 characters captured for this shell call's combined + output. + """ + + +class ApplyPatchCallOperationCreateFile(BaseModel): + diff: str + """Unified diff content to apply when creating the file.""" + + path: str + """Path of the file to create relative to the workspace root.""" + + type: Literal["create_file"] + """The operation type. Always `create_file`.""" + + +class ApplyPatchCallOperationDeleteFile(BaseModel): + path: str + """Path of the file to delete relative to the workspace root.""" + + type: Literal["delete_file"] + """The operation type. Always `delete_file`.""" + + +class ApplyPatchCallOperationUpdateFile(BaseModel): + diff: str + """Unified diff content to apply to the existing file.""" + + path: str + """Path of the file to update relative to the workspace root.""" + + type: Literal["update_file"] + """The operation type. Always `update_file`.""" + + +ApplyPatchCallOperation: TypeAlias = Annotated[ + Union[ApplyPatchCallOperationCreateFile, ApplyPatchCallOperationDeleteFile, ApplyPatchCallOperationUpdateFile], + PropertyInfo(discriminator="type"), +] + + +class ApplyPatchCall(BaseModel): + call_id: str + """The unique ID of the apply patch tool call generated by the model.""" + + operation: ApplyPatchCallOperation + """ + The specific create, delete, or update instruction for the apply_patch tool + call. + """ + + status: Literal["in_progress", "completed"] + """The status of the apply patch tool call. One of `in_progress` or `completed`.""" + + type: Literal["apply_patch_call"] + """The type of the item. Always `apply_patch_call`.""" + + id: Optional[str] = None + """The unique ID of the apply patch tool call. + + Populated when this item is returned via API. + """ + + +class ApplyPatchCallOutput(BaseModel): + call_id: str + """The unique ID of the apply patch tool call generated by the model.""" + + status: Literal["completed", "failed"] + """The status of the apply patch tool call output. One of `completed` or `failed`.""" + + type: Literal["apply_patch_call_output"] + """The type of the item. Always `apply_patch_call_output`.""" + + id: Optional[str] = None + """The unique ID of the apply patch tool call output. + + Populated when this item is returned via API. + """ + + output: Optional[str] = None + """ + Optional human-readable log text from the apply patch tool (e.g., patch results + or errors). + """ + + class McpListToolsTool(BaseModel): input_schema: object """The JSON schema describing the tool's input.""" @@ -311,6 +466,10 @@ class ItemReference(BaseModel): ResponseCodeInterpreterToolCall, LocalShellCall, LocalShellCallOutput, + ShellCall, + ShellCallOutput, + ApplyPatchCall, + ApplyPatchCallOutput, McpListTools, McpApprovalRequest, McpApprovalResponse, diff --git a/src/openai/types/responses/response_input_item_param.py b/src/openai/types/responses/response_input_item_param.py index 115147dc4b..231063cb5e 100644 --- a/src/openai/types/responses/response_input_item_param.py +++ b/src/openai/types/responses/response_input_item_param.py @@ -18,6 +18,7 @@ from .response_code_interpreter_tool_call_param import ResponseCodeInterpreterToolCallParam from .response_input_message_content_list_param import ResponseInputMessageContentListParam from .response_function_call_output_item_list_param import ResponseFunctionCallOutputItemListParam +from .response_function_shell_call_output_content_param import ResponseFunctionShellCallOutputContentParam from .response_computer_tool_call_output_screenshot_param import ResponseComputerToolCallOutputScreenshotParam __all__ = [ @@ -30,6 +31,15 @@ "LocalShellCall", "LocalShellCallAction", "LocalShellCallOutput", + "ShellCall", + "ShellCallAction", + "ShellCallOutput", + "ApplyPatchCall", + "ApplyPatchCallOperation", + "ApplyPatchCallOperationCreateFile", + "ApplyPatchCallOperationDeleteFile", + "ApplyPatchCallOperationUpdateFile", + "ApplyPatchCallOutput", "McpListTools", "McpListToolsTool", "McpApprovalRequest", @@ -187,6 +197,150 @@ class LocalShellCallOutput(TypedDict, total=False): """The status of the item. One of `in_progress`, `completed`, or `incomplete`.""" +class ShellCallAction(TypedDict, total=False): + commands: Required[SequenceNotStr[str]] + """Ordered shell commands for the execution environment to run.""" + + max_output_length: Optional[int] + """ + Maximum number of UTF-8 characters to capture from combined stdout and stderr + output. + """ + + timeout_ms: Optional[int] + """Maximum wall-clock time in milliseconds to allow the shell commands to run.""" + + +class ShellCall(TypedDict, total=False): + action: Required[ShellCallAction] + """The shell commands and limits that describe how to run the tool call.""" + + call_id: Required[str] + """The unique ID of the function shell tool call generated by the model.""" + + type: Required[Literal["shell_call"]] + """The type of the item. Always `function_shell_call`.""" + + id: Optional[str] + """The unique ID of the function shell tool call. + + Populated when this item is returned via API. + """ + + status: Optional[Literal["in_progress", "completed", "incomplete"]] + """The status of the shell call. + + One of `in_progress`, `completed`, or `incomplete`. + """ + + +class ShellCallOutput(TypedDict, total=False): + call_id: Required[str] + """The unique ID of the function shell tool call generated by the model.""" + + output: Required[Iterable[ResponseFunctionShellCallOutputContentParam]] + """ + Captured chunks of stdout and stderr output, along with their associated + outcomes. + """ + + type: Required[Literal["shell_call_output"]] + """The type of the item. Always `function_shell_call_output`.""" + + id: Optional[str] + """The unique ID of the function shell tool call output. + + Populated when this item is returned via API. + """ + + max_output_length: Optional[int] + """ + The maximum number of UTF-8 characters captured for this shell call's combined + output. + """ + + +class ApplyPatchCallOperationCreateFile(TypedDict, total=False): + diff: Required[str] + """Unified diff content to apply when creating the file.""" + + path: Required[str] + """Path of the file to create relative to the workspace root.""" + + type: Required[Literal["create_file"]] + """The operation type. Always `create_file`.""" + + +class ApplyPatchCallOperationDeleteFile(TypedDict, total=False): + path: Required[str] + """Path of the file to delete relative to the workspace root.""" + + type: Required[Literal["delete_file"]] + """The operation type. Always `delete_file`.""" + + +class ApplyPatchCallOperationUpdateFile(TypedDict, total=False): + diff: Required[str] + """Unified diff content to apply to the existing file.""" + + path: Required[str] + """Path of the file to update relative to the workspace root.""" + + type: Required[Literal["update_file"]] + """The operation type. Always `update_file`.""" + + +ApplyPatchCallOperation: TypeAlias = Union[ + ApplyPatchCallOperationCreateFile, ApplyPatchCallOperationDeleteFile, ApplyPatchCallOperationUpdateFile +] + + +class ApplyPatchCall(TypedDict, total=False): + call_id: Required[str] + """The unique ID of the apply patch tool call generated by the model.""" + + operation: Required[ApplyPatchCallOperation] + """ + The specific create, delete, or update instruction for the apply_patch tool + call. + """ + + status: Required[Literal["in_progress", "completed"]] + """The status of the apply patch tool call. One of `in_progress` or `completed`.""" + + type: Required[Literal["apply_patch_call"]] + """The type of the item. Always `apply_patch_call`.""" + + id: Optional[str] + """The unique ID of the apply patch tool call. + + Populated when this item is returned via API. + """ + + +class ApplyPatchCallOutput(TypedDict, total=False): + call_id: Required[str] + """The unique ID of the apply patch tool call generated by the model.""" + + status: Required[Literal["completed", "failed"]] + """The status of the apply patch tool call output. One of `completed` or `failed`.""" + + type: Required[Literal["apply_patch_call_output"]] + """The type of the item. Always `apply_patch_call_output`.""" + + id: Optional[str] + """The unique ID of the apply patch tool call output. + + Populated when this item is returned via API. + """ + + output: str + """ + Optional human-readable log text from the apply patch tool (e.g., patch results + or errors). + """ + + class McpListToolsTool(TypedDict, total=False): input_schema: Required[object] """The JSON schema describing the tool's input.""" @@ -311,6 +465,10 @@ class ItemReference(TypedDict, total=False): ResponseCodeInterpreterToolCallParam, LocalShellCall, LocalShellCallOutput, + ShellCall, + ShellCallOutput, + ApplyPatchCall, + ApplyPatchCallOutput, McpListTools, McpApprovalRequest, McpApprovalResponse, diff --git a/src/openai/types/responses/response_input_param.py b/src/openai/types/responses/response_input_param.py index 9a999c7252..15d9480eaf 100644 --- a/src/openai/types/responses/response_input_param.py +++ b/src/openai/types/responses/response_input_param.py @@ -18,6 +18,7 @@ from .response_code_interpreter_tool_call_param import ResponseCodeInterpreterToolCallParam from .response_input_message_content_list_param import ResponseInputMessageContentListParam from .response_function_call_output_item_list_param import ResponseFunctionCallOutputItemListParam +from .response_function_shell_call_output_content_param import ResponseFunctionShellCallOutputContentParam from .response_computer_tool_call_output_screenshot_param import ResponseComputerToolCallOutputScreenshotParam __all__ = [ @@ -31,6 +32,15 @@ "LocalShellCall", "LocalShellCallAction", "LocalShellCallOutput", + "ShellCall", + "ShellCallAction", + "ShellCallOutput", + "ApplyPatchCall", + "ApplyPatchCallOperation", + "ApplyPatchCallOperationCreateFile", + "ApplyPatchCallOperationDeleteFile", + "ApplyPatchCallOperationUpdateFile", + "ApplyPatchCallOutput", "McpListTools", "McpListToolsTool", "McpApprovalRequest", @@ -188,6 +198,150 @@ class LocalShellCallOutput(TypedDict, total=False): """The status of the item. One of `in_progress`, `completed`, or `incomplete`.""" +class ShellCallAction(TypedDict, total=False): + commands: Required[SequenceNotStr[str]] + """Ordered shell commands for the execution environment to run.""" + + max_output_length: Optional[int] + """ + Maximum number of UTF-8 characters to capture from combined stdout and stderr + output. + """ + + timeout_ms: Optional[int] + """Maximum wall-clock time in milliseconds to allow the shell commands to run.""" + + +class ShellCall(TypedDict, total=False): + action: Required[ShellCallAction] + """The shell commands and limits that describe how to run the tool call.""" + + call_id: Required[str] + """The unique ID of the function shell tool call generated by the model.""" + + type: Required[Literal["shell_call"]] + """The type of the item. Always `function_shell_call`.""" + + id: Optional[str] + """The unique ID of the function shell tool call. + + Populated when this item is returned via API. + """ + + status: Optional[Literal["in_progress", "completed", "incomplete"]] + """The status of the shell call. + + One of `in_progress`, `completed`, or `incomplete`. + """ + + +class ShellCallOutput(TypedDict, total=False): + call_id: Required[str] + """The unique ID of the function shell tool call generated by the model.""" + + output: Required[Iterable[ResponseFunctionShellCallOutputContentParam]] + """ + Captured chunks of stdout and stderr output, along with their associated + outcomes. + """ + + type: Required[Literal["shell_call_output"]] + """The type of the item. Always `function_shell_call_output`.""" + + id: Optional[str] + """The unique ID of the function shell tool call output. + + Populated when this item is returned via API. + """ + + max_output_length: Optional[int] + """ + The maximum number of UTF-8 characters captured for this shell call's combined + output. + """ + + +class ApplyPatchCallOperationCreateFile(TypedDict, total=False): + diff: Required[str] + """Unified diff content to apply when creating the file.""" + + path: Required[str] + """Path of the file to create relative to the workspace root.""" + + type: Required[Literal["create_file"]] + """The operation type. Always `create_file`.""" + + +class ApplyPatchCallOperationDeleteFile(TypedDict, total=False): + path: Required[str] + """Path of the file to delete relative to the workspace root.""" + + type: Required[Literal["delete_file"]] + """The operation type. Always `delete_file`.""" + + +class ApplyPatchCallOperationUpdateFile(TypedDict, total=False): + diff: Required[str] + """Unified diff content to apply to the existing file.""" + + path: Required[str] + """Path of the file to update relative to the workspace root.""" + + type: Required[Literal["update_file"]] + """The operation type. Always `update_file`.""" + + +ApplyPatchCallOperation: TypeAlias = Union[ + ApplyPatchCallOperationCreateFile, ApplyPatchCallOperationDeleteFile, ApplyPatchCallOperationUpdateFile +] + + +class ApplyPatchCall(TypedDict, total=False): + call_id: Required[str] + """The unique ID of the apply patch tool call generated by the model.""" + + operation: Required[ApplyPatchCallOperation] + """ + The specific create, delete, or update instruction for the apply_patch tool + call. + """ + + status: Required[Literal["in_progress", "completed"]] + """The status of the apply patch tool call. One of `in_progress` or `completed`.""" + + type: Required[Literal["apply_patch_call"]] + """The type of the item. Always `apply_patch_call`.""" + + id: Optional[str] + """The unique ID of the apply patch tool call. + + Populated when this item is returned via API. + """ + + +class ApplyPatchCallOutput(TypedDict, total=False): + call_id: Required[str] + """The unique ID of the apply patch tool call generated by the model.""" + + status: Required[Literal["completed", "failed"]] + """The status of the apply patch tool call output. One of `completed` or `failed`.""" + + type: Required[Literal["apply_patch_call_output"]] + """The type of the item. Always `apply_patch_call_output`.""" + + id: Optional[str] + """The unique ID of the apply patch tool call output. + + Populated when this item is returned via API. + """ + + output: str + """ + Optional human-readable log text from the apply patch tool (e.g., patch results + or errors). + """ + + class McpListToolsTool(TypedDict, total=False): input_schema: Required[object] """The JSON schema describing the tool's input.""" @@ -312,6 +466,10 @@ class ItemReference(TypedDict, total=False): ResponseCodeInterpreterToolCallParam, LocalShellCall, LocalShellCallOutput, + ShellCall, + ShellCallOutput, + ApplyPatchCall, + ApplyPatchCallOutput, McpListTools, McpApprovalRequest, McpApprovalResponse, diff --git a/src/openai/types/responses/response_item.py b/src/openai/types/responses/response_item.py index bdd2523baf..5ae2405988 100644 --- a/src/openai/types/responses/response_item.py +++ b/src/openai/types/responses/response_item.py @@ -9,11 +9,15 @@ from .response_computer_tool_call import ResponseComputerToolCall from .response_input_message_item import ResponseInputMessageItem from .response_function_web_search import ResponseFunctionWebSearch +from .response_apply_patch_tool_call import ResponseApplyPatchToolCall from .response_file_search_tool_call import ResponseFileSearchToolCall from .response_function_tool_call_item import ResponseFunctionToolCallItem +from .response_function_shell_tool_call import ResponseFunctionShellToolCall from .response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall +from .response_apply_patch_tool_call_output import ResponseApplyPatchToolCallOutput from .response_computer_tool_call_output_item import ResponseComputerToolCallOutputItem from .response_function_tool_call_output_item import ResponseFunctionToolCallOutputItem +from .response_function_shell_tool_call_output import ResponseFunctionShellToolCallOutput __all__ = [ "ResponseItem", @@ -209,6 +213,10 @@ class McpCall(BaseModel): ResponseCodeInterpreterToolCall, LocalShellCall, LocalShellCallOutput, + ResponseFunctionShellToolCall, + ResponseFunctionShellToolCallOutput, + ResponseApplyPatchToolCall, + ResponseApplyPatchToolCallOutput, McpListTools, McpApprovalRequest, McpApprovalResponse, diff --git a/src/openai/types/responses/response_output_item.py b/src/openai/types/responses/response_output_item.py index e33d59cefe..906ddbb25e 100644 --- a/src/openai/types/responses/response_output_item.py +++ b/src/openai/types/responses/response_output_item.py @@ -11,8 +11,12 @@ from .response_computer_tool_call import ResponseComputerToolCall from .response_function_tool_call import ResponseFunctionToolCall from .response_function_web_search import ResponseFunctionWebSearch +from .response_apply_patch_tool_call import ResponseApplyPatchToolCall from .response_file_search_tool_call import ResponseFileSearchToolCall +from .response_function_shell_tool_call import ResponseFunctionShellToolCall from .response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall +from .response_apply_patch_tool_call_output import ResponseApplyPatchToolCallOutput +from .response_function_shell_tool_call_output import ResponseFunctionShellToolCallOutput __all__ = [ "ResponseOutputItem", @@ -172,6 +176,10 @@ class McpApprovalRequest(BaseModel): ImageGenerationCall, ResponseCodeInterpreterToolCall, LocalShellCall, + ResponseFunctionShellToolCall, + ResponseFunctionShellToolCallOutput, + ResponseApplyPatchToolCall, + ResponseApplyPatchToolCallOutput, McpCall, McpListTools, McpApprovalRequest, diff --git a/src/openai/types/responses/tool.py b/src/openai/types/responses/tool.py index b29fede0c9..ae8b34b1f4 100644 --- a/src/openai/types/responses/tool.py +++ b/src/openai/types/responses/tool.py @@ -10,7 +10,9 @@ from .computer_tool import ComputerTool from .function_tool import FunctionTool from .web_search_tool import WebSearchTool +from .apply_patch_tool import ApplyPatchTool from .file_search_tool import FileSearchTool +from .function_shell_tool import FunctionShellTool from .web_search_preview_tool import WebSearchPreviewTool __all__ = [ @@ -260,8 +262,10 @@ class LocalShell(BaseModel): CodeInterpreter, ImageGeneration, LocalShell, + FunctionShellTool, CustomTool, WebSearchPreviewTool, + ApplyPatchTool, ], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/responses/tool_choice_apply_patch.py b/src/openai/types/responses/tool_choice_apply_patch.py new file mode 100644 index 0000000000..7f815aa1a1 --- /dev/null +++ b/src/openai/types/responses/tool_choice_apply_patch.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ToolChoiceApplyPatch"] + + +class ToolChoiceApplyPatch(BaseModel): + type: Literal["apply_patch"] + """The tool to call. Always `apply_patch`.""" diff --git a/src/openai/types/responses/tool_choice_apply_patch_param.py b/src/openai/types/responses/tool_choice_apply_patch_param.py new file mode 100644 index 0000000000..00d4b25f0e --- /dev/null +++ b/src/openai/types/responses/tool_choice_apply_patch_param.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ToolChoiceApplyPatchParam"] + + +class ToolChoiceApplyPatchParam(TypedDict, total=False): + type: Required[Literal["apply_patch"]] + """The tool to call. Always `apply_patch`.""" diff --git a/src/openai/types/responses/tool_choice_shell.py b/src/openai/types/responses/tool_choice_shell.py new file mode 100644 index 0000000000..1ad21c58f3 --- /dev/null +++ b/src/openai/types/responses/tool_choice_shell.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ToolChoiceShell"] + + +class ToolChoiceShell(BaseModel): + type: Literal["shell"] + """The tool to call. Always `shell`.""" diff --git a/src/openai/types/responses/tool_choice_shell_param.py b/src/openai/types/responses/tool_choice_shell_param.py new file mode 100644 index 0000000000..2b04c00d56 --- /dev/null +++ b/src/openai/types/responses/tool_choice_shell_param.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ToolChoiceShellParam"] + + +class ToolChoiceShellParam(TypedDict, total=False): + type: Required[Literal["shell"]] + """The tool to call. Always `shell`.""" diff --git a/src/openai/types/responses/tool_param.py b/src/openai/types/responses/tool_param.py index dd1ea0bd54..18b044ab8c 100644 --- a/src/openai/types/responses/tool_param.py +++ b/src/openai/types/responses/tool_param.py @@ -12,7 +12,9 @@ from .computer_tool_param import ComputerToolParam from .function_tool_param import FunctionToolParam from .web_search_tool_param import WebSearchToolParam +from .apply_patch_tool_param import ApplyPatchToolParam from .file_search_tool_param import FileSearchToolParam +from .function_shell_tool_param import FunctionShellToolParam from .web_search_preview_tool_param import WebSearchPreviewToolParam __all__ = [ @@ -259,8 +261,10 @@ class LocalShell(TypedDict, total=False): CodeInterpreter, ImageGeneration, LocalShell, + FunctionShellToolParam, CustomToolParam, WebSearchPreviewToolParam, + ApplyPatchToolParam, ] diff --git a/src/openai/types/shared/chat_model.py b/src/openai/types/shared/chat_model.py index 727c60c1c0..b3ae7c3a95 100644 --- a/src/openai/types/shared/chat_model.py +++ b/src/openai/types/shared/chat_model.py @@ -5,6 +5,11 @@ __all__ = ["ChatModel"] ChatModel: TypeAlias = Literal[ + "gpt-5.1", + "gpt-5.1-2025-11-13", + "gpt-5.1-codex", + "gpt-5.1-mini", + "gpt-5.1-chat-latest", "gpt-5", "gpt-5-mini", "gpt-5-nano", diff --git a/src/openai/types/shared/reasoning.py b/src/openai/types/shared/reasoning.py index 6ea2fe82bf..cf470ca057 100644 --- a/src/openai/types/shared/reasoning.py +++ b/src/openai/types/shared/reasoning.py @@ -14,12 +14,16 @@ class Reasoning(BaseModel): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. - - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. + + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. """ generate_summary: Optional[Literal["auto", "concise", "detailed"]] = None diff --git a/src/openai/types/shared/reasoning_effort.py b/src/openai/types/shared/reasoning_effort.py index 4b960cd7e6..c890a133cc 100644 --- a/src/openai/types/shared/reasoning_effort.py +++ b/src/openai/types/shared/reasoning_effort.py @@ -5,4 +5,4 @@ __all__ = ["ReasoningEffort"] -ReasoningEffort: TypeAlias = Optional[Literal["minimal", "low", "medium", "high"]] +ReasoningEffort: TypeAlias = Optional[Literal["none", "minimal", "low", "medium", "high"]] diff --git a/src/openai/types/shared_params/chat_model.py b/src/openai/types/shared_params/chat_model.py index a1e5ab9f30..7505d51d67 100644 --- a/src/openai/types/shared_params/chat_model.py +++ b/src/openai/types/shared_params/chat_model.py @@ -7,6 +7,11 @@ __all__ = ["ChatModel"] ChatModel: TypeAlias = Literal[ + "gpt-5.1", + "gpt-5.1-2025-11-13", + "gpt-5.1-codex", + "gpt-5.1-mini", + "gpt-5.1-chat-latest", "gpt-5", "gpt-5-mini", "gpt-5-nano", diff --git a/src/openai/types/shared_params/reasoning.py b/src/openai/types/shared_params/reasoning.py index 5c1eff683f..ad58f70b71 100644 --- a/src/openai/types/shared_params/reasoning.py +++ b/src/openai/types/shared_params/reasoning.py @@ -15,12 +15,16 @@ class Reasoning(TypedDict, total=False): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `minimal`, `low`, `medium`, and `high`. Reducing reasoning - effort can result in faster responses and fewer tokens used on reasoning in a - response. - - Note: The `gpt-5-pro` model defaults to (and only supports) `high` reasoning - effort. + supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing + reasoning effort can result in faster responses and fewer tokens used on + reasoning in a response. + + - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported + reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool + calls are supported for all reasoning values in gpt-5.1. + - All models before `gpt-5.1` default to `medium` reasoning effort, and do not + support `none`. + - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. """ generate_summary: Optional[Literal["auto", "concise", "detailed"]] diff --git a/src/openai/types/shared_params/reasoning_effort.py b/src/openai/types/shared_params/reasoning_effort.py index 4c095a28d7..e388eebff1 100644 --- a/src/openai/types/shared_params/reasoning_effort.py +++ b/src/openai/types/shared_params/reasoning_effort.py @@ -7,4 +7,4 @@ __all__ = ["ReasoningEffort"] -ReasoningEffort: TypeAlias = Optional[Literal["minimal", "low", "medium", "high"]] +ReasoningEffort: TypeAlias = Optional[Literal["none", "minimal", "low", "medium", "high"]] diff --git a/tests/api_resources/beta/test_assistants.py b/tests/api_resources/beta/test_assistants.py index 875e024a51..2557735426 100644 --- a/tests/api_resources/beta/test_assistants.py +++ b/tests/api_resources/beta/test_assistants.py @@ -36,7 +36,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: instructions="instructions", metadata={"foo": "string"}, name="name", - reasoning_effort="minimal", + reasoning_effort="none", response_format="auto", temperature=1, tool_resources={ @@ -135,7 +135,7 @@ def test_method_update_with_all_params(self, client: OpenAI) -> None: metadata={"foo": "string"}, model="string", name="name", - reasoning_effort="minimal", + reasoning_effort="none", response_format="auto", temperature=1, tool_resources={ @@ -272,7 +272,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> instructions="instructions", metadata={"foo": "string"}, name="name", - reasoning_effort="minimal", + reasoning_effort="none", response_format="auto", temperature=1, tool_resources={ @@ -371,7 +371,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncOpenAI) -> metadata={"foo": "string"}, model="string", name="name", - reasoning_effort="minimal", + reasoning_effort="none", 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 440486bac5..3a6b36864d 100644 --- a/tests/api_resources/beta/threads/test_runs.py +++ b/tests/api_resources/beta/threads/test_runs.py @@ -59,7 +59,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: metadata={"foo": "string"}, model="string", parallel_tool_calls=True, - reasoning_effort="minimal", + reasoning_effort="none", response_format="auto", stream=False, temperature=1, @@ -150,7 +150,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: metadata={"foo": "string"}, model="string", parallel_tool_calls=True, - reasoning_effort="minimal", + reasoning_effort="none", response_format="auto", temperature=1, tool_choice="none", @@ -609,7 +609,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn metadata={"foo": "string"}, model="string", parallel_tool_calls=True, - reasoning_effort="minimal", + reasoning_effort="none", response_format="auto", stream=False, temperature=1, @@ -700,7 +700,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn metadata={"foo": "string"}, model="string", parallel_tool_calls=True, - reasoning_effort="minimal", + reasoning_effort="none", response_format="auto", temperature=1, tool_choice="none", diff --git a/tests/api_resources/chat/test_completions.py b/tests/api_resources/chat/test_completions.py index 358ea18cbb..2b58ff8191 100644 --- a/tests/api_resources/chat/test_completions.py +++ b/tests/api_resources/chat/test_completions.py @@ -73,7 +73,8 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: }, presence_penalty=-2, prompt_cache_key="prompt-cache-key-1234", - reasoning_effort="minimal", + prompt_cache_retention="in-memory", + reasoning_effort="none", response_format={"type": "text"}, safety_identifier="safety-identifier-1234", seed=-9007199254740991, @@ -206,7 +207,8 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: }, presence_penalty=-2, prompt_cache_key="prompt-cache-key-1234", - reasoning_effort="minimal", + prompt_cache_retention="in-memory", + reasoning_effort="none", response_format={"type": "text"}, safety_identifier="safety-identifier-1234", seed=-9007199254740991, @@ -514,7 +516,8 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn }, presence_penalty=-2, prompt_cache_key="prompt-cache-key-1234", - reasoning_effort="minimal", + prompt_cache_retention="in-memory", + reasoning_effort="none", response_format={"type": "text"}, safety_identifier="safety-identifier-1234", seed=-9007199254740991, @@ -647,7 +650,8 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn }, presence_penalty=-2, prompt_cache_key="prompt-cache-key-1234", - reasoning_effort="minimal", + prompt_cache_retention="in-memory", + reasoning_effort="none", response_format={"type": "text"}, safety_identifier="safety-identifier-1234", seed=-9007199254740991, diff --git a/tests/api_resources/responses/test_input_tokens.py b/tests/api_resources/responses/test_input_tokens.py index 54ba2d25c2..d9aecc33bd 100644 --- a/tests/api_resources/responses/test_input_tokens.py +++ b/tests/api_resources/responses/test_input_tokens.py @@ -32,7 +32,7 @@ def test_method_count_with_all_params(self, client: OpenAI) -> None: parallel_tool_calls=True, previous_response_id="resp_123", reasoning={ - "effort": "minimal", + "effort": "none", "generate_summary": "auto", "summary": "auto", }, @@ -95,7 +95,7 @@ async def test_method_count_with_all_params(self, async_client: AsyncOpenAI) -> parallel_tool_calls=True, previous_response_id="resp_123", reasoning={ - "effort": "minimal", + "effort": "none", "generate_summary": "auto", "summary": "auto", }, diff --git a/tests/api_resources/test_responses.py b/tests/api_resources/test_responses.py index a329aa4d9e..b57e6099c4 100644 --- a/tests/api_resources/test_responses.py +++ b/tests/api_resources/test_responses.py @@ -45,8 +45,9 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: "version": "version", }, prompt_cache_key="prompt-cache-key-1234", + prompt_cache_retention="in-memory", reasoning={ - "effort": "minimal", + "effort": "none", "generate_summary": "auto", "summary": "auto", }, @@ -125,8 +126,9 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: "version": "version", }, prompt_cache_key="prompt-cache-key-1234", + prompt_cache_retention="in-memory", reasoning={ - "effort": "minimal", + "effort": "none", "generate_summary": "auto", "summary": "auto", }, @@ -398,8 +400,9 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn "version": "version", }, prompt_cache_key="prompt-cache-key-1234", + prompt_cache_retention="in-memory", reasoning={ - "effort": "minimal", + "effort": "none", "generate_summary": "auto", "summary": "auto", }, @@ -478,8 +481,9 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn "version": "version", }, prompt_cache_key="prompt-cache-key-1234", + prompt_cache_retention="in-memory", reasoning={ - "effort": "minimal", + "effort": "none", "generate_summary": "auto", "summary": "auto", }, From 9b8c7e3e84e3e7bb8b0d88bb7d0538c39bb47a40 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 13 Nov 2025 18:11:54 +0000 Subject: [PATCH 551/769] release: 2.8.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index e3ec769daf..64f9ff4148 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.7.2" + ".": "2.8.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 03dfa94242..5d49a82e5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 2.8.0 (2025-11-13) + +Full Changelog: [v2.7.2...v2.8.0](https://github.com/openai/openai-python/compare/v2.7.2...v2.8.0) + +### Features + +* **api:** gpt 5.1 ([8d9f2ca](https://github.com/openai/openai-python/commit/8d9f2cab4cb2e12f6e2ab1de967f858736a656ac)) + + +### Bug Fixes + +* **compat:** update signatures of `model_dump` and `model_dump_json` for Pydantic v1 ([c7bd234](https://github.com/openai/openai-python/commit/c7bd234b18239fcdbf0edb1b51ca9116c0ac7251)) + ## 2.7.2 (2025-11-10) Full Changelog: [v2.7.1...v2.7.2](https://github.com/openai/openai-python/compare/v2.7.1...v2.7.2) diff --git a/pyproject.toml b/pyproject.toml index ca13765a98..0c4d4b62a7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.7.2" +version = "2.8.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 6c0fcb3469..63e309efdd 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__ = "2.7.2" # x-release-please-version +__version__ = "2.8.0" # x-release-please-version From f0f0ccce35d0f7eccca7f85539a5a23db1e4ec1c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 17 Nov 2025 21:19:50 +0000 Subject: [PATCH 552/769] fix(api): align types of input items / output items for typescript --- .stats.yml | 4 ++-- .../responses/response_apply_patch_tool_call.py | 12 ++++++------ .../response_apply_patch_tool_call_output.py | 6 +++--- .../types/responses/response_input_item_param.py | 2 +- src/openai/types/responses/response_input_param.py | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.stats.yml b/.stats.yml index b44bda286e..fe1a09be6b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 136 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-ca24bc4d8125b5153514ce643c4e3220f25971b7d67ca384d56d493c72c0d977.yml -openapi_spec_hash: c6f048c7b3d29f4de48fde0e845ba33f +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-a7e92d12ebe89ca019a7ac5b29759064eefa2c38fe08d03516f2620e66abb32b.yml +openapi_spec_hash: acbc703b2739447abc6312b2d753631c config_hash: b876221dfb213df9f0a999e75d38a65e diff --git a/src/openai/types/responses/response_apply_patch_tool_call.py b/src/openai/types/responses/response_apply_patch_tool_call.py index 78eb8c8339..7dc2a3c2b5 100644 --- a/src/openai/types/responses/response_apply_patch_tool_call.py +++ b/src/openai/types/responses/response_apply_patch_tool_call.py @@ -60,6 +60,12 @@ class ResponseApplyPatchToolCall(BaseModel): call_id: str """The unique ID of the apply patch tool call generated by the model.""" + operation: Operation + """ + One of the create_file, delete_file, or update_file operations applied via + apply_patch. + """ + status: Literal["in_progress", "completed"] """The status of the apply patch tool call. One of `in_progress` or `completed`.""" @@ -68,9 +74,3 @@ class ResponseApplyPatchToolCall(BaseModel): created_by: Optional[str] = None """The ID of the entity that created this tool call.""" - - operation: Optional[Operation] = None - """ - One of the create_file, delete_file, or update_file operations applied via - apply_patch. - """ diff --git a/src/openai/types/responses/response_apply_patch_tool_call_output.py b/src/openai/types/responses/response_apply_patch_tool_call_output.py index 7aee5fae9c..cf0bcfeecc 100644 --- a/src/openai/types/responses/response_apply_patch_tool_call_output.py +++ b/src/openai/types/responses/response_apply_patch_tool_call_output.py @@ -18,9 +18,6 @@ class ResponseApplyPatchToolCallOutput(BaseModel): call_id: str """The unique ID of the apply patch tool call generated by the model.""" - output: Optional[str] = None - """Optional textual output returned by the apply patch tool.""" - status: Literal["completed", "failed"] """The status of the apply patch tool call output. One of `completed` or `failed`.""" @@ -29,3 +26,6 @@ class ResponseApplyPatchToolCallOutput(BaseModel): created_by: Optional[str] = None """The ID of the entity that created this tool call output.""" + + output: Optional[str] = None + """Optional textual output returned by the apply patch tool.""" diff --git a/src/openai/types/responses/response_input_item_param.py b/src/openai/types/responses/response_input_item_param.py index 231063cb5e..5c2e81c4de 100644 --- a/src/openai/types/responses/response_input_item_param.py +++ b/src/openai/types/responses/response_input_item_param.py @@ -334,7 +334,7 @@ class ApplyPatchCallOutput(TypedDict, total=False): Populated when this item is returned via API. """ - output: str + output: Optional[str] """ Optional human-readable log text from the apply patch tool (e.g., patch results or errors). diff --git a/src/openai/types/responses/response_input_param.py b/src/openai/types/responses/response_input_param.py index 15d9480eaf..365c6b3d7b 100644 --- a/src/openai/types/responses/response_input_param.py +++ b/src/openai/types/responses/response_input_param.py @@ -335,7 +335,7 @@ class ApplyPatchCallOutput(TypedDict, total=False): Populated when this item is returned via API. """ - output: str + output: Optional[str] """ Optional human-readable log text from the apply patch tool (e.g., patch results or errors). From 41ee03ffe985a7362f0275c7f500080cb1d58cdd Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 17 Nov 2025 21:20:21 +0000 Subject: [PATCH 553/769] release: 2.8.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 64f9ff4148..108509ed29 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.8.0" + ".": "2.8.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d49a82e5c..1bfa59348f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 2.8.1 (2025-11-17) + +Full Changelog: [v2.8.0...v2.8.1](https://github.com/openai/openai-python/compare/v2.8.0...v2.8.1) + +### Bug Fixes + +* **api:** align types of input items / output items for typescript ([64c9fb3](https://github.com/openai/openai-python/commit/64c9fb3fcc79f0049b3a36bd429faf0600d969f6)) + ## 2.8.0 (2025-11-13) Full Changelog: [v2.7.2...v2.8.0](https://github.com/openai/openai-python/compare/v2.7.2...v2.8.0) diff --git a/pyproject.toml b/pyproject.toml index 0c4d4b62a7..75118d46be 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.8.0" +version = "2.8.1" 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 63e309efdd..6109cebf91 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__ = "2.8.0" # x-release-please-version +__version__ = "2.8.1" # x-release-please-version From df4109a62b95c8e7ff5ab8d9d03294c738a4ccc0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 21 Nov 2025 23:26:30 +0000 Subject: [PATCH 554/769] chore(internal): codegen related update --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 75118d46be..7a05625aa6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,6 +26,7 @@ classifiers = [ "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Operating System :: OS Independent", "Operating System :: POSIX", "Operating System :: MacOS", From fc4825045e8c95cdd73b5acff6d7b7db7abd19f8 Mon Sep 17 00:00:00 2001 From: peter-zhong-replit Date: Mon, 1 Dec 2025 05:13:27 -0800 Subject: [PATCH 555/769] fix(client): avoid mutating user-provided response config object (#2700) --- src/openai/resources/responses/responses.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index dcf87ba07c..8365b808ae 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -2,6 +2,7 @@ from __future__ import annotations +from copy import copy from typing import Any, List, Type, Union, Iterable, Optional, cast from functools import partial from typing_extensions import Literal, overload @@ -1046,6 +1047,7 @@ def stream( if "format" in text: raise TypeError("Cannot mix and match text.format with text_format") + text = copy(text) text["format"] = _type_to_text_format_param(text_format) api_request: partial[Stream[ResponseStreamEvent]] = partial( @@ -1151,7 +1153,7 @@ def parse( if "format" in text: raise TypeError("Cannot mix and match text.format with text_format") - + text = copy(text) text["format"] = _type_to_text_format_param(text_format) tools = _make_tools(tools) @@ -2507,7 +2509,7 @@ def stream( if "format" in text: raise TypeError("Cannot mix and match text.format with text_format") - + text = copy(text) text["format"] = _type_to_text_format_param(text_format) api_request = self.create( @@ -2617,7 +2619,7 @@ async def parse( if "format" in text: raise TypeError("Cannot mix and match text.format with text_format") - + text = copy(text) text["format"] = _type_to_text_format_param(text_format) tools = _make_tools(tools) From f6552d762e3aec145c49428913a1b9333e4b6be3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 1 Dec 2025 16:56:43 +0000 Subject: [PATCH 556/769] fix: ensure streams are always closed --- src/openai/_streaming.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/openai/_streaming.py b/src/openai/_streaming.py index 05c284a2be..74e54f74fa 100644 --- a/src/openai/_streaming.py +++ b/src/openai/_streaming.py @@ -55,9 +55,10 @@ def __stream__(self) -> Iterator[_T]: process_data = self._client._process_response_data iterator = self._iter_events() - for sse in iterator: - if sse.data.startswith("[DONE]"): - break + try: + for sse in iterator: + if sse.data.startswith("[DONE]"): + break # we have to special case the Assistants `thread.` events since we won't have an "event" key in the data if sse.event and sse.event.startswith("thread."): @@ -96,8 +97,9 @@ def __stream__(self) -> Iterator[_T]: yield process_data(data=data, cast_to=cast_to, response=response) - # As we might not fully consume the response stream, we need to close it explicitly - response.close() + finally: + # Ensure the response is closed even if the consumer doesn't read all data + response.close() def __enter__(self) -> Self: return self @@ -156,9 +158,10 @@ async def __stream__(self) -> AsyncIterator[_T]: process_data = self._client._process_response_data iterator = self._iter_events() - async for sse in iterator: - if sse.data.startswith("[DONE]"): - break + try: + async for sse in iterator: + if sse.data.startswith("[DONE]"): + break # we have to special case the Assistants `thread.` events since we won't have an "event" key in the data if sse.event and sse.event.startswith("thread."): @@ -197,8 +200,9 @@ async def __stream__(self) -> AsyncIterator[_T]: yield process_data(data=data, cast_to=cast_to, response=response) - # As we might not fully consume the response stream, we need to close it explicitly - await response.aclose() + finally: + # Ensure the response is closed even if the consumer doesn't read all data + await response.aclose() async def __aenter__(self) -> Self: return self From 1e7eae9e766c7479507469d7ebaabba13a4fcad5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 1 Dec 2025 17:01:53 +0000 Subject: [PATCH 557/769] chore(deps): mypy 1.18.1 has a regression, pin to 1.17 --- pyproject.toml | 2 +- requirements-dev.lock | 4 +++- requirements.lock | 9 +++++---- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 7a05625aa6..4130dba20a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,7 +54,7 @@ managed = true # version pins are in requirements-dev.lock dev-dependencies = [ "pyright==1.1.399", - "mypy", + "mypy==1.17", "respx", "pytest", "pytest-asyncio", diff --git a/requirements-dev.lock b/requirements-dev.lock index b454537b96..07443f2dae 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -105,7 +105,7 @@ msal-extensions==1.2.0 multidict==6.5.0 # via aiohttp # via yarl -mypy==1.14.1 +mypy==1.17.0 mypy-extensions==1.0.0 # via mypy nest-asyncio==1.6.0 @@ -125,6 +125,8 @@ pandas==2.2.3 # via openai pandas-stubs==2.1.4.231227 # via openai +pathspec==0.12.1 + # via mypy platformdirs==3.11.0 # via virtualenv pluggy==1.5.0 diff --git a/requirements.lock b/requirements.lock index b047cb3f88..386ec3c590 100644 --- a/requirements.lock +++ b/requirements.lock @@ -69,9 +69,9 @@ propcache==0.3.2 # via yarl pycparser==2.23 # via cffi -pydantic==2.11.9 +pydantic==2.12.5 # via openai -pydantic-core==2.33.2 +pydantic-core==2.41.5 # via pydantic python-dateutil==2.9.0.post0 # via pandas @@ -88,13 +88,14 @@ tqdm==4.66.5 # via openai types-pytz==2024.2.0.20241003 # via pandas-stubs -typing-extensions==4.12.2 +typing-extensions==4.15.0 + # via anyio # via multidict # via openai # via pydantic # via pydantic-core # via typing-inspection -typing-inspection==0.4.1 +typing-inspection==0.4.2 # via pydantic tzdata==2025.2 # via pandas From c3c607a2e2abc572bde6220e71921bf8a55949ab Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 2 Dec 2025 11:05:28 +0000 Subject: [PATCH 558/769] chore: update lockfile --- pyproject.toml | 12 +-- requirements-dev.lock | 165 ++++++++++++++++++++++-------------------- requirements.lock | 47 ++++++------ 3 files changed, 119 insertions(+), 105 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 4130dba20a..3ad3b4a58a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,16 +7,18 @@ license = "Apache-2.0" authors = [ { name = "OpenAI", email = "support@openai.com" }, ] + dependencies = [ - "httpx>=0.23.0, <1", - "pydantic>=1.9.0, <3", + "httpx>=0.23.0, <1", + "pydantic>=1.9.0, <3", "typing-extensions>=4.11, <5", - "anyio>=3.5.0, <5", - "distro>=1.7.0, <2", - "sniffio", + "anyio>=3.5.0, <5", + "distro>=1.7.0, <2", + "sniffio", "tqdm > 4", "jiter>=0.10.0, <1", ] + requires-python = ">= 3.9" classifiers = [ "Typing :: Typed", diff --git a/requirements-dev.lock b/requirements-dev.lock index 07443f2dae..a7201a127b 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -12,65 +12,70 @@ -e file:. aiohappyeyeballs==2.6.1 # via aiohttp -aiohttp==3.12.13 +aiohttp==3.13.2 # via httpx-aiohttp # via openai -aiosignal==1.3.2 +aiosignal==1.4.0 # via aiohttp -annotated-types==0.6.0 +annotated-types==0.7.0 # via pydantic -anyio==4.1.0 +anyio==4.12.0 # via httpx # via openai -argcomplete==3.1.2 +argcomplete==3.6.3 # via nox -asttokens==2.4.1 +asttokens==3.0.1 # via inline-snapshot async-timeout==5.0.1 # via aiohttp -attrs==24.2.0 +attrs==25.4.0 # via aiohttp + # via nox # via outcome # via trio -azure-core==1.31.0 +azure-core==1.36.0 # via azure-identity -azure-identity==1.19.0 -certifi==2023.7.22 +azure-identity==1.25.1 +backports-asyncio-runner==1.2.0 + # via pytest-asyncio +certifi==2025.11.12 # via httpcore # via httpx # via requests -cffi==1.16.0 +cffi==2.0.0 # via cryptography # via sounddevice -charset-normalizer==3.3.2 +charset-normalizer==3.4.4 # via requests colorama==0.4.6 # via griffe -colorlog==6.7.0 +colorlog==6.10.1 # via nox -cryptography==42.0.7 +cryptography==46.0.3 # via azure-identity # via msal # via pyjwt -dirty-equals==0.6.0 -distlib==0.3.7 +dependency-groups==1.3.1 + # via nox +dirty-equals==0.11 +distlib==0.4.0 # via virtualenv -distro==1.8.0 +distro==1.9.0 # via openai -exceptiongroup==1.2.2 +exceptiongroup==1.3.1 # via anyio # via pytest # via trio -execnet==2.1.1 +execnet==2.1.2 # via pytest-xdist -executing==2.2.0 +executing==2.2.1 # via inline-snapshot -filelock==3.12.4 +filelock==3.19.1 # via virtualenv -frozenlist==1.7.0 +frozenlist==1.8.0 # via aiohttp # via aiosignal -griffe==1.13.0 +griffe==1.14.0 h11==0.16.0 # via httpcore httpcore==1.0.9 @@ -81,139 +86,145 @@ httpx==0.28.1 # via respx httpx-aiohttp==0.1.9 # via openai -idna==3.4 +humanize==4.13.0 + # via nox +idna==3.11 # via anyio # via httpx # via requests # via trio # via yarl -importlib-metadata==7.0.0 -iniconfig==2.0.0 +importlib-metadata==8.7.0 +iniconfig==2.1.0 # via pytest -inline-snapshot==0.28.0 -jiter==0.11.0 +inline-snapshot==0.31.1 +jiter==0.12.0 # via openai markdown-it-py==3.0.0 # via rich mdurl==0.1.2 # via markdown-it-py -msal==1.31.0 +msal==1.34.0 # via azure-identity # via msal-extensions -msal-extensions==1.2.0 +msal-extensions==1.3.1 # via azure-identity -multidict==6.5.0 +multidict==6.7.0 # via aiohttp # via yarl mypy==1.17.0 -mypy-extensions==1.0.0 +mypy-extensions==1.1.0 # via mypy nest-asyncio==1.6.0 -nodeenv==1.8.0 +nodeenv==1.9.1 # via pyright -nox==2023.4.22 +nox==2025.11.12 numpy==2.0.2 # via openai # via pandas # via pandas-stubs outcome==1.3.0.post0 # via trio -packaging==23.2 +packaging==25.0 + # via dependency-groups # via nox # via pytest -pandas==2.2.3 +pandas==2.3.3 # via openai -pandas-stubs==2.1.4.231227 +pandas-stubs==2.2.2.240807 # via openai pathspec==0.12.1 # via mypy -platformdirs==3.11.0 +platformdirs==4.4.0 # via virtualenv -pluggy==1.5.0 +pluggy==1.6.0 # via pytest -portalocker==2.10.1 - # via msal-extensions -propcache==0.3.2 +propcache==0.4.1 # via aiohttp # via yarl pycparser==2.23 # via cffi -pydantic==2.11.9 +pydantic==2.12.5 # via openai -pydantic-core==2.33.2 +pydantic-core==2.41.5 # via pydantic -pygments==2.18.0 +pygments==2.19.2 # via pytest # via rich -pyjwt==2.8.0 +pyjwt==2.10.1 # via msal pyright==1.1.399 -pytest==8.4.1 +pytest==8.4.2 # via inline-snapshot # via pytest-asyncio # via pytest-xdist -pytest-asyncio==0.24.0 -pytest-xdist==3.7.0 -python-dateutil==2.8.2 +pytest-asyncio==1.2.0 +pytest-xdist==3.8.0 +python-dateutil==2.9.0.post0 # via pandas # via time-machine -pytz==2023.3.post1 - # via dirty-equals +pytz==2025.2 # via pandas -requests==2.31.0 +requests==2.32.5 # via azure-core # via msal respx==0.22.0 -rich==13.7.1 +rich==14.2.0 # via inline-snapshot -ruff==0.9.4 -setuptools==68.2.2 - # via nodeenv -six==1.16.0 - # via asttokens - # via azure-core +ruff==0.14.7 +six==1.17.0 # via python-dateutil -sniffio==1.3.0 - # via anyio +sniffio==1.3.1 # via openai # via trio sortedcontainers==2.4.0 # via trio -sounddevice==0.5.1 +sounddevice==0.5.3 # via openai -time-machine==2.9.0 -tomli==2.0.2 +time-machine==2.19.0 +tomli==2.3.0 + # via dependency-groups # via inline-snapshot # via mypy + # via nox # via pytest -tqdm==4.66.5 +tqdm==4.67.1 # via openai -trio==0.27.0 -types-pyaudio==0.2.16.20240516 -types-pytz==2024.2.0.20241003 +trio==0.31.0 +types-pyaudio==0.2.16.20250801 +types-pytz==2025.2.0.20251108 # via pandas-stubs -types-tqdm==4.66.0.20240417 -typing-extensions==4.12.2 +types-requests==2.32.4.20250913 + # via types-tqdm +types-tqdm==4.67.0.20250809 +typing-extensions==4.15.0 + # via aiosignal + # via anyio # via azure-core # via azure-identity + # via cryptography + # via exceptiongroup # via multidict # via mypy # via openai # via pydantic # via pydantic-core # via pyright + # via pytest-asyncio # via typing-inspection -typing-inspection==0.4.1 + # via virtualenv +typing-inspection==0.4.2 # via pydantic -tzdata==2024.1 +tzdata==2025.2 # via pandas -urllib3==2.2.1 +urllib3==2.5.0 # via requests -virtualenv==20.24.5 + # via types-requests +virtualenv==20.35.4 # via nox websockets==15.0.1 # via openai -yarl==1.20.1 +yarl==1.22.0 # via aiohttp -zipp==3.17.0 +zipp==3.23.0 # via importlib-metadata diff --git a/requirements.lock b/requirements.lock index 386ec3c590..8e021bd69b 100644 --- a/requirements.lock +++ b/requirements.lock @@ -12,30 +12,30 @@ -e file:. aiohappyeyeballs==2.6.1 # via aiohttp -aiohttp==3.12.13 +aiohttp==3.13.2 # via httpx-aiohttp # via openai -aiosignal==1.3.2 +aiosignal==1.4.0 # via aiohttp -annotated-types==0.6.0 +annotated-types==0.7.0 # via pydantic -anyio==4.1.0 +anyio==4.12.0 # via httpx # via openai async-timeout==5.0.1 # via aiohttp -attrs==25.3.0 +attrs==25.4.0 # via aiohttp -certifi==2023.7.22 +certifi==2025.11.12 # via httpcore # via httpx -cffi==1.17.1 +cffi==2.0.0 # via sounddevice -distro==1.8.0 +distro==1.9.0 # via openai -exceptiongroup==1.2.2 +exceptiongroup==1.3.1 # via anyio -frozenlist==1.7.0 +frozenlist==1.8.0 # via aiohttp # via aiosignal h11==0.16.0 @@ -47,24 +47,24 @@ httpx==0.28.1 # via openai httpx-aiohttp==0.1.9 # via openai -idna==3.4 +idna==3.11 # via anyio # via httpx # via yarl -jiter==0.11.0 +jiter==0.12.0 # via openai -multidict==6.5.0 +multidict==6.7.0 # via aiohttp # via yarl numpy==2.0.2 # via openai # via pandas # via pandas-stubs -pandas==2.2.3 +pandas==2.3.3 # via openai pandas-stubs==2.2.2.240807 # via openai -propcache==0.3.2 +propcache==0.4.1 # via aiohttp # via yarl pycparser==2.23 @@ -75,21 +75,22 @@ pydantic-core==2.41.5 # via pydantic python-dateutil==2.9.0.post0 # via pandas -pytz==2024.1 +pytz==2025.2 # via pandas -six==1.16.0 +six==1.17.0 # via python-dateutil -sniffio==1.3.0 - # via anyio +sniffio==1.3.1 # via openai -sounddevice==0.5.1 +sounddevice==0.5.3 # via openai -tqdm==4.66.5 +tqdm==4.67.1 # via openai -types-pytz==2024.2.0.20241003 +types-pytz==2025.2.0.20251108 # via pandas-stubs typing-extensions==4.15.0 + # via aiosignal # via anyio + # via exceptiongroup # via multidict # via openai # via pydantic @@ -101,5 +102,5 @@ tzdata==2025.2 # via pandas websockets==15.0.1 # via openai -yarl==1.20.1 +yarl==1.22.0 # via aiohttp From abc2596652b23318b8b5e7388b7d66fc161f817f Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Tue, 2 Dec 2025 11:29:14 +0000 Subject: [PATCH 559/769] fix(streaming): correct indentation --- src/openai/_streaming.py | 144 +++++++++++++++++++-------------------- 1 file changed, 72 insertions(+), 72 deletions(-) diff --git a/src/openai/_streaming.py b/src/openai/_streaming.py index 74e54f74fa..61a742668a 100644 --- a/src/openai/_streaming.py +++ b/src/openai/_streaming.py @@ -60,42 +60,42 @@ def __stream__(self) -> Iterator[_T]: if sse.data.startswith("[DONE]"): break - # we have to special case the Assistants `thread.` events since we won't have an "event" key in the data - if sse.event and sse.event.startswith("thread."): - data = sse.json() - - if sse.event == "error" and is_mapping(data) and data.get("error"): - message = None - error = data.get("error") - if is_mapping(error): - message = error.get("message") - if not message or not isinstance(message, str): - message = "An error occurred during streaming" - - raise APIError( - message=message, - request=self.response.request, - body=data["error"], - ) - - yield process_data(data={"data": data, "event": sse.event}, cast_to=cast_to, response=response) - else: - data = sse.json() - if is_mapping(data) and data.get("error"): - message = None - error = data.get("error") - if is_mapping(error): - message = error.get("message") - if not message or not isinstance(message, str): - message = "An error occurred during streaming" - - raise APIError( - message=message, - request=self.response.request, - body=data["error"], - ) - - yield process_data(data=data, cast_to=cast_to, response=response) + # we have to special case the Assistants `thread.` events since we won't have an "event" key in the data + if sse.event and sse.event.startswith("thread."): + data = sse.json() + + if sse.event == "error" and is_mapping(data) and data.get("error"): + message = None + error = data.get("error") + if is_mapping(error): + message = error.get("message") + if not message or not isinstance(message, str): + message = "An error occurred during streaming" + + raise APIError( + message=message, + request=self.response.request, + body=data["error"], + ) + + yield process_data(data={"data": data, "event": sse.event}, cast_to=cast_to, response=response) + else: + data = sse.json() + if is_mapping(data) and data.get("error"): + message = None + error = data.get("error") + if is_mapping(error): + message = error.get("message") + if not message or not isinstance(message, str): + message = "An error occurred during streaming" + + raise APIError( + message=message, + request=self.response.request, + body=data["error"], + ) + + yield process_data(data=data, cast_to=cast_to, response=response) finally: # Ensure the response is closed even if the consumer doesn't read all data @@ -163,42 +163,42 @@ async def __stream__(self) -> AsyncIterator[_T]: if sse.data.startswith("[DONE]"): break - # we have to special case the Assistants `thread.` events since we won't have an "event" key in the data - if sse.event and sse.event.startswith("thread."): - data = sse.json() - - if sse.event == "error" and is_mapping(data) and data.get("error"): - message = None - error = data.get("error") - if is_mapping(error): - message = error.get("message") - if not message or not isinstance(message, str): - message = "An error occurred during streaming" - - raise APIError( - message=message, - request=self.response.request, - body=data["error"], - ) - - yield process_data(data={"data": data, "event": sse.event}, cast_to=cast_to, response=response) - else: - data = sse.json() - if is_mapping(data) and data.get("error"): - message = None - error = data.get("error") - if is_mapping(error): - message = error.get("message") - if not message or not isinstance(message, str): - message = "An error occurred during streaming" - - raise APIError( - message=message, - request=self.response.request, - body=data["error"], - ) - - yield process_data(data=data, cast_to=cast_to, response=response) + # we have to special case the Assistants `thread.` events since we won't have an "event" key in the data + if sse.event and sse.event.startswith("thread."): + data = sse.json() + + if sse.event == "error" and is_mapping(data) and data.get("error"): + message = None + error = data.get("error") + if is_mapping(error): + message = error.get("message") + if not message or not isinstance(message, str): + message = "An error occurred during streaming" + + raise APIError( + message=message, + request=self.response.request, + body=data["error"], + ) + + yield process_data(data={"data": data, "event": sse.event}, cast_to=cast_to, response=response) + else: + data = sse.json() + if is_mapping(data) and data.get("error"): + message = None + error = data.get("error") + if is_mapping(error): + message = error.get("message") + if not message or not isinstance(message, str): + message = "An error occurred during streaming" + + raise APIError( + message=message, + request=self.response.request, + body=data["error"], + ) + + yield process_data(data=data, cast_to=cast_to, response=response) finally: # Ensure the response is closed even if the consumer doesn't read all data From bd988473f60e28c1ea13c9cc26d6e0b063df02b8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 2 Dec 2025 21:23:11 +0000 Subject: [PATCH 560/769] chore(docs): use environment variables for authentication in code snippets --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 470707e1f3..b8050a4cd6 100644 --- a/README.md +++ b/README.md @@ -160,6 +160,7 @@ pip install openai[aiohttp] Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`: ```python +import os import asyncio from openai import DefaultAioHttpClient from openai import AsyncOpenAI @@ -167,7 +168,7 @@ from openai import AsyncOpenAI async def main() -> None: async with AsyncOpenAI( - api_key="My API Key", + api_key=os.environ.get("OPENAI_API_KEY"), # This is the default and can be omitted http_client=DefaultAioHttpClient(), ) as client: chat_completion = await client.chat.completions.create( From 1039d5637779e035263019a687b562d3ab5d2c1a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 4 Dec 2025 17:50:57 +0000 Subject: [PATCH 561/769] feat(api): gpt-5.1-codex-max and responses/compact --- .stats.yml | 8 +- api.md | 5 + src/openai/lib/_parsing/_responses.py | 1 + src/openai/resources/beta/assistants.py | 28 +- .../resources/beta/threads/runs/runs.py | 42 ++- .../resources/chat/completions/completions.py | 42 ++- src/openai/resources/containers/containers.py | 8 + src/openai/resources/realtime/calls.py | 46 ++- src/openai/resources/realtime/realtime.py | 4 +- src/openai/resources/responses/responses.py | 319 +++++++++++++++++- src/openai/resources/videos.py | 16 +- .../types/beta/assistant_create_params.py | 7 +- .../types/beta/assistant_update_params.py | 7 +- .../types/beta/threads/run_create_params.py | 7 +- .../types/chat/completion_create_params.py | 7 +- src/openai/types/container_create_params.py | 3 + src/openai/types/container_create_response.py | 6 + src/openai/types/container_list_response.py | 6 + .../types/container_retrieve_response.py | 6 + ...create_eval_completions_run_data_source.py | 7 +- ..._eval_completions_run_data_source_param.py | 7 +- src/openai/types/evals/run_cancel_response.py | 14 +- src/openai/types/evals/run_create_params.py | 14 +- src/openai/types/evals/run_create_response.py | 14 +- src/openai/types/evals/run_list_response.py | 14 +- .../types/evals/run_retrieve_response.py | 14 +- .../types/graders/score_model_grader.py | 7 +- .../types/graders/score_model_grader_param.py | 7 +- src/openai/types/realtime/__init__.py | 3 + .../types/realtime/call_accept_params.py | 23 +- ..._audio_buffer_dtmf_event_received_event.py | 18 + .../realtime_audio_input_turn_detection.py | 19 +- ...altime_audio_input_turn_detection_param.py | 19 +- .../types/realtime/realtime_server_event.py | 2 + .../realtime_session_create_request.py | 23 +- .../realtime_session_create_request_param.py | 23 +- .../realtime_session_create_response.py | 42 ++- ...tion_session_audio_input_turn_detection.py | 19 +- ...ession_audio_input_turn_detection_param.py | 19 +- src/openai/types/responses/__init__.py | 5 + .../types/responses/compacted_response.py | 33 ++ src/openai/types/responses/parsed_response.py | 3 +- .../responses/response_compact_params.py | 126 +++++++ .../responses/response_compaction_item.py | 20 ++ .../response_compaction_item_param.py | 18 + .../response_compaction_item_param_param.py | 18 + ...onse_function_shell_call_output_content.py | 6 +- ...unction_shell_call_output_content_param.py | 6 +- .../response_function_shell_tool_call.py | 4 +- .../types/responses/response_input_item.py | 14 +- .../responses/response_input_item_param.py | 14 +- .../types/responses/response_input_param.py | 14 +- .../types/responses/response_output_item.py | 2 + src/openai/types/responses/tool.py | 2 +- src/openai/types/responses/tool_param.py | 2 +- src/openai/types/shared/all_models.py | 1 + src/openai/types/shared/reasoning.py | 7 +- src/openai/types/shared/reasoning_effort.py | 2 +- src/openai/types/shared/responses_model.py | 1 + src/openai/types/shared_params/reasoning.py | 7 +- .../types/shared_params/reasoning_effort.py | 2 +- .../types/shared_params/responses_model.py | 1 + src/openai/types/video_create_params.py | 12 +- tests/api_resources/test_containers.py | 2 + tests/api_resources/test_responses.py | 79 ++++- 65 files changed, 1029 insertions(+), 248 deletions(-) create mode 100644 src/openai/types/realtime/input_audio_buffer_dtmf_event_received_event.py create mode 100644 src/openai/types/responses/compacted_response.py create mode 100644 src/openai/types/responses/response_compact_params.py create mode 100644 src/openai/types/responses/response_compaction_item.py create mode 100644 src/openai/types/responses/response_compaction_item_param.py create mode 100644 src/openai/types/responses/response_compaction_item_param_param.py diff --git a/.stats.yml b/.stats.yml index fe1a09be6b..7adb61ca2e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 136 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-a7e92d12ebe89ca019a7ac5b29759064eefa2c38fe08d03516f2620e66abb32b.yml -openapi_spec_hash: acbc703b2739447abc6312b2d753631c -config_hash: b876221dfb213df9f0a999e75d38a65e +configured_endpoints: 137 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-fe8a79e6fd407e6c9afec60971f03076b65f711ccd6ea16457933b0e24fb1f6d.yml +openapi_spec_hash: 38c0a73f4e08843732c5f8002a809104 +config_hash: 2c350086d87a4b4532077363087840e7 diff --git a/api.md b/api.md index 28ee551af3..3807603206 100644 --- a/api.md +++ b/api.md @@ -733,6 +733,7 @@ Types: ```python from openai.types.responses import ( ApplyPatchTool, + CompactedResponse, ComputerTool, CustomTool, EasyInputMessage, @@ -752,6 +753,8 @@ from openai.types.responses import ( ResponseCodeInterpreterCallInProgressEvent, ResponseCodeInterpreterCallInterpretingEvent, ResponseCodeInterpreterToolCall, + ResponseCompactionItem, + ResponseCompactionItemParam, ResponseCompletedEvent, ResponseComputerToolCall, ResponseComputerToolCallOutputItem, @@ -861,6 +864,7 @@ Methods: - client.responses.retrieve(response_id, \*\*params) -> Response - client.responses.delete(response_id) -> None - client.responses.cancel(response_id) -> Response +- client.responses.compact(\*\*params) -> CompactedResponse ## InputItems @@ -914,6 +918,7 @@ from openai.types.realtime import ( InputAudioBufferClearedEvent, InputAudioBufferCommitEvent, InputAudioBufferCommittedEvent, + InputAudioBufferDtmfEventReceivedEvent, InputAudioBufferSpeechStartedEvent, InputAudioBufferSpeechStoppedEvent, InputAudioBufferTimeoutTriggered, diff --git a/src/openai/lib/_parsing/_responses.py b/src/openai/lib/_parsing/_responses.py index 4d7b0b6224..4bed171df7 100644 --- a/src/openai/lib/_parsing/_responses.py +++ b/src/openai/lib/_parsing/_responses.py @@ -103,6 +103,7 @@ def parse_response( or output.type == "file_search_call" or output.type == "web_search_call" or output.type == "reasoning" + or output.type == "compaction" or output.type == "mcp_call" or output.type == "mcp_approval_request" or output.type == "image_generation_call" diff --git a/src/openai/resources/beta/assistants.py b/src/openai/resources/beta/assistants.py index e4ec1dca11..aa1f9f9b48 100644 --- a/src/openai/resources/beta/assistants.py +++ b/src/openai/resources/beta/assistants.py @@ -98,9 +98,9 @@ def create( reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -108,6 +108,7 @@ def create( - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), @@ -312,9 +313,9 @@ def update( reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -322,6 +323,7 @@ def update( - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), @@ -565,9 +567,9 @@ async def create( reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -575,6 +577,7 @@ async def create( - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), @@ -779,9 +782,9 @@ async def update( reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -789,6 +792,7 @@ async def update( - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), diff --git a/src/openai/resources/beta/threads/runs/runs.py b/src/openai/resources/beta/threads/runs/runs.py index d7445d52b5..9b6cb3f752 100644 --- a/src/openai/resources/beta/threads/runs/runs.py +++ b/src/openai/resources/beta/threads/runs/runs.py @@ -169,9 +169,9 @@ def create( reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -179,6 +179,7 @@ def create( - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), @@ -330,9 +331,9 @@ def create( reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -340,6 +341,7 @@ def create( - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), @@ -487,9 +489,9 @@ def create( reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -497,6 +499,7 @@ def create( - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), @@ -1620,9 +1623,9 @@ async def create( reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -1630,6 +1633,7 @@ async def create( - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), @@ -1781,9 +1785,9 @@ async def create( reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -1791,6 +1795,7 @@ async def create( - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), @@ -1938,9 +1943,9 @@ async def create( reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -1948,6 +1953,7 @@ async def create( - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index c205011d10..3f2732a608 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -411,9 +411,9 @@ def create( reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -421,6 +421,7 @@ def create( - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. response_format: An object specifying the format that the model must output. @@ -721,9 +722,9 @@ def create( reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -731,6 +732,7 @@ def create( - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. response_format: An object specifying the format that the model must output. @@ -1022,9 +1024,9 @@ def create( reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -1032,6 +1034,7 @@ def create( - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. response_format: An object specifying the format that the model must output. @@ -1894,9 +1897,9 @@ async def create( reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -1904,6 +1907,7 @@ async def create( - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. response_format: An object specifying the format that the model must output. @@ -2204,9 +2208,9 @@ async def create( reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -2214,6 +2218,7 @@ async def create( - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. response_format: An object specifying the format that the model must output. @@ -2505,9 +2510,9 @@ async def create( reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -2515,6 +2520,7 @@ async def create( - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. response_format: An object specifying the format that the model must output. diff --git a/src/openai/resources/containers/containers.py b/src/openai/resources/containers/containers.py index dcdc3e1a3e..0cbb400d4a 100644 --- a/src/openai/resources/containers/containers.py +++ b/src/openai/resources/containers/containers.py @@ -60,6 +60,7 @@ def create( name: str, expires_after: container_create_params.ExpiresAfter | Omit = omit, file_ids: SequenceNotStr[str] | Omit = omit, + memory_limit: Literal["1g", "4g", "16g", "64g"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -77,6 +78,8 @@ def create( file_ids: IDs of files to copy to the container. + memory_limit: Optional memory limit for the container. Defaults to "1g". + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -92,6 +95,7 @@ def create( "name": name, "expires_after": expires_after, "file_ids": file_ids, + "memory_limit": memory_limit, }, container_create_params.ContainerCreateParams, ), @@ -256,6 +260,7 @@ async def create( name: str, expires_after: container_create_params.ExpiresAfter | Omit = omit, file_ids: SequenceNotStr[str] | Omit = omit, + memory_limit: Literal["1g", "4g", "16g", "64g"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -273,6 +278,8 @@ async def create( file_ids: IDs of files to copy to the container. + memory_limit: Optional memory limit for the container. Defaults to "1g". + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -288,6 +295,7 @@ async def create( "name": name, "expires_after": expires_after, "file_ids": file_ids, + "memory_limit": memory_limit, }, container_create_params.ContainerCreateParams, ), diff --git a/src/openai/resources/realtime/calls.py b/src/openai/resources/realtime/calls.py index 7d2c92fe86..cdea492d95 100644 --- a/src/openai/resources/realtime/calls.py +++ b/src/openai/resources/realtime/calls.py @@ -199,15 +199,20 @@ def accept( limit, the conversation be truncated, meaning messages (starting from the oldest) will not be included in the model's context. A 32k context model with 4,096 max output tokens can only include 28,224 tokens in the context before - truncation occurs. Clients can configure truncation behavior to truncate with a - lower max token limit, which is an effective way to control token usage and - cost. Truncation will reduce the number of cached tokens on the next turn - (busting the cache), since messages are dropped from the beginning of the - context. However, clients can also configure truncation to retain messages up to - a fraction of the maximum context size, which will reduce the need for future - truncations and thus improve the cache rate. Truncation can be disabled - entirely, which means the server will never truncate but would instead return an - error if the conversation exceeds the model's input token limit. + truncation occurs. + + Clients can configure truncation behavior to truncate with a lower max token + limit, which is an effective way to control token usage and cost. + + Truncation will reduce the number of cached tokens on the next turn (busting the + cache), since messages are dropped from the beginning of the context. However, + clients can also configure truncation to retain messages up to a fraction of the + maximum context size, which will reduce the need for future truncations and thus + improve the cache rate. + + Truncation can be disabled entirely, which means the server will never truncate + but would instead return an error if the conversation exceeds the model's input + token limit. extra_headers: Send extra headers @@ -519,15 +524,20 @@ async def accept( limit, the conversation be truncated, meaning messages (starting from the oldest) will not be included in the model's context. A 32k context model with 4,096 max output tokens can only include 28,224 tokens in the context before - truncation occurs. Clients can configure truncation behavior to truncate with a - lower max token limit, which is an effective way to control token usage and - cost. Truncation will reduce the number of cached tokens on the next turn - (busting the cache), since messages are dropped from the beginning of the - context. However, clients can also configure truncation to retain messages up to - a fraction of the maximum context size, which will reduce the need for future - truncations and thus improve the cache rate. Truncation can be disabled - entirely, which means the server will never truncate but would instead return an - error if the conversation exceeds the model's input token limit. + truncation occurs. + + Clients can configure truncation behavior to truncate with a lower max token + limit, which is an effective way to control token usage and cost. + + Truncation will reduce the number of cached tokens on the next turn (busting the + cache), since messages are dropped from the beginning of the context. However, + clients can also configure truncation to retain messages up to a fraction of the + maximum context size, which will reduce the need for future truncations and thus + improve the cache rate. + + Truncation can be disabled entirely, which means the server will never truncate + but would instead return an error if the conversation exceeds the model's input + token limit. extra_headers: Send extra headers diff --git a/src/openai/resources/realtime/realtime.py b/src/openai/resources/realtime/realtime.py index 6e69258616..33caba1871 100644 --- a/src/openai/resources/realtime/realtime.py +++ b/src/openai/resources/realtime/realtime.py @@ -829,7 +829,7 @@ def retrieve(self, *, item_id: str, event_id: str | Omit = omit) -> None: class RealtimeOutputAudioBufferResource(BaseRealtimeConnectionResource): def clear(self, *, event_id: str | Omit = omit) -> None: - """**WebRTC Only:** Emit to cut off the current audio response. + """**WebRTC/SIP Only:** Emit to cut off the current audio response. This will trigger the server to stop generating audio and emit a `output_audio_buffer.cleared` event. This @@ -1066,7 +1066,7 @@ async def retrieve(self, *, item_id: str, event_id: str | Omit = omit) -> None: class AsyncRealtimeOutputAudioBufferResource(BaseAsyncRealtimeConnectionResource): async def clear(self, *, event_id: str | Omit = omit) -> None: - """**WebRTC Only:** Emit to cut off the current audio response. + """**WebRTC/SIP Only:** Emit to cut off the current audio response. This will trigger the server to stop generating audio and emit a `output_audio_buffer.cleared` event. This diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 8365b808ae..5f081c3285 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -34,11 +34,10 @@ AsyncInputTokensWithStreamingResponse, ) from ..._base_client import make_request_options -from ...types.responses import response_create_params, response_retrieve_params -from ...lib._parsing._responses import ( - TextFormatT, - parse_response, - type_to_text_format_param as _type_to_text_format_param, +from ...types.responses import ( + response_create_params, + response_compact_params, + response_retrieve_params, ) from ...types.responses.response import Response from ...types.responses.tool_param import ToolParam, ParseableToolParam @@ -46,11 +45,13 @@ from ...types.shared_params.reasoning import Reasoning from ...types.responses.parsed_response import ParsedResponse from ...lib.streaming.responses._responses import ResponseStreamManager, AsyncResponseStreamManager +from ...types.responses.compacted_response import CompactedResponse from ...types.responses.response_includable import ResponseIncludable from ...types.shared_params.responses_model import ResponsesModel from ...types.responses.response_input_param import ResponseInputParam from ...types.responses.response_prompt_param import ResponsePromptParam from ...types.responses.response_stream_event import ResponseStreamEvent +from ...types.responses.response_input_item_param import ResponseInputItemParam from ...types.responses.response_text_config_param import ResponseTextConfigParam __all__ = ["Responses", "AsyncResponses"] @@ -1517,6 +1518,154 @@ def cancel( cast_to=Response, ) + def compact( + self, + *, + input: Union[str, Iterable[ResponseInputItemParam], None] | Omit = omit, + instructions: Optional[str] | Omit = omit, + model: Union[ + Literal[ + "gpt-5.1", + "gpt-5.1-2025-11-13", + "gpt-5.1-codex", + "gpt-5.1-mini", + "gpt-5.1-chat-latest", + "gpt-5", + "gpt-5-mini", + "gpt-5-nano", + "gpt-5-2025-08-07", + "gpt-5-mini-2025-08-07", + "gpt-5-nano-2025-08-07", + "gpt-5-chat-latest", + "gpt-4.1", + "gpt-4.1-mini", + "gpt-4.1-nano", + "gpt-4.1-2025-04-14", + "gpt-4.1-mini-2025-04-14", + "gpt-4.1-nano-2025-04-14", + "o4-mini", + "o4-mini-2025-04-16", + "o3", + "o3-2025-04-16", + "o3-mini", + "o3-mini-2025-01-31", + "o1", + "o1-2024-12-17", + "o1-preview", + "o1-preview-2024-09-12", + "o1-mini", + "o1-mini-2024-09-12", + "gpt-4o", + "gpt-4o-2024-11-20", + "gpt-4o-2024-08-06", + "gpt-4o-2024-05-13", + "gpt-4o-audio-preview", + "gpt-4o-audio-preview-2024-10-01", + "gpt-4o-audio-preview-2024-12-17", + "gpt-4o-audio-preview-2025-06-03", + "gpt-4o-mini-audio-preview", + "gpt-4o-mini-audio-preview-2024-12-17", + "gpt-4o-search-preview", + "gpt-4o-mini-search-preview", + "gpt-4o-search-preview-2025-03-11", + "gpt-4o-mini-search-preview-2025-03-11", + "chatgpt-4o-latest", + "codex-mini-latest", + "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-0301", + "gpt-3.5-turbo-0613", + "gpt-3.5-turbo-1106", + "gpt-3.5-turbo-0125", + "gpt-3.5-turbo-16k-0613", + "o1-pro", + "o1-pro-2025-03-19", + "o3-pro", + "o3-pro-2025-06-10", + "o3-deep-research", + "o3-deep-research-2025-06-26", + "o4-mini-deep-research", + "o4-mini-deep-research-2025-06-26", + "computer-use-preview", + "computer-use-preview-2025-03-11", + "gpt-5-codex", + "gpt-5-pro", + "gpt-5-pro-2025-10-06", + "gpt-5.1-codex-max", + ], + str, + None, + ] + | Omit = omit, + previous_response_id: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CompactedResponse: + """ + Compact conversation + + Args: + input: Text, image, or file inputs to the model, used to generate a response + + instructions: A system (or developer) message inserted into the model's context. When used + along with `previous_response_id`, the instructions from a previous response + will not be carried over to the next response. This makes it simple to swap out + system (or developer) messages in new responses. + + model: Model ID used to generate the response, like `gpt-5` or `o3`. OpenAI offers a + wide range of models with different capabilities, performance characteristics, + and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + + previous_response_id: The unique ID of the previous response to the model. Use this to create + multi-turn conversations. Learn more about + [conversation state](https://platform.openai.com/docs/guides/conversation-state). + Cannot be used in conjunction with `conversation`. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/responses/compact", + body=maybe_transform( + { + "input": input, + "instructions": instructions, + "model": model, + "previous_response_id": previous_response_id, + }, + response_compact_params.ResponseCompactParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CompactedResponse, + ) + class AsyncResponses(AsyncAPIResource): @cached_property @@ -2983,6 +3132,154 @@ async def cancel( cast_to=Response, ) + async def compact( + self, + *, + input: Union[str, Iterable[ResponseInputItemParam], None] | Omit = omit, + instructions: Optional[str] | Omit = omit, + model: Union[ + Literal[ + "gpt-5.1", + "gpt-5.1-2025-11-13", + "gpt-5.1-codex", + "gpt-5.1-mini", + "gpt-5.1-chat-latest", + "gpt-5", + "gpt-5-mini", + "gpt-5-nano", + "gpt-5-2025-08-07", + "gpt-5-mini-2025-08-07", + "gpt-5-nano-2025-08-07", + "gpt-5-chat-latest", + "gpt-4.1", + "gpt-4.1-mini", + "gpt-4.1-nano", + "gpt-4.1-2025-04-14", + "gpt-4.1-mini-2025-04-14", + "gpt-4.1-nano-2025-04-14", + "o4-mini", + "o4-mini-2025-04-16", + "o3", + "o3-2025-04-16", + "o3-mini", + "o3-mini-2025-01-31", + "o1", + "o1-2024-12-17", + "o1-preview", + "o1-preview-2024-09-12", + "o1-mini", + "o1-mini-2024-09-12", + "gpt-4o", + "gpt-4o-2024-11-20", + "gpt-4o-2024-08-06", + "gpt-4o-2024-05-13", + "gpt-4o-audio-preview", + "gpt-4o-audio-preview-2024-10-01", + "gpt-4o-audio-preview-2024-12-17", + "gpt-4o-audio-preview-2025-06-03", + "gpt-4o-mini-audio-preview", + "gpt-4o-mini-audio-preview-2024-12-17", + "gpt-4o-search-preview", + "gpt-4o-mini-search-preview", + "gpt-4o-search-preview-2025-03-11", + "gpt-4o-mini-search-preview-2025-03-11", + "chatgpt-4o-latest", + "codex-mini-latest", + "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-0301", + "gpt-3.5-turbo-0613", + "gpt-3.5-turbo-1106", + "gpt-3.5-turbo-0125", + "gpt-3.5-turbo-16k-0613", + "o1-pro", + "o1-pro-2025-03-19", + "o3-pro", + "o3-pro-2025-06-10", + "o3-deep-research", + "o3-deep-research-2025-06-26", + "o4-mini-deep-research", + "o4-mini-deep-research-2025-06-26", + "computer-use-preview", + "computer-use-preview-2025-03-11", + "gpt-5-codex", + "gpt-5-pro", + "gpt-5-pro-2025-10-06", + "gpt-5.1-codex-max", + ], + str, + None, + ] + | Omit = omit, + previous_response_id: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CompactedResponse: + """ + Compact conversation + + Args: + input: Text, image, or file inputs to the model, used to generate a response + + instructions: A system (or developer) message inserted into the model's context. When used + along with `previous_response_id`, the instructions from a previous response + will not be carried over to the next response. This makes it simple to swap out + system (or developer) messages in new responses. + + model: Model ID used to generate the response, like `gpt-5` or `o3`. OpenAI offers a + wide range of models with different capabilities, performance characteristics, + and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + + previous_response_id: The unique ID of the previous response to the model. Use this to create + multi-turn conversations. Learn more about + [conversation state](https://platform.openai.com/docs/guides/conversation-state). + Cannot be used in conjunction with `conversation`. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/responses/compact", + body=await async_maybe_transform( + { + "input": input, + "instructions": instructions, + "model": model, + "previous_response_id": previous_response_id, + }, + response_compact_params.ResponseCompactParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CompactedResponse, + ) + class ResponsesWithRawResponse: def __init__(self, responses: Responses) -> None: @@ -3000,9 +3297,6 @@ def __init__(self, responses: Responses) -> None: self.cancel = _legacy_response.to_raw_response_wrapper( responses.cancel, ) - self.parse = _legacy_response.to_raw_response_wrapper( - responses.parse, - ) @cached_property def input_items(self) -> InputItemsWithRawResponse: @@ -3029,9 +3323,6 @@ def __init__(self, responses: AsyncResponses) -> None: self.cancel = _legacy_response.async_to_raw_response_wrapper( responses.cancel, ) - self.parse = _legacy_response.async_to_raw_response_wrapper( - responses.parse, - ) @cached_property def input_items(self) -> AsyncInputItemsWithRawResponse: @@ -3058,6 +3349,9 @@ def __init__(self, responses: Responses) -> None: self.cancel = to_streamed_response_wrapper( responses.cancel, ) + self.compact = to_streamed_response_wrapper( + responses.compact, + ) @cached_property def input_items(self) -> InputItemsWithStreamingResponse: @@ -3084,6 +3378,9 @@ def __init__(self, responses: AsyncResponses) -> None: self.cancel = async_to_streamed_response_wrapper( responses.cancel, ) + self.compact = async_to_streamed_response_wrapper( + responses.compact, + ) @cached_property def input_items(self) -> AsyncInputItemsWithStreamingResponse: diff --git a/src/openai/resources/videos.py b/src/openai/resources/videos.py index 4df5f02004..727091c607 100644 --- a/src/openai/resources/videos.py +++ b/src/openai/resources/videos.py @@ -84,11 +84,13 @@ def create( input_reference: Optional image reference that guides generation. - model: The video generation model to use. Defaults to `sora-2`. + model: The video generation model to use (allowed values: sora-2, sora-2-pro). Defaults + to `sora-2`. - seconds: Clip duration in seconds. Defaults to 4 seconds. + seconds: Clip duration in seconds (allowed values: 4, 8, 12). Defaults to 4 seconds. - size: Output resolution formatted as width x height. Defaults to 720x1280. + size: Output resolution formatted as width x height (allowed values: 720x1280, + 1280x720, 1024x1792, 1792x1024). Defaults to 720x1280. extra_headers: Send extra headers @@ -437,11 +439,13 @@ async def create( input_reference: Optional image reference that guides generation. - model: The video generation model to use. Defaults to `sora-2`. + model: The video generation model to use (allowed values: sora-2, sora-2-pro). Defaults + to `sora-2`. - seconds: Clip duration in seconds. Defaults to 4 seconds. + seconds: Clip duration in seconds (allowed values: 4, 8, 12). Defaults to 4 seconds. - size: Output resolution formatted as width x height. Defaults to 720x1280. + size: Output resolution formatted as width x height (allowed values: 720x1280, + 1280x720, 1024x1792, 1792x1024). Defaults to 720x1280. extra_headers: Send extra headers diff --git a/src/openai/types/beta/assistant_create_params.py b/src/openai/types/beta/assistant_create_params.py index 009b0f49e3..38b30f212f 100644 --- a/src/openai/types/beta/assistant_create_params.py +++ b/src/openai/types/beta/assistant_create_params.py @@ -62,9 +62,9 @@ class AssistantCreateParams(TypedDict, total=False): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -72,6 +72,7 @@ class AssistantCreateParams(TypedDict, total=False): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. """ response_format: Optional[AssistantResponseFormatOptionParam] diff --git a/src/openai/types/beta/assistant_update_params.py b/src/openai/types/beta/assistant_update_params.py index 432116ad52..8f774c4e6c 100644 --- a/src/openai/types/beta/assistant_update_params.py +++ b/src/openai/types/beta/assistant_update_params.py @@ -97,9 +97,9 @@ class AssistantUpdateParams(TypedDict, total=False): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -107,6 +107,7 @@ class AssistantUpdateParams(TypedDict, total=False): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. """ response_format: Optional[AssistantResponseFormatOptionParam] diff --git a/src/openai/types/beta/threads/run_create_params.py b/src/openai/types/beta/threads/run_create_params.py index 74786d7d5c..df789decbc 100644 --- a/src/openai/types/beta/threads/run_create_params.py +++ b/src/openai/types/beta/threads/run_create_params.py @@ -111,9 +111,9 @@ class RunCreateParamsBase(TypedDict, total=False): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -121,6 +121,7 @@ class RunCreateParamsBase(TypedDict, total=False): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. """ response_format: Optional[AssistantResponseFormatOptionParam] diff --git a/src/openai/types/chat/completion_create_params.py b/src/openai/types/chat/completion_create_params.py index e02c06cbb0..f2d55f7ec4 100644 --- a/src/openai/types/chat/completion_create_params.py +++ b/src/openai/types/chat/completion_create_params.py @@ -197,9 +197,9 @@ class CompletionCreateParamsBase(TypedDict, total=False): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -207,6 +207,7 @@ class CompletionCreateParamsBase(TypedDict, total=False): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. """ response_format: ResponseFormat diff --git a/src/openai/types/container_create_params.py b/src/openai/types/container_create_params.py index 01a48ac410..d629c24d38 100644 --- a/src/openai/types/container_create_params.py +++ b/src/openai/types/container_create_params.py @@ -19,6 +19,9 @@ class ContainerCreateParams(TypedDict, total=False): file_ids: SequenceNotStr[str] """IDs of files to copy to the container.""" + memory_limit: Literal["1g", "4g", "16g", "64g"] + """Optional memory limit for the container. Defaults to "1g".""" + class ExpiresAfter(TypedDict, total=False): anchor: Required[Literal["last_active_at"]] diff --git a/src/openai/types/container_create_response.py b/src/openai/types/container_create_response.py index c0ccc45a1c..cbad914283 100644 --- a/src/openai/types/container_create_response.py +++ b/src/openai/types/container_create_response.py @@ -38,3 +38,9 @@ class ContainerCreateResponse(BaseModel): point for the expiration. The minutes is the number of minutes after the anchor before the container expires. """ + + last_active_at: Optional[int] = None + """Unix timestamp (in seconds) when the container was last active.""" + + memory_limit: Optional[Literal["1g", "4g", "16g", "64g"]] = None + """The memory limit configured for the container.""" diff --git a/src/openai/types/container_list_response.py b/src/openai/types/container_list_response.py index 2d9c11d8a4..29416f0941 100644 --- a/src/openai/types/container_list_response.py +++ b/src/openai/types/container_list_response.py @@ -38,3 +38,9 @@ class ContainerListResponse(BaseModel): point for the expiration. The minutes is the number of minutes after the anchor before the container expires. """ + + last_active_at: Optional[int] = None + """Unix timestamp (in seconds) when the container was last active.""" + + memory_limit: Optional[Literal["1g", "4g", "16g", "64g"]] = None + """The memory limit configured for the container.""" diff --git a/src/openai/types/container_retrieve_response.py b/src/openai/types/container_retrieve_response.py index eab291b34f..31fedeac64 100644 --- a/src/openai/types/container_retrieve_response.py +++ b/src/openai/types/container_retrieve_response.py @@ -38,3 +38,9 @@ class ContainerRetrieveResponse(BaseModel): point for the expiration. The minutes is the number of minutes after the anchor before the container expires. """ + + last_active_at: Optional[int] = None + """Unix timestamp (in seconds) when the container was last active.""" + + memory_limit: Optional[Literal["1g", "4g", "16g", "64g"]] = None + """The memory limit configured for the container.""" diff --git a/src/openai/types/evals/create_eval_completions_run_data_source.py b/src/openai/types/evals/create_eval_completions_run_data_source.py index 742c27a775..4236746a17 100644 --- a/src/openai/types/evals/create_eval_completions_run_data_source.py +++ b/src/openai/types/evals/create_eval_completions_run_data_source.py @@ -172,9 +172,9 @@ class SamplingParams(BaseModel): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -182,6 +182,7 @@ class SamplingParams(BaseModel): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. """ response_format: Optional[SamplingParamsResponseFormat] = None diff --git a/src/openai/types/evals/create_eval_completions_run_data_source_param.py b/src/openai/types/evals/create_eval_completions_run_data_source_param.py index 18cd5018b1..751a1432b8 100644 --- a/src/openai/types/evals/create_eval_completions_run_data_source_param.py +++ b/src/openai/types/evals/create_eval_completions_run_data_source_param.py @@ -168,9 +168,9 @@ class SamplingParams(TypedDict, total=False): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -178,6 +178,7 @@ class SamplingParams(TypedDict, total=False): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. """ response_format: SamplingParamsResponseFormat diff --git a/src/openai/types/evals/run_cancel_response.py b/src/openai/types/evals/run_cancel_response.py index b18598b20e..f7fb0ec4ad 100644 --- a/src/openai/types/evals/run_cancel_response.py +++ b/src/openai/types/evals/run_cancel_response.py @@ -103,9 +103,9 @@ class DataSourceResponsesSourceResponses(BaseModel): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -113,6 +113,7 @@ class DataSourceResponsesSourceResponses(BaseModel): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. """ temperature: Optional[float] = None @@ -245,9 +246,9 @@ class DataSourceResponsesSamplingParams(BaseModel): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -255,6 +256,7 @@ class DataSourceResponsesSamplingParams(BaseModel): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. """ seed: Optional[int] = None diff --git a/src/openai/types/evals/run_create_params.py b/src/openai/types/evals/run_create_params.py index a50433f06d..a70d1923e5 100644 --- a/src/openai/types/evals/run_create_params.py +++ b/src/openai/types/evals/run_create_params.py @@ -116,9 +116,9 @@ class DataSourceCreateEvalResponsesRunDataSourceSourceResponses(TypedDict, total """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -126,6 +126,7 @@ class DataSourceCreateEvalResponsesRunDataSourceSourceResponses(TypedDict, total - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. """ temperature: Optional[float] @@ -263,9 +264,9 @@ class DataSourceCreateEvalResponsesRunDataSourceSamplingParams(TypedDict, total= """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -273,6 +274,7 @@ class DataSourceCreateEvalResponsesRunDataSourceSamplingParams(TypedDict, total= - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. """ seed: int diff --git a/src/openai/types/evals/run_create_response.py b/src/openai/types/evals/run_create_response.py index 41dac615c7..fb2220b3a1 100644 --- a/src/openai/types/evals/run_create_response.py +++ b/src/openai/types/evals/run_create_response.py @@ -103,9 +103,9 @@ class DataSourceResponsesSourceResponses(BaseModel): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -113,6 +113,7 @@ class DataSourceResponsesSourceResponses(BaseModel): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. """ temperature: Optional[float] = None @@ -245,9 +246,9 @@ class DataSourceResponsesSamplingParams(BaseModel): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -255,6 +256,7 @@ class DataSourceResponsesSamplingParams(BaseModel): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. """ seed: Optional[int] = None diff --git a/src/openai/types/evals/run_list_response.py b/src/openai/types/evals/run_list_response.py index 61bff95447..adac4ffdc8 100644 --- a/src/openai/types/evals/run_list_response.py +++ b/src/openai/types/evals/run_list_response.py @@ -103,9 +103,9 @@ class DataSourceResponsesSourceResponses(BaseModel): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -113,6 +113,7 @@ class DataSourceResponsesSourceResponses(BaseModel): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. """ temperature: Optional[float] = None @@ -245,9 +246,9 @@ class DataSourceResponsesSamplingParams(BaseModel): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -255,6 +256,7 @@ class DataSourceResponsesSamplingParams(BaseModel): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. """ seed: Optional[int] = None diff --git a/src/openai/types/evals/run_retrieve_response.py b/src/openai/types/evals/run_retrieve_response.py index 651d7423a9..abdc5ebae5 100644 --- a/src/openai/types/evals/run_retrieve_response.py +++ b/src/openai/types/evals/run_retrieve_response.py @@ -103,9 +103,9 @@ class DataSourceResponsesSourceResponses(BaseModel): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -113,6 +113,7 @@ class DataSourceResponsesSourceResponses(BaseModel): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. """ temperature: Optional[float] = None @@ -245,9 +246,9 @@ class DataSourceResponsesSamplingParams(BaseModel): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -255,6 +256,7 @@ class DataSourceResponsesSamplingParams(BaseModel): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. """ seed: Optional[int] = None diff --git a/src/openai/types/graders/score_model_grader.py b/src/openai/types/graders/score_model_grader.py index 84686a9642..b3ba6758bb 100644 --- a/src/openai/types/graders/score_model_grader.py +++ b/src/openai/types/graders/score_model_grader.py @@ -67,9 +67,9 @@ class SamplingParams(BaseModel): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -77,6 +77,7 @@ class SamplingParams(BaseModel): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. """ seed: Optional[int] = None diff --git a/src/openai/types/graders/score_model_grader_param.py b/src/openai/types/graders/score_model_grader_param.py index aec7a95ad4..eb1f6e03ac 100644 --- a/src/openai/types/graders/score_model_grader_param.py +++ b/src/openai/types/graders/score_model_grader_param.py @@ -73,9 +73,9 @@ class SamplingParams(TypedDict, total=False): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -83,6 +83,7 @@ class SamplingParams(TypedDict, total=False): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. """ seed: Optional[int] diff --git a/src/openai/types/realtime/__init__.py b/src/openai/types/realtime/__init__.py index 83e81a034a..c2a141d727 100644 --- a/src/openai/types/realtime/__init__.py +++ b/src/openai/types/realtime/__init__.py @@ -175,6 +175,9 @@ from .response_function_call_arguments_done_event import ( ResponseFunctionCallArgumentsDoneEvent as ResponseFunctionCallArgumentsDoneEvent, ) +from .input_audio_buffer_dtmf_event_received_event import ( + InputAudioBufferDtmfEventReceivedEvent as InputAudioBufferDtmfEventReceivedEvent, +) from .realtime_conversation_item_assistant_message import ( RealtimeConversationItemAssistantMessage as RealtimeConversationItemAssistantMessage, ) diff --git a/src/openai/types/realtime/call_accept_params.py b/src/openai/types/realtime/call_accept_params.py index d6fc92b8e5..917b71cb0d 100644 --- a/src/openai/types/realtime/call_accept_params.py +++ b/src/openai/types/realtime/call_accept_params.py @@ -110,13 +110,18 @@ class CallAcceptParams(TypedDict, total=False): limit, the conversation be truncated, meaning messages (starting from the oldest) will not be included in the model's context. A 32k context model with 4,096 max output tokens can only include 28,224 tokens in the context before - truncation occurs. Clients can configure truncation behavior to truncate with a - lower max token limit, which is an effective way to control token usage and - cost. Truncation will reduce the number of cached tokens on the next turn - (busting the cache), since messages are dropped from the beginning of the - context. However, clients can also configure truncation to retain messages up to - a fraction of the maximum context size, which will reduce the need for future - truncations and thus improve the cache rate. Truncation can be disabled - entirely, which means the server will never truncate but would instead return an - error if the conversation exceeds the model's input token limit. + truncation occurs. + + Clients can configure truncation behavior to truncate with a lower max token + limit, which is an effective way to control token usage and cost. + + Truncation will reduce the number of cached tokens on the next turn (busting the + cache), since messages are dropped from the beginning of the context. However, + clients can also configure truncation to retain messages up to a fraction of the + maximum context size, which will reduce the need for future truncations and thus + improve the cache rate. + + Truncation can be disabled entirely, which means the server will never truncate + but would instead return an error if the conversation exceeds the model's input + token limit. """ diff --git a/src/openai/types/realtime/input_audio_buffer_dtmf_event_received_event.py b/src/openai/types/realtime/input_audio_buffer_dtmf_event_received_event.py new file mode 100644 index 0000000000..d61ed4bda7 --- /dev/null +++ b/src/openai/types/realtime/input_audio_buffer_dtmf_event_received_event.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["InputAudioBufferDtmfEventReceivedEvent"] + + +class InputAudioBufferDtmfEventReceivedEvent(BaseModel): + event: str + """The telephone keypad that was pressed by the user.""" + + received_at: int + """UTC Unix Timestamp when DTMF Event was received by server.""" + + type: Literal["input_audio_buffer.dtmf_event_received"] + """The event type, must be `input_audio_buffer.dtmf_event_received`.""" diff --git a/src/openai/types/realtime/realtime_audio_input_turn_detection.py b/src/openai/types/realtime/realtime_audio_input_turn_detection.py index d3f4e00316..9b55353884 100644 --- a/src/openai/types/realtime/realtime_audio_input_turn_detection.py +++ b/src/openai/types/realtime/realtime_audio_input_turn_detection.py @@ -14,9 +14,14 @@ class ServerVad(BaseModel): """Type of turn detection, `server_vad` to turn on simple Server VAD.""" create_response: Optional[bool] = None - """ - Whether or not to automatically generate a response when a VAD stop event + """Whether or not to automatically generate a response when a VAD stop event occurs. + + If `interrupt_response` is set to `false` this may fail to create a response if + the model is already responding. + + If both `create_response` and `interrupt_response` are set to `false`, the model + will never respond automatically but VAD events will still be emitted. """ idle_timeout_ms: Optional[int] = None @@ -37,9 +42,13 @@ class ServerVad(BaseModel): interrupt_response: Optional[bool] = None """ - Whether or not to automatically interrupt any ongoing response with output to - the default conversation (i.e. `conversation` of `auto`) when a VAD start event - occurs. + Whether or not to automatically interrupt (cancel) any ongoing response with + output to the default conversation (i.e. `conversation` of `auto`) when a VAD + start event occurs. If `true` then the response will be cancelled, otherwise it + will continue until complete. + + If both `create_response` and `interrupt_response` are set to `false`, the model + will never respond automatically but VAD events will still be emitted. """ prefix_padding_ms: Optional[int] = None diff --git a/src/openai/types/realtime/realtime_audio_input_turn_detection_param.py b/src/openai/types/realtime/realtime_audio_input_turn_detection_param.py index 09b8cfd159..4ce7640727 100644 --- a/src/openai/types/realtime/realtime_audio_input_turn_detection_param.py +++ b/src/openai/types/realtime/realtime_audio_input_turn_detection_param.py @@ -13,9 +13,14 @@ class ServerVad(TypedDict, total=False): """Type of turn detection, `server_vad` to turn on simple Server VAD.""" create_response: bool - """ - Whether or not to automatically generate a response when a VAD stop event + """Whether or not to automatically generate a response when a VAD stop event occurs. + + If `interrupt_response` is set to `false` this may fail to create a response if + the model is already responding. + + If both `create_response` and `interrupt_response` are set to `false`, the model + will never respond automatically but VAD events will still be emitted. """ idle_timeout_ms: Optional[int] @@ -36,9 +41,13 @@ class ServerVad(TypedDict, total=False): interrupt_response: bool """ - Whether or not to automatically interrupt any ongoing response with output to - the default conversation (i.e. `conversation` of `auto`) when a VAD start event - occurs. + Whether or not to automatically interrupt (cancel) any ongoing response with + output to the default conversation (i.e. `conversation` of `auto`) when a VAD + start event occurs. If `true` then the response will be cancelled, otherwise it + will continue until complete. + + If both `create_response` and `interrupt_response` are set to `false`, the model + will never respond automatically but VAD events will still be emitted. """ prefix_padding_ms: int diff --git a/src/openai/types/realtime/realtime_server_event.py b/src/openai/types/realtime/realtime_server_event.py index 1605b81a97..ead98f1a54 100644 --- a/src/openai/types/realtime/realtime_server_event.py +++ b/src/openai/types/realtime/realtime_server_event.py @@ -42,6 +42,7 @@ from .input_audio_buffer_speech_started_event import InputAudioBufferSpeechStartedEvent from .input_audio_buffer_speech_stopped_event import InputAudioBufferSpeechStoppedEvent from .response_function_call_arguments_done_event import ResponseFunctionCallArgumentsDoneEvent +from .input_audio_buffer_dtmf_event_received_event import InputAudioBufferDtmfEventReceivedEvent from .response_function_call_arguments_delta_event import ResponseFunctionCallArgumentsDeltaEvent from .conversation_item_input_audio_transcription_segment import ConversationItemInputAudioTranscriptionSegment from .conversation_item_input_audio_transcription_delta_event import ConversationItemInputAudioTranscriptionDeltaEvent @@ -116,6 +117,7 @@ class OutputAudioBufferCleared(BaseModel): RealtimeErrorEvent, InputAudioBufferClearedEvent, InputAudioBufferCommittedEvent, + InputAudioBufferDtmfEventReceivedEvent, InputAudioBufferSpeechStartedEvent, InputAudioBufferSpeechStoppedEvent, RateLimitsUpdatedEvent, diff --git a/src/openai/types/realtime/realtime_session_create_request.py b/src/openai/types/realtime/realtime_session_create_request.py index 016ae45b67..80cf468dc8 100644 --- a/src/openai/types/realtime/realtime_session_create_request.py +++ b/src/openai/types/realtime/realtime_session_create_request.py @@ -110,13 +110,18 @@ class RealtimeSessionCreateRequest(BaseModel): limit, the conversation be truncated, meaning messages (starting from the oldest) will not be included in the model's context. A 32k context model with 4,096 max output tokens can only include 28,224 tokens in the context before - truncation occurs. Clients can configure truncation behavior to truncate with a - lower max token limit, which is an effective way to control token usage and - cost. Truncation will reduce the number of cached tokens on the next turn - (busting the cache), since messages are dropped from the beginning of the - context. However, clients can also configure truncation to retain messages up to - a fraction of the maximum context size, which will reduce the need for future - truncations and thus improve the cache rate. Truncation can be disabled - entirely, which means the server will never truncate but would instead return an - error if the conversation exceeds the model's input token limit. + truncation occurs. + + Clients can configure truncation behavior to truncate with a lower max token + limit, which is an effective way to control token usage and cost. + + Truncation will reduce the number of cached tokens on the next turn (busting the + cache), since messages are dropped from the beginning of the context. However, + clients can also configure truncation to retain messages up to a fraction of the + maximum context size, which will reduce the need for future truncations and thus + improve the cache rate. + + Truncation can be disabled entirely, which means the server will never truncate + but would instead return an error if the conversation exceeds the model's input + token limit. """ diff --git a/src/openai/types/realtime/realtime_session_create_request_param.py b/src/openai/types/realtime/realtime_session_create_request_param.py index 8c3998c1ca..578d5a502d 100644 --- a/src/openai/types/realtime/realtime_session_create_request_param.py +++ b/src/openai/types/realtime/realtime_session_create_request_param.py @@ -110,13 +110,18 @@ class RealtimeSessionCreateRequestParam(TypedDict, total=False): limit, the conversation be truncated, meaning messages (starting from the oldest) will not be included in the model's context. A 32k context model with 4,096 max output tokens can only include 28,224 tokens in the context before - truncation occurs. Clients can configure truncation behavior to truncate with a - lower max token limit, which is an effective way to control token usage and - cost. Truncation will reduce the number of cached tokens on the next turn - (busting the cache), since messages are dropped from the beginning of the - context. However, clients can also configure truncation to retain messages up to - a fraction of the maximum context size, which will reduce the need for future - truncations and thus improve the cache rate. Truncation can be disabled - entirely, which means the server will never truncate but would instead return an - error if the conversation exceeds the model's input token limit. + truncation occurs. + + Clients can configure truncation behavior to truncate with a lower max token + limit, which is an effective way to control token usage and cost. + + Truncation will reduce the number of cached tokens on the next turn (busting the + cache), since messages are dropped from the beginning of the context. However, + clients can also configure truncation to retain messages up to a fraction of the + maximum context size, which will reduce the need for future truncations and thus + improve the cache rate. + + Truncation can be disabled entirely, which means the server will never truncate + but would instead return an error if the conversation exceeds the model's input + token limit. """ diff --git a/src/openai/types/realtime/realtime_session_create_response.py b/src/openai/types/realtime/realtime_session_create_response.py index c1336cd6e4..df69dd7bdb 100644 --- a/src/openai/types/realtime/realtime_session_create_response.py +++ b/src/openai/types/realtime/realtime_session_create_response.py @@ -53,9 +53,14 @@ class AudioInputTurnDetectionServerVad(BaseModel): """Type of turn detection, `server_vad` to turn on simple Server VAD.""" create_response: Optional[bool] = None - """ - Whether or not to automatically generate a response when a VAD stop event + """Whether or not to automatically generate a response when a VAD stop event occurs. + + If `interrupt_response` is set to `false` this may fail to create a response if + the model is already responding. + + If both `create_response` and `interrupt_response` are set to `false`, the model + will never respond automatically but VAD events will still be emitted. """ idle_timeout_ms: Optional[int] = None @@ -76,9 +81,13 @@ class AudioInputTurnDetectionServerVad(BaseModel): interrupt_response: Optional[bool] = None """ - Whether or not to automatically interrupt any ongoing response with output to - the default conversation (i.e. `conversation` of `auto`) when a VAD start event - occurs. + Whether or not to automatically interrupt (cancel) any ongoing response with + output to the default conversation (i.e. `conversation` of `auto`) when a VAD + start event occurs. If `true` then the response will be cancelled, otherwise it + will continue until complete. + + If both `create_response` and `interrupt_response` are set to `false`, the model + will never respond automatically but VAD events will still be emitted. """ prefix_padding_ms: Optional[int] = None @@ -463,13 +472,18 @@ class RealtimeSessionCreateResponse(BaseModel): limit, the conversation be truncated, meaning messages (starting from the oldest) will not be included in the model's context. A 32k context model with 4,096 max output tokens can only include 28,224 tokens in the context before - truncation occurs. Clients can configure truncation behavior to truncate with a - lower max token limit, which is an effective way to control token usage and - cost. Truncation will reduce the number of cached tokens on the next turn - (busting the cache), since messages are dropped from the beginning of the - context. However, clients can also configure truncation to retain messages up to - a fraction of the maximum context size, which will reduce the need for future - truncations and thus improve the cache rate. Truncation can be disabled - entirely, which means the server will never truncate but would instead return an - error if the conversation exceeds the model's input token limit. + truncation occurs. + + Clients can configure truncation behavior to truncate with a lower max token + limit, which is an effective way to control token usage and cost. + + Truncation will reduce the number of cached tokens on the next turn (busting the + cache), since messages are dropped from the beginning of the context. However, + clients can also configure truncation to retain messages up to a fraction of the + maximum context size, which will reduce the need for future truncations and thus + improve the cache rate. + + Truncation can be disabled entirely, which means the server will never truncate + but would instead return an error if the conversation exceeds the model's input + token limit. """ diff --git a/src/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection.py b/src/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection.py index 7dc7a8f302..e21844f48f 100644 --- a/src/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection.py +++ b/src/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection.py @@ -14,9 +14,14 @@ class ServerVad(BaseModel): """Type of turn detection, `server_vad` to turn on simple Server VAD.""" create_response: Optional[bool] = None - """ - Whether or not to automatically generate a response when a VAD stop event + """Whether or not to automatically generate a response when a VAD stop event occurs. + + If `interrupt_response` is set to `false` this may fail to create a response if + the model is already responding. + + If both `create_response` and `interrupt_response` are set to `false`, the model + will never respond automatically but VAD events will still be emitted. """ idle_timeout_ms: Optional[int] = None @@ -37,9 +42,13 @@ class ServerVad(BaseModel): interrupt_response: Optional[bool] = None """ - Whether or not to automatically interrupt any ongoing response with output to - the default conversation (i.e. `conversation` of `auto`) when a VAD start event - occurs. + Whether or not to automatically interrupt (cancel) any ongoing response with + output to the default conversation (i.e. `conversation` of `auto`) when a VAD + start event occurs. If `true` then the response will be cancelled, otherwise it + will continue until complete. + + If both `create_response` and `interrupt_response` are set to `false`, the model + will never respond automatically but VAD events will still be emitted. """ prefix_padding_ms: Optional[int] = None diff --git a/src/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection_param.py b/src/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection_param.py index d899b8c5c1..507c43141e 100644 --- a/src/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection_param.py +++ b/src/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection_param.py @@ -13,9 +13,14 @@ class ServerVad(TypedDict, total=False): """Type of turn detection, `server_vad` to turn on simple Server VAD.""" create_response: bool - """ - Whether or not to automatically generate a response when a VAD stop event + """Whether or not to automatically generate a response when a VAD stop event occurs. + + If `interrupt_response` is set to `false` this may fail to create a response if + the model is already responding. + + If both `create_response` and `interrupt_response` are set to `false`, the model + will never respond automatically but VAD events will still be emitted. """ idle_timeout_ms: Optional[int] @@ -36,9 +41,13 @@ class ServerVad(TypedDict, total=False): interrupt_response: bool """ - Whether or not to automatically interrupt any ongoing response with output to - the default conversation (i.e. `conversation` of `auto`) when a VAD start event - occurs. + Whether or not to automatically interrupt (cancel) any ongoing response with + output to the default conversation (i.e. `conversation` of `auto`) when a VAD + start event occurs. If `true` then the response will be cancelled, otherwise it + will continue until complete. + + If both `create_response` and `interrupt_response` are set to `false`, the model + will never respond automatically but VAD events will still be emitted. """ prefix_padding_ms: int diff --git a/src/openai/types/responses/__init__.py b/src/openai/types/responses/__init__.py index e707141d9a..a4d939d9ff 100644 --- a/src/openai/types/responses/__init__.py +++ b/src/openai/types/responses/__init__.py @@ -28,6 +28,7 @@ from .custom_tool_param import CustomToolParam as CustomToolParam from .tool_choice_shell import ToolChoiceShell as ToolChoiceShell from .tool_choice_types import ToolChoiceTypes as ToolChoiceTypes +from .compacted_response import CompactedResponse as CompactedResponse from .easy_input_message import EasyInputMessage as EasyInputMessage from .response_item_list import ResponseItemList as ResponseItemList from .tool_choice_custom import ToolChoiceCustom as ToolChoiceCustom @@ -60,6 +61,7 @@ from .response_create_params import ResponseCreateParams as ResponseCreateParams from .response_created_event import ResponseCreatedEvent as ResponseCreatedEvent from .response_input_content import ResponseInputContent as ResponseInputContent +from .response_compact_params import ResponseCompactParams as ResponseCompactParams from .response_output_message import ResponseOutputMessage as ResponseOutputMessage from .response_output_refusal import ResponseOutputRefusal as ResponseOutputRefusal from .response_reasoning_item import ResponseReasoningItem as ResponseReasoningItem @@ -69,6 +71,7 @@ from .web_search_preview_tool import WebSearchPreviewTool as WebSearchPreviewTool from .easy_input_message_param import EasyInputMessageParam as EasyInputMessageParam from .input_token_count_params import InputTokenCountParams as InputTokenCountParams +from .response_compaction_item import ResponseCompactionItem as ResponseCompactionItem from .response_completed_event import ResponseCompletedEvent as ResponseCompletedEvent from .response_retrieve_params import ResponseRetrieveParams as ResponseRetrieveParams from .response_text_done_event import ResponseTextDoneEvent as ResponseTextDoneEvent @@ -108,6 +111,7 @@ from .tool_choice_apply_patch_param import ToolChoiceApplyPatchParam as ToolChoiceApplyPatchParam from .web_search_preview_tool_param import WebSearchPreviewToolParam as WebSearchPreviewToolParam from .response_apply_patch_tool_call import ResponseApplyPatchToolCall as ResponseApplyPatchToolCall +from .response_compaction_item_param import ResponseCompactionItemParam as ResponseCompactionItemParam from .response_file_search_tool_call import ResponseFileSearchToolCall as ResponseFileSearchToolCall from .response_mcp_call_failed_event import ResponseMcpCallFailedEvent as ResponseMcpCallFailedEvent from .response_custom_tool_call_param import ResponseCustomToolCallParam as ResponseCustomToolCallParam @@ -133,6 +137,7 @@ from .response_mcp_call_in_progress_event import ResponseMcpCallInProgressEvent as ResponseMcpCallInProgressEvent from .response_reasoning_text_delta_event import ResponseReasoningTextDeltaEvent as ResponseReasoningTextDeltaEvent from .response_audio_transcript_done_event import ResponseAudioTranscriptDoneEvent as ResponseAudioTranscriptDoneEvent +from .response_compaction_item_param_param import ResponseCompactionItemParamParam as ResponseCompactionItemParamParam from .response_file_search_tool_call_param import ResponseFileSearchToolCallParam as ResponseFileSearchToolCallParam from .response_mcp_list_tools_failed_event import ResponseMcpListToolsFailedEvent as ResponseMcpListToolsFailedEvent from .response_apply_patch_tool_call_output import ResponseApplyPatchToolCallOutput as ResponseApplyPatchToolCallOutput diff --git a/src/openai/types/responses/compacted_response.py b/src/openai/types/responses/compacted_response.py new file mode 100644 index 0000000000..5b333b83c0 --- /dev/null +++ b/src/openai/types/responses/compacted_response.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import Literal + +from ..._models import BaseModel +from .response_usage import ResponseUsage +from .response_output_item import ResponseOutputItem + +__all__ = ["CompactedResponse"] + + +class CompactedResponse(BaseModel): + id: str + """The unique identifier for the compacted response.""" + + created_at: int + """Unix timestamp (in seconds) when the compacted conversation was created.""" + + object: Literal["response.compaction"] + """The object type. Always `response.compaction`.""" + + output: List[ResponseOutputItem] + """The compacted list of output items. + + This is a list of all user messages, followed by a single compaction item. + """ + + usage: ResponseUsage + """ + Token accounting for the compaction pass, including cached, reasoning, and total + tokens. + """ diff --git a/src/openai/types/responses/parsed_response.py b/src/openai/types/responses/parsed_response.py index c120f4641d..a859710590 100644 --- a/src/openai/types/responses/parsed_response.py +++ b/src/openai/types/responses/parsed_response.py @@ -6,7 +6,6 @@ from ..._utils import PropertyInfo from .response import Response from ..._models import GenericModel -from ..._utils._transform import PropertyInfo from .response_output_item import ( McpCall, McpListTools, @@ -19,6 +18,7 @@ from .response_output_message import ResponseOutputMessage from .response_output_refusal import ResponseOutputRefusal from .response_reasoning_item import ResponseReasoningItem +from .response_compaction_item import ResponseCompactionItem from .response_custom_tool_call import ResponseCustomToolCall from .response_computer_tool_call import ResponseComputerToolCall from .response_function_tool_call import ResponseFunctionToolCall @@ -79,6 +79,7 @@ class ParsedResponseFunctionToolCall(ResponseFunctionToolCall): McpListTools, ResponseCodeInterpreterToolCall, ResponseCustomToolCall, + ResponseCompactionItem, ResponseFunctionShellToolCall, ResponseFunctionShellToolCallOutput, ResponseApplyPatchToolCall, diff --git a/src/openai/types/responses/response_compact_params.py b/src/openai/types/responses/response_compact_params.py new file mode 100644 index 0000000000..fe38b15a9d --- /dev/null +++ b/src/openai/types/responses/response_compact_params.py @@ -0,0 +1,126 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable, Optional +from typing_extensions import Literal, TypedDict + +from .response_input_item_param import ResponseInputItemParam + +__all__ = ["ResponseCompactParams"] + + +class ResponseCompactParams(TypedDict, total=False): + input: Union[str, Iterable[ResponseInputItemParam], None] + """Text, image, or file inputs to the model, used to generate a response""" + + instructions: Optional[str] + """ + A system (or developer) message inserted into the model's context. When used + along with `previous_response_id`, the instructions from a previous response + will not be carried over to the next response. This makes it simple to swap out + system (or developer) messages in new responses. + """ + + model: Union[ + Literal[ + "gpt-5.1", + "gpt-5.1-2025-11-13", + "gpt-5.1-codex", + "gpt-5.1-mini", + "gpt-5.1-chat-latest", + "gpt-5", + "gpt-5-mini", + "gpt-5-nano", + "gpt-5-2025-08-07", + "gpt-5-mini-2025-08-07", + "gpt-5-nano-2025-08-07", + "gpt-5-chat-latest", + "gpt-4.1", + "gpt-4.1-mini", + "gpt-4.1-nano", + "gpt-4.1-2025-04-14", + "gpt-4.1-mini-2025-04-14", + "gpt-4.1-nano-2025-04-14", + "o4-mini", + "o4-mini-2025-04-16", + "o3", + "o3-2025-04-16", + "o3-mini", + "o3-mini-2025-01-31", + "o1", + "o1-2024-12-17", + "o1-preview", + "o1-preview-2024-09-12", + "o1-mini", + "o1-mini-2024-09-12", + "gpt-4o", + "gpt-4o-2024-11-20", + "gpt-4o-2024-08-06", + "gpt-4o-2024-05-13", + "gpt-4o-audio-preview", + "gpt-4o-audio-preview-2024-10-01", + "gpt-4o-audio-preview-2024-12-17", + "gpt-4o-audio-preview-2025-06-03", + "gpt-4o-mini-audio-preview", + "gpt-4o-mini-audio-preview-2024-12-17", + "gpt-4o-search-preview", + "gpt-4o-mini-search-preview", + "gpt-4o-search-preview-2025-03-11", + "gpt-4o-mini-search-preview-2025-03-11", + "chatgpt-4o-latest", + "codex-mini-latest", + "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-0301", + "gpt-3.5-turbo-0613", + "gpt-3.5-turbo-1106", + "gpt-3.5-turbo-0125", + "gpt-3.5-turbo-16k-0613", + "o1-pro", + "o1-pro-2025-03-19", + "o3-pro", + "o3-pro-2025-06-10", + "o3-deep-research", + "o3-deep-research-2025-06-26", + "o4-mini-deep-research", + "o4-mini-deep-research-2025-06-26", + "computer-use-preview", + "computer-use-preview-2025-03-11", + "gpt-5-codex", + "gpt-5-pro", + "gpt-5-pro-2025-10-06", + "gpt-5.1-codex-max", + ], + str, + None, + ] + """Model ID used to generate the response, like `gpt-5` or `o3`. + + OpenAI offers a wide range of models with different capabilities, performance + characteristics, and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + """ + + previous_response_id: Optional[str] + """The unique ID of the previous response to the model. + + Use this to create multi-turn conversations. Learn more about + [conversation state](https://platform.openai.com/docs/guides/conversation-state). + Cannot be used in conjunction with `conversation`. + """ diff --git a/src/openai/types/responses/response_compaction_item.py b/src/openai/types/responses/response_compaction_item.py new file mode 100644 index 0000000000..dc5f839bb8 --- /dev/null +++ b/src/openai/types/responses/response_compaction_item.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseCompactionItem"] + + +class ResponseCompactionItem(BaseModel): + id: str + """The unique ID of the compaction item.""" + + encrypted_content: str + + type: Literal["compaction"] + """The type of the item. Always `compaction`.""" + + created_by: Optional[str] = None diff --git a/src/openai/types/responses/response_compaction_item_param.py b/src/openai/types/responses/response_compaction_item_param.py new file mode 100644 index 0000000000..8fdc2a561a --- /dev/null +++ b/src/openai/types/responses/response_compaction_item_param.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseCompactionItemParam"] + + +class ResponseCompactionItemParam(BaseModel): + encrypted_content: str + + type: Literal["compaction"] + """The type of the item. Always `compaction`.""" + + id: Optional[str] = None + """The ID of the compaction item.""" diff --git a/src/openai/types/responses/response_compaction_item_param_param.py b/src/openai/types/responses/response_compaction_item_param_param.py new file mode 100644 index 0000000000..0d12296589 --- /dev/null +++ b/src/openai/types/responses/response_compaction_item_param_param.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ResponseCompactionItemParamParam"] + + +class ResponseCompactionItemParamParam(TypedDict, total=False): + encrypted_content: Required[str] + + type: Required[Literal["compaction"]] + """The type of the item. Always `compaction`.""" + + id: Optional[str] + """The ID of the compaction item.""" diff --git a/src/openai/types/responses/response_function_shell_call_output_content.py b/src/openai/types/responses/response_function_shell_call_output_content.py index 1429ce9724..e0e2c09ad1 100644 --- a/src/openai/types/responses/response_function_shell_call_output_content.py +++ b/src/openai/types/responses/response_function_shell_call_output_content.py @@ -27,10 +27,10 @@ class OutcomeExit(BaseModel): class ResponseFunctionShellCallOutputContent(BaseModel): outcome: Outcome - """The exit or timeout outcome associated with this chunk.""" + """The exit or timeout outcome associated with this shell call.""" stderr: str - """Captured stderr output for this chunk of the shell call.""" + """Captured stderr output for the shell call.""" stdout: str - """Captured stdout output for this chunk of the shell call.""" + """Captured stdout output for the shell call.""" diff --git a/src/openai/types/responses/response_function_shell_call_output_content_param.py b/src/openai/types/responses/response_function_shell_call_output_content_param.py index 6395541cf5..fa065bd4b5 100644 --- a/src/openai/types/responses/response_function_shell_call_output_content_param.py +++ b/src/openai/types/responses/response_function_shell_call_output_content_param.py @@ -26,10 +26,10 @@ class OutcomeExit(TypedDict, total=False): class ResponseFunctionShellCallOutputContentParam(TypedDict, total=False): outcome: Required[Outcome] - """The exit or timeout outcome associated with this chunk.""" + """The exit or timeout outcome associated with this shell call.""" stderr: Required[str] - """Captured stderr output for this chunk of the shell call.""" + """Captured stderr output for the shell call.""" stdout: Required[str] - """Captured stdout output for this chunk of the shell call.""" + """Captured stdout output for the shell call.""" diff --git a/src/openai/types/responses/response_function_shell_tool_call.py b/src/openai/types/responses/response_function_shell_tool_call.py index be0a5bcff8..de42cb0640 100644 --- a/src/openai/types/responses/response_function_shell_tool_call.py +++ b/src/openai/types/responses/response_function_shell_tool_call.py @@ -20,7 +20,7 @@ class Action(BaseModel): class ResponseFunctionShellToolCall(BaseModel): id: str - """The unique ID of the function shell tool call. + """The unique ID of the shell tool call. Populated when this item is returned via API. """ @@ -29,7 +29,7 @@ class ResponseFunctionShellToolCall(BaseModel): """The shell commands and limits that describe how to run the tool call.""" call_id: str - """The unique ID of the function shell tool call generated by the model.""" + """The unique ID of the shell tool call generated by the model.""" status: Literal["in_progress", "completed", "incomplete"] """The status of the shell call. diff --git a/src/openai/types/responses/response_input_item.py b/src/openai/types/responses/response_input_item.py index eaf5396087..103c8634ce 100644 --- a/src/openai/types/responses/response_input_item.py +++ b/src/openai/types/responses/response_input_item.py @@ -12,6 +12,7 @@ from .response_computer_tool_call import ResponseComputerToolCall from .response_function_tool_call import ResponseFunctionToolCall from .response_function_web_search import ResponseFunctionWebSearch +from .response_compaction_item_param import ResponseCompactionItemParam from .response_file_search_tool_call import ResponseFileSearchToolCall from .response_custom_tool_call_output import ResponseCustomToolCallOutput from .response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall @@ -215,13 +216,13 @@ class ShellCall(BaseModel): """The shell commands and limits that describe how to run the tool call.""" call_id: str - """The unique ID of the function shell tool call generated by the model.""" + """The unique ID of the shell tool call generated by the model.""" type: Literal["shell_call"] - """The type of the item. Always `function_shell_call`.""" + """The type of the item. Always `shell_call`.""" id: Optional[str] = None - """The unique ID of the function shell tool call. + """The unique ID of the shell tool call. Populated when this item is returned via API. """ @@ -235,7 +236,7 @@ class ShellCall(BaseModel): class ShellCallOutput(BaseModel): call_id: str - """The unique ID of the function shell tool call generated by the model.""" + """The unique ID of the shell tool call generated by the model.""" output: List[ResponseFunctionShellCallOutputContent] """ @@ -244,10 +245,10 @@ class ShellCallOutput(BaseModel): """ type: Literal["shell_call_output"] - """The type of the item. Always `function_shell_call_output`.""" + """The type of the item. Always `shell_call_output`.""" id: Optional[str] = None - """The unique ID of the function shell tool call output. + """The unique ID of the shell tool call output. Populated when this item is returned via API. """ @@ -462,6 +463,7 @@ class ItemReference(BaseModel): ResponseFunctionToolCall, FunctionCallOutput, ResponseReasoningItem, + ResponseCompactionItemParam, ImageGenerationCall, ResponseCodeInterpreterToolCall, LocalShellCall, diff --git a/src/openai/types/responses/response_input_item_param.py b/src/openai/types/responses/response_input_item_param.py index 5c2e81c4de..85d9f92b23 100644 --- a/src/openai/types/responses/response_input_item_param.py +++ b/src/openai/types/responses/response_input_item_param.py @@ -13,6 +13,7 @@ from .response_computer_tool_call_param import ResponseComputerToolCallParam from .response_function_tool_call_param import ResponseFunctionToolCallParam from .response_function_web_search_param import ResponseFunctionWebSearchParam +from .response_compaction_item_param_param import ResponseCompactionItemParamParam from .response_file_search_tool_call_param import ResponseFileSearchToolCallParam from .response_custom_tool_call_output_param import ResponseCustomToolCallOutputParam from .response_code_interpreter_tool_call_param import ResponseCodeInterpreterToolCallParam @@ -216,13 +217,13 @@ class ShellCall(TypedDict, total=False): """The shell commands and limits that describe how to run the tool call.""" call_id: Required[str] - """The unique ID of the function shell tool call generated by the model.""" + """The unique ID of the shell tool call generated by the model.""" type: Required[Literal["shell_call"]] - """The type of the item. Always `function_shell_call`.""" + """The type of the item. Always `shell_call`.""" id: Optional[str] - """The unique ID of the function shell tool call. + """The unique ID of the shell tool call. Populated when this item is returned via API. """ @@ -236,7 +237,7 @@ class ShellCall(TypedDict, total=False): class ShellCallOutput(TypedDict, total=False): call_id: Required[str] - """The unique ID of the function shell tool call generated by the model.""" + """The unique ID of the shell tool call generated by the model.""" output: Required[Iterable[ResponseFunctionShellCallOutputContentParam]] """ @@ -245,10 +246,10 @@ class ShellCallOutput(TypedDict, total=False): """ type: Required[Literal["shell_call_output"]] - """The type of the item. Always `function_shell_call_output`.""" + """The type of the item. Always `shell_call_output`.""" id: Optional[str] - """The unique ID of the function shell tool call output. + """The unique ID of the shell tool call output. Populated when this item is returned via API. """ @@ -461,6 +462,7 @@ class ItemReference(TypedDict, total=False): ResponseFunctionToolCallParam, FunctionCallOutput, ResponseReasoningItemParam, + ResponseCompactionItemParamParam, ImageGenerationCall, ResponseCodeInterpreterToolCallParam, LocalShellCall, diff --git a/src/openai/types/responses/response_input_param.py b/src/openai/types/responses/response_input_param.py index 365c6b3d7b..bbd8e6af79 100644 --- a/src/openai/types/responses/response_input_param.py +++ b/src/openai/types/responses/response_input_param.py @@ -13,6 +13,7 @@ from .response_computer_tool_call_param import ResponseComputerToolCallParam from .response_function_tool_call_param import ResponseFunctionToolCallParam from .response_function_web_search_param import ResponseFunctionWebSearchParam +from .response_compaction_item_param_param import ResponseCompactionItemParamParam from .response_file_search_tool_call_param import ResponseFileSearchToolCallParam from .response_custom_tool_call_output_param import ResponseCustomToolCallOutputParam from .response_code_interpreter_tool_call_param import ResponseCodeInterpreterToolCallParam @@ -217,13 +218,13 @@ class ShellCall(TypedDict, total=False): """The shell commands and limits that describe how to run the tool call.""" call_id: Required[str] - """The unique ID of the function shell tool call generated by the model.""" + """The unique ID of the shell tool call generated by the model.""" type: Required[Literal["shell_call"]] - """The type of the item. Always `function_shell_call`.""" + """The type of the item. Always `shell_call`.""" id: Optional[str] - """The unique ID of the function shell tool call. + """The unique ID of the shell tool call. Populated when this item is returned via API. """ @@ -237,7 +238,7 @@ class ShellCall(TypedDict, total=False): class ShellCallOutput(TypedDict, total=False): call_id: Required[str] - """The unique ID of the function shell tool call generated by the model.""" + """The unique ID of the shell tool call generated by the model.""" output: Required[Iterable[ResponseFunctionShellCallOutputContentParam]] """ @@ -246,10 +247,10 @@ class ShellCallOutput(TypedDict, total=False): """ type: Required[Literal["shell_call_output"]] - """The type of the item. Always `function_shell_call_output`.""" + """The type of the item. Always `shell_call_output`.""" id: Optional[str] - """The unique ID of the function shell tool call output. + """The unique ID of the shell tool call output. Populated when this item is returned via API. """ @@ -462,6 +463,7 @@ class ItemReference(TypedDict, total=False): ResponseFunctionToolCallParam, FunctionCallOutput, ResponseReasoningItemParam, + ResponseCompactionItemParamParam, ImageGenerationCall, ResponseCodeInterpreterToolCallParam, LocalShellCall, diff --git a/src/openai/types/responses/response_output_item.py b/src/openai/types/responses/response_output_item.py index 906ddbb25e..f0a66e1836 100644 --- a/src/openai/types/responses/response_output_item.py +++ b/src/openai/types/responses/response_output_item.py @@ -7,6 +7,7 @@ from ..._models import BaseModel from .response_output_message import ResponseOutputMessage from .response_reasoning_item import ResponseReasoningItem +from .response_compaction_item import ResponseCompactionItem from .response_custom_tool_call import ResponseCustomToolCall from .response_computer_tool_call import ResponseComputerToolCall from .response_function_tool_call import ResponseFunctionToolCall @@ -173,6 +174,7 @@ class McpApprovalRequest(BaseModel): ResponseFunctionWebSearch, ResponseComputerToolCall, ResponseReasoningItem, + ResponseCompactionItem, ImageGenerationCall, ResponseCodeInterpreterToolCall, LocalShellCall, diff --git a/src/openai/types/responses/tool.py b/src/openai/types/responses/tool.py index ae8b34b1f4..bb32d4e1ec 100644 --- a/src/openai/types/responses/tool.py +++ b/src/openai/types/responses/tool.py @@ -174,7 +174,7 @@ class CodeInterpreter(BaseModel): """The code interpreter container. Can be a container ID or an object that specifies uploaded file IDs to make - available to your code. + available to your code, along with an optional `memory_limit` setting. """ type: Literal["code_interpreter"] diff --git a/src/openai/types/responses/tool_param.py b/src/openai/types/responses/tool_param.py index 18b044ab8c..779acf0a53 100644 --- a/src/openai/types/responses/tool_param.py +++ b/src/openai/types/responses/tool_param.py @@ -174,7 +174,7 @@ class CodeInterpreter(TypedDict, total=False): """The code interpreter container. Can be a container ID or an object that specifies uploaded file IDs to make - available to your code. + available to your code, along with an optional `memory_limit` setting. """ type: Required[Literal["code_interpreter"]] diff --git a/src/openai/types/shared/all_models.py b/src/openai/types/shared/all_models.py index 3e0b09e2d1..ba8e1d82cf 100644 --- a/src/openai/types/shared/all_models.py +++ b/src/openai/types/shared/all_models.py @@ -24,5 +24,6 @@ "gpt-5-codex", "gpt-5-pro", "gpt-5-pro-2025-10-06", + "gpt-5.1-codex-max", ], ] diff --git a/src/openai/types/shared/reasoning.py b/src/openai/types/shared/reasoning.py index cf470ca057..b19476bcb5 100644 --- a/src/openai/types/shared/reasoning.py +++ b/src/openai/types/shared/reasoning.py @@ -14,9 +14,9 @@ class Reasoning(BaseModel): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -24,6 +24,7 @@ class Reasoning(BaseModel): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. """ generate_summary: Optional[Literal["auto", "concise", "detailed"]] = None diff --git a/src/openai/types/shared/reasoning_effort.py b/src/openai/types/shared/reasoning_effort.py index c890a133cc..24d8516424 100644 --- a/src/openai/types/shared/reasoning_effort.py +++ b/src/openai/types/shared/reasoning_effort.py @@ -5,4 +5,4 @@ __all__ = ["ReasoningEffort"] -ReasoningEffort: TypeAlias = Optional[Literal["none", "minimal", "low", "medium", "high"]] +ReasoningEffort: TypeAlias = Optional[Literal["none", "minimal", "low", "medium", "high", "xhigh"]] diff --git a/src/openai/types/shared/responses_model.py b/src/openai/types/shared/responses_model.py index 432cb82afd..38cdea9a94 100644 --- a/src/openai/types/shared/responses_model.py +++ b/src/openai/types/shared/responses_model.py @@ -24,5 +24,6 @@ "gpt-5-codex", "gpt-5-pro", "gpt-5-pro-2025-10-06", + "gpt-5.1-codex-max", ], ] diff --git a/src/openai/types/shared_params/reasoning.py b/src/openai/types/shared_params/reasoning.py index ad58f70b71..71cb37c65e 100644 --- a/src/openai/types/shared_params/reasoning.py +++ b/src/openai/types/shared_params/reasoning.py @@ -15,9 +15,9 @@ class Reasoning(TypedDict, total=False): """ Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, and `high`. Reducing - reasoning effort can result in faster responses and fewer tokens used on - reasoning in a response. + supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. + Reducing reasoning effort can result in faster responses and fewer tokens used + on reasoning in a response. - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool @@ -25,6 +25,7 @@ class Reasoning(TypedDict, total=False): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. + - `xhigh` is currently only supported for `gpt-5.1-codex-max`. """ generate_summary: Optional[Literal["auto", "concise", "detailed"]] diff --git a/src/openai/types/shared_params/reasoning_effort.py b/src/openai/types/shared_params/reasoning_effort.py index e388eebff1..8518c2b141 100644 --- a/src/openai/types/shared_params/reasoning_effort.py +++ b/src/openai/types/shared_params/reasoning_effort.py @@ -7,4 +7,4 @@ __all__ = ["ReasoningEffort"] -ReasoningEffort: TypeAlias = Optional[Literal["none", "minimal", "low", "medium", "high"]] +ReasoningEffort: TypeAlias = Optional[Literal["none", "minimal", "low", "medium", "high", "xhigh"]] diff --git a/src/openai/types/shared_params/responses_model.py b/src/openai/types/shared_params/responses_model.py index fe34eb0f62..ad44dd6bf7 100644 --- a/src/openai/types/shared_params/responses_model.py +++ b/src/openai/types/shared_params/responses_model.py @@ -26,5 +26,6 @@ "gpt-5-codex", "gpt-5-pro", "gpt-5-pro-2025-10-06", + "gpt-5.1-codex-max", ], ] diff --git a/src/openai/types/video_create_params.py b/src/openai/types/video_create_params.py index 527d62d193..c4d3e0851f 100644 --- a/src/openai/types/video_create_params.py +++ b/src/openai/types/video_create_params.py @@ -20,10 +20,16 @@ class VideoCreateParams(TypedDict, total=False): """Optional image reference that guides generation.""" model: VideoModel - """The video generation model to use. Defaults to `sora-2`.""" + """The video generation model to use (allowed values: sora-2, sora-2-pro). + + Defaults to `sora-2`. + """ seconds: VideoSeconds - """Clip duration in seconds. Defaults to 4 seconds.""" + """Clip duration in seconds (allowed values: 4, 8, 12). Defaults to 4 seconds.""" size: VideoSize - """Output resolution formatted as width x height. Defaults to 720x1280.""" + """ + Output resolution formatted as width x height (allowed values: 720x1280, + 1280x720, 1024x1792, 1792x1024). Defaults to 720x1280. + """ diff --git a/tests/api_resources/test_containers.py b/tests/api_resources/test_containers.py index c972f6539d..cf173c7fd5 100644 --- a/tests/api_resources/test_containers.py +++ b/tests/api_resources/test_containers.py @@ -38,6 +38,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: "minutes": 0, }, file_ids=["string"], + memory_limit="1g", ) assert_matches_type(ContainerCreateResponse, container, path=["response"]) @@ -197,6 +198,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> "minutes": 0, }, file_ids=["string"], + memory_limit="1g", ) assert_matches_type(ContainerCreateResponse, container, path=["response"]) diff --git a/tests/api_resources/test_responses.py b/tests/api_resources/test_responses.py index b57e6099c4..14e2d911ef 100644 --- a/tests/api_resources/test_responses.py +++ b/tests/api_resources/test_responses.py @@ -12,6 +12,7 @@ from openai._utils import assert_signatures_in_sync from openai.types.responses import ( Response, + CompactedResponse, ) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -36,7 +37,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: max_output_tokens=0, max_tool_calls=0, metadata={"foo": "string"}, - model="gpt-4o", + model="gpt-5.1", parallel_tool_calls=True, previous_response_id="previous_response_id", prompt={ @@ -117,7 +118,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: max_output_tokens=0, max_tool_calls=0, metadata={"foo": "string"}, - model="gpt-4o", + model="gpt-5.1", parallel_tool_calls=True, previous_response_id="previous_response_id", prompt={ @@ -358,6 +359,41 @@ def test_path_params_cancel(self, client: OpenAI) -> None: "", ) + @parametrize + def test_method_compact(self, client: OpenAI) -> None: + response = client.responses.compact() + assert_matches_type(CompactedResponse, response, path=["response"]) + + @parametrize + def test_method_compact_with_all_params(self, client: OpenAI) -> None: + response = client.responses.compact( + input="string", + instructions="instructions", + model="gpt-5.1", + previous_response_id="resp_123", + ) + assert_matches_type(CompactedResponse, response, path=["response"]) + + @parametrize + def test_raw_response_compact(self, client: OpenAI) -> None: + http_response = client.responses.with_raw_response.compact() + + assert http_response.is_closed is True + assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" + response = http_response.parse() + assert_matches_type(CompactedResponse, response, path=["response"]) + + @parametrize + def test_streaming_response_compact(self, client: OpenAI) -> None: + with client.responses.with_streaming_response.compact() as http_response: + assert not http_response.is_closed + assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" + + response = http_response.parse() + assert_matches_type(CompactedResponse, response, path=["response"]) + + assert cast(Any, http_response.is_closed) is True + @pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) def test_parse_method_in_sync(sync: bool, client: OpenAI, async_client: AsyncOpenAI) -> None: @@ -391,7 +427,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn max_output_tokens=0, max_tool_calls=0, metadata={"foo": "string"}, - model="gpt-4o", + model="gpt-5.1", parallel_tool_calls=True, previous_response_id="previous_response_id", prompt={ @@ -472,7 +508,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn max_output_tokens=0, max_tool_calls=0, metadata={"foo": "string"}, - model="gpt-4o", + model="gpt-5.1", parallel_tool_calls=True, previous_response_id="previous_response_id", prompt={ @@ -712,3 +748,38 @@ async def test_path_params_cancel(self, async_client: AsyncOpenAI) -> None: await async_client.responses.with_raw_response.cancel( "", ) + + @parametrize + async def test_method_compact(self, async_client: AsyncOpenAI) -> None: + response = await async_client.responses.compact() + assert_matches_type(CompactedResponse, response, path=["response"]) + + @parametrize + async def test_method_compact_with_all_params(self, async_client: AsyncOpenAI) -> None: + response = await async_client.responses.compact( + input="string", + instructions="instructions", + model="gpt-5.1", + previous_response_id="resp_123", + ) + assert_matches_type(CompactedResponse, response, path=["response"]) + + @parametrize + async def test_raw_response_compact(self, async_client: AsyncOpenAI) -> None: + http_response = await async_client.responses.with_raw_response.compact() + + assert http_response.is_closed is True + assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" + response = http_response.parse() + assert_matches_type(CompactedResponse, response, path=["response"]) + + @parametrize + async def test_streaming_response_compact(self, async_client: AsyncOpenAI) -> None: + async with async_client.responses.with_streaming_response.compact() as http_response: + assert not http_response.is_closed + assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" + + response = await http_response.parse() + assert_matches_type(CompactedResponse, response, path=["response"]) + + assert cast(Any, http_response.is_closed) is True From 61841f4a18d5739ee84c9c6d1aba473e05bf1bc1 Mon Sep 17 00:00:00 2001 From: Alex Chang Date: Thu, 4 Dec 2025 12:57:03 -0500 Subject: [PATCH 562/769] fix import --- src/openai/resources/responses/responses.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 5f081c3285..650a54438a 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -39,6 +39,11 @@ response_compact_params, response_retrieve_params, ) +from ...lib._parsing._responses import ( + TextFormatT, + parse_response, + type_to_text_format_param as _type_to_text_format_param, +) from ...types.responses.response import Response from ...types.responses.tool_param import ToolParam, ParseableToolParam from ...types.shared_params.metadata import Metadata From 96b9e700cef2ea78d7fb37b9a469af5af152279b Mon Sep 17 00:00:00 2001 From: Alex Chang Date: Thu, 4 Dec 2025 13:00:31 -0500 Subject: [PATCH 563/769] manually readd --- src/openai/resources/responses/responses.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 650a54438a..2b2bdb4b37 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -3302,6 +3302,9 @@ def __init__(self, responses: Responses) -> None: self.cancel = _legacy_response.to_raw_response_wrapper( responses.cancel, ) + self.compact = _legacy_response.to_raw_response_wrapper( + responses.compact, + ) @cached_property def input_items(self) -> InputItemsWithRawResponse: @@ -3328,6 +3331,9 @@ def __init__(self, responses: AsyncResponses) -> None: self.cancel = _legacy_response.async_to_raw_response_wrapper( responses.cancel, ) + self.compact = _legacy_response.to_raw_response_wrapper( + responses.compact, + ) @cached_property def input_items(self) -> AsyncInputItemsWithRawResponse: From f45b3c3bcd7d3d40898230b8d592408bb208268a Mon Sep 17 00:00:00 2001 From: Alex Chang Date: Thu, 4 Dec 2025 13:03:01 -0500 Subject: [PATCH 564/769] fix bad merge --- src/openai/resources/responses/responses.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 2b2bdb4b37..c532fc0bb0 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -3305,6 +3305,9 @@ def __init__(self, responses: Responses) -> None: self.compact = _legacy_response.to_raw_response_wrapper( responses.compact, ) + self.parse = _legacy_response.to_raw_response_wrapper( + responses.parse, + ) @cached_property def input_items(self) -> InputItemsWithRawResponse: @@ -3331,9 +3334,12 @@ def __init__(self, responses: AsyncResponses) -> None: self.cancel = _legacy_response.async_to_raw_response_wrapper( responses.cancel, ) - self.compact = _legacy_response.to_raw_response_wrapper( + self.compact = _legacy_response.async_to_raw_response_wrapper( responses.compact, ) + self.parse = _legacy_response.async_to_raw_response_wrapper( + responses.parse, + ) @cached_property def input_items(self) -> AsyncInputItemsWithRawResponse: From dc7602151b9042891ccd5042c7be3881337368e5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 4 Dec 2025 18:03:39 +0000 Subject: [PATCH 565/769] release: 2.9.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 23 +++++++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 108509ed29..427b8ec423 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.8.1" + ".": "2.9.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bfa59348f..6de78290fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,28 @@ # Changelog +## 2.9.0 (2025-12-04) + +Full Changelog: [v2.8.1...v2.9.0](https://github.com/openai/openai-python/compare/v2.8.1...v2.9.0) + +### Features + +* **api:** gpt-5.1-codex-max and responses/compact ([22f646e](https://github.com/openai/openai-python/commit/22f646e985b7c93782cf695edbe643844cae7017)) + + +### Bug Fixes + +* **client:** avoid mutating user-provided response config object ([#2700](https://github.com/openai/openai-python/issues/2700)) ([e040d22](https://github.com/openai/openai-python/commit/e040d22c2df068e908f69dc6b892e7f8b3fe6e99)) +* ensure streams are always closed ([0b1a27f](https://github.com/openai/openai-python/commit/0b1a27f08639d14dfe40bf80b48e2b8a1a51593c)) +* **streaming:** correct indentation ([575bbac](https://github.com/openai/openai-python/commit/575bbac13b3a57731a4e07b67636ae94463d43fa)) + + +### Chores + +* **deps:** mypy 1.18.1 has a regression, pin to 1.17 ([22cd586](https://github.com/openai/openai-python/commit/22cd586dbd5484b47f625da55db697691116b22b)) +* **docs:** use environment variables for authentication in code snippets ([c2a3cd5](https://github.com/openai/openai-python/commit/c2a3cd502bfb03f68f62f50aed15a40458c0996e)) +* **internal:** codegen related update ([307a066](https://github.com/openai/openai-python/commit/307a0664383b9d1d4151bc1a05a78c4fdcdcc9b0)) +* update lockfile ([b4109c5](https://github.com/openai/openai-python/commit/b4109c5fcf971ccfb25b4bdaef0bf36999f9eca5)) + ## 2.8.1 (2025-11-17) Full Changelog: [v2.8.0...v2.8.1](https://github.com/openai/openai-python/compare/v2.8.0...v2.8.1) diff --git a/pyproject.toml b/pyproject.toml index 3ad3b4a58a..4735412341 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.8.1" +version = "2.9.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 6109cebf91..e5ddb8f4eb 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__ = "2.8.1" # x-release-please-version +__version__ = "2.9.0" # x-release-please-version From ef00216846515033e4cf73ab3227e91386d958ba Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 10 Dec 2025 10:25:07 -0500 Subject: [PATCH 566/769] release: 2.10.0 (#2767) * chore(internal): update docstring * fix(types): allow pyright to infer TypedDict types within SequenceNotStr * chore: add missing docstrings * feat(api): make model required for the responses/compact endpoint * release: 2.10.0 --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- .stats.yml | 6 +- CHANGELOG.md | 19 ++ pyproject.toml | 2 +- src/openai/_types.py | 5 +- src/openai/_version.py | 2 +- src/openai/resources/realtime/realtime.py | 4 +- src/openai/resources/responses/responses.py | 42 ++-- src/openai/types/audio/transcription.py | 10 + .../types/audio/transcription_diarized.py | 10 + .../audio/transcription_diarized_segment.py | 2 + .../audio/transcription_text_delta_event.py | 5 + .../audio/transcription_text_done_event.py | 9 + .../audio/transcription_text_segment_event.py | 4 + .../types/audio/transcription_verbose.py | 6 + .../auto_file_chunking_strategy_param.py | 5 + src/openai/types/batch_create_params.py | 4 + src/openai/types/batch_request_counts.py | 2 + src/openai/types/batch_usage.py | 10 + src/openai/types/beta/assistant.py | 7 + .../types/beta/assistant_create_params.py | 10 + .../types/beta/assistant_stream_event.py | 96 +++++++++ .../types/beta/assistant_tool_choice.py | 5 + .../types/beta/assistant_tool_choice_param.py | 5 + .../types/beta/assistant_update_params.py | 5 + src/openai/types/beta/chatkit/chat_session.py | 2 + .../chat_session_automatic_thread_titling.py | 2 + .../chat_session_chatkit_configuration.py | 2 + ...hat_session_chatkit_configuration_param.py | 17 ++ .../chat_session_expires_after_param.py | 2 + .../beta/chatkit/chat_session_file_upload.py | 2 + .../beta/chatkit/chat_session_history.py | 2 + .../beta/chatkit/chat_session_rate_limits.py | 2 + .../chatkit/chat_session_rate_limits_param.py | 2 + .../chatkit/chat_session_workflow_param.py | 7 + .../types/beta/chatkit/chatkit_attachment.py | 2 + .../chatkit/chatkit_response_output_text.py | 10 + .../types/beta/chatkit/chatkit_thread.py | 8 + .../chatkit_thread_assistant_message_item.py | 2 + .../beta/chatkit/chatkit_thread_item_list.py | 10 + .../chatkit_thread_user_message_item.py | 10 + .../types/beta/chatkit/chatkit_widget_item.py | 2 + .../beta/chatkit/thread_delete_response.py | 2 + src/openai/types/beta/chatkit_workflow.py | 4 + src/openai/types/beta/file_search_tool.py | 9 + .../types/beta/file_search_tool_param.py | 9 + src/openai/types/beta/thread.py | 8 + .../beta/thread_create_and_run_params.py | 25 +++ src/openai/types/beta/thread_create_params.py | 9 + src/openai/types/beta/thread_update_params.py | 4 + .../beta/threads/file_citation_annotation.py | 4 + .../threads/file_citation_delta_annotation.py | 4 + .../beta/threads/file_path_annotation.py | 4 + .../threads/file_path_delta_annotation.py | 4 + .../beta/threads/image_file_content_block.py | 4 + .../threads/image_file_content_block_param.py | 4 + .../beta/threads/image_file_delta_block.py | 4 + .../beta/threads/image_url_content_block.py | 2 + .../threads/image_url_content_block_param.py | 2 + .../beta/threads/image_url_delta_block.py | 2 + src/openai/types/beta/threads/message.py | 6 + .../types/beta/threads/message_delta.py | 2 + .../types/beta/threads/message_delta_event.py | 5 + .../beta/threads/refusal_content_block.py | 2 + .../types/beta/threads/refusal_delta_block.py | 2 + .../required_action_function_tool_call.py | 4 + src/openai/types/beta/threads/run.py | 28 +++ .../types/beta/threads/run_create_params.py | 5 + .../threads/runs/code_interpreter_logs.py | 2 + .../runs/code_interpreter_tool_call.py | 6 + .../runs/code_interpreter_tool_call_delta.py | 4 + .../threads/runs/file_search_tool_call.py | 6 + .../beta/threads/runs/function_tool_call.py | 2 + .../threads/runs/function_tool_call_delta.py | 2 + .../runs/message_creation_step_details.py | 2 + .../types/beta/threads/runs/run_step.py | 12 ++ .../types/beta/threads/runs/run_step_delta.py | 2 + .../beta/threads/runs/run_step_delta_event.py | 5 + .../runs/run_step_delta_message_delta.py | 2 + .../threads/runs/tool_call_delta_object.py | 2 + .../threads/runs/tool_calls_step_details.py | 2 + .../types/beta/threads/text_content_block.py | 2 + .../beta/threads/text_content_block_param.py | 2 + .../types/beta/threads/text_delta_block.py | 2 + src/openai/types/chat/chat_completion.py | 6 + ...at_completion_allowed_tool_choice_param.py | 2 + .../chat_completion_allowed_tools_param.py | 2 + ...chat_completion_assistant_message_param.py | 12 ++ .../types/chat/chat_completion_audio.py | 5 + .../types/chat/chat_completion_audio_param.py | 6 + .../types/chat/chat_completion_chunk.py | 15 ++ .../chat_completion_content_part_image.py | 2 + ...hat_completion_content_part_image_param.py | 2 + ...mpletion_content_part_input_audio_param.py | 2 + .../chat_completion_content_part_param.py | 4 + .../chat/chat_completion_content_part_text.py | 4 + ...chat_completion_content_part_text_param.py | 4 + .../chat/chat_completion_custom_tool_param.py | 10 + ...chat_completion_developer_message_param.py | 6 + ...t_completion_function_call_option_param.py | 4 + .../chat/chat_completion_function_tool.py | 2 + .../chat_completion_function_tool_param.py | 2 + .../types/chat/chat_completion_message.py | 11 + ...hat_completion_message_custom_tool_call.py | 4 + ...mpletion_message_custom_tool_call_param.py | 4 + ...t_completion_message_function_tool_call.py | 4 + ...letion_message_function_tool_call_param.py | 4 + ...mpletion_named_tool_choice_custom_param.py | 5 + ...chat_completion_named_tool_choice_param.py | 5 + ...hat_completion_prediction_content_param.py | 5 + .../chat/chat_completion_store_message.py | 2 + .../chat_completion_stream_options_param.py | 2 + .../chat_completion_system_message_param.py | 6 + .../chat_completion_user_message_param.py | 5 + .../types/chat/completion_create_params.py | 9 + src/openai/types/completion.py | 5 + src/openai/types/completion_usage.py | 6 + src/openai/types/container_create_params.py | 2 + src/openai/types/container_create_response.py | 6 + src/openai/types/container_list_response.py | 6 + .../types/container_retrieve_response.py | 6 + .../computer_screenshot_content.py | 2 + .../types/conversations/conversation_item.py | 18 ++ .../conversations/conversation_item_list.py | 2 + src/openai/types/conversations/message.py | 4 + .../conversations/summary_text_content.py | 2 + .../types/conversations/text_content.py | 2 + src/openai/types/create_embedding_response.py | 2 + src/openai/types/embedding.py | 2 + src/openai/types/eval_create_params.py | 37 ++++ src/openai/types/eval_create_response.py | 19 ++ .../types/eval_custom_data_source_config.py | 7 + src/openai/types/eval_list_response.py | 19 ++ src/openai/types/eval_retrieve_response.py | 19 ++ ...l_stored_completions_data_source_config.py | 2 + src/openai/types/eval_update_response.py | 19 ++ ...create_eval_completions_run_data_source.py | 16 ++ ..._eval_completions_run_data_source_param.py | 16 ++ .../create_eval_jsonl_run_data_source.py | 4 + ...create_eval_jsonl_run_data_source_param.py | 4 + src/openai/types/evals/eval_api_error.py | 2 + src/openai/types/evals/run_cancel_response.py | 28 +++ src/openai/types/evals/run_create_params.py | 24 +++ src/openai/types/evals/run_create_response.py | 28 +++ src/openai/types/evals/run_list_response.py | 28 +++ .../types/evals/run_retrieve_response.py | 28 +++ .../evals/runs/output_item_list_response.py | 10 + .../runs/output_item_retrieve_response.py | 10 + src/openai/types/file_create_params.py | 5 + src/openai/types/file_object.py | 2 + .../checkpoints/permission_create_response.py | 4 + .../permission_retrieve_response.py | 4 + .../types/fine_tuning/dpo_hyperparameters.py | 2 + .../fine_tuning/dpo_hyperparameters_param.py | 2 + src/openai/types/fine_tuning/dpo_method.py | 2 + .../types/fine_tuning/dpo_method_param.py | 2 + .../types/fine_tuning/fine_tuning_job.py | 15 ++ .../fine_tuning/fine_tuning_job_event.py | 2 + .../fine_tuning_job_wandb_integration.py | 7 + .../types/fine_tuning/job_create_params.py | 14 ++ .../jobs/fine_tuning_job_checkpoint.py | 6 + .../reinforcement_hyperparameters.py | 2 + .../reinforcement_hyperparameters_param.py | 2 + .../types/fine_tuning/reinforcement_method.py | 2 + .../fine_tuning/reinforcement_method_param.py | 2 + .../fine_tuning/supervised_hyperparameters.py | 2 + .../supervised_hyperparameters_param.py | 2 + .../types/fine_tuning/supervised_method.py | 2 + .../fine_tuning/supervised_method_param.py | 2 + .../types/graders/label_model_grader.py | 17 ++ .../types/graders/label_model_grader_param.py | 17 ++ src/openai/types/graders/multi_grader.py | 4 + .../types/graders/multi_grader_param.py | 4 + src/openai/types/graders/python_grader.py | 2 + .../types/graders/python_grader_param.py | 2 + .../types/graders/score_model_grader.py | 16 ++ .../types/graders/score_model_grader_param.py | 16 ++ .../types/graders/string_check_grader.py | 4 + .../graders/string_check_grader_param.py | 4 + .../types/graders/text_similarity_grader.py | 2 + .../graders/text_similarity_grader_param.py | 2 + src/openai/types/image.py | 2 + .../types/image_edit_completed_event.py | 6 + .../types/image_edit_partial_image_event.py | 2 + src/openai/types/image_gen_completed_event.py | 6 + .../types/image_gen_partial_image_event.py | 2 + src/openai/types/images_response.py | 6 + src/openai/types/model.py | 2 + src/openai/types/moderation.py | 8 + .../types/moderation_create_response.py | 2 + .../types/moderation_image_url_input_param.py | 4 + .../types/moderation_text_input_param.py | 2 + .../other_file_chunking_strategy_object.py | 5 + .../realtime/client_secret_create_params.py | 8 + .../realtime/client_secret_create_response.py | 2 + .../realtime/conversation_created_event.py | 4 + .../types/realtime/conversation_item_added.py | 10 + .../conversation_item_create_event.py | 10 + .../conversation_item_create_event_param.py | 10 + .../conversation_item_created_event.py | 13 ++ .../conversation_item_delete_event.py | 8 + .../conversation_item_delete_event_param.py | 8 + .../conversation_item_deleted_event.py | 6 + .../types/realtime/conversation_item_done.py | 5 + ...put_audio_transcription_completed_event.py | 19 ++ ...m_input_audio_transcription_delta_event.py | 4 + ..._input_audio_transcription_failed_event.py | 8 + ..._item_input_audio_transcription_segment.py | 2 + .../conversation_item_retrieve_event.py | 7 + .../conversation_item_retrieve_event_param.py | 7 + .../conversation_item_truncate_event.py | 15 ++ .../conversation_item_truncate_event_param.py | 15 ++ .../conversation_item_truncated_event.py | 9 + .../input_audio_buffer_append_event.py | 17 ++ .../input_audio_buffer_append_event_param.py | 17 ++ .../input_audio_buffer_clear_event.py | 6 + .../input_audio_buffer_clear_event_param.py | 6 + .../input_audio_buffer_cleared_event.py | 5 + .../input_audio_buffer_commit_event.py | 6 + .../input_audio_buffer_commit_event_param.py | 6 + .../input_audio_buffer_committed_event.py | 7 + ..._audio_buffer_dtmf_event_received_event.py | 8 + ...input_audio_buffer_speech_started_event.py | 13 ++ ...input_audio_buffer_speech_stopped_event.py | 6 + .../input_audio_buffer_timeout_triggered.py | 17 ++ .../types/realtime/log_prob_properties.py | 2 + .../realtime/mcp_list_tools_completed.py | 2 + .../types/realtime/mcp_list_tools_failed.py | 2 + .../realtime/mcp_list_tools_in_progress.py | 2 + .../output_audio_buffer_clear_event.py | 9 + .../output_audio_buffer_clear_event_param.py | 9 + .../realtime/rate_limits_updated_event.py | 8 + .../types/realtime/realtime_audio_config.py | 2 + .../realtime/realtime_audio_config_input.py | 7 + .../realtime_audio_config_input_param.py | 7 + .../realtime/realtime_audio_config_param.py | 2 + .../types/realtime/realtime_audio_formats.py | 6 + .../realtime/realtime_audio_formats_param.py | 6 + .../realtime_audio_input_turn_detection.py | 8 + ...altime_audio_input_turn_detection_param.py | 8 + ...ime_conversation_item_assistant_message.py | 2 + ...nversation_item_assistant_message_param.py | 2 + ...ealtime_conversation_item_function_call.py | 2 + ..._conversation_item_function_call_output.py | 2 + ...rsation_item_function_call_output_param.py | 2 + ...e_conversation_item_function_call_param.py | 2 + ...altime_conversation_item_system_message.py | 4 + ..._conversation_item_system_message_param.py | 4 + ...realtime_conversation_item_user_message.py | 2 + ...me_conversation_item_user_message_param.py | 2 + src/openai/types/realtime/realtime_error.py | 2 + .../types/realtime/realtime_error_event.py | 6 + .../realtime/realtime_mcp_approval_request.py | 2 + .../realtime_mcp_approval_request_param.py | 2 + .../realtime_mcp_approval_response.py | 2 + .../realtime_mcp_approval_response_param.py | 2 + .../types/realtime/realtime_mcp_list_tools.py | 4 + .../realtime/realtime_mcp_list_tools_param.py | 4 + .../types/realtime/realtime_mcp_tool_call.py | 2 + .../realtime/realtime_mcp_tool_call_param.py | 2 + .../types/realtime/realtime_response.py | 4 + .../realtime_response_create_audio_output.py | 2 + ...time_response_create_audio_output_param.py | 2 + .../realtime_response_create_mcp_tool.py | 18 ++ ...realtime_response_create_mcp_tool_param.py | 18 ++ .../realtime_response_create_params.py | 2 + .../realtime_response_create_params_param.py | 2 + .../realtime/realtime_response_status.py | 7 + .../types/realtime/realtime_response_usage.py | 8 + ...time_response_usage_input_token_details.py | 7 + ...ime_response_usage_output_token_details.py | 2 + .../types/realtime/realtime_server_event.py | 28 +++ .../realtime_session_client_secret.py | 2 + .../realtime_session_create_request.py | 2 + .../realtime_session_create_request_param.py | 2 + .../realtime_session_create_response.py | 43 ++++ .../realtime/realtime_tools_config_param.py | 18 ++ .../realtime/realtime_tools_config_union.py | 18 ++ .../realtime_tools_config_union_param.py | 18 ++ .../types/realtime/realtime_tracing_config.py | 2 + .../realtime/realtime_tracing_config_param.py | 2 + .../realtime_transcription_session_audio.py | 2 + ...ltime_transcription_session_audio_input.py | 7 + ...transcription_session_audio_input_param.py | 7 + ...tion_session_audio_input_turn_detection.py | 8 + ...ession_audio_input_turn_detection_param.py | 8 + ...ltime_transcription_session_audio_param.py | 2 + ...me_transcription_session_create_request.py | 2 + ...nscription_session_create_request_param.py | 2 + ...e_transcription_session_create_response.py | 6 + ...me_transcription_session_turn_detection.py | 7 + .../realtime_truncation_retention_ratio.py | 9 + ...altime_truncation_retention_ratio_param.py | 9 + .../realtime/response_audio_delta_event.py | 2 + .../realtime/response_audio_done_event.py | 6 + .../response_audio_transcript_delta_event.py | 2 + .../response_audio_transcript_done_event.py | 6 + .../types/realtime/response_cancel_event.py | 9 + .../realtime/response_cancel_event_param.py | 9 + .../response_content_part_added_event.py | 7 + .../response_content_part_done_event.py | 7 + .../types/realtime/response_create_event.py | 28 +++ .../realtime/response_create_event_param.py | 28 +++ .../types/realtime/response_created_event.py | 6 + .../types/realtime/response_done_event.py | 13 ++ ...nse_function_call_arguments_delta_event.py | 2 + ...onse_function_call_arguments_done_event.py | 5 + .../response_mcp_call_arguments_delta.py | 2 + .../response_mcp_call_arguments_done.py | 2 + .../realtime/response_mcp_call_completed.py | 2 + .../realtime/response_mcp_call_failed.py | 2 + .../realtime/response_mcp_call_in_progress.py | 2 + .../response_output_item_added_event.py | 2 + .../response_output_item_done_event.py | 6 + .../realtime/response_text_delta_event.py | 2 + .../realtime/response_text_done_event.py | 6 + .../types/realtime/session_created_event.py | 7 + .../types/realtime/session_update_event.py | 12 ++ .../realtime/session_update_event_param.py | 12 ++ .../types/realtime/session_updated_event.py | 5 + .../types/responses/apply_patch_tool.py | 2 + .../types/responses/apply_patch_tool_param.py | 2 + src/openai/types/responses/computer_tool.py | 5 + .../types/responses/computer_tool_param.py | 5 + src/openai/types/responses/custom_tool.py | 5 + .../types/responses/custom_tool_param.py | 5 + .../types/responses/easy_input_message.py | 8 + .../responses/easy_input_message_param.py | 8 + .../types/responses/file_search_tool.py | 11 + .../types/responses/file_search_tool_param.py | 11 + .../types/responses/function_shell_tool.py | 2 + .../responses/function_shell_tool_param.py | 2 + src/openai/types/responses/function_tool.py | 5 + .../types/responses/function_tool_param.py | 5 + .../responses/input_token_count_params.py | 8 + src/openai/types/responses/response.py | 7 + .../response_apply_patch_tool_call.py | 8 + .../response_apply_patch_tool_call_output.py | 2 + .../responses/response_audio_delta_event.py | 2 + .../responses/response_audio_done_event.py | 2 + .../response_audio_transcript_delta_event.py | 2 + .../response_audio_transcript_done_event.py | 2 + ..._code_interpreter_call_code_delta_event.py | 2 + ...e_code_interpreter_call_code_done_event.py | 2 + ...e_code_interpreter_call_completed_event.py | 2 + ...code_interpreter_call_in_progress_event.py | 2 + ...ode_interpreter_call_interpreting_event.py | 2 + .../response_code_interpreter_tool_call.py | 6 + ...sponse_code_interpreter_tool_call_param.py | 6 + .../responses/response_compact_params.py | 194 +++++++++--------- .../responses/response_compaction_item.py | 4 + .../response_compaction_item_param.py | 4 + .../response_compaction_item_param_param.py | 4 + .../responses/response_completed_event.py | 2 + .../responses/response_computer_tool_call.py | 28 +++ ...response_computer_tool_call_output_item.py | 2 + ...se_computer_tool_call_output_screenshot.py | 2 + ...puter_tool_call_output_screenshot_param.py | 2 + .../response_computer_tool_call_param.py | 28 +++ .../response_content_part_added_event.py | 4 + .../response_content_part_done_event.py | 4 + .../responses/response_conversation_param.py | 2 + .../types/responses/response_create_params.py | 2 + .../types/responses/response_created_event.py | 2 + .../responses/response_custom_tool_call.py | 2 + ...onse_custom_tool_call_input_delta_event.py | 2 + ...ponse_custom_tool_call_input_done_event.py | 2 + .../response_custom_tool_call_output.py | 2 + .../response_custom_tool_call_output_param.py | 2 + .../response_custom_tool_call_param.py | 2 + src/openai/types/responses/response_error.py | 2 + .../types/responses/response_error_event.py | 2 + .../types/responses/response_failed_event.py | 2 + ...sponse_file_search_call_completed_event.py | 2 + ...onse_file_search_call_in_progress_event.py | 2 + ...sponse_file_search_call_searching_event.py | 2 + .../response_file_search_tool_call.py | 6 + .../response_file_search_tool_call_param.py | 6 + ...response_format_text_json_schema_config.py | 6 + ...se_format_text_json_schema_config_param.py | 6 + ...nse_function_call_arguments_delta_event.py | 2 + ...onse_function_call_arguments_done_event.py | 2 + ...onse_function_shell_call_output_content.py | 6 + ...unction_shell_call_output_content_param.py | 6 + .../response_function_shell_tool_call.py | 4 + ...esponse_function_shell_tool_call_output.py | 8 + .../responses/response_function_tool_call.py | 6 + .../response_function_tool_call_item.py | 6 + .../response_function_tool_call_param.py | 6 + .../responses/response_function_web_search.py | 14 ++ .../response_function_web_search_param.py | 14 ++ ...response_image_gen_call_completed_event.py | 4 + ...esponse_image_gen_call_generating_event.py | 4 + ...sponse_image_gen_call_in_progress_event.py | 2 + ...onse_image_gen_call_partial_image_event.py | 2 + .../responses/response_in_progress_event.py | 2 + .../responses/response_incomplete_event.py | 2 + .../types/responses/response_input_audio.py | 2 + .../responses/response_input_audio_param.py | 2 + .../types/responses/response_input_file.py | 2 + .../responses/response_input_file_content.py | 2 + .../response_input_file_content_param.py | 2 + .../responses/response_input_file_param.py | 2 + .../types/responses/response_input_image.py | 5 + .../responses/response_input_image_content.py | 5 + .../response_input_image_content_param.py | 5 + .../responses/response_input_image_param.py | 5 + .../types/responses/response_input_item.py | 50 +++++ .../responses/response_input_item_param.py | 50 +++++ .../types/responses/response_input_param.py | 50 +++++ .../types/responses/response_input_text.py | 2 + .../responses/response_input_text_content.py | 2 + .../response_input_text_content_param.py | 2 + .../responses/response_input_text_param.py | 2 + src/openai/types/responses/response_item.py | 18 ++ .../types/responses/response_item_list.py | 2 + ...response_mcp_call_arguments_delta_event.py | 4 + .../response_mcp_call_arguments_done_event.py | 2 + .../response_mcp_call_completed_event.py | 2 + .../response_mcp_call_failed_event.py | 2 + .../response_mcp_call_in_progress_event.py | 2 + ...response_mcp_list_tools_completed_event.py | 2 + .../response_mcp_list_tools_failed_event.py | 2 + ...sponse_mcp_list_tools_in_progress_event.py | 4 + .../types/responses/response_output_item.py | 14 ++ .../response_output_item_added_event.py | 2 + .../response_output_item_done_event.py | 2 + .../responses/response_output_message.py | 2 + .../response_output_message_param.py | 2 + .../responses/response_output_refusal.py | 2 + .../response_output_refusal_param.py | 2 + .../types/responses/response_output_text.py | 14 ++ ...onse_output_text_annotation_added_event.py | 2 + .../responses/response_output_text_param.py | 14 ++ src/openai/types/responses/response_prompt.py | 5 + .../types/responses/response_prompt_param.py | 5 + .../types/responses/response_queued_event.py | 2 + .../responses/response_reasoning_item.py | 11 + .../response_reasoning_item_param.py | 11 + ...onse_reasoning_summary_part_added_event.py | 4 + ...ponse_reasoning_summary_part_done_event.py | 4 + ...onse_reasoning_summary_text_delta_event.py | 2 + ...ponse_reasoning_summary_text_done_event.py | 2 + .../response_reasoning_text_delta_event.py | 2 + .../response_reasoning_text_done_event.py | 2 + .../responses/response_refusal_delta_event.py | 2 + .../responses/response_refusal_done_event.py | 2 + .../types/responses/response_text_config.py | 8 + .../responses/response_text_config_param.py | 8 + .../responses/response_text_delta_event.py | 8 + .../responses/response_text_done_event.py | 8 + src/openai/types/responses/response_usage.py | 9 + ...esponse_web_search_call_completed_event.py | 2 + ...ponse_web_search_call_in_progress_event.py | 2 + ...esponse_web_search_call_searching_event.py | 2 + src/openai/types/responses/tool.py | 35 ++++ .../types/responses/tool_choice_allowed.py | 2 + .../responses/tool_choice_allowed_param.py | 2 + .../responses/tool_choice_apply_patch.py | 2 + .../tool_choice_apply_patch_param.py | 2 + .../types/responses/tool_choice_custom.py | 2 + .../responses/tool_choice_custom_param.py | 2 + .../types/responses/tool_choice_function.py | 2 + .../responses/tool_choice_function_param.py | 2 + src/openai/types/responses/tool_choice_mcp.py | 4 + .../types/responses/tool_choice_mcp_param.py | 4 + .../types/responses/tool_choice_shell.py | 2 + .../responses/tool_choice_shell_param.py | 2 + .../types/responses/tool_choice_types.py | 5 + .../responses/tool_choice_types_param.py | 5 + src/openai/types/responses/tool_param.py | 35 ++++ .../responses/web_search_preview_tool.py | 7 + .../web_search_preview_tool_param.py | 7 + src/openai/types/responses/web_search_tool.py | 10 + .../types/responses/web_search_tool_param.py | 10 + src/openai/types/shared/comparison_filter.py | 4 + src/openai/types/shared/compound_filter.py | 2 + .../types/shared/custom_tool_input_format.py | 4 + src/openai/types/shared/reasoning.py | 6 + .../shared/response_format_json_object.py | 8 + .../shared/response_format_json_schema.py | 8 + .../types/shared/response_format_text.py | 2 + .../shared/response_format_text_grammar.py | 5 + .../shared/response_format_text_python.py | 6 + .../types/shared_params/comparison_filter.py | 4 + .../types/shared_params/compound_filter.py | 2 + .../shared_params/custom_tool_input_format.py | 4 + src/openai/types/shared_params/reasoning.py | 6 + .../response_format_json_object.py | 8 + .../response_format_json_schema.py | 8 + .../shared_params/response_format_text.py | 2 + ...tic_file_chunking_strategy_object_param.py | 2 + src/openai/types/upload.py | 2 + src/openai/types/upload_create_params.py | 5 + src/openai/types/uploads/upload_part.py | 2 + src/openai/types/vector_store.py | 6 + .../types/vector_store_create_params.py | 2 + .../types/vector_store_search_params.py | 2 + .../types/vector_store_update_params.py | 2 + .../types/vector_stores/vector_store_file.py | 7 + .../vector_stores/vector_store_file_batch.py | 2 + src/openai/types/video.py | 2 + src/openai/types/video_delete_response.py | 2 + .../webhooks/batch_cancelled_webhook_event.py | 4 + .../webhooks/batch_completed_webhook_event.py | 4 + .../webhooks/batch_expired_webhook_event.py | 4 + .../webhooks/batch_failed_webhook_event.py | 4 + .../eval_run_canceled_webhook_event.py | 4 + .../webhooks/eval_run_failed_webhook_event.py | 4 + .../eval_run_succeeded_webhook_event.py | 4 + ...fine_tuning_job_cancelled_webhook_event.py | 4 + .../fine_tuning_job_failed_webhook_event.py | 4 + ...fine_tuning_job_succeeded_webhook_event.py | 4 + .../realtime_call_incoming_webhook_event.py | 6 + .../response_cancelled_webhook_event.py | 4 + .../response_completed_webhook_event.py | 4 + .../webhooks/response_failed_webhook_event.py | 4 + .../response_incomplete_webhook_event.py | 4 + tests/api_resources/test_responses.py | 28 ++- 519 files changed, 3370 insertions(+), 136 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 427b8ec423..21f60560ae 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.9.0" + ".": "2.10.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 7adb61ca2e..0aa25fb4a4 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 137 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-fe8a79e6fd407e6c9afec60971f03076b65f711ccd6ea16457933b0e24fb1f6d.yml -openapi_spec_hash: 38c0a73f4e08843732c5f8002a809104 -config_hash: 2c350086d87a4b4532077363087840e7 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-88d85ff87ad8983262af2b729762a6e05fd509468bb691529bc2f81e4ce27c69.yml +openapi_spec_hash: 46a55acbccd0147534017b92c1f4dd99 +config_hash: 141b101c9f13b90e21af74e1686f1f41 diff --git a/CHANGELOG.md b/CHANGELOG.md index 6de78290fc..58a092665e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## 2.10.0 (2025-12-10) + +Full Changelog: [v2.9.0...v2.10.0](https://github.com/openai/openai-python/compare/v2.9.0...v2.10.0) + +### Features + +* **api:** make model required for the responses/compact endpoint ([a12936b](https://github.com/openai/openai-python/commit/a12936b18cf19009d4e6d586c9b1958359636dbe)) + + +### Bug Fixes + +* **types:** allow pyright to infer TypedDict types within SequenceNotStr ([8f0d230](https://github.com/openai/openai-python/commit/8f0d23066c1edc38a6e9858b054dceaf92ae001b)) + + +### Chores + +* add missing docstrings ([f20a9a1](https://github.com/openai/openai-python/commit/f20a9a18a421ba69622c77ab539509d218e774eb)) +* **internal:** update docstring ([9a993f2](https://github.com/openai/openai-python/commit/9a993f2261b6524aa30b955e006c7ea89f086968)) + ## 2.9.0 (2025-12-04) Full Changelog: [v2.8.1...v2.9.0](https://github.com/openai/openai-python/compare/v2.8.1...v2.9.0) diff --git a/pyproject.toml b/pyproject.toml index 4735412341..e7d181d007 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.9.0" +version = "2.10.0" description = "The official Python library for the openai API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/openai/_types.py b/src/openai/_types.py index 2387d7e01c..d7e2eaac5f 100644 --- a/src/openai/_types.py +++ b/src/openai/_types.py @@ -247,6 +247,9 @@ class HttpxSendArgs(TypedDict, total=False): if TYPE_CHECKING: # This works because str.__contains__ does not accept object (either in typeshed or at runtime) # https://github.com/hauntsaninja/useful_types/blob/5e9710f3875107d068e7679fd7fec9cfab0eff3b/useful_types/__init__.py#L285 + # + # Note: index() and count() methods are intentionally omitted to allow pyright to properly + # infer TypedDict types when dict literals are used in lists assigned to SequenceNotStr. class SequenceNotStr(Protocol[_T_co]): @overload def __getitem__(self, index: SupportsIndex, /) -> _T_co: ... @@ -255,8 +258,6 @@ def __getitem__(self, index: slice, /) -> Sequence[_T_co]: ... def __contains__(self, value: object, /) -> bool: ... def __len__(self) -> int: ... def __iter__(self) -> Iterator[_T_co]: ... - def index(self, value: Any, start: int = 0, stop: int = ..., /) -> int: ... - def count(self, value: Any, /) -> int: ... def __reversed__(self) -> Iterator[_T_co]: ... else: # just point this to a normal `Sequence` at runtime to avoid having to special case diff --git a/src/openai/_version.py b/src/openai/_version.py index e5ddb8f4eb..c7a4f08f04 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__ = "2.9.0" # x-release-please-version +__version__ = "2.10.0" # x-release-please-version diff --git a/src/openai/resources/realtime/realtime.py b/src/openai/resources/realtime/realtime.py index 33caba1871..44f14cd3aa 100644 --- a/src/openai/resources/realtime/realtime.py +++ b/src/openai/resources/realtime/realtime.py @@ -232,7 +232,7 @@ def calls(self) -> AsyncCallsWithStreamingResponse: class AsyncRealtimeConnection: - """Represents a live websocket connection to the Realtime API""" + """Represents a live WebSocket connection to the Realtime API""" session: AsyncRealtimeSessionResource response: AsyncRealtimeResponseResource @@ -421,7 +421,7 @@ async def __aexit__( class RealtimeConnection: - """Represents a live websocket connection to the Realtime API""" + """Represents a live WebSocket connection to the Realtime API""" session: RealtimeSessionResource response: RealtimeResponseResource diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index c532fc0bb0..81e8980faf 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -1526,8 +1526,6 @@ def cancel( def compact( self, *, - input: Union[str, Iterable[ResponseInputItemParam], None] | Omit = omit, - instructions: Optional[str] | Omit = omit, model: Union[ Literal[ "gpt-5.1", @@ -1614,8 +1612,9 @@ def compact( ], str, None, - ] - | Omit = omit, + ], + input: Union[str, Iterable[ResponseInputItemParam], None] | Omit = omit, + instructions: Optional[str] | Omit = omit, previous_response_id: Optional[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -1628,6 +1627,12 @@ def compact( Compact conversation Args: + model: Model ID used to generate the response, like `gpt-5` or `o3`. OpenAI offers a + wide range of models with different capabilities, performance characteristics, + and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + input: Text, image, or file inputs to the model, used to generate a response instructions: A system (or developer) message inserted into the model's context. When used @@ -1635,12 +1640,6 @@ def compact( will not be carried over to the next response. This makes it simple to swap out system (or developer) messages in new responses. - model: Model ID used to generate the response, like `gpt-5` or `o3`. OpenAI offers a - wide range of models with different capabilities, performance characteristics, - and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - previous_response_id: The unique ID of the previous response to the model. Use this to create multi-turn conversations. Learn more about [conversation state](https://platform.openai.com/docs/guides/conversation-state). @@ -1658,9 +1657,9 @@ def compact( "/responses/compact", body=maybe_transform( { + "model": model, "input": input, "instructions": instructions, - "model": model, "previous_response_id": previous_response_id, }, response_compact_params.ResponseCompactParams, @@ -3140,8 +3139,6 @@ async def cancel( async def compact( self, *, - input: Union[str, Iterable[ResponseInputItemParam], None] | Omit = omit, - instructions: Optional[str] | Omit = omit, model: Union[ Literal[ "gpt-5.1", @@ -3228,8 +3225,9 @@ async def compact( ], str, None, - ] - | Omit = omit, + ], + input: Union[str, Iterable[ResponseInputItemParam], None] | Omit = omit, + instructions: Optional[str] | Omit = omit, previous_response_id: Optional[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -3242,6 +3240,12 @@ async def compact( Compact conversation Args: + model: Model ID used to generate the response, like `gpt-5` or `o3`. OpenAI offers a + wide range of models with different capabilities, performance characteristics, + and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + input: Text, image, or file inputs to the model, used to generate a response instructions: A system (or developer) message inserted into the model's context. When used @@ -3249,12 +3253,6 @@ async def compact( will not be carried over to the next response. This makes it simple to swap out system (or developer) messages in new responses. - model: Model ID used to generate the response, like `gpt-5` or `o3`. OpenAI offers a - wide range of models with different capabilities, performance characteristics, - and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - previous_response_id: The unique ID of the previous response to the model. Use this to create multi-turn conversations. Learn more about [conversation state](https://platform.openai.com/docs/guides/conversation-state). @@ -3272,9 +3270,9 @@ async def compact( "/responses/compact", body=await async_maybe_transform( { + "model": model, "input": input, "instructions": instructions, - "model": model, "previous_response_id": previous_response_id, }, response_compact_params.ResponseCompactParams, diff --git a/src/openai/types/audio/transcription.py b/src/openai/types/audio/transcription.py index 4c5882152d..cbae8bf750 100644 --- a/src/openai/types/audio/transcription.py +++ b/src/openai/types/audio/transcription.py @@ -21,6 +21,8 @@ class Logprob(BaseModel): class UsageTokensInputTokenDetails(BaseModel): + """Details about the input tokens billed for this request.""" + audio_tokens: Optional[int] = None """Number of audio tokens billed for this request.""" @@ -29,6 +31,8 @@ class UsageTokensInputTokenDetails(BaseModel): class UsageTokens(BaseModel): + """Usage statistics for models billed by token usage.""" + input_tokens: int """Number of input tokens billed for this request.""" @@ -46,6 +50,8 @@ class UsageTokens(BaseModel): class UsageDuration(BaseModel): + """Usage statistics for models billed by audio input duration.""" + seconds: float """Duration of the input audio in seconds.""" @@ -57,6 +63,10 @@ class UsageDuration(BaseModel): class Transcription(BaseModel): + """ + Represents a transcription response returned by model, based on the provided input. + """ + text: str """The transcribed text.""" diff --git a/src/openai/types/audio/transcription_diarized.py b/src/openai/types/audio/transcription_diarized.py index b7dd2b8ebb..07585fe239 100644 --- a/src/openai/types/audio/transcription_diarized.py +++ b/src/openai/types/audio/transcription_diarized.py @@ -11,6 +11,8 @@ class UsageTokensInputTokenDetails(BaseModel): + """Details about the input tokens billed for this request.""" + audio_tokens: Optional[int] = None """Number of audio tokens billed for this request.""" @@ -19,6 +21,8 @@ class UsageTokensInputTokenDetails(BaseModel): class UsageTokens(BaseModel): + """Usage statistics for models billed by token usage.""" + input_tokens: int """Number of input tokens billed for this request.""" @@ -36,6 +40,8 @@ class UsageTokens(BaseModel): class UsageDuration(BaseModel): + """Usage statistics for models billed by audio input duration.""" + seconds: float """Duration of the input audio in seconds.""" @@ -47,6 +53,10 @@ class UsageDuration(BaseModel): class TranscriptionDiarized(BaseModel): + """ + Represents a diarized transcription response returned by the model, including the combined transcript and speaker-segment annotations. + """ + duration: float """Duration of the input audio in seconds.""" diff --git a/src/openai/types/audio/transcription_diarized_segment.py b/src/openai/types/audio/transcription_diarized_segment.py index fe87bb4fb8..fcfdb3634f 100644 --- a/src/openai/types/audio/transcription_diarized_segment.py +++ b/src/openai/types/audio/transcription_diarized_segment.py @@ -8,6 +8,8 @@ class TranscriptionDiarizedSegment(BaseModel): + """A segment of diarized transcript text with speaker metadata.""" + id: str """Unique identifier for the segment.""" diff --git a/src/openai/types/audio/transcription_text_delta_event.py b/src/openai/types/audio/transcription_text_delta_event.py index 363b6a6335..a6e83133c8 100644 --- a/src/openai/types/audio/transcription_text_delta_event.py +++ b/src/openai/types/audio/transcription_text_delta_event.py @@ -20,6 +20,11 @@ class Logprob(BaseModel): class TranscriptionTextDeltaEvent(BaseModel): + """Emitted when there is an additional text delta. + + This is also the first event emitted when the transcription starts. Only emitted when you [create a transcription](https://platform.openai.com/docs/api-reference/audio/create-transcription) with the `Stream` parameter set to `true`. + """ + delta: str """The text delta that was additionally transcribed.""" diff --git a/src/openai/types/audio/transcription_text_done_event.py b/src/openai/types/audio/transcription_text_done_event.py index 9665edc565..c8f7fc0769 100644 --- a/src/openai/types/audio/transcription_text_done_event.py +++ b/src/openai/types/audio/transcription_text_done_event.py @@ -20,6 +20,8 @@ class Logprob(BaseModel): class UsageInputTokenDetails(BaseModel): + """Details about the input tokens billed for this request.""" + audio_tokens: Optional[int] = None """Number of audio tokens billed for this request.""" @@ -28,6 +30,8 @@ class UsageInputTokenDetails(BaseModel): class Usage(BaseModel): + """Usage statistics for models billed by token usage.""" + input_tokens: int """Number of input tokens billed for this request.""" @@ -45,6 +49,11 @@ class Usage(BaseModel): class TranscriptionTextDoneEvent(BaseModel): + """Emitted when the transcription is complete. + + Contains the complete transcription text. Only emitted when you [create a transcription](https://platform.openai.com/docs/api-reference/audio/create-transcription) with the `Stream` parameter set to `true`. + """ + text: str """The text that was transcribed.""" diff --git a/src/openai/types/audio/transcription_text_segment_event.py b/src/openai/types/audio/transcription_text_segment_event.py index d4f7664578..e95472e6c6 100644 --- a/src/openai/types/audio/transcription_text_segment_event.py +++ b/src/openai/types/audio/transcription_text_segment_event.py @@ -8,6 +8,10 @@ class TranscriptionTextSegmentEvent(BaseModel): + """ + Emitted when a diarized transcription returns a completed segment with speaker information. Only emitted when you [create a transcription](https://platform.openai.com/docs/api-reference/audio/create-transcription) with `stream` set to `true` and `response_format` set to `diarized_json`. + """ + id: str """Unique identifier for the segment.""" diff --git a/src/openai/types/audio/transcription_verbose.py b/src/openai/types/audio/transcription_verbose.py index addda71ec6..b1a95e9c72 100644 --- a/src/openai/types/audio/transcription_verbose.py +++ b/src/openai/types/audio/transcription_verbose.py @@ -11,6 +11,8 @@ class Usage(BaseModel): + """Usage statistics for models billed by audio input duration.""" + seconds: float """Duration of the input audio in seconds.""" @@ -19,6 +21,10 @@ class Usage(BaseModel): class TranscriptionVerbose(BaseModel): + """ + Represents a verbose json transcription response returned by model, based on the provided input. + """ + duration: float """The duration of the input audio.""" diff --git a/src/openai/types/auto_file_chunking_strategy_param.py b/src/openai/types/auto_file_chunking_strategy_param.py index 6f17836bac..db7cbf596d 100644 --- a/src/openai/types/auto_file_chunking_strategy_param.py +++ b/src/openai/types/auto_file_chunking_strategy_param.py @@ -8,5 +8,10 @@ class AutoFileChunkingStrategyParam(TypedDict, total=False): + """The default strategy. + + This strategy currently uses a `max_chunk_size_tokens` of `800` and `chunk_overlap_tokens` of `400`. + """ + type: Required[Literal["auto"]] """Always `auto`.""" diff --git a/src/openai/types/batch_create_params.py b/src/openai/types/batch_create_params.py index c182a87e7f..1088aab380 100644 --- a/src/openai/types/batch_create_params.py +++ b/src/openai/types/batch_create_params.py @@ -58,6 +58,10 @@ class BatchCreateParams(TypedDict, total=False): class OutputExpiresAfter(TypedDict, total=False): + """ + The expiration policy for the output and/or error file that are generated for a batch. + """ + anchor: Required[Literal["created_at"]] """Anchor timestamp after which the expiration policy applies. diff --git a/src/openai/types/batch_request_counts.py b/src/openai/types/batch_request_counts.py index 068b071af1..64a570747d 100644 --- a/src/openai/types/batch_request_counts.py +++ b/src/openai/types/batch_request_counts.py @@ -6,6 +6,8 @@ class BatchRequestCounts(BaseModel): + """The request counts for different statuses within the batch.""" + completed: int """Number of requests that have been completed successfully.""" diff --git a/src/openai/types/batch_usage.py b/src/openai/types/batch_usage.py index 578f64a5e2..d68d7110ac 100644 --- a/src/openai/types/batch_usage.py +++ b/src/openai/types/batch_usage.py @@ -6,6 +6,8 @@ class InputTokensDetails(BaseModel): + """A detailed breakdown of the input tokens.""" + cached_tokens: int """The number of tokens that were retrieved from the cache. @@ -14,11 +16,19 @@ class InputTokensDetails(BaseModel): class OutputTokensDetails(BaseModel): + """A detailed breakdown of the output tokens.""" + reasoning_tokens: int """The number of reasoning tokens.""" class BatchUsage(BaseModel): + """ + Represents token usage details including input tokens, output tokens, a + breakdown of output tokens, and the total tokens used. Only populated on + batches created after September 7, 2025. + """ + input_tokens: int """The number of input tokens.""" diff --git a/src/openai/types/beta/assistant.py b/src/openai/types/beta/assistant.py index 58421e0f66..61344f85a1 100644 --- a/src/openai/types/beta/assistant.py +++ b/src/openai/types/beta/assistant.py @@ -31,12 +31,19 @@ class ToolResourcesFileSearch(BaseModel): class ToolResources(BaseModel): + """A set of resources that are used by the assistant's tools. + + The resources are specific to the type of tool. For example, the `code_interpreter` tool requires a list of file IDs, while the `file_search` tool requires a list of vector store IDs. + """ + code_interpreter: Optional[ToolResourcesCodeInterpreter] = None file_search: Optional[ToolResourcesFileSearch] = None class Assistant(BaseModel): + """Represents an `assistant` that can call the model and use tools.""" + id: str """The identifier, which can be referenced in API endpoints.""" diff --git a/src/openai/types/beta/assistant_create_params.py b/src/openai/types/beta/assistant_create_params.py index 38b30f212f..49e7af2d67 100644 --- a/src/openai/types/beta/assistant_create_params.py +++ b/src/openai/types/beta/assistant_create_params.py @@ -141,6 +141,11 @@ class ToolResourcesCodeInterpreter(TypedDict, total=False): class ToolResourcesFileSearchVectorStoreChunkingStrategyAuto(TypedDict, total=False): + """The default strategy. + + This strategy currently uses a `max_chunk_size_tokens` of `800` and `chunk_overlap_tokens` of `400`. + """ + type: Required[Literal["auto"]] """Always `auto`.""" @@ -216,6 +221,11 @@ class ToolResourcesFileSearch(TypedDict, total=False): class ToolResources(TypedDict, total=False): + """A set of resources that are used by the assistant's tools. + + The resources are specific to the type of tool. For example, the `code_interpreter` tool requires a list of file IDs, while the `file_search` tool requires a list of vector store IDs. + """ + code_interpreter: ToolResourcesCodeInterpreter file_search: ToolResourcesFileSearch diff --git a/src/openai/types/beta/assistant_stream_event.py b/src/openai/types/beta/assistant_stream_event.py index 41d3a0c5ea..87620a11d0 100644 --- a/src/openai/types/beta/assistant_stream_event.py +++ b/src/openai/types/beta/assistant_stream_event.py @@ -43,6 +43,10 @@ class ThreadCreated(BaseModel): + """ + Occurs when a new [thread](https://platform.openai.com/docs/api-reference/threads/object) is created. + """ + data: Thread """ Represents a thread that contains @@ -56,6 +60,10 @@ class ThreadCreated(BaseModel): class ThreadRunCreated(BaseModel): + """ + Occurs when a new [run](https://platform.openai.com/docs/api-reference/runs/object) is created. + """ + data: Run """ Represents an execution run on a @@ -66,6 +74,10 @@ class ThreadRunCreated(BaseModel): class ThreadRunQueued(BaseModel): + """ + Occurs when a [run](https://platform.openai.com/docs/api-reference/runs/object) moves to a `queued` status. + """ + data: Run """ Represents an execution run on a @@ -76,6 +88,10 @@ class ThreadRunQueued(BaseModel): class ThreadRunInProgress(BaseModel): + """ + Occurs when a [run](https://platform.openai.com/docs/api-reference/runs/object) moves to an `in_progress` status. + """ + data: Run """ Represents an execution run on a @@ -86,6 +102,10 @@ class ThreadRunInProgress(BaseModel): class ThreadRunRequiresAction(BaseModel): + """ + Occurs when a [run](https://platform.openai.com/docs/api-reference/runs/object) moves to a `requires_action` status. + """ + data: Run """ Represents an execution run on a @@ -96,6 +116,10 @@ class ThreadRunRequiresAction(BaseModel): class ThreadRunCompleted(BaseModel): + """ + Occurs when a [run](https://platform.openai.com/docs/api-reference/runs/object) is completed. + """ + data: Run """ Represents an execution run on a @@ -106,6 +130,10 @@ class ThreadRunCompleted(BaseModel): class ThreadRunIncomplete(BaseModel): + """ + Occurs when a [run](https://platform.openai.com/docs/api-reference/runs/object) ends with status `incomplete`. + """ + data: Run """ Represents an execution run on a @@ -116,6 +144,10 @@ class ThreadRunIncomplete(BaseModel): class ThreadRunFailed(BaseModel): + """ + Occurs when a [run](https://platform.openai.com/docs/api-reference/runs/object) fails. + """ + data: Run """ Represents an execution run on a @@ -126,6 +158,10 @@ class ThreadRunFailed(BaseModel): class ThreadRunCancelling(BaseModel): + """ + Occurs when a [run](https://platform.openai.com/docs/api-reference/runs/object) moves to a `cancelling` status. + """ + data: Run """ Represents an execution run on a @@ -136,6 +172,10 @@ class ThreadRunCancelling(BaseModel): class ThreadRunCancelled(BaseModel): + """ + Occurs when a [run](https://platform.openai.com/docs/api-reference/runs/object) is cancelled. + """ + data: Run """ Represents an execution run on a @@ -146,6 +186,10 @@ class ThreadRunCancelled(BaseModel): class ThreadRunExpired(BaseModel): + """ + Occurs when a [run](https://platform.openai.com/docs/api-reference/runs/object) expires. + """ + data: Run """ Represents an execution run on a @@ -156,6 +200,10 @@ class ThreadRunExpired(BaseModel): class ThreadRunStepCreated(BaseModel): + """ + Occurs when a [run step](https://platform.openai.com/docs/api-reference/run-steps/step-object) is created. + """ + data: RunStep """Represents a step in execution of a run.""" @@ -163,6 +211,10 @@ class ThreadRunStepCreated(BaseModel): class ThreadRunStepInProgress(BaseModel): + """ + Occurs when a [run step](https://platform.openai.com/docs/api-reference/run-steps/step-object) moves to an `in_progress` state. + """ + data: RunStep """Represents a step in execution of a run.""" @@ -170,6 +222,10 @@ class ThreadRunStepInProgress(BaseModel): class ThreadRunStepDelta(BaseModel): + """ + Occurs when parts of a [run step](https://platform.openai.com/docs/api-reference/run-steps/step-object) are being streamed. + """ + data: RunStepDeltaEvent """Represents a run step delta i.e. @@ -180,6 +236,10 @@ class ThreadRunStepDelta(BaseModel): class ThreadRunStepCompleted(BaseModel): + """ + Occurs when a [run step](https://platform.openai.com/docs/api-reference/run-steps/step-object) is completed. + """ + data: RunStep """Represents a step in execution of a run.""" @@ -187,6 +247,10 @@ class ThreadRunStepCompleted(BaseModel): class ThreadRunStepFailed(BaseModel): + """ + Occurs when a [run step](https://platform.openai.com/docs/api-reference/run-steps/step-object) fails. + """ + data: RunStep """Represents a step in execution of a run.""" @@ -194,6 +258,10 @@ class ThreadRunStepFailed(BaseModel): class ThreadRunStepCancelled(BaseModel): + """ + Occurs when a [run step](https://platform.openai.com/docs/api-reference/run-steps/step-object) is cancelled. + """ + data: RunStep """Represents a step in execution of a run.""" @@ -201,6 +269,10 @@ class ThreadRunStepCancelled(BaseModel): class ThreadRunStepExpired(BaseModel): + """ + Occurs when a [run step](https://platform.openai.com/docs/api-reference/run-steps/step-object) expires. + """ + data: RunStep """Represents a step in execution of a run.""" @@ -208,6 +280,10 @@ class ThreadRunStepExpired(BaseModel): class ThreadMessageCreated(BaseModel): + """ + Occurs when a [message](https://platform.openai.com/docs/api-reference/messages/object) is created. + """ + data: Message """ Represents a message within a @@ -218,6 +294,10 @@ class ThreadMessageCreated(BaseModel): class ThreadMessageInProgress(BaseModel): + """ + Occurs when a [message](https://platform.openai.com/docs/api-reference/messages/object) moves to an `in_progress` state. + """ + data: Message """ Represents a message within a @@ -228,6 +308,10 @@ class ThreadMessageInProgress(BaseModel): class ThreadMessageDelta(BaseModel): + """ + Occurs when parts of a [Message](https://platform.openai.com/docs/api-reference/messages/object) are being streamed. + """ + data: MessageDeltaEvent """Represents a message delta i.e. @@ -238,6 +322,10 @@ class ThreadMessageDelta(BaseModel): class ThreadMessageCompleted(BaseModel): + """ + Occurs when a [message](https://platform.openai.com/docs/api-reference/messages/object) is completed. + """ + data: Message """ Represents a message within a @@ -248,6 +336,10 @@ class ThreadMessageCompleted(BaseModel): class ThreadMessageIncomplete(BaseModel): + """ + Occurs when a [message](https://platform.openai.com/docs/api-reference/messages/object) ends before it is completed. + """ + data: Message """ Represents a message within a @@ -258,6 +350,10 @@ class ThreadMessageIncomplete(BaseModel): class ErrorEvent(BaseModel): + """ + Occurs when an [error](https://platform.openai.com/docs/guides/error-codes#api-errors) occurs. This can happen due to an internal server error or a timeout. + """ + data: ErrorObject event: Literal["error"] diff --git a/src/openai/types/beta/assistant_tool_choice.py b/src/openai/types/beta/assistant_tool_choice.py index d73439f006..cabded0b3c 100644 --- a/src/openai/types/beta/assistant_tool_choice.py +++ b/src/openai/types/beta/assistant_tool_choice.py @@ -10,6 +10,11 @@ class AssistantToolChoice(BaseModel): + """Specifies a tool the model should use. + + Use to force the model to call a specific tool. + """ + type: Literal["function", "code_interpreter", "file_search"] """The type of the tool. If type is `function`, the function name must be set""" diff --git a/src/openai/types/beta/assistant_tool_choice_param.py b/src/openai/types/beta/assistant_tool_choice_param.py index 904f489e26..05916bb668 100644 --- a/src/openai/types/beta/assistant_tool_choice_param.py +++ b/src/openai/types/beta/assistant_tool_choice_param.py @@ -10,6 +10,11 @@ class AssistantToolChoiceParam(TypedDict, total=False): + """Specifies a tool the model should use. + + Use to force the model to call a specific tool. + """ + type: Required[Literal["function", "code_interpreter", "file_search"]] """The type of the tool. If type is `function`, the function name must be set""" diff --git a/src/openai/types/beta/assistant_update_params.py b/src/openai/types/beta/assistant_update_params.py index 8f774c4e6c..d84b15cc5b 100644 --- a/src/openai/types/beta/assistant_update_params.py +++ b/src/openai/types/beta/assistant_update_params.py @@ -187,6 +187,11 @@ class ToolResourcesFileSearch(TypedDict, total=False): class ToolResources(TypedDict, total=False): + """A set of resources that are used by the assistant's tools. + + The resources are specific to the type of tool. For example, the `code_interpreter` tool requires a list of file IDs, while the `file_search` tool requires a list of vector store IDs. + """ + code_interpreter: ToolResourcesCodeInterpreter file_search: ToolResourcesFileSearch diff --git a/src/openai/types/beta/chatkit/chat_session.py b/src/openai/types/beta/chatkit/chat_session.py index 82baea211c..9db9fc93a0 100644 --- a/src/openai/types/beta/chatkit/chat_session.py +++ b/src/openai/types/beta/chatkit/chat_session.py @@ -12,6 +12,8 @@ class ChatSession(BaseModel): + """Represents a ChatKit session and its resolved configuration.""" + id: str """Identifier for the ChatKit session.""" diff --git a/src/openai/types/beta/chatkit/chat_session_automatic_thread_titling.py b/src/openai/types/beta/chatkit/chat_session_automatic_thread_titling.py index 4fa96a4433..1d95255e06 100644 --- a/src/openai/types/beta/chatkit/chat_session_automatic_thread_titling.py +++ b/src/openai/types/beta/chatkit/chat_session_automatic_thread_titling.py @@ -6,5 +6,7 @@ class ChatSessionAutomaticThreadTitling(BaseModel): + """Automatic thread title preferences for the session.""" + enabled: bool """Whether automatic thread titling is enabled.""" diff --git a/src/openai/types/beta/chatkit/chat_session_chatkit_configuration.py b/src/openai/types/beta/chatkit/chat_session_chatkit_configuration.py index 6205b172cf..f9fa0ceff5 100644 --- a/src/openai/types/beta/chatkit/chat_session_chatkit_configuration.py +++ b/src/openai/types/beta/chatkit/chat_session_chatkit_configuration.py @@ -9,6 +9,8 @@ class ChatSessionChatKitConfiguration(BaseModel): + """ChatKit configuration for the session.""" + automatic_thread_titling: ChatSessionAutomaticThreadTitling """Automatic thread titling preferences.""" diff --git a/src/openai/types/beta/chatkit/chat_session_chatkit_configuration_param.py b/src/openai/types/beta/chatkit/chat_session_chatkit_configuration_param.py index 0a5ae80a76..834de71e71 100644 --- a/src/openai/types/beta/chatkit/chat_session_chatkit_configuration_param.py +++ b/src/openai/types/beta/chatkit/chat_session_chatkit_configuration_param.py @@ -8,11 +8,21 @@ class AutomaticThreadTitling(TypedDict, total=False): + """Configuration for automatic thread titling. + + When omitted, automatic thread titling is enabled by default. + """ + enabled: bool """Enable automatic thread title generation. Defaults to true.""" class FileUpload(TypedDict, total=False): + """Configuration for upload enablement and limits. + + When omitted, uploads are disabled by default (max_files 10, max_file_size 512 MB). + """ + enabled: bool """Enable uploads for this session. Defaults to false.""" @@ -27,6 +37,11 @@ class FileUpload(TypedDict, total=False): class History(TypedDict, total=False): + """Configuration for chat history retention. + + When omitted, history is enabled by default with no limit on recent_threads (null). + """ + enabled: bool """Enables chat users to access previous ChatKit threads. Defaults to true.""" @@ -38,6 +53,8 @@ class History(TypedDict, total=False): class ChatSessionChatKitConfigurationParam(TypedDict, total=False): + """Optional per-session configuration settings for ChatKit behavior.""" + automatic_thread_titling: AutomaticThreadTitling """Configuration for automatic thread titling. diff --git a/src/openai/types/beta/chatkit/chat_session_expires_after_param.py b/src/openai/types/beta/chatkit/chat_session_expires_after_param.py index ceb5a984c5..c1de8a767a 100644 --- a/src/openai/types/beta/chatkit/chat_session_expires_after_param.py +++ b/src/openai/types/beta/chatkit/chat_session_expires_after_param.py @@ -8,6 +8,8 @@ class ChatSessionExpiresAfterParam(TypedDict, total=False): + """Controls when the session expires relative to an anchor timestamp.""" + anchor: Required[Literal["created_at"]] """Base timestamp used to calculate expiration. Currently fixed to `created_at`.""" diff --git a/src/openai/types/beta/chatkit/chat_session_file_upload.py b/src/openai/types/beta/chatkit/chat_session_file_upload.py index c63c7a0149..0275859d27 100644 --- a/src/openai/types/beta/chatkit/chat_session_file_upload.py +++ b/src/openai/types/beta/chatkit/chat_session_file_upload.py @@ -8,6 +8,8 @@ class ChatSessionFileUpload(BaseModel): + """Upload permissions and limits applied to the session.""" + enabled: bool """Indicates if uploads are enabled for the session.""" diff --git a/src/openai/types/beta/chatkit/chat_session_history.py b/src/openai/types/beta/chatkit/chat_session_history.py index 66ebe00877..54690009c2 100644 --- a/src/openai/types/beta/chatkit/chat_session_history.py +++ b/src/openai/types/beta/chatkit/chat_session_history.py @@ -8,6 +8,8 @@ class ChatSessionHistory(BaseModel): + """History retention preferences returned for the session.""" + enabled: bool """Indicates if chat history is persisted for the session.""" diff --git a/src/openai/types/beta/chatkit/chat_session_rate_limits.py b/src/openai/types/beta/chatkit/chat_session_rate_limits.py index 392225e347..7c5bd94e76 100644 --- a/src/openai/types/beta/chatkit/chat_session_rate_limits.py +++ b/src/openai/types/beta/chatkit/chat_session_rate_limits.py @@ -6,5 +6,7 @@ class ChatSessionRateLimits(BaseModel): + """Active per-minute request limit for the session.""" + max_requests_per_1_minute: int """Maximum allowed requests per one-minute window.""" diff --git a/src/openai/types/beta/chatkit/chat_session_rate_limits_param.py b/src/openai/types/beta/chatkit/chat_session_rate_limits_param.py index 7894c06484..578f20b0c3 100644 --- a/src/openai/types/beta/chatkit/chat_session_rate_limits_param.py +++ b/src/openai/types/beta/chatkit/chat_session_rate_limits_param.py @@ -8,5 +8,7 @@ class ChatSessionRateLimitsParam(TypedDict, total=False): + """Controls request rate limits for the session.""" + max_requests_per_1_minute: int """Maximum number of requests allowed per minute for the session. Defaults to 10.""" diff --git a/src/openai/types/beta/chatkit/chat_session_workflow_param.py b/src/openai/types/beta/chatkit/chat_session_workflow_param.py index 5542922102..abf52de526 100644 --- a/src/openai/types/beta/chatkit/chat_session_workflow_param.py +++ b/src/openai/types/beta/chatkit/chat_session_workflow_param.py @@ -9,11 +9,18 @@ class Tracing(TypedDict, total=False): + """Optional tracing overrides for the workflow invocation. + + When omitted, tracing is enabled by default. + """ + enabled: bool """Whether tracing is enabled during the session. Defaults to true.""" class ChatSessionWorkflowParam(TypedDict, total=False): + """Workflow reference and overrides applied to the chat session.""" + id: Required[str] """Identifier for the workflow invoked by the session.""" diff --git a/src/openai/types/beta/chatkit/chatkit_attachment.py b/src/openai/types/beta/chatkit/chatkit_attachment.py index 8d8ad3e128..7750925e03 100644 --- a/src/openai/types/beta/chatkit/chatkit_attachment.py +++ b/src/openai/types/beta/chatkit/chatkit_attachment.py @@ -9,6 +9,8 @@ class ChatKitAttachment(BaseModel): + """Attachment metadata included on thread items.""" + id: str """Identifier for the attachment.""" diff --git a/src/openai/types/beta/chatkit/chatkit_response_output_text.py b/src/openai/types/beta/chatkit/chatkit_response_output_text.py index 116b797ec2..1348fed2b2 100644 --- a/src/openai/types/beta/chatkit/chatkit_response_output_text.py +++ b/src/openai/types/beta/chatkit/chatkit_response_output_text.py @@ -17,6 +17,8 @@ class AnnotationFileSource(BaseModel): + """File attachment referenced by the annotation.""" + filename: str """Filename referenced by the annotation.""" @@ -25,6 +27,8 @@ class AnnotationFileSource(BaseModel): class AnnotationFile(BaseModel): + """Annotation that references an uploaded file.""" + source: AnnotationFileSource """File attachment referenced by the annotation.""" @@ -33,6 +37,8 @@ class AnnotationFile(BaseModel): class AnnotationURLSource(BaseModel): + """URL referenced by the annotation.""" + type: Literal["url"] """Type discriminator that is always `url`.""" @@ -41,6 +47,8 @@ class AnnotationURLSource(BaseModel): class AnnotationURL(BaseModel): + """Annotation that references a URL.""" + source: AnnotationURLSource """URL referenced by the annotation.""" @@ -52,6 +60,8 @@ class AnnotationURL(BaseModel): class ChatKitResponseOutputText(BaseModel): + """Assistant response text accompanied by optional annotations.""" + annotations: List[Annotation] """Ordered list of annotations attached to the response text.""" diff --git a/src/openai/types/beta/chatkit/chatkit_thread.py b/src/openai/types/beta/chatkit/chatkit_thread.py index abd1a9ea01..32075233d8 100644 --- a/src/openai/types/beta/chatkit/chatkit_thread.py +++ b/src/openai/types/beta/chatkit/chatkit_thread.py @@ -10,11 +10,15 @@ class StatusActive(BaseModel): + """Indicates that a thread is active.""" + type: Literal["active"] """Status discriminator that is always `active`.""" class StatusLocked(BaseModel): + """Indicates that a thread is locked and cannot accept new input.""" + reason: Optional[str] = None """Reason that the thread was locked. Defaults to null when no reason is recorded.""" @@ -23,6 +27,8 @@ class StatusLocked(BaseModel): class StatusClosed(BaseModel): + """Indicates that a thread has been closed.""" + reason: Optional[str] = None """Reason that the thread was closed. Defaults to null when no reason is recorded.""" @@ -34,6 +40,8 @@ class StatusClosed(BaseModel): class ChatKitThread(BaseModel): + """Represents a ChatKit thread and its current status.""" + id: str """Identifier of the thread.""" diff --git a/src/openai/types/beta/chatkit/chatkit_thread_assistant_message_item.py b/src/openai/types/beta/chatkit/chatkit_thread_assistant_message_item.py index f4afd053b6..337f53a83d 100644 --- a/src/openai/types/beta/chatkit/chatkit_thread_assistant_message_item.py +++ b/src/openai/types/beta/chatkit/chatkit_thread_assistant_message_item.py @@ -10,6 +10,8 @@ class ChatKitThreadAssistantMessageItem(BaseModel): + """Assistant-authored message within a thread.""" + id: str """Identifier of the thread item.""" diff --git a/src/openai/types/beta/chatkit/chatkit_thread_item_list.py b/src/openai/types/beta/chatkit/chatkit_thread_item_list.py index 173bd15055..049ca54429 100644 --- a/src/openai/types/beta/chatkit/chatkit_thread_item_list.py +++ b/src/openai/types/beta/chatkit/chatkit_thread_item_list.py @@ -20,6 +20,8 @@ class DataChatKitClientToolCall(BaseModel): + """Record of a client side tool invocation initiated by the assistant.""" + id: str """Identifier of the thread item.""" @@ -55,6 +57,8 @@ class DataChatKitClientToolCall(BaseModel): class DataChatKitTask(BaseModel): + """Task emitted by the workflow to show progress and status updates.""" + id: str """Identifier of the thread item.""" @@ -81,6 +85,8 @@ class DataChatKitTask(BaseModel): class DataChatKitTaskGroupTask(BaseModel): + """Task entry that appears within a TaskGroup.""" + heading: Optional[str] = None """Optional heading for the grouped task. Defaults to null when not provided.""" @@ -95,6 +101,8 @@ class DataChatKitTaskGroupTask(BaseModel): class DataChatKitTaskGroup(BaseModel): + """Collection of workflow tasks grouped together in the thread.""" + id: str """Identifier of the thread item.""" @@ -128,6 +136,8 @@ class DataChatKitTaskGroup(BaseModel): class ChatKitThreadItemList(BaseModel): + """A paginated list of thread items rendered for the ChatKit API.""" + data: List[Data] """A list of items""" diff --git a/src/openai/types/beta/chatkit/chatkit_thread_user_message_item.py b/src/openai/types/beta/chatkit/chatkit_thread_user_message_item.py index 233d07232f..d7552c4f2e 100644 --- a/src/openai/types/beta/chatkit/chatkit_thread_user_message_item.py +++ b/src/openai/types/beta/chatkit/chatkit_thread_user_message_item.py @@ -18,6 +18,8 @@ class ContentInputText(BaseModel): + """Text block that a user contributed to the thread.""" + text: str """Plain-text content supplied by the user.""" @@ -26,6 +28,8 @@ class ContentInputText(BaseModel): class ContentQuotedText(BaseModel): + """Quoted snippet that the user referenced in their message.""" + text: str """Quoted text content.""" @@ -37,11 +41,15 @@ class ContentQuotedText(BaseModel): class InferenceOptionsToolChoice(BaseModel): + """Preferred tool to invoke. Defaults to null when ChatKit should auto-select.""" + id: str """Identifier of the requested tool.""" class InferenceOptions(BaseModel): + """Inference overrides applied to the message. Defaults to null when unset.""" + model: Optional[str] = None """Model name that generated the response. @@ -53,6 +61,8 @@ class InferenceOptions(BaseModel): class ChatKitThreadUserMessageItem(BaseModel): + """User-authored messages within a thread.""" + id: str """Identifier of the thread item.""" diff --git a/src/openai/types/beta/chatkit/chatkit_widget_item.py b/src/openai/types/beta/chatkit/chatkit_widget_item.py index c7f182259a..a269c736fb 100644 --- a/src/openai/types/beta/chatkit/chatkit_widget_item.py +++ b/src/openai/types/beta/chatkit/chatkit_widget_item.py @@ -8,6 +8,8 @@ class ChatKitWidgetItem(BaseModel): + """Thread item that renders a widget payload.""" + id: str """Identifier of the thread item.""" diff --git a/src/openai/types/beta/chatkit/thread_delete_response.py b/src/openai/types/beta/chatkit/thread_delete_response.py index 03fdec9c2c..45b686bf8b 100644 --- a/src/openai/types/beta/chatkit/thread_delete_response.py +++ b/src/openai/types/beta/chatkit/thread_delete_response.py @@ -8,6 +8,8 @@ class ThreadDeleteResponse(BaseModel): + """Confirmation payload returned after deleting a thread.""" + id: str """Identifier of the deleted thread.""" diff --git a/src/openai/types/beta/chatkit_workflow.py b/src/openai/types/beta/chatkit_workflow.py index 00fbcf41ce..b6f5b55b4a 100644 --- a/src/openai/types/beta/chatkit_workflow.py +++ b/src/openai/types/beta/chatkit_workflow.py @@ -8,11 +8,15 @@ class Tracing(BaseModel): + """Tracing settings applied to the workflow.""" + enabled: bool """Indicates whether tracing is enabled.""" class ChatKitWorkflow(BaseModel): + """Workflow metadata and state returned for the session.""" + id: str """Identifier of the workflow backing the session.""" diff --git a/src/openai/types/beta/file_search_tool.py b/src/openai/types/beta/file_search_tool.py index 89fc16c04c..9e33249e0b 100644 --- a/src/openai/types/beta/file_search_tool.py +++ b/src/openai/types/beta/file_search_tool.py @@ -9,6 +9,13 @@ class FileSearchRankingOptions(BaseModel): + """The ranking options for the file search. + + If not specified, the file search tool will use the `auto` ranker and a score_threshold of 0. + + See the [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) for more information. + """ + score_threshold: float """The score threshold for the file search. @@ -23,6 +30,8 @@ class FileSearchRankingOptions(BaseModel): class FileSearch(BaseModel): + """Overrides for the file search tool.""" + max_num_results: Optional[int] = None """The maximum number of results the file search tool should output. diff --git a/src/openai/types/beta/file_search_tool_param.py b/src/openai/types/beta/file_search_tool_param.py index c73d0af79d..9906b4b2a4 100644 --- a/src/openai/types/beta/file_search_tool_param.py +++ b/src/openai/types/beta/file_search_tool_param.py @@ -8,6 +8,13 @@ class FileSearchRankingOptions(TypedDict, total=False): + """The ranking options for the file search. + + If not specified, the file search tool will use the `auto` ranker and a score_threshold of 0. + + See the [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) for more information. + """ + score_threshold: Required[float] """The score threshold for the file search. @@ -22,6 +29,8 @@ class FileSearchRankingOptions(TypedDict, total=False): class FileSearch(TypedDict, total=False): + """Overrides for the file search tool.""" + max_num_results: int """The maximum number of results the file search tool should output. diff --git a/src/openai/types/beta/thread.py b/src/openai/types/beta/thread.py index 789f66e48b..83d9055194 100644 --- a/src/openai/types/beta/thread.py +++ b/src/openai/types/beta/thread.py @@ -29,12 +29,20 @@ class ToolResourcesFileSearch(BaseModel): class ToolResources(BaseModel): + """ + A set of resources that are made available to the assistant's tools in this thread. The resources are specific to the type of tool. For example, the `code_interpreter` tool requires a list of file IDs, while the `file_search` tool requires a list of vector store IDs. + """ + code_interpreter: Optional[ToolResourcesCodeInterpreter] = None file_search: Optional[ToolResourcesFileSearch] = None class Thread(BaseModel): + """ + Represents a thread that contains [messages](https://platform.openai.com/docs/api-reference/messages). + """ + id: str """The identifier, which can be referenced in API endpoints.""" diff --git a/src/openai/types/beta/thread_create_and_run_params.py b/src/openai/types/beta/thread_create_and_run_params.py index 734e5e2a4e..c0aee3e9f8 100644 --- a/src/openai/types/beta/thread_create_and_run_params.py +++ b/src/openai/types/beta/thread_create_and_run_params.py @@ -227,6 +227,11 @@ class ThreadToolResourcesCodeInterpreter(TypedDict, total=False): class ThreadToolResourcesFileSearchVectorStoreChunkingStrategyAuto(TypedDict, total=False): + """The default strategy. + + This strategy currently uses a `max_chunk_size_tokens` of `800` and `chunk_overlap_tokens` of `400`. + """ + type: Required[Literal["auto"]] """Always `auto`.""" @@ -303,12 +308,22 @@ class ThreadToolResourcesFileSearch(TypedDict, total=False): class ThreadToolResources(TypedDict, total=False): + """ + A set of resources that are made available to the assistant's tools in this thread. The resources are specific to the type of tool. For example, the `code_interpreter` tool requires a list of file IDs, while the `file_search` tool requires a list of vector store IDs. + """ + code_interpreter: ThreadToolResourcesCodeInterpreter file_search: ThreadToolResourcesFileSearch class Thread(TypedDict, total=False): + """Options to create a new thread. + + If no thread is provided when running a + request, an empty thread will be created. + """ + messages: Iterable[ThreadMessage] """ A list of [messages](https://platform.openai.com/docs/api-reference/messages) to @@ -354,12 +369,22 @@ class ToolResourcesFileSearch(TypedDict, total=False): class ToolResources(TypedDict, total=False): + """A set of resources that are used by the assistant's tools. + + The resources are specific to the type of tool. For example, the `code_interpreter` tool requires a list of file IDs, while the `file_search` tool requires a list of vector store IDs. + """ + code_interpreter: ToolResourcesCodeInterpreter file_search: ToolResourcesFileSearch class TruncationStrategy(TypedDict, total=False): + """Controls for how a thread will be truncated prior to the run. + + Use this to control the initial context window of the run. + """ + type: Required[Literal["auto", "last_messages"]] """The truncation strategy to use for the thread. diff --git a/src/openai/types/beta/thread_create_params.py b/src/openai/types/beta/thread_create_params.py index 8fd9f38df7..ef83e3d465 100644 --- a/src/openai/types/beta/thread_create_params.py +++ b/src/openai/types/beta/thread_create_params.py @@ -106,6 +106,11 @@ class ToolResourcesCodeInterpreter(TypedDict, total=False): class ToolResourcesFileSearchVectorStoreChunkingStrategyAuto(TypedDict, total=False): + """The default strategy. + + This strategy currently uses a `max_chunk_size_tokens` of `800` and `chunk_overlap_tokens` of `400`. + """ + type: Required[Literal["auto"]] """Always `auto`.""" @@ -181,6 +186,10 @@ class ToolResourcesFileSearch(TypedDict, total=False): class ToolResources(TypedDict, total=False): + """ + A set of resources that are made available to the assistant's tools in this thread. The resources are specific to the type of tool. For example, the `code_interpreter` tool requires a list of file IDs, while the `file_search` tool requires a list of vector store IDs. + """ + code_interpreter: ToolResourcesCodeInterpreter file_search: ToolResourcesFileSearch diff --git a/src/openai/types/beta/thread_update_params.py b/src/openai/types/beta/thread_update_params.py index 464ea8d7eb..e000edc05f 100644 --- a/src/openai/types/beta/thread_update_params.py +++ b/src/openai/types/beta/thread_update_params.py @@ -51,6 +51,10 @@ class ToolResourcesFileSearch(TypedDict, total=False): class ToolResources(TypedDict, total=False): + """ + A set of resources that are made available to the assistant's tools in this thread. The resources are specific to the type of tool. For example, the `code_interpreter` tool requires a list of file IDs, while the `file_search` tool requires a list of vector store IDs. + """ + code_interpreter: ToolResourcesCodeInterpreter file_search: ToolResourcesFileSearch diff --git a/src/openai/types/beta/threads/file_citation_annotation.py b/src/openai/types/beta/threads/file_citation_annotation.py index c3085aed9b..929da0ac56 100644 --- a/src/openai/types/beta/threads/file_citation_annotation.py +++ b/src/openai/types/beta/threads/file_citation_annotation.py @@ -13,6 +13,10 @@ class FileCitation(BaseModel): class FileCitationAnnotation(BaseModel): + """ + A citation within the message that points to a specific quote from a specific File associated with the assistant or the message. Generated when the assistant uses the "file_search" tool to search files. + """ + end_index: int file_citation: FileCitation diff --git a/src/openai/types/beta/threads/file_citation_delta_annotation.py b/src/openai/types/beta/threads/file_citation_delta_annotation.py index b40c0d123e..591e322332 100644 --- a/src/openai/types/beta/threads/file_citation_delta_annotation.py +++ b/src/openai/types/beta/threads/file_citation_delta_annotation.py @@ -17,6 +17,10 @@ class FileCitation(BaseModel): class FileCitationDeltaAnnotation(BaseModel): + """ + A citation within the message that points to a specific quote from a specific File associated with the assistant or the message. Generated when the assistant uses the "file_search" tool to search files. + """ + index: int """The index of the annotation in the text content part.""" diff --git a/src/openai/types/beta/threads/file_path_annotation.py b/src/openai/types/beta/threads/file_path_annotation.py index 9812737ece..d3c144c2fc 100644 --- a/src/openai/types/beta/threads/file_path_annotation.py +++ b/src/openai/types/beta/threads/file_path_annotation.py @@ -13,6 +13,10 @@ class FilePath(BaseModel): class FilePathAnnotation(BaseModel): + """ + A URL for the file that's generated when the assistant used the `code_interpreter` tool to generate a file. + """ + end_index: int file_path: FilePath diff --git a/src/openai/types/beta/threads/file_path_delta_annotation.py b/src/openai/types/beta/threads/file_path_delta_annotation.py index 0cbb445e48..5416874749 100644 --- a/src/openai/types/beta/threads/file_path_delta_annotation.py +++ b/src/openai/types/beta/threads/file_path_delta_annotation.py @@ -14,6 +14,10 @@ class FilePath(BaseModel): class FilePathDeltaAnnotation(BaseModel): + """ + A URL for the file that's generated when the assistant used the `code_interpreter` tool to generate a file. + """ + index: int """The index of the annotation in the text content part.""" diff --git a/src/openai/types/beta/threads/image_file_content_block.py b/src/openai/types/beta/threads/image_file_content_block.py index a909999065..5a082cd488 100644 --- a/src/openai/types/beta/threads/image_file_content_block.py +++ b/src/openai/types/beta/threads/image_file_content_block.py @@ -9,6 +9,10 @@ class ImageFileContentBlock(BaseModel): + """ + References an image [File](https://platform.openai.com/docs/api-reference/files) in the content of a message. + """ + image_file: ImageFile type: Literal["image_file"] diff --git a/src/openai/types/beta/threads/image_file_content_block_param.py b/src/openai/types/beta/threads/image_file_content_block_param.py index 48d94bee36..da095a5ff6 100644 --- a/src/openai/types/beta/threads/image_file_content_block_param.py +++ b/src/openai/types/beta/threads/image_file_content_block_param.py @@ -10,6 +10,10 @@ class ImageFileContentBlockParam(TypedDict, total=False): + """ + References an image [File](https://platform.openai.com/docs/api-reference/files) in the content of a message. + """ + image_file: Required[ImageFileParam] type: Required[Literal["image_file"]] diff --git a/src/openai/types/beta/threads/image_file_delta_block.py b/src/openai/types/beta/threads/image_file_delta_block.py index 0a5a2e8a5f..ed17f7ff3b 100644 --- a/src/openai/types/beta/threads/image_file_delta_block.py +++ b/src/openai/types/beta/threads/image_file_delta_block.py @@ -10,6 +10,10 @@ class ImageFileDeltaBlock(BaseModel): + """ + References an image [File](https://platform.openai.com/docs/api-reference/files) in the content of a message. + """ + index: int """The index of the content part in the message.""" diff --git a/src/openai/types/beta/threads/image_url_content_block.py b/src/openai/types/beta/threads/image_url_content_block.py index 40a16c1df8..8dc1f16a7a 100644 --- a/src/openai/types/beta/threads/image_url_content_block.py +++ b/src/openai/types/beta/threads/image_url_content_block.py @@ -9,6 +9,8 @@ class ImageURLContentBlock(BaseModel): + """References an image URL in the content of a message.""" + image_url: ImageURL type: Literal["image_url"] diff --git a/src/openai/types/beta/threads/image_url_content_block_param.py b/src/openai/types/beta/threads/image_url_content_block_param.py index 585b926c58..a5c59e02c2 100644 --- a/src/openai/types/beta/threads/image_url_content_block_param.py +++ b/src/openai/types/beta/threads/image_url_content_block_param.py @@ -10,6 +10,8 @@ class ImageURLContentBlockParam(TypedDict, total=False): + """References an image URL in the content of a message.""" + image_url: Required[ImageURLParam] type: Required[Literal["image_url"]] diff --git a/src/openai/types/beta/threads/image_url_delta_block.py b/src/openai/types/beta/threads/image_url_delta_block.py index 5252da12dd..3128d8e709 100644 --- a/src/openai/types/beta/threads/image_url_delta_block.py +++ b/src/openai/types/beta/threads/image_url_delta_block.py @@ -10,6 +10,8 @@ class ImageURLDeltaBlock(BaseModel): + """References an image URL in the content of a message.""" + index: int """The index of the content part in the message.""" diff --git a/src/openai/types/beta/threads/message.py b/src/openai/types/beta/threads/message.py index 4a05a128eb..fc7f73f091 100644 --- a/src/openai/types/beta/threads/message.py +++ b/src/openai/types/beta/threads/message.py @@ -34,11 +34,17 @@ class Attachment(BaseModel): class IncompleteDetails(BaseModel): + """On an incomplete message, details about why the message is incomplete.""" + reason: Literal["content_filter", "max_tokens", "run_cancelled", "run_expired", "run_failed"] """The reason the message is incomplete.""" class Message(BaseModel): + """ + Represents a message within a [thread](https://platform.openai.com/docs/api-reference/threads). + """ + id: str """The identifier, which can be referenced in API endpoints.""" diff --git a/src/openai/types/beta/threads/message_delta.py b/src/openai/types/beta/threads/message_delta.py index ecd0dfe319..fdeebb3a12 100644 --- a/src/openai/types/beta/threads/message_delta.py +++ b/src/openai/types/beta/threads/message_delta.py @@ -10,6 +10,8 @@ class MessageDelta(BaseModel): + """The delta containing the fields that have changed on the Message.""" + content: Optional[List[MessageContentDelta]] = None """The content of the message in array of text and/or images.""" diff --git a/src/openai/types/beta/threads/message_delta_event.py b/src/openai/types/beta/threads/message_delta_event.py index 3811cef679..d5ba1e172d 100644 --- a/src/openai/types/beta/threads/message_delta_event.py +++ b/src/openai/types/beta/threads/message_delta_event.py @@ -9,6 +9,11 @@ class MessageDeltaEvent(BaseModel): + """Represents a message delta i.e. + + any changed fields on a message during streaming. + """ + id: str """The identifier of the message, which can be referenced in API endpoints.""" diff --git a/src/openai/types/beta/threads/refusal_content_block.py b/src/openai/types/beta/threads/refusal_content_block.py index d54f948554..b4512b3ccb 100644 --- a/src/openai/types/beta/threads/refusal_content_block.py +++ b/src/openai/types/beta/threads/refusal_content_block.py @@ -8,6 +8,8 @@ class RefusalContentBlock(BaseModel): + """The refusal content generated by the assistant.""" + refusal: str type: Literal["refusal"] diff --git a/src/openai/types/beta/threads/refusal_delta_block.py b/src/openai/types/beta/threads/refusal_delta_block.py index dbd8e62697..85a1f08db1 100644 --- a/src/openai/types/beta/threads/refusal_delta_block.py +++ b/src/openai/types/beta/threads/refusal_delta_block.py @@ -9,6 +9,8 @@ class RefusalDeltaBlock(BaseModel): + """The refusal content that is part of a message.""" + index: int """The index of the refusal part in the message.""" diff --git a/src/openai/types/beta/threads/required_action_function_tool_call.py b/src/openai/types/beta/threads/required_action_function_tool_call.py index a24dfd068b..3cec8514ca 100644 --- a/src/openai/types/beta/threads/required_action_function_tool_call.py +++ b/src/openai/types/beta/threads/required_action_function_tool_call.py @@ -8,6 +8,8 @@ class Function(BaseModel): + """The function definition.""" + arguments: str """The arguments that the model expects you to pass to the function.""" @@ -16,6 +18,8 @@ class Function(BaseModel): class RequiredActionFunctionToolCall(BaseModel): + """Tool call objects""" + id: str """The ID of the tool call. diff --git a/src/openai/types/beta/threads/run.py b/src/openai/types/beta/threads/run.py index c545cc3759..8a88fa1673 100644 --- a/src/openai/types/beta/threads/run.py +++ b/src/openai/types/beta/threads/run.py @@ -23,6 +23,11 @@ class IncompleteDetails(BaseModel): + """Details on why the run is incomplete. + + Will be `null` if the run is not incomplete. + """ + reason: Optional[Literal["max_completion_tokens", "max_prompt_tokens"]] = None """The reason why the run is incomplete. @@ -32,6 +37,8 @@ class IncompleteDetails(BaseModel): class LastError(BaseModel): + """The last error associated with this run. Will be `null` if there are no errors.""" + code: Literal["server_error", "rate_limit_exceeded", "invalid_prompt"] """One of `server_error`, `rate_limit_exceeded`, or `invalid_prompt`.""" @@ -40,11 +47,18 @@ class LastError(BaseModel): class RequiredActionSubmitToolOutputs(BaseModel): + """Details on the tool outputs needed for this run to continue.""" + tool_calls: List[RequiredActionFunctionToolCall] """A list of the relevant tool calls.""" class RequiredAction(BaseModel): + """Details on the action required to continue the run. + + Will be `null` if no action is required. + """ + submit_tool_outputs: RequiredActionSubmitToolOutputs """Details on the tool outputs needed for this run to continue.""" @@ -53,6 +67,11 @@ class RequiredAction(BaseModel): class TruncationStrategy(BaseModel): + """Controls for how a thread will be truncated prior to the run. + + Use this to control the initial context window of the run. + """ + type: Literal["auto", "last_messages"] """The truncation strategy to use for the thread. @@ -70,6 +89,11 @@ class TruncationStrategy(BaseModel): class Usage(BaseModel): + """Usage statistics related to the run. + + This value will be `null` if the run is not in a terminal state (i.e. `in_progress`, `queued`, etc.). + """ + completion_tokens: int """Number of completion tokens used over the course of the run.""" @@ -81,6 +105,10 @@ class Usage(BaseModel): class Run(BaseModel): + """ + Represents an execution run on a [thread](https://platform.openai.com/docs/api-reference/threads). + """ + id: str """The identifier, which can be referenced in API endpoints.""" diff --git a/src/openai/types/beta/threads/run_create_params.py b/src/openai/types/beta/threads/run_create_params.py index df789decbc..f4c56feb56 100644 --- a/src/openai/types/beta/threads/run_create_params.py +++ b/src/openai/types/beta/threads/run_create_params.py @@ -232,6 +232,11 @@ class AdditionalMessage(TypedDict, total=False): class TruncationStrategy(TypedDict, total=False): + """Controls for how a thread will be truncated prior to the run. + + Use this to control the initial context window of the run. + """ + type: Required[Literal["auto", "last_messages"]] """The truncation strategy to use for the thread. diff --git a/src/openai/types/beta/threads/runs/code_interpreter_logs.py b/src/openai/types/beta/threads/runs/code_interpreter_logs.py index 0bf8c1dac2..722fd2b4c4 100644 --- a/src/openai/types/beta/threads/runs/code_interpreter_logs.py +++ b/src/openai/types/beta/threads/runs/code_interpreter_logs.py @@ -9,6 +9,8 @@ class CodeInterpreterLogs(BaseModel): + """Text output from the Code Interpreter tool call as part of a run step.""" + index: int """The index of the output in the outputs array.""" diff --git a/src/openai/types/beta/threads/runs/code_interpreter_tool_call.py b/src/openai/types/beta/threads/runs/code_interpreter_tool_call.py index e7df4e19c4..bc78b5fa3d 100644 --- a/src/openai/types/beta/threads/runs/code_interpreter_tool_call.py +++ b/src/openai/types/beta/threads/runs/code_interpreter_tool_call.py @@ -17,6 +17,8 @@ class CodeInterpreterOutputLogs(BaseModel): + """Text output from the Code Interpreter tool call as part of a run step.""" + logs: str """The text output from the Code Interpreter tool call.""" @@ -45,6 +47,8 @@ class CodeInterpreterOutputImage(BaseModel): class CodeInterpreter(BaseModel): + """The Code Interpreter tool call definition.""" + input: str """The input to the Code Interpreter tool call.""" @@ -57,6 +61,8 @@ class CodeInterpreter(BaseModel): class CodeInterpreterToolCall(BaseModel): + """Details of the Code Interpreter tool call the run step was involved in.""" + id: str """The ID of the tool call.""" diff --git a/src/openai/types/beta/threads/runs/code_interpreter_tool_call_delta.py b/src/openai/types/beta/threads/runs/code_interpreter_tool_call_delta.py index 9d7a1563cd..efedac795c 100644 --- a/src/openai/types/beta/threads/runs/code_interpreter_tool_call_delta.py +++ b/src/openai/types/beta/threads/runs/code_interpreter_tool_call_delta.py @@ -16,6 +16,8 @@ class CodeInterpreter(BaseModel): + """The Code Interpreter tool call definition.""" + input: Optional[str] = None """The input to the Code Interpreter tool call.""" @@ -28,6 +30,8 @@ class CodeInterpreter(BaseModel): class CodeInterpreterToolCallDelta(BaseModel): + """Details of the Code Interpreter tool call the run step was involved in.""" + index: int """The index of the tool call in the tool calls array.""" diff --git a/src/openai/types/beta/threads/runs/file_search_tool_call.py b/src/openai/types/beta/threads/runs/file_search_tool_call.py index a2068daad1..291a93ec65 100644 --- a/src/openai/types/beta/threads/runs/file_search_tool_call.py +++ b/src/openai/types/beta/threads/runs/file_search_tool_call.py @@ -15,6 +15,8 @@ class FileSearchRankingOptions(BaseModel): + """The ranking options for the file search.""" + ranker: Literal["auto", "default_2024_08_21"] """The ranker to use for the file search. @@ -37,6 +39,8 @@ class FileSearchResultContent(BaseModel): class FileSearchResult(BaseModel): + """A result instance of the file search.""" + file_id: str """The ID of the file that result was found in.""" @@ -57,6 +61,8 @@ class FileSearchResult(BaseModel): class FileSearch(BaseModel): + """For now, this is always going to be an empty object.""" + ranking_options: Optional[FileSearchRankingOptions] = None """The ranking options for the file search.""" diff --git a/src/openai/types/beta/threads/runs/function_tool_call.py b/src/openai/types/beta/threads/runs/function_tool_call.py index b1d354f894..dd0e22cfb1 100644 --- a/src/openai/types/beta/threads/runs/function_tool_call.py +++ b/src/openai/types/beta/threads/runs/function_tool_call.py @@ -9,6 +9,8 @@ class Function(BaseModel): + """The definition of the function that was called.""" + arguments: str """The arguments passed to the function.""" diff --git a/src/openai/types/beta/threads/runs/function_tool_call_delta.py b/src/openai/types/beta/threads/runs/function_tool_call_delta.py index faaf026f7f..4107e1b873 100644 --- a/src/openai/types/beta/threads/runs/function_tool_call_delta.py +++ b/src/openai/types/beta/threads/runs/function_tool_call_delta.py @@ -9,6 +9,8 @@ class Function(BaseModel): + """The definition of the function that was called.""" + arguments: Optional[str] = None """The arguments passed to the function.""" diff --git a/src/openai/types/beta/threads/runs/message_creation_step_details.py b/src/openai/types/beta/threads/runs/message_creation_step_details.py index 73439079d3..cd925b57ce 100644 --- a/src/openai/types/beta/threads/runs/message_creation_step_details.py +++ b/src/openai/types/beta/threads/runs/message_creation_step_details.py @@ -13,6 +13,8 @@ class MessageCreation(BaseModel): class MessageCreationStepDetails(BaseModel): + """Details of the message creation by the run step.""" + message_creation: MessageCreation type: Literal["message_creation"] diff --git a/src/openai/types/beta/threads/runs/run_step.py b/src/openai/types/beta/threads/runs/run_step.py index b5f380c7b1..97451229fc 100644 --- a/src/openai/types/beta/threads/runs/run_step.py +++ b/src/openai/types/beta/threads/runs/run_step.py @@ -13,6 +13,11 @@ class LastError(BaseModel): + """The last error associated with this run step. + + Will be `null` if there are no errors. + """ + code: Literal["server_error", "rate_limit_exceeded"] """One of `server_error` or `rate_limit_exceeded`.""" @@ -26,6 +31,11 @@ class LastError(BaseModel): class Usage(BaseModel): + """Usage statistics related to the run step. + + This value will be `null` while the run step's status is `in_progress`. + """ + completion_tokens: int """Number of completion tokens used over the course of the run step.""" @@ -37,6 +47,8 @@ class Usage(BaseModel): class RunStep(BaseModel): + """Represents a step in execution of a run.""" + id: str """The identifier of the run step, which can be referenced in API endpoints.""" diff --git a/src/openai/types/beta/threads/runs/run_step_delta.py b/src/openai/types/beta/threads/runs/run_step_delta.py index 1139088fb4..2ccb770d57 100644 --- a/src/openai/types/beta/threads/runs/run_step_delta.py +++ b/src/openai/types/beta/threads/runs/run_step_delta.py @@ -16,5 +16,7 @@ class RunStepDelta(BaseModel): + """The delta containing the fields that have changed on the run step.""" + step_details: Optional[StepDetails] = None """The details of the run step.""" diff --git a/src/openai/types/beta/threads/runs/run_step_delta_event.py b/src/openai/types/beta/threads/runs/run_step_delta_event.py index 7f3f92aabf..8f1c095ae4 100644 --- a/src/openai/types/beta/threads/runs/run_step_delta_event.py +++ b/src/openai/types/beta/threads/runs/run_step_delta_event.py @@ -9,6 +9,11 @@ class RunStepDeltaEvent(BaseModel): + """Represents a run step delta i.e. + + any changed fields on a run step during streaming. + """ + id: str """The identifier of the run step, which can be referenced in API endpoints.""" diff --git a/src/openai/types/beta/threads/runs/run_step_delta_message_delta.py b/src/openai/types/beta/threads/runs/run_step_delta_message_delta.py index f58ed3d96d..4b18277c18 100644 --- a/src/openai/types/beta/threads/runs/run_step_delta_message_delta.py +++ b/src/openai/types/beta/threads/runs/run_step_delta_message_delta.py @@ -14,6 +14,8 @@ class MessageCreation(BaseModel): class RunStepDeltaMessageDelta(BaseModel): + """Details of the message creation by the run step.""" + type: Literal["message_creation"] """Always `message_creation`.""" diff --git a/src/openai/types/beta/threads/runs/tool_call_delta_object.py b/src/openai/types/beta/threads/runs/tool_call_delta_object.py index 189dce772c..dbd1096ad6 100644 --- a/src/openai/types/beta/threads/runs/tool_call_delta_object.py +++ b/src/openai/types/beta/threads/runs/tool_call_delta_object.py @@ -10,6 +10,8 @@ class ToolCallDeltaObject(BaseModel): + """Details of the tool call.""" + type: Literal["tool_calls"] """Always `tool_calls`.""" diff --git a/src/openai/types/beta/threads/runs/tool_calls_step_details.py b/src/openai/types/beta/threads/runs/tool_calls_step_details.py index a084d387c7..1f54a6aa71 100644 --- a/src/openai/types/beta/threads/runs/tool_calls_step_details.py +++ b/src/openai/types/beta/threads/runs/tool_calls_step_details.py @@ -10,6 +10,8 @@ class ToolCallsStepDetails(BaseModel): + """Details of the tool call.""" + tool_calls: List[ToolCall] """An array of tool calls the run step was involved in. diff --git a/src/openai/types/beta/threads/text_content_block.py b/src/openai/types/beta/threads/text_content_block.py index 3706d6b9d8..b9b1368a17 100644 --- a/src/openai/types/beta/threads/text_content_block.py +++ b/src/openai/types/beta/threads/text_content_block.py @@ -9,6 +9,8 @@ class TextContentBlock(BaseModel): + """The text content that is part of a message.""" + text: Text type: Literal["text"] diff --git a/src/openai/types/beta/threads/text_content_block_param.py b/src/openai/types/beta/threads/text_content_block_param.py index 6313de32cc..22c864438d 100644 --- a/src/openai/types/beta/threads/text_content_block_param.py +++ b/src/openai/types/beta/threads/text_content_block_param.py @@ -8,6 +8,8 @@ class TextContentBlockParam(TypedDict, total=False): + """The text content that is part of a message.""" + text: Required[str] """Text content to be sent to the model""" diff --git a/src/openai/types/beta/threads/text_delta_block.py b/src/openai/types/beta/threads/text_delta_block.py index 586116e0d6..a3d339ccad 100644 --- a/src/openai/types/beta/threads/text_delta_block.py +++ b/src/openai/types/beta/threads/text_delta_block.py @@ -10,6 +10,8 @@ class TextDeltaBlock(BaseModel): + """The text content that is part of a message.""" + index: int """The index of the content part in the message.""" diff --git a/src/openai/types/chat/chat_completion.py b/src/openai/types/chat/chat_completion.py index 6bc4bafe79..31219aa812 100644 --- a/src/openai/types/chat/chat_completion.py +++ b/src/openai/types/chat/chat_completion.py @@ -12,6 +12,8 @@ class ChoiceLogprobs(BaseModel): + """Log probability information for the choice.""" + content: Optional[List[ChatCompletionTokenLogprob]] = None """A list of message content tokens with log probability information.""" @@ -41,6 +43,10 @@ class Choice(BaseModel): class ChatCompletion(BaseModel): + """ + Represents a chat completion response returned by model, based on the provided input. + """ + id: str """A unique identifier for the chat completion.""" diff --git a/src/openai/types/chat/chat_completion_allowed_tool_choice_param.py b/src/openai/types/chat/chat_completion_allowed_tool_choice_param.py index 813e6293f9..c5ba21626d 100644 --- a/src/openai/types/chat/chat_completion_allowed_tool_choice_param.py +++ b/src/openai/types/chat/chat_completion_allowed_tool_choice_param.py @@ -10,6 +10,8 @@ class ChatCompletionAllowedToolChoiceParam(TypedDict, total=False): + """Constrains the tools available to the model to a pre-defined set.""" + allowed_tools: Required[ChatCompletionAllowedToolsParam] """Constrains the tools available to the model to a pre-defined set.""" diff --git a/src/openai/types/chat/chat_completion_allowed_tools_param.py b/src/openai/types/chat/chat_completion_allowed_tools_param.py index d9b72d8f34..ac31fcb543 100644 --- a/src/openai/types/chat/chat_completion_allowed_tools_param.py +++ b/src/openai/types/chat/chat_completion_allowed_tools_param.py @@ -9,6 +9,8 @@ class ChatCompletionAllowedToolsParam(TypedDict, total=False): + """Constrains the tools available to the model to a pre-defined set.""" + mode: Required[Literal["auto", "required"]] """Constrains the tools available to the model to a pre-defined set. diff --git a/src/openai/types/chat/chat_completion_assistant_message_param.py b/src/openai/types/chat/chat_completion_assistant_message_param.py index 1a08a959db..16a218438a 100644 --- a/src/openai/types/chat/chat_completion_assistant_message_param.py +++ b/src/openai/types/chat/chat_completion_assistant_message_param.py @@ -13,6 +13,11 @@ class Audio(TypedDict, total=False): + """ + Data about a previous audio response from the model. + [Learn more](https://platform.openai.com/docs/guides/audio). + """ + id: Required[str] """Unique identifier for a previous audio response from the model.""" @@ -21,6 +26,11 @@ class Audio(TypedDict, total=False): class FunctionCall(TypedDict, total=False): + """Deprecated and replaced by `tool_calls`. + + The name and arguments of a function that should be called, as generated by the model. + """ + arguments: Required[str] """ The arguments to call the function with, as generated by the model in JSON @@ -34,6 +44,8 @@ class FunctionCall(TypedDict, total=False): class ChatCompletionAssistantMessageParam(TypedDict, total=False): + """Messages sent by the model in response to user messages.""" + role: Required[Literal["assistant"]] """The role of the messages author, in this case `assistant`.""" diff --git a/src/openai/types/chat/chat_completion_audio.py b/src/openai/types/chat/chat_completion_audio.py index 232d60563d..df346d8c9d 100644 --- a/src/openai/types/chat/chat_completion_audio.py +++ b/src/openai/types/chat/chat_completion_audio.py @@ -6,6 +6,11 @@ class ChatCompletionAudio(BaseModel): + """ + If the audio output modality is requested, this object contains data + about the audio response from the model. [Learn more](https://platform.openai.com/docs/guides/audio). + """ + id: str """Unique identifier for this audio response.""" diff --git a/src/openai/types/chat/chat_completion_audio_param.py b/src/openai/types/chat/chat_completion_audio_param.py index b1576b41df..cac3c8b9d4 100644 --- a/src/openai/types/chat/chat_completion_audio_param.py +++ b/src/openai/types/chat/chat_completion_audio_param.py @@ -9,6 +9,12 @@ class ChatCompletionAudioParam(TypedDict, total=False): + """Parameters for audio output. + + Required when audio output is requested with + `modalities: ["audio"]`. [Learn more](https://platform.openai.com/docs/guides/audio). + """ + format: Required[Literal["wav", "aac", "mp3", "flac", "opus", "pcm16"]] """Specifies the output audio format. diff --git a/src/openai/types/chat/chat_completion_chunk.py b/src/openai/types/chat/chat_completion_chunk.py index ea32d157ef..ecbfd0a5aa 100644 --- a/src/openai/types/chat/chat_completion_chunk.py +++ b/src/openai/types/chat/chat_completion_chunk.py @@ -19,6 +19,11 @@ class ChoiceDeltaFunctionCall(BaseModel): + """Deprecated and replaced by `tool_calls`. + + The name and arguments of a function that should be called, as generated by the model. + """ + arguments: Optional[str] = None """ The arguments to call the function with, as generated by the model in JSON @@ -57,6 +62,8 @@ class ChoiceDeltaToolCall(BaseModel): class ChoiceDelta(BaseModel): + """A chat completion delta generated by streamed model responses.""" + content: Optional[str] = None """The contents of the chunk message.""" @@ -77,6 +84,8 @@ class ChoiceDelta(BaseModel): class ChoiceLogprobs(BaseModel): + """Log probability information for the choice.""" + content: Optional[List[ChatCompletionTokenLogprob]] = None """A list of message content tokens with log probability information.""" @@ -106,6 +115,12 @@ class Choice(BaseModel): class ChatCompletionChunk(BaseModel): + """ + Represents a streamed chunk of a chat completion response returned + by the model, based on the provided input. + [Learn more](https://platform.openai.com/docs/guides/streaming-responses). + """ + id: str """A unique identifier for the chat completion. Each chunk has the same ID.""" diff --git a/src/openai/types/chat/chat_completion_content_part_image.py b/src/openai/types/chat/chat_completion_content_part_image.py index c1386b9dd3..a636c51fb4 100644 --- a/src/openai/types/chat/chat_completion_content_part_image.py +++ b/src/openai/types/chat/chat_completion_content_part_image.py @@ -21,6 +21,8 @@ class ImageURL(BaseModel): class ChatCompletionContentPartImage(BaseModel): + """Learn about [image inputs](https://platform.openai.com/docs/guides/vision).""" + image_url: ImageURL type: Literal["image_url"] diff --git a/src/openai/types/chat/chat_completion_content_part_image_param.py b/src/openai/types/chat/chat_completion_content_part_image_param.py index 9d407324d0..a230a340a7 100644 --- a/src/openai/types/chat/chat_completion_content_part_image_param.py +++ b/src/openai/types/chat/chat_completion_content_part_image_param.py @@ -20,6 +20,8 @@ class ImageURL(TypedDict, total=False): class ChatCompletionContentPartImageParam(TypedDict, total=False): + """Learn about [image inputs](https://platform.openai.com/docs/guides/vision).""" + image_url: Required[ImageURL] type: Required[Literal["image_url"]] diff --git a/src/openai/types/chat/chat_completion_content_part_input_audio_param.py b/src/openai/types/chat/chat_completion_content_part_input_audio_param.py index 0b1b1a80b1..98d9e3c5eb 100644 --- a/src/openai/types/chat/chat_completion_content_part_input_audio_param.py +++ b/src/openai/types/chat/chat_completion_content_part_input_audio_param.py @@ -16,6 +16,8 @@ class InputAudio(TypedDict, total=False): class ChatCompletionContentPartInputAudioParam(TypedDict, total=False): + """Learn about [audio inputs](https://platform.openai.com/docs/guides/audio).""" + input_audio: Required[InputAudio] type: Required[Literal["input_audio"]] diff --git a/src/openai/types/chat/chat_completion_content_part_param.py b/src/openai/types/chat/chat_completion_content_part_param.py index cbedc853ba..b8c710a980 100644 --- a/src/openai/types/chat/chat_completion_content_part_param.py +++ b/src/openai/types/chat/chat_completion_content_part_param.py @@ -27,6 +27,10 @@ class FileFile(TypedDict, total=False): class File(TypedDict, total=False): + """ + Learn about [file inputs](https://platform.openai.com/docs/guides/text) for text generation. + """ + file: Required[FileFile] type: Required[Literal["file"]] diff --git a/src/openai/types/chat/chat_completion_content_part_text.py b/src/openai/types/chat/chat_completion_content_part_text.py index f09f35f708..e6d1bf1ec0 100644 --- a/src/openai/types/chat/chat_completion_content_part_text.py +++ b/src/openai/types/chat/chat_completion_content_part_text.py @@ -8,6 +8,10 @@ class ChatCompletionContentPartText(BaseModel): + """ + Learn about [text inputs](https://platform.openai.com/docs/guides/text-generation). + """ + text: str """The text content.""" diff --git a/src/openai/types/chat/chat_completion_content_part_text_param.py b/src/openai/types/chat/chat_completion_content_part_text_param.py index a270744417..be69bf66fa 100644 --- a/src/openai/types/chat/chat_completion_content_part_text_param.py +++ b/src/openai/types/chat/chat_completion_content_part_text_param.py @@ -8,6 +8,10 @@ class ChatCompletionContentPartTextParam(TypedDict, total=False): + """ + Learn about [text inputs](https://platform.openai.com/docs/guides/text-generation). + """ + text: Required[str] """The text content.""" diff --git a/src/openai/types/chat/chat_completion_custom_tool_param.py b/src/openai/types/chat/chat_completion_custom_tool_param.py index 14959ee449..d4f21ba0ca 100644 --- a/src/openai/types/chat/chat_completion_custom_tool_param.py +++ b/src/openai/types/chat/chat_completion_custom_tool_param.py @@ -16,11 +16,15 @@ class CustomFormatText(TypedDict, total=False): + """Unconstrained free-form text.""" + type: Required[Literal["text"]] """Unconstrained text format. Always `text`.""" class CustomFormatGrammarGrammar(TypedDict, total=False): + """Your chosen grammar.""" + definition: Required[str] """The grammar definition.""" @@ -29,6 +33,8 @@ class CustomFormatGrammarGrammar(TypedDict, total=False): class CustomFormatGrammar(TypedDict, total=False): + """A grammar defined by the user.""" + grammar: Required[CustomFormatGrammarGrammar] """Your chosen grammar.""" @@ -40,6 +46,8 @@ class CustomFormatGrammar(TypedDict, total=False): class Custom(TypedDict, total=False): + """Properties of the custom tool.""" + name: Required[str] """The name of the custom tool, used to identify it in tool calls.""" @@ -51,6 +59,8 @@ class Custom(TypedDict, total=False): class ChatCompletionCustomToolParam(TypedDict, total=False): + """A custom tool that processes input using a specified format.""" + custom: Required[Custom] """Properties of the custom tool.""" diff --git a/src/openai/types/chat/chat_completion_developer_message_param.py b/src/openai/types/chat/chat_completion_developer_message_param.py index 01e4fdb654..94fb3359f6 100644 --- a/src/openai/types/chat/chat_completion_developer_message_param.py +++ b/src/openai/types/chat/chat_completion_developer_message_param.py @@ -11,6 +11,12 @@ class ChatCompletionDeveloperMessageParam(TypedDict, total=False): + """ + Developer-provided instructions that the model should follow, regardless of + messages sent by the user. With o1 models and newer, `developer` messages + replace the previous `system` messages. + """ + content: Required[Union[str, Iterable[ChatCompletionContentPartTextParam]]] """The contents of the developer message.""" diff --git a/src/openai/types/chat/chat_completion_function_call_option_param.py b/src/openai/types/chat/chat_completion_function_call_option_param.py index 2bc014af7a..b1ca37bf58 100644 --- a/src/openai/types/chat/chat_completion_function_call_option_param.py +++ b/src/openai/types/chat/chat_completion_function_call_option_param.py @@ -8,5 +8,9 @@ class ChatCompletionFunctionCallOptionParam(TypedDict, total=False): + """ + Specifying a particular function via `{"name": "my_function"}` forces the model to call that function. + """ + name: Required[str] """The name of the function to call.""" diff --git a/src/openai/types/chat/chat_completion_function_tool.py b/src/openai/types/chat/chat_completion_function_tool.py index 641568acf1..5d43a1e836 100644 --- a/src/openai/types/chat/chat_completion_function_tool.py +++ b/src/openai/types/chat/chat_completion_function_tool.py @@ -9,6 +9,8 @@ class ChatCompletionFunctionTool(BaseModel): + """A function tool that can be used to generate a response.""" + function: FunctionDefinition type: Literal["function"] diff --git a/src/openai/types/chat/chat_completion_function_tool_param.py b/src/openai/types/chat/chat_completion_function_tool_param.py index a39feea542..d336e8c08c 100644 --- a/src/openai/types/chat/chat_completion_function_tool_param.py +++ b/src/openai/types/chat/chat_completion_function_tool_param.py @@ -10,6 +10,8 @@ class ChatCompletionFunctionToolParam(TypedDict, total=False): + """A function tool that can be used to generate a response.""" + function: Required[FunctionDefinition] type: Required[Literal["function"]] diff --git a/src/openai/types/chat/chat_completion_message.py b/src/openai/types/chat/chat_completion_message.py index 5bb153fe3f..3f88f776b9 100644 --- a/src/openai/types/chat/chat_completion_message.py +++ b/src/openai/types/chat/chat_completion_message.py @@ -11,6 +11,8 @@ class AnnotationURLCitation(BaseModel): + """A URL citation when using web search.""" + end_index: int """The index of the last character of the URL citation in the message.""" @@ -25,6 +27,8 @@ class AnnotationURLCitation(BaseModel): class Annotation(BaseModel): + """A URL citation when using web search.""" + type: Literal["url_citation"] """The type of the URL citation. Always `url_citation`.""" @@ -33,6 +37,11 @@ class Annotation(BaseModel): class FunctionCall(BaseModel): + """Deprecated and replaced by `tool_calls`. + + The name and arguments of a function that should be called, as generated by the model. + """ + arguments: str """ The arguments to call the function with, as generated by the model in JSON @@ -46,6 +55,8 @@ class FunctionCall(BaseModel): class ChatCompletionMessage(BaseModel): + """A chat completion message generated by the model.""" + content: Optional[str] = None """The contents of the message.""" diff --git a/src/openai/types/chat/chat_completion_message_custom_tool_call.py b/src/openai/types/chat/chat_completion_message_custom_tool_call.py index b13c176afe..9542d8b924 100644 --- a/src/openai/types/chat/chat_completion_message_custom_tool_call.py +++ b/src/openai/types/chat/chat_completion_message_custom_tool_call.py @@ -8,6 +8,8 @@ class Custom(BaseModel): + """The custom tool that the model called.""" + input: str """The input for the custom tool call generated by the model.""" @@ -16,6 +18,8 @@ class Custom(BaseModel): class ChatCompletionMessageCustomToolCall(BaseModel): + """A call to a custom tool created by the model.""" + id: str """The ID of the tool call.""" diff --git a/src/openai/types/chat/chat_completion_message_custom_tool_call_param.py b/src/openai/types/chat/chat_completion_message_custom_tool_call_param.py index 3753e0f200..3d03f0a93c 100644 --- a/src/openai/types/chat/chat_completion_message_custom_tool_call_param.py +++ b/src/openai/types/chat/chat_completion_message_custom_tool_call_param.py @@ -8,6 +8,8 @@ class Custom(TypedDict, total=False): + """The custom tool that the model called.""" + input: Required[str] """The input for the custom tool call generated by the model.""" @@ -16,6 +18,8 @@ class Custom(TypedDict, total=False): class ChatCompletionMessageCustomToolCallParam(TypedDict, total=False): + """A call to a custom tool created by the model.""" + id: Required[str] """The ID of the tool call.""" diff --git a/src/openai/types/chat/chat_completion_message_function_tool_call.py b/src/openai/types/chat/chat_completion_message_function_tool_call.py index d056d9aff6..e7278b923c 100644 --- a/src/openai/types/chat/chat_completion_message_function_tool_call.py +++ b/src/openai/types/chat/chat_completion_message_function_tool_call.py @@ -8,6 +8,8 @@ class Function(BaseModel): + """The function that the model called.""" + arguments: str """ The arguments to call the function with, as generated by the model in JSON @@ -21,6 +23,8 @@ class Function(BaseModel): class ChatCompletionMessageFunctionToolCall(BaseModel): + """A call to a function tool created by the model.""" + id: str """The ID of the tool call.""" diff --git a/src/openai/types/chat/chat_completion_message_function_tool_call_param.py b/src/openai/types/chat/chat_completion_message_function_tool_call_param.py index 7c827edd2c..a8094ea63a 100644 --- a/src/openai/types/chat/chat_completion_message_function_tool_call_param.py +++ b/src/openai/types/chat/chat_completion_message_function_tool_call_param.py @@ -8,6 +8,8 @@ class Function(TypedDict, total=False): + """The function that the model called.""" + arguments: Required[str] """ The arguments to call the function with, as generated by the model in JSON @@ -21,6 +23,8 @@ class Function(TypedDict, total=False): class ChatCompletionMessageFunctionToolCallParam(TypedDict, total=False): + """A call to a function tool created by the model.""" + id: Required[str] """The ID of the tool call.""" diff --git a/src/openai/types/chat/chat_completion_named_tool_choice_custom_param.py b/src/openai/types/chat/chat_completion_named_tool_choice_custom_param.py index 1c123c0acb..147fb87965 100644 --- a/src/openai/types/chat/chat_completion_named_tool_choice_custom_param.py +++ b/src/openai/types/chat/chat_completion_named_tool_choice_custom_param.py @@ -13,6 +13,11 @@ class Custom(TypedDict, total=False): class ChatCompletionNamedToolChoiceCustomParam(TypedDict, total=False): + """Specifies a tool the model should use. + + Use to force the model to call a specific custom tool. + """ + custom: Required[Custom] type: Required[Literal["custom"]] diff --git a/src/openai/types/chat/chat_completion_named_tool_choice_param.py b/src/openai/types/chat/chat_completion_named_tool_choice_param.py index ae1acfb909..f684fcea5e 100644 --- a/src/openai/types/chat/chat_completion_named_tool_choice_param.py +++ b/src/openai/types/chat/chat_completion_named_tool_choice_param.py @@ -13,6 +13,11 @@ class Function(TypedDict, total=False): class ChatCompletionNamedToolChoiceParam(TypedDict, total=False): + """Specifies a tool the model should use. + + Use to force the model to call a specific function. + """ + function: Required[Function] type: Required[Literal["function"]] diff --git a/src/openai/types/chat/chat_completion_prediction_content_param.py b/src/openai/types/chat/chat_completion_prediction_content_param.py index c44e6e3653..6184a314b5 100644 --- a/src/openai/types/chat/chat_completion_prediction_content_param.py +++ b/src/openai/types/chat/chat_completion_prediction_content_param.py @@ -11,6 +11,11 @@ class ChatCompletionPredictionContentParam(TypedDict, total=False): + """ + Static predicted output content, such as the content of a text file that is + being regenerated. + """ + content: Required[Union[str, Iterable[ChatCompletionContentPartTextParam]]] """ The content that should be matched when generating a model response. If diff --git a/src/openai/types/chat/chat_completion_store_message.py b/src/openai/types/chat/chat_completion_store_message.py index 661342716b..6a805cce76 100644 --- a/src/openai/types/chat/chat_completion_store_message.py +++ b/src/openai/types/chat/chat_completion_store_message.py @@ -13,6 +13,8 @@ class ChatCompletionStoreMessage(ChatCompletionMessage): + """A chat completion message generated by the model.""" + id: str """The identifier of the chat message.""" diff --git a/src/openai/types/chat/chat_completion_stream_options_param.py b/src/openai/types/chat/chat_completion_stream_options_param.py index fc3191d2d1..9b881fff02 100644 --- a/src/openai/types/chat/chat_completion_stream_options_param.py +++ b/src/openai/types/chat/chat_completion_stream_options_param.py @@ -8,6 +8,8 @@ class ChatCompletionStreamOptionsParam(TypedDict, total=False): + """Options for streaming response. Only set this when you set `stream: true`.""" + include_obfuscation: bool """When true, stream obfuscation will be enabled. diff --git a/src/openai/types/chat/chat_completion_system_message_param.py b/src/openai/types/chat/chat_completion_system_message_param.py index 172ccea09e..9dcc5e07f9 100644 --- a/src/openai/types/chat/chat_completion_system_message_param.py +++ b/src/openai/types/chat/chat_completion_system_message_param.py @@ -11,6 +11,12 @@ class ChatCompletionSystemMessageParam(TypedDict, total=False): + """ + Developer-provided instructions that the model should follow, regardless of + messages sent by the user. With o1 models and newer, use `developer` messages + for this purpose instead. + """ + content: Required[Union[str, Iterable[ChatCompletionContentPartTextParam]]] """The contents of the system message.""" diff --git a/src/openai/types/chat/chat_completion_user_message_param.py b/src/openai/types/chat/chat_completion_user_message_param.py index 5c15322a22..c97ba535eb 100644 --- a/src/openai/types/chat/chat_completion_user_message_param.py +++ b/src/openai/types/chat/chat_completion_user_message_param.py @@ -11,6 +11,11 @@ class ChatCompletionUserMessageParam(TypedDict, total=False): + """ + Messages sent by an end user, containing prompts or additional context + information. + """ + content: Required[Union[str, Iterable[ChatCompletionContentPartParam]]] """The contents of the user message.""" diff --git a/src/openai/types/chat/completion_create_params.py b/src/openai/types/chat/completion_create_params.py index f2d55f7ec4..613787e9b5 100644 --- a/src/openai/types/chat/completion_create_params.py +++ b/src/openai/types/chat/completion_create_params.py @@ -382,6 +382,8 @@ class Function(TypedDict, total=False): class WebSearchOptionsUserLocationApproximate(TypedDict, total=False): + """Approximate location parameters for the search.""" + city: str """Free text input for the city of the user, e.g. `San Francisco`.""" @@ -402,6 +404,8 @@ class WebSearchOptionsUserLocationApproximate(TypedDict, total=False): class WebSearchOptionsUserLocation(TypedDict, total=False): + """Approximate location parameters for the search.""" + approximate: Required[WebSearchOptionsUserLocationApproximate] """Approximate location parameters for the search.""" @@ -410,6 +414,11 @@ class WebSearchOptionsUserLocation(TypedDict, total=False): class WebSearchOptions(TypedDict, total=False): + """ + This tool searches the web for relevant results to use in a response. + Learn more about the [web search tool](https://platform.openai.com/docs/guides/tools-web-search?api-mode=chat). + """ + search_context_size: Literal["low", "medium", "high"] """ High level guidance for the amount of context window space to use for the diff --git a/src/openai/types/completion.py b/src/openai/types/completion.py index d3b3102a4a..ee59b2e209 100644 --- a/src/openai/types/completion.py +++ b/src/openai/types/completion.py @@ -11,6 +11,11 @@ class Completion(BaseModel): + """Represents a completion response from the API. + + Note: both the streamed and non-streamed response objects share the same shape (unlike the chat endpoint). + """ + id: str """A unique identifier for the completion.""" diff --git a/src/openai/types/completion_usage.py b/src/openai/types/completion_usage.py index d8c4e84cf7..9b5202da14 100644 --- a/src/openai/types/completion_usage.py +++ b/src/openai/types/completion_usage.py @@ -8,6 +8,8 @@ class CompletionTokensDetails(BaseModel): + """Breakdown of tokens used in a completion.""" + accepted_prediction_tokens: Optional[int] = None """ When using Predicted Outputs, the number of tokens in the prediction that @@ -30,6 +32,8 @@ class CompletionTokensDetails(BaseModel): class PromptTokensDetails(BaseModel): + """Breakdown of tokens used in the prompt.""" + audio_tokens: Optional[int] = None """Audio input tokens present in the prompt.""" @@ -38,6 +42,8 @@ class PromptTokensDetails(BaseModel): class CompletionUsage(BaseModel): + """Usage statistics for the completion request.""" + completion_tokens: int """Number of tokens in the generated completion.""" diff --git a/src/openai/types/container_create_params.py b/src/openai/types/container_create_params.py index d629c24d38..47101ecdb6 100644 --- a/src/openai/types/container_create_params.py +++ b/src/openai/types/container_create_params.py @@ -24,6 +24,8 @@ class ContainerCreateParams(TypedDict, total=False): class ExpiresAfter(TypedDict, total=False): + """Container expiration time in seconds relative to the 'anchor' time.""" + anchor: Required[Literal["last_active_at"]] """Time anchor for the expiration time. diff --git a/src/openai/types/container_create_response.py b/src/openai/types/container_create_response.py index cbad914283..0ebcc04062 100644 --- a/src/openai/types/container_create_response.py +++ b/src/openai/types/container_create_response.py @@ -9,6 +9,12 @@ class ExpiresAfter(BaseModel): + """ + The container will expire after this time period. + The anchor is the reference point for the expiration. + The minutes is the number of minutes after the anchor before the container expires. + """ + anchor: Optional[Literal["last_active_at"]] = None """The reference point for the expiration.""" diff --git a/src/openai/types/container_list_response.py b/src/openai/types/container_list_response.py index 29416f0941..8f39548201 100644 --- a/src/openai/types/container_list_response.py +++ b/src/openai/types/container_list_response.py @@ -9,6 +9,12 @@ class ExpiresAfter(BaseModel): + """ + The container will expire after this time period. + The anchor is the reference point for the expiration. + The minutes is the number of minutes after the anchor before the container expires. + """ + anchor: Optional[Literal["last_active_at"]] = None """The reference point for the expiration.""" diff --git a/src/openai/types/container_retrieve_response.py b/src/openai/types/container_retrieve_response.py index 31fedeac64..9ba3e18c3a 100644 --- a/src/openai/types/container_retrieve_response.py +++ b/src/openai/types/container_retrieve_response.py @@ -9,6 +9,12 @@ class ExpiresAfter(BaseModel): + """ + The container will expire after this time period. + The anchor is the reference point for the expiration. + The minutes is the number of minutes after the anchor before the container expires. + """ + anchor: Optional[Literal["last_active_at"]] = None """The reference point for the expiration.""" diff --git a/src/openai/types/conversations/computer_screenshot_content.py b/src/openai/types/conversations/computer_screenshot_content.py index 897b7ada0d..e42096eba2 100644 --- a/src/openai/types/conversations/computer_screenshot_content.py +++ b/src/openai/types/conversations/computer_screenshot_content.py @@ -9,6 +9,8 @@ class ComputerScreenshotContent(BaseModel): + """A screenshot of a computer.""" + file_id: Optional[str] = None """The identifier of an uploaded file that contains the screenshot.""" diff --git a/src/openai/types/conversations/conversation_item.py b/src/openai/types/conversations/conversation_item.py index 052d09ce77..46268d381c 100644 --- a/src/openai/types/conversations/conversation_item.py +++ b/src/openai/types/conversations/conversation_item.py @@ -36,6 +36,8 @@ class ImageGenerationCall(BaseModel): + """An image generation request made by the model.""" + id: str """The unique ID of the image generation call.""" @@ -50,6 +52,8 @@ class ImageGenerationCall(BaseModel): class LocalShellCallAction(BaseModel): + """Execute a shell command on the server.""" + command: List[str] """The command to run.""" @@ -70,6 +74,8 @@ class LocalShellCallAction(BaseModel): class LocalShellCall(BaseModel): + """A tool call to run a command on the local shell.""" + id: str """The unique ID of the local shell call.""" @@ -87,6 +93,8 @@ class LocalShellCall(BaseModel): class LocalShellCallOutput(BaseModel): + """The output of a local shell tool call.""" + id: str """The unique ID of the local shell tool call generated by the model.""" @@ -101,6 +109,8 @@ class LocalShellCallOutput(BaseModel): class McpListToolsTool(BaseModel): + """A tool available on an MCP server.""" + input_schema: object """The JSON schema describing the tool's input.""" @@ -115,6 +125,8 @@ class McpListToolsTool(BaseModel): class McpListTools(BaseModel): + """A list of tools available on an MCP server.""" + id: str """The unique ID of the list.""" @@ -132,6 +144,8 @@ class McpListTools(BaseModel): class McpApprovalRequest(BaseModel): + """A request for human approval of a tool invocation.""" + id: str """The unique ID of the approval request.""" @@ -149,6 +163,8 @@ class McpApprovalRequest(BaseModel): class McpApprovalResponse(BaseModel): + """A response to an MCP approval request.""" + id: str """The unique ID of the approval response""" @@ -166,6 +182,8 @@ class McpApprovalResponse(BaseModel): class McpCall(BaseModel): + """An invocation of a tool on an MCP server.""" + id: str """The unique ID of the tool call.""" diff --git a/src/openai/types/conversations/conversation_item_list.py b/src/openai/types/conversations/conversation_item_list.py index 20091102cb..74d945d864 100644 --- a/src/openai/types/conversations/conversation_item_list.py +++ b/src/openai/types/conversations/conversation_item_list.py @@ -10,6 +10,8 @@ class ConversationItemList(BaseModel): + """A list of Conversation items.""" + data: List[ConversationItem] """A list of conversation items.""" diff --git a/src/openai/types/conversations/message.py b/src/openai/types/conversations/message.py index dbf5a14680..86c8860da8 100644 --- a/src/openai/types/conversations/message.py +++ b/src/openai/types/conversations/message.py @@ -18,6 +18,8 @@ class ContentReasoningText(BaseModel): + """Reasoning text from the model.""" + text: str """The reasoning text from the model.""" @@ -42,6 +44,8 @@ class ContentReasoningText(BaseModel): class Message(BaseModel): + """A message to or from the model.""" + id: str """The unique ID of the message.""" diff --git a/src/openai/types/conversations/summary_text_content.py b/src/openai/types/conversations/summary_text_content.py index d357b15725..6464a36599 100644 --- a/src/openai/types/conversations/summary_text_content.py +++ b/src/openai/types/conversations/summary_text_content.py @@ -8,6 +8,8 @@ class SummaryTextContent(BaseModel): + """A summary text from the model.""" + text: str """A summary of the reasoning output from the model so far.""" diff --git a/src/openai/types/conversations/text_content.py b/src/openai/types/conversations/text_content.py index f1ae079597..e602466c47 100644 --- a/src/openai/types/conversations/text_content.py +++ b/src/openai/types/conversations/text_content.py @@ -8,6 +8,8 @@ class TextContent(BaseModel): + """A text content.""" + text: str type: Literal["text"] diff --git a/src/openai/types/create_embedding_response.py b/src/openai/types/create_embedding_response.py index eff247a112..314a7f9afc 100644 --- a/src/openai/types/create_embedding_response.py +++ b/src/openai/types/create_embedding_response.py @@ -10,6 +10,8 @@ class Usage(BaseModel): + """The usage information for the request.""" + prompt_tokens: int """The number of tokens used by the prompt.""" diff --git a/src/openai/types/embedding.py b/src/openai/types/embedding.py index 769b1d165f..fbffec01e0 100644 --- a/src/openai/types/embedding.py +++ b/src/openai/types/embedding.py @@ -9,6 +9,8 @@ class Embedding(BaseModel): + """Represents an embedding vector returned by embedding endpoint.""" + embedding: List[float] """The embedding vector, which is a list of floats. diff --git a/src/openai/types/eval_create_params.py b/src/openai/types/eval_create_params.py index eb7f86cd92..0f2100b718 100644 --- a/src/openai/types/eval_create_params.py +++ b/src/openai/types/eval_create_params.py @@ -64,6 +64,13 @@ class EvalCreateParams(TypedDict, total=False): class DataSourceConfigCustom(TypedDict, total=False): + """ + A CustomDataSourceConfig object that defines the schema for the data source used for the evaluation runs. + This schema is used to define the shape of the data that will be: + - Used to define your testing criteria and + - What data is required when creating a run + """ + item_schema: Required[Dict[str, object]] """The json schema for each row in the data source.""" @@ -78,6 +85,11 @@ class DataSourceConfigCustom(TypedDict, total=False): class DataSourceConfigLogs(TypedDict, total=False): + """ + A data source config which specifies the metadata property of your logs query. + This is usually metadata like `usecase=chatbot` or `prompt-version=v2`, etc. + """ + type: Required[Literal["logs"]] """The type of data source. Always `logs`.""" @@ -86,6 +98,8 @@ class DataSourceConfigLogs(TypedDict, total=False): class DataSourceConfigStoredCompletions(TypedDict, total=False): + """Deprecated in favor of LogsDataSourceConfig.""" + type: Required[Literal["stored_completions"]] """The type of data source. Always `stored_completions`.""" @@ -105,6 +119,8 @@ class TestingCriterionLabelModelInputSimpleInputMessage(TypedDict, total=False): class TestingCriterionLabelModelInputEvalItemContentOutputText(TypedDict, total=False): + """A text output from the model.""" + text: Required[str] """The text output from the model.""" @@ -113,6 +129,8 @@ class TestingCriterionLabelModelInputEvalItemContentOutputText(TypedDict, total= class TestingCriterionLabelModelInputEvalItemContentInputImage(TypedDict, total=False): + """An image input to the model.""" + image_url: Required[str] """The URL of the image input.""" @@ -137,6 +155,14 @@ class TestingCriterionLabelModelInputEvalItemContentInputImage(TypedDict, total= class TestingCriterionLabelModelInputEvalItem(TypedDict, total=False): + """ + A message input to the model with a role indicating instruction following + hierarchy. Instructions given with the `developer` or `system` role take + precedence over instructions given with the `user` role. Messages with the + `assistant` role are presumed to have been generated by the model in previous + interactions. + """ + content: Required[TestingCriterionLabelModelInputEvalItemContent] """Inputs to the model - can contain template strings.""" @@ -156,6 +182,11 @@ class TestingCriterionLabelModelInputEvalItem(TypedDict, total=False): class TestingCriterionLabelModel(TypedDict, total=False): + """ + A LabelModelGrader object which uses a model to assign labels to each item + in the evaluation. + """ + input: Required[Iterable[TestingCriterionLabelModelInput]] """A list of chat messages forming the prompt or context. @@ -179,16 +210,22 @@ class TestingCriterionLabelModel(TypedDict, total=False): class TestingCriterionTextSimilarity(TextSimilarityGraderParam, total=False): + """A TextSimilarityGrader object which grades text based on similarity metrics.""" + pass_threshold: Required[float] """The threshold for the score.""" class TestingCriterionPython(PythonGraderParam, total=False): + """A PythonGrader object that runs a python script on the input.""" + pass_threshold: float """The threshold for the score.""" class TestingCriterionScoreModel(ScoreModelGraderParam, total=False): + """A ScoreModelGrader object that uses a model to assign a score to the input.""" + pass_threshold: float """The threshold for the score.""" diff --git a/src/openai/types/eval_create_response.py b/src/openai/types/eval_create_response.py index 20b0e3127f..f3166422ba 100644 --- a/src/openai/types/eval_create_response.py +++ b/src/openai/types/eval_create_response.py @@ -28,6 +28,13 @@ class DataSourceConfigLogs(BaseModel): + """ + A LogsDataSourceConfig which specifies the metadata property of your logs query. + This is usually metadata like `usecase=chatbot` or `prompt-version=v2`, etc. + The schema returned by this data source config is used to defined what variables are available in your evals. + `item` and `sample` are both defined when using this data source config. + """ + schema_: Dict[str, object] = FieldInfo(alias="schema") """ The json schema for the run data source items. Learn how to build JSON schemas @@ -56,18 +63,21 @@ class DataSourceConfigLogs(BaseModel): class TestingCriterionEvalGraderTextSimilarity(TextSimilarityGrader): __test__ = False + """A TextSimilarityGrader object which grades text based on similarity metrics.""" pass_threshold: float """The threshold for the score.""" class TestingCriterionEvalGraderPython(PythonGrader): __test__ = False + """A PythonGrader object that runs a python script on the input.""" pass_threshold: Optional[float] = None """The threshold for the score.""" class TestingCriterionEvalGraderScoreModel(ScoreModelGrader): __test__ = False + """A ScoreModelGrader object that uses a model to assign a score to the input.""" pass_threshold: Optional[float] = None """The threshold for the score.""" @@ -82,6 +92,15 @@ class TestingCriterionEvalGraderScoreModel(ScoreModelGrader): class EvalCreateResponse(BaseModel): + """ + An Eval object with a data source config and testing criteria. + An Eval represents a task to be done for your LLM integration. + Like: + - Improve the quality of my chatbot + - See how well my chatbot handles customer support + - Check if o4-mini is better at my usecase than gpt-4o + """ + id: str """Unique identifier for the evaluation.""" diff --git a/src/openai/types/eval_custom_data_source_config.py b/src/openai/types/eval_custom_data_source_config.py index d99701cc71..6234c4f47a 100644 --- a/src/openai/types/eval_custom_data_source_config.py +++ b/src/openai/types/eval_custom_data_source_config.py @@ -11,6 +11,13 @@ class EvalCustomDataSourceConfig(BaseModel): + """ + A CustomDataSourceConfig which specifies the schema of your `item` and optionally `sample` namespaces. + The response schema defines the shape of the data that will be: + - Used to define your testing criteria and + - What data is required when creating a run + """ + schema_: Dict[str, object] = FieldInfo(alias="schema") """ The json schema for the run data source items. Learn how to build JSON schemas diff --git a/src/openai/types/eval_list_response.py b/src/openai/types/eval_list_response.py index 5ac4997cf6..7cd92c5a09 100644 --- a/src/openai/types/eval_list_response.py +++ b/src/openai/types/eval_list_response.py @@ -28,6 +28,13 @@ class DataSourceConfigLogs(BaseModel): + """ + A LogsDataSourceConfig which specifies the metadata property of your logs query. + This is usually metadata like `usecase=chatbot` or `prompt-version=v2`, etc. + The schema returned by this data source config is used to defined what variables are available in your evals. + `item` and `sample` are both defined when using this data source config. + """ + schema_: Dict[str, object] = FieldInfo(alias="schema") """ The json schema for the run data source items. Learn how to build JSON schemas @@ -56,18 +63,21 @@ class DataSourceConfigLogs(BaseModel): class TestingCriterionEvalGraderTextSimilarity(TextSimilarityGrader): __test__ = False + """A TextSimilarityGrader object which grades text based on similarity metrics.""" pass_threshold: float """The threshold for the score.""" class TestingCriterionEvalGraderPython(PythonGrader): __test__ = False + """A PythonGrader object that runs a python script on the input.""" pass_threshold: Optional[float] = None """The threshold for the score.""" class TestingCriterionEvalGraderScoreModel(ScoreModelGrader): __test__ = False + """A ScoreModelGrader object that uses a model to assign a score to the input.""" pass_threshold: Optional[float] = None """The threshold for the score.""" @@ -82,6 +92,15 @@ class TestingCriterionEvalGraderScoreModel(ScoreModelGrader): class EvalListResponse(BaseModel): + """ + An Eval object with a data source config and testing criteria. + An Eval represents a task to be done for your LLM integration. + Like: + - Improve the quality of my chatbot + - See how well my chatbot handles customer support + - Check if o4-mini is better at my usecase than gpt-4o + """ + id: str """Unique identifier for the evaluation.""" diff --git a/src/openai/types/eval_retrieve_response.py b/src/openai/types/eval_retrieve_response.py index 758f9cc040..56db7d6bc1 100644 --- a/src/openai/types/eval_retrieve_response.py +++ b/src/openai/types/eval_retrieve_response.py @@ -28,6 +28,13 @@ class DataSourceConfigLogs(BaseModel): + """ + A LogsDataSourceConfig which specifies the metadata property of your logs query. + This is usually metadata like `usecase=chatbot` or `prompt-version=v2`, etc. + The schema returned by this data source config is used to defined what variables are available in your evals. + `item` and `sample` are both defined when using this data source config. + """ + schema_: Dict[str, object] = FieldInfo(alias="schema") """ The json schema for the run data source items. Learn how to build JSON schemas @@ -56,18 +63,21 @@ class DataSourceConfigLogs(BaseModel): class TestingCriterionEvalGraderTextSimilarity(TextSimilarityGrader): __test__ = False + """A TextSimilarityGrader object which grades text based on similarity metrics.""" pass_threshold: float """The threshold for the score.""" class TestingCriterionEvalGraderPython(PythonGrader): __test__ = False + """A PythonGrader object that runs a python script on the input.""" pass_threshold: Optional[float] = None """The threshold for the score.""" class TestingCriterionEvalGraderScoreModel(ScoreModelGrader): __test__ = False + """A ScoreModelGrader object that uses a model to assign a score to the input.""" pass_threshold: Optional[float] = None """The threshold for the score.""" @@ -82,6 +92,15 @@ class TestingCriterionEvalGraderScoreModel(ScoreModelGrader): class EvalRetrieveResponse(BaseModel): + """ + An Eval object with a data source config and testing criteria. + An Eval represents a task to be done for your LLM integration. + Like: + - Improve the quality of my chatbot + - See how well my chatbot handles customer support + - Check if o4-mini is better at my usecase than gpt-4o + """ + id: str """Unique identifier for the evaluation.""" diff --git a/src/openai/types/eval_stored_completions_data_source_config.py b/src/openai/types/eval_stored_completions_data_source_config.py index 98f86a4719..d11f6ae14c 100644 --- a/src/openai/types/eval_stored_completions_data_source_config.py +++ b/src/openai/types/eval_stored_completions_data_source_config.py @@ -12,6 +12,8 @@ class EvalStoredCompletionsDataSourceConfig(BaseModel): + """Deprecated in favor of LogsDataSourceConfig.""" + schema_: Dict[str, object] = FieldInfo(alias="schema") """ The json schema for the run data source items. Learn how to build JSON schemas diff --git a/src/openai/types/eval_update_response.py b/src/openai/types/eval_update_response.py index 3f0b90ae03..30d4dbc3a1 100644 --- a/src/openai/types/eval_update_response.py +++ b/src/openai/types/eval_update_response.py @@ -28,6 +28,13 @@ class DataSourceConfigLogs(BaseModel): + """ + A LogsDataSourceConfig which specifies the metadata property of your logs query. + This is usually metadata like `usecase=chatbot` or `prompt-version=v2`, etc. + The schema returned by this data source config is used to defined what variables are available in your evals. + `item` and `sample` are both defined when using this data source config. + """ + schema_: Dict[str, object] = FieldInfo(alias="schema") """ The json schema for the run data source items. Learn how to build JSON schemas @@ -56,18 +63,21 @@ class DataSourceConfigLogs(BaseModel): class TestingCriterionEvalGraderTextSimilarity(TextSimilarityGrader): __test__ = False + """A TextSimilarityGrader object which grades text based on similarity metrics.""" pass_threshold: float """The threshold for the score.""" class TestingCriterionEvalGraderPython(PythonGrader): __test__ = False + """A PythonGrader object that runs a python script on the input.""" pass_threshold: Optional[float] = None """The threshold for the score.""" class TestingCriterionEvalGraderScoreModel(ScoreModelGrader): __test__ = False + """A ScoreModelGrader object that uses a model to assign a score to the input.""" pass_threshold: Optional[float] = None """The threshold for the score.""" @@ -82,6 +92,15 @@ class TestingCriterionEvalGraderScoreModel(ScoreModelGrader): class EvalUpdateResponse(BaseModel): + """ + An Eval object with a data source config and testing criteria. + An Eval represents a task to be done for your LLM integration. + Like: + - Improve the quality of my chatbot + - See how well my chatbot handles customer support + - Check if o4-mini is better at my usecase than gpt-4o + """ + id: str """Unique identifier for the evaluation.""" diff --git a/src/openai/types/evals/create_eval_completions_run_data_source.py b/src/openai/types/evals/create_eval_completions_run_data_source.py index 4236746a17..6ec39873b7 100644 --- a/src/openai/types/evals/create_eval_completions_run_data_source.py +++ b/src/openai/types/evals/create_eval_completions_run_data_source.py @@ -58,6 +58,8 @@ class SourceFileID(BaseModel): class SourceStoredCompletions(BaseModel): + """A StoredCompletionsRunDataSource configuration describing a set of filters""" + type: Literal["stored_completions"] """The type of source. Always `stored_completions`.""" @@ -90,6 +92,8 @@ class SourceStoredCompletions(BaseModel): class InputMessagesTemplateTemplateEvalItemContentOutputText(BaseModel): + """A text output from the model.""" + text: str """The text output from the model.""" @@ -98,6 +102,8 @@ class InputMessagesTemplateTemplateEvalItemContentOutputText(BaseModel): class InputMessagesTemplateTemplateEvalItemContentInputImage(BaseModel): + """An image input to the model.""" + image_url: str """The URL of the image input.""" @@ -122,6 +128,14 @@ class InputMessagesTemplateTemplateEvalItemContentInputImage(BaseModel): class InputMessagesTemplateTemplateEvalItem(BaseModel): + """ + A message input to the model with a role indicating instruction following + hierarchy. Instructions given with the `developer` or `system` role take + precedence over instructions given with the `user` role. Messages with the + `assistant` role are presumed to have been generated by the model in previous + interactions. + """ + content: InputMessagesTemplateTemplateEvalItemContent """Inputs to the model - can contain template strings.""" @@ -217,6 +231,8 @@ class SamplingParams(BaseModel): class CreateEvalCompletionsRunDataSource(BaseModel): + """A CompletionsRunDataSource object describing a model sampling configuration.""" + source: Source """Determines what populates the `item` namespace in this run's data source.""" diff --git a/src/openai/types/evals/create_eval_completions_run_data_source_param.py b/src/openai/types/evals/create_eval_completions_run_data_source_param.py index 751a1432b8..22d07c5598 100644 --- a/src/openai/types/evals/create_eval_completions_run_data_source_param.py +++ b/src/openai/types/evals/create_eval_completions_run_data_source_param.py @@ -58,6 +58,8 @@ class SourceFileID(TypedDict, total=False): class SourceStoredCompletions(TypedDict, total=False): + """A StoredCompletionsRunDataSource configuration describing a set of filters""" + type: Required[Literal["stored_completions"]] """The type of source. Always `stored_completions`.""" @@ -88,6 +90,8 @@ class SourceStoredCompletions(TypedDict, total=False): class InputMessagesTemplateTemplateEvalItemContentOutputText(TypedDict, total=False): + """A text output from the model.""" + text: Required[str] """The text output from the model.""" @@ -96,6 +100,8 @@ class InputMessagesTemplateTemplateEvalItemContentOutputText(TypedDict, total=Fa class InputMessagesTemplateTemplateEvalItemContentInputImage(TypedDict, total=False): + """An image input to the model.""" + image_url: Required[str] """The URL of the image input.""" @@ -120,6 +126,14 @@ class InputMessagesTemplateTemplateEvalItemContentInputImage(TypedDict, total=Fa class InputMessagesTemplateTemplateEvalItem(TypedDict, total=False): + """ + A message input to the model with a role indicating instruction following + hierarchy. Instructions given with the `developer` or `system` role take + precedence over instructions given with the `user` role. Messages with the + `assistant` role are presumed to have been generated by the model in previous + interactions. + """ + content: Required[InputMessagesTemplateTemplateEvalItemContent] """Inputs to the model - can contain template strings.""" @@ -213,6 +227,8 @@ class SamplingParams(TypedDict, total=False): class CreateEvalCompletionsRunDataSourceParam(TypedDict, total=False): + """A CompletionsRunDataSource object describing a model sampling configuration.""" + source: Required[Source] """Determines what populates the `item` namespace in this run's data source.""" diff --git a/src/openai/types/evals/create_eval_jsonl_run_data_source.py b/src/openai/types/evals/create_eval_jsonl_run_data_source.py index ae36f8c55f..36ede2d9eb 100644 --- a/src/openai/types/evals/create_eval_jsonl_run_data_source.py +++ b/src/openai/types/evals/create_eval_jsonl_run_data_source.py @@ -35,6 +35,10 @@ class SourceFileID(BaseModel): class CreateEvalJSONLRunDataSource(BaseModel): + """ + A JsonlRunDataSource object with that specifies a JSONL file that matches the eval + """ + source: Source """Determines what populates the `item` namespace in the data source.""" diff --git a/src/openai/types/evals/create_eval_jsonl_run_data_source_param.py b/src/openai/types/evals/create_eval_jsonl_run_data_source_param.py index 217ee36346..b87ba9c5df 100644 --- a/src/openai/types/evals/create_eval_jsonl_run_data_source_param.py +++ b/src/openai/types/evals/create_eval_jsonl_run_data_source_param.py @@ -40,6 +40,10 @@ class SourceFileID(TypedDict, total=False): class CreateEvalJSONLRunDataSourceParam(TypedDict, total=False): + """ + A JsonlRunDataSource object with that specifies a JSONL file that matches the eval + """ + source: Required[Source] """Determines what populates the `item` namespace in the data source.""" diff --git a/src/openai/types/evals/eval_api_error.py b/src/openai/types/evals/eval_api_error.py index fe76871024..9b2c1871fb 100644 --- a/src/openai/types/evals/eval_api_error.py +++ b/src/openai/types/evals/eval_api_error.py @@ -6,6 +6,8 @@ class EvalAPIError(BaseModel): + """An object representing an error response from the Eval API.""" + code: str """The error code.""" diff --git a/src/openai/types/evals/run_cancel_response.py b/src/openai/types/evals/run_cancel_response.py index f7fb0ec4ad..40f071c959 100644 --- a/src/openai/types/evals/run_cancel_response.py +++ b/src/openai/types/evals/run_cancel_response.py @@ -66,6 +66,8 @@ class DataSourceResponsesSourceFileID(BaseModel): class DataSourceResponsesSourceResponses(BaseModel): + """A EvalResponsesSource object describing a run data source configuration.""" + type: Literal["responses"] """The type of run data source. Always `responses`.""" @@ -144,6 +146,8 @@ class DataSourceResponsesInputMessagesTemplateTemplateChatMessage(BaseModel): class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText(BaseModel): + """A text output from the model.""" + text: str """The text output from the model.""" @@ -152,6 +156,8 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText( class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage(BaseModel): + """An image input to the model.""" + image_url: str """The URL of the image input.""" @@ -176,6 +182,14 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage( class DataSourceResponsesInputMessagesTemplateTemplateEvalItem(BaseModel): + """ + A message input to the model with a role indicating instruction following + hierarchy. Instructions given with the `developer` or `system` role take + precedence over instructions given with the `user` role. Messages with the + `assistant` role are presumed to have been generated by the model in previous + interactions. + """ + content: DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent """Inputs to the model - can contain template strings.""" @@ -221,6 +235,14 @@ class DataSourceResponsesInputMessagesItemReference(BaseModel): class DataSourceResponsesSamplingParamsText(BaseModel): + """Configuration options for a text response from the model. + + Can be plain + text or structured JSON data. Learn more: + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + """ + format: Optional[ResponseFormatTextConfig] = None """An object specifying the format that the model must output. @@ -297,6 +319,8 @@ class DataSourceResponsesSamplingParams(BaseModel): class DataSourceResponses(BaseModel): + """A ResponsesRunDataSource object describing a model sampling configuration.""" + source: DataSourceResponsesSource """Determines what populates the `item` namespace in this run's data source.""" @@ -355,6 +379,8 @@ class PerTestingCriteriaResult(BaseModel): class ResultCounts(BaseModel): + """Counters summarizing the outcomes of the evaluation run.""" + errored: int """Number of output items that resulted in an error.""" @@ -369,6 +395,8 @@ class ResultCounts(BaseModel): class RunCancelResponse(BaseModel): + """A schema representing an evaluation run.""" + id: str """Unique identifier for the evaluation run.""" diff --git a/src/openai/types/evals/run_create_params.py b/src/openai/types/evals/run_create_params.py index a70d1923e5..993e10c738 100644 --- a/src/openai/types/evals/run_create_params.py +++ b/src/openai/types/evals/run_create_params.py @@ -79,6 +79,8 @@ class DataSourceCreateEvalResponsesRunDataSourceSourceFileID(TypedDict, total=Fa class DataSourceCreateEvalResponsesRunDataSourceSourceResponses(TypedDict, total=False): + """A EvalResponsesSource object describing a run data source configuration.""" + type: Required[Literal["responses"]] """The type of run data source. Always `responses`.""" @@ -160,6 +162,8 @@ class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateCha class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentOutputText( TypedDict, total=False ): + """A text output from the model.""" + text: Required[str] """The text output from the model.""" @@ -170,6 +174,8 @@ class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEva class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentInputImage( TypedDict, total=False ): + """An image input to the model.""" + image_url: Required[str] """The URL of the image input.""" @@ -194,6 +200,14 @@ class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEva class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItem(TypedDict, total=False): + """ + A message input to the model with a role indicating instruction following + hierarchy. Instructions given with the `developer` or `system` role take + precedence over instructions given with the `user` role. Messages with the + `assistant` role are presumed to have been generated by the model in previous + interactions. + """ + content: Required[DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContent] """Inputs to the model - can contain template strings.""" @@ -239,6 +253,14 @@ class DataSourceCreateEvalResponsesRunDataSourceInputMessagesItemReference(Typed class DataSourceCreateEvalResponsesRunDataSourceSamplingParamsText(TypedDict, total=False): + """Configuration options for a text response from the model. + + Can be plain + text or structured JSON data. Learn more: + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + """ + format: ResponseFormatTextConfigParam """An object specifying the format that the model must output. @@ -315,6 +337,8 @@ class DataSourceCreateEvalResponsesRunDataSourceSamplingParams(TypedDict, total= class DataSourceCreateEvalResponsesRunDataSource(TypedDict, total=False): + """A ResponsesRunDataSource object describing a model sampling configuration.""" + source: Required[DataSourceCreateEvalResponsesRunDataSourceSource] """Determines what populates the `item` namespace in this run's data source.""" diff --git a/src/openai/types/evals/run_create_response.py b/src/openai/types/evals/run_create_response.py index fb2220b3a1..93dae7adde 100644 --- a/src/openai/types/evals/run_create_response.py +++ b/src/openai/types/evals/run_create_response.py @@ -66,6 +66,8 @@ class DataSourceResponsesSourceFileID(BaseModel): class DataSourceResponsesSourceResponses(BaseModel): + """A EvalResponsesSource object describing a run data source configuration.""" + type: Literal["responses"] """The type of run data source. Always `responses`.""" @@ -144,6 +146,8 @@ class DataSourceResponsesInputMessagesTemplateTemplateChatMessage(BaseModel): class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText(BaseModel): + """A text output from the model.""" + text: str """The text output from the model.""" @@ -152,6 +156,8 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText( class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage(BaseModel): + """An image input to the model.""" + image_url: str """The URL of the image input.""" @@ -176,6 +182,14 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage( class DataSourceResponsesInputMessagesTemplateTemplateEvalItem(BaseModel): + """ + A message input to the model with a role indicating instruction following + hierarchy. Instructions given with the `developer` or `system` role take + precedence over instructions given with the `user` role. Messages with the + `assistant` role are presumed to have been generated by the model in previous + interactions. + """ + content: DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent """Inputs to the model - can contain template strings.""" @@ -221,6 +235,14 @@ class DataSourceResponsesInputMessagesItemReference(BaseModel): class DataSourceResponsesSamplingParamsText(BaseModel): + """Configuration options for a text response from the model. + + Can be plain + text or structured JSON data. Learn more: + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + """ + format: Optional[ResponseFormatTextConfig] = None """An object specifying the format that the model must output. @@ -297,6 +319,8 @@ class DataSourceResponsesSamplingParams(BaseModel): class DataSourceResponses(BaseModel): + """A ResponsesRunDataSource object describing a model sampling configuration.""" + source: DataSourceResponsesSource """Determines what populates the `item` namespace in this run's data source.""" @@ -355,6 +379,8 @@ class PerTestingCriteriaResult(BaseModel): class ResultCounts(BaseModel): + """Counters summarizing the outcomes of the evaluation run.""" + errored: int """Number of output items that resulted in an error.""" @@ -369,6 +395,8 @@ class ResultCounts(BaseModel): class RunCreateResponse(BaseModel): + """A schema representing an evaluation run.""" + id: str """Unique identifier for the evaluation run.""" diff --git a/src/openai/types/evals/run_list_response.py b/src/openai/types/evals/run_list_response.py index adac4ffdc8..c3c745b21c 100644 --- a/src/openai/types/evals/run_list_response.py +++ b/src/openai/types/evals/run_list_response.py @@ -66,6 +66,8 @@ class DataSourceResponsesSourceFileID(BaseModel): class DataSourceResponsesSourceResponses(BaseModel): + """A EvalResponsesSource object describing a run data source configuration.""" + type: Literal["responses"] """The type of run data source. Always `responses`.""" @@ -144,6 +146,8 @@ class DataSourceResponsesInputMessagesTemplateTemplateChatMessage(BaseModel): class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText(BaseModel): + """A text output from the model.""" + text: str """The text output from the model.""" @@ -152,6 +156,8 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText( class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage(BaseModel): + """An image input to the model.""" + image_url: str """The URL of the image input.""" @@ -176,6 +182,14 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage( class DataSourceResponsesInputMessagesTemplateTemplateEvalItem(BaseModel): + """ + A message input to the model with a role indicating instruction following + hierarchy. Instructions given with the `developer` or `system` role take + precedence over instructions given with the `user` role. Messages with the + `assistant` role are presumed to have been generated by the model in previous + interactions. + """ + content: DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent """Inputs to the model - can contain template strings.""" @@ -221,6 +235,14 @@ class DataSourceResponsesInputMessagesItemReference(BaseModel): class DataSourceResponsesSamplingParamsText(BaseModel): + """Configuration options for a text response from the model. + + Can be plain + text or structured JSON data. Learn more: + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + """ + format: Optional[ResponseFormatTextConfig] = None """An object specifying the format that the model must output. @@ -297,6 +319,8 @@ class DataSourceResponsesSamplingParams(BaseModel): class DataSourceResponses(BaseModel): + """A ResponsesRunDataSource object describing a model sampling configuration.""" + source: DataSourceResponsesSource """Determines what populates the `item` namespace in this run's data source.""" @@ -355,6 +379,8 @@ class PerTestingCriteriaResult(BaseModel): class ResultCounts(BaseModel): + """Counters summarizing the outcomes of the evaluation run.""" + errored: int """Number of output items that resulted in an error.""" @@ -369,6 +395,8 @@ class ResultCounts(BaseModel): class RunListResponse(BaseModel): + """A schema representing an evaluation run.""" + id: str """Unique identifier for the evaluation run.""" diff --git a/src/openai/types/evals/run_retrieve_response.py b/src/openai/types/evals/run_retrieve_response.py index abdc5ebae5..d02256c679 100644 --- a/src/openai/types/evals/run_retrieve_response.py +++ b/src/openai/types/evals/run_retrieve_response.py @@ -66,6 +66,8 @@ class DataSourceResponsesSourceFileID(BaseModel): class DataSourceResponsesSourceResponses(BaseModel): + """A EvalResponsesSource object describing a run data source configuration.""" + type: Literal["responses"] """The type of run data source. Always `responses`.""" @@ -144,6 +146,8 @@ class DataSourceResponsesInputMessagesTemplateTemplateChatMessage(BaseModel): class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText(BaseModel): + """A text output from the model.""" + text: str """The text output from the model.""" @@ -152,6 +156,8 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText( class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage(BaseModel): + """An image input to the model.""" + image_url: str """The URL of the image input.""" @@ -176,6 +182,14 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage( class DataSourceResponsesInputMessagesTemplateTemplateEvalItem(BaseModel): + """ + A message input to the model with a role indicating instruction following + hierarchy. Instructions given with the `developer` or `system` role take + precedence over instructions given with the `user` role. Messages with the + `assistant` role are presumed to have been generated by the model in previous + interactions. + """ + content: DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent """Inputs to the model - can contain template strings.""" @@ -221,6 +235,14 @@ class DataSourceResponsesInputMessagesItemReference(BaseModel): class DataSourceResponsesSamplingParamsText(BaseModel): + """Configuration options for a text response from the model. + + Can be plain + text or structured JSON data. Learn more: + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + """ + format: Optional[ResponseFormatTextConfig] = None """An object specifying the format that the model must output. @@ -297,6 +319,8 @@ class DataSourceResponsesSamplingParams(BaseModel): class DataSourceResponses(BaseModel): + """A ResponsesRunDataSource object describing a model sampling configuration.""" + source: DataSourceResponsesSource """Determines what populates the `item` namespace in this run's data source.""" @@ -355,6 +379,8 @@ class PerTestingCriteriaResult(BaseModel): class ResultCounts(BaseModel): + """Counters summarizing the outcomes of the evaluation run.""" + errored: int """Number of output items that resulted in an error.""" @@ -369,6 +395,8 @@ class ResultCounts(BaseModel): class RunRetrieveResponse(BaseModel): + """A schema representing an evaluation run.""" + id: str """Unique identifier for the evaluation run.""" diff --git a/src/openai/types/evals/runs/output_item_list_response.py b/src/openai/types/evals/runs/output_item_list_response.py index e88c21766f..a906a29df7 100644 --- a/src/openai/types/evals/runs/output_item_list_response.py +++ b/src/openai/types/evals/runs/output_item_list_response.py @@ -12,6 +12,8 @@ class Result(BaseModel): + """A single grader result for an evaluation run output item.""" + name: str """The name of the grader.""" @@ -41,6 +43,8 @@ def __getattr__(self, attr: str) -> object: ... class SampleInput(BaseModel): + """An input message.""" + content: str """The content of the message.""" @@ -57,6 +61,8 @@ class SampleOutput(BaseModel): class SampleUsage(BaseModel): + """Token usage details for the sample.""" + cached_tokens: int """The number of tokens retrieved from cache.""" @@ -71,6 +77,8 @@ class SampleUsage(BaseModel): class Sample(BaseModel): + """A sample containing the input and output of the evaluation run.""" + error: EvalAPIError """An object representing an error response from the Eval API.""" @@ -103,6 +111,8 @@ class Sample(BaseModel): class OutputItemListResponse(BaseModel): + """A schema representing an evaluation run output item.""" + id: str """Unique identifier for the evaluation run output item.""" diff --git a/src/openai/types/evals/runs/output_item_retrieve_response.py b/src/openai/types/evals/runs/output_item_retrieve_response.py index c728629b41..42ba4b2864 100644 --- a/src/openai/types/evals/runs/output_item_retrieve_response.py +++ b/src/openai/types/evals/runs/output_item_retrieve_response.py @@ -12,6 +12,8 @@ class Result(BaseModel): + """A single grader result for an evaluation run output item.""" + name: str """The name of the grader.""" @@ -41,6 +43,8 @@ def __getattr__(self, attr: str) -> object: ... class SampleInput(BaseModel): + """An input message.""" + content: str """The content of the message.""" @@ -57,6 +61,8 @@ class SampleOutput(BaseModel): class SampleUsage(BaseModel): + """Token usage details for the sample.""" + cached_tokens: int """The number of tokens retrieved from cache.""" @@ -71,6 +77,8 @@ class SampleUsage(BaseModel): class Sample(BaseModel): + """A sample containing the input and output of the evaluation run.""" + error: EvalAPIError """An object representing an error response from the Eval API.""" @@ -103,6 +111,8 @@ class Sample(BaseModel): class OutputItemRetrieveResponse(BaseModel): + """A schema representing an evaluation run output item.""" + id: str """Unique identifier for the evaluation run output item.""" diff --git a/src/openai/types/file_create_params.py b/src/openai/types/file_create_params.py index f4583b16a3..f4367f7a7d 100644 --- a/src/openai/types/file_create_params.py +++ b/src/openai/types/file_create_params.py @@ -32,6 +32,11 @@ class FileCreateParams(TypedDict, total=False): class ExpiresAfter(TypedDict, total=False): + """The expiration policy for a file. + + By default, files with `purpose=batch` expire after 30 days and all other files are persisted until they are manually deleted. + """ + anchor: Required[Literal["created_at"]] """Anchor timestamp after which the expiration policy applies. diff --git a/src/openai/types/file_object.py b/src/openai/types/file_object.py index 883c2de019..4a9901fd3f 100644 --- a/src/openai/types/file_object.py +++ b/src/openai/types/file_object.py @@ -9,6 +9,8 @@ class FileObject(BaseModel): + """The `File` object represents a document that has been uploaded to OpenAI.""" + id: str """The file identifier, which can be referenced in the API endpoints.""" diff --git a/src/openai/types/fine_tuning/checkpoints/permission_create_response.py b/src/openai/types/fine_tuning/checkpoints/permission_create_response.py index 9bc14c00cc..459fa9dee7 100644 --- a/src/openai/types/fine_tuning/checkpoints/permission_create_response.py +++ b/src/openai/types/fine_tuning/checkpoints/permission_create_response.py @@ -8,6 +8,10 @@ class PermissionCreateResponse(BaseModel): + """ + The `checkpoint.permission` object represents a permission for a fine-tuned model checkpoint. + """ + id: str """The permission identifier, which can be referenced in the API endpoints.""" diff --git a/src/openai/types/fine_tuning/checkpoints/permission_retrieve_response.py b/src/openai/types/fine_tuning/checkpoints/permission_retrieve_response.py index 14c73b55d0..34208958ef 100644 --- a/src/openai/types/fine_tuning/checkpoints/permission_retrieve_response.py +++ b/src/openai/types/fine_tuning/checkpoints/permission_retrieve_response.py @@ -9,6 +9,10 @@ class Data(BaseModel): + """ + The `checkpoint.permission` object represents a permission for a fine-tuned model checkpoint. + """ + id: str """The permission identifier, which can be referenced in the API endpoints.""" diff --git a/src/openai/types/fine_tuning/dpo_hyperparameters.py b/src/openai/types/fine_tuning/dpo_hyperparameters.py index b0b3f0581b..cd39f308a4 100644 --- a/src/openai/types/fine_tuning/dpo_hyperparameters.py +++ b/src/openai/types/fine_tuning/dpo_hyperparameters.py @@ -9,6 +9,8 @@ class DpoHyperparameters(BaseModel): + """The hyperparameters used for the DPO fine-tuning job.""" + batch_size: Union[Literal["auto"], int, None] = None """Number of examples in each batch. diff --git a/src/openai/types/fine_tuning/dpo_hyperparameters_param.py b/src/openai/types/fine_tuning/dpo_hyperparameters_param.py index 87c6ee80a5..12b2c41ca8 100644 --- a/src/openai/types/fine_tuning/dpo_hyperparameters_param.py +++ b/src/openai/types/fine_tuning/dpo_hyperparameters_param.py @@ -9,6 +9,8 @@ class DpoHyperparametersParam(TypedDict, total=False): + """The hyperparameters used for the DPO fine-tuning job.""" + batch_size: Union[Literal["auto"], int] """Number of examples in each batch. diff --git a/src/openai/types/fine_tuning/dpo_method.py b/src/openai/types/fine_tuning/dpo_method.py index 3e20f360dd..452c182016 100644 --- a/src/openai/types/fine_tuning/dpo_method.py +++ b/src/openai/types/fine_tuning/dpo_method.py @@ -9,5 +9,7 @@ class DpoMethod(BaseModel): + """Configuration for the DPO fine-tuning method.""" + hyperparameters: Optional[DpoHyperparameters] = None """The hyperparameters used for the DPO fine-tuning job.""" diff --git a/src/openai/types/fine_tuning/dpo_method_param.py b/src/openai/types/fine_tuning/dpo_method_param.py index ce6b6510f6..6bd74d9760 100644 --- a/src/openai/types/fine_tuning/dpo_method_param.py +++ b/src/openai/types/fine_tuning/dpo_method_param.py @@ -10,5 +10,7 @@ class DpoMethodParam(TypedDict, total=False): + """Configuration for the DPO fine-tuning method.""" + hyperparameters: DpoHyperparametersParam """The hyperparameters used for the DPO fine-tuning job.""" diff --git a/src/openai/types/fine_tuning/fine_tuning_job.py b/src/openai/types/fine_tuning/fine_tuning_job.py index f626fbba64..bb8a4d597b 100644 --- a/src/openai/types/fine_tuning/fine_tuning_job.py +++ b/src/openai/types/fine_tuning/fine_tuning_job.py @@ -14,6 +14,10 @@ class Error(BaseModel): + """ + For fine-tuning jobs that have `failed`, this will contain more information on the cause of the failure. + """ + code: str """A machine-readable error code.""" @@ -28,6 +32,11 @@ class Error(BaseModel): class Hyperparameters(BaseModel): + """The hyperparameters used for the fine-tuning job. + + This value will only be returned when running `supervised` jobs. + """ + batch_size: Union[Literal["auto"], int, None] = None """Number of examples in each batch. @@ -49,6 +58,8 @@ class Hyperparameters(BaseModel): class Method(BaseModel): + """The method used for fine-tuning.""" + type: Literal["supervised", "dpo", "reinforcement"] """The type of method. Is either `supervised`, `dpo`, or `reinforcement`.""" @@ -63,6 +74,10 @@ class Method(BaseModel): class FineTuningJob(BaseModel): + """ + The `fine_tuning.job` object represents a fine-tuning job that has been created through the API. + """ + id: str """The object identifier, which can be referenced in the API endpoints.""" diff --git a/src/openai/types/fine_tuning/fine_tuning_job_event.py b/src/openai/types/fine_tuning/fine_tuning_job_event.py index 1d728bd765..7452b818c6 100644 --- a/src/openai/types/fine_tuning/fine_tuning_job_event.py +++ b/src/openai/types/fine_tuning/fine_tuning_job_event.py @@ -10,6 +10,8 @@ class FineTuningJobEvent(BaseModel): + """Fine-tuning job event object""" + id: str """The object identifier.""" diff --git a/src/openai/types/fine_tuning/fine_tuning_job_wandb_integration.py b/src/openai/types/fine_tuning/fine_tuning_job_wandb_integration.py index 4ac282eb54..0e33aa84c8 100644 --- a/src/openai/types/fine_tuning/fine_tuning_job_wandb_integration.py +++ b/src/openai/types/fine_tuning/fine_tuning_job_wandb_integration.py @@ -8,6 +8,13 @@ class FineTuningJobWandbIntegration(BaseModel): + """The settings for your integration with Weights and Biases. + + This payload specifies the project that + metrics will be sent to. Optionally, you can set an explicit display name for your run, add tags + to your run, and set a default entity (team, username, etc) to be associated with your run. + """ + project: str """The name of the project that the new run will be created under.""" diff --git a/src/openai/types/fine_tuning/job_create_params.py b/src/openai/types/fine_tuning/job_create_params.py index 351d4e0e1b..181bede2d9 100644 --- a/src/openai/types/fine_tuning/job_create_params.py +++ b/src/openai/types/fine_tuning/job_create_params.py @@ -100,6 +100,11 @@ class JobCreateParams(TypedDict, total=False): class Hyperparameters(TypedDict, total=False): + """ + The hyperparameters used for the fine-tuning job. + This value is now deprecated in favor of `method`, and should be passed in under the `method` parameter. + """ + batch_size: Union[Literal["auto"], int] """Number of examples in each batch. @@ -121,6 +126,13 @@ class Hyperparameters(TypedDict, total=False): class IntegrationWandb(TypedDict, total=False): + """The settings for your integration with Weights and Biases. + + This payload specifies the project that + metrics will be sent to. Optionally, you can set an explicit display name for your run, add tags + to your run, and set a default entity (team, username, etc) to be associated with your run. + """ + project: Required[str] """The name of the project that the new run will be created under.""" @@ -163,6 +175,8 @@ class Integration(TypedDict, total=False): class Method(TypedDict, total=False): + """The method used for fine-tuning.""" + type: Required[Literal["supervised", "dpo", "reinforcement"]] """The type of method. Is either `supervised`, `dpo`, or `reinforcement`.""" diff --git a/src/openai/types/fine_tuning/jobs/fine_tuning_job_checkpoint.py b/src/openai/types/fine_tuning/jobs/fine_tuning_job_checkpoint.py index bd07317a3e..f8a04b6395 100644 --- a/src/openai/types/fine_tuning/jobs/fine_tuning_job_checkpoint.py +++ b/src/openai/types/fine_tuning/jobs/fine_tuning_job_checkpoint.py @@ -9,6 +9,8 @@ class Metrics(BaseModel): + """Metrics at the step number during the fine-tuning job.""" + full_valid_loss: Optional[float] = None full_valid_mean_token_accuracy: Optional[float] = None @@ -25,6 +27,10 @@ class Metrics(BaseModel): class FineTuningJobCheckpoint(BaseModel): + """ + The `fine_tuning.job.checkpoint` object represents a model checkpoint for a fine-tuning job that is ready to use. + """ + id: str """The checkpoint identifier, which can be referenced in the API endpoints.""" diff --git a/src/openai/types/fine_tuning/reinforcement_hyperparameters.py b/src/openai/types/fine_tuning/reinforcement_hyperparameters.py index 7c1762d38c..4c289fd659 100644 --- a/src/openai/types/fine_tuning/reinforcement_hyperparameters.py +++ b/src/openai/types/fine_tuning/reinforcement_hyperparameters.py @@ -9,6 +9,8 @@ class ReinforcementHyperparameters(BaseModel): + """The hyperparameters used for the reinforcement fine-tuning job.""" + batch_size: Union[Literal["auto"], int, None] = None """Number of examples in each batch. diff --git a/src/openai/types/fine_tuning/reinforcement_hyperparameters_param.py b/src/openai/types/fine_tuning/reinforcement_hyperparameters_param.py index 0cc12fcb17..7be716f143 100644 --- a/src/openai/types/fine_tuning/reinforcement_hyperparameters_param.py +++ b/src/openai/types/fine_tuning/reinforcement_hyperparameters_param.py @@ -9,6 +9,8 @@ class ReinforcementHyperparametersParam(TypedDict, total=False): + """The hyperparameters used for the reinforcement fine-tuning job.""" + batch_size: Union[Literal["auto"], int] """Number of examples in each batch. diff --git a/src/openai/types/fine_tuning/reinforcement_method.py b/src/openai/types/fine_tuning/reinforcement_method.py index 9b65c41033..a8a3685148 100644 --- a/src/openai/types/fine_tuning/reinforcement_method.py +++ b/src/openai/types/fine_tuning/reinforcement_method.py @@ -17,6 +17,8 @@ class ReinforcementMethod(BaseModel): + """Configuration for the reinforcement fine-tuning method.""" + grader: Grader """The grader used for the fine-tuning job.""" diff --git a/src/openai/types/fine_tuning/reinforcement_method_param.py b/src/openai/types/fine_tuning/reinforcement_method_param.py index 00d5060536..ea75bfeb69 100644 --- a/src/openai/types/fine_tuning/reinforcement_method_param.py +++ b/src/openai/types/fine_tuning/reinforcement_method_param.py @@ -20,6 +20,8 @@ class ReinforcementMethodParam(TypedDict, total=False): + """Configuration for the reinforcement fine-tuning method.""" + grader: Required[Grader] """The grader used for the fine-tuning job.""" diff --git a/src/openai/types/fine_tuning/supervised_hyperparameters.py b/src/openai/types/fine_tuning/supervised_hyperparameters.py index 3955ecf437..1231bbdd80 100644 --- a/src/openai/types/fine_tuning/supervised_hyperparameters.py +++ b/src/openai/types/fine_tuning/supervised_hyperparameters.py @@ -9,6 +9,8 @@ class SupervisedHyperparameters(BaseModel): + """The hyperparameters used for the fine-tuning job.""" + batch_size: Union[Literal["auto"], int, None] = None """Number of examples in each batch. diff --git a/src/openai/types/fine_tuning/supervised_hyperparameters_param.py b/src/openai/types/fine_tuning/supervised_hyperparameters_param.py index bd37d9b239..de0e021dea 100644 --- a/src/openai/types/fine_tuning/supervised_hyperparameters_param.py +++ b/src/openai/types/fine_tuning/supervised_hyperparameters_param.py @@ -9,6 +9,8 @@ class SupervisedHyperparametersParam(TypedDict, total=False): + """The hyperparameters used for the fine-tuning job.""" + batch_size: Union[Literal["auto"], int] """Number of examples in each batch. diff --git a/src/openai/types/fine_tuning/supervised_method.py b/src/openai/types/fine_tuning/supervised_method.py index 3a32bf27a0..96e102582d 100644 --- a/src/openai/types/fine_tuning/supervised_method.py +++ b/src/openai/types/fine_tuning/supervised_method.py @@ -9,5 +9,7 @@ class SupervisedMethod(BaseModel): + """Configuration for the supervised fine-tuning method.""" + hyperparameters: Optional[SupervisedHyperparameters] = None """The hyperparameters used for the fine-tuning job.""" diff --git a/src/openai/types/fine_tuning/supervised_method_param.py b/src/openai/types/fine_tuning/supervised_method_param.py index ba277853d7..4381cd184b 100644 --- a/src/openai/types/fine_tuning/supervised_method_param.py +++ b/src/openai/types/fine_tuning/supervised_method_param.py @@ -10,5 +10,7 @@ class SupervisedMethodParam(TypedDict, total=False): + """Configuration for the supervised fine-tuning method.""" + hyperparameters: SupervisedHyperparametersParam """The hyperparameters used for the fine-tuning job.""" diff --git a/src/openai/types/graders/label_model_grader.py b/src/openai/types/graders/label_model_grader.py index 0929349c24..141306b510 100644 --- a/src/openai/types/graders/label_model_grader.py +++ b/src/openai/types/graders/label_model_grader.py @@ -11,6 +11,8 @@ class InputContentOutputText(BaseModel): + """A text output from the model.""" + text: str """The text output from the model.""" @@ -19,6 +21,8 @@ class InputContentOutputText(BaseModel): class InputContentInputImage(BaseModel): + """An image input to the model.""" + image_url: str """The URL of the image input.""" @@ -38,6 +42,14 @@ class InputContentInputImage(BaseModel): class Input(BaseModel): + """ + A message input to the model with a role indicating instruction following + hierarchy. Instructions given with the `developer` or `system` role take + precedence over instructions given with the `user` role. Messages with the + `assistant` role are presumed to have been generated by the model in previous + interactions. + """ + content: InputContent """Inputs to the model - can contain template strings.""" @@ -52,6 +64,11 @@ class Input(BaseModel): class LabelModelGrader(BaseModel): + """ + A LabelModelGrader object which uses a model to assign labels to each item + in the evaluation. + """ + input: List[Input] labels: List[str] diff --git a/src/openai/types/graders/label_model_grader_param.py b/src/openai/types/graders/label_model_grader_param.py index 7bd6fdb4a7..a23be2a236 100644 --- a/src/openai/types/graders/label_model_grader_param.py +++ b/src/openai/types/graders/label_model_grader_param.py @@ -13,6 +13,8 @@ class InputContentOutputText(TypedDict, total=False): + """A text output from the model.""" + text: Required[str] """The text output from the model.""" @@ -21,6 +23,8 @@ class InputContentOutputText(TypedDict, total=False): class InputContentInputImage(TypedDict, total=False): + """An image input to the model.""" + image_url: Required[str] """The URL of the image input.""" @@ -45,6 +49,14 @@ class InputContentInputImage(TypedDict, total=False): class Input(TypedDict, total=False): + """ + A message input to the model with a role indicating instruction following + hierarchy. Instructions given with the `developer` or `system` role take + precedence over instructions given with the `user` role. Messages with the + `assistant` role are presumed to have been generated by the model in previous + interactions. + """ + content: Required[InputContent] """Inputs to the model - can contain template strings.""" @@ -59,6 +71,11 @@ class Input(TypedDict, total=False): class LabelModelGraderParam(TypedDict, total=False): + """ + A LabelModelGrader object which uses a model to assign labels to each item + in the evaluation. + """ + input: Required[Iterable[Input]] labels: Required[SequenceNotStr[str]] diff --git a/src/openai/types/graders/multi_grader.py b/src/openai/types/graders/multi_grader.py index 7539c68ef5..022ddb406a 100644 --- a/src/openai/types/graders/multi_grader.py +++ b/src/openai/types/graders/multi_grader.py @@ -16,6 +16,10 @@ class MultiGrader(BaseModel): + """ + A MultiGrader object combines the output of multiple graders to produce a single score. + """ + calculate_output: str """A formula to calculate the output based on grader results.""" diff --git a/src/openai/types/graders/multi_grader_param.py b/src/openai/types/graders/multi_grader_param.py index 28a6705b81..064267a5aa 100644 --- a/src/openai/types/graders/multi_grader_param.py +++ b/src/openai/types/graders/multi_grader_param.py @@ -19,6 +19,10 @@ class MultiGraderParam(TypedDict, total=False): + """ + A MultiGrader object combines the output of multiple graders to produce a single score. + """ + calculate_output: Required[str] """A formula to calculate the output based on grader results.""" diff --git a/src/openai/types/graders/python_grader.py b/src/openai/types/graders/python_grader.py index faa10b1ef9..81aafdae0a 100644 --- a/src/openai/types/graders/python_grader.py +++ b/src/openai/types/graders/python_grader.py @@ -9,6 +9,8 @@ class PythonGrader(BaseModel): + """A PythonGrader object that runs a python script on the input.""" + name: str """The name of the grader.""" diff --git a/src/openai/types/graders/python_grader_param.py b/src/openai/types/graders/python_grader_param.py index efb923751e..3be7bab432 100644 --- a/src/openai/types/graders/python_grader_param.py +++ b/src/openai/types/graders/python_grader_param.py @@ -8,6 +8,8 @@ class PythonGraderParam(TypedDict, total=False): + """A PythonGrader object that runs a python script on the input.""" + name: Required[str] """The name of the grader.""" diff --git a/src/openai/types/graders/score_model_grader.py b/src/openai/types/graders/score_model_grader.py index b3ba6758bb..6dd5a0eee8 100644 --- a/src/openai/types/graders/score_model_grader.py +++ b/src/openai/types/graders/score_model_grader.py @@ -19,6 +19,8 @@ class InputContentOutputText(BaseModel): + """A text output from the model.""" + text: str """The text output from the model.""" @@ -27,6 +29,8 @@ class InputContentOutputText(BaseModel): class InputContentInputImage(BaseModel): + """An image input to the model.""" + image_url: str """The URL of the image input.""" @@ -46,6 +50,14 @@ class InputContentInputImage(BaseModel): class Input(BaseModel): + """ + A message input to the model with a role indicating instruction following + hierarchy. Instructions given with the `developer` or `system` role take + precedence over instructions given with the `user` role. Messages with the + `assistant` role are presumed to have been generated by the model in previous + interactions. + """ + content: InputContent """Inputs to the model - can contain template strings.""" @@ -60,6 +72,8 @@ class Input(BaseModel): class SamplingParams(BaseModel): + """The sampling parameters for the model.""" + max_completions_tokens: Optional[int] = None """The maximum number of tokens the grader model may generate in its response.""" @@ -91,6 +105,8 @@ class SamplingParams(BaseModel): class ScoreModelGrader(BaseModel): + """A ScoreModelGrader object that uses a model to assign a score to the input.""" + input: List[Input] """The input text. This may include template strings.""" diff --git a/src/openai/types/graders/score_model_grader_param.py b/src/openai/types/graders/score_model_grader_param.py index eb1f6e03ac..33452e43f3 100644 --- a/src/openai/types/graders/score_model_grader_param.py +++ b/src/openai/types/graders/score_model_grader_param.py @@ -20,6 +20,8 @@ class InputContentOutputText(TypedDict, total=False): + """A text output from the model.""" + text: Required[str] """The text output from the model.""" @@ -28,6 +30,8 @@ class InputContentOutputText(TypedDict, total=False): class InputContentInputImage(TypedDict, total=False): + """An image input to the model.""" + image_url: Required[str] """The URL of the image input.""" @@ -52,6 +56,14 @@ class InputContentInputImage(TypedDict, total=False): class Input(TypedDict, total=False): + """ + A message input to the model with a role indicating instruction following + hierarchy. Instructions given with the `developer` or `system` role take + precedence over instructions given with the `user` role. Messages with the + `assistant` role are presumed to have been generated by the model in previous + interactions. + """ + content: Required[InputContent] """Inputs to the model - can contain template strings.""" @@ -66,6 +78,8 @@ class Input(TypedDict, total=False): class SamplingParams(TypedDict, total=False): + """The sampling parameters for the model.""" + max_completions_tokens: Optional[int] """The maximum number of tokens the grader model may generate in its response.""" @@ -97,6 +111,8 @@ class SamplingParams(TypedDict, total=False): class ScoreModelGraderParam(TypedDict, total=False): + """A ScoreModelGrader object that uses a model to assign a score to the input.""" + input: Required[Iterable[Input]] """The input text. This may include template strings.""" diff --git a/src/openai/types/graders/string_check_grader.py b/src/openai/types/graders/string_check_grader.py index 3bf0b8c868..efd3679da9 100644 --- a/src/openai/types/graders/string_check_grader.py +++ b/src/openai/types/graders/string_check_grader.py @@ -8,6 +8,10 @@ class StringCheckGrader(BaseModel): + """ + A StringCheckGrader object that performs a string comparison between input and reference using a specified operation. + """ + input: str """The input text. This may include template strings.""" diff --git a/src/openai/types/graders/string_check_grader_param.py b/src/openai/types/graders/string_check_grader_param.py index 27b204cec0..da9e961568 100644 --- a/src/openai/types/graders/string_check_grader_param.py +++ b/src/openai/types/graders/string_check_grader_param.py @@ -8,6 +8,10 @@ class StringCheckGraderParam(TypedDict, total=False): + """ + A StringCheckGrader object that performs a string comparison between input and reference using a specified operation. + """ + input: Required[str] """The input text. This may include template strings.""" diff --git a/src/openai/types/graders/text_similarity_grader.py b/src/openai/types/graders/text_similarity_grader.py index 9082ac8969..a9d39a2fbd 100644 --- a/src/openai/types/graders/text_similarity_grader.py +++ b/src/openai/types/graders/text_similarity_grader.py @@ -8,6 +8,8 @@ class TextSimilarityGrader(BaseModel): + """A TextSimilarityGrader object which grades text based on similarity metrics.""" + evaluation_metric: Literal[ "cosine", "fuzzy_match", diff --git a/src/openai/types/graders/text_similarity_grader_param.py b/src/openai/types/graders/text_similarity_grader_param.py index 1646afc84b..0907c3c2a7 100644 --- a/src/openai/types/graders/text_similarity_grader_param.py +++ b/src/openai/types/graders/text_similarity_grader_param.py @@ -8,6 +8,8 @@ class TextSimilarityGraderParam(TypedDict, total=False): + """A TextSimilarityGrader object which grades text based on similarity metrics.""" + evaluation_metric: Required[ Literal[ "cosine", diff --git a/src/openai/types/image.py b/src/openai/types/image.py index ecaef3fd58..9e2a23fa40 100644 --- a/src/openai/types/image.py +++ b/src/openai/types/image.py @@ -8,6 +8,8 @@ class Image(BaseModel): + """Represents the content or the URL of an image generated by the OpenAI API.""" + b64_json: Optional[str] = None """The base64-encoded JSON of the generated image. diff --git a/src/openai/types/image_edit_completed_event.py b/src/openai/types/image_edit_completed_event.py index a40682da6a..5bd2986d2a 100644 --- a/src/openai/types/image_edit_completed_event.py +++ b/src/openai/types/image_edit_completed_event.py @@ -8,6 +8,8 @@ class UsageInputTokensDetails(BaseModel): + """The input tokens detailed information for the image generation.""" + image_tokens: int """The number of image tokens in the input prompt.""" @@ -16,6 +18,8 @@ class UsageInputTokensDetails(BaseModel): class Usage(BaseModel): + """For `gpt-image-1` only, the token usage information for the image generation.""" + input_tokens: int """The number of tokens (images and text) in the input prompt.""" @@ -30,6 +34,8 @@ class Usage(BaseModel): class ImageEditCompletedEvent(BaseModel): + """Emitted when image editing has completed and the final image is available.""" + b64_json: str """Base64-encoded final edited image data, suitable for rendering as an image.""" diff --git a/src/openai/types/image_edit_partial_image_event.py b/src/openai/types/image_edit_partial_image_event.py index 20da45efc3..7bbd8c9b13 100644 --- a/src/openai/types/image_edit_partial_image_event.py +++ b/src/openai/types/image_edit_partial_image_event.py @@ -8,6 +8,8 @@ class ImageEditPartialImageEvent(BaseModel): + """Emitted when a partial image is available during image editing streaming.""" + b64_json: str """Base64-encoded partial image data, suitable for rendering as an image.""" diff --git a/src/openai/types/image_gen_completed_event.py b/src/openai/types/image_gen_completed_event.py index e78da842d4..dc9ccb8cfc 100644 --- a/src/openai/types/image_gen_completed_event.py +++ b/src/openai/types/image_gen_completed_event.py @@ -8,6 +8,8 @@ class UsageInputTokensDetails(BaseModel): + """The input tokens detailed information for the image generation.""" + image_tokens: int """The number of image tokens in the input prompt.""" @@ -16,6 +18,8 @@ class UsageInputTokensDetails(BaseModel): class Usage(BaseModel): + """For `gpt-image-1` only, the token usage information for the image generation.""" + input_tokens: int """The number of tokens (images and text) in the input prompt.""" @@ -30,6 +34,8 @@ class Usage(BaseModel): class ImageGenCompletedEvent(BaseModel): + """Emitted when image generation has completed and the final image is available.""" + b64_json: str """Base64-encoded image data, suitable for rendering as an image.""" diff --git a/src/openai/types/image_gen_partial_image_event.py b/src/openai/types/image_gen_partial_image_event.py index 965d450604..df29c00a63 100644 --- a/src/openai/types/image_gen_partial_image_event.py +++ b/src/openai/types/image_gen_partial_image_event.py @@ -8,6 +8,8 @@ class ImageGenPartialImageEvent(BaseModel): + """Emitted when a partial image is available during image generation streaming.""" + b64_json: str """Base64-encoded partial image data, suitable for rendering as an image.""" diff --git a/src/openai/types/images_response.py b/src/openai/types/images_response.py index 89cc71df24..914017823e 100644 --- a/src/openai/types/images_response.py +++ b/src/openai/types/images_response.py @@ -10,6 +10,8 @@ class UsageInputTokensDetails(BaseModel): + """The input tokens detailed information for the image generation.""" + image_tokens: int """The number of image tokens in the input prompt.""" @@ -18,6 +20,8 @@ class UsageInputTokensDetails(BaseModel): class Usage(BaseModel): + """For `gpt-image-1` only, the token usage information for the image generation.""" + input_tokens: int """The number of tokens (images and text) in the input prompt.""" @@ -32,6 +36,8 @@ class Usage(BaseModel): class ImagesResponse(BaseModel): + """The response from the image generation endpoint.""" + created: int """The Unix timestamp (in seconds) of when the image was created.""" diff --git a/src/openai/types/model.py b/src/openai/types/model.py index 2631ee8d1a..6506224a20 100644 --- a/src/openai/types/model.py +++ b/src/openai/types/model.py @@ -8,6 +8,8 @@ class Model(BaseModel): + """Describes an OpenAI model offering that can be used with the API.""" + id: str """The model identifier, which can be referenced in the API endpoints.""" diff --git a/src/openai/types/moderation.py b/src/openai/types/moderation.py index 608f562218..a6acc26db4 100644 --- a/src/openai/types/moderation.py +++ b/src/openai/types/moderation.py @@ -11,6 +11,8 @@ class Categories(BaseModel): + """A list of the categories, and whether they are flagged or not.""" + harassment: bool """ Content that expresses, incites, or promotes harassing language towards any @@ -89,6 +91,10 @@ class Categories(BaseModel): class CategoryAppliedInputTypes(BaseModel): + """ + A list of the categories along with the input type(s) that the score applies to. + """ + harassment: List[Literal["text"]] """The applied input type(s) for the category 'harassment'.""" @@ -130,6 +136,8 @@ class CategoryAppliedInputTypes(BaseModel): class CategoryScores(BaseModel): + """A list of the categories along with their scores as predicted by model.""" + harassment: float """The score for the category 'harassment'.""" diff --git a/src/openai/types/moderation_create_response.py b/src/openai/types/moderation_create_response.py index 79684f8a70..23c03875bf 100644 --- a/src/openai/types/moderation_create_response.py +++ b/src/openai/types/moderation_create_response.py @@ -9,6 +9,8 @@ class ModerationCreateResponse(BaseModel): + """Represents if a given text input is potentially harmful.""" + id: str """The unique identifier for the moderation request.""" diff --git a/src/openai/types/moderation_image_url_input_param.py b/src/openai/types/moderation_image_url_input_param.py index 9a69a6a257..9c0fe25685 100644 --- a/src/openai/types/moderation_image_url_input_param.py +++ b/src/openai/types/moderation_image_url_input_param.py @@ -8,11 +8,15 @@ class ImageURL(TypedDict, total=False): + """Contains either an image URL or a data URL for a base64 encoded image.""" + url: Required[str] """Either a URL of the image or the base64 encoded image data.""" class ModerationImageURLInputParam(TypedDict, total=False): + """An object describing an image to classify.""" + image_url: Required[ImageURL] """Contains either an image URL or a data URL for a base64 encoded image.""" diff --git a/src/openai/types/moderation_text_input_param.py b/src/openai/types/moderation_text_input_param.py index e5da53337b..786ecbe625 100644 --- a/src/openai/types/moderation_text_input_param.py +++ b/src/openai/types/moderation_text_input_param.py @@ -8,6 +8,8 @@ class ModerationTextInputParam(TypedDict, total=False): + """An object describing text to classify.""" + text: Required[str] """A string of text to classify.""" diff --git a/src/openai/types/other_file_chunking_strategy_object.py b/src/openai/types/other_file_chunking_strategy_object.py index e4cd61a8fc..a5371425d7 100644 --- a/src/openai/types/other_file_chunking_strategy_object.py +++ b/src/openai/types/other_file_chunking_strategy_object.py @@ -8,5 +8,10 @@ class OtherFileChunkingStrategyObject(BaseModel): + """This is returned when the chunking strategy is unknown. + + Typically, this is because the file was indexed before the `chunking_strategy` concept was introduced in the API. + """ + type: Literal["other"] """Always `other`.""" diff --git a/src/openai/types/realtime/client_secret_create_params.py b/src/openai/types/realtime/client_secret_create_params.py index 5f0b0d796f..2297f3f6d2 100644 --- a/src/openai/types/realtime/client_secret_create_params.py +++ b/src/openai/types/realtime/client_secret_create_params.py @@ -28,6 +28,14 @@ class ClientSecretCreateParams(TypedDict, total=False): class ExpiresAfter(TypedDict, total=False): + """Configuration for the client secret expiration. + + Expiration refers to the time after which + a client secret will no longer be valid for creating sessions. The session itself may + continue after that time once started. A secret can be used to create multiple sessions + until it expires. + """ + anchor: Literal["created_at"] """ The anchor point for the client secret expiration, meaning that `seconds` will diff --git a/src/openai/types/realtime/client_secret_create_response.py b/src/openai/types/realtime/client_secret_create_response.py index 2aed66a25b..3a30b10544 100644 --- a/src/openai/types/realtime/client_secret_create_response.py +++ b/src/openai/types/realtime/client_secret_create_response.py @@ -16,6 +16,8 @@ class ClientSecretCreateResponse(BaseModel): + """Response from creating a session and client secret for the Realtime API.""" + expires_at: int """Expiration timestamp for the client secret, in seconds since epoch.""" diff --git a/src/openai/types/realtime/conversation_created_event.py b/src/openai/types/realtime/conversation_created_event.py index 6ec1dc8c85..3026322e86 100644 --- a/src/openai/types/realtime/conversation_created_event.py +++ b/src/openai/types/realtime/conversation_created_event.py @@ -9,6 +9,8 @@ class Conversation(BaseModel): + """The conversation resource.""" + id: Optional[str] = None """The unique ID of the conversation.""" @@ -17,6 +19,8 @@ class Conversation(BaseModel): class ConversationCreatedEvent(BaseModel): + """Returned when a conversation is created. Emitted right after session creation.""" + conversation: Conversation """The conversation resource.""" diff --git a/src/openai/types/realtime/conversation_item_added.py b/src/openai/types/realtime/conversation_item_added.py index ae9f6803e4..0e336a9261 100644 --- a/src/openai/types/realtime/conversation_item_added.py +++ b/src/openai/types/realtime/conversation_item_added.py @@ -10,6 +10,16 @@ class ConversationItemAdded(BaseModel): + """Sent by the server when an Item is added to the default Conversation. + + This can happen in several cases: + - When the client sends a `conversation.item.create` event. + - When the input audio buffer is committed. In this case the item will be a user message containing the audio from the buffer. + - When the model is generating a Response. In this case the `conversation.item.added` event will be sent when the model starts generating a specific Item, and thus it will not yet have any content (and `status` will be `in_progress`). + + The event will include the full content of the Item (except when model is generating a Response) except for audio data, which can be retrieved separately with a `conversation.item.retrieve` event if necessary. + """ + event_id: str """The unique ID of the server event.""" diff --git a/src/openai/types/realtime/conversation_item_create_event.py b/src/openai/types/realtime/conversation_item_create_event.py index 8fa2dfe08c..bf2d129744 100644 --- a/src/openai/types/realtime/conversation_item_create_event.py +++ b/src/openai/types/realtime/conversation_item_create_event.py @@ -10,6 +10,16 @@ class ConversationItemCreateEvent(BaseModel): + """ + Add a new Item to the Conversation's context, including messages, function + calls, and function call responses. This event can be used both to populate a + "history" of the conversation and to add new items mid-stream, but has the + current limitation that it cannot populate assistant audio messages. + + If successful, the server will respond with a `conversation.item.created` + event, otherwise an `error` event will be sent. + """ + item: ConversationItem """A single item within a Realtime conversation.""" diff --git a/src/openai/types/realtime/conversation_item_create_event_param.py b/src/openai/types/realtime/conversation_item_create_event_param.py index 8530dc72cd..be7f0ff011 100644 --- a/src/openai/types/realtime/conversation_item_create_event_param.py +++ b/src/openai/types/realtime/conversation_item_create_event_param.py @@ -10,6 +10,16 @@ class ConversationItemCreateEventParam(TypedDict, total=False): + """ + Add a new Item to the Conversation's context, including messages, function + calls, and function call responses. This event can be used both to populate a + "history" of the conversation and to add new items mid-stream, but has the + current limitation that it cannot populate assistant audio messages. + + If successful, the server will respond with a `conversation.item.created` + event, otherwise an `error` event will be sent. + """ + item: Required[ConversationItemParam] """A single item within a Realtime conversation.""" diff --git a/src/openai/types/realtime/conversation_item_created_event.py b/src/openai/types/realtime/conversation_item_created_event.py index 13f24ad31a..6ae6f05ffe 100644 --- a/src/openai/types/realtime/conversation_item_created_event.py +++ b/src/openai/types/realtime/conversation_item_created_event.py @@ -10,6 +10,19 @@ class ConversationItemCreatedEvent(BaseModel): + """Returned when a conversation item is created. + + There are several scenarios that produce this event: + - The server is generating a Response, which if successful will produce + either one or two Items, which will be of type `message` + (role `assistant`) or type `function_call`. + - The input audio buffer has been committed, either by the client or the + server (in `server_vad` mode). The server will take the content of the + input audio buffer and add it to a new user message Item. + - The client has sent a `conversation.item.create` event to add a new Item + to the Conversation. + """ + event_id: str """The unique ID of the server event.""" diff --git a/src/openai/types/realtime/conversation_item_delete_event.py b/src/openai/types/realtime/conversation_item_delete_event.py index 3734f72e9d..c662f386e3 100644 --- a/src/openai/types/realtime/conversation_item_delete_event.py +++ b/src/openai/types/realtime/conversation_item_delete_event.py @@ -9,6 +9,14 @@ class ConversationItemDeleteEvent(BaseModel): + """Send this event when you want to remove any item from the conversation + history. + + The server will respond with a `conversation.item.deleted` event, + unless the item does not exist in the conversation history, in which case the + server will respond with an error. + """ + item_id: str """The ID of the item to delete.""" diff --git a/src/openai/types/realtime/conversation_item_delete_event_param.py b/src/openai/types/realtime/conversation_item_delete_event_param.py index c3f88d6627..e79bb68c9a 100644 --- a/src/openai/types/realtime/conversation_item_delete_event_param.py +++ b/src/openai/types/realtime/conversation_item_delete_event_param.py @@ -8,6 +8,14 @@ class ConversationItemDeleteEventParam(TypedDict, total=False): + """Send this event when you want to remove any item from the conversation + history. + + The server will respond with a `conversation.item.deleted` event, + unless the item does not exist in the conversation history, in which case the + server will respond with an error. + """ + item_id: Required[str] """The ID of the item to delete.""" diff --git a/src/openai/types/realtime/conversation_item_deleted_event.py b/src/openai/types/realtime/conversation_item_deleted_event.py index cfe6fe85fc..9826289ebf 100644 --- a/src/openai/types/realtime/conversation_item_deleted_event.py +++ b/src/openai/types/realtime/conversation_item_deleted_event.py @@ -8,6 +8,12 @@ class ConversationItemDeletedEvent(BaseModel): + """ + Returned when an item in the conversation is deleted by the client with a + `conversation.item.delete` event. This event is used to synchronize the + server's understanding of the conversation history with the client's view. + """ + event_id: str """The unique ID of the server event.""" diff --git a/src/openai/types/realtime/conversation_item_done.py b/src/openai/types/realtime/conversation_item_done.py index a4c9b8a840..6a823c65a8 100644 --- a/src/openai/types/realtime/conversation_item_done.py +++ b/src/openai/types/realtime/conversation_item_done.py @@ -10,6 +10,11 @@ class ConversationItemDone(BaseModel): + """Returned when a conversation item is finalized. + + The event will include the full content of the Item except for audio data, which can be retrieved separately with a `conversation.item.retrieve` event if needed. + """ + event_id: str """The unique ID of the server event.""" diff --git a/src/openai/types/realtime/conversation_item_input_audio_transcription_completed_event.py b/src/openai/types/realtime/conversation_item_input_audio_transcription_completed_event.py index 09b20aa184..3304233f8f 100644 --- a/src/openai/types/realtime/conversation_item_input_audio_transcription_completed_event.py +++ b/src/openai/types/realtime/conversation_item_input_audio_transcription_completed_event.py @@ -16,6 +16,8 @@ class UsageTranscriptTextUsageTokensInputTokenDetails(BaseModel): + """Details about the input tokens billed for this request.""" + audio_tokens: Optional[int] = None """Number of audio tokens billed for this request.""" @@ -24,6 +26,8 @@ class UsageTranscriptTextUsageTokensInputTokenDetails(BaseModel): class UsageTranscriptTextUsageTokens(BaseModel): + """Usage statistics for models billed by token usage.""" + input_tokens: int """Number of input tokens billed for this request.""" @@ -41,6 +45,8 @@ class UsageTranscriptTextUsageTokens(BaseModel): class UsageTranscriptTextUsageDuration(BaseModel): + """Usage statistics for models billed by audio input duration.""" + seconds: float """Duration of the input audio in seconds.""" @@ -52,6 +58,19 @@ class UsageTranscriptTextUsageDuration(BaseModel): class ConversationItemInputAudioTranscriptionCompletedEvent(BaseModel): + """ + This event is the output of audio transcription for user audio written to the + user audio buffer. Transcription begins when the input audio buffer is + committed by the client or server (when VAD is enabled). Transcription runs + asynchronously with Response creation, so this event may come before or after + the Response events. + + Realtime API models accept audio natively, and thus input transcription is a + separate process run on a separate ASR (Automatic Speech Recognition) model. + The transcript may diverge somewhat from the model's interpretation, and + should be treated as a rough guide. + """ + content_index: int """The index of the content part containing the audio.""" diff --git a/src/openai/types/realtime/conversation_item_input_audio_transcription_delta_event.py b/src/openai/types/realtime/conversation_item_input_audio_transcription_delta_event.py index f49e6f636f..5f3f54810f 100644 --- a/src/openai/types/realtime/conversation_item_input_audio_transcription_delta_event.py +++ b/src/openai/types/realtime/conversation_item_input_audio_transcription_delta_event.py @@ -10,6 +10,10 @@ class ConversationItemInputAudioTranscriptionDeltaEvent(BaseModel): + """ + Returned when the text value of an input audio transcription content part is updated with incremental transcription results. + """ + event_id: str """The unique ID of the server event.""" diff --git a/src/openai/types/realtime/conversation_item_input_audio_transcription_failed_event.py b/src/openai/types/realtime/conversation_item_input_audio_transcription_failed_event.py index edb97bbf6f..e8ad05e43c 100644 --- a/src/openai/types/realtime/conversation_item_input_audio_transcription_failed_event.py +++ b/src/openai/types/realtime/conversation_item_input_audio_transcription_failed_event.py @@ -9,6 +9,8 @@ class Error(BaseModel): + """Details of the transcription error.""" + code: Optional[str] = None """Error code, if any.""" @@ -23,6 +25,12 @@ class Error(BaseModel): class ConversationItemInputAudioTranscriptionFailedEvent(BaseModel): + """ + Returned when input audio transcription is configured, and a transcription + request for a user message failed. These events are separate from other + `error` events so that the client can identify the related Item. + """ + content_index: int """The index of the content part containing the audio.""" diff --git a/src/openai/types/realtime/conversation_item_input_audio_transcription_segment.py b/src/openai/types/realtime/conversation_item_input_audio_transcription_segment.py index e2cbc9d299..dcc4916580 100644 --- a/src/openai/types/realtime/conversation_item_input_audio_transcription_segment.py +++ b/src/openai/types/realtime/conversation_item_input_audio_transcription_segment.py @@ -8,6 +8,8 @@ class ConversationItemInputAudioTranscriptionSegment(BaseModel): + """Returned when an input audio transcription segment is identified for an item.""" + id: str """The segment identifier.""" diff --git a/src/openai/types/realtime/conversation_item_retrieve_event.py b/src/openai/types/realtime/conversation_item_retrieve_event.py index 018c2ccc59..e7d8eb6c49 100644 --- a/src/openai/types/realtime/conversation_item_retrieve_event.py +++ b/src/openai/types/realtime/conversation_item_retrieve_event.py @@ -9,6 +9,13 @@ class ConversationItemRetrieveEvent(BaseModel): + """ + Send this event when you want to retrieve the server's representation of a specific item in the conversation history. This is useful, for example, to inspect user audio after noise cancellation and VAD. + The server will respond with a `conversation.item.retrieved` event, + unless the item does not exist in the conversation history, in which case the + server will respond with an error. + """ + item_id: str """The ID of the item to retrieve.""" diff --git a/src/openai/types/realtime/conversation_item_retrieve_event_param.py b/src/openai/types/realtime/conversation_item_retrieve_event_param.py index 71b3ffa499..59fdb6fb93 100644 --- a/src/openai/types/realtime/conversation_item_retrieve_event_param.py +++ b/src/openai/types/realtime/conversation_item_retrieve_event_param.py @@ -8,6 +8,13 @@ class ConversationItemRetrieveEventParam(TypedDict, total=False): + """ + Send this event when you want to retrieve the server's representation of a specific item in the conversation history. This is useful, for example, to inspect user audio after noise cancellation and VAD. + The server will respond with a `conversation.item.retrieved` event, + unless the item does not exist in the conversation history, in which case the + server will respond with an error. + """ + item_id: Required[str] """The ID of the item to retrieve.""" diff --git a/src/openai/types/realtime/conversation_item_truncate_event.py b/src/openai/types/realtime/conversation_item_truncate_event.py index d6c6779cc8..16c82183c4 100644 --- a/src/openai/types/realtime/conversation_item_truncate_event.py +++ b/src/openai/types/realtime/conversation_item_truncate_event.py @@ -9,6 +9,21 @@ class ConversationItemTruncateEvent(BaseModel): + """Send this event to truncate a previous assistant message’s audio. + + The server + will produce audio faster than realtime, so this event is useful when the user + interrupts to truncate audio that has already been sent to the client but not + yet played. This will synchronize the server's understanding of the audio with + the client's playback. + + Truncating audio will delete the server-side text transcript to ensure there + is not text in the context that hasn't been heard by the user. + + If successful, the server will respond with a `conversation.item.truncated` + event. + """ + audio_end_ms: int """Inclusive duration up to which audio is truncated, in milliseconds. diff --git a/src/openai/types/realtime/conversation_item_truncate_event_param.py b/src/openai/types/realtime/conversation_item_truncate_event_param.py index f5ab13a419..e9b41fc980 100644 --- a/src/openai/types/realtime/conversation_item_truncate_event_param.py +++ b/src/openai/types/realtime/conversation_item_truncate_event_param.py @@ -8,6 +8,21 @@ class ConversationItemTruncateEventParam(TypedDict, total=False): + """Send this event to truncate a previous assistant message’s audio. + + The server + will produce audio faster than realtime, so this event is useful when the user + interrupts to truncate audio that has already been sent to the client but not + yet played. This will synchronize the server's understanding of the audio with + the client's playback. + + Truncating audio will delete the server-side text transcript to ensure there + is not text in the context that hasn't been heard by the user. + + If successful, the server will respond with a `conversation.item.truncated` + event. + """ + audio_end_ms: Required[int] """Inclusive duration up to which audio is truncated, in milliseconds. diff --git a/src/openai/types/realtime/conversation_item_truncated_event.py b/src/openai/types/realtime/conversation_item_truncated_event.py index f56cabc3d9..c78a776d9b 100644 --- a/src/openai/types/realtime/conversation_item_truncated_event.py +++ b/src/openai/types/realtime/conversation_item_truncated_event.py @@ -8,6 +8,15 @@ class ConversationItemTruncatedEvent(BaseModel): + """ + Returned when an earlier assistant audio message item is truncated by the + client with a `conversation.item.truncate` event. This event is used to + synchronize the server's understanding of the audio with the client's playback. + + This action will truncate the audio and remove the server-side text transcript + to ensure there is no text in the context that hasn't been heard by the user. + """ + audio_end_ms: int """The duration up to which the audio was truncated, in milliseconds.""" diff --git a/src/openai/types/realtime/input_audio_buffer_append_event.py b/src/openai/types/realtime/input_audio_buffer_append_event.py index 8562cf0af4..4c9e9a544d 100644 --- a/src/openai/types/realtime/input_audio_buffer_append_event.py +++ b/src/openai/types/realtime/input_audio_buffer_append_event.py @@ -9,6 +9,23 @@ class InputAudioBufferAppendEvent(BaseModel): + """Send this event to append audio bytes to the input audio buffer. + + The audio + buffer is temporary storage you can write to and later commit. A "commit" will create a new + user message item in the conversation history from the buffer content and clear the buffer. + Input audio transcription (if enabled) will be generated when the buffer is committed. + + If VAD is enabled the audio buffer is used to detect speech and the server will decide + when to commit. When Server VAD is disabled, you must commit the audio buffer + manually. Input audio noise reduction operates on writes to the audio buffer. + + The client may choose how much audio to place in each event up to a maximum + of 15 MiB, for example streaming smaller chunks from the client may allow the + VAD to be more responsive. Unlike most other client events, the server will + not send a confirmation response to this event. + """ + audio: str """Base64-encoded audio bytes. diff --git a/src/openai/types/realtime/input_audio_buffer_append_event_param.py b/src/openai/types/realtime/input_audio_buffer_append_event_param.py index 3ad0bc737d..a0d308e4d9 100644 --- a/src/openai/types/realtime/input_audio_buffer_append_event_param.py +++ b/src/openai/types/realtime/input_audio_buffer_append_event_param.py @@ -8,6 +8,23 @@ class InputAudioBufferAppendEventParam(TypedDict, total=False): + """Send this event to append audio bytes to the input audio buffer. + + The audio + buffer is temporary storage you can write to and later commit. A "commit" will create a new + user message item in the conversation history from the buffer content and clear the buffer. + Input audio transcription (if enabled) will be generated when the buffer is committed. + + If VAD is enabled the audio buffer is used to detect speech and the server will decide + when to commit. When Server VAD is disabled, you must commit the audio buffer + manually. Input audio noise reduction operates on writes to the audio buffer. + + The client may choose how much audio to place in each event up to a maximum + of 15 MiB, for example streaming smaller chunks from the client may allow the + VAD to be more responsive. Unlike most other client events, the server will + not send a confirmation response to this event. + """ + audio: Required[str] """Base64-encoded audio bytes. diff --git a/src/openai/types/realtime/input_audio_buffer_clear_event.py b/src/openai/types/realtime/input_audio_buffer_clear_event.py index 9922ff3b32..5526bcbfa9 100644 --- a/src/openai/types/realtime/input_audio_buffer_clear_event.py +++ b/src/openai/types/realtime/input_audio_buffer_clear_event.py @@ -9,6 +9,12 @@ class InputAudioBufferClearEvent(BaseModel): + """Send this event to clear the audio bytes in the buffer. + + The server will + respond with an `input_audio_buffer.cleared` event. + """ + type: Literal["input_audio_buffer.clear"] """The event type, must be `input_audio_buffer.clear`.""" diff --git a/src/openai/types/realtime/input_audio_buffer_clear_event_param.py b/src/openai/types/realtime/input_audio_buffer_clear_event_param.py index 2bd6bc5a02..8e0e9c55fa 100644 --- a/src/openai/types/realtime/input_audio_buffer_clear_event_param.py +++ b/src/openai/types/realtime/input_audio_buffer_clear_event_param.py @@ -8,6 +8,12 @@ class InputAudioBufferClearEventParam(TypedDict, total=False): + """Send this event to clear the audio bytes in the buffer. + + The server will + respond with an `input_audio_buffer.cleared` event. + """ + type: Required[Literal["input_audio_buffer.clear"]] """The event type, must be `input_audio_buffer.clear`.""" diff --git a/src/openai/types/realtime/input_audio_buffer_cleared_event.py b/src/openai/types/realtime/input_audio_buffer_cleared_event.py index af71844f2f..e4775567dc 100644 --- a/src/openai/types/realtime/input_audio_buffer_cleared_event.py +++ b/src/openai/types/realtime/input_audio_buffer_cleared_event.py @@ -8,6 +8,11 @@ class InputAudioBufferClearedEvent(BaseModel): + """ + Returned when the input audio buffer is cleared by the client with a + `input_audio_buffer.clear` event. + """ + event_id: str """The unique ID of the server event.""" diff --git a/src/openai/types/realtime/input_audio_buffer_commit_event.py b/src/openai/types/realtime/input_audio_buffer_commit_event.py index 125c3ba1e8..fe2ec01783 100644 --- a/src/openai/types/realtime/input_audio_buffer_commit_event.py +++ b/src/openai/types/realtime/input_audio_buffer_commit_event.py @@ -9,6 +9,12 @@ class InputAudioBufferCommitEvent(BaseModel): + """ + Send this event to commit the user input audio buffer, which will create a new user message item in the conversation. This event will produce an error if the input audio buffer is empty. When in Server VAD mode, the client does not need to send this event, the server will commit the audio buffer automatically. + + Committing the input audio buffer will trigger input audio transcription (if enabled in session configuration), but it will not create a response from the model. The server will respond with an `input_audio_buffer.committed` event. + """ + type: Literal["input_audio_buffer.commit"] """The event type, must be `input_audio_buffer.commit`.""" diff --git a/src/openai/types/realtime/input_audio_buffer_commit_event_param.py b/src/openai/types/realtime/input_audio_buffer_commit_event_param.py index c9c927ab98..20342795e8 100644 --- a/src/openai/types/realtime/input_audio_buffer_commit_event_param.py +++ b/src/openai/types/realtime/input_audio_buffer_commit_event_param.py @@ -8,6 +8,12 @@ class InputAudioBufferCommitEventParam(TypedDict, total=False): + """ + Send this event to commit the user input audio buffer, which will create a new user message item in the conversation. This event will produce an error if the input audio buffer is empty. When in Server VAD mode, the client does not need to send this event, the server will commit the audio buffer automatically. + + Committing the input audio buffer will trigger input audio transcription (if enabled in session configuration), but it will not create a response from the model. The server will respond with an `input_audio_buffer.committed` event. + """ + type: Required[Literal["input_audio_buffer.commit"]] """The event type, must be `input_audio_buffer.commit`.""" diff --git a/src/openai/types/realtime/input_audio_buffer_committed_event.py b/src/openai/types/realtime/input_audio_buffer_committed_event.py index 5ed1b4ccc7..15dc8254f3 100644 --- a/src/openai/types/realtime/input_audio_buffer_committed_event.py +++ b/src/openai/types/realtime/input_audio_buffer_committed_event.py @@ -9,6 +9,13 @@ class InputAudioBufferCommittedEvent(BaseModel): + """ + Returned when an input audio buffer is committed, either by the client or + automatically in server VAD mode. The `item_id` property is the ID of the user + message item that will be created, thus a `conversation.item.created` event + will also be sent to the client. + """ + event_id: str """The unique ID of the server event.""" diff --git a/src/openai/types/realtime/input_audio_buffer_dtmf_event_received_event.py b/src/openai/types/realtime/input_audio_buffer_dtmf_event_received_event.py index d61ed4bda7..c2623cc7b8 100644 --- a/src/openai/types/realtime/input_audio_buffer_dtmf_event_received_event.py +++ b/src/openai/types/realtime/input_audio_buffer_dtmf_event_received_event.py @@ -8,6 +8,14 @@ class InputAudioBufferDtmfEventReceivedEvent(BaseModel): + """**SIP Only:** Returned when an DTMF event is received. + + A DTMF event is a message that + represents a telephone keypad press (0–9, *, #, A–D). The `event` property + is the keypad that the user press. The `received_at` is the UTC Unix Timestamp + that the server received the event. + """ + event: str """The telephone keypad that was pressed by the user.""" diff --git a/src/openai/types/realtime/input_audio_buffer_speech_started_event.py b/src/openai/types/realtime/input_audio_buffer_speech_started_event.py index 865205d786..1bd4c74eb0 100644 --- a/src/openai/types/realtime/input_audio_buffer_speech_started_event.py +++ b/src/openai/types/realtime/input_audio_buffer_speech_started_event.py @@ -8,6 +8,19 @@ class InputAudioBufferSpeechStartedEvent(BaseModel): + """ + Sent by the server when in `server_vad` mode to indicate that speech has been + detected in the audio buffer. This can happen any time audio is added to the + buffer (unless speech is already detected). The client may want to use this + event to interrupt audio playback or provide visual feedback to the user. + + The client should expect to receive a `input_audio_buffer.speech_stopped` event + when speech stops. The `item_id` property is the ID of the user message item + that will be created when speech stops and will also be included in the + `input_audio_buffer.speech_stopped` event (unless the client manually commits + the audio buffer during VAD activation). + """ + audio_start_ms: int """ Milliseconds from the start of all audio written to the buffer during the diff --git a/src/openai/types/realtime/input_audio_buffer_speech_stopped_event.py b/src/openai/types/realtime/input_audio_buffer_speech_stopped_event.py index 6cb7845ff4..b3fb20929a 100644 --- a/src/openai/types/realtime/input_audio_buffer_speech_stopped_event.py +++ b/src/openai/types/realtime/input_audio_buffer_speech_stopped_event.py @@ -8,6 +8,12 @@ class InputAudioBufferSpeechStoppedEvent(BaseModel): + """ + Returned in `server_vad` mode when the server detects the end of speech in + the audio buffer. The server will also send an `conversation.item.created` + event with the user message item that is created from the audio buffer. + """ + audio_end_ms: int """Milliseconds since the session started when speech stopped. diff --git a/src/openai/types/realtime/input_audio_buffer_timeout_triggered.py b/src/openai/types/realtime/input_audio_buffer_timeout_triggered.py index 5c5dc5cfa6..72b107d56e 100644 --- a/src/openai/types/realtime/input_audio_buffer_timeout_triggered.py +++ b/src/openai/types/realtime/input_audio_buffer_timeout_triggered.py @@ -8,6 +8,23 @@ class InputAudioBufferTimeoutTriggered(BaseModel): + """Returned when the Server VAD timeout is triggered for the input audio buffer. + + This is configured + with `idle_timeout_ms` in the `turn_detection` settings of the session, and it indicates that + there hasn't been any speech detected for the configured duration. + + The `audio_start_ms` and `audio_end_ms` fields indicate the segment of audio after the last + model response up to the triggering time, as an offset from the beginning of audio written + to the input audio buffer. This means it demarcates the segment of audio that was silent and + the difference between the start and end values will roughly match the configured timeout. + + The empty audio will be committed to the conversation as an `input_audio` item (there will be a + `input_audio_buffer.committed` event) and a model response will be generated. There may be speech + that didn't trigger VAD but is still detected by the model, so the model may respond with + something relevant to the conversation or a prompt to continue speaking. + """ + audio_end_ms: int """ Millisecond offset of audio written to the input audio buffer at the time the diff --git a/src/openai/types/realtime/log_prob_properties.py b/src/openai/types/realtime/log_prob_properties.py index 92477d67d0..423af1c492 100644 --- a/src/openai/types/realtime/log_prob_properties.py +++ b/src/openai/types/realtime/log_prob_properties.py @@ -8,6 +8,8 @@ class LogProbProperties(BaseModel): + """A log probability object.""" + token: str """The token that was used to generate the log probability.""" diff --git a/src/openai/types/realtime/mcp_list_tools_completed.py b/src/openai/types/realtime/mcp_list_tools_completed.py index 941280f01a..2fe64147d6 100644 --- a/src/openai/types/realtime/mcp_list_tools_completed.py +++ b/src/openai/types/realtime/mcp_list_tools_completed.py @@ -8,6 +8,8 @@ class McpListToolsCompleted(BaseModel): + """Returned when listing MCP tools has completed for an item.""" + event_id: str """The unique ID of the server event.""" diff --git a/src/openai/types/realtime/mcp_list_tools_failed.py b/src/openai/types/realtime/mcp_list_tools_failed.py index 892eda21bd..8cad7c0a12 100644 --- a/src/openai/types/realtime/mcp_list_tools_failed.py +++ b/src/openai/types/realtime/mcp_list_tools_failed.py @@ -8,6 +8,8 @@ class McpListToolsFailed(BaseModel): + """Returned when listing MCP tools has failed for an item.""" + event_id: str """The unique ID of the server event.""" diff --git a/src/openai/types/realtime/mcp_list_tools_in_progress.py b/src/openai/types/realtime/mcp_list_tools_in_progress.py index 4254b5fd33..823bb875a3 100644 --- a/src/openai/types/realtime/mcp_list_tools_in_progress.py +++ b/src/openai/types/realtime/mcp_list_tools_in_progress.py @@ -8,6 +8,8 @@ class McpListToolsInProgress(BaseModel): + """Returned when listing MCP tools is in progress for an item.""" + event_id: str """The unique ID of the server event.""" diff --git a/src/openai/types/realtime/output_audio_buffer_clear_event.py b/src/openai/types/realtime/output_audio_buffer_clear_event.py index b4c95039f3..b3fa7620ac 100644 --- a/src/openai/types/realtime/output_audio_buffer_clear_event.py +++ b/src/openai/types/realtime/output_audio_buffer_clear_event.py @@ -9,6 +9,15 @@ class OutputAudioBufferClearEvent(BaseModel): + """**WebRTC/SIP Only:** Emit to cut off the current audio response. + + This will trigger the server to + stop generating audio and emit a `output_audio_buffer.cleared` event. This + event should be preceded by a `response.cancel` client event to stop the + generation of the current response. + [Learn more](https://platform.openai.com/docs/guides/realtime-conversations#client-and-server-events-for-audio-in-webrtc). + """ + type: Literal["output_audio_buffer.clear"] """The event type, must be `output_audio_buffer.clear`.""" diff --git a/src/openai/types/realtime/output_audio_buffer_clear_event_param.py b/src/openai/types/realtime/output_audio_buffer_clear_event_param.py index a3205ebc6c..59f897a5c1 100644 --- a/src/openai/types/realtime/output_audio_buffer_clear_event_param.py +++ b/src/openai/types/realtime/output_audio_buffer_clear_event_param.py @@ -8,6 +8,15 @@ class OutputAudioBufferClearEventParam(TypedDict, total=False): + """**WebRTC/SIP Only:** Emit to cut off the current audio response. + + This will trigger the server to + stop generating audio and emit a `output_audio_buffer.cleared` event. This + event should be preceded by a `response.cancel` client event to stop the + generation of the current response. + [Learn more](https://platform.openai.com/docs/guides/realtime-conversations#client-and-server-events-for-audio-in-webrtc). + """ + type: Required[Literal["output_audio_buffer.clear"]] """The event type, must be `output_audio_buffer.clear`.""" diff --git a/src/openai/types/realtime/rate_limits_updated_event.py b/src/openai/types/realtime/rate_limits_updated_event.py index 048a4028a1..951de103af 100644 --- a/src/openai/types/realtime/rate_limits_updated_event.py +++ b/src/openai/types/realtime/rate_limits_updated_event.py @@ -23,6 +23,14 @@ class RateLimit(BaseModel): class RateLimitsUpdatedEvent(BaseModel): + """Emitted at the beginning of a Response to indicate the updated rate limits. + + + When a Response is created some tokens will be "reserved" for the output + tokens, the rate limits shown here reflect that reservation, which is then + adjusted accordingly once the Response is completed. + """ + event_id: str """The unique ID of the server event.""" diff --git a/src/openai/types/realtime/realtime_audio_config.py b/src/openai/types/realtime/realtime_audio_config.py index 72d7cc59cc..daa50358a8 100644 --- a/src/openai/types/realtime/realtime_audio_config.py +++ b/src/openai/types/realtime/realtime_audio_config.py @@ -10,6 +10,8 @@ class RealtimeAudioConfig(BaseModel): + """Configuration for input and output audio.""" + input: Optional[RealtimeAudioConfigInput] = None output: Optional[RealtimeAudioConfigOutput] = None diff --git a/src/openai/types/realtime/realtime_audio_config_input.py b/src/openai/types/realtime/realtime_audio_config_input.py index cfcb7f22d4..08e1b14601 100644 --- a/src/openai/types/realtime/realtime_audio_config_input.py +++ b/src/openai/types/realtime/realtime_audio_config_input.py @@ -12,6 +12,13 @@ class NoiseReduction(BaseModel): + """Configuration for input audio noise reduction. + + This can be set to `null` to turn off. + Noise reduction filters audio added to the input audio buffer before it is sent to VAD and the model. + Filtering the audio can improve VAD and turn detection accuracy (reducing false positives) and model performance by improving perception of the input audio. + """ + type: Optional[NoiseReductionType] = None """Type of noise reduction. diff --git a/src/openai/types/realtime/realtime_audio_config_input_param.py b/src/openai/types/realtime/realtime_audio_config_input_param.py index 730f46cfec..73495e6cd3 100644 --- a/src/openai/types/realtime/realtime_audio_config_input_param.py +++ b/src/openai/types/realtime/realtime_audio_config_input_param.py @@ -14,6 +14,13 @@ class NoiseReduction(TypedDict, total=False): + """Configuration for input audio noise reduction. + + This can be set to `null` to turn off. + Noise reduction filters audio added to the input audio buffer before it is sent to VAD and the model. + Filtering the audio can improve VAD and turn detection accuracy (reducing false positives) and model performance by improving perception of the input audio. + """ + type: NoiseReductionType """Type of noise reduction. diff --git a/src/openai/types/realtime/realtime_audio_config_param.py b/src/openai/types/realtime/realtime_audio_config_param.py index 2c41de35ae..7899fe359b 100644 --- a/src/openai/types/realtime/realtime_audio_config_param.py +++ b/src/openai/types/realtime/realtime_audio_config_param.py @@ -11,6 +11,8 @@ class RealtimeAudioConfigParam(TypedDict, total=False): + """Configuration for input and output audio.""" + input: RealtimeAudioConfigInputParam output: RealtimeAudioConfigOutputParam diff --git a/src/openai/types/realtime/realtime_audio_formats.py b/src/openai/types/realtime/realtime_audio_formats.py index 10f91883b6..fa10c9a7a4 100644 --- a/src/openai/types/realtime/realtime_audio_formats.py +++ b/src/openai/types/realtime/realtime_audio_formats.py @@ -10,6 +10,8 @@ class AudioPCM(BaseModel): + """The PCM audio format. Only a 24kHz sample rate is supported.""" + rate: Optional[Literal[24000]] = None """The sample rate of the audio. Always `24000`.""" @@ -18,11 +20,15 @@ class AudioPCM(BaseModel): class AudioPCMU(BaseModel): + """The G.711 μ-law format.""" + type: Optional[Literal["audio/pcmu"]] = None """The audio format. Always `audio/pcmu`.""" class AudioPCMA(BaseModel): + """The G.711 A-law format.""" + type: Optional[Literal["audio/pcma"]] = None """The audio format. Always `audio/pcma`.""" diff --git a/src/openai/types/realtime/realtime_audio_formats_param.py b/src/openai/types/realtime/realtime_audio_formats_param.py index cf58577f38..6392f632c3 100644 --- a/src/openai/types/realtime/realtime_audio_formats_param.py +++ b/src/openai/types/realtime/realtime_audio_formats_param.py @@ -9,6 +9,8 @@ class AudioPCM(TypedDict, total=False): + """The PCM audio format. Only a 24kHz sample rate is supported.""" + rate: Literal[24000] """The sample rate of the audio. Always `24000`.""" @@ -17,11 +19,15 @@ class AudioPCM(TypedDict, total=False): class AudioPCMU(TypedDict, total=False): + """The G.711 μ-law format.""" + type: Literal["audio/pcmu"] """The audio format. Always `audio/pcmu`.""" class AudioPCMA(TypedDict, total=False): + """The G.711 A-law format.""" + type: Literal["audio/pcma"] """The audio format. Always `audio/pcma`.""" diff --git a/src/openai/types/realtime/realtime_audio_input_turn_detection.py b/src/openai/types/realtime/realtime_audio_input_turn_detection.py index 9b55353884..8d9aff3563 100644 --- a/src/openai/types/realtime/realtime_audio_input_turn_detection.py +++ b/src/openai/types/realtime/realtime_audio_input_turn_detection.py @@ -10,6 +10,10 @@ class ServerVad(BaseModel): + """ + Server-side voice activity detection (VAD) which flips on when user speech is detected and off after a period of silence. + """ + type: Literal["server_vad"] """Type of turn detection, `server_vad` to turn on simple Server VAD.""" @@ -76,6 +80,10 @@ class ServerVad(BaseModel): class SemanticVad(BaseModel): + """ + Server-side semantic turn detection which uses a model to determine when the user has finished speaking. + """ + type: Literal["semantic_vad"] """Type of turn detection, `semantic_vad` to turn on Semantic VAD.""" diff --git a/src/openai/types/realtime/realtime_audio_input_turn_detection_param.py b/src/openai/types/realtime/realtime_audio_input_turn_detection_param.py index 4ce7640727..30522d74e1 100644 --- a/src/openai/types/realtime/realtime_audio_input_turn_detection_param.py +++ b/src/openai/types/realtime/realtime_audio_input_turn_detection_param.py @@ -9,6 +9,10 @@ class ServerVad(TypedDict, total=False): + """ + Server-side voice activity detection (VAD) which flips on when user speech is detected and off after a period of silence. + """ + type: Required[Literal["server_vad"]] """Type of turn detection, `server_vad` to turn on simple Server VAD.""" @@ -75,6 +79,10 @@ class ServerVad(TypedDict, total=False): class SemanticVad(TypedDict, total=False): + """ + Server-side semantic turn detection which uses a model to determine when the user has finished speaking. + """ + type: Required[Literal["semantic_vad"]] """Type of turn detection, `semantic_vad` to turn on Semantic VAD.""" diff --git a/src/openai/types/realtime/realtime_conversation_item_assistant_message.py b/src/openai/types/realtime/realtime_conversation_item_assistant_message.py index 6b0f86ee32..207831a3c8 100644 --- a/src/openai/types/realtime/realtime_conversation_item_assistant_message.py +++ b/src/openai/types/realtime/realtime_conversation_item_assistant_message.py @@ -33,6 +33,8 @@ class Content(BaseModel): class RealtimeConversationItemAssistantMessage(BaseModel): + """An assistant message item in a Realtime conversation.""" + content: List[Content] """The content of the message.""" diff --git a/src/openai/types/realtime/realtime_conversation_item_assistant_message_param.py b/src/openai/types/realtime/realtime_conversation_item_assistant_message_param.py index 93699afba2..abc78e7d3f 100644 --- a/src/openai/types/realtime/realtime_conversation_item_assistant_message_param.py +++ b/src/openai/types/realtime/realtime_conversation_item_assistant_message_param.py @@ -33,6 +33,8 @@ class Content(TypedDict, total=False): class RealtimeConversationItemAssistantMessageParam(TypedDict, total=False): + """An assistant message item in a Realtime conversation.""" + content: Required[Iterable[Content]] """The content of the message.""" diff --git a/src/openai/types/realtime/realtime_conversation_item_function_call.py b/src/openai/types/realtime/realtime_conversation_item_function_call.py index 279a2fcdc5..4e40394883 100644 --- a/src/openai/types/realtime/realtime_conversation_item_function_call.py +++ b/src/openai/types/realtime/realtime_conversation_item_function_call.py @@ -9,6 +9,8 @@ class RealtimeConversationItemFunctionCall(BaseModel): + """A function call item in a Realtime conversation.""" + arguments: str """The arguments of the function call. diff --git a/src/openai/types/realtime/realtime_conversation_item_function_call_output.py b/src/openai/types/realtime/realtime_conversation_item_function_call_output.py index 4b6b15d0ad..cdbc352d85 100644 --- a/src/openai/types/realtime/realtime_conversation_item_function_call_output.py +++ b/src/openai/types/realtime/realtime_conversation_item_function_call_output.py @@ -9,6 +9,8 @@ class RealtimeConversationItemFunctionCallOutput(BaseModel): + """A function call output item in a Realtime conversation.""" + call_id: str """The ID of the function call this output is for.""" diff --git a/src/openai/types/realtime/realtime_conversation_item_function_call_output_param.py b/src/openai/types/realtime/realtime_conversation_item_function_call_output_param.py index 56d62da563..2e56a81dc3 100644 --- a/src/openai/types/realtime/realtime_conversation_item_function_call_output_param.py +++ b/src/openai/types/realtime/realtime_conversation_item_function_call_output_param.py @@ -8,6 +8,8 @@ class RealtimeConversationItemFunctionCallOutputParam(TypedDict, total=False): + """A function call output item in a Realtime conversation.""" + call_id: Required[str] """The ID of the function call this output is for.""" diff --git a/src/openai/types/realtime/realtime_conversation_item_function_call_param.py b/src/openai/types/realtime/realtime_conversation_item_function_call_param.py index 36a16a27b3..6467ce149e 100644 --- a/src/openai/types/realtime/realtime_conversation_item_function_call_param.py +++ b/src/openai/types/realtime/realtime_conversation_item_function_call_param.py @@ -8,6 +8,8 @@ class RealtimeConversationItemFunctionCallParam(TypedDict, total=False): + """A function call item in a Realtime conversation.""" + arguments: Required[str] """The arguments of the function call. diff --git a/src/openai/types/realtime/realtime_conversation_item_system_message.py b/src/openai/types/realtime/realtime_conversation_item_system_message.py index 7dac5c9fe2..f69bc03937 100644 --- a/src/openai/types/realtime/realtime_conversation_item_system_message.py +++ b/src/openai/types/realtime/realtime_conversation_item_system_message.py @@ -17,6 +17,10 @@ class Content(BaseModel): class RealtimeConversationItemSystemMessage(BaseModel): + """ + A system message in a Realtime conversation can be used to provide additional context or instructions to the model. This is similar but distinct from the instruction prompt provided at the start of a conversation, as system messages can be added at any point in the conversation. For major changes to the conversation's behavior, use instructions, but for smaller updates (e.g. "the user is now asking about a different topic"), use system messages. + """ + content: List[Content] """The content of the message.""" diff --git a/src/openai/types/realtime/realtime_conversation_item_system_message_param.py b/src/openai/types/realtime/realtime_conversation_item_system_message_param.py index a2790fcf67..93880198fa 100644 --- a/src/openai/types/realtime/realtime_conversation_item_system_message_param.py +++ b/src/openai/types/realtime/realtime_conversation_item_system_message_param.py @@ -17,6 +17,10 @@ class Content(TypedDict, total=False): class RealtimeConversationItemSystemMessageParam(TypedDict, total=False): + """ + A system message in a Realtime conversation can be used to provide additional context or instructions to the model. This is similar but distinct from the instruction prompt provided at the start of a conversation, as system messages can be added at any point in the conversation. For major changes to the conversation's behavior, use instructions, but for smaller updates (e.g. "the user is now asking about a different topic"), use system messages. + """ + content: Required[Iterable[Content]] """The content of the message.""" diff --git a/src/openai/types/realtime/realtime_conversation_item_user_message.py b/src/openai/types/realtime/realtime_conversation_item_user_message.py index 30d9bb10e3..20e9614eb6 100644 --- a/src/openai/types/realtime/realtime_conversation_item_user_message.py +++ b/src/openai/types/realtime/realtime_conversation_item_user_message.py @@ -44,6 +44,8 @@ class Content(BaseModel): class RealtimeConversationItemUserMessage(BaseModel): + """A user message item in a Realtime conversation.""" + content: List[Content] """The content of the message.""" diff --git a/src/openai/types/realtime/realtime_conversation_item_user_message_param.py b/src/openai/types/realtime/realtime_conversation_item_user_message_param.py index 7d3b9bc137..69a24692e8 100644 --- a/src/openai/types/realtime/realtime_conversation_item_user_message_param.py +++ b/src/openai/types/realtime/realtime_conversation_item_user_message_param.py @@ -44,6 +44,8 @@ class Content(TypedDict, total=False): class RealtimeConversationItemUserMessageParam(TypedDict, total=False): + """A user message item in a Realtime conversation.""" + content: Required[Iterable[Content]] """The content of the message.""" diff --git a/src/openai/types/realtime/realtime_error.py b/src/openai/types/realtime/realtime_error.py index f1017d09e4..2aa5bc9425 100644 --- a/src/openai/types/realtime/realtime_error.py +++ b/src/openai/types/realtime/realtime_error.py @@ -8,6 +8,8 @@ class RealtimeError(BaseModel): + """Details of the error.""" + message: str """A human-readable error message.""" diff --git a/src/openai/types/realtime/realtime_error_event.py b/src/openai/types/realtime/realtime_error_event.py index 8b501d6b21..574464b29e 100644 --- a/src/openai/types/realtime/realtime_error_event.py +++ b/src/openai/types/realtime/realtime_error_event.py @@ -9,6 +9,12 @@ class RealtimeErrorEvent(BaseModel): + """ + Returned when an error occurs, which could be a client problem or a server + problem. Most errors are recoverable and the session will stay open, we + recommend to implementors to monitor and log error messages by default. + """ + error: RealtimeError """Details of the error.""" diff --git a/src/openai/types/realtime/realtime_mcp_approval_request.py b/src/openai/types/realtime/realtime_mcp_approval_request.py index bafc8d89d4..1744c90070 100644 --- a/src/openai/types/realtime/realtime_mcp_approval_request.py +++ b/src/openai/types/realtime/realtime_mcp_approval_request.py @@ -8,6 +8,8 @@ class RealtimeMcpApprovalRequest(BaseModel): + """A Realtime item requesting human approval of a tool invocation.""" + id: str """The unique ID of the approval request.""" diff --git a/src/openai/types/realtime/realtime_mcp_approval_request_param.py b/src/openai/types/realtime/realtime_mcp_approval_request_param.py index 57c21a487f..f7cb68d67e 100644 --- a/src/openai/types/realtime/realtime_mcp_approval_request_param.py +++ b/src/openai/types/realtime/realtime_mcp_approval_request_param.py @@ -8,6 +8,8 @@ class RealtimeMcpApprovalRequestParam(TypedDict, total=False): + """A Realtime item requesting human approval of a tool invocation.""" + id: Required[str] """The unique ID of the approval request.""" diff --git a/src/openai/types/realtime/realtime_mcp_approval_response.py b/src/openai/types/realtime/realtime_mcp_approval_response.py index 2cb03bc61a..f8525a12fc 100644 --- a/src/openai/types/realtime/realtime_mcp_approval_response.py +++ b/src/openai/types/realtime/realtime_mcp_approval_response.py @@ -9,6 +9,8 @@ class RealtimeMcpApprovalResponse(BaseModel): + """A Realtime item responding to an MCP approval request.""" + id: str """The unique ID of the approval response.""" diff --git a/src/openai/types/realtime/realtime_mcp_approval_response_param.py b/src/openai/types/realtime/realtime_mcp_approval_response_param.py index 19b6337004..6a65f7ce38 100644 --- a/src/openai/types/realtime/realtime_mcp_approval_response_param.py +++ b/src/openai/types/realtime/realtime_mcp_approval_response_param.py @@ -9,6 +9,8 @@ class RealtimeMcpApprovalResponseParam(TypedDict, total=False): + """A Realtime item responding to an MCP approval request.""" + id: Required[str] """The unique ID of the approval response.""" diff --git a/src/openai/types/realtime/realtime_mcp_list_tools.py b/src/openai/types/realtime/realtime_mcp_list_tools.py index aeb58a1faf..669d1fb43b 100644 --- a/src/openai/types/realtime/realtime_mcp_list_tools.py +++ b/src/openai/types/realtime/realtime_mcp_list_tools.py @@ -9,6 +9,8 @@ class Tool(BaseModel): + """A tool available on an MCP server.""" + input_schema: object """The JSON schema describing the tool's input.""" @@ -23,6 +25,8 @@ class Tool(BaseModel): class RealtimeMcpListTools(BaseModel): + """A Realtime item listing tools available on an MCP server.""" + server_label: str """The label of the MCP server.""" diff --git a/src/openai/types/realtime/realtime_mcp_list_tools_param.py b/src/openai/types/realtime/realtime_mcp_list_tools_param.py index eb8605a061..614fa53347 100644 --- a/src/openai/types/realtime/realtime_mcp_list_tools_param.py +++ b/src/openai/types/realtime/realtime_mcp_list_tools_param.py @@ -9,6 +9,8 @@ class Tool(TypedDict, total=False): + """A tool available on an MCP server.""" + input_schema: Required[object] """The JSON schema describing the tool's input.""" @@ -23,6 +25,8 @@ class Tool(TypedDict, total=False): class RealtimeMcpListToolsParam(TypedDict, total=False): + """A Realtime item listing tools available on an MCP server.""" + server_label: Required[str] """The label of the MCP server.""" diff --git a/src/openai/types/realtime/realtime_mcp_tool_call.py b/src/openai/types/realtime/realtime_mcp_tool_call.py index 019aee25c0..f53ad0eaa9 100644 --- a/src/openai/types/realtime/realtime_mcp_tool_call.py +++ b/src/openai/types/realtime/realtime_mcp_tool_call.py @@ -18,6 +18,8 @@ class RealtimeMcpToolCall(BaseModel): + """A Realtime item representing an invocation of a tool on an MCP server.""" + id: str """The unique ID of the tool call.""" diff --git a/src/openai/types/realtime/realtime_mcp_tool_call_param.py b/src/openai/types/realtime/realtime_mcp_tool_call_param.py index 0ba16d3dc1..8ccb5efc8a 100644 --- a/src/openai/types/realtime/realtime_mcp_tool_call_param.py +++ b/src/openai/types/realtime/realtime_mcp_tool_call_param.py @@ -15,6 +15,8 @@ class RealtimeMcpToolCallParam(TypedDict, total=False): + """A Realtime item representing an invocation of a tool on an MCP server.""" + id: Required[str] """The unique ID of the tool call.""" diff --git a/src/openai/types/realtime/realtime_response.py b/src/openai/types/realtime/realtime_response.py index 92d75491c0..a23edc48ab 100644 --- a/src/openai/types/realtime/realtime_response.py +++ b/src/openai/types/realtime/realtime_response.py @@ -30,10 +30,14 @@ class AudioOutput(BaseModel): class Audio(BaseModel): + """Configuration for audio output.""" + output: Optional[AudioOutput] = None class RealtimeResponse(BaseModel): + """The response resource.""" + id: Optional[str] = None """The unique ID of the response, will look like `resp_1234`.""" diff --git a/src/openai/types/realtime/realtime_response_create_audio_output.py b/src/openai/types/realtime/realtime_response_create_audio_output.py index 48a5d67e20..b8f4d284d5 100644 --- a/src/openai/types/realtime/realtime_response_create_audio_output.py +++ b/src/openai/types/realtime/realtime_response_create_audio_output.py @@ -26,4 +26,6 @@ class Output(BaseModel): class RealtimeResponseCreateAudioOutput(BaseModel): + """Configuration for audio input and output.""" + output: Optional[Output] = None diff --git a/src/openai/types/realtime/realtime_response_create_audio_output_param.py b/src/openai/types/realtime/realtime_response_create_audio_output_param.py index 9aa6d28835..30a4633698 100644 --- a/src/openai/types/realtime/realtime_response_create_audio_output_param.py +++ b/src/openai/types/realtime/realtime_response_create_audio_output_param.py @@ -25,4 +25,6 @@ class Output(TypedDict, total=False): class RealtimeResponseCreateAudioOutputParam(TypedDict, total=False): + """Configuration for audio input and output.""" + output: Output diff --git a/src/openai/types/realtime/realtime_response_create_mcp_tool.py b/src/openai/types/realtime/realtime_response_create_mcp_tool.py index 119b4a455d..72189e10e6 100644 --- a/src/openai/types/realtime/realtime_response_create_mcp_tool.py +++ b/src/openai/types/realtime/realtime_response_create_mcp_tool.py @@ -17,6 +17,8 @@ class AllowedToolsMcpToolFilter(BaseModel): + """A filter object to specify which tools are allowed.""" + read_only: Optional[bool] = None """Indicates whether or not a tool modifies data or is read-only. @@ -33,6 +35,8 @@ class AllowedToolsMcpToolFilter(BaseModel): class RequireApprovalMcpToolApprovalFilterAlways(BaseModel): + """A filter object to specify which tools are allowed.""" + read_only: Optional[bool] = None """Indicates whether or not a tool modifies data or is read-only. @@ -46,6 +50,8 @@ class RequireApprovalMcpToolApprovalFilterAlways(BaseModel): class RequireApprovalMcpToolApprovalFilterNever(BaseModel): + """A filter object to specify which tools are allowed.""" + read_only: Optional[bool] = None """Indicates whether or not a tool modifies data or is read-only. @@ -59,6 +65,13 @@ class RequireApprovalMcpToolApprovalFilterNever(BaseModel): class RequireApprovalMcpToolApprovalFilter(BaseModel): + """Specify which of the MCP server's tools require approval. + + Can be + `always`, `never`, or a filter object associated with tools + that require approval. + """ + always: Optional[RequireApprovalMcpToolApprovalFilterAlways] = None """A filter object to specify which tools are allowed.""" @@ -70,6 +83,11 @@ class RequireApprovalMcpToolApprovalFilter(BaseModel): class RealtimeResponseCreateMcpTool(BaseModel): + """ + Give the model access to additional tools via remote Model Context Protocol + (MCP) servers. [Learn more about MCP](https://platform.openai.com/docs/guides/tools-remote-mcp). + """ + server_label: str """A label for this MCP server, used to identify it in tool calls.""" diff --git a/src/openai/types/realtime/realtime_response_create_mcp_tool_param.py b/src/openai/types/realtime/realtime_response_create_mcp_tool_param.py index 3b9cf047c1..68dd6bdb5c 100644 --- a/src/openai/types/realtime/realtime_response_create_mcp_tool_param.py +++ b/src/openai/types/realtime/realtime_response_create_mcp_tool_param.py @@ -19,6 +19,8 @@ class AllowedToolsMcpToolFilter(TypedDict, total=False): + """A filter object to specify which tools are allowed.""" + read_only: bool """Indicates whether or not a tool modifies data or is read-only. @@ -35,6 +37,8 @@ class AllowedToolsMcpToolFilter(TypedDict, total=False): class RequireApprovalMcpToolApprovalFilterAlways(TypedDict, total=False): + """A filter object to specify which tools are allowed.""" + read_only: bool """Indicates whether or not a tool modifies data or is read-only. @@ -48,6 +52,8 @@ class RequireApprovalMcpToolApprovalFilterAlways(TypedDict, total=False): class RequireApprovalMcpToolApprovalFilterNever(TypedDict, total=False): + """A filter object to specify which tools are allowed.""" + read_only: bool """Indicates whether or not a tool modifies data or is read-only. @@ -61,6 +67,13 @@ class RequireApprovalMcpToolApprovalFilterNever(TypedDict, total=False): class RequireApprovalMcpToolApprovalFilter(TypedDict, total=False): + """Specify which of the MCP server's tools require approval. + + Can be + `always`, `never`, or a filter object associated with tools + that require approval. + """ + always: RequireApprovalMcpToolApprovalFilterAlways """A filter object to specify which tools are allowed.""" @@ -72,6 +85,11 @@ class RequireApprovalMcpToolApprovalFilter(TypedDict, total=False): class RealtimeResponseCreateMcpToolParam(TypedDict, total=False): + """ + Give the model access to additional tools via remote Model Context Protocol + (MCP) servers. [Learn more about MCP](https://platform.openai.com/docs/guides/tools-remote-mcp). + """ + server_label: Required[str] """A label for this MCP server, used to identify it in tool calls.""" diff --git a/src/openai/types/realtime/realtime_response_create_params.py b/src/openai/types/realtime/realtime_response_create_params.py index e8486220bf..deec8c9280 100644 --- a/src/openai/types/realtime/realtime_response_create_params.py +++ b/src/openai/types/realtime/realtime_response_create_params.py @@ -22,6 +22,8 @@ class RealtimeResponseCreateParams(BaseModel): + """Create a new Realtime response with these parameters""" + audio: Optional[RealtimeResponseCreateAudioOutput] = None """Configuration for audio input and output.""" diff --git a/src/openai/types/realtime/realtime_response_create_params_param.py b/src/openai/types/realtime/realtime_response_create_params_param.py index 116384bd82..caad5bc900 100644 --- a/src/openai/types/realtime/realtime_response_create_params_param.py +++ b/src/openai/types/realtime/realtime_response_create_params_param.py @@ -23,6 +23,8 @@ class RealtimeResponseCreateParamsParam(TypedDict, total=False): + """Create a new Realtime response with these parameters""" + audio: RealtimeResponseCreateAudioOutputParam """Configuration for audio input and output.""" diff --git a/src/openai/types/realtime/realtime_response_status.py b/src/openai/types/realtime/realtime_response_status.py index 12999f61a1..26b272ae5a 100644 --- a/src/openai/types/realtime/realtime_response_status.py +++ b/src/openai/types/realtime/realtime_response_status.py @@ -9,6 +9,11 @@ class Error(BaseModel): + """ + A description of the error that caused the response to fail, + populated when the `status` is `failed`. + """ + code: Optional[str] = None """Error code, if any.""" @@ -17,6 +22,8 @@ class Error(BaseModel): class RealtimeResponseStatus(BaseModel): + """Additional details about the status.""" + error: Optional[Error] = None """ A description of the error that caused the response to fail, populated when the diff --git a/src/openai/types/realtime/realtime_response_usage.py b/src/openai/types/realtime/realtime_response_usage.py index fb8893b346..a5985d8a7b 100644 --- a/src/openai/types/realtime/realtime_response_usage.py +++ b/src/openai/types/realtime/realtime_response_usage.py @@ -10,6 +10,14 @@ class RealtimeResponseUsage(BaseModel): + """Usage statistics for the Response, this will correspond to billing. + + A + Realtime API session will maintain a conversation context and append new + Items to the Conversation, thus output from previous turns (text and + audio tokens) will become the input for later turns. + """ + input_token_details: Optional[RealtimeResponseUsageInputTokenDetails] = None """Details about the input tokens used in the Response. diff --git a/src/openai/types/realtime/realtime_response_usage_input_token_details.py b/src/openai/types/realtime/realtime_response_usage_input_token_details.py index e14a74a84e..0fc71749e9 100644 --- a/src/openai/types/realtime/realtime_response_usage_input_token_details.py +++ b/src/openai/types/realtime/realtime_response_usage_input_token_details.py @@ -8,6 +8,8 @@ class CachedTokensDetails(BaseModel): + """Details about the cached tokens used as input for the Response.""" + audio_tokens: Optional[int] = None """The number of cached audio tokens used as input for the Response.""" @@ -19,6 +21,11 @@ class CachedTokensDetails(BaseModel): class RealtimeResponseUsageInputTokenDetails(BaseModel): + """Details about the input tokens used in the Response. + + Cached tokens are tokens from previous turns in the conversation that are included as context for the current response. Cached tokens here are counted as a subset of input tokens, meaning input tokens will include cached and uncached tokens. + """ + audio_tokens: Optional[int] = None """The number of audio tokens used as input for the Response.""" diff --git a/src/openai/types/realtime/realtime_response_usage_output_token_details.py b/src/openai/types/realtime/realtime_response_usage_output_token_details.py index dfa97a1f47..2154c77d5d 100644 --- a/src/openai/types/realtime/realtime_response_usage_output_token_details.py +++ b/src/openai/types/realtime/realtime_response_usage_output_token_details.py @@ -8,6 +8,8 @@ class RealtimeResponseUsageOutputTokenDetails(BaseModel): + """Details about the output tokens used in the Response.""" + audio_tokens: Optional[int] = None """The number of audio tokens used in the Response.""" diff --git a/src/openai/types/realtime/realtime_server_event.py b/src/openai/types/realtime/realtime_server_event.py index ead98f1a54..5de53d053e 100644 --- a/src/openai/types/realtime/realtime_server_event.py +++ b/src/openai/types/realtime/realtime_server_event.py @@ -61,6 +61,11 @@ class ConversationItemRetrieved(BaseModel): + """Returned when a conversation item is retrieved with `conversation.item.retrieve`. + + This is provided as a way to fetch the server's representation of an item, for example to get access to the post-processed audio data after noise cancellation and VAD. It includes the full content of the Item, including audio data. + """ + event_id: str """The unique ID of the server event.""" @@ -72,6 +77,13 @@ class ConversationItemRetrieved(BaseModel): class OutputAudioBufferStarted(BaseModel): + """ + **WebRTC/SIP Only:** Emitted when the server begins streaming audio to the client. This event is + emitted after an audio content part has been added (`response.content_part.added`) + to the response. + [Learn more](https://platform.openai.com/docs/guides/realtime-conversations#client-and-server-events-for-audio-in-webrtc). + """ + event_id: str """The unique ID of the server event.""" @@ -83,6 +95,13 @@ class OutputAudioBufferStarted(BaseModel): class OutputAudioBufferStopped(BaseModel): + """ + **WebRTC/SIP Only:** Emitted when the output audio buffer has been completely drained on the server, + and no more audio is forthcoming. This event is emitted after the full response + data has been sent to the client (`response.done`). + [Learn more](https://platform.openai.com/docs/guides/realtime-conversations#client-and-server-events-for-audio-in-webrtc). + """ + event_id: str """The unique ID of the server event.""" @@ -94,6 +113,15 @@ class OutputAudioBufferStopped(BaseModel): class OutputAudioBufferCleared(BaseModel): + """**WebRTC/SIP Only:** Emitted when the output audio buffer is cleared. + + This happens either in VAD + mode when the user has interrupted (`input_audio_buffer.speech_started`), + or when the client has emitted the `output_audio_buffer.clear` event to manually + cut off the current audio response. + [Learn more](https://platform.openai.com/docs/guides/realtime-conversations#client-and-server-events-for-audio-in-webrtc). + """ + event_id: str """The unique ID of the server event.""" diff --git a/src/openai/types/realtime/realtime_session_client_secret.py b/src/openai/types/realtime/realtime_session_client_secret.py index a4998802bb..13a12f5502 100644 --- a/src/openai/types/realtime/realtime_session_client_secret.py +++ b/src/openai/types/realtime/realtime_session_client_secret.py @@ -6,6 +6,8 @@ class RealtimeSessionClientSecret(BaseModel): + """Ephemeral key returned by the API.""" + expires_at: int """Timestamp for when the token expires. diff --git a/src/openai/types/realtime/realtime_session_create_request.py b/src/openai/types/realtime/realtime_session_create_request.py index 80cf468dc8..76738816a0 100644 --- a/src/openai/types/realtime/realtime_session_create_request.py +++ b/src/openai/types/realtime/realtime_session_create_request.py @@ -15,6 +15,8 @@ class RealtimeSessionCreateRequest(BaseModel): + """Realtime session object configuration.""" + type: Literal["realtime"] """The type of session to create. Always `realtime` for the Realtime API.""" diff --git a/src/openai/types/realtime/realtime_session_create_request_param.py b/src/openai/types/realtime/realtime_session_create_request_param.py index 578d5a502d..cc5806fe11 100644 --- a/src/openai/types/realtime/realtime_session_create_request_param.py +++ b/src/openai/types/realtime/realtime_session_create_request_param.py @@ -16,6 +16,8 @@ class RealtimeSessionCreateRequestParam(TypedDict, total=False): + """Realtime session object configuration.""" + type: Required[Literal["realtime"]] """The type of session to create. Always `realtime` for the Realtime API.""" diff --git a/src/openai/types/realtime/realtime_session_create_response.py b/src/openai/types/realtime/realtime_session_create_response.py index df69dd7bdb..46d32e8571 100644 --- a/src/openai/types/realtime/realtime_session_create_response.py +++ b/src/openai/types/realtime/realtime_session_create_response.py @@ -40,6 +40,13 @@ class AudioInputNoiseReduction(BaseModel): + """Configuration for input audio noise reduction. + + This can be set to `null` to turn off. + Noise reduction filters audio added to the input audio buffer before it is sent to VAD and the model. + Filtering the audio can improve VAD and turn detection accuracy (reducing false positives) and model performance by improving perception of the input audio. + """ + type: Optional[NoiseReductionType] = None """Type of noise reduction. @@ -49,6 +56,10 @@ class AudioInputNoiseReduction(BaseModel): class AudioInputTurnDetectionServerVad(BaseModel): + """ + Server-side voice activity detection (VAD) which flips on when user speech is detected and off after a period of silence. + """ + type: Literal["server_vad"] """Type of turn detection, `server_vad` to turn on simple Server VAD.""" @@ -115,6 +126,10 @@ class AudioInputTurnDetectionServerVad(BaseModel): class AudioInputTurnDetectionSemanticVad(BaseModel): + """ + Server-side semantic turn detection which uses a model to determine when the user has finished speaking. + """ + type: Literal["semantic_vad"] """Type of turn detection, `semantic_vad` to turn on Semantic VAD.""" @@ -218,6 +233,8 @@ class AudioOutput(BaseModel): class Audio(BaseModel): + """Configuration for input and output audio.""" + input: Optional[AudioInput] = None output: Optional[AudioOutput] = None @@ -227,6 +244,8 @@ class Audio(BaseModel): class ToolMcpToolAllowedToolsMcpToolFilter(BaseModel): + """A filter object to specify which tools are allowed.""" + read_only: Optional[bool] = None """Indicates whether or not a tool modifies data or is read-only. @@ -243,6 +262,8 @@ class ToolMcpToolAllowedToolsMcpToolFilter(BaseModel): class ToolMcpToolRequireApprovalMcpToolApprovalFilterAlways(BaseModel): + """A filter object to specify which tools are allowed.""" + read_only: Optional[bool] = None """Indicates whether or not a tool modifies data or is read-only. @@ -256,6 +277,8 @@ class ToolMcpToolRequireApprovalMcpToolApprovalFilterAlways(BaseModel): class ToolMcpToolRequireApprovalMcpToolApprovalFilterNever(BaseModel): + """A filter object to specify which tools are allowed.""" + read_only: Optional[bool] = None """Indicates whether or not a tool modifies data or is read-only. @@ -269,6 +292,13 @@ class ToolMcpToolRequireApprovalMcpToolApprovalFilterNever(BaseModel): class ToolMcpToolRequireApprovalMcpToolApprovalFilter(BaseModel): + """Specify which of the MCP server's tools require approval. + + Can be + `always`, `never`, or a filter object associated with tools + that require approval. + """ + always: Optional[ToolMcpToolRequireApprovalMcpToolApprovalFilterAlways] = None """A filter object to specify which tools are allowed.""" @@ -282,6 +312,11 @@ class ToolMcpToolRequireApprovalMcpToolApprovalFilter(BaseModel): class ToolMcpTool(BaseModel): + """ + Give the model access to additional tools via remote Model Context Protocol + (MCP) servers. [Learn more about MCP](https://platform.openai.com/docs/guides/tools-remote-mcp). + """ + server_label: str """A label for this MCP server, used to identify it in tool calls.""" @@ -351,6 +386,8 @@ class ToolMcpTool(BaseModel): class TracingTracingConfiguration(BaseModel): + """Granular configuration for tracing.""" + group_id: Optional[str] = None """ The group id to attach to this trace to enable filtering and grouping in the @@ -374,6 +411,12 @@ class TracingTracingConfiguration(BaseModel): class RealtimeSessionCreateResponse(BaseModel): + """A new Realtime session configuration, with an ephemeral key. + + Default TTL + for keys is one minute. + """ + client_secret: RealtimeSessionClientSecret """Ephemeral key returned by the API.""" diff --git a/src/openai/types/realtime/realtime_tools_config_param.py b/src/openai/types/realtime/realtime_tools_config_param.py index 630fc74691..3cc404feef 100644 --- a/src/openai/types/realtime/realtime_tools_config_param.py +++ b/src/openai/types/realtime/realtime_tools_config_param.py @@ -22,6 +22,8 @@ class McpAllowedToolsMcpToolFilter(TypedDict, total=False): + """A filter object to specify which tools are allowed.""" + read_only: bool """Indicates whether or not a tool modifies data or is read-only. @@ -38,6 +40,8 @@ class McpAllowedToolsMcpToolFilter(TypedDict, total=False): class McpRequireApprovalMcpToolApprovalFilterAlways(TypedDict, total=False): + """A filter object to specify which tools are allowed.""" + read_only: bool """Indicates whether or not a tool modifies data or is read-only. @@ -51,6 +55,8 @@ class McpRequireApprovalMcpToolApprovalFilterAlways(TypedDict, total=False): class McpRequireApprovalMcpToolApprovalFilterNever(TypedDict, total=False): + """A filter object to specify which tools are allowed.""" + read_only: bool """Indicates whether or not a tool modifies data or is read-only. @@ -64,6 +70,13 @@ class McpRequireApprovalMcpToolApprovalFilterNever(TypedDict, total=False): class McpRequireApprovalMcpToolApprovalFilter(TypedDict, total=False): + """Specify which of the MCP server's tools require approval. + + Can be + `always`, `never`, or a filter object associated with tools + that require approval. + """ + always: McpRequireApprovalMcpToolApprovalFilterAlways """A filter object to specify which tools are allowed.""" @@ -75,6 +88,11 @@ class McpRequireApprovalMcpToolApprovalFilter(TypedDict, total=False): class Mcp(TypedDict, total=False): + """ + Give the model access to additional tools via remote Model Context Protocol + (MCP) servers. [Learn more about MCP](https://platform.openai.com/docs/guides/tools-remote-mcp). + """ + server_label: Required[str] """A label for this MCP server, used to identify it in tool calls.""" diff --git a/src/openai/types/realtime/realtime_tools_config_union.py b/src/openai/types/realtime/realtime_tools_config_union.py index e7126ed60d..92aaee7f26 100644 --- a/src/openai/types/realtime/realtime_tools_config_union.py +++ b/src/openai/types/realtime/realtime_tools_config_union.py @@ -20,6 +20,8 @@ class McpAllowedToolsMcpToolFilter(BaseModel): + """A filter object to specify which tools are allowed.""" + read_only: Optional[bool] = None """Indicates whether or not a tool modifies data or is read-only. @@ -36,6 +38,8 @@ class McpAllowedToolsMcpToolFilter(BaseModel): class McpRequireApprovalMcpToolApprovalFilterAlways(BaseModel): + """A filter object to specify which tools are allowed.""" + read_only: Optional[bool] = None """Indicates whether or not a tool modifies data or is read-only. @@ -49,6 +53,8 @@ class McpRequireApprovalMcpToolApprovalFilterAlways(BaseModel): class McpRequireApprovalMcpToolApprovalFilterNever(BaseModel): + """A filter object to specify which tools are allowed.""" + read_only: Optional[bool] = None """Indicates whether or not a tool modifies data or is read-only. @@ -62,6 +68,13 @@ class McpRequireApprovalMcpToolApprovalFilterNever(BaseModel): class McpRequireApprovalMcpToolApprovalFilter(BaseModel): + """Specify which of the MCP server's tools require approval. + + Can be + `always`, `never`, or a filter object associated with tools + that require approval. + """ + always: Optional[McpRequireApprovalMcpToolApprovalFilterAlways] = None """A filter object to specify which tools are allowed.""" @@ -73,6 +86,11 @@ class McpRequireApprovalMcpToolApprovalFilter(BaseModel): class Mcp(BaseModel): + """ + Give the model access to additional tools via remote Model Context Protocol + (MCP) servers. [Learn more about MCP](https://platform.openai.com/docs/guides/tools-remote-mcp). + """ + server_label: str """A label for this MCP server, used to identify it in tool calls.""" diff --git a/src/openai/types/realtime/realtime_tools_config_union_param.py b/src/openai/types/realtime/realtime_tools_config_union_param.py index 9ee58fdbe6..6889b4c304 100644 --- a/src/openai/types/realtime/realtime_tools_config_union_param.py +++ b/src/openai/types/realtime/realtime_tools_config_union_param.py @@ -21,6 +21,8 @@ class McpAllowedToolsMcpToolFilter(TypedDict, total=False): + """A filter object to specify which tools are allowed.""" + read_only: bool """Indicates whether or not a tool modifies data or is read-only. @@ -37,6 +39,8 @@ class McpAllowedToolsMcpToolFilter(TypedDict, total=False): class McpRequireApprovalMcpToolApprovalFilterAlways(TypedDict, total=False): + """A filter object to specify which tools are allowed.""" + read_only: bool """Indicates whether or not a tool modifies data or is read-only. @@ -50,6 +54,8 @@ class McpRequireApprovalMcpToolApprovalFilterAlways(TypedDict, total=False): class McpRequireApprovalMcpToolApprovalFilterNever(TypedDict, total=False): + """A filter object to specify which tools are allowed.""" + read_only: bool """Indicates whether or not a tool modifies data or is read-only. @@ -63,6 +69,13 @@ class McpRequireApprovalMcpToolApprovalFilterNever(TypedDict, total=False): class McpRequireApprovalMcpToolApprovalFilter(TypedDict, total=False): + """Specify which of the MCP server's tools require approval. + + Can be + `always`, `never`, or a filter object associated with tools + that require approval. + """ + always: McpRequireApprovalMcpToolApprovalFilterAlways """A filter object to specify which tools are allowed.""" @@ -74,6 +87,11 @@ class McpRequireApprovalMcpToolApprovalFilter(TypedDict, total=False): class Mcp(TypedDict, total=False): + """ + Give the model access to additional tools via remote Model Context Protocol + (MCP) servers. [Learn more about MCP](https://platform.openai.com/docs/guides/tools-remote-mcp). + """ + server_label: Required[str] """A label for this MCP server, used to identify it in tool calls.""" diff --git a/src/openai/types/realtime/realtime_tracing_config.py b/src/openai/types/realtime/realtime_tracing_config.py index 1c46de7928..37e3ce8945 100644 --- a/src/openai/types/realtime/realtime_tracing_config.py +++ b/src/openai/types/realtime/realtime_tracing_config.py @@ -9,6 +9,8 @@ class TracingConfiguration(BaseModel): + """Granular configuration for tracing.""" + group_id: Optional[str] = None """ The group id to attach to this trace to enable filtering and grouping in the diff --git a/src/openai/types/realtime/realtime_tracing_config_param.py b/src/openai/types/realtime/realtime_tracing_config_param.py index fd9e266244..742412897f 100644 --- a/src/openai/types/realtime/realtime_tracing_config_param.py +++ b/src/openai/types/realtime/realtime_tracing_config_param.py @@ -9,6 +9,8 @@ class TracingConfiguration(TypedDict, total=False): + """Granular configuration for tracing.""" + group_id: str """ The group id to attach to this trace to enable filtering and grouping in the diff --git a/src/openai/types/realtime/realtime_transcription_session_audio.py b/src/openai/types/realtime/realtime_transcription_session_audio.py index a5506947f1..7ec29afb79 100644 --- a/src/openai/types/realtime/realtime_transcription_session_audio.py +++ b/src/openai/types/realtime/realtime_transcription_session_audio.py @@ -9,4 +9,6 @@ class RealtimeTranscriptionSessionAudio(BaseModel): + """Configuration for input and output audio.""" + input: Optional[RealtimeTranscriptionSessionAudioInput] = None diff --git a/src/openai/types/realtime/realtime_transcription_session_audio_input.py b/src/openai/types/realtime/realtime_transcription_session_audio_input.py index efc321cbeb..80ff223590 100644 --- a/src/openai/types/realtime/realtime_transcription_session_audio_input.py +++ b/src/openai/types/realtime/realtime_transcription_session_audio_input.py @@ -14,6 +14,13 @@ class NoiseReduction(BaseModel): + """Configuration for input audio noise reduction. + + This can be set to `null` to turn off. + Noise reduction filters audio added to the input audio buffer before it is sent to VAD and the model. + Filtering the audio can improve VAD and turn detection accuracy (reducing false positives) and model performance by improving perception of the input audio. + """ + type: Optional[NoiseReductionType] = None """Type of noise reduction. diff --git a/src/openai/types/realtime/realtime_transcription_session_audio_input_param.py b/src/openai/types/realtime/realtime_transcription_session_audio_input_param.py index c9153b68a4..dd908c72f6 100644 --- a/src/openai/types/realtime/realtime_transcription_session_audio_input_param.py +++ b/src/openai/types/realtime/realtime_transcription_session_audio_input_param.py @@ -16,6 +16,13 @@ class NoiseReduction(TypedDict, total=False): + """Configuration for input audio noise reduction. + + This can be set to `null` to turn off. + Noise reduction filters audio added to the input audio buffer before it is sent to VAD and the model. + Filtering the audio can improve VAD and turn detection accuracy (reducing false positives) and model performance by improving perception of the input audio. + """ + type: NoiseReductionType """Type of noise reduction. diff --git a/src/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection.py b/src/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection.py index e21844f48f..3d4ee779f4 100644 --- a/src/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection.py +++ b/src/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection.py @@ -10,6 +10,10 @@ class ServerVad(BaseModel): + """ + Server-side voice activity detection (VAD) which flips on when user speech is detected and off after a period of silence. + """ + type: Literal["server_vad"] """Type of turn detection, `server_vad` to turn on simple Server VAD.""" @@ -76,6 +80,10 @@ class ServerVad(BaseModel): class SemanticVad(BaseModel): + """ + Server-side semantic turn detection which uses a model to determine when the user has finished speaking. + """ + type: Literal["semantic_vad"] """Type of turn detection, `semantic_vad` to turn on Semantic VAD.""" diff --git a/src/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection_param.py b/src/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection_param.py index 507c43141e..0aca59ce11 100644 --- a/src/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection_param.py +++ b/src/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection_param.py @@ -9,6 +9,10 @@ class ServerVad(TypedDict, total=False): + """ + Server-side voice activity detection (VAD) which flips on when user speech is detected and off after a period of silence. + """ + type: Required[Literal["server_vad"]] """Type of turn detection, `server_vad` to turn on simple Server VAD.""" @@ -75,6 +79,10 @@ class ServerVad(TypedDict, total=False): class SemanticVad(TypedDict, total=False): + """ + Server-side semantic turn detection which uses a model to determine when the user has finished speaking. + """ + type: Required[Literal["semantic_vad"]] """Type of turn detection, `semantic_vad` to turn on Semantic VAD.""" diff --git a/src/openai/types/realtime/realtime_transcription_session_audio_param.py b/src/openai/types/realtime/realtime_transcription_session_audio_param.py index 1503a606d3..6bf1117917 100644 --- a/src/openai/types/realtime/realtime_transcription_session_audio_param.py +++ b/src/openai/types/realtime/realtime_transcription_session_audio_param.py @@ -10,4 +10,6 @@ class RealtimeTranscriptionSessionAudioParam(TypedDict, total=False): + """Configuration for input and output audio.""" + input: RealtimeTranscriptionSessionAudioInputParam diff --git a/src/openai/types/realtime/realtime_transcription_session_create_request.py b/src/openai/types/realtime/realtime_transcription_session_create_request.py index 102f2b14fb..f72a4ad93f 100644 --- a/src/openai/types/realtime/realtime_transcription_session_create_request.py +++ b/src/openai/types/realtime/realtime_transcription_session_create_request.py @@ -10,6 +10,8 @@ class RealtimeTranscriptionSessionCreateRequest(BaseModel): + """Realtime transcription session object configuration.""" + type: Literal["transcription"] """The type of session to create. diff --git a/src/openai/types/realtime/realtime_transcription_session_create_request_param.py b/src/openai/types/realtime/realtime_transcription_session_create_request_param.py index 80cbe2d414..9b4d8ead79 100644 --- a/src/openai/types/realtime/realtime_transcription_session_create_request_param.py +++ b/src/openai/types/realtime/realtime_transcription_session_create_request_param.py @@ -11,6 +11,8 @@ class RealtimeTranscriptionSessionCreateRequestParam(TypedDict, total=False): + """Realtime transcription session object configuration.""" + type: Required[Literal["transcription"]] """The type of session to create. diff --git a/src/openai/types/realtime/realtime_transcription_session_create_response.py b/src/openai/types/realtime/realtime_transcription_session_create_response.py index 301af1ac3f..6ca6c3808b 100644 --- a/src/openai/types/realtime/realtime_transcription_session_create_response.py +++ b/src/openai/types/realtime/realtime_transcription_session_create_response.py @@ -13,6 +13,8 @@ class AudioInputNoiseReduction(BaseModel): + """Configuration for input audio noise reduction.""" + type: Optional[NoiseReductionType] = None """Type of noise reduction. @@ -41,10 +43,14 @@ class AudioInput(BaseModel): class Audio(BaseModel): + """Configuration for input audio for the session.""" + input: Optional[AudioInput] = None class RealtimeTranscriptionSessionCreateResponse(BaseModel): + """A Realtime transcription session configuration object.""" + id: str """Unique identifier for the session that looks like `sess_1234567890abcdef`.""" diff --git a/src/openai/types/realtime/realtime_transcription_session_turn_detection.py b/src/openai/types/realtime/realtime_transcription_session_turn_detection.py index f5da31ce77..8dacd60a07 100644 --- a/src/openai/types/realtime/realtime_transcription_session_turn_detection.py +++ b/src/openai/types/realtime/realtime_transcription_session_turn_detection.py @@ -8,6 +8,13 @@ class RealtimeTranscriptionSessionTurnDetection(BaseModel): + """Configuration for turn detection. + + Can be set to `null` to turn off. Server + VAD means that the model will detect the start and end of speech based on + audio volume and respond at the end of user speech. + """ + prefix_padding_ms: Optional[int] = None """Amount of audio to include before the VAD detected speech (in milliseconds). diff --git a/src/openai/types/realtime/realtime_truncation_retention_ratio.py b/src/openai/types/realtime/realtime_truncation_retention_ratio.py index e19ed64831..72a93a5654 100644 --- a/src/openai/types/realtime/realtime_truncation_retention_ratio.py +++ b/src/openai/types/realtime/realtime_truncation_retention_ratio.py @@ -9,6 +9,11 @@ class TokenLimits(BaseModel): + """Optional custom token limits for this truncation strategy. + + If not provided, the model's default token limits will be used. + """ + post_instructions: Optional[int] = None """ Maximum tokens allowed in the conversation after instructions (which including @@ -20,6 +25,10 @@ class TokenLimits(BaseModel): class RealtimeTruncationRetentionRatio(BaseModel): + """ + Retain a fraction of the conversation tokens when the conversation exceeds the input token limit. This allows you to amortize truncations across multiple turns, which can help improve cached token usage. + """ + retention_ratio: float """ Fraction of post-instruction conversation tokens to retain (`0.0` - `1.0`) when diff --git a/src/openai/types/realtime/realtime_truncation_retention_ratio_param.py b/src/openai/types/realtime/realtime_truncation_retention_ratio_param.py index 4ea80fe4ce..4648fa66b0 100644 --- a/src/openai/types/realtime/realtime_truncation_retention_ratio_param.py +++ b/src/openai/types/realtime/realtime_truncation_retention_ratio_param.py @@ -8,6 +8,11 @@ class TokenLimits(TypedDict, total=False): + """Optional custom token limits for this truncation strategy. + + If not provided, the model's default token limits will be used. + """ + post_instructions: int """ Maximum tokens allowed in the conversation after instructions (which including @@ -19,6 +24,10 @@ class TokenLimits(TypedDict, total=False): class RealtimeTruncationRetentionRatioParam(TypedDict, total=False): + """ + Retain a fraction of the conversation tokens when the conversation exceeds the input token limit. This allows you to amortize truncations across multiple turns, which can help improve cached token usage. + """ + retention_ratio: Required[float] """ Fraction of post-instruction conversation tokens to retain (`0.0` - `1.0`) when diff --git a/src/openai/types/realtime/response_audio_delta_event.py b/src/openai/types/realtime/response_audio_delta_event.py index d92c5462d0..ae87014053 100644 --- a/src/openai/types/realtime/response_audio_delta_event.py +++ b/src/openai/types/realtime/response_audio_delta_event.py @@ -8,6 +8,8 @@ class ResponseAudioDeltaEvent(BaseModel): + """Returned when the model-generated audio is updated.""" + content_index: int """The index of the content part in the item's content array.""" diff --git a/src/openai/types/realtime/response_audio_done_event.py b/src/openai/types/realtime/response_audio_done_event.py index 5ea0f07e36..98715aba13 100644 --- a/src/openai/types/realtime/response_audio_done_event.py +++ b/src/openai/types/realtime/response_audio_done_event.py @@ -8,6 +8,12 @@ class ResponseAudioDoneEvent(BaseModel): + """Returned when the model-generated audio is done. + + Also emitted when a Response + is interrupted, incomplete, or cancelled. + """ + content_index: int """The index of the content part in the item's content array.""" diff --git a/src/openai/types/realtime/response_audio_transcript_delta_event.py b/src/openai/types/realtime/response_audio_transcript_delta_event.py index 4dd5fecac0..4ec1a820ba 100644 --- a/src/openai/types/realtime/response_audio_transcript_delta_event.py +++ b/src/openai/types/realtime/response_audio_transcript_delta_event.py @@ -8,6 +8,8 @@ class ResponseAudioTranscriptDeltaEvent(BaseModel): + """Returned when the model-generated transcription of audio output is updated.""" + content_index: int """The index of the content part in the item's content array.""" diff --git a/src/openai/types/realtime/response_audio_transcript_done_event.py b/src/openai/types/realtime/response_audio_transcript_done_event.py index 2de913d277..c2a2416355 100644 --- a/src/openai/types/realtime/response_audio_transcript_done_event.py +++ b/src/openai/types/realtime/response_audio_transcript_done_event.py @@ -8,6 +8,12 @@ class ResponseAudioTranscriptDoneEvent(BaseModel): + """ + Returned when the model-generated transcription of audio output is done + streaming. Also emitted when a Response is interrupted, incomplete, or + cancelled. + """ + content_index: int """The index of the content part in the item's content array.""" diff --git a/src/openai/types/realtime/response_cancel_event.py b/src/openai/types/realtime/response_cancel_event.py index 15dc141cbf..9c6113998f 100644 --- a/src/openai/types/realtime/response_cancel_event.py +++ b/src/openai/types/realtime/response_cancel_event.py @@ -9,6 +9,15 @@ class ResponseCancelEvent(BaseModel): + """Send this event to cancel an in-progress response. + + The server will respond + with a `response.done` event with a status of `response.status=cancelled`. If + there is no response to cancel, the server will respond with an error. It's safe + to call `response.cancel` even if no response is in progress, an error will be + returned the session will remain unaffected. + """ + type: Literal["response.cancel"] """The event type, must be `response.cancel`.""" diff --git a/src/openai/types/realtime/response_cancel_event_param.py b/src/openai/types/realtime/response_cancel_event_param.py index f33740730a..b233b407f9 100644 --- a/src/openai/types/realtime/response_cancel_event_param.py +++ b/src/openai/types/realtime/response_cancel_event_param.py @@ -8,6 +8,15 @@ class ResponseCancelEventParam(TypedDict, total=False): + """Send this event to cancel an in-progress response. + + The server will respond + with a `response.done` event with a status of `response.status=cancelled`. If + there is no response to cancel, the server will respond with an error. It's safe + to call `response.cancel` even if no response is in progress, an error will be + returned the session will remain unaffected. + """ + type: Required[Literal["response.cancel"]] """The event type, must be `response.cancel`.""" diff --git a/src/openai/types/realtime/response_content_part_added_event.py b/src/openai/types/realtime/response_content_part_added_event.py index aca965c3d8..e47c84af20 100644 --- a/src/openai/types/realtime/response_content_part_added_event.py +++ b/src/openai/types/realtime/response_content_part_added_event.py @@ -9,6 +9,8 @@ class Part(BaseModel): + """The content part that was added.""" + audio: Optional[str] = None """Base64-encoded audio data (if type is "audio").""" @@ -23,6 +25,11 @@ class Part(BaseModel): class ResponseContentPartAddedEvent(BaseModel): + """ + Returned when a new content part is added to an assistant message item during + response generation. + """ + content_index: int """The index of the content part in the item's content array.""" diff --git a/src/openai/types/realtime/response_content_part_done_event.py b/src/openai/types/realtime/response_content_part_done_event.py index 59af808a90..a6cb8559b9 100644 --- a/src/openai/types/realtime/response_content_part_done_event.py +++ b/src/openai/types/realtime/response_content_part_done_event.py @@ -9,6 +9,8 @@ class Part(BaseModel): + """The content part that is done.""" + audio: Optional[str] = None """Base64-encoded audio data (if type is "audio").""" @@ -23,6 +25,11 @@ class Part(BaseModel): class ResponseContentPartDoneEvent(BaseModel): + """ + Returned when a content part is done streaming in an assistant message item. + Also emitted when a Response is interrupted, incomplete, or cancelled. + """ + content_index: int """The index of the content part in the item's content array.""" diff --git a/src/openai/types/realtime/response_create_event.py b/src/openai/types/realtime/response_create_event.py index 75a08ee460..3e98a8d858 100644 --- a/src/openai/types/realtime/response_create_event.py +++ b/src/openai/types/realtime/response_create_event.py @@ -10,6 +10,34 @@ class ResponseCreateEvent(BaseModel): + """ + This event instructs the server to create a Response, which means triggering + model inference. When in Server VAD mode, the server will create Responses + automatically. + + A Response will include at least one Item, and may have two, in which case + the second will be a function call. These Items will be appended to the + conversation history by default. + + The server will respond with a `response.created` event, events for Items + and content created, and finally a `response.done` event to indicate the + Response is complete. + + The `response.create` event includes inference configuration like + `instructions` and `tools`. If these are set, they will override the Session's + configuration for this Response only. + + Responses can be created out-of-band of the default Conversation, meaning that they can + have arbitrary input, and it's possible to disable writing the output to the Conversation. + Only one Response can write to the default Conversation at a time, but otherwise multiple + Responses can be created in parallel. The `metadata` field is a good way to disambiguate + multiple simultaneous Responses. + + Clients can set `conversation` to `none` to create a Response that does not write to the default + Conversation. Arbitrary input can be provided with the `input` field, which is an array accepting + raw Items and references to existing Items. + """ + type: Literal["response.create"] """The event type, must be `response.create`.""" diff --git a/src/openai/types/realtime/response_create_event_param.py b/src/openai/types/realtime/response_create_event_param.py index e5dd46d9b6..9da89e14ee 100644 --- a/src/openai/types/realtime/response_create_event_param.py +++ b/src/openai/types/realtime/response_create_event_param.py @@ -10,6 +10,34 @@ class ResponseCreateEventParam(TypedDict, total=False): + """ + This event instructs the server to create a Response, which means triggering + model inference. When in Server VAD mode, the server will create Responses + automatically. + + A Response will include at least one Item, and may have two, in which case + the second will be a function call. These Items will be appended to the + conversation history by default. + + The server will respond with a `response.created` event, events for Items + and content created, and finally a `response.done` event to indicate the + Response is complete. + + The `response.create` event includes inference configuration like + `instructions` and `tools`. If these are set, they will override the Session's + configuration for this Response only. + + Responses can be created out-of-band of the default Conversation, meaning that they can + have arbitrary input, and it's possible to disable writing the output to the Conversation. + Only one Response can write to the default Conversation at a time, but otherwise multiple + Responses can be created in parallel. The `metadata` field is a good way to disambiguate + multiple simultaneous Responses. + + Clients can set `conversation` to `none` to create a Response that does not write to the default + Conversation. Arbitrary input can be provided with the `input` field, which is an array accepting + raw Items and references to existing Items. + """ + type: Required[Literal["response.create"]] """The event type, must be `response.create`.""" diff --git a/src/openai/types/realtime/response_created_event.py b/src/openai/types/realtime/response_created_event.py index 996bf26f75..dc5941262d 100644 --- a/src/openai/types/realtime/response_created_event.py +++ b/src/openai/types/realtime/response_created_event.py @@ -9,6 +9,12 @@ class ResponseCreatedEvent(BaseModel): + """Returned when a new Response is created. + + The first event of response creation, + where the response is in an initial state of `in_progress`. + """ + event_id: str """The unique ID of the server event.""" diff --git a/src/openai/types/realtime/response_done_event.py b/src/openai/types/realtime/response_done_event.py index ce9a4b9f1d..9c31a2aa03 100644 --- a/src/openai/types/realtime/response_done_event.py +++ b/src/openai/types/realtime/response_done_event.py @@ -9,6 +9,19 @@ class ResponseDoneEvent(BaseModel): + """Returned when a Response is done streaming. + + Always emitted, no matter the + final state. The Response object included in the `response.done` event will + include all output Items in the Response but will omit the raw audio data. + + Clients should check the `status` field of the Response to determine if it was successful + (`completed`) or if there was another outcome: `cancelled`, `failed`, or `incomplete`. + + A response will contain all output items that were generated during the response, excluding + any audio content. + """ + event_id: str """The unique ID of the server event.""" diff --git a/src/openai/types/realtime/response_function_call_arguments_delta_event.py b/src/openai/types/realtime/response_function_call_arguments_delta_event.py index 6d96e78b24..a426c3f211 100644 --- a/src/openai/types/realtime/response_function_call_arguments_delta_event.py +++ b/src/openai/types/realtime/response_function_call_arguments_delta_event.py @@ -8,6 +8,8 @@ class ResponseFunctionCallArgumentsDeltaEvent(BaseModel): + """Returned when the model-generated function call arguments are updated.""" + call_id: str """The ID of the function call.""" diff --git a/src/openai/types/realtime/response_function_call_arguments_done_event.py b/src/openai/types/realtime/response_function_call_arguments_done_event.py index be7fae9a1b..504f91d558 100644 --- a/src/openai/types/realtime/response_function_call_arguments_done_event.py +++ b/src/openai/types/realtime/response_function_call_arguments_done_event.py @@ -8,6 +8,11 @@ class ResponseFunctionCallArgumentsDoneEvent(BaseModel): + """ + Returned when the model-generated function call arguments are done streaming. + Also emitted when a Response is interrupted, incomplete, or cancelled. + """ + arguments: str """The final arguments as a JSON string.""" diff --git a/src/openai/types/realtime/response_mcp_call_arguments_delta.py b/src/openai/types/realtime/response_mcp_call_arguments_delta.py index 0a02a1a578..d890de0575 100644 --- a/src/openai/types/realtime/response_mcp_call_arguments_delta.py +++ b/src/openai/types/realtime/response_mcp_call_arguments_delta.py @@ -9,6 +9,8 @@ class ResponseMcpCallArgumentsDelta(BaseModel): + """Returned when MCP tool call arguments are updated during response generation.""" + delta: str """The JSON-encoded arguments delta.""" diff --git a/src/openai/types/realtime/response_mcp_call_arguments_done.py b/src/openai/types/realtime/response_mcp_call_arguments_done.py index 5ec95f1728..a7cb2d1958 100644 --- a/src/openai/types/realtime/response_mcp_call_arguments_done.py +++ b/src/openai/types/realtime/response_mcp_call_arguments_done.py @@ -8,6 +8,8 @@ class ResponseMcpCallArgumentsDone(BaseModel): + """Returned when MCP tool call arguments are finalized during response generation.""" + arguments: str """The final JSON-encoded arguments string.""" diff --git a/src/openai/types/realtime/response_mcp_call_completed.py b/src/openai/types/realtime/response_mcp_call_completed.py index e3fcec21f0..130260539a 100644 --- a/src/openai/types/realtime/response_mcp_call_completed.py +++ b/src/openai/types/realtime/response_mcp_call_completed.py @@ -8,6 +8,8 @@ class ResponseMcpCallCompleted(BaseModel): + """Returned when an MCP tool call has completed successfully.""" + event_id: str """The unique ID of the server event.""" diff --git a/src/openai/types/realtime/response_mcp_call_failed.py b/src/openai/types/realtime/response_mcp_call_failed.py index b7adc8c2a7..1c08d1d4b7 100644 --- a/src/openai/types/realtime/response_mcp_call_failed.py +++ b/src/openai/types/realtime/response_mcp_call_failed.py @@ -8,6 +8,8 @@ class ResponseMcpCallFailed(BaseModel): + """Returned when an MCP tool call has failed.""" + event_id: str """The unique ID of the server event.""" diff --git a/src/openai/types/realtime/response_mcp_call_in_progress.py b/src/openai/types/realtime/response_mcp_call_in_progress.py index d0fcc7615c..4c0ad149e5 100644 --- a/src/openai/types/realtime/response_mcp_call_in_progress.py +++ b/src/openai/types/realtime/response_mcp_call_in_progress.py @@ -8,6 +8,8 @@ class ResponseMcpCallInProgress(BaseModel): + """Returned when an MCP tool call has started and is in progress.""" + event_id: str """The unique ID of the server event.""" diff --git a/src/openai/types/realtime/response_output_item_added_event.py b/src/openai/types/realtime/response_output_item_added_event.py index 509dfcaeaf..abec0d18f1 100644 --- a/src/openai/types/realtime/response_output_item_added_event.py +++ b/src/openai/types/realtime/response_output_item_added_event.py @@ -9,6 +9,8 @@ class ResponseOutputItemAddedEvent(BaseModel): + """Returned when a new Item is created during Response generation.""" + event_id: str """The unique ID of the server event.""" diff --git a/src/openai/types/realtime/response_output_item_done_event.py b/src/openai/types/realtime/response_output_item_done_event.py index 800e4ae8ee..63936b97d5 100644 --- a/src/openai/types/realtime/response_output_item_done_event.py +++ b/src/openai/types/realtime/response_output_item_done_event.py @@ -9,6 +9,12 @@ class ResponseOutputItemDoneEvent(BaseModel): + """Returned when an Item is done streaming. + + Also emitted when a Response is + interrupted, incomplete, or cancelled. + """ + event_id: str """The unique ID of the server event.""" diff --git a/src/openai/types/realtime/response_text_delta_event.py b/src/openai/types/realtime/response_text_delta_event.py index 493348aa22..b251b7639c 100644 --- a/src/openai/types/realtime/response_text_delta_event.py +++ b/src/openai/types/realtime/response_text_delta_event.py @@ -8,6 +8,8 @@ class ResponseTextDeltaEvent(BaseModel): + """Returned when the text value of an "output_text" content part is updated.""" + content_index: int """The index of the content part in the item's content array.""" diff --git a/src/openai/types/realtime/response_text_done_event.py b/src/openai/types/realtime/response_text_done_event.py index 83c6cf0694..046e520222 100644 --- a/src/openai/types/realtime/response_text_done_event.py +++ b/src/openai/types/realtime/response_text_done_event.py @@ -8,6 +8,12 @@ class ResponseTextDoneEvent(BaseModel): + """Returned when the text value of an "output_text" content part is done streaming. + + Also + emitted when a Response is interrupted, incomplete, or cancelled. + """ + content_index: int """The index of the content part in the item's content array.""" diff --git a/src/openai/types/realtime/session_created_event.py b/src/openai/types/realtime/session_created_event.py index b5caad35d7..1b8d4a4d81 100644 --- a/src/openai/types/realtime/session_created_event.py +++ b/src/openai/types/realtime/session_created_event.py @@ -13,6 +13,13 @@ class SessionCreatedEvent(BaseModel): + """Returned when a Session is created. + + Emitted automatically when a new + connection is established as the first server event. This event will contain + the default Session configuration. + """ + event_id: str """The unique ID of the server event.""" diff --git a/src/openai/types/realtime/session_update_event.py b/src/openai/types/realtime/session_update_event.py index 2e226162c4..a8422e4e89 100644 --- a/src/openai/types/realtime/session_update_event.py +++ b/src/openai/types/realtime/session_update_event.py @@ -13,6 +13,18 @@ class SessionUpdateEvent(BaseModel): + """ + Send this event to update the session’s configuration. + The client may send this event at any time to update any field + except for `voice` and `model`. `voice` can be updated only if there have been no other audio outputs yet. + + When the server receives a `session.update`, it will respond + with a `session.updated` event showing the full, effective configuration. + Only the fields that are present in the `session.update` are updated. To clear a field like + `instructions`, pass an empty string. To clear a field like `tools`, pass an empty array. + To clear a field like `turn_detection`, pass `null`. + """ + session: Session """Update the Realtime session. diff --git a/src/openai/types/realtime/session_update_event_param.py b/src/openai/types/realtime/session_update_event_param.py index 5962361431..910e89ca34 100644 --- a/src/openai/types/realtime/session_update_event_param.py +++ b/src/openai/types/realtime/session_update_event_param.py @@ -14,6 +14,18 @@ class SessionUpdateEventParam(TypedDict, total=False): + """ + Send this event to update the session’s configuration. + The client may send this event at any time to update any field + except for `voice` and `model`. `voice` can be updated only if there have been no other audio outputs yet. + + When the server receives a `session.update`, it will respond + with a `session.updated` event showing the full, effective configuration. + Only the fields that are present in the `session.update` are updated. To clear a field like + `instructions`, pass an empty string. To clear a field like `tools`, pass an empty array. + To clear a field like `turn_detection`, pass `null`. + """ + session: Required[Session] """Update the Realtime session. diff --git a/src/openai/types/realtime/session_updated_event.py b/src/openai/types/realtime/session_updated_event.py index eb7ee0332d..e68a08d6cc 100644 --- a/src/openai/types/realtime/session_updated_event.py +++ b/src/openai/types/realtime/session_updated_event.py @@ -13,6 +13,11 @@ class SessionUpdatedEvent(BaseModel): + """ + Returned when a session is updated with a `session.update` event, unless + there is an error. + """ + event_id: str """The unique ID of the server event.""" diff --git a/src/openai/types/responses/apply_patch_tool.py b/src/openai/types/responses/apply_patch_tool.py index 07706ce239..f2ed245d10 100644 --- a/src/openai/types/responses/apply_patch_tool.py +++ b/src/openai/types/responses/apply_patch_tool.py @@ -8,5 +8,7 @@ class ApplyPatchTool(BaseModel): + """Allows the assistant to create, delete, or update files using unified diffs.""" + type: Literal["apply_patch"] """The type of the tool. Always `apply_patch`.""" diff --git a/src/openai/types/responses/apply_patch_tool_param.py b/src/openai/types/responses/apply_patch_tool_param.py index 93d15f0b1f..2e0a809099 100644 --- a/src/openai/types/responses/apply_patch_tool_param.py +++ b/src/openai/types/responses/apply_patch_tool_param.py @@ -8,5 +8,7 @@ class ApplyPatchToolParam(TypedDict, total=False): + """Allows the assistant to create, delete, or update files using unified diffs.""" + type: Required[Literal["apply_patch"]] """The type of the tool. Always `apply_patch`.""" diff --git a/src/openai/types/responses/computer_tool.py b/src/openai/types/responses/computer_tool.py index 5b844f5bf4..22871c841c 100644 --- a/src/openai/types/responses/computer_tool.py +++ b/src/openai/types/responses/computer_tool.py @@ -8,6 +8,11 @@ class ComputerTool(BaseModel): + """A tool that controls a virtual computer. + + Learn more about the [computer tool](https://platform.openai.com/docs/guides/tools-computer-use). + """ + display_height: int """The height of the computer display.""" diff --git a/src/openai/types/responses/computer_tool_param.py b/src/openai/types/responses/computer_tool_param.py index 06a5c132ec..cdf75a43f2 100644 --- a/src/openai/types/responses/computer_tool_param.py +++ b/src/openai/types/responses/computer_tool_param.py @@ -8,6 +8,11 @@ class ComputerToolParam(TypedDict, total=False): + """A tool that controls a virtual computer. + + Learn more about the [computer tool](https://platform.openai.com/docs/guides/tools-computer-use). + """ + display_height: Required[int] """The height of the computer display.""" diff --git a/src/openai/types/responses/custom_tool.py b/src/openai/types/responses/custom_tool.py index c16ae715eb..1ca401a486 100644 --- a/src/openai/types/responses/custom_tool.py +++ b/src/openai/types/responses/custom_tool.py @@ -10,6 +10,11 @@ class CustomTool(BaseModel): + """A custom tool that processes input using a specified format. + + Learn more about [custom tools](https://platform.openai.com/docs/guides/function-calling#custom-tools) + """ + name: str """The name of the custom tool, used to identify it in tool calls.""" diff --git a/src/openai/types/responses/custom_tool_param.py b/src/openai/types/responses/custom_tool_param.py index 2afc8b19b8..4ce43cdfdb 100644 --- a/src/openai/types/responses/custom_tool_param.py +++ b/src/openai/types/responses/custom_tool_param.py @@ -10,6 +10,11 @@ class CustomToolParam(TypedDict, total=False): + """A custom tool that processes input using a specified format. + + Learn more about [custom tools](https://platform.openai.com/docs/guides/function-calling#custom-tools) + """ + name: Required[str] """The name of the custom tool, used to identify it in tool calls.""" diff --git a/src/openai/types/responses/easy_input_message.py b/src/openai/types/responses/easy_input_message.py index 4ed0194f9f..9a36a6b084 100644 --- a/src/openai/types/responses/easy_input_message.py +++ b/src/openai/types/responses/easy_input_message.py @@ -10,6 +10,14 @@ class EasyInputMessage(BaseModel): + """ + A message input to the model with a role indicating instruction following + hierarchy. Instructions given with the `developer` or `system` role take + precedence over instructions given with the `user` role. Messages with the + `assistant` role are presumed to have been generated by the model in previous + interactions. + """ + content: Union[str, ResponseInputMessageContentList] """ Text, image, or audio input to the model, used to generate a response. Can also diff --git a/src/openai/types/responses/easy_input_message_param.py b/src/openai/types/responses/easy_input_message_param.py index ef2f1c5f37..0a382bddee 100644 --- a/src/openai/types/responses/easy_input_message_param.py +++ b/src/openai/types/responses/easy_input_message_param.py @@ -11,6 +11,14 @@ class EasyInputMessageParam(TypedDict, total=False): + """ + A message input to the model with a role indicating instruction following + hierarchy. Instructions given with the `developer` or `system` role take + precedence over instructions given with the `user` role. Messages with the + `assistant` role are presumed to have been generated by the model in previous + interactions. + """ + content: Required[Union[str, ResponseInputMessageContentListParam]] """ Text, image, or audio input to the model, used to generate a response. Can also diff --git a/src/openai/types/responses/file_search_tool.py b/src/openai/types/responses/file_search_tool.py index d0d08a323f..09c12876ca 100644 --- a/src/openai/types/responses/file_search_tool.py +++ b/src/openai/types/responses/file_search_tool.py @@ -13,6 +13,10 @@ class RankingOptionsHybridSearch(BaseModel): + """ + Weights that control how reciprocal rank fusion balances semantic embedding matches versus sparse keyword matches when hybrid search is enabled. + """ + embedding_weight: float """The weight of the embedding in the reciprocal ranking fusion.""" @@ -21,6 +25,8 @@ class RankingOptionsHybridSearch(BaseModel): class RankingOptions(BaseModel): + """Ranking options for search.""" + hybrid_search: Optional[RankingOptionsHybridSearch] = None """ Weights that control how reciprocal rank fusion balances semantic embedding @@ -39,6 +45,11 @@ class RankingOptions(BaseModel): class FileSearchTool(BaseModel): + """A tool that searches for relevant content from uploaded files. + + Learn more about the [file search tool](https://platform.openai.com/docs/guides/tools-file-search). + """ + type: Literal["file_search"] """The type of the file search tool. Always `file_search`.""" diff --git a/src/openai/types/responses/file_search_tool_param.py b/src/openai/types/responses/file_search_tool_param.py index b37a669ebd..82831d0dc0 100644 --- a/src/openai/types/responses/file_search_tool_param.py +++ b/src/openai/types/responses/file_search_tool_param.py @@ -15,6 +15,10 @@ class RankingOptionsHybridSearch(TypedDict, total=False): + """ + Weights that control how reciprocal rank fusion balances semantic embedding matches versus sparse keyword matches when hybrid search is enabled. + """ + embedding_weight: Required[float] """The weight of the embedding in the reciprocal ranking fusion.""" @@ -23,6 +27,8 @@ class RankingOptionsHybridSearch(TypedDict, total=False): class RankingOptions(TypedDict, total=False): + """Ranking options for search.""" + hybrid_search: RankingOptionsHybridSearch """ Weights that control how reciprocal rank fusion balances semantic embedding @@ -41,6 +47,11 @@ class RankingOptions(TypedDict, total=False): class FileSearchToolParam(TypedDict, total=False): + """A tool that searches for relevant content from uploaded files. + + Learn more about the [file search tool](https://platform.openai.com/docs/guides/tools-file-search). + """ + type: Required[Literal["file_search"]] """The type of the file search tool. Always `file_search`.""" diff --git a/src/openai/types/responses/function_shell_tool.py b/src/openai/types/responses/function_shell_tool.py index 1784b6c2f1..5b237aa705 100644 --- a/src/openai/types/responses/function_shell_tool.py +++ b/src/openai/types/responses/function_shell_tool.py @@ -8,5 +8,7 @@ class FunctionShellTool(BaseModel): + """A tool that allows the model to execute shell commands.""" + type: Literal["shell"] """The type of the shell tool. Always `shell`.""" diff --git a/src/openai/types/responses/function_shell_tool_param.py b/src/openai/types/responses/function_shell_tool_param.py index cee7ba23c9..c640ddab99 100644 --- a/src/openai/types/responses/function_shell_tool_param.py +++ b/src/openai/types/responses/function_shell_tool_param.py @@ -8,5 +8,7 @@ class FunctionShellToolParam(TypedDict, total=False): + """A tool that allows the model to execute shell commands.""" + type: Required[Literal["shell"]] """The type of the shell tool. Always `shell`.""" diff --git a/src/openai/types/responses/function_tool.py b/src/openai/types/responses/function_tool.py index d881565356..b0827a9fa7 100644 --- a/src/openai/types/responses/function_tool.py +++ b/src/openai/types/responses/function_tool.py @@ -9,6 +9,11 @@ class FunctionTool(BaseModel): + """Defines a function in your own code the model can choose to call. + + Learn more about [function calling](https://platform.openai.com/docs/guides/function-calling). + """ + name: str """The name of the function to call.""" diff --git a/src/openai/types/responses/function_tool_param.py b/src/openai/types/responses/function_tool_param.py index 56bab36f47..ba0a3168c4 100644 --- a/src/openai/types/responses/function_tool_param.py +++ b/src/openai/types/responses/function_tool_param.py @@ -9,6 +9,11 @@ class FunctionToolParam(TypedDict, total=False): + """Defines a function in your own code the model can choose to call. + + Learn more about [function calling](https://platform.openai.com/docs/guides/function-calling). + """ + name: Required[str] """The name of the function to call.""" diff --git a/src/openai/types/responses/input_token_count_params.py b/src/openai/types/responses/input_token_count_params.py index 296d0718d8..50cc950e41 100644 --- a/src/openai/types/responses/input_token_count_params.py +++ b/src/openai/types/responses/input_token_count_params.py @@ -105,6 +105,14 @@ class InputTokenCountParams(TypedDict, total=False): class Text(TypedDict, total=False): + """Configuration options for a text response from the model. + + Can be plain + text or structured JSON data. Learn more: + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + """ + format: ResponseFormatTextConfigParam """An object specifying the format that the model must output. diff --git a/src/openai/types/responses/response.py b/src/openai/types/responses/response.py index cdd143f1cb..00c38c064e 100644 --- a/src/openai/types/responses/response.py +++ b/src/openai/types/responses/response.py @@ -28,6 +28,8 @@ class IncompleteDetails(BaseModel): + """Details about why the response is incomplete.""" + reason: Optional[Literal["max_output_tokens", "content_filter"]] = None """The reason why the response is incomplete.""" @@ -45,6 +47,11 @@ class IncompleteDetails(BaseModel): class Conversation(BaseModel): + """The conversation that this response belongs to. + + Input items and output items from this response are automatically added to this conversation. + """ + id: str """The unique ID of the conversation.""" diff --git a/src/openai/types/responses/response_apply_patch_tool_call.py b/src/openai/types/responses/response_apply_patch_tool_call.py index 7dc2a3c2b5..7af1300265 100644 --- a/src/openai/types/responses/response_apply_patch_tool_call.py +++ b/src/openai/types/responses/response_apply_patch_tool_call.py @@ -16,6 +16,8 @@ class OperationCreateFile(BaseModel): + """Instruction describing how to create a file via the apply_patch tool.""" + diff: str """Diff to apply.""" @@ -27,6 +29,8 @@ class OperationCreateFile(BaseModel): class OperationDeleteFile(BaseModel): + """Instruction describing how to delete a file via the apply_patch tool.""" + path: str """Path of the file to delete.""" @@ -35,6 +39,8 @@ class OperationDeleteFile(BaseModel): class OperationUpdateFile(BaseModel): + """Instruction describing how to update a file via the apply_patch tool.""" + diff: str """Diff to apply.""" @@ -51,6 +57,8 @@ class OperationUpdateFile(BaseModel): class ResponseApplyPatchToolCall(BaseModel): + """A tool call that applies file diffs by creating, deleting, or updating files.""" + id: str """The unique ID of the apply patch tool call. diff --git a/src/openai/types/responses/response_apply_patch_tool_call_output.py b/src/openai/types/responses/response_apply_patch_tool_call_output.py index cf0bcfeecc..de63c6e2ee 100644 --- a/src/openai/types/responses/response_apply_patch_tool_call_output.py +++ b/src/openai/types/responses/response_apply_patch_tool_call_output.py @@ -9,6 +9,8 @@ class ResponseApplyPatchToolCallOutput(BaseModel): + """The output emitted by an apply patch tool call.""" + id: str """The unique ID of the apply patch tool call output. diff --git a/src/openai/types/responses/response_audio_delta_event.py b/src/openai/types/responses/response_audio_delta_event.py index 6fb7887b80..e577d65d04 100644 --- a/src/openai/types/responses/response_audio_delta_event.py +++ b/src/openai/types/responses/response_audio_delta_event.py @@ -8,6 +8,8 @@ class ResponseAudioDeltaEvent(BaseModel): + """Emitted when there is a partial audio response.""" + delta: str """A chunk of Base64 encoded response audio bytes.""" diff --git a/src/openai/types/responses/response_audio_done_event.py b/src/openai/types/responses/response_audio_done_event.py index 2592ae8dcd..f5f0401c86 100644 --- a/src/openai/types/responses/response_audio_done_event.py +++ b/src/openai/types/responses/response_audio_done_event.py @@ -8,6 +8,8 @@ class ResponseAudioDoneEvent(BaseModel): + """Emitted when the audio response is complete.""" + sequence_number: int """The sequence number of the delta.""" diff --git a/src/openai/types/responses/response_audio_transcript_delta_event.py b/src/openai/types/responses/response_audio_transcript_delta_event.py index 830c133d61..03be59a29f 100644 --- a/src/openai/types/responses/response_audio_transcript_delta_event.py +++ b/src/openai/types/responses/response_audio_transcript_delta_event.py @@ -8,6 +8,8 @@ class ResponseAudioTranscriptDeltaEvent(BaseModel): + """Emitted when there is a partial transcript of audio.""" + delta: str """The partial transcript of the audio response.""" diff --git a/src/openai/types/responses/response_audio_transcript_done_event.py b/src/openai/types/responses/response_audio_transcript_done_event.py index e39f501cf0..87219e4844 100644 --- a/src/openai/types/responses/response_audio_transcript_done_event.py +++ b/src/openai/types/responses/response_audio_transcript_done_event.py @@ -8,6 +8,8 @@ class ResponseAudioTranscriptDoneEvent(BaseModel): + """Emitted when the full audio transcript is completed.""" + sequence_number: int """The sequence number of this event.""" diff --git a/src/openai/types/responses/response_code_interpreter_call_code_delta_event.py b/src/openai/types/responses/response_code_interpreter_call_code_delta_event.py index c5fef939b1..c6bc8b73ea 100644 --- a/src/openai/types/responses/response_code_interpreter_call_code_delta_event.py +++ b/src/openai/types/responses/response_code_interpreter_call_code_delta_event.py @@ -8,6 +8,8 @@ class ResponseCodeInterpreterCallCodeDeltaEvent(BaseModel): + """Emitted when a partial code snippet is streamed by the code interpreter.""" + delta: str """The partial code snippet being streamed by the code interpreter.""" diff --git a/src/openai/types/responses/response_code_interpreter_call_code_done_event.py b/src/openai/types/responses/response_code_interpreter_call_code_done_event.py index 5201a02d36..186c03711a 100644 --- a/src/openai/types/responses/response_code_interpreter_call_code_done_event.py +++ b/src/openai/types/responses/response_code_interpreter_call_code_done_event.py @@ -8,6 +8,8 @@ class ResponseCodeInterpreterCallCodeDoneEvent(BaseModel): + """Emitted when the code snippet is finalized by the code interpreter.""" + code: str """The final code snippet output by the code interpreter.""" diff --git a/src/openai/types/responses/response_code_interpreter_call_completed_event.py b/src/openai/types/responses/response_code_interpreter_call_completed_event.py index bb9563a16b..197e39e7e9 100644 --- a/src/openai/types/responses/response_code_interpreter_call_completed_event.py +++ b/src/openai/types/responses/response_code_interpreter_call_completed_event.py @@ -8,6 +8,8 @@ class ResponseCodeInterpreterCallCompletedEvent(BaseModel): + """Emitted when the code interpreter call is completed.""" + item_id: str """The unique identifier of the code interpreter tool call item.""" diff --git a/src/openai/types/responses/response_code_interpreter_call_in_progress_event.py b/src/openai/types/responses/response_code_interpreter_call_in_progress_event.py index 9c6b221004..c775f1b864 100644 --- a/src/openai/types/responses/response_code_interpreter_call_in_progress_event.py +++ b/src/openai/types/responses/response_code_interpreter_call_in_progress_event.py @@ -8,6 +8,8 @@ class ResponseCodeInterpreterCallInProgressEvent(BaseModel): + """Emitted when a code interpreter call is in progress.""" + item_id: str """The unique identifier of the code interpreter tool call item.""" diff --git a/src/openai/types/responses/response_code_interpreter_call_interpreting_event.py b/src/openai/types/responses/response_code_interpreter_call_interpreting_event.py index f6191e4165..85e9c87f08 100644 --- a/src/openai/types/responses/response_code_interpreter_call_interpreting_event.py +++ b/src/openai/types/responses/response_code_interpreter_call_interpreting_event.py @@ -8,6 +8,8 @@ class ResponseCodeInterpreterCallInterpretingEvent(BaseModel): + """Emitted when the code interpreter is actively interpreting the code snippet.""" + item_id: str """The unique identifier of the code interpreter tool call item.""" diff --git a/src/openai/types/responses/response_code_interpreter_tool_call.py b/src/openai/types/responses/response_code_interpreter_tool_call.py index b651581520..d7e30f4920 100644 --- a/src/openai/types/responses/response_code_interpreter_tool_call.py +++ b/src/openai/types/responses/response_code_interpreter_tool_call.py @@ -10,6 +10,8 @@ class OutputLogs(BaseModel): + """The logs output from the code interpreter.""" + logs: str """The logs output from the code interpreter.""" @@ -18,6 +20,8 @@ class OutputLogs(BaseModel): class OutputImage(BaseModel): + """The image output from the code interpreter.""" + type: Literal["image"] """The type of the output. Always `image`.""" @@ -29,6 +33,8 @@ class OutputImage(BaseModel): class ResponseCodeInterpreterToolCall(BaseModel): + """A tool call to run code.""" + id: str """The unique ID of the code interpreter tool call.""" diff --git a/src/openai/types/responses/response_code_interpreter_tool_call_param.py b/src/openai/types/responses/response_code_interpreter_tool_call_param.py index d402b872a4..fc03a3fe48 100644 --- a/src/openai/types/responses/response_code_interpreter_tool_call_param.py +++ b/src/openai/types/responses/response_code_interpreter_tool_call_param.py @@ -9,6 +9,8 @@ class OutputLogs(TypedDict, total=False): + """The logs output from the code interpreter.""" + logs: Required[str] """The logs output from the code interpreter.""" @@ -17,6 +19,8 @@ class OutputLogs(TypedDict, total=False): class OutputImage(TypedDict, total=False): + """The image output from the code interpreter.""" + type: Required[Literal["image"]] """The type of the output. Always `image`.""" @@ -28,6 +32,8 @@ class OutputImage(TypedDict, total=False): class ResponseCodeInterpreterToolCallParam(TypedDict, total=False): + """A tool call to run code.""" + id: Required[str] """The unique ID of the code interpreter tool call.""" diff --git a/src/openai/types/responses/response_compact_params.py b/src/openai/types/responses/response_compact_params.py index fe38b15a9d..35a390f807 100644 --- a/src/openai/types/responses/response_compact_params.py +++ b/src/openai/types/responses/response_compact_params.py @@ -3,7 +3,7 @@ from __future__ import annotations from typing import Union, Iterable, Optional -from typing_extensions import Literal, TypedDict +from typing_extensions import Literal, Required, TypedDict from .response_input_item_param import ResponseInputItemParam @@ -11,6 +11,103 @@ class ResponseCompactParams(TypedDict, total=False): + model: Required[ + Union[ + Literal[ + "gpt-5.1", + "gpt-5.1-2025-11-13", + "gpt-5.1-codex", + "gpt-5.1-mini", + "gpt-5.1-chat-latest", + "gpt-5", + "gpt-5-mini", + "gpt-5-nano", + "gpt-5-2025-08-07", + "gpt-5-mini-2025-08-07", + "gpt-5-nano-2025-08-07", + "gpt-5-chat-latest", + "gpt-4.1", + "gpt-4.1-mini", + "gpt-4.1-nano", + "gpt-4.1-2025-04-14", + "gpt-4.1-mini-2025-04-14", + "gpt-4.1-nano-2025-04-14", + "o4-mini", + "o4-mini-2025-04-16", + "o3", + "o3-2025-04-16", + "o3-mini", + "o3-mini-2025-01-31", + "o1", + "o1-2024-12-17", + "o1-preview", + "o1-preview-2024-09-12", + "o1-mini", + "o1-mini-2024-09-12", + "gpt-4o", + "gpt-4o-2024-11-20", + "gpt-4o-2024-08-06", + "gpt-4o-2024-05-13", + "gpt-4o-audio-preview", + "gpt-4o-audio-preview-2024-10-01", + "gpt-4o-audio-preview-2024-12-17", + "gpt-4o-audio-preview-2025-06-03", + "gpt-4o-mini-audio-preview", + "gpt-4o-mini-audio-preview-2024-12-17", + "gpt-4o-search-preview", + "gpt-4o-mini-search-preview", + "gpt-4o-search-preview-2025-03-11", + "gpt-4o-mini-search-preview-2025-03-11", + "chatgpt-4o-latest", + "codex-mini-latest", + "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-0301", + "gpt-3.5-turbo-0613", + "gpt-3.5-turbo-1106", + "gpt-3.5-turbo-0125", + "gpt-3.5-turbo-16k-0613", + "o1-pro", + "o1-pro-2025-03-19", + "o3-pro", + "o3-pro-2025-06-10", + "o3-deep-research", + "o3-deep-research-2025-06-26", + "o4-mini-deep-research", + "o4-mini-deep-research-2025-06-26", + "computer-use-preview", + "computer-use-preview-2025-03-11", + "gpt-5-codex", + "gpt-5-pro", + "gpt-5-pro-2025-10-06", + "gpt-5.1-codex-max", + ], + str, + None, + ] + ] + """Model ID used to generate the response, like `gpt-5` or `o3`. + + OpenAI offers a wide range of models with different capabilities, performance + characteristics, and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + """ + input: Union[str, Iterable[ResponseInputItemParam], None] """Text, image, or file inputs to the model, used to generate a response""" @@ -22,101 +119,6 @@ class ResponseCompactParams(TypedDict, total=False): system (or developer) messages in new responses. """ - model: Union[ - Literal[ - "gpt-5.1", - "gpt-5.1-2025-11-13", - "gpt-5.1-codex", - "gpt-5.1-mini", - "gpt-5.1-chat-latest", - "gpt-5", - "gpt-5-mini", - "gpt-5-nano", - "gpt-5-2025-08-07", - "gpt-5-mini-2025-08-07", - "gpt-5-nano-2025-08-07", - "gpt-5-chat-latest", - "gpt-4.1", - "gpt-4.1-mini", - "gpt-4.1-nano", - "gpt-4.1-2025-04-14", - "gpt-4.1-mini-2025-04-14", - "gpt-4.1-nano-2025-04-14", - "o4-mini", - "o4-mini-2025-04-16", - "o3", - "o3-2025-04-16", - "o3-mini", - "o3-mini-2025-01-31", - "o1", - "o1-2024-12-17", - "o1-preview", - "o1-preview-2024-09-12", - "o1-mini", - "o1-mini-2024-09-12", - "gpt-4o", - "gpt-4o-2024-11-20", - "gpt-4o-2024-08-06", - "gpt-4o-2024-05-13", - "gpt-4o-audio-preview", - "gpt-4o-audio-preview-2024-10-01", - "gpt-4o-audio-preview-2024-12-17", - "gpt-4o-audio-preview-2025-06-03", - "gpt-4o-mini-audio-preview", - "gpt-4o-mini-audio-preview-2024-12-17", - "gpt-4o-search-preview", - "gpt-4o-mini-search-preview", - "gpt-4o-search-preview-2025-03-11", - "gpt-4o-mini-search-preview-2025-03-11", - "chatgpt-4o-latest", - "codex-mini-latest", - "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-0301", - "gpt-3.5-turbo-0613", - "gpt-3.5-turbo-1106", - "gpt-3.5-turbo-0125", - "gpt-3.5-turbo-16k-0613", - "o1-pro", - "o1-pro-2025-03-19", - "o3-pro", - "o3-pro-2025-06-10", - "o3-deep-research", - "o3-deep-research-2025-06-26", - "o4-mini-deep-research", - "o4-mini-deep-research-2025-06-26", - "computer-use-preview", - "computer-use-preview-2025-03-11", - "gpt-5-codex", - "gpt-5-pro", - "gpt-5-pro-2025-10-06", - "gpt-5.1-codex-max", - ], - str, - None, - ] - """Model ID used to generate the response, like `gpt-5` or `o3`. - - OpenAI offers a wide range of models with different capabilities, performance - characteristics, and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - """ - previous_response_id: Optional[str] """The unique ID of the previous response to the model. diff --git a/src/openai/types/responses/response_compaction_item.py b/src/openai/types/responses/response_compaction_item.py index dc5f839bb8..f5f8b97f4e 100644 --- a/src/openai/types/responses/response_compaction_item.py +++ b/src/openai/types/responses/response_compaction_item.py @@ -9,6 +9,10 @@ class ResponseCompactionItem(BaseModel): + """ + A compaction item generated by the [`v1/responses/compact` API](https://platform.openai.com/docs/api-reference/responses/compact). + """ + id: str """The unique ID of the compaction item.""" diff --git a/src/openai/types/responses/response_compaction_item_param.py b/src/openai/types/responses/response_compaction_item_param.py index 8fdc2a561a..5dcc921d67 100644 --- a/src/openai/types/responses/response_compaction_item_param.py +++ b/src/openai/types/responses/response_compaction_item_param.py @@ -9,6 +9,10 @@ class ResponseCompactionItemParam(BaseModel): + """ + A compaction item generated by the [`v1/responses/compact` API](https://platform.openai.com/docs/api-reference/responses/compact). + """ + encrypted_content: str type: Literal["compaction"] diff --git a/src/openai/types/responses/response_compaction_item_param_param.py b/src/openai/types/responses/response_compaction_item_param_param.py index 0d12296589..b9b5ab031c 100644 --- a/src/openai/types/responses/response_compaction_item_param_param.py +++ b/src/openai/types/responses/response_compaction_item_param_param.py @@ -9,6 +9,10 @@ class ResponseCompactionItemParamParam(TypedDict, total=False): + """ + A compaction item generated by the [`v1/responses/compact` API](https://platform.openai.com/docs/api-reference/responses/compact). + """ + encrypted_content: Required[str] type: Required[Literal["compaction"]] diff --git a/src/openai/types/responses/response_completed_event.py b/src/openai/types/responses/response_completed_event.py index 8a2bd51f75..6dc958101c 100644 --- a/src/openai/types/responses/response_completed_event.py +++ b/src/openai/types/responses/response_completed_event.py @@ -9,6 +9,8 @@ class ResponseCompletedEvent(BaseModel): + """Emitted when the model response is complete.""" + response: Response """Properties of the completed response.""" diff --git a/src/openai/types/responses/response_computer_tool_call.py b/src/openai/types/responses/response_computer_tool_call.py index f1476fa0fb..4e1b3cf7fd 100644 --- a/src/openai/types/responses/response_computer_tool_call.py +++ b/src/openai/types/responses/response_computer_tool_call.py @@ -24,6 +24,8 @@ class ActionClick(BaseModel): + """A click action.""" + button: Literal["left", "right", "wheel", "back", "forward"] """Indicates which mouse button was pressed during the click. @@ -41,6 +43,8 @@ class ActionClick(BaseModel): class ActionDoubleClick(BaseModel): + """A double click action.""" + type: Literal["double_click"] """Specifies the event type. @@ -55,6 +59,8 @@ class ActionDoubleClick(BaseModel): class ActionDragPath(BaseModel): + """An x/y coordinate pair, e.g. `{ x: 100, y: 200 }`.""" + x: int """The x-coordinate.""" @@ -63,6 +69,8 @@ class ActionDragPath(BaseModel): class ActionDrag(BaseModel): + """A drag action.""" + path: List[ActionDragPath] """An array of coordinates representing the path of the drag action. @@ -84,6 +92,8 @@ class ActionDrag(BaseModel): class ActionKeypress(BaseModel): + """A collection of keypresses the model would like to perform.""" + keys: List[str] """The combination of keys the model is requesting to be pressed. @@ -98,6 +108,8 @@ class ActionKeypress(BaseModel): class ActionMove(BaseModel): + """A mouse move action.""" + type: Literal["move"] """Specifies the event type. @@ -112,6 +124,8 @@ class ActionMove(BaseModel): class ActionScreenshot(BaseModel): + """A screenshot action.""" + type: Literal["screenshot"] """Specifies the event type. @@ -120,6 +134,8 @@ class ActionScreenshot(BaseModel): class ActionScroll(BaseModel): + """A scroll action.""" + scroll_x: int """The horizontal scroll distance.""" @@ -140,6 +156,8 @@ class ActionScroll(BaseModel): class ActionType(BaseModel): + """An action to type in text.""" + text: str """The text to type.""" @@ -151,6 +169,8 @@ class ActionType(BaseModel): class ActionWait(BaseModel): + """A wait action.""" + type: Literal["wait"] """Specifies the event type. @@ -175,6 +195,8 @@ class ActionWait(BaseModel): class PendingSafetyCheck(BaseModel): + """A pending safety check for the computer call.""" + id: str """The ID of the pending safety check.""" @@ -186,6 +208,12 @@ class PendingSafetyCheck(BaseModel): class ResponseComputerToolCall(BaseModel): + """A tool call to a computer use tool. + + See the + [computer use guide](https://platform.openai.com/docs/guides/tools-computer-use) for more information. + """ + id: str """The unique ID of the computer call.""" diff --git a/src/openai/types/responses/response_computer_tool_call_output_item.py b/src/openai/types/responses/response_computer_tool_call_output_item.py index e1ac358cc6..90e935c3bd 100644 --- a/src/openai/types/responses/response_computer_tool_call_output_item.py +++ b/src/openai/types/responses/response_computer_tool_call_output_item.py @@ -10,6 +10,8 @@ class AcknowledgedSafetyCheck(BaseModel): + """A pending safety check for the computer call.""" + id: str """The ID of the pending safety check.""" diff --git a/src/openai/types/responses/response_computer_tool_call_output_screenshot.py b/src/openai/types/responses/response_computer_tool_call_output_screenshot.py index a500da85c1..2c16f215eb 100644 --- a/src/openai/types/responses/response_computer_tool_call_output_screenshot.py +++ b/src/openai/types/responses/response_computer_tool_call_output_screenshot.py @@ -9,6 +9,8 @@ class ResponseComputerToolCallOutputScreenshot(BaseModel): + """A computer screenshot image used with the computer use tool.""" + type: Literal["computer_screenshot"] """Specifies the event type. diff --git a/src/openai/types/responses/response_computer_tool_call_output_screenshot_param.py b/src/openai/types/responses/response_computer_tool_call_output_screenshot_param.py index efc2028aa4..857ccf9fb9 100644 --- a/src/openai/types/responses/response_computer_tool_call_output_screenshot_param.py +++ b/src/openai/types/responses/response_computer_tool_call_output_screenshot_param.py @@ -8,6 +8,8 @@ class ResponseComputerToolCallOutputScreenshotParam(TypedDict, total=False): + """A computer screenshot image used with the computer use tool.""" + type: Required[Literal["computer_screenshot"]] """Specifies the event type. diff --git a/src/openai/types/responses/response_computer_tool_call_param.py b/src/openai/types/responses/response_computer_tool_call_param.py index 228f76bac9..550ba599cd 100644 --- a/src/openai/types/responses/response_computer_tool_call_param.py +++ b/src/openai/types/responses/response_computer_tool_call_param.py @@ -25,6 +25,8 @@ class ActionClick(TypedDict, total=False): + """A click action.""" + button: Required[Literal["left", "right", "wheel", "back", "forward"]] """Indicates which mouse button was pressed during the click. @@ -42,6 +44,8 @@ class ActionClick(TypedDict, total=False): class ActionDoubleClick(TypedDict, total=False): + """A double click action.""" + type: Required[Literal["double_click"]] """Specifies the event type. @@ -56,6 +60,8 @@ class ActionDoubleClick(TypedDict, total=False): class ActionDragPath(TypedDict, total=False): + """An x/y coordinate pair, e.g. `{ x: 100, y: 200 }`.""" + x: Required[int] """The x-coordinate.""" @@ -64,6 +70,8 @@ class ActionDragPath(TypedDict, total=False): class ActionDrag(TypedDict, total=False): + """A drag action.""" + path: Required[Iterable[ActionDragPath]] """An array of coordinates representing the path of the drag action. @@ -85,6 +93,8 @@ class ActionDrag(TypedDict, total=False): class ActionKeypress(TypedDict, total=False): + """A collection of keypresses the model would like to perform.""" + keys: Required[SequenceNotStr[str]] """The combination of keys the model is requesting to be pressed. @@ -99,6 +109,8 @@ class ActionKeypress(TypedDict, total=False): class ActionMove(TypedDict, total=False): + """A mouse move action.""" + type: Required[Literal["move"]] """Specifies the event type. @@ -113,6 +125,8 @@ class ActionMove(TypedDict, total=False): class ActionScreenshot(TypedDict, total=False): + """A screenshot action.""" + type: Required[Literal["screenshot"]] """Specifies the event type. @@ -121,6 +135,8 @@ class ActionScreenshot(TypedDict, total=False): class ActionScroll(TypedDict, total=False): + """A scroll action.""" + scroll_x: Required[int] """The horizontal scroll distance.""" @@ -141,6 +157,8 @@ class ActionScroll(TypedDict, total=False): class ActionType(TypedDict, total=False): + """An action to type in text.""" + text: Required[str] """The text to type.""" @@ -152,6 +170,8 @@ class ActionType(TypedDict, total=False): class ActionWait(TypedDict, total=False): + """A wait action.""" + type: Required[Literal["wait"]] """Specifies the event type. @@ -173,6 +193,8 @@ class ActionWait(TypedDict, total=False): class PendingSafetyCheck(TypedDict, total=False): + """A pending safety check for the computer call.""" + id: Required[str] """The ID of the pending safety check.""" @@ -184,6 +206,12 @@ class PendingSafetyCheck(TypedDict, total=False): class ResponseComputerToolCallParam(TypedDict, total=False): + """A tool call to a computer use tool. + + See the + [computer use guide](https://platform.openai.com/docs/guides/tools-computer-use) for more information. + """ + id: Required[str] """The unique ID of the computer call.""" diff --git a/src/openai/types/responses/response_content_part_added_event.py b/src/openai/types/responses/response_content_part_added_event.py index c78e80d1c4..ec9893159d 100644 --- a/src/openai/types/responses/response_content_part_added_event.py +++ b/src/openai/types/responses/response_content_part_added_event.py @@ -12,6 +12,8 @@ class PartReasoningText(BaseModel): + """Reasoning text from the model.""" + text: str """The reasoning text from the model.""" @@ -25,6 +27,8 @@ class PartReasoningText(BaseModel): class ResponseContentPartAddedEvent(BaseModel): + """Emitted when a new content part is added.""" + content_index: int """The index of the content part that was added.""" diff --git a/src/openai/types/responses/response_content_part_done_event.py b/src/openai/types/responses/response_content_part_done_event.py index 732f2303ef..f896ad8743 100644 --- a/src/openai/types/responses/response_content_part_done_event.py +++ b/src/openai/types/responses/response_content_part_done_event.py @@ -12,6 +12,8 @@ class PartReasoningText(BaseModel): + """Reasoning text from the model.""" + text: str """The reasoning text from the model.""" @@ -25,6 +27,8 @@ class PartReasoningText(BaseModel): class ResponseContentPartDoneEvent(BaseModel): + """Emitted when a content part is done.""" + content_index: int """The index of the content part that is done.""" diff --git a/src/openai/types/responses/response_conversation_param.py b/src/openai/types/responses/response_conversation_param.py index 067bdc7a31..d1587fe68a 100644 --- a/src/openai/types/responses/response_conversation_param.py +++ b/src/openai/types/responses/response_conversation_param.py @@ -8,5 +8,7 @@ class ResponseConversationParam(TypedDict, total=False): + """The conversation that this response belongs to.""" + id: Required[str] """The unique ID of the conversation.""" diff --git a/src/openai/types/responses/response_create_params.py b/src/openai/types/responses/response_create_params.py index 64888ac62d..15844c6597 100644 --- a/src/openai/types/responses/response_create_params.py +++ b/src/openai/types/responses/response_create_params.py @@ -283,6 +283,8 @@ class ResponseCreateParamsBase(TypedDict, total=False): class StreamOptions(TypedDict, total=False): + """Options for streaming responses. Only set this when you set `stream: true`.""" + include_obfuscation: bool """When true, stream obfuscation will be enabled. diff --git a/src/openai/types/responses/response_created_event.py b/src/openai/types/responses/response_created_event.py index 73a9d700d4..308b2f4916 100644 --- a/src/openai/types/responses/response_created_event.py +++ b/src/openai/types/responses/response_created_event.py @@ -9,6 +9,8 @@ class ResponseCreatedEvent(BaseModel): + """An event that is emitted when a response is created.""" + response: Response """The response that was created.""" diff --git a/src/openai/types/responses/response_custom_tool_call.py b/src/openai/types/responses/response_custom_tool_call.py index 38c650e662..f05743966e 100644 --- a/src/openai/types/responses/response_custom_tool_call.py +++ b/src/openai/types/responses/response_custom_tool_call.py @@ -9,6 +9,8 @@ class ResponseCustomToolCall(BaseModel): + """A call to a custom tool created by the model.""" + call_id: str """An identifier used to map this custom tool call to a tool call output.""" diff --git a/src/openai/types/responses/response_custom_tool_call_input_delta_event.py b/src/openai/types/responses/response_custom_tool_call_input_delta_event.py index 6c33102d75..7473d33d9a 100644 --- a/src/openai/types/responses/response_custom_tool_call_input_delta_event.py +++ b/src/openai/types/responses/response_custom_tool_call_input_delta_event.py @@ -8,6 +8,8 @@ class ResponseCustomToolCallInputDeltaEvent(BaseModel): + """Event representing a delta (partial update) to the input of a custom tool call.""" + delta: str """The incremental input data (delta) for the custom tool call.""" diff --git a/src/openai/types/responses/response_custom_tool_call_input_done_event.py b/src/openai/types/responses/response_custom_tool_call_input_done_event.py index 35a2fee22b..be47ae8e96 100644 --- a/src/openai/types/responses/response_custom_tool_call_input_done_event.py +++ b/src/openai/types/responses/response_custom_tool_call_input_done_event.py @@ -8,6 +8,8 @@ class ResponseCustomToolCallInputDoneEvent(BaseModel): + """Event indicating that input for a custom tool call is complete.""" + input: str """The complete input data for the custom tool call.""" diff --git a/src/openai/types/responses/response_custom_tool_call_output.py b/src/openai/types/responses/response_custom_tool_call_output.py index 9db9e7e5cf..833956493b 100644 --- a/src/openai/types/responses/response_custom_tool_call_output.py +++ b/src/openai/types/responses/response_custom_tool_call_output.py @@ -17,6 +17,8 @@ class ResponseCustomToolCallOutput(BaseModel): + """The output of a custom tool call from your code, being sent back to the model.""" + call_id: str """The call ID, used to map this custom tool call output to a custom tool call.""" diff --git a/src/openai/types/responses/response_custom_tool_call_output_param.py b/src/openai/types/responses/response_custom_tool_call_output_param.py index e967a37cff..db0034216a 100644 --- a/src/openai/types/responses/response_custom_tool_call_output_param.py +++ b/src/openai/types/responses/response_custom_tool_call_output_param.py @@ -15,6 +15,8 @@ class ResponseCustomToolCallOutputParam(TypedDict, total=False): + """The output of a custom tool call from your code, being sent back to the model.""" + call_id: Required[str] """The call ID, used to map this custom tool call output to a custom tool call.""" diff --git a/src/openai/types/responses/response_custom_tool_call_param.py b/src/openai/types/responses/response_custom_tool_call_param.py index e15beac29f..5d4ce3376c 100644 --- a/src/openai/types/responses/response_custom_tool_call_param.py +++ b/src/openai/types/responses/response_custom_tool_call_param.py @@ -8,6 +8,8 @@ class ResponseCustomToolCallParam(TypedDict, total=False): + """A call to a custom tool created by the model.""" + call_id: Required[str] """An identifier used to map this custom tool call to a tool call output.""" diff --git a/src/openai/types/responses/response_error.py b/src/openai/types/responses/response_error.py index 90f1fcf5da..90958d1c13 100644 --- a/src/openai/types/responses/response_error.py +++ b/src/openai/types/responses/response_error.py @@ -8,6 +8,8 @@ class ResponseError(BaseModel): + """An error object returned when the model fails to generate a Response.""" + code: Literal[ "server_error", "rate_limit_exceeded", diff --git a/src/openai/types/responses/response_error_event.py b/src/openai/types/responses/response_error_event.py index 826c395125..1789f731b4 100644 --- a/src/openai/types/responses/response_error_event.py +++ b/src/openai/types/responses/response_error_event.py @@ -9,6 +9,8 @@ class ResponseErrorEvent(BaseModel): + """Emitted when an error occurs.""" + code: Optional[str] = None """The error code.""" diff --git a/src/openai/types/responses/response_failed_event.py b/src/openai/types/responses/response_failed_event.py index cdd3d7d808..2232c9678d 100644 --- a/src/openai/types/responses/response_failed_event.py +++ b/src/openai/types/responses/response_failed_event.py @@ -9,6 +9,8 @@ class ResponseFailedEvent(BaseModel): + """An event that is emitted when a response fails.""" + response: Response """The response that failed.""" diff --git a/src/openai/types/responses/response_file_search_call_completed_event.py b/src/openai/types/responses/response_file_search_call_completed_event.py index 08e51b2d3f..88ffa5ac56 100644 --- a/src/openai/types/responses/response_file_search_call_completed_event.py +++ b/src/openai/types/responses/response_file_search_call_completed_event.py @@ -8,6 +8,8 @@ class ResponseFileSearchCallCompletedEvent(BaseModel): + """Emitted when a file search call is completed (results found).""" + item_id: str """The ID of the output item that the file search call is initiated.""" diff --git a/src/openai/types/responses/response_file_search_call_in_progress_event.py b/src/openai/types/responses/response_file_search_call_in_progress_event.py index 63840a649f..4f3504fda4 100644 --- a/src/openai/types/responses/response_file_search_call_in_progress_event.py +++ b/src/openai/types/responses/response_file_search_call_in_progress_event.py @@ -8,6 +8,8 @@ class ResponseFileSearchCallInProgressEvent(BaseModel): + """Emitted when a file search call is initiated.""" + item_id: str """The ID of the output item that the file search call is initiated.""" diff --git a/src/openai/types/responses/response_file_search_call_searching_event.py b/src/openai/types/responses/response_file_search_call_searching_event.py index 706c8c57ad..5bf1a076dd 100644 --- a/src/openai/types/responses/response_file_search_call_searching_event.py +++ b/src/openai/types/responses/response_file_search_call_searching_event.py @@ -8,6 +8,8 @@ class ResponseFileSearchCallSearchingEvent(BaseModel): + """Emitted when a file search is currently searching.""" + item_id: str """The ID of the output item that the file search call is initiated.""" diff --git a/src/openai/types/responses/response_file_search_tool_call.py b/src/openai/types/responses/response_file_search_tool_call.py index ef1c6a5608..fa45631345 100644 --- a/src/openai/types/responses/response_file_search_tool_call.py +++ b/src/openai/types/responses/response_file_search_tool_call.py @@ -32,6 +32,12 @@ class Result(BaseModel): class ResponseFileSearchToolCall(BaseModel): + """The results of a file search tool call. + + See the + [file search guide](https://platform.openai.com/docs/guides/tools-file-search) for more information. + """ + id: str """The unique ID of the file search tool call.""" diff --git a/src/openai/types/responses/response_file_search_tool_call_param.py b/src/openai/types/responses/response_file_search_tool_call_param.py index 4903dca4fb..45a5bbb486 100644 --- a/src/openai/types/responses/response_file_search_tool_call_param.py +++ b/src/openai/types/responses/response_file_search_tool_call_param.py @@ -34,6 +34,12 @@ class Result(TypedDict, total=False): class ResponseFileSearchToolCallParam(TypedDict, total=False): + """The results of a file search tool call. + + See the + [file search guide](https://platform.openai.com/docs/guides/tools-file-search) for more information. + """ + id: Required[str] """The unique ID of the file search tool call.""" diff --git a/src/openai/types/responses/response_format_text_json_schema_config.py b/src/openai/types/responses/response_format_text_json_schema_config.py index 001fcf5bab..b953112621 100644 --- a/src/openai/types/responses/response_format_text_json_schema_config.py +++ b/src/openai/types/responses/response_format_text_json_schema_config.py @@ -11,6 +11,12 @@ class ResponseFormatTextJSONSchemaConfig(BaseModel): + """JSON Schema response format. + + Used to generate structured JSON responses. + Learn more about [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs). + """ + name: str """The name of the response format. diff --git a/src/openai/types/responses/response_format_text_json_schema_config_param.py b/src/openai/types/responses/response_format_text_json_schema_config_param.py index f293a80c5a..6f5c633106 100644 --- a/src/openai/types/responses/response_format_text_json_schema_config_param.py +++ b/src/openai/types/responses/response_format_text_json_schema_config_param.py @@ -9,6 +9,12 @@ class ResponseFormatTextJSONSchemaConfigParam(TypedDict, total=False): + """JSON Schema response format. + + Used to generate structured JSON responses. + Learn more about [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs). + """ + name: Required[str] """The name of the response format. diff --git a/src/openai/types/responses/response_function_call_arguments_delta_event.py b/src/openai/types/responses/response_function_call_arguments_delta_event.py index c6bc5dfad7..0798c2e123 100644 --- a/src/openai/types/responses/response_function_call_arguments_delta_event.py +++ b/src/openai/types/responses/response_function_call_arguments_delta_event.py @@ -8,6 +8,8 @@ class ResponseFunctionCallArgumentsDeltaEvent(BaseModel): + """Emitted when there is a partial function-call arguments delta.""" + delta: str """The function-call arguments delta that is added.""" diff --git a/src/openai/types/responses/response_function_call_arguments_done_event.py b/src/openai/types/responses/response_function_call_arguments_done_event.py index 4ee5ed7fe1..543cd073a2 100644 --- a/src/openai/types/responses/response_function_call_arguments_done_event.py +++ b/src/openai/types/responses/response_function_call_arguments_done_event.py @@ -8,6 +8,8 @@ class ResponseFunctionCallArgumentsDoneEvent(BaseModel): + """Emitted when function-call arguments are finalized.""" + arguments: str """The function-call arguments.""" diff --git a/src/openai/types/responses/response_function_shell_call_output_content.py b/src/openai/types/responses/response_function_shell_call_output_content.py index e0e2c09ad1..dae48f14da 100644 --- a/src/openai/types/responses/response_function_shell_call_output_content.py +++ b/src/openai/types/responses/response_function_shell_call_output_content.py @@ -10,11 +10,15 @@ class OutcomeTimeout(BaseModel): + """Indicates that the shell call exceeded its configured time limit.""" + type: Literal["timeout"] """The outcome type. Always `timeout`.""" class OutcomeExit(BaseModel): + """Indicates that the shell commands finished and returned an exit code.""" + exit_code: int """The exit code returned by the shell process.""" @@ -26,6 +30,8 @@ class OutcomeExit(BaseModel): class ResponseFunctionShellCallOutputContent(BaseModel): + """Captured stdout and stderr for a portion of a shell tool call output.""" + outcome: Outcome """The exit or timeout outcome associated with this shell call.""" diff --git a/src/openai/types/responses/response_function_shell_call_output_content_param.py b/src/openai/types/responses/response_function_shell_call_output_content_param.py index fa065bd4b5..4d8ea70d08 100644 --- a/src/openai/types/responses/response_function_shell_call_output_content_param.py +++ b/src/openai/types/responses/response_function_shell_call_output_content_param.py @@ -9,11 +9,15 @@ class OutcomeTimeout(TypedDict, total=False): + """Indicates that the shell call exceeded its configured time limit.""" + type: Required[Literal["timeout"]] """The outcome type. Always `timeout`.""" class OutcomeExit(TypedDict, total=False): + """Indicates that the shell commands finished and returned an exit code.""" + exit_code: Required[int] """The exit code returned by the shell process.""" @@ -25,6 +29,8 @@ class OutcomeExit(TypedDict, total=False): class ResponseFunctionShellCallOutputContentParam(TypedDict, total=False): + """Captured stdout and stderr for a portion of a shell tool call output.""" + outcome: Required[Outcome] """The exit or timeout outcome associated with this shell call.""" diff --git a/src/openai/types/responses/response_function_shell_tool_call.py b/src/openai/types/responses/response_function_shell_tool_call.py index de42cb0640..7c6a184ed4 100644 --- a/src/openai/types/responses/response_function_shell_tool_call.py +++ b/src/openai/types/responses/response_function_shell_tool_call.py @@ -9,6 +9,8 @@ class Action(BaseModel): + """The shell commands and limits that describe how to run the tool call.""" + commands: List[str] max_output_length: Optional[int] = None @@ -19,6 +21,8 @@ class Action(BaseModel): class ResponseFunctionShellToolCall(BaseModel): + """A tool call that executes one or more shell commands in a managed environment.""" + id: str """The unique ID of the shell tool call. diff --git a/src/openai/types/responses/response_function_shell_tool_call_output.py b/src/openai/types/responses/response_function_shell_tool_call_output.py index e74927df41..7885ee2f83 100644 --- a/src/openai/types/responses/response_function_shell_tool_call_output.py +++ b/src/openai/types/responses/response_function_shell_tool_call_output.py @@ -16,11 +16,15 @@ class OutputOutcomeTimeout(BaseModel): + """Indicates that the shell call exceeded its configured time limit.""" + type: Literal["timeout"] """The outcome type. Always `timeout`.""" class OutputOutcomeExit(BaseModel): + """Indicates that the shell commands finished and returned an exit code.""" + exit_code: int """Exit code from the shell process.""" @@ -32,6 +36,8 @@ class OutputOutcomeExit(BaseModel): class Output(BaseModel): + """The content of a shell call output.""" + outcome: OutputOutcome """ Represents either an exit outcome (with an exit code) or a timeout outcome for a @@ -46,6 +52,8 @@ class Output(BaseModel): class ResponseFunctionShellToolCallOutput(BaseModel): + """The output of a shell tool call.""" + id: str """The unique ID of the shell call output. diff --git a/src/openai/types/responses/response_function_tool_call.py b/src/openai/types/responses/response_function_tool_call.py index 2a8482204e..194e3f7d6a 100644 --- a/src/openai/types/responses/response_function_tool_call.py +++ b/src/openai/types/responses/response_function_tool_call.py @@ -9,6 +9,12 @@ class ResponseFunctionToolCall(BaseModel): + """A tool call to run a function. + + See the + [function calling guide](https://platform.openai.com/docs/guides/function-calling) for more information. + """ + arguments: str """A JSON string of the arguments to pass to the function.""" diff --git a/src/openai/types/responses/response_function_tool_call_item.py b/src/openai/types/responses/response_function_tool_call_item.py index 762015a4b1..3df299e512 100644 --- a/src/openai/types/responses/response_function_tool_call_item.py +++ b/src/openai/types/responses/response_function_tool_call_item.py @@ -6,5 +6,11 @@ class ResponseFunctionToolCallItem(ResponseFunctionToolCall): + """A tool call to run a function. + + See the + [function calling guide](https://platform.openai.com/docs/guides/function-calling) for more information. + """ + id: str # type: ignore """The unique ID of the function tool call.""" diff --git a/src/openai/types/responses/response_function_tool_call_param.py b/src/openai/types/responses/response_function_tool_call_param.py index eaa263cf67..4e8dd3d629 100644 --- a/src/openai/types/responses/response_function_tool_call_param.py +++ b/src/openai/types/responses/response_function_tool_call_param.py @@ -8,6 +8,12 @@ class ResponseFunctionToolCallParam(TypedDict, total=False): + """A tool call to run a function. + + See the + [function calling guide](https://platform.openai.com/docs/guides/function-calling) for more information. + """ + arguments: Required[str] """A JSON string of the arguments to pass to the function.""" diff --git a/src/openai/types/responses/response_function_web_search.py b/src/openai/types/responses/response_function_web_search.py index f3e80e6a8f..1450fba4d1 100644 --- a/src/openai/types/responses/response_function_web_search.py +++ b/src/openai/types/responses/response_function_web_search.py @@ -10,6 +10,8 @@ class ActionSearchSource(BaseModel): + """A source used in the search.""" + type: Literal["url"] """The type of source. Always `url`.""" @@ -18,6 +20,8 @@ class ActionSearchSource(BaseModel): class ActionSearch(BaseModel): + """Action type "search" - Performs a web search query.""" + query: str """The search query.""" @@ -29,6 +33,8 @@ class ActionSearch(BaseModel): class ActionOpenPage(BaseModel): + """Action type "open_page" - Opens a specific URL from search results.""" + type: Literal["open_page"] """The action type.""" @@ -37,6 +43,8 @@ class ActionOpenPage(BaseModel): class ActionFind(BaseModel): + """Action type "find": Searches for a pattern within a loaded page.""" + pattern: str """The pattern or text to search for within the page.""" @@ -51,6 +59,12 @@ class ActionFind(BaseModel): class ResponseFunctionWebSearch(BaseModel): + """The results of a web search tool call. + + See the + [web search guide](https://platform.openai.com/docs/guides/tools-web-search) for more information. + """ + id: str """The unique ID of the web search tool call.""" diff --git a/src/openai/types/responses/response_function_web_search_param.py b/src/openai/types/responses/response_function_web_search_param.py index fc019d3eb7..8d0b60334d 100644 --- a/src/openai/types/responses/response_function_web_search_param.py +++ b/src/openai/types/responses/response_function_web_search_param.py @@ -16,6 +16,8 @@ class ActionSearchSource(TypedDict, total=False): + """A source used in the search.""" + type: Required[Literal["url"]] """The type of source. Always `url`.""" @@ -24,6 +26,8 @@ class ActionSearchSource(TypedDict, total=False): class ActionSearch(TypedDict, total=False): + """Action type "search" - Performs a web search query.""" + query: Required[str] """The search query.""" @@ -35,6 +39,8 @@ class ActionSearch(TypedDict, total=False): class ActionOpenPage(TypedDict, total=False): + """Action type "open_page" - Opens a specific URL from search results.""" + type: Required[Literal["open_page"]] """The action type.""" @@ -43,6 +49,8 @@ class ActionOpenPage(TypedDict, total=False): class ActionFind(TypedDict, total=False): + """Action type "find": Searches for a pattern within a loaded page.""" + pattern: Required[str] """The pattern or text to search for within the page.""" @@ -57,6 +65,12 @@ class ActionFind(TypedDict, total=False): class ResponseFunctionWebSearchParam(TypedDict, total=False): + """The results of a web search tool call. + + See the + [web search guide](https://platform.openai.com/docs/guides/tools-web-search) for more information. + """ + id: Required[str] """The unique ID of the web search tool call.""" diff --git a/src/openai/types/responses/response_image_gen_call_completed_event.py b/src/openai/types/responses/response_image_gen_call_completed_event.py index a554273ed0..f6ce9d0fd8 100644 --- a/src/openai/types/responses/response_image_gen_call_completed_event.py +++ b/src/openai/types/responses/response_image_gen_call_completed_event.py @@ -8,6 +8,10 @@ class ResponseImageGenCallCompletedEvent(BaseModel): + """ + Emitted when an image generation tool call has completed and the final image is available. + """ + item_id: str """The unique identifier of the image generation item being processed.""" diff --git a/src/openai/types/responses/response_image_gen_call_generating_event.py b/src/openai/types/responses/response_image_gen_call_generating_event.py index 74b4f57333..8e3026d0dc 100644 --- a/src/openai/types/responses/response_image_gen_call_generating_event.py +++ b/src/openai/types/responses/response_image_gen_call_generating_event.py @@ -8,6 +8,10 @@ class ResponseImageGenCallGeneratingEvent(BaseModel): + """ + Emitted when an image generation tool call is actively generating an image (intermediate state). + """ + item_id: str """The unique identifier of the image generation item being processed.""" diff --git a/src/openai/types/responses/response_image_gen_call_in_progress_event.py b/src/openai/types/responses/response_image_gen_call_in_progress_event.py index b36ff5fa47..60726a22b4 100644 --- a/src/openai/types/responses/response_image_gen_call_in_progress_event.py +++ b/src/openai/types/responses/response_image_gen_call_in_progress_event.py @@ -8,6 +8,8 @@ class ResponseImageGenCallInProgressEvent(BaseModel): + """Emitted when an image generation tool call is in progress.""" + item_id: str """The unique identifier of the image generation item being processed.""" diff --git a/src/openai/types/responses/response_image_gen_call_partial_image_event.py b/src/openai/types/responses/response_image_gen_call_partial_image_event.py index e69c95fb33..289d5d44c0 100644 --- a/src/openai/types/responses/response_image_gen_call_partial_image_event.py +++ b/src/openai/types/responses/response_image_gen_call_partial_image_event.py @@ -8,6 +8,8 @@ class ResponseImageGenCallPartialImageEvent(BaseModel): + """Emitted when a partial image is available during image generation streaming.""" + item_id: str """The unique identifier of the image generation item being processed.""" diff --git a/src/openai/types/responses/response_in_progress_event.py b/src/openai/types/responses/response_in_progress_event.py index b82e10b357..9d9bbd94b0 100644 --- a/src/openai/types/responses/response_in_progress_event.py +++ b/src/openai/types/responses/response_in_progress_event.py @@ -9,6 +9,8 @@ class ResponseInProgressEvent(BaseModel): + """Emitted when the response is in progress.""" + response: Response """The response that is in progress.""" diff --git a/src/openai/types/responses/response_incomplete_event.py b/src/openai/types/responses/response_incomplete_event.py index 63c969a428..ef99c5f0b2 100644 --- a/src/openai/types/responses/response_incomplete_event.py +++ b/src/openai/types/responses/response_incomplete_event.py @@ -9,6 +9,8 @@ class ResponseIncompleteEvent(BaseModel): + """An event that is emitted when a response finishes as incomplete.""" + response: Response """The response that was incomplete.""" diff --git a/src/openai/types/responses/response_input_audio.py b/src/openai/types/responses/response_input_audio.py index 9fef6de0fd..f362ba4133 100644 --- a/src/openai/types/responses/response_input_audio.py +++ b/src/openai/types/responses/response_input_audio.py @@ -16,6 +16,8 @@ class InputAudio(BaseModel): class ResponseInputAudio(BaseModel): + """An audio input to the model.""" + input_audio: InputAudio type: Literal["input_audio"] diff --git a/src/openai/types/responses/response_input_audio_param.py b/src/openai/types/responses/response_input_audio_param.py index f3fc913cca..0be935c54d 100644 --- a/src/openai/types/responses/response_input_audio_param.py +++ b/src/openai/types/responses/response_input_audio_param.py @@ -16,6 +16,8 @@ class InputAudio(TypedDict, total=False): class ResponseInputAudioParam(TypedDict, total=False): + """An audio input to the model.""" + input_audio: Required[InputAudio] type: Required[Literal["input_audio"]] diff --git a/src/openai/types/responses/response_input_file.py b/src/openai/types/responses/response_input_file.py index 1eecd6a2b6..3e5fb70c5f 100644 --- a/src/openai/types/responses/response_input_file.py +++ b/src/openai/types/responses/response_input_file.py @@ -9,6 +9,8 @@ class ResponseInputFile(BaseModel): + """A file input to the model.""" + type: Literal["input_file"] """The type of the input item. Always `input_file`.""" diff --git a/src/openai/types/responses/response_input_file_content.py b/src/openai/types/responses/response_input_file_content.py index d832bb0e26..f0dfef55d0 100644 --- a/src/openai/types/responses/response_input_file_content.py +++ b/src/openai/types/responses/response_input_file_content.py @@ -9,6 +9,8 @@ class ResponseInputFileContent(BaseModel): + """A file input to the model.""" + type: Literal["input_file"] """The type of the input item. Always `input_file`.""" diff --git a/src/openai/types/responses/response_input_file_content_param.py b/src/openai/types/responses/response_input_file_content_param.py index 71f7b3a281..376f6c7a45 100644 --- a/src/openai/types/responses/response_input_file_content_param.py +++ b/src/openai/types/responses/response_input_file_content_param.py @@ -9,6 +9,8 @@ class ResponseInputFileContentParam(TypedDict, total=False): + """A file input to the model.""" + type: Required[Literal["input_file"]] """The type of the input item. Always `input_file`.""" diff --git a/src/openai/types/responses/response_input_file_param.py b/src/openai/types/responses/response_input_file_param.py index 0b5f513ec6..8b5da20245 100644 --- a/src/openai/types/responses/response_input_file_param.py +++ b/src/openai/types/responses/response_input_file_param.py @@ -9,6 +9,8 @@ class ResponseInputFileParam(TypedDict, total=False): + """A file input to the model.""" + type: Required[Literal["input_file"]] """The type of the input item. Always `input_file`.""" diff --git a/src/openai/types/responses/response_input_image.py b/src/openai/types/responses/response_input_image.py index f2d760b25e..500bc4b346 100644 --- a/src/openai/types/responses/response_input_image.py +++ b/src/openai/types/responses/response_input_image.py @@ -9,6 +9,11 @@ class ResponseInputImage(BaseModel): + """An image input to the model. + + Learn about [image inputs](https://platform.openai.com/docs/guides/vision). + """ + detail: Literal["low", "high", "auto"] """The detail level of the image to be sent to the model. diff --git a/src/openai/types/responses/response_input_image_content.py b/src/openai/types/responses/response_input_image_content.py index fb90cb57eb..e38bc28d5e 100644 --- a/src/openai/types/responses/response_input_image_content.py +++ b/src/openai/types/responses/response_input_image_content.py @@ -9,6 +9,11 @@ class ResponseInputImageContent(BaseModel): + """An image input to the model. + + Learn about [image inputs](https://platform.openai.com/docs/guides/vision) + """ + type: Literal["input_image"] """The type of the input item. Always `input_image`.""" diff --git a/src/openai/types/responses/response_input_image_content_param.py b/src/openai/types/responses/response_input_image_content_param.py index c51509a3f3..c21f46d736 100644 --- a/src/openai/types/responses/response_input_image_content_param.py +++ b/src/openai/types/responses/response_input_image_content_param.py @@ -9,6 +9,11 @@ class ResponseInputImageContentParam(TypedDict, total=False): + """An image input to the model. + + Learn about [image inputs](https://platform.openai.com/docs/guides/vision) + """ + type: Required[Literal["input_image"]] """The type of the input item. Always `input_image`.""" diff --git a/src/openai/types/responses/response_input_image_param.py b/src/openai/types/responses/response_input_image_param.py index bc17e4f1c2..fd8c1bd070 100644 --- a/src/openai/types/responses/response_input_image_param.py +++ b/src/openai/types/responses/response_input_image_param.py @@ -9,6 +9,11 @@ class ResponseInputImageParam(TypedDict, total=False): + """An image input to the model. + + Learn about [image inputs](https://platform.openai.com/docs/guides/vision). + """ + detail: Required[Literal["low", "high", "auto"]] """The detail level of the image to be sent to the model. diff --git a/src/openai/types/responses/response_input_item.py b/src/openai/types/responses/response_input_item.py index 103c8634ce..23eb2c8950 100644 --- a/src/openai/types/responses/response_input_item.py +++ b/src/openai/types/responses/response_input_item.py @@ -50,6 +50,12 @@ class Message(BaseModel): + """ + A message input to the model with a role indicating instruction following + hierarchy. Instructions given with the `developer` or `system` role take + precedence over instructions given with the `user` role. + """ + content: ResponseInputMessageContentList """ A list of one or many input items to the model, containing different content @@ -71,6 +77,8 @@ class Message(BaseModel): class ComputerCallOutputAcknowledgedSafetyCheck(BaseModel): + """A pending safety check for the computer call.""" + id: str """The ID of the pending safety check.""" @@ -82,6 +90,8 @@ class ComputerCallOutputAcknowledgedSafetyCheck(BaseModel): class ComputerCallOutput(BaseModel): + """The output of a computer tool call.""" + call_id: str """The ID of the computer tool call that produced the output.""" @@ -109,6 +119,8 @@ class ComputerCallOutput(BaseModel): class FunctionCallOutput(BaseModel): + """The output of a function tool call.""" + call_id: str """The unique ID of the function tool call generated by the model.""" @@ -133,6 +145,8 @@ class FunctionCallOutput(BaseModel): class ImageGenerationCall(BaseModel): + """An image generation request made by the model.""" + id: str """The unique ID of the image generation call.""" @@ -147,6 +161,8 @@ class ImageGenerationCall(BaseModel): class LocalShellCallAction(BaseModel): + """Execute a shell command on the server.""" + command: List[str] """The command to run.""" @@ -167,6 +183,8 @@ class LocalShellCallAction(BaseModel): class LocalShellCall(BaseModel): + """A tool call to run a command on the local shell.""" + id: str """The unique ID of the local shell call.""" @@ -184,6 +202,8 @@ class LocalShellCall(BaseModel): class LocalShellCallOutput(BaseModel): + """The output of a local shell tool call.""" + id: str """The unique ID of the local shell tool call generated by the model.""" @@ -198,6 +218,8 @@ class LocalShellCallOutput(BaseModel): class ShellCallAction(BaseModel): + """The shell commands and limits that describe how to run the tool call.""" + commands: List[str] """Ordered shell commands for the execution environment to run.""" @@ -212,6 +234,8 @@ class ShellCallAction(BaseModel): class ShellCall(BaseModel): + """A tool representing a request to execute one or more shell commands.""" + action: ShellCallAction """The shell commands and limits that describe how to run the tool call.""" @@ -235,6 +259,8 @@ class ShellCall(BaseModel): class ShellCallOutput(BaseModel): + """The streamed output items emitted by a shell tool call.""" + call_id: str """The unique ID of the shell tool call generated by the model.""" @@ -261,6 +287,8 @@ class ShellCallOutput(BaseModel): class ApplyPatchCallOperationCreateFile(BaseModel): + """Instruction for creating a new file via the apply_patch tool.""" + diff: str """Unified diff content to apply when creating the file.""" @@ -272,6 +300,8 @@ class ApplyPatchCallOperationCreateFile(BaseModel): class ApplyPatchCallOperationDeleteFile(BaseModel): + """Instruction for deleting an existing file via the apply_patch tool.""" + path: str """Path of the file to delete relative to the workspace root.""" @@ -280,6 +310,8 @@ class ApplyPatchCallOperationDeleteFile(BaseModel): class ApplyPatchCallOperationUpdateFile(BaseModel): + """Instruction for updating an existing file via the apply_patch tool.""" + diff: str """Unified diff content to apply to the existing file.""" @@ -297,6 +329,10 @@ class ApplyPatchCallOperationUpdateFile(BaseModel): class ApplyPatchCall(BaseModel): + """ + A tool call representing a request to create, delete, or update files using diff patches. + """ + call_id: str """The unique ID of the apply patch tool call generated by the model.""" @@ -320,6 +356,8 @@ class ApplyPatchCall(BaseModel): class ApplyPatchCallOutput(BaseModel): + """The streamed output emitted by an apply patch tool call.""" + call_id: str """The unique ID of the apply patch tool call generated by the model.""" @@ -343,6 +381,8 @@ class ApplyPatchCallOutput(BaseModel): class McpListToolsTool(BaseModel): + """A tool available on an MCP server.""" + input_schema: object """The JSON schema describing the tool's input.""" @@ -357,6 +397,8 @@ class McpListToolsTool(BaseModel): class McpListTools(BaseModel): + """A list of tools available on an MCP server.""" + id: str """The unique ID of the list.""" @@ -374,6 +416,8 @@ class McpListTools(BaseModel): class McpApprovalRequest(BaseModel): + """A request for human approval of a tool invocation.""" + id: str """The unique ID of the approval request.""" @@ -391,6 +435,8 @@ class McpApprovalRequest(BaseModel): class McpApprovalResponse(BaseModel): + """A response to an MCP approval request.""" + approval_request_id: str """The ID of the approval request being answered.""" @@ -408,6 +454,8 @@ class McpApprovalResponse(BaseModel): class McpCall(BaseModel): + """An invocation of a tool on an MCP server.""" + id: str """The unique ID of the tool call.""" @@ -444,6 +492,8 @@ class McpCall(BaseModel): class ItemReference(BaseModel): + """An internal identifier for an item to reference.""" + id: str """The ID of the item to reference.""" diff --git a/src/openai/types/responses/response_input_item_param.py b/src/openai/types/responses/response_input_item_param.py index 85d9f92b23..2c42b93021 100644 --- a/src/openai/types/responses/response_input_item_param.py +++ b/src/openai/types/responses/response_input_item_param.py @@ -51,6 +51,12 @@ class Message(TypedDict, total=False): + """ + A message input to the model with a role indicating instruction following + hierarchy. Instructions given with the `developer` or `system` role take + precedence over instructions given with the `user` role. + """ + content: Required[ResponseInputMessageContentListParam] """ A list of one or many input items to the model, containing different content @@ -72,6 +78,8 @@ class Message(TypedDict, total=False): class ComputerCallOutputAcknowledgedSafetyCheck(TypedDict, total=False): + """A pending safety check for the computer call.""" + id: Required[str] """The ID of the pending safety check.""" @@ -83,6 +91,8 @@ class ComputerCallOutputAcknowledgedSafetyCheck(TypedDict, total=False): class ComputerCallOutput(TypedDict, total=False): + """The output of a computer tool call.""" + call_id: Required[str] """The ID of the computer tool call that produced the output.""" @@ -110,6 +120,8 @@ class ComputerCallOutput(TypedDict, total=False): class FunctionCallOutput(TypedDict, total=False): + """The output of a function tool call.""" + call_id: Required[str] """The unique ID of the function tool call generated by the model.""" @@ -134,6 +146,8 @@ class FunctionCallOutput(TypedDict, total=False): class ImageGenerationCall(TypedDict, total=False): + """An image generation request made by the model.""" + id: Required[str] """The unique ID of the image generation call.""" @@ -148,6 +162,8 @@ class ImageGenerationCall(TypedDict, total=False): class LocalShellCallAction(TypedDict, total=False): + """Execute a shell command on the server.""" + command: Required[SequenceNotStr[str]] """The command to run.""" @@ -168,6 +184,8 @@ class LocalShellCallAction(TypedDict, total=False): class LocalShellCall(TypedDict, total=False): + """A tool call to run a command on the local shell.""" + id: Required[str] """The unique ID of the local shell call.""" @@ -185,6 +203,8 @@ class LocalShellCall(TypedDict, total=False): class LocalShellCallOutput(TypedDict, total=False): + """The output of a local shell tool call.""" + id: Required[str] """The unique ID of the local shell tool call generated by the model.""" @@ -199,6 +219,8 @@ class LocalShellCallOutput(TypedDict, total=False): class ShellCallAction(TypedDict, total=False): + """The shell commands and limits that describe how to run the tool call.""" + commands: Required[SequenceNotStr[str]] """Ordered shell commands for the execution environment to run.""" @@ -213,6 +235,8 @@ class ShellCallAction(TypedDict, total=False): class ShellCall(TypedDict, total=False): + """A tool representing a request to execute one or more shell commands.""" + action: Required[ShellCallAction] """The shell commands and limits that describe how to run the tool call.""" @@ -236,6 +260,8 @@ class ShellCall(TypedDict, total=False): class ShellCallOutput(TypedDict, total=False): + """The streamed output items emitted by a shell tool call.""" + call_id: Required[str] """The unique ID of the shell tool call generated by the model.""" @@ -262,6 +288,8 @@ class ShellCallOutput(TypedDict, total=False): class ApplyPatchCallOperationCreateFile(TypedDict, total=False): + """Instruction for creating a new file via the apply_patch tool.""" + diff: Required[str] """Unified diff content to apply when creating the file.""" @@ -273,6 +301,8 @@ class ApplyPatchCallOperationCreateFile(TypedDict, total=False): class ApplyPatchCallOperationDeleteFile(TypedDict, total=False): + """Instruction for deleting an existing file via the apply_patch tool.""" + path: Required[str] """Path of the file to delete relative to the workspace root.""" @@ -281,6 +311,8 @@ class ApplyPatchCallOperationDeleteFile(TypedDict, total=False): class ApplyPatchCallOperationUpdateFile(TypedDict, total=False): + """Instruction for updating an existing file via the apply_patch tool.""" + diff: Required[str] """Unified diff content to apply to the existing file.""" @@ -297,6 +329,10 @@ class ApplyPatchCallOperationUpdateFile(TypedDict, total=False): class ApplyPatchCall(TypedDict, total=False): + """ + A tool call representing a request to create, delete, or update files using diff patches. + """ + call_id: Required[str] """The unique ID of the apply patch tool call generated by the model.""" @@ -320,6 +356,8 @@ class ApplyPatchCall(TypedDict, total=False): class ApplyPatchCallOutput(TypedDict, total=False): + """The streamed output emitted by an apply patch tool call.""" + call_id: Required[str] """The unique ID of the apply patch tool call generated by the model.""" @@ -343,6 +381,8 @@ class ApplyPatchCallOutput(TypedDict, total=False): class McpListToolsTool(TypedDict, total=False): + """A tool available on an MCP server.""" + input_schema: Required[object] """The JSON schema describing the tool's input.""" @@ -357,6 +397,8 @@ class McpListToolsTool(TypedDict, total=False): class McpListTools(TypedDict, total=False): + """A list of tools available on an MCP server.""" + id: Required[str] """The unique ID of the list.""" @@ -374,6 +416,8 @@ class McpListTools(TypedDict, total=False): class McpApprovalRequest(TypedDict, total=False): + """A request for human approval of a tool invocation.""" + id: Required[str] """The unique ID of the approval request.""" @@ -391,6 +435,8 @@ class McpApprovalRequest(TypedDict, total=False): class McpApprovalResponse(TypedDict, total=False): + """A response to an MCP approval request.""" + approval_request_id: Required[str] """The ID of the approval request being answered.""" @@ -408,6 +454,8 @@ class McpApprovalResponse(TypedDict, total=False): class McpCall(TypedDict, total=False): + """An invocation of a tool on an MCP server.""" + id: Required[str] """The unique ID of the tool call.""" @@ -444,6 +492,8 @@ class McpCall(TypedDict, total=False): class ItemReference(TypedDict, total=False): + """An internal identifier for an item to reference.""" + id: Required[str] """The ID of the item to reference.""" diff --git a/src/openai/types/responses/response_input_param.py b/src/openai/types/responses/response_input_param.py index bbd8e6af79..c2d12c0ab4 100644 --- a/src/openai/types/responses/response_input_param.py +++ b/src/openai/types/responses/response_input_param.py @@ -52,6 +52,12 @@ class Message(TypedDict, total=False): + """ + A message input to the model with a role indicating instruction following + hierarchy. Instructions given with the `developer` or `system` role take + precedence over instructions given with the `user` role. + """ + content: Required[ResponseInputMessageContentListParam] """ A list of one or many input items to the model, containing different content @@ -73,6 +79,8 @@ class Message(TypedDict, total=False): class ComputerCallOutputAcknowledgedSafetyCheck(TypedDict, total=False): + """A pending safety check for the computer call.""" + id: Required[str] """The ID of the pending safety check.""" @@ -84,6 +92,8 @@ class ComputerCallOutputAcknowledgedSafetyCheck(TypedDict, total=False): class ComputerCallOutput(TypedDict, total=False): + """The output of a computer tool call.""" + call_id: Required[str] """The ID of the computer tool call that produced the output.""" @@ -111,6 +121,8 @@ class ComputerCallOutput(TypedDict, total=False): class FunctionCallOutput(TypedDict, total=False): + """The output of a function tool call.""" + call_id: Required[str] """The unique ID of the function tool call generated by the model.""" @@ -135,6 +147,8 @@ class FunctionCallOutput(TypedDict, total=False): class ImageGenerationCall(TypedDict, total=False): + """An image generation request made by the model.""" + id: Required[str] """The unique ID of the image generation call.""" @@ -149,6 +163,8 @@ class ImageGenerationCall(TypedDict, total=False): class LocalShellCallAction(TypedDict, total=False): + """Execute a shell command on the server.""" + command: Required[SequenceNotStr[str]] """The command to run.""" @@ -169,6 +185,8 @@ class LocalShellCallAction(TypedDict, total=False): class LocalShellCall(TypedDict, total=False): + """A tool call to run a command on the local shell.""" + id: Required[str] """The unique ID of the local shell call.""" @@ -186,6 +204,8 @@ class LocalShellCall(TypedDict, total=False): class LocalShellCallOutput(TypedDict, total=False): + """The output of a local shell tool call.""" + id: Required[str] """The unique ID of the local shell tool call generated by the model.""" @@ -200,6 +220,8 @@ class LocalShellCallOutput(TypedDict, total=False): class ShellCallAction(TypedDict, total=False): + """The shell commands and limits that describe how to run the tool call.""" + commands: Required[SequenceNotStr[str]] """Ordered shell commands for the execution environment to run.""" @@ -214,6 +236,8 @@ class ShellCallAction(TypedDict, total=False): class ShellCall(TypedDict, total=False): + """A tool representing a request to execute one or more shell commands.""" + action: Required[ShellCallAction] """The shell commands and limits that describe how to run the tool call.""" @@ -237,6 +261,8 @@ class ShellCall(TypedDict, total=False): class ShellCallOutput(TypedDict, total=False): + """The streamed output items emitted by a shell tool call.""" + call_id: Required[str] """The unique ID of the shell tool call generated by the model.""" @@ -263,6 +289,8 @@ class ShellCallOutput(TypedDict, total=False): class ApplyPatchCallOperationCreateFile(TypedDict, total=False): + """Instruction for creating a new file via the apply_patch tool.""" + diff: Required[str] """Unified diff content to apply when creating the file.""" @@ -274,6 +302,8 @@ class ApplyPatchCallOperationCreateFile(TypedDict, total=False): class ApplyPatchCallOperationDeleteFile(TypedDict, total=False): + """Instruction for deleting an existing file via the apply_patch tool.""" + path: Required[str] """Path of the file to delete relative to the workspace root.""" @@ -282,6 +312,8 @@ class ApplyPatchCallOperationDeleteFile(TypedDict, total=False): class ApplyPatchCallOperationUpdateFile(TypedDict, total=False): + """Instruction for updating an existing file via the apply_patch tool.""" + diff: Required[str] """Unified diff content to apply to the existing file.""" @@ -298,6 +330,10 @@ class ApplyPatchCallOperationUpdateFile(TypedDict, total=False): class ApplyPatchCall(TypedDict, total=False): + """ + A tool call representing a request to create, delete, or update files using diff patches. + """ + call_id: Required[str] """The unique ID of the apply patch tool call generated by the model.""" @@ -321,6 +357,8 @@ class ApplyPatchCall(TypedDict, total=False): class ApplyPatchCallOutput(TypedDict, total=False): + """The streamed output emitted by an apply patch tool call.""" + call_id: Required[str] """The unique ID of the apply patch tool call generated by the model.""" @@ -344,6 +382,8 @@ class ApplyPatchCallOutput(TypedDict, total=False): class McpListToolsTool(TypedDict, total=False): + """A tool available on an MCP server.""" + input_schema: Required[object] """The JSON schema describing the tool's input.""" @@ -358,6 +398,8 @@ class McpListToolsTool(TypedDict, total=False): class McpListTools(TypedDict, total=False): + """A list of tools available on an MCP server.""" + id: Required[str] """The unique ID of the list.""" @@ -375,6 +417,8 @@ class McpListTools(TypedDict, total=False): class McpApprovalRequest(TypedDict, total=False): + """A request for human approval of a tool invocation.""" + id: Required[str] """The unique ID of the approval request.""" @@ -392,6 +436,8 @@ class McpApprovalRequest(TypedDict, total=False): class McpApprovalResponse(TypedDict, total=False): + """A response to an MCP approval request.""" + approval_request_id: Required[str] """The ID of the approval request being answered.""" @@ -409,6 +455,8 @@ class McpApprovalResponse(TypedDict, total=False): class McpCall(TypedDict, total=False): + """An invocation of a tool on an MCP server.""" + id: Required[str] """The unique ID of the tool call.""" @@ -445,6 +493,8 @@ class McpCall(TypedDict, total=False): class ItemReference(TypedDict, total=False): + """An internal identifier for an item to reference.""" + id: Required[str] """The ID of the item to reference.""" diff --git a/src/openai/types/responses/response_input_text.py b/src/openai/types/responses/response_input_text.py index ba8d1ea18b..1e06ba71f3 100644 --- a/src/openai/types/responses/response_input_text.py +++ b/src/openai/types/responses/response_input_text.py @@ -8,6 +8,8 @@ class ResponseInputText(BaseModel): + """A text input to the model.""" + text: str """The text input to the model.""" diff --git a/src/openai/types/responses/response_input_text_content.py b/src/openai/types/responses/response_input_text_content.py index 2cce849855..66dbb8b0d0 100644 --- a/src/openai/types/responses/response_input_text_content.py +++ b/src/openai/types/responses/response_input_text_content.py @@ -8,6 +8,8 @@ class ResponseInputTextContent(BaseModel): + """A text input to the model.""" + text: str """The text input to the model.""" diff --git a/src/openai/types/responses/response_input_text_content_param.py b/src/openai/types/responses/response_input_text_content_param.py index 85b57df2bd..013f22d0df 100644 --- a/src/openai/types/responses/response_input_text_content_param.py +++ b/src/openai/types/responses/response_input_text_content_param.py @@ -8,6 +8,8 @@ class ResponseInputTextContentParam(TypedDict, total=False): + """A text input to the model.""" + text: Required[str] """The text input to the model.""" diff --git a/src/openai/types/responses/response_input_text_param.py b/src/openai/types/responses/response_input_text_param.py index f2ba834082..e1a2976e2e 100644 --- a/src/openai/types/responses/response_input_text_param.py +++ b/src/openai/types/responses/response_input_text_param.py @@ -8,6 +8,8 @@ class ResponseInputTextParam(TypedDict, total=False): + """A text input to the model.""" + text: Required[str] """The text input to the model.""" diff --git a/src/openai/types/responses/response_item.py b/src/openai/types/responses/response_item.py index 5ae2405988..3dba681d53 100644 --- a/src/openai/types/responses/response_item.py +++ b/src/openai/types/responses/response_item.py @@ -34,6 +34,8 @@ class ImageGenerationCall(BaseModel): + """An image generation request made by the model.""" + id: str """The unique ID of the image generation call.""" @@ -48,6 +50,8 @@ class ImageGenerationCall(BaseModel): class LocalShellCallAction(BaseModel): + """Execute a shell command on the server.""" + command: List[str] """The command to run.""" @@ -68,6 +72,8 @@ class LocalShellCallAction(BaseModel): class LocalShellCall(BaseModel): + """A tool call to run a command on the local shell.""" + id: str """The unique ID of the local shell call.""" @@ -85,6 +91,8 @@ class LocalShellCall(BaseModel): class LocalShellCallOutput(BaseModel): + """The output of a local shell tool call.""" + id: str """The unique ID of the local shell tool call generated by the model.""" @@ -99,6 +107,8 @@ class LocalShellCallOutput(BaseModel): class McpListToolsTool(BaseModel): + """A tool available on an MCP server.""" + input_schema: object """The JSON schema describing the tool's input.""" @@ -113,6 +123,8 @@ class McpListToolsTool(BaseModel): class McpListTools(BaseModel): + """A list of tools available on an MCP server.""" + id: str """The unique ID of the list.""" @@ -130,6 +142,8 @@ class McpListTools(BaseModel): class McpApprovalRequest(BaseModel): + """A request for human approval of a tool invocation.""" + id: str """The unique ID of the approval request.""" @@ -147,6 +161,8 @@ class McpApprovalRequest(BaseModel): class McpApprovalResponse(BaseModel): + """A response to an MCP approval request.""" + id: str """The unique ID of the approval response""" @@ -164,6 +180,8 @@ class McpApprovalResponse(BaseModel): class McpCall(BaseModel): + """An invocation of a tool on an MCP server.""" + id: str """The unique ID of the tool call.""" diff --git a/src/openai/types/responses/response_item_list.py b/src/openai/types/responses/response_item_list.py index b43eacdb51..e2b5a1a961 100644 --- a/src/openai/types/responses/response_item_list.py +++ b/src/openai/types/responses/response_item_list.py @@ -10,6 +10,8 @@ class ResponseItemList(BaseModel): + """A list of Response items.""" + data: List[ResponseItem] """A list of items used to generate this response.""" diff --git a/src/openai/types/responses/response_mcp_call_arguments_delta_event.py b/src/openai/types/responses/response_mcp_call_arguments_delta_event.py index 54eff38373..303ef494a3 100644 --- a/src/openai/types/responses/response_mcp_call_arguments_delta_event.py +++ b/src/openai/types/responses/response_mcp_call_arguments_delta_event.py @@ -8,6 +8,10 @@ class ResponseMcpCallArgumentsDeltaEvent(BaseModel): + """ + Emitted when there is a delta (partial update) to the arguments of an MCP tool call. + """ + delta: str """ A JSON string containing the partial update to the arguments for the MCP tool diff --git a/src/openai/types/responses/response_mcp_call_arguments_done_event.py b/src/openai/types/responses/response_mcp_call_arguments_done_event.py index 59ce9bc944..59e71be77c 100644 --- a/src/openai/types/responses/response_mcp_call_arguments_done_event.py +++ b/src/openai/types/responses/response_mcp_call_arguments_done_event.py @@ -8,6 +8,8 @@ class ResponseMcpCallArgumentsDoneEvent(BaseModel): + """Emitted when the arguments for an MCP tool call are finalized.""" + arguments: str """A JSON string containing the finalized arguments for the MCP tool call.""" diff --git a/src/openai/types/responses/response_mcp_call_completed_event.py b/src/openai/types/responses/response_mcp_call_completed_event.py index 2fee5dff81..bee54d4039 100644 --- a/src/openai/types/responses/response_mcp_call_completed_event.py +++ b/src/openai/types/responses/response_mcp_call_completed_event.py @@ -8,6 +8,8 @@ class ResponseMcpCallCompletedEvent(BaseModel): + """Emitted when an MCP tool call has completed successfully.""" + item_id: str """The ID of the MCP tool call item that completed.""" diff --git a/src/openai/types/responses/response_mcp_call_failed_event.py b/src/openai/types/responses/response_mcp_call_failed_event.py index ca41ab7159..cb3130b155 100644 --- a/src/openai/types/responses/response_mcp_call_failed_event.py +++ b/src/openai/types/responses/response_mcp_call_failed_event.py @@ -8,6 +8,8 @@ class ResponseMcpCallFailedEvent(BaseModel): + """Emitted when an MCP tool call has failed.""" + item_id: str """The ID of the MCP tool call item that failed.""" diff --git a/src/openai/types/responses/response_mcp_call_in_progress_event.py b/src/openai/types/responses/response_mcp_call_in_progress_event.py index 401c316851..7cf6a1decf 100644 --- a/src/openai/types/responses/response_mcp_call_in_progress_event.py +++ b/src/openai/types/responses/response_mcp_call_in_progress_event.py @@ -8,6 +8,8 @@ class ResponseMcpCallInProgressEvent(BaseModel): + """Emitted when an MCP tool call is in progress.""" + item_id: str """The unique identifier of the MCP tool call item being processed.""" diff --git a/src/openai/types/responses/response_mcp_list_tools_completed_event.py b/src/openai/types/responses/response_mcp_list_tools_completed_event.py index c60ad88ee5..685ba59c4d 100644 --- a/src/openai/types/responses/response_mcp_list_tools_completed_event.py +++ b/src/openai/types/responses/response_mcp_list_tools_completed_event.py @@ -8,6 +8,8 @@ class ResponseMcpListToolsCompletedEvent(BaseModel): + """Emitted when the list of available MCP tools has been successfully retrieved.""" + item_id: str """The ID of the MCP tool call item that produced this output.""" diff --git a/src/openai/types/responses/response_mcp_list_tools_failed_event.py b/src/openai/types/responses/response_mcp_list_tools_failed_event.py index 0c966c447a..c5fa54d231 100644 --- a/src/openai/types/responses/response_mcp_list_tools_failed_event.py +++ b/src/openai/types/responses/response_mcp_list_tools_failed_event.py @@ -8,6 +8,8 @@ class ResponseMcpListToolsFailedEvent(BaseModel): + """Emitted when the attempt to list available MCP tools has failed.""" + item_id: str """The ID of the MCP tool call item that failed.""" diff --git a/src/openai/types/responses/response_mcp_list_tools_in_progress_event.py b/src/openai/types/responses/response_mcp_list_tools_in_progress_event.py index f451db1ed5..403fdbdeb3 100644 --- a/src/openai/types/responses/response_mcp_list_tools_in_progress_event.py +++ b/src/openai/types/responses/response_mcp_list_tools_in_progress_event.py @@ -8,6 +8,10 @@ class ResponseMcpListToolsInProgressEvent(BaseModel): + """ + Emitted when the system is in the process of retrieving the list of available MCP tools. + """ + item_id: str """The ID of the MCP tool call item that is being processed.""" diff --git a/src/openai/types/responses/response_output_item.py b/src/openai/types/responses/response_output_item.py index f0a66e1836..990f947b90 100644 --- a/src/openai/types/responses/response_output_item.py +++ b/src/openai/types/responses/response_output_item.py @@ -32,6 +32,8 @@ class ImageGenerationCall(BaseModel): + """An image generation request made by the model.""" + id: str """The unique ID of the image generation call.""" @@ -46,6 +48,8 @@ class ImageGenerationCall(BaseModel): class LocalShellCallAction(BaseModel): + """Execute a shell command on the server.""" + command: List[str] """The command to run.""" @@ -66,6 +70,8 @@ class LocalShellCallAction(BaseModel): class LocalShellCall(BaseModel): + """A tool call to run a command on the local shell.""" + id: str """The unique ID of the local shell call.""" @@ -83,6 +89,8 @@ class LocalShellCall(BaseModel): class McpCall(BaseModel): + """An invocation of a tool on an MCP server.""" + id: str """The unique ID of the tool call.""" @@ -119,6 +127,8 @@ class McpCall(BaseModel): class McpListToolsTool(BaseModel): + """A tool available on an MCP server.""" + input_schema: object """The JSON schema describing the tool's input.""" @@ -133,6 +143,8 @@ class McpListToolsTool(BaseModel): class McpListTools(BaseModel): + """A list of tools available on an MCP server.""" + id: str """The unique ID of the list.""" @@ -150,6 +162,8 @@ class McpListTools(BaseModel): class McpApprovalRequest(BaseModel): + """A request for human approval of a tool invocation.""" + id: str """The unique ID of the approval request.""" diff --git a/src/openai/types/responses/response_output_item_added_event.py b/src/openai/types/responses/response_output_item_added_event.py index 7cd2a3946d..a42f6281e3 100644 --- a/src/openai/types/responses/response_output_item_added_event.py +++ b/src/openai/types/responses/response_output_item_added_event.py @@ -9,6 +9,8 @@ class ResponseOutputItemAddedEvent(BaseModel): + """Emitted when a new output item is added.""" + item: ResponseOutputItem """The output item that was added.""" diff --git a/src/openai/types/responses/response_output_item_done_event.py b/src/openai/types/responses/response_output_item_done_event.py index 37d3694cf7..50b99da569 100644 --- a/src/openai/types/responses/response_output_item_done_event.py +++ b/src/openai/types/responses/response_output_item_done_event.py @@ -9,6 +9,8 @@ class ResponseOutputItemDoneEvent(BaseModel): + """Emitted when an output item is marked done.""" + item: ResponseOutputItem """The output item that was marked done.""" diff --git a/src/openai/types/responses/response_output_message.py b/src/openai/types/responses/response_output_message.py index 3864aa2111..9c1d1f97fc 100644 --- a/src/openai/types/responses/response_output_message.py +++ b/src/openai/types/responses/response_output_message.py @@ -14,6 +14,8 @@ class ResponseOutputMessage(BaseModel): + """An output message from the model.""" + id: str """The unique ID of the output message.""" diff --git a/src/openai/types/responses/response_output_message_param.py b/src/openai/types/responses/response_output_message_param.py index 46cbbd20de..9c2f5246a1 100644 --- a/src/openai/types/responses/response_output_message_param.py +++ b/src/openai/types/responses/response_output_message_param.py @@ -14,6 +14,8 @@ class ResponseOutputMessageParam(TypedDict, total=False): + """An output message from the model.""" + id: Required[str] """The unique ID of the output message.""" diff --git a/src/openai/types/responses/response_output_refusal.py b/src/openai/types/responses/response_output_refusal.py index 685c8722a6..6bce26af74 100644 --- a/src/openai/types/responses/response_output_refusal.py +++ b/src/openai/types/responses/response_output_refusal.py @@ -8,6 +8,8 @@ class ResponseOutputRefusal(BaseModel): + """A refusal from the model.""" + refusal: str """The refusal explanation from the model.""" diff --git a/src/openai/types/responses/response_output_refusal_param.py b/src/openai/types/responses/response_output_refusal_param.py index 54cfaf0791..02bdfdcf4f 100644 --- a/src/openai/types/responses/response_output_refusal_param.py +++ b/src/openai/types/responses/response_output_refusal_param.py @@ -8,6 +8,8 @@ class ResponseOutputRefusalParam(TypedDict, total=False): + """A refusal from the model.""" + refusal: Required[str] """The refusal explanation from the model.""" diff --git a/src/openai/types/responses/response_output_text.py b/src/openai/types/responses/response_output_text.py index aa97b629f0..2386fcb3c0 100644 --- a/src/openai/types/responses/response_output_text.py +++ b/src/openai/types/responses/response_output_text.py @@ -19,6 +19,8 @@ class AnnotationFileCitation(BaseModel): + """A citation to a file.""" + file_id: str """The ID of the file.""" @@ -33,6 +35,8 @@ class AnnotationFileCitation(BaseModel): class AnnotationURLCitation(BaseModel): + """A citation for a web resource used to generate a model response.""" + end_index: int """The index of the last character of the URL citation in the message.""" @@ -50,6 +54,8 @@ class AnnotationURLCitation(BaseModel): class AnnotationContainerFileCitation(BaseModel): + """A citation for a container file used to generate a model response.""" + container_id: str """The ID of the container file.""" @@ -70,6 +76,8 @@ class AnnotationContainerFileCitation(BaseModel): class AnnotationFilePath(BaseModel): + """A path to a file.""" + file_id: str """The ID of the file.""" @@ -87,6 +95,8 @@ class AnnotationFilePath(BaseModel): class LogprobTopLogprob(BaseModel): + """The top log probability of a token.""" + token: str bytes: List[int] @@ -95,6 +105,8 @@ class LogprobTopLogprob(BaseModel): class Logprob(BaseModel): + """The log probability of a token.""" + token: str bytes: List[int] @@ -105,6 +117,8 @@ class Logprob(BaseModel): class ResponseOutputText(BaseModel): + """A text output from the model.""" + annotations: List[Annotation] """The annotations of the text output.""" diff --git a/src/openai/types/responses/response_output_text_annotation_added_event.py b/src/openai/types/responses/response_output_text_annotation_added_event.py index 62d8f72863..b9dc262150 100644 --- a/src/openai/types/responses/response_output_text_annotation_added_event.py +++ b/src/openai/types/responses/response_output_text_annotation_added_event.py @@ -8,6 +8,8 @@ class ResponseOutputTextAnnotationAddedEvent(BaseModel): + """Emitted when an annotation is added to output text content.""" + annotation: object """The annotation object being added. (See annotation schema for details.)""" diff --git a/src/openai/types/responses/response_output_text_param.py b/src/openai/types/responses/response_output_text_param.py index 63d2d394a8..bc30fbcd8e 100644 --- a/src/openai/types/responses/response_output_text_param.py +++ b/src/openai/types/responses/response_output_text_param.py @@ -18,6 +18,8 @@ class AnnotationFileCitation(TypedDict, total=False): + """A citation to a file.""" + file_id: Required[str] """The ID of the file.""" @@ -32,6 +34,8 @@ class AnnotationFileCitation(TypedDict, total=False): class AnnotationURLCitation(TypedDict, total=False): + """A citation for a web resource used to generate a model response.""" + end_index: Required[int] """The index of the last character of the URL citation in the message.""" @@ -49,6 +53,8 @@ class AnnotationURLCitation(TypedDict, total=False): class AnnotationContainerFileCitation(TypedDict, total=False): + """A citation for a container file used to generate a model response.""" + container_id: Required[str] """The ID of the container file.""" @@ -69,6 +75,8 @@ class AnnotationContainerFileCitation(TypedDict, total=False): class AnnotationFilePath(TypedDict, total=False): + """A path to a file.""" + file_id: Required[str] """The ID of the file.""" @@ -85,6 +93,8 @@ class AnnotationFilePath(TypedDict, total=False): class LogprobTopLogprob(TypedDict, total=False): + """The top log probability of a token.""" + token: Required[str] bytes: Required[Iterable[int]] @@ -93,6 +103,8 @@ class LogprobTopLogprob(TypedDict, total=False): class Logprob(TypedDict, total=False): + """The log probability of a token.""" + token: Required[str] bytes: Required[Iterable[int]] @@ -103,6 +115,8 @@ class Logprob(TypedDict, total=False): class ResponseOutputTextParam(TypedDict, total=False): + """A text output from the model.""" + annotations: Required[Iterable[Annotation]] """The annotations of the text output.""" diff --git a/src/openai/types/responses/response_prompt.py b/src/openai/types/responses/response_prompt.py index 537c2f8fbc..e3acacf63a 100644 --- a/src/openai/types/responses/response_prompt.py +++ b/src/openai/types/responses/response_prompt.py @@ -14,6 +14,11 @@ class ResponsePrompt(BaseModel): + """ + Reference to a prompt template and its variables. + [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). + """ + id: str """The unique identifier of the prompt template to use.""" diff --git a/src/openai/types/responses/response_prompt_param.py b/src/openai/types/responses/response_prompt_param.py index d935fa5191..f9a28b62a2 100644 --- a/src/openai/types/responses/response_prompt_param.py +++ b/src/openai/types/responses/response_prompt_param.py @@ -15,6 +15,11 @@ class ResponsePromptParam(TypedDict, total=False): + """ + Reference to a prompt template and its variables. + [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). + """ + id: Required[str] """The unique identifier of the prompt template to use.""" diff --git a/src/openai/types/responses/response_queued_event.py b/src/openai/types/responses/response_queued_event.py index 40257408a4..a554215275 100644 --- a/src/openai/types/responses/response_queued_event.py +++ b/src/openai/types/responses/response_queued_event.py @@ -9,6 +9,8 @@ class ResponseQueuedEvent(BaseModel): + """Emitted when a response is queued and waiting to be processed.""" + response: Response """The full response object that is queued.""" diff --git a/src/openai/types/responses/response_reasoning_item.py b/src/openai/types/responses/response_reasoning_item.py index fc582cf7c5..1a22eb60cc 100644 --- a/src/openai/types/responses/response_reasoning_item.py +++ b/src/openai/types/responses/response_reasoning_item.py @@ -9,6 +9,8 @@ class Summary(BaseModel): + """A summary text from the model.""" + text: str """A summary of the reasoning output from the model so far.""" @@ -17,6 +19,8 @@ class Summary(BaseModel): class Content(BaseModel): + """Reasoning text from the model.""" + text: str """The reasoning text from the model.""" @@ -25,6 +29,13 @@ class Content(BaseModel): class ResponseReasoningItem(BaseModel): + """ + A description of the chain of thought used by a reasoning model while generating + a response. Be sure to include these items in your `input` to the Responses API + for subsequent turns of a conversation if you are manually + [managing context](https://platform.openai.com/docs/guides/conversation-state). + """ + id: str """The unique identifier of the reasoning content.""" diff --git a/src/openai/types/responses/response_reasoning_item_param.py b/src/openai/types/responses/response_reasoning_item_param.py index 56e88ba28d..40320b72e1 100644 --- a/src/openai/types/responses/response_reasoning_item_param.py +++ b/src/openai/types/responses/response_reasoning_item_param.py @@ -9,6 +9,8 @@ class Summary(TypedDict, total=False): + """A summary text from the model.""" + text: Required[str] """A summary of the reasoning output from the model so far.""" @@ -17,6 +19,8 @@ class Summary(TypedDict, total=False): class Content(TypedDict, total=False): + """Reasoning text from the model.""" + text: Required[str] """The reasoning text from the model.""" @@ -25,6 +29,13 @@ class Content(TypedDict, total=False): class ResponseReasoningItemParam(TypedDict, total=False): + """ + A description of the chain of thought used by a reasoning model while generating + a response. Be sure to include these items in your `input` to the Responses API + for subsequent turns of a conversation if you are manually + [managing context](https://platform.openai.com/docs/guides/conversation-state). + """ + id: Required[str] """The unique identifier of the reasoning content.""" diff --git a/src/openai/types/responses/response_reasoning_summary_part_added_event.py b/src/openai/types/responses/response_reasoning_summary_part_added_event.py index dc755b253a..e4b0f34231 100644 --- a/src/openai/types/responses/response_reasoning_summary_part_added_event.py +++ b/src/openai/types/responses/response_reasoning_summary_part_added_event.py @@ -8,6 +8,8 @@ class Part(BaseModel): + """The summary part that was added.""" + text: str """The text of the summary part.""" @@ -16,6 +18,8 @@ class Part(BaseModel): class ResponseReasoningSummaryPartAddedEvent(BaseModel): + """Emitted when a new reasoning summary part is added.""" + item_id: str """The ID of the item this summary part is associated with.""" diff --git a/src/openai/types/responses/response_reasoning_summary_part_done_event.py b/src/openai/types/responses/response_reasoning_summary_part_done_event.py index 7cc0b56d66..48f3f684e8 100644 --- a/src/openai/types/responses/response_reasoning_summary_part_done_event.py +++ b/src/openai/types/responses/response_reasoning_summary_part_done_event.py @@ -8,6 +8,8 @@ class Part(BaseModel): + """The completed summary part.""" + text: str """The text of the summary part.""" @@ -16,6 +18,8 @@ class Part(BaseModel): class ResponseReasoningSummaryPartDoneEvent(BaseModel): + """Emitted when a reasoning summary part is completed.""" + item_id: str """The ID of the item this summary part is associated with.""" diff --git a/src/openai/types/responses/response_reasoning_summary_text_delta_event.py b/src/openai/types/responses/response_reasoning_summary_text_delta_event.py index 96652991b6..84bcf039c4 100644 --- a/src/openai/types/responses/response_reasoning_summary_text_delta_event.py +++ b/src/openai/types/responses/response_reasoning_summary_text_delta_event.py @@ -8,6 +8,8 @@ class ResponseReasoningSummaryTextDeltaEvent(BaseModel): + """Emitted when a delta is added to a reasoning summary text.""" + delta: str """The text delta that was added to the summary.""" diff --git a/src/openai/types/responses/response_reasoning_summary_text_done_event.py b/src/openai/types/responses/response_reasoning_summary_text_done_event.py index b35b82316a..244d001b75 100644 --- a/src/openai/types/responses/response_reasoning_summary_text_done_event.py +++ b/src/openai/types/responses/response_reasoning_summary_text_done_event.py @@ -8,6 +8,8 @@ class ResponseReasoningSummaryTextDoneEvent(BaseModel): + """Emitted when a reasoning summary text is completed.""" + item_id: str """The ID of the item this summary text is associated with.""" diff --git a/src/openai/types/responses/response_reasoning_text_delta_event.py b/src/openai/types/responses/response_reasoning_text_delta_event.py index e1df893bac..0e05226c94 100644 --- a/src/openai/types/responses/response_reasoning_text_delta_event.py +++ b/src/openai/types/responses/response_reasoning_text_delta_event.py @@ -8,6 +8,8 @@ class ResponseReasoningTextDeltaEvent(BaseModel): + """Emitted when a delta is added to a reasoning text.""" + content_index: int """The index of the reasoning content part this delta is associated with.""" diff --git a/src/openai/types/responses/response_reasoning_text_done_event.py b/src/openai/types/responses/response_reasoning_text_done_event.py index d22d984e47..40e3f4701c 100644 --- a/src/openai/types/responses/response_reasoning_text_done_event.py +++ b/src/openai/types/responses/response_reasoning_text_done_event.py @@ -8,6 +8,8 @@ class ResponseReasoningTextDoneEvent(BaseModel): + """Emitted when a reasoning text is completed.""" + content_index: int """The index of the reasoning content part.""" diff --git a/src/openai/types/responses/response_refusal_delta_event.py b/src/openai/types/responses/response_refusal_delta_event.py index 03c903ed28..e3933b7dda 100644 --- a/src/openai/types/responses/response_refusal_delta_event.py +++ b/src/openai/types/responses/response_refusal_delta_event.py @@ -8,6 +8,8 @@ class ResponseRefusalDeltaEvent(BaseModel): + """Emitted when there is a partial refusal text.""" + content_index: int """The index of the content part that the refusal text is added to.""" diff --git a/src/openai/types/responses/response_refusal_done_event.py b/src/openai/types/responses/response_refusal_done_event.py index 61fd51aab0..91adeb6331 100644 --- a/src/openai/types/responses/response_refusal_done_event.py +++ b/src/openai/types/responses/response_refusal_done_event.py @@ -8,6 +8,8 @@ class ResponseRefusalDoneEvent(BaseModel): + """Emitted when refusal text is finalized.""" + content_index: int """The index of the content part that the refusal text is finalized.""" diff --git a/src/openai/types/responses/response_text_config.py b/src/openai/types/responses/response_text_config.py index c53546da6d..fbf4da0b03 100644 --- a/src/openai/types/responses/response_text_config.py +++ b/src/openai/types/responses/response_text_config.py @@ -10,6 +10,14 @@ class ResponseTextConfig(BaseModel): + """Configuration options for a text response from the model. + + Can be plain + text or structured JSON data. Learn more: + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + """ + format: Optional[ResponseFormatTextConfig] = None """An object specifying the format that the model must output. diff --git a/src/openai/types/responses/response_text_config_param.py b/src/openai/types/responses/response_text_config_param.py index 1229fce35b..9cd54765b0 100644 --- a/src/openai/types/responses/response_text_config_param.py +++ b/src/openai/types/responses/response_text_config_param.py @@ -11,6 +11,14 @@ class ResponseTextConfigParam(TypedDict, total=False): + """Configuration options for a text response from the model. + + Can be plain + text or structured JSON data. Learn more: + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + """ + format: ResponseFormatTextConfigParam """An object specifying the format that the model must output. diff --git a/src/openai/types/responses/response_text_delta_event.py b/src/openai/types/responses/response_text_delta_event.py index b5379b7ac3..4f802abfd2 100644 --- a/src/openai/types/responses/response_text_delta_event.py +++ b/src/openai/types/responses/response_text_delta_event.py @@ -17,6 +17,12 @@ class LogprobTopLogprob(BaseModel): class Logprob(BaseModel): + """ + A logprob is the logarithmic probability that the model assigns to producing + a particular token at a given position in the sequence. Less-negative (higher) + logprob values indicate greater model confidence in that token choice. + """ + token: str """A possible text token.""" @@ -28,6 +34,8 @@ class Logprob(BaseModel): class ResponseTextDeltaEvent(BaseModel): + """Emitted when there is an additional text delta.""" + content_index: int """The index of the content part that the text delta was added to.""" diff --git a/src/openai/types/responses/response_text_done_event.py b/src/openai/types/responses/response_text_done_event.py index d9776a1844..75bd479870 100644 --- a/src/openai/types/responses/response_text_done_event.py +++ b/src/openai/types/responses/response_text_done_event.py @@ -17,6 +17,12 @@ class LogprobTopLogprob(BaseModel): class Logprob(BaseModel): + """ + A logprob is the logarithmic probability that the model assigns to producing + a particular token at a given position in the sequence. Less-negative (higher) + logprob values indicate greater model confidence in that token choice. + """ + token: str """A possible text token.""" @@ -28,6 +34,8 @@ class Logprob(BaseModel): class ResponseTextDoneEvent(BaseModel): + """Emitted when text content is finalized.""" + content_index: int """The index of the content part that the text content is finalized.""" diff --git a/src/openai/types/responses/response_usage.py b/src/openai/types/responses/response_usage.py index 52b93ac578..d4b739c598 100644 --- a/src/openai/types/responses/response_usage.py +++ b/src/openai/types/responses/response_usage.py @@ -6,6 +6,8 @@ class InputTokensDetails(BaseModel): + """A detailed breakdown of the input tokens.""" + cached_tokens: int """The number of tokens that were retrieved from the cache. @@ -14,11 +16,18 @@ class InputTokensDetails(BaseModel): class OutputTokensDetails(BaseModel): + """A detailed breakdown of the output tokens.""" + reasoning_tokens: int """The number of reasoning tokens.""" class ResponseUsage(BaseModel): + """ + Represents token usage details including input tokens, output tokens, + a breakdown of output tokens, and the total tokens used. + """ + input_tokens: int """The number of input tokens.""" diff --git a/src/openai/types/responses/response_web_search_call_completed_event.py b/src/openai/types/responses/response_web_search_call_completed_event.py index 497f7bfe35..5aa7afe609 100644 --- a/src/openai/types/responses/response_web_search_call_completed_event.py +++ b/src/openai/types/responses/response_web_search_call_completed_event.py @@ -8,6 +8,8 @@ class ResponseWebSearchCallCompletedEvent(BaseModel): + """Emitted when a web search call is completed.""" + item_id: str """Unique ID for the output item associated with the web search call.""" diff --git a/src/openai/types/responses/response_web_search_call_in_progress_event.py b/src/openai/types/responses/response_web_search_call_in_progress_event.py index da8b3fe404..73b30ff5c0 100644 --- a/src/openai/types/responses/response_web_search_call_in_progress_event.py +++ b/src/openai/types/responses/response_web_search_call_in_progress_event.py @@ -8,6 +8,8 @@ class ResponseWebSearchCallInProgressEvent(BaseModel): + """Emitted when a web search call is initiated.""" + item_id: str """Unique ID for the output item associated with the web search call.""" diff --git a/src/openai/types/responses/response_web_search_call_searching_event.py b/src/openai/types/responses/response_web_search_call_searching_event.py index 42df9cb298..959c095187 100644 --- a/src/openai/types/responses/response_web_search_call_searching_event.py +++ b/src/openai/types/responses/response_web_search_call_searching_event.py @@ -8,6 +8,8 @@ class ResponseWebSearchCallSearchingEvent(BaseModel): + """Emitted when a web search call is executing.""" + item_id: str """Unique ID for the output item associated with the web search call.""" diff --git a/src/openai/types/responses/tool.py b/src/openai/types/responses/tool.py index bb32d4e1ec..1f1ef12358 100644 --- a/src/openai/types/responses/tool.py +++ b/src/openai/types/responses/tool.py @@ -38,6 +38,8 @@ class McpAllowedToolsMcpToolFilter(BaseModel): + """A filter object to specify which tools are allowed.""" + read_only: Optional[bool] = None """Indicates whether or not a tool modifies data or is read-only. @@ -54,6 +56,8 @@ class McpAllowedToolsMcpToolFilter(BaseModel): class McpRequireApprovalMcpToolApprovalFilterAlways(BaseModel): + """A filter object to specify which tools are allowed.""" + read_only: Optional[bool] = None """Indicates whether or not a tool modifies data or is read-only. @@ -67,6 +71,8 @@ class McpRequireApprovalMcpToolApprovalFilterAlways(BaseModel): class McpRequireApprovalMcpToolApprovalFilterNever(BaseModel): + """A filter object to specify which tools are allowed.""" + read_only: Optional[bool] = None """Indicates whether or not a tool modifies data or is read-only. @@ -80,6 +86,13 @@ class McpRequireApprovalMcpToolApprovalFilterNever(BaseModel): class McpRequireApprovalMcpToolApprovalFilter(BaseModel): + """Specify which of the MCP server's tools require approval. + + Can be + `always`, `never`, or a filter object associated with tools + that require approval. + """ + always: Optional[McpRequireApprovalMcpToolApprovalFilterAlways] = None """A filter object to specify which tools are allowed.""" @@ -91,6 +104,11 @@ class McpRequireApprovalMcpToolApprovalFilter(BaseModel): class Mcp(BaseModel): + """ + Give the model access to additional tools via remote Model Context Protocol + (MCP) servers. [Learn more about MCP](https://platform.openai.com/docs/guides/tools-remote-mcp). + """ + server_label: str """A label for this MCP server, used to identify it in tool calls.""" @@ -157,6 +175,11 @@ class Mcp(BaseModel): class CodeInterpreterContainerCodeInterpreterToolAuto(BaseModel): + """Configuration for a code interpreter container. + + Optionally specify the IDs of the files to run the code on. + """ + type: Literal["auto"] """Always `auto`.""" @@ -170,6 +193,8 @@ class CodeInterpreterContainerCodeInterpreterToolAuto(BaseModel): class CodeInterpreter(BaseModel): + """A tool that runs Python code to help generate a response to a prompt.""" + container: CodeInterpreterContainer """The code interpreter container. @@ -182,6 +207,12 @@ class CodeInterpreter(BaseModel): class ImageGenerationInputImageMask(BaseModel): + """Optional mask for inpainting. + + Contains `image_url` + (string, optional) and `file_id` (string, optional). + """ + file_id: Optional[str] = None """File ID for the mask image.""" @@ -190,6 +221,8 @@ class ImageGenerationInputImageMask(BaseModel): class ImageGeneration(BaseModel): + """A tool that generates images using a model like `gpt-image-1`.""" + type: Literal["image_generation"] """The type of the image generation tool. Always `image_generation`.""" @@ -248,6 +281,8 @@ class ImageGeneration(BaseModel): class LocalShell(BaseModel): + """A tool that allows the model to execute shell commands in a local environment.""" + type: Literal["local_shell"] """The type of the local shell tool. Always `local_shell`.""" diff --git a/src/openai/types/responses/tool_choice_allowed.py b/src/openai/types/responses/tool_choice_allowed.py index d7921dcb2a..400e170a57 100644 --- a/src/openai/types/responses/tool_choice_allowed.py +++ b/src/openai/types/responses/tool_choice_allowed.py @@ -9,6 +9,8 @@ class ToolChoiceAllowed(BaseModel): + """Constrains the tools available to the model to a pre-defined set.""" + mode: Literal["auto", "required"] """Constrains the tools available to the model to a pre-defined set. diff --git a/src/openai/types/responses/tool_choice_allowed_param.py b/src/openai/types/responses/tool_choice_allowed_param.py index 0712cab43b..cb316c1560 100644 --- a/src/openai/types/responses/tool_choice_allowed_param.py +++ b/src/openai/types/responses/tool_choice_allowed_param.py @@ -9,6 +9,8 @@ class ToolChoiceAllowedParam(TypedDict, total=False): + """Constrains the tools available to the model to a pre-defined set.""" + mode: Required[Literal["auto", "required"]] """Constrains the tools available to the model to a pre-defined set. diff --git a/src/openai/types/responses/tool_choice_apply_patch.py b/src/openai/types/responses/tool_choice_apply_patch.py index 7f815aa1a1..ef5a5e8bfa 100644 --- a/src/openai/types/responses/tool_choice_apply_patch.py +++ b/src/openai/types/responses/tool_choice_apply_patch.py @@ -8,5 +8,7 @@ class ToolChoiceApplyPatch(BaseModel): + """Forces the model to call the apply_patch tool when executing a tool call.""" + type: Literal["apply_patch"] """The tool to call. Always `apply_patch`.""" diff --git a/src/openai/types/responses/tool_choice_apply_patch_param.py b/src/openai/types/responses/tool_choice_apply_patch_param.py index 00d4b25f0e..193c99328a 100644 --- a/src/openai/types/responses/tool_choice_apply_patch_param.py +++ b/src/openai/types/responses/tool_choice_apply_patch_param.py @@ -8,5 +8,7 @@ class ToolChoiceApplyPatchParam(TypedDict, total=False): + """Forces the model to call the apply_patch tool when executing a tool call.""" + type: Required[Literal["apply_patch"]] """The tool to call. Always `apply_patch`.""" diff --git a/src/openai/types/responses/tool_choice_custom.py b/src/openai/types/responses/tool_choice_custom.py index d600e53616..dec85ef78c 100644 --- a/src/openai/types/responses/tool_choice_custom.py +++ b/src/openai/types/responses/tool_choice_custom.py @@ -8,6 +8,8 @@ class ToolChoiceCustom(BaseModel): + """Use this option to force the model to call a specific custom tool.""" + name: str """The name of the custom tool to call.""" diff --git a/src/openai/types/responses/tool_choice_custom_param.py b/src/openai/types/responses/tool_choice_custom_param.py index 55bc53b730..ccdbab568a 100644 --- a/src/openai/types/responses/tool_choice_custom_param.py +++ b/src/openai/types/responses/tool_choice_custom_param.py @@ -8,6 +8,8 @@ class ToolChoiceCustomParam(TypedDict, total=False): + """Use this option to force the model to call a specific custom tool.""" + name: Required[str] """The name of the custom tool to call.""" diff --git a/src/openai/types/responses/tool_choice_function.py b/src/openai/types/responses/tool_choice_function.py index 8d2a4f2822..b2aab24aca 100644 --- a/src/openai/types/responses/tool_choice_function.py +++ b/src/openai/types/responses/tool_choice_function.py @@ -8,6 +8,8 @@ class ToolChoiceFunction(BaseModel): + """Use this option to force the model to call a specific function.""" + name: str """The name of the function to call.""" diff --git a/src/openai/types/responses/tool_choice_function_param.py b/src/openai/types/responses/tool_choice_function_param.py index 910537fd97..837465ebd7 100644 --- a/src/openai/types/responses/tool_choice_function_param.py +++ b/src/openai/types/responses/tool_choice_function_param.py @@ -8,6 +8,8 @@ class ToolChoiceFunctionParam(TypedDict, total=False): + """Use this option to force the model to call a specific function.""" + name: Required[str] """The name of the function to call.""" diff --git a/src/openai/types/responses/tool_choice_mcp.py b/src/openai/types/responses/tool_choice_mcp.py index 8763d81635..a2c8049c2d 100644 --- a/src/openai/types/responses/tool_choice_mcp.py +++ b/src/openai/types/responses/tool_choice_mcp.py @@ -9,6 +9,10 @@ class ToolChoiceMcp(BaseModel): + """ + Use this option to force the model to call a specific tool on a remote MCP server. + """ + server_label: str """The label of the MCP server to use.""" diff --git a/src/openai/types/responses/tool_choice_mcp_param.py b/src/openai/types/responses/tool_choice_mcp_param.py index afcceb8cc5..9726e47a47 100644 --- a/src/openai/types/responses/tool_choice_mcp_param.py +++ b/src/openai/types/responses/tool_choice_mcp_param.py @@ -9,6 +9,10 @@ class ToolChoiceMcpParam(TypedDict, total=False): + """ + Use this option to force the model to call a specific tool on a remote MCP server. + """ + server_label: Required[str] """The label of the MCP server to use.""" diff --git a/src/openai/types/responses/tool_choice_shell.py b/src/openai/types/responses/tool_choice_shell.py index 1ad21c58f3..a78eccc387 100644 --- a/src/openai/types/responses/tool_choice_shell.py +++ b/src/openai/types/responses/tool_choice_shell.py @@ -8,5 +8,7 @@ class ToolChoiceShell(BaseModel): + """Forces the model to call the shell tool when a tool call is required.""" + type: Literal["shell"] """The tool to call. Always `shell`.""" diff --git a/src/openai/types/responses/tool_choice_shell_param.py b/src/openai/types/responses/tool_choice_shell_param.py index 2b04c00d56..0dbcc90f39 100644 --- a/src/openai/types/responses/tool_choice_shell_param.py +++ b/src/openai/types/responses/tool_choice_shell_param.py @@ -8,5 +8,7 @@ class ToolChoiceShellParam(TypedDict, total=False): + """Forces the model to call the shell tool when a tool call is required.""" + type: Required[Literal["shell"]] """The tool to call. Always `shell`.""" diff --git a/src/openai/types/responses/tool_choice_types.py b/src/openai/types/responses/tool_choice_types.py index b31a826051..044c014b19 100644 --- a/src/openai/types/responses/tool_choice_types.py +++ b/src/openai/types/responses/tool_choice_types.py @@ -8,6 +8,11 @@ class ToolChoiceTypes(BaseModel): + """ + Indicates that the model should use a built-in tool to generate a response. + [Learn more about built-in tools](https://platform.openai.com/docs/guides/tools). + """ + type: Literal[ "file_search", "web_search_preview", diff --git a/src/openai/types/responses/tool_choice_types_param.py b/src/openai/types/responses/tool_choice_types_param.py index 15e0357471..9bf02dbfcc 100644 --- a/src/openai/types/responses/tool_choice_types_param.py +++ b/src/openai/types/responses/tool_choice_types_param.py @@ -8,6 +8,11 @@ class ToolChoiceTypesParam(TypedDict, total=False): + """ + Indicates that the model should use a built-in tool to generate a response. + [Learn more about built-in tools](https://platform.openai.com/docs/guides/tools). + """ + type: Required[ Literal[ "file_search", diff --git a/src/openai/types/responses/tool_param.py b/src/openai/types/responses/tool_param.py index 779acf0a53..c6ffa39192 100644 --- a/src/openai/types/responses/tool_param.py +++ b/src/openai/types/responses/tool_param.py @@ -40,6 +40,8 @@ class McpAllowedToolsMcpToolFilter(TypedDict, total=False): + """A filter object to specify which tools are allowed.""" + read_only: bool """Indicates whether or not a tool modifies data or is read-only. @@ -56,6 +58,8 @@ class McpAllowedToolsMcpToolFilter(TypedDict, total=False): class McpRequireApprovalMcpToolApprovalFilterAlways(TypedDict, total=False): + """A filter object to specify which tools are allowed.""" + read_only: bool """Indicates whether or not a tool modifies data or is read-only. @@ -69,6 +73,8 @@ class McpRequireApprovalMcpToolApprovalFilterAlways(TypedDict, total=False): class McpRequireApprovalMcpToolApprovalFilterNever(TypedDict, total=False): + """A filter object to specify which tools are allowed.""" + read_only: bool """Indicates whether or not a tool modifies data or is read-only. @@ -82,6 +88,13 @@ class McpRequireApprovalMcpToolApprovalFilterNever(TypedDict, total=False): class McpRequireApprovalMcpToolApprovalFilter(TypedDict, total=False): + """Specify which of the MCP server's tools require approval. + + Can be + `always`, `never`, or a filter object associated with tools + that require approval. + """ + always: McpRequireApprovalMcpToolApprovalFilterAlways """A filter object to specify which tools are allowed.""" @@ -93,6 +106,11 @@ class McpRequireApprovalMcpToolApprovalFilter(TypedDict, total=False): class Mcp(TypedDict, total=False): + """ + Give the model access to additional tools via remote Model Context Protocol + (MCP) servers. [Learn more about MCP](https://platform.openai.com/docs/guides/tools-remote-mcp). + """ + server_label: Required[str] """A label for this MCP server, used to identify it in tool calls.""" @@ -157,6 +175,11 @@ class Mcp(TypedDict, total=False): class CodeInterpreterContainerCodeInterpreterToolAuto(TypedDict, total=False): + """Configuration for a code interpreter container. + + Optionally specify the IDs of the files to run the code on. + """ + type: Required[Literal["auto"]] """Always `auto`.""" @@ -170,6 +193,8 @@ class CodeInterpreterContainerCodeInterpreterToolAuto(TypedDict, total=False): class CodeInterpreter(TypedDict, total=False): + """A tool that runs Python code to help generate a response to a prompt.""" + container: Required[CodeInterpreterContainer] """The code interpreter container. @@ -182,6 +207,12 @@ class CodeInterpreter(TypedDict, total=False): class ImageGenerationInputImageMask(TypedDict, total=False): + """Optional mask for inpainting. + + Contains `image_url` + (string, optional) and `file_id` (string, optional). + """ + file_id: str """File ID for the mask image.""" @@ -190,6 +221,8 @@ class ImageGenerationInputImageMask(TypedDict, total=False): class ImageGeneration(TypedDict, total=False): + """A tool that generates images using a model like `gpt-image-1`.""" + type: Required[Literal["image_generation"]] """The type of the image generation tool. Always `image_generation`.""" @@ -248,6 +281,8 @@ class ImageGeneration(TypedDict, total=False): class LocalShell(TypedDict, total=False): + """A tool that allows the model to execute shell commands in a local environment.""" + type: Required[Literal["local_shell"]] """The type of the local shell tool. Always `local_shell`.""" diff --git a/src/openai/types/responses/web_search_preview_tool.py b/src/openai/types/responses/web_search_preview_tool.py index 66d6a24679..12478e896d 100644 --- a/src/openai/types/responses/web_search_preview_tool.py +++ b/src/openai/types/responses/web_search_preview_tool.py @@ -9,6 +9,8 @@ class UserLocation(BaseModel): + """The user's location.""" + type: Literal["approximate"] """The type of location approximation. Always `approximate`.""" @@ -32,6 +34,11 @@ class UserLocation(BaseModel): class WebSearchPreviewTool(BaseModel): + """This tool searches the web for relevant results to use in a response. + + Learn more about the [web search tool](https://platform.openai.com/docs/guides/tools-web-search). + """ + type: Literal["web_search_preview", "web_search_preview_2025_03_11"] """The type of the web search tool. diff --git a/src/openai/types/responses/web_search_preview_tool_param.py b/src/openai/types/responses/web_search_preview_tool_param.py index ec2173f8e8..09619a3394 100644 --- a/src/openai/types/responses/web_search_preview_tool_param.py +++ b/src/openai/types/responses/web_search_preview_tool_param.py @@ -9,6 +9,8 @@ class UserLocation(TypedDict, total=False): + """The user's location.""" + type: Required[Literal["approximate"]] """The type of location approximation. Always `approximate`.""" @@ -32,6 +34,11 @@ class UserLocation(TypedDict, total=False): class WebSearchPreviewToolParam(TypedDict, total=False): + """This tool searches the web for relevant results to use in a response. + + Learn more about the [web search tool](https://platform.openai.com/docs/guides/tools-web-search). + """ + type: Required[Literal["web_search_preview", "web_search_preview_2025_03_11"]] """The type of the web search tool. diff --git a/src/openai/types/responses/web_search_tool.py b/src/openai/types/responses/web_search_tool.py index bde9600c87..769f5c93a4 100644 --- a/src/openai/types/responses/web_search_tool.py +++ b/src/openai/types/responses/web_search_tool.py @@ -9,6 +9,8 @@ class Filters(BaseModel): + """Filters for the search.""" + allowed_domains: Optional[List[str]] = None """Allowed domains for the search. @@ -20,6 +22,8 @@ class Filters(BaseModel): class UserLocation(BaseModel): + """The approximate location of the user.""" + city: Optional[str] = None """Free text input for the city of the user, e.g. `San Francisco`.""" @@ -43,6 +47,12 @@ class UserLocation(BaseModel): class WebSearchTool(BaseModel): + """Search the Internet for sources related to the prompt. + + Learn more about the + [web search tool](https://platform.openai.com/docs/guides/tools-web-search). + """ + type: Literal["web_search", "web_search_2025_08_26"] """The type of the web search tool. diff --git a/src/openai/types/responses/web_search_tool_param.py b/src/openai/types/responses/web_search_tool_param.py index 7fa19e9c23..a4531a9304 100644 --- a/src/openai/types/responses/web_search_tool_param.py +++ b/src/openai/types/responses/web_search_tool_param.py @@ -11,6 +11,8 @@ class Filters(TypedDict, total=False): + """Filters for the search.""" + allowed_domains: Optional[SequenceNotStr[str]] """Allowed domains for the search. @@ -22,6 +24,8 @@ class Filters(TypedDict, total=False): class UserLocation(TypedDict, total=False): + """The approximate location of the user.""" + city: Optional[str] """Free text input for the city of the user, e.g. `San Francisco`.""" @@ -45,6 +49,12 @@ class UserLocation(TypedDict, total=False): class WebSearchToolParam(TypedDict, total=False): + """Search the Internet for sources related to the prompt. + + Learn more about the + [web search tool](https://platform.openai.com/docs/guides/tools-web-search). + """ + type: Required[Literal["web_search", "web_search_2025_08_26"]] """The type of the web search tool. diff --git a/src/openai/types/shared/comparison_filter.py b/src/openai/types/shared/comparison_filter.py index 33415ca4f9..852cac1738 100644 --- a/src/openai/types/shared/comparison_filter.py +++ b/src/openai/types/shared/comparison_filter.py @@ -9,6 +9,10 @@ class ComparisonFilter(BaseModel): + """ + A filter used to compare a specified attribute key to a given value using a defined comparison operation. + """ + key: str """The key to compare against the value.""" diff --git a/src/openai/types/shared/compound_filter.py b/src/openai/types/shared/compound_filter.py index 3aefa43647..4801aaac1a 100644 --- a/src/openai/types/shared/compound_filter.py +++ b/src/openai/types/shared/compound_filter.py @@ -12,6 +12,8 @@ class CompoundFilter(BaseModel): + """Combine multiple filters using `and` or `or`.""" + filters: List[Filter] """Array of filters to combine. diff --git a/src/openai/types/shared/custom_tool_input_format.py b/src/openai/types/shared/custom_tool_input_format.py index 53c8323ed2..9391692b7b 100644 --- a/src/openai/types/shared/custom_tool_input_format.py +++ b/src/openai/types/shared/custom_tool_input_format.py @@ -10,11 +10,15 @@ class Text(BaseModel): + """Unconstrained free-form text.""" + type: Literal["text"] """Unconstrained text format. Always `text`.""" class Grammar(BaseModel): + """A grammar defined by the user.""" + definition: str """The grammar definition.""" diff --git a/src/openai/types/shared/reasoning.py b/src/openai/types/shared/reasoning.py index b19476bcb5..1220a045b1 100644 --- a/src/openai/types/shared/reasoning.py +++ b/src/openai/types/shared/reasoning.py @@ -10,6 +10,12 @@ class Reasoning(BaseModel): + """**gpt-5 and o-series models only** + + Configuration options for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). + """ + effort: Optional[ReasoningEffort] = None """ Constrains effort on reasoning for diff --git a/src/openai/types/shared/response_format_json_object.py b/src/openai/types/shared/response_format_json_object.py index 2aaa5dbdfe..98e0da6a2c 100644 --- a/src/openai/types/shared/response_format_json_object.py +++ b/src/openai/types/shared/response_format_json_object.py @@ -8,5 +8,13 @@ class ResponseFormatJSONObject(BaseModel): + """JSON object response format. + + An older method of generating JSON responses. + Using `json_schema` is recommended for models that support it. Note that the + model will not generate JSON without a system or user message instructing it + to do so. + """ + type: Literal["json_object"] """The type of response format being defined. Always `json_object`.""" diff --git a/src/openai/types/shared/response_format_json_schema.py b/src/openai/types/shared/response_format_json_schema.py index c7924446f4..9b2adb66cd 100644 --- a/src/openai/types/shared/response_format_json_schema.py +++ b/src/openai/types/shared/response_format_json_schema.py @@ -11,6 +11,8 @@ class JSONSchema(BaseModel): + """Structured Outputs configuration options, including a JSON Schema.""" + name: str """The name of the response format. @@ -41,6 +43,12 @@ class JSONSchema(BaseModel): class ResponseFormatJSONSchema(BaseModel): + """JSON Schema response format. + + Used to generate structured JSON responses. + Learn more about [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs). + """ + json_schema: JSONSchema """Structured Outputs configuration options, including a JSON Schema.""" diff --git a/src/openai/types/shared/response_format_text.py b/src/openai/types/shared/response_format_text.py index f0c8cfb700..9f4bc0d13e 100644 --- a/src/openai/types/shared/response_format_text.py +++ b/src/openai/types/shared/response_format_text.py @@ -8,5 +8,7 @@ class ResponseFormatText(BaseModel): + """Default response format. Used to generate text responses.""" + type: Literal["text"] """The type of response format being defined. Always `text`.""" diff --git a/src/openai/types/shared/response_format_text_grammar.py b/src/openai/types/shared/response_format_text_grammar.py index b02f99c1b8..84cd141278 100644 --- a/src/openai/types/shared/response_format_text_grammar.py +++ b/src/openai/types/shared/response_format_text_grammar.py @@ -8,6 +8,11 @@ class ResponseFormatTextGrammar(BaseModel): + """ + A custom grammar for the model to follow when generating text. + Learn more in the [custom grammars guide](https://platform.openai.com/docs/guides/custom-grammars). + """ + grammar: str """The custom grammar for the model to follow.""" diff --git a/src/openai/types/shared/response_format_text_python.py b/src/openai/types/shared/response_format_text_python.py index 4cd18d46fa..1b04cb62ba 100644 --- a/src/openai/types/shared/response_format_text_python.py +++ b/src/openai/types/shared/response_format_text_python.py @@ -8,5 +8,11 @@ class ResponseFormatTextPython(BaseModel): + """Configure the model to generate valid Python code. + + See the + [custom grammars guide](https://platform.openai.com/docs/guides/custom-grammars) for more details. + """ + type: Literal["python"] """The type of response format being defined. Always `python`.""" diff --git a/src/openai/types/shared_params/comparison_filter.py b/src/openai/types/shared_params/comparison_filter.py index 1c40729c19..363688e467 100644 --- a/src/openai/types/shared_params/comparison_filter.py +++ b/src/openai/types/shared_params/comparison_filter.py @@ -11,6 +11,10 @@ class ComparisonFilter(TypedDict, total=False): + """ + A filter used to compare a specified attribute key to a given value using a defined comparison operation. + """ + key: Required[str] """The key to compare against the value.""" diff --git a/src/openai/types/shared_params/compound_filter.py b/src/openai/types/shared_params/compound_filter.py index d12e9b1bda..9358e46083 100644 --- a/src/openai/types/shared_params/compound_filter.py +++ b/src/openai/types/shared_params/compound_filter.py @@ -13,6 +13,8 @@ class CompoundFilter(TypedDict, total=False): + """Combine multiple filters using `and` or `or`.""" + filters: Required[Iterable[Filter]] """Array of filters to combine. diff --git a/src/openai/types/shared_params/custom_tool_input_format.py b/src/openai/types/shared_params/custom_tool_input_format.py index 37df393e39..ddc71cacb4 100644 --- a/src/openai/types/shared_params/custom_tool_input_format.py +++ b/src/openai/types/shared_params/custom_tool_input_format.py @@ -9,11 +9,15 @@ class Text(TypedDict, total=False): + """Unconstrained free-form text.""" + type: Required[Literal["text"]] """Unconstrained text format. Always `text`.""" class Grammar(TypedDict, total=False): + """A grammar defined by the user.""" + definition: Required[str] """The grammar definition.""" diff --git a/src/openai/types/shared_params/reasoning.py b/src/openai/types/shared_params/reasoning.py index 71cb37c65e..68d9c374b8 100644 --- a/src/openai/types/shared_params/reasoning.py +++ b/src/openai/types/shared_params/reasoning.py @@ -11,6 +11,12 @@ class Reasoning(TypedDict, total=False): + """**gpt-5 and o-series models only** + + Configuration options for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). + """ + effort: Optional[ReasoningEffort] """ Constrains effort on reasoning for diff --git a/src/openai/types/shared_params/response_format_json_object.py b/src/openai/types/shared_params/response_format_json_object.py index d4d1deaae5..ef5d43be2e 100644 --- a/src/openai/types/shared_params/response_format_json_object.py +++ b/src/openai/types/shared_params/response_format_json_object.py @@ -8,5 +8,13 @@ class ResponseFormatJSONObject(TypedDict, total=False): + """JSON object response format. + + An older method of generating JSON responses. + Using `json_schema` is recommended for models that support it. Note that the + model will not generate JSON without a system or user message instructing it + to do so. + """ + type: Required[Literal["json_object"]] """The type of response format being defined. Always `json_object`.""" diff --git a/src/openai/types/shared_params/response_format_json_schema.py b/src/openai/types/shared_params/response_format_json_schema.py index 5b0a13ee06..0a0e846873 100644 --- a/src/openai/types/shared_params/response_format_json_schema.py +++ b/src/openai/types/shared_params/response_format_json_schema.py @@ -9,6 +9,8 @@ class JSONSchema(TypedDict, total=False): + """Structured Outputs configuration options, including a JSON Schema.""" + name: Required[str] """The name of the response format. @@ -39,6 +41,12 @@ class JSONSchema(TypedDict, total=False): class ResponseFormatJSONSchema(TypedDict, total=False): + """JSON Schema response format. + + Used to generate structured JSON responses. + Learn more about [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs). + """ + json_schema: Required[JSONSchema] """Structured Outputs configuration options, including a JSON Schema.""" diff --git a/src/openai/types/shared_params/response_format_text.py b/src/openai/types/shared_params/response_format_text.py index c3ef2b0816..c195036f95 100644 --- a/src/openai/types/shared_params/response_format_text.py +++ b/src/openai/types/shared_params/response_format_text.py @@ -8,5 +8,7 @@ class ResponseFormatText(TypedDict, total=False): + """Default response format. Used to generate text responses.""" + type: Required[Literal["text"]] """The type of response format being defined. Always `text`.""" diff --git a/src/openai/types/static_file_chunking_strategy_object_param.py b/src/openai/types/static_file_chunking_strategy_object_param.py index 0cdf35c0df..40188a41d5 100644 --- a/src/openai/types/static_file_chunking_strategy_object_param.py +++ b/src/openai/types/static_file_chunking_strategy_object_param.py @@ -10,6 +10,8 @@ class StaticFileChunkingStrategyObjectParam(TypedDict, total=False): + """Customize your own chunking strategy by setting chunk size and chunk overlap.""" + static: Required[StaticFileChunkingStrategyParam] type: Required[Literal["static"]] diff --git a/src/openai/types/upload.py b/src/openai/types/upload.py index 914b69a863..d248da6ee3 100644 --- a/src/openai/types/upload.py +++ b/src/openai/types/upload.py @@ -10,6 +10,8 @@ class Upload(BaseModel): + """The Upload object can accept byte chunks in the form of Parts.""" + id: str """The Upload unique identifier, which can be referenced in API endpoints.""" diff --git a/src/openai/types/upload_create_params.py b/src/openai/types/upload_create_params.py index ab4cded81d..c25d65bedd 100644 --- a/src/openai/types/upload_create_params.py +++ b/src/openai/types/upload_create_params.py @@ -39,6 +39,11 @@ class UploadCreateParams(TypedDict, total=False): class ExpiresAfter(TypedDict, total=False): + """The expiration policy for a file. + + By default, files with `purpose=batch` expire after 30 days and all other files are persisted until they are manually deleted. + """ + anchor: Required[Literal["created_at"]] """Anchor timestamp after which the expiration policy applies. diff --git a/src/openai/types/uploads/upload_part.py b/src/openai/types/uploads/upload_part.py index e09621d8f9..e585b1a227 100644 --- a/src/openai/types/uploads/upload_part.py +++ b/src/openai/types/uploads/upload_part.py @@ -8,6 +8,8 @@ class UploadPart(BaseModel): + """The upload Part represents a chunk of bytes we can add to an Upload object.""" + id: str """The upload Part unique identifier, which can be referenced in API endpoints.""" diff --git a/src/openai/types/vector_store.py b/src/openai/types/vector_store.py index 2473a442d2..82899ecd1b 100644 --- a/src/openai/types/vector_store.py +++ b/src/openai/types/vector_store.py @@ -27,6 +27,8 @@ class FileCounts(BaseModel): class ExpiresAfter(BaseModel): + """The expiration policy for a vector store.""" + anchor: Literal["last_active_at"] """Anchor timestamp after which the expiration policy applies. @@ -38,6 +40,10 @@ class ExpiresAfter(BaseModel): class VectorStore(BaseModel): + """ + A vector store is a collection of processed files can be used by the `file_search` tool. + """ + id: str """The identifier, which can be referenced in API endpoints.""" diff --git a/src/openai/types/vector_store_create_params.py b/src/openai/types/vector_store_create_params.py index f373a6ed28..2b72562984 100644 --- a/src/openai/types/vector_store_create_params.py +++ b/src/openai/types/vector_store_create_params.py @@ -51,6 +51,8 @@ class VectorStoreCreateParams(TypedDict, total=False): class ExpiresAfter(TypedDict, total=False): + """The expiration policy for a vector store.""" + anchor: Required[Literal["last_active_at"]] """Anchor timestamp after which the expiration policy applies. diff --git a/src/openai/types/vector_store_search_params.py b/src/openai/types/vector_store_search_params.py index 8b7b13c4a1..851d63c5d1 100644 --- a/src/openai/types/vector_store_search_params.py +++ b/src/openai/types/vector_store_search_params.py @@ -36,6 +36,8 @@ class VectorStoreSearchParams(TypedDict, total=False): class RankingOptions(TypedDict, total=False): + """Ranking options for search.""" + ranker: Literal["none", "auto", "default-2024-11-15"] """Enable re-ranking; set to `none` to disable, which can help reduce latency.""" diff --git a/src/openai/types/vector_store_update_params.py b/src/openai/types/vector_store_update_params.py index 4f6ac63963..7c6f891170 100644 --- a/src/openai/types/vector_store_update_params.py +++ b/src/openai/types/vector_store_update_params.py @@ -29,6 +29,8 @@ class VectorStoreUpdateParams(TypedDict, total=False): class ExpiresAfter(TypedDict, total=False): + """The expiration policy for a vector store.""" + anchor: Required[Literal["last_active_at"]] """Anchor timestamp after which the expiration policy applies. diff --git a/src/openai/types/vector_stores/vector_store_file.py b/src/openai/types/vector_stores/vector_store_file.py index 001584dfd7..c1ea02227f 100644 --- a/src/openai/types/vector_stores/vector_store_file.py +++ b/src/openai/types/vector_stores/vector_store_file.py @@ -10,6 +10,11 @@ class LastError(BaseModel): + """The last error associated with this vector store file. + + Will be `null` if there are no errors. + """ + code: Literal["server_error", "unsupported_file", "invalid_file"] """One of `server_error`, `unsupported_file`, or `invalid_file`.""" @@ -18,6 +23,8 @@ class LastError(BaseModel): class VectorStoreFile(BaseModel): + """A list of files attached to a vector store.""" + id: str """The identifier, which can be referenced in API endpoints.""" diff --git a/src/openai/types/vector_stores/vector_store_file_batch.py b/src/openai/types/vector_stores/vector_store_file_batch.py index 57dbfbd809..b07eb25da5 100644 --- a/src/openai/types/vector_stores/vector_store_file_batch.py +++ b/src/openai/types/vector_stores/vector_store_file_batch.py @@ -25,6 +25,8 @@ class FileCounts(BaseModel): class VectorStoreFileBatch(BaseModel): + """A batch of files attached to a vector store.""" + id: str """The identifier, which can be referenced in API endpoints.""" diff --git a/src/openai/types/video.py b/src/openai/types/video.py index 22ee3a11f7..e732ea54ec 100644 --- a/src/openai/types/video.py +++ b/src/openai/types/video.py @@ -13,6 +13,8 @@ class Video(BaseModel): + """Structured information describing a generated video job.""" + id: str """Unique identifier for the video job.""" diff --git a/src/openai/types/video_delete_response.py b/src/openai/types/video_delete_response.py index e2673ffe2b..1ed543aec8 100644 --- a/src/openai/types/video_delete_response.py +++ b/src/openai/types/video_delete_response.py @@ -8,6 +8,8 @@ class VideoDeleteResponse(BaseModel): + """Confirmation payload returned after deleting a video.""" + id: str """Identifier of the deleted video.""" diff --git a/src/openai/types/webhooks/batch_cancelled_webhook_event.py b/src/openai/types/webhooks/batch_cancelled_webhook_event.py index 4bbd7307a5..9d1c485f5e 100644 --- a/src/openai/types/webhooks/batch_cancelled_webhook_event.py +++ b/src/openai/types/webhooks/batch_cancelled_webhook_event.py @@ -9,11 +9,15 @@ class Data(BaseModel): + """Event data payload.""" + id: str """The unique ID of the batch API request.""" class BatchCancelledWebhookEvent(BaseModel): + """Sent when a batch API request has been cancelled.""" + id: str """The unique ID of the event.""" diff --git a/src/openai/types/webhooks/batch_completed_webhook_event.py b/src/openai/types/webhooks/batch_completed_webhook_event.py index a47ca156fa..5ae8191789 100644 --- a/src/openai/types/webhooks/batch_completed_webhook_event.py +++ b/src/openai/types/webhooks/batch_completed_webhook_event.py @@ -9,11 +9,15 @@ class Data(BaseModel): + """Event data payload.""" + id: str """The unique ID of the batch API request.""" class BatchCompletedWebhookEvent(BaseModel): + """Sent when a batch API request has been completed.""" + id: str """The unique ID of the event.""" diff --git a/src/openai/types/webhooks/batch_expired_webhook_event.py b/src/openai/types/webhooks/batch_expired_webhook_event.py index e91001e8d8..2f08a7f579 100644 --- a/src/openai/types/webhooks/batch_expired_webhook_event.py +++ b/src/openai/types/webhooks/batch_expired_webhook_event.py @@ -9,11 +9,15 @@ class Data(BaseModel): + """Event data payload.""" + id: str """The unique ID of the batch API request.""" class BatchExpiredWebhookEvent(BaseModel): + """Sent when a batch API request has expired.""" + id: str """The unique ID of the event.""" diff --git a/src/openai/types/webhooks/batch_failed_webhook_event.py b/src/openai/types/webhooks/batch_failed_webhook_event.py index ef80863edb..7166616588 100644 --- a/src/openai/types/webhooks/batch_failed_webhook_event.py +++ b/src/openai/types/webhooks/batch_failed_webhook_event.py @@ -9,11 +9,15 @@ class Data(BaseModel): + """Event data payload.""" + id: str """The unique ID of the batch API request.""" class BatchFailedWebhookEvent(BaseModel): + """Sent when a batch API request has failed.""" + id: str """The unique ID of the event.""" diff --git a/src/openai/types/webhooks/eval_run_canceled_webhook_event.py b/src/openai/types/webhooks/eval_run_canceled_webhook_event.py index 855359f743..1948f8933b 100644 --- a/src/openai/types/webhooks/eval_run_canceled_webhook_event.py +++ b/src/openai/types/webhooks/eval_run_canceled_webhook_event.py @@ -9,11 +9,15 @@ class Data(BaseModel): + """Event data payload.""" + id: str """The unique ID of the eval run.""" class EvalRunCanceledWebhookEvent(BaseModel): + """Sent when an eval run has been canceled.""" + id: str """The unique ID of the event.""" diff --git a/src/openai/types/webhooks/eval_run_failed_webhook_event.py b/src/openai/types/webhooks/eval_run_failed_webhook_event.py index 7671680720..4e4c860abc 100644 --- a/src/openai/types/webhooks/eval_run_failed_webhook_event.py +++ b/src/openai/types/webhooks/eval_run_failed_webhook_event.py @@ -9,11 +9,15 @@ class Data(BaseModel): + """Event data payload.""" + id: str """The unique ID of the eval run.""" class EvalRunFailedWebhookEvent(BaseModel): + """Sent when an eval run has failed.""" + id: str """The unique ID of the event.""" diff --git a/src/openai/types/webhooks/eval_run_succeeded_webhook_event.py b/src/openai/types/webhooks/eval_run_succeeded_webhook_event.py index d0d1fc2b04..c20f22eeb9 100644 --- a/src/openai/types/webhooks/eval_run_succeeded_webhook_event.py +++ b/src/openai/types/webhooks/eval_run_succeeded_webhook_event.py @@ -9,11 +9,15 @@ class Data(BaseModel): + """Event data payload.""" + id: str """The unique ID of the eval run.""" class EvalRunSucceededWebhookEvent(BaseModel): + """Sent when an eval run has succeeded.""" + id: str """The unique ID of the event.""" diff --git a/src/openai/types/webhooks/fine_tuning_job_cancelled_webhook_event.py b/src/openai/types/webhooks/fine_tuning_job_cancelled_webhook_event.py index 1fe3c06096..0cfff85dad 100644 --- a/src/openai/types/webhooks/fine_tuning_job_cancelled_webhook_event.py +++ b/src/openai/types/webhooks/fine_tuning_job_cancelled_webhook_event.py @@ -9,11 +9,15 @@ class Data(BaseModel): + """Event data payload.""" + id: str """The unique ID of the fine-tuning job.""" class FineTuningJobCancelledWebhookEvent(BaseModel): + """Sent when a fine-tuning job has been cancelled.""" + id: str """The unique ID of the event.""" diff --git a/src/openai/types/webhooks/fine_tuning_job_failed_webhook_event.py b/src/openai/types/webhooks/fine_tuning_job_failed_webhook_event.py index 71d899c8ef..0eb6bf954f 100644 --- a/src/openai/types/webhooks/fine_tuning_job_failed_webhook_event.py +++ b/src/openai/types/webhooks/fine_tuning_job_failed_webhook_event.py @@ -9,11 +9,15 @@ class Data(BaseModel): + """Event data payload.""" + id: str """The unique ID of the fine-tuning job.""" class FineTuningJobFailedWebhookEvent(BaseModel): + """Sent when a fine-tuning job has failed.""" + id: str """The unique ID of the event.""" diff --git a/src/openai/types/webhooks/fine_tuning_job_succeeded_webhook_event.py b/src/openai/types/webhooks/fine_tuning_job_succeeded_webhook_event.py index 470f1fcfaa..26b5ea8955 100644 --- a/src/openai/types/webhooks/fine_tuning_job_succeeded_webhook_event.py +++ b/src/openai/types/webhooks/fine_tuning_job_succeeded_webhook_event.py @@ -9,11 +9,15 @@ class Data(BaseModel): + """Event data payload.""" + id: str """The unique ID of the fine-tuning job.""" class FineTuningJobSucceededWebhookEvent(BaseModel): + """Sent when a fine-tuning job has succeeded.""" + id: str """The unique ID of the event.""" diff --git a/src/openai/types/webhooks/realtime_call_incoming_webhook_event.py b/src/openai/types/webhooks/realtime_call_incoming_webhook_event.py index a166a3471b..4647a2e2ba 100644 --- a/src/openai/types/webhooks/realtime_call_incoming_webhook_event.py +++ b/src/openai/types/webhooks/realtime_call_incoming_webhook_event.py @@ -9,6 +9,8 @@ class DataSipHeader(BaseModel): + """A header from the SIP Invite.""" + name: str """Name of the SIP Header.""" @@ -17,6 +19,8 @@ class DataSipHeader(BaseModel): class Data(BaseModel): + """Event data payload.""" + call_id: str """The unique ID of this call.""" @@ -25,6 +29,8 @@ class Data(BaseModel): class RealtimeCallIncomingWebhookEvent(BaseModel): + """Sent when Realtime API Receives a incoming SIP call.""" + id: str """The unique ID of the event.""" diff --git a/src/openai/types/webhooks/response_cancelled_webhook_event.py b/src/openai/types/webhooks/response_cancelled_webhook_event.py index 443e360e90..cd791b3314 100644 --- a/src/openai/types/webhooks/response_cancelled_webhook_event.py +++ b/src/openai/types/webhooks/response_cancelled_webhook_event.py @@ -9,11 +9,15 @@ class Data(BaseModel): + """Event data payload.""" + id: str """The unique ID of the model response.""" class ResponseCancelledWebhookEvent(BaseModel): + """Sent when a background response has been cancelled.""" + id: str """The unique ID of the event.""" diff --git a/src/openai/types/webhooks/response_completed_webhook_event.py b/src/openai/types/webhooks/response_completed_webhook_event.py index ac1feff32b..cf07f0c2c0 100644 --- a/src/openai/types/webhooks/response_completed_webhook_event.py +++ b/src/openai/types/webhooks/response_completed_webhook_event.py @@ -9,11 +9,15 @@ class Data(BaseModel): + """Event data payload.""" + id: str """The unique ID of the model response.""" class ResponseCompletedWebhookEvent(BaseModel): + """Sent when a background response has been completed.""" + id: str """The unique ID of the event.""" diff --git a/src/openai/types/webhooks/response_failed_webhook_event.py b/src/openai/types/webhooks/response_failed_webhook_event.py index 5b4ba65e18..aecb1b8f47 100644 --- a/src/openai/types/webhooks/response_failed_webhook_event.py +++ b/src/openai/types/webhooks/response_failed_webhook_event.py @@ -9,11 +9,15 @@ class Data(BaseModel): + """Event data payload.""" + id: str """The unique ID of the model response.""" class ResponseFailedWebhookEvent(BaseModel): + """Sent when a background response has failed.""" + id: str """The unique ID of the event.""" diff --git a/src/openai/types/webhooks/response_incomplete_webhook_event.py b/src/openai/types/webhooks/response_incomplete_webhook_event.py index 01609314e0..2367731e85 100644 --- a/src/openai/types/webhooks/response_incomplete_webhook_event.py +++ b/src/openai/types/webhooks/response_incomplete_webhook_event.py @@ -9,11 +9,15 @@ class Data(BaseModel): + """Event data payload.""" + id: str """The unique ID of the model response.""" class ResponseIncompleteWebhookEvent(BaseModel): + """Sent when a background response has been interrupted.""" + id: str """The unique ID of the event.""" diff --git a/tests/api_resources/test_responses.py b/tests/api_resources/test_responses.py index 14e2d911ef..d330eed134 100644 --- a/tests/api_resources/test_responses.py +++ b/tests/api_resources/test_responses.py @@ -361,22 +361,26 @@ def test_path_params_cancel(self, client: OpenAI) -> None: @parametrize def test_method_compact(self, client: OpenAI) -> None: - response = client.responses.compact() + response = client.responses.compact( + model="gpt-5.1", + ) assert_matches_type(CompactedResponse, response, path=["response"]) @parametrize def test_method_compact_with_all_params(self, client: OpenAI) -> None: response = client.responses.compact( + model="gpt-5.1", input="string", instructions="instructions", - model="gpt-5.1", previous_response_id="resp_123", ) assert_matches_type(CompactedResponse, response, path=["response"]) @parametrize def test_raw_response_compact(self, client: OpenAI) -> None: - http_response = client.responses.with_raw_response.compact() + http_response = client.responses.with_raw_response.compact( + model="gpt-5.1", + ) assert http_response.is_closed is True assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -385,7 +389,9 @@ def test_raw_response_compact(self, client: OpenAI) -> None: @parametrize def test_streaming_response_compact(self, client: OpenAI) -> None: - with client.responses.with_streaming_response.compact() as http_response: + with client.responses.with_streaming_response.compact( + model="gpt-5.1", + ) as http_response: assert not http_response.is_closed assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -751,22 +757,26 @@ async def test_path_params_cancel(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_method_compact(self, async_client: AsyncOpenAI) -> None: - response = await async_client.responses.compact() + response = await async_client.responses.compact( + model="gpt-5.1", + ) assert_matches_type(CompactedResponse, response, path=["response"]) @parametrize async def test_method_compact_with_all_params(self, async_client: AsyncOpenAI) -> None: response = await async_client.responses.compact( + model="gpt-5.1", input="string", instructions="instructions", - model="gpt-5.1", previous_response_id="resp_123", ) assert_matches_type(CompactedResponse, response, path=["response"]) @parametrize async def test_raw_response_compact(self, async_client: AsyncOpenAI) -> None: - http_response = await async_client.responses.with_raw_response.compact() + http_response = await async_client.responses.with_raw_response.compact( + model="gpt-5.1", + ) assert http_response.is_closed is True assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -775,7 +785,9 @@ async def test_raw_response_compact(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_compact(self, async_client: AsyncOpenAI) -> None: - async with async_client.responses.with_streaming_response.compact() as http_response: + async with async_client.responses.with_streaming_response.compact( + model="gpt-5.1", + ) as http_response: assert not http_response.is_closed assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" From 752a293da54c72c248afee310fc7cc1324debc1d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 11 Dec 2025 18:06:44 +0000 Subject: [PATCH 567/769] feat(api): gpt 5.2 --- .stats.yml | 4 ++-- src/openai/resources/beta/assistants.py | 8 ++++---- src/openai/resources/beta/threads/runs/runs.py | 12 ++++++------ .../resources/chat/completions/completions.py | 12 ++++++------ src/openai/resources/responses/responses.py | 10 ++++++++++ src/openai/types/beta/assistant_create_params.py | 2 +- src/openai/types/beta/assistant_update_params.py | 2 +- .../types/beta/threads/run_create_params.py | 2 +- .../types/chat/completion_create_params.py | 2 +- .../create_eval_completions_run_data_source.py | 2 +- ...ate_eval_completions_run_data_source_param.py | 2 +- src/openai/types/evals/run_cancel_response.py | 4 ++-- src/openai/types/evals/run_create_params.py | 4 ++-- src/openai/types/evals/run_create_response.py | 4 ++-- src/openai/types/evals/run_list_response.py | 4 ++-- src/openai/types/evals/run_retrieve_response.py | 4 ++-- src/openai/types/graders/score_model_grader.py | 8 ++++++-- .../types/graders/score_model_grader_param.py | 8 ++++++-- .../types/responses/response_compact_params.py | 5 +++++ src/openai/types/shared/chat_model.py | 5 +++++ src/openai/types/shared/reasoning.py | 5 +++-- src/openai/types/shared_params/chat_model.py | 5 +++++ src/openai/types/shared_params/reasoning.py | 5 +++-- tests/api_resources/test_responses.py | 16 ++++++++-------- 24 files changed, 85 insertions(+), 50 deletions(-) diff --git a/.stats.yml b/.stats.yml index 0aa25fb4a4..4e5b38902d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 137 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-88d85ff87ad8983262af2b729762a6e05fd509468bb691529bc2f81e4ce27c69.yml -openapi_spec_hash: 46a55acbccd0147534017b92c1f4dd99 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-41f98da99f44ebe6204fce5c1dc9940f85f3472779e797b674c4fdc20306c77d.yml +openapi_spec_hash: c61259027f421f501bdc6b23cf9e430e config_hash: 141b101c9f13b90e21af74e1686f1f41 diff --git a/src/openai/resources/beta/assistants.py b/src/openai/resources/beta/assistants.py index aa1f9f9b48..ab0947abf4 100644 --- a/src/openai/resources/beta/assistants.py +++ b/src/openai/resources/beta/assistants.py @@ -108,7 +108,7 @@ def create( - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), @@ -323,7 +323,7 @@ def update( - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), @@ -577,7 +577,7 @@ async def create( - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), @@ -792,7 +792,7 @@ async def update( - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), diff --git a/src/openai/resources/beta/threads/runs/runs.py b/src/openai/resources/beta/threads/runs/runs.py index 9b6cb3f752..8a58e91f69 100644 --- a/src/openai/resources/beta/threads/runs/runs.py +++ b/src/openai/resources/beta/threads/runs/runs.py @@ -179,7 +179,7 @@ def create( - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), @@ -341,7 +341,7 @@ def create( - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), @@ -499,7 +499,7 @@ def create( - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), @@ -1633,7 +1633,7 @@ async def create( - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), @@ -1795,7 +1795,7 @@ async def create( - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), @@ -1953,7 +1953,7 @@ async def create( - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. response_format: Specifies the format that the model must output. Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index 3f2732a608..9c0b74b804 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -421,7 +421,7 @@ def create( - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. response_format: An object specifying the format that the model must output. @@ -732,7 +732,7 @@ def create( - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. response_format: An object specifying the format that the model must output. @@ -1034,7 +1034,7 @@ def create( - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. response_format: An object specifying the format that the model must output. @@ -1907,7 +1907,7 @@ async def create( - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. response_format: An object specifying the format that the model must output. @@ -2218,7 +2218,7 @@ async def create( - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. response_format: An object specifying the format that the model must output. @@ -2520,7 +2520,7 @@ async def create( - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. response_format: An object specifying the format that the model must output. diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 81e8980faf..8e80f6793b 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -1528,6 +1528,11 @@ def compact( *, model: Union[ Literal[ + "gpt-5.2", + "gpt-5.2-2025-12-11", + "gpt-5.2-chat-latest", + "gpt-5.2-pro", + "gpt-5.2-pro-2025-12-11", "gpt-5.1", "gpt-5.1-2025-11-13", "gpt-5.1-codex", @@ -3141,6 +3146,11 @@ async def compact( *, model: Union[ Literal[ + "gpt-5.2", + "gpt-5.2-2025-12-11", + "gpt-5.2-chat-latest", + "gpt-5.2-pro", + "gpt-5.2-pro-2025-12-11", "gpt-5.1", "gpt-5.1-2025-11-13", "gpt-5.1-codex", diff --git a/src/openai/types/beta/assistant_create_params.py b/src/openai/types/beta/assistant_create_params.py index 49e7af2d67..461d871ab5 100644 --- a/src/openai/types/beta/assistant_create_params.py +++ b/src/openai/types/beta/assistant_create_params.py @@ -72,7 +72,7 @@ class AssistantCreateParams(TypedDict, total=False): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. """ response_format: Optional[AssistantResponseFormatOptionParam] diff --git a/src/openai/types/beta/assistant_update_params.py b/src/openai/types/beta/assistant_update_params.py index d84b15cc5b..7896fcd9c6 100644 --- a/src/openai/types/beta/assistant_update_params.py +++ b/src/openai/types/beta/assistant_update_params.py @@ -107,7 +107,7 @@ class AssistantUpdateParams(TypedDict, total=False): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. """ response_format: Optional[AssistantResponseFormatOptionParam] diff --git a/src/openai/types/beta/threads/run_create_params.py b/src/openai/types/beta/threads/run_create_params.py index f4c56feb56..376afc9aad 100644 --- a/src/openai/types/beta/threads/run_create_params.py +++ b/src/openai/types/beta/threads/run_create_params.py @@ -121,7 +121,7 @@ class RunCreateParamsBase(TypedDict, total=False): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. """ response_format: Optional[AssistantResponseFormatOptionParam] diff --git a/src/openai/types/chat/completion_create_params.py b/src/openai/types/chat/completion_create_params.py index 613787e9b5..49cefb95fc 100644 --- a/src/openai/types/chat/completion_create_params.py +++ b/src/openai/types/chat/completion_create_params.py @@ -207,7 +207,7 @@ class CompletionCreateParamsBase(TypedDict, total=False): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. """ response_format: ResponseFormat diff --git a/src/openai/types/evals/create_eval_completions_run_data_source.py b/src/openai/types/evals/create_eval_completions_run_data_source.py index 6ec39873b7..cc88450276 100644 --- a/src/openai/types/evals/create_eval_completions_run_data_source.py +++ b/src/openai/types/evals/create_eval_completions_run_data_source.py @@ -196,7 +196,7 @@ class SamplingParams(BaseModel): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. """ response_format: Optional[SamplingParamsResponseFormat] = None diff --git a/src/openai/types/evals/create_eval_completions_run_data_source_param.py b/src/openai/types/evals/create_eval_completions_run_data_source_param.py index 22d07c5598..bab2658afe 100644 --- a/src/openai/types/evals/create_eval_completions_run_data_source_param.py +++ b/src/openai/types/evals/create_eval_completions_run_data_source_param.py @@ -192,7 +192,7 @@ class SamplingParams(TypedDict, total=False): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. """ response_format: SamplingParamsResponseFormat diff --git a/src/openai/types/evals/run_cancel_response.py b/src/openai/types/evals/run_cancel_response.py index 40f071c959..6ad874b2b3 100644 --- a/src/openai/types/evals/run_cancel_response.py +++ b/src/openai/types/evals/run_cancel_response.py @@ -115,7 +115,7 @@ class DataSourceResponsesSourceResponses(BaseModel): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. """ temperature: Optional[float] = None @@ -278,7 +278,7 @@ class DataSourceResponsesSamplingParams(BaseModel): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. """ seed: Optional[int] = None diff --git a/src/openai/types/evals/run_create_params.py b/src/openai/types/evals/run_create_params.py index 993e10c738..fd7d56e39d 100644 --- a/src/openai/types/evals/run_create_params.py +++ b/src/openai/types/evals/run_create_params.py @@ -128,7 +128,7 @@ class DataSourceCreateEvalResponsesRunDataSourceSourceResponses(TypedDict, total - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. """ temperature: Optional[float] @@ -296,7 +296,7 @@ class DataSourceCreateEvalResponsesRunDataSourceSamplingParams(TypedDict, total= - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. """ seed: int diff --git a/src/openai/types/evals/run_create_response.py b/src/openai/types/evals/run_create_response.py index 93dae7adde..1651cb5b2f 100644 --- a/src/openai/types/evals/run_create_response.py +++ b/src/openai/types/evals/run_create_response.py @@ -115,7 +115,7 @@ class DataSourceResponsesSourceResponses(BaseModel): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. """ temperature: Optional[float] = None @@ -278,7 +278,7 @@ class DataSourceResponsesSamplingParams(BaseModel): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. """ seed: Optional[int] = None diff --git a/src/openai/types/evals/run_list_response.py b/src/openai/types/evals/run_list_response.py index c3c745b21c..9ec84330cf 100644 --- a/src/openai/types/evals/run_list_response.py +++ b/src/openai/types/evals/run_list_response.py @@ -115,7 +115,7 @@ class DataSourceResponsesSourceResponses(BaseModel): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. """ temperature: Optional[float] = None @@ -278,7 +278,7 @@ class DataSourceResponsesSamplingParams(BaseModel): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. """ seed: Optional[int] = None diff --git a/src/openai/types/evals/run_retrieve_response.py b/src/openai/types/evals/run_retrieve_response.py index d02256c679..9204635d1e 100644 --- a/src/openai/types/evals/run_retrieve_response.py +++ b/src/openai/types/evals/run_retrieve_response.py @@ -115,7 +115,7 @@ class DataSourceResponsesSourceResponses(BaseModel): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. """ temperature: Optional[float] = None @@ -278,7 +278,7 @@ class DataSourceResponsesSamplingParams(BaseModel): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. """ seed: Optional[int] = None diff --git a/src/openai/types/graders/score_model_grader.py b/src/openai/types/graders/score_model_grader.py index 6dd5a0eee8..bceb8b1ad0 100644 --- a/src/openai/types/graders/score_model_grader.py +++ b/src/openai/types/graders/score_model_grader.py @@ -91,7 +91,7 @@ class SamplingParams(BaseModel): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. """ seed: Optional[int] = None @@ -108,7 +108,11 @@ class ScoreModelGrader(BaseModel): """A ScoreModelGrader object that uses a model to assign a score to the input.""" input: List[Input] - """The input text. This may include template strings.""" + """The input messages evaluated by the grader. + + Supports text, output text, input image, and input audio content blocks, and may + include template strings. + """ model: str """The model to use for the evaluation.""" diff --git a/src/openai/types/graders/score_model_grader_param.py b/src/openai/types/graders/score_model_grader_param.py index 33452e43f3..bd08645a85 100644 --- a/src/openai/types/graders/score_model_grader_param.py +++ b/src/openai/types/graders/score_model_grader_param.py @@ -97,7 +97,7 @@ class SamplingParams(TypedDict, total=False): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. """ seed: Optional[int] @@ -114,7 +114,11 @@ class ScoreModelGraderParam(TypedDict, total=False): """A ScoreModelGrader object that uses a model to assign a score to the input.""" input: Required[Iterable[Input]] - """The input text. This may include template strings.""" + """The input messages evaluated by the grader. + + Supports text, output text, input image, and input audio content blocks, and may + include template strings. + """ model: Required[str] """The model to use for the evaluation.""" diff --git a/src/openai/types/responses/response_compact_params.py b/src/openai/types/responses/response_compact_params.py index 35a390f807..657c6a0764 100644 --- a/src/openai/types/responses/response_compact_params.py +++ b/src/openai/types/responses/response_compact_params.py @@ -14,6 +14,11 @@ class ResponseCompactParams(TypedDict, total=False): model: Required[ Union[ Literal[ + "gpt-5.2", + "gpt-5.2-2025-12-11", + "gpt-5.2-chat-latest", + "gpt-5.2-pro", + "gpt-5.2-pro-2025-12-11", "gpt-5.1", "gpt-5.1-2025-11-13", "gpt-5.1-codex", diff --git a/src/openai/types/shared/chat_model.py b/src/openai/types/shared/chat_model.py index b3ae7c3a95..8223b81bef 100644 --- a/src/openai/types/shared/chat_model.py +++ b/src/openai/types/shared/chat_model.py @@ -5,6 +5,11 @@ __all__ = ["ChatModel"] ChatModel: TypeAlias = Literal[ + "gpt-5.2", + "gpt-5.2-2025-12-11", + "gpt-5.2-chat-latest", + "gpt-5.2-pro", + "gpt-5.2-pro-2025-12-11", "gpt-5.1", "gpt-5.1-2025-11-13", "gpt-5.1-codex", diff --git a/src/openai/types/shared/reasoning.py b/src/openai/types/shared/reasoning.py index 1220a045b1..14f56a04cd 100644 --- a/src/openai/types/shared/reasoning.py +++ b/src/openai/types/shared/reasoning.py @@ -30,7 +30,7 @@ class Reasoning(BaseModel): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. """ generate_summary: Optional[Literal["auto", "concise", "detailed"]] = None @@ -47,5 +47,6 @@ class Reasoning(BaseModel): This can be useful for debugging and understanding the model's reasoning process. One of `auto`, `concise`, or `detailed`. - `concise` is only supported for `computer-use-preview` models. + `concise` is supported for `computer-use-preview` models and all reasoning + models after `gpt-5`. """ diff --git a/src/openai/types/shared_params/chat_model.py b/src/openai/types/shared_params/chat_model.py index 7505d51d67..c1937a8312 100644 --- a/src/openai/types/shared_params/chat_model.py +++ b/src/openai/types/shared_params/chat_model.py @@ -7,6 +7,11 @@ __all__ = ["ChatModel"] ChatModel: TypeAlias = Literal[ + "gpt-5.2", + "gpt-5.2-2025-12-11", + "gpt-5.2-chat-latest", + "gpt-5.2-pro", + "gpt-5.2-pro-2025-12-11", "gpt-5.1", "gpt-5.1-2025-11-13", "gpt-5.1-codex", diff --git a/src/openai/types/shared_params/reasoning.py b/src/openai/types/shared_params/reasoning.py index 68d9c374b8..2bd7ce7268 100644 --- a/src/openai/types/shared_params/reasoning.py +++ b/src/openai/types/shared_params/reasoning.py @@ -31,7 +31,7 @@ class Reasoning(TypedDict, total=False): - All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`. - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is currently only supported for `gpt-5.1-codex-max`. + - `xhigh` is supported for all models after `gpt-5.1-codex-max`. """ generate_summary: Optional[Literal["auto", "concise", "detailed"]] @@ -48,5 +48,6 @@ class Reasoning(TypedDict, total=False): This can be useful for debugging and understanding the model's reasoning process. One of `auto`, `concise`, or `detailed`. - `concise` is only supported for `computer-use-preview` models. + `concise` is supported for `computer-use-preview` models and all reasoning + models after `gpt-5`. """ diff --git a/tests/api_resources/test_responses.py b/tests/api_resources/test_responses.py index d330eed134..3cdbdba8a6 100644 --- a/tests/api_resources/test_responses.py +++ b/tests/api_resources/test_responses.py @@ -362,14 +362,14 @@ def test_path_params_cancel(self, client: OpenAI) -> None: @parametrize def test_method_compact(self, client: OpenAI) -> None: response = client.responses.compact( - model="gpt-5.1", + model="gpt-5.2", ) assert_matches_type(CompactedResponse, response, path=["response"]) @parametrize def test_method_compact_with_all_params(self, client: OpenAI) -> None: response = client.responses.compact( - model="gpt-5.1", + model="gpt-5.2", input="string", instructions="instructions", previous_response_id="resp_123", @@ -379,7 +379,7 @@ def test_method_compact_with_all_params(self, client: OpenAI) -> None: @parametrize def test_raw_response_compact(self, client: OpenAI) -> None: http_response = client.responses.with_raw_response.compact( - model="gpt-5.1", + model="gpt-5.2", ) assert http_response.is_closed is True @@ -390,7 +390,7 @@ def test_raw_response_compact(self, client: OpenAI) -> None: @parametrize def test_streaming_response_compact(self, client: OpenAI) -> None: with client.responses.with_streaming_response.compact( - model="gpt-5.1", + model="gpt-5.2", ) as http_response: assert not http_response.is_closed assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -758,14 +758,14 @@ async def test_path_params_cancel(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_method_compact(self, async_client: AsyncOpenAI) -> None: response = await async_client.responses.compact( - model="gpt-5.1", + model="gpt-5.2", ) assert_matches_type(CompactedResponse, response, path=["response"]) @parametrize async def test_method_compact_with_all_params(self, async_client: AsyncOpenAI) -> None: response = await async_client.responses.compact( - model="gpt-5.1", + model="gpt-5.2", input="string", instructions="instructions", previous_response_id="resp_123", @@ -775,7 +775,7 @@ async def test_method_compact_with_all_params(self, async_client: AsyncOpenAI) - @parametrize async def test_raw_response_compact(self, async_client: AsyncOpenAI) -> None: http_response = await async_client.responses.with_raw_response.compact( - model="gpt-5.1", + model="gpt-5.2", ) assert http_response.is_closed is True @@ -786,7 +786,7 @@ async def test_raw_response_compact(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_compact(self, async_client: AsyncOpenAI) -> None: async with async_client.responses.with_streaming_response.compact( - model="gpt-5.1", + model="gpt-5.2", ) as http_response: assert not http_response.is_closed assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" From 43e324ed7a8a8b6f0738254c59d732be2807a06f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 11 Dec 2025 18:07:20 +0000 Subject: [PATCH 568/769] release: 2.11.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 21f60560ae..e6c39adb99 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.10.0" + ".": "2.11.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 58a092665e..ff0878433f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 2.11.0 (2025-12-11) + +Full Changelog: [v2.10.0...v2.11.0](https://github.com/openai/openai-python/compare/v2.10.0...v2.11.0) + +### Features + +* **api:** gpt 5.2 ([dd9b8e8](https://github.com/openai/openai-python/commit/dd9b8e85cf91fe0d7470143fba10fe950ec740c4)) + ## 2.10.0 (2025-12-10) Full Changelog: [v2.9.0...v2.10.0](https://github.com/openai/openai-python/compare/v2.9.0...v2.10.0) diff --git a/pyproject.toml b/pyproject.toml index e7d181d007..f4e5bdb208 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.10.0" +version = "2.11.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 c7a4f08f04..16036c3b6a 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__ = "2.10.0" # x-release-please-version +__version__ = "2.11.0" # x-release-please-version From caa4a48feae6848d007fe5de39a747759f6baec6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 13 Dec 2025 00:06:47 +0000 Subject: [PATCH 569/769] feat(api): api update --- .stats.yml | 4 +- src/openai/types/eval_create_params.py | 57 +++++++++++++++-- ...create_eval_completions_run_data_source.py | 57 +++++++++++++++-- ..._eval_completions_run_data_source_param.py | 58 +++++++++++++++-- src/openai/types/evals/run_cancel_response.py | 59 ++++++++++++++++-- src/openai/types/evals/run_create_params.py | 59 ++++++++++++++++-- src/openai/types/evals/run_create_response.py | 59 ++++++++++++++++-- src/openai/types/evals/run_list_response.py | 59 ++++++++++++++++-- .../types/evals/run_retrieve_response.py | 59 ++++++++++++++++-- .../types/graders/label_model_grader.py | 62 +++++++++++++++++-- .../types/graders/label_model_grader_param.py | 59 ++++++++++++++++-- .../types/graders/score_model_grader.py | 56 +++++++++++++++-- .../types/graders/score_model_grader_param.py | 54 ++++++++++++++-- src/openai/types/video_model.py | 4 +- 14 files changed, 633 insertions(+), 73 deletions(-) diff --git a/.stats.yml b/.stats.yml index 4e5b38902d..595620b8ac 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 137 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-41f98da99f44ebe6204fce5c1dc9940f85f3472779e797b674c4fdc20306c77d.yml -openapi_spec_hash: c61259027f421f501bdc6b23cf9e430e +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-386042697a8769999956bdc26ff1e70bfc2a56913f724eedc6bfaf82679e9956.yml +openapi_spec_hash: 7072a6a4a43d7ff0bb4098a3e8a6b9a7 config_hash: 141b101c9f13b90e21af74e1686f1f41 diff --git a/src/openai/types/eval_create_params.py b/src/openai/types/eval_create_params.py index 0f2100b718..bfb39568c2 100644 --- a/src/openai/types/eval_create_params.py +++ b/src/openai/types/eval_create_params.py @@ -27,7 +27,10 @@ "TestingCriterionLabelModelInputEvalItem", "TestingCriterionLabelModelInputEvalItemContent", "TestingCriterionLabelModelInputEvalItemContentOutputText", - "TestingCriterionLabelModelInputEvalItemContentInputImage", + "TestingCriterionLabelModelInputEvalItemContentEvalItemInputImage", + "TestingCriterionLabelModelInputEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio", + "TestingCriterionLabelModelInputEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText", + "TestingCriterionLabelModelInputEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage", "TestingCriterionTextSimilarity", "TestingCriterionPython", "TestingCriterionScoreModel", @@ -128,8 +131,8 @@ class TestingCriterionLabelModelInputEvalItemContentOutputText(TypedDict, total= """The type of the output text. Always `output_text`.""" -class TestingCriterionLabelModelInputEvalItemContentInputImage(TypedDict, total=False): - """An image input to the model.""" +class TestingCriterionLabelModelInputEvalItemContentEvalItemInputImage(TypedDict, total=False): + """An image input block used within EvalItem content arrays.""" image_url: Required[str] """The URL of the image input.""" @@ -144,13 +147,51 @@ class TestingCriterionLabelModelInputEvalItemContentInputImage(TypedDict, total= """ +class TestingCriterionLabelModelInputEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText( + TypedDict, total=False +): + """A text output from the model.""" + + text: Required[str] + """The text output from the model.""" + + type: Required[Literal["output_text"]] + """The type of the output text. Always `output_text`.""" + + +class TestingCriterionLabelModelInputEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage( + TypedDict, total=False +): + """An image input block used within EvalItem content arrays.""" + + image_url: Required[str] + """The URL of the image input.""" + + type: Required[Literal["input_image"]] + """The type of the image input. Always `input_image`.""" + + detail: str + """The detail level of the image to be sent to the model. + + One of `high`, `low`, or `auto`. Defaults to `auto`. + """ + + +TestingCriterionLabelModelInputEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio: TypeAlias = Union[ + str, + ResponseInputTextParam, + TestingCriterionLabelModelInputEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText, + TestingCriterionLabelModelInputEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage, + ResponseInputAudioParam, +] + TestingCriterionLabelModelInputEvalItemContent: TypeAlias = Union[ str, ResponseInputTextParam, TestingCriterionLabelModelInputEvalItemContentOutputText, - TestingCriterionLabelModelInputEvalItemContentInputImage, + TestingCriterionLabelModelInputEvalItemContentEvalItemInputImage, ResponseInputAudioParam, - Iterable[object], + SequenceNotStr[TestingCriterionLabelModelInputEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio], ] @@ -164,7 +205,11 @@ class TestingCriterionLabelModelInputEvalItem(TypedDict, total=False): """ content: Required[TestingCriterionLabelModelInputEvalItemContent] - """Inputs to the model - can contain template strings.""" + """Inputs to the model - can contain template strings. + + Supports text, output text, input images, and input audio, either as a single + item or an array of items. + """ role: Required[Literal["user", "assistant", "system", "developer"]] """The role of the message input. diff --git a/src/openai/types/evals/create_eval_completions_run_data_source.py b/src/openai/types/evals/create_eval_completions_run_data_source.py index cc88450276..34118c0dfb 100644 --- a/src/openai/types/evals/create_eval_completions_run_data_source.py +++ b/src/openai/types/evals/create_eval_completions_run_data_source.py @@ -28,7 +28,10 @@ "InputMessagesTemplateTemplateEvalItem", "InputMessagesTemplateTemplateEvalItemContent", "InputMessagesTemplateTemplateEvalItemContentOutputText", - "InputMessagesTemplateTemplateEvalItemContentInputImage", + "InputMessagesTemplateTemplateEvalItemContentEvalItemInputImage", + "InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio", + "InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText", + "InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage", "InputMessagesItemReference", "SamplingParams", "SamplingParamsResponseFormat", @@ -101,8 +104,8 @@ class InputMessagesTemplateTemplateEvalItemContentOutputText(BaseModel): """The type of the output text. Always `output_text`.""" -class InputMessagesTemplateTemplateEvalItemContentInputImage(BaseModel): - """An image input to the model.""" +class InputMessagesTemplateTemplateEvalItemContentEvalItemInputImage(BaseModel): + """An image input block used within EvalItem content arrays.""" image_url: str """The URL of the image input.""" @@ -117,13 +120,51 @@ class InputMessagesTemplateTemplateEvalItemContentInputImage(BaseModel): """ +class InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText( + BaseModel +): + """A text output from the model.""" + + text: str + """The text output from the model.""" + + type: Literal["output_text"] + """The type of the output text. Always `output_text`.""" + + +class InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage( + BaseModel +): + """An image input block used within EvalItem content arrays.""" + + image_url: str + """The URL of the image input.""" + + type: Literal["input_image"] + """The type of the image input. Always `input_image`.""" + + detail: Optional[str] = None + """The detail level of the image to be sent to the model. + + One of `high`, `low`, or `auto`. Defaults to `auto`. + """ + + +InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio: TypeAlias = Union[ + str, + ResponseInputText, + InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText, + InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage, + ResponseInputAudio, +] + InputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ str, ResponseInputText, InputMessagesTemplateTemplateEvalItemContentOutputText, - InputMessagesTemplateTemplateEvalItemContentInputImage, + InputMessagesTemplateTemplateEvalItemContentEvalItemInputImage, ResponseInputAudio, - List[object], + List[InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio], ] @@ -137,7 +178,11 @@ class InputMessagesTemplateTemplateEvalItem(BaseModel): """ content: InputMessagesTemplateTemplateEvalItemContent - """Inputs to the model - can contain template strings.""" + """Inputs to the model - can contain template strings. + + Supports text, output text, input images, and input audio, either as a single + item or an array of items. + """ role: Literal["user", "assistant", "system", "developer"] """The role of the message input. diff --git a/src/openai/types/evals/create_eval_completions_run_data_source_param.py b/src/openai/types/evals/create_eval_completions_run_data_source_param.py index bab2658afe..64c4844d43 100644 --- a/src/openai/types/evals/create_eval_completions_run_data_source_param.py +++ b/src/openai/types/evals/create_eval_completions_run_data_source_param.py @@ -5,6 +5,7 @@ from typing import Dict, Union, Iterable, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict +from ..._types import SequenceNotStr from ..shared_params.metadata import Metadata from ..shared.reasoning_effort import ReasoningEffort from ..responses.easy_input_message_param import EasyInputMessageParam @@ -28,7 +29,10 @@ "InputMessagesTemplateTemplateEvalItem", "InputMessagesTemplateTemplateEvalItemContent", "InputMessagesTemplateTemplateEvalItemContentOutputText", - "InputMessagesTemplateTemplateEvalItemContentInputImage", + "InputMessagesTemplateTemplateEvalItemContentEvalItemInputImage", + "InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio", + "InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText", + "InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage", "InputMessagesItemReference", "SamplingParams", "SamplingParamsResponseFormat", @@ -99,8 +103,8 @@ class InputMessagesTemplateTemplateEvalItemContentOutputText(TypedDict, total=Fa """The type of the output text. Always `output_text`.""" -class InputMessagesTemplateTemplateEvalItemContentInputImage(TypedDict, total=False): - """An image input to the model.""" +class InputMessagesTemplateTemplateEvalItemContentEvalItemInputImage(TypedDict, total=False): + """An image input block used within EvalItem content arrays.""" image_url: Required[str] """The URL of the image input.""" @@ -115,13 +119,51 @@ class InputMessagesTemplateTemplateEvalItemContentInputImage(TypedDict, total=Fa """ +class InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText( + TypedDict, total=False +): + """A text output from the model.""" + + text: Required[str] + """The text output from the model.""" + + type: Required[Literal["output_text"]] + """The type of the output text. Always `output_text`.""" + + +class InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage( + TypedDict, total=False +): + """An image input block used within EvalItem content arrays.""" + + image_url: Required[str] + """The URL of the image input.""" + + type: Required[Literal["input_image"]] + """The type of the image input. Always `input_image`.""" + + detail: str + """The detail level of the image to be sent to the model. + + One of `high`, `low`, or `auto`. Defaults to `auto`. + """ + + +InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio: TypeAlias = Union[ + str, + ResponseInputTextParam, + InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText, + InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage, + ResponseInputAudioParam, +] + InputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ str, ResponseInputTextParam, InputMessagesTemplateTemplateEvalItemContentOutputText, - InputMessagesTemplateTemplateEvalItemContentInputImage, + InputMessagesTemplateTemplateEvalItemContentEvalItemInputImage, ResponseInputAudioParam, - Iterable[object], + SequenceNotStr[InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio], ] @@ -135,7 +177,11 @@ class InputMessagesTemplateTemplateEvalItem(TypedDict, total=False): """ content: Required[InputMessagesTemplateTemplateEvalItemContent] - """Inputs to the model - can contain template strings.""" + """Inputs to the model - can contain template strings. + + Supports text, output text, input images, and input audio, either as a single + item or an array of items. + """ role: Required[Literal["user", "assistant", "system", "developer"]] """The role of the message input. diff --git a/src/openai/types/evals/run_cancel_response.py b/src/openai/types/evals/run_cancel_response.py index 6ad874b2b3..791b1f0444 100644 --- a/src/openai/types/evals/run_cancel_response.py +++ b/src/openai/types/evals/run_cancel_response.py @@ -33,7 +33,10 @@ "DataSourceResponsesInputMessagesTemplateTemplateEvalItem", "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent", "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentEvalItemInputImage", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage", "DataSourceResponsesInputMessagesItemReference", "DataSourceResponsesSamplingParams", "DataSourceResponsesSamplingParamsText", @@ -155,8 +158,8 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText( """The type of the output text. Always `output_text`.""" -class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage(BaseModel): - """An image input to the model.""" +class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentEvalItemInputImage(BaseModel): + """An image input block used within EvalItem content arrays.""" image_url: str """The URL of the image input.""" @@ -171,13 +174,53 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage( """ +class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText( + BaseModel +): + """A text output from the model.""" + + text: str + """The text output from the model.""" + + type: Literal["output_text"] + """The type of the output text. Always `output_text`.""" + + +class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage( + BaseModel +): + """An image input block used within EvalItem content arrays.""" + + image_url: str + """The URL of the image input.""" + + type: Literal["input_image"] + """The type of the image input. Always `input_image`.""" + + detail: Optional[str] = None + """The detail level of the image to be sent to the model. + + One of `high`, `low`, or `auto`. Defaults to `auto`. + """ + + +DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio: TypeAlias = Union[ + str, + ResponseInputText, + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText, + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage, + ResponseInputAudio, +] + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ str, ResponseInputText, DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText, - DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage, + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentEvalItemInputImage, ResponseInputAudio, - List[object], + List[ + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio + ], ] @@ -191,7 +234,11 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItem(BaseModel): """ content: DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent - """Inputs to the model - can contain template strings.""" + """Inputs to the model - can contain template strings. + + Supports text, output text, input images, and input audio, either as a single + item or an array of items. + """ role: Literal["user", "assistant", "system", "developer"] """The role of the message input. diff --git a/src/openai/types/evals/run_create_params.py b/src/openai/types/evals/run_create_params.py index fd7d56e39d..0717f2ee20 100644 --- a/src/openai/types/evals/run_create_params.py +++ b/src/openai/types/evals/run_create_params.py @@ -31,7 +31,10 @@ "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItem", "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContent", "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentOutputText", - "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentInputImage", + "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentEvalItemInputImage", + "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio", + "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText", + "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage", "DataSourceCreateEvalResponsesRunDataSourceInputMessagesItemReference", "DataSourceCreateEvalResponsesRunDataSourceSamplingParams", "DataSourceCreateEvalResponsesRunDataSourceSamplingParamsText", @@ -171,10 +174,10 @@ class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEva """The type of the output text. Always `output_text`.""" -class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentInputImage( +class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentEvalItemInputImage( TypedDict, total=False ): - """An image input to the model.""" + """An image input block used within EvalItem content arrays.""" image_url: Required[str] """The URL of the image input.""" @@ -189,13 +192,53 @@ class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEva """ +class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText( + TypedDict, total=False +): + """A text output from the model.""" + + text: Required[str] + """The text output from the model.""" + + type: Required[Literal["output_text"]] + """The type of the output text. Always `output_text`.""" + + +class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage( + TypedDict, total=False +): + """An image input block used within EvalItem content arrays.""" + + image_url: Required[str] + """The URL of the image input.""" + + type: Required[Literal["input_image"]] + """The type of the image input. Always `input_image`.""" + + detail: str + """The detail level of the image to be sent to the model. + + One of `high`, `low`, or `auto`. Defaults to `auto`. + """ + + +DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio: TypeAlias = Union[ + str, + ResponseInputTextParam, + DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText, + DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage, + ResponseInputAudioParam, +] + DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ str, ResponseInputTextParam, DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentOutputText, - DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentInputImage, + DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentEvalItemInputImage, ResponseInputAudioParam, - Iterable[object], + SequenceNotStr[ + DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio + ], ] @@ -209,7 +252,11 @@ class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEva """ content: Required[DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContent] - """Inputs to the model - can contain template strings.""" + """Inputs to the model - can contain template strings. + + Supports text, output text, input images, and input audio, either as a single + item or an array of items. + """ role: Required[Literal["user", "assistant", "system", "developer"]] """The role of the message input. diff --git a/src/openai/types/evals/run_create_response.py b/src/openai/types/evals/run_create_response.py index 1651cb5b2f..a860bd178a 100644 --- a/src/openai/types/evals/run_create_response.py +++ b/src/openai/types/evals/run_create_response.py @@ -33,7 +33,10 @@ "DataSourceResponsesInputMessagesTemplateTemplateEvalItem", "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent", "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentEvalItemInputImage", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage", "DataSourceResponsesInputMessagesItemReference", "DataSourceResponsesSamplingParams", "DataSourceResponsesSamplingParamsText", @@ -155,8 +158,8 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText( """The type of the output text. Always `output_text`.""" -class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage(BaseModel): - """An image input to the model.""" +class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentEvalItemInputImage(BaseModel): + """An image input block used within EvalItem content arrays.""" image_url: str """The URL of the image input.""" @@ -171,13 +174,53 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage( """ +class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText( + BaseModel +): + """A text output from the model.""" + + text: str + """The text output from the model.""" + + type: Literal["output_text"] + """The type of the output text. Always `output_text`.""" + + +class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage( + BaseModel +): + """An image input block used within EvalItem content arrays.""" + + image_url: str + """The URL of the image input.""" + + type: Literal["input_image"] + """The type of the image input. Always `input_image`.""" + + detail: Optional[str] = None + """The detail level of the image to be sent to the model. + + One of `high`, `low`, or `auto`. Defaults to `auto`. + """ + + +DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio: TypeAlias = Union[ + str, + ResponseInputText, + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText, + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage, + ResponseInputAudio, +] + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ str, ResponseInputText, DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText, - DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage, + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentEvalItemInputImage, ResponseInputAudio, - List[object], + List[ + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio + ], ] @@ -191,7 +234,11 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItem(BaseModel): """ content: DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent - """Inputs to the model - can contain template strings.""" + """Inputs to the model - can contain template strings. + + Supports text, output text, input images, and input audio, either as a single + item or an array of items. + """ role: Literal["user", "assistant", "system", "developer"] """The role of the message input. diff --git a/src/openai/types/evals/run_list_response.py b/src/openai/types/evals/run_list_response.py index 9ec84330cf..aee471e2b6 100644 --- a/src/openai/types/evals/run_list_response.py +++ b/src/openai/types/evals/run_list_response.py @@ -33,7 +33,10 @@ "DataSourceResponsesInputMessagesTemplateTemplateEvalItem", "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent", "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentEvalItemInputImage", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage", "DataSourceResponsesInputMessagesItemReference", "DataSourceResponsesSamplingParams", "DataSourceResponsesSamplingParamsText", @@ -155,8 +158,8 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText( """The type of the output text. Always `output_text`.""" -class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage(BaseModel): - """An image input to the model.""" +class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentEvalItemInputImage(BaseModel): + """An image input block used within EvalItem content arrays.""" image_url: str """The URL of the image input.""" @@ -171,13 +174,53 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage( """ +class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText( + BaseModel +): + """A text output from the model.""" + + text: str + """The text output from the model.""" + + type: Literal["output_text"] + """The type of the output text. Always `output_text`.""" + + +class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage( + BaseModel +): + """An image input block used within EvalItem content arrays.""" + + image_url: str + """The URL of the image input.""" + + type: Literal["input_image"] + """The type of the image input. Always `input_image`.""" + + detail: Optional[str] = None + """The detail level of the image to be sent to the model. + + One of `high`, `low`, or `auto`. Defaults to `auto`. + """ + + +DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio: TypeAlias = Union[ + str, + ResponseInputText, + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText, + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage, + ResponseInputAudio, +] + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ str, ResponseInputText, DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText, - DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage, + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentEvalItemInputImage, ResponseInputAudio, - List[object], + List[ + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio + ], ] @@ -191,7 +234,11 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItem(BaseModel): """ content: DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent - """Inputs to the model - can contain template strings.""" + """Inputs to the model - can contain template strings. + + Supports text, output text, input images, and input audio, either as a single + item or an array of items. + """ role: Literal["user", "assistant", "system", "developer"] """The role of the message input. diff --git a/src/openai/types/evals/run_retrieve_response.py b/src/openai/types/evals/run_retrieve_response.py index 9204635d1e..ff3564de54 100644 --- a/src/openai/types/evals/run_retrieve_response.py +++ b/src/openai/types/evals/run_retrieve_response.py @@ -33,7 +33,10 @@ "DataSourceResponsesInputMessagesTemplateTemplateEvalItem", "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent", "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentEvalItemInputImage", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage", "DataSourceResponsesInputMessagesItemReference", "DataSourceResponsesSamplingParams", "DataSourceResponsesSamplingParamsText", @@ -155,8 +158,8 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText( """The type of the output text. Always `output_text`.""" -class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage(BaseModel): - """An image input to the model.""" +class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentEvalItemInputImage(BaseModel): + """An image input block used within EvalItem content arrays.""" image_url: str """The URL of the image input.""" @@ -171,13 +174,53 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage( """ +class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText( + BaseModel +): + """A text output from the model.""" + + text: str + """The text output from the model.""" + + type: Literal["output_text"] + """The type of the output text. Always `output_text`.""" + + +class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage( + BaseModel +): + """An image input block used within EvalItem content arrays.""" + + image_url: str + """The URL of the image input.""" + + type: Literal["input_image"] + """The type of the image input. Always `input_image`.""" + + detail: Optional[str] = None + """The detail level of the image to be sent to the model. + + One of `high`, `low`, or `auto`. Defaults to `auto`. + """ + + +DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio: TypeAlias = Union[ + str, + ResponseInputText, + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText, + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage, + ResponseInputAudio, +] + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ str, ResponseInputText, DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText, - DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage, + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentEvalItemInputImage, ResponseInputAudio, - List[object], + List[ + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio + ], ] @@ -191,7 +234,11 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItem(BaseModel): """ content: DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent - """Inputs to the model - can contain template strings.""" + """Inputs to the model - can contain template strings. + + Supports text, output text, input images, and input audio, either as a single + item or an array of items. + """ role: Literal["user", "assistant", "system", "developer"] """The role of the message input. diff --git a/src/openai/types/graders/label_model_grader.py b/src/openai/types/graders/label_model_grader.py index 141306b510..def3dd7602 100644 --- a/src/openai/types/graders/label_model_grader.py +++ b/src/openai/types/graders/label_model_grader.py @@ -7,7 +7,16 @@ from ..responses.response_input_text import ResponseInputText from ..responses.response_input_audio import ResponseInputAudio -__all__ = ["LabelModelGrader", "Input", "InputContent", "InputContentOutputText", "InputContentInputImage"] +__all__ = [ + "LabelModelGrader", + "Input", + "InputContent", + "InputContentOutputText", + "InputContentEvalItemInputImage", + "InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudio", + "InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText", + "InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage", +] class InputContentOutputText(BaseModel): @@ -20,8 +29,34 @@ class InputContentOutputText(BaseModel): """The type of the output text. Always `output_text`.""" -class InputContentInputImage(BaseModel): - """An image input to the model.""" +class InputContentEvalItemInputImage(BaseModel): + """An image input block used within EvalItem content arrays.""" + + image_url: str + """The URL of the image input.""" + + type: Literal["input_image"] + """The type of the image input. Always `input_image`.""" + + detail: Optional[str] = None + """The detail level of the image to be sent to the model. + + One of `high`, `low`, or `auto`. Defaults to `auto`. + """ + + +class InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText(BaseModel): + """A text output from the model.""" + + text: str + """The text output from the model.""" + + type: Literal["output_text"] + """The type of the output text. Always `output_text`.""" + + +class InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage(BaseModel): + """An image input block used within EvalItem content arrays.""" image_url: str """The URL of the image input.""" @@ -36,8 +71,21 @@ class InputContentInputImage(BaseModel): """ +InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudio: TypeAlias = Union[ + str, + ResponseInputText, + InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText, + InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage, + ResponseInputAudio, +] + InputContent: TypeAlias = Union[ - str, ResponseInputText, InputContentOutputText, InputContentInputImage, ResponseInputAudio, List[object] + str, + ResponseInputText, + InputContentOutputText, + InputContentEvalItemInputImage, + ResponseInputAudio, + List[InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudio], ] @@ -51,7 +99,11 @@ class Input(BaseModel): """ content: InputContent - """Inputs to the model - can contain template strings.""" + """Inputs to the model - can contain template strings. + + Supports text, output text, input images, and input audio, either as a single + item or an array of items. + """ role: Literal["user", "assistant", "system", "developer"] """The role of the message input. diff --git a/src/openai/types/graders/label_model_grader_param.py b/src/openai/types/graders/label_model_grader_param.py index a23be2a236..6b6faa465d 100644 --- a/src/openai/types/graders/label_model_grader_param.py +++ b/src/openai/types/graders/label_model_grader_param.py @@ -9,7 +9,16 @@ from ..responses.response_input_text_param import ResponseInputTextParam from ..responses.response_input_audio_param import ResponseInputAudioParam -__all__ = ["LabelModelGraderParam", "Input", "InputContent", "InputContentOutputText", "InputContentInputImage"] +__all__ = [ + "LabelModelGraderParam", + "Input", + "InputContent", + "InputContentOutputText", + "InputContentEvalItemInputImage", + "InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudio", + "InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText", + "InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage", +] class InputContentOutputText(TypedDict, total=False): @@ -22,8 +31,8 @@ class InputContentOutputText(TypedDict, total=False): """The type of the output text. Always `output_text`.""" -class InputContentInputImage(TypedDict, total=False): - """An image input to the model.""" +class InputContentEvalItemInputImage(TypedDict, total=False): + """An image input block used within EvalItem content arrays.""" image_url: Required[str] """The URL of the image input.""" @@ -38,13 +47,47 @@ class InputContentInputImage(TypedDict, total=False): """ +class InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText(TypedDict, total=False): + """A text output from the model.""" + + text: Required[str] + """The text output from the model.""" + + type: Required[Literal["output_text"]] + """The type of the output text. Always `output_text`.""" + + +class InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage(TypedDict, total=False): + """An image input block used within EvalItem content arrays.""" + + image_url: Required[str] + """The URL of the image input.""" + + type: Required[Literal["input_image"]] + """The type of the image input. Always `input_image`.""" + + detail: str + """The detail level of the image to be sent to the model. + + One of `high`, `low`, or `auto`. Defaults to `auto`. + """ + + +InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudio: TypeAlias = Union[ + str, + ResponseInputTextParam, + InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText, + InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage, + ResponseInputAudioParam, +] + InputContent: TypeAlias = Union[ str, ResponseInputTextParam, InputContentOutputText, - InputContentInputImage, + InputContentEvalItemInputImage, ResponseInputAudioParam, - Iterable[object], + SequenceNotStr[InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudio], ] @@ -58,7 +101,11 @@ class Input(TypedDict, total=False): """ content: Required[InputContent] - """Inputs to the model - can contain template strings.""" + """Inputs to the model - can contain template strings. + + Supports text, output text, input images, and input audio, either as a single + item or an array of items. + """ role: Required[Literal["user", "assistant", "system", "developer"]] """The role of the message input. diff --git a/src/openai/types/graders/score_model_grader.py b/src/openai/types/graders/score_model_grader.py index bceb8b1ad0..7787c82bb6 100644 --- a/src/openai/types/graders/score_model_grader.py +++ b/src/openai/types/graders/score_model_grader.py @@ -13,7 +13,10 @@ "Input", "InputContent", "InputContentOutputText", - "InputContentInputImage", + "InputContentEvalItemInputImage", + "InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudio", + "InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText", + "InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage", "SamplingParams", ] @@ -28,8 +31,8 @@ class InputContentOutputText(BaseModel): """The type of the output text. Always `output_text`.""" -class InputContentInputImage(BaseModel): - """An image input to the model.""" +class InputContentEvalItemInputImage(BaseModel): + """An image input block used within EvalItem content arrays.""" image_url: str """The URL of the image input.""" @@ -44,8 +47,47 @@ class InputContentInputImage(BaseModel): """ +class InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText(BaseModel): + """A text output from the model.""" + + text: str + """The text output from the model.""" + + type: Literal["output_text"] + """The type of the output text. Always `output_text`.""" + + +class InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage(BaseModel): + """An image input block used within EvalItem content arrays.""" + + image_url: str + """The URL of the image input.""" + + type: Literal["input_image"] + """The type of the image input. Always `input_image`.""" + + detail: Optional[str] = None + """The detail level of the image to be sent to the model. + + One of `high`, `low`, or `auto`. Defaults to `auto`. + """ + + +InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudio: TypeAlias = Union[ + str, + ResponseInputText, + InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText, + InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage, + ResponseInputAudio, +] + InputContent: TypeAlias = Union[ - str, ResponseInputText, InputContentOutputText, InputContentInputImage, ResponseInputAudio, List[object] + str, + ResponseInputText, + InputContentOutputText, + InputContentEvalItemInputImage, + ResponseInputAudio, + List[InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudio], ] @@ -59,7 +101,11 @@ class Input(BaseModel): """ content: InputContent - """Inputs to the model - can contain template strings.""" + """Inputs to the model - can contain template strings. + + Supports text, output text, input images, and input audio, either as a single + item or an array of items. + """ role: Literal["user", "assistant", "system", "developer"] """The role of the message input. diff --git a/src/openai/types/graders/score_model_grader_param.py b/src/openai/types/graders/score_model_grader_param.py index bd08645a85..1f9475d885 100644 --- a/src/openai/types/graders/score_model_grader_param.py +++ b/src/openai/types/graders/score_model_grader_param.py @@ -5,6 +5,7 @@ from typing import Union, Iterable, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict +from ..._types import SequenceNotStr from ..shared.reasoning_effort import ReasoningEffort from ..responses.response_input_text_param import ResponseInputTextParam from ..responses.response_input_audio_param import ResponseInputAudioParam @@ -14,7 +15,10 @@ "Input", "InputContent", "InputContentOutputText", - "InputContentInputImage", + "InputContentEvalItemInputImage", + "InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudio", + "InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText", + "InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage", "SamplingParams", ] @@ -29,8 +33,8 @@ class InputContentOutputText(TypedDict, total=False): """The type of the output text. Always `output_text`.""" -class InputContentInputImage(TypedDict, total=False): - """An image input to the model.""" +class InputContentEvalItemInputImage(TypedDict, total=False): + """An image input block used within EvalItem content arrays.""" image_url: Required[str] """The URL of the image input.""" @@ -45,13 +49,47 @@ class InputContentInputImage(TypedDict, total=False): """ +class InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText(TypedDict, total=False): + """A text output from the model.""" + + text: Required[str] + """The text output from the model.""" + + type: Required[Literal["output_text"]] + """The type of the output text. Always `output_text`.""" + + +class InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage(TypedDict, total=False): + """An image input block used within EvalItem content arrays.""" + + image_url: Required[str] + """The URL of the image input.""" + + type: Required[Literal["input_image"]] + """The type of the image input. Always `input_image`.""" + + detail: str + """The detail level of the image to be sent to the model. + + One of `high`, `low`, or `auto`. Defaults to `auto`. + """ + + +InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudio: TypeAlias = Union[ + str, + ResponseInputTextParam, + InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText, + InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage, + ResponseInputAudioParam, +] + InputContent: TypeAlias = Union[ str, ResponseInputTextParam, InputContentOutputText, - InputContentInputImage, + InputContentEvalItemInputImage, ResponseInputAudioParam, - Iterable[object], + SequenceNotStr[InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudio], ] @@ -65,7 +103,11 @@ class Input(TypedDict, total=False): """ content: Required[InputContent] - """Inputs to the model - can contain template strings.""" + """Inputs to the model - can contain template strings. + + Supports text, output text, input images, and input audio, either as a single + item or an array of items. + """ role: Required[Literal["user", "assistant", "system", "developer"]] """The role of the message input. diff --git a/src/openai/types/video_model.py b/src/openai/types/video_model.py index 0b0835fca4..e96e7685f8 100644 --- a/src/openai/types/video_model.py +++ b/src/openai/types/video_model.py @@ -4,4 +4,6 @@ __all__ = ["VideoModel"] -VideoModel: TypeAlias = Literal["sora-2", "sora-2-pro"] +VideoModel: TypeAlias = Literal[ + "sora-2", "sora-2-pro", "sora-2-2025-10-06", "sora-2-pro-2025-10-06", "sora-2-2025-12-08" +] From 8bb16f7aedf919646e66ddc591fe283d770b8257 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 13 Dec 2025 03:23:48 +0000 Subject: [PATCH 570/769] feat(api): fix grader input list, add dated slugs for sora-2 --- .stats.yml | 6 +- api.md | 1 + src/openai/types/eval_create_params.py | 50 ++--------------- ...create_eval_completions_run_data_source.py | 50 ++--------------- ..._eval_completions_run_data_source_param.py | 51 ++--------------- src/openai/types/evals/run_cancel_response.py | 52 ++---------------- src/openai/types/evals/run_create_params.py | 52 ++---------------- src/openai/types/evals/run_create_response.py | 52 ++---------------- src/openai/types/evals/run_list_response.py | 52 ++---------------- .../types/evals/run_retrieve_response.py | 52 ++---------------- src/openai/types/graders/__init__.py | 2 + src/openai/types/graders/grader_inputs.py | 43 +++++++++++++++ .../types/graders/grader_inputs_param.py | 53 ++++++++++++++++++ .../types/graders/label_model_grader.py | 55 ++----------------- .../types/graders/label_model_grader_param.py | 52 ++---------------- .../types/graders/score_model_grader.py | 49 ++--------------- .../types/graders/score_model_grader_param.py | 47 ++-------------- 17 files changed, 160 insertions(+), 559 deletions(-) create mode 100644 src/openai/types/graders/grader_inputs.py create mode 100644 src/openai/types/graders/grader_inputs_param.py diff --git a/.stats.yml b/.stats.yml index 595620b8ac..2d7e7248c7 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 137 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-386042697a8769999956bdc26ff1e70bfc2a56913f724eedc6bfaf82679e9956.yml -openapi_spec_hash: 7072a6a4a43d7ff0bb4098a3e8a6b9a7 -config_hash: 141b101c9f13b90e21af74e1686f1f41 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-fe8e67bdc351a518b113ab48e775750190e207807903d6b03ab22c438c38a588.yml +openapi_spec_hash: 8af972190647ffb9dcec516e19d8761a +config_hash: 856bee50ee3617e85a9bc9274db01dbb diff --git a/api.md b/api.md index 3807603206..1c054b52fc 100644 --- a/api.md +++ b/api.md @@ -342,6 +342,7 @@ Types: ```python from openai.types.graders import ( + GraderInputs, LabelModelGrader, MultiGrader, PythonGrader, diff --git a/src/openai/types/eval_create_params.py b/src/openai/types/eval_create_params.py index bfb39568c2..a1d5ea5371 100644 --- a/src/openai/types/eval_create_params.py +++ b/src/openai/types/eval_create_params.py @@ -7,6 +7,7 @@ from .._types import SequenceNotStr from .shared_params.metadata import Metadata +from .graders.grader_inputs_param import GraderInputsParam from .graders.python_grader_param import PythonGraderParam from .graders.score_model_grader_param import ScoreModelGraderParam from .graders.string_check_grader_param import StringCheckGraderParam @@ -27,10 +28,7 @@ "TestingCriterionLabelModelInputEvalItem", "TestingCriterionLabelModelInputEvalItemContent", "TestingCriterionLabelModelInputEvalItemContentOutputText", - "TestingCriterionLabelModelInputEvalItemContentEvalItemInputImage", - "TestingCriterionLabelModelInputEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio", - "TestingCriterionLabelModelInputEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText", - "TestingCriterionLabelModelInputEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage", + "TestingCriterionLabelModelInputEvalItemContentInputImage", "TestingCriterionTextSimilarity", "TestingCriterionPython", "TestingCriterionScoreModel", @@ -131,7 +129,7 @@ class TestingCriterionLabelModelInputEvalItemContentOutputText(TypedDict, total= """The type of the output text. Always `output_text`.""" -class TestingCriterionLabelModelInputEvalItemContentEvalItemInputImage(TypedDict, total=False): +class TestingCriterionLabelModelInputEvalItemContentInputImage(TypedDict, total=False): """An image input block used within EvalItem content arrays.""" image_url: Required[str] @@ -147,51 +145,13 @@ class TestingCriterionLabelModelInputEvalItemContentEvalItemInputImage(TypedDict """ -class TestingCriterionLabelModelInputEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText( - TypedDict, total=False -): - """A text output from the model.""" - - text: Required[str] - """The text output from the model.""" - - type: Required[Literal["output_text"]] - """The type of the output text. Always `output_text`.""" - - -class TestingCriterionLabelModelInputEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage( - TypedDict, total=False -): - """An image input block used within EvalItem content arrays.""" - - image_url: Required[str] - """The URL of the image input.""" - - type: Required[Literal["input_image"]] - """The type of the image input. Always `input_image`.""" - - detail: str - """The detail level of the image to be sent to the model. - - One of `high`, `low`, or `auto`. Defaults to `auto`. - """ - - -TestingCriterionLabelModelInputEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio: TypeAlias = Union[ - str, - ResponseInputTextParam, - TestingCriterionLabelModelInputEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText, - TestingCriterionLabelModelInputEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage, - ResponseInputAudioParam, -] - TestingCriterionLabelModelInputEvalItemContent: TypeAlias = Union[ str, ResponseInputTextParam, TestingCriterionLabelModelInputEvalItemContentOutputText, - TestingCriterionLabelModelInputEvalItemContentEvalItemInputImage, + TestingCriterionLabelModelInputEvalItemContentInputImage, ResponseInputAudioParam, - SequenceNotStr[TestingCriterionLabelModelInputEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio], + GraderInputsParam, ] diff --git a/src/openai/types/evals/create_eval_completions_run_data_source.py b/src/openai/types/evals/create_eval_completions_run_data_source.py index 34118c0dfb..726ae6abf0 100644 --- a/src/openai/types/evals/create_eval_completions_run_data_source.py +++ b/src/openai/types/evals/create_eval_completions_run_data_source.py @@ -6,6 +6,7 @@ from ..._utils import PropertyInfo from ..._models import BaseModel from ..shared.metadata import Metadata +from ..graders.grader_inputs import GraderInputs from ..shared.reasoning_effort import ReasoningEffort from ..shared.response_format_text import ResponseFormatText from ..responses.easy_input_message import EasyInputMessage @@ -28,10 +29,7 @@ "InputMessagesTemplateTemplateEvalItem", "InputMessagesTemplateTemplateEvalItemContent", "InputMessagesTemplateTemplateEvalItemContentOutputText", - "InputMessagesTemplateTemplateEvalItemContentEvalItemInputImage", - "InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio", - "InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText", - "InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage", + "InputMessagesTemplateTemplateEvalItemContentInputImage", "InputMessagesItemReference", "SamplingParams", "SamplingParamsResponseFormat", @@ -104,7 +102,7 @@ class InputMessagesTemplateTemplateEvalItemContentOutputText(BaseModel): """The type of the output text. Always `output_text`.""" -class InputMessagesTemplateTemplateEvalItemContentEvalItemInputImage(BaseModel): +class InputMessagesTemplateTemplateEvalItemContentInputImage(BaseModel): """An image input block used within EvalItem content arrays.""" image_url: str @@ -120,51 +118,13 @@ class InputMessagesTemplateTemplateEvalItemContentEvalItemInputImage(BaseModel): """ -class InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText( - BaseModel -): - """A text output from the model.""" - - text: str - """The text output from the model.""" - - type: Literal["output_text"] - """The type of the output text. Always `output_text`.""" - - -class InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage( - BaseModel -): - """An image input block used within EvalItem content arrays.""" - - image_url: str - """The URL of the image input.""" - - type: Literal["input_image"] - """The type of the image input. Always `input_image`.""" - - detail: Optional[str] = None - """The detail level of the image to be sent to the model. - - One of `high`, `low`, or `auto`. Defaults to `auto`. - """ - - -InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio: TypeAlias = Union[ - str, - ResponseInputText, - InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText, - InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage, - ResponseInputAudio, -] - InputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ str, ResponseInputText, InputMessagesTemplateTemplateEvalItemContentOutputText, - InputMessagesTemplateTemplateEvalItemContentEvalItemInputImage, + InputMessagesTemplateTemplateEvalItemContentInputImage, ResponseInputAudio, - List[InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio], + GraderInputs, ] diff --git a/src/openai/types/evals/create_eval_completions_run_data_source_param.py b/src/openai/types/evals/create_eval_completions_run_data_source_param.py index 64c4844d43..6842f84af9 100644 --- a/src/openai/types/evals/create_eval_completions_run_data_source_param.py +++ b/src/openai/types/evals/create_eval_completions_run_data_source_param.py @@ -5,9 +5,9 @@ from typing import Dict, Union, Iterable, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict -from ..._types import SequenceNotStr from ..shared_params.metadata import Metadata from ..shared.reasoning_effort import ReasoningEffort +from ..graders.grader_inputs_param import GraderInputsParam from ..responses.easy_input_message_param import EasyInputMessageParam from ..shared_params.response_format_text import ResponseFormatText from ..responses.response_input_text_param import ResponseInputTextParam @@ -29,10 +29,7 @@ "InputMessagesTemplateTemplateEvalItem", "InputMessagesTemplateTemplateEvalItemContent", "InputMessagesTemplateTemplateEvalItemContentOutputText", - "InputMessagesTemplateTemplateEvalItemContentEvalItemInputImage", - "InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio", - "InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText", - "InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage", + "InputMessagesTemplateTemplateEvalItemContentInputImage", "InputMessagesItemReference", "SamplingParams", "SamplingParamsResponseFormat", @@ -103,7 +100,7 @@ class InputMessagesTemplateTemplateEvalItemContentOutputText(TypedDict, total=Fa """The type of the output text. Always `output_text`.""" -class InputMessagesTemplateTemplateEvalItemContentEvalItemInputImage(TypedDict, total=False): +class InputMessagesTemplateTemplateEvalItemContentInputImage(TypedDict, total=False): """An image input block used within EvalItem content arrays.""" image_url: Required[str] @@ -119,51 +116,13 @@ class InputMessagesTemplateTemplateEvalItemContentEvalItemInputImage(TypedDict, """ -class InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText( - TypedDict, total=False -): - """A text output from the model.""" - - text: Required[str] - """The text output from the model.""" - - type: Required[Literal["output_text"]] - """The type of the output text. Always `output_text`.""" - - -class InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage( - TypedDict, total=False -): - """An image input block used within EvalItem content arrays.""" - - image_url: Required[str] - """The URL of the image input.""" - - type: Required[Literal["input_image"]] - """The type of the image input. Always `input_image`.""" - - detail: str - """The detail level of the image to be sent to the model. - - One of `high`, `low`, or `auto`. Defaults to `auto`. - """ - - -InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio: TypeAlias = Union[ - str, - ResponseInputTextParam, - InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText, - InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage, - ResponseInputAudioParam, -] - InputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ str, ResponseInputTextParam, InputMessagesTemplateTemplateEvalItemContentOutputText, - InputMessagesTemplateTemplateEvalItemContentEvalItemInputImage, + InputMessagesTemplateTemplateEvalItemContentInputImage, ResponseInputAudioParam, - SequenceNotStr[InputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio], + GraderInputsParam, ] diff --git a/src/openai/types/evals/run_cancel_response.py b/src/openai/types/evals/run_cancel_response.py index 791b1f0444..ea4797eecb 100644 --- a/src/openai/types/evals/run_cancel_response.py +++ b/src/openai/types/evals/run_cancel_response.py @@ -10,6 +10,7 @@ from .eval_api_error import EvalAPIError from ..responses.tool import Tool from ..shared.metadata import Metadata +from ..graders.grader_inputs import GraderInputs from ..shared.reasoning_effort import ReasoningEffort from ..responses.response_input_text import ResponseInputText from ..responses.response_input_audio import ResponseInputAudio @@ -33,10 +34,7 @@ "DataSourceResponsesInputMessagesTemplateTemplateEvalItem", "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent", "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentEvalItemInputImage", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage", "DataSourceResponsesInputMessagesItemReference", "DataSourceResponsesSamplingParams", "DataSourceResponsesSamplingParamsText", @@ -158,7 +156,7 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText( """The type of the output text. Always `output_text`.""" -class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentEvalItemInputImage(BaseModel): +class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage(BaseModel): """An image input block used within EvalItem content arrays.""" image_url: str @@ -174,53 +172,13 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentEvalItemInp """ -class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText( - BaseModel -): - """A text output from the model.""" - - text: str - """The text output from the model.""" - - type: Literal["output_text"] - """The type of the output text. Always `output_text`.""" - - -class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage( - BaseModel -): - """An image input block used within EvalItem content arrays.""" - - image_url: str - """The URL of the image input.""" - - type: Literal["input_image"] - """The type of the image input. Always `input_image`.""" - - detail: Optional[str] = None - """The detail level of the image to be sent to the model. - - One of `high`, `low`, or `auto`. Defaults to `auto`. - """ - - -DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio: TypeAlias = Union[ - str, - ResponseInputText, - DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText, - DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage, - ResponseInputAudio, -] - DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ str, ResponseInputText, DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText, - DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentEvalItemInputImage, + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage, ResponseInputAudio, - List[ - DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio - ], + GraderInputs, ] diff --git a/src/openai/types/evals/run_create_params.py b/src/openai/types/evals/run_create_params.py index 0717f2ee20..02804c30da 100644 --- a/src/openai/types/evals/run_create_params.py +++ b/src/openai/types/evals/run_create_params.py @@ -9,6 +9,7 @@ from ..responses.tool_param import ToolParam from ..shared_params.metadata import Metadata from ..shared.reasoning_effort import ReasoningEffort +from ..graders.grader_inputs_param import GraderInputsParam from ..responses.response_input_text_param import ResponseInputTextParam from ..responses.response_input_audio_param import ResponseInputAudioParam from .create_eval_jsonl_run_data_source_param import CreateEvalJSONLRunDataSourceParam @@ -31,10 +32,7 @@ "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItem", "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContent", "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentOutputText", - "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentEvalItemInputImage", - "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio", - "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText", - "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage", + "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentInputImage", "DataSourceCreateEvalResponsesRunDataSourceInputMessagesItemReference", "DataSourceCreateEvalResponsesRunDataSourceSamplingParams", "DataSourceCreateEvalResponsesRunDataSourceSamplingParamsText", @@ -174,7 +172,7 @@ class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEva """The type of the output text. Always `output_text`.""" -class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentEvalItemInputImage( +class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentInputImage( TypedDict, total=False ): """An image input block used within EvalItem content arrays.""" @@ -192,53 +190,13 @@ class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEva """ -class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText( - TypedDict, total=False -): - """A text output from the model.""" - - text: Required[str] - """The text output from the model.""" - - type: Required[Literal["output_text"]] - """The type of the output text. Always `output_text`.""" - - -class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage( - TypedDict, total=False -): - """An image input block used within EvalItem content arrays.""" - - image_url: Required[str] - """The URL of the image input.""" - - type: Required[Literal["input_image"]] - """The type of the image input. Always `input_image`.""" - - detail: str - """The detail level of the image to be sent to the model. - - One of `high`, `low`, or `auto`. Defaults to `auto`. - """ - - -DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio: TypeAlias = Union[ - str, - ResponseInputTextParam, - DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText, - DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage, - ResponseInputAudioParam, -] - DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ str, ResponseInputTextParam, DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentOutputText, - DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentEvalItemInputImage, + DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentInputImage, ResponseInputAudioParam, - SequenceNotStr[ - DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio - ], + GraderInputsParam, ] diff --git a/src/openai/types/evals/run_create_response.py b/src/openai/types/evals/run_create_response.py index a860bd178a..2cb856de6f 100644 --- a/src/openai/types/evals/run_create_response.py +++ b/src/openai/types/evals/run_create_response.py @@ -10,6 +10,7 @@ from .eval_api_error import EvalAPIError from ..responses.tool import Tool from ..shared.metadata import Metadata +from ..graders.grader_inputs import GraderInputs from ..shared.reasoning_effort import ReasoningEffort from ..responses.response_input_text import ResponseInputText from ..responses.response_input_audio import ResponseInputAudio @@ -33,10 +34,7 @@ "DataSourceResponsesInputMessagesTemplateTemplateEvalItem", "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent", "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentEvalItemInputImage", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage", "DataSourceResponsesInputMessagesItemReference", "DataSourceResponsesSamplingParams", "DataSourceResponsesSamplingParamsText", @@ -158,7 +156,7 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText( """The type of the output text. Always `output_text`.""" -class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentEvalItemInputImage(BaseModel): +class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage(BaseModel): """An image input block used within EvalItem content arrays.""" image_url: str @@ -174,53 +172,13 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentEvalItemInp """ -class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText( - BaseModel -): - """A text output from the model.""" - - text: str - """The text output from the model.""" - - type: Literal["output_text"] - """The type of the output text. Always `output_text`.""" - - -class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage( - BaseModel -): - """An image input block used within EvalItem content arrays.""" - - image_url: str - """The URL of the image input.""" - - type: Literal["input_image"] - """The type of the image input. Always `input_image`.""" - - detail: Optional[str] = None - """The detail level of the image to be sent to the model. - - One of `high`, `low`, or `auto`. Defaults to `auto`. - """ - - -DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio: TypeAlias = Union[ - str, - ResponseInputText, - DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText, - DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage, - ResponseInputAudio, -] - DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ str, ResponseInputText, DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText, - DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentEvalItemInputImage, + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage, ResponseInputAudio, - List[ - DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio - ], + GraderInputs, ] diff --git a/src/openai/types/evals/run_list_response.py b/src/openai/types/evals/run_list_response.py index aee471e2b6..defd4aa6f9 100644 --- a/src/openai/types/evals/run_list_response.py +++ b/src/openai/types/evals/run_list_response.py @@ -10,6 +10,7 @@ from .eval_api_error import EvalAPIError from ..responses.tool import Tool from ..shared.metadata import Metadata +from ..graders.grader_inputs import GraderInputs from ..shared.reasoning_effort import ReasoningEffort from ..responses.response_input_text import ResponseInputText from ..responses.response_input_audio import ResponseInputAudio @@ -33,10 +34,7 @@ "DataSourceResponsesInputMessagesTemplateTemplateEvalItem", "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent", "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentEvalItemInputImage", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage", "DataSourceResponsesInputMessagesItemReference", "DataSourceResponsesSamplingParams", "DataSourceResponsesSamplingParamsText", @@ -158,7 +156,7 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText( """The type of the output text. Always `output_text`.""" -class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentEvalItemInputImage(BaseModel): +class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage(BaseModel): """An image input block used within EvalItem content arrays.""" image_url: str @@ -174,53 +172,13 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentEvalItemInp """ -class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText( - BaseModel -): - """A text output from the model.""" - - text: str - """The text output from the model.""" - - type: Literal["output_text"] - """The type of the output text. Always `output_text`.""" - - -class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage( - BaseModel -): - """An image input block used within EvalItem content arrays.""" - - image_url: str - """The URL of the image input.""" - - type: Literal["input_image"] - """The type of the image input. Always `input_image`.""" - - detail: Optional[str] = None - """The detail level of the image to be sent to the model. - - One of `high`, `low`, or `auto`. Defaults to `auto`. - """ - - -DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio: TypeAlias = Union[ - str, - ResponseInputText, - DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText, - DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage, - ResponseInputAudio, -] - DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ str, ResponseInputText, DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText, - DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentEvalItemInputImage, + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage, ResponseInputAudio, - List[ - DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio - ], + GraderInputs, ] diff --git a/src/openai/types/evals/run_retrieve_response.py b/src/openai/types/evals/run_retrieve_response.py index ff3564de54..4c218a0510 100644 --- a/src/openai/types/evals/run_retrieve_response.py +++ b/src/openai/types/evals/run_retrieve_response.py @@ -10,6 +10,7 @@ from .eval_api_error import EvalAPIError from ..responses.tool import Tool from ..shared.metadata import Metadata +from ..graders.grader_inputs import GraderInputs from ..shared.reasoning_effort import ReasoningEffort from ..responses.response_input_text import ResponseInputText from ..responses.response_input_audio import ResponseInputAudio @@ -33,10 +34,7 @@ "DataSourceResponsesInputMessagesTemplateTemplateEvalItem", "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent", "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentEvalItemInputImage", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage", + "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage", "DataSourceResponsesInputMessagesItemReference", "DataSourceResponsesSamplingParams", "DataSourceResponsesSamplingParamsText", @@ -158,7 +156,7 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText( """The type of the output text. Always `output_text`.""" -class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentEvalItemInputImage(BaseModel): +class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage(BaseModel): """An image input block used within EvalItem content arrays.""" image_url: str @@ -174,53 +172,13 @@ class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentEvalItemInp """ -class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText( - BaseModel -): - """A text output from the model.""" - - text: str - """The text output from the model.""" - - type: Literal["output_text"] - """The type of the output text. Always `output_text`.""" - - -class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage( - BaseModel -): - """An image input block used within EvalItem content arrays.""" - - image_url: str - """The URL of the image input.""" - - type: Literal["input_image"] - """The type of the image input. Always `input_image`.""" - - detail: Optional[str] = None - """The detail level of the image to be sent to the model. - - One of `high`, `low`, or `auto`. Defaults to `auto`. - """ - - -DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio: TypeAlias = Union[ - str, - ResponseInputText, - DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText, - DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage, - ResponseInputAudio, -] - DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ str, ResponseInputText, DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText, - DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentEvalItemInputImage, + DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage, ResponseInputAudio, - List[ - DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentAnArrayOfInputTextOutputTextInputImageAndInputAudio - ], + GraderInputs, ] diff --git a/src/openai/types/graders/__init__.py b/src/openai/types/graders/__init__.py index e0a909125e..4f70eb6c2f 100644 --- a/src/openai/types/graders/__init__.py +++ b/src/openai/types/graders/__init__.py @@ -3,10 +3,12 @@ from __future__ import annotations from .multi_grader import MultiGrader as MultiGrader +from .grader_inputs import GraderInputs as GraderInputs from .python_grader import PythonGrader as PythonGrader from .label_model_grader import LabelModelGrader as LabelModelGrader from .multi_grader_param import MultiGraderParam as MultiGraderParam from .score_model_grader import ScoreModelGrader as ScoreModelGrader +from .grader_inputs_param import GraderInputsParam as GraderInputsParam from .python_grader_param import PythonGraderParam as PythonGraderParam from .string_check_grader import StringCheckGrader as StringCheckGrader from .text_similarity_grader import TextSimilarityGrader as TextSimilarityGrader diff --git a/src/openai/types/graders/grader_inputs.py b/src/openai/types/graders/grader_inputs.py new file mode 100644 index 0000000000..edc966d889 --- /dev/null +++ b/src/openai/types/graders/grader_inputs.py @@ -0,0 +1,43 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, TypeAlias + +from ..._models import BaseModel +from ..responses.response_input_text import ResponseInputText +from ..responses.response_input_audio import ResponseInputAudio + +__all__ = ["GraderInputs", "GraderInputItem", "GraderInputItemOutputText", "GraderInputItemInputImage"] + + +class GraderInputItemOutputText(BaseModel): + """A text output from the model.""" + + text: str + """The text output from the model.""" + + type: Literal["output_text"] + """The type of the output text. Always `output_text`.""" + + +class GraderInputItemInputImage(BaseModel): + """An image input block used within EvalItem content arrays.""" + + image_url: str + """The URL of the image input.""" + + type: Literal["input_image"] + """The type of the image input. Always `input_image`.""" + + detail: Optional[str] = None + """The detail level of the image to be sent to the model. + + One of `high`, `low`, or `auto`. Defaults to `auto`. + """ + + +GraderInputItem: TypeAlias = Union[ + str, ResponseInputText, GraderInputItemOutputText, GraderInputItemInputImage, ResponseInputAudio +] + +GraderInputs: TypeAlias = List[GraderInputItem] diff --git a/src/openai/types/graders/grader_inputs_param.py b/src/openai/types/graders/grader_inputs_param.py new file mode 100644 index 0000000000..7d8341eb32 --- /dev/null +++ b/src/openai/types/graders/grader_inputs_param.py @@ -0,0 +1,53 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from ..responses.response_input_text_param import ResponseInputTextParam +from ..responses.response_input_audio_param import ResponseInputAudioParam + +__all__ = [ + "GraderInputsParam", + "GraderInputsParamItem", + "GraderInputsParamItemOutputText", + "GraderInputsParamItemInputImage", +] + + +class GraderInputsParamItemOutputText(TypedDict, total=False): + """A text output from the model.""" + + text: Required[str] + """The text output from the model.""" + + type: Required[Literal["output_text"]] + """The type of the output text. Always `output_text`.""" + + +class GraderInputsParamItemInputImage(TypedDict, total=False): + """An image input block used within EvalItem content arrays.""" + + image_url: Required[str] + """The URL of the image input.""" + + type: Required[Literal["input_image"]] + """The type of the image input. Always `input_image`.""" + + detail: str + """The detail level of the image to be sent to the model. + + One of `high`, `low`, or `auto`. Defaults to `auto`. + """ + + +GraderInputsParamItem: TypeAlias = Union[ + str, + ResponseInputTextParam, + GraderInputsParamItemOutputText, + GraderInputsParamItemInputImage, + ResponseInputAudioParam, +] + +GraderInputsParam: TypeAlias = List[GraderInputsParamItem] diff --git a/src/openai/types/graders/label_model_grader.py b/src/openai/types/graders/label_model_grader.py index def3dd7602..d3c942235e 100644 --- a/src/openai/types/graders/label_model_grader.py +++ b/src/openai/types/graders/label_model_grader.py @@ -4,19 +4,11 @@ from typing_extensions import Literal, TypeAlias from ..._models import BaseModel +from .grader_inputs import GraderInputs from ..responses.response_input_text import ResponseInputText from ..responses.response_input_audio import ResponseInputAudio -__all__ = [ - "LabelModelGrader", - "Input", - "InputContent", - "InputContentOutputText", - "InputContentEvalItemInputImage", - "InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudio", - "InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText", - "InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage", -] +__all__ = ["LabelModelGrader", "Input", "InputContent", "InputContentOutputText", "InputContentInputImage"] class InputContentOutputText(BaseModel): @@ -29,7 +21,7 @@ class InputContentOutputText(BaseModel): """The type of the output text. Always `output_text`.""" -class InputContentEvalItemInputImage(BaseModel): +class InputContentInputImage(BaseModel): """An image input block used within EvalItem content arrays.""" image_url: str @@ -45,47 +37,8 @@ class InputContentEvalItemInputImage(BaseModel): """ -class InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText(BaseModel): - """A text output from the model.""" - - text: str - """The text output from the model.""" - - type: Literal["output_text"] - """The type of the output text. Always `output_text`.""" - - -class InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage(BaseModel): - """An image input block used within EvalItem content arrays.""" - - image_url: str - """The URL of the image input.""" - - type: Literal["input_image"] - """The type of the image input. Always `input_image`.""" - - detail: Optional[str] = None - """The detail level of the image to be sent to the model. - - One of `high`, `low`, or `auto`. Defaults to `auto`. - """ - - -InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudio: TypeAlias = Union[ - str, - ResponseInputText, - InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText, - InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage, - ResponseInputAudio, -] - InputContent: TypeAlias = Union[ - str, - ResponseInputText, - InputContentOutputText, - InputContentEvalItemInputImage, - ResponseInputAudio, - List[InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudio], + str, ResponseInputText, InputContentOutputText, InputContentInputImage, ResponseInputAudio, GraderInputs ] diff --git a/src/openai/types/graders/label_model_grader_param.py b/src/openai/types/graders/label_model_grader_param.py index 6b6faa465d..a5b6959cff 100644 --- a/src/openai/types/graders/label_model_grader_param.py +++ b/src/openai/types/graders/label_model_grader_param.py @@ -6,19 +6,11 @@ from typing_extensions import Literal, Required, TypeAlias, TypedDict from ..._types import SequenceNotStr +from .grader_inputs_param import GraderInputsParam from ..responses.response_input_text_param import ResponseInputTextParam from ..responses.response_input_audio_param import ResponseInputAudioParam -__all__ = [ - "LabelModelGraderParam", - "Input", - "InputContent", - "InputContentOutputText", - "InputContentEvalItemInputImage", - "InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudio", - "InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText", - "InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage", -] +__all__ = ["LabelModelGraderParam", "Input", "InputContent", "InputContentOutputText", "InputContentInputImage"] class InputContentOutputText(TypedDict, total=False): @@ -31,33 +23,7 @@ class InputContentOutputText(TypedDict, total=False): """The type of the output text. Always `output_text`.""" -class InputContentEvalItemInputImage(TypedDict, total=False): - """An image input block used within EvalItem content arrays.""" - - image_url: Required[str] - """The URL of the image input.""" - - type: Required[Literal["input_image"]] - """The type of the image input. Always `input_image`.""" - - detail: str - """The detail level of the image to be sent to the model. - - One of `high`, `low`, or `auto`. Defaults to `auto`. - """ - - -class InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText(TypedDict, total=False): - """A text output from the model.""" - - text: Required[str] - """The text output from the model.""" - - type: Required[Literal["output_text"]] - """The type of the output text. Always `output_text`.""" - - -class InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage(TypedDict, total=False): +class InputContentInputImage(TypedDict, total=False): """An image input block used within EvalItem content arrays.""" image_url: Required[str] @@ -73,21 +39,13 @@ class InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInp """ -InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudio: TypeAlias = Union[ - str, - ResponseInputTextParam, - InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText, - InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage, - ResponseInputAudioParam, -] - InputContent: TypeAlias = Union[ str, ResponseInputTextParam, InputContentOutputText, - InputContentEvalItemInputImage, + InputContentInputImage, ResponseInputAudioParam, - SequenceNotStr[InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudio], + GraderInputsParam, ] diff --git a/src/openai/types/graders/score_model_grader.py b/src/openai/types/graders/score_model_grader.py index 7787c82bb6..85d11e8666 100644 --- a/src/openai/types/graders/score_model_grader.py +++ b/src/openai/types/graders/score_model_grader.py @@ -4,6 +4,7 @@ from typing_extensions import Literal, TypeAlias from ..._models import BaseModel +from .grader_inputs import GraderInputs from ..shared.reasoning_effort import ReasoningEffort from ..responses.response_input_text import ResponseInputText from ..responses.response_input_audio import ResponseInputAudio @@ -13,10 +14,7 @@ "Input", "InputContent", "InputContentOutputText", - "InputContentEvalItemInputImage", - "InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudio", - "InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText", - "InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage", + "InputContentInputImage", "SamplingParams", ] @@ -31,7 +29,7 @@ class InputContentOutputText(BaseModel): """The type of the output text. Always `output_text`.""" -class InputContentEvalItemInputImage(BaseModel): +class InputContentInputImage(BaseModel): """An image input block used within EvalItem content arrays.""" image_url: str @@ -47,47 +45,8 @@ class InputContentEvalItemInputImage(BaseModel): """ -class InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText(BaseModel): - """A text output from the model.""" - - text: str - """The text output from the model.""" - - type: Literal["output_text"] - """The type of the output text. Always `output_text`.""" - - -class InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage(BaseModel): - """An image input block used within EvalItem content arrays.""" - - image_url: str - """The URL of the image input.""" - - type: Literal["input_image"] - """The type of the image input. Always `input_image`.""" - - detail: Optional[str] = None - """The detail level of the image to be sent to the model. - - One of `high`, `low`, or `auto`. Defaults to `auto`. - """ - - -InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudio: TypeAlias = Union[ - str, - ResponseInputText, - InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText, - InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage, - ResponseInputAudio, -] - InputContent: TypeAlias = Union[ - str, - ResponseInputText, - InputContentOutputText, - InputContentEvalItemInputImage, - ResponseInputAudio, - List[InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudio], + str, ResponseInputText, InputContentOutputText, InputContentInputImage, ResponseInputAudio, GraderInputs ] diff --git a/src/openai/types/graders/score_model_grader_param.py b/src/openai/types/graders/score_model_grader_param.py index 1f9475d885..9f1c42e051 100644 --- a/src/openai/types/graders/score_model_grader_param.py +++ b/src/openai/types/graders/score_model_grader_param.py @@ -5,7 +5,7 @@ from typing import Union, Iterable, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict -from ..._types import SequenceNotStr +from .grader_inputs_param import GraderInputsParam from ..shared.reasoning_effort import ReasoningEffort from ..responses.response_input_text_param import ResponseInputTextParam from ..responses.response_input_audio_param import ResponseInputAudioParam @@ -15,10 +15,7 @@ "Input", "InputContent", "InputContentOutputText", - "InputContentEvalItemInputImage", - "InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudio", - "InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText", - "InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage", + "InputContentInputImage", "SamplingParams", ] @@ -33,7 +30,7 @@ class InputContentOutputText(TypedDict, total=False): """The type of the output text. Always `output_text`.""" -class InputContentEvalItemInputImage(TypedDict, total=False): +class InputContentInputImage(TypedDict, total=False): """An image input block used within EvalItem content arrays.""" image_url: Required[str] @@ -49,47 +46,13 @@ class InputContentEvalItemInputImage(TypedDict, total=False): """ -class InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText(TypedDict, total=False): - """A text output from the model.""" - - text: Required[str] - """The text output from the model.""" - - type: Required[Literal["output_text"]] - """The type of the output text. Always `output_text`.""" - - -class InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage(TypedDict, total=False): - """An image input block used within EvalItem content arrays.""" - - image_url: Required[str] - """The URL of the image input.""" - - type: Required[Literal["input_image"]] - """The type of the image input. Always `input_image`.""" - - detail: str - """The detail level of the image to be sent to the model. - - One of `high`, `low`, or `auto`. Defaults to `auto`. - """ - - -InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudio: TypeAlias = Union[ - str, - ResponseInputTextParam, - InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioOutputText, - InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudioEvalItemInputImage, - ResponseInputAudioParam, -] - InputContent: TypeAlias = Union[ str, ResponseInputTextParam, InputContentOutputText, - InputContentEvalItemInputImage, + InputContentInputImage, ResponseInputAudioParam, - SequenceNotStr[InputContentAnArrayOfInputTextOutputTextInputImageAndInputAudio], + GraderInputsParam, ] From 9688ac0a47ea5083d7b08c2b22186b1232d8a87f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 15 Dec 2025 05:07:08 +0000 Subject: [PATCH 571/769] release: 2.12.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 9 +++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index e6c39adb99..0746cbe20a 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.11.0" + ".": "2.12.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index ff0878433f..ec61efaf79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 2.12.0 (2025-12-15) + +Full Changelog: [v2.11.0...v2.12.0](https://github.com/openai/openai-python/compare/v2.11.0...v2.12.0) + +### Features + +* **api:** api update ([a95c4d0](https://github.com/openai/openai-python/commit/a95c4d0952ff5eb767206574e687cb029a49a4ab)) +* **api:** fix grader input list, add dated slugs for sora-2 ([b2c389b](https://github.com/openai/openai-python/commit/b2c389bf5c3bde50bac2d9f60cce58f4aef44a41)) + ## 2.11.0 (2025-12-11) Full Changelog: [v2.10.0...v2.11.0](https://github.com/openai/openai-python/compare/v2.10.0...v2.11.0) diff --git a/pyproject.toml b/pyproject.toml index f4e5bdb208..7d6fec5c1a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.11.0" +version = "2.12.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 16036c3b6a..9d853d6512 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__ = "2.11.0" # x-release-please-version +__version__ = "2.12.0" # x-release-please-version From 445d6beb8eff696b513401d6e5537c372d34dd28 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 15 Dec 2025 17:42:34 +0000 Subject: [PATCH 572/769] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 2d7e7248c7..3793c0f01b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 137 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-fe8e67bdc351a518b113ab48e775750190e207807903d6b03ab22c438c38a588.yml openapi_spec_hash: 8af972190647ffb9dcec516e19d8761a -config_hash: 856bee50ee3617e85a9bc9274db01dbb +config_hash: d013f4fdd4dd59c6f376a9ca482b7f9e From 3c016c6d943e627e9135a67c5bb2fc92d423e9a1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 15 Dec 2025 19:18:24 +0000 Subject: [PATCH 573/769] chore(internal): add missing files argument to base client --- src/openai/_base_client.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index 58490e4430..c0cac43daa 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -1264,9 +1264,12 @@ def patch( *, cast_to: Type[ResponseT], body: Body | None = None, + files: RequestFiles | None = None, options: RequestOptions = {}, ) -> ResponseT: - opts = FinalRequestOptions.construct(method="patch", url=path, json_data=body, **options) + opts = FinalRequestOptions.construct( + method="patch", url=path, json_data=body, files=to_httpx_files(files), **options + ) return self.request(cast_to, opts) def put( @@ -1799,9 +1802,12 @@ async def patch( *, cast_to: Type[ResponseT], body: Body | None = None, + files: RequestFiles | None = None, options: RequestOptions = {}, ) -> ResponseT: - opts = FinalRequestOptions.construct(method="patch", url=path, json_data=body, **options) + opts = FinalRequestOptions.construct( + method="patch", url=path, json_data=body, files=to_httpx_files(files), **options + ) return await self.request(cast_to, opts) async def put( From 74b1e6f9b9e14a923c63b9681eda6af635207391 Mon Sep 17 00:00:00 2001 From: cameron-stainless Date: Tue, 16 Dec 2025 10:28:21 -0500 Subject: [PATCH 574/769] chore(ci): add CI job to detect breaking changes with the Agents SDK (#1436) * chore: Add CI job to detect breaking changes with agents lib * chore: Make changes based on PR comments * chore: Add newline after each new step --------- Co-authored-by: Cameron McAteer --- .github/workflows/detect-breaking-changes.yml | 50 ++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/.github/workflows/detect-breaking-changes.yml b/.github/workflows/detect-breaking-changes.yml index f10fdf3b19..6626d1c376 100644 --- a/.github/workflows/detect-breaking-changes.yml +++ b/.github/workflows/detect-breaking-changes.yml @@ -39,4 +39,52 @@ jobs: # Try to check out previous versions of the breaking change detection script. This ensures that # we still detect breaking changes when entire files and their tests are removed. git checkout "${{ github.event.pull_request.base.sha }}" -- ./scripts/detect-breaking-changes 2>/dev/null || true - ./scripts/detect-breaking-changes ${{ github.event.pull_request.base.sha }} \ No newline at end of file + ./scripts/detect-breaking-changes ${{ github.event.pull_request.base.sha }} + + agents_sdk: + runs-on: 'ubuntu-latest' + name: Detect Agents SDK regressions + if: github.repository == 'openai/openai-python' + steps: + # Setup this sdk + - uses: actions/checkout@v4 + with: + path: openai-python + + - name: Install Rye + working-directory: openai-python + run: | + curl -sSf https://rye.astral.sh/get | bash + echo "$HOME/.rye/shims" >> $GITHUB_PATH + env: + RYE_VERSION: '0.44.0' + RYE_INSTALL_OPTION: '--yes' + + - name: Install dependencies + working-directory: openai-python + run: | + rye sync --all-features + + # Setup the agents lib + - uses: actions/checkout@v4 + with: + repository: openai/openai-agents-python + path: openai-agents-python + + - name: Setup uv + uses: astral-sh/setup-uv@v5 + with: + enable-cache: true + + - name: Link to local SDK + working-directory: openai-agents-python + run: uv add ../openai-python + + - name: Install dependencies + working-directory: openai-agents-python + run: make sync + + - name: Run integration type checks + working-directory: openai-agents-python + run: make mypy + From 9dc1d1a080b85571fe80bc48885c85fff3fec305 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Dec 2025 18:13:42 +0000 Subject: [PATCH 575/769] feat(api): gpt-image-1.5 --- .stats.yml | 4 +- src/openai/resources/images.py | 432 +++++++++--------- src/openai/types/image.py | 8 +- .../types/image_edit_completed_event.py | 9 +- src/openai/types/image_edit_params.py | 31 +- src/openai/types/image_gen_completed_event.py | 9 +- src/openai/types/image_generate_params.py | 40 +- src/openai/types/image_model.py | 2 +- src/openai/types/images_response.py | 15 +- src/openai/types/responses/tool.py | 4 +- src/openai/types/responses/tool_param.py | 4 +- 11 files changed, 298 insertions(+), 260 deletions(-) diff --git a/.stats.yml b/.stats.yml index 3793c0f01b..d9366ce3b3 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 137 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-fe8e67bdc351a518b113ab48e775750190e207807903d6b03ab22c438c38a588.yml -openapi_spec_hash: 8af972190647ffb9dcec516e19d8761a +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-cded37ac004364c2110ebdacf922ef611b3c51258790c72ca479dcfad4df66aa.yml +openapi_spec_hash: 6e615d34cf8c6bc76e0c6933fc8569af config_hash: d013f4fdd4dd59c6f376a9ca482b7f9e diff --git a/src/openai/resources/images.py b/src/openai/resources/images.py index 265be6f743..79505a8269 100644 --- a/src/openai/resources/images.py +++ b/src/openai/resources/images.py @@ -151,19 +151,20 @@ def edit( Args: image: The image(s) to edit. Must be a supported image file or an array of images. - For `gpt-image-1`, each image should be a `png`, `webp`, or `jpg` file less than + For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, and + `gpt-image-1.5`), each image should be a `png`, `webp`, or `jpg` file less than 50MB. You can provide up to 16 images. For `dall-e-2`, you can only provide one image, and it should be a square `png` file less than 4MB. prompt: A text description of the desired image(s). The maximum length is 1000 - characters for `dall-e-2`, and 32000 characters for `gpt-image-1`. + characters for `dall-e-2`, and 32000 characters for the GPT image models. background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for `gpt-image-1`. Must be one of `transparent`, - `opaque` or `auto` (default value). When `auto` is used, the model will - automatically determine the best background for the image. + parameter is only supported for the GPT image models. Must be one of + `transparent`, `opaque` or `auto` (default value). When `auto` is used, the + model will automatically determine the best background for the image. If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. @@ -178,18 +179,18 @@ def edit( the mask will be applied on the first image. Must be a valid PNG file, less than 4MB, and have the same dimensions as `image`. - model: The model to use for image generation. Only `dall-e-2` and `gpt-image-1` are - supported. Defaults to `dall-e-2` unless a parameter specific to `gpt-image-1` - is used. + model: The model to use for image generation. Only `dall-e-2` and the GPT image models + are supported. Defaults to `dall-e-2` unless a parameter specific to the GPT + image models is used. n: The number of images to generate. Must be between 1 and 10. output_compression: The compression level (0-100%) for the generated images. This parameter is only - supported for `gpt-image-1` with the `webp` or `jpeg` output formats, and + supported for the GPT image models with the `webp` or `jpeg` output formats, and defaults to 100. output_format: The format in which the generated images are returned. This parameter is only - supported for `gpt-image-1`. Must be one of `png`, `jpeg`, or `webp`. The + supported for the GPT image models. Must be one of `png`, `jpeg`, or `webp`. The default value is `png`. partial_images: The number of partial images to generate. This parameter is used for streaming @@ -200,17 +201,17 @@ def edit( are generated if the full image is generated more quickly. quality: The quality of the image that will be generated. `high`, `medium` and `low` are - only supported for `gpt-image-1`. `dall-e-2` only supports `standard` quality. - Defaults to `auto`. + only supported for the GPT image models. `dall-e-2` only supports `standard` + quality. Defaults to `auto`. response_format: The format in which the generated images are returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes after the image has been - generated. This parameter is only supported for `dall-e-2`, as `gpt-image-1` - will always return base64-encoded images. + generated. This parameter is only supported for `dall-e-2`, as the GPT image + models always return base64-encoded images. size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for - `gpt-image-1`, and one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`. + (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image + models, and one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`. stream: Edit the image in streaming mode. Defaults to `false`. See the [Image generation guide](https://platform.openai.com/docs/guides/image-generation) @@ -264,23 +265,24 @@ def edit( Args: image: The image(s) to edit. Must be a supported image file or an array of images. - For `gpt-image-1`, each image should be a `png`, `webp`, or `jpg` file less than + For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, and + `gpt-image-1.5`), each image should be a `png`, `webp`, or `jpg` file less than 50MB. You can provide up to 16 images. For `dall-e-2`, you can only provide one image, and it should be a square `png` file less than 4MB. prompt: A text description of the desired image(s). The maximum length is 1000 - characters for `dall-e-2`, and 32000 characters for `gpt-image-1`. + characters for `dall-e-2`, and 32000 characters for the GPT image models. stream: Edit the image in streaming mode. Defaults to `false`. See the [Image generation guide](https://platform.openai.com/docs/guides/image-generation) for more information. background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for `gpt-image-1`. Must be one of `transparent`, - `opaque` or `auto` (default value). When `auto` is used, the model will - automatically determine the best background for the image. + parameter is only supported for the GPT image models. Must be one of + `transparent`, `opaque` or `auto` (default value). When `auto` is used, the + model will automatically determine the best background for the image. If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. @@ -295,18 +297,18 @@ def edit( the mask will be applied on the first image. Must be a valid PNG file, less than 4MB, and have the same dimensions as `image`. - model: The model to use for image generation. Only `dall-e-2` and `gpt-image-1` are - supported. Defaults to `dall-e-2` unless a parameter specific to `gpt-image-1` - is used. + model: The model to use for image generation. Only `dall-e-2` and the GPT image models + are supported. Defaults to `dall-e-2` unless a parameter specific to the GPT + image models is used. n: The number of images to generate. Must be between 1 and 10. output_compression: The compression level (0-100%) for the generated images. This parameter is only - supported for `gpt-image-1` with the `webp` or `jpeg` output formats, and + supported for the GPT image models with the `webp` or `jpeg` output formats, and defaults to 100. output_format: The format in which the generated images are returned. This parameter is only - supported for `gpt-image-1`. Must be one of `png`, `jpeg`, or `webp`. The + supported for the GPT image models. Must be one of `png`, `jpeg`, or `webp`. The default value is `png`. partial_images: The number of partial images to generate. This parameter is used for streaming @@ -317,17 +319,17 @@ def edit( are generated if the full image is generated more quickly. quality: The quality of the image that will be generated. `high`, `medium` and `low` are - only supported for `gpt-image-1`. `dall-e-2` only supports `standard` quality. - Defaults to `auto`. + only supported for the GPT image models. `dall-e-2` only supports `standard` + quality. Defaults to `auto`. response_format: The format in which the generated images are returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes after the image has been - generated. This parameter is only supported for `dall-e-2`, as `gpt-image-1` - will always return base64-encoded images. + generated. This parameter is only supported for `dall-e-2`, as the GPT image + models always return base64-encoded images. size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for - `gpt-image-1`, and one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`. + (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image + models, and one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`. user: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. @@ -377,23 +379,24 @@ def edit( Args: image: The image(s) to edit. Must be a supported image file or an array of images. - For `gpt-image-1`, each image should be a `png`, `webp`, or `jpg` file less than + For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, and + `gpt-image-1.5`), each image should be a `png`, `webp`, or `jpg` file less than 50MB. You can provide up to 16 images. For `dall-e-2`, you can only provide one image, and it should be a square `png` file less than 4MB. prompt: A text description of the desired image(s). The maximum length is 1000 - characters for `dall-e-2`, and 32000 characters for `gpt-image-1`. + characters for `dall-e-2`, and 32000 characters for the GPT image models. stream: Edit the image in streaming mode. Defaults to `false`. See the [Image generation guide](https://platform.openai.com/docs/guides/image-generation) for more information. background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for `gpt-image-1`. Must be one of `transparent`, - `opaque` or `auto` (default value). When `auto` is used, the model will - automatically determine the best background for the image. + parameter is only supported for the GPT image models. Must be one of + `transparent`, `opaque` or `auto` (default value). When `auto` is used, the + model will automatically determine the best background for the image. If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. @@ -408,18 +411,18 @@ def edit( the mask will be applied on the first image. Must be a valid PNG file, less than 4MB, and have the same dimensions as `image`. - model: The model to use for image generation. Only `dall-e-2` and `gpt-image-1` are - supported. Defaults to `dall-e-2` unless a parameter specific to `gpt-image-1` - is used. + model: The model to use for image generation. Only `dall-e-2` and the GPT image models + are supported. Defaults to `dall-e-2` unless a parameter specific to the GPT + image models is used. n: The number of images to generate. Must be between 1 and 10. output_compression: The compression level (0-100%) for the generated images. This parameter is only - supported for `gpt-image-1` with the `webp` or `jpeg` output formats, and + supported for the GPT image models with the `webp` or `jpeg` output formats, and defaults to 100. output_format: The format in which the generated images are returned. This parameter is only - supported for `gpt-image-1`. Must be one of `png`, `jpeg`, or `webp`. The + supported for the GPT image models. Must be one of `png`, `jpeg`, or `webp`. The default value is `png`. partial_images: The number of partial images to generate. This parameter is used for streaming @@ -430,17 +433,17 @@ def edit( are generated if the full image is generated more quickly. quality: The quality of the image that will be generated. `high`, `medium` and `low` are - only supported for `gpt-image-1`. `dall-e-2` only supports `standard` quality. - Defaults to `auto`. + only supported for the GPT image models. `dall-e-2` only supports `standard` + quality. Defaults to `auto`. response_format: The format in which the generated images are returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes after the image has been - generated. This parameter is only supported for `dall-e-2`, as `gpt-image-1` - will always return base64-encoded images. + generated. This parameter is only supported for `dall-e-2`, as the GPT image + models always return base64-encoded images. size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for - `gpt-image-1`, and one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`. + (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image + models, and one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`. user: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. @@ -555,33 +558,34 @@ def generate( Args: prompt: A text description of the desired image(s). The maximum length is 32000 - characters for `gpt-image-1`, 1000 characters for `dall-e-2` and 4000 characters - for `dall-e-3`. + characters for the GPT image models, 1000 characters for `dall-e-2` and 4000 + characters for `dall-e-3`. background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for `gpt-image-1`. Must be one of `transparent`, - `opaque` or `auto` (default value). When `auto` is used, the model will - automatically determine the best background for the image. + parameter is only supported for the GPT image models. Must be one of + `transparent`, `opaque` or `auto` (default value). When `auto` is used, the + model will automatically determine the best background for the image. If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. - model: The model to use for image generation. One of `dall-e-2`, `dall-e-3`, or - `gpt-image-1`. Defaults to `dall-e-2` unless a parameter specific to - `gpt-image-1` is used. + model: The model to use for image generation. One of `dall-e-2`, `dall-e-3`, or a GPT + image model (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`). Defaults to + `dall-e-2` unless a parameter specific to the GPT image models is used. - moderation: Control the content-moderation level for images generated by `gpt-image-1`. Must - be either `low` for less restrictive filtering or `auto` (default value). + moderation: Control the content-moderation level for images generated by the GPT image + models. Must be either `low` for less restrictive filtering or `auto` (default + value). n: The number of images to generate. Must be between 1 and 10. For `dall-e-3`, only `n=1` is supported. output_compression: The compression level (0-100%) for the generated images. This parameter is only - supported for `gpt-image-1` with the `webp` or `jpeg` output formats, and + supported for the GPT image models with the `webp` or `jpeg` output formats, and defaults to 100. output_format: The format in which the generated images are returned. This parameter is only - supported for `gpt-image-1`. Must be one of `png`, `jpeg`, or `webp`. + supported for the GPT image models. Must be one of `png`, `jpeg`, or `webp`. partial_images: The number of partial images to generate. This parameter is used for streaming responses that return partial images. Value must be between 0 and 3. When set to @@ -594,23 +598,23 @@ def generate( - `auto` (default value) will automatically select the best quality for the given model. - - `high`, `medium` and `low` are supported for `gpt-image-1`. + - `high`, `medium` and `low` are supported for the GPT image models. - `hd` and `standard` are supported for `dall-e-3`. - `standard` is the only option for `dall-e-2`. response_format: The format in which generated images with `dall-e-2` and `dall-e-3` are returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes - after the image has been generated. This parameter isn't supported for - `gpt-image-1` which will always return base64-encoded images. + after the image has been generated. This parameter isn't supported for the GPT + image models, which always return base64-encoded images. size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for - `gpt-image-1`, one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`, and - one of `1024x1024`, `1792x1024`, or `1024x1792` for `dall-e-3`. + (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image + models, one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`, and one of + `1024x1024`, `1792x1024`, or `1024x1792` for `dall-e-3`. stream: Generate the image in streaming mode. Defaults to `false`. See the [Image generation guide](https://platform.openai.com/docs/guides/image-generation) - for more information. This parameter is only supported for `gpt-image-1`. + for more information. This parameter is only supported for the GPT image models. style: The style of the generated images. This parameter is only supported for `dall-e-3`. Must be one of `vivid` or `natural`. Vivid causes the model to lean @@ -665,37 +669,38 @@ def generate( Args: prompt: A text description of the desired image(s). The maximum length is 32000 - characters for `gpt-image-1`, 1000 characters for `dall-e-2` and 4000 characters - for `dall-e-3`. + characters for the GPT image models, 1000 characters for `dall-e-2` and 4000 + characters for `dall-e-3`. stream: Generate the image in streaming mode. Defaults to `false`. See the [Image generation guide](https://platform.openai.com/docs/guides/image-generation) - for more information. This parameter is only supported for `gpt-image-1`. + for more information. This parameter is only supported for the GPT image models. background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for `gpt-image-1`. Must be one of `transparent`, - `opaque` or `auto` (default value). When `auto` is used, the model will - automatically determine the best background for the image. + parameter is only supported for the GPT image models. Must be one of + `transparent`, `opaque` or `auto` (default value). When `auto` is used, the + model will automatically determine the best background for the image. If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. - model: The model to use for image generation. One of `dall-e-2`, `dall-e-3`, or - `gpt-image-1`. Defaults to `dall-e-2` unless a parameter specific to - `gpt-image-1` is used. + model: The model to use for image generation. One of `dall-e-2`, `dall-e-3`, or a GPT + image model (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`). Defaults to + `dall-e-2` unless a parameter specific to the GPT image models is used. - moderation: Control the content-moderation level for images generated by `gpt-image-1`. Must - be either `low` for less restrictive filtering or `auto` (default value). + moderation: Control the content-moderation level for images generated by the GPT image + models. Must be either `low` for less restrictive filtering or `auto` (default + value). n: The number of images to generate. Must be between 1 and 10. For `dall-e-3`, only `n=1` is supported. output_compression: The compression level (0-100%) for the generated images. This parameter is only - supported for `gpt-image-1` with the `webp` or `jpeg` output formats, and + supported for the GPT image models with the `webp` or `jpeg` output formats, and defaults to 100. output_format: The format in which the generated images are returned. This parameter is only - supported for `gpt-image-1`. Must be one of `png`, `jpeg`, or `webp`. + supported for the GPT image models. Must be one of `png`, `jpeg`, or `webp`. partial_images: The number of partial images to generate. This parameter is used for streaming responses that return partial images. Value must be between 0 and 3. When set to @@ -708,19 +713,19 @@ def generate( - `auto` (default value) will automatically select the best quality for the given model. - - `high`, `medium` and `low` are supported for `gpt-image-1`. + - `high`, `medium` and `low` are supported for the GPT image models. - `hd` and `standard` are supported for `dall-e-3`. - `standard` is the only option for `dall-e-2`. response_format: The format in which generated images with `dall-e-2` and `dall-e-3` are returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes - after the image has been generated. This parameter isn't supported for - `gpt-image-1` which will always return base64-encoded images. + after the image has been generated. This parameter isn't supported for the GPT + image models, which always return base64-encoded images. size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for - `gpt-image-1`, one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`, and - one of `1024x1024`, `1792x1024`, or `1024x1792` for `dall-e-3`. + (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image + models, one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`, and one of + `1024x1024`, `1792x1024`, or `1024x1792` for `dall-e-3`. style: The style of the generated images. This parameter is only supported for `dall-e-3`. Must be one of `vivid` or `natural`. Vivid causes the model to lean @@ -775,37 +780,38 @@ def generate( Args: prompt: A text description of the desired image(s). The maximum length is 32000 - characters for `gpt-image-1`, 1000 characters for `dall-e-2` and 4000 characters - for `dall-e-3`. + characters for the GPT image models, 1000 characters for `dall-e-2` and 4000 + characters for `dall-e-3`. stream: Generate the image in streaming mode. Defaults to `false`. See the [Image generation guide](https://platform.openai.com/docs/guides/image-generation) - for more information. This parameter is only supported for `gpt-image-1`. + for more information. This parameter is only supported for the GPT image models. background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for `gpt-image-1`. Must be one of `transparent`, - `opaque` or `auto` (default value). When `auto` is used, the model will - automatically determine the best background for the image. + parameter is only supported for the GPT image models. Must be one of + `transparent`, `opaque` or `auto` (default value). When `auto` is used, the + model will automatically determine the best background for the image. If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. - model: The model to use for image generation. One of `dall-e-2`, `dall-e-3`, or - `gpt-image-1`. Defaults to `dall-e-2` unless a parameter specific to - `gpt-image-1` is used. + model: The model to use for image generation. One of `dall-e-2`, `dall-e-3`, or a GPT + image model (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`). Defaults to + `dall-e-2` unless a parameter specific to the GPT image models is used. - moderation: Control the content-moderation level for images generated by `gpt-image-1`. Must - be either `low` for less restrictive filtering or `auto` (default value). + moderation: Control the content-moderation level for images generated by the GPT image + models. Must be either `low` for less restrictive filtering or `auto` (default + value). n: The number of images to generate. Must be between 1 and 10. For `dall-e-3`, only `n=1` is supported. output_compression: The compression level (0-100%) for the generated images. This parameter is only - supported for `gpt-image-1` with the `webp` or `jpeg` output formats, and + supported for the GPT image models with the `webp` or `jpeg` output formats, and defaults to 100. output_format: The format in which the generated images are returned. This parameter is only - supported for `gpt-image-1`. Must be one of `png`, `jpeg`, or `webp`. + supported for the GPT image models. Must be one of `png`, `jpeg`, or `webp`. partial_images: The number of partial images to generate. This parameter is used for streaming responses that return partial images. Value must be between 0 and 3. When set to @@ -818,19 +824,19 @@ def generate( - `auto` (default value) will automatically select the best quality for the given model. - - `high`, `medium` and `low` are supported for `gpt-image-1`. + - `high`, `medium` and `low` are supported for the GPT image models. - `hd` and `standard` are supported for `dall-e-3`. - `standard` is the only option for `dall-e-2`. response_format: The format in which generated images with `dall-e-2` and `dall-e-3` are returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes - after the image has been generated. This parameter isn't supported for - `gpt-image-1` which will always return base64-encoded images. + after the image has been generated. This parameter isn't supported for the GPT + image models, which always return base64-encoded images. size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for - `gpt-image-1`, one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`, and - one of `1024x1024`, `1792x1024`, or `1024x1792` for `dall-e-3`. + (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image + models, one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`, and one of + `1024x1024`, `1792x1024`, or `1024x1792` for `dall-e-3`. style: The style of the generated images. This parameter is only supported for `dall-e-3`. Must be one of `vivid` or `natural`. Vivid causes the model to lean @@ -1038,19 +1044,20 @@ async def edit( Args: image: The image(s) to edit. Must be a supported image file or an array of images. - For `gpt-image-1`, each image should be a `png`, `webp`, or `jpg` file less than + For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, and + `gpt-image-1.5`), each image should be a `png`, `webp`, or `jpg` file less than 50MB. You can provide up to 16 images. For `dall-e-2`, you can only provide one image, and it should be a square `png` file less than 4MB. prompt: A text description of the desired image(s). The maximum length is 1000 - characters for `dall-e-2`, and 32000 characters for `gpt-image-1`. + characters for `dall-e-2`, and 32000 characters for the GPT image models. background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for `gpt-image-1`. Must be one of `transparent`, - `opaque` or `auto` (default value). When `auto` is used, the model will - automatically determine the best background for the image. + parameter is only supported for the GPT image models. Must be one of + `transparent`, `opaque` or `auto` (default value). When `auto` is used, the + model will automatically determine the best background for the image. If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. @@ -1065,18 +1072,18 @@ async def edit( the mask will be applied on the first image. Must be a valid PNG file, less than 4MB, and have the same dimensions as `image`. - model: The model to use for image generation. Only `dall-e-2` and `gpt-image-1` are - supported. Defaults to `dall-e-2` unless a parameter specific to `gpt-image-1` - is used. + model: The model to use for image generation. Only `dall-e-2` and the GPT image models + are supported. Defaults to `dall-e-2` unless a parameter specific to the GPT + image models is used. n: The number of images to generate. Must be between 1 and 10. output_compression: The compression level (0-100%) for the generated images. This parameter is only - supported for `gpt-image-1` with the `webp` or `jpeg` output formats, and + supported for the GPT image models with the `webp` or `jpeg` output formats, and defaults to 100. output_format: The format in which the generated images are returned. This parameter is only - supported for `gpt-image-1`. Must be one of `png`, `jpeg`, or `webp`. The + supported for the GPT image models. Must be one of `png`, `jpeg`, or `webp`. The default value is `png`. partial_images: The number of partial images to generate. This parameter is used for streaming @@ -1087,17 +1094,17 @@ async def edit( are generated if the full image is generated more quickly. quality: The quality of the image that will be generated. `high`, `medium` and `low` are - only supported for `gpt-image-1`. `dall-e-2` only supports `standard` quality. - Defaults to `auto`. + only supported for the GPT image models. `dall-e-2` only supports `standard` + quality. Defaults to `auto`. response_format: The format in which the generated images are returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes after the image has been - generated. This parameter is only supported for `dall-e-2`, as `gpt-image-1` - will always return base64-encoded images. + generated. This parameter is only supported for `dall-e-2`, as the GPT image + models always return base64-encoded images. size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for - `gpt-image-1`, and one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`. + (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image + models, and one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`. stream: Edit the image in streaming mode. Defaults to `false`. See the [Image generation guide](https://platform.openai.com/docs/guides/image-generation) @@ -1151,23 +1158,24 @@ async def edit( Args: image: The image(s) to edit. Must be a supported image file or an array of images. - For `gpt-image-1`, each image should be a `png`, `webp`, or `jpg` file less than + For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, and + `gpt-image-1.5`), each image should be a `png`, `webp`, or `jpg` file less than 50MB. You can provide up to 16 images. For `dall-e-2`, you can only provide one image, and it should be a square `png` file less than 4MB. prompt: A text description of the desired image(s). The maximum length is 1000 - characters for `dall-e-2`, and 32000 characters for `gpt-image-1`. + characters for `dall-e-2`, and 32000 characters for the GPT image models. stream: Edit the image in streaming mode. Defaults to `false`. See the [Image generation guide](https://platform.openai.com/docs/guides/image-generation) for more information. background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for `gpt-image-1`. Must be one of `transparent`, - `opaque` or `auto` (default value). When `auto` is used, the model will - automatically determine the best background for the image. + parameter is only supported for the GPT image models. Must be one of + `transparent`, `opaque` or `auto` (default value). When `auto` is used, the + model will automatically determine the best background for the image. If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. @@ -1182,18 +1190,18 @@ async def edit( the mask will be applied on the first image. Must be a valid PNG file, less than 4MB, and have the same dimensions as `image`. - model: The model to use for image generation. Only `dall-e-2` and `gpt-image-1` are - supported. Defaults to `dall-e-2` unless a parameter specific to `gpt-image-1` - is used. + model: The model to use for image generation. Only `dall-e-2` and the GPT image models + are supported. Defaults to `dall-e-2` unless a parameter specific to the GPT + image models is used. n: The number of images to generate. Must be between 1 and 10. output_compression: The compression level (0-100%) for the generated images. This parameter is only - supported for `gpt-image-1` with the `webp` or `jpeg` output formats, and + supported for the GPT image models with the `webp` or `jpeg` output formats, and defaults to 100. output_format: The format in which the generated images are returned. This parameter is only - supported for `gpt-image-1`. Must be one of `png`, `jpeg`, or `webp`. The + supported for the GPT image models. Must be one of `png`, `jpeg`, or `webp`. The default value is `png`. partial_images: The number of partial images to generate. This parameter is used for streaming @@ -1204,17 +1212,17 @@ async def edit( are generated if the full image is generated more quickly. quality: The quality of the image that will be generated. `high`, `medium` and `low` are - only supported for `gpt-image-1`. `dall-e-2` only supports `standard` quality. - Defaults to `auto`. + only supported for the GPT image models. `dall-e-2` only supports `standard` + quality. Defaults to `auto`. response_format: The format in which the generated images are returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes after the image has been - generated. This parameter is only supported for `dall-e-2`, as `gpt-image-1` - will always return base64-encoded images. + generated. This parameter is only supported for `dall-e-2`, as the GPT image + models always return base64-encoded images. size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for - `gpt-image-1`, and one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`. + (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image + models, and one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`. user: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. @@ -1264,23 +1272,24 @@ async def edit( Args: image: The image(s) to edit. Must be a supported image file or an array of images. - For `gpt-image-1`, each image should be a `png`, `webp`, or `jpg` file less than + For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, and + `gpt-image-1.5`), each image should be a `png`, `webp`, or `jpg` file less than 50MB. You can provide up to 16 images. For `dall-e-2`, you can only provide one image, and it should be a square `png` file less than 4MB. prompt: A text description of the desired image(s). The maximum length is 1000 - characters for `dall-e-2`, and 32000 characters for `gpt-image-1`. + characters for `dall-e-2`, and 32000 characters for the GPT image models. stream: Edit the image in streaming mode. Defaults to `false`. See the [Image generation guide](https://platform.openai.com/docs/guides/image-generation) for more information. background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for `gpt-image-1`. Must be one of `transparent`, - `opaque` or `auto` (default value). When `auto` is used, the model will - automatically determine the best background for the image. + parameter is only supported for the GPT image models. Must be one of + `transparent`, `opaque` or `auto` (default value). When `auto` is used, the + model will automatically determine the best background for the image. If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. @@ -1295,18 +1304,18 @@ async def edit( the mask will be applied on the first image. Must be a valid PNG file, less than 4MB, and have the same dimensions as `image`. - model: The model to use for image generation. Only `dall-e-2` and `gpt-image-1` are - supported. Defaults to `dall-e-2` unless a parameter specific to `gpt-image-1` - is used. + model: The model to use for image generation. Only `dall-e-2` and the GPT image models + are supported. Defaults to `dall-e-2` unless a parameter specific to the GPT + image models is used. n: The number of images to generate. Must be between 1 and 10. output_compression: The compression level (0-100%) for the generated images. This parameter is only - supported for `gpt-image-1` with the `webp` or `jpeg` output formats, and + supported for the GPT image models with the `webp` or `jpeg` output formats, and defaults to 100. output_format: The format in which the generated images are returned. This parameter is only - supported for `gpt-image-1`. Must be one of `png`, `jpeg`, or `webp`. The + supported for the GPT image models. Must be one of `png`, `jpeg`, or `webp`. The default value is `png`. partial_images: The number of partial images to generate. This parameter is used for streaming @@ -1317,17 +1326,17 @@ async def edit( are generated if the full image is generated more quickly. quality: The quality of the image that will be generated. `high`, `medium` and `low` are - only supported for `gpt-image-1`. `dall-e-2` only supports `standard` quality. - Defaults to `auto`. + only supported for the GPT image models. `dall-e-2` only supports `standard` + quality. Defaults to `auto`. response_format: The format in which the generated images are returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes after the image has been - generated. This parameter is only supported for `dall-e-2`, as `gpt-image-1` - will always return base64-encoded images. + generated. This parameter is only supported for `dall-e-2`, as the GPT image + models always return base64-encoded images. size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for - `gpt-image-1`, and one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`. + (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image + models, and one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`. user: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. @@ -1442,33 +1451,34 @@ async def generate( Args: prompt: A text description of the desired image(s). The maximum length is 32000 - characters for `gpt-image-1`, 1000 characters for `dall-e-2` and 4000 characters - for `dall-e-3`. + characters for the GPT image models, 1000 characters for `dall-e-2` and 4000 + characters for `dall-e-3`. background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for `gpt-image-1`. Must be one of `transparent`, - `opaque` or `auto` (default value). When `auto` is used, the model will - automatically determine the best background for the image. + parameter is only supported for the GPT image models. Must be one of + `transparent`, `opaque` or `auto` (default value). When `auto` is used, the + model will automatically determine the best background for the image. If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. - model: The model to use for image generation. One of `dall-e-2`, `dall-e-3`, or - `gpt-image-1`. Defaults to `dall-e-2` unless a parameter specific to - `gpt-image-1` is used. + model: The model to use for image generation. One of `dall-e-2`, `dall-e-3`, or a GPT + image model (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`). Defaults to + `dall-e-2` unless a parameter specific to the GPT image models is used. - moderation: Control the content-moderation level for images generated by `gpt-image-1`. Must - be either `low` for less restrictive filtering or `auto` (default value). + moderation: Control the content-moderation level for images generated by the GPT image + models. Must be either `low` for less restrictive filtering or `auto` (default + value). n: The number of images to generate. Must be between 1 and 10. For `dall-e-3`, only `n=1` is supported. output_compression: The compression level (0-100%) for the generated images. This parameter is only - supported for `gpt-image-1` with the `webp` or `jpeg` output formats, and + supported for the GPT image models with the `webp` or `jpeg` output formats, and defaults to 100. output_format: The format in which the generated images are returned. This parameter is only - supported for `gpt-image-1`. Must be one of `png`, `jpeg`, or `webp`. + supported for the GPT image models. Must be one of `png`, `jpeg`, or `webp`. partial_images: The number of partial images to generate. This parameter is used for streaming responses that return partial images. Value must be between 0 and 3. When set to @@ -1481,23 +1491,23 @@ async def generate( - `auto` (default value) will automatically select the best quality for the given model. - - `high`, `medium` and `low` are supported for `gpt-image-1`. + - `high`, `medium` and `low` are supported for the GPT image models. - `hd` and `standard` are supported for `dall-e-3`. - `standard` is the only option for `dall-e-2`. response_format: The format in which generated images with `dall-e-2` and `dall-e-3` are returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes - after the image has been generated. This parameter isn't supported for - `gpt-image-1` which will always return base64-encoded images. + after the image has been generated. This parameter isn't supported for the GPT + image models, which always return base64-encoded images. size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for - `gpt-image-1`, one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`, and - one of `1024x1024`, `1792x1024`, or `1024x1792` for `dall-e-3`. + (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image + models, one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`, and one of + `1024x1024`, `1792x1024`, or `1024x1792` for `dall-e-3`. stream: Generate the image in streaming mode. Defaults to `false`. See the [Image generation guide](https://platform.openai.com/docs/guides/image-generation) - for more information. This parameter is only supported for `gpt-image-1`. + for more information. This parameter is only supported for the GPT image models. style: The style of the generated images. This parameter is only supported for `dall-e-3`. Must be one of `vivid` or `natural`. Vivid causes the model to lean @@ -1552,37 +1562,38 @@ async def generate( Args: prompt: A text description of the desired image(s). The maximum length is 32000 - characters for `gpt-image-1`, 1000 characters for `dall-e-2` and 4000 characters - for `dall-e-3`. + characters for the GPT image models, 1000 characters for `dall-e-2` and 4000 + characters for `dall-e-3`. stream: Generate the image in streaming mode. Defaults to `false`. See the [Image generation guide](https://platform.openai.com/docs/guides/image-generation) - for more information. This parameter is only supported for `gpt-image-1`. + for more information. This parameter is only supported for the GPT image models. background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for `gpt-image-1`. Must be one of `transparent`, - `opaque` or `auto` (default value). When `auto` is used, the model will - automatically determine the best background for the image. + parameter is only supported for the GPT image models. Must be one of + `transparent`, `opaque` or `auto` (default value). When `auto` is used, the + model will automatically determine the best background for the image. If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. - model: The model to use for image generation. One of `dall-e-2`, `dall-e-3`, or - `gpt-image-1`. Defaults to `dall-e-2` unless a parameter specific to - `gpt-image-1` is used. + model: The model to use for image generation. One of `dall-e-2`, `dall-e-3`, or a GPT + image model (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`). Defaults to + `dall-e-2` unless a parameter specific to the GPT image models is used. - moderation: Control the content-moderation level for images generated by `gpt-image-1`. Must - be either `low` for less restrictive filtering or `auto` (default value). + moderation: Control the content-moderation level for images generated by the GPT image + models. Must be either `low` for less restrictive filtering or `auto` (default + value). n: The number of images to generate. Must be between 1 and 10. For `dall-e-3`, only `n=1` is supported. output_compression: The compression level (0-100%) for the generated images. This parameter is only - supported for `gpt-image-1` with the `webp` or `jpeg` output formats, and + supported for the GPT image models with the `webp` or `jpeg` output formats, and defaults to 100. output_format: The format in which the generated images are returned. This parameter is only - supported for `gpt-image-1`. Must be one of `png`, `jpeg`, or `webp`. + supported for the GPT image models. Must be one of `png`, `jpeg`, or `webp`. partial_images: The number of partial images to generate. This parameter is used for streaming responses that return partial images. Value must be between 0 and 3. When set to @@ -1595,19 +1606,19 @@ async def generate( - `auto` (default value) will automatically select the best quality for the given model. - - `high`, `medium` and `low` are supported for `gpt-image-1`. + - `high`, `medium` and `low` are supported for the GPT image models. - `hd` and `standard` are supported for `dall-e-3`. - `standard` is the only option for `dall-e-2`. response_format: The format in which generated images with `dall-e-2` and `dall-e-3` are returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes - after the image has been generated. This parameter isn't supported for - `gpt-image-1` which will always return base64-encoded images. + after the image has been generated. This parameter isn't supported for the GPT + image models, which always return base64-encoded images. size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for - `gpt-image-1`, one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`, and - one of `1024x1024`, `1792x1024`, or `1024x1792` for `dall-e-3`. + (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image + models, one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`, and one of + `1024x1024`, `1792x1024`, or `1024x1792` for `dall-e-3`. style: The style of the generated images. This parameter is only supported for `dall-e-3`. Must be one of `vivid` or `natural`. Vivid causes the model to lean @@ -1662,37 +1673,38 @@ async def generate( Args: prompt: A text description of the desired image(s). The maximum length is 32000 - characters for `gpt-image-1`, 1000 characters for `dall-e-2` and 4000 characters - for `dall-e-3`. + characters for the GPT image models, 1000 characters for `dall-e-2` and 4000 + characters for `dall-e-3`. stream: Generate the image in streaming mode. Defaults to `false`. See the [Image generation guide](https://platform.openai.com/docs/guides/image-generation) - for more information. This parameter is only supported for `gpt-image-1`. + for more information. This parameter is only supported for the GPT image models. background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for `gpt-image-1`. Must be one of `transparent`, - `opaque` or `auto` (default value). When `auto` is used, the model will - automatically determine the best background for the image. + parameter is only supported for the GPT image models. Must be one of + `transparent`, `opaque` or `auto` (default value). When `auto` is used, the + model will automatically determine the best background for the image. If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. - model: The model to use for image generation. One of `dall-e-2`, `dall-e-3`, or - `gpt-image-1`. Defaults to `dall-e-2` unless a parameter specific to - `gpt-image-1` is used. + model: The model to use for image generation. One of `dall-e-2`, `dall-e-3`, or a GPT + image model (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`). Defaults to + `dall-e-2` unless a parameter specific to the GPT image models is used. - moderation: Control the content-moderation level for images generated by `gpt-image-1`. Must - be either `low` for less restrictive filtering or `auto` (default value). + moderation: Control the content-moderation level for images generated by the GPT image + models. Must be either `low` for less restrictive filtering or `auto` (default + value). n: The number of images to generate. Must be between 1 and 10. For `dall-e-3`, only `n=1` is supported. output_compression: The compression level (0-100%) for the generated images. This parameter is only - supported for `gpt-image-1` with the `webp` or `jpeg` output formats, and + supported for the GPT image models with the `webp` or `jpeg` output formats, and defaults to 100. output_format: The format in which the generated images are returned. This parameter is only - supported for `gpt-image-1`. Must be one of `png`, `jpeg`, or `webp`. + supported for the GPT image models. Must be one of `png`, `jpeg`, or `webp`. partial_images: The number of partial images to generate. This parameter is used for streaming responses that return partial images. Value must be between 0 and 3. When set to @@ -1705,19 +1717,19 @@ async def generate( - `auto` (default value) will automatically select the best quality for the given model. - - `high`, `medium` and `low` are supported for `gpt-image-1`. + - `high`, `medium` and `low` are supported for the GPT image models. - `hd` and `standard` are supported for `dall-e-3`. - `standard` is the only option for `dall-e-2`. response_format: The format in which generated images with `dall-e-2` and `dall-e-3` are returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes - after the image has been generated. This parameter isn't supported for - `gpt-image-1` which will always return base64-encoded images. + after the image has been generated. This parameter isn't supported for the GPT + image models, which always return base64-encoded images. size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for - `gpt-image-1`, one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`, and - one of `1024x1024`, `1792x1024`, or `1024x1792` for `dall-e-3`. + (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image + models, one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`, and one of + `1024x1024`, `1792x1024`, or `1024x1792` for `dall-e-3`. style: The style of the generated images. This parameter is only supported for `dall-e-3`. Must be one of `vivid` or `natural`. Vivid causes the model to lean diff --git a/src/openai/types/image.py b/src/openai/types/image.py index 9e2a23fa40..dcbdb2aceb 100644 --- a/src/openai/types/image.py +++ b/src/openai/types/image.py @@ -13,8 +13,8 @@ class Image(BaseModel): b64_json: Optional[str] = None """The base64-encoded JSON of the generated image. - Default value for `gpt-image-1`, and only present if `response_format` is set to - `b64_json` for `dall-e-2` and `dall-e-3`. + Returned by default for the GPT image models, and only present if + `response_format` is set to `b64_json` for `dall-e-2` and `dall-e-3`. """ revised_prompt: Optional[str] = None @@ -23,6 +23,6 @@ class Image(BaseModel): url: Optional[str] = None """ When using `dall-e-2` or `dall-e-3`, the URL of the generated image if - `response_format` is set to `url` (default value). Unsupported for - `gpt-image-1`. + `response_format` is set to `url` (default value). Unsupported for the GPT image + models. """ diff --git a/src/openai/types/image_edit_completed_event.py b/src/openai/types/image_edit_completed_event.py index 5bd2986d2a..e2e193413f 100644 --- a/src/openai/types/image_edit_completed_event.py +++ b/src/openai/types/image_edit_completed_event.py @@ -18,7 +18,9 @@ class UsageInputTokensDetails(BaseModel): class Usage(BaseModel): - """For `gpt-image-1` only, the token usage information for the image generation.""" + """ + For the GPT image models only, the token usage information for the image generation. + """ input_tokens: int """The number of tokens (images and text) in the input prompt.""" @@ -58,4 +60,7 @@ class ImageEditCompletedEvent(BaseModel): """The type of the event. Always `image_edit.completed`.""" usage: Usage - """For `gpt-image-1` only, the token usage information for the image generation.""" + """ + For the GPT image models only, the token usage information for the image + generation. + """ diff --git a/src/openai/types/image_edit_params.py b/src/openai/types/image_edit_params.py index 2a8fab0f20..0bd5f39fac 100644 --- a/src/openai/types/image_edit_params.py +++ b/src/openai/types/image_edit_params.py @@ -15,7 +15,8 @@ class ImageEditParamsBase(TypedDict, total=False): image: Required[Union[FileTypes, SequenceNotStr[FileTypes]]] """The image(s) to edit. Must be a supported image file or an array of images. - For `gpt-image-1`, each image should be a `png`, `webp`, or `jpg` file less than + For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, and + `gpt-image-1.5`), each image should be a `png`, `webp`, or `jpg` file less than 50MB. You can provide up to 16 images. For `dall-e-2`, you can only provide one image, and it should be a square `png` @@ -26,15 +27,15 @@ class ImageEditParamsBase(TypedDict, total=False): """A text description of the desired image(s). The maximum length is 1000 characters for `dall-e-2`, and 32000 characters for - `gpt-image-1`. + the GPT image models. """ background: Optional[Literal["transparent", "opaque", "auto"]] """ Allows to set transparency for the background of the generated image(s). This - parameter is only supported for `gpt-image-1`. Must be one of `transparent`, - `opaque` or `auto` (default value). When `auto` is used, the model will - automatically determine the best background for the image. + parameter is only supported for the GPT image models. Must be one of + `transparent`, `opaque` or `auto` (default value). When `auto` is used, the + model will automatically determine the best background for the image. If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. @@ -59,8 +60,8 @@ class ImageEditParamsBase(TypedDict, total=False): model: Union[str, ImageModel, None] """The model to use for image generation. - Only `dall-e-2` and `gpt-image-1` are supported. Defaults to `dall-e-2` unless a - parameter specific to `gpt-image-1` is used. + Only `dall-e-2` and the GPT image models are supported. Defaults to `dall-e-2` + unless a parameter specific to the GPT image models is used. """ n: Optional[int] @@ -69,14 +70,14 @@ class ImageEditParamsBase(TypedDict, total=False): output_compression: Optional[int] """The compression level (0-100%) for the generated images. - This parameter is only supported for `gpt-image-1` with the `webp` or `jpeg` - output formats, and defaults to 100. + This parameter is only supported for the GPT image models with the `webp` or + `jpeg` output formats, and defaults to 100. """ output_format: Optional[Literal["png", "jpeg", "webp"]] """The format in which the generated images are returned. - This parameter is only supported for `gpt-image-1`. Must be one of `png`, + This parameter is only supported for the GPT image models. Must be one of `png`, `jpeg`, or `webp`. The default value is `png`. """ @@ -94,8 +95,8 @@ class ImageEditParamsBase(TypedDict, total=False): quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] """The quality of the image that will be generated. - `high`, `medium` and `low` are only supported for `gpt-image-1`. `dall-e-2` only - supports `standard` quality. Defaults to `auto`. + `high`, `medium` and `low` are only supported for the GPT image models. + `dall-e-2` only supports `standard` quality. Defaults to `auto`. """ response_format: Optional[Literal["url", "b64_json"]] @@ -103,15 +104,15 @@ class ImageEditParamsBase(TypedDict, total=False): Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes after the image has been generated. This parameter is only supported for `dall-e-2`, as - `gpt-image-1` will always return base64-encoded images. + the GPT image models always return base64-encoded images. """ size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] """The size of the generated images. Must be one of `1024x1024`, `1536x1024` (landscape), `1024x1536` (portrait), or - `auto` (default value) for `gpt-image-1`, and one of `256x256`, `512x512`, or - `1024x1024` for `dall-e-2`. + `auto` (default value) for the GPT image models, and one of `256x256`, + `512x512`, or `1024x1024` for `dall-e-2`. """ user: str diff --git a/src/openai/types/image_gen_completed_event.py b/src/openai/types/image_gen_completed_event.py index dc9ccb8cfc..813ed889d8 100644 --- a/src/openai/types/image_gen_completed_event.py +++ b/src/openai/types/image_gen_completed_event.py @@ -18,7 +18,9 @@ class UsageInputTokensDetails(BaseModel): class Usage(BaseModel): - """For `gpt-image-1` only, the token usage information for the image generation.""" + """ + For the GPT image models only, the token usage information for the image generation. + """ input_tokens: int """The number of tokens (images and text) in the input prompt.""" @@ -58,4 +60,7 @@ class ImageGenCompletedEvent(BaseModel): """The type of the event. Always `image_generation.completed`.""" usage: Usage - """For `gpt-image-1` only, the token usage information for the image generation.""" + """ + For the GPT image models only, the token usage information for the image + generation. + """ diff --git a/src/openai/types/image_generate_params.py b/src/openai/types/image_generate_params.py index 3270ca1d6e..7a95b3dd3d 100644 --- a/src/openai/types/image_generate_params.py +++ b/src/openai/types/image_generate_params.py @@ -14,16 +14,16 @@ class ImageGenerateParamsBase(TypedDict, total=False): prompt: Required[str] """A text description of the desired image(s). - The maximum length is 32000 characters for `gpt-image-1`, 1000 characters for - `dall-e-2` and 4000 characters for `dall-e-3`. + The maximum length is 32000 characters for the GPT image models, 1000 characters + for `dall-e-2` and 4000 characters for `dall-e-3`. """ background: Optional[Literal["transparent", "opaque", "auto"]] """ Allows to set transparency for the background of the generated image(s). This - parameter is only supported for `gpt-image-1`. Must be one of `transparent`, - `opaque` or `auto` (default value). When `auto` is used, the model will - automatically determine the best background for the image. + parameter is only supported for the GPT image models. Must be one of + `transparent`, `opaque` or `auto` (default value). When `auto` is used, the + model will automatically determine the best background for the image. If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. @@ -32,14 +32,16 @@ class ImageGenerateParamsBase(TypedDict, total=False): model: Union[str, ImageModel, None] """The model to use for image generation. - One of `dall-e-2`, `dall-e-3`, or `gpt-image-1`. Defaults to `dall-e-2` unless a - parameter specific to `gpt-image-1` is used. + One of `dall-e-2`, `dall-e-3`, or a GPT image model (`gpt-image-1`, + `gpt-image-1-mini`, `gpt-image-1.5`). Defaults to `dall-e-2` unless a parameter + specific to the GPT image models is used. """ moderation: Optional[Literal["low", "auto"]] - """Control the content-moderation level for images generated by `gpt-image-1`. - - Must be either `low` for less restrictive filtering or `auto` (default value). + """ + Control the content-moderation level for images generated by the GPT image + models. Must be either `low` for less restrictive filtering or `auto` (default + value). """ n: Optional[int] @@ -51,14 +53,14 @@ class ImageGenerateParamsBase(TypedDict, total=False): output_compression: Optional[int] """The compression level (0-100%) for the generated images. - This parameter is only supported for `gpt-image-1` with the `webp` or `jpeg` - output formats, and defaults to 100. + This parameter is only supported for the GPT image models with the `webp` or + `jpeg` output formats, and defaults to 100. """ output_format: Optional[Literal["png", "jpeg", "webp"]] """The format in which the generated images are returned. - This parameter is only supported for `gpt-image-1`. Must be one of `png`, + This parameter is only supported for the GPT image models. Must be one of `png`, `jpeg`, or `webp`. """ @@ -78,7 +80,7 @@ class ImageGenerateParamsBase(TypedDict, total=False): - `auto` (default value) will automatically select the best quality for the given model. - - `high`, `medium` and `low` are supported for `gpt-image-1`. + - `high`, `medium` and `low` are supported for the GPT image models. - `hd` and `standard` are supported for `dall-e-3`. - `standard` is the only option for `dall-e-2`. """ @@ -88,8 +90,8 @@ class ImageGenerateParamsBase(TypedDict, total=False): returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes after the - image has been generated. This parameter isn't supported for `gpt-image-1` which - will always return base64-encoded images. + image has been generated. This parameter isn't supported for the GPT image + models, which always return base64-encoded images. """ size: Optional[ @@ -98,7 +100,7 @@ class ImageGenerateParamsBase(TypedDict, total=False): """The size of the generated images. Must be one of `1024x1024`, `1536x1024` (landscape), `1024x1536` (portrait), or - `auto` (default value) for `gpt-image-1`, one of `256x256`, `512x512`, or + `auto` (default value) for the GPT image models, one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`, and one of `1024x1024`, `1792x1024`, or `1024x1792` for `dall-e-3`. """ @@ -126,7 +128,7 @@ class ImageGenerateParamsNonStreaming(ImageGenerateParamsBase, total=False): Defaults to `false`. See the [Image generation guide](https://platform.openai.com/docs/guides/image-generation) - for more information. This parameter is only supported for `gpt-image-1`. + for more information. This parameter is only supported for the GPT image models. """ @@ -136,7 +138,7 @@ class ImageGenerateParamsStreaming(ImageGenerateParamsBase): Defaults to `false`. See the [Image generation guide](https://platform.openai.com/docs/guides/image-generation) - for more information. This parameter is only supported for `gpt-image-1`. + for more information. This parameter is only supported for the GPT image models. """ diff --git a/src/openai/types/image_model.py b/src/openai/types/image_model.py index 22b1281fa9..8ea486fbb6 100644 --- a/src/openai/types/image_model.py +++ b/src/openai/types/image_model.py @@ -4,4 +4,4 @@ __all__ = ["ImageModel"] -ImageModel: TypeAlias = Literal["dall-e-2", "dall-e-3", "gpt-image-1", "gpt-image-1-mini"] +ImageModel: TypeAlias = Literal["gpt-image-1.5", "dall-e-2", "dall-e-3", "gpt-image-1", "gpt-image-1-mini"] diff --git a/src/openai/types/images_response.py b/src/openai/types/images_response.py index 914017823e..3e832aadf2 100644 --- a/src/openai/types/images_response.py +++ b/src/openai/types/images_response.py @@ -6,7 +6,7 @@ from .image import Image from .._models import BaseModel -__all__ = ["ImagesResponse", "Usage", "UsageInputTokensDetails"] +__all__ = ["ImagesResponse", "Usage", "UsageInputTokensDetails", "UsageOutputTokensDetails"] class UsageInputTokensDetails(BaseModel): @@ -19,6 +19,16 @@ class UsageInputTokensDetails(BaseModel): """The number of text tokens in the input prompt.""" +class UsageOutputTokensDetails(BaseModel): + """The output token details for the image generation.""" + + image_tokens: int + """The number of image output tokens generated by the model.""" + + text_tokens: int + """The number of text output tokens generated by the model.""" + + class Usage(BaseModel): """For `gpt-image-1` only, the token usage information for the image generation.""" @@ -34,6 +44,9 @@ class Usage(BaseModel): total_tokens: int """The total number of tokens (images and text) used for the image generation.""" + output_tokens_details: Optional[UsageOutputTokensDetails] = None + """The output token details for the image generation.""" + class ImagesResponse(BaseModel): """The response from the image generation endpoint.""" diff --git a/src/openai/types/responses/tool.py b/src/openai/types/responses/tool.py index 1f1ef12358..20f50e4478 100644 --- a/src/openai/types/responses/tool.py +++ b/src/openai/types/responses/tool.py @@ -221,7 +221,7 @@ class ImageGenerationInputImageMask(BaseModel): class ImageGeneration(BaseModel): - """A tool that generates images using a model like `gpt-image-1`.""" + """A tool that generates images using the GPT image models.""" type: Literal["image_generation"] """The type of the image generation tool. Always `image_generation`.""" @@ -246,7 +246,7 @@ class ImageGeneration(BaseModel): Contains `image_url` (string, optional) and `file_id` (string, optional). """ - model: Optional[Literal["gpt-image-1", "gpt-image-1-mini"]] = None + model: Union[str, Literal["gpt-image-1", "gpt-image-1-mini"], None] = None """The image generation model to use. Default: `gpt-image-1`.""" moderation: Optional[Literal["auto", "low"]] = None diff --git a/src/openai/types/responses/tool_param.py b/src/openai/types/responses/tool_param.py index c6ffa39192..69c6162153 100644 --- a/src/openai/types/responses/tool_param.py +++ b/src/openai/types/responses/tool_param.py @@ -221,7 +221,7 @@ class ImageGenerationInputImageMask(TypedDict, total=False): class ImageGeneration(TypedDict, total=False): - """A tool that generates images using a model like `gpt-image-1`.""" + """A tool that generates images using the GPT image models.""" type: Required[Literal["image_generation"]] """The type of the image generation tool. Always `image_generation`.""" @@ -246,7 +246,7 @@ class ImageGeneration(TypedDict, total=False): Contains `image_url` (string, optional) and `file_id` (string, optional). """ - model: Literal["gpt-image-1", "gpt-image-1-mini"] + model: Union[str, Literal["gpt-image-1", "gpt-image-1-mini"]] """The image generation model to use. Default: `gpt-image-1`.""" moderation: Literal["auto", "low"] From f94256daf8f5d7268f28c2330dc343660a959c3e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Dec 2025 18:14:52 +0000 Subject: [PATCH 576/769] release: 2.13.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 14 ++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 0746cbe20a..e6eadb43e0 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.12.0" + ".": "2.13.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index ec61efaf79..745512f15d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## 2.13.0 (2025-12-16) + +Full Changelog: [v2.12.0...v2.13.0](https://github.com/openai/openai-python/compare/v2.12.0...v2.13.0) + +### Features + +* **api:** gpt-image-1.5 ([1c88f03](https://github.com/openai/openai-python/commit/1c88f03bb48aa67426744e5b74f6197f30f61c73)) + + +### Chores + +* **ci:** add CI job to detect breaking changes with the Agents SDK ([#1436](https://github.com/openai/openai-python/issues/1436)) ([237c91e](https://github.com/openai/openai-python/commit/237c91ee6738b6764b139fd7afa68294d3ee0153)) +* **internal:** add missing files argument to base client ([e6d6fd5](https://github.com/openai/openai-python/commit/e6d6fd5989d76358ea5d9abb5949aa87646cbef6)) + ## 2.12.0 (2025-12-15) Full Changelog: [v2.11.0...v2.12.0](https://github.com/openai/openai-python/compare/v2.11.0...v2.12.0) diff --git a/pyproject.toml b/pyproject.toml index 7d6fec5c1a..f9dd23592a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.12.0" +version = "2.13.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 9d853d6512..dfda2f0522 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__ = "2.12.0" # x-release-please-version +__version__ = "2.13.0" # x-release-please-version From 20af6aaae2a7ec066fc64922d314dba693526ca1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Dec 2025 19:44:31 +0000 Subject: [PATCH 577/769] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index d9366ce3b3..d44b98a331 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 137 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-cded37ac004364c2110ebdacf922ef611b3c51258790c72ca479dcfad4df66aa.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-235aa1c75c6cc178b97d074a4671343469f458c4a306ef7beb4e45ab252aa589.yml openapi_spec_hash: 6e615d34cf8c6bc76e0c6933fc8569af -config_hash: d013f4fdd4dd59c6f376a9ca482b7f9e +config_hash: c028ce402ef5f71da947c3f15bf6046d From 62699d97ba171ec109456e3001ecd693e6945060 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 17 Dec 2025 15:47:28 +0000 Subject: [PATCH 578/769] fix: use async_to_httpx_files in patch method --- src/openai/_base_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index c0cac43daa..9e536410d6 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -1806,7 +1806,7 @@ async def patch( options: RequestOptions = {}, ) -> ResponseT: opts = FinalRequestOptions.construct( - method="patch", url=path, json_data=body, files=to_httpx_files(files), **options + method="patch", url=path, json_data=body, files=await async_to_httpx_files(files), **options ) return await self.request(cast_to, opts) From 51c6885537da15fa2fc7e93ec9a4166ad9928f77 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 18 Dec 2025 18:45:19 +0000 Subject: [PATCH 579/769] feat(api): slugs for new audio models; make all `model` params accept strings --- .stats.yml | 4 +- src/openai/resources/audio/speech.py | 4 +- src/openai/resources/audio/transcriptions.py | 65 ++++++++++--------- src/openai/resources/realtime/calls.py | 4 ++ src/openai/resources/videos.py | 11 ++-- src/openai/types/__init__.py | 1 + .../types/audio/speech_create_params.py | 2 +- src/openai/types/audio/speech_model.py | 2 +- .../audio/transcription_create_params.py | 12 ++-- src/openai/types/audio_model.py | 8 ++- .../types/realtime/audio_transcription.py | 19 ++++-- .../realtime/audio_transcription_param.py | 17 ++++- .../types/realtime/call_accept_params.py | 2 + .../realtime_session_create_request.py | 2 + .../realtime_session_create_request_param.py | 2 + .../realtime_session_create_response.py | 2 + src/openai/types/video_create_params.py | 4 +- src/openai/types/video_model.py | 5 +- src/openai/types/video_model_param.py | 12 ++++ tests/api_resources/realtime/test_calls.py | 8 +-- .../realtime/test_client_secrets.py | 4 +- tests/api_resources/test_videos.py | 4 +- 22 files changed, 126 insertions(+), 68 deletions(-) create mode 100644 src/openai/types/video_model_param.py diff --git a/.stats.yml b/.stats.yml index d44b98a331..6ec100546a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 137 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-235aa1c75c6cc178b97d074a4671343469f458c4a306ef7beb4e45ab252aa589.yml -openapi_spec_hash: 6e615d34cf8c6bc76e0c6933fc8569af +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-75926226b642ebb2cb415694da9dff35e8ab40145ac1b791cefb82a83809db4d.yml +openapi_spec_hash: 6a0e391b0ba5747b6b4a3e5fe21de4da config_hash: c028ce402ef5f71da947c3f15bf6046d diff --git a/src/openai/resources/audio/speech.py b/src/openai/resources/audio/speech.py index 992fb5971a..b92fcb73d3 100644 --- a/src/openai/resources/audio/speech.py +++ b/src/openai/resources/audio/speech.py @@ -72,7 +72,7 @@ def create( model: One of the available [TTS models](https://platform.openai.com/docs/models#tts): - `tts-1`, `tts-1-hd` or `gpt-4o-mini-tts`. + `tts-1`, `tts-1-hd`, `gpt-4o-mini-tts`, or `gpt-4o-mini-tts-2025-12-15`. voice: The voice to use when generating the audio. Supported voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, `shimmer`, and @@ -168,7 +168,7 @@ async def create( model: One of the available [TTS models](https://platform.openai.com/docs/models#tts): - `tts-1`, `tts-1-hd` or `gpt-4o-mini-tts`. + `tts-1`, `tts-1-hd`, `gpt-4o-mini-tts`, or `gpt-4o-mini-tts-2025-12-15`. voice: The voice to use when generating the audio. Supported voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, `shimmer`, and diff --git a/src/openai/resources/audio/transcriptions.py b/src/openai/resources/audio/transcriptions.py index a5c86146d4..599534855d 100644 --- a/src/openai/resources/audio/transcriptions.py +++ b/src/openai/resources/audio/transcriptions.py @@ -91,8 +91,9 @@ def create( flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. model: ID of the model to use. The options are `gpt-4o-transcribe`, - `gpt-4o-mini-transcribe`, and `whisper-1` (which is powered by our open source - Whisper V2 model). + `gpt-4o-mini-transcribe`, `gpt-4o-mini-transcribe-2025-12-15`, `whisper-1` + (which is powered by our open source Whisper V2 model), and + `gpt-4o-transcribe-diarize`. chunking_strategy: Controls how the audio is cut into chunks. When set to `"auto"`, the server first normalizes loudness and then uses voice activity detection (VAD) to choose @@ -102,8 +103,9 @@ def create( include: Additional information to include in the transcription response. `logprobs` will return the log probabilities of the tokens in the response to understand the model's confidence in the transcription. `logprobs` only works with - response_format set to `json` and only with the models `gpt-4o-transcribe` and - `gpt-4o-mini-transcribe`. + response_format set to `json` and only with the models `gpt-4o-transcribe`, + `gpt-4o-mini-transcribe`, and `gpt-4o-mini-transcribe-2025-12-15`. This field is + not supported when using `gpt-4o-transcribe-diarize`. language: The language of the input audio. Supplying the input language in [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) @@ -239,8 +241,9 @@ def create( flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. model: ID of the model to use. The options are `gpt-4o-transcribe`, - `gpt-4o-mini-transcribe`, `whisper-1` (which is powered by our open source - Whisper V2 model), and `gpt-4o-transcribe-diarize`. + `gpt-4o-mini-transcribe`, `gpt-4o-mini-transcribe-2025-12-15`, `whisper-1` + (which is powered by our open source Whisper V2 model), and + `gpt-4o-transcribe-diarize`. stream: If set to true, the model response data will be streamed to the client as it is generated using @@ -261,9 +264,9 @@ def create( include: Additional information to include in the transcription response. `logprobs` will return the log probabilities of the tokens in the response to understand the model's confidence in the transcription. `logprobs` only works with - response_format set to `json` and only with the models `gpt-4o-transcribe` and - `gpt-4o-mini-transcribe`. This field is not supported when using - `gpt-4o-transcribe-diarize`. + response_format set to `json` and only with the models `gpt-4o-transcribe`, + `gpt-4o-mini-transcribe`, and `gpt-4o-mini-transcribe-2025-12-15`. This field is + not supported when using `gpt-4o-transcribe-diarize`. known_speaker_names: Optional list of speaker names that correspond to the audio samples provided in `known_speaker_references[]`. Each entry should be a short identifier (for @@ -346,8 +349,9 @@ def create( flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. model: ID of the model to use. The options are `gpt-4o-transcribe`, - `gpt-4o-mini-transcribe`, `whisper-1` (which is powered by our open source - Whisper V2 model), and `gpt-4o-transcribe-diarize`. + `gpt-4o-mini-transcribe`, `gpt-4o-mini-transcribe-2025-12-15`, `whisper-1` + (which is powered by our open source Whisper V2 model), and + `gpt-4o-transcribe-diarize`. stream: If set to true, the model response data will be streamed to the client as it is generated using @@ -368,9 +372,9 @@ def create( include: Additional information to include in the transcription response. `logprobs` will return the log probabilities of the tokens in the response to understand the model's confidence in the transcription. `logprobs` only works with - response_format set to `json` and only with the models `gpt-4o-transcribe` and - `gpt-4o-mini-transcribe`. This field is not supported when using - `gpt-4o-transcribe-diarize`. + response_format set to `json` and only with the models `gpt-4o-transcribe`, + `gpt-4o-mini-transcribe`, and `gpt-4o-mini-transcribe-2025-12-15`. This field is + not supported when using `gpt-4o-transcribe-diarize`. known_speaker_names: Optional list of speaker names that correspond to the audio samples provided in `known_speaker_references[]`. Each entry should be a short identifier (for @@ -535,8 +539,9 @@ async def create( flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. model: ID of the model to use. The options are `gpt-4o-transcribe`, - `gpt-4o-mini-transcribe`, `whisper-1` (which is powered by our open source - Whisper V2 model), and `gpt-4o-transcribe-diarize`. + `gpt-4o-mini-transcribe`, `gpt-4o-mini-transcribe-2025-12-15`, `whisper-1` + (which is powered by our open source Whisper V2 model), and + `gpt-4o-transcribe-diarize`. chunking_strategy: Controls how the audio is cut into chunks. When set to `"auto"`, the server first normalizes loudness and then uses voice activity detection (VAD) to choose @@ -548,9 +553,9 @@ async def create( include: Additional information to include in the transcription response. `logprobs` will return the log probabilities of the tokens in the response to understand the model's confidence in the transcription. `logprobs` only works with - response_format set to `json` and only with the models `gpt-4o-transcribe` and - `gpt-4o-mini-transcribe`. This field is not supported when using - `gpt-4o-transcribe-diarize`. + response_format set to `json` and only with the models `gpt-4o-transcribe`, + `gpt-4o-mini-transcribe`, and `gpt-4o-mini-transcribe-2025-12-15`. This field is + not supported when using `gpt-4o-transcribe-diarize`. known_speaker_names: Optional list of speaker names that correspond to the audio samples provided in `known_speaker_references[]`. Each entry should be a short identifier (for @@ -679,8 +684,9 @@ async def create( flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. model: ID of the model to use. The options are `gpt-4o-transcribe`, - `gpt-4o-mini-transcribe`, `whisper-1` (which is powered by our open source - Whisper V2 model), and `gpt-4o-transcribe-diarize`. + `gpt-4o-mini-transcribe`, `gpt-4o-mini-transcribe-2025-12-15`, `whisper-1` + (which is powered by our open source Whisper V2 model), and + `gpt-4o-transcribe-diarize`. stream: If set to true, the model response data will be streamed to the client as it is generated using @@ -701,9 +707,9 @@ async def create( include: Additional information to include in the transcription response. `logprobs` will return the log probabilities of the tokens in the response to understand the model's confidence in the transcription. `logprobs` only works with - response_format set to `json` and only with the models `gpt-4o-transcribe` and - `gpt-4o-mini-transcribe`. This field is not supported when using - `gpt-4o-transcribe-diarize`. + response_format set to `json` and only with the models `gpt-4o-transcribe`, + `gpt-4o-mini-transcribe`, and `gpt-4o-mini-transcribe-2025-12-15`. This field is + not supported when using `gpt-4o-transcribe-diarize`. known_speaker_names: Optional list of speaker names that correspond to the audio samples provided in `known_speaker_references[]`. Each entry should be a short identifier (for @@ -786,8 +792,9 @@ async def create( flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. model: ID of the model to use. The options are `gpt-4o-transcribe`, - `gpt-4o-mini-transcribe`, `whisper-1` (which is powered by our open source - Whisper V2 model), and `gpt-4o-transcribe-diarize`. + `gpt-4o-mini-transcribe`, `gpt-4o-mini-transcribe-2025-12-15`, `whisper-1` + (which is powered by our open source Whisper V2 model), and + `gpt-4o-transcribe-diarize`. stream: If set to true, the model response data will be streamed to the client as it is generated using @@ -808,9 +815,9 @@ async def create( include: Additional information to include in the transcription response. `logprobs` will return the log probabilities of the tokens in the response to understand the model's confidence in the transcription. `logprobs` only works with - response_format set to `json` and only with the models `gpt-4o-transcribe` and - `gpt-4o-mini-transcribe`. This field is not supported when using - `gpt-4o-transcribe-diarize`. + response_format set to `json` and only with the models `gpt-4o-transcribe`, + `gpt-4o-mini-transcribe`, and `gpt-4o-mini-transcribe-2025-12-15`. This field is + not supported when using `gpt-4o-transcribe-diarize`. known_speaker_names: Optional list of speaker names that correspond to the audio samples provided in `known_speaker_references[]`. Each entry should be a short identifier (for diff --git a/src/openai/resources/realtime/calls.py b/src/openai/resources/realtime/calls.py index cdea492d95..20a22fc3b6 100644 --- a/src/openai/resources/realtime/calls.py +++ b/src/openai/resources/realtime/calls.py @@ -125,8 +125,10 @@ def accept( "gpt-4o-mini-realtime-preview-2024-12-17", "gpt-realtime-mini", "gpt-realtime-mini-2025-10-06", + "gpt-realtime-mini-2025-12-15", "gpt-audio-mini", "gpt-audio-mini-2025-10-06", + "gpt-audio-mini-2025-12-15", ], ] | Omit = omit, @@ -450,8 +452,10 @@ async def accept( "gpt-4o-mini-realtime-preview-2024-12-17", "gpt-realtime-mini", "gpt-realtime-mini-2025-10-06", + "gpt-realtime-mini-2025-12-15", "gpt-audio-mini", "gpt-audio-mini-2025-10-06", + "gpt-audio-mini-2025-12-15", ], ] | Omit = omit, diff --git a/src/openai/resources/videos.py b/src/openai/resources/videos.py index 727091c607..9f74c942bc 100644 --- a/src/openai/resources/videos.py +++ b/src/openai/resources/videos.py @@ -10,7 +10,6 @@ from .. import _legacy_response from ..types import ( VideoSize, - VideoModel, VideoSeconds, video_list_params, video_remix_params, @@ -34,8 +33,8 @@ from .._base_client import AsyncPaginator, make_request_options from .._utils._utils import is_given from ..types.video_size import VideoSize -from ..types.video_model import VideoModel from ..types.video_seconds import VideoSeconds +from ..types.video_model_param import VideoModelParam from ..types.video_delete_response import VideoDeleteResponse __all__ = ["Videos", "AsyncVideos"] @@ -66,7 +65,7 @@ def create( *, prompt: str, input_reference: FileTypes | Omit = omit, - model: VideoModel | Omit = omit, + model: VideoModelParam | Omit = omit, seconds: VideoSeconds | Omit = omit, size: VideoSize | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -130,7 +129,7 @@ def create_and_poll( *, prompt: str, input_reference: FileTypes | Omit = omit, - model: VideoModel | Omit = omit, + model: VideoModelParam | Omit = omit, seconds: VideoSeconds | Omit = omit, size: VideoSize | Omit = omit, poll_interval_ms: int | Omit = omit, @@ -421,7 +420,7 @@ async def create( *, prompt: str, input_reference: FileTypes | Omit = omit, - model: VideoModel | Omit = omit, + model: VideoModelParam | Omit = omit, seconds: VideoSeconds | Omit = omit, size: VideoSize | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -485,7 +484,7 @@ async def create_and_poll( *, prompt: str, input_reference: FileTypes | Omit = omit, - model: VideoModel | Omit = omit, + model: VideoModelParam | Omit = omit, seconds: VideoSeconds | Omit = omit, size: VideoSize | Omit = omit, poll_interval_ms: int | Omit = omit, diff --git a/src/openai/types/__init__.py b/src/openai/types/__init__.py index a98ca16ee9..5eb267e845 100644 --- a/src/openai/types/__init__.py +++ b/src/openai/types/__init__.py @@ -53,6 +53,7 @@ from .completion_choice import CompletionChoice as CompletionChoice from .image_edit_params import ImageEditParams as ImageEditParams from .video_list_params import VideoListParams as VideoListParams +from .video_model_param import VideoModelParam as VideoModelParam from .eval_create_params import EvalCreateParams as EvalCreateParams from .eval_list_response import EvalListResponse as EvalListResponse from .eval_update_params import EvalUpdateParams as EvalUpdateParams diff --git a/src/openai/types/audio/speech_create_params.py b/src/openai/types/audio/speech_create_params.py index 634d788191..37180995c8 100644 --- a/src/openai/types/audio/speech_create_params.py +++ b/src/openai/types/audio/speech_create_params.py @@ -17,7 +17,7 @@ class SpeechCreateParams(TypedDict, total=False): model: Required[Union[str, SpeechModel]] """ One of the available [TTS models](https://platform.openai.com/docs/models#tts): - `tts-1`, `tts-1-hd` or `gpt-4o-mini-tts`. + `tts-1`, `tts-1-hd`, `gpt-4o-mini-tts`, or `gpt-4o-mini-tts-2025-12-15`. """ voice: Required[ diff --git a/src/openai/types/audio/speech_model.py b/src/openai/types/audio/speech_model.py index f004f805da..31294a05b6 100644 --- a/src/openai/types/audio/speech_model.py +++ b/src/openai/types/audio/speech_model.py @@ -4,4 +4,4 @@ __all__ = ["SpeechModel"] -SpeechModel: TypeAlias = Literal["tts-1", "tts-1-hd", "gpt-4o-mini-tts"] +SpeechModel: TypeAlias = Literal["tts-1", "tts-1-hd", "gpt-4o-mini-tts", "gpt-4o-mini-tts-2025-12-15"] diff --git a/src/openai/types/audio/transcription_create_params.py b/src/openai/types/audio/transcription_create_params.py index adaef9f5fe..15540fc73f 100644 --- a/src/openai/types/audio/transcription_create_params.py +++ b/src/openai/types/audio/transcription_create_params.py @@ -29,9 +29,9 @@ class TranscriptionCreateParamsBase(TypedDict, total=False): model: Required[Union[str, AudioModel]] """ID of the model to use. - The options are `gpt-4o-transcribe`, `gpt-4o-mini-transcribe`, `whisper-1` - (which is powered by our open source Whisper V2 model), and - `gpt-4o-transcribe-diarize`. + The options are `gpt-4o-transcribe`, `gpt-4o-mini-transcribe`, + `gpt-4o-mini-transcribe-2025-12-15`, `whisper-1` (which is powered by our open + source Whisper V2 model), and `gpt-4o-transcribe-diarize`. """ chunking_strategy: Optional[ChunkingStrategy] @@ -49,9 +49,9 @@ class TranscriptionCreateParamsBase(TypedDict, total=False): Additional information to include in the transcription response. `logprobs` will return the log probabilities of the tokens in the response to understand the model's confidence in the transcription. `logprobs` only works with - response_format set to `json` and only with the models `gpt-4o-transcribe` and - `gpt-4o-mini-transcribe`. This field is not supported when using - `gpt-4o-transcribe-diarize`. + response_format set to `json` and only with the models `gpt-4o-transcribe`, + `gpt-4o-mini-transcribe`, and `gpt-4o-mini-transcribe-2025-12-15`. This field is + not supported when using `gpt-4o-transcribe-diarize`. """ known_speaker_names: SequenceNotStr[str] diff --git a/src/openai/types/audio_model.py b/src/openai/types/audio_model.py index 68031a2198..8acada6dc3 100644 --- a/src/openai/types/audio_model.py +++ b/src/openai/types/audio_model.py @@ -4,4 +4,10 @@ __all__ = ["AudioModel"] -AudioModel: TypeAlias = Literal["whisper-1", "gpt-4o-transcribe", "gpt-4o-mini-transcribe", "gpt-4o-transcribe-diarize"] +AudioModel: TypeAlias = Literal[ + "whisper-1", + "gpt-4o-transcribe", + "gpt-4o-mini-transcribe", + "gpt-4o-mini-transcribe-2025-12-15", + "gpt-4o-transcribe-diarize", +] diff --git a/src/openai/types/realtime/audio_transcription.py b/src/openai/types/realtime/audio_transcription.py index 3e5c8e0cb4..0a8c1371e0 100644 --- a/src/openai/types/realtime/audio_transcription.py +++ b/src/openai/types/realtime/audio_transcription.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional +from typing import Union, Optional from typing_extensions import Literal from ..._models import BaseModel @@ -17,13 +17,22 @@ class AudioTranscription(BaseModel): format will improve accuracy and latency. """ - model: Optional[ - Literal["whisper-1", "gpt-4o-mini-transcribe", "gpt-4o-transcribe", "gpt-4o-transcribe-diarize"] + model: Union[ + str, + Literal[ + "whisper-1", + "gpt-4o-mini-transcribe", + "gpt-4o-mini-transcribe-2025-12-15", + "gpt-4o-transcribe", + "gpt-4o-transcribe-diarize", + ], + None, ] = None """The model to use for transcription. - Current options are `whisper-1`, `gpt-4o-mini-transcribe`, `gpt-4o-transcribe`, - and `gpt-4o-transcribe-diarize`. Use `gpt-4o-transcribe-diarize` when you need + Current options are `whisper-1`, `gpt-4o-mini-transcribe`, + `gpt-4o-mini-transcribe-2025-12-15`, `gpt-4o-transcribe`, and + `gpt-4o-transcribe-diarize`. Use `gpt-4o-transcribe-diarize` when you need diarization with speaker labels. """ diff --git a/src/openai/types/realtime/audio_transcription_param.py b/src/openai/types/realtime/audio_transcription_param.py index 3b65e42c8f..7e60a003ce 100644 --- a/src/openai/types/realtime/audio_transcription_param.py +++ b/src/openai/types/realtime/audio_transcription_param.py @@ -2,6 +2,7 @@ from __future__ import annotations +from typing import Union from typing_extensions import Literal, TypedDict __all__ = ["AudioTranscriptionParam"] @@ -16,11 +17,21 @@ class AudioTranscriptionParam(TypedDict, total=False): format will improve accuracy and latency. """ - model: Literal["whisper-1", "gpt-4o-mini-transcribe", "gpt-4o-transcribe", "gpt-4o-transcribe-diarize"] + model: Union[ + str, + Literal[ + "whisper-1", + "gpt-4o-mini-transcribe", + "gpt-4o-mini-transcribe-2025-12-15", + "gpt-4o-transcribe", + "gpt-4o-transcribe-diarize", + ], + ] """The model to use for transcription. - Current options are `whisper-1`, `gpt-4o-mini-transcribe`, `gpt-4o-transcribe`, - and `gpt-4o-transcribe-diarize`. Use `gpt-4o-transcribe-diarize` when you need + Current options are `whisper-1`, `gpt-4o-mini-transcribe`, + `gpt-4o-mini-transcribe-2025-12-15`, `gpt-4o-transcribe`, and + `gpt-4o-transcribe-diarize`. Use `gpt-4o-transcribe-diarize` when you need diarization with speaker labels. """ diff --git a/src/openai/types/realtime/call_accept_params.py b/src/openai/types/realtime/call_accept_params.py index 917b71cb0d..d950f59f69 100644 --- a/src/openai/types/realtime/call_accept_params.py +++ b/src/openai/types/realtime/call_accept_params.py @@ -65,8 +65,10 @@ class CallAcceptParams(TypedDict, total=False): "gpt-4o-mini-realtime-preview-2024-12-17", "gpt-realtime-mini", "gpt-realtime-mini-2025-10-06", + "gpt-realtime-mini-2025-12-15", "gpt-audio-mini", "gpt-audio-mini-2025-10-06", + "gpt-audio-mini-2025-12-15", ], ] """The Realtime model used for this session.""" diff --git a/src/openai/types/realtime/realtime_session_create_request.py b/src/openai/types/realtime/realtime_session_create_request.py index 76738816a0..4a93c91c7d 100644 --- a/src/openai/types/realtime/realtime_session_create_request.py +++ b/src/openai/types/realtime/realtime_session_create_request.py @@ -66,8 +66,10 @@ class RealtimeSessionCreateRequest(BaseModel): "gpt-4o-mini-realtime-preview-2024-12-17", "gpt-realtime-mini", "gpt-realtime-mini-2025-10-06", + "gpt-realtime-mini-2025-12-15", "gpt-audio-mini", "gpt-audio-mini-2025-10-06", + "gpt-audio-mini-2025-12-15", ], None, ] = None diff --git a/src/openai/types/realtime/realtime_session_create_request_param.py b/src/openai/types/realtime/realtime_session_create_request_param.py index cc5806fe11..dee63d0967 100644 --- a/src/openai/types/realtime/realtime_session_create_request_param.py +++ b/src/openai/types/realtime/realtime_session_create_request_param.py @@ -67,8 +67,10 @@ class RealtimeSessionCreateRequestParam(TypedDict, total=False): "gpt-4o-mini-realtime-preview-2024-12-17", "gpt-realtime-mini", "gpt-realtime-mini-2025-10-06", + "gpt-realtime-mini-2025-12-15", "gpt-audio-mini", "gpt-audio-mini-2025-10-06", + "gpt-audio-mini-2025-12-15", ], ] """The Realtime model used for this session.""" diff --git a/src/openai/types/realtime/realtime_session_create_response.py b/src/openai/types/realtime/realtime_session_create_response.py index 46d32e8571..15a200ca17 100644 --- a/src/openai/types/realtime/realtime_session_create_response.py +++ b/src/openai/types/realtime/realtime_session_create_response.py @@ -469,8 +469,10 @@ class RealtimeSessionCreateResponse(BaseModel): "gpt-4o-mini-realtime-preview-2024-12-17", "gpt-realtime-mini", "gpt-realtime-mini-2025-10-06", + "gpt-realtime-mini-2025-12-15", "gpt-audio-mini", "gpt-audio-mini-2025-10-06", + "gpt-audio-mini-2025-12-15", ], None, ] = None diff --git a/src/openai/types/video_create_params.py b/src/openai/types/video_create_params.py index c4d3e0851f..d787aaeddd 100644 --- a/src/openai/types/video_create_params.py +++ b/src/openai/types/video_create_params.py @@ -6,8 +6,8 @@ from .._types import FileTypes from .video_size import VideoSize -from .video_model import VideoModel from .video_seconds import VideoSeconds +from .video_model_param import VideoModelParam __all__ = ["VideoCreateParams"] @@ -19,7 +19,7 @@ class VideoCreateParams(TypedDict, total=False): input_reference: FileTypes """Optional image reference that guides generation.""" - model: VideoModel + model: VideoModelParam """The video generation model to use (allowed values: sora-2, sora-2-pro). Defaults to `sora-2`. diff --git a/src/openai/types/video_model.py b/src/openai/types/video_model.py index e96e7685f8..29d8cb16eb 100644 --- a/src/openai/types/video_model.py +++ b/src/openai/types/video_model.py @@ -1,9 +1,10 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from typing import Union from typing_extensions import Literal, TypeAlias __all__ = ["VideoModel"] -VideoModel: TypeAlias = Literal[ - "sora-2", "sora-2-pro", "sora-2-2025-10-06", "sora-2-pro-2025-10-06", "sora-2-2025-12-08" +VideoModel: TypeAlias = Union[ + str, Literal["sora-2", "sora-2-pro", "sora-2-2025-10-06", "sora-2-pro-2025-10-06", "sora-2-2025-12-08"] ] diff --git a/src/openai/types/video_model_param.py b/src/openai/types/video_model_param.py new file mode 100644 index 0000000000..4310b8d057 --- /dev/null +++ b/src/openai/types/video_model_param.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import Literal, TypeAlias + +__all__ = ["VideoModelParam"] + +VideoModelParam: TypeAlias = Union[ + str, Literal["sora-2", "sora-2-pro", "sora-2-2025-10-06", "sora-2-pro-2025-10-06", "sora-2-2025-12-08"] +] diff --git a/tests/api_resources/realtime/test_calls.py b/tests/api_resources/realtime/test_calls.py index 5495a58a4e..9bb6ef3faf 100644 --- a/tests/api_resources/realtime/test_calls.py +++ b/tests/api_resources/realtime/test_calls.py @@ -48,7 +48,7 @@ def test_method_create_with_all_params(self, client: OpenAI, respx_mock: MockRou "noise_reduction": {"type": "near_field"}, "transcription": { "language": "language", - "model": "whisper-1", + "model": "string", "prompt": "prompt", }, "turn_detection": { @@ -147,7 +147,7 @@ def test_method_accept_with_all_params(self, client: OpenAI) -> None: "noise_reduction": {"type": "near_field"}, "transcription": { "language": "language", - "model": "whisper-1", + "model": "string", "prompt": "prompt", }, "turn_detection": { @@ -386,7 +386,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI, re "noise_reduction": {"type": "near_field"}, "transcription": { "language": "language", - "model": "whisper-1", + "model": "string", "prompt": "prompt", }, "turn_detection": { @@ -485,7 +485,7 @@ async def test_method_accept_with_all_params(self, async_client: AsyncOpenAI) -> "noise_reduction": {"type": "near_field"}, "transcription": { "language": "language", - "model": "whisper-1", + "model": "string", "prompt": "prompt", }, "turn_detection": { diff --git a/tests/api_resources/realtime/test_client_secrets.py b/tests/api_resources/realtime/test_client_secrets.py index cd15b4be52..17762771ac 100644 --- a/tests/api_resources/realtime/test_client_secrets.py +++ b/tests/api_resources/realtime/test_client_secrets.py @@ -40,7 +40,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: "noise_reduction": {"type": "near_field"}, "transcription": { "language": "language", - "model": "whisper-1", + "model": "string", "prompt": "prompt", }, "turn_detection": { @@ -136,7 +136,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> "noise_reduction": {"type": "near_field"}, "transcription": { "language": "language", - "model": "whisper-1", + "model": "string", "prompt": "prompt", }, "turn_detection": { diff --git a/tests/api_resources/test_videos.py b/tests/api_resources/test_videos.py index 623cfc2153..b785e03ca5 100644 --- a/tests/api_resources/test_videos.py +++ b/tests/api_resources/test_videos.py @@ -39,7 +39,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: video = client.videos.create( prompt="x", input_reference=b"raw file contents", - model="sora-2", + model="string", seconds="4", size="720x1280", ) @@ -297,7 +297,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> video = await async_client.videos.create( prompt="x", input_reference=b"raw file contents", - model="sora-2", + model="string", seconds="4", size="720x1280", ) From a3c27a28d8a3b69f43e4722f97b3cc96a5f2171f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 18 Dec 2025 21:52:28 +0000 Subject: [PATCH 580/769] chore(internal): add `--fix` argument to lint script --- scripts/lint | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/scripts/lint b/scripts/lint index 55bc1dd711..275a2bf1a1 100755 --- a/scripts/lint +++ b/scripts/lint @@ -4,8 +4,13 @@ set -e cd "$(dirname "$0")/.." -echo "==> Running lints" -rye run lint +if [ "$1" = "--fix" ]; then + echo "==> Running lints with --fix" + rye run fix:ruff +else + echo "==> Running lints" + rye run lint +fi echo "==> Making sure it imports" rye run python -c 'import openai' From 4547f1a0880d9765134e385709c9049462d270b1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 19 Dec 2025 03:04:53 +0000 Subject: [PATCH 581/769] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 6ec100546a..e9485c8224 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 137 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-75926226b642ebb2cb415694da9dff35e8ab40145ac1b791cefb82a83809db4d.yml openapi_spec_hash: 6a0e391b0ba5747b6b4a3e5fe21de4da -config_hash: c028ce402ef5f71da947c3f15bf6046d +config_hash: adcf23ecf5f84d3cadf1d71e82ec636a From d3e632171c7842abf97b26379f564531d80ad096 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 19 Dec 2025 03:05:26 +0000 Subject: [PATCH 582/769] release: 2.14.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 18 ++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index e6eadb43e0..5868289349 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.13.0" + ".": "2.14.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 745512f15d..ca71bc108e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ # Changelog +## 2.14.0 (2025-12-19) + +Full Changelog: [v2.13.0...v2.14.0](https://github.com/openai/openai-python/compare/v2.13.0...v2.14.0) + +### Features + +* **api:** slugs for new audio models; make all `model` params accept strings ([e517792](https://github.com/openai/openai-python/commit/e517792b58d1768cfb3432a555a354ae0a9cfa21)) + + +### Bug Fixes + +* use async_to_httpx_files in patch method ([a6af9ee](https://github.com/openai/openai-python/commit/a6af9ee5643197222f328d5e73a80ab3515c32e2)) + + +### Chores + +* **internal:** add `--fix` argument to lint script ([93107ef](https://github.com/openai/openai-python/commit/93107ef36abcfd9c6b1419533a1720031f03caec)) + ## 2.13.0 (2025-12-16) Full Changelog: [v2.12.0...v2.13.0](https://github.com/openai/openai-python/compare/v2.12.0...v2.13.0) diff --git a/pyproject.toml b/pyproject.toml index f9dd23592a..a720293abb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.13.0" +version = "2.14.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 dfda2f0522..5fe6b5b08c 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__ = "2.13.0" # x-release-please-version +__version__ = "2.14.0" # x-release-please-version From 032e6cb557aab92acd17b883f0801746afd315b9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 5 Jan 2026 04:06:54 +0000 Subject: [PATCH 583/769] chore(internal): codegen related update --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index f011417af6..cbb5bb26e4 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2025 OpenAI + Copyright 2026 OpenAI Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. From 5da8c5f36a3a31050608dbd5de067985275dc176 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 9 Jan 2026 21:53:36 +0000 Subject: [PATCH 584/769] feat(api): add new Response completed_at prop --- .stats.yml | 6 +++--- src/openai/resources/audio/speech.py | 14 ++++++++------ src/openai/resources/images.py | 18 ++++++++++++------ src/openai/resources/responses/input_tokens.py | 8 ++------ src/openai/types/audio/speech_create_params.py | 6 +++--- .../types/chat/chat_completion_audio_param.py | 4 ++-- .../realtime/realtime_audio_config_output.py | 6 +++--- .../realtime_audio_config_output_param.py | 6 +++--- .../realtime_response_create_audio_output.py | 7 +++---- ...ltime_response_create_audio_output_param.py | 7 +++---- .../responses/input_token_count_params.py | 6 +----- src/openai/types/responses/response.py | 16 +++++++++++----- .../responses/response_compaction_item.py | 2 ++ .../response_compaction_item_param.py | 1 + .../response_compaction_item_param_param.py | 1 + ...response_function_shell_tool_call_output.py | 8 ++++++-- .../responses/response_function_web_search.py | 5 ++++- .../response_function_web_search_param.py | 7 ++++++- src/openai/types/responses/tool.py | 1 + src/openai/types/responses/tool_param.py | 1 + src/openai/types/video_create_error.py | 4 ++++ 21 files changed, 80 insertions(+), 54 deletions(-) diff --git a/.stats.yml b/.stats.yml index e9485c8224..fe01e150f9 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 137 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-75926226b642ebb2cb415694da9dff35e8ab40145ac1b791cefb82a83809db4d.yml -openapi_spec_hash: 6a0e391b0ba5747b6b4a3e5fe21de4da -config_hash: adcf23ecf5f84d3cadf1d71e82ec636a +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-9442fa9212dd61aac2bb0edd19744bee381e75888712f9098bc6ebb92c52b557.yml +openapi_spec_hash: f87823d164b7a8f72a42eba04e482a99 +config_hash: ad7136f7366fddec432ec378939e58a7 diff --git a/src/openai/resources/audio/speech.py b/src/openai/resources/audio/speech.py index b92fcb73d3..f2c8d635f3 100644 --- a/src/openai/resources/audio/speech.py +++ b/src/openai/resources/audio/speech.py @@ -74,9 +74,10 @@ def create( One of the available [TTS models](https://platform.openai.com/docs/models#tts): `tts-1`, `tts-1-hd`, `gpt-4o-mini-tts`, or `gpt-4o-mini-tts-2025-12-15`. - voice: The voice to use when generating the audio. Supported voices are `alloy`, `ash`, - `ballad`, `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, `shimmer`, and - `verse`. Previews of the voices are available in the + voice: The voice to use when generating the audio. Supported built-in voices are + `alloy`, `ash`, `ballad`, `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, + `shimmer`, `verse`, `marin`, and `cedar`. Previews of the voices are available + in the [Text to speech guide](https://platform.openai.com/docs/guides/text-to-speech#voice-options). instructions: Control the voice of your generated audio with additional instructions. Does not @@ -170,9 +171,10 @@ async def create( One of the available [TTS models](https://platform.openai.com/docs/models#tts): `tts-1`, `tts-1-hd`, `gpt-4o-mini-tts`, or `gpt-4o-mini-tts-2025-12-15`. - voice: The voice to use when generating the audio. Supported voices are `alloy`, `ash`, - `ballad`, `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, `shimmer`, and - `verse`. Previews of the voices are available in the + voice: The voice to use when generating the audio. Supported built-in voices are + `alloy`, `ash`, `ballad`, `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, + `shimmer`, `verse`, `marin`, and `cedar`. Previews of the voices are available + in the [Text to speech guide](https://platform.openai.com/docs/guides/text-to-speech#voice-options). instructions: Control the voice of your generated audio with additional instructions. Does not diff --git a/src/openai/resources/images.py b/src/openai/resources/images.py index 79505a8269..805828488f 100644 --- a/src/openai/resources/images.py +++ b/src/openai/resources/images.py @@ -146,7 +146,8 @@ def edit( """Creates an edited or extended image given one or more source images and a prompt. - This endpoint only supports `gpt-image-1` and `dall-e-2`. + This endpoint supports GPT Image models (`gpt-image-1.5`, `gpt-image-1`, + and `gpt-image-1-mini`) and `dall-e-2`. Args: image: The image(s) to edit. Must be a supported image file or an array of images. @@ -260,7 +261,8 @@ def edit( """Creates an edited or extended image given one or more source images and a prompt. - This endpoint only supports `gpt-image-1` and `dall-e-2`. + This endpoint supports GPT Image models (`gpt-image-1.5`, `gpt-image-1`, + and `gpt-image-1-mini`) and `dall-e-2`. Args: image: The image(s) to edit. Must be a supported image file or an array of images. @@ -374,7 +376,8 @@ def edit( """Creates an edited or extended image given one or more source images and a prompt. - This endpoint only supports `gpt-image-1` and `dall-e-2`. + This endpoint supports GPT Image models (`gpt-image-1.5`, `gpt-image-1`, + and `gpt-image-1-mini`) and `dall-e-2`. Args: image: The image(s) to edit. Must be a supported image file or an array of images. @@ -1039,7 +1042,8 @@ async def edit( """Creates an edited or extended image given one or more source images and a prompt. - This endpoint only supports `gpt-image-1` and `dall-e-2`. + This endpoint supports GPT Image models (`gpt-image-1.5`, `gpt-image-1`, + and `gpt-image-1-mini`) and `dall-e-2`. Args: image: The image(s) to edit. Must be a supported image file or an array of images. @@ -1153,7 +1157,8 @@ async def edit( """Creates an edited or extended image given one or more source images and a prompt. - This endpoint only supports `gpt-image-1` and `dall-e-2`. + This endpoint supports GPT Image models (`gpt-image-1.5`, `gpt-image-1`, + and `gpt-image-1-mini`) and `dall-e-2`. Args: image: The image(s) to edit. Must be a supported image file or an array of images. @@ -1267,7 +1272,8 @@ async def edit( """Creates an edited or extended image given one or more source images and a prompt. - This endpoint only supports `gpt-image-1` and `dall-e-2`. + This endpoint supports GPT Image models (`gpt-image-1.5`, `gpt-image-1`, + and `gpt-image-1-mini`) and `dall-e-2`. Args: image: The image(s) to edit. Must be a supported image file or an array of images. diff --git a/src/openai/resources/responses/input_tokens.py b/src/openai/resources/responses/input_tokens.py index 0f47955fe4..8664164655 100644 --- a/src/openai/resources/responses/input_tokens.py +++ b/src/openai/resources/responses/input_tokens.py @@ -102,9 +102,7 @@ def count( - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - tool_choice: How the model should select which tool (or tools) to use when generating a - response. See the `tools` parameter to see how to specify which tools the model - can call. + tool_choice: Controls which tool the model should use, if any. tools: An array of tools the model may call while generating a response. You can specify which tool to use by setting the `tool_choice` parameter. @@ -227,9 +225,7 @@ async def count( - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - tool_choice: How the model should select which tool (or tools) to use when generating a - response. See the `tools` parameter to see how to specify which tools the model - can call. + tool_choice: Controls which tool the model should use, if any. tools: An array of tools the model may call while generating a response. You can specify which tool to use by setting the `tool_choice` parameter. diff --git a/src/openai/types/audio/speech_create_params.py b/src/openai/types/audio/speech_create_params.py index 37180995c8..417df5b218 100644 --- a/src/openai/types/audio/speech_create_params.py +++ b/src/openai/types/audio/speech_create_params.py @@ -25,9 +25,9 @@ class SpeechCreateParams(TypedDict, total=False): ] """The voice to use when generating the audio. - Supported voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, `fable`, `onyx`, - `nova`, `sage`, `shimmer`, and `verse`. Previews of the voices are available in - the + Supported built-in voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, + `fable`, `onyx`, `nova`, `sage`, `shimmer`, `verse`, `marin`, and `cedar`. + Previews of the voices are available in the [Text to speech guide](https://platform.openai.com/docs/guides/text-to-speech#voice-options). """ diff --git a/src/openai/types/chat/chat_completion_audio_param.py b/src/openai/types/chat/chat_completion_audio_param.py index cac3c8b9d4..1a73bb0c7e 100644 --- a/src/openai/types/chat/chat_completion_audio_param.py +++ b/src/openai/types/chat/chat_completion_audio_param.py @@ -26,6 +26,6 @@ class ChatCompletionAudioParam(TypedDict, total=False): ] """The voice the model uses to respond. - Supported voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, `fable`, `nova`, - `onyx`, `sage`, and `shimmer`. + Supported built-in voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, + `fable`, `nova`, `onyx`, `sage`, `shimmer`, `marin`, and `cedar`. """ diff --git a/src/openai/types/realtime/realtime_audio_config_output.py b/src/openai/types/realtime/realtime_audio_config_output.py index a8af237c1d..2922405f63 100644 --- a/src/openai/types/realtime/realtime_audio_config_output.py +++ b/src/openai/types/realtime/realtime_audio_config_output.py @@ -29,8 +29,8 @@ class RealtimeAudioConfigOutput(BaseModel): ] = None """The voice the model uses to respond. - Voice cannot be changed during the session once the model has responded with - audio at least once. Current voice options are `alloy`, `ash`, `ballad`, - `coral`, `echo`, `sage`, `shimmer`, `verse`, `marin`, and `cedar`. We recommend + Supported built-in voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`, + `shimmer`, `verse`, `marin`, and `cedar`. Voice cannot be changed during the + session once the model has responded with audio at least once. We recommend `marin` and `cedar` for best quality. """ diff --git a/src/openai/types/realtime/realtime_audio_config_output_param.py b/src/openai/types/realtime/realtime_audio_config_output_param.py index 8e887d3464..d04fd3a303 100644 --- a/src/openai/types/realtime/realtime_audio_config_output_param.py +++ b/src/openai/types/realtime/realtime_audio_config_output_param.py @@ -28,8 +28,8 @@ class RealtimeAudioConfigOutputParam(TypedDict, total=False): voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"]] """The voice the model uses to respond. - Voice cannot be changed during the session once the model has responded with - audio at least once. Current voice options are `alloy`, `ash`, `ballad`, - `coral`, `echo`, `sage`, `shimmer`, `verse`, `marin`, and `cedar`. We recommend + Supported built-in voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`, + `shimmer`, `verse`, `marin`, and `cedar`. Voice cannot be changed during the + session once the model has responded with audio at least once. We recommend `marin` and `cedar` for best quality. """ diff --git a/src/openai/types/realtime/realtime_response_create_audio_output.py b/src/openai/types/realtime/realtime_response_create_audio_output.py index b8f4d284d5..db02511ab1 100644 --- a/src/openai/types/realtime/realtime_response_create_audio_output.py +++ b/src/openai/types/realtime/realtime_response_create_audio_output.py @@ -18,10 +18,9 @@ class Output(BaseModel): ] = None """The voice the model uses to respond. - Voice cannot be changed during the session once the model has responded with - audio at least once. Current voice options are `alloy`, `ash`, `ballad`, - `coral`, `echo`, `sage`, `shimmer`, `verse`, `marin`, and `cedar`. We recommend - `marin` and `cedar` for best quality. + Supported built-in voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`, + `shimmer`, `verse`, `marin`, and `cedar`. Voice cannot be changed during the + session once the model has responded with audio at least once. """ diff --git a/src/openai/types/realtime/realtime_response_create_audio_output_param.py b/src/openai/types/realtime/realtime_response_create_audio_output_param.py index 30a4633698..22787ad106 100644 --- a/src/openai/types/realtime/realtime_response_create_audio_output_param.py +++ b/src/openai/types/realtime/realtime_response_create_audio_output_param.py @@ -17,10 +17,9 @@ class Output(TypedDict, total=False): voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"]] """The voice the model uses to respond. - Voice cannot be changed during the session once the model has responded with - audio at least once. Current voice options are `alloy`, `ash`, `ballad`, - `coral`, `echo`, `sage`, `shimmer`, `verse`, `marin`, and `cedar`. We recommend - `marin` and `cedar` for best quality. + Supported built-in voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`, + `shimmer`, `verse`, `marin`, and `cedar`. Voice cannot be changed during the + session once the model has responded with audio at least once. """ diff --git a/src/openai/types/responses/input_token_count_params.py b/src/openai/types/responses/input_token_count_params.py index 50cc950e41..97ee4bf6ca 100644 --- a/src/openai/types/responses/input_token_count_params.py +++ b/src/openai/types/responses/input_token_count_params.py @@ -78,11 +78,7 @@ class InputTokenCountParams(TypedDict, total=False): """ tool_choice: Optional[ToolChoice] - """ - How the model should select which tool (or tools) to use when generating a - response. See the `tools` parameter to see how to specify which tools the model - can call. - """ + """Controls which tool the model should use, if any.""" tools: Optional[Iterable[ToolParam]] """An array of tools the model may call while generating a response. diff --git a/src/openai/types/responses/response.py b/src/openai/types/responses/response.py index 00c38c064e..6bac7d65de 100644 --- a/src/openai/types/responses/response.py +++ b/src/openai/types/responses/response.py @@ -47,13 +47,13 @@ class IncompleteDetails(BaseModel): class Conversation(BaseModel): - """The conversation that this response belongs to. + """The conversation that this response belonged to. - Input items and output items from this response are automatically added to this conversation. + Input items and output items from this response were automatically added to this conversation. """ id: str - """The unique ID of the conversation.""" + """The unique ID of the conversation that this response was associated with.""" class Response(BaseModel): @@ -165,10 +165,16 @@ class Response(BaseModel): [Learn more](https://platform.openai.com/docs/guides/background). """ + completed_at: Optional[float] = None + """ + Unix timestamp (in seconds) of when this Response was completed. Only present + when the status is `completed`. + """ + conversation: Optional[Conversation] = None - """The conversation that this response belongs to. + """The conversation that this response belonged to. - Input items and output items from this response are automatically added to this + Input items and output items from this response were automatically added to this conversation. """ diff --git a/src/openai/types/responses/response_compaction_item.py b/src/openai/types/responses/response_compaction_item.py index f5f8b97f4e..36e953b127 100644 --- a/src/openai/types/responses/response_compaction_item.py +++ b/src/openai/types/responses/response_compaction_item.py @@ -17,8 +17,10 @@ class ResponseCompactionItem(BaseModel): """The unique ID of the compaction item.""" encrypted_content: str + """The encrypted content that was produced by compaction.""" type: Literal["compaction"] """The type of the item. Always `compaction`.""" created_by: Optional[str] = None + """The identifier of the actor that created the item.""" diff --git a/src/openai/types/responses/response_compaction_item_param.py b/src/openai/types/responses/response_compaction_item_param.py index 5dcc921d67..5ef134b074 100644 --- a/src/openai/types/responses/response_compaction_item_param.py +++ b/src/openai/types/responses/response_compaction_item_param.py @@ -14,6 +14,7 @@ class ResponseCompactionItemParam(BaseModel): """ encrypted_content: str + """The encrypted content of the compaction summary.""" type: Literal["compaction"] """The type of the item. Always `compaction`.""" diff --git a/src/openai/types/responses/response_compaction_item_param_param.py b/src/openai/types/responses/response_compaction_item_param_param.py index b9b5ab031c..b4d72c2e5f 100644 --- a/src/openai/types/responses/response_compaction_item_param_param.py +++ b/src/openai/types/responses/response_compaction_item_param_param.py @@ -14,6 +14,7 @@ class ResponseCompactionItemParamParam(TypedDict, total=False): """ encrypted_content: Required[str] + """The encrypted content of the compaction summary.""" type: Required[Literal["compaction"]] """The type of the item. Always `compaction`.""" diff --git a/src/openai/types/responses/response_function_shell_tool_call_output.py b/src/openai/types/responses/response_function_shell_tool_call_output.py index 7885ee2f83..5523d57ba7 100644 --- a/src/openai/types/responses/response_function_shell_tool_call_output.py +++ b/src/openai/types/responses/response_function_shell_tool_call_output.py @@ -36,7 +36,7 @@ class OutputOutcomeExit(BaseModel): class Output(BaseModel): - """The content of a shell call output.""" + """The content of a shell tool call output that was emitted.""" outcome: OutputOutcome """ @@ -45,14 +45,17 @@ class Output(BaseModel): """ stderr: str + """The standard error output that was captured.""" stdout: str + """The standard output that was captured.""" created_by: Optional[str] = None + """The identifier of the actor that created the item.""" class ResponseFunctionShellToolCallOutput(BaseModel): - """The output of a shell tool call.""" + """The output of a shell tool call that was emitted.""" id: str """The unique ID of the shell call output. @@ -76,3 +79,4 @@ class ResponseFunctionShellToolCallOutput(BaseModel): """The type of the shell call output. Always `shell_call_output`.""" created_by: Optional[str] = None + """The identifier of the actor that created the item.""" diff --git a/src/openai/types/responses/response_function_web_search.py b/src/openai/types/responses/response_function_web_search.py index 1450fba4d1..0cb7e0b0d1 100644 --- a/src/openai/types/responses/response_function_web_search.py +++ b/src/openai/types/responses/response_function_web_search.py @@ -23,11 +23,14 @@ class ActionSearch(BaseModel): """Action type "search" - Performs a web search query.""" query: str - """The search query.""" + """[DEPRECATED] The search query.""" type: Literal["search"] """The action type.""" + queries: Optional[List[str]] = None + """The search queries.""" + sources: Optional[List[ActionSearchSource]] = None """The sources used in the search.""" diff --git a/src/openai/types/responses/response_function_web_search_param.py b/src/openai/types/responses/response_function_web_search_param.py index 8d0b60334d..7db3e3c833 100644 --- a/src/openai/types/responses/response_function_web_search_param.py +++ b/src/openai/types/responses/response_function_web_search_param.py @@ -5,6 +5,8 @@ from typing import Union, Iterable from typing_extensions import Literal, Required, TypeAlias, TypedDict +from ..._types import SequenceNotStr + __all__ = [ "ResponseFunctionWebSearchParam", "Action", @@ -29,11 +31,14 @@ class ActionSearch(TypedDict, total=False): """Action type "search" - Performs a web search query.""" query: Required[str] - """The search query.""" + """[DEPRECATED] The search query.""" type: Required[Literal["search"]] """The action type.""" + queries: SequenceNotStr[str] + """The search queries.""" + sources: Iterable[ActionSearchSource] """The sources used in the search.""" diff --git a/src/openai/types/responses/tool.py b/src/openai/types/responses/tool.py index 20f50e4478..019962a0ba 100644 --- a/src/openai/types/responses/tool.py +++ b/src/openai/types/responses/tool.py @@ -187,6 +187,7 @@ class CodeInterpreterContainerCodeInterpreterToolAuto(BaseModel): """An optional list of uploaded files to make available to your code.""" memory_limit: Optional[Literal["1g", "4g", "16g", "64g"]] = None + """The memory limit for the code interpreter container.""" CodeInterpreterContainer: TypeAlias = Union[str, CodeInterpreterContainerCodeInterpreterToolAuto] diff --git a/src/openai/types/responses/tool_param.py b/src/openai/types/responses/tool_param.py index 69c6162153..37d3dde024 100644 --- a/src/openai/types/responses/tool_param.py +++ b/src/openai/types/responses/tool_param.py @@ -187,6 +187,7 @@ class CodeInterpreterContainerCodeInterpreterToolAuto(TypedDict, total=False): """An optional list of uploaded files to make available to your code.""" memory_limit: Optional[Literal["1g", "4g", "16g", "64g"]] + """The memory limit for the code interpreter container.""" CodeInterpreterContainer: TypeAlias = Union[str, CodeInterpreterContainerCodeInterpreterToolAuto] diff --git a/src/openai/types/video_create_error.py b/src/openai/types/video_create_error.py index ae328b78ea..7f520220c8 100644 --- a/src/openai/types/video_create_error.py +++ b/src/openai/types/video_create_error.py @@ -6,6 +6,10 @@ class VideoCreateError(BaseModel): + """An error that occurred while generating the response.""" + code: str + """A machine-readable error code that was returned.""" message: str + """A human-readable description of the error that was returned.""" From 722d3fffb82e9150a16da01e432b70d126ca5254 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 9 Jan 2026 21:54:50 +0000 Subject: [PATCH 585/769] release: 2.15.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 5868289349..cff01f26f0 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.14.0" + ".": "2.15.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index ca71bc108e..4630e50610 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 2.15.0 (2026-01-09) + +Full Changelog: [v2.14.0...v2.15.0](https://github.com/openai/openai-python/compare/v2.14.0...v2.15.0) + +### Features + +* **api:** add new Response completed_at prop ([f077752](https://github.com/openai/openai-python/commit/f077752f4a8364a74f784f8fb1cbe31277e1762b)) + + +### Chores + +* **internal:** codegen related update ([e7daba6](https://github.com/openai/openai-python/commit/e7daba6662a3c30f73d991e96cb19d2b54d772e0)) + ## 2.14.0 (2025-12-19) Full Changelog: [v2.13.0...v2.14.0](https://github.com/openai/openai-python/compare/v2.13.0...v2.14.0) diff --git a/pyproject.toml b/pyproject.toml index a720293abb..2d835b05af 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.14.0" +version = "2.15.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 5fe6b5b08c..6f0ccf7d72 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__ = "2.14.0" # x-release-please-version +__version__ = "2.15.0" # x-release-please-version From a532f6ef5935f569f0712992d482b3af87fd9e0c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 13 Jan 2026 18:37:21 +0000 Subject: [PATCH 586/769] feat(client): add support for binary request streaming --- src/openai/_base_client.py | 145 +++++++++++++++++++++++++--- src/openai/_models.py | 17 +++- src/openai/_types.py | 9 ++ tests/test_client.py | 187 ++++++++++++++++++++++++++++++++++++- 4 files changed, 344 insertions(+), 14 deletions(-) diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index 9e536410d6..d34208abef 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -9,6 +9,7 @@ import inspect import logging import platform +import warnings import email.utils from types import TracebackType from random import random @@ -51,9 +52,11 @@ ResponseT, AnyMapping, PostParser, + BinaryTypes, RequestFiles, HttpxSendArgs, RequestOptions, + AsyncBinaryTypes, HttpxRequestFiles, ModelBuilderProtocol, not_given, @@ -479,8 +482,19 @@ def _build_request( retries_taken: int = 0, ) -> httpx.Request: if log.isEnabledFor(logging.DEBUG): - log.debug("Request options: %s", model_dump(options, exclude_unset=True)) - + log.debug( + "Request options: %s", + model_dump( + options, + exclude_unset=True, + # Pydantic v1 can't dump every type we support in content, so we exclude it for now. + exclude={ + "content", + } + if PYDANTIC_V1 + else {}, + ), + ) kwargs: dict[str, Any] = {} json_data = options.json_data @@ -534,7 +548,13 @@ def _build_request( is_body_allowed = options.method.lower() != "get" if is_body_allowed: - if isinstance(json_data, bytes): + if options.content is not None and json_data is not None: + raise TypeError("Passing both `content` and `json_data` is not supported") + if options.content is not None and files is not None: + raise TypeError("Passing both `content` and `files` is not supported") + if options.content is not None: + kwargs["content"] = options.content + elif isinstance(json_data, bytes): kwargs["content"] = json_data else: kwargs["json"] = json_data if is_given(json_data) else None @@ -1211,6 +1231,7 @@ def post( *, cast_to: Type[ResponseT], body: Body | None = None, + content: BinaryTypes | None = None, options: RequestOptions = {}, files: RequestFiles | None = None, stream: Literal[False] = False, @@ -1223,6 +1244,7 @@ def post( *, cast_to: Type[ResponseT], body: Body | None = None, + content: BinaryTypes | None = None, options: RequestOptions = {}, files: RequestFiles | None = None, stream: Literal[True], @@ -1236,6 +1258,7 @@ def post( *, cast_to: Type[ResponseT], body: Body | None = None, + content: BinaryTypes | None = None, options: RequestOptions = {}, files: RequestFiles | None = None, stream: bool, @@ -1248,13 +1271,25 @@ def post( *, cast_to: Type[ResponseT], body: Body | None = None, + content: BinaryTypes | None = None, options: RequestOptions = {}, files: RequestFiles | None = None, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if files is not None and content is not None: + raise TypeError("Passing both `files` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) opts = FinalRequestOptions.construct( - method="post", url=path, json_data=body, files=to_httpx_files(files), **options + method="post", url=path, json_data=body, content=content, files=to_httpx_files(files), **options ) return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) @@ -1264,11 +1299,23 @@ def patch( *, cast_to: Type[ResponseT], body: Body | None = None, + content: BinaryTypes | None = None, files: RequestFiles | None = None, options: RequestOptions = {}, ) -> ResponseT: + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if files is not None and content is not None: + raise TypeError("Passing both `files` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) opts = FinalRequestOptions.construct( - method="patch", url=path, json_data=body, files=to_httpx_files(files), **options + method="patch", url=path, json_data=body, content=content, files=to_httpx_files(files), **options ) return self.request(cast_to, opts) @@ -1278,11 +1325,23 @@ def put( *, cast_to: Type[ResponseT], body: Body | None = None, + content: BinaryTypes | None = None, files: RequestFiles | None = None, options: RequestOptions = {}, ) -> ResponseT: + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if files is not None and content is not None: + raise TypeError("Passing both `files` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) opts = FinalRequestOptions.construct( - method="put", url=path, json_data=body, files=to_httpx_files(files), **options + method="put", url=path, json_data=body, content=content, files=to_httpx_files(files), **options ) return self.request(cast_to, opts) @@ -1292,9 +1351,19 @@ def delete( *, cast_to: Type[ResponseT], body: Body | None = None, + content: BinaryTypes | None = None, options: RequestOptions = {}, ) -> ResponseT: - opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, **options) + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) + opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, content=content, **options) return self.request(cast_to, opts) def get_api_list( @@ -1749,6 +1818,7 @@ async def post( *, cast_to: Type[ResponseT], body: Body | None = None, + content: AsyncBinaryTypes | None = None, files: RequestFiles | None = None, options: RequestOptions = {}, stream: Literal[False] = False, @@ -1761,6 +1831,7 @@ async def post( *, cast_to: Type[ResponseT], body: Body | None = None, + content: AsyncBinaryTypes | None = None, files: RequestFiles | None = None, options: RequestOptions = {}, stream: Literal[True], @@ -1774,6 +1845,7 @@ async def post( *, cast_to: Type[ResponseT], body: Body | None = None, + content: AsyncBinaryTypes | None = None, files: RequestFiles | None = None, options: RequestOptions = {}, stream: bool, @@ -1786,13 +1858,25 @@ async def post( *, cast_to: Type[ResponseT], body: Body | None = None, + content: AsyncBinaryTypes | None = None, files: RequestFiles | None = None, options: RequestOptions = {}, stream: bool = False, stream_cls: type[_AsyncStreamT] | None = None, ) -> ResponseT | _AsyncStreamT: + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if files is not None and content is not None: + raise TypeError("Passing both `files` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) opts = FinalRequestOptions.construct( - method="post", url=path, json_data=body, files=await async_to_httpx_files(files), **options + method="post", url=path, json_data=body, content=content, files=await async_to_httpx_files(files), **options ) return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls) @@ -1802,11 +1886,28 @@ async def patch( *, cast_to: Type[ResponseT], body: Body | None = None, + content: AsyncBinaryTypes | None = None, files: RequestFiles | None = None, options: RequestOptions = {}, ) -> ResponseT: + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if files is not None and content is not None: + raise TypeError("Passing both `files` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) opts = FinalRequestOptions.construct( - method="patch", url=path, json_data=body, files=await async_to_httpx_files(files), **options + method="patch", + url=path, + json_data=body, + content=content, + files=await async_to_httpx_files(files), + **options, ) return await self.request(cast_to, opts) @@ -1816,11 +1917,23 @@ async def put( *, cast_to: Type[ResponseT], body: Body | None = None, + content: AsyncBinaryTypes | None = None, files: RequestFiles | None = None, options: RequestOptions = {}, ) -> ResponseT: + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if files is not None and content is not None: + raise TypeError("Passing both `files` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) opts = FinalRequestOptions.construct( - method="put", url=path, json_data=body, files=await async_to_httpx_files(files), **options + method="put", url=path, json_data=body, content=content, files=await async_to_httpx_files(files), **options ) return await self.request(cast_to, opts) @@ -1830,9 +1943,19 @@ async def delete( *, cast_to: Type[ResponseT], body: Body | None = None, + content: AsyncBinaryTypes | None = None, options: RequestOptions = {}, ) -> ResponseT: - opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, **options) + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) + opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, content=content, **options) return await self.request(cast_to, opts) def get_api_list( diff --git a/src/openai/_models.py b/src/openai/_models.py index fac59c2cb8..57b5b448be 100644 --- a/src/openai/_models.py +++ b/src/openai/_models.py @@ -3,7 +3,20 @@ import os import inspect import weakref -from typing import TYPE_CHECKING, Any, Type, Tuple, Union, Generic, TypeVar, Callable, Optional, cast +from typing import ( + IO, + TYPE_CHECKING, + Any, + Type, Tuple, + Union, + Generic, + TypeVar, + Callable, + Iterable, + Optional, + AsyncIterable, + cast, +) from datetime import date, datetime from typing_extensions import ( List, @@ -827,6 +840,7 @@ class FinalRequestOptionsInput(TypedDict, total=False): timeout: float | Timeout | None files: HttpxRequestFiles | None idempotency_key: str + content: Union[bytes, bytearray, IO[bytes], Iterable[bytes], AsyncIterable[bytes], None] json_data: Body extra_json: AnyMapping follow_redirects: bool @@ -845,6 +859,7 @@ class FinalRequestOptions(pydantic.BaseModel): post_parser: Union[Callable[[Any], Any], NotGiven] = NotGiven() follow_redirects: Union[bool, None] = None + content: Union[bytes, bytearray, IO[bytes], Iterable[bytes], AsyncIterable[bytes], None] = None # It should be noted that we cannot use `json` here as that would override # a BaseModel method in an incompatible fashion. json_data: Union[Body, None] = None diff --git a/src/openai/_types.py b/src/openai/_types.py index d7e2eaac5f..42f9df2373 100644 --- a/src/openai/_types.py +++ b/src/openai/_types.py @@ -13,9 +13,11 @@ Mapping, TypeVar, Callable, + Iterable, Iterator, Optional, Sequence, + AsyncIterable, ) from typing_extensions import ( Set, @@ -57,6 +59,13 @@ else: Base64FileInput = Union[IO[bytes], PathLike] FileContent = Union[IO[bytes], bytes, PathLike] # PathLike is not subscriptable in Python 3.8. + + +# Used for sending raw binary data / streaming data in request bodies +# e.g. for file uploads without multipart encoding +BinaryTypes = Union[bytes, bytearray, IO[bytes], Iterable[bytes]] +AsyncBinaryTypes = Union[bytes, bytearray, IO[bytes], AsyncIterable[bytes]] + FileTypes = Union[ # file (or bytes) FileContent, diff --git a/tests/test_client.py b/tests/test_client.py index e8d62f17f7..bd243f68dc 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -8,10 +8,11 @@ import json import asyncio import inspect +import dataclasses import tracemalloc -from typing import Any, Union, Protocol, cast +from typing import Any, Union, Protocol, TypeVar, Callable, Iterable, Iterator, Optional, Coroutine, cast from unittest import mock -from typing_extensions import Literal +from typing_extensions import Literal, AsyncIterator, override import httpx import pytest @@ -37,6 +38,7 @@ from .utils import update_env +T = TypeVar("T") base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") api_key = "My API Key" @@ -55,6 +57,57 @@ def _low_retry_timeout(*_args: Any, **_kwargs: Any) -> float: return 0.1 +def mirror_request_content(request: httpx.Request) -> httpx.Response: + return httpx.Response(200, content=request.content) + + +# note: we can't use the httpx.MockTransport class as it consumes the request +# body itself, which means we can't test that the body is read lazily +class MockTransport(httpx.BaseTransport, httpx.AsyncBaseTransport): + def __init__( + self, + handler: Callable[[httpx.Request], httpx.Response] + | Callable[[httpx.Request], Coroutine[Any, Any, httpx.Response]], + ) -> None: + self.handler = handler + + @override + def handle_request( + self, + request: httpx.Request, + ) -> httpx.Response: + assert not inspect.iscoroutinefunction(self.handler), "handler must not be a coroutine function" + assert inspect.isfunction(self.handler), "handler must be a function" + return self.handler(request) + + @override + async def handle_async_request( + self, + request: httpx.Request, + ) -> httpx.Response: + assert inspect.iscoroutinefunction(self.handler), "handler must be a coroutine function" + return await self.handler(request) + + +@dataclasses.dataclass +class Counter: + value: int = 0 + + +def _make_sync_iterator(iterable: Iterable[T], counter: Optional[Counter] = None) -> Iterator[T]: + for item in iterable: + if counter: + counter.value += 1 + yield item + + +async def _make_async_iterator(iterable: Iterable[T], counter: Optional[Counter] = None) -> AsyncIterator[T]: + for item in iterable: + if counter: + counter.value += 1 + yield item + + def _get_open_connections(client: OpenAI | AsyncOpenAI) -> int: transport = client._client._transport assert isinstance(transport, httpx.HTTPTransport) or isinstance(transport, httpx.AsyncHTTPTransport) @@ -507,6 +560,70 @@ def test_multipart_repeating_array(self, client: OpenAI) -> None: b"", ] + @pytest.mark.respx(base_url=base_url) + def test_binary_content_upload(self, respx_mock: MockRouter, client: OpenAI) -> None: + respx_mock.post("/upload").mock(side_effect=mirror_request_content) + + file_content = b"Hello, this is a test file." + + response = client.post( + "/upload", + content=file_content, + cast_to=httpx.Response, + options={"headers": {"Content-Type": "application/octet-stream"}}, + ) + + assert response.status_code == 200 + assert response.request.headers["Content-Type"] == "application/octet-stream" + assert response.content == file_content + + def test_binary_content_upload_with_iterator(self) -> None: + file_content = b"Hello, this is a test file." + counter = Counter() + iterator = _make_sync_iterator([file_content], counter=counter) + + def mock_handler(request: httpx.Request) -> httpx.Response: + assert counter.value == 0, "the request body should not have been read" + return httpx.Response(200, content=request.read()) + + with OpenAI( + base_url=base_url, + api_key=api_key, + _strict_response_validation=True, + http_client=httpx.Client(transport=MockTransport(handler=mock_handler)), + ) as client: + response = client.post( + "/upload", + content=iterator, + cast_to=httpx.Response, + options={"headers": {"Content-Type": "application/octet-stream"}}, + ) + + assert response.status_code == 200 + assert response.request.headers["Content-Type"] == "application/octet-stream" + assert response.content == file_content + assert counter.value == 1 + + @pytest.mark.respx(base_url=base_url) + def test_binary_content_upload_with_body_is_deprecated(self, respx_mock: MockRouter, client: OpenAI) -> None: + respx_mock.post("/upload").mock(side_effect=mirror_request_content) + + file_content = b"Hello, this is a test file." + + with pytest.deprecated_call( + match="Passing raw bytes as `body` is deprecated and will be removed in a future version. Please pass raw bytes via the `content` parameter instead." + ): + response = client.post( + "/upload", + body=file_content, + cast_to=httpx.Response, + options={"headers": {"Content-Type": "application/octet-stream"}}, + ) + + assert response.status_code == 200 + assert response.request.headers["Content-Type"] == "application/octet-stream" + assert response.content == file_content + @pytest.mark.respx(base_url=base_url) def test_basic_union_response(self, respx_mock: MockRouter, client: OpenAI) -> None: class Model1(BaseModel): @@ -1467,6 +1584,72 @@ def test_multipart_repeating_array(self, async_client: AsyncOpenAI) -> None: b"", ] + @pytest.mark.respx(base_url=base_url) + async def test_binary_content_upload(self, respx_mock: MockRouter, async_client: AsyncOpenAI) -> None: + respx_mock.post("/upload").mock(side_effect=mirror_request_content) + + file_content = b"Hello, this is a test file." + + response = await async_client.post( + "/upload", + content=file_content, + cast_to=httpx.Response, + options={"headers": {"Content-Type": "application/octet-stream"}}, + ) + + assert response.status_code == 200 + assert response.request.headers["Content-Type"] == "application/octet-stream" + assert response.content == file_content + + async def test_binary_content_upload_with_asynciterator(self) -> None: + file_content = b"Hello, this is a test file." + counter = Counter() + iterator = _make_async_iterator([file_content], counter=counter) + + async def mock_handler(request: httpx.Request) -> httpx.Response: + assert counter.value == 0, "the request body should not have been read" + return httpx.Response(200, content=await request.aread()) + + async with AsyncOpenAI( + base_url=base_url, + api_key=api_key, + _strict_response_validation=True, + http_client=httpx.AsyncClient(transport=MockTransport(handler=mock_handler)), + ) as client: + response = await client.post( + "/upload", + content=iterator, + cast_to=httpx.Response, + options={"headers": {"Content-Type": "application/octet-stream"}}, + ) + + assert response.status_code == 200 + assert response.request.headers["Content-Type"] == "application/octet-stream" + assert response.content == file_content + assert counter.value == 1 + + @pytest.mark.respx(base_url=base_url) + async def test_binary_content_upload_with_body_is_deprecated( + self, respx_mock: MockRouter, async_client: AsyncOpenAI + ) -> None: + respx_mock.post("/upload").mock(side_effect=mirror_request_content) + + file_content = b"Hello, this is a test file." + + with pytest.deprecated_call( + match="Passing raw bytes as `body` is deprecated and will be removed in a future version. Please pass raw bytes via the `content` parameter instead." + ): + response = await async_client.post( + "/upload", + body=file_content, + cast_to=httpx.Response, + options={"headers": {"Content-Type": "application/octet-stream"}}, + ) + + assert response.status_code == 200 + assert response.request.headers["Content-Type"] == "application/octet-stream" + assert response.content == file_content + @pytest.mark.respx(base_url=base_url) async def test_basic_union_response(self, respx_mock: MockRouter, async_client: AsyncOpenAI) -> None: class Model1(BaseModel): From 612ad2b5a07c73614e56926c80f486d838fb27f5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 16 Jan 2026 18:34:06 +0000 Subject: [PATCH 587/769] chore(internal): update `actions/checkout` version --- .github/workflows/ci.yml | 8 ++++---- .github/workflows/create-releases.yml | 2 +- .github/workflows/detect-breaking-changes.yml | 2 +- .github/workflows/publish-pypi.yml | 2 +- .github/workflows/release-doctor.yml | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4c617a6f19..0dc13082f6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: runs-on: ${{ github.repository == 'stainless-sdks/openai-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install Rye run: | @@ -44,7 +44,7 @@ jobs: id-token: write runs-on: ${{ github.repository == 'stainless-sdks/openai-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install Rye run: | @@ -81,7 +81,7 @@ jobs: runs-on: ${{ github.repository == 'stainless-sdks/openai-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install Rye run: | @@ -104,7 +104,7 @@ jobs: if: github.repository == 'openai/openai-python' && (github.event_name == 'push' || github.event.pull_request.head.repo.fork) steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install Rye run: | diff --git a/.github/workflows/create-releases.yml b/.github/workflows/create-releases.yml index b3e1c679d4..f0ef434d02 100644 --- a/.github/workflows/create-releases.yml +++ b/.github/workflows/create-releases.yml @@ -14,7 +14,7 @@ jobs: environment: publish steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: stainless-api/trigger-release-please@v1 id: release diff --git a/.github/workflows/detect-breaking-changes.yml b/.github/workflows/detect-breaking-changes.yml index 6626d1c376..5f4ecdd97f 100644 --- a/.github/workflows/detect-breaking-changes.yml +++ b/.github/workflows/detect-breaking-changes.yml @@ -15,7 +15,7 @@ jobs: run: | echo "FETCH_DEPTH=$(expr ${{ github.event.pull_request.commits }} + 1)" >> $GITHUB_ENV - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: # Ensure we can check out the pull request base in the script below. fetch-depth: ${{ env.FETCH_DEPTH }} diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml index 32bd6929e2..b9c959ecf3 100644 --- a/.github/workflows/publish-pypi.yml +++ b/.github/workflows/publish-pypi.yml @@ -11,7 +11,7 @@ jobs: environment: publish steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install Rye run: | diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml index e078964a6f..be7db8df12 100644 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -13,7 +13,7 @@ jobs: if: github.repository == 'openai/openai-python' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next') steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Check release environment run: | From ef09a0abdd6d169a7fece3c12d57908640cb6a52 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 19 Jan 2026 16:36:17 +0000 Subject: [PATCH 588/769] feat(api): api update --- .stats.yml | 4 +-- src/openai/resources/files.py | 26 +++++++++++++------ src/openai/types/file_create_params.py | 14 +++++----- .../conversation_item_create_event.py | 12 ++++++--- .../conversation_item_create_event_param.py | 12 ++++++--- 5 files changed, 44 insertions(+), 24 deletions(-) diff --git a/.stats.yml b/.stats.yml index fe01e150f9..7234d96b78 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 137 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-9442fa9212dd61aac2bb0edd19744bee381e75888712f9098bc6ebb92c52b557.yml -openapi_spec_hash: f87823d164b7a8f72a42eba04e482a99 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-2dede2c933d4c80020715c5e1a21c86b353de336e4dd2c6119125e3eaca6f904.yml +openapi_spec_hash: 52ed6a83d460d3b2bf78e54bac8c503d config_hash: ad7136f7366fddec432ec378939e58a7 diff --git a/src/openai/resources/files.py b/src/openai/resources/files.py index cc117e7f15..202315be6c 100644 --- a/src/openai/resources/files.py +++ b/src/openai/resources/files.py @@ -91,10 +91,15 @@ def create( Args: file: The File object (not file name) to be uploaded. - purpose: The intended purpose of the uploaded file. One of: - `assistants`: Used in the - Assistants API - `batch`: Used in the Batch API - `fine-tune`: Used for - fine-tuning - `vision`: Images used for vision fine-tuning - `user_data`: - Flexible file type for any purpose - `evals`: Used for eval data sets + purpose: + The intended purpose of the uploaded file. One of: + + - `assistants`: Used in the Assistants API + - `batch`: Used in the Batch API + - `fine-tune`: Used for fine-tuning + - `vision`: Images used for vision fine-tuning + - `user_data`: Flexible file type for any purpose + - `evals`: Used for eval data sets expires_after: The expiration policy for a file. By default, files with `purpose=batch` expire after 30 days and all other files are persisted until they are manually deleted. @@ -407,10 +412,15 @@ async def create( Args: file: The File object (not file name) to be uploaded. - purpose: The intended purpose of the uploaded file. One of: - `assistants`: Used in the - Assistants API - `batch`: Used in the Batch API - `fine-tune`: Used for - fine-tuning - `vision`: Images used for vision fine-tuning - `user_data`: - Flexible file type for any purpose - `evals`: Used for eval data sets + purpose: + The intended purpose of the uploaded file. One of: + + - `assistants`: Used in the Assistants API + - `batch`: Used in the Batch API + - `fine-tune`: Used for fine-tuning + - `vision`: Images used for vision fine-tuning + - `user_data`: Flexible file type for any purpose + - `evals`: Used for eval data sets expires_after: The expiration policy for a file. By default, files with `purpose=batch` expire after 30 days and all other files are persisted until they are manually deleted. diff --git a/src/openai/types/file_create_params.py b/src/openai/types/file_create_params.py index f4367f7a7d..5e2afc0655 100644 --- a/src/openai/types/file_create_params.py +++ b/src/openai/types/file_create_params.py @@ -15,12 +15,14 @@ class FileCreateParams(TypedDict, total=False): """The File object (not file name) to be uploaded.""" purpose: Required[FilePurpose] - """The intended purpose of the uploaded file. - - One of: - `assistants`: Used in the Assistants API - `batch`: Used in the Batch - API - `fine-tune`: Used for fine-tuning - `vision`: Images used for vision - fine-tuning - `user_data`: Flexible file type for any purpose - `evals`: Used - for eval data sets + """The intended purpose of the uploaded file. One of: + + - `assistants`: Used in the Assistants API + - `batch`: Used in the Batch API + - `fine-tune`: Used for fine-tuning + - `vision`: Images used for vision fine-tuning + - `user_data`: Flexible file type for any purpose + - `evals`: Used for eval data sets """ expires_after: ExpiresAfter diff --git a/src/openai/types/realtime/conversation_item_create_event.py b/src/openai/types/realtime/conversation_item_create_event.py index bf2d129744..fd0fc00fa2 100644 --- a/src/openai/types/realtime/conversation_item_create_event.py +++ b/src/openai/types/realtime/conversation_item_create_event.py @@ -32,8 +32,12 @@ class ConversationItemCreateEvent(BaseModel): previous_item_id: Optional[str] = None """The ID of the preceding item after which the new item will be inserted. - If not set, the new item will be appended to the end of the conversation. If set - to `root`, the new item will be added to the beginning of the conversation. If - set to an existing ID, it allows an item to be inserted mid-conversation. If the - ID cannot be found, an error will be returned and the item will not be added. + If not set, the new item will be appended to the end of the conversation. + + If set to `root`, the new item will be added to the beginning of the + conversation. + + If set to an existing ID, it allows an item to be inserted mid-conversation. If + the ID cannot be found, an error will be returned and the item will not be + added. """ diff --git a/src/openai/types/realtime/conversation_item_create_event_param.py b/src/openai/types/realtime/conversation_item_create_event_param.py index be7f0ff011..e991e37c3b 100644 --- a/src/openai/types/realtime/conversation_item_create_event_param.py +++ b/src/openai/types/realtime/conversation_item_create_event_param.py @@ -32,8 +32,12 @@ class ConversationItemCreateEventParam(TypedDict, total=False): previous_item_id: str """The ID of the preceding item after which the new item will be inserted. - If not set, the new item will be appended to the end of the conversation. If set - to `root`, the new item will be added to the beginning of the conversation. If - set to an existing ID, it allows an item to be inserted mid-conversation. If the - ID cannot be found, an error will be returned and the item will not be added. + If not set, the new item will be appended to the end of the conversation. + + If set to `root`, the new item will be added to the beginning of the + conversation. + + If set to an existing ID, it allows an item to be inserted mid-conversation. If + the ID cannot be found, an error will be returned and the item will not be + added. """ From 3d93d66d52d709878b9b557d0c8518f291939b0a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 22 Jan 2026 05:15:30 +0000 Subject: [PATCH 589/769] codegen metadata --- .stats.yml | 4 ++-- src/openai/_models.py | 3 ++- src/openai/lib/_realtime.py | 4 ++-- tests/test_client.py | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.stats.yml b/.stats.yml index 7234d96b78..61563b1404 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 137 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-2dede2c933d4c80020715c5e1a21c86b353de336e4dd2c6119125e3eaca6f904.yml -openapi_spec_hash: 52ed6a83d460d3b2bf78e54bac8c503d +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-51075c225b913785fbb988c5d94e2da629241bf0c414b67b6301ddfffb685a83.yml +openapi_spec_hash: 43be3e1dc6823299a6db37d999aa6f11 config_hash: ad7136f7366fddec432ec378939e58a7 diff --git a/src/openai/_models.py b/src/openai/_models.py index 57b5b448be..5cca20c6f9 100644 --- a/src/openai/_models.py +++ b/src/openai/_models.py @@ -7,7 +7,8 @@ IO, TYPE_CHECKING, Any, - Type, Tuple, + Type, + Tuple, Union, Generic, TypeVar, diff --git a/src/openai/lib/_realtime.py b/src/openai/lib/_realtime.py index 999d1e4463..3771b52986 100644 --- a/src/openai/lib/_realtime.py +++ b/src/openai/lib/_realtime.py @@ -34,7 +34,7 @@ def create( extra_headers = {"Accept": "application/sdp", "Content-Type": "application/sdp", **(extra_headers or {})} return self._post( "/realtime/calls", - body=sdp.encode("utf-8"), + content=sdp.encode("utf-8"), options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, timeout=timeout), cast_to=_legacy_response.HttpxBinaryResponseContent, ) @@ -71,7 +71,7 @@ async def create( extra_headers = {"Accept": "application/sdp", "Content-Type": "application/sdp", **(extra_headers or {})} return await self._post( "/realtime/calls", - body=sdp.encode("utf-8"), + content=sdp.encode("utf-8"), options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, timeout=timeout), cast_to=_legacy_response.HttpxBinaryResponseContent, ) diff --git a/tests/test_client.py b/tests/test_client.py index bd243f68dc..396f6dea99 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -10,7 +10,7 @@ import inspect import dataclasses import tracemalloc -from typing import Any, Union, Protocol, TypeVar, Callable, Iterable, Iterator, Optional, Coroutine, cast +from typing import Any, Union, TypeVar, Callable, Iterable, Iterator, Optional, Protocol, Coroutine, cast from unittest import mock from typing_extensions import Literal, AsyncIterator, override From 84e0c1d0d05cd58e28245bff3a1746711dffcb2b Mon Sep 17 00:00:00 2001 From: Charlie Guo Date: Thu, 22 Jan 2026 15:07:34 -0800 Subject: [PATCH 590/769] Update README models to gpt-5.2 --- README.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index b8050a4cd6..7e4f0ae657 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ client = OpenAI( ) response = client.responses.create( - model="gpt-4o", + model="gpt-5.2", instructions="You are a coding assistant that talks like a pirate.", input="How do I check if a Python object is an instance of a class?", ) @@ -52,7 +52,7 @@ from openai import OpenAI client = OpenAI() completion = client.chat.completions.create( - model="gpt-4o", + model="gpt-5.2", messages=[ {"role": "developer", "content": "Talk like a pirate."}, { @@ -80,7 +80,7 @@ prompt = "What is in this image?" img_url = "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d5/2023_06_08_Raccoon1.jpg/1599px-2023_06_08_Raccoon1.jpg" response = client.responses.create( - model="gpt-4o-mini", + model="gpt-5.2", input=[ { "role": "user", @@ -106,7 +106,7 @@ with open("path/to/image.png", "rb") as image_file: b64_image = base64.b64encode(image_file.read()).decode("utf-8") response = client.responses.create( - model="gpt-4o-mini", + model="gpt-5.2", input=[ { "role": "user", @@ -136,7 +136,7 @@ client = AsyncOpenAI( async def main() -> None: response = await client.responses.create( - model="gpt-4o", input="Explain disestablishmentarianism to a smart five year old." + model="gpt-5.2", input="Explain disestablishmentarianism to a smart five year old." ) print(response.output_text) @@ -178,7 +178,7 @@ async def main() -> None: "content": "Say this is a test", } ], - model="gpt-4o", + model="gpt-5.2", ) @@ -195,7 +195,7 @@ from openai import OpenAI client = OpenAI() stream = client.responses.create( - model="gpt-4o", + model="gpt-5.2", input="Write a one-sentence bedtime story about a unicorn.", stream=True, ) @@ -215,7 +215,7 @@ client = AsyncOpenAI() async def main(): stream = await client.responses.create( - model="gpt-4o", + model="gpt-5.2", input="Write a one-sentence bedtime story about a unicorn.", stream=True, ) @@ -386,7 +386,7 @@ response = client.chat.responses.create( "content": "How much ?", } ], - model="gpt-4o", + model="gpt-5.2", response_format={"type": "json_object"}, ) ``` @@ -541,7 +541,7 @@ All object responses in the SDK provide a `_request_id` property which is added ```python response = await client.responses.create( - model="gpt-4o-mini", + model="gpt-5.2", input="Say 'this is a test'.", ) print(response._request_id) # req_123 @@ -559,7 +559,7 @@ import openai try: completion = await client.chat.completions.create( - messages=[{"role": "user", "content": "Say this is a test"}], model="gpt-4" + messages=[{"role": "user", "content": "Say this is a test"}], model="gpt-5.2" ) except openai.APIStatusError as exc: print(exc.request_id) # req_123 @@ -591,7 +591,7 @@ client.with_options(max_retries=5).chat.completions.create( "content": "How can I get the name of the current day in JavaScript?", } ], - model="gpt-4o", + model="gpt-5.2", ) ``` @@ -622,7 +622,7 @@ client.with_options(timeout=5.0).chat.completions.create( "content": "How can I list all files in a directory using Python?", } ], - model="gpt-4o", + model="gpt-5.2", ) ``` @@ -669,7 +669,7 @@ response = client.chat.completions.with_raw_response.create( "role": "user", "content": "Say this is a test", }], - model="gpt-4o", + model="gpt-5.2", ) print(response.headers.get('X-My-Header')) @@ -702,7 +702,7 @@ with client.chat.completions.with_streaming_response.create( "content": "Say this is a test", } ], - model="gpt-4o", + model="gpt-5.2", ) as response: print(response.headers.get("X-My-Header")) From f424d7b336870308f29170633a779b5d4566b421 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 23 Jan 2026 18:18:03 +0000 Subject: [PATCH 591/769] chore(ci): upgrade `actions/github-script` --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0dc13082f6..d087636a64 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -63,7 +63,7 @@ jobs: - name: Get GitHub OIDC Token if: github.repository == 'stainless-sdks/openai-python' id: github-oidc - uses: actions/github-script@v6 + uses: actions/github-script@v8 with: script: core.setOutput('github_token', await core.getIDToken()); From d499f4f8050fdd2eb69339e2881977088f622a0b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 23 Jan 2026 21:31:03 +0000 Subject: [PATCH 592/769] fix(api): mark assistants as deprecated --- .stats.yml | 4 +- src/openai/resources/beta/assistants.py | 131 +++-- src/openai/resources/files.py | 8 +- src/openai/resources/videos.py | 10 +- src/openai/types/video_create_params.py | 5 +- tests/api_resources/beta/test_assistants.py | 532 +++++++++++--------- tests/api_resources/test_videos.py | 2 + 7 files changed, 408 insertions(+), 284 deletions(-) diff --git a/.stats.yml b/.stats.yml index 61563b1404..4f516a48fa 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 137 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-51075c225b913785fbb988c5d94e2da629241bf0c414b67b6301ddfffb685a83.yml -openapi_spec_hash: 43be3e1dc6823299a6db37d999aa6f11 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-a47fcdd0fd85e2910e56b34ab3239edbb50957af8dca11db4184d3ba2cae9ad8.yml +openapi_spec_hash: ff61f44f41561b462da4a930c4eb84df config_hash: ad7136f7366fddec432ec378939e58a7 diff --git a/src/openai/resources/beta/assistants.py b/src/openai/resources/beta/assistants.py index ab0947abf4..8c69700059 100644 --- a/src/openai/resources/beta/assistants.py +++ b/src/openai/resources/beta/assistants.py @@ -2,6 +2,7 @@ from __future__ import annotations +import typing_extensions from typing import Union, Iterable, Optional from typing_extensions import Literal @@ -51,6 +52,7 @@ def with_streaming_response(self) -> AssistantsWithStreamingResponse: """ return AssistantsWithStreamingResponse(self) + @typing_extensions.deprecated("deprecated") def create( self, *, @@ -183,6 +185,7 @@ def create( cast_to=Assistant, ) + @typing_extensions.deprecated("deprecated") def retrieve( self, assistant_id: str, @@ -217,6 +220,7 @@ def retrieve( cast_to=Assistant, ) + @typing_extensions.deprecated("deprecated") def update( self, assistant_id: str, @@ -400,6 +404,7 @@ def update( cast_to=Assistant, ) + @typing_extensions.deprecated("deprecated") def list( self, *, @@ -465,6 +470,7 @@ def list( model=Assistant, ) + @typing_extensions.deprecated("deprecated") def delete( self, assistant_id: str, @@ -520,6 +526,7 @@ def with_streaming_response(self) -> AsyncAssistantsWithStreamingResponse: """ return AsyncAssistantsWithStreamingResponse(self) + @typing_extensions.deprecated("deprecated") async def create( self, *, @@ -652,6 +659,7 @@ async def create( cast_to=Assistant, ) + @typing_extensions.deprecated("deprecated") async def retrieve( self, assistant_id: str, @@ -686,6 +694,7 @@ async def retrieve( cast_to=Assistant, ) + @typing_extensions.deprecated("deprecated") async def update( self, assistant_id: str, @@ -869,6 +878,7 @@ async def update( cast_to=Assistant, ) + @typing_extensions.deprecated("deprecated") def list( self, *, @@ -934,6 +944,7 @@ def list( model=Assistant, ) + @typing_extensions.deprecated("deprecated") async def delete( self, assistant_id: str, @@ -973,20 +984,30 @@ class AssistantsWithRawResponse: def __init__(self, assistants: Assistants) -> None: self._assistants = assistants - self.create = _legacy_response.to_raw_response_wrapper( - assistants.create, + self.create = ( # pyright: ignore[reportDeprecated] + _legacy_response.to_raw_response_wrapper( + assistants.create, # pyright: ignore[reportDeprecated], + ) ) - self.retrieve = _legacy_response.to_raw_response_wrapper( - assistants.retrieve, + self.retrieve = ( # pyright: ignore[reportDeprecated] + _legacy_response.to_raw_response_wrapper( + assistants.retrieve, # pyright: ignore[reportDeprecated], + ) ) - self.update = _legacy_response.to_raw_response_wrapper( - assistants.update, + self.update = ( # pyright: ignore[reportDeprecated] + _legacy_response.to_raw_response_wrapper( + assistants.update, # pyright: ignore[reportDeprecated], + ) ) - self.list = _legacy_response.to_raw_response_wrapper( - assistants.list, + self.list = ( # pyright: ignore[reportDeprecated] + _legacy_response.to_raw_response_wrapper( + assistants.list, # pyright: ignore[reportDeprecated], + ) ) - self.delete = _legacy_response.to_raw_response_wrapper( - assistants.delete, + self.delete = ( # pyright: ignore[reportDeprecated] + _legacy_response.to_raw_response_wrapper( + assistants.delete, # pyright: ignore[reportDeprecated], + ) ) @@ -994,20 +1015,30 @@ class AsyncAssistantsWithRawResponse: def __init__(self, assistants: AsyncAssistants) -> None: self._assistants = assistants - self.create = _legacy_response.async_to_raw_response_wrapper( - assistants.create, + self.create = ( # pyright: ignore[reportDeprecated] + _legacy_response.async_to_raw_response_wrapper( + assistants.create, # pyright: ignore[reportDeprecated], + ) ) - self.retrieve = _legacy_response.async_to_raw_response_wrapper( - assistants.retrieve, + self.retrieve = ( # pyright: ignore[reportDeprecated] + _legacy_response.async_to_raw_response_wrapper( + assistants.retrieve, # pyright: ignore[reportDeprecated], + ) ) - self.update = _legacy_response.async_to_raw_response_wrapper( - assistants.update, + self.update = ( # pyright: ignore[reportDeprecated] + _legacy_response.async_to_raw_response_wrapper( + assistants.update, # pyright: ignore[reportDeprecated], + ) ) - self.list = _legacy_response.async_to_raw_response_wrapper( - assistants.list, + self.list = ( # pyright: ignore[reportDeprecated] + _legacy_response.async_to_raw_response_wrapper( + assistants.list, # pyright: ignore[reportDeprecated], + ) ) - self.delete = _legacy_response.async_to_raw_response_wrapper( - assistants.delete, + self.delete = ( # pyright: ignore[reportDeprecated] + _legacy_response.async_to_raw_response_wrapper( + assistants.delete, # pyright: ignore[reportDeprecated], + ) ) @@ -1015,20 +1046,30 @@ class AssistantsWithStreamingResponse: def __init__(self, assistants: Assistants) -> None: self._assistants = assistants - self.create = to_streamed_response_wrapper( - assistants.create, + self.create = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + assistants.create, # pyright: ignore[reportDeprecated], + ) ) - self.retrieve = to_streamed_response_wrapper( - assistants.retrieve, + self.retrieve = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + assistants.retrieve, # pyright: ignore[reportDeprecated], + ) ) - self.update = to_streamed_response_wrapper( - assistants.update, + self.update = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + assistants.update, # pyright: ignore[reportDeprecated], + ) ) - self.list = to_streamed_response_wrapper( - assistants.list, + self.list = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + assistants.list, # pyright: ignore[reportDeprecated], + ) ) - self.delete = to_streamed_response_wrapper( - assistants.delete, + self.delete = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + assistants.delete, # pyright: ignore[reportDeprecated], + ) ) @@ -1036,18 +1077,28 @@ class AsyncAssistantsWithStreamingResponse: def __init__(self, assistants: AsyncAssistants) -> None: self._assistants = assistants - self.create = async_to_streamed_response_wrapper( - assistants.create, + self.create = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + assistants.create, # pyright: ignore[reportDeprecated], + ) ) - self.retrieve = async_to_streamed_response_wrapper( - assistants.retrieve, + self.retrieve = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + assistants.retrieve, # pyright: ignore[reportDeprecated], + ) ) - self.update = async_to_streamed_response_wrapper( - assistants.update, + self.update = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + assistants.update, # pyright: ignore[reportDeprecated], + ) ) - self.list = async_to_streamed_response_wrapper( - assistants.list, + self.list = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + assistants.list, # pyright: ignore[reportDeprecated], + ) ) - self.delete = async_to_streamed_response_wrapper( - assistants.delete, + self.delete = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + assistants.delete, # pyright: ignore[reportDeprecated], + ) ) diff --git a/src/openai/resources/files.py b/src/openai/resources/files.py index 202315be6c..964d6505e7 100644 --- a/src/openai/resources/files.py +++ b/src/openai/resources/files.py @@ -68,8 +68,8 @@ def create( """Upload a file that can be used across various endpoints. Individual files can be - up to 512 MB, and the size of all files uploaded by one organization can be up - to 1 TB. + up to 512 MB, and each project can store up to 2.5 TB of files in total. There + is no organization-wide storage limit. - The Assistants API supports files up to 2 million tokens and of specific file types. See the @@ -389,8 +389,8 @@ async def create( """Upload a file that can be used across various endpoints. Individual files can be - up to 512 MB, and the size of all files uploaded by one organization can be up - to 1 TB. + up to 512 MB, and each project can store up to 2.5 TB of files in total. There + is no organization-wide storage limit. - The Assistants API supports files up to 2 million tokens and of specific file types. See the diff --git a/src/openai/resources/videos.py b/src/openai/resources/videos.py index 9f74c942bc..8d038ed6d3 100644 --- a/src/openai/resources/videos.py +++ b/src/openai/resources/videos.py @@ -16,7 +16,7 @@ video_create_params, video_download_content_params, ) -from .._types import Body, Omit, Query, Headers, NotGiven, FileTypes, omit, not_given +from .._types import Body, Omit, Query, Headers, NotGiven, FileTypes, SequenceNotStr, omit, not_given from .._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource @@ -64,6 +64,7 @@ def create( self, *, prompt: str, + character_ids: SequenceNotStr[str] | Omit = omit, input_reference: FileTypes | Omit = omit, model: VideoModelParam | Omit = omit, seconds: VideoSeconds | Omit = omit, @@ -81,6 +82,8 @@ def create( Args: prompt: Text prompt that describes the video to generate. + character_ids: Character IDs to include in the generation. + input_reference: Optional image reference that guides generation. model: The video generation model to use (allowed values: sora-2, sora-2-pro). Defaults @@ -102,6 +105,7 @@ def create( body = deepcopy_minimal( { "prompt": prompt, + "character_ids": character_ids, "input_reference": input_reference, "model": model, "seconds": seconds, @@ -419,6 +423,7 @@ async def create( self, *, prompt: str, + character_ids: SequenceNotStr[str] | Omit = omit, input_reference: FileTypes | Omit = omit, model: VideoModelParam | Omit = omit, seconds: VideoSeconds | Omit = omit, @@ -436,6 +441,8 @@ async def create( Args: prompt: Text prompt that describes the video to generate. + character_ids: Character IDs to include in the generation. + input_reference: Optional image reference that guides generation. model: The video generation model to use (allowed values: sora-2, sora-2-pro). Defaults @@ -457,6 +464,7 @@ async def create( body = deepcopy_minimal( { "prompt": prompt, + "character_ids": character_ids, "input_reference": input_reference, "model": model, "seconds": seconds, diff --git a/src/openai/types/video_create_params.py b/src/openai/types/video_create_params.py index d787aaeddd..b5f931af4f 100644 --- a/src/openai/types/video_create_params.py +++ b/src/openai/types/video_create_params.py @@ -4,7 +4,7 @@ from typing_extensions import Required, TypedDict -from .._types import FileTypes +from .._types import FileTypes, SequenceNotStr from .video_size import VideoSize from .video_seconds import VideoSeconds from .video_model_param import VideoModelParam @@ -16,6 +16,9 @@ class VideoCreateParams(TypedDict, total=False): prompt: Required[str] """Text prompt that describes the video to generate.""" + character_ids: SequenceNotStr[str] + """Character IDs to include in the generation.""" + input_reference: FileTypes """Optional image reference that guides generation.""" diff --git a/tests/api_resources/beta/test_assistants.py b/tests/api_resources/beta/test_assistants.py index 2557735426..3e85b56dcc 100644 --- a/tests/api_resources/beta/test_assistants.py +++ b/tests/api_resources/beta/test_assistants.py @@ -15,6 +15,8 @@ AssistantDeleted, ) +# pyright: reportDeprecated=false + base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -23,45 +25,50 @@ class TestAssistants: @parametrize def test_method_create(self, client: OpenAI) -> None: - assistant = client.beta.assistants.create( - model="gpt-4o", - ) + with pytest.warns(DeprecationWarning): + assistant = client.beta.assistants.create( + model="gpt-4o", + ) + assert_matches_type(Assistant, assistant, path=["response"]) @parametrize def test_method_create_with_all_params(self, client: OpenAI) -> None: - assistant = client.beta.assistants.create( - model="gpt-4o", - description="description", - instructions="instructions", - metadata={"foo": "string"}, - name="name", - reasoning_effort="none", - response_format="auto", - temperature=1, - tool_resources={ - "code_interpreter": {"file_ids": ["string"]}, - "file_search": { - "vector_store_ids": ["string"], - "vector_stores": [ - { - "chunking_strategy": {"type": "auto"}, - "file_ids": ["string"], - "metadata": {"foo": "string"}, - } - ], + with pytest.warns(DeprecationWarning): + assistant = client.beta.assistants.create( + model="gpt-4o", + description="description", + instructions="instructions", + metadata={"foo": "string"}, + name="name", + reasoning_effort="none", + response_format="auto", + temperature=1, + tool_resources={ + "code_interpreter": {"file_ids": ["string"]}, + "file_search": { + "vector_store_ids": ["string"], + "vector_stores": [ + { + "chunking_strategy": {"type": "auto"}, + "file_ids": ["string"], + "metadata": {"foo": "string"}, + } + ], + }, }, - }, - tools=[{"type": "code_interpreter"}], - top_p=1, - ) + tools=[{"type": "code_interpreter"}], + top_p=1, + ) + assert_matches_type(Assistant, assistant, path=["response"]) @parametrize def test_raw_response_create(self, client: OpenAI) -> None: - response = client.beta.assistants.with_raw_response.create( - model="gpt-4o", - ) + with pytest.warns(DeprecationWarning): + response = client.beta.assistants.with_raw_response.create( + model="gpt-4o", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -70,29 +77,33 @@ def test_raw_response_create(self, client: OpenAI) -> None: @parametrize def test_streaming_response_create(self, client: OpenAI) -> None: - with client.beta.assistants.with_streaming_response.create( - model="gpt-4o", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + with client.beta.assistants.with_streaming_response.create( + model="gpt-4o", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - assistant = response.parse() - assert_matches_type(Assistant, assistant, path=["response"]) + assistant = response.parse() + assert_matches_type(Assistant, assistant, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize def test_method_retrieve(self, client: OpenAI) -> None: - assistant = client.beta.assistants.retrieve( - "assistant_id", - ) + with pytest.warns(DeprecationWarning): + assistant = client.beta.assistants.retrieve( + "assistant_id", + ) + assert_matches_type(Assistant, assistant, path=["response"]) @parametrize def test_raw_response_retrieve(self, client: OpenAI) -> None: - response = client.beta.assistants.with_raw_response.retrieve( - "assistant_id", - ) + with pytest.warns(DeprecationWarning): + response = client.beta.assistants.with_raw_response.retrieve( + "assistant_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -101,57 +112,64 @@ def test_raw_response_retrieve(self, client: OpenAI) -> None: @parametrize def test_streaming_response_retrieve(self, client: OpenAI) -> None: - with client.beta.assistants.with_streaming_response.retrieve( - "assistant_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + with client.beta.assistants.with_streaming_response.retrieve( + "assistant_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - assistant = response.parse() - assert_matches_type(Assistant, assistant, path=["response"]) + assistant = response.parse() + assert_matches_type(Assistant, assistant, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize def test_path_params_retrieve(self, client: OpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `assistant_id` but received ''"): - client.beta.assistants.with_raw_response.retrieve( - "", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `assistant_id` but received ''"): + client.beta.assistants.with_raw_response.retrieve( + "", + ) @parametrize def test_method_update(self, client: OpenAI) -> None: - assistant = client.beta.assistants.update( - assistant_id="assistant_id", - ) + with pytest.warns(DeprecationWarning): + assistant = client.beta.assistants.update( + assistant_id="assistant_id", + ) + assert_matches_type(Assistant, assistant, path=["response"]) @parametrize def test_method_update_with_all_params(self, client: OpenAI) -> None: - assistant = client.beta.assistants.update( - assistant_id="assistant_id", - description="description", - instructions="instructions", - metadata={"foo": "string"}, - model="string", - name="name", - reasoning_effort="none", - response_format="auto", - temperature=1, - tool_resources={ - "code_interpreter": {"file_ids": ["string"]}, - "file_search": {"vector_store_ids": ["string"]}, - }, - tools=[{"type": "code_interpreter"}], - top_p=1, - ) + with pytest.warns(DeprecationWarning): + assistant = client.beta.assistants.update( + assistant_id="assistant_id", + description="description", + instructions="instructions", + metadata={"foo": "string"}, + model="string", + name="name", + reasoning_effort="none", + response_format="auto", + temperature=1, + tool_resources={ + "code_interpreter": {"file_ids": ["string"]}, + "file_search": {"vector_store_ids": ["string"]}, + }, + tools=[{"type": "code_interpreter"}], + top_p=1, + ) + assert_matches_type(Assistant, assistant, path=["response"]) @parametrize def test_raw_response_update(self, client: OpenAI) -> None: - response = client.beta.assistants.with_raw_response.update( - assistant_id="assistant_id", - ) + with pytest.warns(DeprecationWarning): + response = client.beta.assistants.with_raw_response.update( + assistant_id="assistant_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -160,42 +178,49 @@ def test_raw_response_update(self, client: OpenAI) -> None: @parametrize def test_streaming_response_update(self, client: OpenAI) -> None: - with client.beta.assistants.with_streaming_response.update( - assistant_id="assistant_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + with client.beta.assistants.with_streaming_response.update( + assistant_id="assistant_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - assistant = response.parse() - assert_matches_type(Assistant, assistant, path=["response"]) + assistant = response.parse() + assert_matches_type(Assistant, assistant, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize def test_path_params_update(self, client: OpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `assistant_id` but received ''"): - client.beta.assistants.with_raw_response.update( - assistant_id="", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `assistant_id` but received ''"): + client.beta.assistants.with_raw_response.update( + assistant_id="", + ) @parametrize def test_method_list(self, client: OpenAI) -> None: - assistant = client.beta.assistants.list() + with pytest.warns(DeprecationWarning): + assistant = client.beta.assistants.list() + assert_matches_type(SyncCursorPage[Assistant], assistant, path=["response"]) @parametrize def test_method_list_with_all_params(self, client: OpenAI) -> None: - assistant = client.beta.assistants.list( - after="after", - before="before", - limit=0, - order="asc", - ) + with pytest.warns(DeprecationWarning): + assistant = client.beta.assistants.list( + after="after", + before="before", + limit=0, + order="asc", + ) + assert_matches_type(SyncCursorPage[Assistant], assistant, path=["response"]) @parametrize def test_raw_response_list(self, client: OpenAI) -> None: - response = client.beta.assistants.with_raw_response.list() + with pytest.warns(DeprecationWarning): + response = client.beta.assistants.with_raw_response.list() assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -204,27 +229,31 @@ def test_raw_response_list(self, client: OpenAI) -> None: @parametrize def test_streaming_response_list(self, client: OpenAI) -> None: - with client.beta.assistants.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + with client.beta.assistants.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - assistant = response.parse() - assert_matches_type(SyncCursorPage[Assistant], assistant, path=["response"]) + assistant = response.parse() + assert_matches_type(SyncCursorPage[Assistant], assistant, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize def test_method_delete(self, client: OpenAI) -> None: - assistant = client.beta.assistants.delete( - "assistant_id", - ) + with pytest.warns(DeprecationWarning): + assistant = client.beta.assistants.delete( + "assistant_id", + ) + assert_matches_type(AssistantDeleted, assistant, path=["response"]) @parametrize def test_raw_response_delete(self, client: OpenAI) -> None: - response = client.beta.assistants.with_raw_response.delete( - "assistant_id", - ) + with pytest.warns(DeprecationWarning): + response = client.beta.assistants.with_raw_response.delete( + "assistant_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -233,23 +262,25 @@ def test_raw_response_delete(self, client: OpenAI) -> None: @parametrize def test_streaming_response_delete(self, client: OpenAI) -> None: - with client.beta.assistants.with_streaming_response.delete( - "assistant_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + with client.beta.assistants.with_streaming_response.delete( + "assistant_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - assistant = response.parse() - assert_matches_type(AssistantDeleted, assistant, path=["response"]) + assistant = response.parse() + assert_matches_type(AssistantDeleted, assistant, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize def test_path_params_delete(self, client: OpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `assistant_id` but received ''"): - client.beta.assistants.with_raw_response.delete( - "", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `assistant_id` but received ''"): + client.beta.assistants.with_raw_response.delete( + "", + ) class TestAsyncAssistants: @@ -259,45 +290,50 @@ class TestAsyncAssistants: @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: - assistant = await async_client.beta.assistants.create( - model="gpt-4o", - ) + with pytest.warns(DeprecationWarning): + assistant = await async_client.beta.assistants.create( + model="gpt-4o", + ) + assert_matches_type(Assistant, assistant, path=["response"]) @parametrize async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: - assistant = await async_client.beta.assistants.create( - model="gpt-4o", - description="description", - instructions="instructions", - metadata={"foo": "string"}, - name="name", - reasoning_effort="none", - response_format="auto", - temperature=1, - tool_resources={ - "code_interpreter": {"file_ids": ["string"]}, - "file_search": { - "vector_store_ids": ["string"], - "vector_stores": [ - { - "chunking_strategy": {"type": "auto"}, - "file_ids": ["string"], - "metadata": {"foo": "string"}, - } - ], + with pytest.warns(DeprecationWarning): + assistant = await async_client.beta.assistants.create( + model="gpt-4o", + description="description", + instructions="instructions", + metadata={"foo": "string"}, + name="name", + reasoning_effort="none", + response_format="auto", + temperature=1, + tool_resources={ + "code_interpreter": {"file_ids": ["string"]}, + "file_search": { + "vector_store_ids": ["string"], + "vector_stores": [ + { + "chunking_strategy": {"type": "auto"}, + "file_ids": ["string"], + "metadata": {"foo": "string"}, + } + ], + }, }, - }, - tools=[{"type": "code_interpreter"}], - top_p=1, - ) + tools=[{"type": "code_interpreter"}], + top_p=1, + ) + assert_matches_type(Assistant, assistant, path=["response"]) @parametrize async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.assistants.with_raw_response.create( - model="gpt-4o", - ) + with pytest.warns(DeprecationWarning): + response = await async_client.beta.assistants.with_raw_response.create( + model="gpt-4o", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -306,29 +342,33 @@ async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.assistants.with_streaming_response.create( - model="gpt-4o", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + async with async_client.beta.assistants.with_streaming_response.create( + model="gpt-4o", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - assistant = await response.parse() - assert_matches_type(Assistant, assistant, path=["response"]) + assistant = await response.parse() + assert_matches_type(Assistant, assistant, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: - assistant = await async_client.beta.assistants.retrieve( - "assistant_id", - ) + with pytest.warns(DeprecationWarning): + assistant = await async_client.beta.assistants.retrieve( + "assistant_id", + ) + assert_matches_type(Assistant, assistant, path=["response"]) @parametrize async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.assistants.with_raw_response.retrieve( - "assistant_id", - ) + with pytest.warns(DeprecationWarning): + response = await async_client.beta.assistants.with_raw_response.retrieve( + "assistant_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -337,57 +377,64 @@ async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.assistants.with_streaming_response.retrieve( - "assistant_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + async with async_client.beta.assistants.with_streaming_response.retrieve( + "assistant_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - assistant = await response.parse() - assert_matches_type(Assistant, assistant, path=["response"]) + assistant = await response.parse() + assert_matches_type(Assistant, assistant, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `assistant_id` but received ''"): - await async_client.beta.assistants.with_raw_response.retrieve( - "", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `assistant_id` but received ''"): + await async_client.beta.assistants.with_raw_response.retrieve( + "", + ) @parametrize async def test_method_update(self, async_client: AsyncOpenAI) -> None: - assistant = await async_client.beta.assistants.update( - assistant_id="assistant_id", - ) + with pytest.warns(DeprecationWarning): + assistant = await async_client.beta.assistants.update( + assistant_id="assistant_id", + ) + assert_matches_type(Assistant, assistant, path=["response"]) @parametrize async def test_method_update_with_all_params(self, async_client: AsyncOpenAI) -> None: - assistant = await async_client.beta.assistants.update( - assistant_id="assistant_id", - description="description", - instructions="instructions", - metadata={"foo": "string"}, - model="string", - name="name", - reasoning_effort="none", - response_format="auto", - temperature=1, - tool_resources={ - "code_interpreter": {"file_ids": ["string"]}, - "file_search": {"vector_store_ids": ["string"]}, - }, - tools=[{"type": "code_interpreter"}], - top_p=1, - ) + with pytest.warns(DeprecationWarning): + assistant = await async_client.beta.assistants.update( + assistant_id="assistant_id", + description="description", + instructions="instructions", + metadata={"foo": "string"}, + model="string", + name="name", + reasoning_effort="none", + response_format="auto", + temperature=1, + tool_resources={ + "code_interpreter": {"file_ids": ["string"]}, + "file_search": {"vector_store_ids": ["string"]}, + }, + tools=[{"type": "code_interpreter"}], + top_p=1, + ) + assert_matches_type(Assistant, assistant, path=["response"]) @parametrize async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.assistants.with_raw_response.update( - assistant_id="assistant_id", - ) + with pytest.warns(DeprecationWarning): + response = await async_client.beta.assistants.with_raw_response.update( + assistant_id="assistant_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -396,42 +443,49 @@ async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_update(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.assistants.with_streaming_response.update( - assistant_id="assistant_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + async with async_client.beta.assistants.with_streaming_response.update( + assistant_id="assistant_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - assistant = await response.parse() - assert_matches_type(Assistant, assistant, path=["response"]) + assistant = await response.parse() + assert_matches_type(Assistant, assistant, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize async def test_path_params_update(self, async_client: AsyncOpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `assistant_id` but received ''"): - await async_client.beta.assistants.with_raw_response.update( - assistant_id="", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `assistant_id` but received ''"): + await async_client.beta.assistants.with_raw_response.update( + assistant_id="", + ) @parametrize async def test_method_list(self, async_client: AsyncOpenAI) -> None: - assistant = await async_client.beta.assistants.list() + with pytest.warns(DeprecationWarning): + assistant = await async_client.beta.assistants.list() + assert_matches_type(AsyncCursorPage[Assistant], assistant, path=["response"]) @parametrize async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: - assistant = await async_client.beta.assistants.list( - after="after", - before="before", - limit=0, - order="asc", - ) + with pytest.warns(DeprecationWarning): + assistant = await async_client.beta.assistants.list( + after="after", + before="before", + limit=0, + order="asc", + ) + assert_matches_type(AsyncCursorPage[Assistant], assistant, path=["response"]) @parametrize async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.assistants.with_raw_response.list() + with pytest.warns(DeprecationWarning): + response = await async_client.beta.assistants.with_raw_response.list() assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -440,27 +494,31 @@ async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.assistants.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + async with async_client.beta.assistants.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - assistant = await response.parse() - assert_matches_type(AsyncCursorPage[Assistant], assistant, path=["response"]) + assistant = await response.parse() + assert_matches_type(AsyncCursorPage[Assistant], assistant, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize async def test_method_delete(self, async_client: AsyncOpenAI) -> None: - assistant = await async_client.beta.assistants.delete( - "assistant_id", - ) + with pytest.warns(DeprecationWarning): + assistant = await async_client.beta.assistants.delete( + "assistant_id", + ) + assert_matches_type(AssistantDeleted, assistant, path=["response"]) @parametrize async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.assistants.with_raw_response.delete( - "assistant_id", - ) + with pytest.warns(DeprecationWarning): + response = await async_client.beta.assistants.with_raw_response.delete( + "assistant_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -469,20 +527,22 @@ async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.assistants.with_streaming_response.delete( - "assistant_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + async with async_client.beta.assistants.with_streaming_response.delete( + "assistant_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - assistant = await response.parse() - assert_matches_type(AssistantDeleted, assistant, path=["response"]) + assistant = await response.parse() + assert_matches_type(AssistantDeleted, assistant, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `assistant_id` but received ''"): - await async_client.beta.assistants.with_raw_response.delete( - "", - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `assistant_id` but received ''"): + await async_client.beta.assistants.with_raw_response.delete( + "", + ) diff --git a/tests/api_resources/test_videos.py b/tests/api_resources/test_videos.py index b785e03ca5..2f1bce5f84 100644 --- a/tests/api_resources/test_videos.py +++ b/tests/api_resources/test_videos.py @@ -38,6 +38,7 @@ def test_method_create(self, client: OpenAI) -> None: def test_method_create_with_all_params(self, client: OpenAI) -> None: video = client.videos.create( prompt="x", + character_ids=["char_123"], input_reference=b"raw file contents", model="string", seconds="4", @@ -296,6 +297,7 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None: async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: video = await async_client.videos.create( prompt="x", + character_ids=["char_123"], input_reference=b"raw file contents", model="string", seconds="4", From dc93407352ea88439c58d5bbb028e6f1b703bba4 Mon Sep 17 00:00:00 2001 From: Alex Chang Date: Fri, 23 Jan 2026 16:41:22 -0500 Subject: [PATCH 593/769] fix helper --- src/openai/resources/videos.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/openai/resources/videos.py b/src/openai/resources/videos.py index 8d038ed6d3..e201177baa 100644 --- a/src/openai/resources/videos.py +++ b/src/openai/resources/videos.py @@ -132,6 +132,7 @@ def create_and_poll( self, *, prompt: str, + character_ids: SequenceNotStr[str] | Omit = omit, input_reference: FileTypes | Omit = omit, model: VideoModelParam | Omit = omit, seconds: VideoSeconds | Omit = omit, @@ -148,6 +149,7 @@ def create_and_poll( video = self.create( model=model, prompt=prompt, + character_ids=character_ids, input_reference=input_reference, seconds=seconds, size=size, @@ -491,6 +493,7 @@ async def create_and_poll( self, *, prompt: str, + character_ids: SequenceNotStr[str] | Omit = omit, input_reference: FileTypes | Omit = omit, model: VideoModelParam | Omit = omit, seconds: VideoSeconds | Omit = omit, @@ -507,6 +510,7 @@ async def create_and_poll( video = await self.create( model=model, prompt=prompt, + character_ids=character_ids, input_reference=input_reference, seconds=seconds, size=size, From 8be9907031c1cad0433c0e9543693c9b64c29453 Mon Sep 17 00:00:00 2001 From: Alex Chang Date: Fri, 23 Jan 2026 22:09:40 -0500 Subject: [PATCH 594/769] fix breaking change detection with deprecations --- .github/workflows/detect-breaking-changes.yml | 4 +--- pyproject.toml | 2 +- scripts/detect-breaking-changes | 2 +- scripts/pyrightconfig.breaking-changes.json | 4 ++++ scripts/run-pyright | 8 ++++++++ 5 files changed, 15 insertions(+), 5 deletions(-) create mode 100644 scripts/pyrightconfig.breaking-changes.json create mode 100755 scripts/run-pyright diff --git a/.github/workflows/detect-breaking-changes.yml b/.github/workflows/detect-breaking-changes.yml index 5f4ecdd97f..87c02061c2 100644 --- a/.github/workflows/detect-breaking-changes.yml +++ b/.github/workflows/detect-breaking-changes.yml @@ -36,9 +36,7 @@ jobs: - name: Detect breaking changes run: | - # Try to check out previous versions of the breaking change detection script. This ensures that - # we still detect breaking changes when entire files and their tests are removed. - git checkout "${{ github.event.pull_request.base.sha }}" -- ./scripts/detect-breaking-changes 2>/dev/null || true + test -f ./scripts/detect-breaking-changes || { echo "Missing scripts/detect-breaking-changes"; exit 1; } ./scripts/detect-breaking-changes ${{ github.event.pull_request.base.sha }} agents_sdk: diff --git a/pyproject.toml b/pyproject.toml index 2d835b05af..8bdc519acf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -101,7 +101,7 @@ typecheck = { chain = [ "typecheck:pyright", "typecheck:mypy" ]} -"typecheck:pyright" = "pyright" +"typecheck:pyright" = "scripts/run-pyright" "typecheck:verify-types" = "pyright --verifytypes openai --ignoreexternal" "typecheck:mypy" = "mypy ." diff --git a/scripts/detect-breaking-changes b/scripts/detect-breaking-changes index 833872ef3a..25b6aa485f 100755 --- a/scripts/detect-breaking-changes +++ b/scripts/detect-breaking-changes @@ -21,4 +21,4 @@ done # Instead of running the tests, use the linter to check if an # older test is no longer compatible with the latest SDK. -./scripts/lint +PYRIGHT_PROJECT=scripts/pyrightconfig.breaking-changes.json ./scripts/lint diff --git a/scripts/pyrightconfig.breaking-changes.json b/scripts/pyrightconfig.breaking-changes.json new file mode 100644 index 0000000000..87bfd3bbc0 --- /dev/null +++ b/scripts/pyrightconfig.breaking-changes.json @@ -0,0 +1,4 @@ +{ + "extends": "../pyproject.toml", + "reportDeprecated": false +} diff --git a/scripts/run-pyright b/scripts/run-pyright new file mode 100755 index 0000000000..1c71ba0587 --- /dev/null +++ b/scripts/run-pyright @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -euo pipefail + +cd "$(dirname "$0")/.." + +CONFIG=${PYRIGHT_PROJECT:-pyproject.toml} +exec pyright -p "$CONFIG" "$@" From d167d1456cd27e0448ed2cb91b8bdc576bec5b23 Mon Sep 17 00:00:00 2001 From: Andreas Lachenmann <53483608+andreasjl@users.noreply.github.com> Date: Tue, 27 Jan 2026 21:57:08 +0100 Subject: [PATCH 595/769] docs(examples): update Azure Realtime sample to use v1 API (#2829) --- examples/realtime/azure_realtime.py | 33 +++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/examples/realtime/azure_realtime.py b/examples/realtime/azure_realtime.py index 3cf64b8be9..177c24fdfa 100644 --- a/examples/realtime/azure_realtime.py +++ b/examples/realtime/azure_realtime.py @@ -3,7 +3,7 @@ from azure.identity.aio import DefaultAzureCredential, get_bearer_token_provider -from openai import AsyncAzureOpenAI +from openai import AsyncOpenAI # Azure OpenAI Realtime Docs @@ -21,18 +21,37 @@ async def main() -> None: """ credential = DefaultAzureCredential() - client = AsyncAzureOpenAI( - azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"], - azure_ad_token_provider=get_bearer_token_provider(credential, "https://cognitiveservices.azure.com/.default"), - api_version="2024-10-01-preview", + token_provider = get_bearer_token_provider(credential, "https://cognitiveservices.azure.com/.default") + token = await token_provider() + + # The endpoint of your Azure OpenAI resource is required. You can set it in the AZURE_OPENAI_ENDPOINT + # environment variable. + # You can find it in the Microsoft Foundry portal in the Overview page of your Azure OpenAI resource. + # Example: https://{your-resource}.openai.azure.com + endpoint = os.environ["AZURE_OPENAI_ENDPOINT"] + + # The deployment name of the model you want to use is required. You can set it in the AZURE_OPENAI_DEPLOYMENT_NAME + # environment variable. + # You can find it in the Foundry portal in the "Models + endpoints" page of your Azure OpenAI resource. + # Example: gpt-realtime + deployment_name = os.environ["AZURE_OPENAI_DEPLOYMENT_NAME"] + + base_url = endpoint.replace("https://", "wss://").rstrip("/") + "/openai/v1" + + # The APIs are compatible with the OpenAI client library. + # You can use the OpenAI client library to access the Azure OpenAI APIs. + # Make sure to set the baseURL and apiKey to use the Azure OpenAI endpoint and token. + client = AsyncOpenAI( + websocket_base_url=base_url, + api_key=token ) async with client.realtime.connect( - model="gpt-realtime", # deployment name for your model + model=deployment_name, ) as connection: await connection.session.update( session={ "output_modalities": ["text"], - "model": "gpt-realtime", + "model": deployment_name, "type": "realtime", } ) From eaab2f5c55cbc72d79439f3c114c49a0b9625ffa Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 27 Jan 2026 23:21:10 +0000 Subject: [PATCH 596/769] feat(api): api updates --- .stats.yml | 4 ++-- src/openai/resources/videos.py | 10 +--------- .../response_function_shell_tool_call_output.py | 6 ++++++ src/openai/types/video_create_params.py | 5 +---- tests/api_resources/test_videos.py | 2 -- 5 files changed, 10 insertions(+), 17 deletions(-) diff --git a/.stats.yml b/.stats.yml index 4f516a48fa..a43021242b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 137 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-a47fcdd0fd85e2910e56b34ab3239edbb50957af8dca11db4184d3ba2cae9ad8.yml -openapi_spec_hash: ff61f44f41561b462da4a930c4eb84df +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-506f44f37cccac43899267dd64cc5615e96f6e15f2736aa37e5e4eed2eccc567.yml +openapi_spec_hash: d242c25afd700d928787a46e7901fa45 config_hash: ad7136f7366fddec432ec378939e58a7 diff --git a/src/openai/resources/videos.py b/src/openai/resources/videos.py index e201177baa..e8740d48c2 100644 --- a/src/openai/resources/videos.py +++ b/src/openai/resources/videos.py @@ -16,7 +16,7 @@ video_create_params, video_download_content_params, ) -from .._types import Body, Omit, Query, Headers, NotGiven, FileTypes, SequenceNotStr, omit, not_given +from .._types import Body, Omit, Query, Headers, NotGiven, FileTypes, omit, not_given from .._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource @@ -64,7 +64,6 @@ def create( self, *, prompt: str, - character_ids: SequenceNotStr[str] | Omit = omit, input_reference: FileTypes | Omit = omit, model: VideoModelParam | Omit = omit, seconds: VideoSeconds | Omit = omit, @@ -82,8 +81,6 @@ def create( Args: prompt: Text prompt that describes the video to generate. - character_ids: Character IDs to include in the generation. - input_reference: Optional image reference that guides generation. model: The video generation model to use (allowed values: sora-2, sora-2-pro). Defaults @@ -105,7 +102,6 @@ def create( body = deepcopy_minimal( { "prompt": prompt, - "character_ids": character_ids, "input_reference": input_reference, "model": model, "seconds": seconds, @@ -425,7 +421,6 @@ async def create( self, *, prompt: str, - character_ids: SequenceNotStr[str] | Omit = omit, input_reference: FileTypes | Omit = omit, model: VideoModelParam | Omit = omit, seconds: VideoSeconds | Omit = omit, @@ -443,8 +438,6 @@ async def create( Args: prompt: Text prompt that describes the video to generate. - character_ids: Character IDs to include in the generation. - input_reference: Optional image reference that guides generation. model: The video generation model to use (allowed values: sora-2, sora-2-pro). Defaults @@ -466,7 +459,6 @@ async def create( body = deepcopy_minimal( { "prompt": prompt, - "character_ids": character_ids, "input_reference": input_reference, "model": model, "seconds": seconds, diff --git a/src/openai/types/responses/response_function_shell_tool_call_output.py b/src/openai/types/responses/response_function_shell_tool_call_output.py index 5523d57ba7..7196ab47f7 100644 --- a/src/openai/types/responses/response_function_shell_tool_call_output.py +++ b/src/openai/types/responses/response_function_shell_tool_call_output.py @@ -75,6 +75,12 @@ class ResponseFunctionShellToolCallOutput(BaseModel): output: List[Output] """An array of shell call output contents""" + status: Literal["in_progress", "completed", "incomplete"] + """The status of the shell call output. + + One of `in_progress`, `completed`, or `incomplete`. + """ + type: Literal["shell_call_output"] """The type of the shell call output. Always `shell_call_output`.""" diff --git a/src/openai/types/video_create_params.py b/src/openai/types/video_create_params.py index b5f931af4f..d787aaeddd 100644 --- a/src/openai/types/video_create_params.py +++ b/src/openai/types/video_create_params.py @@ -4,7 +4,7 @@ from typing_extensions import Required, TypedDict -from .._types import FileTypes, SequenceNotStr +from .._types import FileTypes from .video_size import VideoSize from .video_seconds import VideoSeconds from .video_model_param import VideoModelParam @@ -16,9 +16,6 @@ class VideoCreateParams(TypedDict, total=False): prompt: Required[str] """Text prompt that describes the video to generate.""" - character_ids: SequenceNotStr[str] - """Character IDs to include in the generation.""" - input_reference: FileTypes """Optional image reference that guides generation.""" diff --git a/tests/api_resources/test_videos.py b/tests/api_resources/test_videos.py index 2f1bce5f84..b785e03ca5 100644 --- a/tests/api_resources/test_videos.py +++ b/tests/api_resources/test_videos.py @@ -38,7 +38,6 @@ def test_method_create(self, client: OpenAI) -> None: def test_method_create_with_all_params(self, client: OpenAI) -> None: video = client.videos.create( prompt="x", - character_ids=["char_123"], input_reference=b"raw file contents", model="string", seconds="4", @@ -297,7 +296,6 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None: async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: video = await async_client.videos.create( prompt="x", - character_ids=["char_123"], input_reference=b"raw file contents", model="string", seconds="4", From c7f70bd7aeea59e7f4d62813a884a47d11e5b155 Mon Sep 17 00:00:00 2001 From: Alex Chang Date: Tue, 27 Jan 2026 18:23:20 -0500 Subject: [PATCH 597/769] fix videos --- src/openai/resources/videos.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/openai/resources/videos.py b/src/openai/resources/videos.py index e8740d48c2..9f74c942bc 100644 --- a/src/openai/resources/videos.py +++ b/src/openai/resources/videos.py @@ -128,7 +128,6 @@ def create_and_poll( self, *, prompt: str, - character_ids: SequenceNotStr[str] | Omit = omit, input_reference: FileTypes | Omit = omit, model: VideoModelParam | Omit = omit, seconds: VideoSeconds | Omit = omit, @@ -145,7 +144,6 @@ def create_and_poll( video = self.create( model=model, prompt=prompt, - character_ids=character_ids, input_reference=input_reference, seconds=seconds, size=size, @@ -485,7 +483,6 @@ async def create_and_poll( self, *, prompt: str, - character_ids: SequenceNotStr[str] | Omit = omit, input_reference: FileTypes | Omit = omit, model: VideoModelParam | Omit = omit, seconds: VideoSeconds | Omit = omit, @@ -502,7 +499,6 @@ async def create_and_poll( video = await self.create( model=model, prompt=prompt, - character_ids=character_ids, input_reference=input_reference, seconds=seconds, size=size, From dc68b90655912886bd7a6c7787f96005452ebfc9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 27 Jan 2026 23:24:00 +0000 Subject: [PATCH 598/769] release: 2.16.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 26 ++++++++++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index cff01f26f0..b258565371 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.15.0" + ".": "2.16.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 4630e50610..28902cb2b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,31 @@ # Changelog +## 2.16.0 (2026-01-27) + +Full Changelog: [v2.15.0...v2.16.0](https://github.com/openai/openai-python/compare/v2.15.0...v2.16.0) + +### Features + +* **api:** api update ([b97f9f2](https://github.com/openai/openai-python/commit/b97f9f26b9c46ca4519130e60a8bf12ad8d52bf3)) +* **api:** api updates ([9debcc0](https://github.com/openai/openai-python/commit/9debcc02370f5b76a6a609ded18fbf8dea87b9cb)) +* **client:** add support for binary request streaming ([49561d8](https://github.com/openai/openai-python/commit/49561d88279628bc400d1b09aa98765b67018ef1)) + + +### Bug Fixes + +* **api:** mark assistants as deprecated ([0419cbc](https://github.com/openai/openai-python/commit/0419cbcbf1021131c7492321436ed01ca4337835)) + + +### Chores + +* **ci:** upgrade `actions/github-script` ([5139f13](https://github.com/openai/openai-python/commit/5139f13ef35e64dadc65f2ba2bab736977985769)) +* **internal:** update `actions/checkout` version ([f276714](https://github.com/openai/openai-python/commit/f2767144c11833070c0579063ed33918089b4617)) + + +### Documentation + +* **examples:** update Azure Realtime sample to use v1 API ([#2829](https://github.com/openai/openai-python/issues/2829)) ([3b31981](https://github.com/openai/openai-python/commit/3b319819544d629c5b8c206b8b1f6ec6328c6136)) + ## 2.15.0 (2026-01-09) Full Changelog: [v2.14.0...v2.15.0](https://github.com/openai/openai-python/compare/v2.14.0...v2.15.0) diff --git a/pyproject.toml b/pyproject.toml index 8bdc519acf..bd75d0096d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.15.0" +version = "2.16.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 6f0ccf7d72..eb61bdd2c6 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__ = "2.15.0" # x-release-please-version +__version__ = "2.16.0" # x-release-please-version From 27feb0a1b4fc821a47dd6898c5ab8cd2ac3238f4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 28 Jan 2026 22:21:46 +0000 Subject: [PATCH 599/769] feat(api): add shell_call_output status field --- .stats.yml | 6 +++--- src/openai/types/responses/response_input_item.py | 3 +++ src/openai/types/responses/response_input_item_param.py | 3 +++ src/openai/types/responses/response_input_param.py | 3 +++ 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.stats.yml b/.stats.yml index a43021242b..5020dde626 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 137 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-506f44f37cccac43899267dd64cc5615e96f6e15f2736aa37e5e4eed2eccc567.yml -openapi_spec_hash: d242c25afd700d928787a46e7901fa45 -config_hash: ad7136f7366fddec432ec378939e58a7 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-f1f6d4ab31f58e4d3dd84b28802a7cba3b3f042f9d2940e0dae2b133af064968.yml +openapi_spec_hash: 4f5eaf9930f283a039c1a536961591d4 +config_hash: d827d220d7967208cd0207c0518554b7 diff --git a/src/openai/types/responses/response_input_item.py b/src/openai/types/responses/response_input_item.py index 23eb2c8950..e1f521f957 100644 --- a/src/openai/types/responses/response_input_item.py +++ b/src/openai/types/responses/response_input_item.py @@ -285,6 +285,9 @@ class ShellCallOutput(BaseModel): output. """ + status: Optional[Literal["in_progress", "completed", "incomplete"]] = None + """The status of the shell call output.""" + class ApplyPatchCallOperationCreateFile(BaseModel): """Instruction for creating a new file via the apply_patch tool.""" diff --git a/src/openai/types/responses/response_input_item_param.py b/src/openai/types/responses/response_input_item_param.py index 2c42b93021..03fe86c42c 100644 --- a/src/openai/types/responses/response_input_item_param.py +++ b/src/openai/types/responses/response_input_item_param.py @@ -286,6 +286,9 @@ class ShellCallOutput(TypedDict, total=False): output. """ + status: Optional[Literal["in_progress", "completed", "incomplete"]] + """The status of the shell call output.""" + class ApplyPatchCallOperationCreateFile(TypedDict, total=False): """Instruction for creating a new file via the apply_patch tool.""" diff --git a/src/openai/types/responses/response_input_param.py b/src/openai/types/responses/response_input_param.py index c2d12c0ab4..5be65b3e14 100644 --- a/src/openai/types/responses/response_input_param.py +++ b/src/openai/types/responses/response_input_param.py @@ -287,6 +287,9 @@ class ShellCallOutput(TypedDict, total=False): output. """ + status: Optional[Literal["in_progress", "completed", "incomplete"]] + """The status of the shell call output.""" + class ApplyPatchCallOperationCreateFile(TypedDict, total=False): """Instruction for creating a new file via the apply_patch tool.""" From 7da396e2601ea1587c8798a9c60d9d3497146380 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 28 Jan 2026 23:45:56 +0000 Subject: [PATCH 600/769] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 5020dde626..8716fd480e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 137 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-f1f6d4ab31f58e4d3dd84b28802a7cba3b3f042f9d2940e0dae2b133af064968.yml openapi_spec_hash: 4f5eaf9930f283a039c1a536961591d4 -config_hash: d827d220d7967208cd0207c0518554b7 +config_hash: aa92a4ffc7ee4b1d5ac0503d1d0c1fea From 2360dfa7fd26a8f92211702c04752a10fe5fff27 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 29 Jan 2026 15:28:55 +0000 Subject: [PATCH 601/769] codegen metadata --- .stats.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.stats.yml b/.stats.yml index 8716fd480e..3bd66743a1 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 137 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-f1f6d4ab31f58e4d3dd84b28802a7cba3b3f042f9d2940e0dae2b133af064968.yml -openapi_spec_hash: 4f5eaf9930f283a039c1a536961591d4 -config_hash: aa92a4ffc7ee4b1d5ac0503d1d0c1fea +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-7a6ba5212fa9680f9489f4e73c298e1e8f78106b83a465e76290d45fc2fccb70.yml +openapi_spec_hash: 3d3379b7dbf6af484944bc678ec9bf4c +config_hash: a08002d1759a1d0bde3429dccc58d1ef From db4d87193089f60d8a2c2841ded3c7fdcd54a5bb Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 29 Jan 2026 16:56:16 +0000 Subject: [PATCH 602/769] feat(client): add custom JSON encoder for extended type support --- src/openai/_base_client.py | 7 +- src/openai/_compat.py | 6 +- src/openai/_utils/_json.py | 35 ++++++++++ tests/test_utils/test_json.py | 126 ++++++++++++++++++++++++++++++++++ 4 files changed, 169 insertions(+), 5 deletions(-) create mode 100644 src/openai/_utils/_json.py create mode 100644 tests/test_utils/test_json.py diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index d34208abef..17863bc067 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -86,6 +86,7 @@ APIConnectionError, APIResponseValidationError, ) +from ._utils._json import openapi_dumps from ._legacy_response import LegacyAPIResponse log: logging.Logger = logging.getLogger(__name__) @@ -556,8 +557,10 @@ def _build_request( kwargs["content"] = options.content elif isinstance(json_data, bytes): kwargs["content"] = json_data - else: - kwargs["json"] = json_data if is_given(json_data) else None + elif not files: + # Don't set content when JSON is sent as multipart/form-data, + # since httpx's content param overrides other body arguments + kwargs["content"] = openapi_dumps(json_data) if is_given(json_data) and json_data is not None else None kwargs["files"] = files else: headers.pop("Content-Type", None) diff --git a/src/openai/_compat.py b/src/openai/_compat.py index 73a1f3ea93..020ffeb2ca 100644 --- a/src/openai/_compat.py +++ b/src/openai/_compat.py @@ -139,6 +139,7 @@ def model_dump( exclude_defaults: bool = False, warnings: bool = True, mode: Literal["json", "python"] = "python", + by_alias: bool | None = None, ) -> dict[str, Any]: if (not PYDANTIC_V1) or hasattr(model, "model_dump"): return model.model_dump( @@ -148,13 +149,12 @@ def model_dump( exclude_defaults=exclude_defaults, # warnings are not supported in Pydantic v1 warnings=True if PYDANTIC_V1 else warnings, + by_alias=by_alias, ) return cast( "dict[str, Any]", model.dict( # pyright: ignore[reportDeprecated, reportUnnecessaryCast] - exclude=exclude, - exclude_unset=exclude_unset, - exclude_defaults=exclude_defaults, + exclude=exclude, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, by_alias=bool(by_alias) ), ) diff --git a/src/openai/_utils/_json.py b/src/openai/_utils/_json.py new file mode 100644 index 0000000000..60584214af --- /dev/null +++ b/src/openai/_utils/_json.py @@ -0,0 +1,35 @@ +import json +from typing import Any +from datetime import datetime +from typing_extensions import override + +import pydantic + +from .._compat import model_dump + + +def openapi_dumps(obj: Any) -> bytes: + """ + Serialize an object to UTF-8 encoded JSON bytes. + + Extends the standard json.dumps with support for additional types + commonly used in the SDK, such as `datetime`, `pydantic.BaseModel`, etc. + """ + return json.dumps( + obj, + cls=_CustomEncoder, + # Uses the same defaults as httpx's JSON serialization + ensure_ascii=False, + separators=(",", ":"), + allow_nan=False, + ).encode() + + +class _CustomEncoder(json.JSONEncoder): + @override + def default(self, o: Any) -> Any: + if isinstance(o, datetime): + return o.isoformat() + if isinstance(o, pydantic.BaseModel): + return model_dump(o, exclude_unset=True, mode="json", by_alias=True) + return super().default(o) diff --git a/tests/test_utils/test_json.py b/tests/test_utils/test_json.py new file mode 100644 index 0000000000..240c64562f --- /dev/null +++ b/tests/test_utils/test_json.py @@ -0,0 +1,126 @@ +from __future__ import annotations + +import datetime +from typing import Union + +import pydantic + +from openai import _compat +from openai._utils._json import openapi_dumps + + +class TestOpenapiDumps: + def test_basic(self) -> None: + data = {"key": "value", "number": 42} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"key":"value","number":42}' + + def test_datetime_serialization(self) -> None: + dt = datetime.datetime(2023, 1, 1, 12, 0, 0) + data = {"datetime": dt} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"datetime":"2023-01-01T12:00:00"}' + + def test_pydantic_model_serialization(self) -> None: + class User(pydantic.BaseModel): + first_name: str + last_name: str + age: int + + model_instance = User(first_name="John", last_name="Kramer", age=83) + data = {"model": model_instance} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"first_name":"John","last_name":"Kramer","age":83}}' + + def test_pydantic_model_with_default_values(self) -> None: + class User(pydantic.BaseModel): + name: str + role: str = "user" + active: bool = True + score: int = 0 + + model_instance = User(name="Alice") + data = {"model": model_instance} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"name":"Alice"}}' + + def test_pydantic_model_with_default_values_overridden(self) -> None: + class User(pydantic.BaseModel): + name: str + role: str = "user" + active: bool = True + + model_instance = User(name="Bob", role="admin", active=False) + data = {"model": model_instance} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"name":"Bob","role":"admin","active":false}}' + + def test_pydantic_model_with_alias(self) -> None: + class User(pydantic.BaseModel): + first_name: str = pydantic.Field(alias="firstName") + last_name: str = pydantic.Field(alias="lastName") + + model_instance = User(firstName="John", lastName="Doe") + data = {"model": model_instance} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"firstName":"John","lastName":"Doe"}}' + + def test_pydantic_model_with_alias_and_default(self) -> None: + class User(pydantic.BaseModel): + user_name: str = pydantic.Field(alias="userName") + user_role: str = pydantic.Field(default="member", alias="userRole") + is_active: bool = pydantic.Field(default=True, alias="isActive") + + model_instance = User(userName="charlie") + data = {"model": model_instance} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"userName":"charlie"}}' + + model_with_overrides = User(userName="diana", userRole="admin", isActive=False) + data = {"model": model_with_overrides} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"userName":"diana","userRole":"admin","isActive":false}}' + + def test_pydantic_model_with_nested_models_and_defaults(self) -> None: + class Address(pydantic.BaseModel): + street: str + city: str = "Unknown" + + class User(pydantic.BaseModel): + name: str + address: Address + verified: bool = False + + if _compat.PYDANTIC_V1: + # to handle forward references in Pydantic v1 + User.update_forward_refs(**locals()) # type: ignore[reportDeprecated] + + address = Address(street="123 Main St") + user = User(name="Diana", address=address) + data = {"user": user} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"user":{"name":"Diana","address":{"street":"123 Main St"}}}' + + address_with_city = Address(street="456 Oak Ave", city="Boston") + user_verified = User(name="Eve", address=address_with_city, verified=True) + data = {"user": user_verified} + json_bytes = openapi_dumps(data) + assert ( + json_bytes == b'{"user":{"name":"Eve","address":{"street":"456 Oak Ave","city":"Boston"},"verified":true}}' + ) + + def test_pydantic_model_with_optional_fields(self) -> None: + class User(pydantic.BaseModel): + name: str + email: Union[str, None] + phone: Union[str, None] + + model_with_none = User(name="Eve", email=None, phone=None) + data = {"model": model_with_none} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"name":"Eve","email":null,"phone":null}}' + + model_with_values = User(name="Frank", email="frank@example.com", phone=None) + data = {"model": model_with_values} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"name":"Frank","email":"frank@example.com","phone":null}}' From 42cb178759bd2bac2274f4c7afd3c550e6cf9aa2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 30 Jan 2026 19:43:01 +0000 Subject: [PATCH 603/769] feat(api): image generation actions for responses; ResponseFunctionCallArgumentsDoneEvent.name --- .stats.yml | 6 +++--- .../realtime/response_function_call_arguments_done_event.py | 3 +++ src/openai/types/responses/response_function_web_search.py | 4 ++-- .../types/responses/response_function_web_search_param.py | 6 +++--- src/openai/types/responses/tool.py | 5 ++++- src/openai/types/responses/tool_param.py | 5 ++++- 6 files changed, 19 insertions(+), 10 deletions(-) diff --git a/.stats.yml b/.stats.yml index 3bd66743a1..fcd2a277ae 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 137 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-7a6ba5212fa9680f9489f4e73c298e1e8f78106b83a465e76290d45fc2fccb70.yml -openapi_spec_hash: 3d3379b7dbf6af484944bc678ec9bf4c -config_hash: a08002d1759a1d0bde3429dccc58d1ef +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-b956f0004bb930006f4b8d24734b20e89c7420ca6635dd358b9f0299c8ac8d62.yml +openapi_spec_hash: 91b1b7bf3c1a6b6c9c7507d4cac8fe2a +config_hash: 9501b3367f98ede2729f1bfffb3a803a diff --git a/src/openai/types/realtime/response_function_call_arguments_done_event.py b/src/openai/types/realtime/response_function_call_arguments_done_event.py index 504f91d558..01bae80562 100644 --- a/src/openai/types/realtime/response_function_call_arguments_done_event.py +++ b/src/openai/types/realtime/response_function_call_arguments_done_event.py @@ -25,6 +25,9 @@ class ResponseFunctionCallArgumentsDoneEvent(BaseModel): item_id: str """The ID of the function call item.""" + name: str + """The name of the function that was called.""" + output_index: int """The index of the output item in the response.""" diff --git a/src/openai/types/responses/response_function_web_search.py b/src/openai/types/responses/response_function_web_search.py index 0cb7e0b0d1..90d422eece 100644 --- a/src/openai/types/responses/response_function_web_search.py +++ b/src/openai/types/responses/response_function_web_search.py @@ -41,7 +41,7 @@ class ActionOpenPage(BaseModel): type: Literal["open_page"] """The action type.""" - url: str + url: Optional[str] = None """The URL opened by the model.""" @@ -74,7 +74,7 @@ class ResponseFunctionWebSearch(BaseModel): action: Action """ An object describing the specific action taken in this web search call. Includes - details on how the model used the web (search, open_page, find). + details on how the model used the web (search, open_page, find_in_page). """ status: Literal["in_progress", "searching", "completed", "failed"] diff --git a/src/openai/types/responses/response_function_web_search_param.py b/src/openai/types/responses/response_function_web_search_param.py index 7db3e3c833..017e35efbc 100644 --- a/src/openai/types/responses/response_function_web_search_param.py +++ b/src/openai/types/responses/response_function_web_search_param.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Union, Iterable +from typing import Union, Iterable, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict from ..._types import SequenceNotStr @@ -49,7 +49,7 @@ class ActionOpenPage(TypedDict, total=False): type: Required[Literal["open_page"]] """The action type.""" - url: Required[str] + url: Optional[str] """The URL opened by the model.""" @@ -82,7 +82,7 @@ class ResponseFunctionWebSearchParam(TypedDict, total=False): action: Required[Action] """ An object describing the specific action taken in this web search call. Includes - details on how the model used the web (search, open_page, find). + details on how the model used the web (search, open_page, find_in_page). """ status: Required[Literal["in_progress", "searching", "completed", "failed"]] diff --git a/src/openai/types/responses/tool.py b/src/openai/types/responses/tool.py index 019962a0ba..435f046768 100644 --- a/src/openai/types/responses/tool.py +++ b/src/openai/types/responses/tool.py @@ -227,6 +227,9 @@ class ImageGeneration(BaseModel): type: Literal["image_generation"] """The type of the image generation tool. Always `image_generation`.""" + action: Optional[Literal["generate", "edit", "auto"]] = None + """Whether to generate a new image or edit an existing image. Default: `auto`.""" + background: Optional[Literal["transparent", "opaque", "auto"]] = None """Background type for the generated image. @@ -247,7 +250,7 @@ class ImageGeneration(BaseModel): Contains `image_url` (string, optional) and `file_id` (string, optional). """ - model: Union[str, Literal["gpt-image-1", "gpt-image-1-mini"], None] = None + model: Union[str, Literal["gpt-image-1", "gpt-image-1-mini", "gpt-image-1.5"], None] = None """The image generation model to use. Default: `gpt-image-1`.""" moderation: Optional[Literal["auto", "low"]] = None diff --git a/src/openai/types/responses/tool_param.py b/src/openai/types/responses/tool_param.py index 37d3dde024..3afff87892 100644 --- a/src/openai/types/responses/tool_param.py +++ b/src/openai/types/responses/tool_param.py @@ -227,6 +227,9 @@ class ImageGeneration(TypedDict, total=False): type: Required[Literal["image_generation"]] """The type of the image generation tool. Always `image_generation`.""" + action: Literal["generate", "edit", "auto"] + """Whether to generate a new image or edit an existing image. Default: `auto`.""" + background: Literal["transparent", "opaque", "auto"] """Background type for the generated image. @@ -247,7 +250,7 @@ class ImageGeneration(TypedDict, total=False): Contains `image_url` (string, optional) and `file_id` (string, optional). """ - model: Union[str, Literal["gpt-image-1", "gpt-image-1-mini"]] + model: Union[str, Literal["gpt-image-1", "gpt-image-1-mini", "gpt-image-1.5"]] """The image generation model to use. Default: `gpt-image-1`.""" moderation: Literal["auto", "low"] From a1fb97bb3580d58a4534a3b4278b5cd4a43ddbc6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 2 Feb 2026 21:36:28 +0000 Subject: [PATCH 604/769] fix(client): update type for `find_in_page` action --- .stats.yml | 4 ++-- .../responses/response_function_web_search.py | 17 ++++++++++++----- .../response_function_web_search_param.py | 10 +++++----- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/.stats.yml b/.stats.yml index fcd2a277ae..d9e272c17f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 137 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-b956f0004bb930006f4b8d24734b20e89c7420ca6635dd358b9f0299c8ac8d62.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-64c3a646eb5dcad2b7ff7bd976c0e312b886676a542f6ffcd9a6c8503ae24c58.yml openapi_spec_hash: 91b1b7bf3c1a6b6c9c7507d4cac8fe2a -config_hash: 9501b3367f98ede2729f1bfffb3a803a +config_hash: f8e6baff429cf000b8e4ba1da08dff47 diff --git a/src/openai/types/responses/response_function_web_search.py b/src/openai/types/responses/response_function_web_search.py index 90d422eece..e0a9caf43b 100644 --- a/src/openai/types/responses/response_function_web_search.py +++ b/src/openai/types/responses/response_function_web_search.py @@ -6,7 +6,14 @@ from ..._utils import PropertyInfo from ..._models import BaseModel -__all__ = ["ResponseFunctionWebSearch", "Action", "ActionSearch", "ActionSearchSource", "ActionOpenPage", "ActionFind"] +__all__ = [ + "ResponseFunctionWebSearch", + "Action", + "ActionSearch", + "ActionSearchSource", + "ActionOpenPage", + "ActionFindInPage", +] class ActionSearchSource(BaseModel): @@ -45,20 +52,20 @@ class ActionOpenPage(BaseModel): """The URL opened by the model.""" -class ActionFind(BaseModel): - """Action type "find": Searches for a pattern within a loaded page.""" +class ActionFindInPage(BaseModel): + """Action type "find_in_page": Searches for a pattern within a loaded page.""" pattern: str """The pattern or text to search for within the page.""" - type: Literal["find"] + type: Literal["find_in_page"] """The action type.""" url: str """The URL of the page searched for the pattern.""" -Action: TypeAlias = Annotated[Union[ActionSearch, ActionOpenPage, ActionFind], PropertyInfo(discriminator="type")] +Action: TypeAlias = Annotated[Union[ActionSearch, ActionOpenPage, ActionFindInPage], PropertyInfo(discriminator="type")] class ResponseFunctionWebSearch(BaseModel): diff --git a/src/openai/types/responses/response_function_web_search_param.py b/src/openai/types/responses/response_function_web_search_param.py index 017e35efbc..8eea5598e6 100644 --- a/src/openai/types/responses/response_function_web_search_param.py +++ b/src/openai/types/responses/response_function_web_search_param.py @@ -13,7 +13,7 @@ "ActionSearch", "ActionSearchSource", "ActionOpenPage", - "ActionFind", + "ActionFindInPage", ] @@ -53,20 +53,20 @@ class ActionOpenPage(TypedDict, total=False): """The URL opened by the model.""" -class ActionFind(TypedDict, total=False): - """Action type "find": Searches for a pattern within a loaded page.""" +class ActionFindInPage(TypedDict, total=False): + """Action type "find_in_page": Searches for a pattern within a loaded page.""" pattern: Required[str] """The pattern or text to search for within the page.""" - type: Required[Literal["find"]] + type: Required[Literal["find_in_page"]] """The action type.""" url: Required[str] """The URL of the page searched for the pattern.""" -Action: TypeAlias = Union[ActionSearch, ActionOpenPage, ActionFind] +Action: TypeAlias = Union[ActionSearch, ActionOpenPage, ActionFindInPage] class ResponseFunctionWebSearchParam(TypedDict, total=False): From 31b4218b71025c9183eb8320629af5de74682adc Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 3 Feb 2026 04:21:36 +0000 Subject: [PATCH 605/769] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index d9e272c17f..6a1f554cc2 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 137 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-64c3a646eb5dcad2b7ff7bd976c0e312b886676a542f6ffcd9a6c8503ae24c58.yml openapi_spec_hash: 91b1b7bf3c1a6b6c9c7507d4cac8fe2a -config_hash: f8e6baff429cf000b8e4ba1da08dff47 +config_hash: 3e6ddffe104c0689cd9ef9a7a7863225 From b95c09d3f1b760378ee4137b83a8e9b87156bedd Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 3 Feb 2026 15:30:13 +0000 Subject: [PATCH 606/769] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 6a1f554cc2..d9e272c17f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 137 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-64c3a646eb5dcad2b7ff7bd976c0e312b886676a542f6ffcd9a6c8503ae24c58.yml openapi_spec_hash: 91b1b7bf3c1a6b6c9c7507d4cac8fe2a -config_hash: 3e6ddffe104c0689cd9ef9a7a7863225 +config_hash: f8e6baff429cf000b8e4ba1da08dff47 From b982088450a89409ae0eedc1f27f84f383b447af Mon Sep 17 00:00:00 2001 From: David Meadows Date: Tue, 3 Feb 2026 10:36:36 -0500 Subject: [PATCH 607/769] fix(client): undo change to web search Find action --- src/openai/types/responses/response_function_web_search.py | 6 +++--- .../types/responses/response_function_web_search_param.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/openai/types/responses/response_function_web_search.py b/src/openai/types/responses/response_function_web_search.py index e0a9caf43b..de6001e146 100644 --- a/src/openai/types/responses/response_function_web_search.py +++ b/src/openai/types/responses/response_function_web_search.py @@ -12,7 +12,7 @@ "ActionSearch", "ActionSearchSource", "ActionOpenPage", - "ActionFindInPage", + "ActionFind", ] @@ -52,7 +52,7 @@ class ActionOpenPage(BaseModel): """The URL opened by the model.""" -class ActionFindInPage(BaseModel): +class ActionFind(BaseModel): """Action type "find_in_page": Searches for a pattern within a loaded page.""" pattern: str @@ -65,7 +65,7 @@ class ActionFindInPage(BaseModel): """The URL of the page searched for the pattern.""" -Action: TypeAlias = Annotated[Union[ActionSearch, ActionOpenPage, ActionFindInPage], PropertyInfo(discriminator="type")] +Action: TypeAlias = Annotated[Union[ActionSearch, ActionOpenPage, ActionFind], PropertyInfo(discriminator="type")] class ResponseFunctionWebSearch(BaseModel): diff --git a/src/openai/types/responses/response_function_web_search_param.py b/src/openai/types/responses/response_function_web_search_param.py index 8eea5598e6..15e313b0d3 100644 --- a/src/openai/types/responses/response_function_web_search_param.py +++ b/src/openai/types/responses/response_function_web_search_param.py @@ -13,7 +13,7 @@ "ActionSearch", "ActionSearchSource", "ActionOpenPage", - "ActionFindInPage", + "ActionFind", ] @@ -53,7 +53,7 @@ class ActionOpenPage(TypedDict, total=False): """The URL opened by the model.""" -class ActionFindInPage(TypedDict, total=False): +class ActionFind(TypedDict, total=False): """Action type "find_in_page": Searches for a pattern within a loaded page.""" pattern: Required[str] @@ -66,7 +66,7 @@ class ActionFindInPage(TypedDict, total=False): """The URL of the page searched for the pattern.""" -Action: TypeAlias = Union[ActionSearch, ActionOpenPage, ActionFindInPage] +Action: TypeAlias = Union[ActionSearch, ActionOpenPage, ActionFind] class ResponseFunctionWebSearchParam(TypedDict, total=False): From e8888736c86bb1d5a27100867da22b11ab5bb1b7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 5 Feb 2026 05:25:56 +0000 Subject: [PATCH 608/769] release: 2.17.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 16 ++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index b258565371..c1a7e63f69 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.16.0" + ".": "2.17.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 28902cb2b2..ea480c424e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # Changelog +## 2.17.0 (2026-02-05) + +Full Changelog: [v2.16.0...v2.17.0](https://github.com/openai/openai-python/compare/v2.16.0...v2.17.0) + +### Features + +* **api:** add shell_call_output status field ([1bbaf88](https://github.com/openai/openai-python/commit/1bbaf8865000b338c24c9fdd5e985183feaca10f)) +* **api:** image generation actions for responses; ResponseFunctionCallArgumentsDoneEvent.name ([7d96513](https://github.com/openai/openai-python/commit/7d965135f93f41b0c3dbf3dc9f01796bd9645b6c)) +* **client:** add custom JSON encoder for extended type support ([9f43c8b](https://github.com/openai/openai-python/commit/9f43c8b1a1641db2336cc6d0ec0c6dc470a89103)) + + +### Bug Fixes + +* **client:** undo change to web search Find action ([8f14eb0](https://github.com/openai/openai-python/commit/8f14eb0a74363fdfc648c5cd5c6d34a85b938d3c)) +* **client:** update type for `find_in_page` action ([ec54dde](https://github.com/openai/openai-python/commit/ec54ddeb357e49edd81cc3fe53d549c297e59a07)) + ## 2.16.0 (2026-01-27) Full Changelog: [v2.15.0...v2.16.0](https://github.com/openai/openai-python/compare/v2.15.0...v2.16.0) diff --git a/pyproject.toml b/pyproject.toml index bd75d0096d..e3843e1f56 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.16.0" +version = "2.17.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 eb61bdd2c6..5f7901120a 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__ = "2.16.0" # x-release-please-version +__version__ = "2.17.0" # x-release-please-version From a7a60166ad8f686f388719a147f815b053c9e885 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 9 Feb 2026 16:41:09 -0500 Subject: [PATCH 609/769] release: 2.18.0 (#2846) * codegen metadata * test note * feat(api): add context_management to responses * feat(api): responses context_management * release: 2.18.0 --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> Co-authored-by: Alex Chang --- .release-please-manifest.json | 2 +- .stats.yml | 6 +-- CHANGELOG.md | 9 +++++ examples/realtime/azure_realtime.py | 5 +-- pyproject.toml | 2 +- src/openai/_version.py | 2 +- src/openai/resources/images.py | 24 +++++------ src/openai/resources/responses/responses.py | 34 ++++++++++++++++ .../resources/vector_stores/file_batches.py | 40 ++++++++++++++++--- src/openai/resources/vector_stores/files.py | 30 +++++++++++++- src/openai/types/image_edit_params.py | 4 +- .../types/responses/response_create_params.py | 12 ++++++ src/openai/types/responses/tool.py | 4 +- src/openai/types/responses/tool_param.py | 4 +- tests/api_resources/test_responses.py | 24 +++++++++++ .../vector_stores/test_file_batches.py | 12 ++++++ .../api_resources/vector_stores/test_files.py | 1 - 17 files changed, 178 insertions(+), 37 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index c1a7e63f69..ca3496a3e6 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.17.0" + ".": "2.18.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index d9e272c17f..fce116bc4f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 137 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-64c3a646eb5dcad2b7ff7bd976c0e312b886676a542f6ffcd9a6c8503ae24c58.yml -openapi_spec_hash: 91b1b7bf3c1a6b6c9c7507d4cac8fe2a -config_hash: f8e6baff429cf000b8e4ba1da08dff47 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-bff810f46da56eff8d5e189b0d1f56ac07a8289723666138549d4239cad7c2ea.yml +openapi_spec_hash: 7532ce5a6f490c8f5d1e079c76c70535 +config_hash: a1454ffd9612dee11f9d5a98e55eac9e diff --git a/CHANGELOG.md b/CHANGELOG.md index ea480c424e..ad2758cf6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 2.18.0 (2026-02-09) + +Full Changelog: [v2.17.0...v2.18.0](https://github.com/openai/openai-python/compare/v2.17.0...v2.18.0) + +### Features + +* **api:** add context_management to responses ([137e992](https://github.com/openai/openai-python/commit/137e992b80956401d1867274fa7a0969edfdba54)) +* **api:** responses context_management ([c3bd017](https://github.com/openai/openai-python/commit/c3bd017318347af0a0105a7e975c8d91e22f7941)) + ## 2.17.0 (2026-02-05) Full Changelog: [v2.16.0...v2.17.0](https://github.com/openai/openai-python/compare/v2.16.0...v2.17.0) diff --git a/examples/realtime/azure_realtime.py b/examples/realtime/azure_realtime.py index 177c24fdfa..a8bcf4c536 100644 --- a/examples/realtime/azure_realtime.py +++ b/examples/realtime/azure_realtime.py @@ -41,10 +41,7 @@ async def main() -> None: # The APIs are compatible with the OpenAI client library. # You can use the OpenAI client library to access the Azure OpenAI APIs. # Make sure to set the baseURL and apiKey to use the Azure OpenAI endpoint and token. - client = AsyncOpenAI( - websocket_base_url=base_url, - api_key=token - ) + client = AsyncOpenAI(websocket_base_url=base_url, api_key=token) async with client.realtime.connect( model=deployment_name, ) as connection: diff --git a/pyproject.toml b/pyproject.toml index e3843e1f56..4dc3418464 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.17.0" +version = "2.18.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 5f7901120a..aede964362 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__ = "2.17.0" # x-release-please-version +__version__ = "2.18.0" # x-release-please-version diff --git a/src/openai/resources/images.py b/src/openai/resources/images.py index 805828488f..3de5185a87 100644 --- a/src/openai/resources/images.py +++ b/src/openai/resources/images.py @@ -172,8 +172,8 @@ def edit( input_fidelity: Control how much effort the model will exert to match the style and features, especially facial features, of input images. This parameter is only supported - for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and - `low`. Defaults to `low`. + for `gpt-image-1` and `gpt-image-1.5` and later models, unsupported for + `gpt-image-1-mini`. Supports `high` and `low`. Defaults to `low`. mask: An additional image whose fully transparent areas (e.g. where alpha is zero) indicate where `image` should be edited. If there are multiple images provided, @@ -291,8 +291,8 @@ def edit( input_fidelity: Control how much effort the model will exert to match the style and features, especially facial features, of input images. This parameter is only supported - for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and - `low`. Defaults to `low`. + for `gpt-image-1` and `gpt-image-1.5` and later models, unsupported for + `gpt-image-1-mini`. Supports `high` and `low`. Defaults to `low`. mask: An additional image whose fully transparent areas (e.g. where alpha is zero) indicate where `image` should be edited. If there are multiple images provided, @@ -406,8 +406,8 @@ def edit( input_fidelity: Control how much effort the model will exert to match the style and features, especially facial features, of input images. This parameter is only supported - for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and - `low`. Defaults to `low`. + for `gpt-image-1` and `gpt-image-1.5` and later models, unsupported for + `gpt-image-1-mini`. Supports `high` and `low`. Defaults to `low`. mask: An additional image whose fully transparent areas (e.g. where alpha is zero) indicate where `image` should be edited. If there are multiple images provided, @@ -1068,8 +1068,8 @@ async def edit( input_fidelity: Control how much effort the model will exert to match the style and features, especially facial features, of input images. This parameter is only supported - for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and - `low`. Defaults to `low`. + for `gpt-image-1` and `gpt-image-1.5` and later models, unsupported for + `gpt-image-1-mini`. Supports `high` and `low`. Defaults to `low`. mask: An additional image whose fully transparent areas (e.g. where alpha is zero) indicate where `image` should be edited. If there are multiple images provided, @@ -1187,8 +1187,8 @@ async def edit( input_fidelity: Control how much effort the model will exert to match the style and features, especially facial features, of input images. This parameter is only supported - for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and - `low`. Defaults to `low`. + for `gpt-image-1` and `gpt-image-1.5` and later models, unsupported for + `gpt-image-1-mini`. Supports `high` and `low`. Defaults to `low`. mask: An additional image whose fully transparent areas (e.g. where alpha is zero) indicate where `image` should be edited. If there are multiple images provided, @@ -1302,8 +1302,8 @@ async def edit( input_fidelity: Control how much effort the model will exert to match the style and features, especially facial features, of input images. This parameter is only supported - for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and - `low`. Defaults to `low`. + for `gpt-image-1` and `gpt-image-1.5` and later models, unsupported for + `gpt-image-1-mini`. Supports `high` and `low`. Defaults to `low`. mask: An additional image whose fully transparent areas (e.g. where alpha is zero) indicate where `image` should be edited. If there are multiple images provided, diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 8e80f6793b..79034b7e18 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -95,6 +95,7 @@ def create( self, *, background: Optional[bool] | Omit = omit, + context_management: Optional[Iterable[response_create_params.ContextManagement]] | Omit = omit, conversation: Optional[response_create_params.Conversation] | Omit = omit, include: Optional[List[ResponseIncludable]] | Omit = omit, input: Union[str, ResponseInputParam] | Omit = omit, @@ -147,6 +148,8 @@ def create( background: Whether to run the model response in the background. [Learn more](https://platform.openai.com/docs/guides/background). + context_management: Context management configuration for this request. + conversation: The conversation that this response belongs to. Items from this conversation are prepended to `input_items` for this response request. Input items and output items from this response are automatically added to this conversation after this @@ -341,6 +344,7 @@ def create( *, stream: Literal[True], background: Optional[bool] | Omit = omit, + context_management: Optional[Iterable[response_create_params.ContextManagement]] | Omit = omit, conversation: Optional[response_create_params.Conversation] | Omit = omit, include: Optional[List[ResponseIncludable]] | Omit = omit, input: Union[str, ResponseInputParam] | Omit = omit, @@ -399,6 +403,8 @@ def create( background: Whether to run the model response in the background. [Learn more](https://platform.openai.com/docs/guides/background). + context_management: Context management configuration for this request. + conversation: The conversation that this response belongs to. Items from this conversation are prepended to `input_items` for this response request. Input items and output items from this response are automatically added to this conversation after this @@ -586,6 +592,7 @@ def create( *, stream: bool, background: Optional[bool] | Omit = omit, + context_management: Optional[Iterable[response_create_params.ContextManagement]] | Omit = omit, conversation: Optional[response_create_params.Conversation] | Omit = omit, include: Optional[List[ResponseIncludable]] | Omit = omit, input: Union[str, ResponseInputParam] | Omit = omit, @@ -644,6 +651,8 @@ def create( background: Whether to run the model response in the background. [Learn more](https://platform.openai.com/docs/guides/background). + context_management: Context management configuration for this request. + conversation: The conversation that this response belongs to. Items from this conversation are prepended to `input_items` for this response request. Input items and output items from this response are automatically added to this conversation after this @@ -829,6 +838,7 @@ def create( self, *, background: Optional[bool] | Omit = omit, + context_management: Optional[Iterable[response_create_params.ContextManagement]] | Omit = omit, conversation: Optional[response_create_params.Conversation] | Omit = omit, include: Optional[List[ResponseIncludable]] | Omit = omit, input: Union[str, ResponseInputParam] | Omit = omit, @@ -868,6 +878,7 @@ def create( body=maybe_transform( { "background": background, + "context_management": context_management, "conversation": conversation, "include": include, "input": input, @@ -930,6 +941,7 @@ def stream( input: Union[str, ResponseInputParam], model: ResponsesModel, background: Optional[bool] | Omit = omit, + context_management: Optional[Iterable[response_create_params.ContextManagement]] | Omit = omit, text_format: type[TextFormatT] | Omit = omit, tools: Iterable[ParseableToolParam] | Omit = omit, conversation: Optional[response_create_params.Conversation] | Omit = omit, @@ -970,6 +982,7 @@ def stream( input: Union[str, ResponseInputParam] | Omit = omit, model: ResponsesModel | Omit = omit, background: Optional[bool] | Omit = omit, + context_management: Optional[Iterable[response_create_params.ContextManagement]] | Omit = omit, text_format: type[TextFormatT] | Omit = omit, tools: Iterable[ParseableToolParam] | Omit = omit, conversation: Optional[response_create_params.Conversation] | Omit = omit, @@ -1006,6 +1019,7 @@ def stream( new_response_args = { "input": input, "model": model, + "context_management": context_management, "conversation": conversation, "include": include, "instructions": instructions, @@ -1061,6 +1075,7 @@ def stream( input=input, model=model, tools=tools, + context_management=context_management, conversation=conversation, include=include, instructions=instructions, @@ -1118,6 +1133,7 @@ def parse( *, text_format: type[TextFormatT] | Omit = omit, background: Optional[bool] | Omit = omit, + context_management: Optional[Iterable[response_create_params.ContextManagement]] | Omit = omit, conversation: Optional[response_create_params.Conversation] | Omit = omit, include: Optional[List[ResponseIncludable]] | Omit = omit, input: Union[str, ResponseInputParam] | Omit = omit, @@ -1176,6 +1192,7 @@ def parser(raw_response: Response) -> ParsedResponse[TextFormatT]: body=maybe_transform( { "background": background, + "context_management": context_management, "conversation": conversation, "include": include, "input": input, @@ -1709,6 +1726,7 @@ async def create( self, *, background: Optional[bool] | Omit = omit, + context_management: Optional[Iterable[response_create_params.ContextManagement]] | Omit = omit, conversation: Optional[response_create_params.Conversation] | Omit = omit, include: Optional[List[ResponseIncludable]] | Omit = omit, input: Union[str, ResponseInputParam] | Omit = omit, @@ -1761,6 +1779,8 @@ async def create( background: Whether to run the model response in the background. [Learn more](https://platform.openai.com/docs/guides/background). + context_management: Context management configuration for this request. + conversation: The conversation that this response belongs to. Items from this conversation are prepended to `input_items` for this response request. Input items and output items from this response are automatically added to this conversation after this @@ -1955,6 +1975,7 @@ async def create( *, stream: Literal[True], background: Optional[bool] | Omit = omit, + context_management: Optional[Iterable[response_create_params.ContextManagement]] | Omit = omit, conversation: Optional[response_create_params.Conversation] | Omit = omit, include: Optional[List[ResponseIncludable]] | Omit = omit, input: Union[str, ResponseInputParam] | Omit = omit, @@ -2013,6 +2034,8 @@ async def create( background: Whether to run the model response in the background. [Learn more](https://platform.openai.com/docs/guides/background). + context_management: Context management configuration for this request. + conversation: The conversation that this response belongs to. Items from this conversation are prepended to `input_items` for this response request. Input items and output items from this response are automatically added to this conversation after this @@ -2200,6 +2223,7 @@ async def create( *, stream: bool, background: Optional[bool] | Omit = omit, + context_management: Optional[Iterable[response_create_params.ContextManagement]] | Omit = omit, conversation: Optional[response_create_params.Conversation] | Omit = omit, include: Optional[List[ResponseIncludable]] | Omit = omit, input: Union[str, ResponseInputParam] | Omit = omit, @@ -2258,6 +2282,8 @@ async def create( background: Whether to run the model response in the background. [Learn more](https://platform.openai.com/docs/guides/background). + context_management: Context management configuration for this request. + conversation: The conversation that this response belongs to. Items from this conversation are prepended to `input_items` for this response request. Input items and output items from this response are automatically added to this conversation after this @@ -2443,6 +2469,7 @@ async def create( self, *, background: Optional[bool] | Omit = omit, + context_management: Optional[Iterable[response_create_params.ContextManagement]] | Omit = omit, conversation: Optional[response_create_params.Conversation] | Omit = omit, include: Optional[List[ResponseIncludable]] | Omit = omit, input: Union[str, ResponseInputParam] | Omit = omit, @@ -2482,6 +2509,7 @@ async def create( body=await async_maybe_transform( { "background": background, + "context_management": context_management, "conversation": conversation, "include": include, "input": input, @@ -2544,6 +2572,7 @@ def stream( input: Union[str, ResponseInputParam], model: ResponsesModel, background: Optional[bool] | Omit = omit, + context_management: Optional[Iterable[response_create_params.ContextManagement]] | Omit = omit, text_format: type[TextFormatT] | Omit = omit, tools: Iterable[ParseableToolParam] | Omit = omit, conversation: Optional[response_create_params.Conversation] | Omit = omit, @@ -2584,6 +2613,7 @@ def stream( input: Union[str, ResponseInputParam] | Omit = omit, model: ResponsesModel | Omit = omit, background: Optional[bool] | Omit = omit, + context_management: Optional[Iterable[response_create_params.ContextManagement]] | Omit = omit, text_format: type[TextFormatT] | Omit = omit, tools: Iterable[ParseableToolParam] | Omit = omit, conversation: Optional[response_create_params.Conversation] | Omit = omit, @@ -2620,6 +2650,7 @@ def stream( new_response_args = { "input": input, "model": model, + "context_management": context_management, "conversation": conversation, "include": include, "instructions": instructions, @@ -2675,6 +2706,7 @@ def stream( model=model, stream=True, tools=tools, + context_management=context_management, conversation=conversation, include=include, instructions=instructions, @@ -2736,6 +2768,7 @@ async def parse( *, text_format: type[TextFormatT] | Omit = omit, background: Optional[bool] | Omit = omit, + context_management: Optional[Iterable[response_create_params.ContextManagement]] | Omit = omit, conversation: Optional[response_create_params.Conversation] | Omit = omit, include: Optional[List[ResponseIncludable]] | Omit = omit, input: Union[str, ResponseInputParam] | Omit = omit, @@ -2794,6 +2827,7 @@ def parser(raw_response: Response) -> ParsedResponse[TextFormatT]: body=maybe_transform( { "background": background, + "context_management": context_management, "conversation": conversation, "include": include, "input": input, diff --git a/src/openai/resources/vector_stores/file_batches.py b/src/openai/resources/vector_stores/file_batches.py index d31fb59bec..fca1ef89fa 100644 --- a/src/openai/resources/vector_stores/file_batches.py +++ b/src/openai/resources/vector_stores/file_batches.py @@ -194,15 +194,29 @@ def create_and_poll( self, vector_store_id: str, *, - file_ids: SequenceNotStr[str], - poll_interval_ms: int | Omit = omit, + attributes: Optional[Dict[str, Union[str, float, bool]]] | Omit = omit, chunking_strategy: FileChunkingStrategyParam | Omit = omit, + file_ids: SequenceNotStr[str] | Omit = omit, + files: Iterable[file_batch_create_params.File] | Omit = omit, + poll_interval_ms: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> VectorStoreFileBatch: """Create a vector store batch and poll until all files have been processed.""" batch = self.create( vector_store_id=vector_store_id, - file_ids=file_ids, + attributes=attributes, chunking_strategy=chunking_strategy, + file_ids=file_ids, + files=files, + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, ) # TODO: don't poll unless necessary?? return self.poll( @@ -539,15 +553,29 @@ async def create_and_poll( self, vector_store_id: str, *, - file_ids: SequenceNotStr[str], - poll_interval_ms: int | Omit = omit, + attributes: Optional[Dict[str, Union[str, float, bool]]] | Omit = omit, chunking_strategy: FileChunkingStrategyParam | Omit = omit, + file_ids: SequenceNotStr[str] | Omit = omit, + files: Iterable[file_batch_create_params.File] | Omit = omit, + poll_interval_ms: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> VectorStoreFileBatch: """Create a vector store batch and poll until all files have been processed.""" batch = await self.create( vector_store_id=vector_store_id, - file_ids=file_ids, + attributes=attributes, chunking_strategy=chunking_strategy, + file_ids=file_ids, + files=files, + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, ) # TODO: don't poll unless necessary?? return await self.poll( diff --git a/src/openai/resources/vector_stores/files.py b/src/openai/resources/vector_stores/files.py index d2eb4e16ed..29f6e879f1 100644 --- a/src/openai/resources/vector_stores/files.py +++ b/src/openai/resources/vector_stores/files.py @@ -307,10 +307,23 @@ def create_and_poll( attributes: Optional[Dict[str, Union[str, float, bool]]] | Omit = omit, poll_interval_ms: int | Omit = omit, chunking_strategy: FileChunkingStrategyParam | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> VectorStoreFile: """Attach a file to the given vector store and wait for it to be processed.""" self.create( - vector_store_id=vector_store_id, file_id=file_id, chunking_strategy=chunking_strategy, attributes=attributes + vector_store_id=vector_store_id, + file_id=file_id, + chunking_strategy=chunking_strategy, + attributes=attributes, + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, ) return self.poll( @@ -715,10 +728,23 @@ async def create_and_poll( attributes: Optional[Dict[str, Union[str, float, bool]]] | Omit = omit, poll_interval_ms: int | Omit = omit, chunking_strategy: FileChunkingStrategyParam | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> VectorStoreFile: """Attach a file to the given vector store and wait for it to be processed.""" await self.create( - vector_store_id=vector_store_id, file_id=file_id, chunking_strategy=chunking_strategy, attributes=attributes + vector_store_id=vector_store_id, + file_id=file_id, + chunking_strategy=chunking_strategy, + attributes=attributes, + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, ) return await self.poll( diff --git a/src/openai/types/image_edit_params.py b/src/openai/types/image_edit_params.py index 0bd5f39fac..916fbc1411 100644 --- a/src/openai/types/image_edit_params.py +++ b/src/openai/types/image_edit_params.py @@ -45,8 +45,8 @@ class ImageEditParamsBase(TypedDict, total=False): """ Control how much effort the model will exert to match the style and features, especially facial features, of input images. This parameter is only supported - for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and - `low`. Defaults to `low`. + for `gpt-image-1` and `gpt-image-1.5` and later models, unsupported for + `gpt-image-1-mini`. Supports `high` and `low`. Defaults to `low`. """ mask: FileTypes diff --git a/src/openai/types/responses/response_create_params.py b/src/openai/types/responses/response_create_params.py index 15844c6597..97aaf9dc3a 100644 --- a/src/openai/types/responses/response_create_params.py +++ b/src/openai/types/responses/response_create_params.py @@ -25,6 +25,7 @@ __all__ = [ "ResponseCreateParamsBase", + "ContextManagement", "Conversation", "StreamOptions", "ToolChoice", @@ -40,6 +41,9 @@ class ResponseCreateParamsBase(TypedDict, total=False): [Learn more](https://platform.openai.com/docs/guides/background). """ + context_management: Optional[Iterable[ContextManagement]] + """Context management configuration for this request.""" + conversation: Optional[Conversation] """The conversation that this response belongs to. @@ -279,6 +283,14 @@ class ResponseCreateParamsBase(TypedDict, total=False): """ +class ContextManagement(TypedDict, total=False): + type: Required[str] + """The context management entry type. Currently only 'compaction' is supported.""" + + compact_threshold: Optional[int] + """Token threshold at which compaction should be triggered for this entry.""" + + Conversation: TypeAlias = Union[str, ResponseConversationParam] diff --git a/src/openai/types/responses/tool.py b/src/openai/types/responses/tool.py index 435f046768..bd266ea753 100644 --- a/src/openai/types/responses/tool.py +++ b/src/openai/types/responses/tool.py @@ -240,8 +240,8 @@ class ImageGeneration(BaseModel): """ Control how much effort the model will exert to match the style and features, especially facial features, of input images. This parameter is only supported - for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and - `low`. Defaults to `low`. + for `gpt-image-1` and `gpt-image-1.5` and later models, unsupported for + `gpt-image-1-mini`. Supports `high` and `low`. Defaults to `low`. """ input_image_mask: Optional[ImageGenerationInputImageMask] = None diff --git a/src/openai/types/responses/tool_param.py b/src/openai/types/responses/tool_param.py index 3afff87892..a81c69d3ab 100644 --- a/src/openai/types/responses/tool_param.py +++ b/src/openai/types/responses/tool_param.py @@ -240,8 +240,8 @@ class ImageGeneration(TypedDict, total=False): """ Control how much effort the model will exert to match the style and features, especially facial features, of input images. This parameter is only supported - for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and - `low`. Defaults to `low`. + for `gpt-image-1` and `gpt-image-1.5` and later models, unsupported for + `gpt-image-1-mini`. Supports `high` and `low`. Defaults to `low`. """ input_image_mask: ImageGenerationInputImageMask diff --git a/tests/api_resources/test_responses.py b/tests/api_resources/test_responses.py index 3cdbdba8a6..a644b2c6b9 100644 --- a/tests/api_resources/test_responses.py +++ b/tests/api_resources/test_responses.py @@ -30,6 +30,12 @@ def test_method_create_overload_1(self, client: OpenAI) -> None: def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: response = client.responses.create( background=True, + context_management=[ + { + "type": "type", + "compact_threshold": 1000, + } + ], conversation="string", include=["file_search_call.results"], input="string", @@ -111,6 +117,12 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: response_stream = client.responses.create( stream=True, background=True, + context_management=[ + { + "type": "type", + "compact_threshold": 1000, + } + ], conversation="string", include=["file_search_call.results"], input="string", @@ -426,6 +438,12 @@ async def test_method_create_overload_1(self, async_client: AsyncOpenAI) -> None async def test_method_create_with_all_params_overload_1(self, async_client: AsyncOpenAI) -> None: response = await async_client.responses.create( background=True, + context_management=[ + { + "type": "type", + "compact_threshold": 1000, + } + ], conversation="string", include=["file_search_call.results"], input="string", @@ -507,6 +525,12 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn response_stream = await async_client.responses.create( stream=True, background=True, + context_management=[ + { + "type": "type", + "compact_threshold": 1000, + } + ], conversation="string", include=["file_search_call.results"], input="string", diff --git a/tests/api_resources/vector_stores/test_file_batches.py b/tests/api_resources/vector_stores/test_file_batches.py index abbefc20e9..c1fba534a6 100644 --- a/tests/api_resources/vector_stores/test_file_batches.py +++ b/tests/api_resources/vector_stores/test_file_batches.py @@ -9,6 +9,7 @@ from openai import OpenAI, AsyncOpenAI from tests.utils import assert_matches_type +from openai._utils import assert_signatures_in_sync from openai.pagination import SyncCursorPage, AsyncCursorPage from openai.types.vector_stores import ( VectorStoreFile, @@ -450,3 +451,14 @@ async def test_path_params_list_files(self, async_client: AsyncOpenAI) -> None: batch_id="", vector_store_id="vector_store_id", ) + + +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +def test_create_and_poll_method_in_sync(sync: bool, client: OpenAI, async_client: AsyncOpenAI) -> None: + checking_client: OpenAI | AsyncOpenAI = client if sync else async_client + + # ensure helpers do not drift from generated spec + assert_signatures_in_sync( + checking_client.vector_stores.file_batches.create, + checking_client.vector_stores.file_batches.create_and_poll, + ) diff --git a/tests/api_resources/vector_stores/test_files.py b/tests/api_resources/vector_stores/test_files.py index 7394b50d95..53aa5ee041 100644 --- a/tests/api_resources/vector_stores/test_files.py +++ b/tests/api_resources/vector_stores/test_files.py @@ -635,7 +635,6 @@ def test_create_and_poll_method_in_sync(sync: bool, client: OpenAI, async_client assert_signatures_in_sync( checking_client.vector_stores.files.create, checking_client.vector_stores.files.create_and_poll, - exclude_params={"extra_headers", "extra_query", "extra_body", "timeout"}, ) From 57d7fe790c067300ddb02b5482b41fe0ce041769 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 10 Feb 2026 18:10:49 +0000 Subject: [PATCH 610/769] chore(internal): bump dependencies --- requirements-dev.lock | 20 ++++++++++++++------ requirements.lock | 8 ++++---- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/requirements-dev.lock b/requirements-dev.lock index a7201a127b..b4ed71101a 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -12,14 +12,14 @@ -e file:. aiohappyeyeballs==2.6.1 # via aiohttp -aiohttp==3.13.2 +aiohttp==3.13.3 # via httpx-aiohttp # via openai aiosignal==1.4.0 # via aiohttp annotated-types==0.7.0 # via pydantic -anyio==4.12.0 +anyio==4.12.1 # via httpx # via openai argcomplete==3.6.3 @@ -38,7 +38,7 @@ azure-core==1.36.0 azure-identity==1.25.1 backports-asyncio-runner==1.2.0 # via pytest-asyncio -certifi==2025.11.12 +certifi==2026.1.4 # via httpcore # via httpx # via requests @@ -84,7 +84,7 @@ httpx==0.28.1 # via httpx-aiohttp # via openai # via respx -httpx-aiohttp==0.1.9 +httpx-aiohttp==0.1.12 # via openai humanize==4.13.0 # via nox @@ -94,7 +94,7 @@ idna==3.11 # via requests # via trio # via yarl -importlib-metadata==8.7.0 +importlib-metadata==8.7.1 iniconfig==2.1.0 # via pytest inline-snapshot==0.31.1 @@ -170,8 +170,12 @@ requests==2.32.5 # via msal respx==0.22.0 rich==14.2.0 +<<<<<<< HEAD # via inline-snapshot ruff==0.14.7 +======= +ruff==0.14.13 +>>>>>>> origin/generated--merge-conflict six==1.17.0 # via python-dateutil sniffio==1.3.1 @@ -182,7 +186,7 @@ sortedcontainers==2.4.0 sounddevice==0.5.3 # via openai time-machine==2.19.0 -tomli==2.3.0 +tomli==2.4.0 # via dependency-groups # via inline-snapshot # via mypy @@ -215,12 +219,16 @@ typing-extensions==4.15.0 # via virtualenv typing-inspection==0.4.2 # via pydantic +<<<<<<< HEAD tzdata==2025.2 # via pandas urllib3==2.5.0 # via requests # via types-requests virtualenv==20.35.4 +======= +virtualenv==20.36.1 +>>>>>>> origin/generated--merge-conflict # via nox websockets==15.0.1 # via openai diff --git a/requirements.lock b/requirements.lock index 8e021bd69b..af6e4f99e8 100644 --- a/requirements.lock +++ b/requirements.lock @@ -12,21 +12,21 @@ -e file:. aiohappyeyeballs==2.6.1 # via aiohttp -aiohttp==3.13.2 +aiohttp==3.13.3 # via httpx-aiohttp # via openai aiosignal==1.4.0 # via aiohttp annotated-types==0.7.0 # via pydantic -anyio==4.12.0 +anyio==4.12.1 # via httpx # via openai async-timeout==5.0.1 # via aiohttp attrs==25.4.0 # via aiohttp -certifi==2025.11.12 +certifi==2026.1.4 # via httpcore # via httpx cffi==2.0.0 @@ -45,7 +45,7 @@ httpcore==1.0.9 httpx==0.28.1 # via httpx-aiohttp # via openai -httpx-aiohttp==0.1.9 +httpx-aiohttp==0.1.12 # via openai idna==3.11 # via anyio From b3c7207e63c8d961f0b642f574e69f0e947a090b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 10 Feb 2026 18:05:29 +0000 Subject: [PATCH 611/769] feat(api): skills and hosted shell --- .stats.yml | 8 +- api.md | 55 ++ src/openai/__init__.py | 1 + src/openai/_client.py | 38 ++ src/openai/_module_client.py | 8 + src/openai/resources/__init__.py | 14 + src/openai/resources/images.py | 108 ++- src/openai/resources/skills/__init__.py | 47 ++ src/openai/resources/skills/content.py | 167 +++++ src/openai/resources/skills/skills.py | 618 ++++++++++++++++++ .../resources/skills/versions/__init__.py | 33 + .../resources/skills/versions/content.py | 177 +++++ .../resources/skills/versions/versions.py | 544 +++++++++++++++ src/openai/types/__init__.py | 6 + src/openai/types/deleted_skill.py | 15 + src/openai/types/image_edit_params.py | 19 +- src/openai/types/responses/__init__.py | 30 + src/openai/types/responses/container_auto.py | 36 + .../types/responses/container_auto_param.py | 35 + .../container_network_policy_allowlist.py | 20 + ...ontainer_network_policy_allowlist_param.py | 22 + .../container_network_policy_disabled.py | 12 + ...container_network_policy_disabled_param.py | 12 + .../container_network_policy_domain_secret.py | 16 + ...iner_network_policy_domain_secret_param.py | 18 + .../types/responses/container_reference.py | 15 + .../responses/container_reference_param.py | 15 + .../types/responses/function_shell_tool.py | 15 +- .../responses/function_shell_tool_param.py | 13 +- src/openai/types/responses/inline_skill.py | 22 + .../types/responses/inline_skill_param.py | 23 + .../types/responses/inline_skill_source.py | 20 + .../responses/inline_skill_source_param.py | 20 + .../types/responses/local_environment.py | 17 + .../responses/local_environment_param.py | 18 + src/openai/types/responses/local_skill.py | 16 + .../types/responses/local_skill_param.py | 18 + .../responses/response_container_reference.py | 16 + .../response_function_shell_tool_call.py | 17 +- .../types/responses/response_input_item.py | 11 + .../responses/response_input_item_param.py | 9 + .../types/responses/response_input_param.py | 9 + .../responses/response_local_environment.py | 14 + src/openai/types/responses/skill_reference.py | 19 + .../types/responses/skill_reference_param.py | 18 + src/openai/types/responses/tool.py | 11 + src/openai/types/responses/tool_param.py | 11 + src/openai/types/skill.py | 30 + src/openai/types/skill_create_params.py | 15 + src/openai/types/skill_list.py | 26 + src/openai/types/skill_list_params.py | 21 + src/openai/types/skill_update_params.py | 12 + src/openai/types/skills/__init__.py | 9 + .../types/skills/deleted_skill_version.py | 18 + src/openai/types/skills/skill_version.py | 30 + src/openai/types/skills/skill_version_list.py | 26 + .../types/skills/version_create_params.py | 18 + .../types/skills/version_list_params.py | 18 + src/openai/types/skills/versions/__init__.py | 3 + tests/api_resources/skills/__init__.py | 1 + tests/api_resources/skills/test_content.py | 122 ++++ tests/api_resources/skills/test_versions.py | 407 ++++++++++++ .../api_resources/skills/versions/__init__.py | 1 + .../skills/versions/test_content.py | 154 +++++ tests/api_resources/test_skills.py | 393 +++++++++++ 65 files changed, 3628 insertions(+), 82 deletions(-) create mode 100644 src/openai/resources/skills/__init__.py create mode 100644 src/openai/resources/skills/content.py create mode 100644 src/openai/resources/skills/skills.py create mode 100644 src/openai/resources/skills/versions/__init__.py create mode 100644 src/openai/resources/skills/versions/content.py create mode 100644 src/openai/resources/skills/versions/versions.py create mode 100644 src/openai/types/deleted_skill.py create mode 100644 src/openai/types/responses/container_auto.py create mode 100644 src/openai/types/responses/container_auto_param.py create mode 100644 src/openai/types/responses/container_network_policy_allowlist.py create mode 100644 src/openai/types/responses/container_network_policy_allowlist_param.py create mode 100644 src/openai/types/responses/container_network_policy_disabled.py create mode 100644 src/openai/types/responses/container_network_policy_disabled_param.py create mode 100644 src/openai/types/responses/container_network_policy_domain_secret.py create mode 100644 src/openai/types/responses/container_network_policy_domain_secret_param.py create mode 100644 src/openai/types/responses/container_reference.py create mode 100644 src/openai/types/responses/container_reference_param.py create mode 100644 src/openai/types/responses/inline_skill.py create mode 100644 src/openai/types/responses/inline_skill_param.py create mode 100644 src/openai/types/responses/inline_skill_source.py create mode 100644 src/openai/types/responses/inline_skill_source_param.py create mode 100644 src/openai/types/responses/local_environment.py create mode 100644 src/openai/types/responses/local_environment_param.py create mode 100644 src/openai/types/responses/local_skill.py create mode 100644 src/openai/types/responses/local_skill_param.py create mode 100644 src/openai/types/responses/response_container_reference.py create mode 100644 src/openai/types/responses/response_local_environment.py create mode 100644 src/openai/types/responses/skill_reference.py create mode 100644 src/openai/types/responses/skill_reference_param.py create mode 100644 src/openai/types/skill.py create mode 100644 src/openai/types/skill_create_params.py create mode 100644 src/openai/types/skill_list.py create mode 100644 src/openai/types/skill_list_params.py create mode 100644 src/openai/types/skill_update_params.py create mode 100644 src/openai/types/skills/__init__.py create mode 100644 src/openai/types/skills/deleted_skill_version.py create mode 100644 src/openai/types/skills/skill_version.py create mode 100644 src/openai/types/skills/skill_version_list.py create mode 100644 src/openai/types/skills/version_create_params.py create mode 100644 src/openai/types/skills/version_list_params.py create mode 100644 src/openai/types/skills/versions/__init__.py create mode 100644 tests/api_resources/skills/__init__.py create mode 100644 tests/api_resources/skills/test_content.py create mode 100644 tests/api_resources/skills/test_versions.py create mode 100644 tests/api_resources/skills/versions/__init__.py create mode 100644 tests/api_resources/skills/versions/test_content.py create mode 100644 tests/api_resources/test_skills.py diff --git a/.stats.yml b/.stats.yml index fce116bc4f..e91271a6c8 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 137 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-bff810f46da56eff8d5e189b0d1f56ac07a8289723666138549d4239cad7c2ea.yml -openapi_spec_hash: 7532ce5a6f490c8f5d1e079c76c70535 -config_hash: a1454ffd9612dee11f9d5a98e55eac9e +configured_endpoints: 148 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-7debfce2217c66ea87bfddaa244b57de4062dd7fd766fa9a28e869614205c040.yml +openapi_spec_hash: e910fc478b8449134e2af1dc15fd33f7 +config_hash: 8dca0f2dc2706c07cf2f8d0ed4dc062e diff --git a/api.md b/api.md index 1c054b52fc..54fa94da5f 100644 --- a/api.md +++ b/api.md @@ -736,11 +736,20 @@ from openai.types.responses import ( ApplyPatchTool, CompactedResponse, ComputerTool, + ContainerAuto, + ContainerNetworkPolicyAllowlist, + ContainerNetworkPolicyDisabled, + ContainerNetworkPolicyDomainSecret, + ContainerReference, CustomTool, EasyInputMessage, FileSearchTool, FunctionShellTool, FunctionTool, + InlineSkill, + InlineSkillSource, + LocalEnvironment, + LocalSkill, Response, ResponseApplyPatchToolCall, ResponseApplyPatchToolCallOutput, @@ -760,6 +769,7 @@ from openai.types.responses import ( ResponseComputerToolCall, ResponseComputerToolCallOutputItem, ResponseComputerToolCallOutputScreenshot, + ResponseContainerReference, ResponseContent, ResponseContentPartAddedEvent, ResponseContentPartDoneEvent, @@ -809,6 +819,7 @@ from openai.types.responses import ( ResponseInputText, ResponseInputTextContent, ResponseItem, + ResponseLocalEnvironment, ResponseMcpCallArgumentsDeltaEvent, ResponseMcpCallArgumentsDoneEvent, ResponseMcpCallCompletedEvent, @@ -845,6 +856,7 @@ from openai.types.responses import ( ResponseWebSearchCallCompletedEvent, ResponseWebSearchCallInProgressEvent, ResponseWebSearchCallSearchingEvent, + SkillReference, Tool, ToolChoiceAllowed, ToolChoiceApplyPatch, @@ -1170,6 +1182,49 @@ Methods: - client.containers.files.content.retrieve(file_id, \*, container_id) -> HttpxBinaryResponseContent +# Skills + +Types: + +```python +from openai.types import DeletedSkill, Skill, SkillList +``` + +Methods: + +- client.skills.create(\*\*params) -> Skill +- client.skills.retrieve(skill_id) -> Skill +- client.skills.update(skill_id, \*\*params) -> Skill +- client.skills.list(\*\*params) -> SyncCursorPage[Skill] +- client.skills.delete(skill_id) -> DeletedSkill + +## Content + +Methods: + +- client.skills.content.retrieve(skill_id) -> HttpxBinaryResponseContent + +## Versions + +Types: + +```python +from openai.types.skills import DeletedSkillVersion, SkillVersion, SkillVersionList +``` + +Methods: + +- client.skills.versions.create(skill_id, \*\*params) -> SkillVersion +- client.skills.versions.retrieve(version, \*, skill_id) -> SkillVersion +- client.skills.versions.list(skill_id, \*\*params) -> SyncCursorPage[SkillVersion] +- client.skills.versions.delete(version, \*, skill_id) -> DeletedSkillVersion + +### Content + +Methods: + +- client.skills.versions.content.retrieve(version, \*, skill_id) -> HttpxBinaryResponseContent + # Videos Types: diff --git a/src/openai/__init__.py b/src/openai/__init__.py index e7411b3886..b2093ada68 100644 --- a/src/openai/__init__.py +++ b/src/openai/__init__.py @@ -379,6 +379,7 @@ def _reset_client() -> None: # type: ignore[reportUnusedFunction] files as files, images as images, models as models, + skills as skills, videos as videos, batches as batches, uploads as uploads, diff --git a/src/openai/_client.py b/src/openai/_client.py index a3b01b2ce6..440a8a45c8 100644 --- a/src/openai/_client.py +++ b/src/openai/_client.py @@ -44,6 +44,7 @@ files, images, models, + skills, videos, batches, uploads, @@ -70,6 +71,7 @@ from .resources.completions import Completions, AsyncCompletions from .resources.evals.evals import Evals, AsyncEvals from .resources.moderations import Moderations, AsyncModerations + from .resources.skills.skills import Skills, AsyncSkills from .resources.uploads.uploads import Uploads, AsyncUploads from .resources.realtime.realtime import Realtime, AsyncRealtime from .resources.responses.responses import Responses, AsyncResponses @@ -290,6 +292,12 @@ def containers(self) -> Containers: return Containers(self) + @cached_property + def skills(self) -> Skills: + from .resources.skills import Skills + + return Skills(self) + @cached_property def videos(self) -> Videos: from .resources.videos import Videos @@ -641,6 +649,12 @@ def containers(self) -> AsyncContainers: return AsyncContainers(self) + @cached_property + def skills(self) -> AsyncSkills: + from .resources.skills import AsyncSkills + + return AsyncSkills(self) + @cached_property def videos(self) -> AsyncVideos: from .resources.videos import AsyncVideos @@ -897,6 +911,12 @@ def containers(self) -> containers.ContainersWithRawResponse: return ContainersWithRawResponse(self._client.containers) + @cached_property + def skills(self) -> skills.SkillsWithRawResponse: + from .resources.skills import SkillsWithRawResponse + + return SkillsWithRawResponse(self._client.skills) + @cached_property def videos(self) -> videos.VideosWithRawResponse: from .resources.videos import VideosWithRawResponse @@ -1018,6 +1038,12 @@ def containers(self) -> containers.AsyncContainersWithRawResponse: return AsyncContainersWithRawResponse(self._client.containers) + @cached_property + def skills(self) -> skills.AsyncSkillsWithRawResponse: + from .resources.skills import AsyncSkillsWithRawResponse + + return AsyncSkillsWithRawResponse(self._client.skills) + @cached_property def videos(self) -> videos.AsyncVideosWithRawResponse: from .resources.videos import AsyncVideosWithRawResponse @@ -1139,6 +1165,12 @@ def containers(self) -> containers.ContainersWithStreamingResponse: return ContainersWithStreamingResponse(self._client.containers) + @cached_property + def skills(self) -> skills.SkillsWithStreamingResponse: + from .resources.skills import SkillsWithStreamingResponse + + return SkillsWithStreamingResponse(self._client.skills) + @cached_property def videos(self) -> videos.VideosWithStreamingResponse: from .resources.videos import VideosWithStreamingResponse @@ -1260,6 +1292,12 @@ def containers(self) -> containers.AsyncContainersWithStreamingResponse: return AsyncContainersWithStreamingResponse(self._client.containers) + @cached_property + def skills(self) -> skills.AsyncSkillsWithStreamingResponse: + from .resources.skills import AsyncSkillsWithStreamingResponse + + return AsyncSkillsWithStreamingResponse(self._client.skills) + @cached_property def videos(self) -> videos.AsyncVideosWithStreamingResponse: from .resources.videos import AsyncVideosWithStreamingResponse diff --git a/src/openai/_module_client.py b/src/openai/_module_client.py index d0d721887b..17bb9306aa 100644 --- a/src/openai/_module_client.py +++ b/src/openai/_module_client.py @@ -19,6 +19,7 @@ from .resources.completions import Completions from .resources.evals.evals import Evals from .resources.moderations import Moderations + from .resources.skills.skills import Skills from .resources.uploads.uploads import Uploads from .resources.realtime.realtime import Realtime from .resources.responses.responses import Responses @@ -73,6 +74,12 @@ def __load__(self) -> Models: return _load_client().models +class SkillsProxy(LazyProxy["Skills"]): + @override + def __load__(self) -> Skills: + return _load_client().skills + + class VideosProxy(LazyProxy["Videos"]): @override def __load__(self) -> Videos: @@ -158,6 +165,7 @@ def __load__(self) -> Conversations: evals: Evals = EvalsProxy().__as_proxied__() images: Images = ImagesProxy().__as_proxied__() models: Models = ModelsProxy().__as_proxied__() +skills: Skills = SkillsProxy().__as_proxied__() videos: Videos = VideosProxy().__as_proxied__() batches: Batches = BatchesProxy().__as_proxied__() uploads: Uploads = UploadsProxy().__as_proxied__() diff --git a/src/openai/resources/__init__.py b/src/openai/resources/__init__.py index b793fbc7b0..ed030f7188 100644 --- a/src/openai/resources/__init__.py +++ b/src/openai/resources/__init__.py @@ -56,6 +56,14 @@ ModelsWithStreamingResponse, AsyncModelsWithStreamingResponse, ) +from .skills import ( + Skills, + AsyncSkills, + SkillsWithRawResponse, + AsyncSkillsWithRawResponse, + SkillsWithStreamingResponse, + AsyncSkillsWithStreamingResponse, +) from .videos import ( Videos, AsyncVideos, @@ -220,6 +228,12 @@ "AsyncContainersWithRawResponse", "ContainersWithStreamingResponse", "AsyncContainersWithStreamingResponse", + "Skills", + "AsyncSkills", + "SkillsWithRawResponse", + "AsyncSkillsWithRawResponse", + "SkillsWithStreamingResponse", + "AsyncSkillsWithStreamingResponse", "Videos", "AsyncVideos", "VideosWithRawResponse", diff --git a/src/openai/resources/images.py b/src/openai/resources/images.py index 3de5185a87..647eb1ca24 100644 --- a/src/openai/resources/images.py +++ b/src/openai/resources/images.py @@ -147,14 +147,15 @@ def edit( prompt. This endpoint supports GPT Image models (`gpt-image-1.5`, `gpt-image-1`, - and `gpt-image-1-mini`) and `dall-e-2`. + `gpt-image-1-mini`, and `chatgpt-image-latest`) and `dall-e-2`. Args: image: The image(s) to edit. Must be a supported image file or an array of images. For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, and `gpt-image-1.5`), each image should be a `png`, `webp`, or `jpg` file less than - 50MB. You can provide up to 16 images. + 50MB. You can provide up to 16 images. `chatgpt-image-latest` follows the same + input constraints as GPT image models. For `dall-e-2`, you can only provide one image, and it should be a square `png` file less than 4MB. @@ -180,9 +181,7 @@ def edit( the mask will be applied on the first image. Must be a valid PNG file, less than 4MB, and have the same dimensions as `image`. - model: The model to use for image generation. Only `dall-e-2` and the GPT image models - are supported. Defaults to `dall-e-2` unless a parameter specific to the GPT - image models is used. + model: The model to use for image generation. Defaults to `gpt-image-1.5`. n: The number of images to generate. Must be between 1 and 10. @@ -201,14 +200,13 @@ def edit( Note that the final image may be sent before the full number of partial images are generated if the full image is generated more quickly. - quality: The quality of the image that will be generated. `high`, `medium` and `low` are - only supported for the GPT image models. `dall-e-2` only supports `standard` - quality. Defaults to `auto`. + quality: The quality of the image that will be generated for GPT image models. Defaults + to `auto`. response_format: The format in which the generated images are returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes after the image has been - generated. This parameter is only supported for `dall-e-2`, as the GPT image - models always return base64-encoded images. + generated. This parameter is only supported for `dall-e-2` (default is `url` for + `dall-e-2`), as GPT image models always return base64-encoded images. size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image @@ -262,14 +260,15 @@ def edit( prompt. This endpoint supports GPT Image models (`gpt-image-1.5`, `gpt-image-1`, - and `gpt-image-1-mini`) and `dall-e-2`. + `gpt-image-1-mini`, and `chatgpt-image-latest`) and `dall-e-2`. Args: image: The image(s) to edit. Must be a supported image file or an array of images. For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, and `gpt-image-1.5`), each image should be a `png`, `webp`, or `jpg` file less than - 50MB. You can provide up to 16 images. + 50MB. You can provide up to 16 images. `chatgpt-image-latest` follows the same + input constraints as GPT image models. For `dall-e-2`, you can only provide one image, and it should be a square `png` file less than 4MB. @@ -299,9 +298,7 @@ def edit( the mask will be applied on the first image. Must be a valid PNG file, less than 4MB, and have the same dimensions as `image`. - model: The model to use for image generation. Only `dall-e-2` and the GPT image models - are supported. Defaults to `dall-e-2` unless a parameter specific to the GPT - image models is used. + model: The model to use for image generation. Defaults to `gpt-image-1.5`. n: The number of images to generate. Must be between 1 and 10. @@ -320,14 +317,13 @@ def edit( Note that the final image may be sent before the full number of partial images are generated if the full image is generated more quickly. - quality: The quality of the image that will be generated. `high`, `medium` and `low` are - only supported for the GPT image models. `dall-e-2` only supports `standard` - quality. Defaults to `auto`. + quality: The quality of the image that will be generated for GPT image models. Defaults + to `auto`. response_format: The format in which the generated images are returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes after the image has been - generated. This parameter is only supported for `dall-e-2`, as the GPT image - models always return base64-encoded images. + generated. This parameter is only supported for `dall-e-2` (default is `url` for + `dall-e-2`), as GPT image models always return base64-encoded images. size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image @@ -377,14 +373,15 @@ def edit( prompt. This endpoint supports GPT Image models (`gpt-image-1.5`, `gpt-image-1`, - and `gpt-image-1-mini`) and `dall-e-2`. + `gpt-image-1-mini`, and `chatgpt-image-latest`) and `dall-e-2`. Args: image: The image(s) to edit. Must be a supported image file or an array of images. For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, and `gpt-image-1.5`), each image should be a `png`, `webp`, or `jpg` file less than - 50MB. You can provide up to 16 images. + 50MB. You can provide up to 16 images. `chatgpt-image-latest` follows the same + input constraints as GPT image models. For `dall-e-2`, you can only provide one image, and it should be a square `png` file less than 4MB. @@ -414,9 +411,7 @@ def edit( the mask will be applied on the first image. Must be a valid PNG file, less than 4MB, and have the same dimensions as `image`. - model: The model to use for image generation. Only `dall-e-2` and the GPT image models - are supported. Defaults to `dall-e-2` unless a parameter specific to the GPT - image models is used. + model: The model to use for image generation. Defaults to `gpt-image-1.5`. n: The number of images to generate. Must be between 1 and 10. @@ -435,14 +430,13 @@ def edit( Note that the final image may be sent before the full number of partial images are generated if the full image is generated more quickly. - quality: The quality of the image that will be generated. `high`, `medium` and `low` are - only supported for the GPT image models. `dall-e-2` only supports `standard` - quality. Defaults to `auto`. + quality: The quality of the image that will be generated for GPT image models. Defaults + to `auto`. response_format: The format in which the generated images are returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes after the image has been - generated. This parameter is only supported for `dall-e-2`, as the GPT image - models always return base64-encoded images. + generated. This parameter is only supported for `dall-e-2` (default is `url` for + `dall-e-2`), as GPT image models always return base64-encoded images. size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image @@ -1043,14 +1037,15 @@ async def edit( prompt. This endpoint supports GPT Image models (`gpt-image-1.5`, `gpt-image-1`, - and `gpt-image-1-mini`) and `dall-e-2`. + `gpt-image-1-mini`, and `chatgpt-image-latest`) and `dall-e-2`. Args: image: The image(s) to edit. Must be a supported image file or an array of images. For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, and `gpt-image-1.5`), each image should be a `png`, `webp`, or `jpg` file less than - 50MB. You can provide up to 16 images. + 50MB. You can provide up to 16 images. `chatgpt-image-latest` follows the same + input constraints as GPT image models. For `dall-e-2`, you can only provide one image, and it should be a square `png` file less than 4MB. @@ -1076,9 +1071,7 @@ async def edit( the mask will be applied on the first image. Must be a valid PNG file, less than 4MB, and have the same dimensions as `image`. - model: The model to use for image generation. Only `dall-e-2` and the GPT image models - are supported. Defaults to `dall-e-2` unless a parameter specific to the GPT - image models is used. + model: The model to use for image generation. Defaults to `gpt-image-1.5`. n: The number of images to generate. Must be between 1 and 10. @@ -1097,14 +1090,13 @@ async def edit( Note that the final image may be sent before the full number of partial images are generated if the full image is generated more quickly. - quality: The quality of the image that will be generated. `high`, `medium` and `low` are - only supported for the GPT image models. `dall-e-2` only supports `standard` - quality. Defaults to `auto`. + quality: The quality of the image that will be generated for GPT image models. Defaults + to `auto`. response_format: The format in which the generated images are returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes after the image has been - generated. This parameter is only supported for `dall-e-2`, as the GPT image - models always return base64-encoded images. + generated. This parameter is only supported for `dall-e-2` (default is `url` for + `dall-e-2`), as GPT image models always return base64-encoded images. size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image @@ -1158,14 +1150,15 @@ async def edit( prompt. This endpoint supports GPT Image models (`gpt-image-1.5`, `gpt-image-1`, - and `gpt-image-1-mini`) and `dall-e-2`. + `gpt-image-1-mini`, and `chatgpt-image-latest`) and `dall-e-2`. Args: image: The image(s) to edit. Must be a supported image file or an array of images. For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, and `gpt-image-1.5`), each image should be a `png`, `webp`, or `jpg` file less than - 50MB. You can provide up to 16 images. + 50MB. You can provide up to 16 images. `chatgpt-image-latest` follows the same + input constraints as GPT image models. For `dall-e-2`, you can only provide one image, and it should be a square `png` file less than 4MB. @@ -1195,9 +1188,7 @@ async def edit( the mask will be applied on the first image. Must be a valid PNG file, less than 4MB, and have the same dimensions as `image`. - model: The model to use for image generation. Only `dall-e-2` and the GPT image models - are supported. Defaults to `dall-e-2` unless a parameter specific to the GPT - image models is used. + model: The model to use for image generation. Defaults to `gpt-image-1.5`. n: The number of images to generate. Must be between 1 and 10. @@ -1216,14 +1207,13 @@ async def edit( Note that the final image may be sent before the full number of partial images are generated if the full image is generated more quickly. - quality: The quality of the image that will be generated. `high`, `medium` and `low` are - only supported for the GPT image models. `dall-e-2` only supports `standard` - quality. Defaults to `auto`. + quality: The quality of the image that will be generated for GPT image models. Defaults + to `auto`. response_format: The format in which the generated images are returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes after the image has been - generated. This parameter is only supported for `dall-e-2`, as the GPT image - models always return base64-encoded images. + generated. This parameter is only supported for `dall-e-2` (default is `url` for + `dall-e-2`), as GPT image models always return base64-encoded images. size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image @@ -1273,14 +1263,15 @@ async def edit( prompt. This endpoint supports GPT Image models (`gpt-image-1.5`, `gpt-image-1`, - and `gpt-image-1-mini`) and `dall-e-2`. + `gpt-image-1-mini`, and `chatgpt-image-latest`) and `dall-e-2`. Args: image: The image(s) to edit. Must be a supported image file or an array of images. For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, and `gpt-image-1.5`), each image should be a `png`, `webp`, or `jpg` file less than - 50MB. You can provide up to 16 images. + 50MB. You can provide up to 16 images. `chatgpt-image-latest` follows the same + input constraints as GPT image models. For `dall-e-2`, you can only provide one image, and it should be a square `png` file less than 4MB. @@ -1310,9 +1301,7 @@ async def edit( the mask will be applied on the first image. Must be a valid PNG file, less than 4MB, and have the same dimensions as `image`. - model: The model to use for image generation. Only `dall-e-2` and the GPT image models - are supported. Defaults to `dall-e-2` unless a parameter specific to the GPT - image models is used. + model: The model to use for image generation. Defaults to `gpt-image-1.5`. n: The number of images to generate. Must be between 1 and 10. @@ -1331,14 +1320,13 @@ async def edit( Note that the final image may be sent before the full number of partial images are generated if the full image is generated more quickly. - quality: The quality of the image that will be generated. `high`, `medium` and `low` are - only supported for the GPT image models. `dall-e-2` only supports `standard` - quality. Defaults to `auto`. + quality: The quality of the image that will be generated for GPT image models. Defaults + to `auto`. response_format: The format in which the generated images are returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes after the image has been - generated. This parameter is only supported for `dall-e-2`, as the GPT image - models always return base64-encoded images. + generated. This parameter is only supported for `dall-e-2` (default is `url` for + `dall-e-2`), as GPT image models always return base64-encoded images. size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image diff --git a/src/openai/resources/skills/__init__.py b/src/openai/resources/skills/__init__.py new file mode 100644 index 0000000000..07f4d6729d --- /dev/null +++ b/src/openai/resources/skills/__init__.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .skills import ( + Skills, + AsyncSkills, + SkillsWithRawResponse, + AsyncSkillsWithRawResponse, + SkillsWithStreamingResponse, + AsyncSkillsWithStreamingResponse, +) +from .content import ( + Content, + AsyncContent, + ContentWithRawResponse, + AsyncContentWithRawResponse, + ContentWithStreamingResponse, + AsyncContentWithStreamingResponse, +) +from .versions import ( + Versions, + AsyncVersions, + VersionsWithRawResponse, + AsyncVersionsWithRawResponse, + VersionsWithStreamingResponse, + AsyncVersionsWithStreamingResponse, +) + +__all__ = [ + "Content", + "AsyncContent", + "ContentWithRawResponse", + "AsyncContentWithRawResponse", + "ContentWithStreamingResponse", + "AsyncContentWithStreamingResponse", + "Versions", + "AsyncVersions", + "VersionsWithRawResponse", + "AsyncVersionsWithRawResponse", + "VersionsWithStreamingResponse", + "AsyncVersionsWithStreamingResponse", + "Skills", + "AsyncSkills", + "SkillsWithRawResponse", + "AsyncSkillsWithRawResponse", + "SkillsWithStreamingResponse", + "AsyncSkillsWithStreamingResponse", +] diff --git a/src/openai/resources/skills/content.py b/src/openai/resources/skills/content.py new file mode 100644 index 0000000000..98c1531a94 --- /dev/null +++ b/src/openai/resources/skills/content.py @@ -0,0 +1,167 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ... import _legacy_response +from ..._types import Body, Query, Headers, NotGiven, not_given +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + StreamedBinaryAPIResponse, + AsyncStreamedBinaryAPIResponse, + to_custom_streamed_response_wrapper, + async_to_custom_streamed_response_wrapper, +) +from ..._base_client import make_request_options + +__all__ = ["Content", "AsyncContent"] + + +class Content(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ContentWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return ContentWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ContentWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return ContentWithStreamingResponse(self) + + def retrieve( + self, + skill_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> _legacy_response.HttpxBinaryResponseContent: + """ + Get Skill Content + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not skill_id: + raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") + extra_headers = {"Accept": "application/binary", **(extra_headers or {})} + return self._get( + f"/skills/{skill_id}/content", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=_legacy_response.HttpxBinaryResponseContent, + ) + + +class AsyncContent(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncContentWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncContentWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncContentWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncContentWithStreamingResponse(self) + + async def retrieve( + self, + skill_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> _legacy_response.HttpxBinaryResponseContent: + """ + Get Skill Content + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not skill_id: + raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") + extra_headers = {"Accept": "application/binary", **(extra_headers or {})} + return await self._get( + f"/skills/{skill_id}/content", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=_legacy_response.HttpxBinaryResponseContent, + ) + + +class ContentWithRawResponse: + def __init__(self, content: Content) -> None: + self._content = content + + self.retrieve = _legacy_response.to_raw_response_wrapper( + content.retrieve, + ) + + +class AsyncContentWithRawResponse: + def __init__(self, content: AsyncContent) -> None: + self._content = content + + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + content.retrieve, + ) + + +class ContentWithStreamingResponse: + def __init__(self, content: Content) -> None: + self._content = content + + self.retrieve = to_custom_streamed_response_wrapper( + content.retrieve, + StreamedBinaryAPIResponse, + ) + + +class AsyncContentWithStreamingResponse: + def __init__(self, content: AsyncContent) -> None: + self._content = content + + self.retrieve = async_to_custom_streamed_response_wrapper( + content.retrieve, + AsyncStreamedBinaryAPIResponse, + ) diff --git a/src/openai/resources/skills/skills.py b/src/openai/resources/skills/skills.py new file mode 100644 index 0000000000..b0e929bccf --- /dev/null +++ b/src/openai/resources/skills/skills.py @@ -0,0 +1,618 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Mapping, cast +from typing_extensions import Literal + +import httpx + +from ... import _legacy_response +from ...types import skill_list_params, skill_create_params, skill_update_params +from .content import ( + Content, + AsyncContent, + ContentWithRawResponse, + AsyncContentWithRawResponse, + ContentWithStreamingResponse, + AsyncContentWithStreamingResponse, +) +from ..._types import ( + Body, + Omit, + Query, + Headers, + NotGiven, + FileTypes, + SequenceNotStr, + omit, + not_given, +) +from ..._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ...pagination import SyncCursorPage, AsyncCursorPage +from ...types.skill import Skill +from ..._base_client import AsyncPaginator, make_request_options +from .versions.versions import ( + Versions, + AsyncVersions, + VersionsWithRawResponse, + AsyncVersionsWithRawResponse, + VersionsWithStreamingResponse, + AsyncVersionsWithStreamingResponse, +) +from ...types.deleted_skill import DeletedSkill + +__all__ = ["Skills", "AsyncSkills"] + + +class Skills(SyncAPIResource): + @cached_property + def content(self) -> Content: + return Content(self._client) + + @cached_property + def versions(self) -> Versions: + return Versions(self._client) + + @cached_property + def with_raw_response(self) -> SkillsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return SkillsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> SkillsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return SkillsWithStreamingResponse(self) + + def create( + self, + *, + files: Union[SequenceNotStr[FileTypes], FileTypes] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Skill: + """ + Create Skill + + Args: + files: Skill files to upload (directory upload) or a single zip file. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + body = deepcopy_minimal({"files": files}) + extracted_files = extract_files(cast(Mapping[str, object], body), paths=[["files", ""], ["files"]]) + if extracted_files: + # It should be noted that the actual Content-Type header that will be + # sent to the server will contain a `boundary` parameter, e.g. + # multipart/form-data; boundary=---abc-- + extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} + return self._post( + "/skills", + body=maybe_transform(body, skill_create_params.SkillCreateParams), + files=extracted_files, + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Skill, + ) + + def retrieve( + self, + skill_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Skill: + """ + Get Skill + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not skill_id: + raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") + return self._get( + f"/skills/{skill_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Skill, + ) + + def update( + self, + skill_id: str, + *, + default_version: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Skill: + """ + Update Skill Default Version + + Args: + default_version: The skill version number to set as default. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not skill_id: + raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") + return self._post( + f"/skills/{skill_id}", + body=maybe_transform({"default_version": default_version}, skill_update_params.SkillUpdateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Skill, + ) + + def list( + self, + *, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncCursorPage[Skill]: + """ + List Skills + + Args: + after: Identifier for the last item from the previous pagination request + + limit: Number of items to retrieve + + order: Sort order of results by timestamp. Use `asc` for ascending order or `desc` for + descending order. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/skills", + page=SyncCursorPage[Skill], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + skill_list_params.SkillListParams, + ), + ), + model=Skill, + ) + + def delete( + self, + skill_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DeletedSkill: + """ + Delete Skill + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not skill_id: + raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") + return self._delete( + f"/skills/{skill_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DeletedSkill, + ) + + +class AsyncSkills(AsyncAPIResource): + @cached_property + def content(self) -> AsyncContent: + return AsyncContent(self._client) + + @cached_property + def versions(self) -> AsyncVersions: + return AsyncVersions(self._client) + + @cached_property + def with_raw_response(self) -> AsyncSkillsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncSkillsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncSkillsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncSkillsWithStreamingResponse(self) + + async def create( + self, + *, + files: Union[SequenceNotStr[FileTypes], FileTypes] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Skill: + """ + Create Skill + + Args: + files: Skill files to upload (directory upload) or a single zip file. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + body = deepcopy_minimal({"files": files}) + extracted_files = extract_files(cast(Mapping[str, object], body), paths=[["files", ""], ["files"]]) + if extracted_files: + # It should be noted that the actual Content-Type header that will be + # sent to the server will contain a `boundary` parameter, e.g. + # multipart/form-data; boundary=---abc-- + extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} + return await self._post( + "/skills", + body=await async_maybe_transform(body, skill_create_params.SkillCreateParams), + files=extracted_files, + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Skill, + ) + + async def retrieve( + self, + skill_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Skill: + """ + Get Skill + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not skill_id: + raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") + return await self._get( + f"/skills/{skill_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Skill, + ) + + async def update( + self, + skill_id: str, + *, + default_version: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Skill: + """ + Update Skill Default Version + + Args: + default_version: The skill version number to set as default. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not skill_id: + raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") + return await self._post( + f"/skills/{skill_id}", + body=await async_maybe_transform( + {"default_version": default_version}, skill_update_params.SkillUpdateParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Skill, + ) + + def list( + self, + *, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Skill, AsyncCursorPage[Skill]]: + """ + List Skills + + Args: + after: Identifier for the last item from the previous pagination request + + limit: Number of items to retrieve + + order: Sort order of results by timestamp. Use `asc` for ascending order or `desc` for + descending order. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/skills", + page=AsyncCursorPage[Skill], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + skill_list_params.SkillListParams, + ), + ), + model=Skill, + ) + + async def delete( + self, + skill_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DeletedSkill: + """ + Delete Skill + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not skill_id: + raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") + return await self._delete( + f"/skills/{skill_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DeletedSkill, + ) + + +class SkillsWithRawResponse: + def __init__(self, skills: Skills) -> None: + self._skills = skills + + self.create = _legacy_response.to_raw_response_wrapper( + skills.create, + ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + skills.retrieve, + ) + self.update = _legacy_response.to_raw_response_wrapper( + skills.update, + ) + self.list = _legacy_response.to_raw_response_wrapper( + skills.list, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + skills.delete, + ) + + @cached_property + def content(self) -> ContentWithRawResponse: + return ContentWithRawResponse(self._skills.content) + + @cached_property + def versions(self) -> VersionsWithRawResponse: + return VersionsWithRawResponse(self._skills.versions) + + +class AsyncSkillsWithRawResponse: + def __init__(self, skills: AsyncSkills) -> None: + self._skills = skills + + self.create = _legacy_response.async_to_raw_response_wrapper( + skills.create, + ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + skills.retrieve, + ) + self.update = _legacy_response.async_to_raw_response_wrapper( + skills.update, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + skills.list, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + skills.delete, + ) + + @cached_property + def content(self) -> AsyncContentWithRawResponse: + return AsyncContentWithRawResponse(self._skills.content) + + @cached_property + def versions(self) -> AsyncVersionsWithRawResponse: + return AsyncVersionsWithRawResponse(self._skills.versions) + + +class SkillsWithStreamingResponse: + def __init__(self, skills: Skills) -> None: + self._skills = skills + + self.create = to_streamed_response_wrapper( + skills.create, + ) + self.retrieve = to_streamed_response_wrapper( + skills.retrieve, + ) + self.update = to_streamed_response_wrapper( + skills.update, + ) + self.list = to_streamed_response_wrapper( + skills.list, + ) + self.delete = to_streamed_response_wrapper( + skills.delete, + ) + + @cached_property + def content(self) -> ContentWithStreamingResponse: + return ContentWithStreamingResponse(self._skills.content) + + @cached_property + def versions(self) -> VersionsWithStreamingResponse: + return VersionsWithStreamingResponse(self._skills.versions) + + +class AsyncSkillsWithStreamingResponse: + def __init__(self, skills: AsyncSkills) -> None: + self._skills = skills + + self.create = async_to_streamed_response_wrapper( + skills.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + skills.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + skills.update, + ) + self.list = async_to_streamed_response_wrapper( + skills.list, + ) + self.delete = async_to_streamed_response_wrapper( + skills.delete, + ) + + @cached_property + def content(self) -> AsyncContentWithStreamingResponse: + return AsyncContentWithStreamingResponse(self._skills.content) + + @cached_property + def versions(self) -> AsyncVersionsWithStreamingResponse: + return AsyncVersionsWithStreamingResponse(self._skills.versions) diff --git a/src/openai/resources/skills/versions/__init__.py b/src/openai/resources/skills/versions/__init__.py new file mode 100644 index 0000000000..c9ad6fbbca --- /dev/null +++ b/src/openai/resources/skills/versions/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .content import ( + Content, + AsyncContent, + ContentWithRawResponse, + AsyncContentWithRawResponse, + ContentWithStreamingResponse, + AsyncContentWithStreamingResponse, +) +from .versions import ( + Versions, + AsyncVersions, + VersionsWithRawResponse, + AsyncVersionsWithRawResponse, + VersionsWithStreamingResponse, + AsyncVersionsWithStreamingResponse, +) + +__all__ = [ + "Content", + "AsyncContent", + "ContentWithRawResponse", + "AsyncContentWithRawResponse", + "ContentWithStreamingResponse", + "AsyncContentWithStreamingResponse", + "Versions", + "AsyncVersions", + "VersionsWithRawResponse", + "AsyncVersionsWithRawResponse", + "VersionsWithStreamingResponse", + "AsyncVersionsWithStreamingResponse", +] diff --git a/src/openai/resources/skills/versions/content.py b/src/openai/resources/skills/versions/content.py new file mode 100644 index 0000000000..4494ca0e2f --- /dev/null +++ b/src/openai/resources/skills/versions/content.py @@ -0,0 +1,177 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from .... import _legacy_response +from ...._types import Body, Query, Headers, NotGiven, not_given +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + StreamedBinaryAPIResponse, + AsyncStreamedBinaryAPIResponse, + to_custom_streamed_response_wrapper, + async_to_custom_streamed_response_wrapper, +) +from ...._base_client import make_request_options + +__all__ = ["Content", "AsyncContent"] + + +class Content(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ContentWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return ContentWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ContentWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return ContentWithStreamingResponse(self) + + def retrieve( + self, + version: str, + *, + skill_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> _legacy_response.HttpxBinaryResponseContent: + """ + Get Skill Version Content + + Args: + version: The skill version number. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not skill_id: + raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") + if not version: + raise ValueError(f"Expected a non-empty value for `version` but received {version!r}") + extra_headers = {"Accept": "application/binary", **(extra_headers or {})} + return self._get( + f"/skills/{skill_id}/versions/{version}/content", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=_legacy_response.HttpxBinaryResponseContent, + ) + + +class AsyncContent(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncContentWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncContentWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncContentWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncContentWithStreamingResponse(self) + + async def retrieve( + self, + version: str, + *, + skill_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> _legacy_response.HttpxBinaryResponseContent: + """ + Get Skill Version Content + + Args: + version: The skill version number. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not skill_id: + raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") + if not version: + raise ValueError(f"Expected a non-empty value for `version` but received {version!r}") + extra_headers = {"Accept": "application/binary", **(extra_headers or {})} + return await self._get( + f"/skills/{skill_id}/versions/{version}/content", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=_legacy_response.HttpxBinaryResponseContent, + ) + + +class ContentWithRawResponse: + def __init__(self, content: Content) -> None: + self._content = content + + self.retrieve = _legacy_response.to_raw_response_wrapper( + content.retrieve, + ) + + +class AsyncContentWithRawResponse: + def __init__(self, content: AsyncContent) -> None: + self._content = content + + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + content.retrieve, + ) + + +class ContentWithStreamingResponse: + def __init__(self, content: Content) -> None: + self._content = content + + self.retrieve = to_custom_streamed_response_wrapper( + content.retrieve, + StreamedBinaryAPIResponse, + ) + + +class AsyncContentWithStreamingResponse: + def __init__(self, content: AsyncContent) -> None: + self._content = content + + self.retrieve = async_to_custom_streamed_response_wrapper( + content.retrieve, + AsyncStreamedBinaryAPIResponse, + ) diff --git a/src/openai/resources/skills/versions/versions.py b/src/openai/resources/skills/versions/versions.py new file mode 100644 index 0000000000..890a20774e --- /dev/null +++ b/src/openai/resources/skills/versions/versions.py @@ -0,0 +1,544 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Mapping, cast +from typing_extensions import Literal + +import httpx + +from .... import _legacy_response +from .content import ( + Content, + AsyncContent, + ContentWithRawResponse, + AsyncContentWithRawResponse, + ContentWithStreamingResponse, + AsyncContentWithStreamingResponse, +) +from ...._types import ( + Body, + Omit, + Query, + Headers, + NotGiven, + FileTypes, + SequenceNotStr, + omit, + not_given, +) +from ...._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ....pagination import SyncCursorPage, AsyncCursorPage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.skills import version_list_params, version_create_params +from ....types.skills.skill_version import SkillVersion +from ....types.skills.deleted_skill_version import DeletedSkillVersion + +__all__ = ["Versions", "AsyncVersions"] + + +class Versions(SyncAPIResource): + @cached_property + def content(self) -> Content: + return Content(self._client) + + @cached_property + def with_raw_response(self) -> VersionsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return VersionsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> VersionsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return VersionsWithStreamingResponse(self) + + def create( + self, + skill_id: str, + *, + default: bool | Omit = omit, + files: Union[SequenceNotStr[FileTypes], FileTypes] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SkillVersion: + """ + Create Skill Version + + Args: + default: Whether to set this version as the default. + + files: Skill files to upload (directory upload) or a single zip file. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not skill_id: + raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") + body = deepcopy_minimal( + { + "default": default, + "files": files, + } + ) + extracted_files = extract_files(cast(Mapping[str, object], body), paths=[["files", ""], ["files"]]) + if extracted_files: + # It should be noted that the actual Content-Type header that will be + # sent to the server will contain a `boundary` parameter, e.g. + # multipart/form-data; boundary=---abc-- + extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} + return self._post( + f"/skills/{skill_id}/versions", + body=maybe_transform(body, version_create_params.VersionCreateParams), + files=extracted_files, + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SkillVersion, + ) + + def retrieve( + self, + version: str, + *, + skill_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SkillVersion: + """ + Get Skill Version + + Args: + version: The version number to retrieve. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not skill_id: + raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") + if not version: + raise ValueError(f"Expected a non-empty value for `version` but received {version!r}") + return self._get( + f"/skills/{skill_id}/versions/{version}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SkillVersion, + ) + + def list( + self, + skill_id: str, + *, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncCursorPage[SkillVersion]: + """ + List Skill Versions + + Args: + after: The skill version ID to start after. + + limit: Number of versions to retrieve. + + order: Sort order of results by version number. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not skill_id: + raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") + return self._get_api_list( + f"/skills/{skill_id}/versions", + page=SyncCursorPage[SkillVersion], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + version_list_params.VersionListParams, + ), + ), + model=SkillVersion, + ) + + def delete( + self, + version: str, + *, + skill_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DeletedSkillVersion: + """ + Delete Skill Version + + Args: + version: The skill version number. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not skill_id: + raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") + if not version: + raise ValueError(f"Expected a non-empty value for `version` but received {version!r}") + return self._delete( + f"/skills/{skill_id}/versions/{version}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DeletedSkillVersion, + ) + + +class AsyncVersions(AsyncAPIResource): + @cached_property + def content(self) -> AsyncContent: + return AsyncContent(self._client) + + @cached_property + def with_raw_response(self) -> AsyncVersionsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncVersionsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncVersionsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncVersionsWithStreamingResponse(self) + + async def create( + self, + skill_id: str, + *, + default: bool | Omit = omit, + files: Union[SequenceNotStr[FileTypes], FileTypes] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SkillVersion: + """ + Create Skill Version + + Args: + default: Whether to set this version as the default. + + files: Skill files to upload (directory upload) or a single zip file. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not skill_id: + raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") + body = deepcopy_minimal( + { + "default": default, + "files": files, + } + ) + extracted_files = extract_files(cast(Mapping[str, object], body), paths=[["files", ""], ["files"]]) + if extracted_files: + # It should be noted that the actual Content-Type header that will be + # sent to the server will contain a `boundary` parameter, e.g. + # multipart/form-data; boundary=---abc-- + extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} + return await self._post( + f"/skills/{skill_id}/versions", + body=await async_maybe_transform(body, version_create_params.VersionCreateParams), + files=extracted_files, + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SkillVersion, + ) + + async def retrieve( + self, + version: str, + *, + skill_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SkillVersion: + """ + Get Skill Version + + Args: + version: The version number to retrieve. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not skill_id: + raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") + if not version: + raise ValueError(f"Expected a non-empty value for `version` but received {version!r}") + return await self._get( + f"/skills/{skill_id}/versions/{version}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SkillVersion, + ) + + def list( + self, + skill_id: str, + *, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[SkillVersion, AsyncCursorPage[SkillVersion]]: + """ + List Skill Versions + + Args: + after: The skill version ID to start after. + + limit: Number of versions to retrieve. + + order: Sort order of results by version number. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not skill_id: + raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") + return self._get_api_list( + f"/skills/{skill_id}/versions", + page=AsyncCursorPage[SkillVersion], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + version_list_params.VersionListParams, + ), + ), + model=SkillVersion, + ) + + async def delete( + self, + version: str, + *, + skill_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DeletedSkillVersion: + """ + Delete Skill Version + + Args: + version: The skill version number. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not skill_id: + raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") + if not version: + raise ValueError(f"Expected a non-empty value for `version` but received {version!r}") + return await self._delete( + f"/skills/{skill_id}/versions/{version}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DeletedSkillVersion, + ) + + +class VersionsWithRawResponse: + def __init__(self, versions: Versions) -> None: + self._versions = versions + + self.create = _legacy_response.to_raw_response_wrapper( + versions.create, + ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + versions.retrieve, + ) + self.list = _legacy_response.to_raw_response_wrapper( + versions.list, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + versions.delete, + ) + + @cached_property + def content(self) -> ContentWithRawResponse: + return ContentWithRawResponse(self._versions.content) + + +class AsyncVersionsWithRawResponse: + def __init__(self, versions: AsyncVersions) -> None: + self._versions = versions + + self.create = _legacy_response.async_to_raw_response_wrapper( + versions.create, + ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + versions.retrieve, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + versions.list, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + versions.delete, + ) + + @cached_property + def content(self) -> AsyncContentWithRawResponse: + return AsyncContentWithRawResponse(self._versions.content) + + +class VersionsWithStreamingResponse: + def __init__(self, versions: Versions) -> None: + self._versions = versions + + self.create = to_streamed_response_wrapper( + versions.create, + ) + self.retrieve = to_streamed_response_wrapper( + versions.retrieve, + ) + self.list = to_streamed_response_wrapper( + versions.list, + ) + self.delete = to_streamed_response_wrapper( + versions.delete, + ) + + @cached_property + def content(self) -> ContentWithStreamingResponse: + return ContentWithStreamingResponse(self._versions.content) + + +class AsyncVersionsWithStreamingResponse: + def __init__(self, versions: AsyncVersions) -> None: + self._versions = versions + + self.create = async_to_streamed_response_wrapper( + versions.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + versions.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + versions.list, + ) + self.delete = async_to_streamed_response_wrapper( + versions.delete, + ) + + @cached_property + def content(self) -> AsyncContentWithStreamingResponse: + return AsyncContentWithStreamingResponse(self._versions.content) diff --git a/src/openai/types/__init__.py b/src/openai/types/__init__.py index 5eb267e845..9190bc146c 100644 --- a/src/openai/types/__init__.py +++ b/src/openai/types/__init__.py @@ -5,6 +5,7 @@ from .batch import Batch as Batch from .image import Image as Image from .model import Model as Model +from .skill import Skill as Skill from .video import Video as Video from .shared import ( Metadata as Metadata, @@ -30,6 +31,7 @@ from .chat_model import ChatModel as ChatModel from .completion import Completion as Completion from .moderation import Moderation as Moderation +from .skill_list import SkillList as SkillList from .video_size import VideoSize as VideoSize from .audio_model import AudioModel as AudioModel from .batch_error import BatchError as BatchError @@ -41,6 +43,7 @@ from .file_deleted import FileDeleted as FileDeleted from .file_purpose import FilePurpose as FilePurpose from .vector_store import VectorStore as VectorStore +from .deleted_skill import DeletedSkill as DeletedSkill from .model_deleted import ModelDeleted as ModelDeleted from .video_seconds import VideoSeconds as VideoSeconds from .embedding_model import EmbeddingModel as EmbeddingModel @@ -52,6 +55,7 @@ from .batch_list_params import BatchListParams as BatchListParams from .completion_choice import CompletionChoice as CompletionChoice from .image_edit_params import ImageEditParams as ImageEditParams +from .skill_list_params import SkillListParams as SkillListParams from .video_list_params import VideoListParams as VideoListParams from .video_model_param import VideoModelParam as VideoModelParam from .eval_create_params import EvalCreateParams as EvalCreateParams @@ -61,6 +65,8 @@ from .video_create_error import VideoCreateError as VideoCreateError from .video_remix_params import VideoRemixParams as VideoRemixParams from .batch_create_params import BatchCreateParams as BatchCreateParams +from .skill_create_params import SkillCreateParams as SkillCreateParams +from .skill_update_params import SkillUpdateParams as SkillUpdateParams from .video_create_params import VideoCreateParams as VideoCreateParams from .batch_request_counts import BatchRequestCounts as BatchRequestCounts from .eval_create_response import EvalCreateResponse as EvalCreateResponse diff --git a/src/openai/types/deleted_skill.py b/src/openai/types/deleted_skill.py new file mode 100644 index 0000000000..6f02f58ca4 --- /dev/null +++ b/src/openai/types/deleted_skill.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["DeletedSkill"] + + +class DeletedSkill(BaseModel): + id: str + + deleted: bool + + object: Literal["skill.deleted"] diff --git a/src/openai/types/image_edit_params.py b/src/openai/types/image_edit_params.py index 916fbc1411..05f3401d2d 100644 --- a/src/openai/types/image_edit_params.py +++ b/src/openai/types/image_edit_params.py @@ -17,7 +17,8 @@ class ImageEditParamsBase(TypedDict, total=False): For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, and `gpt-image-1.5`), each image should be a `png`, `webp`, or `jpg` file less than - 50MB. You can provide up to 16 images. + 50MB. You can provide up to 16 images. `chatgpt-image-latest` follows the same + input constraints as GPT image models. For `dall-e-2`, you can only provide one image, and it should be a square `png` file less than 4MB. @@ -58,11 +59,7 @@ class ImageEditParamsBase(TypedDict, total=False): """ model: Union[str, ImageModel, None] - """The model to use for image generation. - - Only `dall-e-2` and the GPT image models are supported. Defaults to `dall-e-2` - unless a parameter specific to the GPT image models is used. - """ + """The model to use for image generation. Defaults to `gpt-image-1.5`.""" n: Optional[int] """The number of images to generate. Must be between 1 and 10.""" @@ -93,18 +90,18 @@ class ImageEditParamsBase(TypedDict, total=False): """ quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] - """The quality of the image that will be generated. + """The quality of the image that will be generated for GPT image models. - `high`, `medium` and `low` are only supported for the GPT image models. - `dall-e-2` only supports `standard` quality. Defaults to `auto`. + Defaults to `auto`. """ response_format: Optional[Literal["url", "b64_json"]] """The format in which the generated images are returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes after the - image has been generated. This parameter is only supported for `dall-e-2`, as - the GPT image models always return base64-encoded images. + image has been generated. This parameter is only supported for `dall-e-2` + (default is `url` for `dall-e-2`), as GPT image models always return + base64-encoded images. """ size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] diff --git a/src/openai/types/responses/__init__.py b/src/openai/types/responses/__init__.py index a4d939d9ff..cbb8deae95 100644 --- a/src/openai/types/responses/__init__.py +++ b/src/openai/types/responses/__init__.py @@ -6,9 +6,12 @@ from .response import Response as Response from .tool_param import ToolParam as ToolParam from .custom_tool import CustomTool as CustomTool +from .local_skill import LocalSkill as LocalSkill +from .inline_skill import InlineSkill as InlineSkill from .computer_tool import ComputerTool as ComputerTool from .function_tool import FunctionTool as FunctionTool from .response_item import ResponseItem as ResponseItem +from .container_auto import ContainerAuto as ContainerAuto from .response_error import ResponseError as ResponseError from .response_usage import ResponseUsage as ResponseUsage from .parsed_response import ( @@ -21,26 +24,33 @@ ) from .response_prompt import ResponsePrompt as ResponsePrompt from .response_status import ResponseStatus as ResponseStatus +from .skill_reference import SkillReference as SkillReference from .tool_choice_mcp import ToolChoiceMcp as ToolChoiceMcp from .web_search_tool import WebSearchTool as WebSearchTool from .apply_patch_tool import ApplyPatchTool as ApplyPatchTool from .file_search_tool import FileSearchTool as FileSearchTool from .custom_tool_param import CustomToolParam as CustomToolParam +from .local_environment import LocalEnvironment as LocalEnvironment +from .local_skill_param import LocalSkillParam as LocalSkillParam from .tool_choice_shell import ToolChoiceShell as ToolChoiceShell from .tool_choice_types import ToolChoiceTypes as ToolChoiceTypes from .compacted_response import CompactedResponse as CompactedResponse from .easy_input_message import EasyInputMessage as EasyInputMessage +from .inline_skill_param import InlineSkillParam as InlineSkillParam from .response_item_list import ResponseItemList as ResponseItemList from .tool_choice_custom import ToolChoiceCustom as ToolChoiceCustom from .computer_tool_param import ComputerToolParam as ComputerToolParam +from .container_reference import ContainerReference as ContainerReference from .function_shell_tool import FunctionShellTool as FunctionShellTool from .function_tool_param import FunctionToolParam as FunctionToolParam +from .inline_skill_source import InlineSkillSource as InlineSkillSource from .response_includable import ResponseIncludable as ResponseIncludable from .response_input_file import ResponseInputFile as ResponseInputFile from .response_input_item import ResponseInputItem as ResponseInputItem from .response_input_text import ResponseInputText as ResponseInputText from .tool_choice_allowed import ToolChoiceAllowed as ToolChoiceAllowed from .tool_choice_options import ToolChoiceOptions as ToolChoiceOptions +from .container_auto_param import ContainerAutoParam as ContainerAutoParam from .response_error_event import ResponseErrorEvent as ResponseErrorEvent from .response_input_audio import ResponseInputAudio as ResponseInputAudio from .response_input_image import ResponseInputImage as ResponseInputImage @@ -53,6 +63,7 @@ from .response_prompt_param import ResponsePromptParam as ResponsePromptParam from .response_queued_event import ResponseQueuedEvent as ResponseQueuedEvent from .response_stream_event import ResponseStreamEvent as ResponseStreamEvent +from .skill_reference_param import SkillReferenceParam as SkillReferenceParam from .tool_choice_mcp_param import ToolChoiceMcpParam as ToolChoiceMcpParam from .web_search_tool_param import WebSearchToolParam as WebSearchToolParam from .apply_patch_tool_param import ApplyPatchToolParam as ApplyPatchToolParam @@ -61,6 +72,7 @@ from .response_create_params import ResponseCreateParams as ResponseCreateParams from .response_created_event import ResponseCreatedEvent as ResponseCreatedEvent from .response_input_content import ResponseInputContent as ResponseInputContent +from .local_environment_param import LocalEnvironmentParam as LocalEnvironmentParam from .response_compact_params import ResponseCompactParams as ResponseCompactParams from .response_output_message import ResponseOutputMessage as ResponseOutputMessage from .response_output_refusal import ResponseOutputRefusal as ResponseOutputRefusal @@ -76,7 +88,9 @@ from .response_retrieve_params import ResponseRetrieveParams as ResponseRetrieveParams from .response_text_done_event import ResponseTextDoneEvent as ResponseTextDoneEvent from .tool_choice_custom_param import ToolChoiceCustomParam as ToolChoiceCustomParam +from .container_reference_param import ContainerReferenceParam as ContainerReferenceParam from .function_shell_tool_param import FunctionShellToolParam as FunctionShellToolParam +from .inline_skill_source_param import InlineSkillSourceParam as InlineSkillSourceParam from .response_audio_done_event import ResponseAudioDoneEvent as ResponseAudioDoneEvent from .response_custom_tool_call import ResponseCustomToolCall as ResponseCustomToolCall from .response_incomplete_event import ResponseIncompleteEvent as ResponseIncompleteEvent @@ -90,6 +104,7 @@ from .response_in_progress_event import ResponseInProgressEvent as ResponseInProgressEvent from .response_input_audio_param import ResponseInputAudioParam as ResponseInputAudioParam from .response_input_image_param import ResponseInputImageParam as ResponseInputImageParam +from .response_local_environment import ResponseLocalEnvironment as ResponseLocalEnvironment from .response_output_text_param import ResponseOutputTextParam as ResponseOutputTextParam from .response_text_config_param import ResponseTextConfigParam as ResponseTextConfigParam from .tool_choice_function_param import ToolChoiceFunctionParam as ToolChoiceFunctionParam @@ -101,6 +116,7 @@ from .response_input_message_item import ResponseInputMessageItem as ResponseInputMessageItem from .response_input_text_content import ResponseInputTextContent as ResponseInputTextContent from .response_refusal_done_event import ResponseRefusalDoneEvent as ResponseRefusalDoneEvent +from .response_container_reference import ResponseContainerReference as ResponseContainerReference from .response_function_web_search import ResponseFunctionWebSearch as ResponseFunctionWebSearch from .response_input_content_param import ResponseInputContentParam as ResponseInputContentParam from .response_input_image_content import ResponseInputImageContent as ResponseInputImageContent @@ -120,6 +136,7 @@ from .response_custom_tool_call_output import ResponseCustomToolCallOutput as ResponseCustomToolCallOutput from .response_function_tool_call_item import ResponseFunctionToolCallItem as ResponseFunctionToolCallItem from .response_output_item_added_event import ResponseOutputItemAddedEvent as ResponseOutputItemAddedEvent +from .container_network_policy_disabled import ContainerNetworkPolicyDisabled as ContainerNetworkPolicyDisabled from .response_computer_tool_call_param import ResponseComputerToolCallParam as ResponseComputerToolCallParam from .response_content_part_added_event import ResponseContentPartAddedEvent as ResponseContentPartAddedEvent from .response_format_text_config_param import ResponseFormatTextConfigParam as ResponseFormatTextConfigParam @@ -128,6 +145,7 @@ from .response_input_file_content_param import ResponseInputFileContentParam as ResponseInputFileContentParam from .response_input_text_content_param import ResponseInputTextContentParam as ResponseInputTextContentParam from .response_mcp_call_completed_event import ResponseMcpCallCompletedEvent as ResponseMcpCallCompletedEvent +from .container_network_policy_allowlist import ContainerNetworkPolicyAllowlist as ContainerNetworkPolicyAllowlist from .response_function_call_output_item import ResponseFunctionCallOutputItem as ResponseFunctionCallOutputItem from .response_function_web_search_param import ResponseFunctionWebSearchParam as ResponseFunctionWebSearchParam from .response_input_image_content_param import ResponseInputImageContentParam as ResponseInputImageContentParam @@ -144,12 +162,18 @@ from .response_audio_transcript_delta_event import ( ResponseAudioTranscriptDeltaEvent as ResponseAudioTranscriptDeltaEvent, ) +from .container_network_policy_domain_secret import ( + ContainerNetworkPolicyDomainSecret as ContainerNetworkPolicyDomainSecret, +) from .response_custom_tool_call_output_param import ( ResponseCustomToolCallOutputParam as ResponseCustomToolCallOutputParam, ) from .response_mcp_call_arguments_done_event import ( ResponseMcpCallArgumentsDoneEvent as ResponseMcpCallArgumentsDoneEvent, ) +from .container_network_policy_disabled_param import ( + ContainerNetworkPolicyDisabledParam as ContainerNetworkPolicyDisabledParam, +) from .response_computer_tool_call_output_item import ( ResponseComputerToolCallOutputItem as ResponseComputerToolCallOutputItem, ) @@ -171,6 +195,9 @@ from .response_mcp_list_tools_completed_event import ( ResponseMcpListToolsCompletedEvent as ResponseMcpListToolsCompletedEvent, ) +from .container_network_policy_allowlist_param import ( + ContainerNetworkPolicyAllowlistParam as ContainerNetworkPolicyAllowlistParam, +) from .response_function_call_output_item_param import ( ResponseFunctionCallOutputItemParam as ResponseFunctionCallOutputItemParam, ) @@ -240,6 +267,9 @@ from .response_reasoning_summary_text_delta_event import ( ResponseReasoningSummaryTextDeltaEvent as ResponseReasoningSummaryTextDeltaEvent, ) +from .container_network_policy_domain_secret_param import ( + ContainerNetworkPolicyDomainSecretParam as ContainerNetworkPolicyDomainSecretParam, +) from .response_function_call_arguments_delta_event import ( ResponseFunctionCallArgumentsDeltaEvent as ResponseFunctionCallArgumentsDeltaEvent, ) diff --git a/src/openai/types/responses/container_auto.py b/src/openai/types/responses/container_auto.py new file mode 100644 index 0000000000..06b8a285bf --- /dev/null +++ b/src/openai/types/responses/container_auto.py @@ -0,0 +1,36 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .inline_skill import InlineSkill +from .skill_reference import SkillReference +from .container_network_policy_disabled import ContainerNetworkPolicyDisabled +from .container_network_policy_allowlist import ContainerNetworkPolicyAllowlist + +__all__ = ["ContainerAuto", "NetworkPolicy", "Skill"] + +NetworkPolicy: TypeAlias = Annotated[ + Union[ContainerNetworkPolicyDisabled, ContainerNetworkPolicyAllowlist], PropertyInfo(discriminator="type") +] + +Skill: TypeAlias = Annotated[Union[SkillReference, InlineSkill], PropertyInfo(discriminator="type")] + + +class ContainerAuto(BaseModel): + type: Literal["container_auto"] + """Automatically creates a container for this request""" + + file_ids: Optional[List[str]] = None + """An optional list of uploaded files to make available to your code.""" + + memory_limit: Optional[Literal["1g", "4g", "16g", "64g"]] = None + """The memory limit for the container.""" + + network_policy: Optional[NetworkPolicy] = None + """Network access policy for the container.""" + + skills: Optional[List[Skill]] = None + """An optional list of skills referenced by id or inline data.""" diff --git a/src/openai/types/responses/container_auto_param.py b/src/openai/types/responses/container_auto_param.py new file mode 100644 index 0000000000..b9e8bb5223 --- /dev/null +++ b/src/openai/types/responses/container_auto_param.py @@ -0,0 +1,35 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from ..._types import SequenceNotStr +from .inline_skill_param import InlineSkillParam +from .skill_reference_param import SkillReferenceParam +from .container_network_policy_disabled_param import ContainerNetworkPolicyDisabledParam +from .container_network_policy_allowlist_param import ContainerNetworkPolicyAllowlistParam + +__all__ = ["ContainerAutoParam", "NetworkPolicy", "Skill"] + +NetworkPolicy: TypeAlias = Union[ContainerNetworkPolicyDisabledParam, ContainerNetworkPolicyAllowlistParam] + +Skill: TypeAlias = Union[SkillReferenceParam, InlineSkillParam] + + +class ContainerAutoParam(TypedDict, total=False): + type: Required[Literal["container_auto"]] + """Automatically creates a container for this request""" + + file_ids: SequenceNotStr[str] + """An optional list of uploaded files to make available to your code.""" + + memory_limit: Optional[Literal["1g", "4g", "16g", "64g"]] + """The memory limit for the container.""" + + network_policy: NetworkPolicy + """Network access policy for the container.""" + + skills: Iterable[Skill] + """An optional list of skills referenced by id or inline data.""" diff --git a/src/openai/types/responses/container_network_policy_allowlist.py b/src/openai/types/responses/container_network_policy_allowlist.py new file mode 100644 index 0000000000..caa2565ea2 --- /dev/null +++ b/src/openai/types/responses/container_network_policy_allowlist.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel +from .container_network_policy_domain_secret import ContainerNetworkPolicyDomainSecret + +__all__ = ["ContainerNetworkPolicyAllowlist"] + + +class ContainerNetworkPolicyAllowlist(BaseModel): + allowed_domains: List[str] + """A list of allowed domains when type is `allowlist`.""" + + type: Literal["allowlist"] + """Allow outbound network access only to specified domains. Always `allowlist`.""" + + domain_secrets: Optional[List[ContainerNetworkPolicyDomainSecret]] = None + """Optional domain-scoped secrets for allowlisted domains.""" diff --git a/src/openai/types/responses/container_network_policy_allowlist_param.py b/src/openai/types/responses/container_network_policy_allowlist_param.py new file mode 100644 index 0000000000..583b761e69 --- /dev/null +++ b/src/openai/types/responses/container_network_policy_allowlist_param.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Literal, Required, TypedDict + +from ..._types import SequenceNotStr +from .container_network_policy_domain_secret_param import ContainerNetworkPolicyDomainSecretParam + +__all__ = ["ContainerNetworkPolicyAllowlistParam"] + + +class ContainerNetworkPolicyAllowlistParam(TypedDict, total=False): + allowed_domains: Required[SequenceNotStr[str]] + """A list of allowed domains when type is `allowlist`.""" + + type: Required[Literal["allowlist"]] + """Allow outbound network access only to specified domains. Always `allowlist`.""" + + domain_secrets: Iterable[ContainerNetworkPolicyDomainSecretParam] + """Optional domain-scoped secrets for allowlisted domains.""" diff --git a/src/openai/types/responses/container_network_policy_disabled.py b/src/openai/types/responses/container_network_policy_disabled.py new file mode 100644 index 0000000000..47891aa338 --- /dev/null +++ b/src/openai/types/responses/container_network_policy_disabled.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ContainerNetworkPolicyDisabled"] + + +class ContainerNetworkPolicyDisabled(BaseModel): + type: Literal["disabled"] + """Disable outbound network access. Always `disabled`.""" diff --git a/src/openai/types/responses/container_network_policy_disabled_param.py b/src/openai/types/responses/container_network_policy_disabled_param.py new file mode 100644 index 0000000000..0db7d8ff79 --- /dev/null +++ b/src/openai/types/responses/container_network_policy_disabled_param.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ContainerNetworkPolicyDisabledParam"] + + +class ContainerNetworkPolicyDisabledParam(TypedDict, total=False): + type: Required[Literal["disabled"]] + """Disable outbound network access. Always `disabled`.""" diff --git a/src/openai/types/responses/container_network_policy_domain_secret.py b/src/openai/types/responses/container_network_policy_domain_secret.py new file mode 100644 index 0000000000..d0e18ba977 --- /dev/null +++ b/src/openai/types/responses/container_network_policy_domain_secret.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["ContainerNetworkPolicyDomainSecret"] + + +class ContainerNetworkPolicyDomainSecret(BaseModel): + domain: str + """The domain associated with the secret.""" + + name: str + """The name of the secret to inject for the domain.""" + + value: str + """The secret value to inject for the domain.""" diff --git a/src/openai/types/responses/container_network_policy_domain_secret_param.py b/src/openai/types/responses/container_network_policy_domain_secret_param.py new file mode 100644 index 0000000000..619fbde7a2 --- /dev/null +++ b/src/openai/types/responses/container_network_policy_domain_secret_param.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["ContainerNetworkPolicyDomainSecretParam"] + + +class ContainerNetworkPolicyDomainSecretParam(TypedDict, total=False): + domain: Required[str] + """The domain associated with the secret.""" + + name: Required[str] + """The name of the secret to inject for the domain.""" + + value: Required[str] + """The secret value to inject for the domain.""" diff --git a/src/openai/types/responses/container_reference.py b/src/openai/types/responses/container_reference.py new file mode 100644 index 0000000000..17065bf30a --- /dev/null +++ b/src/openai/types/responses/container_reference.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ContainerReference"] + + +class ContainerReference(BaseModel): + container_id: str + """The ID of the referenced container.""" + + type: Literal["container_reference"] + """References a container created with the /v1/containers endpoint""" diff --git a/src/openai/types/responses/container_reference_param.py b/src/openai/types/responses/container_reference_param.py new file mode 100644 index 0000000000..1da2fb6763 --- /dev/null +++ b/src/openai/types/responses/container_reference_param.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ContainerReferenceParam"] + + +class ContainerReferenceParam(TypedDict, total=False): + container_id: Required[str] + """The ID of the referenced container.""" + + type: Required[Literal["container_reference"]] + """References a container created with the /v1/containers endpoint""" diff --git a/src/openai/types/responses/function_shell_tool.py b/src/openai/types/responses/function_shell_tool.py index 5b237aa705..17d6bb36c9 100644 --- a/src/openai/types/responses/function_shell_tool.py +++ b/src/openai/types/responses/function_shell_tool.py @@ -1,10 +1,19 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing_extensions import Literal +from typing import Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias +from ..._utils import PropertyInfo from ..._models import BaseModel +from .container_auto import ContainerAuto +from .local_environment import LocalEnvironment +from .container_reference import ContainerReference -__all__ = ["FunctionShellTool"] +__all__ = ["FunctionShellTool", "Environment"] + +Environment: TypeAlias = Annotated[ + Union[ContainerAuto, LocalEnvironment, ContainerReference, None], PropertyInfo(discriminator="type") +] class FunctionShellTool(BaseModel): @@ -12,3 +21,5 @@ class FunctionShellTool(BaseModel): type: Literal["shell"] """The type of the shell tool. Always `shell`.""" + + environment: Optional[Environment] = None diff --git a/src/openai/types/responses/function_shell_tool_param.py b/src/openai/types/responses/function_shell_tool_param.py index c640ddab99..b8464ed341 100644 --- a/src/openai/types/responses/function_shell_tool_param.py +++ b/src/openai/types/responses/function_shell_tool_param.py @@ -2,9 +2,16 @@ from __future__ import annotations -from typing_extensions import Literal, Required, TypedDict +from typing import Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict -__all__ = ["FunctionShellToolParam"] +from .container_auto_param import ContainerAutoParam +from .local_environment_param import LocalEnvironmentParam +from .container_reference_param import ContainerReferenceParam + +__all__ = ["FunctionShellToolParam", "Environment"] + +Environment: TypeAlias = Union[ContainerAutoParam, LocalEnvironmentParam, ContainerReferenceParam] class FunctionShellToolParam(TypedDict, total=False): @@ -12,3 +19,5 @@ class FunctionShellToolParam(TypedDict, total=False): type: Required[Literal["shell"]] """The type of the shell tool. Always `shell`.""" + + environment: Optional[Environment] diff --git a/src/openai/types/responses/inline_skill.py b/src/openai/types/responses/inline_skill.py new file mode 100644 index 0000000000..87c7ca5f7a --- /dev/null +++ b/src/openai/types/responses/inline_skill.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel +from .inline_skill_source import InlineSkillSource + +__all__ = ["InlineSkill"] + + +class InlineSkill(BaseModel): + description: str + """The description of the skill.""" + + name: str + """The name of the skill.""" + + source: InlineSkillSource + """Inline skill payload""" + + type: Literal["inline"] + """Defines an inline skill for this request.""" diff --git a/src/openai/types/responses/inline_skill_param.py b/src/openai/types/responses/inline_skill_param.py new file mode 100644 index 0000000000..f9181693be --- /dev/null +++ b/src/openai/types/responses/inline_skill_param.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +from .inline_skill_source_param import InlineSkillSourceParam + +__all__ = ["InlineSkillParam"] + + +class InlineSkillParam(TypedDict, total=False): + description: Required[str] + """The description of the skill.""" + + name: Required[str] + """The name of the skill.""" + + source: Required[InlineSkillSourceParam] + """Inline skill payload""" + + type: Required[Literal["inline"]] + """Defines an inline skill for this request.""" diff --git a/src/openai/types/responses/inline_skill_source.py b/src/openai/types/responses/inline_skill_source.py new file mode 100644 index 0000000000..2586cdb008 --- /dev/null +++ b/src/openai/types/responses/inline_skill_source.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["InlineSkillSource"] + + +class InlineSkillSource(BaseModel): + """Inline skill payload""" + + data: str + """Base64-encoded skill zip bundle.""" + + media_type: Literal["application/zip"] + """The media type of the inline skill payload. Must be `application/zip`.""" + + type: Literal["base64"] + """The type of the inline skill source. Must be `base64`.""" diff --git a/src/openai/types/responses/inline_skill_source_param.py b/src/openai/types/responses/inline_skill_source_param.py new file mode 100644 index 0000000000..b14e63e2af --- /dev/null +++ b/src/openai/types/responses/inline_skill_source_param.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["InlineSkillSourceParam"] + + +class InlineSkillSourceParam(TypedDict, total=False): + """Inline skill payload""" + + data: Required[str] + """Base64-encoded skill zip bundle.""" + + media_type: Required[Literal["application/zip"]] + """The media type of the inline skill payload. Must be `application/zip`.""" + + type: Required[Literal["base64"]] + """The type of the inline skill source. Must be `base64`.""" diff --git a/src/openai/types/responses/local_environment.py b/src/openai/types/responses/local_environment.py new file mode 100644 index 0000000000..3ebdaa7e2a --- /dev/null +++ b/src/openai/types/responses/local_environment.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel +from .local_skill import LocalSkill + +__all__ = ["LocalEnvironment"] + + +class LocalEnvironment(BaseModel): + type: Literal["local"] + """Use a local computer environment.""" + + skills: Optional[List[LocalSkill]] = None + """An optional list of skills.""" diff --git a/src/openai/types/responses/local_environment_param.py b/src/openai/types/responses/local_environment_param.py new file mode 100644 index 0000000000..0ed1e81ffc --- /dev/null +++ b/src/openai/types/responses/local_environment_param.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Literal, Required, TypedDict + +from .local_skill_param import LocalSkillParam + +__all__ = ["LocalEnvironmentParam"] + + +class LocalEnvironmentParam(TypedDict, total=False): + type: Required[Literal["local"]] + """Use a local computer environment.""" + + skills: Iterable[LocalSkillParam] + """An optional list of skills.""" diff --git a/src/openai/types/responses/local_skill.py b/src/openai/types/responses/local_skill.py new file mode 100644 index 0000000000..1033c319d4 --- /dev/null +++ b/src/openai/types/responses/local_skill.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["LocalSkill"] + + +class LocalSkill(BaseModel): + description: str + """The description of the skill.""" + + name: str + """The name of the skill.""" + + path: str + """The path to the directory containing the skill.""" diff --git a/src/openai/types/responses/local_skill_param.py b/src/openai/types/responses/local_skill_param.py new file mode 100644 index 0000000000..63011a49aa --- /dev/null +++ b/src/openai/types/responses/local_skill_param.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["LocalSkillParam"] + + +class LocalSkillParam(TypedDict, total=False): + description: Required[str] + """The description of the skill.""" + + name: Required[str] + """The name of the skill.""" + + path: Required[str] + """The path to the directory containing the skill.""" diff --git a/src/openai/types/responses/response_container_reference.py b/src/openai/types/responses/response_container_reference.py new file mode 100644 index 0000000000..81f5bd8dad --- /dev/null +++ b/src/openai/types/responses/response_container_reference.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseContainerReference"] + + +class ResponseContainerReference(BaseModel): + """Represents a container created with /v1/containers.""" + + container_id: str + + type: Literal["container_reference"] + """The environment type. Always `container_reference`.""" diff --git a/src/openai/types/responses/response_function_shell_tool_call.py b/src/openai/types/responses/response_function_shell_tool_call.py index 7c6a184ed4..22c75cf043 100644 --- a/src/openai/types/responses/response_function_shell_tool_call.py +++ b/src/openai/types/responses/response_function_shell_tool_call.py @@ -1,11 +1,14 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Optional -from typing_extensions import Literal +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias +from ..._utils import PropertyInfo from ..._models import BaseModel +from .response_local_environment import ResponseLocalEnvironment +from .response_container_reference import ResponseContainerReference -__all__ = ["ResponseFunctionShellToolCall", "Action"] +__all__ = ["ResponseFunctionShellToolCall", "Action", "Environment"] class Action(BaseModel): @@ -20,6 +23,11 @@ class Action(BaseModel): """Optional timeout in milliseconds for the commands.""" +Environment: TypeAlias = Annotated[ + Union[ResponseLocalEnvironment, ResponseContainerReference, None], PropertyInfo(discriminator="type") +] + + class ResponseFunctionShellToolCall(BaseModel): """A tool call that executes one or more shell commands in a managed environment.""" @@ -35,6 +43,9 @@ class ResponseFunctionShellToolCall(BaseModel): call_id: str """The unique ID of the shell tool call generated by the model.""" + environment: Optional[Environment] = None + """Represents the use of a local environment to perform shell actions.""" + status: Literal["in_progress", "completed", "incomplete"] """The status of the shell call. diff --git a/src/openai/types/responses/response_input_item.py b/src/openai/types/responses/response_input_item.py index e1f521f957..2b664fd875 100644 --- a/src/openai/types/responses/response_input_item.py +++ b/src/openai/types/responses/response_input_item.py @@ -5,7 +5,9 @@ from ..._utils import PropertyInfo from ..._models import BaseModel +from .local_environment import LocalEnvironment from .easy_input_message import EasyInputMessage +from .container_reference import ContainerReference from .response_output_message import ResponseOutputMessage from .response_reasoning_item import ResponseReasoningItem from .response_custom_tool_call import ResponseCustomToolCall @@ -33,6 +35,7 @@ "LocalShellCallOutput", "ShellCall", "ShellCallAction", + "ShellCallEnvironment", "ShellCallOutput", "ApplyPatchCall", "ApplyPatchCallOperation", @@ -233,6 +236,11 @@ class ShellCallAction(BaseModel): """Maximum wall-clock time in milliseconds to allow the shell commands to run.""" +ShellCallEnvironment: TypeAlias = Annotated[ + Union[LocalEnvironment, ContainerReference, None], PropertyInfo(discriminator="type") +] + + class ShellCall(BaseModel): """A tool representing a request to execute one or more shell commands.""" @@ -251,6 +259,9 @@ class ShellCall(BaseModel): Populated when this item is returned via API. """ + environment: Optional[ShellCallEnvironment] = None + """The environment to execute the shell commands in.""" + status: Optional[Literal["in_progress", "completed", "incomplete"]] = None """The status of the shell call. diff --git a/src/openai/types/responses/response_input_item_param.py b/src/openai/types/responses/response_input_item_param.py index 03fe86c42c..f52a7495db 100644 --- a/src/openai/types/responses/response_input_item_param.py +++ b/src/openai/types/responses/response_input_item_param.py @@ -6,7 +6,9 @@ from typing_extensions import Literal, Required, TypeAlias, TypedDict from ..._types import SequenceNotStr +from .local_environment_param import LocalEnvironmentParam from .easy_input_message_param import EasyInputMessageParam +from .container_reference_param import ContainerReferenceParam from .response_output_message_param import ResponseOutputMessageParam from .response_reasoning_item_param import ResponseReasoningItemParam from .response_custom_tool_call_param import ResponseCustomToolCallParam @@ -34,6 +36,7 @@ "LocalShellCallOutput", "ShellCall", "ShellCallAction", + "ShellCallEnvironment", "ShellCallOutput", "ApplyPatchCall", "ApplyPatchCallOperation", @@ -234,6 +237,9 @@ class ShellCallAction(TypedDict, total=False): """Maximum wall-clock time in milliseconds to allow the shell commands to run.""" +ShellCallEnvironment: TypeAlias = Union[LocalEnvironmentParam, ContainerReferenceParam] + + class ShellCall(TypedDict, total=False): """A tool representing a request to execute one or more shell commands.""" @@ -252,6 +258,9 @@ class ShellCall(TypedDict, total=False): Populated when this item is returned via API. """ + environment: Optional[ShellCallEnvironment] + """The environment to execute the shell commands in.""" + status: Optional[Literal["in_progress", "completed", "incomplete"]] """The status of the shell call. diff --git a/src/openai/types/responses/response_input_param.py b/src/openai/types/responses/response_input_param.py index 5be65b3e14..c125d03f84 100644 --- a/src/openai/types/responses/response_input_param.py +++ b/src/openai/types/responses/response_input_param.py @@ -6,7 +6,9 @@ from typing_extensions import Literal, Required, TypeAlias, TypedDict from ..._types import SequenceNotStr +from .local_environment_param import LocalEnvironmentParam from .easy_input_message_param import EasyInputMessageParam +from .container_reference_param import ContainerReferenceParam from .response_output_message_param import ResponseOutputMessageParam from .response_reasoning_item_param import ResponseReasoningItemParam from .response_custom_tool_call_param import ResponseCustomToolCallParam @@ -35,6 +37,7 @@ "LocalShellCallOutput", "ShellCall", "ShellCallAction", + "ShellCallEnvironment", "ShellCallOutput", "ApplyPatchCall", "ApplyPatchCallOperation", @@ -235,6 +238,9 @@ class ShellCallAction(TypedDict, total=False): """Maximum wall-clock time in milliseconds to allow the shell commands to run.""" +ShellCallEnvironment: TypeAlias = Union[LocalEnvironmentParam, ContainerReferenceParam] + + class ShellCall(TypedDict, total=False): """A tool representing a request to execute one or more shell commands.""" @@ -253,6 +259,9 @@ class ShellCall(TypedDict, total=False): Populated when this item is returned via API. """ + environment: Optional[ShellCallEnvironment] + """The environment to execute the shell commands in.""" + status: Optional[Literal["in_progress", "completed", "incomplete"]] """The status of the shell call. diff --git a/src/openai/types/responses/response_local_environment.py b/src/openai/types/responses/response_local_environment.py new file mode 100644 index 0000000000..6467fcb4c5 --- /dev/null +++ b/src/openai/types/responses/response_local_environment.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseLocalEnvironment"] + + +class ResponseLocalEnvironment(BaseModel): + """Represents the use of a local environment to perform shell actions.""" + + type: Literal["local"] + """The environment type. Always `local`.""" diff --git a/src/openai/types/responses/skill_reference.py b/src/openai/types/responses/skill_reference.py new file mode 100644 index 0000000000..76e614ab6c --- /dev/null +++ b/src/openai/types/responses/skill_reference.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["SkillReference"] + + +class SkillReference(BaseModel): + skill_id: str + """The ID of the referenced skill.""" + + type: Literal["skill_reference"] + """References a skill created with the /v1/skills endpoint.""" + + version: Optional[str] = None + """Optional skill version. Use a positive integer or 'latest'. Omit for default.""" diff --git a/src/openai/types/responses/skill_reference_param.py b/src/openai/types/responses/skill_reference_param.py new file mode 100644 index 0000000000..33b572854d --- /dev/null +++ b/src/openai/types/responses/skill_reference_param.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["SkillReferenceParam"] + + +class SkillReferenceParam(TypedDict, total=False): + skill_id: Required[str] + """The ID of the referenced skill.""" + + type: Required[Literal["skill_reference"]] + """References a skill created with the /v1/skills endpoint.""" + + version: str + """Optional skill version. Use a positive integer or 'latest'. Omit for default.""" diff --git a/src/openai/types/responses/tool.py b/src/openai/types/responses/tool.py index bd266ea753..a98b4ca758 100644 --- a/src/openai/types/responses/tool.py +++ b/src/openai/types/responses/tool.py @@ -14,6 +14,8 @@ from .file_search_tool import FileSearchTool from .function_shell_tool import FunctionShellTool from .web_search_preview_tool import WebSearchPreviewTool +from .container_network_policy_disabled import ContainerNetworkPolicyDisabled +from .container_network_policy_allowlist import ContainerNetworkPolicyAllowlist __all__ = [ "Tool", @@ -28,6 +30,7 @@ "CodeInterpreter", "CodeInterpreterContainer", "CodeInterpreterContainerCodeInterpreterToolAuto", + "CodeInterpreterContainerCodeInterpreterToolAutoNetworkPolicy", "ImageGeneration", "ImageGenerationInputImageMask", "LocalShell", @@ -174,6 +177,11 @@ class Mcp(BaseModel): """ +CodeInterpreterContainerCodeInterpreterToolAutoNetworkPolicy: TypeAlias = Annotated[ + Union[ContainerNetworkPolicyDisabled, ContainerNetworkPolicyAllowlist], PropertyInfo(discriminator="type") +] + + class CodeInterpreterContainerCodeInterpreterToolAuto(BaseModel): """Configuration for a code interpreter container. @@ -189,6 +197,9 @@ class CodeInterpreterContainerCodeInterpreterToolAuto(BaseModel): memory_limit: Optional[Literal["1g", "4g", "16g", "64g"]] = None """The memory limit for the code interpreter container.""" + network_policy: Optional[CodeInterpreterContainerCodeInterpreterToolAutoNetworkPolicy] = None + """Network access policy for the container.""" + CodeInterpreterContainer: TypeAlias = Union[str, CodeInterpreterContainerCodeInterpreterToolAuto] diff --git a/src/openai/types/responses/tool_param.py b/src/openai/types/responses/tool_param.py index a81c69d3ab..a351065dea 100644 --- a/src/openai/types/responses/tool_param.py +++ b/src/openai/types/responses/tool_param.py @@ -16,6 +16,8 @@ from .file_search_tool_param import FileSearchToolParam from .function_shell_tool_param import FunctionShellToolParam from .web_search_preview_tool_param import WebSearchPreviewToolParam +from .container_network_policy_disabled_param import ContainerNetworkPolicyDisabledParam +from .container_network_policy_allowlist_param import ContainerNetworkPolicyAllowlistParam __all__ = [ "ToolParam", @@ -29,6 +31,7 @@ "CodeInterpreter", "CodeInterpreterContainer", "CodeInterpreterContainerCodeInterpreterToolAuto", + "CodeInterpreterContainerCodeInterpreterToolAutoNetworkPolicy", "ImageGeneration", "ImageGenerationInputImageMask", "LocalShell", @@ -174,6 +177,11 @@ class Mcp(TypedDict, total=False): """ +CodeInterpreterContainerCodeInterpreterToolAutoNetworkPolicy: TypeAlias = Union[ + ContainerNetworkPolicyDisabledParam, ContainerNetworkPolicyAllowlistParam +] + + class CodeInterpreterContainerCodeInterpreterToolAuto(TypedDict, total=False): """Configuration for a code interpreter container. @@ -189,6 +197,9 @@ class CodeInterpreterContainerCodeInterpreterToolAuto(TypedDict, total=False): memory_limit: Optional[Literal["1g", "4g", "16g", "64g"]] """The memory limit for the code interpreter container.""" + network_policy: CodeInterpreterContainerCodeInterpreterToolAutoNetworkPolicy + """Network access policy for the container.""" + CodeInterpreterContainer: TypeAlias = Union[str, CodeInterpreterContainerCodeInterpreterToolAuto] diff --git a/src/openai/types/skill.py b/src/openai/types/skill.py new file mode 100644 index 0000000000..25d74978d8 --- /dev/null +++ b/src/openai/types/skill.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["Skill"] + + +class Skill(BaseModel): + id: str + """Unique identifier for the skill.""" + + created_at: int + """Unix timestamp (seconds) for when the skill was created.""" + + default_version: str + """Default version for the skill.""" + + description: str + """Description of the skill.""" + + latest_version: str + """Latest version for the skill.""" + + name: str + """Name of the skill.""" + + object: Literal["skill"] + """The object type, which is `skill`.""" diff --git a/src/openai/types/skill_create_params.py b/src/openai/types/skill_create_params.py new file mode 100644 index 0000000000..5a709286a1 --- /dev/null +++ b/src/openai/types/skill_create_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import TypedDict + +from .._types import FileTypes, SequenceNotStr + +__all__ = ["SkillCreateParams"] + + +class SkillCreateParams(TypedDict, total=False): + files: Union[SequenceNotStr[FileTypes], FileTypes] + """Skill files to upload (directory upload) or a single zip file.""" diff --git a/src/openai/types/skill_list.py b/src/openai/types/skill_list.py new file mode 100644 index 0000000000..fc5b57bc26 --- /dev/null +++ b/src/openai/types/skill_list.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from .skill import Skill +from .._models import BaseModel + +__all__ = ["SkillList"] + + +class SkillList(BaseModel): + data: List[Skill] + """A list of items""" + + first_id: Optional[str] = None + """The ID of the first item in the list.""" + + has_more: bool + """Whether there are more items available.""" + + last_id: Optional[str] = None + """The ID of the last item in the list.""" + + object: Literal["list"] + """The type of object returned, must be `list`.""" diff --git a/src/openai/types/skill_list_params.py b/src/openai/types/skill_list_params.py new file mode 100644 index 0000000000..ffe7967915 --- /dev/null +++ b/src/openai/types/skill_list_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["SkillListParams"] + + +class SkillListParams(TypedDict, total=False): + after: str + """Identifier for the last item from the previous pagination request""" + + limit: int + """Number of items to retrieve""" + + order: Literal["asc", "desc"] + """Sort order of results by timestamp. + + Use `asc` for ascending order or `desc` for descending order. + """ diff --git a/src/openai/types/skill_update_params.py b/src/openai/types/skill_update_params.py new file mode 100644 index 0000000000..48a790e1fc --- /dev/null +++ b/src/openai/types/skill_update_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["SkillUpdateParams"] + + +class SkillUpdateParams(TypedDict, total=False): + default_version: Required[str] + """The skill version number to set as default.""" diff --git a/src/openai/types/skills/__init__.py b/src/openai/types/skills/__init__.py new file mode 100644 index 0000000000..b0605fb85b --- /dev/null +++ b/src/openai/types/skills/__init__.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .skill_version import SkillVersion as SkillVersion +from .skill_version_list import SkillVersionList as SkillVersionList +from .version_list_params import VersionListParams as VersionListParams +from .deleted_skill_version import DeletedSkillVersion as DeletedSkillVersion +from .version_create_params import VersionCreateParams as VersionCreateParams diff --git a/src/openai/types/skills/deleted_skill_version.py b/src/openai/types/skills/deleted_skill_version.py new file mode 100644 index 0000000000..e1fd8c4985 --- /dev/null +++ b/src/openai/types/skills/deleted_skill_version.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["DeletedSkillVersion"] + + +class DeletedSkillVersion(BaseModel): + id: str + + deleted: bool + + object: Literal["skill.version.deleted"] + + version: str + """The deleted skill version.""" diff --git a/src/openai/types/skills/skill_version.py b/src/openai/types/skills/skill_version.py new file mode 100644 index 0000000000..74b47000a5 --- /dev/null +++ b/src/openai/types/skills/skill_version.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["SkillVersion"] + + +class SkillVersion(BaseModel): + id: str + """Unique identifier for the skill version.""" + + created_at: int + """Unix timestamp (seconds) for when the version was created.""" + + description: str + """Description of the skill version.""" + + name: str + """Name of the skill version.""" + + object: Literal["skill.version"] + """The object type, which is `skill.version`.""" + + skill_id: str + """Identifier of the skill for this version.""" + + version: str + """Version number for this skill.""" diff --git a/src/openai/types/skills/skill_version_list.py b/src/openai/types/skills/skill_version_list.py new file mode 100644 index 0000000000..7d10082f1c --- /dev/null +++ b/src/openai/types/skills/skill_version_list.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel +from .skill_version import SkillVersion + +__all__ = ["SkillVersionList"] + + +class SkillVersionList(BaseModel): + data: List[SkillVersion] + """A list of items""" + + first_id: Optional[str] = None + """The ID of the first item in the list.""" + + has_more: bool + """Whether there are more items available.""" + + last_id: Optional[str] = None + """The ID of the last item in the list.""" + + object: Literal["list"] + """The type of object returned, must be `list`.""" diff --git a/src/openai/types/skills/version_create_params.py b/src/openai/types/skills/version_create_params.py new file mode 100644 index 0000000000..043b43a030 --- /dev/null +++ b/src/openai/types/skills/version_create_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import TypedDict + +from ..._types import FileTypes, SequenceNotStr + +__all__ = ["VersionCreateParams"] + + +class VersionCreateParams(TypedDict, total=False): + default: bool + """Whether to set this version as the default.""" + + files: Union[SequenceNotStr[FileTypes], FileTypes] + """Skill files to upload (directory upload) or a single zip file.""" diff --git a/src/openai/types/skills/version_list_params.py b/src/openai/types/skills/version_list_params.py new file mode 100644 index 0000000000..0638f40086 --- /dev/null +++ b/src/openai/types/skills/version_list_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["VersionListParams"] + + +class VersionListParams(TypedDict, total=False): + after: str + """The skill version ID to start after.""" + + limit: int + """Number of versions to retrieve.""" + + order: Literal["asc", "desc"] + """Sort order of results by version number.""" diff --git a/src/openai/types/skills/versions/__init__.py b/src/openai/types/skills/versions/__init__.py new file mode 100644 index 0000000000..f8ee8b14b1 --- /dev/null +++ b/src/openai/types/skills/versions/__init__.py @@ -0,0 +1,3 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations diff --git a/tests/api_resources/skills/__init__.py b/tests/api_resources/skills/__init__.py new file mode 100644 index 0000000000..fd8019a9a1 --- /dev/null +++ b/tests/api_resources/skills/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/skills/test_content.py b/tests/api_resources/skills/test_content.py new file mode 100644 index 0000000000..f93e6fc015 --- /dev/null +++ b/tests/api_resources/skills/test_content.py @@ -0,0 +1,122 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import httpx +import pytest +from respx import MockRouter + +import openai._legacy_response as _legacy_response +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type + +# pyright: reportDeprecated=false + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestContent: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_method_retrieve(self, client: OpenAI, respx_mock: MockRouter) -> None: + respx_mock.get("/skills/skill_123/content").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + content = client.skills.content.retrieve( + "skill_123", + ) + assert isinstance(content, _legacy_response.HttpxBinaryResponseContent) + assert content.json() == {"foo": "bar"} + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_raw_response_retrieve(self, client: OpenAI, respx_mock: MockRouter) -> None: + respx_mock.get("/skills/skill_123/content").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + + response = client.skills.content.with_raw_response.retrieve( + "skill_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + content = response.parse() + assert_matches_type(_legacy_response.HttpxBinaryResponseContent, content, path=["response"]) + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_streaming_response_retrieve(self, client: OpenAI, respx_mock: MockRouter) -> None: + respx_mock.get("/skills/skill_123/content").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + with client.skills.content.with_streaming_response.retrieve( + "skill_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + content = response.parse() + assert_matches_type(bytes, content, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `skill_id` but received ''"): + client.skills.content.with_raw_response.retrieve( + "", + ) + + +class TestAsyncContent: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_method_retrieve(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None: + respx_mock.get("/skills/skill_123/content").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + content = await async_client.skills.content.retrieve( + "skill_123", + ) + assert isinstance(content, _legacy_response.HttpxBinaryResponseContent) + assert content.json() == {"foo": "bar"} + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None: + respx_mock.get("/skills/skill_123/content").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + + response = await async_client.skills.content.with_raw_response.retrieve( + "skill_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + content = response.parse() + assert_matches_type(_legacy_response.HttpxBinaryResponseContent, content, path=["response"]) + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None: + respx_mock.get("/skills/skill_123/content").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + async with async_client.skills.content.with_streaming_response.retrieve( + "skill_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + content = await response.parse() + assert_matches_type(bytes, content, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `skill_id` but received ''"): + await async_client.skills.content.with_raw_response.retrieve( + "", + ) diff --git a/tests/api_resources/skills/test_versions.py b/tests/api_resources/skills/test_versions.py new file mode 100644 index 0000000000..5f4dcbf51d --- /dev/null +++ b/tests/api_resources/skills/test_versions.py @@ -0,0 +1,407 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.pagination import SyncCursorPage, AsyncCursorPage +from openai.types.skills import SkillVersion, DeletedSkillVersion + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestVersions: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: OpenAI) -> None: + version = client.skills.versions.create( + skill_id="skill_123", + ) + assert_matches_type(SkillVersion, version, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: OpenAI) -> None: + version = client.skills.versions.create( + skill_id="skill_123", + default=True, + files=[b"raw file contents"], + ) + assert_matches_type(SkillVersion, version, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: OpenAI) -> None: + response = client.skills.versions.with_raw_response.create( + skill_id="skill_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + version = response.parse() + assert_matches_type(SkillVersion, version, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: OpenAI) -> None: + with client.skills.versions.with_streaming_response.create( + skill_id="skill_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + version = response.parse() + assert_matches_type(SkillVersion, version, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_create(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `skill_id` but received ''"): + client.skills.versions.with_raw_response.create( + skill_id="", + ) + + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + version = client.skills.versions.retrieve( + version="version", + skill_id="skill_123", + ) + assert_matches_type(SkillVersion, version, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.skills.versions.with_raw_response.retrieve( + version="version", + skill_id="skill_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + version = response.parse() + assert_matches_type(SkillVersion, version, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.skills.versions.with_streaming_response.retrieve( + version="version", + skill_id="skill_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + version = response.parse() + assert_matches_type(SkillVersion, version, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `skill_id` but received ''"): + client.skills.versions.with_raw_response.retrieve( + version="version", + skill_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `version` but received ''"): + client.skills.versions.with_raw_response.retrieve( + version="", + skill_id="skill_123", + ) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + version = client.skills.versions.list( + skill_id="skill_123", + ) + assert_matches_type(SyncCursorPage[SkillVersion], version, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + version = client.skills.versions.list( + skill_id="skill_123", + after="skillver_123", + limit=0, + order="asc", + ) + assert_matches_type(SyncCursorPage[SkillVersion], version, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.skills.versions.with_raw_response.list( + skill_id="skill_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + version = response.parse() + assert_matches_type(SyncCursorPage[SkillVersion], version, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.skills.versions.with_streaming_response.list( + skill_id="skill_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + version = response.parse() + assert_matches_type(SyncCursorPage[SkillVersion], version, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `skill_id` but received ''"): + client.skills.versions.with_raw_response.list( + skill_id="", + ) + + @parametrize + def test_method_delete(self, client: OpenAI) -> None: + version = client.skills.versions.delete( + version="version", + skill_id="skill_123", + ) + assert_matches_type(DeletedSkillVersion, version, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: OpenAI) -> None: + response = client.skills.versions.with_raw_response.delete( + version="version", + skill_id="skill_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + version = response.parse() + assert_matches_type(DeletedSkillVersion, version, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: OpenAI) -> None: + with client.skills.versions.with_streaming_response.delete( + version="version", + skill_id="skill_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + version = response.parse() + assert_matches_type(DeletedSkillVersion, version, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `skill_id` but received ''"): + client.skills.versions.with_raw_response.delete( + version="version", + skill_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `version` but received ''"): + client.skills.versions.with_raw_response.delete( + version="", + skill_id="skill_123", + ) + + +class TestAsyncVersions: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncOpenAI) -> None: + version = await async_client.skills.versions.create( + skill_id="skill_123", + ) + assert_matches_type(SkillVersion, version, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: + version = await async_client.skills.versions.create( + skill_id="skill_123", + default=True, + files=[b"raw file contents"], + ) + assert_matches_type(SkillVersion, version, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: + response = await async_client.skills.versions.with_raw_response.create( + skill_id="skill_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + version = response.parse() + assert_matches_type(SkillVersion, version, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: + async with async_client.skills.versions.with_streaming_response.create( + skill_id="skill_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + version = await response.parse() + assert_matches_type(SkillVersion, version, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `skill_id` but received ''"): + await async_client.skills.versions.with_raw_response.create( + skill_id="", + ) + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + version = await async_client.skills.versions.retrieve( + version="version", + skill_id="skill_123", + ) + assert_matches_type(SkillVersion, version, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.skills.versions.with_raw_response.retrieve( + version="version", + skill_id="skill_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + version = response.parse() + assert_matches_type(SkillVersion, version, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.skills.versions.with_streaming_response.retrieve( + version="version", + skill_id="skill_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + version = await response.parse() + assert_matches_type(SkillVersion, version, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `skill_id` but received ''"): + await async_client.skills.versions.with_raw_response.retrieve( + version="version", + skill_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `version` but received ''"): + await async_client.skills.versions.with_raw_response.retrieve( + version="", + skill_id="skill_123", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + version = await async_client.skills.versions.list( + skill_id="skill_123", + ) + assert_matches_type(AsyncCursorPage[SkillVersion], version, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + version = await async_client.skills.versions.list( + skill_id="skill_123", + after="skillver_123", + limit=0, + order="asc", + ) + assert_matches_type(AsyncCursorPage[SkillVersion], version, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.skills.versions.with_raw_response.list( + skill_id="skill_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + version = response.parse() + assert_matches_type(AsyncCursorPage[SkillVersion], version, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.skills.versions.with_streaming_response.list( + skill_id="skill_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + version = await response.parse() + assert_matches_type(AsyncCursorPage[SkillVersion], version, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `skill_id` but received ''"): + await async_client.skills.versions.with_raw_response.list( + skill_id="", + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncOpenAI) -> None: + version = await async_client.skills.versions.delete( + version="version", + skill_id="skill_123", + ) + assert_matches_type(DeletedSkillVersion, version, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: + response = await async_client.skills.versions.with_raw_response.delete( + version="version", + skill_id="skill_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + version = response.parse() + assert_matches_type(DeletedSkillVersion, version, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: + async with async_client.skills.versions.with_streaming_response.delete( + version="version", + skill_id="skill_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + version = await response.parse() + assert_matches_type(DeletedSkillVersion, version, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `skill_id` but received ''"): + await async_client.skills.versions.with_raw_response.delete( + version="version", + skill_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `version` but received ''"): + await async_client.skills.versions.with_raw_response.delete( + version="", + skill_id="skill_123", + ) diff --git a/tests/api_resources/skills/versions/__init__.py b/tests/api_resources/skills/versions/__init__.py new file mode 100644 index 0000000000..fd8019a9a1 --- /dev/null +++ b/tests/api_resources/skills/versions/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/skills/versions/test_content.py b/tests/api_resources/skills/versions/test_content.py new file mode 100644 index 0000000000..3d3e19519e --- /dev/null +++ b/tests/api_resources/skills/versions/test_content.py @@ -0,0 +1,154 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import httpx +import pytest +from respx import MockRouter + +import openai._legacy_response as _legacy_response +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type + +# pyright: reportDeprecated=false + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestContent: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_method_retrieve(self, client: OpenAI, respx_mock: MockRouter) -> None: + respx_mock.get("/skills/skill_123/versions/version/content").mock( + return_value=httpx.Response(200, json={"foo": "bar"}) + ) + content = client.skills.versions.content.retrieve( + version="version", + skill_id="skill_123", + ) + assert isinstance(content, _legacy_response.HttpxBinaryResponseContent) + assert content.json() == {"foo": "bar"} + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_raw_response_retrieve(self, client: OpenAI, respx_mock: MockRouter) -> None: + respx_mock.get("/skills/skill_123/versions/version/content").mock( + return_value=httpx.Response(200, json={"foo": "bar"}) + ) + + response = client.skills.versions.content.with_raw_response.retrieve( + version="version", + skill_id="skill_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + content = response.parse() + assert_matches_type(_legacy_response.HttpxBinaryResponseContent, content, path=["response"]) + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_streaming_response_retrieve(self, client: OpenAI, respx_mock: MockRouter) -> None: + respx_mock.get("/skills/skill_123/versions/version/content").mock( + return_value=httpx.Response(200, json={"foo": "bar"}) + ) + with client.skills.versions.content.with_streaming_response.retrieve( + version="version", + skill_id="skill_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + content = response.parse() + assert_matches_type(bytes, content, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `skill_id` but received ''"): + client.skills.versions.content.with_raw_response.retrieve( + version="version", + skill_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `version` but received ''"): + client.skills.versions.content.with_raw_response.retrieve( + version="", + skill_id="skill_123", + ) + + +class TestAsyncContent: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_method_retrieve(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None: + respx_mock.get("/skills/skill_123/versions/version/content").mock( + return_value=httpx.Response(200, json={"foo": "bar"}) + ) + content = await async_client.skills.versions.content.retrieve( + version="version", + skill_id="skill_123", + ) + assert isinstance(content, _legacy_response.HttpxBinaryResponseContent) + assert content.json() == {"foo": "bar"} + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None: + respx_mock.get("/skills/skill_123/versions/version/content").mock( + return_value=httpx.Response(200, json={"foo": "bar"}) + ) + + response = await async_client.skills.versions.content.with_raw_response.retrieve( + version="version", + skill_id="skill_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + content = response.parse() + assert_matches_type(_legacy_response.HttpxBinaryResponseContent, content, path=["response"]) + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None: + respx_mock.get("/skills/skill_123/versions/version/content").mock( + return_value=httpx.Response(200, json={"foo": "bar"}) + ) + async with async_client.skills.versions.content.with_streaming_response.retrieve( + version="version", + skill_id="skill_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + content = await response.parse() + assert_matches_type(bytes, content, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `skill_id` but received ''"): + await async_client.skills.versions.content.with_raw_response.retrieve( + version="version", + skill_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `version` but received ''"): + await async_client.skills.versions.content.with_raw_response.retrieve( + version="", + skill_id="skill_123", + ) diff --git a/tests/api_resources/test_skills.py b/tests/api_resources/test_skills.py new file mode 100644 index 0000000000..fb4cea92ce --- /dev/null +++ b/tests/api_resources/test_skills.py @@ -0,0 +1,393 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.types import Skill, DeletedSkill +from openai.pagination import SyncCursorPage, AsyncCursorPage + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestSkills: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: OpenAI) -> None: + skill = client.skills.create() + assert_matches_type(Skill, skill, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: OpenAI) -> None: + skill = client.skills.create( + files=[b"raw file contents"], + ) + assert_matches_type(Skill, skill, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: OpenAI) -> None: + response = client.skills.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + skill = response.parse() + assert_matches_type(Skill, skill, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: OpenAI) -> None: + with client.skills.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + skill = response.parse() + assert_matches_type(Skill, skill, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + skill = client.skills.retrieve( + "skill_123", + ) + assert_matches_type(Skill, skill, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.skills.with_raw_response.retrieve( + "skill_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + skill = response.parse() + assert_matches_type(Skill, skill, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.skills.with_streaming_response.retrieve( + "skill_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + skill = response.parse() + assert_matches_type(Skill, skill, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `skill_id` but received ''"): + client.skills.with_raw_response.retrieve( + "", + ) + + @parametrize + def test_method_update(self, client: OpenAI) -> None: + skill = client.skills.update( + skill_id="skill_123", + default_version="default_version", + ) + assert_matches_type(Skill, skill, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: OpenAI) -> None: + response = client.skills.with_raw_response.update( + skill_id="skill_123", + default_version="default_version", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + skill = response.parse() + assert_matches_type(Skill, skill, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: OpenAI) -> None: + with client.skills.with_streaming_response.update( + skill_id="skill_123", + default_version="default_version", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + skill = response.parse() + assert_matches_type(Skill, skill, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `skill_id` but received ''"): + client.skills.with_raw_response.update( + skill_id="", + default_version="default_version", + ) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + skill = client.skills.list() + assert_matches_type(SyncCursorPage[Skill], skill, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + skill = client.skills.list( + after="after", + limit=0, + order="asc", + ) + assert_matches_type(SyncCursorPage[Skill], skill, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.skills.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + skill = response.parse() + assert_matches_type(SyncCursorPage[Skill], skill, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.skills.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + skill = response.parse() + assert_matches_type(SyncCursorPage[Skill], skill, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: OpenAI) -> None: + skill = client.skills.delete( + "skill_123", + ) + assert_matches_type(DeletedSkill, skill, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: OpenAI) -> None: + response = client.skills.with_raw_response.delete( + "skill_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + skill = response.parse() + assert_matches_type(DeletedSkill, skill, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: OpenAI) -> None: + with client.skills.with_streaming_response.delete( + "skill_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + skill = response.parse() + assert_matches_type(DeletedSkill, skill, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `skill_id` but received ''"): + client.skills.with_raw_response.delete( + "", + ) + + +class TestAsyncSkills: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncOpenAI) -> None: + skill = await async_client.skills.create() + assert_matches_type(Skill, skill, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: + skill = await async_client.skills.create( + files=[b"raw file contents"], + ) + assert_matches_type(Skill, skill, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: + response = await async_client.skills.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + skill = response.parse() + assert_matches_type(Skill, skill, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: + async with async_client.skills.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + skill = await response.parse() + assert_matches_type(Skill, skill, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + skill = await async_client.skills.retrieve( + "skill_123", + ) + assert_matches_type(Skill, skill, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.skills.with_raw_response.retrieve( + "skill_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + skill = response.parse() + assert_matches_type(Skill, skill, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.skills.with_streaming_response.retrieve( + "skill_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + skill = await response.parse() + assert_matches_type(Skill, skill, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `skill_id` but received ''"): + await async_client.skills.with_raw_response.retrieve( + "", + ) + + @parametrize + async def test_method_update(self, async_client: AsyncOpenAI) -> None: + skill = await async_client.skills.update( + skill_id="skill_123", + default_version="default_version", + ) + assert_matches_type(Skill, skill, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: + response = await async_client.skills.with_raw_response.update( + skill_id="skill_123", + default_version="default_version", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + skill = response.parse() + assert_matches_type(Skill, skill, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncOpenAI) -> None: + async with async_client.skills.with_streaming_response.update( + skill_id="skill_123", + default_version="default_version", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + skill = await response.parse() + assert_matches_type(Skill, skill, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `skill_id` but received ''"): + await async_client.skills.with_raw_response.update( + skill_id="", + default_version="default_version", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + skill = await async_client.skills.list() + assert_matches_type(AsyncCursorPage[Skill], skill, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + skill = await async_client.skills.list( + after="after", + limit=0, + order="asc", + ) + assert_matches_type(AsyncCursorPage[Skill], skill, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.skills.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + skill = response.parse() + assert_matches_type(AsyncCursorPage[Skill], skill, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.skills.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + skill = await response.parse() + assert_matches_type(AsyncCursorPage[Skill], skill, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncOpenAI) -> None: + skill = await async_client.skills.delete( + "skill_123", + ) + assert_matches_type(DeletedSkill, skill, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: + response = await async_client.skills.with_raw_response.delete( + "skill_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + skill = response.parse() + assert_matches_type(DeletedSkill, skill, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: + async with async_client.skills.with_streaming_response.delete( + "skill_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + skill = await response.parse() + assert_matches_type(DeletedSkill, skill, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `skill_id` but received ''"): + await async_client.skills.with_raw_response.delete( + "", + ) From 89486d6e61b61d85e4a0a20d4f599f40ef1d4895 Mon Sep 17 00:00:00 2001 From: Alex Chang Date: Tue, 10 Feb 2026 13:12:30 -0500 Subject: [PATCH 612/769] fix merge conflict --- requirements-dev.lock | 4 ---- 1 file changed, 4 deletions(-) diff --git a/requirements-dev.lock b/requirements-dev.lock index b4ed71101a..7e2755a021 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -170,12 +170,8 @@ requests==2.32.5 # via msal respx==0.22.0 rich==14.2.0 -<<<<<<< HEAD # via inline-snapshot ruff==0.14.7 -======= -ruff==0.14.13 ->>>>>>> origin/generated--merge-conflict six==1.17.0 # via python-dateutil sniffio==1.3.1 From f1b35ddf5ddb1ae615e34517ed01a94f54d1ec97 Mon Sep 17 00:00:00 2001 From: Alex Chang Date: Tue, 10 Feb 2026 13:16:13 -0500 Subject: [PATCH 613/769] fix one more --- requirements-dev.lock | 4 ---- 1 file changed, 4 deletions(-) diff --git a/requirements-dev.lock b/requirements-dev.lock index 7e2755a021..73312bcee1 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -215,16 +215,12 @@ typing-extensions==4.15.0 # via virtualenv typing-inspection==0.4.2 # via pydantic -<<<<<<< HEAD tzdata==2025.2 # via pandas urllib3==2.5.0 # via requests # via types-requests virtualenv==20.35.4 -======= -virtualenv==20.36.1 ->>>>>>> origin/generated--merge-conflict # via nox websockets==15.0.1 # via openai From 1c6d3d27c24a708fc5b4b2c4a743f08ff4978c35 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 10 Feb 2026 18:17:02 +0000 Subject: [PATCH 614/769] release: 2.19.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index ca3496a3e6..60b44f4d33 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.18.0" + ".": "2.19.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index ad2758cf6d..be67fc97c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 2.19.0 (2026-02-10) + +Full Changelog: [v2.18.0...v2.19.0](https://github.com/openai/openai-python/compare/v2.18.0...v2.19.0) + +### Features + +* **api:** skills and hosted shell ([27fdf68](https://github.com/openai/openai-python/commit/27fdf6820655b5994e3c1eddb3c8d9344a8be744)) + + +### Chores + +* **internal:** bump dependencies ([fae10fd](https://github.com/openai/openai-python/commit/fae10fd6e936a044f8393a454a39906aa325a893)) + ## 2.18.0 (2026-02-09) Full Changelog: [v2.17.0...v2.18.0](https://github.com/openai/openai-python/compare/v2.17.0...v2.18.0) diff --git a/pyproject.toml b/pyproject.toml index 4dc3418464..c7821a9df4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.18.0" +version = "2.19.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 aede964362..a0c43abd1d 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__ = "2.18.0" # x-release-please-version +__version__ = "2.19.0" # x-release-please-version From b13d6fe944ab01b72b9a3256e48752d808c906ff Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 10 Feb 2026 18:51:12 +0000 Subject: [PATCH 615/769] feat(api): support for images in batch api --- .stats.yml | 4 ++-- src/openai/resources/batches.py | 28 ++++++++++++++++++------- src/openai/types/batch_create_params.py | 17 +++++++++++---- 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/.stats.yml b/.stats.yml index e91271a6c8..6c725eaa30 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 148 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-7debfce2217c66ea87bfddaa244b57de4062dd7fd766fa9a28e869614205c040.yml -openapi_spec_hash: e910fc478b8449134e2af1dc15fd33f7 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-47ef7e0aaa2f2052404041650c9b4d7d8c9c51c45ef2cb081548f329c3f81a6a.yml +openapi_spec_hash: 0207b30cf74121a12c1647e25463cee9 config_hash: 8dca0f2dc2706c07cf2f8d0ed4dc062e diff --git a/src/openai/resources/batches.py b/src/openai/resources/batches.py index 80400839e4..bc856bf5aa 100644 --- a/src/openai/resources/batches.py +++ b/src/openai/resources/batches.py @@ -47,7 +47,13 @@ def create( *, completion_window: Literal["24h"], endpoint: Literal[ - "/v1/responses", "/v1/chat/completions", "/v1/embeddings", "/v1/completions", "/v1/moderations" + "/v1/responses", + "/v1/chat/completions", + "/v1/embeddings", + "/v1/completions", + "/v1/moderations", + "/v1/images/generations", + "/v1/images/edits", ], input_file_id: str, metadata: Optional[Metadata] | Omit = omit, @@ -68,9 +74,9 @@ def create( endpoint: The endpoint to be used for all requests in the batch. Currently `/v1/responses`, `/v1/chat/completions`, `/v1/embeddings`, `/v1/completions`, - and `/v1/moderations` are supported. Note that `/v1/embeddings` batches are also - restricted to a maximum of 50,000 embedding inputs across all requests in the - batch. + `/v1/moderations`, `/v1/images/generations`, and `/v1/images/edits` are + supported. Note that `/v1/embeddings` batches are also restricted to a maximum + of 50,000 embedding inputs across all requests in the batch. input_file_id: The ID of an uploaded file that contains requests for the new batch. @@ -265,7 +271,13 @@ async def create( *, completion_window: Literal["24h"], endpoint: Literal[ - "/v1/responses", "/v1/chat/completions", "/v1/embeddings", "/v1/completions", "/v1/moderations" + "/v1/responses", + "/v1/chat/completions", + "/v1/embeddings", + "/v1/completions", + "/v1/moderations", + "/v1/images/generations", + "/v1/images/edits", ], input_file_id: str, metadata: Optional[Metadata] | Omit = omit, @@ -286,9 +298,9 @@ async def create( endpoint: The endpoint to be used for all requests in the batch. Currently `/v1/responses`, `/v1/chat/completions`, `/v1/embeddings`, `/v1/completions`, - and `/v1/moderations` are supported. Note that `/v1/embeddings` batches are also - restricted to a maximum of 50,000 embedding inputs across all requests in the - batch. + `/v1/moderations`, `/v1/images/generations`, and `/v1/images/edits` are + supported. Note that `/v1/embeddings` batches are also restricted to a maximum + of 50,000 embedding inputs across all requests in the batch. input_file_id: The ID of an uploaded file that contains requests for the new batch. diff --git a/src/openai/types/batch_create_params.py b/src/openai/types/batch_create_params.py index 1088aab380..1bcd48aace 100644 --- a/src/openai/types/batch_create_params.py +++ b/src/openai/types/batch_create_params.py @@ -18,14 +18,23 @@ class BatchCreateParams(TypedDict, total=False): """ endpoint: Required[ - Literal["/v1/responses", "/v1/chat/completions", "/v1/embeddings", "/v1/completions", "/v1/moderations"] + Literal[ + "/v1/responses", + "/v1/chat/completions", + "/v1/embeddings", + "/v1/completions", + "/v1/moderations", + "/v1/images/generations", + "/v1/images/edits", + ] ] """The endpoint to be used for all requests in the batch. Currently `/v1/responses`, `/v1/chat/completions`, `/v1/embeddings`, - `/v1/completions`, and `/v1/moderations` are supported. Note that - `/v1/embeddings` batches are also restricted to a maximum of 50,000 embedding - inputs across all requests in the batch. + `/v1/completions`, `/v1/moderations`, `/v1/images/generations`, and + `/v1/images/edits` are supported. Note that `/v1/embeddings` batches are also + restricted to a maximum of 50,000 embedding inputs across all requests in the + batch. """ input_file_id: Required[str] From f2d096fe978a1fe67f58351ddbfa0d38f3d723b9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 10 Feb 2026 18:51:50 +0000 Subject: [PATCH 616/769] release: 2.20.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 60b44f4d33..26b25a25e8 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.19.0" + ".": "2.20.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index be67fc97c9..39ed325e8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 2.20.0 (2026-02-10) + +Full Changelog: [v2.19.0...v2.20.0](https://github.com/openai/openai-python/compare/v2.19.0...v2.20.0) + +### Features + +* **api:** support for images in batch api ([28edb6e](https://github.com/openai/openai-python/commit/28edb6e1b7eb30dbb7be49979cee7882e8889264)) + ## 2.19.0 (2026-02-10) Full Changelog: [v2.18.0...v2.19.0](https://github.com/openai/openai-python/compare/v2.18.0...v2.19.0) diff --git a/pyproject.toml b/pyproject.toml index c7821a9df4..326c715f08 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.19.0" +version = "2.20.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 a0c43abd1d..4987d1ca18 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__ = "2.19.0" # x-release-please-version +__version__ = "2.20.0" # x-release-please-version From 7b26bd3712d80e47130ee5d542895f636e48135d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 11 Feb 2026 02:54:41 +0000 Subject: [PATCH 617/769] docs: update comment --- .../resources/chat/completions/completions.py | 16 ++++++---------- src/openai/types/chat/completion_list_params.py | 8 ++------ 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index 9c0b74b804..fb1887a7d5 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -1346,12 +1346,10 @@ def list( limit: Number of Chat Completions to retrieve. - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. + metadata: + A list of metadata keys to filter the Chat Completions by. Example: - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. + `metadata[key1]=value1&metadata[key2]=value2` model: The model used to generate the Chat Completions. @@ -2832,12 +2830,10 @@ def list( limit: Number of Chat Completions to retrieve. - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. + metadata: + A list of metadata keys to filter the Chat Completions by. Example: - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. + `metadata[key1]=value1&metadata[key2]=value2` model: The model used to generate the Chat Completions. diff --git a/src/openai/types/chat/completion_list_params.py b/src/openai/types/chat/completion_list_params.py index 32bd3f5c0a..d93da834a3 100644 --- a/src/openai/types/chat/completion_list_params.py +++ b/src/openai/types/chat/completion_list_params.py @@ -18,13 +18,9 @@ class CompletionListParams(TypedDict, total=False): """Number of Chat Completions to retrieve.""" metadata: Optional[Metadata] - """Set of 16 key-value pairs that can be attached to an object. + """A list of metadata keys to filter the Chat Completions by. Example: - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. + `metadata[key1]=value1&metadata[key2]=value2` """ model: str From 957dadffc629d3980d603832864ed59df78075e8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 11 Feb 2026 14:28:03 +0000 Subject: [PATCH 618/769] chore(internal): fix lint error on Python 3.14 --- src/openai/_utils/_compat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openai/_utils/_compat.py b/src/openai/_utils/_compat.py index dd703233c5..2c70b299ce 100644 --- a/src/openai/_utils/_compat.py +++ b/src/openai/_utils/_compat.py @@ -26,7 +26,7 @@ def is_union(tp: Optional[Type[Any]]) -> bool: else: import types - return tp is Union or tp is types.UnionType + return tp is Union or tp is types.UnionType # type: ignore[comparison-overlap] def is_typeddict(tp: Type[Any]) -> bool: From 01c9eee2cb3fb0ec14d9026f93fb6a71d432e3a3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 11 Feb 2026 20:45:28 +0000 Subject: [PATCH 619/769] codegen metadata --- .stats.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.stats.yml b/.stats.yml index 6c725eaa30..9a081e2ac0 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 148 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-47ef7e0aaa2f2052404041650c9b4d7d8c9c51c45ef2cb081548f329c3f81a6a.yml -openapi_spec_hash: 0207b30cf74121a12c1647e25463cee9 -config_hash: 8dca0f2dc2706c07cf2f8d0ed4dc062e +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-1595c7e4e1d7bf7eae2e49ad800316e13b69ffb18bff2a2f55236fce792deb53.yml +openapi_spec_hash: c3a3a0d8d4bbf11179149244f017a6dc +config_hash: f6cdeee28c96db61b0a5d92e414bc0ae From d81ee8f85207bdc88c2749ae9d0644d9a997e397 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 11 Feb 2026 22:05:45 +0000 Subject: [PATCH 620/769] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 9a081e2ac0..dcc9c27df3 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 148 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-1595c7e4e1d7bf7eae2e49ad800316e13b69ffb18bff2a2f55236fce792deb53.yml openapi_spec_hash: c3a3a0d8d4bbf11179149244f017a6dc -config_hash: f6cdeee28c96db61b0a5d92e414bc0ae +config_hash: 948733484caf41e71093c6582dbc319c From 72e1e15abfc283fa2714bc4d61e4a31740833084 Mon Sep 17 00:00:00 2001 From: Kar Petrosyan <92274156+karpetrosyan@users.noreply.github.com> Date: Fri, 13 Feb 2026 14:47:25 +0400 Subject: [PATCH 621/769] fix(structured outputs): resolve memory leak in parse methods (#2860) --- src/openai/lib/_parsing/__init__.py | 1 - src/openai/lib/_parsing/_completions.py | 31 ++------ src/openai/lib/_parsing/_responses.py | 24 +++---- src/openai/lib/streaming/chat/_completions.py | 3 +- tests/lib/chat/test_completions.py | 72 +++++++++---------- tests/lib/chat/test_completions_streaming.py | 66 ++++++++--------- tests/lib/utils.py | 30 ++------ 7 files changed, 92 insertions(+), 135 deletions(-) diff --git a/src/openai/lib/_parsing/__init__.py b/src/openai/lib/_parsing/__init__.py index 4d454c3a20..08591f43f4 100644 --- a/src/openai/lib/_parsing/__init__.py +++ b/src/openai/lib/_parsing/__init__.py @@ -6,7 +6,6 @@ validate_input_tools as validate_input_tools, parse_chat_completion as parse_chat_completion, get_input_tool_by_name as get_input_tool_by_name, - solve_response_format_t as solve_response_format_t, parse_function_tool_arguments as parse_function_tool_arguments, type_to_response_format_param as type_to_response_format_param, ) diff --git a/src/openai/lib/_parsing/_completions.py b/src/openai/lib/_parsing/_completions.py index 7903732a4a..7a1bded1de 100644 --- a/src/openai/lib/_parsing/_completions.py +++ b/src/openai/lib/_parsing/_completions.py @@ -138,7 +138,7 @@ def parse_chat_completion( choices.append( construct_type_unchecked( - type_=cast(Any, ParsedChoice)[solve_response_format_t(response_format)], + type_=ParsedChoice[ResponseFormatT], value={ **choice.to_dict(), "message": { @@ -153,15 +153,12 @@ def parse_chat_completion( ) ) - return cast( - ParsedChatCompletion[ResponseFormatT], - construct_type_unchecked( - type_=cast(Any, ParsedChatCompletion)[solve_response_format_t(response_format)], - value={ - **chat_completion.to_dict(), - "choices": choices, - }, - ), + return construct_type_unchecked( + type_=ParsedChatCompletion[ResponseFormatT], + value={ + **chat_completion.to_dict(), + "choices": choices, + }, ) @@ -201,20 +198,6 @@ def maybe_parse_content( return None -def solve_response_format_t( - response_format: type[ResponseFormatT] | ResponseFormatParam | Omit, -) -> type[ResponseFormatT]: - """Return the runtime type for the given response format. - - If no response format is given, or if we won't auto-parse the response format - then we default to `None`. - """ - if has_rich_response_format(response_format): - return response_format - - return cast("type[ResponseFormatT]", _default_response_format) - - def has_parseable_input( *, response_format: type | ResponseFormatParam | Omit, diff --git a/src/openai/lib/_parsing/_responses.py b/src/openai/lib/_parsing/_responses.py index 4bed171df7..5676eb0b63 100644 --- a/src/openai/lib/_parsing/_responses.py +++ b/src/openai/lib/_parsing/_responses.py @@ -1,7 +1,7 @@ from __future__ import annotations import json -from typing import TYPE_CHECKING, Any, List, Iterable, cast +from typing import TYPE_CHECKING, List, Iterable, cast from typing_extensions import TypeVar, assert_never import pydantic @@ -12,7 +12,7 @@ from ..._compat import PYDANTIC_V1, model_parse_json from ..._models import construct_type_unchecked from .._pydantic import is_basemodel_type, is_dataclass_like_type -from ._completions import solve_response_format_t, type_to_response_format_param +from ._completions import type_to_response_format_param from ...types.responses import ( Response, ToolParam, @@ -56,7 +56,6 @@ def parse_response( input_tools: Iterable[ToolParam] | Omit | None, response: Response | ParsedResponse[object], ) -> ParsedResponse[TextFormatT]: - solved_t = solve_response_format_t(text_format) output_list: List[ParsedResponseOutputItem[TextFormatT]] = [] for output in response.output: @@ -69,7 +68,7 @@ def parse_response( content_list.append( construct_type_unchecked( - type_=cast(Any, ParsedResponseOutputText)[solved_t], + type_=ParsedResponseOutputText[TextFormatT], value={ **item.to_dict(), "parsed": parse_text(item.text, text_format=text_format), @@ -79,7 +78,7 @@ def parse_response( output_list.append( construct_type_unchecked( - type_=cast(Any, ParsedResponseOutputMessage)[solved_t], + type_=ParsedResponseOutputMessage[TextFormatT], value={ **output.to_dict(), "content": content_list, @@ -123,15 +122,12 @@ def parse_response( else: output_list.append(output) - return cast( - ParsedResponse[TextFormatT], - construct_type_unchecked( - type_=cast(Any, ParsedResponse)[solved_t], - value={ - **response.to_dict(), - "output": output_list, - }, - ), + return construct_type_unchecked( + type_=ParsedResponse[TextFormatT], + value={ + **response.to_dict(), + "output": output_list, + }, ) diff --git a/src/openai/lib/streaming/chat/_completions.py b/src/openai/lib/streaming/chat/_completions.py index c4610e2120..5f072cafbd 100644 --- a/src/openai/lib/streaming/chat/_completions.py +++ b/src/openai/lib/streaming/chat/_completions.py @@ -33,7 +33,6 @@ maybe_parse_content, parse_chat_completion, get_input_tool_by_name, - solve_response_format_t, parse_function_tool_arguments, ) from ...._streaming import Stream, AsyncStream @@ -663,7 +662,7 @@ def _content_done_events( # type variable, e.g. `ContentDoneEvent[MyModelType]` cast( # pyright: ignore[reportUnnecessaryCast] "type[ContentDoneEvent[ResponseFormatT]]", - cast(Any, ContentDoneEvent)[solve_response_format_t(response_format)], + cast(Any, ContentDoneEvent), ), type="content.done", content=choice_snapshot.message.content, diff --git a/tests/lib/chat/test_completions.py b/tests/lib/chat/test_completions.py index afad5a1391..85bab4f095 100644 --- a/tests/lib/chat/test_completions.py +++ b/tests/lib/chat/test_completions.py @@ -50,13 +50,13 @@ def test_parse_nothing(client: OpenAI, respx_mock: MockRouter, monkeypatch: pyte assert print_obj(completion, monkeypatch) == snapshot( """\ -ParsedChatCompletion[NoneType]( +ParsedChatCompletion( choices=[ - ParsedChoice[NoneType]( + ParsedChoice( finish_reason='stop', index=0, logprobs=None, - message=ParsedChatCompletionMessage[NoneType]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content="I'm unable to provide real-time weather updates. To get the current weather in San Francisco, I @@ -120,13 +120,13 @@ class Location(BaseModel): assert print_obj(completion, monkeypatch) == snapshot( """\ -ParsedChatCompletion[Location]( +ParsedChatCompletion( choices=[ - ParsedChoice[Location]( + ParsedChoice( finish_reason='stop', index=0, logprobs=None, - message=ParsedChatCompletionMessage[Location]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content='{"city":"San Francisco","temperature":65,"units":"f"}', @@ -191,13 +191,13 @@ class Location(BaseModel): assert print_obj(completion, monkeypatch) == snapshot( """\ -ParsedChatCompletion[Location]( +ParsedChatCompletion( choices=[ - ParsedChoice[Location]( + ParsedChoice( finish_reason='stop', index=0, logprobs=None, - message=ParsedChatCompletionMessage[Location]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content='{"city":"San Francisco","temperature":65,"units":"f"}', @@ -266,11 +266,11 @@ class ColorDetection(BaseModel): assert print_obj(completion.choices[0], monkeypatch) == snapshot( """\ -ParsedChoice[ColorDetection]( +ParsedChoice( finish_reason='stop', index=0, logprobs=None, - message=ParsedChatCompletionMessage[ColorDetection]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content='{"color":"red","hex_color_code":"#FF0000"}', @@ -317,11 +317,11 @@ class Location(BaseModel): assert print_obj(completion.choices, monkeypatch) == snapshot( """\ [ - ParsedChoice[Location]( + ParsedChoice( finish_reason='stop', index=0, logprobs=None, - message=ParsedChatCompletionMessage[Location]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content='{"city":"San Francisco","temperature":64,"units":"f"}', @@ -332,11 +332,11 @@ class Location(BaseModel): tool_calls=None ) ), - ParsedChoice[Location]( + ParsedChoice( finish_reason='stop', index=1, logprobs=None, - message=ParsedChatCompletionMessage[Location]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content='{"city":"San Francisco","temperature":65,"units":"f"}', @@ -347,11 +347,11 @@ class Location(BaseModel): tool_calls=None ) ), - ParsedChoice[Location]( + ParsedChoice( finish_reason='stop', index=2, logprobs=None, - message=ParsedChatCompletionMessage[Location]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content='{"city":"San Francisco","temperature":63.0,"units":"f"}', @@ -397,13 +397,13 @@ class CalendarEvent: assert print_obj(completion, monkeypatch) == snapshot( """\ -ParsedChatCompletion[CalendarEvent]( +ParsedChatCompletion( choices=[ - ParsedChoice[CalendarEvent]( + ParsedChoice( finish_reason='stop', index=0, logprobs=None, - message=ParsedChatCompletionMessage[CalendarEvent]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content='{"name":"Science Fair","date":"Friday","participants":["Alice","Bob"]}', @@ -462,11 +462,11 @@ def test_pydantic_tool_model_all_types(client: OpenAI, respx_mock: MockRouter, m assert print_obj(completion.choices[0], monkeypatch) == snapshot( """\ -ParsedChoice[Query]( +ParsedChoice( finish_reason='tool_calls', index=0, logprobs=None, - message=ParsedChatCompletionMessage[Query]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content=None, @@ -576,11 +576,11 @@ class Location(BaseModel): assert print_obj(completion.choices, monkeypatch) == snapshot( """\ [ - ParsedChoice[Location]( + ParsedChoice( finish_reason='stop', index=0, logprobs=None, - message=ParsedChatCompletionMessage[Location]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content=None, @@ -627,11 +627,11 @@ class GetWeatherArgs(BaseModel): assert print_obj(completion.choices, monkeypatch) == snapshot( """\ [ - ParsedChoice[NoneType]( + ParsedChoice( finish_reason='tool_calls', index=0, logprobs=None, - message=ParsedChatCompletionMessage[NoneType]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content=None, @@ -701,11 +701,11 @@ class GetStockPrice(BaseModel): assert print_obj(completion.choices, monkeypatch) == snapshot( """\ [ - ParsedChoice[NoneType]( + ParsedChoice( finish_reason='tool_calls', index=0, logprobs=None, - message=ParsedChatCompletionMessage[NoneType]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content=None, @@ -784,11 +784,11 @@ def test_parse_strict_tools(client: OpenAI, respx_mock: MockRouter, monkeypatch: assert print_obj(completion.choices, monkeypatch) == snapshot( """\ [ - ParsedChoice[NoneType]( + ParsedChoice( finish_reason='tool_calls', index=0, logprobs=None, - message=ParsedChatCompletionMessage[NoneType]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content=None, @@ -866,13 +866,13 @@ class Location(BaseModel): assert isinstance(message.parsed.city, str) assert print_obj(completion, monkeypatch) == snapshot( """\ -ParsedChatCompletion[Location]( +ParsedChatCompletion( choices=[ - ParsedChoice[Location]( + ParsedChoice( finish_reason='stop', index=0, logprobs=None, - message=ParsedChatCompletionMessage[Location]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content='{"city":"San Francisco","temperature":58,"units":"f"}', @@ -943,13 +943,13 @@ class Location(BaseModel): assert isinstance(message.parsed.city, str) assert print_obj(completion, monkeypatch) == snapshot( """\ -ParsedChatCompletion[Location]( +ParsedChatCompletion( choices=[ - ParsedChoice[Location]( + ParsedChoice( finish_reason='stop', index=0, logprobs=None, - message=ParsedChatCompletionMessage[Location]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content='{"city":"San Francisco","temperature":65,"units":"f"}', diff --git a/tests/lib/chat/test_completions_streaming.py b/tests/lib/chat/test_completions_streaming.py index 548416dfe2..eb3a0973ac 100644 --- a/tests/lib/chat/test_completions_streaming.py +++ b/tests/lib/chat/test_completions_streaming.py @@ -63,11 +63,11 @@ def test_parse_nothing(client: OpenAI, respx_mock: MockRouter, monkeypatch: pyte assert print_obj(listener.stream.get_final_completion().choices, monkeypatch) == snapshot( """\ [ - ParsedChoice[NoneType]( + ParsedChoice( finish_reason='stop', index=0, logprobs=None, - message=ParsedChatCompletionMessage[NoneType]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content="I'm unable to provide real-time weather updates. To get the current weather in San Francisco, I @@ -84,7 +84,7 @@ def test_parse_nothing(client: OpenAI, respx_mock: MockRouter, monkeypatch: pyte ) assert print_obj(listener.get_event_by_type("content.done"), monkeypatch) == snapshot( """\ -ContentDoneEvent[NoneType]( +ContentDoneEvent( content="I'm unable to provide real-time weather updates. To get the current weather in San Francisco, I recommend checking a reliable weather website or a weather app.", parsed=None, @@ -140,13 +140,13 @@ def on_event(stream: ChatCompletionStream[Location], event: ChatCompletionStream assert print_obj(listener.stream.get_final_completion(), monkeypatch) == snapshot( """\ -ParsedChatCompletion[Location]( +ParsedChatCompletion( choices=[ - ParsedChoice[Location]( + ParsedChoice( finish_reason='stop', index=0, logprobs=None, - message=ParsedChatCompletionMessage[Location]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content='{"city":"San Francisco","temperature":61,"units":"f"}', @@ -181,7 +181,7 @@ def on_event(stream: ChatCompletionStream[Location], event: ChatCompletionStream ) assert print_obj(listener.get_event_by_type("content.done"), monkeypatch) == snapshot( """\ -ContentDoneEvent[Location]( +ContentDoneEvent( content='{"city":"San Francisco","temperature":61,"units":"f"}', parsed=Location(city='San Francisco', temperature=61.0, units='f'), type='content.done' @@ -320,11 +320,11 @@ class Location(BaseModel): assert print_obj(listener.stream.get_final_completion().choices, monkeypatch) == snapshot( """\ [ - ParsedChoice[Location]( + ParsedChoice( finish_reason='stop', index=0, logprobs=None, - message=ParsedChatCompletionMessage[Location]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content='{"city":"San Francisco","temperature":65,"units":"f"}', @@ -335,11 +335,11 @@ class Location(BaseModel): tool_calls=None ) ), - ParsedChoice[Location]( + ParsedChoice( finish_reason='stop', index=1, logprobs=None, - message=ParsedChatCompletionMessage[Location]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content='{"city":"San Francisco","temperature":61,"units":"f"}', @@ -350,11 +350,11 @@ class Location(BaseModel): tool_calls=None ) ), - ParsedChoice[Location]( + ParsedChoice( finish_reason='stop', index=2, logprobs=None, - message=ParsedChatCompletionMessage[Location]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content='{"city":"San Francisco","temperature":59,"units":"f"}', @@ -426,11 +426,11 @@ class Location(BaseModel): assert print_obj(listener.stream.get_final_completion().choices, monkeypatch) == snapshot( """\ [ - ParsedChoice[Location]( + ParsedChoice( finish_reason='stop', index=0, logprobs=None, - message=ParsedChatCompletionMessage[Location]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content=None, @@ -495,7 +495,7 @@ def test_content_logprobs_events(client: OpenAI, respx_mock: MockRouter, monkeyp assert print_obj(listener.stream.get_final_completion().choices, monkeypatch) == snapshot("""\ [ - ParsedChoice[NoneType]( + ParsedChoice( finish_reason='stop', index=0, logprobs=ChoiceLogprobs( @@ -505,7 +505,7 @@ def test_content_logprobs_events(client: OpenAI, respx_mock: MockRouter, monkeyp ], refusal=None ), - message=ParsedChatCompletionMessage[NoneType]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content='Foo!', @@ -563,7 +563,7 @@ class Location(BaseModel): assert print_obj(listener.stream.get_final_completion().choices, monkeypatch) == snapshot("""\ [ - ParsedChoice[Location]( + ParsedChoice( finish_reason='stop', index=0, logprobs=ChoiceLogprobs( @@ -617,7 +617,7 @@ class Location(BaseModel): ChatCompletionTokenLogprob(bytes=[46], logprob=-0.57687104, token='.', top_logprobs=[]) ] ), - message=ParsedChatCompletionMessage[Location]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content=None, @@ -660,11 +660,11 @@ class GetWeatherArgs(BaseModel): assert print_obj(listener.stream.current_completion_snapshot.choices, monkeypatch) == snapshot( """\ [ - ParsedChoice[object]( + ParsedChoice( finish_reason='tool_calls', index=0, logprobs=None, - message=ParsedChatCompletionMessage[object]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content=None, @@ -693,11 +693,11 @@ class GetWeatherArgs(BaseModel): assert print_obj(listener.stream.get_final_completion().choices, monkeypatch) == snapshot( """\ [ - ParsedChoice[NoneType]( + ParsedChoice( finish_reason='tool_calls', index=0, logprobs=None, - message=ParsedChatCompletionMessage[NoneType]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content=None, @@ -765,11 +765,11 @@ class GetStockPrice(BaseModel): assert print_obj(listener.stream.current_completion_snapshot.choices, monkeypatch) == snapshot( """\ [ - ParsedChoice[object]( + ParsedChoice( finish_reason='tool_calls', index=0, logprobs=None, - message=ParsedChatCompletionMessage[object]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content=None, @@ -874,11 +874,11 @@ def test_parse_strict_tools(client: OpenAI, respx_mock: MockRouter, monkeypatch: assert print_obj(listener.stream.current_completion_snapshot.choices, monkeypatch) == snapshot( """\ [ - ParsedChoice[object]( + ParsedChoice( finish_reason='tool_calls', index=0, logprobs=None, - message=ParsedChatCompletionMessage[object]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content=None, @@ -926,11 +926,11 @@ def test_non_pydantic_response_format(client: OpenAI, respx_mock: MockRouter, mo assert print_obj(listener.stream.get_final_completion().choices, monkeypatch) == snapshot( """\ [ - ParsedChoice[NoneType]( + ParsedChoice( finish_reason='stop', index=0, logprobs=None, - message=ParsedChatCompletionMessage[NoneType]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content='\\n {\\n "location": "San Francisco, CA",\\n "weather": {\\n "temperature": "18°C",\\n @@ -987,11 +987,11 @@ def test_allows_non_strict_tools_but_no_parsing( assert print_obj(listener.stream.get_final_completion().choices, monkeypatch) == snapshot( """\ [ - ParsedChoice[NoneType]( + ParsedChoice( finish_reason='tool_calls', index=0, logprobs=None, - message=ParsedChatCompletionMessage[NoneType]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content=None, @@ -1047,11 +1047,11 @@ def streamer(client: OpenAI) -> Iterator[ChatCompletionChunk]: assert print_obj(state.get_final_completion().choices, monkeypatch) == snapshot( """\ [ - ParsedChoice[NoneType]( + ParsedChoice( finish_reason='stop', index=0, logprobs=None, - message=ParsedChatCompletionMessage[NoneType]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content="I'm unable to provide real-time weather updates. To get the current weather in San Francisco, I diff --git a/tests/lib/utils.py b/tests/lib/utils.py index e6b6a29434..0efdfca968 100644 --- a/tests/lib/utils.py +++ b/tests/lib/utils.py @@ -1,6 +1,6 @@ from __future__ import annotations -import inspect +import re from typing import Any, Iterable from typing_extensions import TypeAlias @@ -28,27 +28,7 @@ def __repr_args__(self: pydantic.BaseModel) -> ReprArgs: string = rich_print_str(obj) - # we remove all `fn_name..` occurrences - # so that we can share the same snapshots between - # pydantic v1 and pydantic v2 as their output for - # generic models differs, e.g. - # - # v2: `ParsedChatCompletion[test_parse_pydantic_model..Location]` - # v1: `ParsedChatCompletion[Location]` - return clear_locals(string, stacklevel=2) - - -def get_caller_name(*, stacklevel: int = 1) -> str: - frame = inspect.currentframe() - assert frame is not None - - for i in range(stacklevel): - frame = frame.f_back - assert frame is not None, f"no {i}th frame" - - return frame.f_code.co_name - - -def clear_locals(string: str, *, stacklevel: int) -> str: - caller = get_caller_name(stacklevel=stacklevel + 1) - return string.replace(f"{caller}..", "") + # Pydantic v1 and v2 have different implementations of __repr__ and print out + # generics differently, so we strip out generic type parameters to ensure + # consistent snapshot tests across both versions + return re.sub(r"([A-Za-z_]\w*)\[[^\[\]]+\](?=\()", r"\1", string) From 156d51801b051277708763124a1b7afe61ffa171 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 13 Feb 2026 23:25:40 +0000 Subject: [PATCH 622/769] docs: split `api.md` by standalone resources --- api.md | 382 +----------------- pyproject.toml | 2 +- src/openai/_client.py | 2 +- src/openai/_module_client.py | 2 +- src/openai/resources/conversations/api.md | 42 ++ src/openai/resources/realtime/api.md | 137 +++++++ src/openai/resources/responses/api.md | 175 ++++++++ src/openai/resources/webhooks/__init__.py | 5 + src/openai/resources/webhooks/api.md | 24 ++ .../resources/{ => webhooks}/webhooks.py | 12 +- tests/api_resources/webhooks/__init__.py | 1 + 11 files changed, 397 insertions(+), 387 deletions(-) create mode 100644 src/openai/resources/conversations/api.md create mode 100644 src/openai/resources/realtime/api.md create mode 100644 src/openai/resources/responses/api.md create mode 100644 src/openai/resources/webhooks/__init__.py create mode 100644 src/openai/resources/webhooks/api.md rename src/openai/resources/{ => webhooks}/webhooks.py (96%) create mode 100644 tests/api_resources/webhooks/__init__.py diff --git a/api.md b/api.md index 54fa94da5f..da521d3418 100644 --- a/api.md +++ b/api.md @@ -419,30 +419,7 @@ Methods: - client.vector_stores.file_batches.poll(\*args) -> VectorStoreFileBatch - client.vector_stores.file_batches.upload_and_poll(\*args) -> VectorStoreFileBatch -# Webhooks - -Types: - -```python -from openai.types.webhooks import ( - BatchCancelledWebhookEvent, - BatchCompletedWebhookEvent, - BatchExpiredWebhookEvent, - BatchFailedWebhookEvent, - EvalRunCanceledWebhookEvent, - EvalRunFailedWebhookEvent, - EvalRunSucceededWebhookEvent, - FineTuningJobCancelledWebhookEvent, - FineTuningJobFailedWebhookEvent, - FineTuningJobSucceededWebhookEvent, - RealtimeCallIncomingWebhookEvent, - ResponseCancelledWebhookEvent, - ResponseCompletedWebhookEvent, - ResponseFailedWebhookEvent, - ResponseIncompleteWebhookEvent, - UnwrapWebhookEvent, -) -``` +# [Webhooks](src/openai/resources/webhooks/api.md) Methods: @@ -727,362 +704,11 @@ Methods: - client.uploads.parts.create(upload_id, \*\*params) -> UploadPart -# Responses - -Types: - -```python -from openai.types.responses import ( - ApplyPatchTool, - CompactedResponse, - ComputerTool, - ContainerAuto, - ContainerNetworkPolicyAllowlist, - ContainerNetworkPolicyDisabled, - ContainerNetworkPolicyDomainSecret, - ContainerReference, - CustomTool, - EasyInputMessage, - FileSearchTool, - FunctionShellTool, - FunctionTool, - InlineSkill, - InlineSkillSource, - LocalEnvironment, - LocalSkill, - Response, - ResponseApplyPatchToolCall, - ResponseApplyPatchToolCallOutput, - ResponseAudioDeltaEvent, - ResponseAudioDoneEvent, - ResponseAudioTranscriptDeltaEvent, - ResponseAudioTranscriptDoneEvent, - ResponseCodeInterpreterCallCodeDeltaEvent, - ResponseCodeInterpreterCallCodeDoneEvent, - ResponseCodeInterpreterCallCompletedEvent, - ResponseCodeInterpreterCallInProgressEvent, - ResponseCodeInterpreterCallInterpretingEvent, - ResponseCodeInterpreterToolCall, - ResponseCompactionItem, - ResponseCompactionItemParam, - ResponseCompletedEvent, - ResponseComputerToolCall, - ResponseComputerToolCallOutputItem, - ResponseComputerToolCallOutputScreenshot, - ResponseContainerReference, - ResponseContent, - ResponseContentPartAddedEvent, - ResponseContentPartDoneEvent, - ResponseConversationParam, - ResponseCreatedEvent, - ResponseCustomToolCall, - ResponseCustomToolCallInputDeltaEvent, - ResponseCustomToolCallInputDoneEvent, - ResponseCustomToolCallOutput, - ResponseError, - ResponseErrorEvent, - ResponseFailedEvent, - ResponseFileSearchCallCompletedEvent, - ResponseFileSearchCallInProgressEvent, - ResponseFileSearchCallSearchingEvent, - ResponseFileSearchToolCall, - ResponseFormatTextConfig, - ResponseFormatTextJSONSchemaConfig, - ResponseFunctionCallArgumentsDeltaEvent, - ResponseFunctionCallArgumentsDoneEvent, - ResponseFunctionCallOutputItem, - ResponseFunctionCallOutputItemList, - ResponseFunctionShellCallOutputContent, - ResponseFunctionShellToolCall, - ResponseFunctionShellToolCallOutput, - ResponseFunctionToolCall, - ResponseFunctionToolCallItem, - ResponseFunctionToolCallOutputItem, - ResponseFunctionWebSearch, - ResponseImageGenCallCompletedEvent, - ResponseImageGenCallGeneratingEvent, - ResponseImageGenCallInProgressEvent, - ResponseImageGenCallPartialImageEvent, - ResponseInProgressEvent, - ResponseIncludable, - ResponseIncompleteEvent, - ResponseInput, - ResponseInputAudio, - ResponseInputContent, - ResponseInputFile, - ResponseInputFileContent, - ResponseInputImage, - ResponseInputImageContent, - ResponseInputItem, - ResponseInputMessageContentList, - ResponseInputMessageItem, - ResponseInputText, - ResponseInputTextContent, - ResponseItem, - ResponseLocalEnvironment, - ResponseMcpCallArgumentsDeltaEvent, - ResponseMcpCallArgumentsDoneEvent, - ResponseMcpCallCompletedEvent, - ResponseMcpCallFailedEvent, - ResponseMcpCallInProgressEvent, - ResponseMcpListToolsCompletedEvent, - ResponseMcpListToolsFailedEvent, - ResponseMcpListToolsInProgressEvent, - ResponseOutputAudio, - ResponseOutputItem, - ResponseOutputItemAddedEvent, - ResponseOutputItemDoneEvent, - ResponseOutputMessage, - ResponseOutputRefusal, - ResponseOutputText, - ResponseOutputTextAnnotationAddedEvent, - ResponsePrompt, - ResponseQueuedEvent, - ResponseReasoningItem, - ResponseReasoningSummaryPartAddedEvent, - ResponseReasoningSummaryPartDoneEvent, - ResponseReasoningSummaryTextDeltaEvent, - ResponseReasoningSummaryTextDoneEvent, - ResponseReasoningTextDeltaEvent, - ResponseReasoningTextDoneEvent, - ResponseRefusalDeltaEvent, - ResponseRefusalDoneEvent, - ResponseStatus, - ResponseStreamEvent, - ResponseTextConfig, - ResponseTextDeltaEvent, - ResponseTextDoneEvent, - ResponseUsage, - ResponseWebSearchCallCompletedEvent, - ResponseWebSearchCallInProgressEvent, - ResponseWebSearchCallSearchingEvent, - SkillReference, - Tool, - ToolChoiceAllowed, - ToolChoiceApplyPatch, - ToolChoiceCustom, - ToolChoiceFunction, - ToolChoiceMcp, - ToolChoiceOptions, - ToolChoiceShell, - ToolChoiceTypes, - WebSearchPreviewTool, - WebSearchTool, -) -``` - -Methods: - -- client.responses.create(\*\*params) -> Response -- client.responses.retrieve(response_id, \*\*params) -> Response -- client.responses.delete(response_id) -> None -- client.responses.cancel(response_id) -> Response -- client.responses.compact(\*\*params) -> CompactedResponse - -## InputItems - -Types: - -```python -from openai.types.responses import ResponseItemList -``` - -Methods: - -- client.responses.input_items.list(response_id, \*\*params) -> SyncCursorPage[ResponseItem] - -## InputTokens - -Types: - -```python -from openai.types.responses import InputTokenCountResponse -``` - -Methods: - -- client.responses.input_tokens.count(\*\*params) -> InputTokenCountResponse - -# Realtime - -Types: - -```python -from openai.types.realtime import ( - AudioTranscription, - ConversationCreatedEvent, - ConversationItem, - ConversationItemAdded, - ConversationItemCreateEvent, - ConversationItemCreatedEvent, - ConversationItemDeleteEvent, - ConversationItemDeletedEvent, - ConversationItemDone, - ConversationItemInputAudioTranscriptionCompletedEvent, - ConversationItemInputAudioTranscriptionDeltaEvent, - ConversationItemInputAudioTranscriptionFailedEvent, - ConversationItemInputAudioTranscriptionSegment, - ConversationItemRetrieveEvent, - ConversationItemTruncateEvent, - ConversationItemTruncatedEvent, - ConversationItemWithReference, - InputAudioBufferAppendEvent, - InputAudioBufferClearEvent, - InputAudioBufferClearedEvent, - InputAudioBufferCommitEvent, - InputAudioBufferCommittedEvent, - InputAudioBufferDtmfEventReceivedEvent, - InputAudioBufferSpeechStartedEvent, - InputAudioBufferSpeechStoppedEvent, - InputAudioBufferTimeoutTriggered, - LogProbProperties, - McpListToolsCompleted, - McpListToolsFailed, - McpListToolsInProgress, - NoiseReductionType, - OutputAudioBufferClearEvent, - RateLimitsUpdatedEvent, - RealtimeAudioConfig, - RealtimeAudioConfigInput, - RealtimeAudioConfigOutput, - RealtimeAudioFormats, - RealtimeAudioInputTurnDetection, - RealtimeClientEvent, - RealtimeConversationItemAssistantMessage, - RealtimeConversationItemFunctionCall, - RealtimeConversationItemFunctionCallOutput, - RealtimeConversationItemSystemMessage, - RealtimeConversationItemUserMessage, - RealtimeError, - RealtimeErrorEvent, - RealtimeFunctionTool, - RealtimeMcpApprovalRequest, - RealtimeMcpApprovalResponse, - RealtimeMcpListTools, - RealtimeMcpProtocolError, - RealtimeMcpToolCall, - RealtimeMcpToolExecutionError, - RealtimeMcphttpError, - RealtimeResponse, - RealtimeResponseCreateAudioOutput, - RealtimeResponseCreateMcpTool, - RealtimeResponseCreateParams, - RealtimeResponseStatus, - RealtimeResponseUsage, - RealtimeResponseUsageInputTokenDetails, - RealtimeResponseUsageOutputTokenDetails, - RealtimeServerEvent, - RealtimeSession, - RealtimeSessionCreateRequest, - RealtimeToolChoiceConfig, - RealtimeToolsConfig, - RealtimeToolsConfigUnion, - RealtimeTracingConfig, - RealtimeTranscriptionSessionAudio, - RealtimeTranscriptionSessionAudioInput, - RealtimeTranscriptionSessionAudioInputTurnDetection, - RealtimeTranscriptionSessionCreateRequest, - RealtimeTruncation, - RealtimeTruncationRetentionRatio, - ResponseAudioDeltaEvent, - ResponseAudioDoneEvent, - ResponseAudioTranscriptDeltaEvent, - ResponseAudioTranscriptDoneEvent, - ResponseCancelEvent, - ResponseContentPartAddedEvent, - ResponseContentPartDoneEvent, - ResponseCreateEvent, - ResponseCreatedEvent, - ResponseDoneEvent, - ResponseFunctionCallArgumentsDeltaEvent, - ResponseFunctionCallArgumentsDoneEvent, - ResponseMcpCallArgumentsDelta, - ResponseMcpCallArgumentsDone, - ResponseMcpCallCompleted, - ResponseMcpCallFailed, - ResponseMcpCallInProgress, - ResponseOutputItemAddedEvent, - ResponseOutputItemDoneEvent, - ResponseTextDeltaEvent, - ResponseTextDoneEvent, - SessionCreatedEvent, - SessionUpdateEvent, - SessionUpdatedEvent, - TranscriptionSessionUpdate, - TranscriptionSessionUpdatedEvent, -) -``` - -## ClientSecrets +# [Responses](src/openai/resources/responses/api.md) -Types: - -```python -from openai.types.realtime import ( - RealtimeSessionClientSecret, - RealtimeSessionCreateResponse, - RealtimeTranscriptionSessionCreateResponse, - RealtimeTranscriptionSessionTurnDetection, - ClientSecretCreateResponse, -) -``` - -Methods: - -- client.realtime.client_secrets.create(\*\*params) -> ClientSecretCreateResponse - -## Calls - -Methods: - -- client.realtime.calls.create(\*\*params) -> HttpxBinaryResponseContent -- client.realtime.calls.accept(call_id, \*\*params) -> None -- client.realtime.calls.hangup(call_id) -> None -- client.realtime.calls.refer(call_id, \*\*params) -> None -- client.realtime.calls.reject(call_id, \*\*params) -> None - -# Conversations - -Types: - -```python -from openai.types.conversations import ( - ComputerScreenshotContent, - Conversation, - ConversationDeleted, - ConversationDeletedResource, - Message, - SummaryTextContent, - TextContent, - InputTextContent, - OutputTextContent, - RefusalContent, - InputImageContent, - InputFileContent, -) -``` - -Methods: - -- client.conversations.create(\*\*params) -> Conversation -- client.conversations.retrieve(conversation_id) -> Conversation -- client.conversations.update(conversation_id, \*\*params) -> Conversation -- client.conversations.delete(conversation_id) -> ConversationDeletedResource - -## Items - -Types: - -```python -from openai.types.conversations import ConversationItem, ConversationItemList -``` - -Methods: +# [Realtime](src/openai/resources/realtime/api.md) -- client.conversations.items.create(conversation_id, \*\*params) -> ConversationItemList -- client.conversations.items.retrieve(item_id, \*, conversation_id, \*\*params) -> ConversationItem -- client.conversations.items.list(conversation_id, \*\*params) -> SyncConversationCursorPage[ConversationItem] -- client.conversations.items.delete(item_id, \*, conversation_id) -> Conversation +# [Conversations](src/openai/resources/conversations/api.md) # Evals diff --git a/pyproject.toml b/pyproject.toml index 326c715f08..ed8ee459cd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -84,7 +84,7 @@ format = { chain = [ # run formatting again to fix any inconsistencies when imports are stripped "format:ruff", ]} -"format:docs" = "python scripts/utils/ruffen-docs.py README.md api.md" +"format:docs" = "bash -c 'python scripts/utils/ruffen-docs.py README.md $(find . -type f -name api.md)'" "format:ruff" = "ruff format" "lint" = { chain = [ diff --git a/src/openai/_client.py b/src/openai/_client.py index 440a8a45c8..0399bbf742 100644 --- a/src/openai/_client.py +++ b/src/openai/_client.py @@ -63,7 +63,6 @@ from .resources.models import Models, AsyncModels from .resources.videos import Videos, AsyncVideos from .resources.batches import Batches, AsyncBatches - from .resources.webhooks import Webhooks, AsyncWebhooks from .resources.beta.beta import Beta, AsyncBeta from .resources.chat.chat import Chat, AsyncChat from .resources.embeddings import Embeddings, AsyncEmbeddings @@ -74,6 +73,7 @@ from .resources.skills.skills import Skills, AsyncSkills from .resources.uploads.uploads import Uploads, AsyncUploads from .resources.realtime.realtime import Realtime, AsyncRealtime + from .resources.webhooks.webhooks import Webhooks, AsyncWebhooks from .resources.responses.responses import Responses, AsyncResponses from .resources.containers.containers import Containers, AsyncContainers from .resources.fine_tuning.fine_tuning import FineTuning, AsyncFineTuning diff --git a/src/openai/_module_client.py b/src/openai/_module_client.py index 17bb9306aa..98901c0446 100644 --- a/src/openai/_module_client.py +++ b/src/openai/_module_client.py @@ -11,7 +11,6 @@ from .resources.models import Models from .resources.videos import Videos from .resources.batches import Batches - from .resources.webhooks import Webhooks from .resources.beta.beta import Beta from .resources.chat.chat import Chat from .resources.embeddings import Embeddings @@ -22,6 +21,7 @@ from .resources.skills.skills import Skills from .resources.uploads.uploads import Uploads from .resources.realtime.realtime import Realtime + from .resources.webhooks.webhooks import Webhooks from .resources.responses.responses import Responses from .resources.containers.containers import Containers from .resources.fine_tuning.fine_tuning import FineTuning diff --git a/src/openai/resources/conversations/api.md b/src/openai/resources/conversations/api.md new file mode 100644 index 0000000000..9e9181a367 --- /dev/null +++ b/src/openai/resources/conversations/api.md @@ -0,0 +1,42 @@ +# Conversations + +Types: + +```python +from openai.types.conversations import ( + ComputerScreenshotContent, + Conversation, + ConversationDeleted, + ConversationDeletedResource, + Message, + SummaryTextContent, + TextContent, + InputTextContent, + OutputTextContent, + RefusalContent, + InputImageContent, + InputFileContent, +) +``` + +Methods: + +- client.conversations.create(\*\*params) -> Conversation +- client.conversations.retrieve(conversation_id) -> Conversation +- client.conversations.update(conversation_id, \*\*params) -> Conversation +- client.conversations.delete(conversation_id) -> ConversationDeletedResource + +## Items + +Types: + +```python +from openai.types.conversations import ConversationItem, ConversationItemList +``` + +Methods: + +- client.conversations.items.create(conversation_id, \*\*params) -> ConversationItemList +- client.conversations.items.retrieve(item_id, \*, conversation_id, \*\*params) -> ConversationItem +- client.conversations.items.list(conversation_id, \*\*params) -> SyncConversationCursorPage[ConversationItem] +- client.conversations.items.delete(item_id, \*, conversation_id) -> Conversation diff --git a/src/openai/resources/realtime/api.md b/src/openai/resources/realtime/api.md new file mode 100644 index 0000000000..1a178384db --- /dev/null +++ b/src/openai/resources/realtime/api.md @@ -0,0 +1,137 @@ +# Realtime + +Types: + +```python +from openai.types.realtime import ( + AudioTranscription, + ConversationCreatedEvent, + ConversationItem, + ConversationItemAdded, + ConversationItemCreateEvent, + ConversationItemCreatedEvent, + ConversationItemDeleteEvent, + ConversationItemDeletedEvent, + ConversationItemDone, + ConversationItemInputAudioTranscriptionCompletedEvent, + ConversationItemInputAudioTranscriptionDeltaEvent, + ConversationItemInputAudioTranscriptionFailedEvent, + ConversationItemInputAudioTranscriptionSegment, + ConversationItemRetrieveEvent, + ConversationItemTruncateEvent, + ConversationItemTruncatedEvent, + ConversationItemWithReference, + InputAudioBufferAppendEvent, + InputAudioBufferClearEvent, + InputAudioBufferClearedEvent, + InputAudioBufferCommitEvent, + InputAudioBufferCommittedEvent, + InputAudioBufferDtmfEventReceivedEvent, + InputAudioBufferSpeechStartedEvent, + InputAudioBufferSpeechStoppedEvent, + InputAudioBufferTimeoutTriggered, + LogProbProperties, + McpListToolsCompleted, + McpListToolsFailed, + McpListToolsInProgress, + NoiseReductionType, + OutputAudioBufferClearEvent, + RateLimitsUpdatedEvent, + RealtimeAudioConfig, + RealtimeAudioConfigInput, + RealtimeAudioConfigOutput, + RealtimeAudioFormats, + RealtimeAudioInputTurnDetection, + RealtimeClientEvent, + RealtimeConversationItemAssistantMessage, + RealtimeConversationItemFunctionCall, + RealtimeConversationItemFunctionCallOutput, + RealtimeConversationItemSystemMessage, + RealtimeConversationItemUserMessage, + RealtimeError, + RealtimeErrorEvent, + RealtimeFunctionTool, + RealtimeMcpApprovalRequest, + RealtimeMcpApprovalResponse, + RealtimeMcpListTools, + RealtimeMcpProtocolError, + RealtimeMcpToolCall, + RealtimeMcpToolExecutionError, + RealtimeMcphttpError, + RealtimeResponse, + RealtimeResponseCreateAudioOutput, + RealtimeResponseCreateMcpTool, + RealtimeResponseCreateParams, + RealtimeResponseStatus, + RealtimeResponseUsage, + RealtimeResponseUsageInputTokenDetails, + RealtimeResponseUsageOutputTokenDetails, + RealtimeServerEvent, + RealtimeSession, + RealtimeSessionCreateRequest, + RealtimeToolChoiceConfig, + RealtimeToolsConfig, + RealtimeToolsConfigUnion, + RealtimeTracingConfig, + RealtimeTranscriptionSessionAudio, + RealtimeTranscriptionSessionAudioInput, + RealtimeTranscriptionSessionAudioInputTurnDetection, + RealtimeTranscriptionSessionCreateRequest, + RealtimeTruncation, + RealtimeTruncationRetentionRatio, + ResponseAudioDeltaEvent, + ResponseAudioDoneEvent, + ResponseAudioTranscriptDeltaEvent, + ResponseAudioTranscriptDoneEvent, + ResponseCancelEvent, + ResponseContentPartAddedEvent, + ResponseContentPartDoneEvent, + ResponseCreateEvent, + ResponseCreatedEvent, + ResponseDoneEvent, + ResponseFunctionCallArgumentsDeltaEvent, + ResponseFunctionCallArgumentsDoneEvent, + ResponseMcpCallArgumentsDelta, + ResponseMcpCallArgumentsDone, + ResponseMcpCallCompleted, + ResponseMcpCallFailed, + ResponseMcpCallInProgress, + ResponseOutputItemAddedEvent, + ResponseOutputItemDoneEvent, + ResponseTextDeltaEvent, + ResponseTextDoneEvent, + SessionCreatedEvent, + SessionUpdateEvent, + SessionUpdatedEvent, + TranscriptionSessionUpdate, + TranscriptionSessionUpdatedEvent, +) +``` + +## ClientSecrets + +Types: + +```python +from openai.types.realtime import ( + RealtimeSessionClientSecret, + RealtimeSessionCreateResponse, + RealtimeTranscriptionSessionCreateResponse, + RealtimeTranscriptionSessionTurnDetection, + ClientSecretCreateResponse, +) +``` + +Methods: + +- client.realtime.client_secrets.create(\*\*params) -> ClientSecretCreateResponse + +## Calls + +Methods: + +- client.realtime.calls.create(\*\*params) -> HttpxBinaryResponseContent +- client.realtime.calls.accept(call_id, \*\*params) -> None +- client.realtime.calls.hangup(call_id) -> None +- client.realtime.calls.refer(call_id, \*\*params) -> None +- client.realtime.calls.reject(call_id, \*\*params) -> None diff --git a/src/openai/resources/responses/api.md b/src/openai/resources/responses/api.md new file mode 100644 index 0000000000..6eb1b999fa --- /dev/null +++ b/src/openai/resources/responses/api.md @@ -0,0 +1,175 @@ +# Responses + +Types: + +```python +from openai.types.responses import ( + ApplyPatchTool, + CompactedResponse, + ComputerTool, + ContainerAuto, + ContainerNetworkPolicyAllowlist, + ContainerNetworkPolicyDisabled, + ContainerNetworkPolicyDomainSecret, + ContainerReference, + CustomTool, + EasyInputMessage, + FileSearchTool, + FunctionShellTool, + FunctionTool, + InlineSkill, + InlineSkillSource, + LocalEnvironment, + LocalSkill, + Response, + ResponseApplyPatchToolCall, + ResponseApplyPatchToolCallOutput, + ResponseAudioDeltaEvent, + ResponseAudioDoneEvent, + ResponseAudioTranscriptDeltaEvent, + ResponseAudioTranscriptDoneEvent, + ResponseCodeInterpreterCallCodeDeltaEvent, + ResponseCodeInterpreterCallCodeDoneEvent, + ResponseCodeInterpreterCallCompletedEvent, + ResponseCodeInterpreterCallInProgressEvent, + ResponseCodeInterpreterCallInterpretingEvent, + ResponseCodeInterpreterToolCall, + ResponseCompactionItem, + ResponseCompactionItemParam, + ResponseCompletedEvent, + ResponseComputerToolCall, + ResponseComputerToolCallOutputItem, + ResponseComputerToolCallOutputScreenshot, + ResponseContainerReference, + ResponseContent, + ResponseContentPartAddedEvent, + ResponseContentPartDoneEvent, + ResponseConversationParam, + ResponseCreatedEvent, + ResponseCustomToolCall, + ResponseCustomToolCallInputDeltaEvent, + ResponseCustomToolCallInputDoneEvent, + ResponseCustomToolCallOutput, + ResponseError, + ResponseErrorEvent, + ResponseFailedEvent, + ResponseFileSearchCallCompletedEvent, + ResponseFileSearchCallInProgressEvent, + ResponseFileSearchCallSearchingEvent, + ResponseFileSearchToolCall, + ResponseFormatTextConfig, + ResponseFormatTextJSONSchemaConfig, + ResponseFunctionCallArgumentsDeltaEvent, + ResponseFunctionCallArgumentsDoneEvent, + ResponseFunctionCallOutputItem, + ResponseFunctionCallOutputItemList, + ResponseFunctionShellCallOutputContent, + ResponseFunctionShellToolCall, + ResponseFunctionShellToolCallOutput, + ResponseFunctionToolCall, + ResponseFunctionToolCallItem, + ResponseFunctionToolCallOutputItem, + ResponseFunctionWebSearch, + ResponseImageGenCallCompletedEvent, + ResponseImageGenCallGeneratingEvent, + ResponseImageGenCallInProgressEvent, + ResponseImageGenCallPartialImageEvent, + ResponseInProgressEvent, + ResponseIncludable, + ResponseIncompleteEvent, + ResponseInput, + ResponseInputAudio, + ResponseInputContent, + ResponseInputFile, + ResponseInputFileContent, + ResponseInputImage, + ResponseInputImageContent, + ResponseInputItem, + ResponseInputMessageContentList, + ResponseInputMessageItem, + ResponseInputText, + ResponseInputTextContent, + ResponseItem, + ResponseLocalEnvironment, + ResponseMcpCallArgumentsDeltaEvent, + ResponseMcpCallArgumentsDoneEvent, + ResponseMcpCallCompletedEvent, + ResponseMcpCallFailedEvent, + ResponseMcpCallInProgressEvent, + ResponseMcpListToolsCompletedEvent, + ResponseMcpListToolsFailedEvent, + ResponseMcpListToolsInProgressEvent, + ResponseOutputAudio, + ResponseOutputItem, + ResponseOutputItemAddedEvent, + ResponseOutputItemDoneEvent, + ResponseOutputMessage, + ResponseOutputRefusal, + ResponseOutputText, + ResponseOutputTextAnnotationAddedEvent, + ResponsePrompt, + ResponseQueuedEvent, + ResponseReasoningItem, + ResponseReasoningSummaryPartAddedEvent, + ResponseReasoningSummaryPartDoneEvent, + ResponseReasoningSummaryTextDeltaEvent, + ResponseReasoningSummaryTextDoneEvent, + ResponseReasoningTextDeltaEvent, + ResponseReasoningTextDoneEvent, + ResponseRefusalDeltaEvent, + ResponseRefusalDoneEvent, + ResponseStatus, + ResponseStreamEvent, + ResponseTextConfig, + ResponseTextDeltaEvent, + ResponseTextDoneEvent, + ResponseUsage, + ResponseWebSearchCallCompletedEvent, + ResponseWebSearchCallInProgressEvent, + ResponseWebSearchCallSearchingEvent, + SkillReference, + Tool, + ToolChoiceAllowed, + ToolChoiceApplyPatch, + ToolChoiceCustom, + ToolChoiceFunction, + ToolChoiceMcp, + ToolChoiceOptions, + ToolChoiceShell, + ToolChoiceTypes, + WebSearchPreviewTool, + WebSearchTool, +) +``` + +Methods: + +- client.responses.create(\*\*params) -> Response +- client.responses.retrieve(response_id, \*\*params) -> Response +- client.responses.delete(response_id) -> None +- client.responses.cancel(response_id) -> Response +- client.responses.compact(\*\*params) -> CompactedResponse + +## InputItems + +Types: + +```python +from openai.types.responses import ResponseItemList +``` + +Methods: + +- client.responses.input_items.list(response_id, \*\*params) -> SyncCursorPage[ResponseItem] + +## InputTokens + +Types: + +```python +from openai.types.responses import InputTokenCountResponse +``` + +Methods: + +- client.responses.input_tokens.count(\*\*params) -> InputTokenCountResponse diff --git a/src/openai/resources/webhooks/__init__.py b/src/openai/resources/webhooks/__init__.py new file mode 100644 index 0000000000..ba241ddffc --- /dev/null +++ b/src/openai/resources/webhooks/__init__.py @@ -0,0 +1,5 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .webhooks import Webhooks, AsyncWebhooks + +__all__ = ["Webhooks", "AsyncWebhooks"] diff --git a/src/openai/resources/webhooks/api.md b/src/openai/resources/webhooks/api.md new file mode 100644 index 0000000000..8e3c312eb0 --- /dev/null +++ b/src/openai/resources/webhooks/api.md @@ -0,0 +1,24 @@ +# Webhooks + +Types: + +```python +from openai.types.webhooks import ( + BatchCancelledWebhookEvent, + BatchCompletedWebhookEvent, + BatchExpiredWebhookEvent, + BatchFailedWebhookEvent, + EvalRunCanceledWebhookEvent, + EvalRunFailedWebhookEvent, + EvalRunSucceededWebhookEvent, + FineTuningJobCancelledWebhookEvent, + FineTuningJobFailedWebhookEvent, + FineTuningJobSucceededWebhookEvent, + RealtimeCallIncomingWebhookEvent, + ResponseCancelledWebhookEvent, + ResponseCompletedWebhookEvent, + ResponseFailedWebhookEvent, + ResponseIncompleteWebhookEvent, + UnwrapWebhookEvent, +) +``` diff --git a/src/openai/resources/webhooks.py b/src/openai/resources/webhooks/webhooks.py similarity index 96% rename from src/openai/resources/webhooks.py rename to src/openai/resources/webhooks/webhooks.py index 3e13d3faae..8d99568aad 100644 --- a/src/openai/resources/webhooks.py +++ b/src/openai/resources/webhooks/webhooks.py @@ -9,12 +9,12 @@ import hashlib from typing import cast -from .._types import HeadersLike -from .._utils import get_required_header -from .._models import construct_type -from .._resource import SyncAPIResource, AsyncAPIResource -from .._exceptions import InvalidWebhookSignatureError -from ..types.webhooks.unwrap_webhook_event import UnwrapWebhookEvent +from ..._types import HeadersLike +from ..._utils import get_required_header +from ..._models import construct_type +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._exceptions import InvalidWebhookSignatureError +from ...types.webhooks.unwrap_webhook_event import UnwrapWebhookEvent __all__ = ["Webhooks", "AsyncWebhooks"] diff --git a/tests/api_resources/webhooks/__init__.py b/tests/api_resources/webhooks/__init__.py new file mode 100644 index 0000000000..fd8019a9a1 --- /dev/null +++ b/tests/api_resources/webhooks/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. From 3ddbb7ec8dde5ac28e37dcfff95477b9eb48be05 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 13 Feb 2026 19:13:18 +0000 Subject: [PATCH 623/769] feat(api): container network_policy and skills --- .stats.yml | 4 +-- src/openai/resources/containers/containers.py | 25 +++++++++++++++++++ .../resources/containers/files/files.py | 18 +++++++------ src/openai/types/container_create_params.py | 20 +++++++++++++-- src/openai/types/container_create_response.py | 17 +++++++++++-- src/openai/types/container_list_params.py | 3 +++ src/openai/types/container_list_response.py | 17 +++++++++++-- .../types/container_retrieve_response.py | 17 +++++++++++-- tests/api_resources/test_containers.py | 18 +++++++++++++ 9 files changed, 121 insertions(+), 18 deletions(-) diff --git a/.stats.yml b/.stats.yml index dcc9c27df3..1d0140eb64 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 148 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-1595c7e4e1d7bf7eae2e49ad800316e13b69ffb18bff2a2f55236fce792deb53.yml -openapi_spec_hash: c3a3a0d8d4bbf11179149244f017a6dc +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-0db5326a0fb6a30ffad9242c72872c3388ef927e8a4549ddd20aec3420541209.yml +openapi_spec_hash: 9523fe30739802e15c88f4e7aac44e7f config_hash: 948733484caf41e71093c6582dbc319c diff --git a/src/openai/resources/containers/containers.py b/src/openai/resources/containers/containers.py index 0cbb400d4a..216097d9c8 100644 --- a/src/openai/resources/containers/containers.py +++ b/src/openai/resources/containers/containers.py @@ -2,6 +2,7 @@ from __future__ import annotations +from typing import Iterable from typing_extensions import Literal import httpx @@ -61,6 +62,8 @@ def create( expires_after: container_create_params.ExpiresAfter | Omit = omit, file_ids: SequenceNotStr[str] | Omit = omit, memory_limit: Literal["1g", "4g", "16g", "64g"] | Omit = omit, + network_policy: container_create_params.NetworkPolicy | Omit = omit, + skills: Iterable[container_create_params.Skill] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -80,6 +83,10 @@ def create( memory_limit: Optional memory limit for the container. Defaults to "1g". + network_policy: Network access policy for the container. + + skills: An optional list of skills referenced by id or inline data. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -96,6 +103,8 @@ def create( "expires_after": expires_after, "file_ids": file_ids, "memory_limit": memory_limit, + "network_policy": network_policy, + "skills": skills, }, container_create_params.ContainerCreateParams, ), @@ -143,6 +152,7 @@ def list( *, after: str | Omit = omit, limit: int | Omit = omit, + name: str | Omit = omit, order: Literal["asc", "desc"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -164,6 +174,8 @@ def list( limit: A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 20. + name: Filter results by container name. + order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending order and `desc` for descending order. @@ -187,6 +199,7 @@ def list( { "after": after, "limit": limit, + "name": name, "order": order, }, container_list_params.ContainerListParams, @@ -261,6 +274,8 @@ async def create( expires_after: container_create_params.ExpiresAfter | Omit = omit, file_ids: SequenceNotStr[str] | Omit = omit, memory_limit: Literal["1g", "4g", "16g", "64g"] | Omit = omit, + network_policy: container_create_params.NetworkPolicy | Omit = omit, + skills: Iterable[container_create_params.Skill] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -280,6 +295,10 @@ async def create( memory_limit: Optional memory limit for the container. Defaults to "1g". + network_policy: Network access policy for the container. + + skills: An optional list of skills referenced by id or inline data. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -296,6 +315,8 @@ async def create( "expires_after": expires_after, "file_ids": file_ids, "memory_limit": memory_limit, + "network_policy": network_policy, + "skills": skills, }, container_create_params.ContainerCreateParams, ), @@ -343,6 +364,7 @@ def list( *, after: str | Omit = omit, limit: int | Omit = omit, + name: str | Omit = omit, order: Literal["asc", "desc"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -364,6 +386,8 @@ def list( limit: A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 20. + name: Filter results by container name. + order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending order and `desc` for descending order. @@ -387,6 +411,7 @@ def list( { "after": after, "limit": limit, + "name": name, "order": order, }, container_list_params.ContainerListParams, diff --git a/src/openai/resources/containers/files/files.py b/src/openai/resources/containers/files/files.py index a472cfc9f3..62659a5c3d 100644 --- a/src/openai/resources/containers/files/files.py +++ b/src/openai/resources/containers/files/files.py @@ -96,10 +96,11 @@ def create( } ) files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) - # It should be noted that the actual Content-Type header that will be - # sent to the server will contain a `boundary` parameter, e.g. - # multipart/form-data; boundary=---abc-- - extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} + if files: + # It should be noted that the actual Content-Type header that will be + # sent to the server will contain a `boundary` parameter, e.g. + # multipart/form-data; boundary=---abc-- + extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} return self._post( f"/containers/{container_id}/files", body=maybe_transform(body, file_create_params.FileCreateParams), @@ -309,10 +310,11 @@ async def create( } ) files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) - # It should be noted that the actual Content-Type header that will be - # sent to the server will contain a `boundary` parameter, e.g. - # multipart/form-data; boundary=---abc-- - extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} + if files: + # It should be noted that the actual Content-Type header that will be + # sent to the server will contain a `boundary` parameter, e.g. + # multipart/form-data; boundary=---abc-- + extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} return await self._post( f"/containers/{container_id}/files", body=await async_maybe_transform(body, file_create_params.FileCreateParams), diff --git a/src/openai/types/container_create_params.py b/src/openai/types/container_create_params.py index 47101ecdb6..63d28f3955 100644 --- a/src/openai/types/container_create_params.py +++ b/src/openai/types/container_create_params.py @@ -2,11 +2,16 @@ from __future__ import annotations -from typing_extensions import Literal, Required, TypedDict +from typing import Union, Iterable +from typing_extensions import Literal, Required, TypeAlias, TypedDict from .._types import SequenceNotStr +from .responses.inline_skill_param import InlineSkillParam +from .responses.skill_reference_param import SkillReferenceParam +from .responses.container_network_policy_disabled_param import ContainerNetworkPolicyDisabledParam +from .responses.container_network_policy_allowlist_param import ContainerNetworkPolicyAllowlistParam -__all__ = ["ContainerCreateParams", "ExpiresAfter"] +__all__ = ["ContainerCreateParams", "ExpiresAfter", "NetworkPolicy", "Skill"] class ContainerCreateParams(TypedDict, total=False): @@ -22,6 +27,12 @@ class ContainerCreateParams(TypedDict, total=False): memory_limit: Literal["1g", "4g", "16g", "64g"] """Optional memory limit for the container. Defaults to "1g".""" + network_policy: NetworkPolicy + """Network access policy for the container.""" + + skills: Iterable[Skill] + """An optional list of skills referenced by id or inline data.""" + class ExpiresAfter(TypedDict, total=False): """Container expiration time in seconds relative to the 'anchor' time.""" @@ -33,3 +44,8 @@ class ExpiresAfter(TypedDict, total=False): """ minutes: Required[int] + + +NetworkPolicy: TypeAlias = Union[ContainerNetworkPolicyDisabledParam, ContainerNetworkPolicyAllowlistParam] + +Skill: TypeAlias = Union[SkillReferenceParam, InlineSkillParam] diff --git a/src/openai/types/container_create_response.py b/src/openai/types/container_create_response.py index 0ebcc04062..34bc56ad13 100644 --- a/src/openai/types/container_create_response.py +++ b/src/openai/types/container_create_response.py @@ -1,11 +1,11 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional +from typing import List, Optional from typing_extensions import Literal from .._models import BaseModel -__all__ = ["ContainerCreateResponse", "ExpiresAfter"] +__all__ = ["ContainerCreateResponse", "ExpiresAfter", "NetworkPolicy"] class ExpiresAfter(BaseModel): @@ -22,6 +22,16 @@ class ExpiresAfter(BaseModel): """The number of minutes after the anchor before the container expires.""" +class NetworkPolicy(BaseModel): + """Network access policy for the container.""" + + type: Literal["allowlist", "disabled"] + """The network policy mode.""" + + allowed_domains: Optional[List[str]] = None + """Allowed outbound domains when `type` is `allowlist`.""" + + class ContainerCreateResponse(BaseModel): id: str """Unique identifier for the container.""" @@ -50,3 +60,6 @@ class ContainerCreateResponse(BaseModel): memory_limit: Optional[Literal["1g", "4g", "16g", "64g"]] = None """The memory limit configured for the container.""" + + network_policy: Optional[NetworkPolicy] = None + """Network access policy for the container.""" diff --git a/src/openai/types/container_list_params.py b/src/openai/types/container_list_params.py index 4821a87d18..01ec43af32 100644 --- a/src/openai/types/container_list_params.py +++ b/src/openai/types/container_list_params.py @@ -23,6 +23,9 @@ class ContainerListParams(TypedDict, total=False): Limit can range between 1 and 100, and the default is 20. """ + name: str + """Filter results by container name.""" + order: Literal["asc", "desc"] """Sort order by the `created_at` timestamp of the objects. diff --git a/src/openai/types/container_list_response.py b/src/openai/types/container_list_response.py index 8f39548201..bf572acd6b 100644 --- a/src/openai/types/container_list_response.py +++ b/src/openai/types/container_list_response.py @@ -1,11 +1,11 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional +from typing import List, Optional from typing_extensions import Literal from .._models import BaseModel -__all__ = ["ContainerListResponse", "ExpiresAfter"] +__all__ = ["ContainerListResponse", "ExpiresAfter", "NetworkPolicy"] class ExpiresAfter(BaseModel): @@ -22,6 +22,16 @@ class ExpiresAfter(BaseModel): """The number of minutes after the anchor before the container expires.""" +class NetworkPolicy(BaseModel): + """Network access policy for the container.""" + + type: Literal["allowlist", "disabled"] + """The network policy mode.""" + + allowed_domains: Optional[List[str]] = None + """Allowed outbound domains when `type` is `allowlist`.""" + + class ContainerListResponse(BaseModel): id: str """Unique identifier for the container.""" @@ -50,3 +60,6 @@ class ContainerListResponse(BaseModel): memory_limit: Optional[Literal["1g", "4g", "16g", "64g"]] = None """The memory limit configured for the container.""" + + network_policy: Optional[NetworkPolicy] = None + """Network access policy for the container.""" diff --git a/src/openai/types/container_retrieve_response.py b/src/openai/types/container_retrieve_response.py index 9ba3e18c3a..b5a6d350ff 100644 --- a/src/openai/types/container_retrieve_response.py +++ b/src/openai/types/container_retrieve_response.py @@ -1,11 +1,11 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional +from typing import List, Optional from typing_extensions import Literal from .._models import BaseModel -__all__ = ["ContainerRetrieveResponse", "ExpiresAfter"] +__all__ = ["ContainerRetrieveResponse", "ExpiresAfter", "NetworkPolicy"] class ExpiresAfter(BaseModel): @@ -22,6 +22,16 @@ class ExpiresAfter(BaseModel): """The number of minutes after the anchor before the container expires.""" +class NetworkPolicy(BaseModel): + """Network access policy for the container.""" + + type: Literal["allowlist", "disabled"] + """The network policy mode.""" + + allowed_domains: Optional[List[str]] = None + """Allowed outbound domains when `type` is `allowlist`.""" + + class ContainerRetrieveResponse(BaseModel): id: str """Unique identifier for the container.""" @@ -50,3 +60,6 @@ class ContainerRetrieveResponse(BaseModel): memory_limit: Optional[Literal["1g", "4g", "16g", "64g"]] = None """The memory limit configured for the container.""" + + network_policy: Optional[NetworkPolicy] = None + """Network access policy for the container.""" diff --git a/tests/api_resources/test_containers.py b/tests/api_resources/test_containers.py index cf173c7fd5..321d7778b0 100644 --- a/tests/api_resources/test_containers.py +++ b/tests/api_resources/test_containers.py @@ -39,6 +39,14 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: }, file_ids=["string"], memory_limit="1g", + network_policy={"type": "disabled"}, + skills=[ + { + "skill_id": "x", + "type": "skill_reference", + "version": "version", + } + ], ) assert_matches_type(ContainerCreateResponse, container, path=["response"]) @@ -114,6 +122,7 @@ def test_method_list_with_all_params(self, client: OpenAI) -> None: container = client.containers.list( after="after", limit=0, + name="name", order="asc", ) assert_matches_type(SyncCursorPage[ContainerListResponse], container, path=["response"]) @@ -199,6 +208,14 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> }, file_ids=["string"], memory_limit="1g", + network_policy={"type": "disabled"}, + skills=[ + { + "skill_id": "x", + "type": "skill_reference", + "version": "version", + } + ], ) assert_matches_type(ContainerCreateResponse, container, path=["response"]) @@ -274,6 +291,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> N container = await async_client.containers.list( after="after", limit=0, + name="name", order="asc", ) assert_matches_type(AsyncCursorPage[ContainerListResponse], container, path=["response"]) From e93f6cff4f542388409c25bf2fbb5e7ce28fec9c Mon Sep 17 00:00:00 2001 From: Alex Chang Date: Fri, 13 Feb 2026 18:46:01 -0500 Subject: [PATCH 624/769] fix(webhooks): preserve method visibility for compatibility checks --- src/openai/resources/webhooks/__init__.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/openai/resources/webhooks/__init__.py b/src/openai/resources/webhooks/__init__.py index ba241ddffc..371906299b 100644 --- a/src/openai/resources/webhooks/__init__.py +++ b/src/openai/resources/webhooks/__init__.py @@ -1,5 +1,13 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from .webhooks import Webhooks, AsyncWebhooks +from .webhooks import Webhooks as _Webhooks, AsyncWebhooks as _AsyncWebhooks + + +class Webhooks(_Webhooks): + pass + + +class AsyncWebhooks(_AsyncWebhooks): + pass __all__ = ["Webhooks", "AsyncWebhooks"] From 3e0c05b84a2056870abf3bd6a5e7849020209cc3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 13 Feb 2026 23:46:41 +0000 Subject: [PATCH 625/769] release: 2.21.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 25 +++++++++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 26b25a25e8..49df20d2b8 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.20.0" + ".": "2.21.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 39ed325e8e..6f558b3626 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,30 @@ # Changelog +## 2.21.0 (2026-02-13) + +Full Changelog: [v2.20.0...v2.21.0](https://github.com/openai/openai-python/compare/v2.20.0...v2.21.0) + +### Features + +* **api:** container network_policy and skills ([d19de2e](https://github.com/openai/openai-python/commit/d19de2ee5c74413f9dc52684b650df1898dee82b)) + + +### Bug Fixes + +* **structured outputs:** resolve memory leak in parse methods ([#2860](https://github.com/openai/openai-python/issues/2860)) ([6dcbe21](https://github.com/openai/openai-python/commit/6dcbe211f12f8470db542a5cb95724cb933786dd)) +* **webhooks:** preserve method visibility for compatibility checks ([44a8936](https://github.com/openai/openai-python/commit/44a8936d580b770f23fae79659101a27eadafad6)) + + +### Chores + +* **internal:** fix lint error on Python 3.14 ([534f215](https://github.com/openai/openai-python/commit/534f215941f504443d63509e872409a0b1236452)) + + +### Documentation + +* split `api.md` by standalone resources ([96e41b3](https://github.com/openai/openai-python/commit/96e41b398a110212ddec71436b2439343bea87d4)) +* update comment ([63def23](https://github.com/openai/openai-python/commit/63def23b7acd5c6dacf03337fe1bd08439d1dba8)) + ## 2.20.0 (2026-02-10) Full Changelog: [v2.19.0...v2.20.0](https://github.com/openai/openai-python/compare/v2.19.0...v2.20.0) diff --git a/pyproject.toml b/pyproject.toml index ed8ee459cd..fe2e394592 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.20.0" +version = "2.21.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 4987d1ca18..0d4ef7b71c 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__ = "2.20.0" # x-release-please-version +__version__ = "2.21.0" # x-release-please-version From 5047206f02c0470fbabac705e91bae9cb0911c52 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 18 Feb 2026 02:31:27 +0000 Subject: [PATCH 626/769] docs(api): enhance method descriptions across audio, chat, realtime, skills, uploads, videos --- .stats.yml | 4 +- src/openai/resources/audio/speech.py | 4 ++ src/openai/resources/audio/transcriptions.py | 18 +++++++++ src/openai/resources/beta/chatkit/sessions.py | 12 ++++-- src/openai/resources/beta/chatkit/threads.py | 16 ++++---- .../resources/chat/completions/completions.py | 18 +++++++++ src/openai/resources/completions.py | 18 +++++++++ .../resources/realtime/client_secrets.py | 28 ++++++++++++++ .../resources/responses/input_tokens.py | 10 ++++- src/openai/resources/responses/responses.py | 20 ++++++++-- src/openai/resources/skills/content.py | 4 +- src/openai/resources/skills/skills.py | 20 +++++----- .../resources/skills/versions/content.py | 4 +- .../resources/skills/versions/versions.py | 16 ++++---- src/openai/resources/uploads/uploads.py | 16 +++++++- src/openai/resources/videos.py | 38 ++++++++++--------- 16 files changed, 184 insertions(+), 62 deletions(-) diff --git a/.stats.yml b/.stats.yml index 1d0140eb64..0ab1454b8b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 148 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-0db5326a0fb6a30ffad9242c72872c3388ef927e8a4549ddd20aec3420541209.yml -openapi_spec_hash: 9523fe30739802e15c88f4e7aac44e7f +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-c20486f46004d6be2d280d7792c64d47fcea3e5b7fbbb50d3ffc6241aba653df.yml +openapi_spec_hash: bf1dbabc5a923d897309273183525c02 config_hash: 948733484caf41e71093c6582dbc319c diff --git a/src/openai/resources/audio/speech.py b/src/openai/resources/audio/speech.py index f2c8d635f3..96a32f9268 100644 --- a/src/openai/resources/audio/speech.py +++ b/src/openai/resources/audio/speech.py @@ -67,6 +67,8 @@ def create( """ Generates audio from the input text. + Returns the audio file content, or a stream of audio events. + Args: input: The text to generate audio for. The maximum length is 4096 characters. @@ -164,6 +166,8 @@ async def create( """ Generates audio from the input text. + Returns the audio file content, or a stream of audio events. + Args: input: The text to generate audio for. The maximum length is 4096 characters. diff --git a/src/openai/resources/audio/transcriptions.py b/src/openai/resources/audio/transcriptions.py index 599534855d..bc6e9f22de 100644 --- a/src/openai/resources/audio/transcriptions.py +++ b/src/openai/resources/audio/transcriptions.py @@ -85,6 +85,9 @@ def create( """ Transcribes audio into the input language. + Returns a transcription object in `json`, `diarized_json`, or `verbose_json` + format, or a stream of transcript events. + Args: file: The audio file object (not file name) to transcribe, in one of these formats: @@ -235,6 +238,9 @@ def create( """ Transcribes audio into the input language. + Returns a transcription object in `json`, `diarized_json`, or `verbose_json` + format, or a stream of transcript events. + Args: file: The audio file object (not file name) to transcribe, in one of these formats: @@ -343,6 +349,9 @@ def create( """ Transcribes audio into the input language. + Returns a transcription object in `json`, `diarized_json`, or `verbose_json` + format, or a stream of transcript events. + Args: file: The audio file object (not file name) to transcribe, in one of these formats: @@ -533,6 +542,9 @@ async def create( """ Transcribes audio into the input language. + Returns a transcription object in `json`, `diarized_json`, or `verbose_json` + format, or a stream of transcript events. + Args: file: The audio file object (not file name) to transcribe, in one of these formats: @@ -678,6 +690,9 @@ async def create( """ Transcribes audio into the input language. + Returns a transcription object in `json`, `diarized_json`, or `verbose_json` + format, or a stream of transcript events. + Args: file: The audio file object (not file name) to transcribe, in one of these formats: @@ -786,6 +801,9 @@ async def create( """ Transcribes audio into the input language. + Returns a transcription object in `json`, `diarized_json`, or `verbose_json` + format, or a stream of transcript events. + Args: file: The audio file object (not file name) to transcribe, in one of these formats: diff --git a/src/openai/resources/beta/chatkit/sessions.py b/src/openai/resources/beta/chatkit/sessions.py index a814f1058e..abfa496a56 100644 --- a/src/openai/resources/beta/chatkit/sessions.py +++ b/src/openai/resources/beta/chatkit/sessions.py @@ -63,7 +63,7 @@ def create( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ChatSession: """ - Create a ChatKit session + Create a ChatKit session. Args: user: A free-form string that identifies your end user; ensures this Session can @@ -117,7 +117,9 @@ def cancel( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ChatSession: """ - Cancel a ChatKit session + Cancel an active ChatKit session and return its most recent metadata. + + Cancelling prevents new requests from using the issued client secret. Args: extra_headers: Send extra headers @@ -176,7 +178,7 @@ async def create( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ChatSession: """ - Create a ChatKit session + Create a ChatKit session. Args: user: A free-form string that identifies your end user; ensures this Session can @@ -230,7 +232,9 @@ async def cancel( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ChatSession: """ - Cancel a ChatKit session + Cancel an active ChatKit session and return its most recent metadata. + + Cancelling prevents new requests from using the issued client secret. Args: extra_headers: Send extra headers diff --git a/src/openai/resources/beta/chatkit/threads.py b/src/openai/resources/beta/chatkit/threads.py index 37cd57295a..7a2d4c4a30 100644 --- a/src/openai/resources/beta/chatkit/threads.py +++ b/src/openai/resources/beta/chatkit/threads.py @@ -55,7 +55,7 @@ def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ChatKitThread: """ - Retrieve a ChatKit thread + Retrieve a ChatKit thread by its identifier. Args: extra_headers: Send extra headers @@ -93,7 +93,7 @@ def list( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncConversationCursorPage[ChatKitThread]: """ - List ChatKit threads + List ChatKit threads with optional pagination and user filters. Args: after: List items created after this thread item ID. Defaults to null for the first @@ -152,7 +152,7 @@ def delete( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ThreadDeleteResponse: """ - Delete a ChatKit thread + Delete a ChatKit thread along with its items and stored attachments. Args: extra_headers: Send extra headers @@ -190,7 +190,7 @@ def list_items( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncConversationCursorPage[Data]: """ - List ChatKit thread items + List items that belong to a ChatKit thread. Args: after: List items created after this thread item ID. Defaults to null for the first @@ -268,7 +268,7 @@ async def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ChatKitThread: """ - Retrieve a ChatKit thread + Retrieve a ChatKit thread by its identifier. Args: extra_headers: Send extra headers @@ -306,7 +306,7 @@ def list( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[ChatKitThread, AsyncConversationCursorPage[ChatKitThread]]: """ - List ChatKit threads + List ChatKit threads with optional pagination and user filters. Args: after: List items created after this thread item ID. Defaults to null for the first @@ -365,7 +365,7 @@ async def delete( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ThreadDeleteResponse: """ - Delete a ChatKit thread + Delete a ChatKit thread along with its items and stored attachments. Args: extra_headers: Send extra headers @@ -403,7 +403,7 @@ def list_items( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[Data, AsyncConversationCursorPage[Data]]: """ - List ChatKit thread items + List items that belong to a ChatKit thread. Args: after: List items created after this thread item ID. Defaults to null for the first diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index fb1887a7d5..e1fc531fa9 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -301,6 +301,9 @@ def create( unsupported parameters in reasoning models, [refer to the reasoning guide](https://platform.openai.com/docs/guides/reasoning). + Returns a chat completion object, or a streamed sequence of chat completion + chunk objects if the request is streamed. + Args: messages: A list of messages comprising the conversation so far. Depending on the [model](https://platform.openai.com/docs/models) you use, different message @@ -603,6 +606,9 @@ def create( unsupported parameters in reasoning models, [refer to the reasoning guide](https://platform.openai.com/docs/guides/reasoning). + Returns a chat completion object, or a streamed sequence of chat completion + chunk objects if the request is streamed. + Args: messages: A list of messages comprising the conversation so far. Depending on the [model](https://platform.openai.com/docs/models) you use, different message @@ -905,6 +911,9 @@ def create( unsupported parameters in reasoning models, [refer to the reasoning guide](https://platform.openai.com/docs/guides/reasoning). + Returns a chat completion object, or a streamed sequence of chat completion + chunk objects if the request is streamed. + Args: messages: A list of messages comprising the conversation so far. Depending on the [model](https://platform.openai.com/docs/models) you use, different message @@ -1785,6 +1794,9 @@ async def create( unsupported parameters in reasoning models, [refer to the reasoning guide](https://platform.openai.com/docs/guides/reasoning). + Returns a chat completion object, or a streamed sequence of chat completion + chunk objects if the request is streamed. + Args: messages: A list of messages comprising the conversation so far. Depending on the [model](https://platform.openai.com/docs/models) you use, different message @@ -2087,6 +2099,9 @@ async def create( unsupported parameters in reasoning models, [refer to the reasoning guide](https://platform.openai.com/docs/guides/reasoning). + Returns a chat completion object, or a streamed sequence of chat completion + chunk objects if the request is streamed. + Args: messages: A list of messages comprising the conversation so far. Depending on the [model](https://platform.openai.com/docs/models) you use, different message @@ -2389,6 +2404,9 @@ async def create( unsupported parameters in reasoning models, [refer to the reasoning guide](https://platform.openai.com/docs/guides/reasoning). + Returns a chat completion object, or a streamed sequence of chat completion + chunk objects if the request is streamed. + Args: messages: A list of messages comprising the conversation so far. Depending on the [model](https://platform.openai.com/docs/models) you use, different message diff --git a/src/openai/resources/completions.py b/src/openai/resources/completions.py index 2f2284a622..4b6e29395b 100644 --- a/src/openai/resources/completions.py +++ b/src/openai/resources/completions.py @@ -76,6 +76,9 @@ def create( """ Creates a completion for the provided prompt and parameters. + Returns a completion object, or a sequence of completion objects if the request + is streamed. + Args: model: ID of the model to use. You can use the [List models](https://platform.openai.com/docs/api-reference/models/list) API to @@ -231,6 +234,9 @@ def create( """ Creates a completion for the provided prompt and parameters. + Returns a completion object, or a sequence of completion objects if the request + is streamed. + Args: model: ID of the model to use. You can use the [List models](https://platform.openai.com/docs/api-reference/models/list) API to @@ -386,6 +392,9 @@ def create( """ Creates a completion for the provided prompt and parameters. + Returns a completion object, or a sequence of completion objects if the request + is streamed. + Args: model: ID of the model to use. You can use the [List models](https://platform.openai.com/docs/api-reference/models/list) API to @@ -626,6 +635,9 @@ async def create( """ Creates a completion for the provided prompt and parameters. + Returns a completion object, or a sequence of completion objects if the request + is streamed. + Args: model: ID of the model to use. You can use the [List models](https://platform.openai.com/docs/api-reference/models/list) API to @@ -781,6 +793,9 @@ async def create( """ Creates a completion for the provided prompt and parameters. + Returns a completion object, or a sequence of completion objects if the request + is streamed. + Args: model: ID of the model to use. You can use the [List models](https://platform.openai.com/docs/api-reference/models/list) API to @@ -936,6 +951,9 @@ async def create( """ Creates a completion for the provided prompt and parameters. + Returns a completion object, or a sequence of completion objects if the request + is streamed. + Args: model: ID of the model to use. You can use the [List models](https://platform.openai.com/docs/api-reference/models/list) API to diff --git a/src/openai/resources/realtime/client_secrets.py b/src/openai/resources/realtime/client_secrets.py index 5ceba7bef1..d9947dd7e8 100644 --- a/src/openai/resources/realtime/client_secrets.py +++ b/src/openai/resources/realtime/client_secrets.py @@ -52,6 +52,20 @@ def create( """ Create a Realtime client secret with an associated session configuration. + Client secrets are short-lived tokens that can be passed to a client app, such + as a web frontend or mobile client, which grants access to the Realtime API + without leaking your main API key. You can configure a custom TTL for each + client secret. + + You can also attach session configuration options to the client secret, which + will be applied to any sessions created using that client secret, but these can + also be overridden by the client connection. + + [Learn more about authentication with client secrets over WebRTC](https://platform.openai.com/docs/guides/realtime-webrtc). + + Returns the created client secret and the effective session object. The client + secret is a string that looks like `ek_1234`. + Args: expires_after: Configuration for the client secret expiration. Expiration refers to the time after which a client secret will no longer be valid for creating sessions. The @@ -120,6 +134,20 @@ async def create( """ Create a Realtime client secret with an associated session configuration. + Client secrets are short-lived tokens that can be passed to a client app, such + as a web frontend or mobile client, which grants access to the Realtime API + without leaking your main API key. You can configure a custom TTL for each + client secret. + + You can also attach session configuration options to the client secret, which + will be applied to any sessions created using that client secret, but these can + also be overridden by the client connection. + + [Learn more about authentication with client secrets over WebRTC](https://platform.openai.com/docs/guides/realtime-webrtc). + + Returns the created client secret and the effective session object. The client + secret is a string that looks like `ek_1234`. + Args: expires_after: Configuration for the client secret expiration. Expiration refers to the time after which a client secret will no longer be valid for creating sessions. The diff --git a/src/openai/resources/responses/input_tokens.py b/src/openai/resources/responses/input_tokens.py index 8664164655..0056727fa0 100644 --- a/src/openai/resources/responses/input_tokens.py +++ b/src/openai/resources/responses/input_tokens.py @@ -65,7 +65,10 @@ def count( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> InputTokenCountResponse: """ - Get input token counts + Returns input token counts of the request. + + Returns an object with `object` set to `response.input_tokens` and an + `input_tokens` count. Args: conversation: The conversation that this response belongs to. Items from this conversation are @@ -188,7 +191,10 @@ async def count( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> InputTokenCountResponse: """ - Get input token counts + Returns input token counts of the request. + + Returns an object with `object` set to `response.input_tokens` and an + `input_tokens` count. Args: conversation: The conversation that this response belongs to. Items from this conversation are diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 79034b7e18..4cb0e35cd3 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -1645,8 +1645,14 @@ def compact( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> CompactedResponse: - """ - Compact conversation + """Compact a conversation. + + Returns a compacted response object. + + Learn when and how to compact long-running conversations in the + [conversation state guide](https://platform.openai.com/docs/guides/conversation-state#managing-the-context-window). + For ZDR-compatible compaction details, see + [Compaction (advanced)](https://platform.openai.com/docs/guides/conversation-state#compaction-advanced). Args: model: Model ID used to generate the response, like `gpt-5` or `o3`. OpenAI offers a @@ -3280,8 +3286,14 @@ async def compact( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> CompactedResponse: - """ - Compact conversation + """Compact a conversation. + + Returns a compacted response object. + + Learn when and how to compact long-running conversations in the + [conversation state guide](https://platform.openai.com/docs/guides/conversation-state#managing-the-context-window). + For ZDR-compatible compaction details, see + [Compaction (advanced)](https://platform.openai.com/docs/guides/conversation-state#compaction-advanced). Args: model: Model ID used to generate the response, like `gpt-5` or `o3`. OpenAI offers a diff --git a/src/openai/resources/skills/content.py b/src/openai/resources/skills/content.py index 98c1531a94..c912fd3eb3 100644 --- a/src/openai/resources/skills/content.py +++ b/src/openai/resources/skills/content.py @@ -51,7 +51,7 @@ def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> _legacy_response.HttpxBinaryResponseContent: """ - Get Skill Content + Download a skill zip bundle by its ID. Args: extra_headers: Send extra headers @@ -106,7 +106,7 @@ async def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> _legacy_response.HttpxBinaryResponseContent: """ - Get Skill Content + Download a skill zip bundle by its ID. Args: extra_headers: Send extra headers diff --git a/src/openai/resources/skills/skills.py b/src/openai/resources/skills/skills.py index b0e929bccf..77bed029df 100644 --- a/src/openai/resources/skills/skills.py +++ b/src/openai/resources/skills/skills.py @@ -88,7 +88,7 @@ def create( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Skill: """ - Create Skill + Create a new skill. Args: files: Skill files to upload (directory upload) or a single zip file. @@ -130,7 +130,7 @@ def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Skill: """ - Get Skill + Get a skill by its ID. Args: extra_headers: Send extra headers @@ -164,7 +164,7 @@ def update( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Skill: """ - Update Skill Default Version + Update the default version pointer for a skill. Args: default_version: The skill version number to set as default. @@ -202,7 +202,7 @@ def list( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncCursorPage[Skill]: """ - List Skills + List all skills for the current project. Args: after: Identifier for the last item from the previous pagination request @@ -252,7 +252,7 @@ def delete( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> DeletedSkill: """ - Delete Skill + Delete a skill by its ID. Args: extra_headers: Send extra headers @@ -314,7 +314,7 @@ async def create( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Skill: """ - Create Skill + Create a new skill. Args: files: Skill files to upload (directory upload) or a single zip file. @@ -356,7 +356,7 @@ async def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Skill: """ - Get Skill + Get a skill by its ID. Args: extra_headers: Send extra headers @@ -390,7 +390,7 @@ async def update( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Skill: """ - Update Skill Default Version + Update the default version pointer for a skill. Args: default_version: The skill version number to set as default. @@ -430,7 +430,7 @@ def list( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[Skill, AsyncCursorPage[Skill]]: """ - List Skills + List all skills for the current project. Args: after: Identifier for the last item from the previous pagination request @@ -480,7 +480,7 @@ async def delete( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> DeletedSkill: """ - Delete Skill + Delete a skill by its ID. Args: extra_headers: Send extra headers diff --git a/src/openai/resources/skills/versions/content.py b/src/openai/resources/skills/versions/content.py index 4494ca0e2f..182a563dde 100644 --- a/src/openai/resources/skills/versions/content.py +++ b/src/openai/resources/skills/versions/content.py @@ -52,7 +52,7 @@ def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> _legacy_response.HttpxBinaryResponseContent: """ - Get Skill Version Content + Download a skill version zip bundle. Args: version: The skill version number. @@ -112,7 +112,7 @@ async def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> _legacy_response.HttpxBinaryResponseContent: """ - Get Skill Version Content + Download a skill version zip bundle. Args: version: The skill version number. diff --git a/src/openai/resources/skills/versions/versions.py b/src/openai/resources/skills/versions/versions.py index 890a20774e..610a24240a 100644 --- a/src/openai/resources/skills/versions/versions.py +++ b/src/openai/resources/skills/versions/versions.py @@ -78,7 +78,7 @@ def create( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SkillVersion: """ - Create Skill Version + Create a new immutable skill version. Args: default: Whether to set this version as the default. @@ -130,7 +130,7 @@ def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SkillVersion: """ - Get Skill Version + Get a specific skill version. Args: version: The version number to retrieve. @@ -170,7 +170,7 @@ def list( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncCursorPage[SkillVersion]: """ - List Skill Versions + List skill versions for a skill. Args: after: The skill version ID to start after. @@ -222,7 +222,7 @@ def delete( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> DeletedSkillVersion: """ - Delete Skill Version + Delete a skill version. Args: version: The skill version number. @@ -286,7 +286,7 @@ async def create( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SkillVersion: """ - Create Skill Version + Create a new immutable skill version. Args: default: Whether to set this version as the default. @@ -338,7 +338,7 @@ async def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SkillVersion: """ - Get Skill Version + Get a specific skill version. Args: version: The version number to retrieve. @@ -378,7 +378,7 @@ def list( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[SkillVersion, AsyncCursorPage[SkillVersion]]: """ - List Skill Versions + List skill versions for a skill. Args: after: The skill version ID to start after. @@ -430,7 +430,7 @@ async def delete( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> DeletedSkillVersion: """ - Delete Skill Version + Delete a skill version. Args: version: The skill version number. diff --git a/src/openai/resources/uploads/uploads.py b/src/openai/resources/uploads/uploads.py index e8c047bd4f..2873b913ba 100644 --- a/src/openai/resources/uploads/uploads.py +++ b/src/openai/resources/uploads/uploads.py @@ -198,6 +198,8 @@ def create( the documentation on [creating a File](https://platform.openai.com/docs/api-reference/files/create). + Returns the Upload object with status `pending`. + Args: bytes: The number of bytes in the file you are uploading. @@ -257,6 +259,8 @@ def cancel( No Parts may be added after an Upload is cancelled. + Returns the Upload object with status `cancelled`. + Args: extra_headers: Send extra headers @@ -302,7 +306,9 @@ def complete( The number of bytes uploaded upon completion must match the number of bytes initially specified when creating the Upload object. No Parts may be added after - an Upload is completed. + an Upload is completed. Returns the Upload object with status `completed`, + including an additional `file` property containing the created usable File + object. Args: part_ids: The ordered list of Part IDs. @@ -505,6 +511,8 @@ async def create( the documentation on [creating a File](https://platform.openai.com/docs/api-reference/files/create). + Returns the Upload object with status `pending`. + Args: bytes: The number of bytes in the file you are uploading. @@ -564,6 +572,8 @@ async def cancel( No Parts may be added after an Upload is cancelled. + Returns the Upload object with status `cancelled`. + Args: extra_headers: Send extra headers @@ -609,7 +619,9 @@ async def complete( The number of bytes uploaded upon completion must match the number of bytes initially specified when creating the Upload object. No Parts may be added after - an Upload is completed. + an Upload is completed. Returns the Upload object with status `completed`, + including an additional `file` property containing the created usable File + object. Args: part_ids: The ordered list of Part IDs. diff --git a/src/openai/resources/videos.py b/src/openai/resources/videos.py index 9f74c942bc..85ea79f8bc 100644 --- a/src/openai/resources/videos.py +++ b/src/openai/resources/videos.py @@ -76,7 +76,7 @@ def create( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Video: """ - Create a video + Create a new video generation job from a prompt and optional reference assets. Args: prompt: Text prompt that describes the video to generate. @@ -209,7 +209,7 @@ def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Video: """ - Retrieve a video + Fetch the latest metadata for a generated video. Args: extra_headers: Send extra headers @@ -244,7 +244,7 @@ def list( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncConversationCursorPage[Video]: """ - List videos + List recently generated videos for the current project. Args: after: Identifier for the last item from the previous pagination request @@ -294,7 +294,7 @@ def delete( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> VideoDeleteResponse: """ - Delete a video + Permanently delete a completed or failed video and its stored assets. Args: extra_headers: Send extra headers @@ -327,12 +327,13 @@ def download_content( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> _legacy_response.HttpxBinaryResponseContent: - """Download video content + """ + Download the generated video bytes or a derived preview asset. - Args: - variant: Which downloadable asset to return. + Streams the rendered video content for the specified video job. - Defaults to the MP4 video. + Args: + variant: Which downloadable asset to return. Defaults to the MP4 video. extra_headers: Send extra headers @@ -370,7 +371,7 @@ def remix( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Video: """ - Create a video remix + Create a remix of a completed video using a refreshed prompt. Args: prompt: Updated text prompt that directs the remix generation. @@ -431,7 +432,7 @@ async def create( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Video: """ - Create a video + Create a new video generation job from a prompt and optional reference assets. Args: prompt: Text prompt that describes the video to generate. @@ -564,7 +565,7 @@ async def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Video: """ - Retrieve a video + Fetch the latest metadata for a generated video. Args: extra_headers: Send extra headers @@ -599,7 +600,7 @@ def list( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[Video, AsyncConversationCursorPage[Video]]: """ - List videos + List recently generated videos for the current project. Args: after: Identifier for the last item from the previous pagination request @@ -649,7 +650,7 @@ async def delete( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> VideoDeleteResponse: """ - Delete a video + Permanently delete a completed or failed video and its stored assets. Args: extra_headers: Send extra headers @@ -682,12 +683,13 @@ async def download_content( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> _legacy_response.HttpxBinaryResponseContent: - """Download video content + """ + Download the generated video bytes or a derived preview asset. - Args: - variant: Which downloadable asset to return. + Streams the rendered video content for the specified video job. - Defaults to the MP4 video. + Args: + variant: Which downloadable asset to return. Defaults to the MP4 video. extra_headers: Send extra headers @@ -727,7 +729,7 @@ async def remix( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Video: """ - Create a video remix + Create a remix of a completed video using a refreshed prompt. Args: prompt: Updated text prompt that directs the remix generation. From d1efdc4abdd93d73994dba69293d5f235010c16c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 18 Feb 2026 02:54:17 +0000 Subject: [PATCH 627/769] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 0ab1454b8b..88bd7bd561 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 148 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-c20486f46004d6be2d280d7792c64d47fcea3e5b7fbbb50d3ffc6241aba653df.yml -openapi_spec_hash: bf1dbabc5a923d897309273183525c02 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-a6dd5f8d7318fb1c5370d5ccb7148bacdfb3f3a665c4b85b7666e6188d9bd909.yml +openapi_spec_hash: c4824e385a81b9021428304ccc96538f config_hash: 948733484caf41e71093c6582dbc319c From f82957313692ed99e321906780c57d4d99e737af Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 19 Feb 2026 16:38:04 +0000 Subject: [PATCH 628/769] chore: update mock server docs --- CONTRIBUTING.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c14e652328..3a1cf70bb8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -88,8 +88,7 @@ $ pip install ./path-to-wheel-file.whl Most tests require you to [set up a mock server](https://github.com/stoplightio/prism) against the OpenAPI spec to run the tests. ```sh -# you will need npm installed -$ npx prism mock path/to/your/openapi.yml +$ ./scripts/mock ``` ```sh From 5e5bc78aa1a8db86876635c786f127f242fdb0f1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Feb 2026 00:06:42 +0000 Subject: [PATCH 629/769] docs(api): update safety_identifier documentation in chat completions and responses --- .stats.yml | 4 +-- .../resources/chat/completions/completions.py | 30 +++++++++++-------- src/openai/resources/responses/responses.py | 30 +++++++++++-------- .../types/chat/completion_create_params.py | 5 ++-- src/openai/types/responses/response.py | 5 ++-- .../types/responses/response_create_params.py | 5 ++-- 6 files changed, 47 insertions(+), 32 deletions(-) diff --git a/.stats.yml b/.stats.yml index 88bd7bd561..af7cf829be 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 148 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-a6dd5f8d7318fb1c5370d5ccb7148bacdfb3f3a665c4b85b7666e6188d9bd909.yml -openapi_spec_hash: c4824e385a81b9021428304ccc96538f +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-0d1a3d48d59d864f24002e6e58a4cf38cb80ba1f4b234f6f766789e2866820c8.yml +openapi_spec_hash: 65fce2adfac759c10dc8bd51e09fa3db config_hash: 948733484caf41e71093c6582dbc319c diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index e1fc531fa9..5d56d05d87 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -439,8 +439,9 @@ def create( safety_identifier: A stable identifier used to help detect users of your application that may be violating OpenAI's usage policies. The IDs should be a string that uniquely - identifies each user. We recommend hashing their username or email address, in - order to avoid sending us any identifying information. + identifies each user, with a maximum length of 64 characters. We recommend + hashing their username or email address, in order to avoid sending us any + identifying information. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). seed: This feature is in Beta. If specified, our system will make a best effort to @@ -753,8 +754,9 @@ def create( safety_identifier: A stable identifier used to help detect users of your application that may be violating OpenAI's usage policies. The IDs should be a string that uniquely - identifies each user. We recommend hashing their username or email address, in - order to avoid sending us any identifying information. + identifies each user, with a maximum length of 64 characters. We recommend + hashing their username or email address, in order to avoid sending us any + identifying information. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). seed: This feature is in Beta. If specified, our system will make a best effort to @@ -1058,8 +1060,9 @@ def create( safety_identifier: A stable identifier used to help detect users of your application that may be violating OpenAI's usage policies. The IDs should be a string that uniquely - identifies each user. We recommend hashing their username or email address, in - order to avoid sending us any identifying information. + identifies each user, with a maximum length of 64 characters. We recommend + hashing their username or email address, in order to avoid sending us any + identifying information. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). seed: This feature is in Beta. If specified, our system will make a best effort to @@ -1932,8 +1935,9 @@ async def create( safety_identifier: A stable identifier used to help detect users of your application that may be violating OpenAI's usage policies. The IDs should be a string that uniquely - identifies each user. We recommend hashing their username or email address, in - order to avoid sending us any identifying information. + identifies each user, with a maximum length of 64 characters. We recommend + hashing their username or email address, in order to avoid sending us any + identifying information. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). seed: This feature is in Beta. If specified, our system will make a best effort to @@ -2246,8 +2250,9 @@ async def create( safety_identifier: A stable identifier used to help detect users of your application that may be violating OpenAI's usage policies. The IDs should be a string that uniquely - identifies each user. We recommend hashing their username or email address, in - order to avoid sending us any identifying information. + identifies each user, with a maximum length of 64 characters. We recommend + hashing their username or email address, in order to avoid sending us any + identifying information. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). seed: This feature is in Beta. If specified, our system will make a best effort to @@ -2551,8 +2556,9 @@ async def create( safety_identifier: A stable identifier used to help detect users of your application that may be violating OpenAI's usage policies. The IDs should be a string that uniquely - identifies each user. We recommend hashing their username or email address, in - order to avoid sending us any identifying information. + identifies each user, with a maximum length of 64 characters. We recommend + hashing their username or email address, in order to avoid sending us any + identifying information. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). seed: This feature is in Beta. If specified, our system will make a best effort to diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 4cb0e35cd3..3e1eb53d88 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -238,8 +238,9 @@ def create( safety_identifier: A stable identifier used to help detect users of your application that may be violating OpenAI's usage policies. The IDs should be a string that uniquely - identifies each user. We recommend hashing their username or email address, in - order to avoid sending us any identifying information. + identifies each user, with a maximum length of 64 characters. We recommend + hashing their username or email address, in order to avoid sending us any + identifying information. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). service_tier: Specifies the processing type used for serving the request. @@ -493,8 +494,9 @@ def create( safety_identifier: A stable identifier used to help detect users of your application that may be violating OpenAI's usage policies. The IDs should be a string that uniquely - identifies each user. We recommend hashing their username or email address, in - order to avoid sending us any identifying information. + identifies each user, with a maximum length of 64 characters. We recommend + hashing their username or email address, in order to avoid sending us any + identifying information. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). service_tier: Specifies the processing type used for serving the request. @@ -741,8 +743,9 @@ def create( safety_identifier: A stable identifier used to help detect users of your application that may be violating OpenAI's usage policies. The IDs should be a string that uniquely - identifies each user. We recommend hashing their username or email address, in - order to avoid sending us any identifying information. + identifies each user, with a maximum length of 64 characters. We recommend + hashing their username or email address, in order to avoid sending us any + identifying information. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). service_tier: Specifies the processing type used for serving the request. @@ -1875,8 +1878,9 @@ async def create( safety_identifier: A stable identifier used to help detect users of your application that may be violating OpenAI's usage policies. The IDs should be a string that uniquely - identifies each user. We recommend hashing their username or email address, in - order to avoid sending us any identifying information. + identifies each user, with a maximum length of 64 characters. We recommend + hashing their username or email address, in order to avoid sending us any + identifying information. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). service_tier: Specifies the processing type used for serving the request. @@ -2130,8 +2134,9 @@ async def create( safety_identifier: A stable identifier used to help detect users of your application that may be violating OpenAI's usage policies. The IDs should be a string that uniquely - identifies each user. We recommend hashing their username or email address, in - order to avoid sending us any identifying information. + identifies each user, with a maximum length of 64 characters. We recommend + hashing their username or email address, in order to avoid sending us any + identifying information. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). service_tier: Specifies the processing type used for serving the request. @@ -2378,8 +2383,9 @@ async def create( safety_identifier: A stable identifier used to help detect users of your application that may be violating OpenAI's usage policies. The IDs should be a string that uniquely - identifies each user. We recommend hashing their username or email address, in - order to avoid sending us any identifying information. + identifies each user, with a maximum length of 64 characters. We recommend + hashing their username or email address, in order to avoid sending us any + identifying information. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). service_tier: Specifies the processing type used for serving the request. diff --git a/src/openai/types/chat/completion_create_params.py b/src/openai/types/chat/completion_create_params.py index 49cefb95fc..8e71ccbe41 100644 --- a/src/openai/types/chat/completion_create_params.py +++ b/src/openai/types/chat/completion_create_params.py @@ -227,8 +227,9 @@ class CompletionCreateParamsBase(TypedDict, total=False): """ A stable identifier used to help detect users of your application that may be violating OpenAI's usage policies. The IDs should be a string that uniquely - identifies each user. We recommend hashing their username or email address, in - order to avoid sending us any identifying information. + identifies each user, with a maximum length of 64 characters. We recommend + hashing their username or email address, in order to avoid sending us any + identifying information. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). """ diff --git a/src/openai/types/responses/response.py b/src/openai/types/responses/response.py index 6bac7d65de..ada0783bce 100644 --- a/src/openai/types/responses/response.py +++ b/src/openai/types/responses/response.py @@ -233,8 +233,9 @@ class Response(BaseModel): """ A stable identifier used to help detect users of your application that may be violating OpenAI's usage policies. The IDs should be a string that uniquely - identifies each user. We recommend hashing their username or email address, in - order to avoid sending us any identifying information. + identifies each user, with a maximum length of 64 characters. We recommend + hashing their username or email address, in order to avoid sending us any + identifying information. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). """ diff --git a/src/openai/types/responses/response_create_params.py b/src/openai/types/responses/response_create_params.py index 97aaf9dc3a..0e78d1559b 100644 --- a/src/openai/types/responses/response_create_params.py +++ b/src/openai/types/responses/response_create_params.py @@ -171,8 +171,9 @@ class ResponseCreateParamsBase(TypedDict, total=False): """ A stable identifier used to help detect users of your application that may be violating OpenAI's usage policies. The IDs should be a string that uniquely - identifies each user. We recommend hashing their username or email address, in - order to avoid sending us any identifying information. + identifies each user, with a maximum length of 64 characters. We recommend + hashing their username or email address, in order to avoid sending us any + identifying information. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). """ From 849c8df45c8d295604031edfbfcf7e5ce4699c5a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Feb 2026 22:06:51 +0000 Subject: [PATCH 630/769] docs(api): add batch size limit to file_batches parameter descriptions --- .stats.yml | 4 ++-- src/openai/resources/vector_stores/file_batches.py | 12 ++++++++---- .../types/vector_stores/file_batch_create_params.py | 6 ++++-- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/.stats.yml b/.stats.yml index af7cf829be..3c69681b59 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 148 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-0d1a3d48d59d864f24002e6e58a4cf38cb80ba1f4b234f6f766789e2866820c8.yml -openapi_spec_hash: 65fce2adfac759c10dc8bd51e09fa3db +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-46434d15307c0a84fad213c705ba29ab7342f27aa377e302d506a51cb784613b.yml +openapi_spec_hash: 4a64f88af6142d69d6e01dc9207f232a config_hash: 948733484caf41e71093c6582dbc319c diff --git a/src/openai/resources/vector_stores/file_batches.py b/src/openai/resources/vector_stores/file_batches.py index fca1ef89fa..13ffa66d1a 100644 --- a/src/openai/resources/vector_stores/file_batches.py +++ b/src/openai/resources/vector_stores/file_batches.py @@ -79,12 +79,14 @@ def create( file_ids: A list of [File](https://platform.openai.com/docs/api-reference/files) IDs that the vector store should use. Useful for tools like `file_search` that can access files. If `attributes` or `chunking_strategy` are provided, they will be applied - to all files in the batch. Mutually exclusive with `files`. + to all files in the batch. The maximum batch size is 2000 files. Mutually + exclusive with `files`. files: A list of objects that each include a `file_id` plus optional `attributes` or `chunking_strategy`. Use this when you need to override metadata for specific files. The global `attributes` or `chunking_strategy` will be ignored and must - be specified for each file. Mutually exclusive with `file_ids`. + be specified for each file. The maximum batch size is 2000 files. Mutually + exclusive with `file_ids`. extra_headers: Send extra headers @@ -438,12 +440,14 @@ async def create( file_ids: A list of [File](https://platform.openai.com/docs/api-reference/files) IDs that the vector store should use. Useful for tools like `file_search` that can access files. If `attributes` or `chunking_strategy` are provided, they will be applied - to all files in the batch. Mutually exclusive with `files`. + to all files in the batch. The maximum batch size is 2000 files. Mutually + exclusive with `files`. files: A list of objects that each include a `file_id` plus optional `attributes` or `chunking_strategy`. Use this when you need to override metadata for specific files. The global `attributes` or `chunking_strategy` will be ignored and must - be specified for each file. Mutually exclusive with `file_ids`. + be specified for each file. The maximum batch size is 2000 files. Mutually + exclusive with `file_ids`. extra_headers: Send extra headers diff --git a/src/openai/types/vector_stores/file_batch_create_params.py b/src/openai/types/vector_stores/file_batch_create_params.py index 2ab98a83ab..7ca0de81da 100644 --- a/src/openai/types/vector_stores/file_batch_create_params.py +++ b/src/openai/types/vector_stores/file_batch_create_params.py @@ -33,7 +33,8 @@ class FileBatchCreateParams(TypedDict, total=False): A list of [File](https://platform.openai.com/docs/api-reference/files) IDs that the vector store should use. Useful for tools like `file_search` that can access files. If `attributes` or `chunking_strategy` are provided, they will be applied - to all files in the batch. Mutually exclusive with `files`. + to all files in the batch. The maximum batch size is 2000 files. Mutually + exclusive with `files`. """ files: Iterable[File] @@ -41,7 +42,8 @@ class FileBatchCreateParams(TypedDict, total=False): A list of objects that each include a `file_id` plus optional `attributes` or `chunking_strategy`. Use this when you need to override metadata for specific files. The global `attributes` or `chunking_strategy` will be ignored and must - be specified for each file. Mutually exclusive with `file_ids`. + be specified for each file. The maximum batch size is 2000 files. Mutually + exclusive with `file_ids`. """ From c612cfb2bbf8f119839c0625edee523dbf9f54d3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Feb 2026 13:36:19 +0000 Subject: [PATCH 631/769] chore(internal): add request options to SSE classes --- src/openai/_legacy_response.py | 3 +++ src/openai/_response.py | 3 +++ src/openai/_streaming.py | 11 ++++++++--- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/openai/_legacy_response.py b/src/openai/_legacy_response.py index cfabaa2fc2..1a58c2dfc3 100644 --- a/src/openai/_legacy_response.py +++ b/src/openai/_legacy_response.py @@ -221,6 +221,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: ), response=self.http_response, client=cast(Any, self._client), + options=self._options, ), ) @@ -231,6 +232,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: cast_to=extract_stream_chunk_type(self._stream_cls), response=self.http_response, client=cast(Any, self._client), + options=self._options, ), ) @@ -244,6 +246,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: cast_to=cast_to, response=self.http_response, client=cast(Any, self._client), + options=self._options, ), ) diff --git a/src/openai/_response.py b/src/openai/_response.py index 350da38dd4..f286d38e6c 100644 --- a/src/openai/_response.py +++ b/src/openai/_response.py @@ -152,6 +152,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: ), response=self.http_response, client=cast(Any, self._client), + options=self._options, ), ) @@ -162,6 +163,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: cast_to=extract_stream_chunk_type(self._stream_cls), response=self.http_response, client=cast(Any, self._client), + options=self._options, ), ) @@ -175,6 +177,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: cast_to=cast_to, response=self.http_response, client=cast(Any, self._client), + options=self._options, ), ) diff --git a/src/openai/_streaming.py b/src/openai/_streaming.py index 61a742668a..86b81c324f 100644 --- a/src/openai/_streaming.py +++ b/src/openai/_streaming.py @@ -4,7 +4,7 @@ import json import inspect from types import TracebackType -from typing import TYPE_CHECKING, Any, Generic, TypeVar, Iterator, AsyncIterator, cast +from typing import TYPE_CHECKING, Any, Generic, TypeVar, Iterator, Optional, AsyncIterator, cast from typing_extensions import Self, Protocol, TypeGuard, override, get_origin, runtime_checkable import httpx @@ -14,6 +14,7 @@ if TYPE_CHECKING: from ._client import OpenAI, AsyncOpenAI + from ._models import FinalRequestOptions _T = TypeVar("_T") @@ -23,7 +24,7 @@ class Stream(Generic[_T]): """Provides the core interface to iterate over a synchronous stream response.""" response: httpx.Response - + _options: Optional[FinalRequestOptions] = None _decoder: SSEBytesDecoder def __init__( @@ -32,10 +33,12 @@ def __init__( cast_to: type[_T], response: httpx.Response, client: OpenAI, + options: Optional[FinalRequestOptions] = None, ) -> None: self.response = response self._cast_to = cast_to self._client = client + self._options = options self._decoder = client._make_sse_decoder() self._iterator = self.__stream__() @@ -125,7 +128,7 @@ class AsyncStream(Generic[_T]): """Provides the core interface to iterate over an asynchronous stream response.""" response: httpx.Response - + _options: Optional[FinalRequestOptions] = None _decoder: SSEDecoder | SSEBytesDecoder def __init__( @@ -134,10 +137,12 @@ def __init__( cast_to: type[_T], response: httpx.Response, client: AsyncOpenAI, + options: Optional[FinalRequestOptions] = None, ) -> None: self.response = response self._cast_to = cast_to self._client = client + self._options = options self._decoder = client._make_sse_decoder() self._iterator = self.__stream__() From e273d622e85d7380f5ce715172c23d55ce8625a9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Feb 2026 19:56:46 +0000 Subject: [PATCH 632/769] feat(api): websockets for responses api --- .stats.yml | 6 +- examples/responses/websocket.py | 436 ++++++++++++++ src/openai/resources/responses/api.md | 2 + src/openai/resources/responses/responses.py | 547 +++++++++++++++++- src/openai/types/responses/__init__.py | 5 + .../responses/input_token_count_params.py | 4 +- .../responses/response_conversation_param.py | 8 +- .../response_conversation_param_param.py | 14 + .../types/responses/response_create_params.py | 4 +- src/openai/types/responses/response_input.py | 10 + .../types/responses/responses_client_event.py | 326 +++++++++++ .../responses/responses_client_event_param.py | 327 +++++++++++ .../types/responses/responses_server_event.py | 120 ++++ 13 files changed, 1794 insertions(+), 15 deletions(-) create mode 100644 examples/responses/websocket.py create mode 100644 src/openai/types/responses/response_conversation_param_param.py create mode 100644 src/openai/types/responses/response_input.py create mode 100644 src/openai/types/responses/responses_client_event.py create mode 100644 src/openai/types/responses/responses_client_event_param.py create mode 100644 src/openai/types/responses/responses_server_event.py diff --git a/.stats.yml b/.stats.yml index 3c69681b59..6d954e3ef8 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 148 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-46434d15307c0a84fad213c705ba29ab7342f27aa377e302d506a51cb784613b.yml -openapi_spec_hash: 4a64f88af6142d69d6e01dc9207f232a -config_hash: 948733484caf41e71093c6582dbc319c +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-95886b357a553078e7f15505fe1c518c7daf11506946049c75eadf89d44da863.yml +openapi_spec_hash: 8dfdf1e1d1dbe58b236b89203aa2a1b0 +config_hash: 4c2841519fd72fe44c18de4c18db231f diff --git a/examples/responses/websocket.py b/examples/responses/websocket.py new file mode 100644 index 0000000000..2c51d8ef02 --- /dev/null +++ b/examples/responses/websocket.py @@ -0,0 +1,436 @@ +from __future__ import annotations + +import json +import argparse +from typing import TYPE_CHECKING, Dict, Union, Literal, Optional, TypedDict, NamedTuple, cast + +from openai import OpenAI +from openai.types.responses import ( + FunctionToolParam, + ToolChoiceOptions, + ResponseInputParam, + ResponseFailedEvent, + ResponseCompletedEvent, + ResponseInputItemParam, + ResponseIncompleteEvent, + ToolChoiceFunctionParam, +) + +if TYPE_CHECKING: + from openai.resources.responses.responses import ResponsesConnection + +ToolName = Literal["get_sku_inventory", "get_supplier_eta", "get_quality_alerts"] +ToolChoice = Union[ToolChoiceOptions, ToolChoiceFunctionParam] + + +class DemoTurn(TypedDict): + tool_name: ToolName + prompt: str + + +class SKUArguments(TypedDict): + sku: str + + +class SKUInventoryOutput(TypedDict): + sku: str + warehouse: str + on_hand_units: int + reserved_units: int + reorder_point: int + safety_stock: int + + +class SupplierShipment(TypedDict): + shipment_id: str + eta_date: str + quantity: int + risk: str + + +class SupplierETAOutput(TypedDict): + sku: str + supplier_shipments: list[SupplierShipment] + + +class QualityAlert(TypedDict): + alert_id: str + status: str + severity: str + summary: str + + +class QualityAlertsOutput(TypedDict): + sku: str + alerts: list[QualityAlert] + + +class FunctionCallOutputItem(TypedDict): + type: Literal["function_call_output"] + call_id: str + output: str + + +class FunctionCallRequest(NamedTuple): + name: str + arguments_json: str + call_id: str + + +class RunResponseResult(NamedTuple): + text: str + response_id: str + function_calls: list[FunctionCallRequest] + + +class RunTurnResult(NamedTuple): + assistant_text: str + response_id: str + + +ToolOutput = Union[SKUInventoryOutput, SupplierETAOutput, QualityAlertsOutput] + +TOOLS: list[FunctionToolParam] = [ + { + "type": "function", + "name": "get_sku_inventory", + "description": "Return froge pond inventory details for a SKU.", + "strict": True, + "parameters": { + "type": "object", + "properties": { + "sku": { + "type": "string", + "description": "Stock-keeping unit identifier, such as sku-froge-lily-pad-deluxe.", + } + }, + "required": ["sku"], + "additionalProperties": False, + }, + }, + { + "type": "function", + "name": "get_supplier_eta", + "description": "Return tadpole supplier restock ETA data for a SKU.", + "strict": True, + "parameters": { + "type": "object", + "properties": { + "sku": { + "type": "string", + "description": "Stock-keeping unit identifier, such as sku-froge-lily-pad-deluxe.", + } + }, + "required": ["sku"], + "additionalProperties": False, + }, + }, + { + "type": "function", + "name": "get_quality_alerts", + "description": "Return recent froge quality alerts for a SKU.", + "strict": True, + "parameters": { + "type": "object", + "properties": { + "sku": { + "type": "string", + "description": "Stock-keeping unit identifier, such as sku-froge-lily-pad-deluxe.", + } + }, + "required": ["sku"], + "additionalProperties": False, + }, + }, +] + +DEMO_TURNS: list[DemoTurn] = [ + { + "tool_name": "get_sku_inventory", + "prompt": "Use get_sku_inventory for sku='sku-froge-lily-pad-deluxe' and summarize current pond stock health in one sentence.", + }, + { + "tool_name": "get_supplier_eta", + "prompt": "Now use get_supplier_eta for the same SKU and summarize restock ETA and tadpole shipment risk.", + }, + { + "tool_name": "get_quality_alerts", + "prompt": "Finally use get_quality_alerts for the same SKU and summarize unresolved froge quality concerns in one short paragraph.", + }, +] + +BETA_HEADER_VALUE = "responses_websockets=2026-02-06" + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + description=("Run a 3-turn Responses WebSocket demo with function calling and chained previous_response_id.") + ) + parser.add_argument("--model", default="gpt-5.2", help="Model used in the `response.create` payload.") + parser.add_argument( + "--use-beta-header", + action="store_true", + help=f"Include `OpenAI-Beta: {BETA_HEADER_VALUE}` for beta websocket behavior.", + ) + parser.add_argument( + "--show-events", + action="store_true", + help="Print non-text event types while streaming.", + ) + parser.add_argument( + "--show-tool-io", + action="store_true", + help="Print each tool call and tool output payload.", + ) + return parser.parse_args() + + +def parse_tool_name(name: str) -> ToolName: + if name not in {"get_sku_inventory", "get_supplier_eta", "get_quality_alerts"}: + raise ValueError(f"Unsupported tool requested: {name}") + return cast(ToolName, name) + + +def parse_sku_arguments(raw_arguments: str) -> SKUArguments: + parsed_raw = json.loads(raw_arguments) + if not isinstance(parsed_raw, dict): + raise ValueError(f"Tool arguments must be a JSON object: {raw_arguments}") + + parsed = cast(Dict[str, object], parsed_raw) + sku_value = parsed.get("sku") + if not isinstance(sku_value, str): + raise ValueError(f"Tool arguments must include a string `sku`: {raw_arguments}") + + return {"sku": sku_value} + + +def call_tool(name: ToolName, arguments: SKUArguments) -> ToolOutput: + sku = arguments["sku"] + + if name == "get_sku_inventory": + return { + "sku": sku, + "warehouse": "pond-west-1", + "on_hand_units": 84, + "reserved_units": 26, + "reorder_point": 60, + "safety_stock": 40, + } + + if name == "get_supplier_eta": + return { + "sku": sku, + "supplier_shipments": [ + { + "shipment_id": "frog_ship_2201", + "eta_date": "2026-02-24", + "quantity": 180, + "risk": "low", + }, + { + "shipment_id": "frog_ship_2205", + "eta_date": "2026-03-03", + "quantity": 220, + "risk": "medium", + }, + ], + } + + if name == "get_quality_alerts": + return { + "sku": sku, + "alerts": [ + { + "alert_id": "frog_qa_781", + "status": "open", + "severity": "high", + "summary": "Lily-pad coating chipping in lot LP-42", + }, + { + "alert_id": "frog_qa_795", + "status": "in_progress", + "severity": "medium", + "summary": "Pond-crate scuff rate above threshold", + }, + { + "alert_id": "frog_qa_802", + "status": "resolved", + "severity": "low", + "summary": "Froge label alignment issue corrected", + }, + ], + } + + raise ValueError(f"Unknown tool: {name}") + + +def run_response( + *, + connection: ResponsesConnection, + model: str, + previous_response_id: Optional[str], + input_payload: Union[str, ResponseInputParam], + tools: list[FunctionToolParam], + tool_choice: ToolChoice, + show_events: bool, +) -> RunResponseResult: + connection.response.create( + model=model, + input=input_payload, + stream=True, + previous_response_id=previous_response_id, + tools=tools, + tool_choice=tool_choice, + ) + + text_parts: list[str] = [] + function_calls: list[FunctionCallRequest] = [] + response_id: Optional[str] = None + + for event in connection: + if event.type == "response.output_text.delta": + text_parts.append(event.delta) + continue + + if event.type == "response.output_item.done" and event.item.type == "function_call": + function_calls.append( + FunctionCallRequest( + name=event.item.name, + arguments_json=event.item.arguments, + call_id=event.item.call_id, + ) + ) + continue + + if getattr(event, "type", None) == "error": + raise RuntimeError(f"WebSocket error event: {event!r}") + + if isinstance(event, (ResponseCompletedEvent, ResponseFailedEvent, ResponseIncompleteEvent)): + response_id = event.response.id + if not isinstance(event, ResponseCompletedEvent): + raise RuntimeError(f"Response ended with {event.type} (id={response_id})") + if show_events: + print(f"[{event.type}]") + break + + if getattr(event, "type", None) == "response.done": + # Responses over WebSocket currently emit `response.done` as the final event. + # The payload still includes `response.id`, which we use for chaining. + event_response = getattr(event, "response", None) + event_response_id: Optional[str] = None + if isinstance(event_response, dict): + event_response_dict = cast(Dict[str, object], event_response) + raw_event_response_id = event_response_dict.get("id") + if isinstance(raw_event_response_id, str): + event_response_id = raw_event_response_id + else: + raw_event_response_id = getattr(event_response, "id", None) + if isinstance(raw_event_response_id, str): + event_response_id = raw_event_response_id + + if not isinstance(event_response_id, str): + raise RuntimeError(f"response.done event did not include a valid response.id: {event!r}") + + response_id = event_response_id + if show_events: + print("[response.done]") + break + + if show_events: + print(f"[{event.type}]") + + if response_id is None: + raise RuntimeError("No terminal response event received.") + + return RunResponseResult( + text="".join(text_parts), + response_id=response_id, + function_calls=function_calls, + ) + + +def run_turn( + *, + connection: ResponsesConnection, + model: str, + previous_response_id: Optional[str], + turn_prompt: str, + forced_tool_name: ToolName, + show_events: bool, + show_tool_io: bool, +) -> RunTurnResult: + accumulated_text_parts: list[str] = [] + + current_input: Union[str, ResponseInputParam] = turn_prompt + current_tool_choice: ToolChoice = {"type": "function", "name": forced_tool_name} + current_previous_response_id = previous_response_id + + while True: + response_result = run_response( + connection=connection, + model=model, + previous_response_id=current_previous_response_id, + input_payload=current_input, + tools=TOOLS, + tool_choice=current_tool_choice, + show_events=show_events, + ) + + if response_result.text: + accumulated_text_parts.append(response_result.text) + + current_previous_response_id = response_result.response_id + if not response_result.function_calls: + break + + tool_outputs: ResponseInputParam = [] + for function_call in response_result.function_calls: + tool_name = parse_tool_name(function_call.name) + arguments = parse_sku_arguments(function_call.arguments_json) + output_payload = call_tool(tool_name, arguments) + if show_tool_io: + print(f"[tool_call] {function_call.name}({function_call.arguments_json})") + print(f"[tool_output] {json.dumps(output_payload)}") + + function_call_output: FunctionCallOutputItem = { + "type": "function_call_output", + "call_id": function_call.call_id, + "output": json.dumps(output_payload), + } + tool_outputs.append(cast(ResponseInputItemParam, function_call_output)) + + current_input = tool_outputs + current_tool_choice = "none" + + return RunTurnResult( + assistant_text="".join(accumulated_text_parts).strip(), + response_id=current_previous_response_id, + ) + + +def main() -> None: + args = parse_args() + + client = OpenAI() + extra_headers = {"OpenAI-Beta": BETA_HEADER_VALUE} if args.use_beta_header else {} + + with client.responses.connect(extra_headers=extra_headers) as connection: + previous_response_id: Optional[str] = None + for index, turn in enumerate(DEMO_TURNS, start=1): + print(f"\n=== Turn {index} ===") + print(f"User: {turn['prompt']}") + turn_result = run_turn( + connection=connection, + model=args.model, + previous_response_id=previous_response_id, + turn_prompt=turn["prompt"], + forced_tool_name=turn["tool_name"], + show_events=args.show_events, + show_tool_io=args.show_tool_io, + ) + previous_response_id = turn_result.response_id + print(f"Assistant: {turn_result.assistant_text}") + + +if __name__ == "__main__": + main() diff --git a/src/openai/resources/responses/api.md b/src/openai/resources/responses/api.md index 6eb1b999fa..36c95d7b83 100644 --- a/src/openai/resources/responses/api.md +++ b/src/openai/resources/responses/api.md @@ -127,6 +127,8 @@ from openai.types.responses import ( ResponseWebSearchCallCompletedEvent, ResponseWebSearchCallInProgressEvent, ResponseWebSearchCallSearchingEvent, + ResponsesClientEvent, + ResponsesServerEvent, SkillReference, Tool, ToolChoiceAllowed, diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 3e1eb53d88..2ad1e6716c 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -2,17 +2,22 @@ from __future__ import annotations +import json +import logging from copy import copy -from typing import Any, List, Type, Union, Iterable, Optional, cast +from types import TracebackType +from typing import TYPE_CHECKING, Any, List, Type, Union, Iterable, Iterator, Optional, AsyncIterator, cast from functools import partial from typing_extensions import Literal, overload import httpx +from pydantic import BaseModel from ... import _legacy_response from ..._types import NOT_GIVEN, Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given -from ..._utils import is_given, maybe_transform, async_maybe_transform +from ..._utils import is_given, maybe_transform, strip_not_given, async_maybe_transform from ..._compat import cached_property +from ..._models import construct_type_unchecked from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper from .input_items import ( @@ -33,11 +38,13 @@ InputTokensWithStreamingResponse, AsyncInputTokensWithStreamingResponse, ) -from ..._base_client import make_request_options +from ..._exceptions import OpenAIError +from ..._base_client import _merge_mappings, make_request_options from ...types.responses import ( response_create_params, response_compact_params, response_retrieve_params, + responses_client_event_param, ) from ...lib._parsing._responses import ( TextFormatT, @@ -51,16 +58,28 @@ from ...types.responses.parsed_response import ParsedResponse from ...lib.streaming.responses._responses import ResponseStreamManager, AsyncResponseStreamManager from ...types.responses.compacted_response import CompactedResponse +from ...types.websocket_connection_options import WebsocketConnectionOptions from ...types.responses.response_includable import ResponseIncludable from ...types.shared_params.responses_model import ResponsesModel from ...types.responses.response_input_param import ResponseInputParam from ...types.responses.response_prompt_param import ResponsePromptParam from ...types.responses.response_stream_event import ResponseStreamEvent +from ...types.responses.responses_client_event import ResponsesClientEvent +from ...types.responses.responses_server_event import ResponsesServerEvent from ...types.responses.response_input_item_param import ResponseInputItemParam from ...types.responses.response_text_config_param import ResponseTextConfigParam +from ...types.responses.responses_client_event_param import ResponsesClientEventParam + +if TYPE_CHECKING: + from websockets.sync.client import ClientConnection as WebsocketConnection + from websockets.asyncio.client import ClientConnection as AsyncWebsocketConnection + + from ..._client import OpenAI, AsyncOpenAI __all__ = ["Responses", "AsyncResponses"] +log: logging.Logger = logging.getLogger(__name__) + class Responses(SyncAPIResource): @cached_property @@ -1701,6 +1720,23 @@ def compact( cast_to=CompactedResponse, ) + def connect( + self, + extra_query: Query = {}, + extra_headers: Headers = {}, + websocket_connection_options: WebsocketConnectionOptions = {}, + ) -> ResponsesConnectionManager: + """Connect to a persistent Responses API WebSocket. + + Send `response.create` events and receive response stream events over the socket. + """ + return ResponsesConnectionManager( + client=self._client, + extra_query=extra_query, + extra_headers=extra_headers, + websocket_connection_options=websocket_connection_options, + ) + class AsyncResponses(AsyncAPIResource): @cached_property @@ -3345,6 +3381,23 @@ async def compact( cast_to=CompactedResponse, ) + def connect( + self, + extra_query: Query = {}, + extra_headers: Headers = {}, + websocket_connection_options: WebsocketConnectionOptions = {}, + ) -> AsyncResponsesConnectionManager: + """Connect to a persistent Responses API WebSocket. + + Send `response.create` events and receive response stream events over the socket. + """ + return AsyncResponsesConnectionManager( + client=self._client, + extra_query=extra_query, + extra_headers=extra_headers, + websocket_connection_options=websocket_connection_options, + ) + class ResponsesWithRawResponse: def __init__(self, responses: Responses) -> None: @@ -3504,3 +3557,491 @@ def _make_tools(tools: Iterable[ParseableToolParam] | Omit) -> List[ToolParam] | converted_tools.append(new_tool.cast()) return converted_tools + + +class AsyncResponsesConnection: + """Represents a live WebSocket connection to the Responses API""" + + response: AsyncResponsesResponseResource + + _connection: AsyncWebsocketConnection + + def __init__(self, connection: AsyncWebsocketConnection) -> None: + self._connection = connection + + self.response = AsyncResponsesResponseResource(self) + + async def __aiter__(self) -> AsyncIterator[ResponsesServerEvent]: + """ + An infinite-iterator that will continue to yield events until + the connection is closed. + """ + from websockets.exceptions import ConnectionClosedOK + + try: + while True: + yield await self.recv() + except ConnectionClosedOK: + return + + async def recv(self) -> ResponsesServerEvent: + """ + Receive the next message from the connection and parses it into a `ResponsesServerEvent` object. + + Canceling this method is safe. There's no risk of losing data. + """ + return self.parse_event(await self.recv_bytes()) + + async def recv_bytes(self) -> bytes: + """Receive the next message from the connection as raw bytes. + + Canceling this method is safe. There's no risk of losing data. + + If you want to parse the message into a `ResponsesServerEvent` object like `.recv()` does, + then you can call `.parse_event(data)`. + """ + message = await self._connection.recv(decode=False) + log.debug(f"Received websocket message: %s", message) + return message + + async def send(self, event: ResponsesClientEvent | ResponsesClientEventParam) -> None: + data = ( + event.to_json(use_api_names=True, exclude_defaults=True, exclude_unset=True) + if isinstance(event, BaseModel) + else json.dumps(await async_maybe_transform(event, ResponsesClientEventParam)) + ) + await self._connection.send(data) + + async def close(self, *, code: int = 1000, reason: str = "") -> None: + await self._connection.close(code=code, reason=reason) + + def parse_event(self, data: str | bytes) -> ResponsesServerEvent: + """ + Converts a raw `str` or `bytes` message into a `ResponsesServerEvent` object. + + This is helpful if you're using `.recv_bytes()`. + """ + return cast( + ResponsesServerEvent, + construct_type_unchecked(value=json.loads(data), type_=cast(Any, ResponsesServerEvent)), + ) + + +class AsyncResponsesConnectionManager: + """ + Context manager over a `AsyncResponsesConnection` that is returned by `responses.connect()` + + This context manager ensures that the connection will be closed when it exits. + + --- + + Note that if your application doesn't work well with the context manager approach then you + can call the `.enter()` method directly to initiate a connection. + + **Warning**: You must remember to close the connection with `.close()`. + + ```py + connection = await client.responses.connect(...).enter() + # ... + await connection.close() + ``` + """ + + def __init__( + self, + *, + client: AsyncOpenAI, + extra_query: Query, + extra_headers: Headers, + websocket_connection_options: WebsocketConnectionOptions, + ) -> None: + self.__client = client + self.__connection: AsyncResponsesConnection | None = None + self.__extra_query = extra_query + self.__extra_headers = extra_headers + self.__websocket_connection_options = websocket_connection_options + + async def __aenter__(self) -> AsyncResponsesConnection: + """ + 👋 If your application doesn't work well with the context manager approach then you + can call this method directly to initiate a connection. + + **Warning**: You must remember to close the connection with `.close()`. + + ```py + connection = await client.responses.connect(...).enter() + # ... + await connection.close() + ``` + """ + try: + from websockets.asyncio.client import connect + except ImportError as exc: + raise OpenAIError("You need to install `openai[realtime]` to use this method") from exc + + url = self._prepare_url().copy_with( + params={ + **self.__client.base_url.params, + **self.__extra_query, + }, + ) + log.debug("Connecting to %s", url) + if self.__websocket_connection_options: + log.debug("Connection options: %s", self.__websocket_connection_options) + + self.__connection = AsyncResponsesConnection( + await connect( + str(url), + user_agent_header=self.__client.user_agent, + additional_headers=_merge_mappings( + { + **self.__client.auth_headers, + }, + self.__extra_headers, + ), + **self.__websocket_connection_options, + ) + ) + + return self.__connection + + enter = __aenter__ + + def _prepare_url(self) -> httpx.URL: + if self.__client.websocket_base_url is not None: + base_url = httpx.URL(self.__client.websocket_base_url) + else: + base_url = self.__client._base_url.copy_with(scheme="wss") + + merge_raw_path = base_url.raw_path.rstrip(b"/") + b"/responses" + return base_url.copy_with(raw_path=merge_raw_path) + + async def __aexit__( + self, exc_type: type[BaseException] | None, exc: BaseException | None, exc_tb: TracebackType | None + ) -> None: + if self.__connection is not None: + await self.__connection.close() + + +class ResponsesConnection: + """Represents a live WebSocket connection to the Responses API""" + + response: ResponsesResponseResource + + _connection: WebsocketConnection + + def __init__(self, connection: WebsocketConnection) -> None: + self._connection = connection + + self.response = ResponsesResponseResource(self) + + def __iter__(self) -> Iterator[ResponsesServerEvent]: + """ + An infinite-iterator that will continue to yield events until + the connection is closed. + """ + from websockets.exceptions import ConnectionClosedOK + + try: + while True: + yield self.recv() + except ConnectionClosedOK: + return + + def recv(self) -> ResponsesServerEvent: + """ + Receive the next message from the connection and parses it into a `ResponsesServerEvent` object. + + Canceling this method is safe. There's no risk of losing data. + """ + return self.parse_event(self.recv_bytes()) + + def recv_bytes(self) -> bytes: + """Receive the next message from the connection as raw bytes. + + Canceling this method is safe. There's no risk of losing data. + + If you want to parse the message into a `ResponsesServerEvent` object like `.recv()` does, + then you can call `.parse_event(data)`. + """ + message = self._connection.recv(decode=False) + log.debug(f"Received websocket message: %s", message) + return message + + def send(self, event: ResponsesClientEvent | ResponsesClientEventParam) -> None: + data = ( + event.to_json(use_api_names=True, exclude_defaults=True, exclude_unset=True) + if isinstance(event, BaseModel) + else json.dumps(maybe_transform(event, ResponsesClientEventParam)) + ) + self._connection.send(data) + + def close(self, *, code: int = 1000, reason: str = "") -> None: + self._connection.close(code=code, reason=reason) + + def parse_event(self, data: str | bytes) -> ResponsesServerEvent: + """ + Converts a raw `str` or `bytes` message into a `ResponsesServerEvent` object. + + This is helpful if you're using `.recv_bytes()`. + """ + return cast( + ResponsesServerEvent, + construct_type_unchecked(value=json.loads(data), type_=cast(Any, ResponsesServerEvent)), + ) + + +class ResponsesConnectionManager: + """ + Context manager over a `ResponsesConnection` that is returned by `responses.connect()` + + This context manager ensures that the connection will be closed when it exits. + + --- + + Note that if your application doesn't work well with the context manager approach then you + can call the `.enter()` method directly to initiate a connection. + + **Warning**: You must remember to close the connection with `.close()`. + + ```py + connection = client.responses.connect(...).enter() + # ... + connection.close() + ``` + """ + + def __init__( + self, + *, + client: OpenAI, + extra_query: Query, + extra_headers: Headers, + websocket_connection_options: WebsocketConnectionOptions, + ) -> None: + self.__client = client + self.__connection: ResponsesConnection | None = None + self.__extra_query = extra_query + self.__extra_headers = extra_headers + self.__websocket_connection_options = websocket_connection_options + + def __enter__(self) -> ResponsesConnection: + """ + 👋 If your application doesn't work well with the context manager approach then you + can call this method directly to initiate a connection. + + **Warning**: You must remember to close the connection with `.close()`. + + ```py + connection = client.responses.connect(...).enter() + # ... + connection.close() + ``` + """ + try: + from websockets.sync.client import connect + except ImportError as exc: + raise OpenAIError("You need to install `openai[realtime]` to use this method") from exc + + url = self._prepare_url().copy_with( + params={ + **self.__client.base_url.params, + **self.__extra_query, + }, + ) + log.debug("Connecting to %s", url) + if self.__websocket_connection_options: + log.debug("Connection options: %s", self.__websocket_connection_options) + + self.__connection = ResponsesConnection( + connect( + str(url), + user_agent_header=self.__client.user_agent, + additional_headers=_merge_mappings( + { + **self.__client.auth_headers, + }, + self.__extra_headers, + ), + **self.__websocket_connection_options, + ) + ) + + return self.__connection + + enter = __enter__ + + def _prepare_url(self) -> httpx.URL: + if self.__client.websocket_base_url is not None: + base_url = httpx.URL(self.__client.websocket_base_url) + else: + base_url = self.__client._base_url.copy_with(scheme="wss") + + merge_raw_path = base_url.raw_path.rstrip(b"/") + b"/responses" + return base_url.copy_with(raw_path=merge_raw_path) + + def __exit__( + self, exc_type: type[BaseException] | None, exc: BaseException | None, exc_tb: TracebackType | None + ) -> None: + if self.__connection is not None: + self.__connection.close() + + +class BaseResponsesConnectionResource: + def __init__(self, connection: ResponsesConnection) -> None: + self._connection = connection + + +class ResponsesResponseResource(BaseResponsesConnectionResource): + def create( + self, + *, + background: Optional[bool] | Omit = omit, + context_management: Optional[Iterable[responses_client_event_param.ContextManagement]] | Omit = omit, + conversation: Optional[responses_client_event_param.Conversation] | Omit = omit, + include: Optional[List[ResponseIncludable]] | Omit = omit, + input: Union[str, ResponseInputParam] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_output_tokens: Optional[int] | Omit = omit, + max_tool_calls: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: ResponsesModel | Omit = omit, + parallel_tool_calls: Optional[bool] | Omit = omit, + previous_response_id: Optional[str] | Omit = omit, + prompt: Optional[ResponsePromptParam] | Omit = omit, + prompt_cache_key: str | Omit = omit, + prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, + reasoning: Optional[Reasoning] | Omit = omit, + safety_identifier: str | Omit = omit, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, + store: Optional[bool] | Omit = omit, + stream: Optional[bool] | Omit = omit, + stream_options: Optional[responses_client_event_param.StreamOptions] | Omit = omit, + temperature: Optional[float] | Omit = omit, + text: ResponseTextConfigParam | Omit = omit, + tool_choice: responses_client_event_param.ToolChoice | Omit = omit, + tools: Iterable[ToolParam] | Omit = omit, + top_logprobs: Optional[int] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation: Optional[Literal["auto", "disabled"]] | Omit = omit, + user: str | Omit = omit, + ) -> None: + self._connection.send( + cast( + ResponsesClientEventParam, + strip_not_given( + { + "type": "response.create", + "background": background, + "context_management": context_management, + "conversation": conversation, + "include": include, + "input": input, + "instructions": instructions, + "max_output_tokens": max_output_tokens, + "max_tool_calls": max_tool_calls, + "metadata": metadata, + "model": model, + "parallel_tool_calls": parallel_tool_calls, + "previous_response_id": previous_response_id, + "prompt": prompt, + "prompt_cache_key": prompt_cache_key, + "prompt_cache_retention": prompt_cache_retention, + "reasoning": reasoning, + "safety_identifier": safety_identifier, + "service_tier": service_tier, + "store": store, + "stream": stream, + "stream_options": stream_options, + "temperature": temperature, + "text": text, + "tool_choice": tool_choice, + "tools": tools, + "top_logprobs": top_logprobs, + "top_p": top_p, + "truncation": truncation, + "user": user, + } + ), + ) + ) + + +class BaseAsyncResponsesConnectionResource: + def __init__(self, connection: AsyncResponsesConnection) -> None: + self._connection = connection + + +class AsyncResponsesResponseResource(BaseAsyncResponsesConnectionResource): + async def create( + self, + *, + background: Optional[bool] | Omit = omit, + context_management: Optional[Iterable[responses_client_event_param.ContextManagement]] | Omit = omit, + conversation: Optional[responses_client_event_param.Conversation] | Omit = omit, + include: Optional[List[ResponseIncludable]] | Omit = omit, + input: Union[str, ResponseInputParam] | Omit = omit, + instructions: Optional[str] | Omit = omit, + max_output_tokens: Optional[int] | Omit = omit, + max_tool_calls: Optional[int] | Omit = omit, + metadata: Optional[Metadata] | Omit = omit, + model: ResponsesModel | Omit = omit, + parallel_tool_calls: Optional[bool] | Omit = omit, + previous_response_id: Optional[str] | Omit = omit, + prompt: Optional[ResponsePromptParam] | Omit = omit, + prompt_cache_key: str | Omit = omit, + prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, + reasoning: Optional[Reasoning] | Omit = omit, + safety_identifier: str | Omit = omit, + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, + store: Optional[bool] | Omit = omit, + stream: Optional[bool] | Omit = omit, + stream_options: Optional[responses_client_event_param.StreamOptions] | Omit = omit, + temperature: Optional[float] | Omit = omit, + text: ResponseTextConfigParam | Omit = omit, + tool_choice: responses_client_event_param.ToolChoice | Omit = omit, + tools: Iterable[ToolParam] | Omit = omit, + top_logprobs: Optional[int] | Omit = omit, + top_p: Optional[float] | Omit = omit, + truncation: Optional[Literal["auto", "disabled"]] | Omit = omit, + user: str | Omit = omit, + ) -> None: + await self._connection.send( + cast( + ResponsesClientEventParam, + strip_not_given( + { + "type": "response.create", + "background": background, + "context_management": context_management, + "conversation": conversation, + "include": include, + "input": input, + "instructions": instructions, + "max_output_tokens": max_output_tokens, + "max_tool_calls": max_tool_calls, + "metadata": metadata, + "model": model, + "parallel_tool_calls": parallel_tool_calls, + "previous_response_id": previous_response_id, + "prompt": prompt, + "prompt_cache_key": prompt_cache_key, + "prompt_cache_retention": prompt_cache_retention, + "reasoning": reasoning, + "safety_identifier": safety_identifier, + "service_tier": service_tier, + "store": store, + "stream": stream, + "stream_options": stream_options, + "temperature": temperature, + "text": text, + "tool_choice": tool_choice, + "tools": tools, + "top_logprobs": top_logprobs, + "top_p": top_p, + "truncation": truncation, + "user": user, + } + ), + ) + ) diff --git a/src/openai/types/responses/__init__.py b/src/openai/types/responses/__init__.py index cbb8deae95..de6f68989b 100644 --- a/src/openai/types/responses/__init__.py +++ b/src/openai/types/responses/__init__.py @@ -13,6 +13,7 @@ from .response_item import ResponseItem as ResponseItem from .container_auto import ContainerAuto as ContainerAuto from .response_error import ResponseError as ResponseError +from .response_input import ResponseInput as ResponseInput from .response_usage import ResponseUsage as ResponseUsage from .parsed_response import ( ParsedContent as ParsedContent, @@ -72,6 +73,8 @@ from .response_create_params import ResponseCreateParams as ResponseCreateParams from .response_created_event import ResponseCreatedEvent as ResponseCreatedEvent from .response_input_content import ResponseInputContent as ResponseInputContent +from .responses_client_event import ResponsesClientEvent as ResponsesClientEvent +from .responses_server_event import ResponsesServerEvent as ResponsesServerEvent from .local_environment_param import LocalEnvironmentParam as LocalEnvironmentParam from .response_compact_params import ResponseCompactParams as ResponseCompactParams from .response_output_message import ResponseOutputMessage as ResponseOutputMessage @@ -121,6 +124,7 @@ from .response_input_content_param import ResponseInputContentParam as ResponseInputContentParam from .response_input_image_content import ResponseInputImageContent as ResponseInputImageContent from .response_refusal_delta_event import ResponseRefusalDeltaEvent as ResponseRefusalDeltaEvent +from .responses_client_event_param import ResponsesClientEventParam as ResponsesClientEventParam from .response_output_message_param import ResponseOutputMessageParam as ResponseOutputMessageParam from .response_output_refusal_param import ResponseOutputRefusalParam as ResponseOutputRefusalParam from .response_reasoning_item_param import ResponseReasoningItemParam as ResponseReasoningItemParam @@ -139,6 +143,7 @@ from .container_network_policy_disabled import ContainerNetworkPolicyDisabled as ContainerNetworkPolicyDisabled from .response_computer_tool_call_param import ResponseComputerToolCallParam as ResponseComputerToolCallParam from .response_content_part_added_event import ResponseContentPartAddedEvent as ResponseContentPartAddedEvent +from .response_conversation_param_param import ResponseConversationParamParam as ResponseConversationParamParam from .response_format_text_config_param import ResponseFormatTextConfigParam as ResponseFormatTextConfigParam from .response_function_shell_tool_call import ResponseFunctionShellToolCall as ResponseFunctionShellToolCall from .response_function_tool_call_param import ResponseFunctionToolCallParam as ResponseFunctionToolCallParam diff --git a/src/openai/types/responses/input_token_count_params.py b/src/openai/types/responses/input_token_count_params.py index 97ee4bf6ca..f8a2026537 100644 --- a/src/openai/types/responses/input_token_count_params.py +++ b/src/openai/types/responses/input_token_count_params.py @@ -15,8 +15,8 @@ from .response_input_item_param import ResponseInputItemParam from .tool_choice_allowed_param import ToolChoiceAllowedParam from .tool_choice_function_param import ToolChoiceFunctionParam -from .response_conversation_param import ResponseConversationParam from .tool_choice_apply_patch_param import ToolChoiceApplyPatchParam +from .response_conversation_param_param import ResponseConversationParamParam from .response_format_text_config_param import ResponseFormatTextConfigParam __all__ = ["InputTokenCountParams", "Conversation", "Text", "ToolChoice"] @@ -97,7 +97,7 @@ class InputTokenCountParams(TypedDict, total=False): """ -Conversation: TypeAlias = Union[str, ResponseConversationParam] +Conversation: TypeAlias = Union[str, ResponseConversationParamParam] class Text(TypedDict, total=False): diff --git a/src/openai/types/responses/response_conversation_param.py b/src/openai/types/responses/response_conversation_param.py index d1587fe68a..7db4129bf4 100644 --- a/src/openai/types/responses/response_conversation_param.py +++ b/src/openai/types/responses/response_conversation_param.py @@ -1,14 +1,12 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from __future__ import annotations - -from typing_extensions import Required, TypedDict +from ..._models import BaseModel __all__ = ["ResponseConversationParam"] -class ResponseConversationParam(TypedDict, total=False): +class ResponseConversationParam(BaseModel): """The conversation that this response belongs to.""" - id: Required[str] + id: str """The unique ID of the conversation.""" diff --git a/src/openai/types/responses/response_conversation_param_param.py b/src/openai/types/responses/response_conversation_param_param.py new file mode 100644 index 0000000000..dba3628d0b --- /dev/null +++ b/src/openai/types/responses/response_conversation_param_param.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["ResponseConversationParamParam"] + + +class ResponseConversationParamParam(TypedDict, total=False): + """The conversation that this response belongs to.""" + + id: Required[str] + """The unique ID of the conversation.""" diff --git a/src/openai/types/responses/response_create_params.py b/src/openai/types/responses/response_create_params.py index 0e78d1559b..bf7170da1f 100644 --- a/src/openai/types/responses/response_create_params.py +++ b/src/openai/types/responses/response_create_params.py @@ -19,9 +19,9 @@ from .tool_choice_allowed_param import ToolChoiceAllowedParam from .response_text_config_param import ResponseTextConfigParam from .tool_choice_function_param import ToolChoiceFunctionParam -from .response_conversation_param import ResponseConversationParam from .tool_choice_apply_patch_param import ToolChoiceApplyPatchParam from ..shared_params.responses_model import ResponsesModel +from .response_conversation_param_param import ResponseConversationParamParam __all__ = [ "ResponseCreateParamsBase", @@ -292,7 +292,7 @@ class ContextManagement(TypedDict, total=False): """Token threshold at which compaction should be triggered for this entry.""" -Conversation: TypeAlias = Union[str, ResponseConversationParam] +Conversation: TypeAlias = Union[str, ResponseConversationParamParam] class StreamOptions(TypedDict, total=False): diff --git a/src/openai/types/responses/response_input.py b/src/openai/types/responses/response_input.py new file mode 100644 index 0000000000..e2180dec05 --- /dev/null +++ b/src/openai/types/responses/response_input.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .response_input_item import ResponseInputItem + +__all__ = ["ResponseInput"] + +ResponseInput: TypeAlias = List[ResponseInputItem] diff --git a/src/openai/types/responses/responses_client_event.py b/src/openai/types/responses/responses_client_event.py new file mode 100644 index 0000000000..2bc6f899c5 --- /dev/null +++ b/src/openai/types/responses/responses_client_event.py @@ -0,0 +1,326 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, TypeAlias + +from .tool import Tool +from ..._models import BaseModel +from .response_input import ResponseInput +from .response_prompt import ResponsePrompt +from .tool_choice_mcp import ToolChoiceMcp +from ..shared.metadata import Metadata +from ..shared.reasoning import Reasoning +from .tool_choice_shell import ToolChoiceShell +from .tool_choice_types import ToolChoiceTypes +from .tool_choice_custom import ToolChoiceCustom +from .response_includable import ResponseIncludable +from .tool_choice_allowed import ToolChoiceAllowed +from .tool_choice_options import ToolChoiceOptions +from .response_text_config import ResponseTextConfig +from .tool_choice_function import ToolChoiceFunction +from ..shared.responses_model import ResponsesModel +from .tool_choice_apply_patch import ToolChoiceApplyPatch +from .response_conversation_param import ResponseConversationParam + +__all__ = ["ResponsesClientEvent", "ContextManagement", "Conversation", "StreamOptions", "ToolChoice"] + + +class ContextManagement(BaseModel): + type: str + """The context management entry type. Currently only 'compaction' is supported.""" + + compact_threshold: Optional[int] = None + """Token threshold at which compaction should be triggered for this entry.""" + + +Conversation: TypeAlias = Union[str, ResponseConversationParam, None] + + +class StreamOptions(BaseModel): + """Options for streaming responses. Only set this when you set `stream: true`.""" + + include_obfuscation: Optional[bool] = None + """When true, stream obfuscation will be enabled. + + Stream obfuscation adds random characters to an `obfuscation` field on streaming + delta events to normalize payload sizes as a mitigation to certain side-channel + attacks. These obfuscation fields are included by default, but add a small + amount of overhead to the data stream. You can set `include_obfuscation` to + false to optimize for bandwidth if you trust the network links between your + application and the OpenAI API. + """ + + +ToolChoice: TypeAlias = Union[ + ToolChoiceOptions, + ToolChoiceAllowed, + ToolChoiceTypes, + ToolChoiceFunction, + ToolChoiceMcp, + ToolChoiceCustom, + ToolChoiceApplyPatch, + ToolChoiceShell, +] + + +class ResponsesClientEvent(BaseModel): + type: Literal["response.create"] + """The type of the client event. Always `response.create`.""" + + background: Optional[bool] = None + """ + Whether to run the model response in the background. + [Learn more](https://platform.openai.com/docs/guides/background). + """ + + context_management: Optional[List[ContextManagement]] = None + """Context management configuration for this request.""" + + conversation: Optional[Conversation] = None + """The conversation that this response belongs to. + + Items from this conversation are prepended to `input_items` for this response + request. Input items and output items from this response are automatically added + to this conversation after this response completes. + """ + + include: Optional[List[ResponseIncludable]] = None + """Specify additional output data to include in the model response. + + Currently supported values are: + + - `web_search_call.action.sources`: Include the sources of the web search tool + call. + - `code_interpreter_call.outputs`: Includes the outputs of python code execution + in code interpreter tool call items. + - `computer_call_output.output.image_url`: Include image urls from the computer + call output. + - `file_search_call.results`: Include the search results of the file search tool + call. + - `message.input_image.image_url`: Include image urls from the input message. + - `message.output_text.logprobs`: Include logprobs with assistant messages. + - `reasoning.encrypted_content`: Includes an encrypted version of reasoning + tokens in reasoning item outputs. This enables reasoning items to be used in + multi-turn conversations when using the Responses API statelessly (like when + the `store` parameter is set to `false`, or when an organization is enrolled + in the zero data retention program). + """ + + input: Union[str, ResponseInput, None] = None + """Text, image, or file inputs to the model, used to generate a response. + + Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Image inputs](https://platform.openai.com/docs/guides/images) + - [File inputs](https://platform.openai.com/docs/guides/pdf-files) + - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) + - [Function calling](https://platform.openai.com/docs/guides/function-calling) + """ + + instructions: Optional[str] = None + """A system (or developer) message inserted into the model's context. + + When using along with `previous_response_id`, the instructions from a previous + response will not be carried over to the next response. This makes it simple to + swap out system (or developer) messages in new responses. + """ + + max_output_tokens: Optional[int] = None + """ + An upper bound for the number of tokens that can be generated for a response, + including visible output tokens and + [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). + """ + + max_tool_calls: Optional[int] = None + """ + The maximum number of total calls to built-in tools that can be processed in a + response. This maximum number applies across all built-in tool calls, not per + individual tool. Any further attempts to call a tool by the model will be + ignored. + """ + + metadata: Optional[Metadata] = None + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + """ + + model: Optional[ResponsesModel] = None + """Model ID used to generate the response, like `gpt-4o` or `o3`. + + OpenAI offers a wide range of models with different capabilities, performance + characteristics, and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + """ + + parallel_tool_calls: Optional[bool] = None + """Whether to allow the model to run tool calls in parallel.""" + + previous_response_id: Optional[str] = None + """The unique ID of the previous response to the model. + + Use this to create multi-turn conversations. Learn more about + [conversation state](https://platform.openai.com/docs/guides/conversation-state). + Cannot be used in conjunction with `conversation`. + """ + + prompt: Optional[ResponsePrompt] = None + """ + Reference to a prompt template and its variables. + [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). + """ + + prompt_cache_key: Optional[str] = None + """ + Used by OpenAI to cache responses for similar requests to optimize your cache + hit rates. Replaces the `user` field. + [Learn more](https://platform.openai.com/docs/guides/prompt-caching). + """ + + prompt_cache_retention: Optional[Literal["in-memory", "24h"]] = None + """The retention policy for the prompt cache. + + Set to `24h` to enable extended prompt caching, which keeps cached prefixes + active for longer, up to a maximum of 24 hours. + [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). + """ + + reasoning: Optional[Reasoning] = None + """**gpt-5 and o-series models only** + + Configuration options for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). + """ + + safety_identifier: Optional[str] = None + """ + A stable identifier used to help detect users of your application that may be + violating OpenAI's usage policies. The IDs should be a string that uniquely + identifies each user, with a maximum length of 64 characters. We recommend + hashing their username or email address, in order to avoid sending us any + identifying information. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). + """ + + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] = None + """Specifies the processing type used for serving the request. + + - If set to 'auto', then the request will be processed with the service tier + configured in the Project settings. Unless otherwise configured, the Project + will use 'default'. + - If set to 'default', then the request will be processed with the standard + pricing and performance for the selected model. + - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or + '[priority](https://openai.com/api-priority-processing/)', then the request + will be processed with the corresponding service tier. + - When not set, the default behavior is 'auto'. + + When the `service_tier` parameter is set, the response body will include the + `service_tier` value based on the processing mode actually used to serve the + request. This response value may be different from the value set in the + parameter. + """ + + store: Optional[bool] = None + """Whether to store the generated model response for later retrieval via API.""" + + stream: Optional[bool] = None + """ + If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) + for more information. + """ + + stream_options: Optional[StreamOptions] = None + """Options for streaming responses. Only set this when you set `stream: true`.""" + + temperature: Optional[float] = None + """What sampling temperature to use, between 0 and 2. + + Higher values like 0.8 will make the output more random, while lower values like + 0.2 will make it more focused and deterministic. We generally recommend altering + this or `top_p` but not both. + """ + + text: Optional[ResponseTextConfig] = None + """Configuration options for a text response from the model. + + Can be plain text or structured JSON data. Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + """ + + tool_choice: Optional[ToolChoice] = None + """ + How the model should select which tool (or tools) to use when generating a + response. See the `tools` parameter to see how to specify which tools the model + can call. + """ + + tools: Optional[List[Tool]] = None + """An array of tools the model may call while generating a response. + + You can specify which tool to use by setting the `tool_choice` parameter. + + We support the following categories of tools: + + - **Built-in tools**: Tools that are provided by OpenAI that extend the model's + capabilities, like + [web search](https://platform.openai.com/docs/guides/tools-web-search) or + [file search](https://platform.openai.com/docs/guides/tools-file-search). + Learn more about + [built-in tools](https://platform.openai.com/docs/guides/tools). + - **MCP Tools**: Integrations with third-party systems via custom MCP servers or + predefined connectors such as Google Drive and SharePoint. Learn more about + [MCP Tools](https://platform.openai.com/docs/guides/tools-connectors-mcp). + - **Function calls (custom tools)**: Functions that are defined by you, enabling + the model to call your own code with strongly typed arguments and outputs. + Learn more about + [function calling](https://platform.openai.com/docs/guides/function-calling). + You can also use custom tools to call your own code. + """ + + top_logprobs: Optional[int] = None + """ + An integer between 0 and 20 specifying the number of most likely tokens to + return at each token position, each with an associated log probability. + """ + + top_p: Optional[float] = None + """ + An alternative to sampling with temperature, called nucleus sampling, where the + model considers the results of the tokens with top_p probability mass. So 0.1 + means only the tokens comprising the top 10% probability mass are considered. + + We generally recommend altering this or `temperature` but not both. + """ + + truncation: Optional[Literal["auto", "disabled"]] = None + """The truncation strategy to use for the model response. + + - `auto`: If the input to this Response exceeds the model's context window size, + the model will truncate the response to fit the context window by dropping + items from the beginning of the conversation. + - `disabled` (default): If the input size will exceed the context window size + for a model, the request will fail with a 400 error. + """ + + user: Optional[str] = None + """This field is being replaced by `safety_identifier` and `prompt_cache_key`. + + Use `prompt_cache_key` instead to maintain caching optimizations. A stable + identifier for your end-users. Used to boost cache hit rates by better bucketing + similar requests and to help OpenAI detect and prevent abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). + """ diff --git a/src/openai/types/responses/responses_client_event_param.py b/src/openai/types/responses/responses_client_event_param.py new file mode 100644 index 0000000000..08596ef9ea --- /dev/null +++ b/src/openai/types/responses/responses_client_event_param.py @@ -0,0 +1,327 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .tool_param import ToolParam +from .response_includable import ResponseIncludable +from .tool_choice_options import ToolChoiceOptions +from .response_input_param import ResponseInputParam +from .response_prompt_param import ResponsePromptParam +from .tool_choice_mcp_param import ToolChoiceMcpParam +from ..shared_params.metadata import Metadata +from .tool_choice_shell_param import ToolChoiceShellParam +from .tool_choice_types_param import ToolChoiceTypesParam +from ..shared_params.reasoning import Reasoning +from .tool_choice_custom_param import ToolChoiceCustomParam +from .tool_choice_allowed_param import ToolChoiceAllowedParam +from .response_text_config_param import ResponseTextConfigParam +from .tool_choice_function_param import ToolChoiceFunctionParam +from .tool_choice_apply_patch_param import ToolChoiceApplyPatchParam +from ..shared_params.responses_model import ResponsesModel +from .response_conversation_param_param import ResponseConversationParamParam + +__all__ = ["ResponsesClientEventParam", "ContextManagement", "Conversation", "StreamOptions", "ToolChoice"] + + +class ContextManagement(TypedDict, total=False): + type: Required[str] + """The context management entry type. Currently only 'compaction' is supported.""" + + compact_threshold: Optional[int] + """Token threshold at which compaction should be triggered for this entry.""" + + +Conversation: TypeAlias = Union[str, ResponseConversationParamParam] + + +class StreamOptions(TypedDict, total=False): + """Options for streaming responses. Only set this when you set `stream: true`.""" + + include_obfuscation: bool + """When true, stream obfuscation will be enabled. + + Stream obfuscation adds random characters to an `obfuscation` field on streaming + delta events to normalize payload sizes as a mitigation to certain side-channel + attacks. These obfuscation fields are included by default, but add a small + amount of overhead to the data stream. You can set `include_obfuscation` to + false to optimize for bandwidth if you trust the network links between your + application and the OpenAI API. + """ + + +ToolChoice: TypeAlias = Union[ + ToolChoiceOptions, + ToolChoiceAllowedParam, + ToolChoiceTypesParam, + ToolChoiceFunctionParam, + ToolChoiceMcpParam, + ToolChoiceCustomParam, + ToolChoiceApplyPatchParam, + ToolChoiceShellParam, +] + + +class ResponsesClientEventParam(TypedDict, total=False): + type: Required[Literal["response.create"]] + """The type of the client event. Always `response.create`.""" + + background: Optional[bool] + """ + Whether to run the model response in the background. + [Learn more](https://platform.openai.com/docs/guides/background). + """ + + context_management: Optional[Iterable[ContextManagement]] + """Context management configuration for this request.""" + + conversation: Optional[Conversation] + """The conversation that this response belongs to. + + Items from this conversation are prepended to `input_items` for this response + request. Input items and output items from this response are automatically added + to this conversation after this response completes. + """ + + include: Optional[List[ResponseIncludable]] + """Specify additional output data to include in the model response. + + Currently supported values are: + + - `web_search_call.action.sources`: Include the sources of the web search tool + call. + - `code_interpreter_call.outputs`: Includes the outputs of python code execution + in code interpreter tool call items. + - `computer_call_output.output.image_url`: Include image urls from the computer + call output. + - `file_search_call.results`: Include the search results of the file search tool + call. + - `message.input_image.image_url`: Include image urls from the input message. + - `message.output_text.logprobs`: Include logprobs with assistant messages. + - `reasoning.encrypted_content`: Includes an encrypted version of reasoning + tokens in reasoning item outputs. This enables reasoning items to be used in + multi-turn conversations when using the Responses API statelessly (like when + the `store` parameter is set to `false`, or when an organization is enrolled + in the zero data retention program). + """ + + input: Union[str, ResponseInputParam] + """Text, image, or file inputs to the model, used to generate a response. + + Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Image inputs](https://platform.openai.com/docs/guides/images) + - [File inputs](https://platform.openai.com/docs/guides/pdf-files) + - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) + - [Function calling](https://platform.openai.com/docs/guides/function-calling) + """ + + instructions: Optional[str] + """A system (or developer) message inserted into the model's context. + + When using along with `previous_response_id`, the instructions from a previous + response will not be carried over to the next response. This makes it simple to + swap out system (or developer) messages in new responses. + """ + + max_output_tokens: Optional[int] + """ + An upper bound for the number of tokens that can be generated for a response, + including visible output tokens and + [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). + """ + + max_tool_calls: Optional[int] + """ + The maximum number of total calls to built-in tools that can be processed in a + response. This maximum number applies across all built-in tool calls, not per + individual tool. Any further attempts to call a tool by the model will be + ignored. + """ + + metadata: Optional[Metadata] + """Set of 16 key-value pairs that can be attached to an object. + + This can be useful for storing additional information about the object in a + structured format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings with + a maximum length of 512 characters. + """ + + model: ResponsesModel + """Model ID used to generate the response, like `gpt-4o` or `o3`. + + OpenAI offers a wide range of models with different capabilities, performance + characteristics, and price points. Refer to the + [model guide](https://platform.openai.com/docs/models) to browse and compare + available models. + """ + + parallel_tool_calls: Optional[bool] + """Whether to allow the model to run tool calls in parallel.""" + + previous_response_id: Optional[str] + """The unique ID of the previous response to the model. + + Use this to create multi-turn conversations. Learn more about + [conversation state](https://platform.openai.com/docs/guides/conversation-state). + Cannot be used in conjunction with `conversation`. + """ + + prompt: Optional[ResponsePromptParam] + """ + Reference to a prompt template and its variables. + [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). + """ + + prompt_cache_key: str + """ + Used by OpenAI to cache responses for similar requests to optimize your cache + hit rates. Replaces the `user` field. + [Learn more](https://platform.openai.com/docs/guides/prompt-caching). + """ + + prompt_cache_retention: Optional[Literal["in-memory", "24h"]] + """The retention policy for the prompt cache. + + Set to `24h` to enable extended prompt caching, which keeps cached prefixes + active for longer, up to a maximum of 24 hours. + [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). + """ + + reasoning: Optional[Reasoning] + """**gpt-5 and o-series models only** + + Configuration options for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). + """ + + safety_identifier: str + """ + A stable identifier used to help detect users of your application that may be + violating OpenAI's usage policies. The IDs should be a string that uniquely + identifies each user, with a maximum length of 64 characters. We recommend + hashing their username or email address, in order to avoid sending us any + identifying information. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). + """ + + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] + """Specifies the processing type used for serving the request. + + - If set to 'auto', then the request will be processed with the service tier + configured in the Project settings. Unless otherwise configured, the Project + will use 'default'. + - If set to 'default', then the request will be processed with the standard + pricing and performance for the selected model. + - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or + '[priority](https://openai.com/api-priority-processing/)', then the request + will be processed with the corresponding service tier. + - When not set, the default behavior is 'auto'. + + When the `service_tier` parameter is set, the response body will include the + `service_tier` value based on the processing mode actually used to serve the + request. This response value may be different from the value set in the + parameter. + """ + + store: Optional[bool] + """Whether to store the generated model response for later retrieval via API.""" + + stream: Optional[bool] + """ + If set to true, the model response data will be streamed to the client as it is + generated using + [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + See the + [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) + for more information. + """ + + stream_options: Optional[StreamOptions] + """Options for streaming responses. Only set this when you set `stream: true`.""" + + temperature: Optional[float] + """What sampling temperature to use, between 0 and 2. + + Higher values like 0.8 will make the output more random, while lower values like + 0.2 will make it more focused and deterministic. We generally recommend altering + this or `top_p` but not both. + """ + + text: ResponseTextConfigParam + """Configuration options for a text response from the model. + + Can be plain text or structured JSON data. Learn more: + + - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) + - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) + """ + + tool_choice: ToolChoice + """ + How the model should select which tool (or tools) to use when generating a + response. See the `tools` parameter to see how to specify which tools the model + can call. + """ + + tools: Iterable[ToolParam] + """An array of tools the model may call while generating a response. + + You can specify which tool to use by setting the `tool_choice` parameter. + + We support the following categories of tools: + + - **Built-in tools**: Tools that are provided by OpenAI that extend the model's + capabilities, like + [web search](https://platform.openai.com/docs/guides/tools-web-search) or + [file search](https://platform.openai.com/docs/guides/tools-file-search). + Learn more about + [built-in tools](https://platform.openai.com/docs/guides/tools). + - **MCP Tools**: Integrations with third-party systems via custom MCP servers or + predefined connectors such as Google Drive and SharePoint. Learn more about + [MCP Tools](https://platform.openai.com/docs/guides/tools-connectors-mcp). + - **Function calls (custom tools)**: Functions that are defined by you, enabling + the model to call your own code with strongly typed arguments and outputs. + Learn more about + [function calling](https://platform.openai.com/docs/guides/function-calling). + You can also use custom tools to call your own code. + """ + + top_logprobs: Optional[int] + """ + An integer between 0 and 20 specifying the number of most likely tokens to + return at each token position, each with an associated log probability. + """ + + top_p: Optional[float] + """ + An alternative to sampling with temperature, called nucleus sampling, where the + model considers the results of the tokens with top_p probability mass. So 0.1 + means only the tokens comprising the top 10% probability mass are considered. + + We generally recommend altering this or `temperature` but not both. + """ + + truncation: Optional[Literal["auto", "disabled"]] + """The truncation strategy to use for the model response. + + - `auto`: If the input to this Response exceeds the model's context window size, + the model will truncate the response to fit the context window by dropping + items from the beginning of the conversation. + - `disabled` (default): If the input size will exceed the context window size + for a model, the request will fail with a 400 error. + """ + + user: str + """This field is being replaced by `safety_identifier` and `prompt_cache_key`. + + Use `prompt_cache_key` instead to maintain caching optimizations. A stable + identifier for your end-users. Used to boost cache hit rates by better bucketing + similar requests and to help OpenAI detect and prevent abuse. + [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). + """ diff --git a/src/openai/types/responses/responses_server_event.py b/src/openai/types/responses/responses_server_event.py new file mode 100644 index 0000000000..c543587ad0 --- /dev/null +++ b/src/openai/types/responses/responses_server_event.py @@ -0,0 +1,120 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from typing_extensions import Annotated, TypeAlias + +from ..._utils import PropertyInfo +from .response_error_event import ResponseErrorEvent +from .response_failed_event import ResponseFailedEvent +from .response_queued_event import ResponseQueuedEvent +from .response_created_event import ResponseCreatedEvent +from .response_completed_event import ResponseCompletedEvent +from .response_text_done_event import ResponseTextDoneEvent +from .response_audio_done_event import ResponseAudioDoneEvent +from .response_incomplete_event import ResponseIncompleteEvent +from .response_text_delta_event import ResponseTextDeltaEvent +from .response_audio_delta_event import ResponseAudioDeltaEvent +from .response_in_progress_event import ResponseInProgressEvent +from .response_refusal_done_event import ResponseRefusalDoneEvent +from .response_refusal_delta_event import ResponseRefusalDeltaEvent +from .response_mcp_call_failed_event import ResponseMcpCallFailedEvent +from .response_output_item_done_event import ResponseOutputItemDoneEvent +from .response_content_part_done_event import ResponseContentPartDoneEvent +from .response_output_item_added_event import ResponseOutputItemAddedEvent +from .response_content_part_added_event import ResponseContentPartAddedEvent +from .response_mcp_call_completed_event import ResponseMcpCallCompletedEvent +from .response_reasoning_text_done_event import ResponseReasoningTextDoneEvent +from .response_mcp_call_in_progress_event import ResponseMcpCallInProgressEvent +from .response_reasoning_text_delta_event import ResponseReasoningTextDeltaEvent +from .response_audio_transcript_done_event import ResponseAudioTranscriptDoneEvent +from .response_mcp_list_tools_failed_event import ResponseMcpListToolsFailedEvent +from .response_audio_transcript_delta_event import ResponseAudioTranscriptDeltaEvent +from .response_mcp_call_arguments_done_event import ResponseMcpCallArgumentsDoneEvent +from .response_image_gen_call_completed_event import ResponseImageGenCallCompletedEvent +from .response_mcp_call_arguments_delta_event import ResponseMcpCallArgumentsDeltaEvent +from .response_mcp_list_tools_completed_event import ResponseMcpListToolsCompletedEvent +from .response_image_gen_call_generating_event import ResponseImageGenCallGeneratingEvent +from .response_web_search_call_completed_event import ResponseWebSearchCallCompletedEvent +from .response_web_search_call_searching_event import ResponseWebSearchCallSearchingEvent +from .response_file_search_call_completed_event import ResponseFileSearchCallCompletedEvent +from .response_file_search_call_searching_event import ResponseFileSearchCallSearchingEvent +from .response_image_gen_call_in_progress_event import ResponseImageGenCallInProgressEvent +from .response_mcp_list_tools_in_progress_event import ResponseMcpListToolsInProgressEvent +from .response_custom_tool_call_input_done_event import ResponseCustomToolCallInputDoneEvent +from .response_reasoning_summary_part_done_event import ResponseReasoningSummaryPartDoneEvent +from .response_reasoning_summary_text_done_event import ResponseReasoningSummaryTextDoneEvent +from .response_web_search_call_in_progress_event import ResponseWebSearchCallInProgressEvent +from .response_custom_tool_call_input_delta_event import ResponseCustomToolCallInputDeltaEvent +from .response_file_search_call_in_progress_event import ResponseFileSearchCallInProgressEvent +from .response_function_call_arguments_done_event import ResponseFunctionCallArgumentsDoneEvent +from .response_image_gen_call_partial_image_event import ResponseImageGenCallPartialImageEvent +from .response_output_text_annotation_added_event import ResponseOutputTextAnnotationAddedEvent +from .response_reasoning_summary_part_added_event import ResponseReasoningSummaryPartAddedEvent +from .response_reasoning_summary_text_delta_event import ResponseReasoningSummaryTextDeltaEvent +from .response_function_call_arguments_delta_event import ResponseFunctionCallArgumentsDeltaEvent +from .response_code_interpreter_call_code_done_event import ResponseCodeInterpreterCallCodeDoneEvent +from .response_code_interpreter_call_completed_event import ResponseCodeInterpreterCallCompletedEvent +from .response_code_interpreter_call_code_delta_event import ResponseCodeInterpreterCallCodeDeltaEvent +from .response_code_interpreter_call_in_progress_event import ResponseCodeInterpreterCallInProgressEvent +from .response_code_interpreter_call_interpreting_event import ResponseCodeInterpreterCallInterpretingEvent + +__all__ = ["ResponsesServerEvent"] + +ResponsesServerEvent: TypeAlias = Annotated[ + Union[ + ResponseAudioDeltaEvent, + ResponseAudioDoneEvent, + ResponseAudioTranscriptDeltaEvent, + ResponseAudioTranscriptDoneEvent, + ResponseCodeInterpreterCallCodeDeltaEvent, + ResponseCodeInterpreterCallCodeDoneEvent, + ResponseCodeInterpreterCallCompletedEvent, + ResponseCodeInterpreterCallInProgressEvent, + ResponseCodeInterpreterCallInterpretingEvent, + ResponseCompletedEvent, + ResponseContentPartAddedEvent, + ResponseContentPartDoneEvent, + ResponseCreatedEvent, + ResponseErrorEvent, + ResponseFileSearchCallCompletedEvent, + ResponseFileSearchCallInProgressEvent, + ResponseFileSearchCallSearchingEvent, + ResponseFunctionCallArgumentsDeltaEvent, + ResponseFunctionCallArgumentsDoneEvent, + ResponseInProgressEvent, + ResponseFailedEvent, + ResponseIncompleteEvent, + ResponseOutputItemAddedEvent, + ResponseOutputItemDoneEvent, + ResponseReasoningSummaryPartAddedEvent, + ResponseReasoningSummaryPartDoneEvent, + ResponseReasoningSummaryTextDeltaEvent, + ResponseReasoningSummaryTextDoneEvent, + ResponseReasoningTextDeltaEvent, + ResponseReasoningTextDoneEvent, + ResponseRefusalDeltaEvent, + ResponseRefusalDoneEvent, + ResponseTextDeltaEvent, + ResponseTextDoneEvent, + ResponseWebSearchCallCompletedEvent, + ResponseWebSearchCallInProgressEvent, + ResponseWebSearchCallSearchingEvent, + ResponseImageGenCallCompletedEvent, + ResponseImageGenCallGeneratingEvent, + ResponseImageGenCallInProgressEvent, + ResponseImageGenCallPartialImageEvent, + ResponseMcpCallArgumentsDeltaEvent, + ResponseMcpCallArgumentsDoneEvent, + ResponseMcpCallCompletedEvent, + ResponseMcpCallFailedEvent, + ResponseMcpCallInProgressEvent, + ResponseMcpListToolsCompletedEvent, + ResponseMcpListToolsFailedEvent, + ResponseMcpListToolsInProgressEvent, + ResponseOutputTextAnnotationAddedEvent, + ResponseQueuedEvent, + ResponseCustomToolCallInputDeltaEvent, + ResponseCustomToolCallInputDoneEvent, + ], + PropertyInfo(discriminator="type"), +] From 481ff6ef4c050469fa971746fb14b675d90a2e56 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Feb 2026 20:08:32 +0000 Subject: [PATCH 633/769] release: 2.22.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 21 +++++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 49df20d2b8..c4563a87af 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.21.0" + ".": "2.22.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f558b3626..34bfd056ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,26 @@ # Changelog +## 2.22.0 (2026-02-23) + +Full Changelog: [v2.21.0...v2.22.0](https://github.com/openai/openai-python/compare/v2.21.0...v2.22.0) + +### Features + +* **api:** websockets for responses api ([c01f6fb](https://github.com/openai/openai-python/commit/c01f6fb0d55b7454f73c4904ea7a1954553085dc)) + + +### Chores + +* **internal:** add request options to SSE classes ([cdb4315](https://github.com/openai/openai-python/commit/cdb4315ee29d5260bb373625d74cb523b4e3859c)) +* update mock server docs ([91f4da8](https://github.com/openai/openai-python/commit/91f4da80ec3dba5d3566961560dfd6feb9c2feb0)) + + +### Documentation + +* **api:** add batch size limit to file_batches parameter descriptions ([16ae76a](https://github.com/openai/openai-python/commit/16ae76a20a47f94c91ee2ca0b2ada274633abab3)) +* **api:** enhance method descriptions across audio, chat, realtime, skills, uploads, videos ([21f9e5a](https://github.com/openai/openai-python/commit/21f9e5aaf6ae27f0235fddb3ffa30fe73337f59b)) +* **api:** update safety_identifier documentation in chat completions and responses ([d74bfff](https://github.com/openai/openai-python/commit/d74bfff62c1c2b32d4dc88fd47ae7b1b2a962017)) + ## 2.21.0 (2026-02-13) Full Changelog: [v2.20.0...v2.21.0](https://github.com/openai/openai-python/compare/v2.20.0...v2.21.0) diff --git a/pyproject.toml b/pyproject.toml index fe2e394592..4358af79c9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.21.0" +version = "2.22.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 0d4ef7b71c..7bea27c44f 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__ = "2.21.0" # x-release-please-version +__version__ = "2.22.0" # x-release-please-version From 588d239c1073442f982165d310f9ccf09f631f7c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Feb 2026 20:32:05 +0000 Subject: [PATCH 634/769] chore(internal): make `test_proxy_environment_variables` more resilient --- tests/test_client.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/test_client.py b/tests/test_client.py index 396f6dea99..7e8954d8a1 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -1036,6 +1036,8 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None: # Test that the proxy environment variables are set correctly monkeypatch.setenv("HTTPS_PROXY", "https://example.org") + # Delete in case our environment has this set + monkeypatch.delenv("HTTP_PROXY", raising=False) client = DefaultHttpxClient() @@ -2079,6 +2081,8 @@ async def test_get_platform(self) -> None: async def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None: # Test that the proxy environment variables are set correctly monkeypatch.setenv("HTTPS_PROXY", "https://example.org") + # Delete in case our environment has this set + monkeypatch.delenv("HTTP_PROXY", raising=False) client = DefaultAsyncHttpxClient() From 9e9a4f1712ec0ec637ca4f6e3f50e1647d268576 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Feb 2026 23:06:41 +0000 Subject: [PATCH 635/769] feat(api): add gpt-realtime-1.5 and gpt-audio-1.5 model options to realtime calls --- .stats.yml | 4 ++-- src/openai/resources/realtime/calls.py | 4 ++++ src/openai/types/realtime/call_accept_params.py | 2 ++ src/openai/types/realtime/realtime_session_create_request.py | 2 ++ .../types/realtime/realtime_session_create_request_param.py | 2 ++ src/openai/types/realtime/realtime_session_create_response.py | 2 ++ 6 files changed, 14 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 6d954e3ef8..365da3794f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 148 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-95886b357a553078e7f15505fe1c518c7daf11506946049c75eadf89d44da863.yml -openapi_spec_hash: 8dfdf1e1d1dbe58b236b89203aa2a1b0 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-a0aa54a302fbd7fff4ed7ad8a8547587d37b63324fc4af652bfa685ee9f8da44.yml +openapi_spec_hash: e45c5af19307cfc8b9baa4b8f8e865a0 config_hash: 4c2841519fd72fe44c18de4c18db231f diff --git a/src/openai/resources/realtime/calls.py b/src/openai/resources/realtime/calls.py index 20a22fc3b6..1520a97b0a 100644 --- a/src/openai/resources/realtime/calls.py +++ b/src/openai/resources/realtime/calls.py @@ -116,6 +116,7 @@ def accept( str, Literal[ "gpt-realtime", + "gpt-realtime-1.5", "gpt-realtime-2025-08-28", "gpt-4o-realtime-preview", "gpt-4o-realtime-preview-2024-10-01", @@ -126,6 +127,7 @@ def accept( "gpt-realtime-mini", "gpt-realtime-mini-2025-10-06", "gpt-realtime-mini-2025-12-15", + "gpt-audio-1.5", "gpt-audio-mini", "gpt-audio-mini-2025-10-06", "gpt-audio-mini-2025-12-15", @@ -443,6 +445,7 @@ async def accept( str, Literal[ "gpt-realtime", + "gpt-realtime-1.5", "gpt-realtime-2025-08-28", "gpt-4o-realtime-preview", "gpt-4o-realtime-preview-2024-10-01", @@ -453,6 +456,7 @@ async def accept( "gpt-realtime-mini", "gpt-realtime-mini-2025-10-06", "gpt-realtime-mini-2025-12-15", + "gpt-audio-1.5", "gpt-audio-mini", "gpt-audio-mini-2025-10-06", "gpt-audio-mini-2025-12-15", diff --git a/src/openai/types/realtime/call_accept_params.py b/src/openai/types/realtime/call_accept_params.py index d950f59f69..6d8caf9306 100644 --- a/src/openai/types/realtime/call_accept_params.py +++ b/src/openai/types/realtime/call_accept_params.py @@ -56,6 +56,7 @@ class CallAcceptParams(TypedDict, total=False): str, Literal[ "gpt-realtime", + "gpt-realtime-1.5", "gpt-realtime-2025-08-28", "gpt-4o-realtime-preview", "gpt-4o-realtime-preview-2024-10-01", @@ -66,6 +67,7 @@ class CallAcceptParams(TypedDict, total=False): "gpt-realtime-mini", "gpt-realtime-mini-2025-10-06", "gpt-realtime-mini-2025-12-15", + "gpt-audio-1.5", "gpt-audio-mini", "gpt-audio-mini-2025-10-06", "gpt-audio-mini-2025-12-15", diff --git a/src/openai/types/realtime/realtime_session_create_request.py b/src/openai/types/realtime/realtime_session_create_request.py index 4a93c91c7d..e34136a10a 100644 --- a/src/openai/types/realtime/realtime_session_create_request.py +++ b/src/openai/types/realtime/realtime_session_create_request.py @@ -57,6 +57,7 @@ class RealtimeSessionCreateRequest(BaseModel): str, Literal[ "gpt-realtime", + "gpt-realtime-1.5", "gpt-realtime-2025-08-28", "gpt-4o-realtime-preview", "gpt-4o-realtime-preview-2024-10-01", @@ -67,6 +68,7 @@ class RealtimeSessionCreateRequest(BaseModel): "gpt-realtime-mini", "gpt-realtime-mini-2025-10-06", "gpt-realtime-mini-2025-12-15", + "gpt-audio-1.5", "gpt-audio-mini", "gpt-audio-mini-2025-10-06", "gpt-audio-mini-2025-12-15", diff --git a/src/openai/types/realtime/realtime_session_create_request_param.py b/src/openai/types/realtime/realtime_session_create_request_param.py index dee63d0967..f3180c9ed6 100644 --- a/src/openai/types/realtime/realtime_session_create_request_param.py +++ b/src/openai/types/realtime/realtime_session_create_request_param.py @@ -58,6 +58,7 @@ class RealtimeSessionCreateRequestParam(TypedDict, total=False): str, Literal[ "gpt-realtime", + "gpt-realtime-1.5", "gpt-realtime-2025-08-28", "gpt-4o-realtime-preview", "gpt-4o-realtime-preview-2024-10-01", @@ -68,6 +69,7 @@ class RealtimeSessionCreateRequestParam(TypedDict, total=False): "gpt-realtime-mini", "gpt-realtime-mini-2025-10-06", "gpt-realtime-mini-2025-12-15", + "gpt-audio-1.5", "gpt-audio-mini", "gpt-audio-mini-2025-10-06", "gpt-audio-mini-2025-12-15", diff --git a/src/openai/types/realtime/realtime_session_create_response.py b/src/openai/types/realtime/realtime_session_create_response.py index 15a200ca17..a74615bd60 100644 --- a/src/openai/types/realtime/realtime_session_create_response.py +++ b/src/openai/types/realtime/realtime_session_create_response.py @@ -460,6 +460,7 @@ class RealtimeSessionCreateResponse(BaseModel): str, Literal[ "gpt-realtime", + "gpt-realtime-1.5", "gpt-realtime-2025-08-28", "gpt-4o-realtime-preview", "gpt-4o-realtime-preview-2024-10-01", @@ -470,6 +471,7 @@ class RealtimeSessionCreateResponse(BaseModel): "gpt-realtime-mini", "gpt-realtime-mini-2025-10-06", "gpt-realtime-mini-2025-12-15", + "gpt-audio-1.5", "gpt-audio-mini", "gpt-audio-mini-2025-10-06", "gpt-audio-mini-2025-12-15", From 650ccd90dcad0ce23c06b95d8d07911f19d52513 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Feb 2026 00:35:26 +0000 Subject: [PATCH 636/769] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 365da3794f..2e3e64a4ec 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 148 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-a0aa54a302fbd7fff4ed7ad8a8547587d37b63324fc4af652bfa685ee9f8da44.yml openapi_spec_hash: e45c5af19307cfc8b9baa4b8f8e865a0 -config_hash: 4c2841519fd72fe44c18de4c18db231f +config_hash: 2cbce279be85ff86a2fabbc85d62b011 From 921c330d4baebb04bbdb8070e9ced539cf49d97a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Feb 2026 00:36:00 +0000 Subject: [PATCH 637/769] release: 2.23.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index c4563a87af..29dfa68625 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.22.0" + ".": "2.23.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 34bfd056ba..31245bfe99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 2.23.0 (2026-02-24) + +Full Changelog: [v2.22.0...v2.23.0](https://github.com/openai/openai-python/compare/v2.22.0...v2.23.0) + +### Features + +* **api:** add gpt-realtime-1.5 and gpt-audio-1.5 model options to realtime calls ([3300b61](https://github.com/openai/openai-python/commit/3300b61e1d5a34c9d28ec9cebbebd0de1fa93aa6)) + + +### Chores + +* **internal:** make `test_proxy_environment_variables` more resilient ([6b441e2](https://github.com/openai/openai-python/commit/6b441e2c43df60a773f62308e918d76b8eb3c4d3)) + ## 2.22.0 (2026-02-23) Full Changelog: [v2.21.0...v2.22.0](https://github.com/openai/openai-python/compare/v2.21.0...v2.22.0) diff --git a/pyproject.toml b/pyproject.toml index 4358af79c9..0803c313d1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.22.0" +version = "2.23.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 7bea27c44f..693ba82537 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__ = "2.22.0" # x-release-please-version +__version__ = "2.23.0" # x-release-please-version From 656e3cab4a18262a49b961d41293367e45ee71b9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Feb 2026 12:01:04 -0800 Subject: [PATCH 638/769] release: 2.24.0 (#2890) * chore(internal): refactor sse event parsing * codegen metadata * chore(internal): make `test_proxy_environment_variables` more resilient to env * feat(api): add phase * fix(api): phase docs * fix(api): fix phase enum * release: 2.24.0 --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- .stats.yml | 6 +++--- CHANGELOG.md | 20 +++++++++++++++++++ pyproject.toml | 2 +- src/openai/_base_client.py | 4 ++++ src/openai/_models.py | 2 ++ src/openai/_streaming.py | 18 +++++++++++++---- src/openai/_types.py | 1 + src/openai/_version.py | 2 +- .../resources/beta/threads/runs/runs.py | 14 +++++++++++-- src/openai/resources/beta/threads/threads.py | 12 +++++++++-- src/openai/resources/responses/responses.py | 8 ++++++++ .../types/responses/easy_input_message.py | 9 +++++++++ .../responses/easy_input_message_param.py | 11 +++++++++- .../responses/response_compact_params.py | 3 +++ .../responses/response_output_message.py | 11 +++++++++- .../response_output_message_param.py | 11 +++++++++- .../api_resources/conversations/test_items.py | 2 ++ tests/api_resources/test_conversations.py | 2 ++ tests/api_resources/test_responses.py | 2 ++ tests/test_client.py | 16 +++++++++++++-- 21 files changed, 139 insertions(+), 19 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 29dfa68625..288087c17b 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.23.0" + ".": "2.24.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 2e3e64a4ec..476a5b7658 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 148 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-a0aa54a302fbd7fff4ed7ad8a8547587d37b63324fc4af652bfa685ee9f8da44.yml -openapi_spec_hash: e45c5af19307cfc8b9baa4b8f8e865a0 -config_hash: 2cbce279be85ff86a2fabbc85d62b011 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-6bfe886b5ded0fe3bf37ca672698814e16e0836a093ceef65dac37ae44d1ad6b.yml +openapi_spec_hash: 6b1344a59044318e824c8d1af96033c7 +config_hash: 7f49c38fa3abe9b7038ffe62262c4912 diff --git a/CHANGELOG.md b/CHANGELOG.md index 31245bfe99..91da3fc859 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,25 @@ # Changelog +## 2.24.0 (2026-02-24) + +Full Changelog: [v2.23.0...v2.24.0](https://github.com/openai/openai-python/compare/v2.23.0...v2.24.0) + +### Features + +* **api:** add phase ([391deb9](https://github.com/openai/openai-python/commit/391deb99f6a92e51bffb25efd8dfe367d144bb9d)) + + +### Bug Fixes + +* **api:** fix phase enum ([42ebf7c](https://github.com/openai/openai-python/commit/42ebf7c30b7e27a175c0d75fcf42c8dc858e56d6)) +* **api:** phase docs ([7ddc61c](https://github.com/openai/openai-python/commit/7ddc61cd0f7825d5e7f3a10daf809135511d8d20)) + + +### Chores + +* **internal:** make `test_proxy_environment_variables` more resilient to env ([65af8fd](https://github.com/openai/openai-python/commit/65af8fd8550e99236e3f4dcb035312441788157a)) +* **internal:** refactor sse event parsing ([2344600](https://github.com/openai/openai-python/commit/23446008f06fb474d8c75d14a1bce26f4c5b95d8)) + ## 2.23.0 (2026-02-24) Full Changelog: [v2.22.0...v2.23.0](https://github.com/openai/openai-python/compare/v2.22.0...v2.23.0) diff --git a/pyproject.toml b/pyproject.toml index 0803c313d1..49ab3668e8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.23.0" +version = "2.24.0" description = "The official Python library for the openai API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index 17863bc067..cf4571bf45 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -1984,6 +1984,7 @@ def make_request_options( idempotency_key: str | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, post_parser: PostParser | NotGiven = not_given, + synthesize_event_and_data: bool | None = None, ) -> RequestOptions: """Create a dict of type RequestOptions without keys of NotGiven values.""" options: RequestOptions = {} @@ -2009,6 +2010,9 @@ def make_request_options( # internal options["post_parser"] = post_parser # type: ignore + if synthesize_event_and_data is not None: + options["synthesize_event_and_data"] = synthesize_event_and_data + return options diff --git a/src/openai/_models.py b/src/openai/_models.py index 5cca20c6f9..810e49dfc5 100644 --- a/src/openai/_models.py +++ b/src/openai/_models.py @@ -845,6 +845,7 @@ class FinalRequestOptionsInput(TypedDict, total=False): json_data: Body extra_json: AnyMapping follow_redirects: bool + synthesize_event_and_data: bool @final @@ -859,6 +860,7 @@ class FinalRequestOptions(pydantic.BaseModel): idempotency_key: Union[str, None] = None post_parser: Union[Callable[[Any], Any], NotGiven] = NotGiven() follow_redirects: Union[bool, None] = None + synthesize_event_and_data: Optional[bool] = None content: Union[bytes, bytearray, IO[bytes], Iterable[bytes], AsyncIterable[bytes], None] = None # It should be noted that we cannot use `json` here as that would override diff --git a/src/openai/_streaming.py b/src/openai/_streaming.py index 86b81c324f..45c13cc11d 100644 --- a/src/openai/_streaming.py +++ b/src/openai/_streaming.py @@ -98,8 +98,13 @@ def __stream__(self) -> Iterator[_T]: body=data["error"], ) - yield process_data(data=data, cast_to=cast_to, response=response) - + yield process_data( + data={"data": data, "event": sse.event} + if self._options is not None and self._options.synthesize_event_and_data + else data, + cast_to=cast_to, + response=response, + ) finally: # Ensure the response is closed even if the consumer doesn't read all data response.close() @@ -203,8 +208,13 @@ async def __stream__(self) -> AsyncIterator[_T]: body=data["error"], ) - yield process_data(data=data, cast_to=cast_to, response=response) - + yield process_data( + data={"data": data, "event": sse.event} + if self._options is not None and self._options.synthesize_event_and_data + else data, + cast_to=cast_to, + response=response, + ) finally: # Ensure the response is closed even if the consumer doesn't read all data await response.aclose() diff --git a/src/openai/_types.py b/src/openai/_types.py index 42f9df2373..c55c6f808d 100644 --- a/src/openai/_types.py +++ b/src/openai/_types.py @@ -122,6 +122,7 @@ class RequestOptions(TypedDict, total=False): extra_json: AnyMapping idempotency_key: str follow_redirects: bool + synthesize_event_and_data: bool # Sentinel class used until PEP 0661 is accepted diff --git a/src/openai/_version.py b/src/openai/_version.py index 693ba82537..08cf29390a 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__ = "2.23.0" # x-release-please-version +__version__ = "2.24.0" # x-release-please-version diff --git a/src/openai/resources/beta/threads/runs/runs.py b/src/openai/resources/beta/threads/runs/runs.py index 8a58e91f69..90845a2f62 100644 --- a/src/openai/resources/beta/threads/runs/runs.py +++ b/src/openai/resources/beta/threads/runs/runs.py @@ -620,6 +620,7 @@ def create( extra_body=extra_body, timeout=timeout, query=maybe_transform({"include": include}, run_create_params.RunCreateParams), + synthesize_event_and_data=True, ), cast_to=Run, stream=stream or False, @@ -1368,7 +1369,11 @@ def submit_tool_outputs( else run_submit_tool_outputs_params.RunSubmitToolOutputsParamsNonStreaming, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + synthesize_event_and_data=True, ), cast_to=Run, stream=stream or False, @@ -2075,6 +2080,7 @@ async def create( extra_body=extra_body, timeout=timeout, query=await async_maybe_transform({"include": include}, run_create_params.RunCreateParams), + synthesize_event_and_data=True, ), cast_to=Run, stream=stream or False, @@ -2822,7 +2828,11 @@ async def submit_tool_outputs( else run_submit_tool_outputs_params.RunSubmitToolOutputsParamsNonStreaming, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + synthesize_event_and_data=True, ), cast_to=Run, stream=stream or False, diff --git a/src/openai/resources/beta/threads/threads.py b/src/openai/resources/beta/threads/threads.py index 681d3c2933..a804fda159 100644 --- a/src/openai/resources/beta/threads/threads.py +++ b/src/openai/resources/beta/threads/threads.py @@ -729,7 +729,11 @@ def create_and_run( else thread_create_and_run_params.ThreadCreateAndRunParamsNonStreaming, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + synthesize_event_and_data=True, ), cast_to=Run, stream=stream or False, @@ -1587,7 +1591,11 @@ async def create_and_run( else thread_create_and_run_params.ThreadCreateAndRunParamsNonStreaming, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + synthesize_event_and_data=True, ), cast_to=Run, stream=stream or False, diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 2ad1e6716c..c85a94495d 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -1660,6 +1660,7 @@ def compact( input: Union[str, Iterable[ResponseInputItemParam], None] | Omit = omit, instructions: Optional[str] | Omit = omit, previous_response_id: Optional[str] | Omit = omit, + prompt_cache_key: Optional[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1695,6 +1696,8 @@ def compact( [conversation state](https://platform.openai.com/docs/guides/conversation-state). Cannot be used in conjunction with `conversation`. + prompt_cache_key: A key to use when reading from or writing to the prompt cache. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -1711,6 +1714,7 @@ def compact( "input": input, "instructions": instructions, "previous_response_id": previous_response_id, + "prompt_cache_key": prompt_cache_key, }, response_compact_params.ResponseCompactParams, ), @@ -3321,6 +3325,7 @@ async def compact( input: Union[str, Iterable[ResponseInputItemParam], None] | Omit = omit, instructions: Optional[str] | Omit = omit, previous_response_id: Optional[str] | Omit = omit, + prompt_cache_key: Optional[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -3356,6 +3361,8 @@ async def compact( [conversation state](https://platform.openai.com/docs/guides/conversation-state). Cannot be used in conjunction with `conversation`. + prompt_cache_key: A key to use when reading from or writing to the prompt cache. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -3372,6 +3379,7 @@ async def compact( "input": input, "instructions": instructions, "previous_response_id": previous_response_id, + "prompt_cache_key": prompt_cache_key, }, response_compact_params.ResponseCompactParams, ), diff --git a/src/openai/types/responses/easy_input_message.py b/src/openai/types/responses/easy_input_message.py index 9a36a6b084..6f4d782734 100644 --- a/src/openai/types/responses/easy_input_message.py +++ b/src/openai/types/responses/easy_input_message.py @@ -30,5 +30,14 @@ class EasyInputMessage(BaseModel): One of `user`, `assistant`, `system`, or `developer`. """ + phase: Optional[Literal["commentary", "final_answer"]] = None + """The phase of an assistant message. + + Use `commentary` for an intermediate assistant message and `final_answer` for + the final assistant message. For follow-up requests with models like + `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. + Omitting it can degrade performance. Not used for user messages. + """ + type: Optional[Literal["message"]] = None """The type of the message input. Always `message`.""" diff --git a/src/openai/types/responses/easy_input_message_param.py b/src/openai/types/responses/easy_input_message_param.py index 0a382bddee..f7eb42ba71 100644 --- a/src/openai/types/responses/easy_input_message_param.py +++ b/src/openai/types/responses/easy_input_message_param.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Union +from typing import Union, Optional from typing_extensions import Literal, Required, TypedDict from .response_input_message_content_list_param import ResponseInputMessageContentListParam @@ -31,5 +31,14 @@ class EasyInputMessageParam(TypedDict, total=False): One of `user`, `assistant`, `system`, or `developer`. """ + phase: Optional[Literal["commentary", "final_answer"]] + """The phase of an assistant message. + + Use `commentary` for an intermediate assistant message and `final_answer` for + the final assistant message. For follow-up requests with models like + `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. + Omitting it can degrade performance. Not used for user messages. + """ + type: Literal["message"] """The type of the message input. Always `message`.""" diff --git a/src/openai/types/responses/response_compact_params.py b/src/openai/types/responses/response_compact_params.py index 657c6a0764..4fb0e7ddc3 100644 --- a/src/openai/types/responses/response_compact_params.py +++ b/src/openai/types/responses/response_compact_params.py @@ -131,3 +131,6 @@ class ResponseCompactParams(TypedDict, total=False): [conversation state](https://platform.openai.com/docs/guides/conversation-state). Cannot be used in conjunction with `conversation`. """ + + prompt_cache_key: Optional[str] + """A key to use when reading from or writing to the prompt cache.""" diff --git a/src/openai/types/responses/response_output_message.py b/src/openai/types/responses/response_output_message.py index 9c1d1f97fc..a8720e1c57 100644 --- a/src/openai/types/responses/response_output_message.py +++ b/src/openai/types/responses/response_output_message.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union +from typing import List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias from ..._utils import PropertyInfo @@ -34,3 +34,12 @@ class ResponseOutputMessage(BaseModel): type: Literal["message"] """The type of the output message. Always `message`.""" + + phase: Optional[Literal["commentary", "final_answer"]] = None + """The phase of an assistant message. + + Use `commentary` for an intermediate assistant message and `final_answer` for + the final assistant message. For follow-up requests with models like + `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. + Omitting it can degrade performance. Not used for user messages. + """ diff --git a/src/openai/types/responses/response_output_message_param.py b/src/openai/types/responses/response_output_message_param.py index 9c2f5246a1..5d488d8c6b 100644 --- a/src/openai/types/responses/response_output_message_param.py +++ b/src/openai/types/responses/response_output_message_param.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Union, Iterable +from typing import Union, Iterable, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict from .response_output_text_param import ResponseOutputTextParam @@ -34,3 +34,12 @@ class ResponseOutputMessageParam(TypedDict, total=False): type: Required[Literal["message"]] """The type of the output message. Always `message`.""" + + phase: Optional[Literal["commentary", "final_answer"]] + """The phase of an assistant message. + + Use `commentary` for an intermediate assistant message and `final_answer` for + the final assistant message. For follow-up requests with models like + `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. + Omitting it can degrade performance. Not used for user messages. + """ diff --git a/tests/api_resources/conversations/test_items.py b/tests/api_resources/conversations/test_items.py index 0503301f16..aca9568410 100644 --- a/tests/api_resources/conversations/test_items.py +++ b/tests/api_resources/conversations/test_items.py @@ -44,6 +44,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: { "content": "string", "role": "user", + "phase": "commentary", "type": "message", } ], @@ -285,6 +286,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> { "content": "string", "role": "user", + "phase": "commentary", "type": "message", } ], diff --git a/tests/api_resources/test_conversations.py b/tests/api_resources/test_conversations.py index d21e685a04..a451d339e8 100644 --- a/tests/api_resources/test_conversations.py +++ b/tests/api_resources/test_conversations.py @@ -32,6 +32,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: { "content": "string", "role": "user", + "phase": "commentary", "type": "message", } ], @@ -195,6 +196,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> { "content": "string", "role": "user", + "phase": "commentary", "type": "message", } ], diff --git a/tests/api_resources/test_responses.py b/tests/api_resources/test_responses.py index a644b2c6b9..8f82f2046d 100644 --- a/tests/api_resources/test_responses.py +++ b/tests/api_resources/test_responses.py @@ -385,6 +385,7 @@ def test_method_compact_with_all_params(self, client: OpenAI) -> None: input="string", instructions="instructions", previous_response_id="resp_123", + prompt_cache_key="prompt_cache_key", ) assert_matches_type(CompactedResponse, response, path=["response"]) @@ -793,6 +794,7 @@ async def test_method_compact_with_all_params(self, async_client: AsyncOpenAI) - input="string", instructions="instructions", previous_response_id="resp_123", + prompt_cache_key="prompt_cache_key", ) assert_matches_type(CompactedResponse, response, path=["response"]) diff --git a/tests/test_client.py b/tests/test_client.py index 7e8954d8a1..b8b963aa4c 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -1036,8 +1036,14 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None: # Test that the proxy environment variables are set correctly monkeypatch.setenv("HTTPS_PROXY", "https://example.org") - # Delete in case our environment has this set + # Delete in case our environment has any proxy env vars set monkeypatch.delenv("HTTP_PROXY", raising=False) + monkeypatch.delenv("ALL_PROXY", raising=False) + monkeypatch.delenv("NO_PROXY", raising=False) + monkeypatch.delenv("http_proxy", raising=False) + monkeypatch.delenv("https_proxy", raising=False) + monkeypatch.delenv("all_proxy", raising=False) + monkeypatch.delenv("no_proxy", raising=False) client = DefaultHttpxClient() @@ -2081,8 +2087,14 @@ async def test_get_platform(self) -> None: async def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None: # Test that the proxy environment variables are set correctly monkeypatch.setenv("HTTPS_PROXY", "https://example.org") - # Delete in case our environment has this set + # Delete in case our environment has any proxy env vars set monkeypatch.delenv("HTTP_PROXY", raising=False) + monkeypatch.delenv("ALL_PROXY", raising=False) + monkeypatch.delenv("NO_PROXY", raising=False) + monkeypatch.delenv("http_proxy", raising=False) + monkeypatch.delenv("https_proxy", raising=False) + monkeypatch.delenv("all_proxy", raising=False) + monkeypatch.delenv("no_proxy", raising=False) client = DefaultAsyncHttpxClient() From 9b1bb6ee10d4a0a04d04b1f67907f3747c57f5a2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 5 Mar 2026 13:34:23 -0500 Subject: [PATCH 639/769] release: 2.25.0 (#2891) * feat(api): remove prompt_cache_key param from responses, phase field from message types * fix(api): readd phase * fix(api): manual updates * fix(api): internal schema fixes * codegen metadata * chore(internal): codegen related update * chore(internal): reduce warnings * chore(internal): codegen related update * feat(api): gpt-5.4, tool search tool, and new computer tool * release: 2.25.0 --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- .stats.yml | 6 +- CHANGELOG.md | 23 +++ api.md | 2 + pyproject.toml | 2 +- scripts/mock | 13 +- src/openai/_client.py | 108 +++++++++++ src/openai/_version.py | 2 +- src/openai/lib/_parsing/_responses.py | 2 + src/openai/resources/audio/audio.py | 18 ++ src/openai/resources/audio/speech.py | 4 + src/openai/resources/audio/transcriptions.py | 4 + src/openai/resources/audio/translations.py | 4 + src/openai/resources/batches.py | 4 + src/openai/resources/beta/assistants.py | 4 + src/openai/resources/beta/beta.py | 12 ++ src/openai/resources/beta/threads/messages.py | 4 + .../resources/beta/threads/runs/runs.py | 10 + .../resources/beta/threads/runs/steps.py | 4 + src/openai/resources/beta/threads/threads.py | 16 ++ src/openai/resources/chat/chat.py | 18 ++ .../resources/chat/completions/completions.py | 26 +++ .../resources/chat/completions/messages.py | 8 + src/openai/resources/completions.py | 8 + .../resources/conversations/conversations.py | 10 + src/openai/resources/conversations/items.py | 4 + src/openai/resources/embeddings.py | 8 + src/openai/resources/evals/evals.py | 10 + .../resources/evals/runs/output_items.py | 4 + src/openai/resources/evals/runs/runs.py | 10 + src/openai/resources/files.py | 8 + .../resources/fine_tuning/alpha/alpha.py | 6 + .../resources/fine_tuning/alpha/graders.py | 4 + .../fine_tuning/checkpoints/checkpoints.py | 6 + .../fine_tuning/checkpoints/permissions.py | 178 ++++++++++++++++- .../resources/fine_tuning/fine_tuning.py | 6 + .../resources/fine_tuning/jobs/checkpoints.py | 4 + src/openai/resources/fine_tuning/jobs/jobs.py | 10 + src/openai/resources/images.py | 4 + src/openai/resources/models.py | 4 + src/openai/resources/moderations.py | 8 + src/openai/resources/responses/api.md | 8 + src/openai/resources/responses/responses.py | 4 + src/openai/resources/uploads/parts.py | 4 + src/openai/resources/uploads/uploads.py | 10 + src/openai/resources/videos.py | 4 +- src/openai/resources/webhooks/__init__.py | 1 + .../types/beta/assistant_create_params.py | 5 +- .../beta/thread_create_and_run_params.py | 5 +- src/openai/types/beta/thread_create_params.py | 5 +- .../computer_screenshot_content.py | 6 + .../types/conversations/conversation_item.py | 4 + .../types/fine_tuning/checkpoints/__init__.py | 2 + .../checkpoints/permission_list_params.py | 21 ++ .../checkpoints/permission_list_response.py | 25 +++ .../realtime_response_create_mcp_tool.py | 3 + ...realtime_response_create_mcp_tool_param.py | 3 + .../realtime_session_create_response.py | 3 + .../realtime/realtime_tools_config_param.py | 3 + .../realtime/realtime_tools_config_union.py | 3 + .../realtime_tools_config_union_param.py | 3 + src/openai/types/responses/__init__.py | 18 ++ src/openai/types/responses/computer_action.py | 181 +++++++++++++++++ .../types/responses/computer_action_list.py | 10 + .../responses/computer_action_list_param.py | 183 ++++++++++++++++++ .../types/responses/computer_action_param.py | 180 +++++++++++++++++ .../types/responses/computer_use_tool.py | 17 ++ .../responses/computer_use_tool_param.py | 17 ++ src/openai/types/responses/custom_tool.py | 3 + .../types/responses/custom_tool_param.py | 3 + .../types/responses/easy_input_message.py | 11 +- .../responses/easy_input_message_param.py | 11 +- src/openai/types/responses/function_tool.py | 3 + .../types/responses/function_tool_param.py | 3 + src/openai/types/responses/namespace_tool.py | 41 ++++ .../types/responses/namespace_tool_param.py | 41 ++++ src/openai/types/responses/parsed_response.py | 4 + .../responses/response_compact_params.py | 2 + .../responses/response_computer_tool_call.py | 41 ++-- .../response_computer_tool_call_param.py | 41 ++-- .../responses/response_custom_tool_call.py | 3 + .../response_custom_tool_call_param.py | 3 + .../responses/response_function_tool_call.py | 3 + .../response_function_tool_call_param.py | 3 + .../types/responses/response_input_file.py | 6 + .../responses/response_input_file_content.py | 6 + .../response_input_file_content_param.py | 6 + .../responses/response_input_file_param.py | 6 + .../types/responses/response_input_image.py | 4 +- .../responses/response_input_image_content.py | 4 +- .../response_input_image_content_param.py | 4 +- .../responses/response_input_image_param.py | 4 +- .../types/responses/response_input_item.py | 24 +++ .../responses/response_input_item_param.py | 24 +++ .../types/responses/response_input_param.py | 24 +++ src/openai/types/responses/response_item.py | 4 + .../types/responses/response_output_item.py | 4 + .../responses/response_output_message.py | 11 +- .../response_output_message_param.py | 11 +- .../responses/response_tool_search_call.py | 31 +++ .../response_tool_search_output_item.py | 32 +++ .../response_tool_search_output_item_param.py | 29 +++ ...nse_tool_search_output_item_param_param.py | 30 +++ src/openai/types/responses/tool.py | 9 + .../types/responses/tool_choice_types.py | 4 + .../responses/tool_choice_types_param.py | 4 + src/openai/types/responses/tool_param.py | 9 + .../types/responses/tool_search_tool.py | 24 +++ .../types/responses/tool_search_tool_param.py | 24 +++ .../responses/web_search_preview_tool.py | 4 +- .../web_search_preview_tool_param.py | 4 +- src/openai/types/shared/chat_model.py | 2 + src/openai/types/shared_params/chat_model.py | 2 + src/openai/types/video.py | 9 +- src/openai/types/video_create_params.py | 2 +- tests/api_resources/chat/test_completions.py | 32 +-- .../checkpoints/test_permissions.py | 173 ++++++++++++++--- .../responses/test_input_tokens.py | 2 + tests/api_resources/test_responses.py | 20 +- tests/test_client.py | 24 +-- 120 files changed, 1984 insertions(+), 160 deletions(-) create mode 100644 src/openai/types/fine_tuning/checkpoints/permission_list_params.py create mode 100644 src/openai/types/fine_tuning/checkpoints/permission_list_response.py create mode 100644 src/openai/types/responses/computer_action.py create mode 100644 src/openai/types/responses/computer_action_list.py create mode 100644 src/openai/types/responses/computer_action_list_param.py create mode 100644 src/openai/types/responses/computer_action_param.py create mode 100644 src/openai/types/responses/computer_use_tool.py create mode 100644 src/openai/types/responses/computer_use_tool_param.py create mode 100644 src/openai/types/responses/namespace_tool.py create mode 100644 src/openai/types/responses/namespace_tool_param.py create mode 100644 src/openai/types/responses/response_tool_search_call.py create mode 100644 src/openai/types/responses/response_tool_search_output_item.py create mode 100644 src/openai/types/responses/response_tool_search_output_item_param.py create mode 100644 src/openai/types/responses/response_tool_search_output_item_param_param.py create mode 100644 src/openai/types/responses/tool_search_tool.py create mode 100644 src/openai/types/responses/tool_search_tool_param.py diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 288087c17b..c5fe8ab6d6 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.24.0" + ".": "2.25.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 476a5b7658..a59953aaa9 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 148 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-6bfe886b5ded0fe3bf37ca672698814e16e0836a093ceef65dac37ae44d1ad6b.yml -openapi_spec_hash: 6b1344a59044318e824c8d1af96033c7 -config_hash: 7f49c38fa3abe9b7038ffe62262c4912 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-9c802d45a9bf2a896b5fd22ac22bba185e8a145bd40ed242df9bb87a05e954eb.yml +openapi_spec_hash: 97984ed69285e660b7d5c810c69ed449 +config_hash: acb0b1eb5d7284bfedaddb29f7f5a691 diff --git a/CHANGELOG.md b/CHANGELOG.md index 91da3fc859..780a961a43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,28 @@ # Changelog +## 2.25.0 (2026-03-05) + +Full Changelog: [v2.24.0...v2.25.0](https://github.com/openai/openai-python/compare/v2.24.0...v2.25.0) + +### Features + +* **api:** gpt-5.4, tool search tool, and new computer tool ([6b2043f](https://github.com/openai/openai-python/commit/6b2043f3d63058f5582eab7a7705b30a3d5536f0)) +* **api:** remove prompt_cache_key param from responses, phase field from message types ([44fb382](https://github.com/openai/openai-python/commit/44fb382698872d98d5f72c880b47846c7b594f4f)) + + +### Bug Fixes + +* **api:** internal schema fixes ([0c0f970](https://github.com/openai/openai-python/commit/0c0f970cbd164131bf06f7ab38f170bbcb323683)) +* **api:** manual updates ([9fc323f](https://github.com/openai/openai-python/commit/9fc323f4da6cfca9de194e12c1486a3cd1bfa4b5)) +* **api:** readd phase ([1b27b5a](https://github.com/openai/openai-python/commit/1b27b5a834f5cb75f80c597259d0df0352ba83bd)) + + +### Chores + +* **internal:** codegen related update ([bdb837d](https://github.com/openai/openai-python/commit/bdb837d2c1d2a161cc4b22ef26e9e8446d5dc2a3)) +* **internal:** codegen related update ([b1de941](https://github.com/openai/openai-python/commit/b1de9419a68fd6fb97a63f415fb3d1e5851582cb)) +* **internal:** reduce warnings ([7cdbd06](https://github.com/openai/openai-python/commit/7cdbd06d3ca41af64d616b4b4bb61226cc38b662)) + ## 2.24.0 (2026-02-24) Full Changelog: [v2.23.0...v2.24.0](https://github.com/openai/openai-python/compare/v2.23.0...v2.24.0) diff --git a/api.md b/api.md index da521d3418..a7981f7185 100644 --- a/api.md +++ b/api.md @@ -309,6 +309,7 @@ Types: from openai.types.fine_tuning.checkpoints import ( PermissionCreateResponse, PermissionRetrieveResponse, + PermissionListResponse, PermissionDeleteResponse, ) ``` @@ -317,6 +318,7 @@ Methods: - client.fine_tuning.checkpoints.permissions.create(fine_tuned_model_checkpoint, \*\*params) -> SyncPage[PermissionCreateResponse] - client.fine_tuning.checkpoints.permissions.retrieve(fine_tuned_model_checkpoint, \*\*params) -> PermissionRetrieveResponse +- client.fine_tuning.checkpoints.permissions.list(fine_tuned_model_checkpoint, \*\*params) -> SyncConversationCursorPage[PermissionListResponse] - client.fine_tuning.checkpoints.permissions.delete(permission_id, \*, fine_tuned_model_checkpoint) -> PermissionDeleteResponse ## Alpha diff --git a/pyproject.toml b/pyproject.toml index 49ab3668e8..f7aae6cbdb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.24.0" +version = "2.25.0" description = "The official Python library for the openai API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/scripts/mock b/scripts/mock index 0b28f6ea23..bcf3b392b3 100755 --- a/scripts/mock +++ b/scripts/mock @@ -21,11 +21,22 @@ echo "==> Starting mock server with URL ${URL}" # Run prism mock on the given spec if [ "$1" == "--daemon" ]; then + # Pre-install the package so the download doesn't eat into the startup timeout + npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism --version + npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" &> .prism.log & - # Wait for server to come online + # Wait for server to come online (max 30s) echo -n "Waiting for server" + attempts=0 while ! grep -q "✖ fatal\|Prism is listening" ".prism.log" ; do + attempts=$((attempts + 1)) + if [ "$attempts" -ge 300 ]; then + echo + echo "Timed out waiting for Prism server to start" + cat .prism.log + exit 1 + fi echo -n "." sleep 0.1 done diff --git a/src/openai/_client.py b/src/openai/_client.py index 0399bbf742..aadf3601f2 100644 --- a/src/openai/_client.py +++ b/src/openai/_client.py @@ -180,6 +180,9 @@ def __init__( @cached_property def completions(self) -> Completions: + """ + Given a prompt, the model will return one or more predicted completions, and can also return the probabilities of alternative tokens at each position. + """ from .resources.completions import Completions return Completions(self) @@ -192,18 +195,25 @@ def chat(self) -> Chat: @cached_property def embeddings(self) -> Embeddings: + """ + Get a vector representation of a given input that can be easily consumed by machine learning models and algorithms. + """ from .resources.embeddings import Embeddings return Embeddings(self) @cached_property def files(self) -> Files: + """ + Files are used to upload documents that can be used with features like Assistants and Fine-tuning. + """ from .resources.files import Files return Files(self) @cached_property def images(self) -> Images: + """Given a prompt and/or an input image, the model will generate a new image.""" from .resources.images import Images return Images(self) @@ -216,12 +226,16 @@ def audio(self) -> Audio: @cached_property def moderations(self) -> Moderations: + """ + Given text and/or image inputs, classifies if those inputs are potentially harmful. + """ from .resources.moderations import Moderations return Moderations(self) @cached_property def models(self) -> Models: + """List and describe the various models available in the API.""" from .resources.models import Models return Models(self) @@ -252,12 +266,14 @@ def beta(self) -> Beta: @cached_property def batches(self) -> Batches: + """Create large batches of API requests to run asynchronously.""" from .resources.batches import Batches return Batches(self) @cached_property def uploads(self) -> Uploads: + """Use Uploads to upload large files in multiple parts.""" from .resources.uploads import Uploads return Uploads(self) @@ -276,12 +292,14 @@ def realtime(self) -> Realtime: @cached_property def conversations(self) -> Conversations: + """Manage conversations and conversation items.""" from .resources.conversations import Conversations return Conversations(self) @cached_property def evals(self) -> Evals: + """Manage and run evals in the OpenAI platform.""" from .resources.evals import Evals return Evals(self) @@ -537,6 +555,9 @@ def __init__( @cached_property def completions(self) -> AsyncCompletions: + """ + Given a prompt, the model will return one or more predicted completions, and can also return the probabilities of alternative tokens at each position. + """ from .resources.completions import AsyncCompletions return AsyncCompletions(self) @@ -549,18 +570,25 @@ def chat(self) -> AsyncChat: @cached_property def embeddings(self) -> AsyncEmbeddings: + """ + Get a vector representation of a given input that can be easily consumed by machine learning models and algorithms. + """ from .resources.embeddings import AsyncEmbeddings return AsyncEmbeddings(self) @cached_property def files(self) -> AsyncFiles: + """ + Files are used to upload documents that can be used with features like Assistants and Fine-tuning. + """ from .resources.files import AsyncFiles return AsyncFiles(self) @cached_property def images(self) -> AsyncImages: + """Given a prompt and/or an input image, the model will generate a new image.""" from .resources.images import AsyncImages return AsyncImages(self) @@ -573,12 +601,16 @@ def audio(self) -> AsyncAudio: @cached_property def moderations(self) -> AsyncModerations: + """ + Given text and/or image inputs, classifies if those inputs are potentially harmful. + """ from .resources.moderations import AsyncModerations return AsyncModerations(self) @cached_property def models(self) -> AsyncModels: + """List and describe the various models available in the API.""" from .resources.models import AsyncModels return AsyncModels(self) @@ -609,12 +641,14 @@ def beta(self) -> AsyncBeta: @cached_property def batches(self) -> AsyncBatches: + """Create large batches of API requests to run asynchronously.""" from .resources.batches import AsyncBatches return AsyncBatches(self) @cached_property def uploads(self) -> AsyncUploads: + """Use Uploads to upload large files in multiple parts.""" from .resources.uploads import AsyncUploads return AsyncUploads(self) @@ -633,12 +667,14 @@ def realtime(self) -> AsyncRealtime: @cached_property def conversations(self) -> AsyncConversations: + """Manage conversations and conversation items.""" from .resources.conversations import AsyncConversations return AsyncConversations(self) @cached_property def evals(self) -> AsyncEvals: + """Manage and run evals in the OpenAI platform.""" from .resources.evals import AsyncEvals return AsyncEvals(self) @@ -805,6 +841,9 @@ def __init__(self, client: OpenAI) -> None: @cached_property def completions(self) -> completions.CompletionsWithRawResponse: + """ + Given a prompt, the model will return one or more predicted completions, and can also return the probabilities of alternative tokens at each position. + """ from .resources.completions import CompletionsWithRawResponse return CompletionsWithRawResponse(self._client.completions) @@ -817,18 +856,25 @@ def chat(self) -> chat.ChatWithRawResponse: @cached_property def embeddings(self) -> embeddings.EmbeddingsWithRawResponse: + """ + Get a vector representation of a given input that can be easily consumed by machine learning models and algorithms. + """ from .resources.embeddings import EmbeddingsWithRawResponse return EmbeddingsWithRawResponse(self._client.embeddings) @cached_property def files(self) -> files.FilesWithRawResponse: + """ + Files are used to upload documents that can be used with features like Assistants and Fine-tuning. + """ from .resources.files import FilesWithRawResponse return FilesWithRawResponse(self._client.files) @cached_property def images(self) -> images.ImagesWithRawResponse: + """Given a prompt and/or an input image, the model will generate a new image.""" from .resources.images import ImagesWithRawResponse return ImagesWithRawResponse(self._client.images) @@ -841,12 +887,16 @@ def audio(self) -> audio.AudioWithRawResponse: @cached_property def moderations(self) -> moderations.ModerationsWithRawResponse: + """ + Given text and/or image inputs, classifies if those inputs are potentially harmful. + """ from .resources.moderations import ModerationsWithRawResponse return ModerationsWithRawResponse(self._client.moderations) @cached_property def models(self) -> models.ModelsWithRawResponse: + """List and describe the various models available in the API.""" from .resources.models import ModelsWithRawResponse return ModelsWithRawResponse(self._client.models) @@ -871,12 +921,14 @@ def beta(self) -> beta.BetaWithRawResponse: @cached_property def batches(self) -> batches.BatchesWithRawResponse: + """Create large batches of API requests to run asynchronously.""" from .resources.batches import BatchesWithRawResponse return BatchesWithRawResponse(self._client.batches) @cached_property def uploads(self) -> uploads.UploadsWithRawResponse: + """Use Uploads to upload large files in multiple parts.""" from .resources.uploads import UploadsWithRawResponse return UploadsWithRawResponse(self._client.uploads) @@ -895,12 +947,14 @@ def realtime(self) -> realtime.RealtimeWithRawResponse: @cached_property def conversations(self) -> conversations.ConversationsWithRawResponse: + """Manage conversations and conversation items.""" from .resources.conversations import ConversationsWithRawResponse return ConversationsWithRawResponse(self._client.conversations) @cached_property def evals(self) -> evals.EvalsWithRawResponse: + """Manage and run evals in the OpenAI platform.""" from .resources.evals import EvalsWithRawResponse return EvalsWithRawResponse(self._client.evals) @@ -932,6 +986,9 @@ def __init__(self, client: AsyncOpenAI) -> None: @cached_property def completions(self) -> completions.AsyncCompletionsWithRawResponse: + """ + Given a prompt, the model will return one or more predicted completions, and can also return the probabilities of alternative tokens at each position. + """ from .resources.completions import AsyncCompletionsWithRawResponse return AsyncCompletionsWithRawResponse(self._client.completions) @@ -944,18 +1001,25 @@ def chat(self) -> chat.AsyncChatWithRawResponse: @cached_property def embeddings(self) -> embeddings.AsyncEmbeddingsWithRawResponse: + """ + Get a vector representation of a given input that can be easily consumed by machine learning models and algorithms. + """ from .resources.embeddings import AsyncEmbeddingsWithRawResponse return AsyncEmbeddingsWithRawResponse(self._client.embeddings) @cached_property def files(self) -> files.AsyncFilesWithRawResponse: + """ + Files are used to upload documents that can be used with features like Assistants and Fine-tuning. + """ from .resources.files import AsyncFilesWithRawResponse return AsyncFilesWithRawResponse(self._client.files) @cached_property def images(self) -> images.AsyncImagesWithRawResponse: + """Given a prompt and/or an input image, the model will generate a new image.""" from .resources.images import AsyncImagesWithRawResponse return AsyncImagesWithRawResponse(self._client.images) @@ -968,12 +1032,16 @@ def audio(self) -> audio.AsyncAudioWithRawResponse: @cached_property def moderations(self) -> moderations.AsyncModerationsWithRawResponse: + """ + Given text and/or image inputs, classifies if those inputs are potentially harmful. + """ from .resources.moderations import AsyncModerationsWithRawResponse return AsyncModerationsWithRawResponse(self._client.moderations) @cached_property def models(self) -> models.AsyncModelsWithRawResponse: + """List and describe the various models available in the API.""" from .resources.models import AsyncModelsWithRawResponse return AsyncModelsWithRawResponse(self._client.models) @@ -998,12 +1066,14 @@ def beta(self) -> beta.AsyncBetaWithRawResponse: @cached_property def batches(self) -> batches.AsyncBatchesWithRawResponse: + """Create large batches of API requests to run asynchronously.""" from .resources.batches import AsyncBatchesWithRawResponse return AsyncBatchesWithRawResponse(self._client.batches) @cached_property def uploads(self) -> uploads.AsyncUploadsWithRawResponse: + """Use Uploads to upload large files in multiple parts.""" from .resources.uploads import AsyncUploadsWithRawResponse return AsyncUploadsWithRawResponse(self._client.uploads) @@ -1022,12 +1092,14 @@ def realtime(self) -> realtime.AsyncRealtimeWithRawResponse: @cached_property def conversations(self) -> conversations.AsyncConversationsWithRawResponse: + """Manage conversations and conversation items.""" from .resources.conversations import AsyncConversationsWithRawResponse return AsyncConversationsWithRawResponse(self._client.conversations) @cached_property def evals(self) -> evals.AsyncEvalsWithRawResponse: + """Manage and run evals in the OpenAI platform.""" from .resources.evals import AsyncEvalsWithRawResponse return AsyncEvalsWithRawResponse(self._client.evals) @@ -1059,6 +1131,9 @@ def __init__(self, client: OpenAI) -> None: @cached_property def completions(self) -> completions.CompletionsWithStreamingResponse: + """ + Given a prompt, the model will return one or more predicted completions, and can also return the probabilities of alternative tokens at each position. + """ from .resources.completions import CompletionsWithStreamingResponse return CompletionsWithStreamingResponse(self._client.completions) @@ -1071,18 +1146,25 @@ def chat(self) -> chat.ChatWithStreamingResponse: @cached_property def embeddings(self) -> embeddings.EmbeddingsWithStreamingResponse: + """ + Get a vector representation of a given input that can be easily consumed by machine learning models and algorithms. + """ from .resources.embeddings import EmbeddingsWithStreamingResponse return EmbeddingsWithStreamingResponse(self._client.embeddings) @cached_property def files(self) -> files.FilesWithStreamingResponse: + """ + Files are used to upload documents that can be used with features like Assistants and Fine-tuning. + """ from .resources.files import FilesWithStreamingResponse return FilesWithStreamingResponse(self._client.files) @cached_property def images(self) -> images.ImagesWithStreamingResponse: + """Given a prompt and/or an input image, the model will generate a new image.""" from .resources.images import ImagesWithStreamingResponse return ImagesWithStreamingResponse(self._client.images) @@ -1095,12 +1177,16 @@ def audio(self) -> audio.AudioWithStreamingResponse: @cached_property def moderations(self) -> moderations.ModerationsWithStreamingResponse: + """ + Given text and/or image inputs, classifies if those inputs are potentially harmful. + """ from .resources.moderations import ModerationsWithStreamingResponse return ModerationsWithStreamingResponse(self._client.moderations) @cached_property def models(self) -> models.ModelsWithStreamingResponse: + """List and describe the various models available in the API.""" from .resources.models import ModelsWithStreamingResponse return ModelsWithStreamingResponse(self._client.models) @@ -1125,12 +1211,14 @@ def beta(self) -> beta.BetaWithStreamingResponse: @cached_property def batches(self) -> batches.BatchesWithStreamingResponse: + """Create large batches of API requests to run asynchronously.""" from .resources.batches import BatchesWithStreamingResponse return BatchesWithStreamingResponse(self._client.batches) @cached_property def uploads(self) -> uploads.UploadsWithStreamingResponse: + """Use Uploads to upload large files in multiple parts.""" from .resources.uploads import UploadsWithStreamingResponse return UploadsWithStreamingResponse(self._client.uploads) @@ -1149,12 +1237,14 @@ def realtime(self) -> realtime.RealtimeWithStreamingResponse: @cached_property def conversations(self) -> conversations.ConversationsWithStreamingResponse: + """Manage conversations and conversation items.""" from .resources.conversations import ConversationsWithStreamingResponse return ConversationsWithStreamingResponse(self._client.conversations) @cached_property def evals(self) -> evals.EvalsWithStreamingResponse: + """Manage and run evals in the OpenAI platform.""" from .resources.evals import EvalsWithStreamingResponse return EvalsWithStreamingResponse(self._client.evals) @@ -1186,6 +1276,9 @@ def __init__(self, client: AsyncOpenAI) -> None: @cached_property def completions(self) -> completions.AsyncCompletionsWithStreamingResponse: + """ + Given a prompt, the model will return one or more predicted completions, and can also return the probabilities of alternative tokens at each position. + """ from .resources.completions import AsyncCompletionsWithStreamingResponse return AsyncCompletionsWithStreamingResponse(self._client.completions) @@ -1198,18 +1291,25 @@ def chat(self) -> chat.AsyncChatWithStreamingResponse: @cached_property def embeddings(self) -> embeddings.AsyncEmbeddingsWithStreamingResponse: + """ + Get a vector representation of a given input that can be easily consumed by machine learning models and algorithms. + """ from .resources.embeddings import AsyncEmbeddingsWithStreamingResponse return AsyncEmbeddingsWithStreamingResponse(self._client.embeddings) @cached_property def files(self) -> files.AsyncFilesWithStreamingResponse: + """ + Files are used to upload documents that can be used with features like Assistants and Fine-tuning. + """ from .resources.files import AsyncFilesWithStreamingResponse return AsyncFilesWithStreamingResponse(self._client.files) @cached_property def images(self) -> images.AsyncImagesWithStreamingResponse: + """Given a prompt and/or an input image, the model will generate a new image.""" from .resources.images import AsyncImagesWithStreamingResponse return AsyncImagesWithStreamingResponse(self._client.images) @@ -1222,12 +1322,16 @@ def audio(self) -> audio.AsyncAudioWithStreamingResponse: @cached_property def moderations(self) -> moderations.AsyncModerationsWithStreamingResponse: + """ + Given text and/or image inputs, classifies if those inputs are potentially harmful. + """ from .resources.moderations import AsyncModerationsWithStreamingResponse return AsyncModerationsWithStreamingResponse(self._client.moderations) @cached_property def models(self) -> models.AsyncModelsWithStreamingResponse: + """List and describe the various models available in the API.""" from .resources.models import AsyncModelsWithStreamingResponse return AsyncModelsWithStreamingResponse(self._client.models) @@ -1252,12 +1356,14 @@ def beta(self) -> beta.AsyncBetaWithStreamingResponse: @cached_property def batches(self) -> batches.AsyncBatchesWithStreamingResponse: + """Create large batches of API requests to run asynchronously.""" from .resources.batches import AsyncBatchesWithStreamingResponse return AsyncBatchesWithStreamingResponse(self._client.batches) @cached_property def uploads(self) -> uploads.AsyncUploadsWithStreamingResponse: + """Use Uploads to upload large files in multiple parts.""" from .resources.uploads import AsyncUploadsWithStreamingResponse return AsyncUploadsWithStreamingResponse(self._client.uploads) @@ -1276,12 +1382,14 @@ def realtime(self) -> realtime.AsyncRealtimeWithStreamingResponse: @cached_property def conversations(self) -> conversations.AsyncConversationsWithStreamingResponse: + """Manage conversations and conversation items.""" from .resources.conversations import AsyncConversationsWithStreamingResponse return AsyncConversationsWithStreamingResponse(self._client.conversations) @cached_property def evals(self) -> evals.AsyncEvalsWithStreamingResponse: + """Manage and run evals in the OpenAI platform.""" from .resources.evals import AsyncEvalsWithStreamingResponse return AsyncEvalsWithStreamingResponse(self._client.evals) diff --git a/src/openai/_version.py b/src/openai/_version.py index 08cf29390a..417b40c283 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__ = "2.24.0" # x-release-please-version +__version__ = "2.25.0" # x-release-please-version diff --git a/src/openai/lib/_parsing/_responses.py b/src/openai/lib/_parsing/_responses.py index 5676eb0b63..df0f52cdc8 100644 --- a/src/openai/lib/_parsing/_responses.py +++ b/src/openai/lib/_parsing/_responses.py @@ -101,6 +101,8 @@ def parse_response( output.type == "computer_call" or output.type == "file_search_call" or output.type == "web_search_call" + or output.type == "tool_search_call" + or output.type == "tool_search_output" or output.type == "reasoning" or output.type == "compaction" or output.type == "mcp_call" diff --git a/src/openai/resources/audio/audio.py b/src/openai/resources/audio/audio.py index 383b7073bf..040a058df6 100644 --- a/src/openai/resources/audio/audio.py +++ b/src/openai/resources/audio/audio.py @@ -35,14 +35,17 @@ class Audio(SyncAPIResource): @cached_property def transcriptions(self) -> Transcriptions: + """Turn audio into text or text into audio.""" return Transcriptions(self._client) @cached_property def translations(self) -> Translations: + """Turn audio into text or text into audio.""" return Translations(self._client) @cached_property def speech(self) -> Speech: + """Turn audio into text or text into audio.""" return Speech(self._client) @cached_property @@ -68,14 +71,17 @@ def with_streaming_response(self) -> AudioWithStreamingResponse: class AsyncAudio(AsyncAPIResource): @cached_property def transcriptions(self) -> AsyncTranscriptions: + """Turn audio into text or text into audio.""" return AsyncTranscriptions(self._client) @cached_property def translations(self) -> AsyncTranslations: + """Turn audio into text or text into audio.""" return AsyncTranslations(self._client) @cached_property def speech(self) -> AsyncSpeech: + """Turn audio into text or text into audio.""" return AsyncSpeech(self._client) @cached_property @@ -104,14 +110,17 @@ def __init__(self, audio: Audio) -> None: @cached_property def transcriptions(self) -> TranscriptionsWithRawResponse: + """Turn audio into text or text into audio.""" return TranscriptionsWithRawResponse(self._audio.transcriptions) @cached_property def translations(self) -> TranslationsWithRawResponse: + """Turn audio into text or text into audio.""" return TranslationsWithRawResponse(self._audio.translations) @cached_property def speech(self) -> SpeechWithRawResponse: + """Turn audio into text or text into audio.""" return SpeechWithRawResponse(self._audio.speech) @@ -121,14 +130,17 @@ def __init__(self, audio: AsyncAudio) -> None: @cached_property def transcriptions(self) -> AsyncTranscriptionsWithRawResponse: + """Turn audio into text or text into audio.""" return AsyncTranscriptionsWithRawResponse(self._audio.transcriptions) @cached_property def translations(self) -> AsyncTranslationsWithRawResponse: + """Turn audio into text or text into audio.""" return AsyncTranslationsWithRawResponse(self._audio.translations) @cached_property def speech(self) -> AsyncSpeechWithRawResponse: + """Turn audio into text or text into audio.""" return AsyncSpeechWithRawResponse(self._audio.speech) @@ -138,14 +150,17 @@ def __init__(self, audio: Audio) -> None: @cached_property def transcriptions(self) -> TranscriptionsWithStreamingResponse: + """Turn audio into text or text into audio.""" return TranscriptionsWithStreamingResponse(self._audio.transcriptions) @cached_property def translations(self) -> TranslationsWithStreamingResponse: + """Turn audio into text or text into audio.""" return TranslationsWithStreamingResponse(self._audio.translations) @cached_property def speech(self) -> SpeechWithStreamingResponse: + """Turn audio into text or text into audio.""" return SpeechWithStreamingResponse(self._audio.speech) @@ -155,12 +170,15 @@ def __init__(self, audio: AsyncAudio) -> None: @cached_property def transcriptions(self) -> AsyncTranscriptionsWithStreamingResponse: + """Turn audio into text or text into audio.""" return AsyncTranscriptionsWithStreamingResponse(self._audio.transcriptions) @cached_property def translations(self) -> AsyncTranslationsWithStreamingResponse: + """Turn audio into text or text into audio.""" return AsyncTranslationsWithStreamingResponse(self._audio.translations) @cached_property def speech(self) -> AsyncSpeechWithStreamingResponse: + """Turn audio into text or text into audio.""" return AsyncSpeechWithStreamingResponse(self._audio.speech) diff --git a/src/openai/resources/audio/speech.py b/src/openai/resources/audio/speech.py index 96a32f9268..f937321baa 100644 --- a/src/openai/resources/audio/speech.py +++ b/src/openai/resources/audio/speech.py @@ -26,6 +26,8 @@ class Speech(SyncAPIResource): + """Turn audio into text or text into audio.""" + @cached_property def with_raw_response(self) -> SpeechWithRawResponse: """ @@ -125,6 +127,8 @@ def create( class AsyncSpeech(AsyncAPIResource): + """Turn audio into text or text into audio.""" + @cached_property def with_raw_response(self) -> AsyncSpeechWithRawResponse: """ diff --git a/src/openai/resources/audio/transcriptions.py b/src/openai/resources/audio/transcriptions.py index bc6e9f22de..25e6e0cb5e 100644 --- a/src/openai/resources/audio/transcriptions.py +++ b/src/openai/resources/audio/transcriptions.py @@ -42,6 +42,8 @@ class Transcriptions(SyncAPIResource): + """Turn audio into text or text into audio.""" + @cached_property def with_raw_response(self) -> TranscriptionsWithRawResponse: """ @@ -497,6 +499,8 @@ def create( class AsyncTranscriptions(AsyncAPIResource): + """Turn audio into text or text into audio.""" + @cached_property def with_raw_response(self) -> AsyncTranscriptionsWithRawResponse: """ diff --git a/src/openai/resources/audio/translations.py b/src/openai/resources/audio/translations.py index 310f901fb3..0751a65586 100644 --- a/src/openai/resources/audio/translations.py +++ b/src/openai/resources/audio/translations.py @@ -27,6 +27,8 @@ class Translations(SyncAPIResource): + """Turn audio into text or text into audio.""" + @cached_property def with_raw_response(self) -> TranslationsWithRawResponse: """ @@ -170,6 +172,8 @@ def create( class AsyncTranslations(AsyncAPIResource): + """Turn audio into text or text into audio.""" + @cached_property def with_raw_response(self) -> AsyncTranslationsWithRawResponse: """ diff --git a/src/openai/resources/batches.py b/src/openai/resources/batches.py index bc856bf5aa..005a32870e 100644 --- a/src/openai/resources/batches.py +++ b/src/openai/resources/batches.py @@ -23,6 +23,8 @@ class Batches(SyncAPIResource): + """Create large batches of API requests to run asynchronously.""" + @cached_property def with_raw_response(self) -> BatchesWithRawResponse: """ @@ -247,6 +249,8 @@ def cancel( class AsyncBatches(AsyncAPIResource): + """Create large batches of API requests to run asynchronously.""" + @cached_property def with_raw_response(self) -> AsyncBatchesWithRawResponse: """ diff --git a/src/openai/resources/beta/assistants.py b/src/openai/resources/beta/assistants.py index 8c69700059..bf22122553 100644 --- a/src/openai/resources/beta/assistants.py +++ b/src/openai/resources/beta/assistants.py @@ -33,6 +33,8 @@ class Assistants(SyncAPIResource): + """Build Assistants that can call models and use tools.""" + @cached_property def with_raw_response(self) -> AssistantsWithRawResponse: """ @@ -507,6 +509,8 @@ def delete( class AsyncAssistants(AsyncAPIResource): + """Build Assistants that can call models and use tools.""" + @cached_property def with_raw_response(self) -> AsyncAssistantsWithRawResponse: """ diff --git a/src/openai/resources/beta/beta.py b/src/openai/resources/beta/beta.py index 5ee3639db1..388a1c5d1f 100644 --- a/src/openai/resources/beta/beta.py +++ b/src/openai/resources/beta/beta.py @@ -52,10 +52,12 @@ def chatkit(self) -> ChatKit: @cached_property def assistants(self) -> Assistants: + """Build Assistants that can call models and use tools.""" return Assistants(self._client) @cached_property def threads(self) -> Threads: + """Build Assistants that can call models and use tools.""" return Threads(self._client) @cached_property @@ -93,10 +95,12 @@ def chatkit(self) -> AsyncChatKit: @cached_property def assistants(self) -> AsyncAssistants: + """Build Assistants that can call models and use tools.""" return AsyncAssistants(self._client) @cached_property def threads(self) -> AsyncThreads: + """Build Assistants that can call models and use tools.""" return AsyncThreads(self._client) @cached_property @@ -129,10 +133,12 @@ def chatkit(self) -> ChatKitWithRawResponse: @cached_property def assistants(self) -> AssistantsWithRawResponse: + """Build Assistants that can call models and use tools.""" return AssistantsWithRawResponse(self._beta.assistants) @cached_property def threads(self) -> ThreadsWithRawResponse: + """Build Assistants that can call models and use tools.""" return ThreadsWithRawResponse(self._beta.threads) @@ -146,10 +152,12 @@ def chatkit(self) -> AsyncChatKitWithRawResponse: @cached_property def assistants(self) -> AsyncAssistantsWithRawResponse: + """Build Assistants that can call models and use tools.""" return AsyncAssistantsWithRawResponse(self._beta.assistants) @cached_property def threads(self) -> AsyncThreadsWithRawResponse: + """Build Assistants that can call models and use tools.""" return AsyncThreadsWithRawResponse(self._beta.threads) @@ -163,10 +171,12 @@ def chatkit(self) -> ChatKitWithStreamingResponse: @cached_property def assistants(self) -> AssistantsWithStreamingResponse: + """Build Assistants that can call models and use tools.""" return AssistantsWithStreamingResponse(self._beta.assistants) @cached_property def threads(self) -> ThreadsWithStreamingResponse: + """Build Assistants that can call models and use tools.""" return ThreadsWithStreamingResponse(self._beta.threads) @@ -180,8 +190,10 @@ def chatkit(self) -> AsyncChatKitWithStreamingResponse: @cached_property def assistants(self) -> AsyncAssistantsWithStreamingResponse: + """Build Assistants that can call models and use tools.""" return AsyncAssistantsWithStreamingResponse(self._beta.assistants) @cached_property def threads(self) -> AsyncThreadsWithStreamingResponse: + """Build Assistants that can call models and use tools.""" return AsyncThreadsWithStreamingResponse(self._beta.threads) diff --git a/src/openai/resources/beta/threads/messages.py b/src/openai/resources/beta/threads/messages.py index d94ecca9a2..e783310933 100644 --- a/src/openai/resources/beta/threads/messages.py +++ b/src/openai/resources/beta/threads/messages.py @@ -29,6 +29,8 @@ class Messages(SyncAPIResource): + """Build Assistants that can call models and use tools.""" + @cached_property def with_raw_response(self) -> MessagesWithRawResponse: """ @@ -312,6 +314,8 @@ def delete( class AsyncMessages(AsyncAPIResource): + """Build Assistants that can call models and use tools.""" + @cached_property def with_raw_response(self) -> AsyncMessagesWithRawResponse: """ diff --git a/src/openai/resources/beta/threads/runs/runs.py b/src/openai/resources/beta/threads/runs/runs.py index 90845a2f62..20862185d2 100644 --- a/src/openai/resources/beta/threads/runs/runs.py +++ b/src/openai/resources/beta/threads/runs/runs.py @@ -59,8 +59,11 @@ class Runs(SyncAPIResource): + """Build Assistants that can call models and use tools.""" + @cached_property def steps(self) -> Steps: + """Build Assistants that can call models and use tools.""" return Steps(self._client) @cached_property @@ -1518,8 +1521,11 @@ def submit_tool_outputs_stream( class AsyncRuns(AsyncAPIResource): + """Build Assistants that can call models and use tools.""" + @cached_property def steps(self) -> AsyncSteps: + """Build Assistants that can call models and use tools.""" return AsyncSteps(self._client) @cached_property @@ -3015,6 +3021,7 @@ def __init__(self, runs: Runs) -> None: @cached_property def steps(self) -> StepsWithRawResponse: + """Build Assistants that can call models and use tools.""" return StepsWithRawResponse(self._runs.steps) @@ -3055,6 +3062,7 @@ def __init__(self, runs: AsyncRuns) -> None: @cached_property def steps(self) -> AsyncStepsWithRawResponse: + """Build Assistants that can call models and use tools.""" return AsyncStepsWithRawResponse(self._runs.steps) @@ -3095,6 +3103,7 @@ def __init__(self, runs: Runs) -> None: @cached_property def steps(self) -> StepsWithStreamingResponse: + """Build Assistants that can call models and use tools.""" return StepsWithStreamingResponse(self._runs.steps) @@ -3135,4 +3144,5 @@ def __init__(self, runs: AsyncRuns) -> None: @cached_property def steps(self) -> AsyncStepsWithStreamingResponse: + """Build Assistants that can call models and use tools.""" return AsyncStepsWithStreamingResponse(self._runs.steps) diff --git a/src/openai/resources/beta/threads/runs/steps.py b/src/openai/resources/beta/threads/runs/steps.py index 254a94435c..dea5df69bc 100644 --- a/src/openai/resources/beta/threads/runs/steps.py +++ b/src/openai/resources/beta/threads/runs/steps.py @@ -24,6 +24,8 @@ class Steps(SyncAPIResource): + """Build Assistants that can call models and use tools.""" + @cached_property def with_raw_response(self) -> StepsWithRawResponse: """ @@ -180,6 +182,8 @@ def list( class AsyncSteps(AsyncAPIResource): + """Build Assistants that can call models and use tools.""" + @cached_property def with_raw_response(self) -> AsyncStepsWithRawResponse: """ diff --git a/src/openai/resources/beta/threads/threads.py b/src/openai/resources/beta/threads/threads.py index a804fda159..0a93baf452 100644 --- a/src/openai/resources/beta/threads/threads.py +++ b/src/openai/resources/beta/threads/threads.py @@ -60,12 +60,16 @@ class Threads(SyncAPIResource): + """Build Assistants that can call models and use tools.""" + @cached_property def runs(self) -> Runs: + """Build Assistants that can call models and use tools.""" return Runs(self._client) @cached_property def messages(self) -> Messages: + """Build Assistants that can call models and use tools.""" return Messages(self._client) @cached_property @@ -922,12 +926,16 @@ def create_and_run_stream( class AsyncThreads(AsyncAPIResource): + """Build Assistants that can call models and use tools.""" + @cached_property def runs(self) -> AsyncRuns: + """Build Assistants that can call models and use tools.""" return AsyncRuns(self._client) @cached_property def messages(self) -> AsyncMessages: + """Build Assistants that can call models and use tools.""" return AsyncMessages(self._client) @cached_property @@ -1819,10 +1827,12 @@ def __init__(self, threads: Threads) -> None: @cached_property def runs(self) -> RunsWithRawResponse: + """Build Assistants that can call models and use tools.""" return RunsWithRawResponse(self._threads.runs) @cached_property def messages(self) -> MessagesWithRawResponse: + """Build Assistants that can call models and use tools.""" return MessagesWithRawResponse(self._threads.messages) @@ -1858,10 +1868,12 @@ def __init__(self, threads: AsyncThreads) -> None: @cached_property def runs(self) -> AsyncRunsWithRawResponse: + """Build Assistants that can call models and use tools.""" return AsyncRunsWithRawResponse(self._threads.runs) @cached_property def messages(self) -> AsyncMessagesWithRawResponse: + """Build Assistants that can call models and use tools.""" return AsyncMessagesWithRawResponse(self._threads.messages) @@ -1897,10 +1909,12 @@ def __init__(self, threads: Threads) -> None: @cached_property def runs(self) -> RunsWithStreamingResponse: + """Build Assistants that can call models and use tools.""" return RunsWithStreamingResponse(self._threads.runs) @cached_property def messages(self) -> MessagesWithStreamingResponse: + """Build Assistants that can call models and use tools.""" return MessagesWithStreamingResponse(self._threads.messages) @@ -1936,8 +1950,10 @@ def __init__(self, threads: AsyncThreads) -> None: @cached_property def runs(self) -> AsyncRunsWithStreamingResponse: + """Build Assistants that can call models and use tools.""" return AsyncRunsWithStreamingResponse(self._threads.runs) @cached_property def messages(self) -> AsyncMessagesWithStreamingResponse: + """Build Assistants that can call models and use tools.""" return AsyncMessagesWithStreamingResponse(self._threads.messages) diff --git a/src/openai/resources/chat/chat.py b/src/openai/resources/chat/chat.py index 14f9224b41..2c921e7480 100644 --- a/src/openai/resources/chat/chat.py +++ b/src/openai/resources/chat/chat.py @@ -19,6 +19,9 @@ class Chat(SyncAPIResource): @cached_property def completions(self) -> Completions: + """ + Given a list of messages comprising a conversation, the model will return a response. + """ return Completions(self._client) @cached_property @@ -44,6 +47,9 @@ def with_streaming_response(self) -> ChatWithStreamingResponse: class AsyncChat(AsyncAPIResource): @cached_property def completions(self) -> AsyncCompletions: + """ + Given a list of messages comprising a conversation, the model will return a response. + """ return AsyncCompletions(self._client) @cached_property @@ -72,6 +78,9 @@ def __init__(self, chat: Chat) -> None: @cached_property def completions(self) -> CompletionsWithRawResponse: + """ + Given a list of messages comprising a conversation, the model will return a response. + """ return CompletionsWithRawResponse(self._chat.completions) @@ -81,6 +90,9 @@ def __init__(self, chat: AsyncChat) -> None: @cached_property def completions(self) -> AsyncCompletionsWithRawResponse: + """ + Given a list of messages comprising a conversation, the model will return a response. + """ return AsyncCompletionsWithRawResponse(self._chat.completions) @@ -90,6 +102,9 @@ def __init__(self, chat: Chat) -> None: @cached_property def completions(self) -> CompletionsWithStreamingResponse: + """ + Given a list of messages comprising a conversation, the model will return a response. + """ return CompletionsWithStreamingResponse(self._chat.completions) @@ -99,4 +114,7 @@ def __init__(self, chat: AsyncChat) -> None: @cached_property def completions(self) -> AsyncCompletionsWithStreamingResponse: + """ + Given a list of messages comprising a conversation, the model will return a response. + """ return AsyncCompletionsWithStreamingResponse(self._chat.completions) diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index 5d56d05d87..a705c1f658 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -58,8 +58,15 @@ class Completions(SyncAPIResource): + """ + Given a list of messages comprising a conversation, the model will return a response. + """ + @cached_property def messages(self) -> Messages: + """ + Given a list of messages comprising a conversation, the model will return a response. + """ return Messages(self._client) @cached_property @@ -1554,8 +1561,15 @@ def stream( class AsyncCompletions(AsyncAPIResource): + """ + Given a list of messages comprising a conversation, the model will return a response. + """ + @cached_property def messages(self) -> AsyncMessages: + """ + Given a list of messages comprising a conversation, the model will return a response. + """ return AsyncMessages(self._client) @cached_property @@ -3075,6 +3089,9 @@ def __init__(self, completions: Completions) -> None: @cached_property def messages(self) -> MessagesWithRawResponse: + """ + Given a list of messages comprising a conversation, the model will return a response. + """ return MessagesWithRawResponse(self._completions.messages) @@ -3103,6 +3120,9 @@ def __init__(self, completions: AsyncCompletions) -> None: @cached_property def messages(self) -> AsyncMessagesWithRawResponse: + """ + Given a list of messages comprising a conversation, the model will return a response. + """ return AsyncMessagesWithRawResponse(self._completions.messages) @@ -3131,6 +3151,9 @@ def __init__(self, completions: Completions) -> None: @cached_property def messages(self) -> MessagesWithStreamingResponse: + """ + Given a list of messages comprising a conversation, the model will return a response. + """ return MessagesWithStreamingResponse(self._completions.messages) @@ -3159,6 +3182,9 @@ def __init__(self, completions: AsyncCompletions) -> None: @cached_property def messages(self) -> AsyncMessagesWithStreamingResponse: + """ + Given a list of messages comprising a conversation, the model will return a response. + """ return AsyncMessagesWithStreamingResponse(self._completions.messages) diff --git a/src/openai/resources/chat/completions/messages.py b/src/openai/resources/chat/completions/messages.py index 3d6dc79cd6..b1c6a08d51 100644 --- a/src/openai/resources/chat/completions/messages.py +++ b/src/openai/resources/chat/completions/messages.py @@ -21,6 +21,10 @@ class Messages(SyncAPIResource): + """ + Given a list of messages comprising a conversation, the model will return a response. + """ + @cached_property def with_raw_response(self) -> MessagesWithRawResponse: """ @@ -99,6 +103,10 @@ def list( class AsyncMessages(AsyncAPIResource): + """ + Given a list of messages comprising a conversation, the model will return a response. + """ + @cached_property def with_raw_response(self) -> AsyncMessagesWithRawResponse: """ diff --git a/src/openai/resources/completions.py b/src/openai/resources/completions.py index 4b6e29395b..4c9e266787 100644 --- a/src/openai/resources/completions.py +++ b/src/openai/resources/completions.py @@ -25,6 +25,10 @@ class Completions(SyncAPIResource): + """ + Given a prompt, the model will return one or more predicted completions, and can also return the probabilities of alternative tokens at each position. + """ + @cached_property def with_raw_response(self) -> CompletionsWithRawResponse: """ @@ -584,6 +588,10 @@ def create( class AsyncCompletions(AsyncAPIResource): + """ + Given a prompt, the model will return one or more predicted completions, and can also return the probabilities of alternative tokens at each position. + """ + @cached_property def with_raw_response(self) -> AsyncCompletionsWithRawResponse: """ diff --git a/src/openai/resources/conversations/conversations.py b/src/openai/resources/conversations/conversations.py index da037a4e22..f2c54e4d04 100644 --- a/src/openai/resources/conversations/conversations.py +++ b/src/openai/resources/conversations/conversations.py @@ -31,8 +31,11 @@ class Conversations(SyncAPIResource): + """Manage conversations and conversation items.""" + @cached_property def items(self) -> Items: + """Manage conversations and conversation items.""" return Items(self._client) @cached_property @@ -214,8 +217,11 @@ def delete( class AsyncConversations(AsyncAPIResource): + """Manage conversations and conversation items.""" + @cached_property def items(self) -> AsyncItems: + """Manage conversations and conversation items.""" return AsyncItems(self._client) @cached_property @@ -417,6 +423,7 @@ def __init__(self, conversations: Conversations) -> None: @cached_property def items(self) -> ItemsWithRawResponse: + """Manage conversations and conversation items.""" return ItemsWithRawResponse(self._conversations.items) @@ -439,6 +446,7 @@ def __init__(self, conversations: AsyncConversations) -> None: @cached_property def items(self) -> AsyncItemsWithRawResponse: + """Manage conversations and conversation items.""" return AsyncItemsWithRawResponse(self._conversations.items) @@ -461,6 +469,7 @@ def __init__(self, conversations: Conversations) -> None: @cached_property def items(self) -> ItemsWithStreamingResponse: + """Manage conversations and conversation items.""" return ItemsWithStreamingResponse(self._conversations.items) @@ -483,4 +492,5 @@ def __init__(self, conversations: AsyncConversations) -> None: @cached_property def items(self) -> AsyncItemsWithStreamingResponse: + """Manage conversations and conversation items.""" return AsyncItemsWithStreamingResponse(self._conversations.items) diff --git a/src/openai/resources/conversations/items.py b/src/openai/resources/conversations/items.py index 3dba144849..1f8e101f7f 100644 --- a/src/openai/resources/conversations/items.py +++ b/src/openai/resources/conversations/items.py @@ -26,6 +26,8 @@ class Items(SyncAPIResource): + """Manage conversations and conversation items.""" + @cached_property def with_raw_response(self) -> ItemsWithRawResponse: """ @@ -256,6 +258,8 @@ def delete( class AsyncItems(AsyncAPIResource): + """Manage conversations and conversation items.""" + @cached_property def with_raw_response(self) -> AsyncItemsWithRawResponse: """ diff --git a/src/openai/resources/embeddings.py b/src/openai/resources/embeddings.py index 5dc3dfa9b3..86eb949a40 100644 --- a/src/openai/resources/embeddings.py +++ b/src/openai/resources/embeddings.py @@ -25,6 +25,10 @@ class Embeddings(SyncAPIResource): + """ + Get a vector representation of a given input that can be easily consumed by machine learning models and algorithms. + """ + @cached_property def with_raw_response(self) -> EmbeddingsWithRawResponse: """ @@ -144,6 +148,10 @@ def parser(obj: CreateEmbeddingResponse) -> CreateEmbeddingResponse: class AsyncEmbeddings(AsyncAPIResource): + """ + Get a vector representation of a given input that can be easily consumed by machine learning models and algorithms. + """ + @cached_property def with_raw_response(self) -> AsyncEmbeddingsWithRawResponse: """ diff --git a/src/openai/resources/evals/evals.py b/src/openai/resources/evals/evals.py index 40c4a3e9a3..f0fe28fe8c 100644 --- a/src/openai/resources/evals/evals.py +++ b/src/openai/resources/evals/evals.py @@ -35,8 +35,11 @@ class Evals(SyncAPIResource): + """Manage and run evals in the OpenAI platform.""" + @cached_property def runs(self) -> Runs: + """Manage and run evals in the OpenAI platform.""" return Runs(self._client) @cached_property @@ -299,8 +302,11 @@ def delete( class AsyncEvals(AsyncAPIResource): + """Manage and run evals in the OpenAI platform.""" + @cached_property def runs(self) -> AsyncRuns: + """Manage and run evals in the OpenAI platform.""" return AsyncRuns(self._client) @cached_property @@ -584,6 +590,7 @@ def __init__(self, evals: Evals) -> None: @cached_property def runs(self) -> RunsWithRawResponse: + """Manage and run evals in the OpenAI platform.""" return RunsWithRawResponse(self._evals.runs) @@ -609,6 +616,7 @@ def __init__(self, evals: AsyncEvals) -> None: @cached_property def runs(self) -> AsyncRunsWithRawResponse: + """Manage and run evals in the OpenAI platform.""" return AsyncRunsWithRawResponse(self._evals.runs) @@ -634,6 +642,7 @@ def __init__(self, evals: Evals) -> None: @cached_property def runs(self) -> RunsWithStreamingResponse: + """Manage and run evals in the OpenAI platform.""" return RunsWithStreamingResponse(self._evals.runs) @@ -659,4 +668,5 @@ def __init__(self, evals: AsyncEvals) -> None: @cached_property def runs(self) -> AsyncRunsWithStreamingResponse: + """Manage and run evals in the OpenAI platform.""" return AsyncRunsWithStreamingResponse(self._evals.runs) diff --git a/src/openai/resources/evals/runs/output_items.py b/src/openai/resources/evals/runs/output_items.py index c2dee72122..c2e6647715 100644 --- a/src/openai/resources/evals/runs/output_items.py +++ b/src/openai/resources/evals/runs/output_items.py @@ -22,6 +22,8 @@ class OutputItems(SyncAPIResource): + """Manage and run evals in the OpenAI platform.""" + @cached_property def with_raw_response(self) -> OutputItemsWithRawResponse: """ @@ -145,6 +147,8 @@ def list( class AsyncOutputItems(AsyncAPIResource): + """Manage and run evals in the OpenAI platform.""" + @cached_property def with_raw_response(self) -> AsyncOutputItemsWithRawResponse: """ diff --git a/src/openai/resources/evals/runs/runs.py b/src/openai/resources/evals/runs/runs.py index b747b198f8..49eecd768f 100644 --- a/src/openai/resources/evals/runs/runs.py +++ b/src/openai/resources/evals/runs/runs.py @@ -35,8 +35,11 @@ class Runs(SyncAPIResource): + """Manage and run evals in the OpenAI platform.""" + @cached_property def output_items(self) -> OutputItems: + """Manage and run evals in the OpenAI platform.""" return OutputItems(self._client) @cached_property @@ -285,8 +288,11 @@ def cancel( class AsyncRuns(AsyncAPIResource): + """Manage and run evals in the OpenAI platform.""" + @cached_property def output_items(self) -> AsyncOutputItems: + """Manage and run evals in the OpenAI platform.""" return AsyncOutputItems(self._client) @cached_property @@ -556,6 +562,7 @@ def __init__(self, runs: Runs) -> None: @cached_property def output_items(self) -> OutputItemsWithRawResponse: + """Manage and run evals in the OpenAI platform.""" return OutputItemsWithRawResponse(self._runs.output_items) @@ -581,6 +588,7 @@ def __init__(self, runs: AsyncRuns) -> None: @cached_property def output_items(self) -> AsyncOutputItemsWithRawResponse: + """Manage and run evals in the OpenAI platform.""" return AsyncOutputItemsWithRawResponse(self._runs.output_items) @@ -606,6 +614,7 @@ def __init__(self, runs: Runs) -> None: @cached_property def output_items(self) -> OutputItemsWithStreamingResponse: + """Manage and run evals in the OpenAI platform.""" return OutputItemsWithStreamingResponse(self._runs.output_items) @@ -631,4 +640,5 @@ def __init__(self, runs: AsyncRuns) -> None: @cached_property def output_items(self) -> AsyncOutputItemsWithStreamingResponse: + """Manage and run evals in the OpenAI platform.""" return AsyncOutputItemsWithStreamingResponse(self._runs.output_items) diff --git a/src/openai/resources/files.py b/src/openai/resources/files.py index 964d6505e7..7341b326dc 100644 --- a/src/openai/resources/files.py +++ b/src/openai/resources/files.py @@ -33,6 +33,10 @@ class Files(SyncAPIResource): + """ + Files are used to upload documents that can be used with features like Assistants and Fine-tuning. + """ + @cached_property def with_raw_response(self) -> FilesWithRawResponse: """ @@ -354,6 +358,10 @@ def wait_for_processing( class AsyncFiles(AsyncAPIResource): + """ + Files are used to upload documents that can be used with features like Assistants and Fine-tuning. + """ + @cached_property def with_raw_response(self) -> AsyncFilesWithRawResponse: """ diff --git a/src/openai/resources/fine_tuning/alpha/alpha.py b/src/openai/resources/fine_tuning/alpha/alpha.py index 54c05fab69..183208d0ab 100644 --- a/src/openai/resources/fine_tuning/alpha/alpha.py +++ b/src/openai/resources/fine_tuning/alpha/alpha.py @@ -19,6 +19,7 @@ class Alpha(SyncAPIResource): @cached_property def graders(self) -> Graders: + """Manage fine-tuning jobs to tailor a model to your specific training data.""" return Graders(self._client) @cached_property @@ -44,6 +45,7 @@ def with_streaming_response(self) -> AlphaWithStreamingResponse: class AsyncAlpha(AsyncAPIResource): @cached_property def graders(self) -> AsyncGraders: + """Manage fine-tuning jobs to tailor a model to your specific training data.""" return AsyncGraders(self._client) @cached_property @@ -72,6 +74,7 @@ def __init__(self, alpha: Alpha) -> None: @cached_property def graders(self) -> GradersWithRawResponse: + """Manage fine-tuning jobs to tailor a model to your specific training data.""" return GradersWithRawResponse(self._alpha.graders) @@ -81,6 +84,7 @@ def __init__(self, alpha: AsyncAlpha) -> None: @cached_property def graders(self) -> AsyncGradersWithRawResponse: + """Manage fine-tuning jobs to tailor a model to your specific training data.""" return AsyncGradersWithRawResponse(self._alpha.graders) @@ -90,6 +94,7 @@ def __init__(self, alpha: Alpha) -> None: @cached_property def graders(self) -> GradersWithStreamingResponse: + """Manage fine-tuning jobs to tailor a model to your specific training data.""" return GradersWithStreamingResponse(self._alpha.graders) @@ -99,4 +104,5 @@ def __init__(self, alpha: AsyncAlpha) -> None: @cached_property def graders(self) -> AsyncGradersWithStreamingResponse: + """Manage fine-tuning jobs to tailor a model to your specific training data.""" return AsyncGradersWithStreamingResponse(self._alpha.graders) diff --git a/src/openai/resources/fine_tuning/alpha/graders.py b/src/openai/resources/fine_tuning/alpha/graders.py index e7a9b925ea..e5d5dea5de 100644 --- a/src/openai/resources/fine_tuning/alpha/graders.py +++ b/src/openai/resources/fine_tuning/alpha/graders.py @@ -19,6 +19,8 @@ class Graders(SyncAPIResource): + """Manage fine-tuning jobs to tailor a model to your specific training data.""" + @cached_property def with_raw_response(self) -> GradersWithRawResponse: """ @@ -127,6 +129,8 @@ def validate( class AsyncGraders(AsyncAPIResource): + """Manage fine-tuning jobs to tailor a model to your specific training data.""" + @cached_property def with_raw_response(self) -> AsyncGradersWithRawResponse: """ diff --git a/src/openai/resources/fine_tuning/checkpoints/checkpoints.py b/src/openai/resources/fine_tuning/checkpoints/checkpoints.py index f59976a264..9c2ed6f576 100644 --- a/src/openai/resources/fine_tuning/checkpoints/checkpoints.py +++ b/src/openai/resources/fine_tuning/checkpoints/checkpoints.py @@ -19,6 +19,7 @@ class Checkpoints(SyncAPIResource): @cached_property def permissions(self) -> Permissions: + """Manage fine-tuning jobs to tailor a model to your specific training data.""" return Permissions(self._client) @cached_property @@ -44,6 +45,7 @@ def with_streaming_response(self) -> CheckpointsWithStreamingResponse: class AsyncCheckpoints(AsyncAPIResource): @cached_property def permissions(self) -> AsyncPermissions: + """Manage fine-tuning jobs to tailor a model to your specific training data.""" return AsyncPermissions(self._client) @cached_property @@ -72,6 +74,7 @@ def __init__(self, checkpoints: Checkpoints) -> None: @cached_property def permissions(self) -> PermissionsWithRawResponse: + """Manage fine-tuning jobs to tailor a model to your specific training data.""" return PermissionsWithRawResponse(self._checkpoints.permissions) @@ -81,6 +84,7 @@ def __init__(self, checkpoints: AsyncCheckpoints) -> None: @cached_property def permissions(self) -> AsyncPermissionsWithRawResponse: + """Manage fine-tuning jobs to tailor a model to your specific training data.""" return AsyncPermissionsWithRawResponse(self._checkpoints.permissions) @@ -90,6 +94,7 @@ def __init__(self, checkpoints: Checkpoints) -> None: @cached_property def permissions(self) -> PermissionsWithStreamingResponse: + """Manage fine-tuning jobs to tailor a model to your specific training data.""" return PermissionsWithStreamingResponse(self._checkpoints.permissions) @@ -99,4 +104,5 @@ def __init__(self, checkpoints: AsyncCheckpoints) -> None: @cached_property def permissions(self) -> AsyncPermissionsWithStreamingResponse: + """Manage fine-tuning jobs to tailor a model to your specific training data.""" return AsyncPermissionsWithStreamingResponse(self._checkpoints.permissions) diff --git a/src/openai/resources/fine_tuning/checkpoints/permissions.py b/src/openai/resources/fine_tuning/checkpoints/permissions.py index e7f55b82d9..35e06feee0 100644 --- a/src/openai/resources/fine_tuning/checkpoints/permissions.py +++ b/src/openai/resources/fine_tuning/checkpoints/permissions.py @@ -2,6 +2,7 @@ from __future__ import annotations +import typing_extensions from typing_extensions import Literal import httpx @@ -12,9 +13,14 @@ from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ....pagination import SyncPage, AsyncPage +from ....pagination import SyncPage, AsyncPage, SyncConversationCursorPage, AsyncConversationCursorPage from ...._base_client import AsyncPaginator, make_request_options -from ....types.fine_tuning.checkpoints import permission_create_params, permission_retrieve_params +from ....types.fine_tuning.checkpoints import ( + permission_list_params, + permission_create_params, + permission_retrieve_params, +) +from ....types.fine_tuning.checkpoints.permission_list_response import PermissionListResponse from ....types.fine_tuning.checkpoints.permission_create_response import PermissionCreateResponse from ....types.fine_tuning.checkpoints.permission_delete_response import PermissionDeleteResponse from ....types.fine_tuning.checkpoints.permission_retrieve_response import PermissionRetrieveResponse @@ -23,6 +29,8 @@ class Permissions(SyncAPIResource): + """Manage fine-tuning jobs to tailor a model to your specific training data.""" + @cached_property def with_raw_response(self) -> PermissionsWithRawResponse: """ @@ -86,6 +94,7 @@ def create( method="post", ) + @typing_extensions.deprecated("Retrieve is deprecated. Please swap to the paginated list method instead.") def retrieve( self, fine_tuned_model_checkpoint: str, @@ -148,6 +157,69 @@ def retrieve( cast_to=PermissionRetrieveResponse, ) + def list( + self, + fine_tuned_model_checkpoint: str, + *, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["ascending", "descending"] | Omit = omit, + project_id: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncConversationCursorPage[PermissionListResponse]: + """ + **NOTE:** This endpoint requires an [admin API key](../admin-api-keys). + + Organization owners can use this endpoint to view all permissions for a + fine-tuned model checkpoint. + + Args: + after: Identifier for the last permission ID from the previous pagination request. + + limit: Number of permissions to retrieve. + + order: The order in which to retrieve permissions. + + project_id: The ID of the project to get permissions for. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not fine_tuned_model_checkpoint: + raise ValueError( + f"Expected a non-empty value for `fine_tuned_model_checkpoint` but received {fine_tuned_model_checkpoint!r}" + ) + return self._get_api_list( + f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + page=SyncConversationCursorPage[PermissionListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + "project_id": project_id, + }, + permission_list_params.PermissionListParams, + ), + ), + model=PermissionListResponse, + ) + def delete( self, permission_id: str, @@ -191,6 +263,8 @@ def delete( class AsyncPermissions(AsyncAPIResource): + """Manage fine-tuning jobs to tailor a model to your specific training data.""" + @cached_property def with_raw_response(self) -> AsyncPermissionsWithRawResponse: """ @@ -254,6 +328,7 @@ def create( method="post", ) + @typing_extensions.deprecated("Retrieve is deprecated. Please swap to the paginated list method instead.") async def retrieve( self, fine_tuned_model_checkpoint: str, @@ -316,6 +391,69 @@ async def retrieve( cast_to=PermissionRetrieveResponse, ) + def list( + self, + fine_tuned_model_checkpoint: str, + *, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["ascending", "descending"] | Omit = omit, + project_id: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[PermissionListResponse, AsyncConversationCursorPage[PermissionListResponse]]: + """ + **NOTE:** This endpoint requires an [admin API key](../admin-api-keys). + + Organization owners can use this endpoint to view all permissions for a + fine-tuned model checkpoint. + + Args: + after: Identifier for the last permission ID from the previous pagination request. + + limit: Number of permissions to retrieve. + + order: The order in which to retrieve permissions. + + project_id: The ID of the project to get permissions for. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not fine_tuned_model_checkpoint: + raise ValueError( + f"Expected a non-empty value for `fine_tuned_model_checkpoint` but received {fine_tuned_model_checkpoint!r}" + ) + return self._get_api_list( + f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + page=AsyncConversationCursorPage[PermissionListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + "project_id": project_id, + }, + permission_list_params.PermissionListParams, + ), + ), + model=PermissionListResponse, + ) + async def delete( self, permission_id: str, @@ -365,8 +503,13 @@ def __init__(self, permissions: Permissions) -> None: self.create = _legacy_response.to_raw_response_wrapper( permissions.create, ) - self.retrieve = _legacy_response.to_raw_response_wrapper( - permissions.retrieve, + self.retrieve = ( # pyright: ignore[reportDeprecated] + _legacy_response.to_raw_response_wrapper( + permissions.retrieve, # pyright: ignore[reportDeprecated], + ) + ) + self.list = _legacy_response.to_raw_response_wrapper( + permissions.list, ) self.delete = _legacy_response.to_raw_response_wrapper( permissions.delete, @@ -380,8 +523,13 @@ def __init__(self, permissions: AsyncPermissions) -> None: self.create = _legacy_response.async_to_raw_response_wrapper( permissions.create, ) - self.retrieve = _legacy_response.async_to_raw_response_wrapper( - permissions.retrieve, + self.retrieve = ( # pyright: ignore[reportDeprecated] + _legacy_response.async_to_raw_response_wrapper( + permissions.retrieve, # pyright: ignore[reportDeprecated], + ) + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + permissions.list, ) self.delete = _legacy_response.async_to_raw_response_wrapper( permissions.delete, @@ -395,8 +543,13 @@ def __init__(self, permissions: Permissions) -> None: self.create = to_streamed_response_wrapper( permissions.create, ) - self.retrieve = to_streamed_response_wrapper( - permissions.retrieve, + self.retrieve = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + permissions.retrieve, # pyright: ignore[reportDeprecated], + ) + ) + self.list = to_streamed_response_wrapper( + permissions.list, ) self.delete = to_streamed_response_wrapper( permissions.delete, @@ -410,8 +563,13 @@ def __init__(self, permissions: AsyncPermissions) -> None: self.create = async_to_streamed_response_wrapper( permissions.create, ) - self.retrieve = async_to_streamed_response_wrapper( - permissions.retrieve, + self.retrieve = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + permissions.retrieve, # pyright: ignore[reportDeprecated], + ) + ) + self.list = async_to_streamed_response_wrapper( + permissions.list, ) self.delete = async_to_streamed_response_wrapper( permissions.delete, diff --git a/src/openai/resources/fine_tuning/fine_tuning.py b/src/openai/resources/fine_tuning/fine_tuning.py index 25ae3e8cf4..60f1f44bdc 100644 --- a/src/openai/resources/fine_tuning/fine_tuning.py +++ b/src/openai/resources/fine_tuning/fine_tuning.py @@ -35,6 +35,7 @@ class FineTuning(SyncAPIResource): @cached_property def jobs(self) -> Jobs: + """Manage fine-tuning jobs to tailor a model to your specific training data.""" return Jobs(self._client) @cached_property @@ -68,6 +69,7 @@ def with_streaming_response(self) -> FineTuningWithStreamingResponse: class AsyncFineTuning(AsyncAPIResource): @cached_property def jobs(self) -> AsyncJobs: + """Manage fine-tuning jobs to tailor a model to your specific training data.""" return AsyncJobs(self._client) @cached_property @@ -104,6 +106,7 @@ def __init__(self, fine_tuning: FineTuning) -> None: @cached_property def jobs(self) -> JobsWithRawResponse: + """Manage fine-tuning jobs to tailor a model to your specific training data.""" return JobsWithRawResponse(self._fine_tuning.jobs) @cached_property @@ -121,6 +124,7 @@ def __init__(self, fine_tuning: AsyncFineTuning) -> None: @cached_property def jobs(self) -> AsyncJobsWithRawResponse: + """Manage fine-tuning jobs to tailor a model to your specific training data.""" return AsyncJobsWithRawResponse(self._fine_tuning.jobs) @cached_property @@ -138,6 +142,7 @@ def __init__(self, fine_tuning: FineTuning) -> None: @cached_property def jobs(self) -> JobsWithStreamingResponse: + """Manage fine-tuning jobs to tailor a model to your specific training data.""" return JobsWithStreamingResponse(self._fine_tuning.jobs) @cached_property @@ -155,6 +160,7 @@ def __init__(self, fine_tuning: AsyncFineTuning) -> None: @cached_property def jobs(self) -> AsyncJobsWithStreamingResponse: + """Manage fine-tuning jobs to tailor a model to your specific training data.""" return AsyncJobsWithStreamingResponse(self._fine_tuning.jobs) @cached_property diff --git a/src/openai/resources/fine_tuning/jobs/checkpoints.py b/src/openai/resources/fine_tuning/jobs/checkpoints.py index f65856f0c6..6f14a0994e 100644 --- a/src/openai/resources/fine_tuning/jobs/checkpoints.py +++ b/src/openai/resources/fine_tuning/jobs/checkpoints.py @@ -22,6 +22,8 @@ class Checkpoints(SyncAPIResource): + """Manage fine-tuning jobs to tailor a model to your specific training data.""" + @cached_property def with_raw_response(self) -> CheckpointsWithRawResponse: """ @@ -93,6 +95,8 @@ def list( class AsyncCheckpoints(AsyncAPIResource): + """Manage fine-tuning jobs to tailor a model to your specific training data.""" + @cached_property def with_raw_response(self) -> AsyncCheckpointsWithRawResponse: """ diff --git a/src/openai/resources/fine_tuning/jobs/jobs.py b/src/openai/resources/fine_tuning/jobs/jobs.py index b292e057cf..e38baa5539 100644 --- a/src/openai/resources/fine_tuning/jobs/jobs.py +++ b/src/openai/resources/fine_tuning/jobs/jobs.py @@ -35,8 +35,11 @@ class Jobs(SyncAPIResource): + """Manage fine-tuning jobs to tailor a model to your specific training data.""" + @cached_property def checkpoints(self) -> Checkpoints: + """Manage fine-tuning jobs to tailor a model to your specific training data.""" return Checkpoints(self._client) @cached_property @@ -415,8 +418,11 @@ def resume( class AsyncJobs(AsyncAPIResource): + """Manage fine-tuning jobs to tailor a model to your specific training data.""" + @cached_property def checkpoints(self) -> AsyncCheckpoints: + """Manage fine-tuning jobs to tailor a model to your specific training data.""" return AsyncCheckpoints(self._client) @cached_property @@ -822,6 +828,7 @@ def __init__(self, jobs: Jobs) -> None: @cached_property def checkpoints(self) -> CheckpointsWithRawResponse: + """Manage fine-tuning jobs to tailor a model to your specific training data.""" return CheckpointsWithRawResponse(self._jobs.checkpoints) @@ -853,6 +860,7 @@ def __init__(self, jobs: AsyncJobs) -> None: @cached_property def checkpoints(self) -> AsyncCheckpointsWithRawResponse: + """Manage fine-tuning jobs to tailor a model to your specific training data.""" return AsyncCheckpointsWithRawResponse(self._jobs.checkpoints) @@ -884,6 +892,7 @@ def __init__(self, jobs: Jobs) -> None: @cached_property def checkpoints(self) -> CheckpointsWithStreamingResponse: + """Manage fine-tuning jobs to tailor a model to your specific training data.""" return CheckpointsWithStreamingResponse(self._jobs.checkpoints) @@ -915,4 +924,5 @@ def __init__(self, jobs: AsyncJobs) -> None: @cached_property def checkpoints(self) -> AsyncCheckpointsWithStreamingResponse: + """Manage fine-tuning jobs to tailor a model to your specific training data.""" return AsyncCheckpointsWithStreamingResponse(self._jobs.checkpoints) diff --git a/src/openai/resources/images.py b/src/openai/resources/images.py index 647eb1ca24..6959c2aeff 100644 --- a/src/openai/resources/images.py +++ b/src/openai/resources/images.py @@ -25,6 +25,8 @@ class Images(SyncAPIResource): + """Given a prompt and/or an input image, the model will generate a new image.""" + @cached_property def with_raw_response(self) -> ImagesWithRawResponse: """ @@ -915,6 +917,8 @@ def generate( class AsyncImages(AsyncAPIResource): + """Given a prompt and/or an input image, the model will generate a new image.""" + @cached_property def with_raw_response(self) -> AsyncImagesWithRawResponse: """ diff --git a/src/openai/resources/models.py b/src/openai/resources/models.py index a8f7691055..508393263f 100644 --- a/src/openai/resources/models.py +++ b/src/openai/resources/models.py @@ -21,6 +21,8 @@ class Models(SyncAPIResource): + """List and describe the various models available in the API.""" + @cached_property def with_raw_response(self) -> ModelsWithRawResponse: """ @@ -134,6 +136,8 @@ def delete( class AsyncModels(AsyncAPIResource): + """List and describe the various models available in the API.""" + @cached_property def with_raw_response(self) -> AsyncModelsWithRawResponse: """ diff --git a/src/openai/resources/moderations.py b/src/openai/resources/moderations.py index 5f378f71e7..0b9a2d23c7 100644 --- a/src/openai/resources/moderations.py +++ b/src/openai/resources/moderations.py @@ -22,6 +22,10 @@ class Moderations(SyncAPIResource): + """ + Given text and/or image inputs, classifies if those inputs are potentially harmful. + """ + @cached_property def with_raw_response(self) -> ModerationsWithRawResponse: """ @@ -92,6 +96,10 @@ def create( class AsyncModerations(AsyncAPIResource): + """ + Given text and/or image inputs, classifies if those inputs are potentially harmful. + """ + @cached_property def with_raw_response(self) -> AsyncModerationsWithRawResponse: """ diff --git a/src/openai/resources/responses/api.md b/src/openai/resources/responses/api.md index 36c95d7b83..d654abb99a 100644 --- a/src/openai/resources/responses/api.md +++ b/src/openai/resources/responses/api.md @@ -6,7 +6,10 @@ Types: from openai.types.responses import ( ApplyPatchTool, CompactedResponse, + ComputerAction, + ComputerActionList, ComputerTool, + ComputerUseTool, ContainerAuto, ContainerNetworkPolicyAllowlist, ContainerNetworkPolicyDisabled, @@ -21,6 +24,7 @@ from openai.types.responses import ( InlineSkillSource, LocalEnvironment, LocalSkill, + NamespaceTool, Response, ResponseApplyPatchToolCall, ResponseApplyPatchToolCallOutput, @@ -123,6 +127,9 @@ from openai.types.responses import ( ResponseTextConfig, ResponseTextDeltaEvent, ResponseTextDoneEvent, + ResponseToolSearchCall, + ResponseToolSearchOutputItem, + ResponseToolSearchOutputItemParam, ResponseUsage, ResponseWebSearchCallCompletedEvent, ResponseWebSearchCallInProgressEvent, @@ -139,6 +146,7 @@ from openai.types.responses import ( ToolChoiceOptions, ToolChoiceShell, ToolChoiceTypes, + ToolSearchTool, WebSearchPreviewTool, WebSearchTool, ) diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index c85a94495d..5d34909fd1 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -1567,6 +1567,8 @@ def compact( *, model: Union[ Literal[ + "gpt-5.4", + "gpt-5.3-chat-latest", "gpt-5.2", "gpt-5.2-2025-12-11", "gpt-5.2-chat-latest", @@ -3232,6 +3234,8 @@ async def compact( *, model: Union[ Literal[ + "gpt-5.4", + "gpt-5.3-chat-latest", "gpt-5.2", "gpt-5.2-2025-12-11", "gpt-5.2-chat-latest", diff --git a/src/openai/resources/uploads/parts.py b/src/openai/resources/uploads/parts.py index 73eabd4083..034547f308 100644 --- a/src/openai/resources/uploads/parts.py +++ b/src/openai/resources/uploads/parts.py @@ -20,6 +20,8 @@ class Parts(SyncAPIResource): + """Use Uploads to upload large files in multiple parts.""" + @cached_property def with_raw_response(self) -> PartsWithRawResponse: """ @@ -95,6 +97,8 @@ def create( class AsyncParts(AsyncAPIResource): + """Use Uploads to upload large files in multiple parts.""" + @cached_property def with_raw_response(self) -> AsyncPartsWithRawResponse: """ diff --git a/src/openai/resources/uploads/uploads.py b/src/openai/resources/uploads/uploads.py index 2873b913ba..f5e5e6f664 100644 --- a/src/openai/resources/uploads/uploads.py +++ b/src/openai/resources/uploads/uploads.py @@ -41,8 +41,11 @@ class Uploads(SyncAPIResource): + """Use Uploads to upload large files in multiple parts.""" + @cached_property def parts(self) -> Parts: + """Use Uploads to upload large files in multiple parts.""" return Parts(self._client) @cached_property @@ -343,8 +346,11 @@ def complete( class AsyncUploads(AsyncAPIResource): + """Use Uploads to upload large files in multiple parts.""" + @cached_property def parts(self) -> AsyncParts: + """Use Uploads to upload large files in multiple parts.""" return AsyncParts(self._client) @cached_property @@ -671,6 +677,7 @@ def __init__(self, uploads: Uploads) -> None: @cached_property def parts(self) -> PartsWithRawResponse: + """Use Uploads to upload large files in multiple parts.""" return PartsWithRawResponse(self._uploads.parts) @@ -690,6 +697,7 @@ def __init__(self, uploads: AsyncUploads) -> None: @cached_property def parts(self) -> AsyncPartsWithRawResponse: + """Use Uploads to upload large files in multiple parts.""" return AsyncPartsWithRawResponse(self._uploads.parts) @@ -709,6 +717,7 @@ def __init__(self, uploads: Uploads) -> None: @cached_property def parts(self) -> PartsWithStreamingResponse: + """Use Uploads to upload large files in multiple parts.""" return PartsWithStreamingResponse(self._uploads.parts) @@ -728,4 +737,5 @@ def __init__(self, uploads: AsyncUploads) -> None: @cached_property def parts(self) -> AsyncPartsWithStreamingResponse: + """Use Uploads to upload large files in multiple parts.""" return AsyncPartsWithStreamingResponse(self._uploads.parts) diff --git a/src/openai/resources/videos.py b/src/openai/resources/videos.py index 85ea79f8bc..51df6da4d3 100644 --- a/src/openai/resources/videos.py +++ b/src/openai/resources/videos.py @@ -81,7 +81,7 @@ def create( Args: prompt: Text prompt that describes the video to generate. - input_reference: Optional image reference that guides generation. + input_reference: Optional multipart reference asset that guides generation. model: The video generation model to use (allowed values: sora-2, sora-2-pro). Defaults to `sora-2`. @@ -437,7 +437,7 @@ async def create( Args: prompt: Text prompt that describes the video to generate. - input_reference: Optional image reference that guides generation. + input_reference: Optional multipart reference asset that guides generation. model: The video generation model to use (allowed values: sora-2, sora-2-pro). Defaults to `sora-2`. diff --git a/src/openai/resources/webhooks/__init__.py b/src/openai/resources/webhooks/__init__.py index 371906299b..66449ee7e3 100644 --- a/src/openai/resources/webhooks/__init__.py +++ b/src/openai/resources/webhooks/__init__.py @@ -10,4 +10,5 @@ class Webhooks(_Webhooks): class AsyncWebhooks(_AsyncWebhooks): pass + __all__ = ["Webhooks", "AsyncWebhooks"] diff --git a/src/openai/types/beta/assistant_create_params.py b/src/openai/types/beta/assistant_create_params.py index 461d871ab5..5a468a351b 100644 --- a/src/openai/types/beta/assistant_create_params.py +++ b/src/openai/types/beta/assistant_create_params.py @@ -187,8 +187,9 @@ class ToolResourcesFileSearchVectorStore(TypedDict, total=False): file_ids: SequenceNotStr[str] """ A list of [file](https://platform.openai.com/docs/api-reference/files) IDs to - add to the vector store. There can be a maximum of 10000 files in a vector - store. + add to the vector store. For vector stores created before Nov 2025, there can be + a maximum of 10,000 files in a vector store. For vector stores created starting + in Nov 2025, the limit is 100,000,000 files. """ metadata: Optional[Metadata] diff --git a/src/openai/types/beta/thread_create_and_run_params.py b/src/openai/types/beta/thread_create_and_run_params.py index c0aee3e9f8..3d3d5d4f2e 100644 --- a/src/openai/types/beta/thread_create_and_run_params.py +++ b/src/openai/types/beta/thread_create_and_run_params.py @@ -274,8 +274,9 @@ class ThreadToolResourcesFileSearchVectorStore(TypedDict, total=False): file_ids: SequenceNotStr[str] """ A list of [file](https://platform.openai.com/docs/api-reference/files) IDs to - add to the vector store. There can be a maximum of 10000 files in a vector - store. + add to the vector store. For vector stores created before Nov 2025, there can be + a maximum of 10,000 files in a vector store. For vector stores created starting + in Nov 2025, the limit is 100,000,000 files. """ metadata: Optional[Metadata] diff --git a/src/openai/types/beta/thread_create_params.py b/src/openai/types/beta/thread_create_params.py index ef83e3d465..b823d1c263 100644 --- a/src/openai/types/beta/thread_create_params.py +++ b/src/openai/types/beta/thread_create_params.py @@ -152,8 +152,9 @@ class ToolResourcesFileSearchVectorStore(TypedDict, total=False): file_ids: SequenceNotStr[str] """ A list of [file](https://platform.openai.com/docs/api-reference/files) IDs to - add to the vector store. There can be a maximum of 10000 files in a vector - store. + add to the vector store. For vector stores created before Nov 2025, there can be + a maximum of 10,000 files in a vector store. For vector stores created starting + in Nov 2025, the limit is 100,000,000 files. """ metadata: Optional[Metadata] diff --git a/src/openai/types/conversations/computer_screenshot_content.py b/src/openai/types/conversations/computer_screenshot_content.py index e42096eba2..ff43a7e589 100644 --- a/src/openai/types/conversations/computer_screenshot_content.py +++ b/src/openai/types/conversations/computer_screenshot_content.py @@ -11,6 +11,12 @@ class ComputerScreenshotContent(BaseModel): """A screenshot of a computer.""" + detail: Literal["low", "high", "auto", "original"] + """The detail level of the screenshot image to be sent to the model. + + One of `high`, `low`, `auto`, or `original`. Defaults to `auto`. + """ + file_id: Optional[str] = None """The identifier of an uploaded file that contains the screenshot.""" diff --git a/src/openai/types/conversations/conversation_item.py b/src/openai/types/conversations/conversation_item.py index 46268d381c..33bd3ba043 100644 --- a/src/openai/types/conversations/conversation_item.py +++ b/src/openai/types/conversations/conversation_item.py @@ -8,12 +8,14 @@ from ..._models import BaseModel from ..responses.response_reasoning_item import ResponseReasoningItem from ..responses.response_custom_tool_call import ResponseCustomToolCall +from ..responses.response_tool_search_call import ResponseToolSearchCall from ..responses.response_computer_tool_call import ResponseComputerToolCall from ..responses.response_function_web_search import ResponseFunctionWebSearch from ..responses.response_apply_patch_tool_call import ResponseApplyPatchToolCall from ..responses.response_file_search_tool_call import ResponseFileSearchToolCall from ..responses.response_custom_tool_call_output import ResponseCustomToolCallOutput from ..responses.response_function_tool_call_item import ResponseFunctionToolCallItem +from ..responses.response_tool_search_output_item import ResponseToolSearchOutputItem from ..responses.response_function_shell_tool_call import ResponseFunctionShellToolCall from ..responses.response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall from ..responses.response_apply_patch_tool_call_output import ResponseApplyPatchToolCallOutput @@ -229,6 +231,8 @@ class McpCall(BaseModel): ImageGenerationCall, ResponseComputerToolCall, ResponseComputerToolCallOutputItem, + ResponseToolSearchCall, + ResponseToolSearchOutputItem, ResponseReasoningItem, ResponseCodeInterpreterToolCall, LocalShellCall, diff --git a/src/openai/types/fine_tuning/checkpoints/__init__.py b/src/openai/types/fine_tuning/checkpoints/__init__.py index 2947b33145..5447b4d818 100644 --- a/src/openai/types/fine_tuning/checkpoints/__init__.py +++ b/src/openai/types/fine_tuning/checkpoints/__init__.py @@ -2,7 +2,9 @@ from __future__ import annotations +from .permission_list_params import PermissionListParams as PermissionListParams from .permission_create_params import PermissionCreateParams as PermissionCreateParams +from .permission_list_response import PermissionListResponse as PermissionListResponse from .permission_create_response import PermissionCreateResponse as PermissionCreateResponse from .permission_delete_response import PermissionDeleteResponse as PermissionDeleteResponse from .permission_retrieve_params import PermissionRetrieveParams as PermissionRetrieveParams diff --git a/src/openai/types/fine_tuning/checkpoints/permission_list_params.py b/src/openai/types/fine_tuning/checkpoints/permission_list_params.py new file mode 100644 index 0000000000..1f389920aa --- /dev/null +++ b/src/openai/types/fine_tuning/checkpoints/permission_list_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["PermissionListParams"] + + +class PermissionListParams(TypedDict, total=False): + after: str + """Identifier for the last permission ID from the previous pagination request.""" + + limit: int + """Number of permissions to retrieve.""" + + order: Literal["ascending", "descending"] + """The order in which to retrieve permissions.""" + + project_id: str + """The ID of the project to get permissions for.""" diff --git a/src/openai/types/fine_tuning/checkpoints/permission_list_response.py b/src/openai/types/fine_tuning/checkpoints/permission_list_response.py new file mode 100644 index 0000000000..26e913e0c2 --- /dev/null +++ b/src/openai/types/fine_tuning/checkpoints/permission_list_response.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["PermissionListResponse"] + + +class PermissionListResponse(BaseModel): + """ + The `checkpoint.permission` object represents a permission for a fine-tuned model checkpoint. + """ + + id: str + """The permission identifier, which can be referenced in the API endpoints.""" + + created_at: int + """The Unix timestamp (in seconds) for when the permission was created.""" + + object: Literal["checkpoint.permission"] + """The object type, which is always "checkpoint.permission".""" + + project_id: str + """The project identifier that the permission is for.""" diff --git a/src/openai/types/realtime/realtime_response_create_mcp_tool.py b/src/openai/types/realtime/realtime_response_create_mcp_tool.py index 72189e10e6..cb5eae42d4 100644 --- a/src/openai/types/realtime/realtime_response_create_mcp_tool.py +++ b/src/openai/types/realtime/realtime_response_create_mcp_tool.py @@ -134,6 +134,9 @@ class RealtimeResponseCreateMcpTool(BaseModel): - SharePoint: `connector_sharepoint` """ + defer_loading: Optional[bool] = None + """Whether this MCP tool is deferred and discovered via tool search.""" + headers: Optional[Dict[str, str]] = None """Optional HTTP headers to send to the MCP server. diff --git a/src/openai/types/realtime/realtime_response_create_mcp_tool_param.py b/src/openai/types/realtime/realtime_response_create_mcp_tool_param.py index 68dd6bdb5c..dd8c2e018f 100644 --- a/src/openai/types/realtime/realtime_response_create_mcp_tool_param.py +++ b/src/openai/types/realtime/realtime_response_create_mcp_tool_param.py @@ -134,6 +134,9 @@ class RealtimeResponseCreateMcpToolParam(TypedDict, total=False): - SharePoint: `connector_sharepoint` """ + defer_loading: bool + """Whether this MCP tool is deferred and discovered via tool search.""" + headers: Optional[Dict[str, str]] """Optional HTTP headers to send to the MCP server. diff --git a/src/openai/types/realtime/realtime_session_create_response.py b/src/openai/types/realtime/realtime_session_create_response.py index a74615bd60..3c3bef93f4 100644 --- a/src/openai/types/realtime/realtime_session_create_response.py +++ b/src/openai/types/realtime/realtime_session_create_response.py @@ -363,6 +363,9 @@ class ToolMcpTool(BaseModel): - SharePoint: `connector_sharepoint` """ + defer_loading: Optional[bool] = None + """Whether this MCP tool is deferred and discovered via tool search.""" + headers: Optional[Dict[str, str]] = None """Optional HTTP headers to send to the MCP server. diff --git a/src/openai/types/realtime/realtime_tools_config_param.py b/src/openai/types/realtime/realtime_tools_config_param.py index 3cc404feef..217130922a 100644 --- a/src/openai/types/realtime/realtime_tools_config_param.py +++ b/src/openai/types/realtime/realtime_tools_config_param.py @@ -137,6 +137,9 @@ class Mcp(TypedDict, total=False): - SharePoint: `connector_sharepoint` """ + defer_loading: bool + """Whether this MCP tool is deferred and discovered via tool search.""" + headers: Optional[Dict[str, str]] """Optional HTTP headers to send to the MCP server. diff --git a/src/openai/types/realtime/realtime_tools_config_union.py b/src/openai/types/realtime/realtime_tools_config_union.py index 92aaee7f26..55da58269c 100644 --- a/src/openai/types/realtime/realtime_tools_config_union.py +++ b/src/openai/types/realtime/realtime_tools_config_union.py @@ -137,6 +137,9 @@ class Mcp(BaseModel): - SharePoint: `connector_sharepoint` """ + defer_loading: Optional[bool] = None + """Whether this MCP tool is deferred and discovered via tool search.""" + headers: Optional[Dict[str, str]] = None """Optional HTTP headers to send to the MCP server. diff --git a/src/openai/types/realtime/realtime_tools_config_union_param.py b/src/openai/types/realtime/realtime_tools_config_union_param.py index 6889b4c304..15118f3388 100644 --- a/src/openai/types/realtime/realtime_tools_config_union_param.py +++ b/src/openai/types/realtime/realtime_tools_config_union_param.py @@ -136,6 +136,9 @@ class Mcp(TypedDict, total=False): - SharePoint: `connector_sharepoint` """ + defer_loading: bool + """Whether this MCP tool is deferred and discovered via tool search.""" + headers: Optional[Dict[str, str]] """Optional HTTP headers to send to the MCP server. diff --git a/src/openai/types/responses/__init__.py b/src/openai/types/responses/__init__.py index de6f68989b..714347b05d 100644 --- a/src/openai/types/responses/__init__.py +++ b/src/openai/types/responses/__init__.py @@ -12,9 +12,11 @@ from .function_tool import FunctionTool as FunctionTool from .response_item import ResponseItem as ResponseItem from .container_auto import ContainerAuto as ContainerAuto +from .namespace_tool import NamespaceTool as NamespaceTool from .response_error import ResponseError as ResponseError from .response_input import ResponseInput as ResponseInput from .response_usage import ResponseUsage as ResponseUsage +from .computer_action import ComputerAction as ComputerAction from .parsed_response import ( ParsedContent as ParsedContent, ParsedResponse as ParsedResponse, @@ -30,6 +32,8 @@ from .web_search_tool import WebSearchTool as WebSearchTool from .apply_patch_tool import ApplyPatchTool as ApplyPatchTool from .file_search_tool import FileSearchTool as FileSearchTool +from .tool_search_tool import ToolSearchTool as ToolSearchTool +from .computer_use_tool import ComputerUseTool as ComputerUseTool from .custom_tool_param import CustomToolParam as CustomToolParam from .local_environment import LocalEnvironment as LocalEnvironment from .local_skill_param import LocalSkillParam as LocalSkillParam @@ -51,7 +55,9 @@ from .response_input_text import ResponseInputText as ResponseInputText from .tool_choice_allowed import ToolChoiceAllowed as ToolChoiceAllowed from .tool_choice_options import ToolChoiceOptions as ToolChoiceOptions +from .computer_action_list import ComputerActionList as ComputerActionList from .container_auto_param import ContainerAutoParam as ContainerAutoParam +from .namespace_tool_param import NamespaceToolParam as NamespaceToolParam from .response_error_event import ResponseErrorEvent as ResponseErrorEvent from .response_input_audio import ResponseInputAudio as ResponseInputAudio from .response_input_image import ResponseInputImage as ResponseInputImage @@ -60,6 +66,7 @@ from .response_output_text import ResponseOutputText as ResponseOutputText from .response_text_config import ResponseTextConfig as ResponseTextConfig from .tool_choice_function import ToolChoiceFunction as ToolChoiceFunction +from .computer_action_param import ComputerActionParam as ComputerActionParam from .response_failed_event import ResponseFailedEvent as ResponseFailedEvent from .response_prompt_param import ResponsePromptParam as ResponsePromptParam from .response_queued_event import ResponseQueuedEvent as ResponseQueuedEvent @@ -75,6 +82,8 @@ from .response_input_content import ResponseInputContent as ResponseInputContent from .responses_client_event import ResponsesClientEvent as ResponsesClientEvent from .responses_server_event import ResponsesServerEvent as ResponsesServerEvent +from .tool_search_tool_param import ToolSearchToolParam as ToolSearchToolParam +from .computer_use_tool_param import ComputerUseToolParam as ComputerUseToolParam from .local_environment_param import LocalEnvironmentParam as LocalEnvironmentParam from .response_compact_params import ResponseCompactParams as ResponseCompactParams from .response_output_message import ResponseOutputMessage as ResponseOutputMessage @@ -101,7 +110,9 @@ from .response_input_item_param import ResponseInputItemParam as ResponseInputItemParam from .response_input_text_param import ResponseInputTextParam as ResponseInputTextParam from .response_text_delta_event import ResponseTextDeltaEvent as ResponseTextDeltaEvent +from .response_tool_search_call import ResponseToolSearchCall as ResponseToolSearchCall from .tool_choice_allowed_param import ToolChoiceAllowedParam as ToolChoiceAllowedParam +from .computer_action_list_param import ComputerActionListParam as ComputerActionListParam from .input_token_count_response import InputTokenCountResponse as InputTokenCountResponse from .response_audio_delta_event import ResponseAudioDeltaEvent as ResponseAudioDeltaEvent from .response_in_progress_event import ResponseInProgressEvent as ResponseInProgressEvent @@ -140,6 +151,7 @@ from .response_custom_tool_call_output import ResponseCustomToolCallOutput as ResponseCustomToolCallOutput from .response_function_tool_call_item import ResponseFunctionToolCallItem as ResponseFunctionToolCallItem from .response_output_item_added_event import ResponseOutputItemAddedEvent as ResponseOutputItemAddedEvent +from .response_tool_search_output_item import ResponseToolSearchOutputItem as ResponseToolSearchOutputItem from .container_network_policy_disabled import ContainerNetworkPolicyDisabled as ContainerNetworkPolicyDisabled from .response_computer_tool_call_param import ResponseComputerToolCallParam as ResponseComputerToolCallParam from .response_content_part_added_event import ResponseContentPartAddedEvent as ResponseContentPartAddedEvent @@ -176,6 +188,9 @@ from .response_mcp_call_arguments_done_event import ( ResponseMcpCallArgumentsDoneEvent as ResponseMcpCallArgumentsDoneEvent, ) +from .response_tool_search_output_item_param import ( + ResponseToolSearchOutputItemParam as ResponseToolSearchOutputItemParam, +) from .container_network_policy_disabled_param import ( ContainerNetworkPolicyDisabledParam as ContainerNetworkPolicyDisabledParam, ) @@ -278,6 +293,9 @@ from .response_function_call_arguments_delta_event import ( ResponseFunctionCallArgumentsDeltaEvent as ResponseFunctionCallArgumentsDeltaEvent, ) +from .response_tool_search_output_item_param_param import ( + ResponseToolSearchOutputItemParamParam as ResponseToolSearchOutputItemParamParam, +) from .response_computer_tool_call_output_screenshot import ( ResponseComputerToolCallOutputScreenshot as ResponseComputerToolCallOutputScreenshot, ) diff --git a/src/openai/types/responses/computer_action.py b/src/openai/types/responses/computer_action.py new file mode 100644 index 0000000000..a0c11084ba --- /dev/null +++ b/src/openai/types/responses/computer_action.py @@ -0,0 +1,181 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel + +__all__ = [ + "ComputerAction", + "Click", + "DoubleClick", + "Drag", + "DragPath", + "Keypress", + "Move", + "Screenshot", + "Scroll", + "Type", + "Wait", +] + + +class Click(BaseModel): + """A click action.""" + + button: Literal["left", "right", "wheel", "back", "forward"] + """Indicates which mouse button was pressed during the click. + + One of `left`, `right`, `wheel`, `back`, or `forward`. + """ + + type: Literal["click"] + """Specifies the event type. For a click action, this property is always `click`.""" + + x: int + """The x-coordinate where the click occurred.""" + + y: int + """The y-coordinate where the click occurred.""" + + +class DoubleClick(BaseModel): + """A double click action.""" + + type: Literal["double_click"] + """Specifies the event type. + + For a double click action, this property is always set to `double_click`. + """ + + x: int + """The x-coordinate where the double click occurred.""" + + y: int + """The y-coordinate where the double click occurred.""" + + +class DragPath(BaseModel): + """An x/y coordinate pair, e.g. `{ x: 100, y: 200 }`.""" + + x: int + """The x-coordinate.""" + + y: int + """The y-coordinate.""" + + +class Drag(BaseModel): + """A drag action.""" + + path: List[DragPath] + """An array of coordinates representing the path of the drag action. + + Coordinates will appear as an array of objects, eg + + ``` + [ + { x: 100, y: 200 }, + { x: 200, y: 300 } + ] + ``` + """ + + type: Literal["drag"] + """Specifies the event type. + + For a drag action, this property is always set to `drag`. + """ + + +class Keypress(BaseModel): + """A collection of keypresses the model would like to perform.""" + + keys: List[str] + """The combination of keys the model is requesting to be pressed. + + This is an array of strings, each representing a key. + """ + + type: Literal["keypress"] + """Specifies the event type. + + For a keypress action, this property is always set to `keypress`. + """ + + +class Move(BaseModel): + """A mouse move action.""" + + type: Literal["move"] + """Specifies the event type. + + For a move action, this property is always set to `move`. + """ + + x: int + """The x-coordinate to move to.""" + + y: int + """The y-coordinate to move to.""" + + +class Screenshot(BaseModel): + """A screenshot action.""" + + type: Literal["screenshot"] + """Specifies the event type. + + For a screenshot action, this property is always set to `screenshot`. + """ + + +class Scroll(BaseModel): + """A scroll action.""" + + scroll_x: int + """The horizontal scroll distance.""" + + scroll_y: int + """The vertical scroll distance.""" + + type: Literal["scroll"] + """Specifies the event type. + + For a scroll action, this property is always set to `scroll`. + """ + + x: int + """The x-coordinate where the scroll occurred.""" + + y: int + """The y-coordinate where the scroll occurred.""" + + +class Type(BaseModel): + """An action to type in text.""" + + text: str + """The text to type.""" + + type: Literal["type"] + """Specifies the event type. + + For a type action, this property is always set to `type`. + """ + + +class Wait(BaseModel): + """A wait action.""" + + type: Literal["wait"] + """Specifies the event type. + + For a wait action, this property is always set to `wait`. + """ + + +ComputerAction: TypeAlias = Annotated[ + Union[Click, DoubleClick, Drag, Keypress, Move, Screenshot, Scroll, Type, Wait], PropertyInfo(discriminator="type") +] diff --git a/src/openai/types/responses/computer_action_list.py b/src/openai/types/responses/computer_action_list.py new file mode 100644 index 0000000000..0198c6e866 --- /dev/null +++ b/src/openai/types/responses/computer_action_list.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .computer_action import ComputerAction + +__all__ = ["ComputerActionList"] + +ComputerActionList: TypeAlias = List[ComputerAction] diff --git a/src/openai/types/responses/computer_action_list_param.py b/src/openai/types/responses/computer_action_list_param.py new file mode 100644 index 0000000000..ec609ffd1b --- /dev/null +++ b/src/openai/types/responses/computer_action_list_param.py @@ -0,0 +1,183 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union, Iterable +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from ..._types import SequenceNotStr + +__all__ = [ + "ComputerActionListParam", + "ComputerActionParam", + "Click", + "DoubleClick", + "Drag", + "DragPath", + "Keypress", + "Move", + "Screenshot", + "Scroll", + "Type", + "Wait", +] + + +class Click(TypedDict, total=False): + """A click action.""" + + button: Required[Literal["left", "right", "wheel", "back", "forward"]] + """Indicates which mouse button was pressed during the click. + + One of `left`, `right`, `wheel`, `back`, or `forward`. + """ + + type: Required[Literal["click"]] + """Specifies the event type. For a click action, this property is always `click`.""" + + x: Required[int] + """The x-coordinate where the click occurred.""" + + y: Required[int] + """The y-coordinate where the click occurred.""" + + +class DoubleClick(TypedDict, total=False): + """A double click action.""" + + type: Required[Literal["double_click"]] + """Specifies the event type. + + For a double click action, this property is always set to `double_click`. + """ + + x: Required[int] + """The x-coordinate where the double click occurred.""" + + y: Required[int] + """The y-coordinate where the double click occurred.""" + + +class DragPath(TypedDict, total=False): + """An x/y coordinate pair, e.g. `{ x: 100, y: 200 }`.""" + + x: Required[int] + """The x-coordinate.""" + + y: Required[int] + """The y-coordinate.""" + + +class Drag(TypedDict, total=False): + """A drag action.""" + + path: Required[Iterable[DragPath]] + """An array of coordinates representing the path of the drag action. + + Coordinates will appear as an array of objects, eg + + ``` + [ + { x: 100, y: 200 }, + { x: 200, y: 300 } + ] + ``` + """ + + type: Required[Literal["drag"]] + """Specifies the event type. + + For a drag action, this property is always set to `drag`. + """ + + +class Keypress(TypedDict, total=False): + """A collection of keypresses the model would like to perform.""" + + keys: Required[SequenceNotStr[str]] + """The combination of keys the model is requesting to be pressed. + + This is an array of strings, each representing a key. + """ + + type: Required[Literal["keypress"]] + """Specifies the event type. + + For a keypress action, this property is always set to `keypress`. + """ + + +class Move(TypedDict, total=False): + """A mouse move action.""" + + type: Required[Literal["move"]] + """Specifies the event type. + + For a move action, this property is always set to `move`. + """ + + x: Required[int] + """The x-coordinate to move to.""" + + y: Required[int] + """The y-coordinate to move to.""" + + +class Screenshot(TypedDict, total=False): + """A screenshot action.""" + + type: Required[Literal["screenshot"]] + """Specifies the event type. + + For a screenshot action, this property is always set to `screenshot`. + """ + + +class Scroll(TypedDict, total=False): + """A scroll action.""" + + scroll_x: Required[int] + """The horizontal scroll distance.""" + + scroll_y: Required[int] + """The vertical scroll distance.""" + + type: Required[Literal["scroll"]] + """Specifies the event type. + + For a scroll action, this property is always set to `scroll`. + """ + + x: Required[int] + """The x-coordinate where the scroll occurred.""" + + y: Required[int] + """The y-coordinate where the scroll occurred.""" + + +class Type(TypedDict, total=False): + """An action to type in text.""" + + text: Required[str] + """The text to type.""" + + type: Required[Literal["type"]] + """Specifies the event type. + + For a type action, this property is always set to `type`. + """ + + +class Wait(TypedDict, total=False): + """A wait action.""" + + type: Required[Literal["wait"]] + """Specifies the event type. + + For a wait action, this property is always set to `wait`. + """ + + +ComputerActionParam: TypeAlias = Union[Click, DoubleClick, Drag, Keypress, Move, Screenshot, Scroll, Type, Wait] + +ComputerActionListParam: TypeAlias = List[ComputerActionParam] diff --git a/src/openai/types/responses/computer_action_param.py b/src/openai/types/responses/computer_action_param.py new file mode 100644 index 0000000000..822a77d759 --- /dev/null +++ b/src/openai/types/responses/computer_action_param.py @@ -0,0 +1,180 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from ..._types import SequenceNotStr + +__all__ = [ + "ComputerActionParam", + "Click", + "DoubleClick", + "Drag", + "DragPath", + "Keypress", + "Move", + "Screenshot", + "Scroll", + "Type", + "Wait", +] + + +class Click(TypedDict, total=False): + """A click action.""" + + button: Required[Literal["left", "right", "wheel", "back", "forward"]] + """Indicates which mouse button was pressed during the click. + + One of `left`, `right`, `wheel`, `back`, or `forward`. + """ + + type: Required[Literal["click"]] + """Specifies the event type. For a click action, this property is always `click`.""" + + x: Required[int] + """The x-coordinate where the click occurred.""" + + y: Required[int] + """The y-coordinate where the click occurred.""" + + +class DoubleClick(TypedDict, total=False): + """A double click action.""" + + type: Required[Literal["double_click"]] + """Specifies the event type. + + For a double click action, this property is always set to `double_click`. + """ + + x: Required[int] + """The x-coordinate where the double click occurred.""" + + y: Required[int] + """The y-coordinate where the double click occurred.""" + + +class DragPath(TypedDict, total=False): + """An x/y coordinate pair, e.g. `{ x: 100, y: 200 }`.""" + + x: Required[int] + """The x-coordinate.""" + + y: Required[int] + """The y-coordinate.""" + + +class Drag(TypedDict, total=False): + """A drag action.""" + + path: Required[Iterable[DragPath]] + """An array of coordinates representing the path of the drag action. + + Coordinates will appear as an array of objects, eg + + ``` + [ + { x: 100, y: 200 }, + { x: 200, y: 300 } + ] + ``` + """ + + type: Required[Literal["drag"]] + """Specifies the event type. + + For a drag action, this property is always set to `drag`. + """ + + +class Keypress(TypedDict, total=False): + """A collection of keypresses the model would like to perform.""" + + keys: Required[SequenceNotStr[str]] + """The combination of keys the model is requesting to be pressed. + + This is an array of strings, each representing a key. + """ + + type: Required[Literal["keypress"]] + """Specifies the event type. + + For a keypress action, this property is always set to `keypress`. + """ + + +class Move(TypedDict, total=False): + """A mouse move action.""" + + type: Required[Literal["move"]] + """Specifies the event type. + + For a move action, this property is always set to `move`. + """ + + x: Required[int] + """The x-coordinate to move to.""" + + y: Required[int] + """The y-coordinate to move to.""" + + +class Screenshot(TypedDict, total=False): + """A screenshot action.""" + + type: Required[Literal["screenshot"]] + """Specifies the event type. + + For a screenshot action, this property is always set to `screenshot`. + """ + + +class Scroll(TypedDict, total=False): + """A scroll action.""" + + scroll_x: Required[int] + """The horizontal scroll distance.""" + + scroll_y: Required[int] + """The vertical scroll distance.""" + + type: Required[Literal["scroll"]] + """Specifies the event type. + + For a scroll action, this property is always set to `scroll`. + """ + + x: Required[int] + """The x-coordinate where the scroll occurred.""" + + y: Required[int] + """The y-coordinate where the scroll occurred.""" + + +class Type(TypedDict, total=False): + """An action to type in text.""" + + text: Required[str] + """The text to type.""" + + type: Required[Literal["type"]] + """Specifies the event type. + + For a type action, this property is always set to `type`. + """ + + +class Wait(TypedDict, total=False): + """A wait action.""" + + type: Required[Literal["wait"]] + """Specifies the event type. + + For a wait action, this property is always set to `wait`. + """ + + +ComputerActionParam: TypeAlias = Union[Click, DoubleClick, Drag, Keypress, Move, Screenshot, Scroll, Type, Wait] diff --git a/src/openai/types/responses/computer_use_tool.py b/src/openai/types/responses/computer_use_tool.py new file mode 100644 index 0000000000..1704b25424 --- /dev/null +++ b/src/openai/types/responses/computer_use_tool.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ComputerUseTool"] + + +class ComputerUseTool(BaseModel): + """A tool that controls a virtual computer. + + Learn more about the [computer tool](https://platform.openai.com/docs/guides/tools-computer-use). + """ + + type: Literal["computer"] + """The type of the computer tool. Always `computer`.""" diff --git a/src/openai/types/responses/computer_use_tool_param.py b/src/openai/types/responses/computer_use_tool_param.py new file mode 100644 index 0000000000..e81dbe8206 --- /dev/null +++ b/src/openai/types/responses/computer_use_tool_param.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ComputerUseToolParam"] + + +class ComputerUseToolParam(TypedDict, total=False): + """A tool that controls a virtual computer. + + Learn more about the [computer tool](https://platform.openai.com/docs/guides/tools-computer-use). + """ + + type: Required[Literal["computer"]] + """The type of the computer tool. Always `computer`.""" diff --git a/src/openai/types/responses/custom_tool.py b/src/openai/types/responses/custom_tool.py index 1ca401a486..017c6d699b 100644 --- a/src/openai/types/responses/custom_tool.py +++ b/src/openai/types/responses/custom_tool.py @@ -21,6 +21,9 @@ class CustomTool(BaseModel): type: Literal["custom"] """The type of the custom tool. Always `custom`.""" + defer_loading: Optional[bool] = None + """Whether this tool should be deferred and discovered via tool search.""" + description: Optional[str] = None """Optional description of the custom tool, used to provide more context.""" diff --git a/src/openai/types/responses/custom_tool_param.py b/src/openai/types/responses/custom_tool_param.py index 4ce43cdfdb..e64001366e 100644 --- a/src/openai/types/responses/custom_tool_param.py +++ b/src/openai/types/responses/custom_tool_param.py @@ -21,6 +21,9 @@ class CustomToolParam(TypedDict, total=False): type: Required[Literal["custom"]] """The type of the custom tool. Always `custom`.""" + defer_loading: bool + """Whether this tool should be deferred and discovered via tool search.""" + description: str """Optional description of the custom tool, used to provide more context.""" diff --git a/src/openai/types/responses/easy_input_message.py b/src/openai/types/responses/easy_input_message.py index 6f4d782734..aa97827bc0 100644 --- a/src/openai/types/responses/easy_input_message.py +++ b/src/openai/types/responses/easy_input_message.py @@ -31,12 +31,11 @@ class EasyInputMessage(BaseModel): """ phase: Optional[Literal["commentary", "final_answer"]] = None - """The phase of an assistant message. - - Use `commentary` for an intermediate assistant message and `final_answer` for - the final assistant message. For follow-up requests with models like - `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. - Omitting it can degrade performance. Not used for user messages. + """ + Labels an `assistant` message as intermediate commentary (`commentary`) or the + final answer (`final_answer`). For models like `gpt-5.3-codex` and beyond, when + sending follow-up requests, preserve and resend phase on all assistant messages + — dropping it can degrade performance. Not used for user messages. """ type: Optional[Literal["message"]] = None diff --git a/src/openai/types/responses/easy_input_message_param.py b/src/openai/types/responses/easy_input_message_param.py index f7eb42ba71..bfc8d577ba 100644 --- a/src/openai/types/responses/easy_input_message_param.py +++ b/src/openai/types/responses/easy_input_message_param.py @@ -32,12 +32,11 @@ class EasyInputMessageParam(TypedDict, total=False): """ phase: Optional[Literal["commentary", "final_answer"]] - """The phase of an assistant message. - - Use `commentary` for an intermediate assistant message and `final_answer` for - the final assistant message. For follow-up requests with models like - `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. - Omitting it can degrade performance. Not used for user messages. + """ + Labels an `assistant` message as intermediate commentary (`commentary`) or the + final answer (`final_answer`). For models like `gpt-5.3-codex` and beyond, when + sending follow-up requests, preserve and resend phase on all assistant messages + — dropping it can degrade performance. Not used for user messages. """ type: Literal["message"] diff --git a/src/openai/types/responses/function_tool.py b/src/openai/types/responses/function_tool.py index b0827a9fa7..6e9751ad88 100644 --- a/src/openai/types/responses/function_tool.py +++ b/src/openai/types/responses/function_tool.py @@ -26,6 +26,9 @@ class FunctionTool(BaseModel): type: Literal["function"] """The type of the function tool. Always `function`.""" + defer_loading: Optional[bool] = None + """Whether this function is deferred and loaded via tool search.""" + description: Optional[str] = None """A description of the function. diff --git a/src/openai/types/responses/function_tool_param.py b/src/openai/types/responses/function_tool_param.py index ba0a3168c4..e7978b44a2 100644 --- a/src/openai/types/responses/function_tool_param.py +++ b/src/openai/types/responses/function_tool_param.py @@ -26,6 +26,9 @@ class FunctionToolParam(TypedDict, total=False): type: Required[Literal["function"]] """The type of the function tool. Always `function`.""" + defer_loading: bool + """Whether this function is deferred and loaded via tool search.""" + description: Optional[str] """A description of the function. diff --git a/src/openai/types/responses/namespace_tool.py b/src/openai/types/responses/namespace_tool.py new file mode 100644 index 0000000000..2c311dbe17 --- /dev/null +++ b/src/openai/types/responses/namespace_tool.py @@ -0,0 +1,41 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .custom_tool import CustomTool + +__all__ = ["NamespaceTool", "Tool", "ToolFunction"] + + +class ToolFunction(BaseModel): + name: str + + type: Literal["function"] + + description: Optional[str] = None + + parameters: Optional[object] = None + + strict: Optional[bool] = None + + +Tool: TypeAlias = Annotated[Union[ToolFunction, CustomTool], PropertyInfo(discriminator="type")] + + +class NamespaceTool(BaseModel): + """Groups function/custom tools under a shared namespace.""" + + description: str + """A description of the namespace shown to the model.""" + + name: str + """The namespace name used in tool calls (for example, `crm`).""" + + tools: List[Tool] + """The function/custom tools available inside this namespace.""" + + type: Literal["namespace"] + """The type of the tool. Always `namespace`.""" diff --git a/src/openai/types/responses/namespace_tool_param.py b/src/openai/types/responses/namespace_tool_param.py new file mode 100644 index 0000000000..4bda2ecd83 --- /dev/null +++ b/src/openai/types/responses/namespace_tool_param.py @@ -0,0 +1,41 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .custom_tool_param import CustomToolParam + +__all__ = ["NamespaceToolParam", "Tool", "ToolFunction"] + + +class ToolFunction(TypedDict, total=False): + name: Required[str] + + type: Required[Literal["function"]] + + description: Optional[str] + + parameters: Optional[object] + + strict: Optional[bool] + + +Tool: TypeAlias = Union[ToolFunction, CustomToolParam] + + +class NamespaceToolParam(TypedDict, total=False): + """Groups function/custom tools under a shared namespace.""" + + description: Required[str] + """A description of the namespace shown to the model.""" + + name: Required[str] + """The namespace name used in tool calls (for example, `crm`).""" + + tools: Required[Iterable[Tool]] + """The function/custom tools available inside this namespace.""" + + type: Required[Literal["namespace"]] + """The type of the tool. Always `namespace`.""" diff --git a/src/openai/types/responses/parsed_response.py b/src/openai/types/responses/parsed_response.py index a859710590..306e52677d 100644 --- a/src/openai/types/responses/parsed_response.py +++ b/src/openai/types/responses/parsed_response.py @@ -20,11 +20,13 @@ from .response_reasoning_item import ResponseReasoningItem from .response_compaction_item import ResponseCompactionItem from .response_custom_tool_call import ResponseCustomToolCall +from .response_tool_search_call import ResponseToolSearchCall from .response_computer_tool_call import ResponseComputerToolCall from .response_function_tool_call import ResponseFunctionToolCall from .response_function_web_search import ResponseFunctionWebSearch from .response_apply_patch_tool_call import ResponseApplyPatchToolCall from .response_file_search_tool_call import ResponseFileSearchToolCall +from .response_tool_search_output_item import ResponseToolSearchOutputItem from .response_function_shell_tool_call import ResponseFunctionShellToolCall from .response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall from .response_apply_patch_tool_call_output import ResponseApplyPatchToolCallOutput @@ -70,6 +72,8 @@ class ParsedResponseFunctionToolCall(ResponseFunctionToolCall): ResponseFileSearchToolCall, ResponseFunctionWebSearch, ResponseComputerToolCall, + ResponseToolSearchCall, + ResponseToolSearchOutputItem, ResponseReasoningItem, McpCall, McpApprovalRequest, diff --git a/src/openai/types/responses/response_compact_params.py b/src/openai/types/responses/response_compact_params.py index 4fb0e7ddc3..95b5da437d 100644 --- a/src/openai/types/responses/response_compact_params.py +++ b/src/openai/types/responses/response_compact_params.py @@ -14,6 +14,8 @@ class ResponseCompactParams(TypedDict, total=False): model: Required[ Union[ Literal[ + "gpt-5.4", + "gpt-5.3-chat-latest", "gpt-5.2", "gpt-5.2-2025-12-11", "gpt-5.2-chat-latest", diff --git a/src/openai/types/responses/response_computer_tool_call.py b/src/openai/types/responses/response_computer_tool_call.py index 4e1b3cf7fd..f796846560 100644 --- a/src/openai/types/responses/response_computer_tool_call.py +++ b/src/openai/types/responses/response_computer_tool_call.py @@ -5,9 +5,11 @@ from ..._utils import PropertyInfo from ..._models import BaseModel +from .computer_action_list import ComputerActionList __all__ = [ "ResponseComputerToolCall", + "PendingSafetyCheck", "Action", "ActionClick", "ActionDoubleClick", @@ -19,10 +21,22 @@ "ActionScroll", "ActionType", "ActionWait", - "PendingSafetyCheck", ] +class PendingSafetyCheck(BaseModel): + """A pending safety check for the computer call.""" + + id: str + """The ID of the pending safety check.""" + + code: Optional[str] = None + """The type of the pending safety check.""" + + message: Optional[str] = None + """Details about the pending safety check.""" + + class ActionClick(BaseModel): """A click action.""" @@ -194,19 +208,6 @@ class ActionWait(BaseModel): ] -class PendingSafetyCheck(BaseModel): - """A pending safety check for the computer call.""" - - id: str - """The ID of the pending safety check.""" - - code: Optional[str] = None - """The type of the pending safety check.""" - - message: Optional[str] = None - """Details about the pending safety check.""" - - class ResponseComputerToolCall(BaseModel): """A tool call to a computer use tool. @@ -217,9 +218,6 @@ class ResponseComputerToolCall(BaseModel): id: str """The unique ID of the computer call.""" - action: Action - """A click action.""" - call_id: str """An identifier used when responding to the tool call with output.""" @@ -235,3 +233,12 @@ class ResponseComputerToolCall(BaseModel): type: Literal["computer_call"] """The type of the computer call. Always `computer_call`.""" + + action: Optional[Action] = None + """A click action.""" + + actions: Optional[ComputerActionList] = None + """Flattened batched actions for `computer_use`. + + Each action includes an `type` discriminator and action-specific fields. + """ diff --git a/src/openai/types/responses/response_computer_tool_call_param.py b/src/openai/types/responses/response_computer_tool_call_param.py index 550ba599cd..05cc2c2f67 100644 --- a/src/openai/types/responses/response_computer_tool_call_param.py +++ b/src/openai/types/responses/response_computer_tool_call_param.py @@ -6,9 +6,11 @@ from typing_extensions import Literal, Required, TypeAlias, TypedDict from ..._types import SequenceNotStr +from .computer_action_list_param import ComputerActionListParam __all__ = [ "ResponseComputerToolCallParam", + "PendingSafetyCheck", "Action", "ActionClick", "ActionDoubleClick", @@ -20,10 +22,22 @@ "ActionScroll", "ActionType", "ActionWait", - "PendingSafetyCheck", ] +class PendingSafetyCheck(TypedDict, total=False): + """A pending safety check for the computer call.""" + + id: Required[str] + """The ID of the pending safety check.""" + + code: Optional[str] + """The type of the pending safety check.""" + + message: Optional[str] + """Details about the pending safety check.""" + + class ActionClick(TypedDict, total=False): """A click action.""" @@ -192,19 +206,6 @@ class ActionWait(TypedDict, total=False): ] -class PendingSafetyCheck(TypedDict, total=False): - """A pending safety check for the computer call.""" - - id: Required[str] - """The ID of the pending safety check.""" - - code: Optional[str] - """The type of the pending safety check.""" - - message: Optional[str] - """Details about the pending safety check.""" - - class ResponseComputerToolCallParam(TypedDict, total=False): """A tool call to a computer use tool. @@ -215,9 +216,6 @@ class ResponseComputerToolCallParam(TypedDict, total=False): id: Required[str] """The unique ID of the computer call.""" - action: Required[Action] - """A click action.""" - call_id: Required[str] """An identifier used when responding to the tool call with output.""" @@ -233,3 +231,12 @@ class ResponseComputerToolCallParam(TypedDict, total=False): type: Required[Literal["computer_call"]] """The type of the computer call. Always `computer_call`.""" + + action: Action + """A click action.""" + + actions: ComputerActionListParam + """Flattened batched actions for `computer_use`. + + Each action includes an `type` discriminator and action-specific fields. + """ diff --git a/src/openai/types/responses/response_custom_tool_call.py b/src/openai/types/responses/response_custom_tool_call.py index f05743966e..965ed88f96 100644 --- a/src/openai/types/responses/response_custom_tool_call.py +++ b/src/openai/types/responses/response_custom_tool_call.py @@ -25,3 +25,6 @@ class ResponseCustomToolCall(BaseModel): id: Optional[str] = None """The unique ID of the custom tool call in the OpenAI platform.""" + + namespace: Optional[str] = None + """The namespace of the custom tool being called.""" diff --git a/src/openai/types/responses/response_custom_tool_call_param.py b/src/openai/types/responses/response_custom_tool_call_param.py index 5d4ce3376c..9f82546ef1 100644 --- a/src/openai/types/responses/response_custom_tool_call_param.py +++ b/src/openai/types/responses/response_custom_tool_call_param.py @@ -24,3 +24,6 @@ class ResponseCustomToolCallParam(TypedDict, total=False): id: str """The unique ID of the custom tool call in the OpenAI platform.""" + + namespace: str + """The namespace of the custom tool being called.""" diff --git a/src/openai/types/responses/response_function_tool_call.py b/src/openai/types/responses/response_function_tool_call.py index 194e3f7d6a..3ff4c67a3f 100644 --- a/src/openai/types/responses/response_function_tool_call.py +++ b/src/openai/types/responses/response_function_tool_call.py @@ -30,6 +30,9 @@ class ResponseFunctionToolCall(BaseModel): id: Optional[str] = None """The unique ID of the function tool call.""" + namespace: Optional[str] = None + """The namespace of the function to run.""" + status: Optional[Literal["in_progress", "completed", "incomplete"]] = None """The status of the item. diff --git a/src/openai/types/responses/response_function_tool_call_param.py b/src/openai/types/responses/response_function_tool_call_param.py index 4e8dd3d629..5183e9e233 100644 --- a/src/openai/types/responses/response_function_tool_call_param.py +++ b/src/openai/types/responses/response_function_tool_call_param.py @@ -29,6 +29,9 @@ class ResponseFunctionToolCallParam(TypedDict, total=False): id: str """The unique ID of the function tool call.""" + namespace: str + """The namespace of the function to run.""" + status: Literal["in_progress", "completed", "incomplete"] """The status of the item. diff --git a/src/openai/types/responses/response_input_file.py b/src/openai/types/responses/response_input_file.py index 3e5fb70c5f..97cc176f35 100644 --- a/src/openai/types/responses/response_input_file.py +++ b/src/openai/types/responses/response_input_file.py @@ -14,6 +14,12 @@ class ResponseInputFile(BaseModel): type: Literal["input_file"] """The type of the input item. Always `input_file`.""" + detail: Optional[Literal["low", "high"]] = None + """The detail level of the file to be sent to the model. + + One of `high` or `low`. Defaults to `high`. + """ + file_data: Optional[str] = None """The content of the file to be sent to the model.""" diff --git a/src/openai/types/responses/response_input_file_content.py b/src/openai/types/responses/response_input_file_content.py index f0dfef55d0..7b1c76bff7 100644 --- a/src/openai/types/responses/response_input_file_content.py +++ b/src/openai/types/responses/response_input_file_content.py @@ -14,6 +14,12 @@ class ResponseInputFileContent(BaseModel): type: Literal["input_file"] """The type of the input item. Always `input_file`.""" + detail: Optional[Literal["high", "low"]] = None + """The detail level of the file to be sent to the model. + + One of `high` or `low`. Defaults to `high`. + """ + file_data: Optional[str] = None """The base64-encoded data of the file to be sent to the model.""" diff --git a/src/openai/types/responses/response_input_file_content_param.py b/src/openai/types/responses/response_input_file_content_param.py index 376f6c7a45..73e8acd27b 100644 --- a/src/openai/types/responses/response_input_file_content_param.py +++ b/src/openai/types/responses/response_input_file_content_param.py @@ -14,6 +14,12 @@ class ResponseInputFileContentParam(TypedDict, total=False): type: Required[Literal["input_file"]] """The type of the input item. Always `input_file`.""" + detail: Literal["high", "low"] + """The detail level of the file to be sent to the model. + + One of `high` or `low`. Defaults to `high`. + """ + file_data: Optional[str] """The base64-encoded data of the file to be sent to the model.""" diff --git a/src/openai/types/responses/response_input_file_param.py b/src/openai/types/responses/response_input_file_param.py index 8b5da20245..25eec2fe01 100644 --- a/src/openai/types/responses/response_input_file_param.py +++ b/src/openai/types/responses/response_input_file_param.py @@ -14,6 +14,12 @@ class ResponseInputFileParam(TypedDict, total=False): type: Required[Literal["input_file"]] """The type of the input item. Always `input_file`.""" + detail: Literal["low", "high"] + """The detail level of the file to be sent to the model. + + One of `high` or `low`. Defaults to `high`. + """ + file_data: str """The content of the file to be sent to the model.""" diff --git a/src/openai/types/responses/response_input_image.py b/src/openai/types/responses/response_input_image.py index 500bc4b346..63c4b42cbd 100644 --- a/src/openai/types/responses/response_input_image.py +++ b/src/openai/types/responses/response_input_image.py @@ -14,10 +14,10 @@ class ResponseInputImage(BaseModel): Learn about [image inputs](https://platform.openai.com/docs/guides/vision). """ - detail: Literal["low", "high", "auto"] + detail: Literal["low", "high", "auto", "original"] """The detail level of the image to be sent to the model. - One of `high`, `low`, or `auto`. Defaults to `auto`. + One of `high`, `low`, `auto`, or `original`. Defaults to `auto`. """ type: Literal["input_image"] diff --git a/src/openai/types/responses/response_input_image_content.py b/src/openai/types/responses/response_input_image_content.py index e38bc28d5e..d9619f65d8 100644 --- a/src/openai/types/responses/response_input_image_content.py +++ b/src/openai/types/responses/response_input_image_content.py @@ -17,10 +17,10 @@ class ResponseInputImageContent(BaseModel): type: Literal["input_image"] """The type of the input item. Always `input_image`.""" - detail: Optional[Literal["low", "high", "auto"]] = None + detail: Optional[Literal["low", "high", "auto", "original"]] = None """The detail level of the image to be sent to the model. - One of `high`, `low`, or `auto`. Defaults to `auto`. + One of `high`, `low`, `auto`, or `original`. Defaults to `auto`. """ file_id: Optional[str] = None diff --git a/src/openai/types/responses/response_input_image_content_param.py b/src/openai/types/responses/response_input_image_content_param.py index c21f46d736..743642d4cf 100644 --- a/src/openai/types/responses/response_input_image_content_param.py +++ b/src/openai/types/responses/response_input_image_content_param.py @@ -17,10 +17,10 @@ class ResponseInputImageContentParam(TypedDict, total=False): type: Required[Literal["input_image"]] """The type of the input item. Always `input_image`.""" - detail: Optional[Literal["low", "high", "auto"]] + detail: Optional[Literal["low", "high", "auto", "original"]] """The detail level of the image to be sent to the model. - One of `high`, `low`, or `auto`. Defaults to `auto`. + One of `high`, `low`, `auto`, or `original`. Defaults to `auto`. """ file_id: Optional[str] diff --git a/src/openai/types/responses/response_input_image_param.py b/src/openai/types/responses/response_input_image_param.py index fd8c1bd070..118f0b5f72 100644 --- a/src/openai/types/responses/response_input_image_param.py +++ b/src/openai/types/responses/response_input_image_param.py @@ -14,10 +14,10 @@ class ResponseInputImageParam(TypedDict, total=False): Learn about [image inputs](https://platform.openai.com/docs/guides/vision). """ - detail: Required[Literal["low", "high", "auto"]] + detail: Required[Literal["low", "high", "auto", "original"]] """The detail level of the image to be sent to the model. - One of `high`, `low`, or `auto`. Defaults to `auto`. + One of `high`, `low`, `auto`, or `original`. Defaults to `auto`. """ type: Required[Literal["input_image"]] diff --git a/src/openai/types/responses/response_input_item.py b/src/openai/types/responses/response_input_item.py index 2b664fd875..af3ce5bdc9 100644 --- a/src/openai/types/responses/response_input_item.py +++ b/src/openai/types/responses/response_input_item.py @@ -19,6 +19,7 @@ from .response_custom_tool_call_output import ResponseCustomToolCallOutput from .response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall from .response_input_message_content_list import ResponseInputMessageContentList +from .response_tool_search_output_item_param import ResponseToolSearchOutputItemParam from .response_function_call_output_item_list import ResponseFunctionCallOutputItemList from .response_function_shell_call_output_content import ResponseFunctionShellCallOutputContent from .response_computer_tool_call_output_screenshot import ResponseComputerToolCallOutputScreenshot @@ -29,6 +30,7 @@ "ComputerCallOutput", "ComputerCallOutputAcknowledgedSafetyCheck", "FunctionCallOutput", + "ToolSearchCall", "ImageGenerationCall", "LocalShellCall", "LocalShellCallAction", @@ -147,6 +149,26 @@ class FunctionCallOutput(BaseModel): """ +class ToolSearchCall(BaseModel): + arguments: object + """The arguments supplied to the tool search call.""" + + type: Literal["tool_search_call"] + """The item type. Always `tool_search_call`.""" + + id: Optional[str] = None + """The unique ID of this tool search call.""" + + call_id: Optional[str] = None + """The unique ID of the tool search call generated by the model.""" + + execution: Optional[Literal["server", "client"]] = None + """Whether tool search was executed by the server or by the client.""" + + status: Optional[Literal["in_progress", "completed", "incomplete"]] = None + """The status of the tool search call.""" + + class ImageGenerationCall(BaseModel): """An image generation request made by the model.""" @@ -526,6 +548,8 @@ class ItemReference(BaseModel): ResponseFunctionWebSearch, ResponseFunctionToolCall, FunctionCallOutput, + ToolSearchCall, + ResponseToolSearchOutputItemParam, ResponseReasoningItem, ResponseCompactionItemParam, ImageGenerationCall, diff --git a/src/openai/types/responses/response_input_item_param.py b/src/openai/types/responses/response_input_item_param.py index f52a7495db..87ea1bc572 100644 --- a/src/openai/types/responses/response_input_item_param.py +++ b/src/openai/types/responses/response_input_item_param.py @@ -20,6 +20,7 @@ from .response_custom_tool_call_output_param import ResponseCustomToolCallOutputParam from .response_code_interpreter_tool_call_param import ResponseCodeInterpreterToolCallParam from .response_input_message_content_list_param import ResponseInputMessageContentListParam +from .response_tool_search_output_item_param_param import ResponseToolSearchOutputItemParamParam from .response_function_call_output_item_list_param import ResponseFunctionCallOutputItemListParam from .response_function_shell_call_output_content_param import ResponseFunctionShellCallOutputContentParam from .response_computer_tool_call_output_screenshot_param import ResponseComputerToolCallOutputScreenshotParam @@ -30,6 +31,7 @@ "ComputerCallOutput", "ComputerCallOutputAcknowledgedSafetyCheck", "FunctionCallOutput", + "ToolSearchCall", "ImageGenerationCall", "LocalShellCall", "LocalShellCallAction", @@ -148,6 +150,26 @@ class FunctionCallOutput(TypedDict, total=False): """ +class ToolSearchCall(TypedDict, total=False): + arguments: Required[object] + """The arguments supplied to the tool search call.""" + + type: Required[Literal["tool_search_call"]] + """The item type. Always `tool_search_call`.""" + + id: Optional[str] + """The unique ID of this tool search call.""" + + call_id: Optional[str] + """The unique ID of the tool search call generated by the model.""" + + execution: Literal["server", "client"] + """Whether tool search was executed by the server or by the client.""" + + status: Optional[Literal["in_progress", "completed", "incomplete"]] + """The status of the tool search call.""" + + class ImageGenerationCall(TypedDict, total=False): """An image generation request made by the model.""" @@ -523,6 +545,8 @@ class ItemReference(TypedDict, total=False): ResponseFunctionWebSearchParam, ResponseFunctionToolCallParam, FunctionCallOutput, + ToolSearchCall, + ResponseToolSearchOutputItemParamParam, ResponseReasoningItemParam, ResponseCompactionItemParamParam, ImageGenerationCall, diff --git a/src/openai/types/responses/response_input_param.py b/src/openai/types/responses/response_input_param.py index c125d03f84..cf4d529521 100644 --- a/src/openai/types/responses/response_input_param.py +++ b/src/openai/types/responses/response_input_param.py @@ -20,6 +20,7 @@ from .response_custom_tool_call_output_param import ResponseCustomToolCallOutputParam from .response_code_interpreter_tool_call_param import ResponseCodeInterpreterToolCallParam from .response_input_message_content_list_param import ResponseInputMessageContentListParam +from .response_tool_search_output_item_param_param import ResponseToolSearchOutputItemParamParam from .response_function_call_output_item_list_param import ResponseFunctionCallOutputItemListParam from .response_function_shell_call_output_content_param import ResponseFunctionShellCallOutputContentParam from .response_computer_tool_call_output_screenshot_param import ResponseComputerToolCallOutputScreenshotParam @@ -31,6 +32,7 @@ "ComputerCallOutput", "ComputerCallOutputAcknowledgedSafetyCheck", "FunctionCallOutput", + "ToolSearchCall", "ImageGenerationCall", "LocalShellCall", "LocalShellCallAction", @@ -149,6 +151,26 @@ class FunctionCallOutput(TypedDict, total=False): """ +class ToolSearchCall(TypedDict, total=False): + arguments: Required[object] + """The arguments supplied to the tool search call.""" + + type: Required[Literal["tool_search_call"]] + """The item type. Always `tool_search_call`.""" + + id: Optional[str] + """The unique ID of this tool search call.""" + + call_id: Optional[str] + """The unique ID of the tool search call generated by the model.""" + + execution: Literal["server", "client"] + """Whether tool search was executed by the server or by the client.""" + + status: Optional[Literal["in_progress", "completed", "incomplete"]] + """The status of the tool search call.""" + + class ImageGenerationCall(TypedDict, total=False): """An image generation request made by the model.""" @@ -524,6 +546,8 @@ class ItemReference(TypedDict, total=False): ResponseFunctionWebSearchParam, ResponseFunctionToolCallParam, FunctionCallOutput, + ToolSearchCall, + ResponseToolSearchOutputItemParamParam, ResponseReasoningItemParam, ResponseCompactionItemParamParam, ImageGenerationCall, diff --git a/src/openai/types/responses/response_item.py b/src/openai/types/responses/response_item.py index 3dba681d53..316a912f62 100644 --- a/src/openai/types/responses/response_item.py +++ b/src/openai/types/responses/response_item.py @@ -6,12 +6,14 @@ from ..._utils import PropertyInfo from ..._models import BaseModel from .response_output_message import ResponseOutputMessage +from .response_tool_search_call import ResponseToolSearchCall from .response_computer_tool_call import ResponseComputerToolCall from .response_input_message_item import ResponseInputMessageItem from .response_function_web_search import ResponseFunctionWebSearch from .response_apply_patch_tool_call import ResponseApplyPatchToolCall from .response_file_search_tool_call import ResponseFileSearchToolCall from .response_function_tool_call_item import ResponseFunctionToolCallItem +from .response_tool_search_output_item import ResponseToolSearchOutputItem from .response_function_shell_tool_call import ResponseFunctionShellToolCall from .response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall from .response_apply_patch_tool_call_output import ResponseApplyPatchToolCallOutput @@ -227,6 +229,8 @@ class McpCall(BaseModel): ResponseFunctionWebSearch, ResponseFunctionToolCallItem, ResponseFunctionToolCallOutputItem, + ResponseToolSearchCall, + ResponseToolSearchOutputItem, ImageGenerationCall, ResponseCodeInterpreterToolCall, LocalShellCall, diff --git a/src/openai/types/responses/response_output_item.py b/src/openai/types/responses/response_output_item.py index 990f947b90..4be4cbf78e 100644 --- a/src/openai/types/responses/response_output_item.py +++ b/src/openai/types/responses/response_output_item.py @@ -9,11 +9,13 @@ from .response_reasoning_item import ResponseReasoningItem from .response_compaction_item import ResponseCompactionItem from .response_custom_tool_call import ResponseCustomToolCall +from .response_tool_search_call import ResponseToolSearchCall from .response_computer_tool_call import ResponseComputerToolCall from .response_function_tool_call import ResponseFunctionToolCall from .response_function_web_search import ResponseFunctionWebSearch from .response_apply_patch_tool_call import ResponseApplyPatchToolCall from .response_file_search_tool_call import ResponseFileSearchToolCall +from .response_tool_search_output_item import ResponseToolSearchOutputItem from .response_function_shell_tool_call import ResponseFunctionShellToolCall from .response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall from .response_apply_patch_tool_call_output import ResponseApplyPatchToolCallOutput @@ -188,6 +190,8 @@ class McpApprovalRequest(BaseModel): ResponseFunctionWebSearch, ResponseComputerToolCall, ResponseReasoningItem, + ResponseToolSearchCall, + ResponseToolSearchOutputItem, ResponseCompactionItem, ImageGenerationCall, ResponseCodeInterpreterToolCall, diff --git a/src/openai/types/responses/response_output_message.py b/src/openai/types/responses/response_output_message.py index a8720e1c57..760d72d58d 100644 --- a/src/openai/types/responses/response_output_message.py +++ b/src/openai/types/responses/response_output_message.py @@ -36,10 +36,9 @@ class ResponseOutputMessage(BaseModel): """The type of the output message. Always `message`.""" phase: Optional[Literal["commentary", "final_answer"]] = None - """The phase of an assistant message. - - Use `commentary` for an intermediate assistant message and `final_answer` for - the final assistant message. For follow-up requests with models like - `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. - Omitting it can degrade performance. Not used for user messages. + """ + Labels an `assistant` message as intermediate commentary (`commentary`) or the + final answer (`final_answer`). For models like `gpt-5.3-codex` and beyond, when + sending follow-up requests, preserve and resend phase on all assistant messages + — dropping it can degrade performance. Not used for user messages. """ diff --git a/src/openai/types/responses/response_output_message_param.py b/src/openai/types/responses/response_output_message_param.py index 5d488d8c6b..09fec5bd58 100644 --- a/src/openai/types/responses/response_output_message_param.py +++ b/src/openai/types/responses/response_output_message_param.py @@ -36,10 +36,9 @@ class ResponseOutputMessageParam(TypedDict, total=False): """The type of the output message. Always `message`.""" phase: Optional[Literal["commentary", "final_answer"]] - """The phase of an assistant message. - - Use `commentary` for an intermediate assistant message and `final_answer` for - the final assistant message. For follow-up requests with models like - `gpt-5.3-codex` and later, preserve and resend phase on all assistant messages. - Omitting it can degrade performance. Not used for user messages. + """ + Labels an `assistant` message as intermediate commentary (`commentary`) or the + final answer (`final_answer`). For models like `gpt-5.3-codex` and beyond, when + sending follow-up requests, preserve and resend phase on all assistant messages + — dropping it can degrade performance. Not used for user messages. """ diff --git a/src/openai/types/responses/response_tool_search_call.py b/src/openai/types/responses/response_tool_search_call.py new file mode 100644 index 0000000000..495bf17119 --- /dev/null +++ b/src/openai/types/responses/response_tool_search_call.py @@ -0,0 +1,31 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ResponseToolSearchCall"] + + +class ResponseToolSearchCall(BaseModel): + id: str + """The unique ID of the tool search call item.""" + + arguments: object + """Arguments used for the tool search call.""" + + call_id: Optional[str] = None + """The unique ID of the tool search call generated by the model.""" + + execution: Literal["server", "client"] + """Whether tool search was executed by the server or by the client.""" + + status: Literal["in_progress", "completed", "incomplete"] + """The status of the tool search call item that was recorded.""" + + type: Literal["tool_search_call"] + """The type of the item. Always `tool_search_call`.""" + + created_by: Optional[str] = None + """The identifier of the actor that created the item.""" diff --git a/src/openai/types/responses/response_tool_search_output_item.py b/src/openai/types/responses/response_tool_search_output_item.py new file mode 100644 index 0000000000..f8911dd491 --- /dev/null +++ b/src/openai/types/responses/response_tool_search_output_item.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from .tool import Tool +from ..._models import BaseModel + +__all__ = ["ResponseToolSearchOutputItem"] + + +class ResponseToolSearchOutputItem(BaseModel): + id: str + """The unique ID of the tool search output item.""" + + call_id: Optional[str] = None + """The unique ID of the tool search call generated by the model.""" + + execution: Literal["server", "client"] + """Whether tool search was executed by the server or by the client.""" + + status: Literal["in_progress", "completed", "incomplete"] + """The status of the tool search output item that was recorded.""" + + tools: List[Tool] + """The loaded tool definitions returned by tool search.""" + + type: Literal["tool_search_output"] + """The type of the item. Always `tool_search_output`.""" + + created_by: Optional[str] = None + """The identifier of the actor that created the item.""" diff --git a/src/openai/types/responses/response_tool_search_output_item_param.py b/src/openai/types/responses/response_tool_search_output_item_param.py new file mode 100644 index 0000000000..f4d4ef34c6 --- /dev/null +++ b/src/openai/types/responses/response_tool_search_output_item_param.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from .tool import Tool +from ..._models import BaseModel + +__all__ = ["ResponseToolSearchOutputItemParam"] + + +class ResponseToolSearchOutputItemParam(BaseModel): + tools: List[Tool] + """The loaded tool definitions returned by the tool search output.""" + + type: Literal["tool_search_output"] + """The item type. Always `tool_search_output`.""" + + id: Optional[str] = None + """The unique ID of this tool search output.""" + + call_id: Optional[str] = None + """The unique ID of the tool search call generated by the model.""" + + execution: Optional[Literal["server", "client"]] = None + """Whether tool search was executed by the server or by the client.""" + + status: Optional[Literal["in_progress", "completed", "incomplete"]] = None + """The status of the tool search output.""" diff --git a/src/openai/types/responses/response_tool_search_output_item_param_param.py b/src/openai/types/responses/response_tool_search_output_item_param_param.py new file mode 100644 index 0000000000..28e9b1e186 --- /dev/null +++ b/src/openai/types/responses/response_tool_search_output_item_param_param.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Literal, Required, TypedDict + +from .tool_param import ToolParam + +__all__ = ["ResponseToolSearchOutputItemParamParam"] + + +class ResponseToolSearchOutputItemParamParam(TypedDict, total=False): + tools: Required[Iterable[ToolParam]] + """The loaded tool definitions returned by the tool search output.""" + + type: Required[Literal["tool_search_output"]] + """The item type. Always `tool_search_output`.""" + + id: Optional[str] + """The unique ID of this tool search output.""" + + call_id: Optional[str] + """The unique ID of the tool search call generated by the model.""" + + execution: Literal["server", "client"] + """Whether tool search was executed by the server or by the client.""" + + status: Optional[Literal["in_progress", "completed", "incomplete"]] + """The status of the tool search output.""" diff --git a/src/openai/types/responses/tool.py b/src/openai/types/responses/tool.py index a98b4ca758..140cd520c7 100644 --- a/src/openai/types/responses/tool.py +++ b/src/openai/types/responses/tool.py @@ -9,9 +9,12 @@ from .custom_tool import CustomTool from .computer_tool import ComputerTool from .function_tool import FunctionTool +from .namespace_tool import NamespaceTool from .web_search_tool import WebSearchTool from .apply_patch_tool import ApplyPatchTool from .file_search_tool import FileSearchTool +from .tool_search_tool import ToolSearchTool +from .computer_use_tool import ComputerUseTool from .function_shell_tool import FunctionShellTool from .web_search_preview_tool import WebSearchPreviewTool from .container_network_policy_disabled import ContainerNetworkPolicyDisabled @@ -158,6 +161,9 @@ class Mcp(BaseModel): - SharePoint: `connector_sharepoint` """ + defer_loading: Optional[bool] = None + """Whether this MCP tool is deferred and discovered via tool search.""" + headers: Optional[Dict[str, str]] = None """Optional HTTP headers to send to the MCP server. @@ -306,6 +312,7 @@ class LocalShell(BaseModel): Union[ FunctionTool, FileSearchTool, + ComputerUseTool, ComputerTool, WebSearchTool, Mcp, @@ -314,6 +321,8 @@ class LocalShell(BaseModel): LocalShell, FunctionShellTool, CustomTool, + NamespaceTool, + ToolSearchTool, WebSearchPreviewTool, ApplyPatchTool, ], diff --git a/src/openai/types/responses/tool_choice_types.py b/src/openai/types/responses/tool_choice_types.py index 044c014b19..3cd1d3f64c 100644 --- a/src/openai/types/responses/tool_choice_types.py +++ b/src/openai/types/responses/tool_choice_types.py @@ -16,7 +16,9 @@ class ToolChoiceTypes(BaseModel): type: Literal[ "file_search", "web_search_preview", + "computer", "computer_use_preview", + "computer_use", "web_search_preview_2025_03_11", "image_generation", "code_interpreter", @@ -30,7 +32,9 @@ class ToolChoiceTypes(BaseModel): - `file_search` - `web_search_preview` + - `computer` - `computer_use_preview` + - `computer_use` - `code_interpreter` - `image_generation` """ diff --git a/src/openai/types/responses/tool_choice_types_param.py b/src/openai/types/responses/tool_choice_types_param.py index 9bf02dbfcc..5d08380a22 100644 --- a/src/openai/types/responses/tool_choice_types_param.py +++ b/src/openai/types/responses/tool_choice_types_param.py @@ -17,7 +17,9 @@ class ToolChoiceTypesParam(TypedDict, total=False): Literal[ "file_search", "web_search_preview", + "computer", "computer_use_preview", + "computer_use", "web_search_preview_2025_03_11", "image_generation", "code_interpreter", @@ -32,7 +34,9 @@ class ToolChoiceTypesParam(TypedDict, total=False): - `file_search` - `web_search_preview` + - `computer` - `computer_use_preview` + - `computer_use` - `code_interpreter` - `image_generation` """ diff --git a/src/openai/types/responses/tool_param.py b/src/openai/types/responses/tool_param.py index a351065dea..e35d178d6e 100644 --- a/src/openai/types/responses/tool_param.py +++ b/src/openai/types/responses/tool_param.py @@ -11,9 +11,12 @@ from .custom_tool_param import CustomToolParam from .computer_tool_param import ComputerToolParam from .function_tool_param import FunctionToolParam +from .namespace_tool_param import NamespaceToolParam from .web_search_tool_param import WebSearchToolParam from .apply_patch_tool_param import ApplyPatchToolParam from .file_search_tool_param import FileSearchToolParam +from .tool_search_tool_param import ToolSearchToolParam +from .computer_use_tool_param import ComputerUseToolParam from .function_shell_tool_param import FunctionShellToolParam from .web_search_preview_tool_param import WebSearchPreviewToolParam from .container_network_policy_disabled_param import ContainerNetworkPolicyDisabledParam @@ -158,6 +161,9 @@ class Mcp(TypedDict, total=False): - SharePoint: `connector_sharepoint` """ + defer_loading: bool + """Whether this MCP tool is deferred and discovered via tool search.""" + headers: Optional[Dict[str, str]] """Optional HTTP headers to send to the MCP server. @@ -305,6 +311,7 @@ class LocalShell(TypedDict, total=False): ToolParam: TypeAlias = Union[ FunctionToolParam, FileSearchToolParam, + ComputerUseToolParam, ComputerToolParam, WebSearchToolParam, Mcp, @@ -313,6 +320,8 @@ class LocalShell(TypedDict, total=False): LocalShell, FunctionShellToolParam, CustomToolParam, + NamespaceToolParam, + ToolSearchToolParam, WebSearchPreviewToolParam, ApplyPatchToolParam, ] diff --git a/src/openai/types/responses/tool_search_tool.py b/src/openai/types/responses/tool_search_tool.py new file mode 100644 index 0000000000..44a741a1c4 --- /dev/null +++ b/src/openai/types/responses/tool_search_tool.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ToolSearchTool"] + + +class ToolSearchTool(BaseModel): + """Hosted or BYOT tool search configuration for deferred tools.""" + + type: Literal["tool_search"] + """The type of the tool. Always `tool_search`.""" + + description: Optional[str] = None + """Description shown to the model for a client-executed tool search tool.""" + + execution: Optional[Literal["server", "client"]] = None + """Whether tool search is executed by the server or by the client.""" + + parameters: Optional[object] = None + """Parameter schema for a client-executed tool search tool.""" diff --git a/src/openai/types/responses/tool_search_tool_param.py b/src/openai/types/responses/tool_search_tool_param.py new file mode 100644 index 0000000000..3063da276c --- /dev/null +++ b/src/openai/types/responses/tool_search_tool_param.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ToolSearchToolParam"] + + +class ToolSearchToolParam(TypedDict, total=False): + """Hosted or BYOT tool search configuration for deferred tools.""" + + type: Required[Literal["tool_search"]] + """The type of the tool. Always `tool_search`.""" + + description: Optional[str] + """Description shown to the model for a client-executed tool search tool.""" + + execution: Literal["server", "client"] + """Whether tool search is executed by the server or by the client.""" + + parameters: Optional[object] + """Parameter schema for a client-executed tool search tool.""" diff --git a/src/openai/types/responses/web_search_preview_tool.py b/src/openai/types/responses/web_search_preview_tool.py index 12478e896d..bdf092f196 100644 --- a/src/openai/types/responses/web_search_preview_tool.py +++ b/src/openai/types/responses/web_search_preview_tool.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional +from typing import List, Optional from typing_extensions import Literal from ..._models import BaseModel @@ -45,6 +45,8 @@ class WebSearchPreviewTool(BaseModel): One of `web_search_preview` or `web_search_preview_2025_03_11`. """ + search_content_types: Optional[List[Literal["text", "image"]]] = None + search_context_size: Optional[Literal["low", "medium", "high"]] = None """High level guidance for the amount of context window space to use for the search. diff --git a/src/openai/types/responses/web_search_preview_tool_param.py b/src/openai/types/responses/web_search_preview_tool_param.py index 09619a3394..b81f95e308 100644 --- a/src/openai/types/responses/web_search_preview_tool_param.py +++ b/src/openai/types/responses/web_search_preview_tool_param.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Optional +from typing import List, Optional from typing_extensions import Literal, Required, TypedDict __all__ = ["WebSearchPreviewToolParam", "UserLocation"] @@ -45,6 +45,8 @@ class WebSearchPreviewToolParam(TypedDict, total=False): One of `web_search_preview` or `web_search_preview_2025_03_11`. """ + search_content_types: List[Literal["text", "image"]] + search_context_size: Literal["low", "medium", "high"] """High level guidance for the amount of context window space to use for the search. diff --git a/src/openai/types/shared/chat_model.py b/src/openai/types/shared/chat_model.py index 8223b81bef..b86bd28ef9 100644 --- a/src/openai/types/shared/chat_model.py +++ b/src/openai/types/shared/chat_model.py @@ -5,6 +5,8 @@ __all__ = ["ChatModel"] ChatModel: TypeAlias = Literal[ + "gpt-5.4", + "gpt-5.3-chat-latest", "gpt-5.2", "gpt-5.2-2025-12-11", "gpt-5.2-chat-latest", diff --git a/src/openai/types/shared_params/chat_model.py b/src/openai/types/shared_params/chat_model.py index c1937a8312..2a45c8f423 100644 --- a/src/openai/types/shared_params/chat_model.py +++ b/src/openai/types/shared_params/chat_model.py @@ -7,6 +7,8 @@ __all__ = ["ChatModel"] ChatModel: TypeAlias = Literal[ + "gpt-5.4", + "gpt-5.3-chat-latest", "gpt-5.2", "gpt-5.2-2025-12-11", "gpt-5.2-chat-latest", diff --git a/src/openai/types/video.py b/src/openai/types/video.py index e732ea54ec..051b951ede 100644 --- a/src/openai/types/video.py +++ b/src/openai/types/video.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional +from typing import Union, Optional from typing_extensions import Literal from .._models import BaseModel @@ -45,8 +45,11 @@ class Video(BaseModel): remixed_from_video_id: Optional[str] = None """Identifier of the source video if this video is a remix.""" - seconds: VideoSeconds - """Duration of the generated clip in seconds.""" + seconds: Union[str, VideoSeconds] + """Duration of the generated clip in seconds. + + For extensions, this is the stitched total duration. + """ size: VideoSize """The resolution of the generated video.""" diff --git a/src/openai/types/video_create_params.py b/src/openai/types/video_create_params.py index d787aaeddd..282b1db429 100644 --- a/src/openai/types/video_create_params.py +++ b/src/openai/types/video_create_params.py @@ -17,7 +17,7 @@ class VideoCreateParams(TypedDict, total=False): """Text prompt that describes the video to generate.""" input_reference: FileTypes - """Optional image reference that guides generation.""" + """Optional multipart reference asset that guides generation.""" model: VideoModelParam """The video generation model to use (allowed values: sora-2, sora-2-pro). diff --git a/tests/api_resources/chat/test_completions.py b/tests/api_resources/chat/test_completions.py index 2b58ff8191..995b752e11 100644 --- a/tests/api_resources/chat/test_completions.py +++ b/tests/api_resources/chat/test_completions.py @@ -31,7 +31,7 @@ def test_method_create_overload_1(self, client: OpenAI) -> None: "role": "developer", } ], - model="gpt-4o", + model="gpt-5.4", ) assert_matches_type(ChatCompletion, completion, path=["response"]) @@ -45,7 +45,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: "name": "name", } ], - model="gpt-4o", + model="gpt-5.4", audio={ "format": "wav", "voice": "ash", @@ -127,7 +127,7 @@ def test_raw_response_create_overload_1(self, client: OpenAI) -> None: "role": "developer", } ], - model="gpt-4o", + model="gpt-5.4", ) assert response.is_closed is True @@ -144,7 +144,7 @@ def test_streaming_response_create_overload_1(self, client: OpenAI) -> None: "role": "developer", } ], - model="gpt-4o", + model="gpt-5.4", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -163,7 +163,7 @@ def test_method_create_overload_2(self, client: OpenAI) -> None: "role": "developer", } ], - model="gpt-4o", + model="gpt-5.4", stream=True, ) completion_stream.response.close() @@ -178,7 +178,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: "name": "name", } ], - model="gpt-4o", + model="gpt-5.4", stream=True, audio={ "format": "wav", @@ -260,7 +260,7 @@ def test_raw_response_create_overload_2(self, client: OpenAI) -> None: "role": "developer", } ], - model="gpt-4o", + model="gpt-5.4", stream=True, ) @@ -277,7 +277,7 @@ def test_streaming_response_create_overload_2(self, client: OpenAI) -> None: "role": "developer", } ], - model="gpt-4o", + model="gpt-5.4", stream=True, ) as response: assert not response.is_closed @@ -474,7 +474,7 @@ async def test_method_create_overload_1(self, async_client: AsyncOpenAI) -> None "role": "developer", } ], - model="gpt-4o", + model="gpt-5.4", ) assert_matches_type(ChatCompletion, completion, path=["response"]) @@ -488,7 +488,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn "name": "name", } ], - model="gpt-4o", + model="gpt-5.4", audio={ "format": "wav", "voice": "ash", @@ -570,7 +570,7 @@ async def test_raw_response_create_overload_1(self, async_client: AsyncOpenAI) - "role": "developer", } ], - model="gpt-4o", + model="gpt-5.4", ) assert response.is_closed is True @@ -587,7 +587,7 @@ async def test_streaming_response_create_overload_1(self, async_client: AsyncOpe "role": "developer", } ], - model="gpt-4o", + model="gpt-5.4", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -606,7 +606,7 @@ async def test_method_create_overload_2(self, async_client: AsyncOpenAI) -> None "role": "developer", } ], - model="gpt-4o", + model="gpt-5.4", stream=True, ) await completion_stream.response.aclose() @@ -621,7 +621,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn "name": "name", } ], - model="gpt-4o", + model="gpt-5.4", stream=True, audio={ "format": "wav", @@ -703,7 +703,7 @@ async def test_raw_response_create_overload_2(self, async_client: AsyncOpenAI) - "role": "developer", } ], - model="gpt-4o", + model="gpt-5.4", stream=True, ) @@ -720,7 +720,7 @@ async def test_streaming_response_create_overload_2(self, async_client: AsyncOpe "role": "developer", } ], - model="gpt-4o", + model="gpt-5.4", stream=True, ) as response: assert not response.is_closed diff --git a/tests/api_resources/fine_tuning/checkpoints/test_permissions.py b/tests/api_resources/fine_tuning/checkpoints/test_permissions.py index 9420e3a34c..a3118fc838 100644 --- a/tests/api_resources/fine_tuning/checkpoints/test_permissions.py +++ b/tests/api_resources/fine_tuning/checkpoints/test_permissions.py @@ -9,13 +9,16 @@ from openai import OpenAI, AsyncOpenAI from tests.utils import assert_matches_type -from openai.pagination import SyncPage, AsyncPage +from openai.pagination import SyncPage, AsyncPage, SyncConversationCursorPage, AsyncConversationCursorPage from openai.types.fine_tuning.checkpoints import ( + PermissionListResponse, PermissionCreateResponse, PermissionDeleteResponse, PermissionRetrieveResponse, ) +# pyright: reportDeprecated=false + base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -68,52 +71,110 @@ def test_path_params_create(self, client: OpenAI) -> None: @parametrize def test_method_retrieve(self, client: OpenAI) -> None: - permission = client.fine_tuning.checkpoints.permissions.retrieve( - fine_tuned_model_checkpoint="ft-AF1WoRqd3aJAHsqc9NY7iL8F", - ) + with pytest.warns(DeprecationWarning): + permission = client.fine_tuning.checkpoints.permissions.retrieve( + fine_tuned_model_checkpoint="ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) + assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) @parametrize def test_method_retrieve_with_all_params(self, client: OpenAI) -> None: - permission = client.fine_tuning.checkpoints.permissions.retrieve( + with pytest.warns(DeprecationWarning): + permission = client.fine_tuning.checkpoints.permissions.retrieve( + fine_tuned_model_checkpoint="ft-AF1WoRqd3aJAHsqc9NY7iL8F", + after="after", + limit=0, + order="ascending", + project_id="project_id", + ) + + assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + with pytest.warns(DeprecationWarning): + response = client.fine_tuning.checkpoints.permissions.with_raw_response.retrieve( + fine_tuned_model_checkpoint="ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + permission = response.parse() + assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with pytest.warns(DeprecationWarning): + with client.fine_tuning.checkpoints.permissions.with_streaming_response.retrieve( + fine_tuned_model_checkpoint="ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + permission = response.parse() + assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.warns(DeprecationWarning): + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `fine_tuned_model_checkpoint` but received ''" + ): + client.fine_tuning.checkpoints.permissions.with_raw_response.retrieve( + fine_tuned_model_checkpoint="", + ) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + permission = client.fine_tuning.checkpoints.permissions.list( + fine_tuned_model_checkpoint="ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) + assert_matches_type(SyncConversationCursorPage[PermissionListResponse], permission, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + permission = client.fine_tuning.checkpoints.permissions.list( fine_tuned_model_checkpoint="ft-AF1WoRqd3aJAHsqc9NY7iL8F", after="after", limit=0, order="ascending", project_id="project_id", ) - assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) + assert_matches_type(SyncConversationCursorPage[PermissionListResponse], permission, path=["response"]) @parametrize - def test_raw_response_retrieve(self, client: OpenAI) -> None: - response = client.fine_tuning.checkpoints.permissions.with_raw_response.retrieve( + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.fine_tuning.checkpoints.permissions.with_raw_response.list( fine_tuned_model_checkpoint="ft-AF1WoRqd3aJAHsqc9NY7iL8F", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" permission = response.parse() - assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) + assert_matches_type(SyncConversationCursorPage[PermissionListResponse], permission, path=["response"]) @parametrize - def test_streaming_response_retrieve(self, client: OpenAI) -> None: - with client.fine_tuning.checkpoints.permissions.with_streaming_response.retrieve( + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.fine_tuning.checkpoints.permissions.with_streaming_response.list( fine_tuned_model_checkpoint="ft-AF1WoRqd3aJAHsqc9NY7iL8F", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" permission = response.parse() - assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) + assert_matches_type(SyncConversationCursorPage[PermissionListResponse], permission, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize - def test_path_params_retrieve(self, client: OpenAI) -> None: + def test_path_params_list(self, client: OpenAI) -> None: with pytest.raises( ValueError, match=r"Expected a non-empty value for `fine_tuned_model_checkpoint` but received ''" ): - client.fine_tuning.checkpoints.permissions.with_raw_response.retrieve( + client.fine_tuning.checkpoints.permissions.with_raw_response.list( fine_tuned_model_checkpoint="", ) @@ -219,52 +280,110 @@ async def test_path_params_create(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: - permission = await async_client.fine_tuning.checkpoints.permissions.retrieve( - fine_tuned_model_checkpoint="ft-AF1WoRqd3aJAHsqc9NY7iL8F", - ) + with pytest.warns(DeprecationWarning): + permission = await async_client.fine_tuning.checkpoints.permissions.retrieve( + fine_tuned_model_checkpoint="ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) + assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) @parametrize async def test_method_retrieve_with_all_params(self, async_client: AsyncOpenAI) -> None: - permission = await async_client.fine_tuning.checkpoints.permissions.retrieve( + with pytest.warns(DeprecationWarning): + permission = await async_client.fine_tuning.checkpoints.permissions.retrieve( + fine_tuned_model_checkpoint="ft-AF1WoRqd3aJAHsqc9NY7iL8F", + after="after", + limit=0, + order="ascending", + project_id="project_id", + ) + + assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.warns(DeprecationWarning): + response = await async_client.fine_tuning.checkpoints.permissions.with_raw_response.retrieve( + fine_tuned_model_checkpoint="ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + permission = response.parse() + assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.warns(DeprecationWarning): + async with async_client.fine_tuning.checkpoints.permissions.with_streaming_response.retrieve( + fine_tuned_model_checkpoint="ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + permission = await response.parse() + assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.warns(DeprecationWarning): + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `fine_tuned_model_checkpoint` but received ''" + ): + await async_client.fine_tuning.checkpoints.permissions.with_raw_response.retrieve( + fine_tuned_model_checkpoint="", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + permission = await async_client.fine_tuning.checkpoints.permissions.list( + fine_tuned_model_checkpoint="ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) + assert_matches_type(AsyncConversationCursorPage[PermissionListResponse], permission, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + permission = await async_client.fine_tuning.checkpoints.permissions.list( fine_tuned_model_checkpoint="ft-AF1WoRqd3aJAHsqc9NY7iL8F", after="after", limit=0, order="ascending", project_id="project_id", ) - assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) + assert_matches_type(AsyncConversationCursorPage[PermissionListResponse], permission, path=["response"]) @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: - response = await async_client.fine_tuning.checkpoints.permissions.with_raw_response.retrieve( + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.fine_tuning.checkpoints.permissions.with_raw_response.list( fine_tuned_model_checkpoint="ft-AF1WoRqd3aJAHsqc9NY7iL8F", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" permission = response.parse() - assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) + assert_matches_type(AsyncConversationCursorPage[PermissionListResponse], permission, path=["response"]) @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: - async with async_client.fine_tuning.checkpoints.permissions.with_streaming_response.retrieve( + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.fine_tuning.checkpoints.permissions.with_streaming_response.list( fine_tuned_model_checkpoint="ft-AF1WoRqd3aJAHsqc9NY7iL8F", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" permission = await response.parse() - assert_matches_type(PermissionRetrieveResponse, permission, path=["response"]) + assert_matches_type(AsyncConversationCursorPage[PermissionListResponse], permission, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize - async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + async def test_path_params_list(self, async_client: AsyncOpenAI) -> None: with pytest.raises( ValueError, match=r"Expected a non-empty value for `fine_tuned_model_checkpoint` but received ''" ): - await async_client.fine_tuning.checkpoints.permissions.with_raw_response.retrieve( + await async_client.fine_tuning.checkpoints.permissions.with_raw_response.list( fine_tuned_model_checkpoint="", ) diff --git a/tests/api_resources/responses/test_input_tokens.py b/tests/api_resources/responses/test_input_tokens.py index d9aecc33bd..b4bc627837 100644 --- a/tests/api_resources/responses/test_input_tokens.py +++ b/tests/api_resources/responses/test_input_tokens.py @@ -47,6 +47,7 @@ def test_method_count_with_all_params(self, client: OpenAI) -> None: "parameters": {"foo": "bar"}, "strict": True, "type": "function", + "defer_loading": True, "description": "description", } ], @@ -110,6 +111,7 @@ async def test_method_count_with_all_params(self, async_client: AsyncOpenAI) -> "parameters": {"foo": "bar"}, "strict": True, "type": "function", + "defer_loading": True, "description": "description", } ], diff --git a/tests/api_resources/test_responses.py b/tests/api_resources/test_responses.py index 8f82f2046d..deaf35970f 100644 --- a/tests/api_resources/test_responses.py +++ b/tests/api_resources/test_responses.py @@ -75,6 +75,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: "parameters": {"foo": "bar"}, "strict": True, "type": "function", + "defer_loading": True, "description": "description", } ], @@ -161,6 +162,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: "parameters": {"foo": "bar"}, "strict": True, "type": "function", + "defer_loading": True, "description": "description", } ], @@ -374,14 +376,14 @@ def test_path_params_cancel(self, client: OpenAI) -> None: @parametrize def test_method_compact(self, client: OpenAI) -> None: response = client.responses.compact( - model="gpt-5.2", + model="gpt-5.4", ) assert_matches_type(CompactedResponse, response, path=["response"]) @parametrize def test_method_compact_with_all_params(self, client: OpenAI) -> None: response = client.responses.compact( - model="gpt-5.2", + model="gpt-5.4", input="string", instructions="instructions", previous_response_id="resp_123", @@ -392,7 +394,7 @@ def test_method_compact_with_all_params(self, client: OpenAI) -> None: @parametrize def test_raw_response_compact(self, client: OpenAI) -> None: http_response = client.responses.with_raw_response.compact( - model="gpt-5.2", + model="gpt-5.4", ) assert http_response.is_closed is True @@ -403,7 +405,7 @@ def test_raw_response_compact(self, client: OpenAI) -> None: @parametrize def test_streaming_response_compact(self, client: OpenAI) -> None: with client.responses.with_streaming_response.compact( - model="gpt-5.2", + model="gpt-5.4", ) as http_response: assert not http_response.is_closed assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -484,6 +486,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn "parameters": {"foo": "bar"}, "strict": True, "type": "function", + "defer_loading": True, "description": "description", } ], @@ -570,6 +573,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn "parameters": {"foo": "bar"}, "strict": True, "type": "function", + "defer_loading": True, "description": "description", } ], @@ -783,14 +787,14 @@ async def test_path_params_cancel(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_method_compact(self, async_client: AsyncOpenAI) -> None: response = await async_client.responses.compact( - model="gpt-5.2", + model="gpt-5.4", ) assert_matches_type(CompactedResponse, response, path=["response"]) @parametrize async def test_method_compact_with_all_params(self, async_client: AsyncOpenAI) -> None: response = await async_client.responses.compact( - model="gpt-5.2", + model="gpt-5.4", input="string", instructions="instructions", previous_response_id="resp_123", @@ -801,7 +805,7 @@ async def test_method_compact_with_all_params(self, async_client: AsyncOpenAI) - @parametrize async def test_raw_response_compact(self, async_client: AsyncOpenAI) -> None: http_response = await async_client.responses.with_raw_response.compact( - model="gpt-5.2", + model="gpt-5.4", ) assert http_response.is_closed is True @@ -812,7 +816,7 @@ async def test_raw_response_compact(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_compact(self, async_client: AsyncOpenAI) -> None: async with async_client.responses.with_streaming_response.compact( - model="gpt-5.2", + model="gpt-5.4", ) as http_response: assert not http_response.is_closed assert http_response.http_request.headers.get("X-Stainless-Lang") == "python" diff --git a/tests/test_client.py b/tests/test_client.py index b8b963aa4c..a015cd7d40 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -877,7 +877,7 @@ def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter, clien "role": "developer", } ], - model="gpt-4o", + model="gpt-5.4", ).__enter__() assert _get_open_connections(client) == 0 @@ -895,7 +895,7 @@ def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter, client "role": "developer", } ], - model="gpt-4o", + model="gpt-5.4", ).__enter__() assert _get_open_connections(client) == 0 @@ -932,7 +932,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: "role": "developer", } ], - model="gpt-4o", + model="gpt-5.4", ) assert response.retries_taken == failures_before_success @@ -964,7 +964,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: "role": "developer", } ], - model="gpt-4o", + model="gpt-5.4", extra_headers={"x-stainless-retry-count": Omit()}, ) @@ -996,7 +996,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: "role": "developer", } ], - model="gpt-4o", + model="gpt-5.4", extra_headers={"x-stainless-retry-count": "42"}, ) @@ -1028,7 +1028,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: "role": "developer", } ], - model="gpt-4o", + model="gpt-5.4", ) as response: assert response.retries_taken == failures_before_success assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success @@ -1924,7 +1924,7 @@ async def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter, "role": "developer", } ], - model="gpt-4o", + model="gpt-5.4", ).__aenter__() assert _get_open_connections(async_client) == 0 @@ -1942,7 +1942,7 @@ async def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter, "role": "developer", } ], - model="gpt-4o", + model="gpt-5.4", ).__aenter__() assert _get_open_connections(async_client) == 0 @@ -1979,7 +1979,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: "role": "developer", } ], - model="gpt-4o", + model="gpt-5.4", ) assert response.retries_taken == failures_before_success @@ -2011,7 +2011,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: "role": "developer", } ], - model="gpt-4o", + model="gpt-5.4", extra_headers={"x-stainless-retry-count": Omit()}, ) @@ -2043,7 +2043,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: "role": "developer", } ], - model="gpt-4o", + model="gpt-5.4", extra_headers={"x-stainless-retry-count": "42"}, ) @@ -2075,7 +2075,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: "role": "developer", } ], - model="gpt-4o", + model="gpt-5.4", ) as response: assert response.retries_taken == failures_before_success assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success From 15afa21e54952c06e2ac4d3e3a82f144c2cf9ed9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 5 Mar 2026 18:13:25 -0500 Subject: [PATCH 640/769] release: 2.26.0 (#2932) * feat(api): The GA ComputerTool now uses the CompuerTool class. The 'computer_use_preview' tool is moved to ComputerUsePreview This fixes naming of the old computer_use_preview, which previously took the ComputerTool name. There is a newly GAed `computer` tool now available, which will use the ComputerTool name. This may be a breaking change for users of the preview tool. * release: 2.26.0 --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- .stats.yml | 2 +- CHANGELOG.md | 8 ++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- src/openai/resources/responses/api.md | 2 +- src/openai/types/responses/__init__.py | 4 +-- src/openai/types/responses/computer_tool.py | 13 ++-------- .../types/responses/computer_tool_param.py | 13 ++-------- .../responses/computer_use_preview_tool.py | 26 +++++++++++++++++++ .../computer_use_preview_tool_param.py | 26 +++++++++++++++++++ .../types/responses/computer_use_tool.py | 17 ------------ .../responses/computer_use_tool_param.py | 17 ------------ src/openai/types/responses/tool.py | 4 +-- src/openai/types/responses/tool_param.py | 4 +-- 15 files changed, 75 insertions(+), 67 deletions(-) create mode 100644 src/openai/types/responses/computer_use_preview_tool.py create mode 100644 src/openai/types/responses/computer_use_preview_tool_param.py delete mode 100644 src/openai/types/responses/computer_use_tool.py delete mode 100644 src/openai/types/responses/computer_use_tool_param.py diff --git a/.release-please-manifest.json b/.release-please-manifest.json index c5fe8ab6d6..1441304df6 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.25.0" + ".": "2.26.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index a59953aaa9..bd550123f1 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 148 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-9c802d45a9bf2a896b5fd22ac22bba185e8a145bd40ed242df9bb87a05e954eb.yml openapi_spec_hash: 97984ed69285e660b7d5c810c69ed449 -config_hash: acb0b1eb5d7284bfedaddb29f7f5a691 +config_hash: 8240b8a7a7fc145a45b93bda435612d6 diff --git a/CHANGELOG.md b/CHANGELOG.md index 780a961a43..c8508a0b1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 2.26.0 (2026-03-05) + +Full Changelog: [v2.25.0...v2.26.0](https://github.com/openai/openai-python/compare/v2.25.0...v2.26.0) + +### Features + +* **api:** The GA ComputerTool now uses the CompuerTool class. The 'computer_use_preview' tool is moved to ComputerUsePreview ([78f5b3c](https://github.com/openai/openai-python/commit/78f5b3c287b71ed6fbeb71fb6b5c0366db704cd2)) + ## 2.25.0 (2026-03-05) Full Changelog: [v2.24.0...v2.25.0](https://github.com/openai/openai-python/compare/v2.24.0...v2.25.0) diff --git a/pyproject.toml b/pyproject.toml index f7aae6cbdb..41738c8c5e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.25.0" +version = "2.26.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 417b40c283..2feccec170 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__ = "2.25.0" # x-release-please-version +__version__ = "2.26.0" # x-release-please-version diff --git a/src/openai/resources/responses/api.md b/src/openai/resources/responses/api.md index d654abb99a..d211cd9899 100644 --- a/src/openai/resources/responses/api.md +++ b/src/openai/resources/responses/api.md @@ -9,7 +9,7 @@ from openai.types.responses import ( ComputerAction, ComputerActionList, ComputerTool, - ComputerUseTool, + ComputerUsePreviewTool, ContainerAuto, ContainerNetworkPolicyAllowlist, ContainerNetworkPolicyDisabled, diff --git a/src/openai/types/responses/__init__.py b/src/openai/types/responses/__init__.py index 714347b05d..d06f17f6a3 100644 --- a/src/openai/types/responses/__init__.py +++ b/src/openai/types/responses/__init__.py @@ -33,7 +33,6 @@ from .apply_patch_tool import ApplyPatchTool as ApplyPatchTool from .file_search_tool import FileSearchTool as FileSearchTool from .tool_search_tool import ToolSearchTool as ToolSearchTool -from .computer_use_tool import ComputerUseTool as ComputerUseTool from .custom_tool_param import CustomToolParam as CustomToolParam from .local_environment import LocalEnvironment as LocalEnvironment from .local_skill_param import LocalSkillParam as LocalSkillParam @@ -83,7 +82,6 @@ from .responses_client_event import ResponsesClientEvent as ResponsesClientEvent from .responses_server_event import ResponsesServerEvent as ResponsesServerEvent from .tool_search_tool_param import ToolSearchToolParam as ToolSearchToolParam -from .computer_use_tool_param import ComputerUseToolParam as ComputerUseToolParam from .local_environment_param import LocalEnvironmentParam as LocalEnvironmentParam from .response_compact_params import ResponseCompactParams as ResponseCompactParams from .response_output_message import ResponseOutputMessage as ResponseOutputMessage @@ -100,6 +98,7 @@ from .response_retrieve_params import ResponseRetrieveParams as ResponseRetrieveParams from .response_text_done_event import ResponseTextDoneEvent as ResponseTextDoneEvent from .tool_choice_custom_param import ToolChoiceCustomParam as ToolChoiceCustomParam +from .computer_use_preview_tool import ComputerUsePreviewTool as ComputerUsePreviewTool from .container_reference_param import ContainerReferenceParam as ContainerReferenceParam from .function_shell_tool_param import FunctionShellToolParam as FunctionShellToolParam from .inline_skill_source_param import InlineSkillSourceParam as InlineSkillSourceParam @@ -145,6 +144,7 @@ from .response_compaction_item_param import ResponseCompactionItemParam as ResponseCompactionItemParam from .response_file_search_tool_call import ResponseFileSearchToolCall as ResponseFileSearchToolCall from .response_mcp_call_failed_event import ResponseMcpCallFailedEvent as ResponseMcpCallFailedEvent +from .computer_use_preview_tool_param import ComputerUsePreviewToolParam as ComputerUsePreviewToolParam from .response_custom_tool_call_param import ResponseCustomToolCallParam as ResponseCustomToolCallParam from .response_output_item_done_event import ResponseOutputItemDoneEvent as ResponseOutputItemDoneEvent from .response_content_part_done_event import ResponseContentPartDoneEvent as ResponseContentPartDoneEvent diff --git a/src/openai/types/responses/computer_tool.py b/src/openai/types/responses/computer_tool.py index 22871c841c..392faa9e79 100644 --- a/src/openai/types/responses/computer_tool.py +++ b/src/openai/types/responses/computer_tool.py @@ -13,14 +13,5 @@ class ComputerTool(BaseModel): Learn more about the [computer tool](https://platform.openai.com/docs/guides/tools-computer-use). """ - display_height: int - """The height of the computer display.""" - - display_width: int - """The width of the computer display.""" - - environment: Literal["windows", "mac", "linux", "ubuntu", "browser"] - """The type of computer environment to control.""" - - type: Literal["computer_use_preview"] - """The type of the computer use tool. Always `computer_use_preview`.""" + type: Literal["computer"] + """The type of the computer tool. Always `computer`.""" diff --git a/src/openai/types/responses/computer_tool_param.py b/src/openai/types/responses/computer_tool_param.py index cdf75a43f2..b5931dea4f 100644 --- a/src/openai/types/responses/computer_tool_param.py +++ b/src/openai/types/responses/computer_tool_param.py @@ -13,14 +13,5 @@ class ComputerToolParam(TypedDict, total=False): Learn more about the [computer tool](https://platform.openai.com/docs/guides/tools-computer-use). """ - display_height: Required[int] - """The height of the computer display.""" - - display_width: Required[int] - """The width of the computer display.""" - - environment: Required[Literal["windows", "mac", "linux", "ubuntu", "browser"]] - """The type of computer environment to control.""" - - type: Required[Literal["computer_use_preview"]] - """The type of the computer use tool. Always `computer_use_preview`.""" + type: Required[Literal["computer"]] + """The type of the computer tool. Always `computer`.""" diff --git a/src/openai/types/responses/computer_use_preview_tool.py b/src/openai/types/responses/computer_use_preview_tool.py new file mode 100644 index 0000000000..686860e2cf --- /dev/null +++ b/src/openai/types/responses/computer_use_preview_tool.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ComputerUsePreviewTool"] + + +class ComputerUsePreviewTool(BaseModel): + """A tool that controls a virtual computer. + + Learn more about the [computer tool](https://platform.openai.com/docs/guides/tools-computer-use). + """ + + display_height: int + """The height of the computer display.""" + + display_width: int + """The width of the computer display.""" + + environment: Literal["windows", "mac", "linux", "ubuntu", "browser"] + """The type of computer environment to control.""" + + type: Literal["computer_use_preview"] + """The type of the computer use tool. Always `computer_use_preview`.""" diff --git a/src/openai/types/responses/computer_use_preview_tool_param.py b/src/openai/types/responses/computer_use_preview_tool_param.py new file mode 100644 index 0000000000..2611c7297f --- /dev/null +++ b/src/openai/types/responses/computer_use_preview_tool_param.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ComputerUsePreviewToolParam"] + + +class ComputerUsePreviewToolParam(TypedDict, total=False): + """A tool that controls a virtual computer. + + Learn more about the [computer tool](https://platform.openai.com/docs/guides/tools-computer-use). + """ + + display_height: Required[int] + """The height of the computer display.""" + + display_width: Required[int] + """The width of the computer display.""" + + environment: Required[Literal["windows", "mac", "linux", "ubuntu", "browser"]] + """The type of computer environment to control.""" + + type: Required[Literal["computer_use_preview"]] + """The type of the computer use tool. Always `computer_use_preview`.""" diff --git a/src/openai/types/responses/computer_use_tool.py b/src/openai/types/responses/computer_use_tool.py deleted file mode 100644 index 1704b25424..0000000000 --- a/src/openai/types/responses/computer_use_tool.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ComputerUseTool"] - - -class ComputerUseTool(BaseModel): - """A tool that controls a virtual computer. - - Learn more about the [computer tool](https://platform.openai.com/docs/guides/tools-computer-use). - """ - - type: Literal["computer"] - """The type of the computer tool. Always `computer`.""" diff --git a/src/openai/types/responses/computer_use_tool_param.py b/src/openai/types/responses/computer_use_tool_param.py deleted file mode 100644 index e81dbe8206..0000000000 --- a/src/openai/types/responses/computer_use_tool_param.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ComputerUseToolParam"] - - -class ComputerUseToolParam(TypedDict, total=False): - """A tool that controls a virtual computer. - - Learn more about the [computer tool](https://platform.openai.com/docs/guides/tools-computer-use). - """ - - type: Required[Literal["computer"]] - """The type of the computer tool. Always `computer`.""" diff --git a/src/openai/types/responses/tool.py b/src/openai/types/responses/tool.py index 140cd520c7..34120a287e 100644 --- a/src/openai/types/responses/tool.py +++ b/src/openai/types/responses/tool.py @@ -14,9 +14,9 @@ from .apply_patch_tool import ApplyPatchTool from .file_search_tool import FileSearchTool from .tool_search_tool import ToolSearchTool -from .computer_use_tool import ComputerUseTool from .function_shell_tool import FunctionShellTool from .web_search_preview_tool import WebSearchPreviewTool +from .computer_use_preview_tool import ComputerUsePreviewTool from .container_network_policy_disabled import ContainerNetworkPolicyDisabled from .container_network_policy_allowlist import ContainerNetworkPolicyAllowlist @@ -312,8 +312,8 @@ class LocalShell(BaseModel): Union[ FunctionTool, FileSearchTool, - ComputerUseTool, ComputerTool, + ComputerUsePreviewTool, WebSearchTool, Mcp, CodeInterpreter, diff --git a/src/openai/types/responses/tool_param.py b/src/openai/types/responses/tool_param.py index e35d178d6e..c0f33c4513 100644 --- a/src/openai/types/responses/tool_param.py +++ b/src/openai/types/responses/tool_param.py @@ -16,9 +16,9 @@ from .apply_patch_tool_param import ApplyPatchToolParam from .file_search_tool_param import FileSearchToolParam from .tool_search_tool_param import ToolSearchToolParam -from .computer_use_tool_param import ComputerUseToolParam from .function_shell_tool_param import FunctionShellToolParam from .web_search_preview_tool_param import WebSearchPreviewToolParam +from .computer_use_preview_tool_param import ComputerUsePreviewToolParam from .container_network_policy_disabled_param import ContainerNetworkPolicyDisabledParam from .container_network_policy_allowlist_param import ContainerNetworkPolicyAllowlistParam @@ -311,8 +311,8 @@ class LocalShell(TypedDict, total=False): ToolParam: TypeAlias = Union[ FunctionToolParam, FileSearchToolParam, - ComputerUseToolParam, ComputerToolParam, + ComputerUsePreviewToolParam, WebSearchToolParam, Mcp, CodeInterpreter, From 0a4ca536f356aa23a021962b442d0c187559326d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 13 Mar 2026 15:15:35 -0400 Subject: [PATCH 641/769] release: 2.27.0 (#2938) * chore(internal): codegen related update * codegen metadata * feat(api): api update * chore: match http protocol with ws protocol instead of wss * chore: use proper capitalization for WebSockets * chore(internal): codegen related update * feat(api): manual updates * feat(api): manual updates merge sora api changes * feat(api): sora api improvements: character api, video extensions/edits, higher resolution exports. * fix(api): repair merged videos resource * release: 2.27.0 --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> Co-authored-by: Alex Chang --- .github/workflows/ci.yml | 8 +- .release-please-manifest.json | 2 +- .stats.yml | 8 +- CHANGELOG.md | 24 + api.md | 9 +- pyproject.toml | 2 +- src/openai/_version.py | 2 +- src/openai/resources/realtime/realtime.py | 34 +- src/openai/resources/responses/responses.py | 34 +- src/openai/resources/videos.py | 455 +++++++++++++++++- src/openai/types/__init__.py | 11 +- .../types/image_input_reference_param.py | 14 + .../types/responses/response_input_file.py | 6 - .../responses/response_input_file_content.py | 6 - .../response_input_file_content_param.py | 6 - .../responses/response_input_file_param.py | 6 - .../types/video_create_character_params.py | 17 + .../types/video_create_character_response.py | 18 + src/openai/types/video_create_params.py | 13 +- src/openai/types/video_edit_params.py | 28 ++ src/openai/types/video_extend_params.py | 35 ++ .../types/video_get_character_response.py | 18 + .../types/websocket_connection_options.py | 12 +- .../audio/test_transcriptions.py | 32 +- .../api_resources/audio/test_translations.py | 16 +- tests/api_resources/containers/test_files.py | 4 +- tests/api_resources/skills/test_versions.py | 4 +- tests/api_resources/test_files.py | 16 +- tests/api_resources/test_images.py | 56 +-- tests/api_resources/test_skills.py | 4 +- tests/api_resources/test_videos.py | 292 ++++++++++- tests/api_resources/uploads/test_parts.py | 16 +- tests/test_websocket_connection_options.py | 20 + 33 files changed, 1064 insertions(+), 164 deletions(-) create mode 100644 src/openai/types/image_input_reference_param.py create mode 100644 src/openai/types/video_create_character_params.py create mode 100644 src/openai/types/video_create_character_response.py create mode 100644 src/openai/types/video_edit_params.py create mode 100644 src/openai/types/video_extend_params.py create mode 100644 src/openai/types/video_get_character_response.py create mode 100644 tests/test_websocket_connection_options.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d087636a64..9c28de3543 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -61,14 +61,18 @@ jobs: run: rye build - name: Get GitHub OIDC Token - if: github.repository == 'stainless-sdks/openai-python' + if: |- + github.repository == 'stainless-sdks/openai-python' && + !startsWith(github.ref, 'refs/heads/stl/') id: github-oidc uses: actions/github-script@v8 with: script: core.setOutput('github_token', await core.getIDToken()); - name: Upload tarball - if: github.repository == 'stainless-sdks/openai-python' + if: |- + github.repository == 'stainless-sdks/openai-python' && + !startsWith(github.ref, 'refs/heads/stl/') env: URL: https://pkg.stainless.com/s AUTH: ${{ steps.github-oidc.outputs.github_token }} diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 1441304df6..4bdf489489 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.26.0" + ".": "2.27.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index bd550123f1..60deb7e24e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 148 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-9c802d45a9bf2a896b5fd22ac22bba185e8a145bd40ed242df9bb87a05e954eb.yml -openapi_spec_hash: 97984ed69285e660b7d5c810c69ed449 -config_hash: 8240b8a7a7fc145a45b93bda435612d6 +configured_endpoints: 152 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-3e207c26eea3b15837c78ef2fe0e1c68937708fd0763971ce749c0bdb7db6376.yml +openapi_spec_hash: 626982004d5a594a822fa7883422efb4 +config_hash: 0dda4b3af379312c9c55467a5e1e1ec0 diff --git a/CHANGELOG.md b/CHANGELOG.md index c8508a0b1d..c750be23c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,29 @@ # Changelog +## 2.27.0 (2026-03-13) + +Full Changelog: [v2.26.0...v2.27.0](https://github.com/openai/openai-python/compare/v2.26.0...v2.27.0) + +### Features + +* **api:** api update ([60ab24a](https://github.com/openai/openai-python/commit/60ab24ae722a7fa280eb4b2273da4ded1f930231)) +* **api:** manual updates ([b244b09](https://github.com/openai/openai-python/commit/b244b0946045aaa0dbfa8c0ce5164b64e1156834)) +* **api:** manual updates ([d806635](https://github.com/openai/openai-python/commit/d806635081a736cc81344bf1e62b57956a88d093)) +* **api:** sora api improvements: character api, video extensions/edits, higher resolution exports. ([58b70d3](https://github.com/openai/openai-python/commit/58b70d304a4b2cf70eae4db4b448d439fc8b8ba3)) + + +### Bug Fixes + +* **api:** repair merged videos resource ([742d8ee](https://github.com/openai/openai-python/commit/742d8ee1f969ee1bbb39ba9d799dcd5c480d8ddb)) + + +### Chores + +* **internal:** codegen related update ([4e6498e](https://github.com/openai/openai-python/commit/4e6498e2d222dd35d76bb397ba976ff53c852e12)) +* **internal:** codegen related update ([93af129](https://github.com/openai/openai-python/commit/93af129e8919de6d3aee19329c8bdef0532bd20a)) +* match http protocol with ws protocol instead of wss ([026f9de](https://github.com/openai/openai-python/commit/026f9de35d2aa74f35c91261eb5ea43d4ab1b8ba)) +* use proper capitalization for WebSockets ([a2f9b07](https://github.com/openai/openai-python/commit/a2f9b0722597627e8d01aa05c27a52015072726b)) + ## 2.26.0 (2026-03-05) Full Changelog: [v2.25.0...v2.26.0](https://github.com/openai/openai-python/compare/v2.25.0...v2.26.0) diff --git a/api.md b/api.md index a7981f7185..852df5bb8a 100644 --- a/api.md +++ b/api.md @@ -859,12 +859,15 @@ Types: ```python from openai.types import ( + ImageInputReferenceParam, Video, VideoCreateError, VideoModel, VideoSeconds, VideoSize, VideoDeleteResponse, + VideoCreateCharacterResponse, + VideoGetCharacterResponse, ) ``` @@ -874,7 +877,11 @@ Methods: - client.videos.retrieve(video_id) -> Video - client.videos.list(\*\*params) -> SyncConversationCursorPage[Video] - client.videos.delete(video_id) -> VideoDeleteResponse +- client.videos.create_character(\*\*params) -> VideoCreateCharacterResponse - client.videos.download_content(video_id, \*\*params) -> HttpxBinaryResponseContent +- client.videos.edit(\*\*params) -> Video +- client.videos.extend(\*\*params) -> Video +- client.videos.get_character(character_id) -> VideoGetCharacterResponse - client.videos.remix(video_id, \*\*params) -> Video - client.videos.create_and_poll(\*args) -> Video - +- client.videos.poll(\*args) -> Video diff --git a/pyproject.toml b/pyproject.toml index 41738c8c5e..1419825193 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.26.0" +version = "2.27.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 2feccec170..755c8a9f5c 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__ = "2.26.0" # x-release-please-version +__version__ = "2.27.0" # x-release-please-version diff --git a/src/openai/resources/realtime/realtime.py b/src/openai/resources/realtime/realtime.py index 44f14cd3aa..73a87fc2e7 100644 --- a/src/openai/resources/realtime/realtime.py +++ b/src/openai/resources/realtime/realtime.py @@ -41,7 +41,7 @@ AsyncClientSecretsWithStreamingResponse, ) from ...types.realtime import session_update_event_param -from ...types.websocket_connection_options import WebsocketConnectionOptions +from ...types.websocket_connection_options import WebSocketConnectionOptions from ...types.realtime.realtime_client_event import RealtimeClientEvent from ...types.realtime.realtime_server_event import RealtimeServerEvent from ...types.realtime.conversation_item_param import ConversationItemParam @@ -49,8 +49,8 @@ from ...types.realtime.realtime_response_create_params_param import RealtimeResponseCreateParamsParam if TYPE_CHECKING: - from websockets.sync.client import ClientConnection as WebsocketConnection - from websockets.asyncio.client import ClientConnection as AsyncWebsocketConnection + from websockets.sync.client import ClientConnection as WebSocketConnection + from websockets.asyncio.client import ClientConnection as AsyncWebSocketConnection from ..._client import OpenAI, AsyncOpenAI @@ -96,7 +96,7 @@ def connect( model: str | Omit = omit, extra_query: Query = {}, extra_headers: Headers = {}, - websocket_connection_options: WebsocketConnectionOptions = {}, + websocket_connection_options: WebSocketConnectionOptions = {}, ) -> RealtimeConnectionManager: """ The Realtime API enables you to build low-latency, multi-modal conversational experiences. It currently supports text and audio as both input and output, as well as function calling. @@ -156,7 +156,7 @@ def connect( model: str | Omit = omit, extra_query: Query = {}, extra_headers: Headers = {}, - websocket_connection_options: WebsocketConnectionOptions = {}, + websocket_connection_options: WebSocketConnectionOptions = {}, ) -> AsyncRealtimeConnectionManager: """ The Realtime API enables you to build low-latency, multi-modal conversational experiences. It currently supports text and audio as both input and output, as well as function calling. @@ -240,9 +240,9 @@ class AsyncRealtimeConnection: conversation: AsyncRealtimeConversationResource output_audio_buffer: AsyncRealtimeOutputAudioBufferResource - _connection: AsyncWebsocketConnection + _connection: AsyncWebSocketConnection - def __init__(self, connection: AsyncWebsocketConnection) -> None: + def __init__(self, connection: AsyncWebSocketConnection) -> None: self._connection = connection self.session = AsyncRealtimeSessionResource(self) @@ -281,7 +281,7 @@ async def recv_bytes(self) -> bytes: then you can call `.parse_event(data)`. """ message = await self._connection.recv(decode=False) - log.debug(f"Received websocket message: %s", message) + log.debug(f"Received WebSocket message: %s", message) return message async def send(self, event: RealtimeClientEvent | RealtimeClientEventParam) -> None: @@ -334,7 +334,7 @@ def __init__( model: str | Omit = omit, extra_query: Query, extra_headers: Headers, - websocket_connection_options: WebsocketConnectionOptions, + websocket_connection_options: WebSocketConnectionOptions, ) -> None: self.__client = client self.__call_id = call_id @@ -408,7 +408,9 @@ def _prepare_url(self) -> httpx.URL: if self.__client.websocket_base_url is not None: base_url = httpx.URL(self.__client.websocket_base_url) else: - base_url = self.__client._base_url.copy_with(scheme="wss") + scheme = self.__client._base_url.scheme + ws_scheme = "ws" if scheme == "http" else "wss" + base_url = self.__client._base_url.copy_with(scheme=ws_scheme) merge_raw_path = base_url.raw_path.rstrip(b"/") + b"/realtime" return base_url.copy_with(raw_path=merge_raw_path) @@ -429,9 +431,9 @@ class RealtimeConnection: conversation: RealtimeConversationResource output_audio_buffer: RealtimeOutputAudioBufferResource - _connection: WebsocketConnection + _connection: WebSocketConnection - def __init__(self, connection: WebsocketConnection) -> None: + def __init__(self, connection: WebSocketConnection) -> None: self._connection = connection self.session = RealtimeSessionResource(self) @@ -470,7 +472,7 @@ def recv_bytes(self) -> bytes: then you can call `.parse_event(data)`. """ message = self._connection.recv(decode=False) - log.debug(f"Received websocket message: %s", message) + log.debug(f"Received WebSocket message: %s", message) return message def send(self, event: RealtimeClientEvent | RealtimeClientEventParam) -> None: @@ -523,7 +525,7 @@ def __init__( model: str | Omit = omit, extra_query: Query, extra_headers: Headers, - websocket_connection_options: WebsocketConnectionOptions, + websocket_connection_options: WebSocketConnectionOptions, ) -> None: self.__client = client self.__call_id = call_id @@ -597,7 +599,9 @@ def _prepare_url(self) -> httpx.URL: if self.__client.websocket_base_url is not None: base_url = httpx.URL(self.__client.websocket_base_url) else: - base_url = self.__client._base_url.copy_with(scheme="wss") + scheme = self.__client._base_url.scheme + ws_scheme = "ws" if scheme == "http" else "wss" + base_url = self.__client._base_url.copy_with(scheme=ws_scheme) merge_raw_path = base_url.raw_path.rstrip(b"/") + b"/realtime" return base_url.copy_with(raw_path=merge_raw_path) diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 5d34909fd1..12f1e1aea1 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -58,7 +58,7 @@ from ...types.responses.parsed_response import ParsedResponse from ...lib.streaming.responses._responses import ResponseStreamManager, AsyncResponseStreamManager from ...types.responses.compacted_response import CompactedResponse -from ...types.websocket_connection_options import WebsocketConnectionOptions +from ...types.websocket_connection_options import WebSocketConnectionOptions from ...types.responses.response_includable import ResponseIncludable from ...types.shared_params.responses_model import ResponsesModel from ...types.responses.response_input_param import ResponseInputParam @@ -71,8 +71,8 @@ from ...types.responses.responses_client_event_param import ResponsesClientEventParam if TYPE_CHECKING: - from websockets.sync.client import ClientConnection as WebsocketConnection - from websockets.asyncio.client import ClientConnection as AsyncWebsocketConnection + from websockets.sync.client import ClientConnection as WebSocketConnection + from websockets.asyncio.client import ClientConnection as AsyncWebSocketConnection from ..._client import OpenAI, AsyncOpenAI @@ -1730,7 +1730,7 @@ def connect( self, extra_query: Query = {}, extra_headers: Headers = {}, - websocket_connection_options: WebsocketConnectionOptions = {}, + websocket_connection_options: WebSocketConnectionOptions = {}, ) -> ResponsesConnectionManager: """Connect to a persistent Responses API WebSocket. @@ -3397,7 +3397,7 @@ def connect( self, extra_query: Query = {}, extra_headers: Headers = {}, - websocket_connection_options: WebsocketConnectionOptions = {}, + websocket_connection_options: WebSocketConnectionOptions = {}, ) -> AsyncResponsesConnectionManager: """Connect to a persistent Responses API WebSocket. @@ -3576,9 +3576,9 @@ class AsyncResponsesConnection: response: AsyncResponsesResponseResource - _connection: AsyncWebsocketConnection + _connection: AsyncWebSocketConnection - def __init__(self, connection: AsyncWebsocketConnection) -> None: + def __init__(self, connection: AsyncWebSocketConnection) -> None: self._connection = connection self.response = AsyncResponsesResponseResource(self) @@ -3613,7 +3613,7 @@ async def recv_bytes(self) -> bytes: then you can call `.parse_event(data)`. """ message = await self._connection.recv(decode=False) - log.debug(f"Received websocket message: %s", message) + log.debug(f"Received WebSocket message: %s", message) return message async def send(self, event: ResponsesClientEvent | ResponsesClientEventParam) -> None: @@ -3665,7 +3665,7 @@ def __init__( client: AsyncOpenAI, extra_query: Query, extra_headers: Headers, - websocket_connection_options: WebsocketConnectionOptions, + websocket_connection_options: WebSocketConnectionOptions, ) -> None: self.__client = client self.__connection: AsyncResponsesConnection | None = None @@ -3723,7 +3723,9 @@ def _prepare_url(self) -> httpx.URL: if self.__client.websocket_base_url is not None: base_url = httpx.URL(self.__client.websocket_base_url) else: - base_url = self.__client._base_url.copy_with(scheme="wss") + scheme = self.__client._base_url.scheme + ws_scheme = "ws" if scheme == "http" else "wss" + base_url = self.__client._base_url.copy_with(scheme=ws_scheme) merge_raw_path = base_url.raw_path.rstrip(b"/") + b"/responses" return base_url.copy_with(raw_path=merge_raw_path) @@ -3740,9 +3742,9 @@ class ResponsesConnection: response: ResponsesResponseResource - _connection: WebsocketConnection + _connection: WebSocketConnection - def __init__(self, connection: WebsocketConnection) -> None: + def __init__(self, connection: WebSocketConnection) -> None: self._connection = connection self.response = ResponsesResponseResource(self) @@ -3777,7 +3779,7 @@ def recv_bytes(self) -> bytes: then you can call `.parse_event(data)`. """ message = self._connection.recv(decode=False) - log.debug(f"Received websocket message: %s", message) + log.debug(f"Received WebSocket message: %s", message) return message def send(self, event: ResponsesClientEvent | ResponsesClientEventParam) -> None: @@ -3829,7 +3831,7 @@ def __init__( client: OpenAI, extra_query: Query, extra_headers: Headers, - websocket_connection_options: WebsocketConnectionOptions, + websocket_connection_options: WebSocketConnectionOptions, ) -> None: self.__client = client self.__connection: ResponsesConnection | None = None @@ -3887,7 +3889,9 @@ def _prepare_url(self) -> httpx.URL: if self.__client.websocket_base_url is not None: base_url = httpx.URL(self.__client.websocket_base_url) else: - base_url = self.__client._base_url.copy_with(scheme="wss") + scheme = self.__client._base_url.scheme + ws_scheme = "ws" if scheme == "http" else "wss" + base_url = self.__client._base_url.copy_with(scheme=ws_scheme) merge_raw_path = base_url.raw_path.rstrip(b"/") + b"/responses" return base_url.copy_with(raw_path=merge_raw_path) diff --git a/src/openai/resources/videos.py b/src/openai/resources/videos.py index 51df6da4d3..f387f55824 100644 --- a/src/openai/resources/videos.py +++ b/src/openai/resources/videos.py @@ -11,9 +11,12 @@ from ..types import ( VideoSize, VideoSeconds, + video_edit_params, video_list_params, video_remix_params, video_create_params, + video_extend_params, + video_create_character_params, video_download_content_params, ) from .._types import Body, Omit, Query, Headers, NotGiven, FileTypes, omit, not_given @@ -36,6 +39,8 @@ from ..types.video_seconds import VideoSeconds from ..types.video_model_param import VideoModelParam from ..types.video_delete_response import VideoDeleteResponse +from ..types.video_get_character_response import VideoGetCharacterResponse +from ..types.video_create_character_response import VideoCreateCharacterResponse __all__ = ["Videos", "AsyncVideos"] @@ -64,7 +69,7 @@ def create( self, *, prompt: str, - input_reference: FileTypes | Omit = omit, + input_reference: video_create_params.InputReference | Omit = omit, model: VideoModelParam | Omit = omit, seconds: VideoSeconds | Omit = omit, size: VideoSize | Omit = omit, @@ -81,7 +86,7 @@ def create( Args: prompt: Text prompt that describes the video to generate. - input_reference: Optional multipart reference asset that guides generation. + input_reference: Optional reference asset upload or reference object that guides generation. model: The video generation model to use (allowed values: sora-2, sora-2-pro). Defaults to `sora-2`. @@ -109,11 +114,10 @@ def create( } ) files = extract_files(cast(Mapping[str, object], body), paths=[["input_reference"]]) - if files: - # It should be noted that the actual Content-Type header that will be - # sent to the server will contain a `boundary` parameter, e.g. - # multipart/form-data; boundary=---abc-- - extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} + # It should be noted that the actual Content-Type header that will be + # sent to the server will contain a `boundary` parameter, e.g. + # multipart/form-data; boundary=---abc-- + extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} return self._post( "/videos", body=maybe_transform(body, video_create_params.VideoCreateParams), @@ -128,7 +132,7 @@ def create_and_poll( self, *, prompt: str, - input_reference: FileTypes | Omit = omit, + input_reference: video_create_params.InputReference | Omit = omit, model: VideoModelParam | Omit = omit, seconds: VideoSeconds | Omit = omit, size: VideoSize | Omit = omit, @@ -315,6 +319,55 @@ def delete( cast_to=VideoDeleteResponse, ) + def create_character( + self, + *, + name: str, + video: FileTypes, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> VideoCreateCharacterResponse: + """ + Create a character from an uploaded video. + + Args: + name: Display name for this API character. + + video: Video file used to create a character. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + body = deepcopy_minimal( + { + "name": name, + "video": video, + } + ) + files = extract_files(cast(Mapping[str, object], body), paths=[["video"]]) + # It should be noted that the actual Content-Type header that will be + # sent to the server will contain a `boundary` parameter, e.g. + # multipart/form-data; boundary=---abc-- + extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} + return self._post( + "/videos/characters", + body=maybe_transform(body, video_create_character_params.VideoCreateCharacterParams), + files=files, + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=VideoCreateCharacterResponse, + ) + def download_content( self, video_id: str, @@ -358,6 +411,143 @@ def download_content( cast_to=_legacy_response.HttpxBinaryResponseContent, ) + def edit( + self, + *, + prompt: str, + video: video_edit_params.Video, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Video: + """ + Create a new video generation job by editing a source video or existing + generated video. + + Args: + prompt: Text prompt that describes how to edit the source video. + + video: Reference to the completed video to edit. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + body = deepcopy_minimal( + { + "prompt": prompt, + "video": video, + } + ) + files = extract_files(cast(Mapping[str, object], body), paths=[["video"]]) + # It should be noted that the actual Content-Type header that will be + # sent to the server will contain a `boundary` parameter, e.g. + # multipart/form-data; boundary=---abc-- + extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} + return self._post( + "/videos/edits", + body=maybe_transform(body, video_edit_params.VideoEditParams), + files=files, + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Video, + ) + + def extend( + self, + *, + prompt: str, + seconds: VideoSeconds, + video: video_extend_params.Video, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Video: + """ + Create an extension of a completed video. + + Args: + prompt: Updated text prompt that directs the extension generation. + + seconds: Length of the newly generated extension segment in seconds (allowed values: 4, + 8, 12, 16, 20). + + video: Reference to the completed video to extend. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + body = deepcopy_minimal( + { + "prompt": prompt, + "seconds": seconds, + "video": video, + } + ) + files = extract_files(cast(Mapping[str, object], body), paths=[["video"]]) + # It should be noted that the actual Content-Type header that will be + # sent to the server will contain a `boundary` parameter, e.g. + # multipart/form-data; boundary=---abc-- + extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} + return self._post( + "/videos/extensions", + body=maybe_transform(body, video_extend_params.VideoExtendParams), + files=files, + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Video, + ) + + def get_character( + self, + character_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> VideoGetCharacterResponse: + """ + Fetch a character. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not character_id: + raise ValueError(f"Expected a non-empty value for `character_id` but received {character_id!r}") + return self._get( + f"/videos/characters/{character_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=VideoGetCharacterResponse, + ) + def remix( self, video_id: str, @@ -420,7 +610,7 @@ async def create( self, *, prompt: str, - input_reference: FileTypes | Omit = omit, + input_reference: video_create_params.InputReference | Omit = omit, model: VideoModelParam | Omit = omit, seconds: VideoSeconds | Omit = omit, size: VideoSize | Omit = omit, @@ -437,7 +627,7 @@ async def create( Args: prompt: Text prompt that describes the video to generate. - input_reference: Optional multipart reference asset that guides generation. + input_reference: Optional reference asset upload or reference object that guides generation. model: The video generation model to use (allowed values: sora-2, sora-2-pro). Defaults to `sora-2`. @@ -465,11 +655,10 @@ async def create( } ) files = extract_files(cast(Mapping[str, object], body), paths=[["input_reference"]]) - if files: - # It should be noted that the actual Content-Type header that will be - # sent to the server will contain a `boundary` parameter, e.g. - # multipart/form-data; boundary=---abc-- - extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} + # It should be noted that the actual Content-Type header that will be + # sent to the server will contain a `boundary` parameter, e.g. + # multipart/form-data; boundary=---abc-- + extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} return await self._post( "/videos", body=await async_maybe_transform(body, video_create_params.VideoCreateParams), @@ -484,7 +673,7 @@ async def create_and_poll( self, *, prompt: str, - input_reference: FileTypes | Omit = omit, + input_reference: video_create_params.InputReference | Omit = omit, model: VideoModelParam | Omit = omit, seconds: VideoSeconds | Omit = omit, size: VideoSize | Omit = omit, @@ -671,6 +860,55 @@ async def delete( cast_to=VideoDeleteResponse, ) + async def create_character( + self, + *, + name: str, + video: FileTypes, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> VideoCreateCharacterResponse: + """ + Create a character from an uploaded video. + + Args: + name: Display name for this API character. + + video: Video file used to create a character. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + body = deepcopy_minimal( + { + "name": name, + "video": video, + } + ) + files = extract_files(cast(Mapping[str, object], body), paths=[["video"]]) + # It should be noted that the actual Content-Type header that will be + # sent to the server will contain a `boundary` parameter, e.g. + # multipart/form-data; boundary=---abc-- + extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} + return await self._post( + "/videos/characters", + body=await async_maybe_transform(body, video_create_character_params.VideoCreateCharacterParams), + files=files, + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=VideoCreateCharacterResponse, + ) + async def download_content( self, video_id: str, @@ -716,6 +954,143 @@ async def download_content( cast_to=_legacy_response.HttpxBinaryResponseContent, ) + async def edit( + self, + *, + prompt: str, + video: video_edit_params.Video, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Video: + """ + Create a new video generation job by editing a source video or existing + generated video. + + Args: + prompt: Text prompt that describes how to edit the source video. + + video: Reference to the completed video to edit. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + body = deepcopy_minimal( + { + "prompt": prompt, + "video": video, + } + ) + files = extract_files(cast(Mapping[str, object], body), paths=[["video"]]) + # It should be noted that the actual Content-Type header that will be + # sent to the server will contain a `boundary` parameter, e.g. + # multipart/form-data; boundary=---abc-- + extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} + return await self._post( + "/videos/edits", + body=await async_maybe_transform(body, video_edit_params.VideoEditParams), + files=files, + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Video, + ) + + async def extend( + self, + *, + prompt: str, + seconds: VideoSeconds, + video: video_extend_params.Video, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Video: + """ + Create an extension of a completed video. + + Args: + prompt: Updated text prompt that directs the extension generation. + + seconds: Length of the newly generated extension segment in seconds (allowed values: 4, + 8, 12, 16, 20). + + video: Reference to the completed video to extend. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + body = deepcopy_minimal( + { + "prompt": prompt, + "seconds": seconds, + "video": video, + } + ) + files = extract_files(cast(Mapping[str, object], body), paths=[["video"]]) + # It should be noted that the actual Content-Type header that will be + # sent to the server will contain a `boundary` parameter, e.g. + # multipart/form-data; boundary=---abc-- + extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} + return await self._post( + "/videos/extensions", + body=await async_maybe_transform(body, video_extend_params.VideoExtendParams), + files=files, + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Video, + ) + + async def get_character( + self, + character_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> VideoGetCharacterResponse: + """ + Fetch a character. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not character_id: + raise ValueError(f"Expected a non-empty value for `character_id` but received {character_id!r}") + return await self._get( + f"/videos/characters/{character_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=VideoGetCharacterResponse, + ) + async def remix( self, video_id: str, @@ -770,9 +1145,21 @@ def __init__(self, videos: Videos) -> None: self.delete = _legacy_response.to_raw_response_wrapper( videos.delete, ) + self.create_character = _legacy_response.to_raw_response_wrapper( + videos.create_character, + ) self.download_content = _legacy_response.to_raw_response_wrapper( videos.download_content, ) + self.edit = _legacy_response.to_raw_response_wrapper( + videos.edit, + ) + self.extend = _legacy_response.to_raw_response_wrapper( + videos.extend, + ) + self.get_character = _legacy_response.to_raw_response_wrapper( + videos.get_character, + ) self.remix = _legacy_response.to_raw_response_wrapper( videos.remix, ) @@ -794,9 +1181,21 @@ def __init__(self, videos: AsyncVideos) -> None: self.delete = _legacy_response.async_to_raw_response_wrapper( videos.delete, ) + self.create_character = _legacy_response.async_to_raw_response_wrapper( + videos.create_character, + ) self.download_content = _legacy_response.async_to_raw_response_wrapper( videos.download_content, ) + self.edit = _legacy_response.async_to_raw_response_wrapper( + videos.edit, + ) + self.extend = _legacy_response.async_to_raw_response_wrapper( + videos.extend, + ) + self.get_character = _legacy_response.async_to_raw_response_wrapper( + videos.get_character, + ) self.remix = _legacy_response.async_to_raw_response_wrapper( videos.remix, ) @@ -818,10 +1217,22 @@ def __init__(self, videos: Videos) -> None: self.delete = to_streamed_response_wrapper( videos.delete, ) + self.create_character = to_streamed_response_wrapper( + videos.create_character, + ) self.download_content = to_custom_streamed_response_wrapper( videos.download_content, StreamedBinaryAPIResponse, ) + self.edit = to_streamed_response_wrapper( + videos.edit, + ) + self.extend = to_streamed_response_wrapper( + videos.extend, + ) + self.get_character = to_streamed_response_wrapper( + videos.get_character, + ) self.remix = to_streamed_response_wrapper( videos.remix, ) @@ -843,10 +1254,22 @@ def __init__(self, videos: AsyncVideos) -> None: self.delete = async_to_streamed_response_wrapper( videos.delete, ) + self.create_character = async_to_streamed_response_wrapper( + videos.create_character, + ) self.download_content = async_to_custom_streamed_response_wrapper( videos.download_content, AsyncStreamedBinaryAPIResponse, ) + self.edit = async_to_streamed_response_wrapper( + videos.edit, + ) + self.extend = async_to_streamed_response_wrapper( + videos.extend, + ) + self.get_character = async_to_streamed_response_wrapper( + videos.get_character, + ) self.remix = async_to_streamed_response_wrapper( videos.remix, ) diff --git a/src/openai/types/__init__.py b/src/openai/types/__init__.py index 9190bc146c..d8dbea71ad 100644 --- a/src/openai/types/__init__.py +++ b/src/openai/types/__init__.py @@ -56,6 +56,7 @@ from .completion_choice import CompletionChoice as CompletionChoice from .image_edit_params import ImageEditParams as ImageEditParams from .skill_list_params import SkillListParams as SkillListParams +from .video_edit_params import VideoEditParams as VideoEditParams from .video_list_params import VideoListParams as VideoListParams from .video_model_param import VideoModelParam as VideoModelParam from .eval_create_params import EvalCreateParams as EvalCreateParams @@ -68,6 +69,7 @@ from .skill_create_params import SkillCreateParams as SkillCreateParams from .skill_update_params import SkillUpdateParams as SkillUpdateParams from .video_create_params import VideoCreateParams as VideoCreateParams +from .video_extend_params import VideoExtendParams as VideoExtendParams from .batch_request_counts import BatchRequestCounts as BatchRequestCounts from .eval_create_response import EvalCreateResponse as EvalCreateResponse from .eval_delete_response import EvalDeleteResponse as EvalDeleteResponse @@ -98,16 +100,23 @@ from .vector_store_search_params import VectorStoreSearchParams as VectorStoreSearchParams from .vector_store_update_params import VectorStoreUpdateParams as VectorStoreUpdateParams from .container_retrieve_response import ContainerRetrieveResponse as ContainerRetrieveResponse +from .image_input_reference_param import ImageInputReferenceParam as ImageInputReferenceParam from .moderation_text_input_param import ModerationTextInputParam as ModerationTextInputParam from .file_chunking_strategy_param import FileChunkingStrategyParam as FileChunkingStrategyParam from .vector_store_search_response import VectorStoreSearchResponse as VectorStoreSearchResponse -from .websocket_connection_options import WebsocketConnectionOptions as WebsocketConnectionOptions +from .video_get_character_response import VideoGetCharacterResponse as VideoGetCharacterResponse +from .websocket_connection_options import ( + WebSocketConnectionOptions as WebSocketConnectionOptions, + WebsocketConnectionOptions as WebsocketConnectionOptions, +) from .image_create_variation_params import ImageCreateVariationParams as ImageCreateVariationParams from .image_gen_partial_image_event import ImageGenPartialImageEvent as ImageGenPartialImageEvent from .static_file_chunking_strategy import StaticFileChunkingStrategy as StaticFileChunkingStrategy +from .video_create_character_params import VideoCreateCharacterParams as VideoCreateCharacterParams from .video_download_content_params import VideoDownloadContentParams as VideoDownloadContentParams from .eval_custom_data_source_config import EvalCustomDataSourceConfig as EvalCustomDataSourceConfig from .image_edit_partial_image_event import ImageEditPartialImageEvent as ImageEditPartialImageEvent +from .video_create_character_response import VideoCreateCharacterResponse as VideoCreateCharacterResponse from .moderation_image_url_input_param import ModerationImageURLInputParam as ModerationImageURLInputParam from .auto_file_chunking_strategy_param import AutoFileChunkingStrategyParam as AutoFileChunkingStrategyParam from .moderation_multi_modal_input_param import ModerationMultiModalInputParam as ModerationMultiModalInputParam diff --git a/src/openai/types/image_input_reference_param.py b/src/openai/types/image_input_reference_param.py new file mode 100644 index 0000000000..1065632910 --- /dev/null +++ b/src/openai/types/image_input_reference_param.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["ImageInputReferenceParam"] + + +class ImageInputReferenceParam(TypedDict, total=False): + file_id: str + + image_url: str + """A fully qualified URL or base64-encoded data URL.""" diff --git a/src/openai/types/responses/response_input_file.py b/src/openai/types/responses/response_input_file.py index 97cc176f35..3e5fb70c5f 100644 --- a/src/openai/types/responses/response_input_file.py +++ b/src/openai/types/responses/response_input_file.py @@ -14,12 +14,6 @@ class ResponseInputFile(BaseModel): type: Literal["input_file"] """The type of the input item. Always `input_file`.""" - detail: Optional[Literal["low", "high"]] = None - """The detail level of the file to be sent to the model. - - One of `high` or `low`. Defaults to `high`. - """ - file_data: Optional[str] = None """The content of the file to be sent to the model.""" diff --git a/src/openai/types/responses/response_input_file_content.py b/src/openai/types/responses/response_input_file_content.py index 7b1c76bff7..f0dfef55d0 100644 --- a/src/openai/types/responses/response_input_file_content.py +++ b/src/openai/types/responses/response_input_file_content.py @@ -14,12 +14,6 @@ class ResponseInputFileContent(BaseModel): type: Literal["input_file"] """The type of the input item. Always `input_file`.""" - detail: Optional[Literal["high", "low"]] = None - """The detail level of the file to be sent to the model. - - One of `high` or `low`. Defaults to `high`. - """ - file_data: Optional[str] = None """The base64-encoded data of the file to be sent to the model.""" diff --git a/src/openai/types/responses/response_input_file_content_param.py b/src/openai/types/responses/response_input_file_content_param.py index 73e8acd27b..376f6c7a45 100644 --- a/src/openai/types/responses/response_input_file_content_param.py +++ b/src/openai/types/responses/response_input_file_content_param.py @@ -14,12 +14,6 @@ class ResponseInputFileContentParam(TypedDict, total=False): type: Required[Literal["input_file"]] """The type of the input item. Always `input_file`.""" - detail: Literal["high", "low"] - """The detail level of the file to be sent to the model. - - One of `high` or `low`. Defaults to `high`. - """ - file_data: Optional[str] """The base64-encoded data of the file to be sent to the model.""" diff --git a/src/openai/types/responses/response_input_file_param.py b/src/openai/types/responses/response_input_file_param.py index 25eec2fe01..8b5da20245 100644 --- a/src/openai/types/responses/response_input_file_param.py +++ b/src/openai/types/responses/response_input_file_param.py @@ -14,12 +14,6 @@ class ResponseInputFileParam(TypedDict, total=False): type: Required[Literal["input_file"]] """The type of the input item. Always `input_file`.""" - detail: Literal["low", "high"] - """The detail level of the file to be sent to the model. - - One of `high` or `low`. Defaults to `high`. - """ - file_data: str """The content of the file to be sent to the model.""" diff --git a/src/openai/types/video_create_character_params.py b/src/openai/types/video_create_character_params.py new file mode 100644 index 0000000000..ef671e598f --- /dev/null +++ b/src/openai/types/video_create_character_params.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +from .._types import FileTypes + +__all__ = ["VideoCreateCharacterParams"] + + +class VideoCreateCharacterParams(TypedDict, total=False): + name: Required[str] + """Display name for this API character.""" + + video: Required[FileTypes] + """Video file used to create a character.""" diff --git a/src/openai/types/video_create_character_response.py b/src/openai/types/video_create_character_response.py new file mode 100644 index 0000000000..e3a65a0200 --- /dev/null +++ b/src/openai/types/video_create_character_response.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from .._models import BaseModel + +__all__ = ["VideoCreateCharacterResponse"] + + +class VideoCreateCharacterResponse(BaseModel): + id: Optional[str] = None + """Identifier for the character creation cameo.""" + + created_at: int + """Unix timestamp (in seconds) when the character was created.""" + + name: Optional[str] = None + """Display name for the character.""" diff --git a/src/openai/types/video_create_params.py b/src/openai/types/video_create_params.py index 282b1db429..641ac7db45 100644 --- a/src/openai/types/video_create_params.py +++ b/src/openai/types/video_create_params.py @@ -2,22 +2,24 @@ from __future__ import annotations -from typing_extensions import Required, TypedDict +from typing import Union +from typing_extensions import Required, TypeAlias, TypedDict from .._types import FileTypes from .video_size import VideoSize from .video_seconds import VideoSeconds from .video_model_param import VideoModelParam +from .image_input_reference_param import ImageInputReferenceParam -__all__ = ["VideoCreateParams"] +__all__ = ["VideoCreateParams", "InputReference"] class VideoCreateParams(TypedDict, total=False): prompt: Required[str] """Text prompt that describes the video to generate.""" - input_reference: FileTypes - """Optional multipart reference asset that guides generation.""" + input_reference: InputReference + """Optional reference asset upload or reference object that guides generation.""" model: VideoModelParam """The video generation model to use (allowed values: sora-2, sora-2-pro). @@ -33,3 +35,6 @@ class VideoCreateParams(TypedDict, total=False): Output resolution formatted as width x height (allowed values: 720x1280, 1280x720, 1024x1792, 1792x1024). Defaults to 720x1280. """ + + +InputReference: TypeAlias = Union[FileTypes, ImageInputReferenceParam] diff --git a/src/openai/types/video_edit_params.py b/src/openai/types/video_edit_params.py new file mode 100644 index 0000000000..8d3b15fc6f --- /dev/null +++ b/src/openai/types/video_edit_params.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import Required, TypeAlias, TypedDict + +from .._types import FileTypes + +__all__ = ["VideoEditParams", "Video", "VideoVideoReferenceInputParam"] + + +class VideoEditParams(TypedDict, total=False): + prompt: Required[str] + """Text prompt that describes how to edit the source video.""" + + video: Required[Video] + """Reference to the completed video to edit.""" + + +class VideoVideoReferenceInputParam(TypedDict, total=False): + """Reference to the completed video.""" + + id: Required[str] + """The identifier of the completed video.""" + + +Video: TypeAlias = Union[FileTypes, VideoVideoReferenceInputParam] diff --git a/src/openai/types/video_extend_params.py b/src/openai/types/video_extend_params.py new file mode 100644 index 0000000000..65be4b5270 --- /dev/null +++ b/src/openai/types/video_extend_params.py @@ -0,0 +1,35 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import Required, TypeAlias, TypedDict + +from .._types import FileTypes +from .video_seconds import VideoSeconds + +__all__ = ["VideoExtendParams", "Video", "VideoVideoReferenceInputParam"] + + +class VideoExtendParams(TypedDict, total=False): + prompt: Required[str] + """Updated text prompt that directs the extension generation.""" + + seconds: Required[VideoSeconds] + """ + Length of the newly generated extension segment in seconds (allowed values: 4, + 8, 12, 16, 20). + """ + + video: Required[Video] + """Reference to the completed video to extend.""" + + +class VideoVideoReferenceInputParam(TypedDict, total=False): + """Reference to the completed video.""" + + id: Required[str] + """The identifier of the completed video.""" + + +Video: TypeAlias = Union[FileTypes, VideoVideoReferenceInputParam] diff --git a/src/openai/types/video_get_character_response.py b/src/openai/types/video_get_character_response.py new file mode 100644 index 0000000000..df6202ed03 --- /dev/null +++ b/src/openai/types/video_get_character_response.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from .._models import BaseModel + +__all__ = ["VideoGetCharacterResponse"] + + +class VideoGetCharacterResponse(BaseModel): + id: Optional[str] = None + """Identifier for the character creation cameo.""" + + created_at: int + """Unix timestamp (in seconds) when the character was created.""" + + name: Optional[str] = None + """Display name for the character.""" diff --git a/src/openai/types/websocket_connection_options.py b/src/openai/types/websocket_connection_options.py index 40fd24ab03..519e434124 100644 --- a/src/openai/types/websocket_connection_options.py +++ b/src/openai/types/websocket_connection_options.py @@ -3,15 +3,17 @@ from __future__ import annotations from typing import TYPE_CHECKING -from typing_extensions import Sequence, TypedDict +from typing_extensions import Sequence, TypeAlias, TypedDict + +__all__ = ["WebSocketConnectionOptions", "WebsocketConnectionOptions"] if TYPE_CHECKING: from websockets import Subprotocol from websockets.extensions import ClientExtensionFactory -class WebsocketConnectionOptions(TypedDict, total=False): - """Websocket connection options copied from `websockets`. +class WebSocketConnectionOptions(TypedDict, total=False): + """WebSocket connection options copied from `websockets`. For example: https://websockets.readthedocs.io/en/stable/reference/asyncio/client.html#websockets.asyncio.client.connect """ @@ -34,3 +36,7 @@ class WebsocketConnectionOptions(TypedDict, total=False): write_limit: int | tuple[int, int | None] """High-water mark of write buffer in bytes. It is passed to set_write_buffer_limits(). It defaults to 32 KiB. You may pass a (high, low) tuple to set the high-water and low-water marks.""" + + +# Backward compatibility for pre-rename imports. +WebsocketConnectionOptions: TypeAlias = WebSocketConnectionOptions diff --git a/tests/api_resources/audio/test_transcriptions.py b/tests/api_resources/audio/test_transcriptions.py index b5eaa4be1f..b4525937b4 100644 --- a/tests/api_resources/audio/test_transcriptions.py +++ b/tests/api_resources/audio/test_transcriptions.py @@ -20,7 +20,7 @@ class TestTranscriptions: @parametrize def test_method_create_overload_1(self, client: OpenAI) -> None: transcription = client.audio.transcriptions.create( - file=b"raw file contents", + file=b"Example data", model="gpt-4o-transcribe", ) assert_matches_type(TranscriptionCreateResponse, transcription, path=["response"]) @@ -28,7 +28,7 @@ def test_method_create_overload_1(self, client: OpenAI) -> None: @parametrize def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: transcription = client.audio.transcriptions.create( - file=b"raw file contents", + file=b"Example data", model="gpt-4o-transcribe", chunking_strategy="auto", include=["logprobs"], @@ -46,7 +46,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: @parametrize def test_raw_response_create_overload_1(self, client: OpenAI) -> None: response = client.audio.transcriptions.with_raw_response.create( - file=b"raw file contents", + file=b"Example data", model="gpt-4o-transcribe", ) @@ -58,7 +58,7 @@ def test_raw_response_create_overload_1(self, client: OpenAI) -> None: @parametrize def test_streaming_response_create_overload_1(self, client: OpenAI) -> None: with client.audio.transcriptions.with_streaming_response.create( - file=b"raw file contents", + file=b"Example data", model="gpt-4o-transcribe", ) as response: assert not response.is_closed @@ -72,7 +72,7 @@ def test_streaming_response_create_overload_1(self, client: OpenAI) -> None: @parametrize def test_method_create_overload_2(self, client: OpenAI) -> None: transcription_stream = client.audio.transcriptions.create( - file=b"raw file contents", + file=b"Example data", model="gpt-4o-transcribe", stream=True, ) @@ -81,7 +81,7 @@ def test_method_create_overload_2(self, client: OpenAI) -> None: @parametrize def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: transcription_stream = client.audio.transcriptions.create( - file=b"raw file contents", + file=b"Example data", model="gpt-4o-transcribe", stream=True, chunking_strategy="auto", @@ -99,7 +99,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: @parametrize def test_raw_response_create_overload_2(self, client: OpenAI) -> None: response = client.audio.transcriptions.with_raw_response.create( - file=b"raw file contents", + file=b"Example data", model="gpt-4o-transcribe", stream=True, ) @@ -111,7 +111,7 @@ def test_raw_response_create_overload_2(self, client: OpenAI) -> None: @parametrize def test_streaming_response_create_overload_2(self, client: OpenAI) -> None: with client.audio.transcriptions.with_streaming_response.create( - file=b"raw file contents", + file=b"Example data", model="gpt-4o-transcribe", stream=True, ) as response: @@ -132,7 +132,7 @@ class TestAsyncTranscriptions: @parametrize async def test_method_create_overload_1(self, async_client: AsyncOpenAI) -> None: transcription = await async_client.audio.transcriptions.create( - file=b"raw file contents", + file=b"Example data", model="gpt-4o-transcribe", ) assert_matches_type(TranscriptionCreateResponse, transcription, path=["response"]) @@ -140,7 +140,7 @@ async def test_method_create_overload_1(self, async_client: AsyncOpenAI) -> None @parametrize async def test_method_create_with_all_params_overload_1(self, async_client: AsyncOpenAI) -> None: transcription = await async_client.audio.transcriptions.create( - file=b"raw file contents", + file=b"Example data", model="gpt-4o-transcribe", chunking_strategy="auto", include=["logprobs"], @@ -158,7 +158,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn @parametrize async def test_raw_response_create_overload_1(self, async_client: AsyncOpenAI) -> None: response = await async_client.audio.transcriptions.with_raw_response.create( - file=b"raw file contents", + file=b"Example data", model="gpt-4o-transcribe", ) @@ -170,7 +170,7 @@ async def test_raw_response_create_overload_1(self, async_client: AsyncOpenAI) - @parametrize async def test_streaming_response_create_overload_1(self, async_client: AsyncOpenAI) -> None: async with async_client.audio.transcriptions.with_streaming_response.create( - file=b"raw file contents", + file=b"Example data", model="gpt-4o-transcribe", ) as response: assert not response.is_closed @@ -184,7 +184,7 @@ async def test_streaming_response_create_overload_1(self, async_client: AsyncOpe @parametrize async def test_method_create_overload_2(self, async_client: AsyncOpenAI) -> None: transcription_stream = await async_client.audio.transcriptions.create( - file=b"raw file contents", + file=b"Example data", model="gpt-4o-transcribe", stream=True, ) @@ -193,7 +193,7 @@ async def test_method_create_overload_2(self, async_client: AsyncOpenAI) -> None @parametrize async def test_method_create_with_all_params_overload_2(self, async_client: AsyncOpenAI) -> None: transcription_stream = await async_client.audio.transcriptions.create( - file=b"raw file contents", + file=b"Example data", model="gpt-4o-transcribe", stream=True, chunking_strategy="auto", @@ -211,7 +211,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn @parametrize async def test_raw_response_create_overload_2(self, async_client: AsyncOpenAI) -> None: response = await async_client.audio.transcriptions.with_raw_response.create( - file=b"raw file contents", + file=b"Example data", model="gpt-4o-transcribe", stream=True, ) @@ -223,7 +223,7 @@ async def test_raw_response_create_overload_2(self, async_client: AsyncOpenAI) - @parametrize async def test_streaming_response_create_overload_2(self, async_client: AsyncOpenAI) -> None: async with async_client.audio.transcriptions.with_streaming_response.create( - file=b"raw file contents", + file=b"Example data", model="gpt-4o-transcribe", stream=True, ) as response: diff --git a/tests/api_resources/audio/test_translations.py b/tests/api_resources/audio/test_translations.py index ead69e9369..d6848d1278 100644 --- a/tests/api_resources/audio/test_translations.py +++ b/tests/api_resources/audio/test_translations.py @@ -20,7 +20,7 @@ class TestTranslations: @parametrize def test_method_create(self, client: OpenAI) -> None: translation = client.audio.translations.create( - file=b"raw file contents", + file=b"Example data", model="whisper-1", ) assert_matches_type(TranslationCreateResponse, translation, path=["response"]) @@ -28,7 +28,7 @@ def test_method_create(self, client: OpenAI) -> None: @parametrize def test_method_create_with_all_params(self, client: OpenAI) -> None: translation = client.audio.translations.create( - file=b"raw file contents", + file=b"Example data", model="whisper-1", prompt="prompt", response_format="json", @@ -39,7 +39,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: @parametrize def test_raw_response_create(self, client: OpenAI) -> None: response = client.audio.translations.with_raw_response.create( - file=b"raw file contents", + file=b"Example data", model="whisper-1", ) @@ -51,7 +51,7 @@ def test_raw_response_create(self, client: OpenAI) -> None: @parametrize def test_streaming_response_create(self, client: OpenAI) -> None: with client.audio.translations.with_streaming_response.create( - file=b"raw file contents", + file=b"Example data", model="whisper-1", ) as response: assert not response.is_closed @@ -71,7 +71,7 @@ class TestAsyncTranslations: @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: translation = await async_client.audio.translations.create( - file=b"raw file contents", + file=b"Example data", model="whisper-1", ) assert_matches_type(TranslationCreateResponse, translation, path=["response"]) @@ -79,7 +79,7 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: translation = await async_client.audio.translations.create( - file=b"raw file contents", + file=b"Example data", model="whisper-1", prompt="prompt", response_format="json", @@ -90,7 +90,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> @parametrize async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: response = await async_client.audio.translations.with_raw_response.create( - file=b"raw file contents", + file=b"Example data", model="whisper-1", ) @@ -102,7 +102,7 @@ async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: async with async_client.audio.translations.with_streaming_response.create( - file=b"raw file contents", + file=b"Example data", model="whisper-1", ) as response: assert not response.is_closed diff --git a/tests/api_resources/containers/test_files.py b/tests/api_resources/containers/test_files.py index f9d82d005c..9d47785894 100644 --- a/tests/api_resources/containers/test_files.py +++ b/tests/api_resources/containers/test_files.py @@ -33,7 +33,7 @@ def test_method_create(self, client: OpenAI) -> None: def test_method_create_with_all_params(self, client: OpenAI) -> None: file = client.containers.files.create( container_id="container_id", - file=b"raw file contents", + file=b"Example data", file_id="file_id", ) assert_matches_type(FileCreateResponse, file, path=["response"]) @@ -230,7 +230,7 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None: async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: file = await async_client.containers.files.create( container_id="container_id", - file=b"raw file contents", + file=b"Example data", file_id="file_id", ) assert_matches_type(FileCreateResponse, file, path=["response"]) diff --git a/tests/api_resources/skills/test_versions.py b/tests/api_resources/skills/test_versions.py index 5f4dcbf51d..40c807354a 100644 --- a/tests/api_resources/skills/test_versions.py +++ b/tests/api_resources/skills/test_versions.py @@ -30,7 +30,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: version = client.skills.versions.create( skill_id="skill_123", default=True, - files=[b"raw file contents"], + files=[b"Example data"], ) assert_matches_type(SkillVersion, version, path=["response"]) @@ -227,7 +227,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> version = await async_client.skills.versions.create( skill_id="skill_123", default=True, - files=[b"raw file contents"], + files=[b"Example data"], ) assert_matches_type(SkillVersion, version, path=["response"]) diff --git a/tests/api_resources/test_files.py b/tests/api_resources/test_files.py index 67c809f155..940ac97022 100644 --- a/tests/api_resources/test_files.py +++ b/tests/api_resources/test_files.py @@ -26,7 +26,7 @@ class TestFiles: @parametrize def test_method_create(self, client: OpenAI) -> None: file = client.files.create( - file=b"raw file contents", + file=b"Example data", purpose="assistants", ) assert_matches_type(FileObject, file, path=["response"]) @@ -34,7 +34,7 @@ def test_method_create(self, client: OpenAI) -> None: @parametrize def test_method_create_with_all_params(self, client: OpenAI) -> None: file = client.files.create( - file=b"raw file contents", + file=b"Example data", purpose="assistants", expires_after={ "anchor": "created_at", @@ -46,7 +46,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: @parametrize def test_raw_response_create(self, client: OpenAI) -> None: response = client.files.with_raw_response.create( - file=b"raw file contents", + file=b"Example data", purpose="assistants", ) @@ -58,7 +58,7 @@ def test_raw_response_create(self, client: OpenAI) -> None: @parametrize def test_streaming_response_create(self, client: OpenAI) -> None: with client.files.with_streaming_response.create( - file=b"raw file contents", + file=b"Example data", purpose="assistants", ) as response: assert not response.is_closed @@ -279,7 +279,7 @@ class TestAsyncFiles: @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: file = await async_client.files.create( - file=b"raw file contents", + file=b"Example data", purpose="assistants", ) assert_matches_type(FileObject, file, path=["response"]) @@ -287,7 +287,7 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: file = await async_client.files.create( - file=b"raw file contents", + file=b"Example data", purpose="assistants", expires_after={ "anchor": "created_at", @@ -299,7 +299,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> @parametrize async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: response = await async_client.files.with_raw_response.create( - file=b"raw file contents", + file=b"Example data", purpose="assistants", ) @@ -311,7 +311,7 @@ async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: async with async_client.files.with_streaming_response.create( - file=b"raw file contents", + file=b"Example data", purpose="assistants", ) as response: assert not response.is_closed diff --git a/tests/api_resources/test_images.py b/tests/api_resources/test_images.py index 99fe77d8e0..9862b79c65 100644 --- a/tests/api_resources/test_images.py +++ b/tests/api_resources/test_images.py @@ -20,14 +20,14 @@ class TestImages: @parametrize def test_method_create_variation(self, client: OpenAI) -> None: image = client.images.create_variation( - image=b"raw file contents", + image=b"Example data", ) assert_matches_type(ImagesResponse, image, path=["response"]) @parametrize def test_method_create_variation_with_all_params(self, client: OpenAI) -> None: image = client.images.create_variation( - image=b"raw file contents", + image=b"Example data", model="string", n=1, response_format="url", @@ -39,7 +39,7 @@ def test_method_create_variation_with_all_params(self, client: OpenAI) -> None: @parametrize def test_raw_response_create_variation(self, client: OpenAI) -> None: response = client.images.with_raw_response.create_variation( - image=b"raw file contents", + image=b"Example data", ) assert response.is_closed is True @@ -50,7 +50,7 @@ def test_raw_response_create_variation(self, client: OpenAI) -> None: @parametrize def test_streaming_response_create_variation(self, client: OpenAI) -> None: with client.images.with_streaming_response.create_variation( - image=b"raw file contents", + image=b"Example data", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -63,7 +63,7 @@ def test_streaming_response_create_variation(self, client: OpenAI) -> None: @parametrize def test_method_edit_overload_1(self, client: OpenAI) -> None: image = client.images.edit( - image=b"raw file contents", + image=b"Example data", prompt="A cute baby sea otter wearing a beret", ) assert_matches_type(ImagesResponse, image, path=["response"]) @@ -71,11 +71,11 @@ def test_method_edit_overload_1(self, client: OpenAI) -> None: @parametrize def test_method_edit_with_all_params_overload_1(self, client: OpenAI) -> None: image = client.images.edit( - image=b"raw file contents", + image=b"Example data", prompt="A cute baby sea otter wearing a beret", background="transparent", input_fidelity="high", - mask=b"raw file contents", + mask=b"Example data", model="string", n=1, output_compression=100, @@ -92,7 +92,7 @@ def test_method_edit_with_all_params_overload_1(self, client: OpenAI) -> None: @parametrize def test_raw_response_edit_overload_1(self, client: OpenAI) -> None: response = client.images.with_raw_response.edit( - image=b"raw file contents", + image=b"Example data", prompt="A cute baby sea otter wearing a beret", ) @@ -104,7 +104,7 @@ def test_raw_response_edit_overload_1(self, client: OpenAI) -> None: @parametrize def test_streaming_response_edit_overload_1(self, client: OpenAI) -> None: with client.images.with_streaming_response.edit( - image=b"raw file contents", + image=b"Example data", prompt="A cute baby sea otter wearing a beret", ) as response: assert not response.is_closed @@ -118,7 +118,7 @@ def test_streaming_response_edit_overload_1(self, client: OpenAI) -> None: @parametrize def test_method_edit_overload_2(self, client: OpenAI) -> None: image_stream = client.images.edit( - image=b"raw file contents", + image=b"Example data", prompt="A cute baby sea otter wearing a beret", stream=True, ) @@ -127,12 +127,12 @@ def test_method_edit_overload_2(self, client: OpenAI) -> None: @parametrize def test_method_edit_with_all_params_overload_2(self, client: OpenAI) -> None: image_stream = client.images.edit( - image=b"raw file contents", + image=b"Example data", prompt="A cute baby sea otter wearing a beret", stream=True, background="transparent", input_fidelity="high", - mask=b"raw file contents", + mask=b"Example data", model="string", n=1, output_compression=100, @@ -148,7 +148,7 @@ def test_method_edit_with_all_params_overload_2(self, client: OpenAI) -> None: @parametrize def test_raw_response_edit_overload_2(self, client: OpenAI) -> None: response = client.images.with_raw_response.edit( - image=b"raw file contents", + image=b"Example data", prompt="A cute baby sea otter wearing a beret", stream=True, ) @@ -160,7 +160,7 @@ def test_raw_response_edit_overload_2(self, client: OpenAI) -> None: @parametrize def test_streaming_response_edit_overload_2(self, client: OpenAI) -> None: with client.images.with_streaming_response.edit( - image=b"raw file contents", + image=b"Example data", prompt="A cute baby sea otter wearing a beret", stream=True, ) as response: @@ -285,14 +285,14 @@ class TestAsyncImages: @parametrize async def test_method_create_variation(self, async_client: AsyncOpenAI) -> None: image = await async_client.images.create_variation( - image=b"raw file contents", + image=b"Example data", ) assert_matches_type(ImagesResponse, image, path=["response"]) @parametrize async def test_method_create_variation_with_all_params(self, async_client: AsyncOpenAI) -> None: image = await async_client.images.create_variation( - image=b"raw file contents", + image=b"Example data", model="string", n=1, response_format="url", @@ -304,7 +304,7 @@ async def test_method_create_variation_with_all_params(self, async_client: Async @parametrize async def test_raw_response_create_variation(self, async_client: AsyncOpenAI) -> None: response = await async_client.images.with_raw_response.create_variation( - image=b"raw file contents", + image=b"Example data", ) assert response.is_closed is True @@ -315,7 +315,7 @@ async def test_raw_response_create_variation(self, async_client: AsyncOpenAI) -> @parametrize async def test_streaming_response_create_variation(self, async_client: AsyncOpenAI) -> None: async with async_client.images.with_streaming_response.create_variation( - image=b"raw file contents", + image=b"Example data", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -328,7 +328,7 @@ async def test_streaming_response_create_variation(self, async_client: AsyncOpen @parametrize async def test_method_edit_overload_1(self, async_client: AsyncOpenAI) -> None: image = await async_client.images.edit( - image=b"raw file contents", + image=b"Example data", prompt="A cute baby sea otter wearing a beret", ) assert_matches_type(ImagesResponse, image, path=["response"]) @@ -336,11 +336,11 @@ async def test_method_edit_overload_1(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_method_edit_with_all_params_overload_1(self, async_client: AsyncOpenAI) -> None: image = await async_client.images.edit( - image=b"raw file contents", + image=b"Example data", prompt="A cute baby sea otter wearing a beret", background="transparent", input_fidelity="high", - mask=b"raw file contents", + mask=b"Example data", model="string", n=1, output_compression=100, @@ -357,7 +357,7 @@ async def test_method_edit_with_all_params_overload_1(self, async_client: AsyncO @parametrize async def test_raw_response_edit_overload_1(self, async_client: AsyncOpenAI) -> None: response = await async_client.images.with_raw_response.edit( - image=b"raw file contents", + image=b"Example data", prompt="A cute baby sea otter wearing a beret", ) @@ -369,7 +369,7 @@ async def test_raw_response_edit_overload_1(self, async_client: AsyncOpenAI) -> @parametrize async def test_streaming_response_edit_overload_1(self, async_client: AsyncOpenAI) -> None: async with async_client.images.with_streaming_response.edit( - image=b"raw file contents", + image=b"Example data", prompt="A cute baby sea otter wearing a beret", ) as response: assert not response.is_closed @@ -383,7 +383,7 @@ async def test_streaming_response_edit_overload_1(self, async_client: AsyncOpenA @parametrize async def test_method_edit_overload_2(self, async_client: AsyncOpenAI) -> None: image_stream = await async_client.images.edit( - image=b"raw file contents", + image=b"Example data", prompt="A cute baby sea otter wearing a beret", stream=True, ) @@ -392,12 +392,12 @@ async def test_method_edit_overload_2(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_method_edit_with_all_params_overload_2(self, async_client: AsyncOpenAI) -> None: image_stream = await async_client.images.edit( - image=b"raw file contents", + image=b"Example data", prompt="A cute baby sea otter wearing a beret", stream=True, background="transparent", input_fidelity="high", - mask=b"raw file contents", + mask=b"Example data", model="string", n=1, output_compression=100, @@ -413,7 +413,7 @@ async def test_method_edit_with_all_params_overload_2(self, async_client: AsyncO @parametrize async def test_raw_response_edit_overload_2(self, async_client: AsyncOpenAI) -> None: response = await async_client.images.with_raw_response.edit( - image=b"raw file contents", + image=b"Example data", prompt="A cute baby sea otter wearing a beret", stream=True, ) @@ -425,7 +425,7 @@ async def test_raw_response_edit_overload_2(self, async_client: AsyncOpenAI) -> @parametrize async def test_streaming_response_edit_overload_2(self, async_client: AsyncOpenAI) -> None: async with async_client.images.with_streaming_response.edit( - image=b"raw file contents", + image=b"Example data", prompt="A cute baby sea otter wearing a beret", stream=True, ) as response: diff --git a/tests/api_resources/test_skills.py b/tests/api_resources/test_skills.py index fb4cea92ce..6708fb3cbf 100644 --- a/tests/api_resources/test_skills.py +++ b/tests/api_resources/test_skills.py @@ -26,7 +26,7 @@ def test_method_create(self, client: OpenAI) -> None: @parametrize def test_method_create_with_all_params(self, client: OpenAI) -> None: skill = client.skills.create( - files=[b"raw file contents"], + files=[b"Example data"], ) assert_matches_type(Skill, skill, path=["response"]) @@ -216,7 +216,7 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: skill = await async_client.skills.create( - files=[b"raw file contents"], + files=[b"Example data"], ) assert_matches_type(Skill, skill, path=["response"]) diff --git a/tests/api_resources/test_videos.py b/tests/api_resources/test_videos.py index b785e03ca5..73acf6d05d 100644 --- a/tests/api_resources/test_videos.py +++ b/tests/api_resources/test_videos.py @@ -15,6 +15,8 @@ from openai.types import ( Video, VideoDeleteResponse, + VideoGetCharacterResponse, + VideoCreateCharacterResponse, ) from openai._utils import assert_signatures_in_sync from openai.pagination import SyncConversationCursorPage, AsyncConversationCursorPage @@ -38,7 +40,7 @@ def test_method_create(self, client: OpenAI) -> None: def test_method_create_with_all_params(self, client: OpenAI) -> None: video = client.videos.create( prompt="x", - input_reference=b"raw file contents", + input_reference=b"Example data", model="string", seconds="4", size="720x1280", @@ -179,6 +181,40 @@ def test_path_params_delete(self, client: OpenAI) -> None: "", ) + @parametrize + def test_method_create_character(self, client: OpenAI) -> None: + video = client.videos.create_character( + name="x", + video=b"Example data", + ) + assert_matches_type(VideoCreateCharacterResponse, video, path=["response"]) + + @parametrize + def test_raw_response_create_character(self, client: OpenAI) -> None: + response = client.videos.with_raw_response.create_character( + name="x", + video=b"Example data", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = response.parse() + assert_matches_type(VideoCreateCharacterResponse, video, path=["response"]) + + @parametrize + def test_streaming_response_create_character(self, client: OpenAI) -> None: + with client.videos.with_streaming_response.create_character( + name="x", + video=b"Example data", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = response.parse() + assert_matches_type(VideoCreateCharacterResponse, video, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize @pytest.mark.respx(base_url=base_url) def test_method_download_content(self, client: OpenAI, respx_mock: MockRouter) -> None: @@ -237,6 +273,115 @@ def test_path_params_download_content(self, client: OpenAI) -> None: video_id="", ) + @parametrize + def test_method_edit(self, client: OpenAI) -> None: + video = client.videos.edit( + prompt="x", + video=b"Example data", + ) + assert_matches_type(Video, video, path=["response"]) + + @parametrize + def test_raw_response_edit(self, client: OpenAI) -> None: + response = client.videos.with_raw_response.edit( + prompt="x", + video=b"Example data", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = response.parse() + assert_matches_type(Video, video, path=["response"]) + + @parametrize + def test_streaming_response_edit(self, client: OpenAI) -> None: + with client.videos.with_streaming_response.edit( + prompt="x", + video=b"Example data", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = response.parse() + assert_matches_type(Video, video, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_extend(self, client: OpenAI) -> None: + video = client.videos.extend( + prompt="x", + seconds="4", + video=b"Example data", + ) + assert_matches_type(Video, video, path=["response"]) + + @parametrize + def test_raw_response_extend(self, client: OpenAI) -> None: + response = client.videos.with_raw_response.extend( + prompt="x", + seconds="4", + video=b"Example data", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = response.parse() + assert_matches_type(Video, video, path=["response"]) + + @parametrize + def test_streaming_response_extend(self, client: OpenAI) -> None: + with client.videos.with_streaming_response.extend( + prompt="x", + seconds="4", + video=b"Example data", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = response.parse() + assert_matches_type(Video, video, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_character(self, client: OpenAI) -> None: + video = client.videos.get_character( + "char_123", + ) + assert_matches_type(VideoGetCharacterResponse, video, path=["response"]) + + @parametrize + def test_raw_response_get_character(self, client: OpenAI) -> None: + response = client.videos.with_raw_response.get_character( + "char_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = response.parse() + assert_matches_type(VideoGetCharacterResponse, video, path=["response"]) + + @parametrize + def test_streaming_response_get_character(self, client: OpenAI) -> None: + with client.videos.with_streaming_response.get_character( + "char_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = response.parse() + assert_matches_type(VideoGetCharacterResponse, video, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get_character(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `character_id` but received ''"): + client.videos.with_raw_response.get_character( + "", + ) + @parametrize def test_method_remix(self, client: OpenAI) -> None: video = client.videos.remix( @@ -296,7 +441,7 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None: async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: video = await async_client.videos.create( prompt="x", - input_reference=b"raw file contents", + input_reference=b"Example data", model="string", seconds="4", size="720x1280", @@ -437,6 +582,40 @@ async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: "", ) + @parametrize + async def test_method_create_character(self, async_client: AsyncOpenAI) -> None: + video = await async_client.videos.create_character( + name="x", + video=b"Example data", + ) + assert_matches_type(VideoCreateCharacterResponse, video, path=["response"]) + + @parametrize + async def test_raw_response_create_character(self, async_client: AsyncOpenAI) -> None: + response = await async_client.videos.with_raw_response.create_character( + name="x", + video=b"Example data", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = response.parse() + assert_matches_type(VideoCreateCharacterResponse, video, path=["response"]) + + @parametrize + async def test_streaming_response_create_character(self, async_client: AsyncOpenAI) -> None: + async with async_client.videos.with_streaming_response.create_character( + name="x", + video=b"Example data", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = await response.parse() + assert_matches_type(VideoCreateCharacterResponse, video, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize @pytest.mark.respx(base_url=base_url) async def test_method_download_content(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None: @@ -497,6 +676,115 @@ async def test_path_params_download_content(self, async_client: AsyncOpenAI) -> video_id="", ) + @parametrize + async def test_method_edit(self, async_client: AsyncOpenAI) -> None: + video = await async_client.videos.edit( + prompt="x", + video=b"Example data", + ) + assert_matches_type(Video, video, path=["response"]) + + @parametrize + async def test_raw_response_edit(self, async_client: AsyncOpenAI) -> None: + response = await async_client.videos.with_raw_response.edit( + prompt="x", + video=b"Example data", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = response.parse() + assert_matches_type(Video, video, path=["response"]) + + @parametrize + async def test_streaming_response_edit(self, async_client: AsyncOpenAI) -> None: + async with async_client.videos.with_streaming_response.edit( + prompt="x", + video=b"Example data", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = await response.parse() + assert_matches_type(Video, video, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_extend(self, async_client: AsyncOpenAI) -> None: + video = await async_client.videos.extend( + prompt="x", + seconds="4", + video=b"Example data", + ) + assert_matches_type(Video, video, path=["response"]) + + @parametrize + async def test_raw_response_extend(self, async_client: AsyncOpenAI) -> None: + response = await async_client.videos.with_raw_response.extend( + prompt="x", + seconds="4", + video=b"Example data", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = response.parse() + assert_matches_type(Video, video, path=["response"]) + + @parametrize + async def test_streaming_response_extend(self, async_client: AsyncOpenAI) -> None: + async with async_client.videos.with_streaming_response.extend( + prompt="x", + seconds="4", + video=b"Example data", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = await response.parse() + assert_matches_type(Video, video, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_character(self, async_client: AsyncOpenAI) -> None: + video = await async_client.videos.get_character( + "char_123", + ) + assert_matches_type(VideoGetCharacterResponse, video, path=["response"]) + + @parametrize + async def test_raw_response_get_character(self, async_client: AsyncOpenAI) -> None: + response = await async_client.videos.with_raw_response.get_character( + "char_123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = response.parse() + assert_matches_type(VideoGetCharacterResponse, video, path=["response"]) + + @parametrize + async def test_streaming_response_get_character(self, async_client: AsyncOpenAI) -> None: + async with async_client.videos.with_streaming_response.get_character( + "char_123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = await response.parse() + assert_matches_type(VideoGetCharacterResponse, video, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get_character(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `character_id` but received ''"): + await async_client.videos.with_raw_response.get_character( + "", + ) + @parametrize async def test_method_remix(self, async_client: AsyncOpenAI) -> None: video = await async_client.videos.remix( diff --git a/tests/api_resources/uploads/test_parts.py b/tests/api_resources/uploads/test_parts.py index 191d3a1b04..b5956d263b 100644 --- a/tests/api_resources/uploads/test_parts.py +++ b/tests/api_resources/uploads/test_parts.py @@ -21,7 +21,7 @@ class TestParts: def test_method_create(self, client: OpenAI) -> None: part = client.uploads.parts.create( upload_id="upload_abc123", - data=b"raw file contents", + data=b"Example data", ) assert_matches_type(UploadPart, part, path=["response"]) @@ -29,7 +29,7 @@ def test_method_create(self, client: OpenAI) -> None: def test_raw_response_create(self, client: OpenAI) -> None: response = client.uploads.parts.with_raw_response.create( upload_id="upload_abc123", - data=b"raw file contents", + data=b"Example data", ) assert response.is_closed is True @@ -41,7 +41,7 @@ def test_raw_response_create(self, client: OpenAI) -> None: def test_streaming_response_create(self, client: OpenAI) -> None: with client.uploads.parts.with_streaming_response.create( upload_id="upload_abc123", - data=b"raw file contents", + data=b"Example data", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -56,7 +56,7 @@ def test_path_params_create(self, client: OpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `upload_id` but received ''"): client.uploads.parts.with_raw_response.create( upload_id="", - data=b"raw file contents", + data=b"Example data", ) @@ -69,7 +69,7 @@ class TestAsyncParts: async def test_method_create(self, async_client: AsyncOpenAI) -> None: part = await async_client.uploads.parts.create( upload_id="upload_abc123", - data=b"raw file contents", + data=b"Example data", ) assert_matches_type(UploadPart, part, path=["response"]) @@ -77,7 +77,7 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None: async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: response = await async_client.uploads.parts.with_raw_response.create( upload_id="upload_abc123", - data=b"raw file contents", + data=b"Example data", ) assert response.is_closed is True @@ -89,7 +89,7 @@ async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: async with async_client.uploads.parts.with_streaming_response.create( upload_id="upload_abc123", - data=b"raw file contents", + data=b"Example data", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -104,5 +104,5 @@ async def test_path_params_create(self, async_client: AsyncOpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `upload_id` but received ''"): await async_client.uploads.parts.with_raw_response.create( upload_id="", - data=b"raw file contents", + data=b"Example data", ) diff --git a/tests/test_websocket_connection_options.py b/tests/test_websocket_connection_options.py new file mode 100644 index 0000000000..122ee10078 --- /dev/null +++ b/tests/test_websocket_connection_options.py @@ -0,0 +1,20 @@ +from openai import types +from openai.types import websocket_connection_options + + +def test_submodule_alias_is_preserved() -> None: + assert ( + websocket_connection_options.WebsocketConnectionOptions + is websocket_connection_options.WebSocketConnectionOptions + ) + + +def test_public_types_alias_is_preserved() -> None: + assert types.WebsocketConnectionOptions is types.WebSocketConnectionOptions + + +def test_beta_realtime_import_still_works_with_old_alias() -> None: + from openai.resources.beta.realtime.realtime import Realtime, AsyncRealtime + + assert Realtime.__name__ == "Realtime" + assert AsyncRealtime.__name__ == "AsyncRealtime" From c1a87d945359f6ed4bfaa5328bb2e9ab3ff67874 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 13 Mar 2026 19:49:07 +0000 Subject: [PATCH 642/769] feat(api): custom voices --- .stats.yml | 6 ++--- src/openai/resources/audio/speech.py | 18 ++++++------- .../types/audio/speech_create_params.py | 25 ++++++++++++----- .../types/chat/chat_completion_audio_param.py | 24 ++++++++++++----- .../realtime/realtime_audio_config_output.py | 27 +++++++++++++------ .../realtime_audio_config_output_param.py | 25 ++++++++++++----- .../realtime_response_create_audio_output.py | 26 +++++++++++++----- ...time_response_create_audio_output_param.py | 24 +++++++++++++---- tests/api_resources/audio/test_speech.py | 16 +++++------ tests/api_resources/chat/test_completions.py | 8 +++--- tests/api_resources/realtime/test_calls.py | 8 +++--- .../realtime/test_client_secrets.py | 4 +-- 12 files changed, 141 insertions(+), 70 deletions(-) diff --git a/.stats.yml b/.stats.yml index 60deb7e24e..3e6307edaf 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 152 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-3e207c26eea3b15837c78ef2fe0e1c68937708fd0763971ce749c0bdb7db6376.yml -openapi_spec_hash: 626982004d5a594a822fa7883422efb4 -config_hash: 0dda4b3af379312c9c55467a5e1e1ec0 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-cb3e4451108eed58d59cff25bf77ec0dc960ec9c6f3dba68f90e7a9847c09d21.yml +openapi_spec_hash: dec6d9be64a5ba8f474a1f2a7a4fafef +config_hash: e922f01e25accd07d8fd3641c37fbd62 diff --git a/src/openai/resources/audio/speech.py b/src/openai/resources/audio/speech.py index f937321baa..80dbb44077 100644 --- a/src/openai/resources/audio/speech.py +++ b/src/openai/resources/audio/speech.py @@ -52,9 +52,7 @@ def create( *, input: str, model: Union[str, SpeechModel], - voice: Union[ - str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"] - ], + voice: speech_create_params.Voice, instructions: str | Omit = omit, response_format: Literal["mp3", "opus", "aac", "flac", "wav", "pcm"] | Omit = omit, speed: float | Omit = omit, @@ -80,8 +78,9 @@ def create( voice: The voice to use when generating the audio. Supported built-in voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, - `shimmer`, `verse`, `marin`, and `cedar`. Previews of the voices are available - in the + `shimmer`, `verse`, `marin`, and `cedar`. You may also provide a custom voice + object with an `id`, for example `{ "id": "voice_1234" }`. Previews of the + voices are available in the [Text to speech guide](https://platform.openai.com/docs/guides/text-to-speech#voice-options). instructions: Control the voice of your generated audio with additional instructions. Does not @@ -153,9 +152,7 @@ async def create( *, input: str, model: Union[str, SpeechModel], - voice: Union[ - str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"] - ], + voice: speech_create_params.Voice, instructions: str | Omit = omit, response_format: Literal["mp3", "opus", "aac", "flac", "wav", "pcm"] | Omit = omit, speed: float | Omit = omit, @@ -181,8 +178,9 @@ async def create( voice: The voice to use when generating the audio. Supported built-in voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, - `shimmer`, `verse`, `marin`, and `cedar`. Previews of the voices are available - in the + `shimmer`, `verse`, `marin`, and `cedar`. You may also provide a custom voice + object with an `id`, for example `{ "id": "voice_1234" }`. Previews of the + voices are available in the [Text to speech guide](https://platform.openai.com/docs/guides/text-to-speech#voice-options). instructions: Control the voice of your generated audio with additional instructions. Does not diff --git a/src/openai/types/audio/speech_create_params.py b/src/openai/types/audio/speech_create_params.py index 417df5b218..1c0472ea85 100644 --- a/src/openai/types/audio/speech_create_params.py +++ b/src/openai/types/audio/speech_create_params.py @@ -3,11 +3,11 @@ from __future__ import annotations from typing import Union -from typing_extensions import Literal, Required, TypedDict +from typing_extensions import Literal, Required, TypeAlias, TypedDict from .speech_model import SpeechModel -__all__ = ["SpeechCreateParams"] +__all__ = ["SpeechCreateParams", "Voice", "VoiceID"] class SpeechCreateParams(TypedDict, total=False): @@ -20,14 +20,13 @@ class SpeechCreateParams(TypedDict, total=False): `tts-1`, `tts-1-hd`, `gpt-4o-mini-tts`, or `gpt-4o-mini-tts-2025-12-15`. """ - voice: Required[ - Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"]] - ] + voice: Required[Voice] """The voice to use when generating the audio. Supported built-in voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, - `fable`, `onyx`, `nova`, `sage`, `shimmer`, `verse`, `marin`, and `cedar`. - Previews of the voices are available in the + `fable`, `onyx`, `nova`, `sage`, `shimmer`, `verse`, `marin`, and `cedar`. You + may also provide a custom voice object with an `id`, for example + `{ "id": "voice_1234" }`. Previews of the voices are available in the [Text to speech guide](https://platform.openai.com/docs/guides/text-to-speech#voice-options). """ @@ -55,3 +54,15 @@ class SpeechCreateParams(TypedDict, total=False): Supported formats are `sse` and `audio`. `sse` is not supported for `tts-1` or `tts-1-hd`. """ + + +class VoiceID(TypedDict, total=False): + """Custom voice reference.""" + + id: Required[str] + """The custom voice ID, e.g. `voice_1234`.""" + + +Voice: TypeAlias = Union[ + str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"], VoiceID +] diff --git a/src/openai/types/chat/chat_completion_audio_param.py b/src/openai/types/chat/chat_completion_audio_param.py index 1a73bb0c7e..fe64ba49aa 100644 --- a/src/openai/types/chat/chat_completion_audio_param.py +++ b/src/openai/types/chat/chat_completion_audio_param.py @@ -3,9 +3,21 @@ from __future__ import annotations from typing import Union -from typing_extensions import Literal, Required, TypedDict +from typing_extensions import Literal, Required, TypeAlias, TypedDict -__all__ = ["ChatCompletionAudioParam"] +__all__ = ["ChatCompletionAudioParam", "Voice", "VoiceID"] + + +class VoiceID(TypedDict, total=False): + """Custom voice reference.""" + + id: Required[str] + """The custom voice ID, e.g. `voice_1234`.""" + + +Voice: TypeAlias = Union[ + str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"], VoiceID +] class ChatCompletionAudioParam(TypedDict, total=False): @@ -21,11 +33,11 @@ class ChatCompletionAudioParam(TypedDict, total=False): Must be one of `wav`, `mp3`, `flac`, `opus`, or `pcm16`. """ - voice: Required[ - Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"]] - ] + voice: Required[Voice] """The voice the model uses to respond. Supported built-in voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, - `fable`, `nova`, `onyx`, `sage`, `shimmer`, `marin`, and `cedar`. + `fable`, `nova`, `onyx`, `sage`, `shimmer`, `marin`, and `cedar`. You may also + provide a custom voice object with an `id`, for example + `{ "id": "voice_1234" }`. """ diff --git a/src/openai/types/realtime/realtime_audio_config_output.py b/src/openai/types/realtime/realtime_audio_config_output.py index 2922405f63..143cef67a5 100644 --- a/src/openai/types/realtime/realtime_audio_config_output.py +++ b/src/openai/types/realtime/realtime_audio_config_output.py @@ -1,12 +1,24 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from typing import Union, Optional -from typing_extensions import Literal +from typing_extensions import Literal, TypeAlias from ..._models import BaseModel from .realtime_audio_formats import RealtimeAudioFormats -__all__ = ["RealtimeAudioConfigOutput"] +__all__ = ["RealtimeAudioConfigOutput", "Voice", "VoiceID"] + + +class VoiceID(BaseModel): + """Custom voice reference.""" + + id: str + """The custom voice ID, e.g. `voice_1234`.""" + + +Voice: TypeAlias = Union[ + str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"], VoiceID +] class RealtimeAudioConfigOutput(BaseModel): @@ -24,13 +36,12 @@ class RealtimeAudioConfigOutput(BaseModel): generated, it's also possible to prompt the model to speak faster or slower. """ - voice: Union[ - str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"], None - ] = None + voice: Optional[Voice] = None """The voice the model uses to respond. Supported built-in voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`, - `shimmer`, `verse`, `marin`, and `cedar`. Voice cannot be changed during the - session once the model has responded with audio at least once. We recommend - `marin` and `cedar` for best quality. + `shimmer`, `verse`, `marin`, and `cedar`. You may also provide a custom voice + object with an `id`, for example `{ "id": "voice_1234" }`. Voice cannot be + changed during the session once the model has responded with audio at least + once. We recommend `marin` and `cedar` for best quality. """ diff --git a/src/openai/types/realtime/realtime_audio_config_output_param.py b/src/openai/types/realtime/realtime_audio_config_output_param.py index d04fd3a303..5d920f69a6 100644 --- a/src/openai/types/realtime/realtime_audio_config_output_param.py +++ b/src/openai/types/realtime/realtime_audio_config_output_param.py @@ -3,11 +3,23 @@ from __future__ import annotations from typing import Union -from typing_extensions import Literal, TypedDict +from typing_extensions import Literal, Required, TypeAlias, TypedDict from .realtime_audio_formats_param import RealtimeAudioFormatsParam -__all__ = ["RealtimeAudioConfigOutputParam"] +__all__ = ["RealtimeAudioConfigOutputParam", "Voice", "VoiceID"] + + +class VoiceID(TypedDict, total=False): + """Custom voice reference.""" + + id: Required[str] + """The custom voice ID, e.g. `voice_1234`.""" + + +Voice: TypeAlias = Union[ + str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"], VoiceID +] class RealtimeAudioConfigOutputParam(TypedDict, total=False): @@ -25,11 +37,12 @@ class RealtimeAudioConfigOutputParam(TypedDict, total=False): generated, it's also possible to prompt the model to speak faster or slower. """ - voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"]] + voice: Voice """The voice the model uses to respond. Supported built-in voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`, - `shimmer`, `verse`, `marin`, and `cedar`. Voice cannot be changed during the - session once the model has responded with audio at least once. We recommend - `marin` and `cedar` for best quality. + `shimmer`, `verse`, `marin`, and `cedar`. You may also provide a custom voice + object with an `id`, for example `{ "id": "voice_1234" }`. Voice cannot be + changed during the session once the model has responded with audio at least + once. We recommend `marin` and `cedar` for best quality. """ diff --git a/src/openai/types/realtime/realtime_response_create_audio_output.py b/src/openai/types/realtime/realtime_response_create_audio_output.py index db02511ab1..7848357236 100644 --- a/src/openai/types/realtime/realtime_response_create_audio_output.py +++ b/src/openai/types/realtime/realtime_response_create_audio_output.py @@ -1,26 +1,38 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from typing import Union, Optional -from typing_extensions import Literal +from typing_extensions import Literal, TypeAlias from ..._models import BaseModel from .realtime_audio_formats import RealtimeAudioFormats -__all__ = ["RealtimeResponseCreateAudioOutput", "Output"] +__all__ = ["RealtimeResponseCreateAudioOutput", "Output", "OutputVoice", "OutputVoiceID"] + + +class OutputVoiceID(BaseModel): + """Custom voice reference.""" + + id: str + """The custom voice ID, e.g. `voice_1234`.""" + + +OutputVoice: TypeAlias = Union[ + str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"], OutputVoiceID +] class Output(BaseModel): format: Optional[RealtimeAudioFormats] = None """The format of the output audio.""" - voice: Union[ - str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"], None - ] = None + voice: Optional[OutputVoice] = None """The voice the model uses to respond. Supported built-in voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`, - `shimmer`, `verse`, `marin`, and `cedar`. Voice cannot be changed during the - session once the model has responded with audio at least once. + `shimmer`, `verse`, `marin`, and `cedar`. You may also provide a custom voice + object with an `id`, for example `{ "id": "voice_1234" }`. Voice cannot be + changed during the session once the model has responded with audio at least + once. We recommend `marin` and `cedar` for best quality. """ diff --git a/src/openai/types/realtime/realtime_response_create_audio_output_param.py b/src/openai/types/realtime/realtime_response_create_audio_output_param.py index 22787ad106..bb930f5488 100644 --- a/src/openai/types/realtime/realtime_response_create_audio_output_param.py +++ b/src/openai/types/realtime/realtime_response_create_audio_output_param.py @@ -3,23 +3,37 @@ from __future__ import annotations from typing import Union -from typing_extensions import Literal, TypedDict +from typing_extensions import Literal, Required, TypeAlias, TypedDict from .realtime_audio_formats_param import RealtimeAudioFormatsParam -__all__ = ["RealtimeResponseCreateAudioOutputParam", "Output"] +__all__ = ["RealtimeResponseCreateAudioOutputParam", "Output", "OutputVoice", "OutputVoiceID"] + + +class OutputVoiceID(TypedDict, total=False): + """Custom voice reference.""" + + id: Required[str] + """The custom voice ID, e.g. `voice_1234`.""" + + +OutputVoice: TypeAlias = Union[ + str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"], OutputVoiceID +] class Output(TypedDict, total=False): format: RealtimeAudioFormatsParam """The format of the output audio.""" - voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"]] + voice: OutputVoice """The voice the model uses to respond. Supported built-in voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`, - `shimmer`, `verse`, `marin`, and `cedar`. Voice cannot be changed during the - session once the model has responded with audio at least once. + `shimmer`, `verse`, `marin`, and `cedar`. You may also provide a custom voice + object with an `id`, for example `{ "id": "voice_1234" }`. Voice cannot be + changed during the session once the model has responded with audio at least + once. We recommend `marin` and `cedar` for best quality. """ diff --git a/tests/api_resources/audio/test_speech.py b/tests/api_resources/audio/test_speech.py index 2c77f38949..a42c77126d 100644 --- a/tests/api_resources/audio/test_speech.py +++ b/tests/api_resources/audio/test_speech.py @@ -28,7 +28,7 @@ def test_method_create(self, client: OpenAI, respx_mock: MockRouter) -> None: speech = client.audio.speech.create( input="string", model="string", - voice="ash", + voice="string", ) assert isinstance(speech, _legacy_response.HttpxBinaryResponseContent) assert speech.json() == {"foo": "bar"} @@ -40,7 +40,7 @@ def test_method_create_with_all_params(self, client: OpenAI, respx_mock: MockRou speech = client.audio.speech.create( input="string", model="string", - voice="ash", + voice="string", instructions="instructions", response_format="mp3", speed=0.25, @@ -57,7 +57,7 @@ def test_raw_response_create(self, client: OpenAI, respx_mock: MockRouter) -> No response = client.audio.speech.with_raw_response.create( input="string", model="string", - voice="ash", + voice="string", ) assert response.is_closed is True @@ -72,7 +72,7 @@ def test_streaming_response_create(self, client: OpenAI, respx_mock: MockRouter) with client.audio.speech.with_streaming_response.create( input="string", model="string", - voice="ash", + voice="string", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -95,7 +95,7 @@ async def test_method_create(self, async_client: AsyncOpenAI, respx_mock: MockRo speech = await async_client.audio.speech.create( input="string", model="string", - voice="ash", + voice="string", ) assert isinstance(speech, _legacy_response.HttpxBinaryResponseContent) assert speech.json() == {"foo": "bar"} @@ -107,7 +107,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI, re speech = await async_client.audio.speech.create( input="string", model="string", - voice="ash", + voice="string", instructions="instructions", response_format="mp3", speed=0.25, @@ -124,7 +124,7 @@ async def test_raw_response_create(self, async_client: AsyncOpenAI, respx_mock: response = await async_client.audio.speech.with_raw_response.create( input="string", model="string", - voice="ash", + voice="string", ) assert response.is_closed is True @@ -139,7 +139,7 @@ async def test_streaming_response_create(self, async_client: AsyncOpenAI, respx_ async with async_client.audio.speech.with_streaming_response.create( input="string", model="string", - voice="ash", + voice="string", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" diff --git a/tests/api_resources/chat/test_completions.py b/tests/api_resources/chat/test_completions.py index 995b752e11..c55c132697 100644 --- a/tests/api_resources/chat/test_completions.py +++ b/tests/api_resources/chat/test_completions.py @@ -48,7 +48,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: model="gpt-5.4", audio={ "format": "wav", - "voice": "ash", + "voice": "string", }, frequency_penalty=-2, function_call="none", @@ -182,7 +182,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: stream=True, audio={ "format": "wav", - "voice": "ash", + "voice": "string", }, frequency_penalty=-2, function_call="none", @@ -491,7 +491,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn model="gpt-5.4", audio={ "format": "wav", - "voice": "ash", + "voice": "string", }, frequency_penalty=-2, function_call="none", @@ -625,7 +625,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn stream=True, audio={ "format": "wav", - "voice": "ash", + "voice": "string", }, frequency_penalty=-2, function_call="none", diff --git a/tests/api_resources/realtime/test_calls.py b/tests/api_resources/realtime/test_calls.py index 9bb6ef3faf..9e2810841d 100644 --- a/tests/api_resources/realtime/test_calls.py +++ b/tests/api_resources/realtime/test_calls.py @@ -67,7 +67,7 @@ def test_method_create_with_all_params(self, client: OpenAI, respx_mock: MockRou "type": "audio/pcm", }, "speed": 0.25, - "voice": "ash", + "voice": "string", }, }, "include": ["item.input_audio_transcription.logprobs"], @@ -166,7 +166,7 @@ def test_method_accept_with_all_params(self, client: OpenAI) -> None: "type": "audio/pcm", }, "speed": 0.25, - "voice": "ash", + "voice": "string", }, }, include=["item.input_audio_transcription.logprobs"], @@ -405,7 +405,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI, re "type": "audio/pcm", }, "speed": 0.25, - "voice": "ash", + "voice": "string", }, }, "include": ["item.input_audio_transcription.logprobs"], @@ -504,7 +504,7 @@ async def test_method_accept_with_all_params(self, async_client: AsyncOpenAI) -> "type": "audio/pcm", }, "speed": 0.25, - "voice": "ash", + "voice": "string", }, }, include=["item.input_audio_transcription.logprobs"], diff --git a/tests/api_resources/realtime/test_client_secrets.py b/tests/api_resources/realtime/test_client_secrets.py index 17762771ac..bfa0deac55 100644 --- a/tests/api_resources/realtime/test_client_secrets.py +++ b/tests/api_resources/realtime/test_client_secrets.py @@ -59,7 +59,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: "type": "audio/pcm", }, "speed": 0.25, - "voice": "ash", + "voice": "string", }, }, "include": ["item.input_audio_transcription.logprobs"], @@ -155,7 +155,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> "type": "audio/pcm", }, "speed": 0.25, - "voice": "ash", + "voice": "string", }, }, "include": ["item.input_audio_transcription.logprobs"], From fc7f598efa70c6bef5ad15d1a8c9dfcd0fbd33fa Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 13 Mar 2026 19:49:41 +0000 Subject: [PATCH 643/769] release: 2.28.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 4bdf489489..fa4d75253f 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.27.0" + ".": "2.28.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index c750be23c4..dfc7ddca89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 2.28.0 (2026-03-13) + +Full Changelog: [v2.27.0...v2.28.0](https://github.com/openai/openai-python/compare/v2.27.0...v2.28.0) + +### Features + +* **api:** custom voices ([50dc060](https://github.com/openai/openai-python/commit/50dc060b55767615419219ef567d31210517e613)) + ## 2.27.0 (2026-03-13) Full Changelog: [v2.26.0...v2.27.0](https://github.com/openai/openai-python/compare/v2.26.0...v2.27.0) diff --git a/pyproject.toml b/pyproject.toml index 1419825193..ea82be70c4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.27.0" +version = "2.28.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 755c8a9f5c..45ae8eb37a 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__ = "2.27.0" # x-release-please-version +__version__ = "2.28.0" # x-release-please-version From a499adcd6d9b31b87f8257b2e85c781f0ea17749 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 13 Mar 2026 21:12:01 +0000 Subject: [PATCH 644/769] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 3e6307edaf..5d6c5c38a7 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 152 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-cb3e4451108eed58d59cff25bf77ec0dc960ec9c6f3dba68f90e7a9847c09d21.yml openapi_spec_hash: dec6d9be64a5ba8f474a1f2a7a4fafef -config_hash: e922f01e25accd07d8fd3641c37fbd62 +config_hash: 1cb55f2105c291f6f4721d06655d40f0 From c9ccb8fcaba323e10d8117f4565c9ef79602c1f1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 14 Mar 2026 01:19:29 +0000 Subject: [PATCH 645/769] feat(api): add /v1/videos endpoint to batches create method --- .stats.yml | 4 ++-- src/openai/resources/batches.py | 16 ++++++++++------ src/openai/types/batch_create_params.py | 9 +++++---- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/.stats.yml b/.stats.yml index 5d6c5c38a7..1f91787668 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 152 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-cb3e4451108eed58d59cff25bf77ec0dc960ec9c6f3dba68f90e7a9847c09d21.yml -openapi_spec_hash: dec6d9be64a5ba8f474a1f2a7a4fafef +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-bb3e130670aa251441ebf4857acd20c836da88350785a91be9d9af4a4ca25e98.yml +openapi_spec_hash: 45b78734bc16e9658175ca758c608a1e config_hash: 1cb55f2105c291f6f4721d06655d40f0 diff --git a/src/openai/resources/batches.py b/src/openai/resources/batches.py index 005a32870e..c269b93e2c 100644 --- a/src/openai/resources/batches.py +++ b/src/openai/resources/batches.py @@ -56,6 +56,7 @@ def create( "/v1/moderations", "/v1/images/generations", "/v1/images/edits", + "/v1/videos", ], input_file_id: str, metadata: Optional[Metadata] | Omit = omit, @@ -76,9 +77,10 @@ def create( endpoint: The endpoint to be used for all requests in the batch. Currently `/v1/responses`, `/v1/chat/completions`, `/v1/embeddings`, `/v1/completions`, - `/v1/moderations`, `/v1/images/generations`, and `/v1/images/edits` are - supported. Note that `/v1/embeddings` batches are also restricted to a maximum - of 50,000 embedding inputs across all requests in the batch. + `/v1/moderations`, `/v1/images/generations`, `/v1/images/edits`, and + `/v1/videos` are supported. Note that `/v1/embeddings` batches are also + restricted to a maximum of 50,000 embedding inputs across all requests in the + batch. input_file_id: The ID of an uploaded file that contains requests for the new batch. @@ -282,6 +284,7 @@ async def create( "/v1/moderations", "/v1/images/generations", "/v1/images/edits", + "/v1/videos", ], input_file_id: str, metadata: Optional[Metadata] | Omit = omit, @@ -302,9 +305,10 @@ async def create( endpoint: The endpoint to be used for all requests in the batch. Currently `/v1/responses`, `/v1/chat/completions`, `/v1/embeddings`, `/v1/completions`, - `/v1/moderations`, `/v1/images/generations`, and `/v1/images/edits` are - supported. Note that `/v1/embeddings` batches are also restricted to a maximum - of 50,000 embedding inputs across all requests in the batch. + `/v1/moderations`, `/v1/images/generations`, `/v1/images/edits`, and + `/v1/videos` are supported. Note that `/v1/embeddings` batches are also + restricted to a maximum of 50,000 embedding inputs across all requests in the + batch. input_file_id: The ID of an uploaded file that contains requests for the new batch. diff --git a/src/openai/types/batch_create_params.py b/src/openai/types/batch_create_params.py index 1bcd48aace..97bd2c67ed 100644 --- a/src/openai/types/batch_create_params.py +++ b/src/openai/types/batch_create_params.py @@ -26,15 +26,16 @@ class BatchCreateParams(TypedDict, total=False): "/v1/moderations", "/v1/images/generations", "/v1/images/edits", + "/v1/videos", ] ] """The endpoint to be used for all requests in the batch. Currently `/v1/responses`, `/v1/chat/completions`, `/v1/embeddings`, - `/v1/completions`, `/v1/moderations`, `/v1/images/generations`, and - `/v1/images/edits` are supported. Note that `/v1/embeddings` batches are also - restricted to a maximum of 50,000 embedding inputs across all requests in the - batch. + `/v1/completions`, `/v1/moderations`, `/v1/images/generations`, + `/v1/images/edits`, and `/v1/videos` are supported. Note that `/v1/embeddings` + batches are also restricted to a maximum of 50,000 embedding inputs across all + requests in the batch. """ input_file_id: Required[str] From f857bdc3ad7bf72c247dfa0c25b3422758e9d15d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 14 Mar 2026 02:18:11 +0000 Subject: [PATCH 646/769] feat(api): add defer_loading field to ToolFunction --- .stats.yml | 4 ++-- src/openai/types/responses/namespace_tool.py | 3 +++ src/openai/types/responses/namespace_tool_param.py | 3 +++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 1f91787668..3205b5bfa4 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 152 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-bb3e130670aa251441ebf4857acd20c836da88350785a91be9d9af4a4ca25e98.yml -openapi_spec_hash: 45b78734bc16e9658175ca758c608a1e +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-2ab0731e8c94b7c783b55939d2d2a46c2594c1da2ec444c543e17a9eea6d9164.yml +openapi_spec_hash: 5557d4cd48565e8b98dfcb96a5804965 config_hash: 1cb55f2105c291f6f4721d06655d40f0 diff --git a/src/openai/types/responses/namespace_tool.py b/src/openai/types/responses/namespace_tool.py index 2c311dbe17..88f76a9732 100644 --- a/src/openai/types/responses/namespace_tool.py +++ b/src/openai/types/responses/namespace_tool.py @@ -15,6 +15,9 @@ class ToolFunction(BaseModel): type: Literal["function"] + defer_loading: Optional[bool] = None + """Whether this function should be deferred and discovered via tool search.""" + description: Optional[str] = None parameters: Optional[object] = None diff --git a/src/openai/types/responses/namespace_tool_param.py b/src/openai/types/responses/namespace_tool_param.py index 4bda2ecd83..cb1e5e17f4 100644 --- a/src/openai/types/responses/namespace_tool_param.py +++ b/src/openai/types/responses/namespace_tool_param.py @@ -15,6 +15,9 @@ class ToolFunction(TypedDict, total=False): type: Required[Literal["function"]] + defer_loading: bool + """Whether this function should be deferred and discovered via tool search.""" + description: Optional[str] parameters: Optional[object] From 28bda04ca2bc849e188d68e0bfe3de9cae682a81 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 16 Mar 2026 14:49:55 +0000 Subject: [PATCH 647/769] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 3205b5bfa4..db892f8ebb 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 152 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-2ab0731e8c94b7c783b55939d2d2a46c2594c1da2ec444c543e17a9eea6d9164.yml openapi_spec_hash: 5557d4cd48565e8b98dfcb96a5804965 -config_hash: 1cb55f2105c291f6f4721d06655d40f0 +config_hash: 1e4cbbae1fcd20c0b729289210c04d1a From fdf7f83d2b5171c70e97ec164a482cd675cd05a7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 16 Mar 2026 16:07:36 +0000 Subject: [PATCH 648/769] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index db892f8ebb..b27e3589a8 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 152 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-2ab0731e8c94b7c783b55939d2d2a46c2594c1da2ec444c543e17a9eea6d9164.yml openapi_spec_hash: 5557d4cd48565e8b98dfcb96a5804965 -config_hash: 1e4cbbae1fcd20c0b729289210c04d1a +config_hash: 96fbf82cf74a44ccd513f5acf0956ffd From 02b30719a6eb40bba58cd86c85c1f63a671786fd Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 16 Mar 2026 17:34:07 +0000 Subject: [PATCH 649/769] fix(pydantic): do not pass `by_alias` unless set --- src/openai/_compat.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/openai/_compat.py b/src/openai/_compat.py index 020ffeb2ca..340c91a6d0 100644 --- a/src/openai/_compat.py +++ b/src/openai/_compat.py @@ -2,7 +2,7 @@ from typing import TYPE_CHECKING, Any, Union, Generic, TypeVar, Callable, cast, overload from datetime import date, datetime -from typing_extensions import Self, Literal +from typing_extensions import Self, Literal, TypedDict import pydantic from pydantic.fields import FieldInfo @@ -131,6 +131,10 @@ def model_json(model: pydantic.BaseModel, *, indent: int | None = None) -> str: return model.model_dump_json(indent=indent) +class _ModelDumpKwargs(TypedDict, total=False): + by_alias: bool + + def model_dump( model: pydantic.BaseModel, *, @@ -142,6 +146,9 @@ def model_dump( by_alias: bool | None = None, ) -> dict[str, Any]: if (not PYDANTIC_V1) or hasattr(model, "model_dump"): + kwargs: _ModelDumpKwargs = {} + if by_alias is not None: + kwargs["by_alias"] = by_alias return model.model_dump( mode=mode, exclude=exclude, @@ -149,7 +156,7 @@ def model_dump( exclude_defaults=exclude_defaults, # warnings are not supported in Pydantic v1 warnings=True if PYDANTIC_V1 else warnings, - by_alias=by_alias, + **kwargs, ) return cast( "dict[str, Any]", From 11f50b68f3ce05e2299dd27a0e7af293210ca919 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 16 Mar 2026 19:03:06 +0000 Subject: [PATCH 650/769] fix(deps): bump minimum typing-extensions version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index ea82be70c4..f70513a8be 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ authors = [ dependencies = [ "httpx>=0.23.0, <1", "pydantic>=1.9.0, <3", - "typing-extensions>=4.11, <5", + "typing-extensions>=4.11, <5", "typing-extensions>=4.14, <5", "anyio>=3.5.0, <5", "distro>=1.7.0, <2", "sniffio", From cf8e9e7beaedc7bfa2b142c1aa12672efd68024c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 16 Mar 2026 20:47:20 +0000 Subject: [PATCH 651/769] chore(internal): tweak CI branches --- .github/workflows/ci.yml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9c28de3543..3ad9f39206 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,12 +1,14 @@ name: CI on: push: - branches-ignore: - - 'generated' - - 'codegen/**' - - 'integrated/**' - - 'stl-preview-head/**' - - 'stl-preview-base/**' + branches: + - '**' + - '!integrated/**' + - '!stl-preview-head/**' + - '!stl-preview-base/**' + - '!generated' + - '!codegen/**' + - 'codegen/stl/**' pull_request: branches-ignore: - 'stl-preview-head/**' From bc96310eddc1aa1c22c490fc5c5d99daf60b55e8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 16 Mar 2026 22:08:41 +0000 Subject: [PATCH 652/769] feat(api): add in and nin operators to ComparisonFilter type --- .stats.yml | 4 ++-- src/openai/types/shared/comparison_filter.py | 2 +- src/openai/types/shared_params/comparison_filter.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.stats.yml b/.stats.yml index b27e3589a8..45b3b3f373 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 152 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-2ab0731e8c94b7c783b55939d2d2a46c2594c1da2ec444c543e17a9eea6d9164.yml -openapi_spec_hash: 5557d4cd48565e8b98dfcb96a5804965 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-5a660d5b485aae5061d55301f7c8522654a533c7d7d9596c4da54f0e481d8880.yml +openapi_spec_hash: 50297cf7c625ec3c4bb0bc0f5a9d318a config_hash: 96fbf82cf74a44ccd513f5acf0956ffd diff --git a/src/openai/types/shared/comparison_filter.py b/src/openai/types/shared/comparison_filter.py index 852cac1738..57c26cd016 100644 --- a/src/openai/types/shared/comparison_filter.py +++ b/src/openai/types/shared/comparison_filter.py @@ -16,7 +16,7 @@ class ComparisonFilter(BaseModel): key: str """The key to compare against the value.""" - type: Literal["eq", "ne", "gt", "gte", "lt", "lte"] + type: Literal["eq", "ne", "gt", "gte", "lt", "lte", "in", "nin"] """ Specifies the comparison operator: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `in`, `nin`. diff --git a/src/openai/types/shared_params/comparison_filter.py b/src/openai/types/shared_params/comparison_filter.py index 363688e467..005f4d1f0d 100644 --- a/src/openai/types/shared_params/comparison_filter.py +++ b/src/openai/types/shared_params/comparison_filter.py @@ -18,7 +18,7 @@ class ComparisonFilter(TypedDict, total=False): key: Required[str] """The key to compare against the value.""" - type: Required[Literal["eq", "ne", "gt", "gte", "lt", "lte"]] + type: Required[Literal["eq", "ne", "gt", "gte", "lt", "lte", "in", "nin"]] """ Specifies the comparison operator: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `in`, `nin`. From 2c67256406df9c9d4367a0dfcda63dbe84cd1522 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Mar 2026 17:36:00 +0000 Subject: [PATCH 653/769] feat(api): 5.4 nano and mini model slugs --- .stats.yml | 4 ++-- src/openai/resources/responses/responses.py | 8 ++++++++ src/openai/types/responses/response_compact_params.py | 4 ++++ src/openai/types/shared/chat_model.py | 4 ++++ src/openai/types/shared_params/chat_model.py | 4 ++++ 5 files changed, 22 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 45b3b3f373..b47f21a4ac 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 152 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-5a660d5b485aae5061d55301f7c8522654a533c7d7d9596c4da54f0e481d8880.yml -openapi_spec_hash: 50297cf7c625ec3c4bb0bc0f5a9d318a +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-55ef7034334e938c30656a404ce5e21466103be87542a796425346299f450404.yml +openapi_spec_hash: 4a5bfd2ee4ad47f5b7cf6f1ad08d5d7f config_hash: 96fbf82cf74a44ccd513f5acf0956ffd diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 12f1e1aea1..6d57f86313 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -1568,6 +1568,10 @@ def compact( model: Union[ Literal[ "gpt-5.4", + "gpt-5.4-mini", + "gpt-5.4-nano", + "gpt-5.4-mini-2026-03-17", + "gpt-5.4-nano-2026-03-17", "gpt-5.3-chat-latest", "gpt-5.2", "gpt-5.2-2025-12-11", @@ -3235,6 +3239,10 @@ async def compact( model: Union[ Literal[ "gpt-5.4", + "gpt-5.4-mini", + "gpt-5.4-nano", + "gpt-5.4-mini-2026-03-17", + "gpt-5.4-nano-2026-03-17", "gpt-5.3-chat-latest", "gpt-5.2", "gpt-5.2-2025-12-11", diff --git a/src/openai/types/responses/response_compact_params.py b/src/openai/types/responses/response_compact_params.py index 95b5da437d..0b163a9e78 100644 --- a/src/openai/types/responses/response_compact_params.py +++ b/src/openai/types/responses/response_compact_params.py @@ -15,6 +15,10 @@ class ResponseCompactParams(TypedDict, total=False): Union[ Literal[ "gpt-5.4", + "gpt-5.4-mini", + "gpt-5.4-nano", + "gpt-5.4-mini-2026-03-17", + "gpt-5.4-nano-2026-03-17", "gpt-5.3-chat-latest", "gpt-5.2", "gpt-5.2-2025-12-11", diff --git a/src/openai/types/shared/chat_model.py b/src/openai/types/shared/chat_model.py index b86bd28ef9..501a22a8bd 100644 --- a/src/openai/types/shared/chat_model.py +++ b/src/openai/types/shared/chat_model.py @@ -6,6 +6,10 @@ ChatModel: TypeAlias = Literal[ "gpt-5.4", + "gpt-5.4-mini", + "gpt-5.4-nano", + "gpt-5.4-mini-2026-03-17", + "gpt-5.4-nano-2026-03-17", "gpt-5.3-chat-latest", "gpt-5.2", "gpt-5.2-2025-12-11", diff --git a/src/openai/types/shared_params/chat_model.py b/src/openai/types/shared_params/chat_model.py index 2a45c8f423..17eaacd905 100644 --- a/src/openai/types/shared_params/chat_model.py +++ b/src/openai/types/shared_params/chat_model.py @@ -8,6 +8,10 @@ ChatModel: TypeAlias = Literal[ "gpt-5.4", + "gpt-5.4-mini", + "gpt-5.4-nano", + "gpt-5.4-mini-2026-03-17", + "gpt-5.4-nano-2026-03-17", "gpt-5.3-chat-latest", "gpt-5.2", "gpt-5.2-2025-12-11", From acd0c54d8a68efeedde0e5b4e6c310eef1ce7867 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Mar 2026 17:36:45 +0000 Subject: [PATCH 654/769] release: 2.29.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 fa4d75253f..3a5058bfce 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.28.0" + ".": "2.29.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index dfc7ddca89..eea76f7709 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,27 @@ # Changelog +## 2.29.0 (2026-03-17) + +Full Changelog: [v2.28.0...v2.29.0](https://github.com/openai/openai-python/compare/v2.28.0...v2.29.0) + +### Features + +* **api:** 5.4 nano and mini model slugs ([3b45666](https://github.com/openai/openai-python/commit/3b456661f77ca3196aceb5ab3350664a63481114)) +* **api:** add /v1/videos endpoint to batches create method ([c0e7a16](https://github.com/openai/openai-python/commit/c0e7a161a996854021e9eb69ea2a60ca0d08047f)) +* **api:** add defer_loading field to ToolFunction ([3167595](https://github.com/openai/openai-python/commit/3167595432bdda2f90721901d30ad316db49323e)) +* **api:** add in and nin operators to ComparisonFilter type ([664f02b](https://github.com/openai/openai-python/commit/664f02b051af84e1ca3fa313981ec72fdea269b3)) + + +### Bug Fixes + +* **deps:** bump minimum typing-extensions version ([a2fb2ca](https://github.com/openai/openai-python/commit/a2fb2ca55142c6658a18be7bd1392a01f5a83f35)) +* **pydantic:** do not pass `by_alias` unless set ([8ebe8fb](https://github.com/openai/openai-python/commit/8ebe8fbcb011c6a005a715cae50c6400a8596ee0)) + + +### Chores + +* **internal:** tweak CI branches ([96ccc3c](https://github.com/openai/openai-python/commit/96ccc3cca35645fd3140f99b0fc8e55545065212)) + ## 2.28.0 (2026-03-13) Full Changelog: [v2.27.0...v2.28.0](https://github.com/openai/openai-python/compare/v2.27.0...v2.28.0) diff --git a/pyproject.toml b/pyproject.toml index f70513a8be..46a72007df 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.28.0" +version = "2.29.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 45ae8eb37a..b8a1b37e13 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__ = "2.28.0" # x-release-please-version +__version__ = "2.29.0" # x-release-please-version From 9445eac0a424fee4df2666343c31cde69ecb2fbd Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 19 Mar 2026 15:40:52 +0000 Subject: [PATCH 655/769] fix: sanitize endpoint path params --- src/openai/_utils/__init__.py | 1 + src/openai/_utils/_path.py | 127 ++++++++++++++++++ src/openai/resources/batches.py | 10 +- src/openai/resources/beta/assistants.py | 14 +- src/openai/resources/beta/chatkit/sessions.py | 6 +- src/openai/resources/beta/chatkit/threads.py | 14 +- src/openai/resources/beta/threads/messages.py | 22 +-- .../resources/beta/threads/runs/runs.py | 37 ++--- .../resources/beta/threads/runs/steps.py | 20 ++- src/openai/resources/beta/threads/threads.py | 14 +- .../resources/chat/completions/completions.py | 14 +- .../resources/chat/completions/messages.py | 6 +- src/openai/resources/containers/containers.py | 10 +- .../resources/containers/files/content.py | 9 +- .../resources/containers/files/files.py | 18 +-- .../resources/conversations/conversations.py | 14 +- src/openai/resources/conversations/items.py | 26 ++-- src/openai/resources/evals/evals.py | 14 +- .../resources/evals/runs/output_items.py | 20 ++- src/openai/resources/evals/runs/runs.py | 22 +-- src/openai/resources/files.py | 18 +-- .../fine_tuning/checkpoints/permissions.py | 44 ++++-- .../resources/fine_tuning/jobs/checkpoints.py | 6 +- src/openai/resources/fine_tuning/jobs/jobs.py | 22 +-- src/openai/resources/models.py | 9 +- src/openai/resources/realtime/calls.py | 18 +-- src/openai/resources/responses/input_items.py | 6 +- src/openai/resources/responses/responses.py | 14 +- src/openai/resources/skills/content.py | 5 +- src/openai/resources/skills/skills.py | 14 +- .../resources/skills/versions/content.py | 5 +- .../resources/skills/versions/versions.py | 18 +-- src/openai/resources/uploads/parts.py | 6 +- src/openai/resources/uploads/uploads.py | 10 +- .../resources/vector_stores/file_batches.py | 42 ++++-- src/openai/resources/vector_stores/files.py | 46 +++++-- .../resources/vector_stores/vector_stores.py | 18 +-- src/openai/resources/videos.py | 22 +-- tests/test_utils/test_path.py | 89 ++++++++++++ 39 files changed, 577 insertions(+), 253 deletions(-) create mode 100644 src/openai/_utils/_path.py create mode 100644 tests/test_utils/test_path.py diff --git a/src/openai/_utils/__init__.py b/src/openai/_utils/__init__.py index 963c83b6d4..52853aaf03 100644 --- a/src/openai/_utils/__init__.py +++ b/src/openai/_utils/__init__.py @@ -1,4 +1,5 @@ from ._logs import SensitiveHeadersFilter as SensitiveHeadersFilter +from ._path import path_template as path_template from ._sync import asyncify as asyncify from ._proxy import LazyProxy as LazyProxy from ._utils import ( diff --git a/src/openai/_utils/_path.py b/src/openai/_utils/_path.py new file mode 100644 index 0000000000..4d6e1e4cbc --- /dev/null +++ b/src/openai/_utils/_path.py @@ -0,0 +1,127 @@ +from __future__ import annotations + +import re +from typing import ( + Any, + Mapping, + Callable, +) +from urllib.parse import quote + +# Matches '.' or '..' where each dot is either literal or percent-encoded (%2e / %2E). +_DOT_SEGMENT_RE = re.compile(r"^(?:\.|%2[eE]){1,2}$") + +_PLACEHOLDER_RE = re.compile(r"\{(\w+)\}") + + +def _quote_path_segment_part(value: str) -> str: + """Percent-encode `value` for use in a URI path segment. + + Considers characters not in `pchar` set from RFC 3986 §3.3 to be unsafe. + https://datatracker.ietf.org/doc/html/rfc3986#section-3.3 + """ + # quote() already treats unreserved characters (letters, digits, and -._~) + # as safe, so we only need to add sub-delims, ':', and '@'. + # Notably, unlike the default `safe` for quote(), / is unsafe and must be quoted. + return quote(value, safe="!$&'()*+,;=:@") + + +def _quote_query_part(value: str) -> str: + """Percent-encode `value` for use in a URI query string. + + Considers &, = and characters not in `query` set from RFC 3986 §3.4 to be unsafe. + https://datatracker.ietf.org/doc/html/rfc3986#section-3.4 + """ + return quote(value, safe="!$'()*+,;:@/?") + + +def _quote_fragment_part(value: str) -> str: + """Percent-encode `value` for use in a URI fragment. + + Considers characters not in `fragment` set from RFC 3986 §3.5 to be unsafe. + https://datatracker.ietf.org/doc/html/rfc3986#section-3.5 + """ + return quote(value, safe="!$&'()*+,;=:@/?") + + +def _interpolate( + template: str, + values: Mapping[str, Any], + quoter: Callable[[str], str], +) -> str: + """Replace {name} placeholders in `template`, quoting each value with `quoter`. + + Placeholder names are looked up in `values`. + + Raises: + KeyError: If a placeholder is not found in `values`. + """ + # re.split with a capturing group returns alternating + # [text, name, text, name, ..., text] elements. + parts = _PLACEHOLDER_RE.split(template) + + for i in range(1, len(parts), 2): + name = parts[i] + if name not in values: + raise KeyError(f"a value for placeholder {{{name}}} was not provided") + val = values[name] + if val is None: + parts[i] = "null" + elif isinstance(val, bool): + parts[i] = "true" if val else "false" + else: + parts[i] = quoter(str(values[name])) + + return "".join(parts) + + +def path_template(template: str, /, **kwargs: Any) -> str: + """Interpolate {name} placeholders in `template` from keyword arguments. + + Args: + template: The template string containing {name} placeholders. + **kwargs: Keyword arguments to interpolate into the template. + + Returns: + The template with placeholders interpolated and percent-encoded. + + Safe characters for percent-encoding are dependent on the URI component. + Placeholders in path and fragment portions are percent-encoded where the `segment` + and `fragment` sets from RFC 3986 respectively are considered safe. + Placeholders in the query portion are percent-encoded where the `query` set from + RFC 3986 §3.3 is considered safe except for = and & characters. + + Raises: + KeyError: If a placeholder is not found in `kwargs`. + ValueError: If resulting path contains /./ or /../ segments (including percent-encoded dot-segments). + """ + # Split the template into path, query, and fragment portions. + fragment_template: str | None = None + query_template: str | None = None + + rest = template + if "#" in rest: + rest, fragment_template = rest.split("#", 1) + if "?" in rest: + rest, query_template = rest.split("?", 1) + path_template = rest + + # Interpolate each portion with the appropriate quoting rules. + path_result = _interpolate(path_template, kwargs, _quote_path_segment_part) + + # Reject dot-segments (. and ..) in the final assembled path. The check + # runs after interpolation so that adjacent placeholders or a mix of static + # text and placeholders that together form a dot-segment are caught. + # Also reject percent-encoded dot-segments to protect against incorrectly + # implemented normalization in servers/proxies. + for segment in path_result.split("/"): + if _DOT_SEGMENT_RE.match(segment): + raise ValueError(f"Constructed path {path_result!r} contains dot-segment {segment!r} which is not allowed") + + result = path_result + if query_template is not None: + result += "?" + _interpolate(query_template, kwargs, _quote_query_part) + if fragment_template is not None: + result += "#" + _interpolate(fragment_template, kwargs, _quote_fragment_part) + + return result diff --git a/src/openai/resources/batches.py b/src/openai/resources/batches.py index c269b93e2c..6cdb50c280 100644 --- a/src/openai/resources/batches.py +++ b/src/openai/resources/batches.py @@ -10,7 +10,7 @@ from .. import _legacy_response from ..types import batch_list_params, batch_create_params from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from .._utils import maybe_transform, async_maybe_transform +from .._utils import path_template, maybe_transform, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -154,7 +154,7 @@ def retrieve( if not batch_id: raise ValueError(f"Expected a non-empty value for `batch_id` but received {batch_id!r}") return self._get( - f"/batches/{batch_id}", + path_template("/batches/{batch_id}", batch_id=batch_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -242,7 +242,7 @@ def cancel( if not batch_id: raise ValueError(f"Expected a non-empty value for `batch_id` but received {batch_id!r}") return self._post( - f"/batches/{batch_id}/cancel", + path_template("/batches/{batch_id}/cancel", batch_id=batch_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -382,7 +382,7 @@ async def retrieve( if not batch_id: raise ValueError(f"Expected a non-empty value for `batch_id` but received {batch_id!r}") return await self._get( - f"/batches/{batch_id}", + path_template("/batches/{batch_id}", batch_id=batch_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -470,7 +470,7 @@ async def cancel( if not batch_id: raise ValueError(f"Expected a non-empty value for `batch_id` but received {batch_id!r}") return await self._post( - f"/batches/{batch_id}/cancel", + path_template("/batches/{batch_id}/cancel", batch_id=batch_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/beta/assistants.py b/src/openai/resources/beta/assistants.py index bf22122553..7ea8a918ca 100644 --- a/src/openai/resources/beta/assistants.py +++ b/src/openai/resources/beta/assistants.py @@ -10,7 +10,7 @@ from ... import _legacy_response from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform +from ..._utils import path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -215,7 +215,7 @@ def retrieve( raise ValueError(f"Expected a non-empty value for `assistant_id` but received {assistant_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get( - f"/assistants/{assistant_id}", + path_template("/assistants/{assistant_id}", assistant_id=assistant_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -383,7 +383,7 @@ def update( raise ValueError(f"Expected a non-empty value for `assistant_id` but received {assistant_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( - f"/assistants/{assistant_id}", + path_template("/assistants/{assistant_id}", assistant_id=assistant_id), body=maybe_transform( { "description": description, @@ -500,7 +500,7 @@ def delete( raise ValueError(f"Expected a non-empty value for `assistant_id` but received {assistant_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._delete( - f"/assistants/{assistant_id}", + path_template("/assistants/{assistant_id}", assistant_id=assistant_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -691,7 +691,7 @@ async def retrieve( raise ValueError(f"Expected a non-empty value for `assistant_id` but received {assistant_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._get( - f"/assistants/{assistant_id}", + path_template("/assistants/{assistant_id}", assistant_id=assistant_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -859,7 +859,7 @@ async def update( raise ValueError(f"Expected a non-empty value for `assistant_id` but received {assistant_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( - f"/assistants/{assistant_id}", + path_template("/assistants/{assistant_id}", assistant_id=assistant_id), body=await async_maybe_transform( { "description": description, @@ -976,7 +976,7 @@ async def delete( raise ValueError(f"Expected a non-empty value for `assistant_id` but received {assistant_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._delete( - f"/assistants/{assistant_id}", + path_template("/assistants/{assistant_id}", assistant_id=assistant_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/beta/chatkit/sessions.py b/src/openai/resources/beta/chatkit/sessions.py index abfa496a56..6e95fd65fb 100644 --- a/src/openai/resources/beta/chatkit/sessions.py +++ b/src/openai/resources/beta/chatkit/sessions.py @@ -6,7 +6,7 @@ from .... import _legacy_response from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import maybe_transform, async_maybe_transform +from ...._utils import path_template, maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -134,7 +134,7 @@ def cancel( raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} return self._post( - f"/chatkit/sessions/{session_id}/cancel", + path_template("/chatkit/sessions/{session_id}/cancel", session_id=session_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -249,7 +249,7 @@ async def cancel( raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} return await self._post( - f"/chatkit/sessions/{session_id}/cancel", + path_template("/chatkit/sessions/{session_id}/cancel", session_id=session_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/beta/chatkit/threads.py b/src/openai/resources/beta/chatkit/threads.py index 7a2d4c4a30..16e0e11a0a 100644 --- a/src/openai/resources/beta/chatkit/threads.py +++ b/src/openai/resources/beta/chatkit/threads.py @@ -9,7 +9,7 @@ from .... import _legacy_response from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import maybe_transform +from ...._utils import path_template, maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -70,7 +70,7 @@ def retrieve( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} return self._get( - f"/chatkit/threads/{thread_id}", + path_template("/chatkit/threads/{thread_id}", thread_id=thread_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -167,7 +167,7 @@ def delete( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} return self._delete( - f"/chatkit/threads/{thread_id}", + path_template("/chatkit/threads/{thread_id}", thread_id=thread_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -215,7 +215,7 @@ def list_items( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} return self._get_api_list( - f"/chatkit/threads/{thread_id}/items", + path_template("/chatkit/threads/{thread_id}/items", thread_id=thread_id), page=SyncConversationCursorPage[Data], options=make_request_options( extra_headers=extra_headers, @@ -283,7 +283,7 @@ async def retrieve( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} return await self._get( - f"/chatkit/threads/{thread_id}", + path_template("/chatkit/threads/{thread_id}", thread_id=thread_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -380,7 +380,7 @@ async def delete( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} return await self._delete( - f"/chatkit/threads/{thread_id}", + path_template("/chatkit/threads/{thread_id}", thread_id=thread_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -428,7 +428,7 @@ def list_items( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} return self._get_api_list( - f"/chatkit/threads/{thread_id}/items", + path_template("/chatkit/threads/{thread_id}/items", thread_id=thread_id), page=AsyncConversationCursorPage[Data], options=make_request_options( extra_headers=extra_headers, diff --git a/src/openai/resources/beta/threads/messages.py b/src/openai/resources/beta/threads/messages.py index e783310933..95b750d4e4 100644 --- a/src/openai/resources/beta/threads/messages.py +++ b/src/openai/resources/beta/threads/messages.py @@ -10,7 +10,7 @@ from .... import _legacy_response from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import maybe_transform, async_maybe_transform +from ...._utils import path_template, maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -101,7 +101,7 @@ def create( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( - f"/threads/{thread_id}/messages", + path_template("/threads/{thread_id}/messages", thread_id=thread_id), body=maybe_transform( { "content": content, @@ -148,7 +148,7 @@ def retrieve( raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get( - f"/threads/{thread_id}/messages/{message_id}", + path_template("/threads/{thread_id}/messages/{message_id}", thread_id=thread_id, message_id=message_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -194,7 +194,7 @@ def update( raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( - f"/threads/{thread_id}/messages/{message_id}", + path_template("/threads/{thread_id}/messages/{message_id}", thread_id=thread_id, message_id=message_id), body=maybe_transform({"metadata": metadata}, message_update_params.MessageUpdateParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -253,7 +253,7 @@ def list( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( - f"/threads/{thread_id}/messages", + path_template("/threads/{thread_id}/messages", thread_id=thread_id), page=SyncCursorPage[Message], options=make_request_options( extra_headers=extra_headers, @@ -305,7 +305,7 @@ def delete( raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._delete( - f"/threads/{thread_id}/messages/{message_id}", + path_template("/threads/{thread_id}/messages/{message_id}", thread_id=thread_id, message_id=message_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -386,7 +386,7 @@ async def create( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( - f"/threads/{thread_id}/messages", + path_template("/threads/{thread_id}/messages", thread_id=thread_id), body=await async_maybe_transform( { "content": content, @@ -433,7 +433,7 @@ async def retrieve( raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._get( - f"/threads/{thread_id}/messages/{message_id}", + path_template("/threads/{thread_id}/messages/{message_id}", thread_id=thread_id, message_id=message_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -479,7 +479,7 @@ async def update( raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( - f"/threads/{thread_id}/messages/{message_id}", + path_template("/threads/{thread_id}/messages/{message_id}", thread_id=thread_id, message_id=message_id), body=await async_maybe_transform({"metadata": metadata}, message_update_params.MessageUpdateParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -538,7 +538,7 @@ def list( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( - f"/threads/{thread_id}/messages", + path_template("/threads/{thread_id}/messages", thread_id=thread_id), page=AsyncCursorPage[Message], options=make_request_options( extra_headers=extra_headers, @@ -590,7 +590,7 @@ async def delete( raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._delete( - f"/threads/{thread_id}/messages/{message_id}", + path_template("/threads/{thread_id}/messages/{message_id}", thread_id=thread_id, message_id=message_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/beta/threads/runs/runs.py b/src/openai/resources/beta/threads/runs/runs.py index 20862185d2..882e88dfa6 100644 --- a/src/openai/resources/beta/threads/runs/runs.py +++ b/src/openai/resources/beta/threads/runs/runs.py @@ -21,6 +21,7 @@ from ....._types import NOT_GIVEN, Body, Omit, Query, Headers, NotGiven, omit, not_given from ....._utils import ( is_given, + path_template, required_args, maybe_transform, async_maybe_transform, @@ -594,7 +595,7 @@ def create( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( - f"/threads/{thread_id}/runs", + path_template("/threads/{thread_id}/runs", thread_id=thread_id), body=maybe_transform( { "assistant_id": assistant_id, @@ -661,7 +662,7 @@ def retrieve( raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get( - f"/threads/{thread_id}/runs/{run_id}", + path_template("/threads/{thread_id}/runs/{run_id}", thread_id=thread_id, run_id=run_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -707,7 +708,7 @@ def update( raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( - f"/threads/{thread_id}/runs/{run_id}", + path_template("/threads/{thread_id}/runs/{run_id}", thread_id=thread_id, run_id=run_id), body=maybe_transform({"metadata": metadata}, run_update_params.RunUpdateParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -763,7 +764,7 @@ def list( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( - f"/threads/{thread_id}/runs", + path_template("/threads/{thread_id}/runs", thread_id=thread_id), page=SyncCursorPage[Run], options=make_request_options( extra_headers=extra_headers, @@ -814,7 +815,7 @@ def cancel( raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( - f"/threads/{thread_id}/runs/{run_id}/cancel", + path_template("/threads/{thread_id}/runs/{run_id}/cancel", thread_id=thread_id, run_id=run_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -998,7 +999,7 @@ def create_and_stream( } make_request = partial( self._post, - f"/threads/{thread_id}/runs", + path_template("/threads/{thread_id}/runs", thread_id=thread_id), body=maybe_transform( { "assistant_id": assistant_id, @@ -1185,7 +1186,7 @@ def stream( } make_request = partial( self._post, - f"/threads/{thread_id}/runs", + path_template("/threads/{thread_id}/runs", thread_id=thread_id), body=maybe_transform( { "assistant_id": assistant_id, @@ -1361,7 +1362,7 @@ def submit_tool_outputs( raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( - f"/threads/{thread_id}/runs/{run_id}/submit_tool_outputs", + path_template("/threads/{thread_id}/runs/{run_id}/submit_tool_outputs", thread_id=thread_id, run_id=run_id), body=maybe_transform( { "tool_outputs": tool_outputs, @@ -1502,7 +1503,7 @@ def submit_tool_outputs_stream( } request = partial( self._post, - f"/threads/{thread_id}/runs/{run_id}/submit_tool_outputs", + path_template("/threads/{thread_id}/runs/{run_id}/submit_tool_outputs", thread_id=thread_id, run_id=run_id), body=maybe_transform( { "tool_outputs": tool_outputs, @@ -2057,7 +2058,7 @@ async def create( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( - f"/threads/{thread_id}/runs", + path_template("/threads/{thread_id}/runs", thread_id=thread_id), body=await async_maybe_transform( { "assistant_id": assistant_id, @@ -2124,7 +2125,7 @@ async def retrieve( raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._get( - f"/threads/{thread_id}/runs/{run_id}", + path_template("/threads/{thread_id}/runs/{run_id}", thread_id=thread_id, run_id=run_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -2170,7 +2171,7 @@ async def update( raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( - f"/threads/{thread_id}/runs/{run_id}", + path_template("/threads/{thread_id}/runs/{run_id}", thread_id=thread_id, run_id=run_id), body=await async_maybe_transform({"metadata": metadata}, run_update_params.RunUpdateParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -2226,7 +2227,7 @@ def list( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( - f"/threads/{thread_id}/runs", + path_template("/threads/{thread_id}/runs", thread_id=thread_id), page=AsyncCursorPage[Run], options=make_request_options( extra_headers=extra_headers, @@ -2277,7 +2278,7 @@ async def cancel( raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( - f"/threads/{thread_id}/runs/{run_id}/cancel", + path_template("/threads/{thread_id}/runs/{run_id}/cancel", thread_id=thread_id, run_id=run_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -2460,7 +2461,7 @@ def create_and_stream( **(extra_headers or {}), } request = self._post( - f"/threads/{thread_id}/runs", + path_template("/threads/{thread_id}/runs", thread_id=thread_id), body=maybe_transform( { "assistant_id": assistant_id, @@ -2647,7 +2648,7 @@ def stream( **(extra_headers or {}), } request = self._post( - f"/threads/{thread_id}/runs", + path_template("/threads/{thread_id}/runs", thread_id=thread_id), body=maybe_transform( { "assistant_id": assistant_id, @@ -2823,7 +2824,7 @@ async def submit_tool_outputs( raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( - f"/threads/{thread_id}/runs/{run_id}/submit_tool_outputs", + path_template("/threads/{thread_id}/runs/{run_id}/submit_tool_outputs", thread_id=thread_id, run_id=run_id), body=await async_maybe_transform( { "tool_outputs": tool_outputs, @@ -2966,7 +2967,7 @@ def submit_tool_outputs_stream( **(extra_headers or {}), } request = self._post( - f"/threads/{thread_id}/runs/{run_id}/submit_tool_outputs", + path_template("/threads/{thread_id}/runs/{run_id}/submit_tool_outputs", thread_id=thread_id, run_id=run_id), body=maybe_transform( { "tool_outputs": tool_outputs, diff --git a/src/openai/resources/beta/threads/runs/steps.py b/src/openai/resources/beta/threads/runs/steps.py index dea5df69bc..9a6402b263 100644 --- a/src/openai/resources/beta/threads/runs/steps.py +++ b/src/openai/resources/beta/threads/runs/steps.py @@ -10,7 +10,7 @@ from ..... import _legacy_response from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ....._utils import maybe_transform, async_maybe_transform +from ....._utils import path_template, maybe_transform, async_maybe_transform from ....._compat import cached_property from ....._resource import SyncAPIResource, AsyncAPIResource from ....._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -88,7 +88,12 @@ def retrieve( raise ValueError(f"Expected a non-empty value for `step_id` but received {step_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get( - f"/threads/{thread_id}/runs/{run_id}/steps/{step_id}", + path_template( + "/threads/{thread_id}/runs/{run_id}/steps/{step_id}", + thread_id=thread_id, + run_id=run_id, + step_id=step_id, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -159,7 +164,7 @@ def list( raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( - f"/threads/{thread_id}/runs/{run_id}/steps", + path_template("/threads/{thread_id}/runs/{run_id}/steps", thread_id=thread_id, run_id=run_id), page=SyncCursorPage[RunStep], options=make_request_options( extra_headers=extra_headers, @@ -246,7 +251,12 @@ async def retrieve( raise ValueError(f"Expected a non-empty value for `step_id` but received {step_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._get( - f"/threads/{thread_id}/runs/{run_id}/steps/{step_id}", + path_template( + "/threads/{thread_id}/runs/{run_id}/steps/{step_id}", + thread_id=thread_id, + run_id=run_id, + step_id=step_id, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -317,7 +327,7 @@ def list( raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( - f"/threads/{thread_id}/runs/{run_id}/steps", + path_template("/threads/{thread_id}/runs/{run_id}/steps", thread_id=thread_id, run_id=run_id), page=AsyncCursorPage[RunStep], options=make_request_options( extra_headers=extra_headers, diff --git a/src/openai/resources/beta/threads/threads.py b/src/openai/resources/beta/threads/threads.py index 0a93baf452..4b0f18fe47 100644 --- a/src/openai/resources/beta/threads/threads.py +++ b/src/openai/resources/beta/threads/threads.py @@ -19,7 +19,7 @@ AsyncMessagesWithStreamingResponse, ) from ...._types import NOT_GIVEN, Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import required_args, maybe_transform, async_maybe_transform +from ...._utils import path_template, required_args, maybe_transform, async_maybe_transform from .runs.runs import ( Runs, AsyncRuns, @@ -177,7 +177,7 @@ def retrieve( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get( - f"/threads/{thread_id}", + path_template("/threads/{thread_id}", thread_id=thread_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -226,7 +226,7 @@ def update( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( - f"/threads/{thread_id}", + path_template("/threads/{thread_id}", thread_id=thread_id), body=maybe_transform( { "metadata": metadata, @@ -268,7 +268,7 @@ def delete( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._delete( - f"/threads/{thread_id}", + path_template("/threads/{thread_id}", thread_id=thread_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1043,7 +1043,7 @@ async def retrieve( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._get( - f"/threads/{thread_id}", + path_template("/threads/{thread_id}", thread_id=thread_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1092,7 +1092,7 @@ async def update( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( - f"/threads/{thread_id}", + path_template("/threads/{thread_id}", thread_id=thread_id), body=await async_maybe_transform( { "metadata": metadata, @@ -1134,7 +1134,7 @@ async def delete( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._delete( - f"/threads/{thread_id}", + path_template("/threads/{thread_id}", thread_id=thread_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index a705c1f658..845bd1a1e1 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -20,7 +20,7 @@ AsyncMessagesWithStreamingResponse, ) from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given -from ...._utils import required_args, maybe_transform, async_maybe_transform +from ...._utils import path_template, required_args, maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -1288,7 +1288,7 @@ def retrieve( if not completion_id: raise ValueError(f"Expected a non-empty value for `completion_id` but received {completion_id!r}") return self._get( - f"/chat/completions/{completion_id}", + path_template("/chat/completions/{completion_id}", completion_id=completion_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1332,7 +1332,7 @@ def update( if not completion_id: raise ValueError(f"Expected a non-empty value for `completion_id` but received {completion_id!r}") return self._post( - f"/chat/completions/{completion_id}", + path_template("/chat/completions/{completion_id}", completion_id=completion_id), body=maybe_transform({"metadata": metadata}, completion_update_params.CompletionUpdateParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -1433,7 +1433,7 @@ def delete( if not completion_id: raise ValueError(f"Expected a non-empty value for `completion_id` but received {completion_id!r}") return self._delete( - f"/chat/completions/{completion_id}", + path_template("/chat/completions/{completion_id}", completion_id=completion_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -2791,7 +2791,7 @@ async def retrieve( if not completion_id: raise ValueError(f"Expected a non-empty value for `completion_id` but received {completion_id!r}") return await self._get( - f"/chat/completions/{completion_id}", + path_template("/chat/completions/{completion_id}", completion_id=completion_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -2835,7 +2835,7 @@ async def update( if not completion_id: raise ValueError(f"Expected a non-empty value for `completion_id` but received {completion_id!r}") return await self._post( - f"/chat/completions/{completion_id}", + path_template("/chat/completions/{completion_id}", completion_id=completion_id), body=await async_maybe_transform({"metadata": metadata}, completion_update_params.CompletionUpdateParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -2936,7 +2936,7 @@ async def delete( if not completion_id: raise ValueError(f"Expected a non-empty value for `completion_id` but received {completion_id!r}") return await self._delete( - f"/chat/completions/{completion_id}", + path_template("/chat/completions/{completion_id}", completion_id=completion_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/chat/completions/messages.py b/src/openai/resources/chat/completions/messages.py index b1c6a08d51..ffbff566db 100644 --- a/src/openai/resources/chat/completions/messages.py +++ b/src/openai/resources/chat/completions/messages.py @@ -8,7 +8,7 @@ from .... import _legacy_response from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import maybe_transform +from ...._utils import path_template, maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -82,7 +82,7 @@ def list( if not completion_id: raise ValueError(f"Expected a non-empty value for `completion_id` but received {completion_id!r}") return self._get_api_list( - f"/chat/completions/{completion_id}/messages", + path_template("/chat/completions/{completion_id}/messages", completion_id=completion_id), page=SyncCursorPage[ChatCompletionStoreMessage], options=make_request_options( extra_headers=extra_headers, @@ -164,7 +164,7 @@ def list( if not completion_id: raise ValueError(f"Expected a non-empty value for `completion_id` but received {completion_id!r}") return self._get_api_list( - f"/chat/completions/{completion_id}/messages", + path_template("/chat/completions/{completion_id}/messages", completion_id=completion_id), page=AsyncCursorPage[ChatCompletionStoreMessage], options=make_request_options( extra_headers=extra_headers, diff --git a/src/openai/resources/containers/containers.py b/src/openai/resources/containers/containers.py index 216097d9c8..f6b8c33c75 100644 --- a/src/openai/resources/containers/containers.py +++ b/src/openai/resources/containers/containers.py @@ -10,7 +10,7 @@ from ... import _legacy_response from ...types import container_list_params, container_create_params from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform +from ..._utils import path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -140,7 +140,7 @@ def retrieve( if not container_id: raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") return self._get( - f"/containers/{container_id}", + path_template("/containers/{container_id}", container_id=container_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -235,7 +235,7 @@ def delete( raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._delete( - f"/containers/{container_id}", + path_template("/containers/{container_id}", container_id=container_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -352,7 +352,7 @@ async def retrieve( if not container_id: raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") return await self._get( - f"/containers/{container_id}", + path_template("/containers/{container_id}", container_id=container_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -447,7 +447,7 @@ async def delete( raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._delete( - f"/containers/{container_id}", + path_template("/containers/{container_id}", container_id=container_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/containers/files/content.py b/src/openai/resources/containers/files/content.py index a3dbd0e8c7..eb915b9c13 100644 --- a/src/openai/resources/containers/files/content.py +++ b/src/openai/resources/containers/files/content.py @@ -6,6 +6,7 @@ from .... import _legacy_response from ...._types import Body, Query, Headers, NotGiven, not_given +from ...._utils import path_template from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import ( @@ -69,7 +70,9 @@ def retrieve( raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") extra_headers = {"Accept": "application/binary", **(extra_headers or {})} return self._get( - f"/containers/{container_id}/files/{file_id}/content", + path_template( + "/containers/{container_id}/files/{file_id}/content", container_id=container_id, file_id=file_id + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -127,7 +130,9 @@ async def retrieve( raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") extra_headers = {"Accept": "application/binary", **(extra_headers or {})} return await self._get( - f"/containers/{container_id}/files/{file_id}/content", + path_template( + "/containers/{container_id}/files/{file_id}/content", container_id=container_id, file_id=file_id + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/containers/files/files.py b/src/openai/resources/containers/files/files.py index 62659a5c3d..f48adf3a2a 100644 --- a/src/openai/resources/containers/files/files.py +++ b/src/openai/resources/containers/files/files.py @@ -17,7 +17,7 @@ AsyncContentWithStreamingResponse, ) from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, FileTypes, omit, not_given -from ...._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform +from ...._utils import extract_files, path_template, maybe_transform, deepcopy_minimal, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -102,7 +102,7 @@ def create( # multipart/form-data; boundary=---abc-- extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} return self._post( - f"/containers/{container_id}/files", + path_template("/containers/{container_id}/files", container_id=container_id), body=maybe_transform(body, file_create_params.FileCreateParams), files=files, options=make_request_options( @@ -140,7 +140,7 @@ def retrieve( if not file_id: raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") return self._get( - f"/containers/{container_id}/files/{file_id}", + path_template("/containers/{container_id}/files/{file_id}", container_id=container_id, file_id=file_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -188,7 +188,7 @@ def list( if not container_id: raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") return self._get_api_list( - f"/containers/{container_id}/files", + path_template("/containers/{container_id}/files", container_id=container_id), page=SyncCursorPage[FileListResponse], options=make_request_options( extra_headers=extra_headers, @@ -237,7 +237,7 @@ def delete( raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._delete( - f"/containers/{container_id}/files/{file_id}", + path_template("/containers/{container_id}/files/{file_id}", container_id=container_id, file_id=file_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -316,7 +316,7 @@ async def create( # multipart/form-data; boundary=---abc-- extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} return await self._post( - f"/containers/{container_id}/files", + path_template("/containers/{container_id}/files", container_id=container_id), body=await async_maybe_transform(body, file_create_params.FileCreateParams), files=files, options=make_request_options( @@ -354,7 +354,7 @@ async def retrieve( if not file_id: raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") return await self._get( - f"/containers/{container_id}/files/{file_id}", + path_template("/containers/{container_id}/files/{file_id}", container_id=container_id, file_id=file_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -402,7 +402,7 @@ def list( if not container_id: raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") return self._get_api_list( - f"/containers/{container_id}/files", + path_template("/containers/{container_id}/files", container_id=container_id), page=AsyncCursorPage[FileListResponse], options=make_request_options( extra_headers=extra_headers, @@ -451,7 +451,7 @@ async def delete( raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._delete( - f"/containers/{container_id}/files/{file_id}", + path_template("/containers/{container_id}/files/{file_id}", container_id=container_id, file_id=file_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/conversations/conversations.py b/src/openai/resources/conversations/conversations.py index f2c54e4d04..d349f38546 100644 --- a/src/openai/resources/conversations/conversations.py +++ b/src/openai/resources/conversations/conversations.py @@ -16,7 +16,7 @@ AsyncItemsWithStreamingResponse, ) from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform +from ..._utils import path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -132,7 +132,7 @@ def retrieve( if not conversation_id: raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") return self._get( - f"/conversations/{conversation_id}", + path_template("/conversations/{conversation_id}", conversation_id=conversation_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -173,7 +173,7 @@ def update( if not conversation_id: raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") return self._post( - f"/conversations/{conversation_id}", + path_template("/conversations/{conversation_id}", conversation_id=conversation_id), body=maybe_transform({"metadata": metadata}, conversation_update_params.ConversationUpdateParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -208,7 +208,7 @@ def delete( if not conversation_id: raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") return self._delete( - f"/conversations/{conversation_id}", + path_template("/conversations/{conversation_id}", conversation_id=conversation_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -318,7 +318,7 @@ async def retrieve( if not conversation_id: raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") return await self._get( - f"/conversations/{conversation_id}", + path_template("/conversations/{conversation_id}", conversation_id=conversation_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -359,7 +359,7 @@ async def update( if not conversation_id: raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") return await self._post( - f"/conversations/{conversation_id}", + path_template("/conversations/{conversation_id}", conversation_id=conversation_id), body=await async_maybe_transform( {"metadata": metadata}, conversation_update_params.ConversationUpdateParams ), @@ -396,7 +396,7 @@ async def delete( if not conversation_id: raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") return await self._delete( - f"/conversations/{conversation_id}", + path_template("/conversations/{conversation_id}", conversation_id=conversation_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/conversations/items.py b/src/openai/resources/conversations/items.py index 1f8e101f7f..7d7c9a4aba 100644 --- a/src/openai/resources/conversations/items.py +++ b/src/openai/resources/conversations/items.py @@ -9,7 +9,7 @@ from ... import _legacy_response from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform +from ..._utils import path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -81,7 +81,7 @@ def create( if not conversation_id: raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") return self._post( - f"/conversations/{conversation_id}/items", + path_template("/conversations/{conversation_id}/items", conversation_id=conversation_id), body=maybe_transform({"items": items}, item_create_params.ItemCreateParams), options=make_request_options( extra_headers=extra_headers, @@ -129,7 +129,9 @@ def retrieve( return cast( ConversationItem, self._get( - f"/conversations/{conversation_id}/items/{item_id}", + path_template( + "/conversations/{conversation_id}/items/{item_id}", conversation_id=conversation_id, item_id=item_id + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -200,7 +202,7 @@ def list( if not conversation_id: raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") return self._get_api_list( - f"/conversations/{conversation_id}/items", + path_template("/conversations/{conversation_id}/items", conversation_id=conversation_id), page=SyncConversationCursorPage[ConversationItem], options=make_request_options( extra_headers=extra_headers, @@ -249,7 +251,9 @@ def delete( if not item_id: raise ValueError(f"Expected a non-empty value for `item_id` but received {item_id!r}") return self._delete( - f"/conversations/{conversation_id}/items/{item_id}", + path_template( + "/conversations/{conversation_id}/items/{item_id}", conversation_id=conversation_id, item_id=item_id + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -313,7 +317,7 @@ async def create( if not conversation_id: raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") return await self._post( - f"/conversations/{conversation_id}/items", + path_template("/conversations/{conversation_id}/items", conversation_id=conversation_id), body=await async_maybe_transform({"items": items}, item_create_params.ItemCreateParams), options=make_request_options( extra_headers=extra_headers, @@ -361,7 +365,9 @@ async def retrieve( return cast( ConversationItem, await self._get( - f"/conversations/{conversation_id}/items/{item_id}", + path_template( + "/conversations/{conversation_id}/items/{item_id}", conversation_id=conversation_id, item_id=item_id + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -432,7 +438,7 @@ def list( if not conversation_id: raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") return self._get_api_list( - f"/conversations/{conversation_id}/items", + path_template("/conversations/{conversation_id}/items", conversation_id=conversation_id), page=AsyncConversationCursorPage[ConversationItem], options=make_request_options( extra_headers=extra_headers, @@ -481,7 +487,9 @@ async def delete( if not item_id: raise ValueError(f"Expected a non-empty value for `item_id` but received {item_id!r}") return await self._delete( - f"/conversations/{conversation_id}/items/{item_id}", + path_template( + "/conversations/{conversation_id}/items/{item_id}", conversation_id=conversation_id, item_id=item_id + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/evals/evals.py b/src/openai/resources/evals/evals.py index f0fe28fe8c..6acd669a2c 100644 --- a/src/openai/resources/evals/evals.py +++ b/src/openai/resources/evals/evals.py @@ -10,7 +10,7 @@ from ... import _legacy_response from ...types import eval_list_params, eval_create_params, eval_update_params from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform +from ..._utils import path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from .runs.runs import ( Runs, @@ -152,7 +152,7 @@ def retrieve( if not eval_id: raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") return self._get( - f"/evals/{eval_id}", + path_template("/evals/{eval_id}", eval_id=eval_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -196,7 +196,7 @@ def update( if not eval_id: raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") return self._post( - f"/evals/{eval_id}", + path_template("/evals/{eval_id}", eval_id=eval_id), body=maybe_transform( { "metadata": metadata, @@ -293,7 +293,7 @@ def delete( if not eval_id: raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") return self._delete( - f"/evals/{eval_id}", + path_template("/evals/{eval_id}", eval_id=eval_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -419,7 +419,7 @@ async def retrieve( if not eval_id: raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") return await self._get( - f"/evals/{eval_id}", + path_template("/evals/{eval_id}", eval_id=eval_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -463,7 +463,7 @@ async def update( if not eval_id: raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") return await self._post( - f"/evals/{eval_id}", + path_template("/evals/{eval_id}", eval_id=eval_id), body=await async_maybe_transform( { "metadata": metadata, @@ -560,7 +560,7 @@ async def delete( if not eval_id: raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") return await self._delete( - f"/evals/{eval_id}", + path_template("/evals/{eval_id}", eval_id=eval_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/evals/runs/output_items.py b/src/openai/resources/evals/runs/output_items.py index c2e6647715..7a498a7ebf 100644 --- a/src/openai/resources/evals/runs/output_items.py +++ b/src/openai/resources/evals/runs/output_items.py @@ -8,7 +8,7 @@ from .... import _legacy_response from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import maybe_transform +from ...._utils import path_template, maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -75,7 +75,12 @@ def retrieve( if not output_item_id: raise ValueError(f"Expected a non-empty value for `output_item_id` but received {output_item_id!r}") return self._get( - f"/evals/{eval_id}/runs/{run_id}/output_items/{output_item_id}", + path_template( + "/evals/{eval_id}/runs/{run_id}/output_items/{output_item_id}", + eval_id=eval_id, + run_id=run_id, + output_item_id=output_item_id, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -125,7 +130,7 @@ def list( if not run_id: raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") return self._get_api_list( - f"/evals/{eval_id}/runs/{run_id}/output_items", + path_template("/evals/{eval_id}/runs/{run_id}/output_items", eval_id=eval_id, run_id=run_id), page=SyncCursorPage[OutputItemListResponse], options=make_request_options( extra_headers=extra_headers, @@ -200,7 +205,12 @@ async def retrieve( if not output_item_id: raise ValueError(f"Expected a non-empty value for `output_item_id` but received {output_item_id!r}") return await self._get( - f"/evals/{eval_id}/runs/{run_id}/output_items/{output_item_id}", + path_template( + "/evals/{eval_id}/runs/{run_id}/output_items/{output_item_id}", + eval_id=eval_id, + run_id=run_id, + output_item_id=output_item_id, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -250,7 +260,7 @@ def list( if not run_id: raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") return self._get_api_list( - f"/evals/{eval_id}/runs/{run_id}/output_items", + path_template("/evals/{eval_id}/runs/{run_id}/output_items", eval_id=eval_id, run_id=run_id), page=AsyncCursorPage[OutputItemListResponse], options=make_request_options( extra_headers=extra_headers, diff --git a/src/openai/resources/evals/runs/runs.py b/src/openai/resources/evals/runs/runs.py index 49eecd768f..152ce9cb77 100644 --- a/src/openai/resources/evals/runs/runs.py +++ b/src/openai/resources/evals/runs/runs.py @@ -9,7 +9,7 @@ from .... import _legacy_response from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import maybe_transform, async_maybe_transform +from ...._utils import path_template, maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -103,7 +103,7 @@ def create( if not eval_id: raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") return self._post( - f"/evals/{eval_id}/runs", + path_template("/evals/{eval_id}/runs", eval_id=eval_id), body=maybe_transform( { "data_source": data_source, @@ -147,7 +147,7 @@ def retrieve( if not run_id: raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") return self._get( - f"/evals/{eval_id}/runs/{run_id}", + path_template("/evals/{eval_id}/runs/{run_id}", eval_id=eval_id, run_id=run_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -194,7 +194,7 @@ def list( if not eval_id: raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") return self._get_api_list( - f"/evals/{eval_id}/runs", + path_template("/evals/{eval_id}/runs", eval_id=eval_id), page=SyncCursorPage[RunListResponse], options=make_request_options( extra_headers=extra_headers, @@ -243,7 +243,7 @@ def delete( if not run_id: raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") return self._delete( - f"/evals/{eval_id}/runs/{run_id}", + path_template("/evals/{eval_id}/runs/{run_id}", eval_id=eval_id, run_id=run_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -279,7 +279,7 @@ def cancel( if not run_id: raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") return self._post( - f"/evals/{eval_id}/runs/{run_id}", + path_template("/evals/{eval_id}/runs/{run_id}", eval_id=eval_id, run_id=run_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -356,7 +356,7 @@ async def create( if not eval_id: raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") return await self._post( - f"/evals/{eval_id}/runs", + path_template("/evals/{eval_id}/runs", eval_id=eval_id), body=await async_maybe_transform( { "data_source": data_source, @@ -400,7 +400,7 @@ async def retrieve( if not run_id: raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") return await self._get( - f"/evals/{eval_id}/runs/{run_id}", + path_template("/evals/{eval_id}/runs/{run_id}", eval_id=eval_id, run_id=run_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -447,7 +447,7 @@ def list( if not eval_id: raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") return self._get_api_list( - f"/evals/{eval_id}/runs", + path_template("/evals/{eval_id}/runs", eval_id=eval_id), page=AsyncCursorPage[RunListResponse], options=make_request_options( extra_headers=extra_headers, @@ -496,7 +496,7 @@ async def delete( if not run_id: raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") return await self._delete( - f"/evals/{eval_id}/runs/{run_id}", + path_template("/evals/{eval_id}/runs/{run_id}", eval_id=eval_id, run_id=run_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -532,7 +532,7 @@ async def cancel( if not run_id: raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") return await self._post( - f"/evals/{eval_id}/runs/{run_id}", + path_template("/evals/{eval_id}/runs/{run_id}", eval_id=eval_id, run_id=run_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/files.py b/src/openai/resources/files.py index 7341b326dc..b03f11b06a 100644 --- a/src/openai/resources/files.py +++ b/src/openai/resources/files.py @@ -12,7 +12,7 @@ from .. import _legacy_response from ..types import FilePurpose, file_list_params, file_create_params from .._types import Body, Omit, Query, Headers, NotGiven, FileTypes, omit, not_given -from .._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform +from .._utils import extract_files, path_template, maybe_transform, deepcopy_minimal, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import ( @@ -164,7 +164,7 @@ def retrieve( if not file_id: raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") return self._get( - f"/files/{file_id}", + path_template("/files/{file_id}", file_id=file_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -258,7 +258,7 @@ def delete( if not file_id: raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") return self._delete( - f"/files/{file_id}", + path_template("/files/{file_id}", file_id=file_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -292,7 +292,7 @@ def content( raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") extra_headers = {"Accept": "application/binary", **(extra_headers or {})} return self._get( - f"/files/{file_id}/content", + path_template("/files/{file_id}/content", file_id=file_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -326,7 +326,7 @@ def retrieve_content( if not file_id: raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") return self._get( - f"/files/{file_id}/content", + path_template("/files/{file_id}/content", file_id=file_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -489,7 +489,7 @@ async def retrieve( if not file_id: raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") return await self._get( - f"/files/{file_id}", + path_template("/files/{file_id}", file_id=file_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -583,7 +583,7 @@ async def delete( if not file_id: raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") return await self._delete( - f"/files/{file_id}", + path_template("/files/{file_id}", file_id=file_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -617,7 +617,7 @@ async def content( raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") extra_headers = {"Accept": "application/binary", **(extra_headers or {})} return await self._get( - f"/files/{file_id}/content", + path_template("/files/{file_id}/content", file_id=file_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -651,7 +651,7 @@ async def retrieve_content( if not file_id: raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") return await self._get( - f"/files/{file_id}/content", + path_template("/files/{file_id}/content", file_id=file_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/fine_tuning/checkpoints/permissions.py b/src/openai/resources/fine_tuning/checkpoints/permissions.py index 35e06feee0..15184e130b 100644 --- a/src/openai/resources/fine_tuning/checkpoints/permissions.py +++ b/src/openai/resources/fine_tuning/checkpoints/permissions.py @@ -9,7 +9,7 @@ from .... import _legacy_response from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given -from ...._utils import maybe_transform, async_maybe_transform +from ...._utils import path_template, maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -84,7 +84,10 @@ def create( f"Expected a non-empty value for `fine_tuned_model_checkpoint` but received {fine_tuned_model_checkpoint!r}" ) return self._get_api_list( - f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + path_template( + "/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + fine_tuned_model_checkpoint=fine_tuned_model_checkpoint, + ), page=SyncPage[PermissionCreateResponse], body=maybe_transform({"project_ids": project_ids}, permission_create_params.PermissionCreateParams), options=make_request_options( @@ -138,7 +141,10 @@ def retrieve( f"Expected a non-empty value for `fine_tuned_model_checkpoint` but received {fine_tuned_model_checkpoint!r}" ) return self._get( - f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + path_template( + "/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + fine_tuned_model_checkpoint=fine_tuned_model_checkpoint, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -200,7 +206,10 @@ def list( f"Expected a non-empty value for `fine_tuned_model_checkpoint` but received {fine_tuned_model_checkpoint!r}" ) return self._get_api_list( - f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + path_template( + "/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + fine_tuned_model_checkpoint=fine_tuned_model_checkpoint, + ), page=SyncConversationCursorPage[PermissionListResponse], options=make_request_options( extra_headers=extra_headers, @@ -254,7 +263,11 @@ def delete( if not permission_id: raise ValueError(f"Expected a non-empty value for `permission_id` but received {permission_id!r}") return self._delete( - f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions/{permission_id}", + path_template( + "/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions/{permission_id}", + fine_tuned_model_checkpoint=fine_tuned_model_checkpoint, + permission_id=permission_id, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -318,7 +331,10 @@ def create( f"Expected a non-empty value for `fine_tuned_model_checkpoint` but received {fine_tuned_model_checkpoint!r}" ) return self._get_api_list( - f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + path_template( + "/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + fine_tuned_model_checkpoint=fine_tuned_model_checkpoint, + ), page=AsyncPage[PermissionCreateResponse], body=maybe_transform({"project_ids": project_ids}, permission_create_params.PermissionCreateParams), options=make_request_options( @@ -372,7 +388,10 @@ async def retrieve( f"Expected a non-empty value for `fine_tuned_model_checkpoint` but received {fine_tuned_model_checkpoint!r}" ) return await self._get( - f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + path_template( + "/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + fine_tuned_model_checkpoint=fine_tuned_model_checkpoint, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -434,7 +453,10 @@ def list( f"Expected a non-empty value for `fine_tuned_model_checkpoint` but received {fine_tuned_model_checkpoint!r}" ) return self._get_api_list( - f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + path_template( + "/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + fine_tuned_model_checkpoint=fine_tuned_model_checkpoint, + ), page=AsyncConversationCursorPage[PermissionListResponse], options=make_request_options( extra_headers=extra_headers, @@ -488,7 +510,11 @@ async def delete( if not permission_id: raise ValueError(f"Expected a non-empty value for `permission_id` but received {permission_id!r}") return await self._delete( - f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions/{permission_id}", + path_template( + "/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions/{permission_id}", + fine_tuned_model_checkpoint=fine_tuned_model_checkpoint, + permission_id=permission_id, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/fine_tuning/jobs/checkpoints.py b/src/openai/resources/fine_tuning/jobs/checkpoints.py index 6f14a0994e..0f91a6218a 100644 --- a/src/openai/resources/fine_tuning/jobs/checkpoints.py +++ b/src/openai/resources/fine_tuning/jobs/checkpoints.py @@ -6,7 +6,7 @@ from .... import _legacy_response from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import maybe_transform +from ...._utils import path_template, maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -75,7 +75,7 @@ def list( if not fine_tuning_job_id: raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") return self._get_api_list( - f"/fine_tuning/jobs/{fine_tuning_job_id}/checkpoints", + path_template("/fine_tuning/jobs/{fine_tuning_job_id}/checkpoints", fine_tuning_job_id=fine_tuning_job_id), page=SyncCursorPage[FineTuningJobCheckpoint], options=make_request_options( extra_headers=extra_headers, @@ -148,7 +148,7 @@ def list( if not fine_tuning_job_id: raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") return self._get_api_list( - f"/fine_tuning/jobs/{fine_tuning_job_id}/checkpoints", + path_template("/fine_tuning/jobs/{fine_tuning_job_id}/checkpoints", fine_tuning_job_id=fine_tuning_job_id), page=AsyncCursorPage[FineTuningJobCheckpoint], options=make_request_options( extra_headers=extra_headers, diff --git a/src/openai/resources/fine_tuning/jobs/jobs.py b/src/openai/resources/fine_tuning/jobs/jobs.py index e38baa5539..a948b10349 100644 --- a/src/openai/resources/fine_tuning/jobs/jobs.py +++ b/src/openai/resources/fine_tuning/jobs/jobs.py @@ -9,7 +9,7 @@ from .... import _legacy_response from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import maybe_transform, async_maybe_transform +from ...._utils import path_template, maybe_transform, async_maybe_transform from ...._compat import cached_property from .checkpoints import ( Checkpoints, @@ -208,7 +208,7 @@ def retrieve( if not fine_tuning_job_id: raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") return self._get( - f"/fine_tuning/jobs/{fine_tuning_job_id}", + path_template("/fine_tuning/jobs/{fine_tuning_job_id}", fine_tuning_job_id=fine_tuning_job_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -293,7 +293,7 @@ def cancel( if not fine_tuning_job_id: raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") return self._post( - f"/fine_tuning/jobs/{fine_tuning_job_id}/cancel", + path_template("/fine_tuning/jobs/{fine_tuning_job_id}/cancel", fine_tuning_job_id=fine_tuning_job_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -332,7 +332,7 @@ def list_events( if not fine_tuning_job_id: raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") return self._get_api_list( - f"/fine_tuning/jobs/{fine_tuning_job_id}/events", + path_template("/fine_tuning/jobs/{fine_tuning_job_id}/events", fine_tuning_job_id=fine_tuning_job_id), page=SyncCursorPage[FineTuningJobEvent], options=make_request_options( extra_headers=extra_headers, @@ -376,7 +376,7 @@ def pause( if not fine_tuning_job_id: raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") return self._post( - f"/fine_tuning/jobs/{fine_tuning_job_id}/pause", + path_template("/fine_tuning/jobs/{fine_tuning_job_id}/pause", fine_tuning_job_id=fine_tuning_job_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -409,7 +409,7 @@ def resume( if not fine_tuning_job_id: raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") return self._post( - f"/fine_tuning/jobs/{fine_tuning_job_id}/resume", + path_template("/fine_tuning/jobs/{fine_tuning_job_id}/resume", fine_tuning_job_id=fine_tuning_job_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -591,7 +591,7 @@ async def retrieve( if not fine_tuning_job_id: raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") return await self._get( - f"/fine_tuning/jobs/{fine_tuning_job_id}", + path_template("/fine_tuning/jobs/{fine_tuning_job_id}", fine_tuning_job_id=fine_tuning_job_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -676,7 +676,7 @@ async def cancel( if not fine_tuning_job_id: raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") return await self._post( - f"/fine_tuning/jobs/{fine_tuning_job_id}/cancel", + path_template("/fine_tuning/jobs/{fine_tuning_job_id}/cancel", fine_tuning_job_id=fine_tuning_job_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -715,7 +715,7 @@ def list_events( if not fine_tuning_job_id: raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") return self._get_api_list( - f"/fine_tuning/jobs/{fine_tuning_job_id}/events", + path_template("/fine_tuning/jobs/{fine_tuning_job_id}/events", fine_tuning_job_id=fine_tuning_job_id), page=AsyncCursorPage[FineTuningJobEvent], options=make_request_options( extra_headers=extra_headers, @@ -759,7 +759,7 @@ async def pause( if not fine_tuning_job_id: raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") return await self._post( - f"/fine_tuning/jobs/{fine_tuning_job_id}/pause", + path_template("/fine_tuning/jobs/{fine_tuning_job_id}/pause", fine_tuning_job_id=fine_tuning_job_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -792,7 +792,7 @@ async def resume( if not fine_tuning_job_id: raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") return await self._post( - f"/fine_tuning/jobs/{fine_tuning_job_id}/resume", + path_template("/fine_tuning/jobs/{fine_tuning_job_id}/resume", fine_tuning_job_id=fine_tuning_job_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/models.py b/src/openai/resources/models.py index 508393263f..a1fe0d395e 100644 --- a/src/openai/resources/models.py +++ b/src/openai/resources/models.py @@ -6,6 +6,7 @@ from .. import _legacy_response from .._types import Body, Query, Headers, NotGiven, not_given +from .._utils import path_template from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -69,7 +70,7 @@ def retrieve( if not model: raise ValueError(f"Expected a non-empty value for `model` but received {model!r}") return self._get( - f"/models/{model}", + path_template("/models/{model}", model=model), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -127,7 +128,7 @@ def delete( if not model: raise ValueError(f"Expected a non-empty value for `model` but received {model!r}") return self._delete( - f"/models/{model}", + path_template("/models/{model}", model=model), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -184,7 +185,7 @@ async def retrieve( if not model: raise ValueError(f"Expected a non-empty value for `model` but received {model!r}") return await self._get( - f"/models/{model}", + path_template("/models/{model}", model=model), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -242,7 +243,7 @@ async def delete( if not model: raise ValueError(f"Expected a non-empty value for `model` but received {model!r}") return await self._delete( - f"/models/{model}", + path_template("/models/{model}", model=model), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/realtime/calls.py b/src/openai/resources/realtime/calls.py index 1520a97b0a..f34748d239 100644 --- a/src/openai/resources/realtime/calls.py +++ b/src/openai/resources/realtime/calls.py @@ -9,7 +9,7 @@ from ... import _legacy_response from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform +from ..._utils import path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import ( @@ -230,7 +230,7 @@ def accept( raise ValueError(f"Expected a non-empty value for `call_id` but received {call_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._post( - f"/realtime/calls/{call_id}/accept", + path_template("/realtime/calls/{call_id}/accept", call_id=call_id), body=maybe_transform( { "type": type, @@ -281,7 +281,7 @@ def hangup( raise ValueError(f"Expected a non-empty value for `call_id` but received {call_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._post( - f"/realtime/calls/{call_id}/hangup", + path_template("/realtime/calls/{call_id}/hangup", call_id=call_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -319,7 +319,7 @@ def refer( raise ValueError(f"Expected a non-empty value for `call_id` but received {call_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._post( - f"/realtime/calls/{call_id}/refer", + path_template("/realtime/calls/{call_id}/refer", call_id=call_id), body=maybe_transform({"target_uri": target_uri}, call_refer_params.CallReferParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -358,7 +358,7 @@ def reject( raise ValueError(f"Expected a non-empty value for `call_id` but received {call_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._post( - f"/realtime/calls/{call_id}/reject", + path_template("/realtime/calls/{call_id}/reject", call_id=call_id), body=maybe_transform({"status_code": status_code}, call_reject_params.CallRejectParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -559,7 +559,7 @@ async def accept( raise ValueError(f"Expected a non-empty value for `call_id` but received {call_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._post( - f"/realtime/calls/{call_id}/accept", + path_template("/realtime/calls/{call_id}/accept", call_id=call_id), body=await async_maybe_transform( { "type": type, @@ -610,7 +610,7 @@ async def hangup( raise ValueError(f"Expected a non-empty value for `call_id` but received {call_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._post( - f"/realtime/calls/{call_id}/hangup", + path_template("/realtime/calls/{call_id}/hangup", call_id=call_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -648,7 +648,7 @@ async def refer( raise ValueError(f"Expected a non-empty value for `call_id` but received {call_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._post( - f"/realtime/calls/{call_id}/refer", + path_template("/realtime/calls/{call_id}/refer", call_id=call_id), body=await async_maybe_transform({"target_uri": target_uri}, call_refer_params.CallReferParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -687,7 +687,7 @@ async def reject( raise ValueError(f"Expected a non-empty value for `call_id` but received {call_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._post( - f"/realtime/calls/{call_id}/reject", + path_template("/realtime/calls/{call_id}/reject", call_id=call_id), body=await async_maybe_transform({"status_code": status_code}, call_reject_params.CallRejectParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout diff --git a/src/openai/resources/responses/input_items.py b/src/openai/resources/responses/input_items.py index 3311bfe10a..b9ae5eeeae 100644 --- a/src/openai/resources/responses/input_items.py +++ b/src/openai/resources/responses/input_items.py @@ -9,7 +9,7 @@ from ... import _legacy_response from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import maybe_transform +from ..._utils import path_template, maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -85,7 +85,7 @@ def list( if not response_id: raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") return self._get_api_list( - f"/responses/{response_id}/input_items", + path_template("/responses/{response_id}/input_items", response_id=response_id), page=SyncCursorPage[ResponseItem], options=make_request_options( extra_headers=extra_headers, @@ -169,7 +169,7 @@ def list( if not response_id: raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") return self._get_api_list( - f"/responses/{response_id}/input_items", + path_template("/responses/{response_id}/input_items", response_id=response_id), page=AsyncCursorPage[ResponseItem], options=make_request_options( extra_headers=extra_headers, diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 6d57f86313..63795f95a9 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -15,7 +15,7 @@ from ... import _legacy_response from ..._types import NOT_GIVEN, Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given -from ..._utils import is_given, maybe_transform, strip_not_given, async_maybe_transform +from ..._utils import is_given, path_template, maybe_transform, strip_not_given, async_maybe_transform from ..._compat import cached_property from ..._models import construct_type_unchecked from ..._resource import SyncAPIResource, AsyncAPIResource @@ -1471,7 +1471,7 @@ def retrieve( if not response_id: raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") return self._get( - f"/responses/{response_id}", + path_template("/responses/{response_id}", response_id=response_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -1519,7 +1519,7 @@ def delete( raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._delete( - f"/responses/{response_id}", + path_template("/responses/{response_id}", response_id=response_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1555,7 +1555,7 @@ def cancel( if not response_id: raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") return self._post( - f"/responses/{response_id}/cancel", + path_template("/responses/{response_id}/cancel", response_id=response_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -3142,7 +3142,7 @@ async def retrieve( if not response_id: raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") return await self._get( - f"/responses/{response_id}", + path_template("/responses/{response_id}", response_id=response_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -3190,7 +3190,7 @@ async def delete( raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._delete( - f"/responses/{response_id}", + path_template("/responses/{response_id}", response_id=response_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -3226,7 +3226,7 @@ async def cancel( if not response_id: raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") return await self._post( - f"/responses/{response_id}/cancel", + path_template("/responses/{response_id}/cancel", response_id=response_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/skills/content.py b/src/openai/resources/skills/content.py index c912fd3eb3..96b237177e 100644 --- a/src/openai/resources/skills/content.py +++ b/src/openai/resources/skills/content.py @@ -6,6 +6,7 @@ from ... import _legacy_response from ..._types import Body, Query, Headers, NotGiven, not_given +from ..._utils import path_template from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import ( @@ -66,7 +67,7 @@ def retrieve( raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") extra_headers = {"Accept": "application/binary", **(extra_headers or {})} return self._get( - f"/skills/{skill_id}/content", + path_template("/skills/{skill_id}/content", skill_id=skill_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -121,7 +122,7 @@ async def retrieve( raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") extra_headers = {"Accept": "application/binary", **(extra_headers or {})} return await self._get( - f"/skills/{skill_id}/content", + path_template("/skills/{skill_id}/content", skill_id=skill_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/skills/skills.py b/src/openai/resources/skills/skills.py index 77bed029df..f44fb24607 100644 --- a/src/openai/resources/skills/skills.py +++ b/src/openai/resources/skills/skills.py @@ -28,7 +28,7 @@ omit, not_given, ) -from ..._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform +from ..._utils import extract_files, path_template, maybe_transform, deepcopy_minimal, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -144,7 +144,7 @@ def retrieve( if not skill_id: raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") return self._get( - f"/skills/{skill_id}", + path_template("/skills/{skill_id}", skill_id=skill_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -180,7 +180,7 @@ def update( if not skill_id: raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") return self._post( - f"/skills/{skill_id}", + path_template("/skills/{skill_id}", skill_id=skill_id), body=maybe_transform({"default_version": default_version}, skill_update_params.SkillUpdateParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -266,7 +266,7 @@ def delete( if not skill_id: raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") return self._delete( - f"/skills/{skill_id}", + path_template("/skills/{skill_id}", skill_id=skill_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -370,7 +370,7 @@ async def retrieve( if not skill_id: raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") return await self._get( - f"/skills/{skill_id}", + path_template("/skills/{skill_id}", skill_id=skill_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -406,7 +406,7 @@ async def update( if not skill_id: raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") return await self._post( - f"/skills/{skill_id}", + path_template("/skills/{skill_id}", skill_id=skill_id), body=await async_maybe_transform( {"default_version": default_version}, skill_update_params.SkillUpdateParams ), @@ -494,7 +494,7 @@ async def delete( if not skill_id: raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") return await self._delete( - f"/skills/{skill_id}", + path_template("/skills/{skill_id}", skill_id=skill_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/skills/versions/content.py b/src/openai/resources/skills/versions/content.py index 182a563dde..2f54586718 100644 --- a/src/openai/resources/skills/versions/content.py +++ b/src/openai/resources/skills/versions/content.py @@ -6,6 +6,7 @@ from .... import _legacy_response from ...._types import Body, Query, Headers, NotGiven, not_given +from ...._utils import path_template from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import ( @@ -71,7 +72,7 @@ def retrieve( raise ValueError(f"Expected a non-empty value for `version` but received {version!r}") extra_headers = {"Accept": "application/binary", **(extra_headers or {})} return self._get( - f"/skills/{skill_id}/versions/{version}/content", + path_template("/skills/{skill_id}/versions/{version}/content", skill_id=skill_id, version=version), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -131,7 +132,7 @@ async def retrieve( raise ValueError(f"Expected a non-empty value for `version` but received {version!r}") extra_headers = {"Accept": "application/binary", **(extra_headers or {})} return await self._get( - f"/skills/{skill_id}/versions/{version}/content", + path_template("/skills/{skill_id}/versions/{version}/content", skill_id=skill_id, version=version), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/skills/versions/versions.py b/src/openai/resources/skills/versions/versions.py index 610a24240a..8b48075cc3 100644 --- a/src/openai/resources/skills/versions/versions.py +++ b/src/openai/resources/skills/versions/versions.py @@ -27,7 +27,7 @@ omit, not_given, ) -from ...._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform +from ...._utils import extract_files, path_template, maybe_transform, deepcopy_minimal, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -108,7 +108,7 @@ def create( # multipart/form-data; boundary=---abc-- extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} return self._post( - f"/skills/{skill_id}/versions", + path_template("/skills/{skill_id}/versions", skill_id=skill_id), body=maybe_transform(body, version_create_params.VersionCreateParams), files=extracted_files, options=make_request_options( @@ -148,7 +148,7 @@ def retrieve( if not version: raise ValueError(f"Expected a non-empty value for `version` but received {version!r}") return self._get( - f"/skills/{skill_id}/versions/{version}", + path_template("/skills/{skill_id}/versions/{version}", skill_id=skill_id, version=version), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -190,7 +190,7 @@ def list( if not skill_id: raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") return self._get_api_list( - f"/skills/{skill_id}/versions", + path_template("/skills/{skill_id}/versions", skill_id=skill_id), page=SyncCursorPage[SkillVersion], options=make_request_options( extra_headers=extra_headers, @@ -240,7 +240,7 @@ def delete( if not version: raise ValueError(f"Expected a non-empty value for `version` but received {version!r}") return self._delete( - f"/skills/{skill_id}/versions/{version}", + path_template("/skills/{skill_id}/versions/{version}", skill_id=skill_id, version=version), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -316,7 +316,7 @@ async def create( # multipart/form-data; boundary=---abc-- extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} return await self._post( - f"/skills/{skill_id}/versions", + path_template("/skills/{skill_id}/versions", skill_id=skill_id), body=await async_maybe_transform(body, version_create_params.VersionCreateParams), files=extracted_files, options=make_request_options( @@ -356,7 +356,7 @@ async def retrieve( if not version: raise ValueError(f"Expected a non-empty value for `version` but received {version!r}") return await self._get( - f"/skills/{skill_id}/versions/{version}", + path_template("/skills/{skill_id}/versions/{version}", skill_id=skill_id, version=version), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -398,7 +398,7 @@ def list( if not skill_id: raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") return self._get_api_list( - f"/skills/{skill_id}/versions", + path_template("/skills/{skill_id}/versions", skill_id=skill_id), page=AsyncCursorPage[SkillVersion], options=make_request_options( extra_headers=extra_headers, @@ -448,7 +448,7 @@ async def delete( if not version: raise ValueError(f"Expected a non-empty value for `version` but received {version!r}") return await self._delete( - f"/skills/{skill_id}/versions/{version}", + path_template("/skills/{skill_id}/versions/{version}", skill_id=skill_id, version=version), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/uploads/parts.py b/src/openai/resources/uploads/parts.py index 034547f308..cf09eea75e 100644 --- a/src/openai/resources/uploads/parts.py +++ b/src/openai/resources/uploads/parts.py @@ -8,7 +8,7 @@ from ... import _legacy_response from ..._types import Body, Query, Headers, NotGiven, FileTypes, not_given -from ..._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform +from ..._utils import extract_files, path_template, maybe_transform, deepcopy_minimal, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -86,7 +86,7 @@ def create( # multipart/form-data; boundary=---abc-- extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} return self._post( - f"/uploads/{upload_id}/parts", + path_template("/uploads/{upload_id}/parts", upload_id=upload_id), body=maybe_transform(body, part_create_params.PartCreateParams), files=files, options=make_request_options( @@ -163,7 +163,7 @@ async def create( # multipart/form-data; boundary=---abc-- extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} return await self._post( - f"/uploads/{upload_id}/parts", + path_template("/uploads/{upload_id}/parts", upload_id=upload_id), body=await async_maybe_transform(body, part_create_params.PartCreateParams), files=files, options=make_request_options( diff --git a/src/openai/resources/uploads/uploads.py b/src/openai/resources/uploads/uploads.py index f5e5e6f664..7778e51539 100644 --- a/src/openai/resources/uploads/uploads.py +++ b/src/openai/resources/uploads/uploads.py @@ -23,7 +23,7 @@ ) from ...types import FilePurpose, upload_create_params, upload_complete_params from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform +from ..._utils import path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -276,7 +276,7 @@ def cancel( if not upload_id: raise ValueError(f"Expected a non-empty value for `upload_id` but received {upload_id!r}") return self._post( - f"/uploads/{upload_id}/cancel", + path_template("/uploads/{upload_id}/cancel", upload_id=upload_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -330,7 +330,7 @@ def complete( if not upload_id: raise ValueError(f"Expected a non-empty value for `upload_id` but received {upload_id!r}") return self._post( - f"/uploads/{upload_id}/complete", + path_template("/uploads/{upload_id}/complete", upload_id=upload_id), body=maybe_transform( { "part_ids": part_ids, @@ -592,7 +592,7 @@ async def cancel( if not upload_id: raise ValueError(f"Expected a non-empty value for `upload_id` but received {upload_id!r}") return await self._post( - f"/uploads/{upload_id}/cancel", + path_template("/uploads/{upload_id}/cancel", upload_id=upload_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -646,7 +646,7 @@ async def complete( if not upload_id: raise ValueError(f"Expected a non-empty value for `upload_id` but received {upload_id!r}") return await self._post( - f"/uploads/{upload_id}/complete", + path_template("/uploads/{upload_id}/complete", upload_id=upload_id), body=await async_maybe_transform( { "part_ids": part_ids, diff --git a/src/openai/resources/vector_stores/file_batches.py b/src/openai/resources/vector_stores/file_batches.py index 13ffa66d1a..f097cf8a92 100644 --- a/src/openai/resources/vector_stores/file_batches.py +++ b/src/openai/resources/vector_stores/file_batches.py @@ -13,7 +13,7 @@ from ... import _legacy_response from ...types import FileChunkingStrategyParam from ..._types import Body, Omit, Query, Headers, NotGiven, FileTypes, SequenceNotStr, omit, not_given -from ..._utils import is_given, maybe_transform, async_maybe_transform +from ..._utils import is_given, path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -100,7 +100,7 @@ def create( raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( - f"/vector_stores/{vector_store_id}/file_batches", + path_template("/vector_stores/{vector_store_id}/file_batches", vector_store_id=vector_store_id), body=maybe_transform( { "attributes": attributes, @@ -146,7 +146,11 @@ def retrieve( raise ValueError(f"Expected a non-empty value for `batch_id` but received {batch_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get( - f"/vector_stores/{vector_store_id}/file_batches/{batch_id}", + path_template( + "/vector_stores/{vector_store_id}/file_batches/{batch_id}", + vector_store_id=vector_store_id, + batch_id=batch_id, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -185,7 +189,11 @@ def cancel( raise ValueError(f"Expected a non-empty value for `batch_id` but received {batch_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( - f"/vector_stores/{vector_store_id}/file_batches/{batch_id}/cancel", + path_template( + "/vector_stores/{vector_store_id}/file_batches/{batch_id}/cancel", + vector_store_id=vector_store_id, + batch_id=batch_id, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -280,7 +288,11 @@ def list_files( raise ValueError(f"Expected a non-empty value for `batch_id` but received {batch_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( - f"/vector_stores/{vector_store_id}/file_batches/{batch_id}/files", + path_template( + "/vector_stores/{vector_store_id}/file_batches/{batch_id}/files", + vector_store_id=vector_store_id, + batch_id=batch_id, + ), page=SyncCursorPage[VectorStoreFile], options=make_request_options( extra_headers=extra_headers, @@ -461,7 +473,7 @@ async def create( raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( - f"/vector_stores/{vector_store_id}/file_batches", + path_template("/vector_stores/{vector_store_id}/file_batches", vector_store_id=vector_store_id), body=await async_maybe_transform( { "attributes": attributes, @@ -507,7 +519,11 @@ async def retrieve( raise ValueError(f"Expected a non-empty value for `batch_id` but received {batch_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._get( - f"/vector_stores/{vector_store_id}/file_batches/{batch_id}", + path_template( + "/vector_stores/{vector_store_id}/file_batches/{batch_id}", + vector_store_id=vector_store_id, + batch_id=batch_id, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -546,7 +562,11 @@ async def cancel( raise ValueError(f"Expected a non-empty value for `batch_id` but received {batch_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( - f"/vector_stores/{vector_store_id}/file_batches/{batch_id}/cancel", + path_template( + "/vector_stores/{vector_store_id}/file_batches/{batch_id}/cancel", + vector_store_id=vector_store_id, + batch_id=batch_id, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -641,7 +661,11 @@ def list_files( raise ValueError(f"Expected a non-empty value for `batch_id` but received {batch_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( - f"/vector_stores/{vector_store_id}/file_batches/{batch_id}/files", + path_template( + "/vector_stores/{vector_store_id}/file_batches/{batch_id}/files", + vector_store_id=vector_store_id, + batch_id=batch_id, + ), page=AsyncCursorPage[VectorStoreFile], options=make_request_options( extra_headers=extra_headers, diff --git a/src/openai/resources/vector_stores/files.py b/src/openai/resources/vector_stores/files.py index 29f6e879f1..8666434587 100644 --- a/src/openai/resources/vector_stores/files.py +++ b/src/openai/resources/vector_stores/files.py @@ -10,7 +10,7 @@ from ... import _legacy_response from ...types import FileChunkingStrategyParam from ..._types import Body, Omit, Query, Headers, NotGiven, FileTypes, omit, not_given -from ..._utils import is_given, maybe_transform, async_maybe_transform +from ..._utils import is_given, path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -90,7 +90,7 @@ def create( raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( - f"/vector_stores/{vector_store_id}/files", + path_template("/vector_stores/{vector_store_id}/files", vector_store_id=vector_store_id), body=maybe_transform( { "file_id": file_id, @@ -135,7 +135,9 @@ def retrieve( raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get( - f"/vector_stores/{vector_store_id}/files/{file_id}", + path_template( + "/vector_stores/{vector_store_id}/files/{file_id}", vector_store_id=vector_store_id, file_id=file_id + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -179,7 +181,9 @@ def update( raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( - f"/vector_stores/{vector_store_id}/files/{file_id}", + path_template( + "/vector_stores/{vector_store_id}/files/{file_id}", vector_store_id=vector_store_id, file_id=file_id + ), body=maybe_transform({"attributes": attributes}, file_update_params.FileUpdateParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -237,7 +241,7 @@ def list( raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( - f"/vector_stores/{vector_store_id}/files", + path_template("/vector_stores/{vector_store_id}/files", vector_store_id=vector_store_id), page=SyncCursorPage[VectorStoreFile], options=make_request_options( extra_headers=extra_headers, @@ -292,7 +296,9 @@ def delete( raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._delete( - f"/vector_stores/{vector_store_id}/files/{file_id}", + path_template( + "/vector_stores/{vector_store_id}/files/{file_id}", vector_store_id=vector_store_id, file_id=file_id + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -437,7 +443,11 @@ def content( raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( - f"/vector_stores/{vector_store_id}/files/{file_id}/content", + path_template( + "/vector_stores/{vector_store_id}/files/{file_id}/content", + vector_store_id=vector_store_id, + file_id=file_id, + ), page=SyncPage[FileContentResponse], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -511,7 +521,7 @@ async def create( raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( - f"/vector_stores/{vector_store_id}/files", + path_template("/vector_stores/{vector_store_id}/files", vector_store_id=vector_store_id), body=await async_maybe_transform( { "file_id": file_id, @@ -556,7 +566,9 @@ async def retrieve( raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._get( - f"/vector_stores/{vector_store_id}/files/{file_id}", + path_template( + "/vector_stores/{vector_store_id}/files/{file_id}", vector_store_id=vector_store_id, file_id=file_id + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -600,7 +612,9 @@ async def update( raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( - f"/vector_stores/{vector_store_id}/files/{file_id}", + path_template( + "/vector_stores/{vector_store_id}/files/{file_id}", vector_store_id=vector_store_id, file_id=file_id + ), body=await async_maybe_transform({"attributes": attributes}, file_update_params.FileUpdateParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -658,7 +672,7 @@ def list( raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( - f"/vector_stores/{vector_store_id}/files", + path_template("/vector_stores/{vector_store_id}/files", vector_store_id=vector_store_id), page=AsyncCursorPage[VectorStoreFile], options=make_request_options( extra_headers=extra_headers, @@ -713,7 +727,9 @@ async def delete( raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._delete( - f"/vector_stores/{vector_store_id}/files/{file_id}", + path_template( + "/vector_stores/{vector_store_id}/files/{file_id}", vector_store_id=vector_store_id, file_id=file_id + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -860,7 +876,11 @@ def content( raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( - f"/vector_stores/{vector_store_id}/files/{file_id}/content", + path_template( + "/vector_stores/{vector_store_id}/files/{file_id}/content", + vector_store_id=vector_store_id, + file_id=file_id, + ), page=AsyncPage[FileContentResponse], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout diff --git a/src/openai/resources/vector_stores/vector_stores.py b/src/openai/resources/vector_stores/vector_stores.py index 490e3e7fdb..7fa2ad5274 100644 --- a/src/openai/resources/vector_stores/vector_stores.py +++ b/src/openai/resources/vector_stores/vector_stores.py @@ -24,7 +24,7 @@ vector_store_update_params, ) from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform +from ..._utils import path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -171,7 +171,7 @@ def retrieve( raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get( - f"/vector_stores/{vector_store_id}", + path_template("/vector_stores/{vector_store_id}", vector_store_id=vector_store_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -219,7 +219,7 @@ def update( raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( - f"/vector_stores/{vector_store_id}", + path_template("/vector_stores/{vector_store_id}", vector_store_id=vector_store_id), body=maybe_transform( { "expires_after": expires_after, @@ -326,7 +326,7 @@ def delete( raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._delete( - f"/vector_stores/{vector_store_id}", + path_template("/vector_stores/{vector_store_id}", vector_store_id=vector_store_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -377,7 +377,7 @@ def search( raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( - f"/vector_stores/{vector_store_id}/search", + path_template("/vector_stores/{vector_store_id}/search", vector_store_id=vector_store_id), page=SyncPage[VectorStoreSearchResponse], body=maybe_transform( { @@ -521,7 +521,7 @@ async def retrieve( raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._get( - f"/vector_stores/{vector_store_id}", + path_template("/vector_stores/{vector_store_id}", vector_store_id=vector_store_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -569,7 +569,7 @@ async def update( raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( - f"/vector_stores/{vector_store_id}", + path_template("/vector_stores/{vector_store_id}", vector_store_id=vector_store_id), body=await async_maybe_transform( { "expires_after": expires_after, @@ -676,7 +676,7 @@ async def delete( raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._delete( - f"/vector_stores/{vector_store_id}", + path_template("/vector_stores/{vector_store_id}", vector_store_id=vector_store_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -727,7 +727,7 @@ def search( raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( - f"/vector_stores/{vector_store_id}/search", + path_template("/vector_stores/{vector_store_id}/search", vector_store_id=vector_store_id), page=AsyncPage[VectorStoreSearchResponse], body=maybe_transform( { diff --git a/src/openai/resources/videos.py b/src/openai/resources/videos.py index f387f55824..a006e64705 100644 --- a/src/openai/resources/videos.py +++ b/src/openai/resources/videos.py @@ -20,7 +20,7 @@ video_download_content_params, ) from .._types import Body, Omit, Query, Headers, NotGiven, FileTypes, omit, not_given -from .._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform +from .._utils import extract_files, path_template, maybe_transform, deepcopy_minimal, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import ( @@ -227,7 +227,7 @@ def retrieve( if not video_id: raise ValueError(f"Expected a non-empty value for `video_id` but received {video_id!r}") return self._get( - f"/videos/{video_id}", + path_template("/videos/{video_id}", video_id=video_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -312,7 +312,7 @@ def delete( if not video_id: raise ValueError(f"Expected a non-empty value for `video_id` but received {video_id!r}") return self._delete( - f"/videos/{video_id}", + path_template("/videos/{video_id}", video_id=video_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -400,7 +400,7 @@ def download_content( raise ValueError(f"Expected a non-empty value for `video_id` but received {video_id!r}") extra_headers = {"Accept": "application/binary", **(extra_headers or {})} return self._get( - f"/videos/{video_id}/content", + path_template("/videos/{video_id}/content", video_id=video_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -541,7 +541,7 @@ def get_character( if not character_id: raise ValueError(f"Expected a non-empty value for `character_id` but received {character_id!r}") return self._get( - f"/videos/characters/{character_id}", + path_template("/videos/characters/{character_id}", character_id=character_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -577,7 +577,7 @@ def remix( if not video_id: raise ValueError(f"Expected a non-empty value for `video_id` but received {video_id!r}") return self._post( - f"/videos/{video_id}/remix", + path_template("/videos/{video_id}/remix", video_id=video_id), body=maybe_transform({"prompt": prompt}, video_remix_params.VideoRemixParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -768,7 +768,7 @@ async def retrieve( if not video_id: raise ValueError(f"Expected a non-empty value for `video_id` but received {video_id!r}") return await self._get( - f"/videos/{video_id}", + path_template("/videos/{video_id}", video_id=video_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -853,7 +853,7 @@ async def delete( if not video_id: raise ValueError(f"Expected a non-empty value for `video_id` but received {video_id!r}") return await self._delete( - f"/videos/{video_id}", + path_template("/videos/{video_id}", video_id=video_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -941,7 +941,7 @@ async def download_content( raise ValueError(f"Expected a non-empty value for `video_id` but received {video_id!r}") extra_headers = {"Accept": "application/binary", **(extra_headers or {})} return await self._get( - f"/videos/{video_id}/content", + path_template("/videos/{video_id}/content", video_id=video_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -1084,7 +1084,7 @@ async def get_character( if not character_id: raise ValueError(f"Expected a non-empty value for `character_id` but received {character_id!r}") return await self._get( - f"/videos/characters/{character_id}", + path_template("/videos/characters/{character_id}", character_id=character_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1120,7 +1120,7 @@ async def remix( if not video_id: raise ValueError(f"Expected a non-empty value for `video_id` but received {video_id!r}") return await self._post( - f"/videos/{video_id}/remix", + path_template("/videos/{video_id}/remix", video_id=video_id), body=await async_maybe_transform({"prompt": prompt}, video_remix_params.VideoRemixParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout diff --git a/tests/test_utils/test_path.py b/tests/test_utils/test_path.py new file mode 100644 index 0000000000..420cd19973 --- /dev/null +++ b/tests/test_utils/test_path.py @@ -0,0 +1,89 @@ +from __future__ import annotations + +from typing import Any + +import pytest + +from openai._utils._path import path_template + + +@pytest.mark.parametrize( + "template, kwargs, expected", + [ + ("/v1/{id}", dict(id="abc"), "/v1/abc"), + ("/v1/{a}/{b}", dict(a="x", b="y"), "/v1/x/y"), + ("/v1/{a}{b}/path/{c}?val={d}#{e}", dict(a="x", b="y", c="z", d="u", e="v"), "/v1/xy/path/z?val=u#v"), + ("/{w}/{w}", dict(w="echo"), "/echo/echo"), + ("/v1/static", {}, "/v1/static"), + ("", {}, ""), + ("/v1/?q={n}&count=10", dict(n=42), "/v1/?q=42&count=10"), + ("/v1/{v}", dict(v=None), "/v1/null"), + ("/v1/{v}", dict(v=True), "/v1/true"), + ("/v1/{v}", dict(v=False), "/v1/false"), + ("/v1/{v}", dict(v=".hidden"), "/v1/.hidden"), # dot prefix ok + ("/v1/{v}", dict(v="file.txt"), "/v1/file.txt"), # dot in middle ok + ("/v1/{v}", dict(v="..."), "/v1/..."), # triple dot ok + ("/v1/{a}{b}", dict(a=".", b="txt"), "/v1/.txt"), # dot var combining with adjacent to be ok + ("/items?q={v}#{f}", dict(v=".", f=".."), "/items?q=.#.."), # dots in query/fragment are fine + ( + "/v1/{a}?query={b}", + dict(a="../../other/endpoint", b="a&bad=true"), + "/v1/..%2F..%2Fother%2Fendpoint?query=a%26bad%3Dtrue", + ), + ("/v1/{val}", dict(val="a/b/c"), "/v1/a%2Fb%2Fc"), + ("/v1/{val}", dict(val="a/b/c?query=value"), "/v1/a%2Fb%2Fc%3Fquery=value"), + ("/v1/{val}", dict(val="a/b/c?query=value&bad=true"), "/v1/a%2Fb%2Fc%3Fquery=value&bad=true"), + ("/v1/{val}", dict(val="%20"), "/v1/%2520"), # escapes escape sequences in input + # Query: slash and ? are safe, # is not + ("/items?q={v}", dict(v="a/b"), "/items?q=a/b"), + ("/items?q={v}", dict(v="a?b"), "/items?q=a?b"), + ("/items?q={v}", dict(v="a#b"), "/items?q=a%23b"), + ("/items?q={v}", dict(v="a b"), "/items?q=a%20b"), + # Fragment: slash and ? are safe + ("/docs#{v}", dict(v="a/b"), "/docs#a/b"), + ("/docs#{v}", dict(v="a?b"), "/docs#a?b"), + # Path: slash, ? and # are all encoded + ("/v1/{v}", dict(v="a/b"), "/v1/a%2Fb"), + ("/v1/{v}", dict(v="a?b"), "/v1/a%3Fb"), + ("/v1/{v}", dict(v="a#b"), "/v1/a%23b"), + # same var encoded differently by component + ( + "/v1/{v}?q={v}#{v}", + dict(v="a/b?c#d"), + "/v1/a%2Fb%3Fc%23d?q=a/b?c%23d#a/b?c%23d", + ), + ("/v1/{val}", dict(val="x?admin=true"), "/v1/x%3Fadmin=true"), # query injection + ("/v1/{val}", dict(val="x#admin"), "/v1/x%23admin"), # fragment injection + ], +) +def test_interpolation(template: str, kwargs: dict[str, Any], expected: str) -> None: + assert path_template(template, **kwargs) == expected + + +def test_missing_kwarg_raises_key_error() -> None: + with pytest.raises(KeyError, match="org_id"): + path_template("/v1/{org_id}") + + +@pytest.mark.parametrize( + "template, kwargs", + [ + ("{a}/path", dict(a=".")), + ("{a}/path", dict(a="..")), + ("/v1/{a}", dict(a=".")), + ("/v1/{a}", dict(a="..")), + ("/v1/{a}/path", dict(a=".")), + ("/v1/{a}/path", dict(a="..")), + ("/v1/{a}{b}", dict(a=".", b=".")), # adjacent vars → ".." + ("/v1/{a}.", dict(a=".")), # var + static → ".." + ("/v1/{a}{b}", dict(a="", b=".")), # empty + dot → "." + ("/v1/%2e/{x}", dict(x="ok")), # encoded dot in static text + ("/v1/%2e./{x}", dict(x="ok")), # mixed encoded ".." in static + ("/v1/.%2E/{x}", dict(x="ok")), # mixed encoded ".." in static + ("/v1/{v}?q=1", dict(v="..")), + ("/v1/{v}#frag", dict(v="..")), + ], +) +def test_dot_segment_rejected(template: str, kwargs: dict[str, Any]) -> None: + with pytest.raises(ValueError, match="dot-segment"): + path_template(template, **kwargs) From 85ac93132025f39452c1cd7a17695803c9fc5867 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 19 Mar 2026 18:59:11 +0000 Subject: [PATCH 656/769] refactor(tests): switch from prism to steady --- CONTRIBUTING.md | 2 +- scripts/mock | 26 +++++++++++++------------- scripts/test | 16 ++++++++-------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3a1cf70bb8..253b9ce5e6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -85,7 +85,7 @@ $ pip install ./path-to-wheel-file.whl ## Running tests -Most tests require you to [set up a mock server](https://github.com/stoplightio/prism) against the OpenAPI spec to run the tests. +Most tests require you to [set up a mock server](https://github.com/dgellow/steady) against the OpenAPI spec to run the tests. ```sh $ ./scripts/mock diff --git a/scripts/mock b/scripts/mock index bcf3b392b3..3d1d19c19f 100755 --- a/scripts/mock +++ b/scripts/mock @@ -19,34 +19,34 @@ fi echo "==> Starting mock server with URL ${URL}" -# Run prism mock on the given spec +# Run steady mock on the given spec if [ "$1" == "--daemon" ]; then # Pre-install the package so the download doesn't eat into the startup timeout - npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism --version + npm exec --package=@stdy/cli@0.19.3 -- steady --version - npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" &> .prism.log & + npm exec --package=@stdy/cli@0.19.3 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=brackets --validator-query-object-format=brackets "$URL" &> .stdy.log & - # Wait for server to come online (max 30s) + # Wait for server to come online via health endpoint (max 30s) echo -n "Waiting for server" attempts=0 - while ! grep -q "✖ fatal\|Prism is listening" ".prism.log" ; do + while ! curl --silent --fail "http://127.0.0.1:4010/_x-steady/health" >/dev/null 2>&1; do + if ! kill -0 $! 2>/dev/null; then + echo + cat .stdy.log + exit 1 + fi attempts=$((attempts + 1)) if [ "$attempts" -ge 300 ]; then echo - echo "Timed out waiting for Prism server to start" - cat .prism.log + echo "Timed out waiting for Steady server to start" + cat .stdy.log exit 1 fi echo -n "." sleep 0.1 done - if grep -q "✖ fatal" ".prism.log"; then - cat .prism.log - exit 1 - fi - echo else - npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" + npm exec --package=@stdy/cli@0.19.3 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=brackets --validator-query-object-format=brackets "$URL" fi diff --git a/scripts/test b/scripts/test index dbeda2d217..d4fac354ef 100755 --- a/scripts/test +++ b/scripts/test @@ -9,8 +9,8 @@ GREEN='\033[0;32m' YELLOW='\033[0;33m' NC='\033[0m' # No Color -function prism_is_running() { - curl --silent "http://localhost:4010" >/dev/null 2>&1 +function steady_is_running() { + curl --silent "http://127.0.0.1:4010/_x-steady/health" >/dev/null 2>&1 } kill_server_on_port() { @@ -25,7 +25,7 @@ function is_overriding_api_base_url() { [ -n "$TEST_API_BASE_URL" ] } -if ! is_overriding_api_base_url && ! prism_is_running ; then +if ! is_overriding_api_base_url && ! steady_is_running ; then # When we exit this script, make sure to kill the background mock server process trap 'kill_server_on_port 4010' EXIT @@ -36,19 +36,19 @@ fi if is_overriding_api_base_url ; then echo -e "${GREEN}✔ Running tests against ${TEST_API_BASE_URL}${NC}" echo -elif ! prism_is_running ; then - echo -e "${RED}ERROR:${NC} The test suite will not run without a mock Prism server" +elif ! steady_is_running ; then + echo -e "${RED}ERROR:${NC} The test suite will not run without a mock Steady server" echo -e "running against your OpenAPI spec." echo echo -e "To run the server, pass in the path or url of your OpenAPI" - echo -e "spec to the prism command:" + echo -e "spec to the steady command:" echo - echo -e " \$ ${YELLOW}npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock path/to/your.openapi.yml${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.3 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-query-array-format=brackets --validator-query-object-format=brackets${NC}" echo exit 1 else - echo -e "${GREEN}✔ Mock prism server is running with your OpenAPI spec${NC}" + echo -e "${GREEN}✔ Mock steady server is running with your OpenAPI spec${NC}" echo fi From c8c9508899b2119cc69e006403d09cbad7f616e4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Mar 2026 17:50:22 +0000 Subject: [PATCH 657/769] chore(tests): bump steady to v0.19.4 --- scripts/mock | 6 +++--- scripts/test | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/mock b/scripts/mock index 3d1d19c19f..e2ca85a09f 100755 --- a/scripts/mock +++ b/scripts/mock @@ -22,9 +22,9 @@ echo "==> Starting mock server with URL ${URL}" # Run steady mock on the given spec if [ "$1" == "--daemon" ]; then # Pre-install the package so the download doesn't eat into the startup timeout - npm exec --package=@stdy/cli@0.19.3 -- steady --version + npm exec --package=@stdy/cli@0.19.4 -- steady --version - npm exec --package=@stdy/cli@0.19.3 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=brackets --validator-query-object-format=brackets "$URL" &> .stdy.log & + npm exec --package=@stdy/cli@0.19.4 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=brackets --validator-query-array-format=brackets --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" &> .stdy.log & # Wait for server to come online via health endpoint (max 30s) echo -n "Waiting for server" @@ -48,5 +48,5 @@ if [ "$1" == "--daemon" ]; then echo else - npm exec --package=@stdy/cli@0.19.3 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=brackets --validator-query-object-format=brackets "$URL" + npm exec --package=@stdy/cli@0.19.4 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=brackets --validator-query-array-format=brackets --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" fi diff --git a/scripts/test b/scripts/test index d4fac354ef..4d15877e75 100755 --- a/scripts/test +++ b/scripts/test @@ -43,7 +43,7 @@ elif ! steady_is_running ; then echo -e "To run the server, pass in the path or url of your OpenAPI" echo -e "spec to the steady command:" echo - echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.3 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-query-array-format=brackets --validator-query-object-format=brackets${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.4 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-form-array-format=brackets --validator-query-array-format=brackets --validator-form-object-format=brackets --validator-query-object-format=brackets${NC}" echo exit 1 From 634b74edd4aaa07a74f9ee30241410d61624264f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Mar 2026 21:32:14 +0000 Subject: [PATCH 658/769] chore(tests): bump steady to v0.19.5 --- scripts/mock | 6 +++--- scripts/test | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/mock b/scripts/mock index e2ca85a09f..4f7dfd12b4 100755 --- a/scripts/mock +++ b/scripts/mock @@ -22,9 +22,9 @@ echo "==> Starting mock server with URL ${URL}" # Run steady mock on the given spec if [ "$1" == "--daemon" ]; then # Pre-install the package so the download doesn't eat into the startup timeout - npm exec --package=@stdy/cli@0.19.4 -- steady --version + npm exec --package=@stdy/cli@0.19.5 -- steady --version - npm exec --package=@stdy/cli@0.19.4 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=brackets --validator-query-array-format=brackets --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" &> .stdy.log & + npm exec --package=@stdy/cli@0.19.5 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=brackets --validator-query-array-format=brackets --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" &> .stdy.log & # Wait for server to come online via health endpoint (max 30s) echo -n "Waiting for server" @@ -48,5 +48,5 @@ if [ "$1" == "--daemon" ]; then echo else - npm exec --package=@stdy/cli@0.19.4 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=brackets --validator-query-array-format=brackets --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" + npm exec --package=@stdy/cli@0.19.5 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=brackets --validator-query-array-format=brackets --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" fi diff --git a/scripts/test b/scripts/test index 4d15877e75..3861edc6d1 100755 --- a/scripts/test +++ b/scripts/test @@ -43,7 +43,7 @@ elif ! steady_is_running ; then echo -e "To run the server, pass in the path or url of your OpenAPI" echo -e "spec to the steady command:" echo - echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.4 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-form-array-format=brackets --validator-query-array-format=brackets --validator-form-object-format=brackets --validator-query-object-format=brackets${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.5 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-form-array-format=brackets --validator-query-array-format=brackets --validator-form-object-format=brackets --validator-query-object-format=brackets${NC}" echo exit 1 From 78c764bdf483a0c48789bfdefe6299830d5abde0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Mar 2026 12:39:34 +0000 Subject: [PATCH 659/769] chore(internal): update gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 55c6ca861f..3a7a575390 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .prism.log +.stdy.log _dev __pycache__ From 56ad9ca089394e535d7df52fe48d544e54086ddc Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Mar 2026 16:54:49 +0000 Subject: [PATCH 660/769] fix(types): make type required in ResponseInputMessageItem --- .stats.yml | 4 ++-- src/openai/types/responses/response_input_message_item.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.stats.yml b/.stats.yml index b47f21a4ac..2cf8eb516d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 152 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-55ef7034334e938c30656a404ce5e21466103be87542a796425346299f450404.yml -openapi_spec_hash: 4a5bfd2ee4ad47f5b7cf6f1ad08d5d7f +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-0fea07225431c8d0cf5fc1a70c9363a91d259f7a169f410717e162de1b24e489.yml +openapi_spec_hash: 41b34c1678ec0e95daf62ca4cd52c8f8 config_hash: 96fbf82cf74a44ccd513f5acf0956ffd diff --git a/src/openai/types/responses/response_input_message_item.py b/src/openai/types/responses/response_input_message_item.py index 6a788e7fa4..788c92c9bd 100644 --- a/src/openai/types/responses/response_input_message_item.py +++ b/src/openai/types/responses/response_input_message_item.py @@ -22,12 +22,12 @@ class ResponseInputMessageItem(BaseModel): role: Literal["user", "system", "developer"] """The role of the message input. One of `user`, `system`, or `developer`.""" + type: Literal["message"] + """The type of the message input. Always set to `message`.""" + status: Optional[Literal["in_progress", "completed", "incomplete"]] = None """The status of item. One of `in_progress`, `completed`, or `incomplete`. Populated when items are returned via API. """ - - type: Optional[Literal["message"]] = None - """The type of the message input. Always set to `message`.""" From e3c59bf1ac8533a1be831a6d166f9f7abeabf8e0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Mar 2026 18:03:55 +0000 Subject: [PATCH 661/769] chore(tests): bump steady to v0.19.6 --- scripts/mock | 6 +++--- scripts/test | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/mock b/scripts/mock index 4f7dfd12b4..dba3058989 100755 --- a/scripts/mock +++ b/scripts/mock @@ -22,9 +22,9 @@ echo "==> Starting mock server with URL ${URL}" # Run steady mock on the given spec if [ "$1" == "--daemon" ]; then # Pre-install the package so the download doesn't eat into the startup timeout - npm exec --package=@stdy/cli@0.19.5 -- steady --version + npm exec --package=@stdy/cli@0.19.6 -- steady --version - npm exec --package=@stdy/cli@0.19.5 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=brackets --validator-query-array-format=brackets --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" &> .stdy.log & + npm exec --package=@stdy/cli@0.19.6 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=brackets --validator-query-array-format=brackets --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" &> .stdy.log & # Wait for server to come online via health endpoint (max 30s) echo -n "Waiting for server" @@ -48,5 +48,5 @@ if [ "$1" == "--daemon" ]; then echo else - npm exec --package=@stdy/cli@0.19.5 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=brackets --validator-query-array-format=brackets --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" + npm exec --package=@stdy/cli@0.19.6 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=brackets --validator-query-array-format=brackets --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" fi diff --git a/scripts/test b/scripts/test index 3861edc6d1..004577df10 100755 --- a/scripts/test +++ b/scripts/test @@ -43,7 +43,7 @@ elif ! steady_is_running ; then echo -e "To run the server, pass in the path or url of your OpenAPI" echo -e "spec to the steady command:" echo - echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.5 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-form-array-format=brackets --validator-query-array-format=brackets --validator-form-object-format=brackets --validator-query-object-format=brackets${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.6 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-form-array-format=brackets --validator-query-array-format=brackets --validator-form-object-format=brackets --validator-query-object-format=brackets${NC}" echo exit 1 From 23bc02703bbb9497eadd5d56497d5d6954372a62 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Mar 2026 15:16:40 +0000 Subject: [PATCH 662/769] chore(ci): skip lint on metadata-only changes Note that we still want to run tests, as these depend on the metadata. --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3ad9f39206..b786cbcf6a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: timeout-minutes: 10 name: lint runs-on: ${{ github.repository == 'stainless-sdks/openai-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} - if: github.event_name == 'push' || github.event.pull_request.head.repo.fork + if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') steps: - uses: actions/checkout@v6 @@ -38,7 +38,7 @@ jobs: run: ./scripts/lint build: - if: github.event_name == 'push' || github.event.pull_request.head.repo.fork + if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') timeout-minutes: 10 name: build permissions: @@ -107,7 +107,7 @@ jobs: timeout-minutes: 10 name: examples runs-on: ${{ github.repository == 'stainless-sdks/openai-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} - if: github.repository == 'openai/openai-python' && (github.event_name == 'push' || github.event.pull_request.head.repo.fork) + if: github.repository == 'openai/openai-python' && (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') steps: - uses: actions/checkout@v6 From 4f43fe371037415ace13981a277917366b6fc24e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Mar 2026 15:44:12 +0000 Subject: [PATCH 663/769] chore(tests): bump steady to v0.19.7 --- scripts/mock | 6 +++--- scripts/test | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/mock b/scripts/mock index dba3058989..9ecceca0a7 100755 --- a/scripts/mock +++ b/scripts/mock @@ -22,9 +22,9 @@ echo "==> Starting mock server with URL ${URL}" # Run steady mock on the given spec if [ "$1" == "--daemon" ]; then # Pre-install the package so the download doesn't eat into the startup timeout - npm exec --package=@stdy/cli@0.19.6 -- steady --version + npm exec --package=@stdy/cli@0.19.7 -- steady --version - npm exec --package=@stdy/cli@0.19.6 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=brackets --validator-query-array-format=brackets --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" &> .stdy.log & + npm exec --package=@stdy/cli@0.19.7 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=brackets --validator-query-array-format=brackets --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" &> .stdy.log & # Wait for server to come online via health endpoint (max 30s) echo -n "Waiting for server" @@ -48,5 +48,5 @@ if [ "$1" == "--daemon" ]; then echo else - npm exec --package=@stdy/cli@0.19.6 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=brackets --validator-query-array-format=brackets --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" + npm exec --package=@stdy/cli@0.19.7 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=brackets --validator-query-array-format=brackets --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" fi diff --git a/scripts/test b/scripts/test index 004577df10..9231513853 100755 --- a/scripts/test +++ b/scripts/test @@ -43,7 +43,7 @@ elif ! steady_is_running ; then echo -e "To run the server, pass in the path or url of your OpenAPI" echo -e "spec to the steady command:" echo - echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.6 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-form-array-format=brackets --validator-query-array-format=brackets --validator-form-object-format=brackets --validator-query-object-format=brackets${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.7 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-form-array-format=brackets --validator-query-array-format=brackets --validator-form-object-format=brackets --validator-query-object-format=brackets${NC}" echo exit 1 From cd72fba37866bfdddd4a84420afe2ff397279582 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Mar 2026 16:19:13 +0000 Subject: [PATCH 664/769] feat(api): add keys field to Click/DoubleClick/Drag/Move/Scroll computer actions --- .stats.yml | 4 ++-- src/openai/types/responses/computer_action.py | 17 ++++++++++++++++- .../responses/computer_action_list_param.py | 17 ++++++++++++++++- .../types/responses/computer_action_param.py | 17 ++++++++++++++++- .../responses/response_computer_tool_call.py | 15 +++++++++++++++ .../response_computer_tool_call_param.py | 15 +++++++++++++++ 6 files changed, 80 insertions(+), 5 deletions(-) diff --git a/.stats.yml b/.stats.yml index 2cf8eb516d..297349aa88 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 152 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-0fea07225431c8d0cf5fc1a70c9363a91d259f7a169f410717e162de1b24e489.yml -openapi_spec_hash: 41b34c1678ec0e95daf62ca4cd52c8f8 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-13599f99dceef322e19171dcc63d90f638d225a445999442249e1ed7a4924c43.yml +openapi_spec_hash: aac8cf8ec3c7dc6d14ecf5dbb289ee7c config_hash: 96fbf82cf74a44ccd513f5acf0956ffd diff --git a/src/openai/types/responses/computer_action.py b/src/openai/types/responses/computer_action.py index a0c11084ba..f7a21d2ac4 100644 --- a/src/openai/types/responses/computer_action.py +++ b/src/openai/types/responses/computer_action.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union +from typing import List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias from ..._utils import PropertyInfo @@ -39,10 +39,16 @@ class Click(BaseModel): y: int """The y-coordinate where the click occurred.""" + keys: Optional[List[str]] = None + """The keys being held while clicking.""" + class DoubleClick(BaseModel): """A double click action.""" + keys: Optional[List[str]] = None + """The keys being held while double-clicking.""" + type: Literal["double_click"] """Specifies the event type. @@ -88,6 +94,9 @@ class Drag(BaseModel): For a drag action, this property is always set to `drag`. """ + keys: Optional[List[str]] = None + """The keys being held while dragging the mouse.""" + class Keypress(BaseModel): """A collection of keypresses the model would like to perform.""" @@ -120,6 +129,9 @@ class Move(BaseModel): y: int """The y-coordinate to move to.""" + keys: Optional[List[str]] = None + """The keys being held while moving the mouse.""" + class Screenshot(BaseModel): """A screenshot action.""" @@ -152,6 +164,9 @@ class Scroll(BaseModel): y: int """The y-coordinate where the scroll occurred.""" + keys: Optional[List[str]] = None + """The keys being held while scrolling.""" + class Type(BaseModel): """An action to type in text.""" diff --git a/src/openai/types/responses/computer_action_list_param.py b/src/openai/types/responses/computer_action_list_param.py index ec609ffd1b..66a03520f7 100644 --- a/src/openai/types/responses/computer_action_list_param.py +++ b/src/openai/types/responses/computer_action_list_param.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import List, Union, Iterable +from typing import List, Union, Iterable, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict from ..._types import SequenceNotStr @@ -41,10 +41,16 @@ class Click(TypedDict, total=False): y: Required[int] """The y-coordinate where the click occurred.""" + keys: Optional[SequenceNotStr[str]] + """The keys being held while clicking.""" + class DoubleClick(TypedDict, total=False): """A double click action.""" + keys: Required[Optional[SequenceNotStr[str]]] + """The keys being held while double-clicking.""" + type: Required[Literal["double_click"]] """Specifies the event type. @@ -90,6 +96,9 @@ class Drag(TypedDict, total=False): For a drag action, this property is always set to `drag`. """ + keys: Optional[SequenceNotStr[str]] + """The keys being held while dragging the mouse.""" + class Keypress(TypedDict, total=False): """A collection of keypresses the model would like to perform.""" @@ -122,6 +131,9 @@ class Move(TypedDict, total=False): y: Required[int] """The y-coordinate to move to.""" + keys: Optional[SequenceNotStr[str]] + """The keys being held while moving the mouse.""" + class Screenshot(TypedDict, total=False): """A screenshot action.""" @@ -154,6 +166,9 @@ class Scroll(TypedDict, total=False): y: Required[int] """The y-coordinate where the scroll occurred.""" + keys: Optional[SequenceNotStr[str]] + """The keys being held while scrolling.""" + class Type(TypedDict, total=False): """An action to type in text.""" diff --git a/src/openai/types/responses/computer_action_param.py b/src/openai/types/responses/computer_action_param.py index 822a77d759..f60c72b1b4 100644 --- a/src/openai/types/responses/computer_action_param.py +++ b/src/openai/types/responses/computer_action_param.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Union, Iterable +from typing import Union, Iterable, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict from ..._types import SequenceNotStr @@ -40,10 +40,16 @@ class Click(TypedDict, total=False): y: Required[int] """The y-coordinate where the click occurred.""" + keys: Optional[SequenceNotStr[str]] + """The keys being held while clicking.""" + class DoubleClick(TypedDict, total=False): """A double click action.""" + keys: Required[Optional[SequenceNotStr[str]]] + """The keys being held while double-clicking.""" + type: Required[Literal["double_click"]] """Specifies the event type. @@ -89,6 +95,9 @@ class Drag(TypedDict, total=False): For a drag action, this property is always set to `drag`. """ + keys: Optional[SequenceNotStr[str]] + """The keys being held while dragging the mouse.""" + class Keypress(TypedDict, total=False): """A collection of keypresses the model would like to perform.""" @@ -121,6 +130,9 @@ class Move(TypedDict, total=False): y: Required[int] """The y-coordinate to move to.""" + keys: Optional[SequenceNotStr[str]] + """The keys being held while moving the mouse.""" + class Screenshot(TypedDict, total=False): """A screenshot action.""" @@ -153,6 +165,9 @@ class Scroll(TypedDict, total=False): y: Required[int] """The y-coordinate where the scroll occurred.""" + keys: Optional[SequenceNotStr[str]] + """The keys being held while scrolling.""" + class Type(TypedDict, total=False): """An action to type in text.""" diff --git a/src/openai/types/responses/response_computer_tool_call.py b/src/openai/types/responses/response_computer_tool_call.py index f796846560..e0339e4afd 100644 --- a/src/openai/types/responses/response_computer_tool_call.py +++ b/src/openai/types/responses/response_computer_tool_call.py @@ -55,10 +55,16 @@ class ActionClick(BaseModel): y: int """The y-coordinate where the click occurred.""" + keys: Optional[List[str]] = None + """The keys being held while clicking.""" + class ActionDoubleClick(BaseModel): """A double click action.""" + keys: Optional[List[str]] = None + """The keys being held while double-clicking.""" + type: Literal["double_click"] """Specifies the event type. @@ -104,6 +110,9 @@ class ActionDrag(BaseModel): For a drag action, this property is always set to `drag`. """ + keys: Optional[List[str]] = None + """The keys being held while dragging the mouse.""" + class ActionKeypress(BaseModel): """A collection of keypresses the model would like to perform.""" @@ -136,6 +145,9 @@ class ActionMove(BaseModel): y: int """The y-coordinate to move to.""" + keys: Optional[List[str]] = None + """The keys being held while moving the mouse.""" + class ActionScreenshot(BaseModel): """A screenshot action.""" @@ -168,6 +180,9 @@ class ActionScroll(BaseModel): y: int """The y-coordinate where the scroll occurred.""" + keys: Optional[List[str]] = None + """The keys being held while scrolling.""" + class ActionType(BaseModel): """An action to type in text.""" diff --git a/src/openai/types/responses/response_computer_tool_call_param.py b/src/openai/types/responses/response_computer_tool_call_param.py index 05cc2c2f67..3c121097e5 100644 --- a/src/openai/types/responses/response_computer_tool_call_param.py +++ b/src/openai/types/responses/response_computer_tool_call_param.py @@ -56,10 +56,16 @@ class ActionClick(TypedDict, total=False): y: Required[int] """The y-coordinate where the click occurred.""" + keys: Optional[SequenceNotStr[str]] + """The keys being held while clicking.""" + class ActionDoubleClick(TypedDict, total=False): """A double click action.""" + keys: Required[Optional[SequenceNotStr[str]]] + """The keys being held while double-clicking.""" + type: Required[Literal["double_click"]] """Specifies the event type. @@ -105,6 +111,9 @@ class ActionDrag(TypedDict, total=False): For a drag action, this property is always set to `drag`. """ + keys: Optional[SequenceNotStr[str]] + """The keys being held while dragging the mouse.""" + class ActionKeypress(TypedDict, total=False): """A collection of keypresses the model would like to perform.""" @@ -137,6 +146,9 @@ class ActionMove(TypedDict, total=False): y: Required[int] """The y-coordinate to move to.""" + keys: Optional[SequenceNotStr[str]] + """The keys being held while moving the mouse.""" + class ActionScreenshot(TypedDict, total=False): """A screenshot action.""" @@ -169,6 +181,9 @@ class ActionScroll(TypedDict, total=False): y: Required[int] """The y-coordinate where the scroll occurred.""" + keys: Optional[SequenceNotStr[str]] + """The keys being held while scrolling.""" + class ActionType(TypedDict, total=False): """An action to type in text.""" From 6e772ae791759b25de83313614e0fb26eba895b7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Mar 2026 20:33:05 +0000 Subject: [PATCH 665/769] fix(api): align SDK response types with expanded item schemas Fixes a variety of missing Items on Responses. OutputItem: add function_call_output, computer_tool_call_output, local_shell_call_output, mcp_approval_response, custom_tool_call_output ItemResource: add reasoning, compaction, custom_tool_call, custom_tool_call_output --- .stats.yml | 6 +-- src/openai/lib/_parsing/_responses.py | 5 +++ src/openai/resources/responses/api.md | 2 + .../types/conversations/conversation_item.py | 2 + src/openai/types/responses/__init__.py | 2 + src/openai/types/responses/parsed_response.py | 12 ++++- ...response_computer_tool_call_output_item.py | 15 ++++--- .../response_custom_tool_call_item.py | 25 +++++++++++ .../response_custom_tool_call_output_item.py | 25 +++++++++++ .../response_function_tool_call_item.py | 13 ++++++ ...response_function_tool_call_output_item.py | 11 +++-- src/openai/types/responses/response_item.py | 8 ++++ .../types/responses/response_output_item.py | 45 +++++++++++++++++++ 13 files changed, 157 insertions(+), 14 deletions(-) create mode 100644 src/openai/types/responses/response_custom_tool_call_item.py create mode 100644 src/openai/types/responses/response_custom_tool_call_output_item.py diff --git a/.stats.yml b/.stats.yml index 297349aa88..b2067da764 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 152 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-13599f99dceef322e19171dcc63d90f638d225a445999442249e1ed7a4924c43.yml -openapi_spec_hash: aac8cf8ec3c7dc6d14ecf5dbb289ee7c -config_hash: 96fbf82cf74a44ccd513f5acf0956ffd +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-00994178cc8e20d71754b00c54b0e4f5b4128e1c1cce765e9b7d696bd8c80d33.yml +openapi_spec_hash: 81f404053b663f987209b4fb2d08a230 +config_hash: 5635033cdc8c930255f8b529a78de722 diff --git a/src/openai/lib/_parsing/_responses.py b/src/openai/lib/_parsing/_responses.py index df0f52cdc8..8853a0749f 100644 --- a/src/openai/lib/_parsing/_responses.py +++ b/src/openai/lib/_parsing/_responses.py @@ -107,9 +107,11 @@ def parse_response( or output.type == "compaction" or output.type == "mcp_call" or output.type == "mcp_approval_request" + or output.type == "mcp_approval_response" or output.type == "image_generation_call" or output.type == "code_interpreter_call" or output.type == "local_shell_call" + or output.type == "local_shell_call_output" or output.type == "shell_call" or output.type == "shell_call_output" or output.type == "apply_patch_call" @@ -117,6 +119,9 @@ def parse_response( or output.type == "mcp_list_tools" or output.type == "exec" or output.type == "custom_tool_call" + or output.type == "function_call_output" + or output.type == "computer_call_output" + or output.type == "custom_tool_call_output" ): output_list.append(output) elif TYPE_CHECKING: # type: ignore diff --git a/src/openai/resources/responses/api.md b/src/openai/resources/responses/api.md index d211cd9899..891e0f9796 100644 --- a/src/openai/resources/responses/api.md +++ b/src/openai/resources/responses/api.md @@ -53,7 +53,9 @@ from openai.types.responses import ( ResponseCustomToolCall, ResponseCustomToolCallInputDeltaEvent, ResponseCustomToolCallInputDoneEvent, + ResponseCustomToolCallItem, ResponseCustomToolCallOutput, + ResponseCustomToolCallOutputItem, ResponseError, ResponseErrorEvent, ResponseFailedEvent, diff --git a/src/openai/types/conversations/conversation_item.py b/src/openai/types/conversations/conversation_item.py index 33bd3ba043..52e87ccb0b 100644 --- a/src/openai/types/conversations/conversation_item.py +++ b/src/openai/types/conversations/conversation_item.py @@ -7,6 +7,7 @@ from ..._utils import PropertyInfo from ..._models import BaseModel from ..responses.response_reasoning_item import ResponseReasoningItem +from ..responses.response_compaction_item import ResponseCompactionItem from ..responses.response_custom_tool_call import ResponseCustomToolCall from ..responses.response_tool_search_call import ResponseToolSearchCall from ..responses.response_computer_tool_call import ResponseComputerToolCall @@ -234,6 +235,7 @@ class McpCall(BaseModel): ResponseToolSearchCall, ResponseToolSearchOutputItem, ResponseReasoningItem, + ResponseCompactionItem, ResponseCodeInterpreterToolCall, LocalShellCall, LocalShellCallOutput, diff --git a/src/openai/types/responses/__init__.py b/src/openai/types/responses/__init__.py index d06f17f6a3..5e6f45e9b1 100644 --- a/src/openai/types/responses/__init__.py +++ b/src/openai/types/responses/__init__.py @@ -142,6 +142,7 @@ from .web_search_preview_tool_param import WebSearchPreviewToolParam as WebSearchPreviewToolParam from .response_apply_patch_tool_call import ResponseApplyPatchToolCall as ResponseApplyPatchToolCall from .response_compaction_item_param import ResponseCompactionItemParam as ResponseCompactionItemParam +from .response_custom_tool_call_item import ResponseCustomToolCallItem as ResponseCustomToolCallItem from .response_file_search_tool_call import ResponseFileSearchToolCall as ResponseFileSearchToolCall from .response_mcp_call_failed_event import ResponseMcpCallFailedEvent as ResponseMcpCallFailedEvent from .computer_use_preview_tool_param import ComputerUsePreviewToolParam as ComputerUsePreviewToolParam @@ -179,6 +180,7 @@ from .response_audio_transcript_delta_event import ( ResponseAudioTranscriptDeltaEvent as ResponseAudioTranscriptDeltaEvent, ) +from .response_custom_tool_call_output_item import ResponseCustomToolCallOutputItem as ResponseCustomToolCallOutputItem from .container_network_policy_domain_secret import ( ContainerNetworkPolicyDomainSecret as ContainerNetworkPolicyDomainSecret, ) diff --git a/src/openai/types/responses/parsed_response.py b/src/openai/types/responses/parsed_response.py index 306e52677d..4100a8d9d0 100644 --- a/src/openai/types/responses/parsed_response.py +++ b/src/openai/types/responses/parsed_response.py @@ -12,7 +12,9 @@ LocalShellCall, McpApprovalRequest, ImageGenerationCall, + McpApprovalResponse, LocalShellCallAction, + LocalShellCallOutput, ) from .response_output_text import ResponseOutputText from .response_output_message import ResponseOutputMessage @@ -30,6 +32,9 @@ from .response_function_shell_tool_call import ResponseFunctionShellToolCall from .response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall from .response_apply_patch_tool_call_output import ResponseApplyPatchToolCallOutput +from .response_custom_tool_call_output_item import ResponseCustomToolCallOutputItem +from .response_computer_tool_call_output_item import ResponseComputerToolCallOutputItem +from .response_function_tool_call_output_item import ResponseFunctionToolCallOutputItem from .response_function_shell_tool_call_output import ResponseFunctionShellToolCallOutput __all__ = ["ParsedResponse", "ParsedResponseOutputMessage", "ParsedResponseOutputText"] @@ -72,22 +77,27 @@ class ParsedResponseFunctionToolCall(ResponseFunctionToolCall): ResponseFileSearchToolCall, ResponseFunctionWebSearch, ResponseComputerToolCall, + ResponseComputerToolCallOutputItem, ResponseToolSearchCall, ResponseToolSearchOutputItem, ResponseReasoningItem, McpCall, McpApprovalRequest, + McpApprovalResponse, ImageGenerationCall, LocalShellCall, + LocalShellCallOutput, LocalShellCallAction, McpListTools, ResponseCodeInterpreterToolCall, - ResponseCustomToolCall, ResponseCompactionItem, ResponseFunctionShellToolCall, ResponseFunctionShellToolCallOutput, ResponseApplyPatchToolCall, ResponseApplyPatchToolCallOutput, + ResponseFunctionToolCallOutputItem, + ResponseCustomToolCall, + ResponseCustomToolCallOutputItem, ], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/responses/response_computer_tool_call_output_item.py b/src/openai/types/responses/response_computer_tool_call_output_item.py index 90e935c3bd..bf5555d056 100644 --- a/src/openai/types/responses/response_computer_tool_call_output_item.py +++ b/src/openai/types/responses/response_computer_tool_call_output_item.py @@ -32,6 +32,13 @@ class ResponseComputerToolCallOutputItem(BaseModel): output: ResponseComputerToolCallOutputScreenshot """A computer screenshot image used with the computer use tool.""" + status: Literal["completed", "incomplete", "failed", "in_progress"] + """The status of the message input. + + One of `in_progress`, `completed`, or `incomplete`. Populated when input items + are returned via API. + """ + type: Literal["computer_call_output"] """The type of the computer tool call output. Always `computer_call_output`.""" @@ -41,9 +48,5 @@ class ResponseComputerToolCallOutputItem(BaseModel): developer. """ - status: Optional[Literal["in_progress", "completed", "incomplete"]] = None - """The status of the message input. - - One of `in_progress`, `completed`, or `incomplete`. Populated when input items - are returned via API. - """ + created_by: Optional[str] = None + """The identifier of the actor that created the item.""" diff --git a/src/openai/types/responses/response_custom_tool_call_item.py b/src/openai/types/responses/response_custom_tool_call_item.py new file mode 100644 index 0000000000..4f0f930674 --- /dev/null +++ b/src/openai/types/responses/response_custom_tool_call_item.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from .response_custom_tool_call import ResponseCustomToolCall + +__all__ = ["ResponseCustomToolCallItem"] + + +class ResponseCustomToolCallItem(ResponseCustomToolCall): + """A call to a custom tool created by the model.""" + + id: str # type: ignore + """The unique ID of the custom tool call item.""" + + status: Literal["in_progress", "completed", "incomplete"] + """The status of the item. + + One of `in_progress`, `completed`, or `incomplete`. Populated when items are + returned via API. + """ + + created_by: Optional[str] = None + """The identifier of the actor that created the item.""" diff --git a/src/openai/types/responses/response_custom_tool_call_output_item.py b/src/openai/types/responses/response_custom_tool_call_output_item.py new file mode 100644 index 0000000000..5e5a469e8d --- /dev/null +++ b/src/openai/types/responses/response_custom_tool_call_output_item.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from .response_custom_tool_call_output import ResponseCustomToolCallOutput + +__all__ = ["ResponseCustomToolCallOutputItem"] + + +class ResponseCustomToolCallOutputItem(ResponseCustomToolCallOutput): + """The output of a custom tool call from your code, being sent back to the model.""" + + id: str # type: ignore + """The unique ID of the custom tool call output item.""" + + status: Literal["in_progress", "completed", "incomplete"] + """The status of the item. + + One of `in_progress`, `completed`, or `incomplete`. Populated when items are + returned via API. + """ + + created_by: Optional[str] = None + """The identifier of the actor that created the item.""" diff --git a/src/openai/types/responses/response_function_tool_call_item.py b/src/openai/types/responses/response_function_tool_call_item.py index 3df299e512..c8a4488949 100644 --- a/src/openai/types/responses/response_function_tool_call_item.py +++ b/src/openai/types/responses/response_function_tool_call_item.py @@ -1,5 +1,8 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from typing import Optional +from typing_extensions import Literal + from .response_function_tool_call import ResponseFunctionToolCall __all__ = ["ResponseFunctionToolCallItem"] @@ -14,3 +17,13 @@ class ResponseFunctionToolCallItem(ResponseFunctionToolCall): id: str # type: ignore """The unique ID of the function tool call.""" + + status: Literal["in_progress", "completed", "incomplete"] # type: ignore + """The status of the item. + + One of `in_progress`, `completed`, or `incomplete`. Populated when items are + returned via API. + """ + + created_by: Optional[str] = None + """The identifier of the actor that created the item.""" diff --git a/src/openai/types/responses/response_function_tool_call_output_item.py b/src/openai/types/responses/response_function_tool_call_output_item.py index 1a2c848cb3..e40feeb37e 100644 --- a/src/openai/types/responses/response_function_tool_call_output_item.py +++ b/src/openai/types/responses/response_function_tool_call_output_item.py @@ -29,12 +29,15 @@ class ResponseFunctionToolCallOutputItem(BaseModel): list of output content. """ - type: Literal["function_call_output"] - """The type of the function tool call output. Always `function_call_output`.""" - - status: Optional[Literal["in_progress", "completed", "incomplete"]] = None + status: Literal["in_progress", "completed", "incomplete"] """The status of the item. One of `in_progress`, `completed`, or `incomplete`. Populated when items are returned via API. """ + + type: Literal["function_call_output"] + """The type of the function tool call output. Always `function_call_output`.""" + + created_by: Optional[str] = None + """The identifier of the actor that created the item.""" diff --git a/src/openai/types/responses/response_item.py b/src/openai/types/responses/response_item.py index 316a912f62..721bf02ecb 100644 --- a/src/openai/types/responses/response_item.py +++ b/src/openai/types/responses/response_item.py @@ -6,17 +6,21 @@ from ..._utils import PropertyInfo from ..._models import BaseModel from .response_output_message import ResponseOutputMessage +from .response_reasoning_item import ResponseReasoningItem +from .response_compaction_item import ResponseCompactionItem from .response_tool_search_call import ResponseToolSearchCall from .response_computer_tool_call import ResponseComputerToolCall from .response_input_message_item import ResponseInputMessageItem from .response_function_web_search import ResponseFunctionWebSearch from .response_apply_patch_tool_call import ResponseApplyPatchToolCall +from .response_custom_tool_call_item import ResponseCustomToolCallItem from .response_file_search_tool_call import ResponseFileSearchToolCall from .response_function_tool_call_item import ResponseFunctionToolCallItem from .response_tool_search_output_item import ResponseToolSearchOutputItem from .response_function_shell_tool_call import ResponseFunctionShellToolCall from .response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall from .response_apply_patch_tool_call_output import ResponseApplyPatchToolCallOutput +from .response_custom_tool_call_output_item import ResponseCustomToolCallOutputItem from .response_computer_tool_call_output_item import ResponseComputerToolCallOutputItem from .response_function_tool_call_output_item import ResponseFunctionToolCallOutputItem from .response_function_shell_tool_call_output import ResponseFunctionShellToolCallOutput @@ -231,6 +235,8 @@ class McpCall(BaseModel): ResponseFunctionToolCallOutputItem, ResponseToolSearchCall, ResponseToolSearchOutputItem, + ResponseReasoningItem, + ResponseCompactionItem, ImageGenerationCall, ResponseCodeInterpreterToolCall, LocalShellCall, @@ -243,6 +249,8 @@ class McpCall(BaseModel): McpApprovalRequest, McpApprovalResponse, McpCall, + ResponseCustomToolCallItem, + ResponseCustomToolCallOutputItem, ], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/responses/response_output_item.py b/src/openai/types/responses/response_output_item.py index 4be4cbf78e..a4b23f26fd 100644 --- a/src/openai/types/responses/response_output_item.py +++ b/src/openai/types/responses/response_output_item.py @@ -19,6 +19,9 @@ from .response_function_shell_tool_call import ResponseFunctionShellToolCall from .response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall from .response_apply_patch_tool_call_output import ResponseApplyPatchToolCallOutput +from .response_custom_tool_call_output_item import ResponseCustomToolCallOutputItem +from .response_computer_tool_call_output_item import ResponseComputerToolCallOutputItem +from .response_function_tool_call_output_item import ResponseFunctionToolCallOutputItem from .response_function_shell_tool_call_output import ResponseFunctionShellToolCallOutput __all__ = [ @@ -26,10 +29,12 @@ "ImageGenerationCall", "LocalShellCall", "LocalShellCallAction", + "LocalShellCallOutput", "McpCall", "McpListTools", "McpListToolsTool", "McpApprovalRequest", + "McpApprovalResponse", ] @@ -90,6 +95,22 @@ class LocalShellCall(BaseModel): """The type of the local shell call. Always `local_shell_call`.""" +class LocalShellCallOutput(BaseModel): + """The output of a local shell tool call.""" + + id: str + """The unique ID of the local shell tool call generated by the model.""" + + output: str + """A JSON string of the output of the local shell tool call.""" + + type: Literal["local_shell_call_output"] + """The type of the local shell tool call output. Always `local_shell_call_output`.""" + + status: Optional[Literal["in_progress", "completed", "incomplete"]] = None + """The status of the item. One of `in_progress`, `completed`, or `incomplete`.""" + + class McpCall(BaseModel): """An invocation of a tool on an MCP server.""" @@ -182,13 +203,34 @@ class McpApprovalRequest(BaseModel): """The type of the item. Always `mcp_approval_request`.""" +class McpApprovalResponse(BaseModel): + """A response to an MCP approval request.""" + + id: str + """The unique ID of the approval response""" + + approval_request_id: str + """The ID of the approval request being answered.""" + + approve: bool + """Whether the request was approved.""" + + type: Literal["mcp_approval_response"] + """The type of the item. Always `mcp_approval_response`.""" + + reason: Optional[str] = None + """Optional reason for the decision.""" + + ResponseOutputItem: TypeAlias = Annotated[ Union[ ResponseOutputMessage, ResponseFileSearchToolCall, ResponseFunctionToolCall, + ResponseFunctionToolCallOutputItem, ResponseFunctionWebSearch, ResponseComputerToolCall, + ResponseComputerToolCallOutputItem, ResponseReasoningItem, ResponseToolSearchCall, ResponseToolSearchOutputItem, @@ -196,6 +238,7 @@ class McpApprovalRequest(BaseModel): ImageGenerationCall, ResponseCodeInterpreterToolCall, LocalShellCall, + LocalShellCallOutput, ResponseFunctionShellToolCall, ResponseFunctionShellToolCallOutput, ResponseApplyPatchToolCall, @@ -203,7 +246,9 @@ class McpApprovalRequest(BaseModel): McpCall, McpListTools, McpApprovalRequest, + McpApprovalResponse, ResponseCustomToolCall, + ResponseCustomToolCallOutputItem, ], PropertyInfo(discriminator="type"), ] From 5ae2cc10e4140d36aa236fa7c0bc5ce5ff190a01 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Mar 2026 20:33:44 +0000 Subject: [PATCH 666/769] release: 2.30.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 30 ++++++++++++++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 3a5058bfce..ef8743735a 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.29.0" + ".": "2.30.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index eea76f7709..785fab5782 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,35 @@ # Changelog +## 2.30.0 (2026-03-25) + +Full Changelog: [v2.29.0...v2.30.0](https://github.com/openai/openai-python/compare/v2.29.0...v2.30.0) + +### Features + +* **api:** add keys field to Click/DoubleClick/Drag/Move/Scroll computer actions ([ee1bbed](https://github.com/openai/openai-python/commit/ee1bbeddbb38dab817557412dc106354409bb950)) + + +### Bug Fixes + +* **api:** align SDK response types with expanded item schemas ([f3f258a](https://github.com/openai/openai-python/commit/f3f258a9d4d19db3fb0c6c35e25ad3cedbe71254)) +* sanitize endpoint path params ([89f6698](https://github.com/openai/openai-python/commit/89f66988fde790c0c83ff8b876d1e1b10d616367)) +* **types:** make type required in ResponseInputMessageItem ([cfdb167](https://github.com/openai/openai-python/commit/cfdb1676ea0550840330a58f1a31a40a41a0a53f)) + + +### Chores + +* **ci:** skip lint on metadata-only changes ([faa93e1](https://github.com/openai/openai-python/commit/faa93e19a1d5c30c7dd672a08dbbdbb3c0374714)) +* **internal:** update gitignore ([c468477](https://github.com/openai/openai-python/commit/c468477f1546579618865a726e35a685cffeacd9)) +* **tests:** bump steady to v0.19.4 ([f350af8](https://github.com/openai/openai-python/commit/f350af86c13ade0237778010d264c55fda443354)) +* **tests:** bump steady to v0.19.5 ([5c03401](https://github.com/openai/openai-python/commit/5c0340128fc1a416e2dfdc6ab4b05f1e954e8482)) +* **tests:** bump steady to v0.19.6 ([b6353b8](https://github.com/openai/openai-python/commit/b6353b8411d31dcc95875d801ce9e90a21e0fd52)) +* **tests:** bump steady to v0.19.7 ([1d654be](https://github.com/openai/openai-python/commit/1d654bea74ac9c3d43302587f98f33cfff502e48)) + + +### Refactors + +* **tests:** switch from prism to steady ([4a82035](https://github.com/openai/openai-python/commit/4a82035669b739d16a0e85d4ded778d51e061948)) + ## 2.29.0 (2026-03-17) Full Changelog: [v2.28.0...v2.29.0](https://github.com/openai/openai-python/compare/v2.28.0...v2.29.0) diff --git a/pyproject.toml b/pyproject.toml index 46a72007df..bfc0e13be7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.29.0" +version = "2.30.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 b8a1b37e13..788e82e056 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__ = "2.29.0" # x-release-please-version +__version__ = "2.30.0" # x-release-please-version From 58184ad545ee2abd98e171ee09766f259d7f38cd Mon Sep 17 00:00:00 2001 From: Drew Hintz Date: Fri, 27 Mar 2026 20:16:28 -0500 Subject: [PATCH 667/769] Pin GitHub Actions workflow references (#3021) --- .github/workflows/ci.yml | 10 +++++----- .github/workflows/create-releases.yml | 4 ++-- .github/workflows/detect-breaking-changes.yml | 8 ++++---- .github/workflows/publish-pypi.yml | 2 +- .github/workflows/release-doctor.yml | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b786cbcf6a..414f8ce856 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: runs-on: ${{ github.repository == 'stainless-sdks/openai-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - name: Install Rye run: | @@ -46,7 +46,7 @@ jobs: id-token: write runs-on: ${{ github.repository == 'stainless-sdks/openai-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - name: Install Rye run: | @@ -67,7 +67,7 @@ jobs: github.repository == 'stainless-sdks/openai-python' && !startsWith(github.ref, 'refs/heads/stl/') id: github-oidc - uses: actions/github-script@v8 + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 with: script: core.setOutput('github_token', await core.getIDToken()); @@ -87,7 +87,7 @@ jobs: runs-on: ${{ github.repository == 'stainless-sdks/openai-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - name: Install Rye run: | @@ -110,7 +110,7 @@ jobs: if: github.repository == 'openai/openai-python' && (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - name: Install Rye run: | diff --git a/.github/workflows/create-releases.yml b/.github/workflows/create-releases.yml index f0ef434d02..98b7f20ffe 100644 --- a/.github/workflows/create-releases.yml +++ b/.github/workflows/create-releases.yml @@ -14,9 +14,9 @@ jobs: environment: publish steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - - uses: stainless-api/trigger-release-please@v1 + - uses: stainless-api/trigger-release-please@bb6677c5a04578eec1ccfd9e1913b5b78ed64c61 # v1 id: release with: repo: ${{ github.event.repository.full_name }} diff --git a/.github/workflows/detect-breaking-changes.yml b/.github/workflows/detect-breaking-changes.yml index 87c02061c2..bd73bb6e2a 100644 --- a/.github/workflows/detect-breaking-changes.yml +++ b/.github/workflows/detect-breaking-changes.yml @@ -15,7 +15,7 @@ jobs: run: | echo "FETCH_DEPTH=$(expr ${{ github.event.pull_request.commits }} + 1)" >> $GITHUB_ENV - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: # Ensure we can check out the pull request base in the script below. fetch-depth: ${{ env.FETCH_DEPTH }} @@ -45,7 +45,7 @@ jobs: if: github.repository == 'openai/openai-python' steps: # Setup this sdk - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: path: openai-python @@ -64,13 +64,13 @@ jobs: rye sync --all-features # Setup the agents lib - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: repository: openai/openai-agents-python path: openai-agents-python - name: Setup uv - uses: astral-sh/setup-uv@v5 + uses: astral-sh/setup-uv@e58605a9b6da7c637471fab8847a5e5a6b8df081 # v5 with: enable-cache: true diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml index b9c959ecf3..f67347f2fa 100644 --- a/.github/workflows/publish-pypi.yml +++ b/.github/workflows/publish-pypi.yml @@ -11,7 +11,7 @@ jobs: environment: publish steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - name: Install Rye run: | diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml index be7db8df12..503de9d99a 100644 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -13,7 +13,7 @@ jobs: if: github.repository == 'openai/openai-python' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next') steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - name: Check release environment run: | From d392aae08a2e2f0fdc3eb8985944102a86913694 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 26 Mar 2026 19:29:58 +0000 Subject: [PATCH 668/769] feat(internal): implement indices array format for query and form serialization --- scripts/mock | 4 ++-- scripts/test | 2 +- src/openai/_qs.py | 5 ++++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/scripts/mock b/scripts/mock index 9ecceca0a7..4931f304c7 100755 --- a/scripts/mock +++ b/scripts/mock @@ -24,7 +24,7 @@ if [ "$1" == "--daemon" ]; then # Pre-install the package so the download doesn't eat into the startup timeout npm exec --package=@stdy/cli@0.19.7 -- steady --version - npm exec --package=@stdy/cli@0.19.7 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=brackets --validator-query-array-format=brackets --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" &> .stdy.log & + npm exec --package=@stdy/cli@0.19.7 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=brackets --validator-form-array-format=brackets --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" &> .stdy.log & # Wait for server to come online via health endpoint (max 30s) echo -n "Waiting for server" @@ -48,5 +48,5 @@ if [ "$1" == "--daemon" ]; then echo else - npm exec --package=@stdy/cli@0.19.7 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=brackets --validator-query-array-format=brackets --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" + npm exec --package=@stdy/cli@0.19.7 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=brackets --validator-form-array-format=brackets --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" fi diff --git a/scripts/test b/scripts/test index 9231513853..52bcc4cec8 100755 --- a/scripts/test +++ b/scripts/test @@ -43,7 +43,7 @@ elif ! steady_is_running ; then echo -e "To run the server, pass in the path or url of your OpenAPI" echo -e "spec to the steady command:" echo - echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.7 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-form-array-format=brackets --validator-query-array-format=brackets --validator-form-object-format=brackets --validator-query-object-format=brackets${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.7 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-query-array-format=brackets --validator-form-array-format=brackets --validator-query-object-format=brackets --validator-form-object-format=brackets${NC}" echo exit 1 diff --git a/src/openai/_qs.py b/src/openai/_qs.py index ada6fd3f72..de8c99bc63 100644 --- a/src/openai/_qs.py +++ b/src/openai/_qs.py @@ -101,7 +101,10 @@ def _stringify_item( items.extend(self._stringify_item(key, item, opts)) return items elif array_format == "indices": - raise NotImplementedError("The array indices format is not supported yet") + items = [] + for i, item in enumerate(value): + items.extend(self._stringify_item(f"{key}[{i}]", item, opts)) + return items elif array_format == "brackets": items = [] key = key + "[]" From ad7cc79c80b7ddffb03c0339be05f468ae46d54f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 26 Mar 2026 20:46:42 +0000 Subject: [PATCH 669/769] docs(api): update file parameter descriptions in vector_stores files and file_batches --- .stats.yml | 4 ++-- .../resources/vector_stores/file_batches.py | 20 +++++++++++-------- src/openai/resources/vector_stores/files.py | 8 ++++++-- .../vector_stores/file_batch_create_params.py | 14 ++++++++----- .../types/vector_stores/file_create_params.py | 4 +++- 5 files changed, 32 insertions(+), 18 deletions(-) diff --git a/.stats.yml b/.stats.yml index b2067da764..7fb8cd473d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 152 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-00994178cc8e20d71754b00c54b0e4f5b4128e1c1cce765e9b7d696bd8c80d33.yml -openapi_spec_hash: 81f404053b663f987209b4fb2d08a230 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-24647ccd7356fee965aaca347476460727c6aec762e16a9eb41950d6fbccf0be.yml +openapi_spec_hash: ef99e305f20ae8ae7b2758a205280cca config_hash: 5635033cdc8c930255f8b529a78de722 diff --git a/src/openai/resources/vector_stores/file_batches.py b/src/openai/resources/vector_stores/file_batches.py index f097cf8a92..1ffd7642c0 100644 --- a/src/openai/resources/vector_stores/file_batches.py +++ b/src/openai/resources/vector_stores/file_batches.py @@ -79,14 +79,16 @@ def create( file_ids: A list of [File](https://platform.openai.com/docs/api-reference/files) IDs that the vector store should use. Useful for tools like `file_search` that can access files. If `attributes` or `chunking_strategy` are provided, they will be applied - to all files in the batch. The maximum batch size is 2000 files. Mutually - exclusive with `files`. + to all files in the batch. The maximum batch size is 2000 files. This endpoint + is recommended for multi-file ingestion and helps reduce per-vector-store write + request pressure. Mutually exclusive with `files`. files: A list of objects that each include a `file_id` plus optional `attributes` or `chunking_strategy`. Use this when you need to override metadata for specific files. The global `attributes` or `chunking_strategy` will be ignored and must - be specified for each file. The maximum batch size is 2000 files. Mutually - exclusive with `file_ids`. + be specified for each file. The maximum batch size is 2000 files. This endpoint + is recommended for multi-file ingestion and helps reduce per-vector-store write + request pressure. Mutually exclusive with `file_ids`. extra_headers: Send extra headers @@ -452,14 +454,16 @@ async def create( file_ids: A list of [File](https://platform.openai.com/docs/api-reference/files) IDs that the vector store should use. Useful for tools like `file_search` that can access files. If `attributes` or `chunking_strategy` are provided, they will be applied - to all files in the batch. The maximum batch size is 2000 files. Mutually - exclusive with `files`. + to all files in the batch. The maximum batch size is 2000 files. This endpoint + is recommended for multi-file ingestion and helps reduce per-vector-store write + request pressure. Mutually exclusive with `files`. files: A list of objects that each include a `file_id` plus optional `attributes` or `chunking_strategy`. Use this when you need to override metadata for specific files. The global `attributes` or `chunking_strategy` will be ignored and must - be specified for each file. The maximum batch size is 2000 files. Mutually - exclusive with `file_ids`. + be specified for each file. The maximum batch size is 2000 files. This endpoint + is recommended for multi-file ingestion and helps reduce per-vector-store write + request pressure. Mutually exclusive with `file_ids`. extra_headers: Send extra headers diff --git a/src/openai/resources/vector_stores/files.py b/src/openai/resources/vector_stores/files.py index 8666434587..3ef6137267 100644 --- a/src/openai/resources/vector_stores/files.py +++ b/src/openai/resources/vector_stores/files.py @@ -67,7 +67,9 @@ def create( Args: file_id: A [File](https://platform.openai.com/docs/api-reference/files) ID that the vector store should use. Useful for tools like `file_search` that can access - files. + files. For multi-file ingestion, we recommend + [`file_batches`](https://platform.openai.com/docs/api-reference/vector-stores-file-batches/createBatch) + to minimize per-vector-store write requests. attributes: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format, and @@ -498,7 +500,9 @@ async def create( Args: file_id: A [File](https://platform.openai.com/docs/api-reference/files) ID that the vector store should use. Useful for tools like `file_search` that can access - files. + files. For multi-file ingestion, we recommend + [`file_batches`](https://platform.openai.com/docs/api-reference/vector-stores-file-batches/createBatch) + to minimize per-vector-store write requests. attributes: Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format, and diff --git a/src/openai/types/vector_stores/file_batch_create_params.py b/src/openai/types/vector_stores/file_batch_create_params.py index 7ca0de81da..1e578888c5 100644 --- a/src/openai/types/vector_stores/file_batch_create_params.py +++ b/src/openai/types/vector_stores/file_batch_create_params.py @@ -33,8 +33,9 @@ class FileBatchCreateParams(TypedDict, total=False): A list of [File](https://platform.openai.com/docs/api-reference/files) IDs that the vector store should use. Useful for tools like `file_search` that can access files. If `attributes` or `chunking_strategy` are provided, they will be applied - to all files in the batch. The maximum batch size is 2000 files. Mutually - exclusive with `files`. + to all files in the batch. The maximum batch size is 2000 files. This endpoint + is recommended for multi-file ingestion and helps reduce per-vector-store write + request pressure. Mutually exclusive with `files`. """ files: Iterable[File] @@ -42,8 +43,9 @@ class FileBatchCreateParams(TypedDict, total=False): A list of objects that each include a `file_id` plus optional `attributes` or `chunking_strategy`. Use this when you need to override metadata for specific files. The global `attributes` or `chunking_strategy` will be ignored and must - be specified for each file. The maximum batch size is 2000 files. Mutually - exclusive with `file_ids`. + be specified for each file. The maximum batch size is 2000 files. This endpoint + is recommended for multi-file ingestion and helps reduce per-vector-store write + request pressure. Mutually exclusive with `file_ids`. """ @@ -52,7 +54,9 @@ class File(TypedDict, total=False): """ A [File](https://platform.openai.com/docs/api-reference/files) ID that the vector store should use. Useful for tools like `file_search` that can access - files. + files. For multi-file ingestion, we recommend + [`file_batches`](https://platform.openai.com/docs/api-reference/vector-stores-file-batches/createBatch) + to minimize per-vector-store write requests. """ attributes: Optional[Dict[str, Union[str, float, bool]]] diff --git a/src/openai/types/vector_stores/file_create_params.py b/src/openai/types/vector_stores/file_create_params.py index 5b8989251a..530adee8f6 100644 --- a/src/openai/types/vector_stores/file_create_params.py +++ b/src/openai/types/vector_stores/file_create_params.py @@ -15,7 +15,9 @@ class FileCreateParams(TypedDict, total=False): """ A [File](https://platform.openai.com/docs/api-reference/files) ID that the vector store should use. Useful for tools like `file_search` that can access - files. + files. For multi-file ingestion, we recommend + [`file_batches`](https://platform.openai.com/docs/api-reference/vector-stores-file-batches/createBatch) + to minimize per-vector-store write requests. """ attributes: Optional[Dict[str, Union[str, float, bool]]] From c0c59afa39a82f73063a52f624a9a4a2a6bf3313 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Mar 2026 18:13:17 +0000 Subject: [PATCH 670/769] fix(types): remove web_search_call.results from ResponseIncludable --- .stats.yml | 4 ++-- src/openai/resources/realtime/calls.py | 10 ++++++---- src/openai/types/realtime/call_accept_params.py | 5 +++-- .../types/realtime/realtime_session_create_request.py | 5 +++-- .../realtime/realtime_session_create_request_param.py | 5 +++-- .../types/realtime/realtime_session_create_response.py | 5 +++-- src/openai/types/responses/response_includable.py | 1 - 7 files changed, 20 insertions(+), 15 deletions(-) diff --git a/.stats.yml b/.stats.yml index 7fb8cd473d..4d731cc503 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 152 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-24647ccd7356fee965aaca347476460727c6aec762e16a9eb41950d6fbccf0be.yml -openapi_spec_hash: ef99e305f20ae8ae7b2758a205280cca +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-2fab88288cbbe872f5d61d1d47da2286662a123b4312bc7fc36addba6607cd67.yml +openapi_spec_hash: a7ee80374e409ed9ecc8ea2e3cd31071 config_hash: 5635033cdc8c930255f8b529a78de722 diff --git a/src/openai/resources/realtime/calls.py b/src/openai/resources/realtime/calls.py index f34748d239..8fa2569a96 100644 --- a/src/openai/resources/realtime/calls.py +++ b/src/openai/resources/realtime/calls.py @@ -193,8 +193,9 @@ def accept( tools: Tools available to the model. tracing: Realtime API can write session traces to the - [Traces Dashboard](/logs?api=traces). Set to null to disable tracing. Once - tracing is enabled for a session, the configuration cannot be modified. + [Traces Dashboard](https://platform.openai.com/logs?api=traces). Set to null to + disable tracing. Once tracing is enabled for a session, the configuration cannot + be modified. `auto` will create a trace for the session with default values for the workflow name, group id, and metadata. @@ -522,8 +523,9 @@ async def accept( tools: Tools available to the model. tracing: Realtime API can write session traces to the - [Traces Dashboard](/logs?api=traces). Set to null to disable tracing. Once - tracing is enabled for a session, the configuration cannot be modified. + [Traces Dashboard](https://platform.openai.com/logs?api=traces). Set to null to + disable tracing. Once tracing is enabled for a session, the configuration cannot + be modified. `auto` will create a trace for the session with default values for the workflow name, group id, and metadata. diff --git a/src/openai/types/realtime/call_accept_params.py b/src/openai/types/realtime/call_accept_params.py index 6d8caf9306..1baddbfc2c 100644 --- a/src/openai/types/realtime/call_accept_params.py +++ b/src/openai/types/realtime/call_accept_params.py @@ -101,8 +101,9 @@ class CallAcceptParams(TypedDict, total=False): tracing: Optional[RealtimeTracingConfigParam] """ Realtime API can write session traces to the - [Traces Dashboard](/logs?api=traces). Set to null to disable tracing. Once - tracing is enabled for a session, the configuration cannot be modified. + [Traces Dashboard](https://platform.openai.com/logs?api=traces). Set to null to + disable tracing. Once tracing is enabled for a session, the configuration cannot + be modified. `auto` will create a trace for the session with default values for the workflow name, group id, and metadata. diff --git a/src/openai/types/realtime/realtime_session_create_request.py b/src/openai/types/realtime/realtime_session_create_request.py index e34136a10a..163a0d16d8 100644 --- a/src/openai/types/realtime/realtime_session_create_request.py +++ b/src/openai/types/realtime/realtime_session_create_request.py @@ -103,8 +103,9 @@ class RealtimeSessionCreateRequest(BaseModel): tracing: Optional[RealtimeTracingConfig] = None """ Realtime API can write session traces to the - [Traces Dashboard](/logs?api=traces). Set to null to disable tracing. Once - tracing is enabled for a session, the configuration cannot be modified. + [Traces Dashboard](https://platform.openai.com/logs?api=traces). Set to null to + disable tracing. Once tracing is enabled for a session, the configuration cannot + be modified. `auto` will create a trace for the session with default values for the workflow name, group id, and metadata. diff --git a/src/openai/types/realtime/realtime_session_create_request_param.py b/src/openai/types/realtime/realtime_session_create_request_param.py index f3180c9ed6..19c73b909b 100644 --- a/src/openai/types/realtime/realtime_session_create_request_param.py +++ b/src/openai/types/realtime/realtime_session_create_request_param.py @@ -103,8 +103,9 @@ class RealtimeSessionCreateRequestParam(TypedDict, total=False): tracing: Optional[RealtimeTracingConfigParam] """ Realtime API can write session traces to the - [Traces Dashboard](/logs?api=traces). Set to null to disable tracing. Once - tracing is enabled for a session, the configuration cannot be modified. + [Traces Dashboard](https://platform.openai.com/logs?api=traces). Set to null to + disable tracing. Once tracing is enabled for a session, the configuration cannot + be modified. `auto` will create a trace for the session with default values for the workflow name, group id, and metadata. diff --git a/src/openai/types/realtime/realtime_session_create_response.py b/src/openai/types/realtime/realtime_session_create_response.py index 3c3bef93f4..e2ed5ddce5 100644 --- a/src/openai/types/realtime/realtime_session_create_response.py +++ b/src/openai/types/realtime/realtime_session_create_response.py @@ -509,8 +509,9 @@ class RealtimeSessionCreateResponse(BaseModel): tracing: Optional[Tracing] = None """ Realtime API can write session traces to the - [Traces Dashboard](/logs?api=traces). Set to null to disable tracing. Once - tracing is enabled for a session, the configuration cannot be modified. + [Traces Dashboard](https://platform.openai.com/logs?api=traces). Set to null to + disable tracing. Once tracing is enabled for a session, the configuration cannot + be modified. `auto` will create a trace for the session with default values for the workflow name, group id, and metadata. diff --git a/src/openai/types/responses/response_includable.py b/src/openai/types/responses/response_includable.py index 675c83405a..06e56be8a7 100644 --- a/src/openai/types/responses/response_includable.py +++ b/src/openai/types/responses/response_includable.py @@ -6,7 +6,6 @@ ResponseIncludable: TypeAlias = Literal[ "file_search_call.results", - "web_search_call.results", "web_search_call.action.sources", "message.input_image.image_url", "computer_call_output.output.image_url", From 2076d85f9226113e4ba360a7f456091988092dbf Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 30 Mar 2026 22:45:02 +0000 Subject: [PATCH 671/769] feat(api): add phase field to conversations message --- .stats.yml | 4 ++-- src/openai/types/conversations/message.py | 10 +++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.stats.yml b/.stats.yml index 4d731cc503..de471b8f60 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 152 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-2fab88288cbbe872f5d61d1d47da2286662a123b4312bc7fc36addba6607cd67.yml -openapi_spec_hash: a7ee80374e409ed9ecc8ea2e3cd31071 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-89e54b8e2c185d30e869f73e7798308d56a6a835a675d54628dd86836f147879.yml +openapi_spec_hash: 85b0dd465aa1a034f2764b0758671f21 config_hash: 5635033cdc8c930255f8b529a78de722 diff --git a/src/openai/types/conversations/message.py b/src/openai/types/conversations/message.py index 86c8860da8..075f5bd290 100644 --- a/src/openai/types/conversations/message.py +++ b/src/openai/types/conversations/message.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union +from typing import List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias from ..._utils import PropertyInfo @@ -68,3 +68,11 @@ class Message(BaseModel): type: Literal["message"] """The type of the message. Always set to `message`.""" + + phase: Optional[Literal["commentary", "final_answer"]] = None + """ + Labels an `assistant` message as intermediate commentary (`commentary`) or the + final answer (`final_answer`). For models like `gpt-5.3-codex` and beyond, when + sending follow-up requests, preserve and resend phase on all assistant messages + — dropping it can degrade performance. Not used for user messages. + """ From 6efca95a76f6ca9cb91fdf536c6c9ebcef075541 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 31 Mar 2026 13:33:41 +0000 Subject: [PATCH 672/769] chore(tests): bump steady to v0.20.1 --- scripts/mock | 6 +++--- scripts/test | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/mock b/scripts/mock index 4931f304c7..8b82c3e59c 100755 --- a/scripts/mock +++ b/scripts/mock @@ -22,9 +22,9 @@ echo "==> Starting mock server with URL ${URL}" # Run steady mock on the given spec if [ "$1" == "--daemon" ]; then # Pre-install the package so the download doesn't eat into the startup timeout - npm exec --package=@stdy/cli@0.19.7 -- steady --version + npm exec --package=@stdy/cli@0.20.1 -- steady --version - npm exec --package=@stdy/cli@0.19.7 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=brackets --validator-form-array-format=brackets --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" &> .stdy.log & + npm exec --package=@stdy/cli@0.20.1 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=brackets --validator-form-array-format=brackets --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" &> .stdy.log & # Wait for server to come online via health endpoint (max 30s) echo -n "Waiting for server" @@ -48,5 +48,5 @@ if [ "$1" == "--daemon" ]; then echo else - npm exec --package=@stdy/cli@0.19.7 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=brackets --validator-form-array-format=brackets --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" + npm exec --package=@stdy/cli@0.20.1 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=brackets --validator-form-array-format=brackets --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" fi diff --git a/scripts/test b/scripts/test index 52bcc4cec8..ed64d32077 100755 --- a/scripts/test +++ b/scripts/test @@ -43,7 +43,7 @@ elif ! steady_is_running ; then echo -e "To run the server, pass in the path or url of your OpenAPI" echo -e "spec to the steady command:" echo - echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.7 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-query-array-format=brackets --validator-form-array-format=brackets --validator-query-object-format=brackets --validator-form-object-format=brackets${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.20.1 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-query-array-format=brackets --validator-form-array-format=brackets --validator-query-object-format=brackets --validator-form-object-format=brackets${NC}" echo exit 1 From de2c7b1d087f41f33ada85a7460f32e55331778a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 31 Mar 2026 19:26:08 +0000 Subject: [PATCH 673/769] chore(tests): bump steady to v0.20.2 --- scripts/mock | 6 +++--- scripts/test | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/mock b/scripts/mock index 8b82c3e59c..886f2ffc14 100755 --- a/scripts/mock +++ b/scripts/mock @@ -22,9 +22,9 @@ echo "==> Starting mock server with URL ${URL}" # Run steady mock on the given spec if [ "$1" == "--daemon" ]; then # Pre-install the package so the download doesn't eat into the startup timeout - npm exec --package=@stdy/cli@0.20.1 -- steady --version + npm exec --package=@stdy/cli@0.20.2 -- steady --version - npm exec --package=@stdy/cli@0.20.1 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=brackets --validator-form-array-format=brackets --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" &> .stdy.log & + npm exec --package=@stdy/cli@0.20.2 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=brackets --validator-form-array-format=brackets --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" &> .stdy.log & # Wait for server to come online via health endpoint (max 30s) echo -n "Waiting for server" @@ -48,5 +48,5 @@ if [ "$1" == "--daemon" ]; then echo else - npm exec --package=@stdy/cli@0.20.1 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=brackets --validator-form-array-format=brackets --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" + npm exec --package=@stdy/cli@0.20.2 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=brackets --validator-form-array-format=brackets --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" fi diff --git a/scripts/test b/scripts/test index ed64d32077..57cabda6ae 100755 --- a/scripts/test +++ b/scripts/test @@ -43,7 +43,7 @@ elif ! steady_is_running ; then echo -e "To run the server, pass in the path or url of your OpenAPI" echo -e "spec to the steady command:" echo - echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.20.1 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-query-array-format=brackets --validator-form-array-format=brackets --validator-query-object-format=brackets --validator-form-object-format=brackets${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.20.2 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-query-array-format=brackets --validator-form-array-format=brackets --validator-query-object-format=brackets --validator-form-object-format=brackets${NC}" echo exit 1 From 454b2575d59a086f279d99dc791058acee2f14c0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 4 Apr 2026 04:45:12 +0000 Subject: [PATCH 674/769] feat(api): add web_search_call.results to ResponseIncludable type --- .stats.yml | 4 ++-- src/openai/types/responses/response_includable.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index de471b8f60..b542dc82ac 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 152 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-89e54b8e2c185d30e869f73e7798308d56a6a835a675d54628dd86836f147879.yml -openapi_spec_hash: 85b0dd465aa1a034f2764b0758671f21 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-dd99495ad509338e6de862802839360dfe394d5cd6d6ba6d13fec8fca92328b8.yml +openapi_spec_hash: 68abda9122013a9ae3f084cfdbe8e8c1 config_hash: 5635033cdc8c930255f8b529a78de722 diff --git a/src/openai/types/responses/response_includable.py b/src/openai/types/responses/response_includable.py index 06e56be8a7..675c83405a 100644 --- a/src/openai/types/responses/response_includable.py +++ b/src/openai/types/responses/response_includable.py @@ -6,6 +6,7 @@ ResponseIncludable: TypeAlias = Literal[ "file_search_call.results", + "web_search_call.results", "web_search_call.action.sources", "message.input_image.image_url", "computer_call_output.output.image_url", From 73ea2f75ba57a1db964518b33b790b1e1251b8d5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 7 Apr 2026 16:09:47 +0000 Subject: [PATCH 675/769] fix(client): preserve hardcoded query params when merging with user params --- src/openai/_base_client.py | 4 ++++ tests/test_client.py | 48 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index cf4571bf45..148e273135 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -542,6 +542,10 @@ def _build_request( files = cast(HttpxRequestFiles, ForceMultipartDict()) prepared_url = self._prepare_url(options.url) + # preserve hard-coded query params from the url + if params and prepared_url.query: + params = {**dict(prepared_url.params.items()), **params} + prepared_url = prepared_url.copy_with(raw_path=prepared_url.raw_path.split(b"?", 1)[0]) if "_" in prepared_url.host: # work around https://github.com/encode/httpx/discussions/2880 kwargs["extensions"] = {"sni_hostname": prepared_url.host.replace("_", "-")} diff --git a/tests/test_client.py b/tests/test_client.py index a015cd7d40..04ef6794ed 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -434,6 +434,30 @@ def test_default_query_option(self) -> None: client.close() + def test_hardcoded_query_params_in_url(self, client: OpenAI) -> None: + request = client._build_request(FinalRequestOptions(method="get", url="/foo?beta=true")) + url = httpx.URL(request.url) + assert dict(url.params) == {"beta": "true"} + + request = client._build_request( + FinalRequestOptions( + method="get", + url="/foo?beta=true", + params={"limit": "10", "page": "abc"}, + ) + ) + url = httpx.URL(request.url) + assert dict(url.params) == {"beta": "true", "limit": "10", "page": "abc"} + + request = client._build_request( + FinalRequestOptions( + method="get", + url="/files/a%2Fb?beta=true", + params={"limit": "10"}, + ) + ) + assert request.url.raw_path == b"/files/a%2Fb?beta=true&limit=10" + def test_request_extra_json(self, client: OpenAI) -> None: request = client._build_request( FinalRequestOptions( @@ -1466,6 +1490,30 @@ async def test_default_query_option(self) -> None: await client.close() + async def test_hardcoded_query_params_in_url(self, async_client: AsyncOpenAI) -> None: + request = async_client._build_request(FinalRequestOptions(method="get", url="/foo?beta=true")) + url = httpx.URL(request.url) + assert dict(url.params) == {"beta": "true"} + + request = async_client._build_request( + FinalRequestOptions( + method="get", + url="/foo?beta=true", + params={"limit": "10", "page": "abc"}, + ) + ) + url = httpx.URL(request.url) + assert dict(url.params) == {"beta": "true", "limit": "10", "page": "abc"} + + request = async_client._build_request( + FinalRequestOptions( + method="get", + url="/files/a%2Fb?beta=true", + params={"limit": "10"}, + ) + ) + assert request.url.raw_path == b"/files/a%2Fb?beta=true&limit=10" + def test_request_extra_json(self, client: OpenAI) -> None: request = client._build_request( FinalRequestOptions( From f1fd4fae0329ee3df2f1bb25d93f51311782ad1a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 8 Apr 2026 15:06:02 +0000 Subject: [PATCH 676/769] feat(client): support sending raw data over websockets --- src/openai/resources/realtime/realtime.py | 6 ++++++ src/openai/resources/responses/responses.py | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/openai/resources/realtime/realtime.py b/src/openai/resources/realtime/realtime.py index 73a87fc2e7..82c9815b03 100644 --- a/src/openai/resources/realtime/realtime.py +++ b/src/openai/resources/realtime/realtime.py @@ -292,6 +292,9 @@ async def send(self, event: RealtimeClientEvent | RealtimeClientEventParam) -> N ) await self._connection.send(data) + async def send_raw(self, data: bytes | str) -> None: + await self._connection.send(data) + async def close(self, *, code: int = 1000, reason: str = "") -> None: await self._connection.close(code=code, reason=reason) @@ -483,6 +486,9 @@ def send(self, event: RealtimeClientEvent | RealtimeClientEventParam) -> None: ) self._connection.send(data) + def send_raw(self, data: bytes | str) -> None: + self._connection.send(data) + def close(self, *, code: int = 1000, reason: str = "") -> None: self._connection.close(code=code, reason=reason) diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 63795f95a9..360c5afa1a 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -3632,6 +3632,9 @@ async def send(self, event: ResponsesClientEvent | ResponsesClientEventParam) -> ) await self._connection.send(data) + async def send_raw(self, data: bytes | str) -> None: + await self._connection.send(data) + async def close(self, *, code: int = 1000, reason: str = "") -> None: await self._connection.close(code=code, reason=reason) @@ -3798,6 +3801,9 @@ def send(self, event: ResponsesClientEvent | ResponsesClientEventParam) -> None: ) self._connection.send(data) + def send_raw(self, data: bytes | str) -> None: + self._connection.send(data) + def close(self, *, code: int = 1000, reason: str = "") -> None: self._connection.close(code=code, reason=reason) From 5be95364a5a82746cb7b1c77df10dfaf138496bb Mon Sep 17 00:00:00 2001 From: Kar Petrosyan <92274156+karpetrosyan@users.noreply.github.com> Date: Wed, 8 Apr 2026 23:57:12 +0400 Subject: [PATCH 677/769] feat(client): add support for short-lived tokens (#1608) Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> --- .stats.yml | 4 +- README.md | 103 ++++++ api.md | 1 + src/openai/__init__.py | 2 + src/openai/_base_client.py | 31 +- src/openai/_client.py | 159 +++++++-- src/openai/_exceptions.py | 28 ++ src/openai/auth/__init__.py | 19 ++ src/openai/auth/_workload.py | 313 +++++++++++++++++ src/openai/lib/azure.py | 9 + src/openai/types/__init__.py | 1 + src/openai/types/shared/__init__.py | 1 + src/openai/types/shared/oauth_error_code.py | 8 + src/openai/types/shared_params/__init__.py | 1 + .../types/shared_params/oauth_error_code.py | 10 + tests/test_auth.py | 190 +++++++++++ tests/test_client.py | 323 +++++++++++++++++- 17 files changed, 1170 insertions(+), 33 deletions(-) create mode 100644 src/openai/auth/__init__.py create mode 100644 src/openai/auth/_workload.py create mode 100644 src/openai/types/shared/oauth_error_code.py create mode 100644 src/openai/types/shared_params/oauth_error_code.py create mode 100644 tests/test_auth.py diff --git a/.stats.yml b/.stats.yml index b542dc82ac..461d4c7c07 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 152 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-dd99495ad509338e6de862802839360dfe394d5cd6d6ba6d13fec8fca92328b8.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-a6eca1bd01e0c434af356fe5275c206057216a4e626d1051d294c27016cd6d05.yml openapi_spec_hash: 68abda9122013a9ae3f084cfdbe8e8c1 -config_hash: 5635033cdc8c930255f8b529a78de722 +config_hash: 4975e16a94e8f9901428022044131888 diff --git a/README.md b/README.md index 7e4f0ae657..9450c0bc51 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,109 @@ to add `OPENAI_API_KEY="My API Key"` to your `.env` file so that your API key is not stored in source control. [Get an API key here](https://platform.openai.com/settings/organization/api-keys). +### Workload Identity Authentication + +For secure, automated environments like cloud-managed Kubernetes, Azure, and Google Cloud Platform, you can use workload identity authentication with short-lived tokens from cloud identity providers instead of long-lived API keys. + +#### Kubernetes (service account tokens) + +```python +from openai import OpenAI +from openai.auth import k8s_service_account_token_provider + +client = OpenAI( + workload_identity={ + "client_id": "your-client-id", + "identity_provider_id": "idp-123", + "service_account_id": "sa-456", + "provider": k8s_service_account_token_provider( + "/var/run/secrets/kubernetes.io/serviceaccount/token" + ), + }, + organization="org-xyz", + project="proj-abc", +) + +response = client.chat.completions.create( + model="gpt-4", + messages=[{"role": "user", "content": "Hello!"}], +) +``` + +#### Azure (managed identity) + +```python +from openai import OpenAI +from openai.auth import azure_managed_identity_token_provider + +client = OpenAI( + workload_identity={ + "client_id": "your-client-id", + "identity_provider_id": "idp-123", + "service_account_id": "sa-456", + "provider": azure_managed_identity_token_provider( + resource="https://management.azure.com/", + ), + }, +) +``` + +#### Google Cloud Platform (compute engine metadata) + +```python +from openai import OpenAI +from openai.auth import gcp_id_token_provider + +client = OpenAI( + workload_identity={ + "client_id": "your-client-id", + "identity_provider_id": "idp-123", + "service_account_id": "sa-456", + "provider": gcp_id_token_provider(audience="https://api.openai.com/v1"), + }, +) +``` + +#### Custom subject token provider + +```python +from openai import OpenAI + + +def get_custom_token() -> str: + return "your-jwt-token" + + +client = OpenAI( + workload_identity={ + "client_id": "your-client-id", + "identity_provider_id": "idp-123", + "service_account_id": "sa-456", + "provider": { + "token_type": "jwt", + "get_token": get_custom_token, + }, + } +) +``` + +You can also customize the token refresh buffer (default is 1200 seconds (20 minutes) before expiration): + +```python +from openai import OpenAI +from openai.auth import k8s_service_account_token_provider + +client = OpenAI( + workload_identity={ + "client_id": "your-client-id", + "identity_provider_id": "idp-123", + "service_account_id": "sa-456", + "provider": k8s_service_account_token_provider("/var/token"), + "refresh_buffer_seconds": 120.0, + } +) +``` + ### Vision With an image URL: diff --git a/api.md b/api.md index 852df5bb8a..decf4e0129 100644 --- a/api.md +++ b/api.md @@ -11,6 +11,7 @@ from openai.types import ( FunctionDefinition, FunctionParameters, Metadata, + OAuthErrorCode, Reasoning, ReasoningEffort, ResponseFormatJSONObject, diff --git a/src/openai/__init__.py b/src/openai/__init__.py index b2093ada68..3e0a135929 100644 --- a/src/openai/__init__.py +++ b/src/openai/__init__.py @@ -16,6 +16,7 @@ from ._constants import DEFAULT_TIMEOUT, DEFAULT_MAX_RETRIES, DEFAULT_CONNECTION_LIMITS from ._exceptions import ( APIError, + OAuthError, OpenAIError, ConflictError, NotFoundError, @@ -57,6 +58,7 @@ "APIResponseValidationError", "BadRequestError", "AuthenticationError", + "OAuthError", "PermissionDeniedError", "NotFoundError", "ConflictError", diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index 148e273135..a1d0960700 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -30,7 +30,7 @@ cast, overload, ) -from typing_extensions import Literal, override, get_origin +from typing_extensions import Unpack, Literal, override, get_origin import anyio import httpx @@ -81,6 +81,7 @@ ) from ._streaming import Stream, SSEDecoder, AsyncStream, SSEBytesDecoder from ._exceptions import ( + OpenAIError, APIStatusError, APITimeoutError, APIConnectionError, @@ -936,6 +937,15 @@ def _prepare_request( """ return None + def _send_request( + self, + request: httpx.Request, + *, + stream: bool, + **kwargs: Unpack[HttpxSendArgs], + ) -> httpx.Response: + return self._client.send(request, stream=stream, **kwargs) + @overload def request( self, @@ -1006,7 +1016,7 @@ def request( response = None try: - response = self._client.send( + response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, @@ -1025,6 +1035,9 @@ def request( log.debug("Raising timeout error") raise APITimeoutError(request=request) from err + except OpenAIError as err: + # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError + raise err except Exception as err: log.debug("Encountered Exception", exc_info=True) @@ -1530,6 +1543,15 @@ async def _prepare_request( """ return None + async def _send_request( + self, + request: httpx.Request, + *, + stream: bool, + **kwargs: Unpack[HttpxSendArgs], + ) -> httpx.Response: + return await self._client.send(request, stream=stream, **kwargs) + @overload async def request( self, @@ -1605,7 +1627,7 @@ async def request( response = None try: - response = await self._client.send( + response = await self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, @@ -1624,6 +1646,9 @@ async def request( log.debug("Raising timeout error") raise APITimeoutError(request=request) from err + except OpenAIError as err: + # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError + raise err except Exception as err: log.debug("Encountered Exception", exc_info=True) diff --git a/src/openai/_client.py b/src/openai/_client.py index aadf3601f2..434f957e19 100644 --- a/src/openai/_client.py +++ b/src/openai/_client.py @@ -4,18 +4,20 @@ import os from typing import TYPE_CHECKING, Any, Mapping, Callable, Awaitable -from typing_extensions import Self, override +from typing_extensions import Self, Unpack, override import httpx from . import _exceptions from ._qs import Querystring +from .auth import WorkloadIdentity, WorkloadIdentityAuth from ._types import ( Omit, Timeout, NotGiven, Transport, ProxiesTypes, + HttpxSendArgs, RequestOptions, not_given, ) @@ -82,13 +84,17 @@ __all__ = ["Timeout", "Transport", "ProxiesTypes", "RequestOptions", "OpenAI", "AsyncOpenAI", "Client", "AsyncClient"] +WORKLOAD_IDENTITY_API_KEY_PLACEHOLDER = "workload-identity-auth" + class OpenAI(SyncAPIClient): # client options api_key: str + workload_identity: WorkloadIdentity | None organization: str | None project: str | None webhook_secret: str | None + _workload_identity_auth: WorkloadIdentityAuth | None websocket_base_url: str | httpx.URL | None """Base URL for WebSocket connections. @@ -102,6 +108,7 @@ def __init__( self, *, api_key: str | None | Callable[[], str] = None, + workload_identity: WorkloadIdentity | None = None, organization: str | None = None, project: str | None = None, webhook_secret: str | None = None, @@ -133,18 +140,31 @@ def __init__( - `project` from `OPENAI_PROJECT_ID` - `webhook_secret` from `OPENAI_WEBHOOK_SECRET` """ - if api_key is None: - api_key = os.environ.get("OPENAI_API_KEY") - if api_key is None: - raise OpenAIError( - "The api_key client option must be set either by passing api_key to the client or by setting the OPENAI_API_KEY environment variable" + if api_key is not None and api_key != WORKLOAD_IDENTITY_API_KEY_PLACEHOLDER and workload_identity is not None: + raise OpenAIError("The `api_key` and `workload_identity` arguments are mutually exclusive") + + self.workload_identity = workload_identity + + if workload_identity is not None: + self.api_key = WORKLOAD_IDENTITY_API_KEY_PLACEHOLDER + self._api_key_provider = None + self._workload_identity_auth = WorkloadIdentityAuth( + workload_identity=workload_identity, ) - if callable(api_key): - self.api_key = "" - self._api_key_provider: Callable[[], str] | None = api_key else: - self.api_key = api_key - self._api_key_provider = None + if api_key is None: + api_key = os.environ.get("OPENAI_API_KEY") + if api_key is None: + raise OpenAIError( + "The api_key client option must be set either by passing api_key to the client or by setting the OPENAI_API_KEY environment variable" + ) + if callable(api_key): + self.api_key = "" + self._api_key_provider: Callable[[], str] | None = api_key # type: ignore[no-redef] + else: + self.api_key = api_key + self._api_key_provider = None + self._workload_identity_auth = None if organization is None: organization = os.environ.get("OPENAI_ORG_ID") @@ -344,11 +364,46 @@ def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOptions: self._refresh_api_key() return super()._prepare_options(options) + def _send_with_auth_retry( + self, + request: httpx.Request, + *, + stream: bool, + retried: bool = False, + **kwargs: Unpack[HttpxSendArgs], + ) -> httpx.Response: + if self._workload_identity_auth: + request.headers["Authorization"] = f"Bearer {self._workload_identity_auth.get_token()}" + + response = super()._send_request(request, stream=stream, **kwargs) + + if not retried and response.status_code == 401 and self._workload_identity_auth: + response.close() + + self._workload_identity_auth.invalidate_token() + fresh_token = self._workload_identity_auth.get_token() + + request.headers["Authorization"] = f"Bearer {fresh_token}" + + return self._send_with_auth_retry(request, stream=stream, retried=True, **kwargs) + + return response + + @override + def _send_request( + self, + request: httpx.Request, + *, + stream: bool, + **kwargs: Unpack[HttpxSendArgs], + ) -> httpx.Response: + return self._send_with_auth_retry(request, stream=stream, **kwargs) + @property @override def auth_headers(self) -> dict[str, str]: api_key = self.api_key - if not api_key: + if not api_key or api_key == WORKLOAD_IDENTITY_API_KEY_PLACEHOLDER: # if the api key is an empty string, encoding the header will fail return {} return {"Authorization": f"Bearer {api_key}"} @@ -368,6 +423,7 @@ def copy( self, *, api_key: str | Callable[[], str] | None = None, + workload_identity: WorkloadIdentity | None = None, organization: str | None = None, project: str | None = None, webhook_secret: str | None = None, @@ -404,8 +460,10 @@ def copy( params = set_default_query http_client = http_client or self._client + return self.__class__( api_key=api_key or self._api_key_provider or self.api_key, + workload_identity=workload_identity or self.workload_identity, organization=organization or self.organization, project=project or self.project, webhook_secret=webhook_secret or self.webhook_secret, @@ -461,9 +519,11 @@ def _make_status_error( class AsyncOpenAI(AsyncAPIClient): # client options api_key: str + workload_identity: WorkloadIdentity | None organization: str | None project: str | None webhook_secret: str | None + _workload_identity_auth: WorkloadIdentityAuth | None websocket_base_url: str | httpx.URL | None """Base URL for WebSocket connections. @@ -476,7 +536,8 @@ class AsyncOpenAI(AsyncAPIClient): def __init__( self, *, - api_key: str | Callable[[], Awaitable[str]] | None = None, + api_key: str | None | Callable[[], Awaitable[str]] = None, + workload_identity: WorkloadIdentity | None = None, organization: str | None = None, project: str | None = None, webhook_secret: str | None = None, @@ -508,18 +569,31 @@ def __init__( - `project` from `OPENAI_PROJECT_ID` - `webhook_secret` from `OPENAI_WEBHOOK_SECRET` """ - if api_key is None: - api_key = os.environ.get("OPENAI_API_KEY") - if api_key is None: - raise OpenAIError( - "The api_key client option must be set either by passing api_key to the client or by setting the OPENAI_API_KEY environment variable" + if api_key is not None and api_key != WORKLOAD_IDENTITY_API_KEY_PLACEHOLDER and workload_identity is not None: + raise OpenAIError("The `api_key` and `workload_identity` arguments are mutually exclusive") + + self.workload_identity = workload_identity + + if workload_identity is not None: + self.api_key = WORKLOAD_IDENTITY_API_KEY_PLACEHOLDER + self._api_key_provider = None + self._workload_identity_auth = WorkloadIdentityAuth( + workload_identity=workload_identity, ) - if callable(api_key): - self.api_key = "" - self._api_key_provider: Callable[[], Awaitable[str]] | None = api_key else: - self.api_key = api_key - self._api_key_provider = None + if api_key is None: + api_key = os.environ.get("OPENAI_API_KEY") + if api_key is None: + raise OpenAIError( + "The api_key client option must be set either by passing api_key to the client or by setting the OPENAI_API_KEY environment variable" + ) + if callable(api_key): + self.api_key = "" + self._api_key_provider: Callable[[], Awaitable[str]] | None = api_key # type: ignore[no-redef] + else: + self.api_key = api_key + self._api_key_provider = None + self._workload_identity_auth = None if organization is None: organization = os.environ.get("OPENAI_ORG_ID") @@ -719,11 +793,46 @@ async def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOp await self._refresh_api_key() return await super()._prepare_options(options) + async def _send_with_auth_retry( + self, + request: httpx.Request, + *, + stream: bool, + retried: bool = False, + **kwargs: Unpack[HttpxSendArgs], + ) -> httpx.Response: + if self._workload_identity_auth: + request.headers["Authorization"] = f"Bearer {await self._workload_identity_auth.get_token_async()}" + + response = await super()._send_request(request, stream=stream, **kwargs) + + if not retried and response.status_code == 401 and self._workload_identity_auth: + await response.aclose() + + self._workload_identity_auth.invalidate_token() + fresh_token = await self._workload_identity_auth.get_token_async() + + request.headers["Authorization"] = f"Bearer {fresh_token}" + + return await self._send_with_auth_retry(request, stream=stream, retried=True, **kwargs) + + return response + + @override + async def _send_request( + self, + request: httpx.Request, + *, + stream: bool, + **kwargs: Unpack[HttpxSendArgs], + ) -> httpx.Response: + return await self._send_with_auth_retry(request, stream=stream, **kwargs) + @property @override def auth_headers(self) -> dict[str, str]: api_key = self.api_key - if not api_key: + if not api_key or api_key == WORKLOAD_IDENTITY_API_KEY_PLACEHOLDER: # if the api key is an empty string, encoding the header will fail return {} return {"Authorization": f"Bearer {api_key}"} @@ -743,6 +852,7 @@ def copy( self, *, api_key: str | Callable[[], Awaitable[str]] | None = None, + workload_identity: WorkloadIdentity | None = None, organization: str | None = None, project: str | None = None, webhook_secret: str | None = None, @@ -781,6 +891,7 @@ def copy( http_client = http_client or self._client return self.__class__( api_key=api_key or self._api_key_provider or self.api_key, + workload_identity=workload_identity or self.workload_identity, organization=organization or self.organization, project=project or self.project, webhook_secret=webhook_secret or self.webhook_secret, diff --git a/src/openai/_exceptions.py b/src/openai/_exceptions.py index 09016dfedb..a37ed8ca82 100644 --- a/src/openai/_exceptions.py +++ b/src/openai/_exceptions.py @@ -9,6 +9,7 @@ from ._utils import is_dict from ._models import construct_type +from .types.shared.oauth_error_code import OAuthErrorCode if TYPE_CHECKING: from .types.chat import ChatCompletion @@ -16,6 +17,7 @@ __all__ = [ "BadRequestError", "AuthenticationError", + "OAuthError", "PermissionDeniedError", "NotFoundError", "ConflictError", @@ -25,6 +27,7 @@ "LengthFinishReasonError", "ContentFilterFinishReasonError", "InvalidWebhookSignatureError", + "SubjectTokenProviderError", ] @@ -32,6 +35,14 @@ class OpenAIError(Exception): pass +class SubjectTokenProviderError(OpenAIError): + response: httpx.Response | None + + def __init__(self, message: str, *, response: httpx.Response | None = None) -> None: + super().__init__(message) + self.response = response + + class APIError(OpenAIError): message: str request: httpx.Request @@ -109,6 +120,23 @@ class AuthenticationError(APIStatusError): status_code: Literal[401] = 401 # pyright: ignore[reportIncompatibleVariableOverride] +class OAuthError(AuthenticationError): + error: Optional[OAuthErrorCode] + + def __init__(self, *, response: httpx.Response, body: object | None) -> None: + message = "OAuth authentication error." + error = None + + if is_dict(body): + error = body.get("error") + description = body.get("error_description") + if description and isinstance(description, str): + message = description + + super().__init__(message, response=response, body=body) + self.error = cast(Optional[OAuthErrorCode], error) + + class PermissionDeniedError(APIStatusError): status_code: Literal[403] = 403 # pyright: ignore[reportIncompatibleVariableOverride] diff --git a/src/openai/auth/__init__.py b/src/openai/auth/__init__.py new file mode 100644 index 0000000000..367aa86b72 --- /dev/null +++ b/src/openai/auth/__init__.py @@ -0,0 +1,19 @@ +from __future__ import annotations + +from ._workload import ( + WorkloadIdentity as WorkloadIdentity, + SubjectTokenProvider as SubjectTokenProvider, + WorkloadIdentityAuth as WorkloadIdentityAuth, + gcp_id_token_provider as gcp_id_token_provider, + k8s_service_account_token_provider as k8s_service_account_token_provider, + azure_managed_identity_token_provider as azure_managed_identity_token_provider, +) + +__all__ = [ + "SubjectTokenProvider", + "WorkloadIdentity", + "WorkloadIdentityAuth", + "k8s_service_account_token_provider", + "azure_managed_identity_token_provider", + "gcp_id_token_provider", +] diff --git a/src/openai/auth/_workload.py b/src/openai/auth/_workload.py new file mode 100644 index 0000000000..e3f6f7fb75 --- /dev/null +++ b/src/openai/auth/_workload.py @@ -0,0 +1,313 @@ +from __future__ import annotations + +import time +import threading +from typing import Any, Callable, TypedDict, cast +from pathlib import Path +from typing_extensions import Literal, NotRequired + +import httpx + +from .._exceptions import OAuthError, OpenAIError, SubjectTokenProviderError +from .._utils._sync import to_thread + +TOKEN_EXCHANGE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:token-exchange" +DEFAULT_TOKEN_EXCHANGE_URL = "https://auth.openai.com/oauth/token" +DEFAULT_REFRESH_BUFFER_SECONDS = 1200 + +SUBJECT_TOKEN_TYPES = { + "jwt": "urn:ietf:params:oauth:token-type:jwt", + "id": "urn:ietf:params:oauth:token-type:id_token", +} + + +class SubjectTokenProvider(TypedDict): + token_type: Literal["jwt", "id"] + get_token: Callable[[], str] + + +class WorkloadIdentity(TypedDict): + """A unique string that identifies the client.""" + + client_id: str + + """Identity provider resource id in WIFAPI.""" + identity_provider_id: str + + """Service account id to bind the verified external identity to.""" + service_account_id: str + + """The provider configuration for obtaining the subject token.""" + provider: SubjectTokenProvider + + """Optional buffer time in seconds to refresh the OpenAI token before it expires. Defaults to 1200 seconds (20 minutes).""" + refresh_buffer_seconds: NotRequired[float] + + +def k8s_service_account_token_provider( + token_file_path: str | Path = "/var/run/secrets/kubernetes.io/serviceaccount/token", +) -> SubjectTokenProvider: + """ + Get a subject token provider for Kubernetes clusters with Workload Identity configured. + + Cloud providers typically mount the subject token as a file in the container. + + Args: + token_file_path: path to the mounted service account token file. Defaults to `/var/run/secrets/kubernetes.io/serviceaccount/token`. + """ + + def get_token() -> str: + try: + with open(token_file_path, "r") as f: + token = f.read().strip() + if not token: + raise SubjectTokenProviderError(f"The token file at {token_file_path} is empty.") + return token + except Exception as e: + raise SubjectTokenProviderError(f"Failed to read the token file at {token_file_path}: {e}") from e + + return {"token_type": "jwt", "get_token": get_token} + + +def azure_managed_identity_token_provider( + resource: str = "https://management.azure.com/", + *, + object_id: str | None = None, + client_id: str | None = None, + msi_res_id: str | None = None, + api_version: str = "2018-02-01", + timeout: float = 10.0, + http_client: httpx.Client | None = None, +) -> SubjectTokenProvider: + """ + Get a subject token provider for Azure Managed Identities. + + See: https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/how-to-use-vm-token#get-a-token-using-http + + Args: + resource: the resource URI to request a token for. Defaults to `https://management.azure.com/` (Azure Resource Manager). + object_id: the object ID of the managed identity to use, when multiple are assigned. + client_id: the client ID of the managed identity to use, when multiple are assigned. + msi_res_id: the ARM resource ID of the managed identity to use, when multiple are assigned. + api_version: the Azure IMDS API version. Defaults to `2018-02-01`. + timeout: the request timeout in seconds. Defaults to 10.0. + http_client: optional httpx.Client instance to use for requests. If not provided, a new client will be created for each request. + """ + + def get_token() -> str: + try: + url = "http://169.254.169.254/metadata/identity/oauth2/token" + params: dict[str, str] = {"api-version": api_version, "resource": resource} + if object_id is not None: + params["object_id"] = object_id + if client_id is not None: + params["client_id"] = client_id + if msi_res_id is not None: + params["msi_res_id"] = msi_res_id + + if http_client is not None: + response = http_client.get(url, params=params, headers={"Metadata": "true"}, timeout=timeout) + else: + with httpx.Client() as client: + response = client.get(url, params=params, headers={"Metadata": "true"}, timeout=timeout) + + if response.is_error: + raise SubjectTokenProviderError( + f"Failed to fetch Azure subject token from IMDS: HTTP {response.status_code}", + response=response, + ) + data = response.json() + token = data.get("access_token") + if not token: + raise SubjectTokenProviderError( + "Azure IMDS response did not include an access_token", response=response + ) + return cast(str, token) + except Exception as e: + raise SubjectTokenProviderError(f"Failed to fetch Azure subject token from IMDS: {e}") from e + + return {"token_type": "jwt", "get_token": get_token} + + +def gcp_id_token_provider( + audience: str = "https://api.openai.com/v1", + *, + timeout: float = 10.0, + http_client: httpx.Client | None = None, +) -> SubjectTokenProvider: + """ + Get a subject token provider for GCP VM instances using the instance metadata server. + + See: https://cloud.google.com/compute/docs/instances/verifying-instance-identity + + Args: + audience: the unique URI agreed upon by both the instance and the system verifying + the instance's identity. Defaults to `https://api.openai.com/v1`. + timeout: the request timeout in seconds. Defaults to 10.0. + http_client: optional httpx.Client instance to use for requests. If not provided, a new client will be created for each request. + """ + + def get_token() -> str: + try: + url = "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity" + params = {"audience": audience} + + if http_client is not None: + response = http_client.get(url, params=params, headers={"Metadata-Flavor": "Google"}, timeout=timeout) + else: + with httpx.Client() as client: + response = client.get(url, params=params, headers={"Metadata-Flavor": "Google"}, timeout=timeout) + + if response.is_error: + raise SubjectTokenProviderError( + f"Failed to fetch GCP subject token from metadata server: HTTP {response.status_code}", + response=response, + ) + token = response.text.strip() + if not token: + raise SubjectTokenProviderError("GCP metadata server returned an empty token", response=response) + return token + except Exception as e: + raise SubjectTokenProviderError(f"Failed to fetch GCP subject token from metadata server: {e}") from e + + return {"token_type": "id", "get_token": get_token} + + +class WorkloadIdentityAuth: + def __init__( + self, + *, + workload_identity: WorkloadIdentity, + token_exchange_url: str = DEFAULT_TOKEN_EXCHANGE_URL, + ): + self.workload_identity = workload_identity + self.token_exchange_url = token_exchange_url + + self._cached_token: str | None = None + self._cached_token_expires_at_monotonic: float | None = None + self._cached_token_refresh_at_monotonic: float | None = None + self._refreshing: bool = False + self._lock = threading.Lock() + self._condition = threading.Condition(self._lock) + + def get_token(self) -> str: + with self._lock: + while self._refreshing and self._token_unusable(): + self._condition.wait() + + if not self._token_unusable() and not self._needs_refresh(): + return cast(str, self._cached_token) + + if self._refreshing: + while self._refreshing: + self._condition.wait() + token = self._cached_token # type: ignore[unreachable] + if self._token_unusable(): + raise RuntimeError("Token is unusable after refresh completed") + return cast(str, token) + + self._refreshing = True + + try: + self._perform_refresh() + with self._lock: + if self._token_unusable(): + raise RuntimeError("Token is unusable after refresh completed") + return cast(str, self._cached_token) + finally: + with self._lock: + self._refreshing = False + self._condition.notify_all() + + async def get_token_async(self) -> str: + return await to_thread(self.get_token) + + def invalidate_token(self) -> None: + with self._lock: + self._cached_token = None + self._cached_token_expires_at_monotonic = None + self._cached_token_refresh_at_monotonic = None + + def _perform_refresh(self) -> None: + token_data = self._fetch_token_from_exchange() + now = time.monotonic() + expires_in = token_data["expires_in"] + + with self._lock: + self._cached_token = token_data["access_token"] + self._cached_token_expires_at_monotonic = now + expires_in + self._cached_token_refresh_at_monotonic = now + self._refresh_delay_seconds(expires_in) + + def _fetch_token_from_exchange(self) -> dict[str, Any]: + subject_token = self._get_subject_token() + + token_type = self.workload_identity["provider"]["token_type"] + subject_token_type = SUBJECT_TOKEN_TYPES.get(token_type) + if subject_token_type is None: + raise OpenAIError( + f"Unsupported token type: {token_type!r}. Supported types: {', '.join(SUBJECT_TOKEN_TYPES.keys())}" + ) + + with httpx.Client() as client: + response = client.post( + self.token_exchange_url, + json={ + "grant_type": TOKEN_EXCHANGE_GRANT_TYPE, + "client_id": self.workload_identity["client_id"], + "subject_token": subject_token, + "subject_token_type": subject_token_type, + "identity_provider_id": self.workload_identity["identity_provider_id"], + "service_account_id": self.workload_identity["service_account_id"], + }, + timeout=10.0, + ) + return self._handle_token_response(response) + + def _handle_token_response(self, response: httpx.Response) -> dict[str, Any]: + try: + body = response.json() if response.content else None + except ValueError: + body = None + + if response.status_code in (400, 401, 403): + raise OAuthError(response=response, body=body) + + if response.is_success: + if body is None: + raise OpenAIError("Token exchange succeeded but response body was empty") + access_token = body.get("access_token") + expires_in = body.get("expires_in") + if not isinstance(access_token, str) or not access_token: + raise OpenAIError("Token exchange response did not include a valid access_token") + if not isinstance(expires_in, (int, float)): + raise OpenAIError("Token exchange response did not include a valid expires_in") + return {"access_token": access_token, "expires_in": float(expires_in)} + + raise OpenAIError( + f"Token exchange failed with status {response.status_code}", + ) + + def _get_subject_token(self) -> str: + provider = self.workload_identity["provider"] + subject_token = provider["get_token"]() + if not subject_token: + raise OpenAIError("The workload identity provider returned an empty subject token") + return subject_token + + def _token_unusable(self) -> bool: + return self._cached_token is None or self._token_expired() + + def _token_expired(self) -> bool: + if self._cached_token_expires_at_monotonic is None: + return True + return time.monotonic() >= self._cached_token_expires_at_monotonic + + def _needs_refresh(self) -> bool: + if self._cached_token_refresh_at_monotonic is None: + return False + return time.monotonic() >= self._cached_token_refresh_at_monotonic + + def _refresh_delay_seconds(self, expires_in: float) -> float: + configured_buffer = self.workload_identity.get("refresh_buffer_seconds", DEFAULT_REFRESH_BUFFER_SECONDS) + effective_buffer = min(configured_buffer, expires_in / 2) + return max(expires_in - effective_buffer, 0.0) diff --git a/src/openai/lib/azure.py b/src/openai/lib/azure.py index ad64707261..09fdd9507e 100644 --- a/src/openai/lib/azure.py +++ b/src/openai/lib/azure.py @@ -7,6 +7,7 @@ import httpx +from ..auth import WorkloadIdentity from .._types import NOT_GIVEN, Omit, Query, Timeout, NotGiven from .._utils import is_given, is_mapping from .._client import OpenAI, AsyncOpenAI @@ -155,6 +156,8 @@ def __init__( azure_endpoint: str | None = None, azure_deployment: str | None = None, api_key: str | Callable[[], str] | None = None, + # workload_identity is not functional in the Azure client + workload_identity: WorkloadIdentity | None = None, # noqa: ARG002 azure_ad_token: str | None = None, azure_ad_token_provider: AzureADTokenProvider | None = None, organization: str | None = None, @@ -259,6 +262,7 @@ def copy( self, *, api_key: str | Callable[[], str] | None = None, + workload_identity: WorkloadIdentity | None = None, organization: str | None = None, project: str | None = None, webhook_secret: str | None = None, @@ -281,6 +285,7 @@ def copy( """ return super().copy( api_key=api_key, + workload_identity=workload_identity, organization=organization, project=project, webhook_secret=webhook_secret, @@ -436,6 +441,8 @@ def __init__( azure_deployment: str | None = None, api_version: str | None = None, api_key: str | Callable[[], Awaitable[str]] | None = None, + # workload_identity is not functional in the Azure client + workload_identity: WorkloadIdentity | None = None, # noqa: ARG002 azure_ad_token: str | None = None, azure_ad_token_provider: AsyncAzureADTokenProvider | None = None, organization: str | None = None, @@ -540,6 +547,7 @@ def copy( self, *, api_key: str | Callable[[], Awaitable[str]] | None = None, + workload_identity: WorkloadIdentity | None = None, organization: str | None = None, project: str | None = None, webhook_secret: str | None = None, @@ -562,6 +570,7 @@ def copy( """ return super().copy( api_key=api_key, + workload_identity=workload_identity, organization=organization, project=project, webhook_secret=webhook_secret, diff --git a/src/openai/types/__init__.py b/src/openai/types/__init__.py index d8dbea71ad..6074eb0a1d 100644 --- a/src/openai/types/__init__.py +++ b/src/openai/types/__init__.py @@ -14,6 +14,7 @@ Reasoning as Reasoning, ErrorObject as ErrorObject, CompoundFilter as CompoundFilter, + OAuthErrorCode as OAuthErrorCode, ResponsesModel as ResponsesModel, ReasoningEffort as ReasoningEffort, ComparisonFilter as ComparisonFilter, diff --git a/src/openai/types/shared/__init__.py b/src/openai/types/shared/__init__.py index 2930b9ae3b..55d3e86371 100644 --- a/src/openai/types/shared/__init__.py +++ b/src/openai/types/shared/__init__.py @@ -7,6 +7,7 @@ from .error_object import ErrorObject as ErrorObject from .compound_filter import CompoundFilter as CompoundFilter from .responses_model import ResponsesModel as ResponsesModel +from .oauth_error_code import OAuthErrorCode as OAuthErrorCode from .reasoning_effort import ReasoningEffort as ReasoningEffort from .comparison_filter import ComparisonFilter as ComparisonFilter from .function_definition import FunctionDefinition as FunctionDefinition diff --git a/src/openai/types/shared/oauth_error_code.py b/src/openai/types/shared/oauth_error_code.py new file mode 100644 index 0000000000..4ef3924293 --- /dev/null +++ b/src/openai/types/shared/oauth_error_code.py @@ -0,0 +1,8 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from typing_extensions import Literal, TypeAlias + +__all__ = ["OAuthErrorCode"] + +OAuthErrorCode: TypeAlias = Union[Literal["invalid_grant", "invalid_subject_token"], str] diff --git a/src/openai/types/shared_params/__init__.py b/src/openai/types/shared_params/__init__.py index b6c0912b0f..0ed5fbaa80 100644 --- a/src/openai/types/shared_params/__init__.py +++ b/src/openai/types/shared_params/__init__.py @@ -5,6 +5,7 @@ from .chat_model import ChatModel as ChatModel from .compound_filter import CompoundFilter as CompoundFilter from .responses_model import ResponsesModel as ResponsesModel +from .oauth_error_code import OAuthErrorCode as OAuthErrorCode from .reasoning_effort import ReasoningEffort as ReasoningEffort from .comparison_filter import ComparisonFilter as ComparisonFilter from .function_definition import FunctionDefinition as FunctionDefinition diff --git a/src/openai/types/shared_params/oauth_error_code.py b/src/openai/types/shared_params/oauth_error_code.py new file mode 100644 index 0000000000..cb3c981881 --- /dev/null +++ b/src/openai/types/shared_params/oauth_error_code.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import Literal, TypeAlias + +__all__ = ["OAuthErrorCode"] + +OAuthErrorCode: TypeAlias = Union[Literal["invalid_grant", "invalid_subject_token"], str] diff --git a/tests/test_auth.py b/tests/test_auth.py new file mode 100644 index 0000000000..c8f4f2d7cf --- /dev/null +++ b/tests/test_auth.py @@ -0,0 +1,190 @@ +import json +from typing import cast +from pathlib import Path + +import httpx +import respx +import pytest +from respx.models import Call +from inline_snapshot import snapshot + +from openai import OpenAI, OAuthError +from openai.auth._workload import ( + gcp_id_token_provider, + k8s_service_account_token_provider, + azure_managed_identity_token_provider, +) + + +@respx.mock +def test_basic_auth(): + respx.post("https://auth.openai.com/oauth/token").mock( + return_value=httpx.Response( + 200, + json={ + "access_token": "fake_access_token", + "issued_token_type": "urn:ietf:params:oauth:token-type:access_token", + "token_type": "Bearer", + "expires_in": 3600, + }, + ) + ) + + respx.get("https://api.openai.com/v1/models").mock( + return_value=httpx.Response(200, json={"data": [], "object": "list"}) + ) + + client = OpenAI( + workload_identity={ + "client_id": "client_123", + "identity_provider_id": "idp_123", + "service_account_id": "sa_123", + "provider": { + "get_token": lambda: "fake_subject_token", + "token_type": "jwt", + }, + }, + ) + + client.models.list() + + assert len(respx.calls) == 2 + token_call = cast(Call, respx.calls[0]) + api_call = cast(Call, respx.calls[1]) + + assert token_call.request.url == "https://auth.openai.com/oauth/token" + assert api_call.request.headers.get("Authorization") == "Bearer fake_access_token" + + +@respx.mock +def test_workload_identity_exchange_payload_and_cache() -> None: + provider_call_count = 0 + + def provider() -> str: + nonlocal provider_call_count + provider_call_count += 1 + return "fake_subject_token" + + exchange_route = respx.post("https://auth.openai.com/oauth/token").mock( + return_value=httpx.Response( + 200, + json={ + "access_token": "fake_access_token", + "issued_token_type": "urn:ietf:params:oauth:token-type:access_token", + "token_type": "Bearer", + "expires_in": 3600, + }, + ) + ) + api_route = respx.get("https://api.openai.com/v1/models").mock( + return_value=httpx.Response(200, json={"data": [], "object": "list"}) + ) + + client = OpenAI( + workload_identity={ + "client_id": "client_123", + "identity_provider_id": "idp_123", + "service_account_id": "sa_123", + "provider": { + "get_token": provider, + "token_type": "jwt", + }, + }, + ) + + client.models.list() + client.models.list() + + assert provider_call_count == 1 + assert exchange_route.call_count == 1 + assert api_route.call_count == 2 + + exchange_request = cast(respx.models.Call, exchange_route.calls[0]).request + assert json.loads(exchange_request.content) == snapshot( + { + "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange", + "client_id": "client_123", + "subject_token": "fake_subject_token", + "subject_token_type": "urn:ietf:params:oauth:token-type:jwt", + "identity_provider_id": "idp_123", + "service_account_id": "sa_123", + } + ) + + assert ( + cast(respx.models.Call, api_route.calls[0]).request.headers.get("Authorization") == "Bearer fake_access_token" + ) + assert ( + cast(respx.models.Call, api_route.calls[1]).request.headers.get("Authorization") == "Bearer fake_access_token" + ) + + +@respx.mock +def test_workload_identity_exchange_error() -> None: + exchange_route = respx.post("https://auth.openai.com/oauth/token").mock( + return_value=httpx.Response( + 401, + json={ + "error": "invalid_grant", + "error_description": "No service account mapping found for the provided service_account_id.", + }, + ) + ) + api_route = respx.get("https://api.openai.com/v1/models").mock( + return_value=httpx.Response(200, json={"data": [], "object": "list"}) + ) + + client = OpenAI( + workload_identity={ + "client_id": "client_123", + "identity_provider_id": "idp_123", + "service_account_id": "sa_123", + "provider": { + "get_token": lambda: "fake_subject_token", + "token_type": "jwt", + }, + }, + ) + + with pytest.raises(OAuthError) as exc: + client.models.list() + + assert exc.value.message == "No service account mapping found for the provided service_account_id." + assert exc.value.error == "invalid_grant" + assert exc.value.status_code == 401 + assert exchange_route.call_count == 1 + assert api_route.call_count == 0 + + +def test_k8s_service_account_token_provider(tmp_path: Path) -> None: + token_file = tmp_path / "token" + token_file.write_text("my-k8s-token") + + provider = k8s_service_account_token_provider(token_file) + + assert provider["token_type"] == "jwt" + assert provider["get_token"]() == "my-k8s-token" + + +@respx.mock +def test_azure_managed_identity_token_provider() -> None: + respx.get("http://169.254.169.254/metadata/identity/oauth2/token").mock( + return_value=httpx.Response(200, json={"access_token": "azure-token"}) + ) + + provider = azure_managed_identity_token_provider() + + assert provider["token_type"] == "jwt" + assert provider["get_token"]() == "azure-token" + + +@respx.mock +def test_gcp_id_token_provider() -> None: + respx.get("http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity").mock( + return_value=httpx.Response(200, text="gcp-token") + ) + + provider = gcp_id_token_provider() + + assert provider["token_type"] == "id" + assert provider["get_token"]() == "gcp-token" diff --git a/tests/test_client.py b/tests/test_client.py index 04ef6794ed..570042c46a 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -20,6 +20,7 @@ from pydantic import ValidationError from openai import OpenAI, AsyncOpenAI, APIResponseValidationError +from openai.auth import WorkloadIdentity from openai._types import Omit from openai._utils import asyncify from openai._models import BaseModel, FinalRequestOptions @@ -41,6 +42,15 @@ T = TypeVar("T") base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") api_key = "My API Key" +workload_identity: WorkloadIdentity = { + "client_id": "client-id", + "identity_provider_id": "identity-provider-id", + "service_account_id": "service-account-id", + "provider": { + "token_type": "jwt", + "get_token": lambda: "external-subject-token", + }, +} class MockRequestCall(Protocol): @@ -414,6 +424,19 @@ def test_validate_headers(self) -> None: client2 = OpenAI(base_url=base_url, api_key=None, _strict_response_validation=True) _ = client2 + def test_workload_identity_is_mutually_exclusive_with_api_key(self) -> None: + with pytest.raises( + OpenAIError, + match="The `api_key` and `workload_identity` arguments are mutually exclusive", + ): + OpenAI( + base_url=base_url, + api_key=api_key, + workload_identity=workload_identity, # type: ignore[reportArgumentType] + organization="org_123", + _strict_response_validation=True, + ) + def test_default_query_option(self) -> None: client = OpenAI( base_url=base_url, api_key=api_key, _strict_response_validation=True, default_query={"query_param": "bar"} @@ -2189,7 +2212,6 @@ async def test_follow_redirects_disabled(self, respx_mock: MockRouter, async_cli assert exc_info.value.response.status_code == 302 assert exc_info.value.response.headers["Location"] == f"{base_url}/redirected" - @pytest.mark.asyncio async def test_api_key_before_after_refresh_provider(self) -> None: async def mock_api_key_provider(): return "test_bearer_token" @@ -2204,7 +2226,6 @@ async def mock_api_key_provider(): assert client.api_key == "test_bearer_token" assert client.auth_headers.get("Authorization") == "Bearer test_bearer_token" - @pytest.mark.asyncio async def test_api_key_before_after_refresh_str(self) -> None: client = AsyncOpenAI(base_url=base_url, api_key="test_api_key") @@ -2213,7 +2234,6 @@ async def test_api_key_before_after_refresh_str(self) -> None: assert client.auth_headers.get("Authorization") == "Bearer test_api_key" - @pytest.mark.asyncio @pytest.mark.respx() async def test_bearer_token_refresh_async(self, respx_mock: MockRouter) -> None: respx_mock.post(base_url + "/chat/completions").mock( @@ -2244,7 +2264,6 @@ async def token_provider() -> str: assert calls[0].request.headers.get("Authorization") == "Bearer first" assert calls[1].request.headers.get("Authorization") == "Bearer second" - @pytest.mark.asyncio async def test_copy_auth(self) -> None: async def token_provider_1() -> str: return "test_bearer_token_1" @@ -2255,3 +2274,299 @@ async def token_provider_2() -> str: client = AsyncOpenAI(base_url=base_url, api_key=token_provider_1).copy(api_key=token_provider_2) await client._refresh_api_key() assert client.auth_headers == {"Authorization": "Bearer test_bearer_token_2"} + + +class TestWorkloadIdentity401Retry: + @pytest.mark.respx() + def test_workload_identity_401_retry(self, respx_mock: MockRouter) -> None: + provider_call_count = 0 + + def provider() -> str: + nonlocal provider_call_count + provider_call_count += 1 + return f"external-subject-token-{provider_call_count}" + + respx_mock.post("https://auth.openai.com/oauth/token").mock( + side_effect=[ + httpx.Response( + 200, + json={ + "access_token": "openai-access-token-1", + "issued_token_type": "urn:ietf:params:oauth:token-type:access_token", + "token_type": "Bearer", + "expires_in": 3600, + }, + ), + httpx.Response( + 200, + json={ + "access_token": "openai-access-token-2", + "issued_token_type": "urn:ietf:params:oauth:token-type:access_token", + "token_type": "Bearer", + "expires_in": 3600, + }, + ), + ] + ) + + respx_mock.post(base_url + "/chat/completions").mock( + side_effect=[ + httpx.Response(401, json={"error": {"message": "Unauthorized", "type": "invalid_request_error"}}), + httpx.Response( + 200, + json={ + "id": "chatcmpl-123", + "object": "chat.completion", + "created": 1234567890, + "model": "gpt-4", + "choices": [], + }, + ), + ] + ) + + with OpenAI( + base_url=base_url, + workload_identity={ + **workload_identity, + "provider": { + "get_token": provider, + "token_type": "jwt", + }, + }, + organization="org_123", + project="proj_123", + _strict_response_validation=True, + ) as client: + client.chat.completions.create(messages=[], model="gpt-4") + + calls = cast("list[MockRequestCall]", respx_mock.calls) + assert len(calls) == 4 + + assert calls[0].request.url == httpx.URL("https://auth.openai.com/oauth/token") + assert calls[1].request.url == httpx.URL(base_url + "/chat/completions") + assert calls[1].request.headers.get("Authorization") == "Bearer openai-access-token-1" + + assert calls[2].request.url == httpx.URL("https://auth.openai.com/oauth/token") + + assert calls[3].request.url == httpx.URL(base_url + "/chat/completions") + assert calls[3].request.headers.get("Authorization") == "Bearer openai-access-token-2" + + assert provider_call_count == 2 + + @pytest.mark.respx() + def test_401_without_workload_identity_no_retry(self, respx_mock: MockRouter) -> None: + respx_mock.post(base_url + "/chat/completions").mock( + return_value=httpx.Response( + 401, json={"error": {"message": "Unauthorized", "type": "invalid_request_error"}} + ) + ) + + with OpenAI( + base_url=base_url, + api_key="test-api-key", + _strict_response_validation=True, + ) as client: + with pytest.raises(APIStatusError) as exc_info: + client.chat.completions.create(messages=[], model="gpt-4") + + assert exc_info.value.status_code == 401 + + calls = cast("list[MockRequestCall]", respx_mock.calls) + assert len(calls) == 1 + + @pytest.mark.respx() + def test_non_401_errors_no_retry(self, respx_mock: MockRouter) -> None: + provider_call_count = 0 + + def provider() -> str: + nonlocal provider_call_count + provider_call_count += 1 + return "external-subject-token" + + respx_mock.post("https://auth.openai.com/oauth/token").mock( + return_value=httpx.Response( + 200, + json={ + "access_token": "openai-access-token-1", + "issued_token_type": "urn:ietf:params:oauth:token-type:access_token", + "token_type": "Bearer", + "expires_in": 3600, + }, + ) + ) + + respx_mock.post(base_url + "/chat/completions").mock( + return_value=httpx.Response(403, json={"error": {"message": "Forbidden", "type": "invalid_request_error"}}) + ) + + with OpenAI( + base_url=base_url, + workload_identity={ + **workload_identity, + "provider": { + "get_token": provider, + "token_type": "jwt", + }, + }, + organization="org_123", + project="proj_123", + _strict_response_validation=True, + ) as client: + with pytest.raises(APIStatusError) as exc_info: + client.chat.completions.create(messages=[], model="gpt-4") + + assert exc_info.value.status_code == 403 + + calls = cast("list[MockRequestCall]", respx_mock.calls) + assert len(calls) == 2 + + assert provider_call_count == 1 + + +class TestAsyncWorkloadIdentity401Retry: + @pytest.mark.respx() + async def test_workload_identity_401_retry(self, respx_mock: MockRouter) -> None: + provider_call_count = 0 + + def provider() -> str: + nonlocal provider_call_count + provider_call_count += 1 + return f"external-subject-token-{provider_call_count}" + + respx_mock.post("https://auth.openai.com/oauth/token").mock( + side_effect=[ + httpx.Response( + 200, + json={ + "access_token": "openai-access-token-1", + "issued_token_type": "urn:ietf:params:oauth:token-type:access_token", + "token_type": "Bearer", + "expires_in": 3600, + }, + ), + httpx.Response( + 200, + json={ + "access_token": "openai-access-token-2", + "issued_token_type": "urn:ietf:params:oauth:token-type:access_token", + "token_type": "Bearer", + "expires_in": 3600, + }, + ), + ] + ) + + respx_mock.post(base_url + "/chat/completions").mock( + side_effect=[ + httpx.Response(401, json={"error": {"message": "Unauthorized", "type": "invalid_request_error"}}), + httpx.Response( + 200, + json={ + "id": "chatcmpl-123", + "object": "chat.completion", + "created": 1234567890, + "model": "gpt-4", + "choices": [], + }, + ), + ] + ) + + async with AsyncOpenAI( + base_url=base_url, + workload_identity={ + **workload_identity, + "provider": { + "get_token": provider, + "token_type": "jwt", + }, + }, + organization="org_123", + project="proj_123", + _strict_response_validation=True, + ) as client: + await client.chat.completions.create(messages=[], model="gpt-4") + + calls = cast("list[MockRequestCall]", respx_mock.calls) + assert len(calls) == 4 + + assert calls[0].request.url == httpx.URL("https://auth.openai.com/oauth/token") + assert calls[1].request.url == httpx.URL(base_url + "/chat/completions") + assert calls[1].request.headers.get("Authorization") == "Bearer openai-access-token-1" + + assert calls[2].request.url == httpx.URL("https://auth.openai.com/oauth/token") + + assert calls[3].request.url == httpx.URL(base_url + "/chat/completions") + assert calls[3].request.headers.get("Authorization") == "Bearer openai-access-token-2" + + assert provider_call_count == 2 + + @pytest.mark.respx() + async def test_401_without_workload_identity_no_retry(self, respx_mock: MockRouter) -> None: + respx_mock.post(base_url + "/chat/completions").mock( + return_value=httpx.Response( + 401, json={"error": {"message": "Unauthorized", "type": "invalid_request_error"}} + ) + ) + + async with AsyncOpenAI( + base_url=base_url, + api_key="test-api-key", + _strict_response_validation=True, + ) as client: + with pytest.raises(APIStatusError) as exc_info: + await client.chat.completions.create(messages=[], model="gpt-4") + + assert exc_info.value.status_code == 401 + + calls = cast("list[MockRequestCall]", respx_mock.calls) + assert len(calls) == 1 + + @pytest.mark.respx() + async def test_non_401_errors_no_retry(self, respx_mock: MockRouter) -> None: + provider_call_count = 0 + + def provider() -> str: + nonlocal provider_call_count + provider_call_count += 1 + return "external-subject-token" + + respx_mock.post("https://auth.openai.com/oauth/token").mock( + return_value=httpx.Response( + 200, + json={ + "access_token": "openai-access-token-1", + "issued_token_type": "urn:ietf:params:oauth:token-type:access_token", + "token_type": "Bearer", + "expires_in": 3600, + }, + ) + ) + + respx_mock.post(base_url + "/chat/completions").mock( + return_value=httpx.Response(403, json={"error": {"message": "Forbidden", "type": "invalid_request_error"}}) + ) + + async with AsyncOpenAI( + base_url=base_url, + workload_identity={ + **workload_identity, + "provider": { + "get_token": provider, + "token_type": "jwt", + }, + }, + organization="org_123", + project="proj_123", + _strict_response_validation=True, + ) as client: + with pytest.raises(APIStatusError) as exc_info: + await client.chat.completions.create(messages=[], model="gpt-4") + + assert exc_info.value.status_code == 403 + + calls = cast("list[MockRequestCall]", respx_mock.calls) + assert len(calls) == 2 + + assert provider_call_count == 1 From 750354ed65565b31d0547bf00f4f3180ac1bfeef Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 8 Apr 2026 19:57:59 +0000 Subject: [PATCH 678/769] release: 2.31.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 29 +++++++++++++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index ef8743735a..8f5c652f67 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.30.0" + ".": "2.31.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 785fab5782..bf8092f51f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,34 @@ # Changelog +## 2.31.0 (2026-04-08) + +Full Changelog: [v2.30.0...v2.31.0](https://github.com/openai/openai-python/compare/v2.30.0...v2.31.0) + +### Features + +* **api:** add phase field to conversations message ([3e5834e](https://github.com/openai/openai-python/commit/3e5834efb39b24e019a29dc54d890c67d18cbb54)) +* **api:** add web_search_call.results to ResponseIncludable type ([ffd8741](https://github.com/openai/openai-python/commit/ffd8741dd38609a5af0159ceb800d8ddba7925f8)) +* **client:** add support for short-lived tokens ([#1608](https://github.com/openai/openai-python/issues/1608)) ([22fe722](https://github.com/openai/openai-python/commit/22fe7228d4990c197cd721b3ad7931ad05cca5dd)) +* **client:** support sending raw data over websockets ([f1bc52e](https://github.com/openai/openai-python/commit/f1bc52ef641dfca6fdf2a5b00ce3b09bff2552f5)) +* **internal:** implement indices array format for query and form serialization ([49194cf](https://github.com/openai/openai-python/commit/49194cfa711328216ff131d6f65c9298822a7c51)) + + +### Bug Fixes + +* **client:** preserve hardcoded query params when merging with user params ([92e109c](https://github.com/openai/openai-python/commit/92e109c3d9569a942e1919e75977dc13fa015f9a)) +* **types:** remove web_search_call.results from ResponseIncludable ([d3cc401](https://github.com/openai/openai-python/commit/d3cc40165cd86015833d15167cc7712b4102f932)) + + +### Chores + +* **tests:** bump steady to v0.20.1 ([d60e2ee](https://github.com/openai/openai-python/commit/d60e2eea7f6916540cd4ba901dceb07051119da4)) +* **tests:** bump steady to v0.20.2 ([6508d47](https://github.com/openai/openai-python/commit/6508d474332d4e82d9615c0a9a77379f9b5e4412)) + + +### Documentation + +* **api:** update file parameter descriptions in vector_stores files and file_batches ([a9e7ebd](https://github.com/openai/openai-python/commit/a9e7ebd505b9ae90514339aa63c6f1984a08cf6b)) + ## 2.30.0 (2026-03-25) Full Changelog: [v2.29.0...v2.30.0](https://github.com/openai/openai-python/compare/v2.29.0...v2.30.0) diff --git a/pyproject.toml b/pyproject.toml index bfc0e13be7..c85db6b519 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.30.0" +version = "2.31.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 788e82e056..a435bdb765 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__ = "2.30.0" # x-release-please-version +__version__ = "2.31.0" # x-release-please-version From e507a4ebeea4c3f93cd48986014a3e2ca79230c2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 15 Apr 2026 18:27:17 -0400 Subject: [PATCH 679/769] release: 2.32.0 (#3074) --- .github/workflows/ci.yml | 48 +- .github/workflows/create-releases.yml | 12 +- .github/workflows/detect-breaking-changes.yml | 27 +- .github/workflows/publish-pypi.yml | 12 +- .release-please-manifest.json | 2 +- .stats.yml | 6 +- CHANGELOG.md | 22 + pyproject.toml | 2 +- src/openai/__init__.py | 7 + src/openai/_event_handler.py | 85 +++ src/openai/_exceptions.py | 18 + src/openai/_send_queue.py | 90 +++ src/openai/_utils/_utils.py | 5 +- src/openai/_version.py | 2 +- src/openai/resources/realtime/realtime.py | 694 +++++++++++++++-- src/openai/resources/responses/responses.py | 707 ++++++++++++++++-- src/openai/types/__init__.py | 4 + .../types/responses/response_input_file.py | 7 + .../responses/response_input_file_content.py | 7 + .../response_input_file_content_param.py | 7 + .../responses/response_input_file_param.py | 7 + src/openai/types/websocket_reconnection.py | 64 ++ tests/api_resources/audio/test_speech.py | 32 +- tests/api_resources/beta/test_assistants.py | 4 +- tests/api_resources/beta/test_threads.py | 8 +- tests/api_resources/beta/threads/test_runs.py | 8 +- tests/api_resources/chat/test_completions.py | 8 +- tests/api_resources/realtime/test_calls.py | 32 +- .../realtime/test_client_secrets.py | 16 +- tests/api_resources/test_completions.py | 32 +- tests/api_resources/test_images.py | 20 +- tests/api_resources/test_moderations.py | 4 +- tests/api_resources/test_responses.py | 8 +- tests/api_resources/test_videos.py | 4 +- tests/test_extract_files.py | 9 + tests/test_send_queue.py | 128 ++++ 36 files changed, 1888 insertions(+), 260 deletions(-) create mode 100644 src/openai/_event_handler.py create mode 100644 src/openai/_send_queue.py create mode 100644 src/openai/types/websocket_reconnection.py create mode 100644 tests/test_send_queue.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 414f8ce856..527e036a0e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,13 +23,11 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - - name: Install Rye - run: | - curl -sSf https://rye.astral.sh/get | bash - echo "$HOME/.rye/shims" >> $GITHUB_PATH - env: - RYE_VERSION: '0.44.0' - RYE_INSTALL_OPTION: '--yes' + - name: Set up Rye + uses: eifinger/setup-rye@c694239a43768373e87d0103d7f547027a23f3c8 + with: + version: '0.44.0' + enable-cache: true - name: Install dependencies run: rye sync --all-features @@ -48,13 +46,11 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - - name: Install Rye - run: | - curl -sSf https://rye.astral.sh/get | bash - echo "$HOME/.rye/shims" >> $GITHUB_PATH - env: - RYE_VERSION: '0.44.0' - RYE_INSTALL_OPTION: '--yes' + - name: Set up Rye + uses: eifinger/setup-rye@c694239a43768373e87d0103d7f547027a23f3c8 + with: + version: '0.44.0' + enable-cache: true - name: Install dependencies run: rye sync --all-features @@ -89,13 +85,11 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - - name: Install Rye - run: | - curl -sSf https://rye.astral.sh/get | bash - echo "$HOME/.rye/shims" >> $GITHUB_PATH - env: - RYE_VERSION: '0.44.0' - RYE_INSTALL_OPTION: '--yes' + - name: Set up Rye + uses: eifinger/setup-rye@c694239a43768373e87d0103d7f547027a23f3c8 + with: + version: '0.44.0' + enable-cache: true - name: Bootstrap run: ./scripts/bootstrap @@ -112,13 +106,11 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - - name: Install Rye - run: | - curl -sSf https://rye.astral.sh/get | bash - echo "$HOME/.rye/shims" >> $GITHUB_PATH - env: - RYE_VERSION: '0.44.0' - RYE_INSTALL_OPTION: '--yes' + - name: Set up Rye + uses: eifinger/setup-rye@c694239a43768373e87d0103d7f547027a23f3c8 + with: + version: '0.44.0' + enable-cache: true - name: Install dependencies run: | rye sync --all-features diff --git a/.github/workflows/create-releases.yml b/.github/workflows/create-releases.yml index 98b7f20ffe..f819d07310 100644 --- a/.github/workflows/create-releases.yml +++ b/.github/workflows/create-releases.yml @@ -22,14 +22,12 @@ jobs: repo: ${{ github.event.repository.full_name }} stainless-api-key: ${{ secrets.STAINLESS_API_KEY }} - - name: Install Rye + - name: Set up Rye if: ${{ steps.release.outputs.releases_created }} - run: | - curl -sSf https://rye.astral.sh/get | bash - echo "$HOME/.rye/shims" >> $GITHUB_PATH - env: - RYE_VERSION: '0.44.0' - RYE_INSTALL_OPTION: '--yes' + uses: eifinger/setup-rye@c694239a43768373e87d0103d7f547027a23f3c8 + with: + version: '0.44.0' + enable-cache: true - name: Publish to PyPI if: ${{ steps.release.outputs.releases_created }} diff --git a/.github/workflows/detect-breaking-changes.yml b/.github/workflows/detect-breaking-changes.yml index bd73bb6e2a..641129f010 100644 --- a/.github/workflows/detect-breaking-changes.yml +++ b/.github/workflows/detect-breaking-changes.yml @@ -20,13 +20,11 @@ jobs: # Ensure we can check out the pull request base in the script below. fetch-depth: ${{ env.FETCH_DEPTH }} - - name: Install Rye - run: | - curl -sSf https://rye.astral.sh/get | bash - echo "$HOME/.rye/shims" >> $GITHUB_PATH - env: - RYE_VERSION: '0.44.0' - RYE_INSTALL_OPTION: '--yes' + - name: Set up Rye + uses: eifinger/setup-rye@c694239a43768373e87d0103d7f547027a23f3c8 + with: + version: '0.44.0' + enable-cache: true - name: Install dependencies run: | rye sync --all-features @@ -49,14 +47,12 @@ jobs: with: path: openai-python - - name: Install Rye - working-directory: openai-python - run: | - curl -sSf https://rye.astral.sh/get | bash - echo "$HOME/.rye/shims" >> $GITHUB_PATH - env: - RYE_VERSION: '0.44.0' - RYE_INSTALL_OPTION: '--yes' + - name: Set up Rye + uses: eifinger/setup-rye@c694239a43768373e87d0103d7f547027a23f3c8 + with: + version: '0.44.0' + enable-cache: true + working-directory: openai-python - name: Install dependencies working-directory: openai-python @@ -85,4 +81,3 @@ jobs: - name: Run integration type checks working-directory: openai-agents-python run: make mypy - diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml index f67347f2fa..a7c62c4c4d 100644 --- a/.github/workflows/publish-pypi.yml +++ b/.github/workflows/publish-pypi.yml @@ -13,13 +13,11 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - - name: Install Rye - run: | - curl -sSf https://rye.astral.sh/get | bash - echo "$HOME/.rye/shims" >> $GITHUB_PATH - env: - RYE_VERSION: '0.44.0' - RYE_INSTALL_OPTION: '--yes' + - name: Set up Rye + uses: eifinger/setup-rye@c694239a43768373e87d0103d7f547027a23f3c8 + with: + version: '0.44.0' + enable-cache: true - name: Publish to PyPI run: | diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 8f5c652f67..527d2e30b0 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.31.0" + ".": "2.32.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 461d4c7c07..f069d6c8b9 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 152 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-a6eca1bd01e0c434af356fe5275c206057216a4e626d1051d294c27016cd6d05.yml -openapi_spec_hash: 68abda9122013a9ae3f084cfdbe8e8c1 -config_hash: 4975e16a94e8f9901428022044131888 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-7c540cce6eb30401259f4831ea9803b6d88501605d13734f98212cbb3b199e10.yml +openapi_spec_hash: 06e656be22bbb92689954253668b42fc +config_hash: 1a88b104658b6c854117996c080ebe6b diff --git a/CHANGELOG.md b/CHANGELOG.md index bf8092f51f..2640bc3d63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,27 @@ # Changelog +## 2.32.0 (2026-04-15) + +Full Changelog: [v2.31.0...v2.32.0](https://github.com/openai/openai-python/compare/v2.31.0...v2.32.0) + +### Features + +* **api:** Add detail to InputFileContent ([60de21d](https://github.com/openai/openai-python/commit/60de21d1fcfbcadea0d9b8d884c73c9dc49d14ff)) +* **api:** add OAuthErrorCode type ([0c8d2c3](https://github.com/openai/openai-python/commit/0c8d2c3b44242c9139dc554896ea489b56e236b8)) +* **client:** add event handler implementation for websockets ([0280d05](https://github.com/openai/openai-python/commit/0280d0568f706684ecbf0aabf3575cdcb7fd22d5)) +* **client:** allow enqueuing to websockets even when not connected ([67aa20e](https://github.com/openai/openai-python/commit/67aa20e69bc0e4a3b7694327c808606bfa24a966)) +* **client:** support reconnection in websockets ([eb72a95](https://github.com/openai/openai-python/commit/eb72a953ea9dc5beec3eef537be6eb32292c3f65)) + + +### Bug Fixes + +* ensure file data are only sent as 1 parameter ([c0c2ecd](https://github.com/openai/openai-python/commit/c0c2ecd0f6b64fa5fafda6134bb06995b143a2cf)) + + +### Documentation + +* improve examples ([84712fa](https://github.com/openai/openai-python/commit/84712fa0f094b53151a0fe6ac85aa98018b2a7e2)) + ## 2.31.0 (2026-04-08) Full Changelog: [v2.30.0...v2.31.0](https://github.com/openai/openai-python/compare/v2.30.0...v2.31.0) diff --git a/pyproject.toml b/pyproject.toml index c85db6b519..d0d533e8a6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.31.0" +version = "2.32.0" description = "The official Python library for the openai API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/openai/__init__.py b/src/openai/__init__.py index 3e0a135929..fc9675a8b5 100644 --- a/src/openai/__init__.py +++ b/src/openai/__init__.py @@ -29,14 +29,17 @@ InternalServerError, PermissionDeniedError, LengthFinishReasonError, + WebSocketQueueFullError, UnprocessableEntityError, APIResponseValidationError, InvalidWebhookSignatureError, ContentFilterFinishReasonError, + WebSocketConnectionClosedError, ) from ._base_client import DefaultHttpxClient, DefaultAioHttpClient, DefaultAsyncHttpxClient from ._utils._logs import setup_logging as _setup_logging from ._legacy_response import HttpxBinaryResponseContent as HttpxBinaryResponseContent +from .types.websocket_reconnection import ReconnectingEvent, ReconnectingOverrides __all__ = [ "types", @@ -84,6 +87,10 @@ "DefaultHttpxClient", "DefaultAsyncHttpxClient", "DefaultAioHttpClient", + "ReconnectingEvent", + "ReconnectingOverrides", + "WebSocketQueueFullError", + "WebSocketConnectionClosedError", ] if not _t.TYPE_CHECKING: diff --git a/src/openai/_event_handler.py b/src/openai/_event_handler.py new file mode 100644 index 0000000000..d9a3a59d71 --- /dev/null +++ b/src/openai/_event_handler.py @@ -0,0 +1,85 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import threading +from typing import Any, Callable + +EventHandler = Callable[..., Any] + + +class EventHandlerRegistry: + """Thread-safe (optional) registry of event handlers.""" + + def __init__(self, *, use_lock: bool = False) -> None: + self._handlers: dict[str, list[EventHandler]] = {} + self._once_ids: set[int] = set() + self._lock: threading.Lock | None = threading.Lock() if use_lock else None + + def _acquire(self) -> None: + if self._lock is not None: + self._lock.acquire() + + def _release(self) -> None: + if self._lock is not None: + self._lock.release() + + def add(self, event_type: str, handler: EventHandler, *, once: bool = False) -> None: + self._acquire() + try: + handlers = self._handlers.setdefault(event_type, []) + handlers.append(handler) + if once: + self._once_ids.add(id(handler)) + finally: + self._release() + + def remove(self, event_type: str, handler: EventHandler) -> None: + self._acquire() + try: + handlers = self._handlers.get(event_type) + if handlers is not None: + try: + handlers.remove(handler) + except ValueError: + pass + self._once_ids.discard(id(handler)) + finally: + self._release() + + def get_handlers(self, event_type: str) -> list[EventHandler]: + """Return a snapshot of handlers for the given event type, removing once-handlers.""" + self._acquire() + try: + handlers = self._handlers.get(event_type) + if not handlers: + return [] + result = list(handlers) + to_remove = [h for h in result if id(h) in self._once_ids] + for h in to_remove: + handlers.remove(h) + self._once_ids.discard(id(h)) + return result + finally: + self._release() + + def has_handlers(self, event_type: str) -> bool: + self._acquire() + try: + handlers = self._handlers.get(event_type) + return bool(handlers) + finally: + self._release() + + def merge_into(self, target: EventHandlerRegistry) -> None: + """Move all handlers from this registry into *target*, then clear self.""" + self._acquire() + try: + for event_type, handlers in self._handlers.items(): + for handler in handlers: + once = id(handler) in self._once_ids + target.add(event_type, handler, once=once) + self._handlers.clear() + self._once_ids.clear() + finally: + self._release() diff --git a/src/openai/_exceptions.py b/src/openai/_exceptions.py index a37ed8ca82..86f44b0e15 100644 --- a/src/openai/_exceptions.py +++ b/src/openai/_exceptions.py @@ -28,6 +28,8 @@ "ContentFilterFinishReasonError", "InvalidWebhookSignatureError", "SubjectTokenProviderError", + "WebSocketConnectionClosedError", + "WebSocketQueueFullError", ] @@ -187,3 +189,19 @@ def __init__(self) -> None: class InvalidWebhookSignatureError(ValueError): """Raised when a webhook signature is invalid, meaning the computed signature does not match the expected signature.""" + + +class WebSocketConnectionClosedError(OpenAIError): + """Raised when a WebSocket connection closes with unsent messages.""" + + unsent_messages: list[str] + + def __init__(self, message: str, *, unsent_messages: list[str]) -> None: + super().__init__(message) + self.unsent_messages = unsent_messages + + +class WebSocketQueueFullError(OpenAIError): + """Raised when the outgoing WebSocket message queue exceeds its byte-size limit.""" + + pass diff --git a/src/openai/_send_queue.py b/src/openai/_send_queue.py new file mode 100644 index 0000000000..b35d0fbcba --- /dev/null +++ b/src/openai/_send_queue.py @@ -0,0 +1,90 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import typing +import threading + +from ._exceptions import WebSocketQueueFullError + + +class SendQueue: + """Bounded byte-size queue for outgoing WebSocket messages. + + Messages are stored as pre-serialized strings. The queue enforces a + maximum byte budget so that unbounded buffering cannot occur during + reconnection windows. + """ + + def __init__(self, max_bytes: int = 1_048_576) -> None: + self._queue: list[tuple[str, int]] = [] # (data, byte_length) + self._bytes: int = 0 + self._max_bytes = max_bytes + self._lock = threading.Lock() + + def enqueue(self, data: str) -> None: + """Append *data* to the queue. + + Raises :class:`WebSocketQueueFullError` if the message would + exceed the byte-size limit. + """ + byte_length = len(data.encode("utf-8")) + with self._lock: + if self._bytes + byte_length > self._max_bytes: + raise WebSocketQueueFullError("send queue is full, message discarded") + self._queue.append((data, byte_length)) + self._bytes += byte_length + + def flush_sync(self, send: typing.Callable[[str], object]) -> None: + """Send every queued message via *send*. + + If *send* raises, the failing message and all subsequent messages + are re-queued and the error is re-raised. + """ + with self._lock: + pending = list(self._queue) + self._queue.clear() + self._bytes = 0 + + for i, (data, _byte_length) in enumerate(pending): + try: + send(data) + except Exception: + with self._lock: + remaining = pending[i:] + self._queue = remaining + self._queue + self._bytes = sum(bl for _, bl in self._queue) + raise + + async def flush_async(self, send: typing.Callable[[str], typing.Awaitable[object]]) -> None: + """Async variant of :meth:`flush_sync`.""" + with self._lock: + pending = list(self._queue) + self._queue.clear() + self._bytes = 0 + + for i, (data, _byte_length) in enumerate(pending): + try: + await send(data) + except Exception: + with self._lock: + remaining = pending[i:] + self._queue = remaining + self._queue + self._bytes = sum(bl for _, bl in self._queue) + raise + + def drain(self) -> list[str]: + """Remove and return all queued messages.""" + with self._lock: + items = [data for data, _ in self._queue] + self._queue.clear() + self._bytes = 0 + return items + + def __len__(self) -> int: + with self._lock: + return len(self._queue) + + def __bool__(self) -> bool: + with self._lock: + return len(self._queue) > 0 diff --git a/src/openai/_utils/_utils.py b/src/openai/_utils/_utils.py index 90494748cc..b1e8e0d041 100644 --- a/src/openai/_utils/_utils.py +++ b/src/openai/_utils/_utils.py @@ -90,8 +90,9 @@ def _extract_items( index += 1 if is_dict(obj): try: - # We are at the last entry in the path so we must remove the field - if (len(path)) == index: + # Remove the field if there are no more dict keys in the path, + # only "" traversal markers or end. + if all(p == "" for p in path[index:]): item = obj.pop(key) else: item = obj[key] diff --git a/src/openai/_version.py b/src/openai/_version.py index a435bdb765..a98695ba0e 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__ = "2.31.0" # x-release-please-version +__version__ = "2.32.0" # x-release-please-version diff --git a/src/openai/resources/realtime/realtime.py b/src/openai/resources/realtime/realtime.py index 82c9815b03..e4c5bd8163 100644 --- a/src/openai/resources/realtime/realtime.py +++ b/src/openai/resources/realtime/realtime.py @@ -3,9 +3,11 @@ from __future__ import annotations import json +import time +import random import logging from types import TracebackType -from typing import TYPE_CHECKING, Any, Iterator, cast +from typing import TYPE_CHECKING, Any, Union, Callable, Iterator, Awaitable, cast from typing_extensions import AsyncIterator import httpx @@ -30,7 +32,8 @@ from ..._compat import cached_property from ..._models import construct_type_unchecked from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._exceptions import OpenAIError +from ..._exceptions import OpenAIError, WebSocketConnectionClosedError +from ..._send_queue import SendQueue from ..._base_client import _merge_mappings from .client_secrets import ( ClientSecrets, @@ -40,8 +43,11 @@ ClientSecretsWithStreamingResponse, AsyncClientSecretsWithStreamingResponse, ) +from ..._event_handler import EventHandlerRegistry from ...types.realtime import session_update_event_param +from ...types.websocket_reconnection import ReconnectingEvent, ReconnectingOverrides, is_recoverable_close from ...types.websocket_connection_options import WebSocketConnectionOptions +from ...types.realtime.realtime_error_event import RealtimeErrorEvent from ...types.realtime.realtime_client_event import RealtimeClientEvent from ...types.realtime.realtime_server_event import RealtimeServerEvent from ...types.realtime.conversation_item_param import ConversationItemParam @@ -97,6 +103,11 @@ def connect( extra_query: Query = {}, extra_headers: Headers = {}, websocket_connection_options: WebSocketConnectionOptions = {}, + on_reconnecting: Callable[[ReconnectingEvent], ReconnectingOverrides | None] | None = None, + max_retries: int = 5, + initial_delay: float = 0.5, + max_delay: float = 8.0, + max_queue_size: int = 1_048_576, ) -> RealtimeConnectionManager: """ The Realtime API enables you to build low-latency, multi-modal conversational experiences. It currently supports text and audio as both input and output, as well as function calling. @@ -114,6 +125,11 @@ def connect( extra_query=extra_query, extra_headers=extra_headers, websocket_connection_options=websocket_connection_options, + on_reconnecting=on_reconnecting, + max_retries=max_retries, + initial_delay=initial_delay, + max_delay=max_delay, + max_queue_size=max_queue_size, call_id=call_id, model=model, ) @@ -157,6 +173,11 @@ def connect( extra_query: Query = {}, extra_headers: Headers = {}, websocket_connection_options: WebSocketConnectionOptions = {}, + on_reconnecting: Callable[[ReconnectingEvent], ReconnectingOverrides | None] | None = None, + max_retries: int = 5, + initial_delay: float = 0.5, + max_delay: float = 8.0, + max_queue_size: int = 1_048_576, ) -> AsyncRealtimeConnectionManager: """ The Realtime API enables you to build low-latency, multi-modal conversational experiences. It currently supports text and audio as both input and output, as well as function calling. @@ -174,6 +195,11 @@ def connect( extra_query=extra_query, extra_headers=extra_headers, websocket_connection_options=websocket_connection_options, + on_reconnecting=on_reconnecting, + max_retries=max_retries, + initial_delay=initial_delay, + max_delay=max_delay, + max_queue_size=max_queue_size, call_id=call_id, model=model, ) @@ -242,8 +268,31 @@ class AsyncRealtimeConnection: _connection: AsyncWebSocketConnection - def __init__(self, connection: AsyncWebSocketConnection) -> None: + def __init__( + self, + connection: AsyncWebSocketConnection, + *, + make_ws: Callable[[Query, Headers], Awaitable[AsyncWebSocketConnection]] | None = None, + on_reconnecting: Callable[[ReconnectingEvent], ReconnectingOverrides | None] | None = None, + max_retries: int = 5, + initial_delay: float = 0.5, + max_delay: float = 8.0, + extra_query: Query = {}, + extra_headers: Headers = {}, + send_queue: SendQueue | None = None, + ) -> None: self._connection = connection + self._make_ws = make_ws + self._on_reconnecting = on_reconnecting + self._max_retries = max_retries + self._initial_delay = initial_delay + self._max_delay = max_delay + self._extra_query = extra_query + self._extra_headers = extra_headers + self._intentionally_closed = False + self._is_reconnecting = False + self._send_queue = send_queue or SendQueue() + self._event_handler_registry = EventHandlerRegistry(use_lock=False) self.session = AsyncRealtimeSessionResource(self) self.response = AsyncRealtimeResponseResource(self) @@ -256,13 +305,22 @@ async def __aiter__(self) -> AsyncIterator[RealtimeServerEvent]: An infinite-iterator that will continue to yield events until the connection is closed. """ - from websockets.exceptions import ConnectionClosedOK + from websockets.exceptions import ConnectionClosedOK, ConnectionClosedError - try: - while True: + while True: + try: yield await self.recv() - except ConnectionClosedOK: - return + except ConnectionClosedOK: + return + except ConnectionClosedError as exc: + if not await self._reconnect(exc): + unsent = self._send_queue.drain() + if unsent: + raise WebSocketConnectionClosedError( + "WebSocket connection closed with unsent messages", + unsent_messages=unsent, + ) from exc + raise async def recv(self) -> RealtimeServerEvent: """ @@ -290,12 +348,24 @@ async def send(self, event: RealtimeClientEvent | RealtimeClientEventParam) -> N if isinstance(event, BaseModel) else json.dumps(await async_maybe_transform(event, RealtimeClientEventParam)) ) - await self._connection.send(data) + if self._is_reconnecting: + self._send_queue.enqueue(data) + return + try: + await self._connection.send(data) + except Exception: + self._send_queue.enqueue(data) + raise async def send_raw(self, data: bytes | str) -> None: + if self._is_reconnecting: + raw = data if isinstance(data, str) else data.decode("utf-8") + self._send_queue.enqueue(raw) + return await self._connection.send(data) async def close(self, *, code: int = 1000, reason: str = "") -> None: + self._intentionally_closed = True await self._connection.close(code=code, reason=reason) def parse_event(self, data: str | bytes) -> RealtimeServerEvent: @@ -308,6 +378,173 @@ def parse_event(self, data: str | bytes) -> RealtimeServerEvent: RealtimeServerEvent, construct_type_unchecked(value=json.loads(data), type_=cast(Any, RealtimeServerEvent)) ) + async def _reconnect(self, exc: Exception) -> bool: + """Attempt to reconnect after a connection failure. + + Returns ``True`` if a new connection was established, ``False`` if the + caller should re-raise the original exception. + """ + import asyncio + + if self._on_reconnecting is None or self._make_ws is None: + return False + + from websockets.exceptions import ConnectionClosedError + + close_code = 1006 + if isinstance(exc, ConnectionClosedError) and exc.rcvd is not None: + close_code = exc.rcvd.code + + if not is_recoverable_close(close_code): + return False + + self._is_reconnecting = True + + for attempt in range(1, self._max_retries + 1): + base_delay = min(self._initial_delay * (2 ** (attempt - 1)), self._max_delay) + jitter = 0.75 + random.random() * 0.25 + delay = base_delay * jitter + + event = ReconnectingEvent( + attempt=attempt, + max_attempts=self._max_retries, + delay=delay, + close_code=close_code, + extra_query=self._extra_query, + extra_headers=self._extra_headers, + ) + + try: + result = self._on_reconnecting(event) + except Exception: + self._is_reconnecting = False + return False + + if result is not None and result.get("abort"): + self._is_reconnecting = False + return False + + if result is not None: + if "extra_query" in result: + self._extra_query = result["extra_query"] + if "extra_headers" in result: + self._extra_headers = result["extra_headers"] + + log.info( + "Reconnecting to WebSocket API (attempt %d/%d) after %.1fs delay", + attempt, + self._max_retries, + delay, + ) + await asyncio.sleep(delay) + + if self._intentionally_closed: + self._is_reconnecting = False + return False + + try: + self._connection = await self._make_ws(self._extra_query, self._extra_headers) + log.info("Reconnected to WebSocket API") + self._is_reconnecting = False + await self._flush_send_queue() + return True + except Exception: + pass + + self._is_reconnecting = False + return False + + async def _flush_send_queue(self) -> None: + """Send all queued messages over the current connection.""" + + async def _send(data: str) -> None: + await self._connection.send(data) + + try: + await self._send_queue.flush_async(_send) + except Exception: + log.warning("Failed to flush send queue after reconnect", exc_info=True) + + def on( + self, event_type: str, handler: Callable[..., Any] | None = None + ) -> Union[AsyncRealtimeConnection, Callable[[Callable[..., Any]], Callable[..., Any]]]: + """Adds the handler to the end of the handlers list for the given event type. + + No checks are made to see if the handler has already been added. Multiple calls + passing the same combination of event type and handler will result in the handler + being added, and called, multiple times. + + Can be used as a method (returns ``self`` for chaining):: + + connection.on("conversation.created", my_handler) + + Or as a decorator:: + + @connection.on("conversation.created") + async def my_handler(event): ... + """ + if handler is not None: + self._event_handler_registry.add(event_type, handler) + return self + + def decorator(fn: Callable[..., Any]) -> Callable[..., Any]: + self._event_handler_registry.add(event_type, fn) + return fn + + return decorator + + def off(self, event_type: str, handler: Callable[..., Any]) -> AsyncRealtimeConnection: + """Remove a previously registered event handler.""" + self._event_handler_registry.remove(event_type, handler) + return self + + def once( + self, event_type: str, handler: Callable[..., Any] | None = None + ) -> Union[AsyncRealtimeConnection, Callable[[Callable[..., Any]], Callable[..., Any]]]: + """Register a one-time event handler. + + Automatically removed after first invocation. + """ + if handler is not None: + self._event_handler_registry.add(event_type, handler, once=True) + return self + + def decorator(fn: Callable[..., Any]) -> Callable[..., Any]: + self._event_handler_registry.add(event_type, fn, once=True) + return fn + + return decorator + + async def dispatch_events(self) -> None: + """Run the event loop, dispatching received events to registered handlers. + + Blocks until the connection is closed. This is the push-based + alternative to iterating with ``async for event in connection``. + + If an ``"error"`` event arrives and no handler is registered for + ``"error"`` or ``"event"``, an ``OpenAIError`` is raised. + """ + import asyncio + + async for event in self: + event_type = event.type + specific = self._event_handler_registry.get_handlers(event_type) + generic = self._event_handler_registry.get_handlers("event") + + if event_type == "error" and not specific and not generic: + if isinstance(event, RealtimeErrorEvent): + raise OpenAIError(f"WebSocket error: {event}") + + for handler in specific: + result = handler(event) + if asyncio.iscoroutine(result): + await result + + for handler in generic: + result = handler(event) + if asyncio.iscoroutine(result): + await result + class AsyncRealtimeConnectionManager: """ @@ -338,6 +575,11 @@ def __init__( extra_query: Query, extra_headers: Headers, websocket_connection_options: WebSocketConnectionOptions, + on_reconnecting: Callable[[ReconnectingEvent], ReconnectingOverrides | None] | None = None, + max_retries: int = 5, + initial_delay: float = 0.5, + max_delay: float = 8.0, + max_queue_size: int = 1_048_576, ) -> None: self.__client = client self.__call_id = call_id @@ -346,10 +588,66 @@ def __init__( self.__extra_query = extra_query self.__extra_headers = extra_headers self.__websocket_connection_options = websocket_connection_options + self.__on_reconnecting = on_reconnecting + self.__max_retries = max_retries + self.__initial_delay = initial_delay + self.__max_delay = max_delay + self.__send_queue = SendQueue(max_bytes=max_queue_size) + self.__event_handler_registry = EventHandlerRegistry(use_lock=False) + + def send(self, event: RealtimeClientEvent | RealtimeClientEventParam) -> None: + """Queue a message to be sent when the connection is established. + + This can be called before entering the context manager. Queued messages + are automatically sent once the WebSocket connection opens. + """ + data = ( + event.to_json(use_api_names=True, exclude_defaults=True, exclude_unset=True) + if isinstance(event, BaseModel) + else json.dumps(event) + ) + self.__send_queue.enqueue(data) + + def on( + self, event_type: str, handler: Callable[..., Any] | None = None + ) -> Union[AsyncRealtimeConnectionManager, Callable[[Callable[..., Any]], Callable[..., Any]]]: + """Register an event handler before the connection is established. + + Handlers are transferred to the connection on enter. Supports the + same method and decorator forms as ``AsyncRealtimeConnection.on``. + """ + if handler is not None: + self.__event_handler_registry.add(event_type, handler) + return self + + def decorator(fn: Callable[..., Any]) -> Callable[..., Any]: + self.__event_handler_registry.add(event_type, fn) + return fn + + return decorator + + def off(self, event_type: str, handler: Callable[..., Any]) -> AsyncRealtimeConnectionManager: + """Remove a previously registered event handler.""" + self.__event_handler_registry.remove(event_type, handler) + return self + + def once( + self, event_type: str, handler: Callable[..., Any] | None = None + ) -> Union[AsyncRealtimeConnectionManager, Callable[[Callable[..., Any]], Callable[..., Any]]]: + """Register a one-time event handler before the connection is established.""" + if handler is not None: + self.__event_handler_registry.add(event_type, handler, once=True) + return self + + def decorator(fn: Callable[..., Any]) -> Callable[..., Any]: + self.__event_handler_registry.add(event_type, fn, once=True) + return fn + + return decorator async def __aenter__(self) -> AsyncRealtimeConnection: """ - 👋 If your application doesn't work well with the context manager approach then you + If your application doesn't work well with the context manager approach then you can call this method directly to initiate a connection. **Warning**: You must remember to close the connection with `.close()`. @@ -360,15 +658,35 @@ async def __aenter__(self) -> AsyncRealtimeConnection: await connection.close() ``` """ + ws = await self._connect_ws(self.__extra_query, self.__extra_headers) + + self.__connection = AsyncRealtimeConnection( + ws, + make_ws=self._connect_ws if self.__on_reconnecting is not None else None, + on_reconnecting=self.__on_reconnecting, + max_retries=self.__max_retries, + initial_delay=self.__initial_delay, + max_delay=self.__max_delay, + extra_query=self.__extra_query, + extra_headers=self.__extra_headers, + send_queue=self.__send_queue, + ) + + self.__event_handler_registry.merge_into(self.__connection._event_handler_registry) + await self.__connection._flush_send_queue() + + return self.__connection + + enter = __aenter__ + + async def _connect_ws(self, extra_query: Query, extra_headers: Headers) -> AsyncWebSocketConnection: try: from websockets.asyncio.client import connect except ImportError as exc: raise OpenAIError("You need to install `openai[realtime]` to use this method") from exc - extra_query = self.__extra_query await self.__client._refresh_api_key() auth_headers = self.__client.auth_headers - extra_query = self.__extra_query if self.__call_id is not omit: extra_query = {**extra_query, "call_id": self.__call_id} if is_async_azure_client(self.__client): @@ -389,24 +707,18 @@ async def __aenter__(self) -> AsyncRealtimeConnection: if self.__websocket_connection_options: log.debug("Connection options: %s", self.__websocket_connection_options) - self.__connection = AsyncRealtimeConnection( - await connect( - str(url), - user_agent_header=self.__client.user_agent, - additional_headers=_merge_mappings( - { - **auth_headers, - }, - self.__extra_headers, - ), - **self.__websocket_connection_options, - ) + return await connect( + str(url), + user_agent_header=self.__client.user_agent, + additional_headers=_merge_mappings( + { + **auth_headers, + }, + extra_headers, + ), + **self.__websocket_connection_options, ) - return self.__connection - - enter = __aenter__ - def _prepare_url(self) -> httpx.URL: if self.__client.websocket_base_url is not None: base_url = httpx.URL(self.__client.websocket_base_url) @@ -436,8 +748,31 @@ class RealtimeConnection: _connection: WebSocketConnection - def __init__(self, connection: WebSocketConnection) -> None: + def __init__( + self, + connection: WebSocketConnection, + *, + make_ws: Callable[[Query, Headers], WebSocketConnection] | None = None, + on_reconnecting: Callable[[ReconnectingEvent], ReconnectingOverrides | None] | None = None, + max_retries: int = 5, + initial_delay: float = 0.5, + max_delay: float = 8.0, + extra_query: Query = {}, + extra_headers: Headers = {}, + send_queue: SendQueue | None = None, + ) -> None: self._connection = connection + self._make_ws = make_ws + self._on_reconnecting = on_reconnecting + self._max_retries = max_retries + self._initial_delay = initial_delay + self._max_delay = max_delay + self._extra_query = extra_query + self._extra_headers = extra_headers + self._intentionally_closed = False + self._is_reconnecting = False + self._send_queue = send_queue or SendQueue() + self._event_handler_registry = EventHandlerRegistry(use_lock=True) self.session = RealtimeSessionResource(self) self.response = RealtimeResponseResource(self) @@ -450,13 +785,22 @@ def __iter__(self) -> Iterator[RealtimeServerEvent]: An infinite-iterator that will continue to yield events until the connection is closed. """ - from websockets.exceptions import ConnectionClosedOK + from websockets.exceptions import ConnectionClosedOK, ConnectionClosedError - try: - while True: + while True: + try: yield self.recv() - except ConnectionClosedOK: - return + except ConnectionClosedOK: + return + except ConnectionClosedError as exc: + if not self._reconnect(exc): + unsent = self._send_queue.drain() + if unsent: + raise WebSocketConnectionClosedError( + "WebSocket connection closed with unsent messages", + unsent_messages=unsent, + ) from exc + raise def recv(self) -> RealtimeServerEvent: """ @@ -484,12 +828,24 @@ def send(self, event: RealtimeClientEvent | RealtimeClientEventParam) -> None: if isinstance(event, BaseModel) else json.dumps(maybe_transform(event, RealtimeClientEventParam)) ) - self._connection.send(data) + if self._is_reconnecting: + self._send_queue.enqueue(data) + return + try: + self._connection.send(data) + except Exception: + self._send_queue.enqueue(data) + raise def send_raw(self, data: bytes | str) -> None: + if self._is_reconnecting: + raw = data if isinstance(data, str) else data.decode("utf-8") + self._send_queue.enqueue(raw) + return self._connection.send(data) def close(self, *, code: int = 1000, reason: str = "") -> None: + self._intentionally_closed = True self._connection.close(code=code, reason=reason) def parse_event(self, data: str | bytes) -> RealtimeServerEvent: @@ -502,6 +858,161 @@ def parse_event(self, data: str | bytes) -> RealtimeServerEvent: RealtimeServerEvent, construct_type_unchecked(value=json.loads(data), type_=cast(Any, RealtimeServerEvent)) ) + def _reconnect(self, exc: Exception) -> bool: + """Attempt to reconnect after a connection failure. + + Returns ``True`` if a new connection was established, ``False`` if the + caller should re-raise the original exception. + """ + if self._on_reconnecting is None or self._make_ws is None: + return False + + from websockets.exceptions import ConnectionClosedError + + close_code = 1006 + if isinstance(exc, ConnectionClosedError) and exc.rcvd is not None: + close_code = exc.rcvd.code + + if not is_recoverable_close(close_code): + return False + + self._is_reconnecting = True + + for attempt in range(1, self._max_retries + 1): + base_delay = min(self._initial_delay * (2 ** (attempt - 1)), self._max_delay) + jitter = 0.75 + random.random() * 0.25 + delay = base_delay * jitter + + event = ReconnectingEvent( + attempt=attempt, + max_attempts=self._max_retries, + delay=delay, + close_code=close_code, + extra_query=self._extra_query, + extra_headers=self._extra_headers, + ) + + try: + result = self._on_reconnecting(event) + except Exception: + self._is_reconnecting = False + return False + + if result is not None and result.get("abort"): + self._is_reconnecting = False + return False + + if result is not None: + if "extra_query" in result: + self._extra_query = result["extra_query"] + if "extra_headers" in result: + self._extra_headers = result["extra_headers"] + + log.info( + "Reconnecting to WebSocket API (attempt %d/%d) after %.1fs delay", + attempt, + self._max_retries, + delay, + ) + time.sleep(delay) + + if self._intentionally_closed: + self._is_reconnecting = False + return False + + try: + self._connection = self._make_ws(self._extra_query, self._extra_headers) + log.info("Reconnected to WebSocket API") + self._is_reconnecting = False + self._flush_send_queue() + return True + except Exception: + pass + + self._is_reconnecting = False + return False + + def _flush_send_queue(self) -> None: + """Send all queued messages over the current connection.""" + try: + self._send_queue.flush_sync(lambda data: self._connection.send(data)) + except Exception: + log.warning("Failed to flush send queue after reconnect", exc_info=True) + + def on( + self, event_type: str, handler: Callable[..., Any] | None = None + ) -> Union[RealtimeConnection, Callable[[Callable[..., Any]], Callable[..., Any]]]: + """Adds the handler to the end of the handlers list for the given event type. + + No checks are made to see if the handler has already been added. Multiple calls + passing the same combination of event type and handler will result in the handler + being added, and called, multiple times. + + Can be used as a method (returns ``self`` for chaining):: + + connection.on("conversation.created", my_handler) + + Or as a decorator:: + + @connection.on("conversation.created") + def my_handler(event): ... + """ + if handler is not None: + self._event_handler_registry.add(event_type, handler) + return self + + def decorator(fn: Callable[..., Any]) -> Callable[..., Any]: + self._event_handler_registry.add(event_type, fn) + return fn + + return decorator + + def off(self, event_type: str, handler: Callable[..., Any]) -> RealtimeConnection: + """Remove a previously registered event handler.""" + self._event_handler_registry.remove(event_type, handler) + return self + + def once( + self, event_type: str, handler: Callable[..., Any] | None = None + ) -> Union[RealtimeConnection, Callable[[Callable[..., Any]], Callable[..., Any]]]: + """Register a one-time event handler. + + Automatically removed after first invocation. + """ + if handler is not None: + self._event_handler_registry.add(event_type, handler, once=True) + return self + + def decorator(fn: Callable[..., Any]) -> Callable[..., Any]: + self._event_handler_registry.add(event_type, fn, once=True) + return fn + + return decorator + + def dispatch_events(self) -> None: + """Run the event loop, dispatching received events to registered handlers. + + Blocks the current thread until the connection is closed. This is the push-based + alternative to iterating with ``for event in connection``. + + If an ``"error"`` event arrives and no handler is registered for + ``"error"`` or ``"event"``, an ``OpenAIError`` is raised. + """ + for event in self: + event_type = event.type + specific = self._event_handler_registry.get_handlers(event_type) + generic = self._event_handler_registry.get_handlers("event") + + if event_type == "error" and not specific and not generic: + if isinstance(event, RealtimeErrorEvent): + raise OpenAIError(f"WebSocket error: {event}") + + for handler in specific: + handler(event) + + for handler in generic: + handler(event) + class RealtimeConnectionManager: """ @@ -532,6 +1043,11 @@ def __init__( extra_query: Query, extra_headers: Headers, websocket_connection_options: WebSocketConnectionOptions, + on_reconnecting: Callable[[ReconnectingEvent], ReconnectingOverrides | None] | None = None, + max_retries: int = 5, + initial_delay: float = 0.5, + max_delay: float = 8.0, + max_queue_size: int = 1_048_576, ) -> None: self.__client = client self.__call_id = call_id @@ -540,10 +1056,66 @@ def __init__( self.__extra_query = extra_query self.__extra_headers = extra_headers self.__websocket_connection_options = websocket_connection_options + self.__on_reconnecting = on_reconnecting + self.__max_retries = max_retries + self.__initial_delay = initial_delay + self.__max_delay = max_delay + self.__send_queue = SendQueue(max_bytes=max_queue_size) + self.__event_handler_registry = EventHandlerRegistry(use_lock=True) + + def send(self, event: RealtimeClientEvent | RealtimeClientEventParam) -> None: + """Queue a message to be sent when the connection is established. + + This can be called before entering the context manager. Queued messages + are automatically sent once the WebSocket connection opens. + """ + data = ( + event.to_json(use_api_names=True, exclude_defaults=True, exclude_unset=True) + if isinstance(event, BaseModel) + else json.dumps(event) + ) + self.__send_queue.enqueue(data) + + def on( + self, event_type: str, handler: Callable[..., Any] | None = None + ) -> Union[RealtimeConnectionManager, Callable[[Callable[..., Any]], Callable[..., Any]]]: + """Register an event handler before the connection is established. + + Handlers are transferred to the connection on enter. Supports the + same method and decorator forms as ``RealtimeConnection.on``. + """ + if handler is not None: + self.__event_handler_registry.add(event_type, handler) + return self + + def decorator(fn: Callable[..., Any]) -> Callable[..., Any]: + self.__event_handler_registry.add(event_type, fn) + return fn + + return decorator + + def off(self, event_type: str, handler: Callable[..., Any]) -> RealtimeConnectionManager: + """Remove a previously registered event handler.""" + self.__event_handler_registry.remove(event_type, handler) + return self + + def once( + self, event_type: str, handler: Callable[..., Any] | None = None + ) -> Union[RealtimeConnectionManager, Callable[[Callable[..., Any]], Callable[..., Any]]]: + """Register a one-time event handler before the connection is established.""" + if handler is not None: + self.__event_handler_registry.add(event_type, handler, once=True) + return self + + def decorator(fn: Callable[..., Any]) -> Callable[..., Any]: + self.__event_handler_registry.add(event_type, fn, once=True) + return fn + + return decorator def __enter__(self) -> RealtimeConnection: """ - 👋 If your application doesn't work well with the context manager approach then you + If your application doesn't work well with the context manager approach then you can call this method directly to initiate a connection. **Warning**: You must remember to close the connection with `.close()`. @@ -554,15 +1126,35 @@ def __enter__(self) -> RealtimeConnection: connection.close() ``` """ + ws = self._connect_ws(self.__extra_query, self.__extra_headers) + + self.__connection = RealtimeConnection( + ws, + make_ws=self._connect_ws if self.__on_reconnecting is not None else None, + on_reconnecting=self.__on_reconnecting, + max_retries=self.__max_retries, + initial_delay=self.__initial_delay, + max_delay=self.__max_delay, + extra_query=self.__extra_query, + extra_headers=self.__extra_headers, + send_queue=self.__send_queue, + ) + + self.__event_handler_registry.merge_into(self.__connection._event_handler_registry) + self.__connection._flush_send_queue() + + return self.__connection + + enter = __enter__ + + def _connect_ws(self, extra_query: Query, extra_headers: Headers) -> WebSocketConnection: try: from websockets.sync.client import connect except ImportError as exc: raise OpenAIError("You need to install `openai[realtime]` to use this method") from exc - extra_query = self.__extra_query self.__client._refresh_api_key() auth_headers = self.__client.auth_headers - extra_query = self.__extra_query if self.__call_id is not omit: extra_query = {**extra_query, "call_id": self.__call_id} if is_azure_client(self.__client): @@ -583,24 +1175,18 @@ def __enter__(self) -> RealtimeConnection: if self.__websocket_connection_options: log.debug("Connection options: %s", self.__websocket_connection_options) - self.__connection = RealtimeConnection( - connect( - str(url), - user_agent_header=self.__client.user_agent, - additional_headers=_merge_mappings( - { - **auth_headers, - }, - self.__extra_headers, - ), - **self.__websocket_connection_options, - ) + return connect( + str(url), + user_agent_header=self.__client.user_agent, + additional_headers=_merge_mappings( + { + **auth_headers, + }, + extra_headers, + ), + **self.__websocket_connection_options, ) - return self.__connection - - enter = __enter__ - def _prepare_url(self) -> httpx.URL: if self.__client.websocket_base_url is not None: base_url = httpx.URL(self.__client.websocket_base_url) diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 360c5afa1a..ab5f7688a5 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -3,10 +3,25 @@ from __future__ import annotations import json +import time +import random import logging from copy import copy from types import TracebackType -from typing import TYPE_CHECKING, Any, List, Type, Union, Iterable, Iterator, Optional, AsyncIterator, cast +from typing import ( + TYPE_CHECKING, + Any, + List, + Type, + Union, + Callable, + Iterable, + Iterator, + Optional, + Awaitable, + AsyncIterator, + cast, +) from functools import partial from typing_extensions import Literal, overload @@ -38,8 +53,10 @@ InputTokensWithStreamingResponse, AsyncInputTokensWithStreamingResponse, ) -from ..._exceptions import OpenAIError +from ..._exceptions import OpenAIError, WebSocketConnectionClosedError +from ..._send_queue import SendQueue from ..._base_client import _merge_mappings, make_request_options +from ..._event_handler import EventHandlerRegistry from ...types.responses import ( response_create_params, response_compact_params, @@ -54,6 +71,7 @@ from ...types.responses.response import Response from ...types.responses.tool_param import ToolParam, ParseableToolParam from ...types.shared_params.metadata import Metadata +from ...types.websocket_reconnection import ReconnectingEvent, ReconnectingOverrides, is_recoverable_close from ...types.shared_params.reasoning import Reasoning from ...types.responses.parsed_response import ParsedResponse from ...lib.streaming.responses._responses import ResponseStreamManager, AsyncResponseStreamManager @@ -61,6 +79,7 @@ from ...types.websocket_connection_options import WebSocketConnectionOptions from ...types.responses.response_includable import ResponseIncludable from ...types.shared_params.responses_model import ResponsesModel +from ...types.responses.response_error_event import ResponseErrorEvent from ...types.responses.response_input_param import ResponseInputParam from ...types.responses.response_prompt_param import ResponsePromptParam from ...types.responses.response_stream_event import ResponseStreamEvent @@ -1735,6 +1754,11 @@ def connect( extra_query: Query = {}, extra_headers: Headers = {}, websocket_connection_options: WebSocketConnectionOptions = {}, + on_reconnecting: Callable[[ReconnectingEvent], ReconnectingOverrides | None] | None = None, + max_retries: int = 5, + initial_delay: float = 0.5, + max_delay: float = 8.0, + max_queue_size: int = 1_048_576, ) -> ResponsesConnectionManager: """Connect to a persistent Responses API WebSocket. @@ -1745,6 +1769,11 @@ def connect( extra_query=extra_query, extra_headers=extra_headers, websocket_connection_options=websocket_connection_options, + on_reconnecting=on_reconnecting, + max_retries=max_retries, + initial_delay=initial_delay, + max_delay=max_delay, + max_queue_size=max_queue_size, ) @@ -3406,6 +3435,11 @@ def connect( extra_query: Query = {}, extra_headers: Headers = {}, websocket_connection_options: WebSocketConnectionOptions = {}, + on_reconnecting: Callable[[ReconnectingEvent], ReconnectingOverrides | None] | None = None, + max_retries: int = 5, + initial_delay: float = 0.5, + max_delay: float = 8.0, + max_queue_size: int = 1_048_576, ) -> AsyncResponsesConnectionManager: """Connect to a persistent Responses API WebSocket. @@ -3416,6 +3450,11 @@ def connect( extra_query=extra_query, extra_headers=extra_headers, websocket_connection_options=websocket_connection_options, + on_reconnecting=on_reconnecting, + max_retries=max_retries, + initial_delay=initial_delay, + max_delay=max_delay, + max_queue_size=max_queue_size, ) @@ -3586,8 +3625,31 @@ class AsyncResponsesConnection: _connection: AsyncWebSocketConnection - def __init__(self, connection: AsyncWebSocketConnection) -> None: + def __init__( + self, + connection: AsyncWebSocketConnection, + *, + make_ws: Callable[[Query, Headers], Awaitable[AsyncWebSocketConnection]] | None = None, + on_reconnecting: Callable[[ReconnectingEvent], ReconnectingOverrides | None] | None = None, + max_retries: int = 5, + initial_delay: float = 0.5, + max_delay: float = 8.0, + extra_query: Query = {}, + extra_headers: Headers = {}, + send_queue: SendQueue | None = None, + ) -> None: self._connection = connection + self._make_ws = make_ws + self._on_reconnecting = on_reconnecting + self._max_retries = max_retries + self._initial_delay = initial_delay + self._max_delay = max_delay + self._extra_query = extra_query + self._extra_headers = extra_headers + self._intentionally_closed = False + self._is_reconnecting = False + self._send_queue = send_queue or SendQueue() + self._event_handler_registry = EventHandlerRegistry(use_lock=False) self.response = AsyncResponsesResponseResource(self) @@ -3596,13 +3658,22 @@ async def __aiter__(self) -> AsyncIterator[ResponsesServerEvent]: An infinite-iterator that will continue to yield events until the connection is closed. """ - from websockets.exceptions import ConnectionClosedOK + from websockets.exceptions import ConnectionClosedOK, ConnectionClosedError - try: - while True: + while True: + try: yield await self.recv() - except ConnectionClosedOK: - return + except ConnectionClosedOK: + return + except ConnectionClosedError as exc: + if not await self._reconnect(exc): + unsent = self._send_queue.drain() + if unsent: + raise WebSocketConnectionClosedError( + "WebSocket connection closed with unsent messages", + unsent_messages=unsent, + ) from exc + raise async def recv(self) -> ResponsesServerEvent: """ @@ -3630,12 +3701,24 @@ async def send(self, event: ResponsesClientEvent | ResponsesClientEventParam) -> if isinstance(event, BaseModel) else json.dumps(await async_maybe_transform(event, ResponsesClientEventParam)) ) - await self._connection.send(data) + if self._is_reconnecting: + self._send_queue.enqueue(data) + return + try: + await self._connection.send(data) + except Exception: + self._send_queue.enqueue(data) + raise async def send_raw(self, data: bytes | str) -> None: + if self._is_reconnecting: + raw = data if isinstance(data, str) else data.decode("utf-8") + self._send_queue.enqueue(raw) + return await self._connection.send(data) async def close(self, *, code: int = 1000, reason: str = "") -> None: + self._intentionally_closed = True await self._connection.close(code=code, reason=reason) def parse_event(self, data: str | bytes) -> ResponsesServerEvent: @@ -3649,6 +3732,173 @@ def parse_event(self, data: str | bytes) -> ResponsesServerEvent: construct_type_unchecked(value=json.loads(data), type_=cast(Any, ResponsesServerEvent)), ) + async def _reconnect(self, exc: Exception) -> bool: + """Attempt to reconnect after a connection failure. + + Returns ``True`` if a new connection was established, ``False`` if the + caller should re-raise the original exception. + """ + import asyncio + + if self._on_reconnecting is None or self._make_ws is None: + return False + + from websockets.exceptions import ConnectionClosedError + + close_code = 1006 + if isinstance(exc, ConnectionClosedError) and exc.rcvd is not None: + close_code = exc.rcvd.code + + if not is_recoverable_close(close_code): + return False + + self._is_reconnecting = True + + for attempt in range(1, self._max_retries + 1): + base_delay = min(self._initial_delay * (2 ** (attempt - 1)), self._max_delay) + jitter = 0.75 + random.random() * 0.25 + delay = base_delay * jitter + + event = ReconnectingEvent( + attempt=attempt, + max_attempts=self._max_retries, + delay=delay, + close_code=close_code, + extra_query=self._extra_query, + extra_headers=self._extra_headers, + ) + + try: + result = self._on_reconnecting(event) + except Exception: + self._is_reconnecting = False + return False + + if result is not None and result.get("abort"): + self._is_reconnecting = False + return False + + if result is not None: + if "extra_query" in result: + self._extra_query = result["extra_query"] + if "extra_headers" in result: + self._extra_headers = result["extra_headers"] + + log.info( + "Reconnecting to WebSocket API (attempt %d/%d) after %.1fs delay", + attempt, + self._max_retries, + delay, + ) + await asyncio.sleep(delay) + + if self._intentionally_closed: + self._is_reconnecting = False + return False + + try: + self._connection = await self._make_ws(self._extra_query, self._extra_headers) + log.info("Reconnected to WebSocket API") + self._is_reconnecting = False + await self._flush_send_queue() + return True + except Exception: + pass + + self._is_reconnecting = False + return False + + async def _flush_send_queue(self) -> None: + """Send all queued messages over the current connection.""" + + async def _send(data: str) -> None: + await self._connection.send(data) + + try: + await self._send_queue.flush_async(_send) + except Exception: + log.warning("Failed to flush send queue after reconnect", exc_info=True) + + def on( + self, event_type: str, handler: Callable[..., Any] | None = None + ) -> Union[AsyncResponsesConnection, Callable[[Callable[..., Any]], Callable[..., Any]]]: + """Adds the handler to the end of the handlers list for the given event type. + + No checks are made to see if the handler has already been added. Multiple calls + passing the same combination of event type and handler will result in the handler + being added, and called, multiple times. + + Can be used as a method (returns ``self`` for chaining):: + + connection.on("response.audio.delta", my_handler) + + Or as a decorator:: + + @connection.on("response.audio.delta") + async def my_handler(event): ... + """ + if handler is not None: + self._event_handler_registry.add(event_type, handler) + return self + + def decorator(fn: Callable[..., Any]) -> Callable[..., Any]: + self._event_handler_registry.add(event_type, fn) + return fn + + return decorator + + def off(self, event_type: str, handler: Callable[..., Any]) -> AsyncResponsesConnection: + """Remove a previously registered event handler.""" + self._event_handler_registry.remove(event_type, handler) + return self + + def once( + self, event_type: str, handler: Callable[..., Any] | None = None + ) -> Union[AsyncResponsesConnection, Callable[[Callable[..., Any]], Callable[..., Any]]]: + """Register a one-time event handler. + + Automatically removed after first invocation. + """ + if handler is not None: + self._event_handler_registry.add(event_type, handler, once=True) + return self + + def decorator(fn: Callable[..., Any]) -> Callable[..., Any]: + self._event_handler_registry.add(event_type, fn, once=True) + return fn + + return decorator + + async def dispatch_events(self) -> None: + """Run the event loop, dispatching received events to registered handlers. + + Blocks until the connection is closed. This is the push-based + alternative to iterating with ``async for event in connection``. + + If an ``"error"`` event arrives and no handler is registered for + ``"error"`` or ``"event"``, an ``OpenAIError`` is raised. + """ + import asyncio + + async for event in self: + event_type = event.type + specific = self._event_handler_registry.get_handlers(event_type) + generic = self._event_handler_registry.get_handlers("event") + + if event_type == "error" and not specific and not generic: + if isinstance(event, ResponseErrorEvent): + raise OpenAIError(f"WebSocket error: {event}") + + for handler in specific: + result = handler(event) + if asyncio.iscoroutine(result): + await result + + for handler in generic: + result = handler(event) + if asyncio.iscoroutine(result): + await result + class AsyncResponsesConnectionManager: """ @@ -3677,16 +3927,77 @@ def __init__( extra_query: Query, extra_headers: Headers, websocket_connection_options: WebSocketConnectionOptions, + on_reconnecting: Callable[[ReconnectingEvent], ReconnectingOverrides | None] | None = None, + max_retries: int = 5, + initial_delay: float = 0.5, + max_delay: float = 8.0, + max_queue_size: int = 1_048_576, ) -> None: self.__client = client self.__connection: AsyncResponsesConnection | None = None self.__extra_query = extra_query self.__extra_headers = extra_headers self.__websocket_connection_options = websocket_connection_options + self.__on_reconnecting = on_reconnecting + self.__max_retries = max_retries + self.__initial_delay = initial_delay + self.__max_delay = max_delay + self.__send_queue = SendQueue(max_bytes=max_queue_size) + self.__event_handler_registry = EventHandlerRegistry(use_lock=False) + + def send(self, event: ResponsesClientEvent | ResponsesClientEventParam) -> None: + """Queue a message to be sent when the connection is established. + + This can be called before entering the context manager. Queued messages + are automatically sent once the WebSocket connection opens. + """ + data = ( + event.to_json(use_api_names=True, exclude_defaults=True, exclude_unset=True) + if isinstance(event, BaseModel) + else json.dumps(event) + ) + self.__send_queue.enqueue(data) + + def on( + self, event_type: str, handler: Callable[..., Any] | None = None + ) -> Union[AsyncResponsesConnectionManager, Callable[[Callable[..., Any]], Callable[..., Any]]]: + """Register an event handler before the connection is established. + + Handlers are transferred to the connection on enter. Supports the + same method and decorator forms as ``AsyncResponsesConnection.on``. + """ + if handler is not None: + self.__event_handler_registry.add(event_type, handler) + return self + + def decorator(fn: Callable[..., Any]) -> Callable[..., Any]: + self.__event_handler_registry.add(event_type, fn) + return fn + + return decorator + + def off(self, event_type: str, handler: Callable[..., Any]) -> AsyncResponsesConnectionManager: + """Remove a previously registered event handler.""" + self.__event_handler_registry.remove(event_type, handler) + return self + + def once( + self, event_type: str, handler: Callable[..., Any] | None = None + ) -> Union[AsyncResponsesConnectionManager, Callable[[Callable[..., Any]], Callable[..., Any]]]: + """Register a one-time event handler before the connection is established.""" + if handler is not None: + self.__event_handler_registry.add(event_type, handler, once=True) + return self + + def decorator(fn: Callable[..., Any]) -> Callable[..., Any]: + self.__event_handler_registry.add(event_type, fn, once=True) + return fn + + return decorator async def __aenter__(self) -> AsyncResponsesConnection: """ - 👋 If your application doesn't work well with the context manager approach then you + If your application doesn't work well with the context manager approach then you can call this method directly to initiate a connection. **Warning**: You must remember to close the connection with `.close()`. @@ -3697,6 +4008,28 @@ async def __aenter__(self) -> AsyncResponsesConnection: await connection.close() ``` """ + ws = await self._connect_ws(self.__extra_query, self.__extra_headers) + + self.__connection = AsyncResponsesConnection( + ws, + make_ws=self._connect_ws if self.__on_reconnecting is not None else None, + on_reconnecting=self.__on_reconnecting, + max_retries=self.__max_retries, + initial_delay=self.__initial_delay, + max_delay=self.__max_delay, + extra_query=self.__extra_query, + extra_headers=self.__extra_headers, + send_queue=self.__send_queue, + ) + + self.__event_handler_registry.merge_into(self.__connection._event_handler_registry) + await self.__connection._flush_send_queue() + + return self.__connection + + enter = __aenter__ + + async def _connect_ws(self, extra_query: Query, extra_headers: Headers) -> AsyncWebSocketConnection: try: from websockets.asyncio.client import connect except ImportError as exc: @@ -3705,31 +4038,25 @@ async def __aenter__(self) -> AsyncResponsesConnection: url = self._prepare_url().copy_with( params={ **self.__client.base_url.params, - **self.__extra_query, + **extra_query, }, ) log.debug("Connecting to %s", url) if self.__websocket_connection_options: log.debug("Connection options: %s", self.__websocket_connection_options) - self.__connection = AsyncResponsesConnection( - await connect( - str(url), - user_agent_header=self.__client.user_agent, - additional_headers=_merge_mappings( - { - **self.__client.auth_headers, - }, - self.__extra_headers, - ), - **self.__websocket_connection_options, - ) + return await connect( + str(url), + user_agent_header=self.__client.user_agent, + additional_headers=_merge_mappings( + { + **self.__client.auth_headers, + }, + extra_headers, + ), + **self.__websocket_connection_options, ) - return self.__connection - - enter = __aenter__ - def _prepare_url(self) -> httpx.URL: if self.__client.websocket_base_url is not None: base_url = httpx.URL(self.__client.websocket_base_url) @@ -3755,8 +4082,31 @@ class ResponsesConnection: _connection: WebSocketConnection - def __init__(self, connection: WebSocketConnection) -> None: + def __init__( + self, + connection: WebSocketConnection, + *, + make_ws: Callable[[Query, Headers], WebSocketConnection] | None = None, + on_reconnecting: Callable[[ReconnectingEvent], ReconnectingOverrides | None] | None = None, + max_retries: int = 5, + initial_delay: float = 0.5, + max_delay: float = 8.0, + extra_query: Query = {}, + extra_headers: Headers = {}, + send_queue: SendQueue | None = None, + ) -> None: self._connection = connection + self._make_ws = make_ws + self._on_reconnecting = on_reconnecting + self._max_retries = max_retries + self._initial_delay = initial_delay + self._max_delay = max_delay + self._extra_query = extra_query + self._extra_headers = extra_headers + self._intentionally_closed = False + self._is_reconnecting = False + self._send_queue = send_queue or SendQueue() + self._event_handler_registry = EventHandlerRegistry(use_lock=True) self.response = ResponsesResponseResource(self) @@ -3765,13 +4115,22 @@ def __iter__(self) -> Iterator[ResponsesServerEvent]: An infinite-iterator that will continue to yield events until the connection is closed. """ - from websockets.exceptions import ConnectionClosedOK + from websockets.exceptions import ConnectionClosedOK, ConnectionClosedError - try: - while True: + while True: + try: yield self.recv() - except ConnectionClosedOK: - return + except ConnectionClosedOK: + return + except ConnectionClosedError as exc: + if not self._reconnect(exc): + unsent = self._send_queue.drain() + if unsent: + raise WebSocketConnectionClosedError( + "WebSocket connection closed with unsent messages", + unsent_messages=unsent, + ) from exc + raise def recv(self) -> ResponsesServerEvent: """ @@ -3799,12 +4158,24 @@ def send(self, event: ResponsesClientEvent | ResponsesClientEventParam) -> None: if isinstance(event, BaseModel) else json.dumps(maybe_transform(event, ResponsesClientEventParam)) ) - self._connection.send(data) + if self._is_reconnecting: + self._send_queue.enqueue(data) + return + try: + self._connection.send(data) + except Exception: + self._send_queue.enqueue(data) + raise def send_raw(self, data: bytes | str) -> None: + if self._is_reconnecting: + raw = data if isinstance(data, str) else data.decode("utf-8") + self._send_queue.enqueue(raw) + return self._connection.send(data) def close(self, *, code: int = 1000, reason: str = "") -> None: + self._intentionally_closed = True self._connection.close(code=code, reason=reason) def parse_event(self, data: str | bytes) -> ResponsesServerEvent: @@ -3818,6 +4189,161 @@ def parse_event(self, data: str | bytes) -> ResponsesServerEvent: construct_type_unchecked(value=json.loads(data), type_=cast(Any, ResponsesServerEvent)), ) + def _reconnect(self, exc: Exception) -> bool: + """Attempt to reconnect after a connection failure. + + Returns ``True`` if a new connection was established, ``False`` if the + caller should re-raise the original exception. + """ + if self._on_reconnecting is None or self._make_ws is None: + return False + + from websockets.exceptions import ConnectionClosedError + + close_code = 1006 + if isinstance(exc, ConnectionClosedError) and exc.rcvd is not None: + close_code = exc.rcvd.code + + if not is_recoverable_close(close_code): + return False + + self._is_reconnecting = True + + for attempt in range(1, self._max_retries + 1): + base_delay = min(self._initial_delay * (2 ** (attempt - 1)), self._max_delay) + jitter = 0.75 + random.random() * 0.25 + delay = base_delay * jitter + + event = ReconnectingEvent( + attempt=attempt, + max_attempts=self._max_retries, + delay=delay, + close_code=close_code, + extra_query=self._extra_query, + extra_headers=self._extra_headers, + ) + + try: + result = self._on_reconnecting(event) + except Exception: + self._is_reconnecting = False + return False + + if result is not None and result.get("abort"): + self._is_reconnecting = False + return False + + if result is not None: + if "extra_query" in result: + self._extra_query = result["extra_query"] + if "extra_headers" in result: + self._extra_headers = result["extra_headers"] + + log.info( + "Reconnecting to WebSocket API (attempt %d/%d) after %.1fs delay", + attempt, + self._max_retries, + delay, + ) + time.sleep(delay) + + if self._intentionally_closed: + self._is_reconnecting = False + return False + + try: + self._connection = self._make_ws(self._extra_query, self._extra_headers) + log.info("Reconnected to WebSocket API") + self._is_reconnecting = False + self._flush_send_queue() + return True + except Exception: + pass + + self._is_reconnecting = False + return False + + def _flush_send_queue(self) -> None: + """Send all queued messages over the current connection.""" + try: + self._send_queue.flush_sync(lambda data: self._connection.send(data)) + except Exception: + log.warning("Failed to flush send queue after reconnect", exc_info=True) + + def on( + self, event_type: str, handler: Callable[..., Any] | None = None + ) -> Union[ResponsesConnection, Callable[[Callable[..., Any]], Callable[..., Any]]]: + """Adds the handler to the end of the handlers list for the given event type. + + No checks are made to see if the handler has already been added. Multiple calls + passing the same combination of event type and handler will result in the handler + being added, and called, multiple times. + + Can be used as a method (returns ``self`` for chaining):: + + connection.on("response.audio.delta", my_handler) + + Or as a decorator:: + + @connection.on("response.audio.delta") + def my_handler(event): ... + """ + if handler is not None: + self._event_handler_registry.add(event_type, handler) + return self + + def decorator(fn: Callable[..., Any]) -> Callable[..., Any]: + self._event_handler_registry.add(event_type, fn) + return fn + + return decorator + + def off(self, event_type: str, handler: Callable[..., Any]) -> ResponsesConnection: + """Remove a previously registered event handler.""" + self._event_handler_registry.remove(event_type, handler) + return self + + def once( + self, event_type: str, handler: Callable[..., Any] | None = None + ) -> Union[ResponsesConnection, Callable[[Callable[..., Any]], Callable[..., Any]]]: + """Register a one-time event handler. + + Automatically removed after first invocation. + """ + if handler is not None: + self._event_handler_registry.add(event_type, handler, once=True) + return self + + def decorator(fn: Callable[..., Any]) -> Callable[..., Any]: + self._event_handler_registry.add(event_type, fn, once=True) + return fn + + return decorator + + def dispatch_events(self) -> None: + """Run the event loop, dispatching received events to registered handlers. + + Blocks the current thread until the connection is closed. This is the push-based + alternative to iterating with ``for event in connection``. + + If an ``"error"`` event arrives and no handler is registered for + ``"error"`` or ``"event"``, an ``OpenAIError`` is raised. + """ + for event in self: + event_type = event.type + specific = self._event_handler_registry.get_handlers(event_type) + generic = self._event_handler_registry.get_handlers("event") + + if event_type == "error" and not specific and not generic: + if isinstance(event, ResponseErrorEvent): + raise OpenAIError(f"WebSocket error: {event}") + + for handler in specific: + handler(event) + + for handler in generic: + handler(event) + class ResponsesConnectionManager: """ @@ -3846,16 +4372,77 @@ def __init__( extra_query: Query, extra_headers: Headers, websocket_connection_options: WebSocketConnectionOptions, + on_reconnecting: Callable[[ReconnectingEvent], ReconnectingOverrides | None] | None = None, + max_retries: int = 5, + initial_delay: float = 0.5, + max_delay: float = 8.0, + max_queue_size: int = 1_048_576, ) -> None: self.__client = client self.__connection: ResponsesConnection | None = None self.__extra_query = extra_query self.__extra_headers = extra_headers self.__websocket_connection_options = websocket_connection_options + self.__on_reconnecting = on_reconnecting + self.__max_retries = max_retries + self.__initial_delay = initial_delay + self.__max_delay = max_delay + self.__send_queue = SendQueue(max_bytes=max_queue_size) + self.__event_handler_registry = EventHandlerRegistry(use_lock=True) + + def send(self, event: ResponsesClientEvent | ResponsesClientEventParam) -> None: + """Queue a message to be sent when the connection is established. + + This can be called before entering the context manager. Queued messages + are automatically sent once the WebSocket connection opens. + """ + data = ( + event.to_json(use_api_names=True, exclude_defaults=True, exclude_unset=True) + if isinstance(event, BaseModel) + else json.dumps(event) + ) + self.__send_queue.enqueue(data) + + def on( + self, event_type: str, handler: Callable[..., Any] | None = None + ) -> Union[ResponsesConnectionManager, Callable[[Callable[..., Any]], Callable[..., Any]]]: + """Register an event handler before the connection is established. + + Handlers are transferred to the connection on enter. Supports the + same method and decorator forms as ``ResponsesConnection.on``. + """ + if handler is not None: + self.__event_handler_registry.add(event_type, handler) + return self + + def decorator(fn: Callable[..., Any]) -> Callable[..., Any]: + self.__event_handler_registry.add(event_type, fn) + return fn + + return decorator + + def off(self, event_type: str, handler: Callable[..., Any]) -> ResponsesConnectionManager: + """Remove a previously registered event handler.""" + self.__event_handler_registry.remove(event_type, handler) + return self + + def once( + self, event_type: str, handler: Callable[..., Any] | None = None + ) -> Union[ResponsesConnectionManager, Callable[[Callable[..., Any]], Callable[..., Any]]]: + """Register a one-time event handler before the connection is established.""" + if handler is not None: + self.__event_handler_registry.add(event_type, handler, once=True) + return self + + def decorator(fn: Callable[..., Any]) -> Callable[..., Any]: + self.__event_handler_registry.add(event_type, fn, once=True) + return fn + + return decorator def __enter__(self) -> ResponsesConnection: """ - 👋 If your application doesn't work well with the context manager approach then you + If your application doesn't work well with the context manager approach then you can call this method directly to initiate a connection. **Warning**: You must remember to close the connection with `.close()`. @@ -3866,6 +4453,28 @@ def __enter__(self) -> ResponsesConnection: connection.close() ``` """ + ws = self._connect_ws(self.__extra_query, self.__extra_headers) + + self.__connection = ResponsesConnection( + ws, + make_ws=self._connect_ws if self.__on_reconnecting is not None else None, + on_reconnecting=self.__on_reconnecting, + max_retries=self.__max_retries, + initial_delay=self.__initial_delay, + max_delay=self.__max_delay, + extra_query=self.__extra_query, + extra_headers=self.__extra_headers, + send_queue=self.__send_queue, + ) + + self.__event_handler_registry.merge_into(self.__connection._event_handler_registry) + self.__connection._flush_send_queue() + + return self.__connection + + enter = __enter__ + + def _connect_ws(self, extra_query: Query, extra_headers: Headers) -> WebSocketConnection: try: from websockets.sync.client import connect except ImportError as exc: @@ -3874,31 +4483,25 @@ def __enter__(self) -> ResponsesConnection: url = self._prepare_url().copy_with( params={ **self.__client.base_url.params, - **self.__extra_query, + **extra_query, }, ) log.debug("Connecting to %s", url) if self.__websocket_connection_options: log.debug("Connection options: %s", self.__websocket_connection_options) - self.__connection = ResponsesConnection( - connect( - str(url), - user_agent_header=self.__client.user_agent, - additional_headers=_merge_mappings( - { - **self.__client.auth_headers, - }, - self.__extra_headers, - ), - **self.__websocket_connection_options, - ) + return connect( + str(url), + user_agent_header=self.__client.user_agent, + additional_headers=_merge_mappings( + { + **self.__client.auth_headers, + }, + extra_headers, + ), + **self.__websocket_connection_options, ) - return self.__connection - - enter = __enter__ - def _prepare_url(self) -> httpx.URL: if self.__client.websocket_base_url is not None: base_url = httpx.URL(self.__client.websocket_base_url) diff --git a/src/openai/types/__init__.py b/src/openai/types/__init__.py index 6074eb0a1d..dc2c8a348c 100644 --- a/src/openai/types/__init__.py +++ b/src/openai/types/__init__.py @@ -85,6 +85,10 @@ from .file_chunking_strategy import FileChunkingStrategy as FileChunkingStrategy from .image_gen_stream_event import ImageGenStreamEvent as ImageGenStreamEvent from .upload_complete_params import UploadCompleteParams as UploadCompleteParams +from .websocket_reconnection import ( + ReconnectingEvent as ReconnectingEvent, + ReconnectingOverrides as ReconnectingOverrides, +) from .container_create_params import ContainerCreateParams as ContainerCreateParams from .container_list_response import ContainerListResponse as ContainerListResponse from .embedding_create_params import EmbeddingCreateParams as EmbeddingCreateParams diff --git a/src/openai/types/responses/response_input_file.py b/src/openai/types/responses/response_input_file.py index 3e5fb70c5f..f07ff7c049 100644 --- a/src/openai/types/responses/response_input_file.py +++ b/src/openai/types/responses/response_input_file.py @@ -14,6 +14,13 @@ class ResponseInputFile(BaseModel): type: Literal["input_file"] """The type of the input item. Always `input_file`.""" + detail: Optional[Literal["low", "high"]] = None + """The detail level of the file to be sent to the model. + + Use `low` for the default rendering behavior, or `high` to render the file at + higher quality. Defaults to `low`. + """ + file_data: Optional[str] = None """The content of the file to be sent to the model.""" diff --git a/src/openai/types/responses/response_input_file_content.py b/src/openai/types/responses/response_input_file_content.py index f0dfef55d0..a0c2de4823 100644 --- a/src/openai/types/responses/response_input_file_content.py +++ b/src/openai/types/responses/response_input_file_content.py @@ -14,6 +14,13 @@ class ResponseInputFileContent(BaseModel): type: Literal["input_file"] """The type of the input item. Always `input_file`.""" + detail: Optional[Literal["low", "high"]] = None + """The detail level of the file to be sent to the model. + + Use `low` for the default rendering behavior, or `high` to render the file at + higher quality. Defaults to `low`. + """ + file_data: Optional[str] = None """The base64-encoded data of the file to be sent to the model.""" diff --git a/src/openai/types/responses/response_input_file_content_param.py b/src/openai/types/responses/response_input_file_content_param.py index 376f6c7a45..4206ea09f3 100644 --- a/src/openai/types/responses/response_input_file_content_param.py +++ b/src/openai/types/responses/response_input_file_content_param.py @@ -14,6 +14,13 @@ class ResponseInputFileContentParam(TypedDict, total=False): type: Required[Literal["input_file"]] """The type of the input item. Always `input_file`.""" + detail: Literal["low", "high"] + """The detail level of the file to be sent to the model. + + Use `low` for the default rendering behavior, or `high` to render the file at + higher quality. Defaults to `low`. + """ + file_data: Optional[str] """The base64-encoded data of the file to be sent to the model.""" diff --git a/src/openai/types/responses/response_input_file_param.py b/src/openai/types/responses/response_input_file_param.py index 8b5da20245..a6bdb6e18c 100644 --- a/src/openai/types/responses/response_input_file_param.py +++ b/src/openai/types/responses/response_input_file_param.py @@ -14,6 +14,13 @@ class ResponseInputFileParam(TypedDict, total=False): type: Required[Literal["input_file"]] """The type of the input item. Always `input_file`.""" + detail: Literal["low", "high"] + """The detail level of the file to be sent to the model. + + Use `low` for the default rendering behavior, or `high` to render the file at + higher quality. Defaults to `low`. + """ + file_data: str """The content of the file to be sent to the model.""" diff --git a/src/openai/types/websocket_reconnection.py b/src/openai/types/websocket_reconnection.py new file mode 100644 index 0000000000..9ba66d0ca5 --- /dev/null +++ b/src/openai/types/websocket_reconnection.py @@ -0,0 +1,64 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import dataclasses +from typing_extensions import TypedDict + +from .._types import Query, Headers + + +@dataclasses.dataclass(frozen=True) +class ReconnectingEvent: + """Information about a reconnection attempt, passed to the ``on_reconnecting`` handler.""" + + attempt: int + """Which retry attempt this is (1-based).""" + + max_attempts: int + """Total attempts that will be made.""" + + delay: float + """Delay in seconds before this attempt connects.""" + + close_code: int + """The WebSocket close code that triggered reconnection.""" + + extra_query: Query + """The current query parameters.""" + + extra_headers: Headers + """The current headers.""" + + +class ReconnectingOverrides(TypedDict, total=False): + """Optional overrides returned from the ``on_reconnecting`` handler + to customize the next reconnection attempt.""" + + extra_query: Query + """If provided, assigns the query parameters for the next connection.""" + + extra_headers: Headers + """If provided, assigns the headers for the next connection.""" + + abort: bool + """If set to ``True``, will stop attempting to reconnect.""" + + +# RFC 6455 §7.4.1 +_RECOVERABLE_CLOSE_CODES: frozenset[int] = frozenset( + { + 1001, # Going away (server shutting down) + 1005, # No status code (abnormal) + 1006, # Abnormal closure (network drop) + 1011, # Internal server error + 1012, # Service restart + 1013, # Try again later + 1015, # TLS handshake failure + } +) + + +def is_recoverable_close(code: int) -> bool: + """Return ``True`` if the WebSocket close *code* is worth retrying.""" + return code in _RECOVERABLE_CLOSE_CODES diff --git a/tests/api_resources/audio/test_speech.py b/tests/api_resources/audio/test_speech.py index a42c77126d..93ede5193d 100644 --- a/tests/api_resources/audio/test_speech.py +++ b/tests/api_resources/audio/test_speech.py @@ -27,8 +27,8 @@ def test_method_create(self, client: OpenAI, respx_mock: MockRouter) -> None: respx_mock.post("/audio/speech").mock(return_value=httpx.Response(200, json={"foo": "bar"})) speech = client.audio.speech.create( input="string", - model="string", - voice="string", + model="tts-1", + voice="alloy", ) assert isinstance(speech, _legacy_response.HttpxBinaryResponseContent) assert speech.json() == {"foo": "bar"} @@ -39,8 +39,8 @@ def test_method_create_with_all_params(self, client: OpenAI, respx_mock: MockRou respx_mock.post("/audio/speech").mock(return_value=httpx.Response(200, json={"foo": "bar"})) speech = client.audio.speech.create( input="string", - model="string", - voice="string", + model="tts-1", + voice="alloy", instructions="instructions", response_format="mp3", speed=0.25, @@ -56,8 +56,8 @@ def test_raw_response_create(self, client: OpenAI, respx_mock: MockRouter) -> No response = client.audio.speech.with_raw_response.create( input="string", - model="string", - voice="string", + model="tts-1", + voice="alloy", ) assert response.is_closed is True @@ -71,8 +71,8 @@ def test_streaming_response_create(self, client: OpenAI, respx_mock: MockRouter) respx_mock.post("/audio/speech").mock(return_value=httpx.Response(200, json={"foo": "bar"})) with client.audio.speech.with_streaming_response.create( input="string", - model="string", - voice="string", + model="tts-1", + voice="alloy", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -94,8 +94,8 @@ async def test_method_create(self, async_client: AsyncOpenAI, respx_mock: MockRo respx_mock.post("/audio/speech").mock(return_value=httpx.Response(200, json={"foo": "bar"})) speech = await async_client.audio.speech.create( input="string", - model="string", - voice="string", + model="tts-1", + voice="alloy", ) assert isinstance(speech, _legacy_response.HttpxBinaryResponseContent) assert speech.json() == {"foo": "bar"} @@ -106,8 +106,8 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI, re respx_mock.post("/audio/speech").mock(return_value=httpx.Response(200, json={"foo": "bar"})) speech = await async_client.audio.speech.create( input="string", - model="string", - voice="string", + model="tts-1", + voice="alloy", instructions="instructions", response_format="mp3", speed=0.25, @@ -123,8 +123,8 @@ async def test_raw_response_create(self, async_client: AsyncOpenAI, respx_mock: response = await async_client.audio.speech.with_raw_response.create( input="string", - model="string", - voice="string", + model="tts-1", + voice="alloy", ) assert response.is_closed is True @@ -138,8 +138,8 @@ async def test_streaming_response_create(self, async_client: AsyncOpenAI, respx_ respx_mock.post("/audio/speech").mock(return_value=httpx.Response(200, json={"foo": "bar"})) async with async_client.audio.speech.with_streaming_response.create( input="string", - model="string", - voice="string", + model="tts-1", + voice="alloy", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" diff --git a/tests/api_resources/beta/test_assistants.py b/tests/api_resources/beta/test_assistants.py index 3e85b56dcc..91ff13dded 100644 --- a/tests/api_resources/beta/test_assistants.py +++ b/tests/api_resources/beta/test_assistants.py @@ -149,7 +149,7 @@ def test_method_update_with_all_params(self, client: OpenAI) -> None: description="description", instructions="instructions", metadata={"foo": "string"}, - model="string", + model="gpt-5", name="name", reasoning_effort="none", response_format="auto", @@ -414,7 +414,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncOpenAI) -> description="description", instructions="instructions", metadata={"foo": "string"}, - model="string", + model="gpt-5", name="name", reasoning_effort="none", response_format="auto", diff --git a/tests/api_resources/beta/test_threads.py b/tests/api_resources/beta/test_threads.py index f392c86729..7163511951 100644 --- a/tests/api_resources/beta/test_threads.py +++ b/tests/api_resources/beta/test_threads.py @@ -248,7 +248,7 @@ def test_method_create_and_run_with_all_params_overload_1(self, client: OpenAI) max_completion_tokens=256, max_prompt_tokens=256, metadata={"foo": "string"}, - model="string", + model="gpt-5.4", parallel_tool_calls=True, response_format="auto", stream=False, @@ -343,7 +343,7 @@ def test_method_create_and_run_with_all_params_overload_2(self, client: OpenAI) max_completion_tokens=256, max_prompt_tokens=256, metadata={"foo": "string"}, - model="string", + model="gpt-5.4", parallel_tool_calls=True, response_format="auto", temperature=1, @@ -649,7 +649,7 @@ async def test_method_create_and_run_with_all_params_overload_1(self, async_clie max_completion_tokens=256, max_prompt_tokens=256, metadata={"foo": "string"}, - model="string", + model="gpt-5.4", parallel_tool_calls=True, response_format="auto", stream=False, @@ -744,7 +744,7 @@ async def test_method_create_and_run_with_all_params_overload_2(self, async_clie max_completion_tokens=256, max_prompt_tokens=256, metadata={"foo": "string"}, - model="string", + model="gpt-5.4", parallel_tool_calls=True, response_format="auto", temperature=1, diff --git a/tests/api_resources/beta/threads/test_runs.py b/tests/api_resources/beta/threads/test_runs.py index 3a6b36864d..aa85871325 100644 --- a/tests/api_resources/beta/threads/test_runs.py +++ b/tests/api_resources/beta/threads/test_runs.py @@ -57,7 +57,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: max_completion_tokens=256, max_prompt_tokens=256, metadata={"foo": "string"}, - model="string", + model="gpt-5.4", parallel_tool_calls=True, reasoning_effort="none", response_format="auto", @@ -148,7 +148,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: max_completion_tokens=256, max_prompt_tokens=256, metadata={"foo": "string"}, - model="string", + model="gpt-5.4", parallel_tool_calls=True, reasoning_effort="none", response_format="auto", @@ -607,7 +607,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn max_completion_tokens=256, max_prompt_tokens=256, metadata={"foo": "string"}, - model="string", + model="gpt-5.4", parallel_tool_calls=True, reasoning_effort="none", response_format="auto", @@ -698,7 +698,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn max_completion_tokens=256, max_prompt_tokens=256, metadata={"foo": "string"}, - model="string", + model="gpt-5.4", parallel_tool_calls=True, reasoning_effort="none", response_format="auto", diff --git a/tests/api_resources/chat/test_completions.py b/tests/api_resources/chat/test_completions.py index c55c132697..a75764b5e9 100644 --- a/tests/api_resources/chat/test_completions.py +++ b/tests/api_resources/chat/test_completions.py @@ -48,7 +48,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: model="gpt-5.4", audio={ "format": "wav", - "voice": "string", + "voice": "alloy", }, frequency_penalty=-2, function_call="none", @@ -182,7 +182,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: stream=True, audio={ "format": "wav", - "voice": "string", + "voice": "alloy", }, frequency_penalty=-2, function_call="none", @@ -491,7 +491,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn model="gpt-5.4", audio={ "format": "wav", - "voice": "string", + "voice": "alloy", }, frequency_penalty=-2, function_call="none", @@ -625,7 +625,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn stream=True, audio={ "format": "wav", - "voice": "string", + "voice": "alloy", }, frequency_penalty=-2, function_call="none", diff --git a/tests/api_resources/realtime/test_calls.py b/tests/api_resources/realtime/test_calls.py index 9e2810841d..43ab9afe01 100644 --- a/tests/api_resources/realtime/test_calls.py +++ b/tests/api_resources/realtime/test_calls.py @@ -48,7 +48,7 @@ def test_method_create_with_all_params(self, client: OpenAI, respx_mock: MockRou "noise_reduction": {"type": "near_field"}, "transcription": { "language": "language", - "model": "string", + "model": "whisper-1", "prompt": "prompt", }, "turn_detection": { @@ -67,13 +67,13 @@ def test_method_create_with_all_params(self, client: OpenAI, respx_mock: MockRou "type": "audio/pcm", }, "speed": 0.25, - "voice": "string", + "voice": "alloy", }, }, "include": ["item.input_audio_transcription.logprobs"], "instructions": "instructions", - "max_output_tokens": 0, - "model": "string", + "max_output_tokens": "inf", + "model": "gpt-realtime", "output_modalities": ["text"], "prompt": { "id": "id", @@ -147,7 +147,7 @@ def test_method_accept_with_all_params(self, client: OpenAI) -> None: "noise_reduction": {"type": "near_field"}, "transcription": { "language": "language", - "model": "string", + "model": "whisper-1", "prompt": "prompt", }, "turn_detection": { @@ -166,13 +166,13 @@ def test_method_accept_with_all_params(self, client: OpenAI) -> None: "type": "audio/pcm", }, "speed": 0.25, - "voice": "string", + "voice": "alloy", }, }, include=["item.input_audio_transcription.logprobs"], instructions="instructions", - max_output_tokens=0, - model="string", + max_output_tokens="inf", + model="gpt-realtime", output_modalities=["text"], prompt={ "id": "id", @@ -386,7 +386,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI, re "noise_reduction": {"type": "near_field"}, "transcription": { "language": "language", - "model": "string", + "model": "whisper-1", "prompt": "prompt", }, "turn_detection": { @@ -405,13 +405,13 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI, re "type": "audio/pcm", }, "speed": 0.25, - "voice": "string", + "voice": "alloy", }, }, "include": ["item.input_audio_transcription.logprobs"], "instructions": "instructions", - "max_output_tokens": 0, - "model": "string", + "max_output_tokens": "inf", + "model": "gpt-realtime", "output_modalities": ["text"], "prompt": { "id": "id", @@ -485,7 +485,7 @@ async def test_method_accept_with_all_params(self, async_client: AsyncOpenAI) -> "noise_reduction": {"type": "near_field"}, "transcription": { "language": "language", - "model": "string", + "model": "whisper-1", "prompt": "prompt", }, "turn_detection": { @@ -504,13 +504,13 @@ async def test_method_accept_with_all_params(self, async_client: AsyncOpenAI) -> "type": "audio/pcm", }, "speed": 0.25, - "voice": "string", + "voice": "alloy", }, }, include=["item.input_audio_transcription.logprobs"], instructions="instructions", - max_output_tokens=0, - model="string", + max_output_tokens="inf", + model="gpt-realtime", output_modalities=["text"], prompt={ "id": "id", diff --git a/tests/api_resources/realtime/test_client_secrets.py b/tests/api_resources/realtime/test_client_secrets.py index bfa0deac55..a354019eac 100644 --- a/tests/api_resources/realtime/test_client_secrets.py +++ b/tests/api_resources/realtime/test_client_secrets.py @@ -40,7 +40,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: "noise_reduction": {"type": "near_field"}, "transcription": { "language": "language", - "model": "string", + "model": "whisper-1", "prompt": "prompt", }, "turn_detection": { @@ -59,13 +59,13 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: "type": "audio/pcm", }, "speed": 0.25, - "voice": "string", + "voice": "alloy", }, }, "include": ["item.input_audio_transcription.logprobs"], "instructions": "instructions", - "max_output_tokens": 0, - "model": "string", + "max_output_tokens": "inf", + "model": "gpt-realtime", "output_modalities": ["text"], "prompt": { "id": "id", @@ -136,7 +136,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> "noise_reduction": {"type": "near_field"}, "transcription": { "language": "language", - "model": "string", + "model": "whisper-1", "prompt": "prompt", }, "turn_detection": { @@ -155,13 +155,13 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> "type": "audio/pcm", }, "speed": 0.25, - "voice": "string", + "voice": "alloy", }, }, "include": ["item.input_audio_transcription.logprobs"], "instructions": "instructions", - "max_output_tokens": 0, - "model": "string", + "max_output_tokens": "inf", + "model": "gpt-realtime", "output_modalities": ["text"], "prompt": { "id": "id", diff --git a/tests/api_resources/test_completions.py b/tests/api_resources/test_completions.py index a8fb0e59eb..d0081aaca2 100644 --- a/tests/api_resources/test_completions.py +++ b/tests/api_resources/test_completions.py @@ -20,7 +20,7 @@ class TestCompletions: @parametrize def test_method_create_overload_1(self, client: OpenAI) -> None: completion = client.completions.create( - model="string", + model="gpt-3.5-turbo-instruct", prompt="This is a test.", ) assert_matches_type(Completion, completion, path=["response"]) @@ -28,7 +28,7 @@ def test_method_create_overload_1(self, client: OpenAI) -> None: @parametrize def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: completion = client.completions.create( - model="string", + model="gpt-3.5-turbo-instruct", prompt="This is a test.", best_of=0, echo=True, @@ -55,7 +55,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: @parametrize def test_raw_response_create_overload_1(self, client: OpenAI) -> None: response = client.completions.with_raw_response.create( - model="string", + model="gpt-3.5-turbo-instruct", prompt="This is a test.", ) @@ -67,7 +67,7 @@ def test_raw_response_create_overload_1(self, client: OpenAI) -> None: @parametrize def test_streaming_response_create_overload_1(self, client: OpenAI) -> None: with client.completions.with_streaming_response.create( - model="string", + model="gpt-3.5-turbo-instruct", prompt="This is a test.", ) as response: assert not response.is_closed @@ -81,7 +81,7 @@ def test_streaming_response_create_overload_1(self, client: OpenAI) -> None: @parametrize def test_method_create_overload_2(self, client: OpenAI) -> None: completion_stream = client.completions.create( - model="string", + model="gpt-3.5-turbo-instruct", prompt="This is a test.", stream=True, ) @@ -90,7 +90,7 @@ def test_method_create_overload_2(self, client: OpenAI) -> None: @parametrize def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: completion_stream = client.completions.create( - model="string", + model="gpt-3.5-turbo-instruct", prompt="This is a test.", stream=True, best_of=0, @@ -117,7 +117,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: @parametrize def test_raw_response_create_overload_2(self, client: OpenAI) -> None: response = client.completions.with_raw_response.create( - model="string", + model="gpt-3.5-turbo-instruct", prompt="This is a test.", stream=True, ) @@ -129,7 +129,7 @@ def test_raw_response_create_overload_2(self, client: OpenAI) -> None: @parametrize def test_streaming_response_create_overload_2(self, client: OpenAI) -> None: with client.completions.with_streaming_response.create( - model="string", + model="gpt-3.5-turbo-instruct", prompt="This is a test.", stream=True, ) as response: @@ -150,7 +150,7 @@ class TestAsyncCompletions: @parametrize async def test_method_create_overload_1(self, async_client: AsyncOpenAI) -> None: completion = await async_client.completions.create( - model="string", + model="gpt-3.5-turbo-instruct", prompt="This is a test.", ) assert_matches_type(Completion, completion, path=["response"]) @@ -158,7 +158,7 @@ async def test_method_create_overload_1(self, async_client: AsyncOpenAI) -> None @parametrize async def test_method_create_with_all_params_overload_1(self, async_client: AsyncOpenAI) -> None: completion = await async_client.completions.create( - model="string", + model="gpt-3.5-turbo-instruct", prompt="This is a test.", best_of=0, echo=True, @@ -185,7 +185,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn @parametrize async def test_raw_response_create_overload_1(self, async_client: AsyncOpenAI) -> None: response = await async_client.completions.with_raw_response.create( - model="string", + model="gpt-3.5-turbo-instruct", prompt="This is a test.", ) @@ -197,7 +197,7 @@ async def test_raw_response_create_overload_1(self, async_client: AsyncOpenAI) - @parametrize async def test_streaming_response_create_overload_1(self, async_client: AsyncOpenAI) -> None: async with async_client.completions.with_streaming_response.create( - model="string", + model="gpt-3.5-turbo-instruct", prompt="This is a test.", ) as response: assert not response.is_closed @@ -211,7 +211,7 @@ async def test_streaming_response_create_overload_1(self, async_client: AsyncOpe @parametrize async def test_method_create_overload_2(self, async_client: AsyncOpenAI) -> None: completion_stream = await async_client.completions.create( - model="string", + model="gpt-3.5-turbo-instruct", prompt="This is a test.", stream=True, ) @@ -220,7 +220,7 @@ async def test_method_create_overload_2(self, async_client: AsyncOpenAI) -> None @parametrize async def test_method_create_with_all_params_overload_2(self, async_client: AsyncOpenAI) -> None: completion_stream = await async_client.completions.create( - model="string", + model="gpt-3.5-turbo-instruct", prompt="This is a test.", stream=True, best_of=0, @@ -247,7 +247,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn @parametrize async def test_raw_response_create_overload_2(self, async_client: AsyncOpenAI) -> None: response = await async_client.completions.with_raw_response.create( - model="string", + model="gpt-3.5-turbo-instruct", prompt="This is a test.", stream=True, ) @@ -259,7 +259,7 @@ async def test_raw_response_create_overload_2(self, async_client: AsyncOpenAI) - @parametrize async def test_streaming_response_create_overload_2(self, async_client: AsyncOpenAI) -> None: async with async_client.completions.with_streaming_response.create( - model="string", + model="gpt-3.5-turbo-instruct", prompt="This is a test.", stream=True, ) as response: diff --git a/tests/api_resources/test_images.py b/tests/api_resources/test_images.py index 9862b79c65..13cbc0acb7 100644 --- a/tests/api_resources/test_images.py +++ b/tests/api_resources/test_images.py @@ -28,7 +28,7 @@ def test_method_create_variation(self, client: OpenAI) -> None: def test_method_create_variation_with_all_params(self, client: OpenAI) -> None: image = client.images.create_variation( image=b"Example data", - model="string", + model="gpt-image-1.5", n=1, response_format="url", size="1024x1024", @@ -76,7 +76,7 @@ def test_method_edit_with_all_params_overload_1(self, client: OpenAI) -> None: background="transparent", input_fidelity="high", mask=b"Example data", - model="string", + model="gpt-image-1.5", n=1, output_compression=100, output_format="png", @@ -133,7 +133,7 @@ def test_method_edit_with_all_params_overload_2(self, client: OpenAI) -> None: background="transparent", input_fidelity="high", mask=b"Example data", - model="string", + model="gpt-image-1.5", n=1, output_compression=100, output_format="png", @@ -184,7 +184,7 @@ def test_method_generate_with_all_params_overload_1(self, client: OpenAI) -> Non image = client.images.generate( prompt="A cute baby sea otter", background="transparent", - model="string", + model="gpt-image-1.5", moderation="low", n=1, output_compression=100, @@ -237,7 +237,7 @@ def test_method_generate_with_all_params_overload_2(self, client: OpenAI) -> Non prompt="A cute baby sea otter", stream=True, background="transparent", - model="string", + model="gpt-image-1.5", moderation="low", n=1, output_compression=100, @@ -293,7 +293,7 @@ async def test_method_create_variation(self, async_client: AsyncOpenAI) -> None: async def test_method_create_variation_with_all_params(self, async_client: AsyncOpenAI) -> None: image = await async_client.images.create_variation( image=b"Example data", - model="string", + model="gpt-image-1.5", n=1, response_format="url", size="1024x1024", @@ -341,7 +341,7 @@ async def test_method_edit_with_all_params_overload_1(self, async_client: AsyncO background="transparent", input_fidelity="high", mask=b"Example data", - model="string", + model="gpt-image-1.5", n=1, output_compression=100, output_format="png", @@ -398,7 +398,7 @@ async def test_method_edit_with_all_params_overload_2(self, async_client: AsyncO background="transparent", input_fidelity="high", mask=b"Example data", - model="string", + model="gpt-image-1.5", n=1, output_compression=100, output_format="png", @@ -449,7 +449,7 @@ async def test_method_generate_with_all_params_overload_1(self, async_client: As image = await async_client.images.generate( prompt="A cute baby sea otter", background="transparent", - model="string", + model="gpt-image-1.5", moderation="low", n=1, output_compression=100, @@ -502,7 +502,7 @@ async def test_method_generate_with_all_params_overload_2(self, async_client: As prompt="A cute baby sea otter", stream=True, background="transparent", - model="string", + model="gpt-image-1.5", moderation="low", n=1, output_compression=100, diff --git a/tests/api_resources/test_moderations.py b/tests/api_resources/test_moderations.py index 870c9e342f..8487d4a7a6 100644 --- a/tests/api_resources/test_moderations.py +++ b/tests/api_resources/test_moderations.py @@ -28,7 +28,7 @@ def test_method_create(self, client: OpenAI) -> None: def test_method_create_with_all_params(self, client: OpenAI) -> None: moderation = client.moderations.create( input="I want to kill them.", - model="string", + model="omni-moderation-latest", ) assert_matches_type(ModerationCreateResponse, moderation, path=["response"]) @@ -73,7 +73,7 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None: async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: moderation = await async_client.moderations.create( input="I want to kill them.", - model="string", + model="omni-moderation-latest", ) assert_matches_type(ModerationCreateResponse, moderation, path=["response"]) diff --git a/tests/api_resources/test_responses.py b/tests/api_resources/test_responses.py index deaf35970f..0b871d525d 100644 --- a/tests/api_resources/test_responses.py +++ b/tests/api_resources/test_responses.py @@ -40,7 +40,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: include=["file_search_call.results"], input="string", instructions="instructions", - max_output_tokens=0, + max_output_tokens=16, max_tool_calls=0, metadata={"foo": "string"}, model="gpt-5.1", @@ -128,7 +128,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: include=["file_search_call.results"], input="string", instructions="instructions", - max_output_tokens=0, + max_output_tokens=16, max_tool_calls=0, metadata={"foo": "string"}, model="gpt-5.1", @@ -451,7 +451,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn include=["file_search_call.results"], input="string", instructions="instructions", - max_output_tokens=0, + max_output_tokens=16, max_tool_calls=0, metadata={"foo": "string"}, model="gpt-5.1", @@ -539,7 +539,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn include=["file_search_call.results"], input="string", instructions="instructions", - max_output_tokens=0, + max_output_tokens=16, max_tool_calls=0, metadata={"foo": "string"}, model="gpt-5.1", diff --git a/tests/api_resources/test_videos.py b/tests/api_resources/test_videos.py index 73acf6d05d..d6b51f9674 100644 --- a/tests/api_resources/test_videos.py +++ b/tests/api_resources/test_videos.py @@ -41,7 +41,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: video = client.videos.create( prompt="x", input_reference=b"Example data", - model="string", + model="sora-2", seconds="4", size="720x1280", ) @@ -442,7 +442,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> video = await async_client.videos.create( prompt="x", input_reference=b"Example data", - model="string", + model="sora-2", seconds="4", size="720x1280", ) diff --git a/tests/test_extract_files.py b/tests/test_extract_files.py index 0f6fb04d7d..dcf85bd7c7 100644 --- a/tests/test_extract_files.py +++ b/tests/test_extract_files.py @@ -35,6 +35,15 @@ def test_multiple_files() -> None: assert query == {"documents": [{}, {}]} +def test_top_level_file_array() -> None: + query = {"files": [b"file one", b"file two"], "title": "hello"} + assert extract_files(query, paths=[["files", ""]]) == [ + ("files[]", b"file one"), + ("files[]", b"file two"), + ] + assert query == {"title": "hello"} + + @pytest.mark.parametrize( "query,paths,expected", [ diff --git a/tests/test_send_queue.py b/tests/test_send_queue.py new file mode 100644 index 0000000000..61db916bc4 --- /dev/null +++ b/tests/test_send_queue.py @@ -0,0 +1,128 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import pytest + +from openai._exceptions import WebSocketQueueFullError +from openai._send_queue import SendQueue + + +class TestSendQueue: + def test_enqueue_and_drain(self) -> None: + q = SendQueue() + q.enqueue('{"type": "session.update"}') + q.enqueue('{"type": "response.create"}') + assert len(q) == 2 + + items = q.drain() + assert items == ['{"type": "session.update"}', '{"type": "response.create"}'] + assert len(q) == 0 + + def test_enqueue_respects_byte_limit(self) -> None: + q = SendQueue(max_bytes=10) + q.enqueue("12345") # 5 bytes, fits + with pytest.raises(WebSocketQueueFullError): + q.enqueue("123456") # 6 bytes, would exceed 10 + assert len(q) == 1 + + def test_drain_empties_queue(self) -> None: + q = SendQueue() + q.enqueue("hello") + q.drain() + assert len(q) == 0 + assert not q + + def test_bool(self) -> None: + q = SendQueue() + assert not q + q.enqueue("x") + assert q + + def test_flush_sync(self) -> None: + q = SendQueue() + q.enqueue("a") + q.enqueue("b") + q.enqueue("c") + + sent: list[str] = [] + q.flush_sync(sent.append) + assert sent == ["a", "b", "c"] + assert len(q) == 0 + + def test_flush_sync_requeues_on_failure(self) -> None: + q = SendQueue() + q.enqueue("a") + q.enqueue("b") + q.enqueue("c") + + sent: list[str] = [] + + def failing_send(data: str) -> None: + if data == "b": + raise RuntimeError("send failed") + sent.append(data) + + with pytest.raises(RuntimeError, match="send failed"): + q.flush_sync(failing_send) + + assert sent == ["a"] + # b and c should be re-queued + remaining = q.drain() + assert remaining == ["b", "c"] + + @pytest.mark.asyncio + async def test_flush_async(self) -> None: + q = SendQueue() + q.enqueue("a") + q.enqueue("b") + + sent: list[str] = [] + + async def async_send(data: str) -> None: + sent.append(data) + + await q.flush_async(async_send) + assert sent == ["a", "b"] + assert len(q) == 0 + + @pytest.mark.asyncio + async def test_flush_async_requeues_on_failure(self) -> None: + q = SendQueue() + q.enqueue("a") + q.enqueue("b") + q.enqueue("c") + + sent: list[str] = [] + + async def failing_send(data: str) -> None: + if data == "b": + raise RuntimeError("send failed") + sent.append(data) + + with pytest.raises(RuntimeError, match="send failed"): + await q.flush_async(failing_send) + + assert sent == ["a"] + remaining = q.drain() + assert remaining == ["b", "c"] + + def test_flush_sync_preserves_new_items_on_failure(self) -> None: + """If items are enqueued after flush starts and flush fails, + the re-queued items should come before the new items.""" + q = SendQueue() + q.enqueue("a") + q.enqueue("b") + + def failing_send(data: str) -> None: + if data == "b": + # Simulate another thread enqueuing during flush + q.enqueue("new") + raise RuntimeError("fail") + + with pytest.raises(RuntimeError): + q.flush_sync(failing_send) + + # "b" (failed) should come before "new" (added during flush) + remaining = q.drain() + assert remaining == ["b", "new"] From f9d2d1359688a6247ecba858fc687173c480c9c8 Mon Sep 17 00:00:00 2001 From: Cameron McAteer <246350779+cameron-mcateer@users.noreply.github.com> Date: Fri, 24 Apr 2026 14:52:29 -0400 Subject: [PATCH 680/769] fix(api): correct prompt_cache_retention enum value from in-memory to in_memory (#1822) Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> --- .../resources/chat/completions/completions.py | 24 +++++++------- src/openai/resources/responses/responses.py | 32 +++++++++---------- .../types/chat/completion_create_params.py | 2 +- src/openai/types/responses/response.py | 2 +- .../types/responses/response_create_params.py | 2 +- .../types/responses/responses_client_event.py | 2 +- .../responses/responses_client_event_param.py | 2 +- tests/api_resources/chat/test_completions.py | 8 ++--- tests/api_resources/test_responses.py | 8 ++--- 9 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index 845bd1a1e1..8b4fc12ae9 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -109,7 +109,7 @@ def parse( prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, presence_penalty: Optional[float] | Omit = omit, prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit, reasoning_effort: Optional[ReasoningEffort] | Omit = omit, safety_identifier: str | Omit = omit, seed: Optional[int] | Omit = omit, @@ -264,7 +264,7 @@ def create( prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, presence_penalty: Optional[float] | Omit = omit, prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit, reasoning_effort: Optional[ReasoningEffort] | Omit = omit, response_format: completion_create_params.ResponseFormat | Omit = omit, safety_identifier: str | Omit = omit, @@ -571,7 +571,7 @@ def create( prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, presence_penalty: Optional[float] | Omit = omit, prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit, reasoning_effort: Optional[ReasoningEffort] | Omit = omit, response_format: completion_create_params.ResponseFormat | Omit = omit, safety_identifier: str | Omit = omit, @@ -877,7 +877,7 @@ def create( prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, presence_penalty: Optional[float] | Omit = omit, prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit, reasoning_effort: Optional[ReasoningEffort] | Omit = omit, response_format: completion_create_params.ResponseFormat | Omit = omit, safety_identifier: str | Omit = omit, @@ -1182,7 +1182,7 @@ def create( prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, presence_penalty: Optional[float] | Omit = omit, prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit, reasoning_effort: Optional[ReasoningEffort] | Omit = omit, response_format: completion_create_params.ResponseFormat | Omit = omit, safety_identifier: str | Omit = omit, @@ -1461,7 +1461,7 @@ def stream( prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, presence_penalty: Optional[float] | Omit = omit, prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit, reasoning_effort: Optional[ReasoningEffort] | Omit = omit, safety_identifier: str | Omit = omit, seed: Optional[int] | Omit = omit, @@ -1612,7 +1612,7 @@ async def parse( prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, presence_penalty: Optional[float] | Omit = omit, prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit, reasoning_effort: Optional[ReasoningEffort] | Omit = omit, safety_identifier: str | Omit = omit, seed: Optional[int] | Omit = omit, @@ -1767,7 +1767,7 @@ async def create( prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, presence_penalty: Optional[float] | Omit = omit, prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit, reasoning_effort: Optional[ReasoningEffort] | Omit = omit, response_format: completion_create_params.ResponseFormat | Omit = omit, safety_identifier: str | Omit = omit, @@ -2074,7 +2074,7 @@ async def create( prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, presence_penalty: Optional[float] | Omit = omit, prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit, reasoning_effort: Optional[ReasoningEffort] | Omit = omit, response_format: completion_create_params.ResponseFormat | Omit = omit, safety_identifier: str | Omit = omit, @@ -2380,7 +2380,7 @@ async def create( prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, presence_penalty: Optional[float] | Omit = omit, prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit, reasoning_effort: Optional[ReasoningEffort] | Omit = omit, response_format: completion_create_params.ResponseFormat | Omit = omit, safety_identifier: str | Omit = omit, @@ -2685,7 +2685,7 @@ async def create( prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, presence_penalty: Optional[float] | Omit = omit, prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit, reasoning_effort: Optional[ReasoningEffort] | Omit = omit, response_format: completion_create_params.ResponseFormat | Omit = omit, safety_identifier: str | Omit = omit, @@ -2964,7 +2964,7 @@ def stream( prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, presence_penalty: Optional[float] | Omit = omit, prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit, reasoning_effort: Optional[ReasoningEffort] | Omit = omit, safety_identifier: str | Omit = omit, seed: Optional[int] | Omit = omit, diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index ab5f7688a5..cb9a09bf22 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -146,7 +146,7 @@ def create( previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit, reasoning: Optional[Reasoning] | Omit = omit, safety_identifier: str | Omit = omit, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, @@ -396,7 +396,7 @@ def create( previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit, reasoning: Optional[Reasoning] | Omit = omit, safety_identifier: str | Omit = omit, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, @@ -645,7 +645,7 @@ def create( previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit, reasoning: Optional[Reasoning] | Omit = omit, safety_identifier: str | Omit = omit, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, @@ -892,7 +892,7 @@ def create( previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit, reasoning: Optional[Reasoning] | Omit = omit, safety_identifier: str | Omit = omit, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, @@ -995,7 +995,7 @@ def stream( previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit, reasoning: Optional[Reasoning] | Omit = omit, safety_identifier: str | Omit = omit, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, @@ -1036,7 +1036,7 @@ def stream( previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit, reasoning: Optional[Reasoning] | Omit = omit, safety_identifier: str | Omit = omit, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, @@ -1187,7 +1187,7 @@ def parse( previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit, reasoning: Optional[Reasoning] | Omit = omit, safety_identifier: str | Omit = omit, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, @@ -1823,7 +1823,7 @@ async def create( previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit, reasoning: Optional[Reasoning] | Omit = omit, safety_identifier: str | Omit = omit, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, @@ -2073,7 +2073,7 @@ async def create( previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit, reasoning: Optional[Reasoning] | Omit = omit, safety_identifier: str | Omit = omit, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, @@ -2322,7 +2322,7 @@ async def create( previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit, reasoning: Optional[Reasoning] | Omit = omit, safety_identifier: str | Omit = omit, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, @@ -2569,7 +2569,7 @@ async def create( previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit, reasoning: Optional[Reasoning] | Omit = omit, safety_identifier: str | Omit = omit, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, @@ -2672,7 +2672,7 @@ def stream( previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit, reasoning: Optional[Reasoning] | Omit = omit, safety_identifier: str | Omit = omit, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, @@ -2713,7 +2713,7 @@ def stream( previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit, reasoning: Optional[Reasoning] | Omit = omit, safety_identifier: str | Omit = omit, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, @@ -2868,7 +2868,7 @@ async def parse( previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit, reasoning: Optional[Reasoning] | Omit = omit, safety_identifier: str | Omit = omit, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, @@ -4543,7 +4543,7 @@ def create( previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit, reasoning: Optional[Reasoning] | Omit = omit, safety_identifier: str | Omit = omit, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, @@ -4623,7 +4623,7 @@ async def create( previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit, reasoning: Optional[Reasoning] | Omit = omit, safety_identifier: str | Omit = omit, service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, diff --git a/src/openai/types/chat/completion_create_params.py b/src/openai/types/chat/completion_create_params.py index 8e71ccbe41..0379ee0865 100644 --- a/src/openai/types/chat/completion_create_params.py +++ b/src/openai/types/chat/completion_create_params.py @@ -185,7 +185,7 @@ class CompletionCreateParamsBase(TypedDict, total=False): [Learn more](https://platform.openai.com/docs/guides/prompt-caching). """ - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] """The retention policy for the prompt cache. Set to `24h` to enable extended prompt caching, which keeps cached prefixes diff --git a/src/openai/types/responses/response.py b/src/openai/types/responses/response.py index ada0783bce..0d2491ea7c 100644 --- a/src/openai/types/responses/response.py +++ b/src/openai/types/responses/response.py @@ -214,7 +214,7 @@ class Response(BaseModel): [Learn more](https://platform.openai.com/docs/guides/prompt-caching). """ - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] = None + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] = None """The retention policy for the prompt cache. Set to `24h` to enable extended prompt caching, which keeps cached prefixes diff --git a/src/openai/types/responses/response_create_params.py b/src/openai/types/responses/response_create_params.py index bf7170da1f..a04495f40a 100644 --- a/src/openai/types/responses/response_create_params.py +++ b/src/openai/types/responses/response_create_params.py @@ -152,7 +152,7 @@ class ResponseCreateParamsBase(TypedDict, total=False): [Learn more](https://platform.openai.com/docs/guides/prompt-caching). """ - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] """The retention policy for the prompt cache. Set to `24h` to enable extended prompt caching, which keeps cached prefixes diff --git a/src/openai/types/responses/responses_client_event.py b/src/openai/types/responses/responses_client_event.py index 2bc6f899c5..5f9e73c61f 100644 --- a/src/openai/types/responses/responses_client_event.py +++ b/src/openai/types/responses/responses_client_event.py @@ -184,7 +184,7 @@ class ResponsesClientEvent(BaseModel): [Learn more](https://platform.openai.com/docs/guides/prompt-caching). """ - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] = None + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] = None """The retention policy for the prompt cache. Set to `24h` to enable extended prompt caching, which keeps cached prefixes diff --git a/src/openai/types/responses/responses_client_event_param.py b/src/openai/types/responses/responses_client_event_param.py index 08596ef9ea..249c812116 100644 --- a/src/openai/types/responses/responses_client_event_param.py +++ b/src/openai/types/responses/responses_client_event_param.py @@ -185,7 +185,7 @@ class ResponsesClientEventParam(TypedDict, total=False): [Learn more](https://platform.openai.com/docs/guides/prompt-caching). """ - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] """The retention policy for the prompt cache. Set to `24h` to enable extended prompt caching, which keeps cached prefixes diff --git a/tests/api_resources/chat/test_completions.py b/tests/api_resources/chat/test_completions.py index a75764b5e9..ea3066a505 100644 --- a/tests/api_resources/chat/test_completions.py +++ b/tests/api_resources/chat/test_completions.py @@ -73,7 +73,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: }, presence_penalty=-2, prompt_cache_key="prompt-cache-key-1234", - prompt_cache_retention="in-memory", + prompt_cache_retention="in_memory", reasoning_effort="none", response_format={"type": "text"}, safety_identifier="safety-identifier-1234", @@ -207,7 +207,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: }, presence_penalty=-2, prompt_cache_key="prompt-cache-key-1234", - prompt_cache_retention="in-memory", + prompt_cache_retention="in_memory", reasoning_effort="none", response_format={"type": "text"}, safety_identifier="safety-identifier-1234", @@ -516,7 +516,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn }, presence_penalty=-2, prompt_cache_key="prompt-cache-key-1234", - prompt_cache_retention="in-memory", + prompt_cache_retention="in_memory", reasoning_effort="none", response_format={"type": "text"}, safety_identifier="safety-identifier-1234", @@ -650,7 +650,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn }, presence_penalty=-2, prompt_cache_key="prompt-cache-key-1234", - prompt_cache_retention="in-memory", + prompt_cache_retention="in_memory", reasoning_effort="none", response_format={"type": "text"}, safety_identifier="safety-identifier-1234", diff --git a/tests/api_resources/test_responses.py b/tests/api_resources/test_responses.py index 0b871d525d..096b983be2 100644 --- a/tests/api_resources/test_responses.py +++ b/tests/api_resources/test_responses.py @@ -52,7 +52,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: "version": "version", }, prompt_cache_key="prompt-cache-key-1234", - prompt_cache_retention="in-memory", + prompt_cache_retention="in_memory", reasoning={ "effort": "none", "generate_summary": "auto", @@ -140,7 +140,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: "version": "version", }, prompt_cache_key="prompt-cache-key-1234", - prompt_cache_retention="in-memory", + prompt_cache_retention="in_memory", reasoning={ "effort": "none", "generate_summary": "auto", @@ -463,7 +463,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn "version": "version", }, prompt_cache_key="prompt-cache-key-1234", - prompt_cache_retention="in-memory", + prompt_cache_retention="in_memory", reasoning={ "effort": "none", "generate_summary": "auto", @@ -551,7 +551,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn "version": "version", }, prompt_cache_key="prompt-cache-key-1234", - prompt_cache_retention="in-memory", + prompt_cache_retention="in_memory", reasoning={ "effort": "none", "generate_summary": "auto", From 00b20910e3539842f21d86ab5928fb5216d3a765 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 27 Apr 2026 15:04:42 +0000 Subject: [PATCH 681/769] chore(ci): remove release-doctor workflow --- .github/workflows/release-doctor.yml | 23 ----------------------- bin/check-release-environment | 25 ------------------------- 2 files changed, 48 deletions(-) delete mode 100644 .github/workflows/release-doctor.yml delete mode 100644 bin/check-release-environment diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml deleted file mode 100644 index 503de9d99a..0000000000 --- a/.github/workflows/release-doctor.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: Release Doctor -on: - push: - branches: - - main - workflow_dispatch: - -jobs: - release_doctor: - name: release doctor - runs-on: ubuntu-latest - environment: publish - if: github.repository == 'openai/openai-python' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next') - - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - - - name: Check release environment - run: | - bash ./bin/check-release-environment - env: - STAINLESS_API_KEY: ${{ secrets.STAINLESS_API_KEY }} - PYPI_TOKEN: ${{ secrets.OPENAI_PYPI_TOKEN || secrets.PYPI_TOKEN }} diff --git a/bin/check-release-environment b/bin/check-release-environment deleted file mode 100644 index 044ed525d1..0000000000 --- a/bin/check-release-environment +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env bash - -errors=() - -if [ -z "${STAINLESS_API_KEY}" ]; then - errors+=("The STAINLESS_API_KEY secret has not been set. Please contact Stainless for an API key & set it in your organization secrets on GitHub.") -fi - -if [ -z "${PYPI_TOKEN}" ]; then - errors+=("The PYPI_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets.") -fi - -lenErrors=${#errors[@]} - -if [[ lenErrors -gt 0 ]]; then - echo -e "Found the following errors in the release environment:\n" - - for error in "${errors[@]}"; do - echo -e "- $error\n" - done - - exit 1 -fi - -echo "The environment is ready to push releases!" From 18f834a54f92ea827452471a46a4f442f251e2c8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 15 Apr 2026 02:44:29 +0000 Subject: [PATCH 682/769] feat(api): api update --- .stats.yml | 4 ++-- src/openai/resources/responses/responses.py | 8 ++++++++ src/openai/types/responses/response_compact_params.py | 3 +++ tests/api_resources/test_responses.py | 2 ++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index f069d6c8b9..60efa98d0f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 152 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-7c540cce6eb30401259f4831ea9803b6d88501605d13734f98212cbb3b199e10.yml -openapi_spec_hash: 06e656be22bbb92689954253668b42fc +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-64c6ba619ccbf87e56b4f464230d04401fd78ad924d2606176309d19ca281af5.yml +openapi_spec_hash: 5e4f2073040a12c26ce58e86a72fe47e config_hash: 1a88b104658b6c854117996c080ebe6b diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index cb9a09bf22..48705098cc 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -1686,6 +1686,7 @@ def compact( instructions: Optional[str] | Omit = omit, previous_response_id: Optional[str] | Omit = omit, prompt_cache_key: Optional[str] | Omit = omit, + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1723,6 +1724,8 @@ def compact( prompt_cache_key: A key to use when reading from or writing to the prompt cache. + prompt_cache_retention: How long to retain a prompt cache entry created by this request. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -1740,6 +1743,7 @@ def compact( "instructions": instructions, "previous_response_id": previous_response_id, "prompt_cache_key": prompt_cache_key, + "prompt_cache_retention": prompt_cache_retention, }, response_compact_params.ResponseCompactParams, ), @@ -3367,6 +3371,7 @@ async def compact( instructions: Optional[str] | Omit = omit, previous_response_id: Optional[str] | Omit = omit, prompt_cache_key: Optional[str] | Omit = omit, + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -3404,6 +3409,8 @@ async def compact( prompt_cache_key: A key to use when reading from or writing to the prompt cache. + prompt_cache_retention: How long to retain a prompt cache entry created by this request. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -3421,6 +3428,7 @@ async def compact( "instructions": instructions, "previous_response_id": previous_response_id, "prompt_cache_key": prompt_cache_key, + "prompt_cache_retention": prompt_cache_retention, }, response_compact_params.ResponseCompactParams, ), diff --git a/src/openai/types/responses/response_compact_params.py b/src/openai/types/responses/response_compact_params.py index 0b163a9e78..2575438b34 100644 --- a/src/openai/types/responses/response_compact_params.py +++ b/src/openai/types/responses/response_compact_params.py @@ -140,3 +140,6 @@ class ResponseCompactParams(TypedDict, total=False): prompt_cache_key: Optional[str] """A key to use when reading from or writing to the prompt cache.""" + + prompt_cache_retention: Optional[Literal["in_memory", "24h"]] + """How long to retain a prompt cache entry created by this request.""" diff --git a/tests/api_resources/test_responses.py b/tests/api_resources/test_responses.py index 096b983be2..40405f61b2 100644 --- a/tests/api_resources/test_responses.py +++ b/tests/api_resources/test_responses.py @@ -388,6 +388,7 @@ def test_method_compact_with_all_params(self, client: OpenAI) -> None: instructions="instructions", previous_response_id="resp_123", prompt_cache_key="prompt_cache_key", + prompt_cache_retention="in_memory", ) assert_matches_type(CompactedResponse, response, path=["response"]) @@ -799,6 +800,7 @@ async def test_method_compact_with_all_params(self, async_client: AsyncOpenAI) - instructions="instructions", previous_response_id="resp_123", prompt_cache_key="prompt_cache_key", + prompt_cache_retention="in_memory", ) assert_matches_type(CompactedResponse, response, path=["response"]) From cb63de72923d89de4ba870e329038f99e10eb9dd Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 16 Apr 2026 19:50:54 +0000 Subject: [PATCH 683/769] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 60efa98d0f..9a106e0f6d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 152 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-64c6ba619ccbf87e56b4f464230d04401fd78ad924d2606176309d19ca281af5.yml openapi_spec_hash: 5e4f2073040a12c26ce58e86a72fe47e -config_hash: 1a88b104658b6c854117996c080ebe6b +config_hash: 50c98d8869a8cfdee2ab7dc664c4b6fe From c5b099cf9f08e2b0cda02a68f8cbfadbc35da4de Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 28 Apr 2026 06:02:46 +0000 Subject: [PATCH 684/769] release: 2.33.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 18 ++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 527d2e30b0..7ef8288ed5 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.32.0" + ".": "2.33.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 2640bc3d63..effb1cc263 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ # Changelog +## 2.33.0 (2026-04-28) + +Full Changelog: [v2.32.0...v2.33.0](https://github.com/openai/openai-python/compare/v2.32.0...v2.33.0) + +### Features + +* **api:** api update ([18f834a](https://github.com/openai/openai-python/commit/18f834a54f92ea827452471a46a4f442f251e2c8)) + + +### Bug Fixes + +* **api:** correct prompt_cache_retention enum value from in-memory to in_memory ([#1822](https://github.com/openai/openai-python/issues/1822)) ([f9d2d13](https://github.com/openai/openai-python/commit/f9d2d1359688a6247ecba858fc687173c480c9c8)) + + +### Chores + +* **ci:** remove release-doctor workflow ([00b2091](https://github.com/openai/openai-python/commit/00b20910e3539842f21d86ab5928fb5216d3a765)) + ## 2.32.0 (2026-04-15) Full Changelog: [v2.31.0...v2.32.0](https://github.com/openai/openai-python/compare/v2.31.0...v2.32.0) diff --git a/pyproject.toml b/pyproject.toml index d0d533e8a6..b2f4dd11cb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.32.0" +version = "2.33.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 a98695ba0e..b73f7aa7bd 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__ = "2.32.0" # x-release-please-version +__version__ = "2.33.0" # x-release-please-version From 7912497291fb075fe6c688dadfed4825d7bd89d2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 28 Apr 2026 15:51:31 +0000 Subject: [PATCH 685/769] perf(client): optimize file structure copying in multipart requests --- src/openai/_files.py | 56 ++++++++++- src/openai/_utils/__init__.py | 1 - src/openai/_utils/_utils.py | 15 --- src/openai/resources/audio/transcriptions.py | 13 ++- src/openai/resources/audio/translations.py | 13 ++- .../resources/containers/files/files.py | 13 ++- src/openai/resources/files.py | 13 ++- src/openai/resources/images.py | 23 +++-- src/openai/resources/skills/skills.py | 7 +- .../resources/skills/versions/versions.py | 13 ++- src/openai/resources/uploads/parts.py | 7 +- src/openai/resources/videos.py | 43 ++++---- tests/test_deepcopy.py | 58 ----------- tests/test_files.py | 99 ++++++++++++++++++- 14 files changed, 239 insertions(+), 135 deletions(-) delete mode 100644 tests/test_deepcopy.py diff --git a/src/openai/_files.py b/src/openai/_files.py index 7b23ca084a..4cc4f35d8f 100644 --- a/src/openai/_files.py +++ b/src/openai/_files.py @@ -3,8 +3,8 @@ import io import os import pathlib -from typing import overload -from typing_extensions import TypeGuard +from typing import Sequence, cast, overload +from typing_extensions import TypeVar, TypeGuard import anyio @@ -17,7 +17,9 @@ HttpxFileContent, HttpxRequestFiles, ) -from ._utils import is_tuple_t, is_mapping_t, is_sequence_t +from ._utils import is_list, is_mapping, is_tuple_t, is_mapping_t, is_sequence_t + +_T = TypeVar("_T") def is_base64_file_input(obj: object) -> TypeGuard[Base64FileInput]: @@ -121,3 +123,51 @@ async def async_read_file_content(file: FileContent) -> HttpxFileContent: return await anyio.Path(file).read_bytes() return file + + +def deepcopy_with_paths(item: _T, paths: Sequence[Sequence[str]]) -> _T: + """Copy only the containers along the given paths. + + Used to guard against mutation by extract_files without copying the entire structure. + Only dicts and lists that lie on a path are copied; everything else + is returned by reference. + + For example, given paths=[["foo", "files", "file"]] and the structure: + { + "foo": { + "bar": {"baz": {}}, + "files": {"file": } + } + } + The root dict, "foo", and "files" are copied (they lie on the path). + "bar" and "baz" are returned by reference (off the path). + """ + return _deepcopy_with_paths(item, paths, 0) + + +def _deepcopy_with_paths(item: _T, paths: Sequence[Sequence[str]], index: int) -> _T: + if not paths: + return item + if is_mapping(item): + key_to_paths: dict[str, list[Sequence[str]]] = {} + for path in paths: + if index < len(path): + key_to_paths.setdefault(path[index], []).append(path) + + # if no path continues through this mapping, it won't be mutated and copying it is redundant + if not key_to_paths: + return item + + result = dict(item) + for key, subpaths in key_to_paths.items(): + if key in result: + result[key] = _deepcopy_with_paths(result[key], subpaths, index + 1) + return cast(_T, result) + if is_list(item): + array_paths = [path for path in paths if index < len(path) and path[index] == ""] + + # if no path expects a list here, nothing will be mutated inside it - return by reference + if not array_paths: + return cast(_T, item) + return cast(_T, [_deepcopy_with_paths(entry, array_paths, index + 1) for entry in item]) + return item diff --git a/src/openai/_utils/__init__.py b/src/openai/_utils/__init__.py index 52853aaf03..bbd79691fa 100644 --- a/src/openai/_utils/__init__.py +++ b/src/openai/_utils/__init__.py @@ -26,7 +26,6 @@ file_from_path as file_from_path, is_azure_client as is_azure_client, strip_not_given as strip_not_given, - deepcopy_minimal as deepcopy_minimal, get_async_library as get_async_library, maybe_coerce_float as maybe_coerce_float, get_required_header as get_required_header, diff --git a/src/openai/_utils/_utils.py b/src/openai/_utils/_utils.py index b1e8e0d041..e18fb09bee 100644 --- a/src/openai/_utils/_utils.py +++ b/src/openai/_utils/_utils.py @@ -181,21 +181,6 @@ def is_iterable(obj: object) -> TypeGuard[Iterable[object]]: return isinstance(obj, Iterable) -def deepcopy_minimal(item: _T) -> _T: - """Minimal reimplementation of copy.deepcopy() that will only copy certain object types: - - - mappings, e.g. `dict` - - list - - This is done for performance reasons. - """ - if is_mapping(item): - return cast(_T, {k: deepcopy_minimal(v) for k, v in item.items()}) - if is_list(item): - return cast(_T, [deepcopy_minimal(entry) for entry in item]) - return item - - # copied from https://github.com/Rapptz/RoboDanny def human_join(seq: Sequence[str], *, delim: str = ", ", final: str = "or") -> str: size = len(seq) diff --git a/src/openai/resources/audio/transcriptions.py b/src/openai/resources/audio/transcriptions.py index 25e6e0cb5e..e5f415f278 100644 --- a/src/openai/resources/audio/transcriptions.py +++ b/src/openai/resources/audio/transcriptions.py @@ -9,6 +9,7 @@ import httpx from ... import _legacy_response +from ..._files import deepcopy_with_paths from ..._types import ( Body, Omit, @@ -20,7 +21,7 @@ omit, not_given, ) -from ..._utils import extract_files, required_args, maybe_transform, deepcopy_minimal, async_maybe_transform +from ..._utils import extract_files, required_args, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -459,7 +460,7 @@ def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> str | Transcription | TranscriptionDiarized | TranscriptionVerbose | Stream[TranscriptionStreamEvent]: - body = deepcopy_minimal( + body = deepcopy_with_paths( { "file": file, "model": model, @@ -473,7 +474,8 @@ def create( "stream": stream, "temperature": temperature, "timestamp_granularities": timestamp_granularities, - } + }, + [["file"]], ) files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) # It should be noted that the actual Content-Type header that will be @@ -913,7 +915,7 @@ async def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Transcription | TranscriptionVerbose | TranscriptionDiarized | str | AsyncStream[TranscriptionStreamEvent]: - body = deepcopy_minimal( + body = deepcopy_with_paths( { "file": file, "model": model, @@ -927,7 +929,8 @@ async def create( "stream": stream, "temperature": temperature, "timestamp_granularities": timestamp_granularities, - } + }, + [["file"]], ) files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) # It should be noted that the actual Content-Type header that will be diff --git a/src/openai/resources/audio/translations.py b/src/openai/resources/audio/translations.py index 0751a65586..d6df25c1b7 100644 --- a/src/openai/resources/audio/translations.py +++ b/src/openai/resources/audio/translations.py @@ -9,8 +9,9 @@ import httpx from ... import _legacy_response +from ..._files import deepcopy_with_paths from ..._types import Body, Omit, Query, Headers, NotGiven, FileTypes, omit, not_given -from ..._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform +from ..._utils import extract_files, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -146,14 +147,15 @@ def create( timeout: Override the client-level default timeout for this request, in seconds """ - body = deepcopy_minimal( + body = deepcopy_with_paths( { "file": file, "model": model, "prompt": prompt, "response_format": response_format, "temperature": temperature, - } + }, + [["file"]], ) files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) # It should be noted that the actual Content-Type header that will be @@ -291,14 +293,15 @@ async def create( timeout: Override the client-level default timeout for this request, in seconds """ - body = deepcopy_minimal( + body = deepcopy_with_paths( { "file": file, "model": model, "prompt": prompt, "response_format": response_format, "temperature": temperature, - } + }, + [["file"]], ) files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) # It should be noted that the actual Content-Type header that will be diff --git a/src/openai/resources/containers/files/files.py b/src/openai/resources/containers/files/files.py index f48adf3a2a..80e0d61e0a 100644 --- a/src/openai/resources/containers/files/files.py +++ b/src/openai/resources/containers/files/files.py @@ -16,8 +16,9 @@ ContentWithStreamingResponse, AsyncContentWithStreamingResponse, ) +from ...._files import deepcopy_with_paths from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, FileTypes, omit, not_given -from ...._utils import extract_files, path_template, maybe_transform, deepcopy_minimal, async_maybe_transform +from ...._utils import extract_files, path_template, maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -89,11 +90,12 @@ def create( """ if not container_id: raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") - body = deepcopy_minimal( + body = deepcopy_with_paths( { "file": file, "file_id": file_id, - } + }, + [["file"]], ) files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) if files: @@ -303,11 +305,12 @@ async def create( """ if not container_id: raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") - body = deepcopy_minimal( + body = deepcopy_with_paths( { "file": file, "file_id": file_id, - } + }, + [["file"]], ) files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) if files: diff --git a/src/openai/resources/files.py b/src/openai/resources/files.py index b03f11b06a..0cc6b046ff 100644 --- a/src/openai/resources/files.py +++ b/src/openai/resources/files.py @@ -11,8 +11,9 @@ from .. import _legacy_response from ..types import FilePurpose, file_list_params, file_create_params +from .._files import deepcopy_with_paths from .._types import Body, Omit, Query, Headers, NotGiven, FileTypes, omit, not_given -from .._utils import extract_files, path_template, maybe_transform, deepcopy_minimal, async_maybe_transform +from .._utils import extract_files, path_template, maybe_transform, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import ( @@ -116,12 +117,13 @@ def create( timeout: Override the client-level default timeout for this request, in seconds """ - body = deepcopy_minimal( + body = deepcopy_with_paths( { "file": file, "purpose": purpose, "expires_after": expires_after, - } + }, + [["file"]], ) files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) # It should be noted that the actual Content-Type header that will be @@ -441,12 +443,13 @@ async def create( timeout: Override the client-level default timeout for this request, in seconds """ - body = deepcopy_minimal( + body = deepcopy_with_paths( { "file": file, "purpose": purpose, "expires_after": expires_after, - } + }, + [["file"]], ) files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) # It should be noted that the actual Content-Type header that will be diff --git a/src/openai/resources/images.py b/src/openai/resources/images.py index 6959c2aeff..2555b6c5db 100644 --- a/src/openai/resources/images.py +++ b/src/openai/resources/images.py @@ -9,8 +9,9 @@ from .. import _legacy_response from ..types import image_edit_params, image_generate_params, image_create_variation_params +from .._files import deepcopy_with_paths from .._types import Body, Omit, Query, Headers, NotGiven, FileTypes, SequenceNotStr, omit, not_given -from .._utils import extract_files, required_args, maybe_transform, deepcopy_minimal, async_maybe_transform +from .._utils import extract_files, required_args, maybe_transform, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -94,7 +95,7 @@ def create_variation( timeout: Override the client-level default timeout for this request, in seconds """ - body = deepcopy_minimal( + body = deepcopy_with_paths( { "image": image, "model": model, @@ -102,7 +103,8 @@ def create_variation( "response_format": response_format, "size": size, "user": user, - } + }, + [["image"]], ) files = extract_files(cast(Mapping[str, object], body), paths=[["image"]]) # It should be noted that the actual Content-Type header that will be @@ -484,7 +486,7 @@ def edit( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ImagesResponse | Stream[ImageEditStreamEvent]: - body = deepcopy_minimal( + body = deepcopy_with_paths( { "image": image, "prompt": prompt, @@ -501,7 +503,8 @@ def edit( "size": size, "stream": stream, "user": user, - } + }, + [["image"], ["image", ""], ["mask"]], ) files = extract_files(cast(Mapping[str, object], body), paths=[["image"], ["image", ""], ["mask"]]) # It should be noted that the actual Content-Type header that will be @@ -986,7 +989,7 @@ async def create_variation( timeout: Override the client-level default timeout for this request, in seconds """ - body = deepcopy_minimal( + body = deepcopy_with_paths( { "image": image, "model": model, @@ -994,7 +997,8 @@ async def create_variation( "response_format": response_format, "size": size, "user": user, - } + }, + [["image"]], ) files = extract_files(cast(Mapping[str, object], body), paths=[["image"]]) # It should be noted that the actual Content-Type header that will be @@ -1376,7 +1380,7 @@ async def edit( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ImagesResponse | AsyncStream[ImageEditStreamEvent]: - body = deepcopy_minimal( + body = deepcopy_with_paths( { "image": image, "prompt": prompt, @@ -1393,7 +1397,8 @@ async def edit( "size": size, "stream": stream, "user": user, - } + }, + [["image"], ["image", ""], ["mask"]], ) files = extract_files(cast(Mapping[str, object], body), paths=[["image"], ["image", ""], ["mask"]]) # It should be noted that the actual Content-Type header that will be diff --git a/src/openai/resources/skills/skills.py b/src/openai/resources/skills/skills.py index f44fb24607..764ed65e84 100644 --- a/src/openai/resources/skills/skills.py +++ b/src/openai/resources/skills/skills.py @@ -17,6 +17,7 @@ ContentWithStreamingResponse, AsyncContentWithStreamingResponse, ) +from ..._files import deepcopy_with_paths from ..._types import ( Body, Omit, @@ -28,7 +29,7 @@ omit, not_given, ) -from ..._utils import extract_files, path_template, maybe_transform, deepcopy_minimal, async_maybe_transform +from ..._utils import extract_files, path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -101,7 +102,7 @@ def create( timeout: Override the client-level default timeout for this request, in seconds """ - body = deepcopy_minimal({"files": files}) + body = deepcopy_with_paths({"files": files}, [["files", ""], ["files"]]) extracted_files = extract_files(cast(Mapping[str, object], body), paths=[["files", ""], ["files"]]) if extracted_files: # It should be noted that the actual Content-Type header that will be @@ -327,7 +328,7 @@ async def create( timeout: Override the client-level default timeout for this request, in seconds """ - body = deepcopy_minimal({"files": files}) + body = deepcopy_with_paths({"files": files}, [["files", ""], ["files"]]) extracted_files = extract_files(cast(Mapping[str, object], body), paths=[["files", ""], ["files"]]) if extracted_files: # It should be noted that the actual Content-Type header that will be diff --git a/src/openai/resources/skills/versions/versions.py b/src/openai/resources/skills/versions/versions.py index 8b48075cc3..2259306a86 100644 --- a/src/openai/resources/skills/versions/versions.py +++ b/src/openai/resources/skills/versions/versions.py @@ -16,6 +16,7 @@ ContentWithStreamingResponse, AsyncContentWithStreamingResponse, ) +from ...._files import deepcopy_with_paths from ...._types import ( Body, Omit, @@ -27,7 +28,7 @@ omit, not_given, ) -from ...._utils import extract_files, path_template, maybe_transform, deepcopy_minimal, async_maybe_transform +from ...._utils import extract_files, path_template, maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -95,11 +96,12 @@ def create( """ if not skill_id: raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") - body = deepcopy_minimal( + body = deepcopy_with_paths( { "default": default, "files": files, - } + }, + [["files", ""], ["files"]], ) extracted_files = extract_files(cast(Mapping[str, object], body), paths=[["files", ""], ["files"]]) if extracted_files: @@ -303,11 +305,12 @@ async def create( """ if not skill_id: raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") - body = deepcopy_minimal( + body = deepcopy_with_paths( { "default": default, "files": files, - } + }, + [["files", ""], ["files"]], ) extracted_files = extract_files(cast(Mapping[str, object], body), paths=[["files", ""], ["files"]]) if extracted_files: diff --git a/src/openai/resources/uploads/parts.py b/src/openai/resources/uploads/parts.py index cf09eea75e..3891fc028c 100644 --- a/src/openai/resources/uploads/parts.py +++ b/src/openai/resources/uploads/parts.py @@ -7,8 +7,9 @@ import httpx from ... import _legacy_response +from ..._files import deepcopy_with_paths from ..._types import Body, Query, Headers, NotGiven, FileTypes, not_given -from ..._utils import extract_files, path_template, maybe_transform, deepcopy_minimal, async_maybe_transform +from ..._utils import extract_files, path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -79,7 +80,7 @@ def create( """ if not upload_id: raise ValueError(f"Expected a non-empty value for `upload_id` but received {upload_id!r}") - body = deepcopy_minimal({"data": data}) + body = deepcopy_with_paths({"data": data}, [["data"]]) files = extract_files(cast(Mapping[str, object], body), paths=[["data"]]) # It should be noted that the actual Content-Type header that will be # sent to the server will contain a `boundary` parameter, e.g. @@ -156,7 +157,7 @@ async def create( """ if not upload_id: raise ValueError(f"Expected a non-empty value for `upload_id` but received {upload_id!r}") - body = deepcopy_minimal({"data": data}) + body = deepcopy_with_paths({"data": data}, [["data"]]) files = extract_files(cast(Mapping[str, object], body), paths=[["data"]]) # It should be noted that the actual Content-Type header that will be # sent to the server will contain a `boundary` parameter, e.g. diff --git a/src/openai/resources/videos.py b/src/openai/resources/videos.py index a006e64705..3b80400cac 100644 --- a/src/openai/resources/videos.py +++ b/src/openai/resources/videos.py @@ -19,8 +19,9 @@ video_create_character_params, video_download_content_params, ) +from .._files import deepcopy_with_paths from .._types import Body, Omit, Query, Headers, NotGiven, FileTypes, omit, not_given -from .._utils import extract_files, path_template, maybe_transform, deepcopy_minimal, async_maybe_transform +from .._utils import extract_files, path_template, maybe_transform, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import ( @@ -104,14 +105,15 @@ def create( timeout: Override the client-level default timeout for this request, in seconds """ - body = deepcopy_minimal( + body = deepcopy_with_paths( { "prompt": prompt, "input_reference": input_reference, "model": model, "seconds": seconds, "size": size, - } + }, + [["input_reference"]], ) files = extract_files(cast(Mapping[str, object], body), paths=[["input_reference"]]) # It should be noted that the actual Content-Type header that will be @@ -347,11 +349,12 @@ def create_character( timeout: Override the client-level default timeout for this request, in seconds """ - body = deepcopy_minimal( + body = deepcopy_with_paths( { "name": name, "video": video, - } + }, + [["video"]], ) files = extract_files(cast(Mapping[str, object], body), paths=[["video"]]) # It should be noted that the actual Content-Type header that will be @@ -440,11 +443,12 @@ def edit( timeout: Override the client-level default timeout for this request, in seconds """ - body = deepcopy_minimal( + body = deepcopy_with_paths( { "prompt": prompt, "video": video, - } + }, + [["video"]], ) files = extract_files(cast(Mapping[str, object], body), paths=[["video"]]) # It should be noted that the actual Content-Type header that will be @@ -493,12 +497,13 @@ def extend( timeout: Override the client-level default timeout for this request, in seconds """ - body = deepcopy_minimal( + body = deepcopy_with_paths( { "prompt": prompt, "seconds": seconds, "video": video, - } + }, + [["video"]], ) files = extract_files(cast(Mapping[str, object], body), paths=[["video"]]) # It should be noted that the actual Content-Type header that will be @@ -645,14 +650,15 @@ async def create( timeout: Override the client-level default timeout for this request, in seconds """ - body = deepcopy_minimal( + body = deepcopy_with_paths( { "prompt": prompt, "input_reference": input_reference, "model": model, "seconds": seconds, "size": size, - } + }, + [["input_reference"]], ) files = extract_files(cast(Mapping[str, object], body), paths=[["input_reference"]]) # It should be noted that the actual Content-Type header that will be @@ -888,11 +894,12 @@ async def create_character( timeout: Override the client-level default timeout for this request, in seconds """ - body = deepcopy_minimal( + body = deepcopy_with_paths( { "name": name, "video": video, - } + }, + [["video"]], ) files = extract_files(cast(Mapping[str, object], body), paths=[["video"]]) # It should be noted that the actual Content-Type header that will be @@ -983,11 +990,12 @@ async def edit( timeout: Override the client-level default timeout for this request, in seconds """ - body = deepcopy_minimal( + body = deepcopy_with_paths( { "prompt": prompt, "video": video, - } + }, + [["video"]], ) files = extract_files(cast(Mapping[str, object], body), paths=[["video"]]) # It should be noted that the actual Content-Type header that will be @@ -1036,12 +1044,13 @@ async def extend( timeout: Override the client-level default timeout for this request, in seconds """ - body = deepcopy_minimal( + body = deepcopy_with_paths( { "prompt": prompt, "seconds": seconds, "video": video, - } + }, + [["video"]], ) files = extract_files(cast(Mapping[str, object], body), paths=[["video"]]) # It should be noted that the actual Content-Type header that will be diff --git a/tests/test_deepcopy.py b/tests/test_deepcopy.py deleted file mode 100644 index 86a2adb1a2..0000000000 --- a/tests/test_deepcopy.py +++ /dev/null @@ -1,58 +0,0 @@ -from openai._utils import deepcopy_minimal - - -def assert_different_identities(obj1: object, obj2: object) -> None: - assert obj1 == obj2 - assert id(obj1) != id(obj2) - - -def test_simple_dict() -> None: - obj1 = {"foo": "bar"} - obj2 = deepcopy_minimal(obj1) - assert_different_identities(obj1, obj2) - - -def test_nested_dict() -> None: - obj1 = {"foo": {"bar": True}} - obj2 = deepcopy_minimal(obj1) - assert_different_identities(obj1, obj2) - assert_different_identities(obj1["foo"], obj2["foo"]) - - -def test_complex_nested_dict() -> None: - obj1 = {"foo": {"bar": [{"hello": "world"}]}} - obj2 = deepcopy_minimal(obj1) - assert_different_identities(obj1, obj2) - assert_different_identities(obj1["foo"], obj2["foo"]) - assert_different_identities(obj1["foo"]["bar"], obj2["foo"]["bar"]) - assert_different_identities(obj1["foo"]["bar"][0], obj2["foo"]["bar"][0]) - - -def test_simple_list() -> None: - obj1 = ["a", "b", "c"] - obj2 = deepcopy_minimal(obj1) - assert_different_identities(obj1, obj2) - - -def test_nested_list() -> None: - obj1 = ["a", [1, 2, 3]] - obj2 = deepcopy_minimal(obj1) - assert_different_identities(obj1, obj2) - assert_different_identities(obj1[1], obj2[1]) - - -class MyObject: ... - - -def test_ignores_other_types() -> None: - # custom classes - my_obj = MyObject() - obj1 = {"foo": my_obj} - obj2 = deepcopy_minimal(obj1) - assert_different_identities(obj1, obj2) - assert obj1["foo"] is my_obj - - # tuples - obj3 = ("a", "b") - obj4 = deepcopy_minimal(obj3) - assert obj3 is obj4 diff --git a/tests/test_files.py b/tests/test_files.py index 15d5c6a811..3d3851f5f8 100644 --- a/tests/test_files.py +++ b/tests/test_files.py @@ -4,7 +4,8 @@ import pytest from dirty_equals import IsDict, IsList, IsBytes, IsTuple -from openai._files import to_httpx_files, async_to_httpx_files +from openai._files import to_httpx_files, deepcopy_with_paths, async_to_httpx_files +from openai._utils import extract_files readme_path = Path(__file__).parent.parent.joinpath("README.md") @@ -49,3 +50,99 @@ def test_string_not_allowed() -> None: "file": "foo", # type: ignore } ) + + +def assert_different_identities(obj1: object, obj2: object) -> None: + assert obj1 == obj2 + assert obj1 is not obj2 + + +class TestDeepcopyWithPaths: + def test_copies_top_level_dict(self) -> None: + original = {"file": b"data", "other": "value"} + result = deepcopy_with_paths(original, [["file"]]) + assert_different_identities(result, original) + + def test_file_value_is_same_reference(self) -> None: + file_bytes = b"contents" + original = {"file": file_bytes} + result = deepcopy_with_paths(original, [["file"]]) + assert_different_identities(result, original) + assert result["file"] is file_bytes + + def test_list_popped_wholesale(self) -> None: + files = [b"f1", b"f2"] + original = {"files": files, "title": "t"} + result = deepcopy_with_paths(original, [["files", ""]]) + assert_different_identities(result, original) + result_files = result["files"] + assert isinstance(result_files, list) + assert_different_identities(result_files, files) + + def test_nested_array_path_copies_list_and_elements(self) -> None: + elem1 = {"file": b"f1", "extra": 1} + elem2 = {"file": b"f2", "extra": 2} + original = {"items": [elem1, elem2]} + result = deepcopy_with_paths(original, [["items", "", "file"]]) + assert_different_identities(result, original) + result_items = result["items"] + assert isinstance(result_items, list) + assert_different_identities(result_items, original["items"]) + assert_different_identities(result_items[0], elem1) + assert_different_identities(result_items[1], elem2) + + def test_empty_paths_returns_same_object(self) -> None: + original = {"foo": "bar"} + result = deepcopy_with_paths(original, []) + assert result is original + + def test_multiple_paths(self) -> None: + f1 = b"file1" + f2 = b"file2" + original = {"a": f1, "b": f2, "c": "unchanged"} + result = deepcopy_with_paths(original, [["a"], ["b"]]) + assert_different_identities(result, original) + assert result["a"] is f1 + assert result["b"] is f2 + assert result["c"] is original["c"] + + def test_extract_files_does_not_mutate_original_top_level(self) -> None: + file_bytes = b"contents" + original = {"file": file_bytes, "other": "value"} + + copied = deepcopy_with_paths(original, [["file"]]) + extracted = extract_files(copied, paths=[["file"]]) + + assert extracted == [("file", file_bytes)] + assert original == {"file": file_bytes, "other": "value"} + assert copied == {"other": "value"} + + def test_extract_files_does_not_mutate_original_nested_array_path(self) -> None: + file1 = b"f1" + file2 = b"f2" + original = { + "items": [ + {"file": file1, "extra": 1}, + {"file": file2, "extra": 2}, + ], + "title": "example", + } + + copied = deepcopy_with_paths(original, [["items", "", "file"]]) + extracted = extract_files(copied, paths=[["items", "", "file"]]) + + assert extracted == [("items[][file]", file1), ("items[][file]", file2)] + assert original == { + "items": [ + {"file": file1, "extra": 1}, + {"file": file2, "extra": 2}, + ], + "title": "example", + } + assert copied == { + "items": [ + {"extra": 1}, + {"extra": 2}, + ], + "title": "example", + } From 3390091c751ee61a5f789fd6c6f3fb154ad55c39 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 19:50:25 +0000 Subject: [PATCH 686/769] chore(tests): bump steady to v0.22.1 --- scripts/mock | 6 +++--- scripts/test | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/mock b/scripts/mock index 886f2ffc14..04d29019fc 100755 --- a/scripts/mock +++ b/scripts/mock @@ -22,9 +22,9 @@ echo "==> Starting mock server with URL ${URL}" # Run steady mock on the given spec if [ "$1" == "--daemon" ]; then # Pre-install the package so the download doesn't eat into the startup timeout - npm exec --package=@stdy/cli@0.20.2 -- steady --version + npm exec --package=@stdy/cli@0.22.1 -- steady --version - npm exec --package=@stdy/cli@0.20.2 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=brackets --validator-form-array-format=brackets --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" &> .stdy.log & + npm exec --package=@stdy/cli@0.22.1 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=brackets --validator-form-array-format=brackets --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" &> .stdy.log & # Wait for server to come online via health endpoint (max 30s) echo -n "Waiting for server" @@ -48,5 +48,5 @@ if [ "$1" == "--daemon" ]; then echo else - npm exec --package=@stdy/cli@0.20.2 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=brackets --validator-form-array-format=brackets --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" + npm exec --package=@stdy/cli@0.22.1 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=brackets --validator-form-array-format=brackets --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" fi diff --git a/scripts/test b/scripts/test index 57cabda6ae..7b05e44fd9 100755 --- a/scripts/test +++ b/scripts/test @@ -43,7 +43,7 @@ elif ! steady_is_running ; then echo -e "To run the server, pass in the path or url of your OpenAPI" echo -e "spec to the steady command:" echo - echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.20.2 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-query-array-format=brackets --validator-form-array-format=brackets --validator-query-object-format=brackets --validator-form-object-format=brackets${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.22.1 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-query-array-format=brackets --validator-form-array-format=brackets --validator-query-object-format=brackets --validator-form-object-format=brackets${NC}" echo exit 1 From e5cad0908da34eb998d8c4b1d9a131f2207121cf Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 22 Apr 2026 13:58:48 +0000 Subject: [PATCH 687/769] chore(internal): more robust bootstrap script --- scripts/bootstrap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/bootstrap b/scripts/bootstrap index 953993addb..3e25ebec99 100755 --- a/scripts/bootstrap +++ b/scripts/bootstrap @@ -4,7 +4,7 @@ set -e cd "$(dirname "$0")/.." -if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "$SKIP_BREW" != "1" ] && [ -t 0 ]; then +if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "${SKIP_BREW:-}" != "1" ] && [ -t 0 ]; then brew bundle check >/dev/null 2>&1 || { echo -n "==> Install Homebrew dependencies? (y/N): " read -r response From cefadc522446e8f656a867250aef1300cc04fd07 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 22 Apr 2026 16:21:41 +0000 Subject: [PATCH 688/769] fix(api): correct prompt_cache_retention enum value from in-memory to in_memory --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 9a106e0f6d..fc7d71ecd5 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 152 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-64c6ba619ccbf87e56b4f464230d04401fd78ad924d2606176309d19ca281af5.yml -openapi_spec_hash: 5e4f2073040a12c26ce58e86a72fe47e +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-bbf1d88b9b565b893dcae280be68848dc1518ecb65e009d1e94c9f0e5ecaacb2.yml +openapi_spec_hash: 0757a960c980e26cc813615d6823bfd5 config_hash: 50c98d8869a8cfdee2ab7dc664c4b6fe From e92f5609e180ffef33b640863d76ecee0d2808ed Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 22 Apr 2026 20:39:40 +0000 Subject: [PATCH 689/769] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index fc7d71ecd5..8dd709a65e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 152 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-bbf1d88b9b565b893dcae280be68848dc1518ecb65e009d1e94c9f0e5ecaacb2.yml openapi_spec_hash: 0757a960c980e26cc813615d6823bfd5 -config_hash: 50c98d8869a8cfdee2ab7dc664c4b6fe +config_hash: 6d772efaf4dd9acfe40be2855124118d From 1c2cef5ceacc9ccbc7ccb1d62f0463bc8fe96703 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 22 Apr 2026 21:13:31 +0000 Subject: [PATCH 690/769] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 8dd709a65e..0908a17fe9 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 152 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-bbf1d88b9b565b893dcae280be68848dc1518ecb65e009d1e94c9f0e5ecaacb2.yml openapi_spec_hash: 0757a960c980e26cc813615d6823bfd5 -config_hash: 6d772efaf4dd9acfe40be2855124118d +config_hash: 1d3eb2a6fc36f206d2d67bfcf1a7080d From f9dcd90d8de1689cdf9f0ed6a9f31115562b6984 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 27 Apr 2026 15:00:02 +0000 Subject: [PATCH 691/769] fix: use correct field name format for multipart file arrays --- src/openai/_qs.py | 8 ++----- src/openai/_types.py | 3 +++ src/openai/_utils/_utils.py | 42 ++++++++++++++++++++++++++++++------- tests/test_extract_files.py | 28 ++++++++++++++++++++----- tests/test_files.py | 2 +- 5 files changed, 63 insertions(+), 20 deletions(-) diff --git a/src/openai/_qs.py b/src/openai/_qs.py index de8c99bc63..4127c19c62 100644 --- a/src/openai/_qs.py +++ b/src/openai/_qs.py @@ -2,17 +2,13 @@ from typing import Any, List, Tuple, Union, Mapping, TypeVar from urllib.parse import parse_qs, urlencode -from typing_extensions import Literal, get_args +from typing_extensions import get_args -from ._types import NotGiven, not_given +from ._types import NotGiven, ArrayFormat, NestedFormat, not_given from ._utils import flatten _T = TypeVar("_T") - -ArrayFormat = Literal["comma", "repeat", "indices", "brackets"] -NestedFormat = Literal["dots", "brackets"] - PrimitiveData = Union[str, int, float, bool, None] # this should be Data = Union[PrimitiveData, "List[Data]", "Tuple[Data]", "Mapping[str, Data]"] # https://github.com/microsoft/pyright/issues/3555 diff --git a/src/openai/_types.py b/src/openai/_types.py index c55c6f808d..680a74ddb6 100644 --- a/src/openai/_types.py +++ b/src/openai/_types.py @@ -48,6 +48,9 @@ ModelT = TypeVar("ModelT", bound=pydantic.BaseModel) _T = TypeVar("_T") +ArrayFormat = Literal["comma", "repeat", "indices", "brackets"] +NestedFormat = Literal["dots", "brackets"] + # Approximates httpx internal ProxiesTypes and RequestFiles types # while adding support for `PathLike` instances diff --git a/src/openai/_utils/_utils.py b/src/openai/_utils/_utils.py index e18fb09bee..9f7401ca83 100644 --- a/src/openai/_utils/_utils.py +++ b/src/openai/_utils/_utils.py @@ -18,11 +18,11 @@ ) from pathlib import Path from datetime import date, datetime -from typing_extensions import TypeGuard +from typing_extensions import TypeGuard, get_args import sniffio -from .._types import Omit, NotGiven, FileTypes, HeadersLike +from .._types import Omit, NotGiven, FileTypes, ArrayFormat, HeadersLike _T = TypeVar("_T") _TupleT = TypeVar("_TupleT", bound=Tuple[object, ...]) @@ -44,25 +44,45 @@ def extract_files( query: Mapping[str, object], *, paths: Sequence[Sequence[str]], + array_format: ArrayFormat = "brackets", ) -> list[tuple[str, FileTypes]]: """Recursively extract files from the given dictionary based on specified paths. A path may look like this ['foo', 'files', '', 'data']. + ``array_format`` controls how ```` segments contribute to the emitted + field name. Supported values: ``"brackets"`` (``foo[]``), ``"repeat"`` and + ``"comma"`` (``foo``), ``"indices"`` (``foo[0]``, ``foo[1]``). + Note: this mutates the given dictionary. """ files: list[tuple[str, FileTypes]] = [] for path in paths: - files.extend(_extract_items(query, path, index=0, flattened_key=None)) + files.extend(_extract_items(query, path, index=0, flattened_key=None, array_format=array_format)) return files +def _array_suffix(array_format: ArrayFormat, array_index: int) -> str: + if array_format == "brackets": + return "[]" + if array_format == "indices": + return f"[{array_index}]" + if array_format == "repeat" or array_format == "comma": + # Both repeat the bare field name for each file part; there is no + # meaningful way to comma-join binary parts. + return "" + raise NotImplementedError( + f"Unknown array_format value: {array_format}, choose from {', '.join(get_args(ArrayFormat))}" + ) + + def _extract_items( obj: object, path: Sequence[str], *, index: int, flattened_key: str | None, + array_format: ArrayFormat, ) -> list[tuple[str, FileTypes]]: try: key = path[index] @@ -79,9 +99,11 @@ def _extract_items( if is_list(obj): files: list[tuple[str, FileTypes]] = [] - for entry in obj: - assert_is_file_content(entry, key=flattened_key + "[]" if flattened_key else "") - files.append((flattened_key + "[]", cast(FileTypes, entry))) + for array_index, entry in enumerate(obj): + suffix = _array_suffix(array_format, array_index) + emitted_key = (flattened_key + suffix) if flattened_key else suffix + assert_is_file_content(entry, key=emitted_key) + files.append((emitted_key, cast(FileTypes, entry))) return files assert_is_file_content(obj, key=flattened_key) @@ -110,6 +132,7 @@ def _extract_items( path, index=index, flattened_key=flattened_key, + array_format=array_format, ) elif is_list(obj): if key != "": @@ -121,9 +144,12 @@ def _extract_items( item, path, index=index, - flattened_key=flattened_key + "[]" if flattened_key is not None else "[]", + flattened_key=( + (flattened_key if flattened_key is not None else "") + _array_suffix(array_format, array_index) + ), + array_format=array_format, ) - for item in obj + for array_index, item in enumerate(obj) ] ) diff --git a/tests/test_extract_files.py b/tests/test_extract_files.py index dcf85bd7c7..54490e133f 100644 --- a/tests/test_extract_files.py +++ b/tests/test_extract_files.py @@ -4,7 +4,7 @@ import pytest -from openai._types import FileTypes +from openai._types import FileTypes, ArrayFormat from openai._utils import extract_files @@ -37,10 +37,7 @@ def test_multiple_files() -> None: def test_top_level_file_array() -> None: query = {"files": [b"file one", b"file two"], "title": "hello"} - assert extract_files(query, paths=[["files", ""]]) == [ - ("files[]", b"file one"), - ("files[]", b"file two"), - ] + assert extract_files(query, paths=[["files", ""]]) == [("files[]", b"file one"), ("files[]", b"file two")] assert query == {"title": "hello"} @@ -71,3 +68,24 @@ def test_ignores_incorrect_paths( expected: list[tuple[str, FileTypes]], ) -> None: assert extract_files(query, paths=paths) == expected + + +@pytest.mark.parametrize( + "array_format,expected_top_level,expected_nested", + [ + ("brackets", [("files[]", b"a"), ("files[]", b"b")], [("items[][file]", b"a"), ("items[][file]", b"b")]), + ("repeat", [("files", b"a"), ("files", b"b")], [("items[file]", b"a"), ("items[file]", b"b")]), + ("comma", [("files", b"a"), ("files", b"b")], [("items[file]", b"a"), ("items[file]", b"b")]), + ("indices", [("files[0]", b"a"), ("files[1]", b"b")], [("items[0][file]", b"a"), ("items[1][file]", b"b")]), + ], +) +def test_array_format_controls_file_field_names( + array_format: ArrayFormat, + expected_top_level: list[tuple[str, FileTypes]], + expected_nested: list[tuple[str, FileTypes]], +) -> None: + top_level = {"files": [b"a", b"b"]} + assert extract_files(top_level, paths=[["files", ""]], array_format=array_format) == expected_top_level + + nested = {"items": [{"file": b"a"}, {"file": b"b"}]} + assert extract_files(nested, paths=[["items", "", "file"]], array_format=array_format) == expected_nested diff --git a/tests/test_files.py b/tests/test_files.py index 3d3851f5f8..56445fb550 100644 --- a/tests/test_files.py +++ b/tests/test_files.py @@ -131,7 +131,7 @@ def test_extract_files_does_not_mutate_original_nested_array_path(self) -> None: copied = deepcopy_with_paths(original, [["items", "", "file"]]) extracted = extract_files(copied, paths=[["items", "", "file"]]) - assert extracted == [("items[][file]", file1), ("items[][file]", file2)] + assert [entry for _, entry in extracted] == [file1, file2] assert original == { "items": [ {"file": file1, "extra": 1}, From 166446b8522b47304e035015ca2175b7266806f5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 27 Apr 2026 19:02:28 +0000 Subject: [PATCH 692/769] docs(api): add rate limit and vector store info to files create --- .stats.yml | 4 ++-- src/openai/resources/files.py | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/.stats.yml b/.stats.yml index 0908a17fe9..ce8792b2e8 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 152 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-bbf1d88b9b565b893dcae280be68848dc1518ecb65e009d1e94c9f0e5ecaacb2.yml -openapi_spec_hash: 0757a960c980e26cc813615d6823bfd5 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-9919ae12a2ab24389e4bcd032e986437cbc8a4b70057dda0f524976c9378f4c1.yml +openapi_spec_hash: d7bf0be60f2af5c1d2f73b2b0f4e562a config_hash: 1d3eb2a6fc36f206d2d67bfcf1a7080d diff --git a/src/openai/resources/files.py b/src/openai/resources/files.py index 0cc6b046ff..c91e626b9b 100644 --- a/src/openai/resources/files.py +++ b/src/openai/resources/files.py @@ -74,7 +74,8 @@ def create( Individual files can be up to 512 MB, and each project can store up to 2.5 TB of files in total. There - is no organization-wide storage limit. + is no organization-wide storage limit. Uploads to this endpoint are rate-limited + to 2,000 files per minute per organization. - The Assistants API supports files up to 2 million tokens and of specific file types. See the @@ -89,6 +90,10 @@ def create( - The Batch API only supports `.jsonl` files up to 200 MB in size. The input also has a specific required [format](https://platform.openai.com/docs/api-reference/batch/request-input). + - For Retrieval or `file_search` ingestion, upload files here first. If you need + to attach multiple uploaded files to the same vector store, use + [`/vector_stores/{vector_store_id}/file_batches`](https://platform.openai.com/docs/api-reference/vector-stores-file-batches/createBatch) + instead of attaching them one by one. Please [contact us](https://help.openai.com/) if you need to increase these storage limits. @@ -400,7 +405,8 @@ async def create( Individual files can be up to 512 MB, and each project can store up to 2.5 TB of files in total. There - is no organization-wide storage limit. + is no organization-wide storage limit. Uploads to this endpoint are rate-limited + to 2,000 files per minute per organization. - The Assistants API supports files up to 2 million tokens and of specific file types. See the @@ -415,6 +421,10 @@ async def create( - The Batch API only supports `.jsonl` files up to 200 MB in size. The input also has a specific required [format](https://platform.openai.com/docs/api-reference/batch/request-input). + - For Retrieval or `file_search` ingestion, upload files here first. If you need + to attach multiple uploaded files to the same vector store, use + [`/vector_stores/{vector_store_id}/file_batches`](https://platform.openai.com/docs/api-reference/vector-stores-file-batches/createBatch) + instead of attaching them one by one. Please [contact us](https://help.openai.com/) if you need to increase these storage limits. From dc98fa42d167197e3a2d6be353c108df0d43b456 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 27 Apr 2026 22:27:54 +0000 Subject: [PATCH 693/769] feat: support setting headers via env --- src/openai/_client.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/openai/_client.py b/src/openai/_client.py index 434f957e19..18bc80d1a0 100644 --- a/src/openai/_client.py +++ b/src/openai/_client.py @@ -24,6 +24,7 @@ from ._utils import ( is_given, is_mapping, + is_mapping_t, get_async_library, ) from ._compat import cached_property @@ -185,6 +186,15 @@ def __init__( if base_url is None: base_url = f"https://api.openai.com/v1" + custom_headers_env = os.environ.get("OPENAI_CUSTOM_HEADERS") + if custom_headers_env is not None: + parsed: dict[str, str] = {} + for line in custom_headers_env.split("\n"): + colon = line.find(":") + if colon >= 0: + parsed[line[:colon].strip()] = line[colon + 1 :].strip() + default_headers = {**parsed, **(default_headers if is_mapping_t(default_headers) else {})} + super().__init__( version=__version__, base_url=base_url, @@ -614,6 +624,15 @@ def __init__( if base_url is None: base_url = f"https://api.openai.com/v1" + custom_headers_env = os.environ.get("OPENAI_CUSTOM_HEADERS") + if custom_headers_env is not None: + parsed: dict[str, str] = {} + for line in custom_headers_env.split("\n"): + colon = line.find(":") + if colon >= 0: + parsed[line[:colon].strip()] = line[colon + 1 :].strip() + default_headers = {**parsed, **(default_headers if is_mapping_t(default_headers) else {})} + super().__init__( version=__version__, base_url=base_url, From 3380ecb943bbf293ca39a51eed55a125b0a27716 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 27 Apr 2026 22:45:59 +0000 Subject: [PATCH 694/769] docs(api): update files rate limit documentation --- .stats.yml | 2 +- src/openai/resources/files.py | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.stats.yml b/.stats.yml index ce8792b2e8..158de3fccf 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 152 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-9919ae12a2ab24389e4bcd032e986437cbc8a4b70057dda0f524976c9378f4c1.yml -openapi_spec_hash: d7bf0be60f2af5c1d2f73b2b0f4e562a +openapi_spec_hash: cb2783cf8428574ffd54b31e4ca87c31 config_hash: 1d3eb2a6fc36f206d2d67bfcf1a7080d diff --git a/src/openai/resources/files.py b/src/openai/resources/files.py index c91e626b9b..0cceb94b9d 100644 --- a/src/openai/resources/files.py +++ b/src/openai/resources/files.py @@ -75,7 +75,7 @@ def create( Individual files can be up to 512 MB, and each project can store up to 2.5 TB of files in total. There is no organization-wide storage limit. Uploads to this endpoint are rate-limited - to 2,000 files per minute per organization. + to 1,000 requests per minute per authenticated user. - The Assistants API supports files up to 2 million tokens and of specific file types. See the @@ -93,7 +93,9 @@ def create( - For Retrieval or `file_search` ingestion, upload files here first. If you need to attach multiple uploaded files to the same vector store, use [`/vector_stores/{vector_store_id}/file_batches`](https://platform.openai.com/docs/api-reference/vector-stores-file-batches/createBatch) - instead of attaching them one by one. + instead of attaching them one by one. Vector store attachment has separate + limits from file upload, including 2,000 attached files per minute per + organization. Please [contact us](https://help.openai.com/) if you need to increase these storage limits. @@ -406,7 +408,7 @@ async def create( Individual files can be up to 512 MB, and each project can store up to 2.5 TB of files in total. There is no organization-wide storage limit. Uploads to this endpoint are rate-limited - to 2,000 files per minute per organization. + to 1,000 requests per minute per authenticated user. - The Assistants API supports files up to 2 million tokens and of specific file types. See the @@ -424,7 +426,9 @@ async def create( - For Retrieval or `file_search` ingestion, upload files here first. If you need to attach multiple uploaded files to the same vector store, use [`/vector_stores/{vector_store_id}/file_batches`](https://platform.openai.com/docs/api-reference/vector-stores-file-batches/createBatch) - instead of attaching them one by one. + instead of attaching them one by one. Vector store attachment has separate + limits from file upload, including 2,000 attached files per minute per + organization. Please [contact us](https://help.openai.com/) if you need to increase these storage limits. From 7903bcc69694ba2a41d48f8f45e5e3b07892d734 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 28 Apr 2026 00:13:47 +0000 Subject: [PATCH 695/769] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 158de3fccf..8a3f1b60a1 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 152 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-9919ae12a2ab24389e4bcd032e986437cbc8a4b70057dda0f524976c9378f4c1.yml -openapi_spec_hash: cb2783cf8428574ffd54b31e4ca87c31 +openapi_spec_hash: c670ab80573e61e664f6a16f5a96d67f config_hash: 1d3eb2a6fc36f206d2d67bfcf1a7080d From b29a2501d8406bbd432af5921d54f4de4415cd4f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 28 Apr 2026 18:58:13 +0000 Subject: [PATCH 696/769] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 8a3f1b60a1..b09ae1b6fd 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 152 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-9919ae12a2ab24389e4bcd032e986437cbc8a4b70057dda0f524976c9378f4c1.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-4f1d8a0ff9f48dc0b798df6a8ef0cfecafb1ccf14713ebb2a03dbe8ed192200e.yml openapi_spec_hash: c670ab80573e61e664f6a16f5a96d67f config_hash: 1d3eb2a6fc36f206d2d67bfcf1a7080d From 0e81ff2f45b7acf6a6de5620a66c3bd60af93b84 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 28 Apr 2026 21:54:50 +0000 Subject: [PATCH 697/769] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index b09ae1b6fd..20d21ace07 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 152 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-4f1d8a0ff9f48dc0b798df6a8ef0cfecafb1ccf14713ebb2a03dbe8ed192200e.yml -openapi_spec_hash: c670ab80573e61e664f6a16f5a96d67f +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-fa32d6e7d961e6a9090bfd42dada0302b1b11c40308587ea36bd46be854f33ab.yml +openapi_spec_hash: e582137699583c1fb37ddb0553a8a2d0 config_hash: 1d3eb2a6fc36f206d2d67bfcf1a7080d From 044ffcfdb749be9677a442b67f309b886a9cf3fb Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 28 Apr 2026 22:21:05 +0000 Subject: [PATCH 698/769] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 20d21ace07..58e688f32e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 152 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-fa32d6e7d961e6a9090bfd42dada0302b1b11c40308587ea36bd46be854f33ab.yml openapi_spec_hash: e582137699583c1fb37ddb0553a8a2d0 -config_hash: 1d3eb2a6fc36f206d2d67bfcf1a7080d +config_hash: 2b2791e02f87210a840b88c95ccefd31 From ae9ca46f22a01a1584c15b5db8854c017a91fa46 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 29 Apr 2026 01:54:01 +0000 Subject: [PATCH 699/769] feat(api): add support for Admin API Keys per endpoint --- .stats.yml | 2 +- src/openai/__init__.py | 15 + src/openai/_base_client.py | 34 +- src/openai/_client.py | 234 ++++++++---- src/openai/_models.py | 10 + src/openai/_types.py | 3 +- src/openai/lib/azure.py | 32 +- src/openai/resources/audio/speech.py | 12 +- src/openai/resources/audio/transcriptions.py | 12 +- src/openai/resources/audio/translations.py | 12 +- src/openai/resources/batches.py | 38 +- src/openai/resources/beta/assistants.py | 50 ++- src/openai/resources/beta/chatkit/sessions.py | 24 +- src/openai/resources/beta/chatkit/threads.py | 28 +- src/openai/resources/beta/threads/messages.py | 50 ++- .../resources/beta/threads/runs/runs.py | 42 ++- .../resources/beta/threads/runs/steps.py | 4 + src/openai/resources/beta/threads/threads.py | 50 ++- .../resources/chat/completions/completions.py | 50 ++- .../resources/chat/completions/messages.py | 2 + src/openai/resources/completions.py | 12 +- src/openai/resources/containers/containers.py | 38 +- .../resources/containers/files/content.py | 12 +- .../resources/containers/files/files.py | 38 +- .../resources/conversations/conversations.py | 48 ++- src/openai/resources/conversations/items.py | 18 +- src/openai/resources/embeddings.py | 2 + src/openai/resources/evals/evals.py | 50 ++- .../resources/evals/runs/output_items.py | 14 +- src/openai/resources/evals/runs/runs.py | 50 ++- src/openai/resources/files.py | 62 +++- .../resources/fine_tuning/alpha/graders.py | 24 +- .../fine_tuning/checkpoints/permissions.py | 28 +- .../resources/fine_tuning/jobs/checkpoints.py | 2 + src/openai/resources/fine_tuning/jobs/jobs.py | 64 +++- src/openai/resources/images.py | 36 +- src/openai/resources/models.py | 36 +- src/openai/resources/moderations.py | 12 +- src/openai/resources/realtime/calls.py | 60 ++- .../resources/realtime/client_secrets.py | 12 +- src/openai/resources/responses/input_items.py | 2 + .../resources/responses/input_tokens.py | 12 +- src/openai/resources/responses/responses.py | 50 ++- src/openai/resources/skills/content.py | 12 +- src/openai/resources/skills/skills.py | 50 ++- .../resources/skills/versions/content.py | 12 +- .../resources/skills/versions/versions.py | 38 +- src/openai/resources/uploads/parts.py | 12 +- src/openai/resources/uploads/uploads.py | 36 +- .../resources/vector_stores/file_batches.py | 38 +- src/openai/resources/vector_stores/files.py | 62 +++- .../resources/vector_stores/vector_stores.py | 62 +++- src/openai/resources/videos.py | 100 ++++- src/openai/types/admin/__init__.py | 3 + tests/conftest.py | 11 +- tests/test_client.py | 351 +++++++++++++++--- tests/test_module_client.py | 3 +- 57 files changed, 1807 insertions(+), 369 deletions(-) create mode 100644 src/openai/types/admin/__init__.py diff --git a/.stats.yml b/.stats.yml index 58e688f32e..613a7fb245 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 152 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-fa32d6e7d961e6a9090bfd42dada0302b1b11c40308587ea36bd46be854f33ab.yml openapi_spec_hash: e582137699583c1fb37ddb0553a8a2d0 -config_hash: 2b2791e02f87210a840b88c95ccefd31 +config_hash: 5dcd82ad6d930cf0a04c3cd7bbda82cc diff --git a/src/openai/__init__.py b/src/openai/__init__.py index fc9675a8b5..5fc22da800 100644 --- a/src/openai/__init__.py +++ b/src/openai/__init__.py @@ -130,6 +130,8 @@ api_key: str | None = None +admin_api_key: str | None = None + organization: str | None = None project: str | None = None @@ -176,6 +178,17 @@ def api_key(self, value: str | None) -> None: # type: ignore api_key = value + @property # type: ignore + @override + def admin_api_key(self) -> str | None: + return admin_api_key + + @admin_api_key.setter # type: ignore + def admin_api_key(self, value: str | None) -> None: # type: ignore + global admin_api_key + + admin_api_key = value + @property # type: ignore @override def organization(self) -> str | None: @@ -359,6 +372,7 @@ def _load_client() -> OpenAI: # type: ignore[reportUnusedFunction] _client = _ModuleClient( api_key=api_key, + admin_api_key=admin_api_key, organization=organization, project=project, webhook_secret=webhook_secret, @@ -368,6 +382,7 @@ def _load_client() -> OpenAI: # type: ignore[reportUnusedFunction] default_headers=default_headers, default_query=default_query, http_client=http_client, + _enforce_credentials=False, ) return _client diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index a1d0960700..216b36aabd 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -63,7 +63,7 @@ ) from ._utils import SensitiveHeadersFilter, is_dict, is_list, asyncify, is_given, lru_cache, is_mapping from ._compat import PYDANTIC_V1, model_copy, model_dump -from ._models import GenericModel, FinalRequestOptions, validate_type, construct_type +from ._models import GenericModel, SecurityOptions, FinalRequestOptions, validate_type, construct_type from ._response import ( APIResponse, BaseAPIResponse, @@ -435,9 +435,27 @@ def _make_status_error( ) -> _exceptions.APIStatusError: raise NotImplementedError() + def _auth_headers( + self, + security: SecurityOptions, # noqa: ARG002 + ) -> dict[str, str]: + return {} + + def _auth_query( + self, + security: SecurityOptions, # noqa: ARG002 + ) -> dict[str, str]: + return {} + + def _custom_auth( + self, + security: SecurityOptions, # noqa: ARG002 + ) -> httpx.Auth | None: + return None + def _build_headers(self, options: FinalRequestOptions, *, retries_taken: int = 0) -> httpx.Headers: custom_headers = options.headers or {} - headers_dict = _merge_mappings(self.default_headers, custom_headers) + headers_dict = _merge_mappings({**self._auth_headers(options.security), **self.default_headers}, custom_headers) self._validate_headers(headers_dict, custom_headers) # headers are case-insensitive while dictionaries are not. @@ -509,7 +527,7 @@ def _build_request( raise RuntimeError(f"Unexpected JSON data type, {type(json_data)}, cannot merge with `extra_body`") headers = self._build_headers(options, retries_taken=retries_taken) - params = _merge_mappings(self.default_query, options.params) + params = _merge_mappings({**self._auth_query(options.security), **self.default_query}, options.params) content_type = headers.get("Content-Type") files = options.files @@ -678,7 +696,6 @@ def default_headers(self) -> dict[str, str | Omit]: "Content-Type": "application/json", "User-Agent": self.user_agent, **self.platform_headers(), - **self.auth_headers, **self._custom_headers, } @@ -1006,8 +1023,9 @@ def request( self._prepare_request(request) kwargs: HttpxSendArgs = {} - if self.custom_auth is not None: - kwargs["auth"] = self.custom_auth + custom_auth = self._custom_auth(options.security) + if custom_auth is not None: + kwargs["auth"] = custom_auth if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects @@ -2013,6 +2031,7 @@ def make_request_options( idempotency_key: str | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, post_parser: PostParser | NotGiven = not_given, + security: SecurityOptions | None = None, synthesize_event_and_data: bool | None = None, ) -> RequestOptions: """Create a dict of type RequestOptions without keys of NotGiven values.""" @@ -2039,6 +2058,9 @@ def make_request_options( # internal options["post_parser"] = post_parser # type: ignore + if security is not None: + options["security"] = security + if synthesize_event_and_data is not None: options["synthesize_event_and_data"] = synthesize_event_and_data diff --git a/src/openai/_client.py b/src/openai/_client.py index 18bc80d1a0..3009989beb 100644 --- a/src/openai/_client.py +++ b/src/openai/_client.py @@ -13,6 +13,7 @@ from .auth import WorkloadIdentity, WorkloadIdentityAuth from ._types import ( Omit, + Headers, Timeout, NotGiven, Transport, @@ -28,10 +29,10 @@ get_async_library, ) from ._compat import cached_property -from ._models import FinalRequestOptions + from ._version import __version__ from ._streaming import Stream as Stream, AsyncStream as AsyncStream -from ._exceptions import OpenAIError, APIStatusError +from ._exceptions import APIStatusError from ._base_client import ( DEFAULT_MAX_RETRIES, SyncAPIClient, @@ -90,7 +91,10 @@ class OpenAI(SyncAPIClient): # client options - api_key: str +class OpenAI(SyncAPIClient): + # client options + api_key: str | None + admin_api_key: str | None workload_identity: WorkloadIdentity | None organization: str | None project: str | None @@ -108,7 +112,8 @@ class OpenAI(SyncAPIClient): def __init__( self, *, - api_key: str | None | Callable[[], str] = None, + api_key: str | Callable[[], str] | None = None, + admin_api_key: str | None = None, workload_identity: WorkloadIdentity | None = None, organization: str | None = None, project: str | None = None, @@ -137,6 +142,7 @@ def __init__( This automatically infers the following arguments from their corresponding environment variables if they are not provided: - `api_key` from `OPENAI_API_KEY` + - `admin_api_key` from `OPENAI_ADMIN_KEY` - `organization` from `OPENAI_ORG_ID` - `project` from `OPENAI_PROJECT_ID` - `webhook_secret` from `OPENAI_WEBHOOK_SECRET` @@ -155,10 +161,6 @@ def __init__( else: if api_key is None: api_key = os.environ.get("OPENAI_API_KEY") - if api_key is None: - raise OpenAIError( - "The api_key client option must be set either by passing api_key to the client or by setting the OPENAI_API_KEY environment variable" - ) if callable(api_key): self.api_key = "" self._api_key_provider: Callable[[], str] | None = api_key # type: ignore[no-redef] @@ -167,6 +169,10 @@ def __init__( self._api_key_provider = None self._workload_identity_auth = None + if admin_api_key is None: + admin_api_key = os.environ.get("OPENAI_ADMIN_KEY") + self.admin_api_key = admin_api_key + if organization is None: organization = os.environ.get("OPENAI_ORG_ID") self.organization = organization @@ -365,35 +371,50 @@ def with_streaming_response(self) -> OpenAIWithStreamedResponse: def qs(self) -> Querystring: return Querystring(array_format="brackets") - def _refresh_api_key(self) -> None: - if self._api_key_provider: - self.api_key = self._api_key_provider() @override - def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOptions: - self._refresh_api_key() - return super()._prepare_options(options) + def _auth_headers(self, security: SecurityOptions) -> dict[str, str]: + return { + **(self._bearer_auth if security.get("bearer_auth", False) else {}), + **(self._admin_api_key_auth if security.get("admin_api_key_auth", False) else {}), + } - def _send_with_auth_retry( - self, - request: httpx.Request, - *, - stream: bool, - retried: bool = False, - **kwargs: Unpack[HttpxSendArgs], - ) -> httpx.Response: - if self._workload_identity_auth: - request.headers["Authorization"] = f"Bearer {self._workload_identity_auth.get_token()}" + @property + def _bearer_auth(self) -> dict[str, str]: + api_key = self.api_key - response = super()._send_request(request, stream=stream, **kwargs) + return {"Authorization": f"Bearer {api_key}"} + + @property + def _admin_api_key_auth(self) -> dict[str, str]: + admin_api_key = self.admin_api_key + if admin_api_key is None: + return {} + return {"Authorization": f"Bearer {admin_api_key}"} + + @property + @override + def default_headers(self) -> dict[str, str | Omit]: + return { + **super().default_headers, + "X-Stainless-Async": "false", + "OpenAI-Organization": self.organization if self.organization is not None else Omit(), + "OpenAI-Project": self.project if self.project is not None else Omit(), + **self._custom_headers, + } - if not retried and response.status_code == 401 and self._workload_identity_auth: - response.close() + @override + def _validate_headers(self, headers: Headers, custom_headers: Headers) -> None: + if headers.get("Authorization") or isinstance(custom_headers.get("Authorization"), Omit): + return - self._workload_identity_auth.invalidate_token() - fresh_token = self._workload_identity_auth.get_token() + raise TypeError( + '"Could not resolve authentication method. Expected either api_key or admin_api_key to be set. Or for one of the `Authorization` or `Authorization` headers to be explicitly omitted"' + ) - request.headers["Authorization"] = f"Bearer {fresh_token}" + def copy( + self, + *, return self._send_with_auth_retry(request, stream=stream, retried=True, **kwargs) @@ -409,15 +430,40 @@ def _send_request( ) -> httpx.Response: return self._send_with_auth_retry(request, stream=stream, **kwargs) + @override + def _auth_headers(self, security: SecurityOptions) -> dict[str, str]: + if security.get("bearer_auth", False): + headers = self._bearer_auth + if headers: + return headers + + if security.get("admin_api_key_auth", False): + return self._admin_api_key_auth + + return {} + + @property + def _bearer_auth(self) -> dict[str, str]: + api_key = self.api_key + if not api_key: + return {} + return {"Authorization": f"Bearer {api_key}"} + @property @override def auth_headers(self) -> dict[str, str]: api_key = self.api_key if not api_key or api_key == WORKLOAD_IDENTITY_API_KEY_PLACEHOLDER: - # if the api key is an empty string, encoding the header will fail return {} return {"Authorization": f"Bearer {api_key}"} + @property + def _admin_api_key_auth(self) -> dict[str, str]: + admin_api_key = self.admin_api_key + if admin_api_key is None: + return {} + return {"Authorization": f"Bearer {admin_api_key}"} + @property @override def default_headers(self) -> dict[str, str | Omit]: @@ -429,10 +475,20 @@ def default_headers(self) -> dict[str, str | Omit]: **self._custom_headers, } + @override + def _validate_headers(self, headers: Headers, custom_headers: Headers) -> None: + if headers.get("Authorization") or isinstance(custom_headers.get("Authorization"), Omit): + return + + raise TypeError( + '"Could not resolve authentication method. Expected either api_key or admin_api_key to be set. Or for one of the `Authorization` or `Authorization` headers to be explicitly omitted"' + ) + def copy( self, *, api_key: str | Callable[[], str] | None = None, + admin_api_key: str | None = None, workload_identity: WorkloadIdentity | None = None, organization: str | None = None, project: str | None = None, @@ -472,7 +528,7 @@ def copy( http_client = http_client or self._client return self.__class__( - api_key=api_key or self._api_key_provider or self.api_key, + admin_api_key=admin_api_key or self.admin_api_key, workload_identity=workload_identity or self.workload_identity, organization=organization or self.organization, project=project or self.project, @@ -528,8 +584,8 @@ def _make_status_error( class AsyncOpenAI(AsyncAPIClient): # client options - api_key: str - workload_identity: WorkloadIdentity | None + api_key: str | None + admin_api_key: str | None organization: str | None project: str | None webhook_secret: str | None @@ -546,7 +602,9 @@ class AsyncOpenAI(AsyncAPIClient): def __init__( self, *, - api_key: str | None | Callable[[], Awaitable[str]] = None, + *, + api_key: str | Callable[[], Awaitable[str]] | None = None, + admin_api_key: str | None = None, workload_identity: WorkloadIdentity | None = None, organization: str | None = None, project: str | None = None, @@ -575,6 +633,7 @@ def __init__( This automatically infers the following arguments from their corresponding environment variables if they are not provided: - `api_key` from `OPENAI_API_KEY` + - `admin_api_key` from `OPENAI_ADMIN_KEY` - `organization` from `OPENAI_ORG_ID` - `project` from `OPENAI_PROJECT_ID` - `webhook_secret` from `OPENAI_WEBHOOK_SECRET` @@ -593,10 +652,6 @@ def __init__( else: if api_key is None: api_key = os.environ.get("OPENAI_API_KEY") - if api_key is None: - raise OpenAIError( - "The api_key client option must be set either by passing api_key to the client or by setting the OPENAI_API_KEY environment variable" - ) if callable(api_key): self.api_key = "" self._api_key_provider: Callable[[], Awaitable[str]] | None = api_key # type: ignore[no-redef] @@ -605,6 +660,10 @@ def __init__( self._api_key_provider = None self._workload_identity_auth = None + if admin_api_key is None: + admin_api_key = os.environ.get("OPENAI_ADMIN_KEY") + self.admin_api_key = admin_api_key + if organization is None: organization = os.environ.get("OPENAI_ORG_ID") self.organization = organization @@ -803,35 +862,50 @@ def with_streaming_response(self) -> AsyncOpenAIWithStreamedResponse: def qs(self) -> Querystring: return Querystring(array_format="brackets") - async def _refresh_api_key(self) -> None: - if self._api_key_provider: - self.api_key = await self._api_key_provider() @override - async def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOptions: - await self._refresh_api_key() - return await super()._prepare_options(options) + def _auth_headers(self, security: SecurityOptions) -> dict[str, str]: + return { + **(self._bearer_auth if security.get("bearer_auth", False) else {}), + **(self._admin_api_key_auth if security.get("admin_api_key_auth", False) else {}), + } - async def _send_with_auth_retry( - self, - request: httpx.Request, - *, - stream: bool, - retried: bool = False, - **kwargs: Unpack[HttpxSendArgs], - ) -> httpx.Response: - if self._workload_identity_auth: - request.headers["Authorization"] = f"Bearer {await self._workload_identity_auth.get_token_async()}" + @property + def _bearer_auth(self) -> dict[str, str]: + api_key = self.api_key - response = await super()._send_request(request, stream=stream, **kwargs) + return {"Authorization": f"Bearer {api_key}"} + + @property + def _admin_api_key_auth(self) -> dict[str, str]: + admin_api_key = self.admin_api_key + if admin_api_key is None: + return {} + return {"Authorization": f"Bearer {admin_api_key}"} + + @property + @override + def default_headers(self) -> dict[str, str | Omit]: + return { + **super().default_headers, + "X-Stainless-Async": f"async:{get_async_library()}", + "OpenAI-Organization": self.organization if self.organization is not None else Omit(), + "OpenAI-Project": self.project if self.project is not None else Omit(), + **self._custom_headers, + } - if not retried and response.status_code == 401 and self._workload_identity_auth: - await response.aclose() + @override + def _validate_headers(self, headers: Headers, custom_headers: Headers) -> None: + if headers.get("Authorization") or isinstance(custom_headers.get("Authorization"), Omit): + return - self._workload_identity_auth.invalidate_token() - fresh_token = await self._workload_identity_auth.get_token_async() + raise TypeError( + '"Could not resolve authentication method. Expected either api_key or admin_api_key to be set. Or for one of the `Authorization` or `Authorization` headers to be explicitly omitted"' + ) - request.headers["Authorization"] = f"Bearer {fresh_token}" + def copy( + self, + *, return await self._send_with_auth_retry(request, stream=stream, retried=True, **kwargs) @@ -847,15 +921,40 @@ async def _send_request( ) -> httpx.Response: return await self._send_with_auth_retry(request, stream=stream, **kwargs) + @override + def _auth_headers(self, security: SecurityOptions) -> dict[str, str]: + if security.get("bearer_auth", False): + headers = self._bearer_auth + if headers: + return headers + + if security.get("admin_api_key_auth", False): + return self._admin_api_key_auth + + return {} + + @property + def _bearer_auth(self) -> dict[str, str]: + api_key = self.api_key + if not api_key: + return {} + return {"Authorization": f"Bearer {api_key}"} + @property @override def auth_headers(self) -> dict[str, str]: api_key = self.api_key if not api_key or api_key == WORKLOAD_IDENTITY_API_KEY_PLACEHOLDER: - # if the api key is an empty string, encoding the header will fail return {} return {"Authorization": f"Bearer {api_key}"} + @property + def _admin_api_key_auth(self) -> dict[str, str]: + admin_api_key = self.admin_api_key + if admin_api_key is None: + return {} + return {"Authorization": f"Bearer {admin_api_key}"} + @property @override def default_headers(self) -> dict[str, str | Omit]: @@ -867,10 +966,20 @@ def default_headers(self) -> dict[str, str | Omit]: **self._custom_headers, } + @override + def _validate_headers(self, headers: Headers, custom_headers: Headers) -> None: + if headers.get("Authorization") or isinstance(custom_headers.get("Authorization"), Omit): + return + + raise TypeError( + '"Could not resolve authentication method. Expected either api_key or admin_api_key to be set. Or for one of the `Authorization` or `Authorization` headers to be explicitly omitted"' + ) + def copy( self, *, api_key: str | Callable[[], Awaitable[str]] | None = None, + admin_api_key: str | None = None, workload_identity: WorkloadIdentity | None = None, organization: str | None = None, project: str | None = None, @@ -910,6 +1019,7 @@ def copy( http_client = http_client or self._client return self.__class__( api_key=api_key or self._api_key_provider or self.api_key, + admin_api_key=admin_api_key or self.admin_api_key, workload_identity=workload_identity or self.workload_identity, organization=organization or self.organization, project=project or self.project, diff --git a/src/openai/_models.py b/src/openai/_models.py index 810e49dfc5..5f12232437 100644 --- a/src/openai/_models.py +++ b/src/openai/_models.py @@ -832,6 +832,11 @@ def _create_pydantic_model(type_: _T) -> Type[RootModel[_T]]: return RootModel[type_] # type: ignore +class SecurityOptions(TypedDict, total=False): + bearer_auth: bool + admin_api_key_auth: bool + + class FinalRequestOptionsInput(TypedDict, total=False): method: Required[str] url: Required[str] @@ -845,6 +850,7 @@ class FinalRequestOptionsInput(TypedDict, total=False): json_data: Body extra_json: AnyMapping follow_redirects: bool + security: SecurityOptions synthesize_event_and_data: bool @@ -860,6 +866,10 @@ class FinalRequestOptions(pydantic.BaseModel): idempotency_key: Union[str, None] = None post_parser: Union[Callable[[Any], Any], NotGiven] = NotGiven() follow_redirects: Union[bool, None] = None + security: SecurityOptions = { + "bearer_auth": True, + "admin_api_key_auth": True, + } synthesize_event_and_data: Optional[bool] = None content: Union[bytes, bytearray, IO[bytes], Iterable[bytes], AsyncIterable[bytes], None] = None diff --git a/src/openai/_types.py b/src/openai/_types.py index 680a74ddb6..9936b00f73 100644 --- a/src/openai/_types.py +++ b/src/openai/_types.py @@ -36,7 +36,7 @@ from httpx import URL, Proxy, Timeout, Response, BaseTransport, AsyncBaseTransport if TYPE_CHECKING: - from ._models import BaseModel + from ._models import BaseModel, SecurityOptions from ._response import APIResponse, AsyncAPIResponse from ._legacy_response import HttpxBinaryResponseContent @@ -125,6 +125,7 @@ class RequestOptions(TypedDict, total=False): extra_json: AnyMapping idempotency_key: str follow_redirects: bool + security: SecurityOptions synthesize_event_and_data: bool diff --git a/src/openai/lib/azure.py b/src/openai/lib/azure.py index 09fdd9507e..a7b23f8de9 100644 --- a/src/openai/lib/azure.py +++ b/src/openai/lib/azure.py @@ -96,6 +96,7 @@ def __init__( azure_deployment: str | None = None, api_version: str | None = None, api_key: str | Callable[[], str] | None = None, + admin_api_key: str | None = None, azure_ad_token: str | None = None, azure_ad_token_provider: AzureADTokenProvider | None = None, organization: str | None = None, @@ -107,6 +108,7 @@ def __init__( default_query: Mapping[str, object] | None = None, http_client: httpx.Client | None = None, _strict_response_validation: bool = False, + _enforce_credentials: bool = True, ) -> None: ... @overload @@ -116,6 +118,7 @@ def __init__( azure_deployment: str | None = None, api_version: str | None = None, api_key: str | Callable[[], str] | None = None, + admin_api_key: str | None = None, azure_ad_token: str | None = None, azure_ad_token_provider: AzureADTokenProvider | None = None, organization: str | None = None, @@ -127,6 +130,7 @@ def __init__( default_query: Mapping[str, object] | None = None, http_client: httpx.Client | None = None, _strict_response_validation: bool = False, + _enforce_credentials: bool = True, ) -> None: ... @overload @@ -136,6 +140,7 @@ def __init__( base_url: str, api_version: str | None = None, api_key: str | Callable[[], str] | None = None, + admin_api_key: str | None = None, azure_ad_token: str | None = None, azure_ad_token_provider: AzureADTokenProvider | None = None, organization: str | None = None, @@ -147,6 +152,7 @@ def __init__( default_query: Mapping[str, object] | None = None, http_client: httpx.Client | None = None, _strict_response_validation: bool = False, + _enforce_credentials: bool = True, ) -> None: ... def __init__( @@ -156,6 +162,7 @@ def __init__( azure_endpoint: str | None = None, azure_deployment: str | None = None, api_key: str | Callable[[], str] | None = None, + admin_api_key: str | None = None, # workload_identity is not functional in the Azure client workload_identity: WorkloadIdentity | None = None, # noqa: ARG002 azure_ad_token: str | None = None, @@ -171,6 +178,7 @@ def __init__( default_query: Mapping[str, object] | None = None, http_client: httpx.Client | None = None, _strict_response_validation: bool = False, + _enforce_credentials: bool = True, ) -> None: """Construct a new synchronous azure openai client instance. @@ -239,6 +247,7 @@ def __init__( super().__init__( api_key=api_key, + admin_api_key=admin_api_key, organization=organization, project=project, webhook_secret=webhook_secret, @@ -250,6 +259,7 @@ def __init__( http_client=http_client, websocket_base_url=websocket_base_url, _strict_response_validation=_strict_response_validation, + _enforce_credentials=_enforce_credentials, ) self._api_version = api_version self._azure_ad_token = azure_ad_token @@ -262,6 +272,7 @@ def copy( self, *, api_key: str | Callable[[], str] | None = None, + admin_api_key: str | None = None, workload_identity: WorkloadIdentity | None = None, organization: str | None = None, project: str | None = None, @@ -278,6 +289,7 @@ def copy( set_default_headers: Mapping[str, str] | None = None, default_query: Mapping[str, object] | None = None, set_default_query: Mapping[str, object] | None = None, + _enforce_credentials: bool | None = None, _extra_kwargs: Mapping[str, Any] = {}, ) -> Self: """ @@ -285,6 +297,7 @@ def copy( """ return super().copy( api_key=api_key, + admin_api_key=admin_api_key, workload_identity=workload_identity, organization=organization, project=project, @@ -298,6 +311,7 @@ def copy( set_default_headers=set_default_headers, default_query=default_query, set_default_query=set_default_query, + _enforce_credentials=_enforce_credentials, _extra_kwargs={ "api_version": api_version or self._api_version, "azure_ad_token": azure_ad_token or self._azure_ad_token, @@ -334,7 +348,7 @@ def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOptions: if azure_ad_token is not None: if headers.get("Authorization") is None: headers["Authorization"] = f"Bearer {azure_ad_token}" - elif self.api_key is not API_KEY_SENTINEL: + elif self.api_key is not None and self.api_key is not API_KEY_SENTINEL: if headers.get("api-key") is None: headers["api-key"] = self.api_key else: @@ -378,6 +392,7 @@ def __init__( azure_deployment: str | None = None, api_version: str | None = None, api_key: str | Callable[[], Awaitable[str]] | None = None, + admin_api_key: str | None = None, azure_ad_token: str | None = None, azure_ad_token_provider: AsyncAzureADTokenProvider | None = None, organization: str | None = None, @@ -390,6 +405,7 @@ def __init__( default_query: Mapping[str, object] | None = None, http_client: httpx.AsyncClient | None = None, _strict_response_validation: bool = False, + _enforce_credentials: bool = True, ) -> None: ... @overload @@ -399,6 +415,7 @@ def __init__( azure_deployment: str | None = None, api_version: str | None = None, api_key: str | Callable[[], Awaitable[str]] | None = None, + admin_api_key: str | None = None, azure_ad_token: str | None = None, azure_ad_token_provider: AsyncAzureADTokenProvider | None = None, organization: str | None = None, @@ -411,6 +428,7 @@ def __init__( default_query: Mapping[str, object] | None = None, http_client: httpx.AsyncClient | None = None, _strict_response_validation: bool = False, + _enforce_credentials: bool = True, ) -> None: ... @overload @@ -420,6 +438,7 @@ def __init__( base_url: str, api_version: str | None = None, api_key: str | Callable[[], Awaitable[str]] | None = None, + admin_api_key: str | None = None, azure_ad_token: str | None = None, azure_ad_token_provider: AsyncAzureADTokenProvider | None = None, organization: str | None = None, @@ -432,6 +451,7 @@ def __init__( default_query: Mapping[str, object] | None = None, http_client: httpx.AsyncClient | None = None, _strict_response_validation: bool = False, + _enforce_credentials: bool = True, ) -> None: ... def __init__( @@ -441,6 +461,7 @@ def __init__( azure_deployment: str | None = None, api_version: str | None = None, api_key: str | Callable[[], Awaitable[str]] | None = None, + admin_api_key: str | None = None, # workload_identity is not functional in the Azure client workload_identity: WorkloadIdentity | None = None, # noqa: ARG002 azure_ad_token: str | None = None, @@ -456,6 +477,7 @@ def __init__( default_query: Mapping[str, object] | None = None, http_client: httpx.AsyncClient | None = None, _strict_response_validation: bool = False, + _enforce_credentials: bool = True, ) -> None: """Construct a new asynchronous azure openai client instance. @@ -524,6 +546,7 @@ def __init__( super().__init__( api_key=api_key, + admin_api_key=admin_api_key, organization=organization, project=project, webhook_secret=webhook_secret, @@ -535,6 +558,7 @@ def __init__( http_client=http_client, websocket_base_url=websocket_base_url, _strict_response_validation=_strict_response_validation, + _enforce_credentials=_enforce_credentials, ) self._api_version = api_version self._azure_ad_token = azure_ad_token @@ -547,6 +571,7 @@ def copy( self, *, api_key: str | Callable[[], Awaitable[str]] | None = None, + admin_api_key: str | None = None, workload_identity: WorkloadIdentity | None = None, organization: str | None = None, project: str | None = None, @@ -563,6 +588,7 @@ def copy( set_default_headers: Mapping[str, str] | None = None, default_query: Mapping[str, object] | None = None, set_default_query: Mapping[str, object] | None = None, + _enforce_credentials: bool | None = None, _extra_kwargs: Mapping[str, Any] = {}, ) -> Self: """ @@ -570,6 +596,7 @@ def copy( """ return super().copy( api_key=api_key, + admin_api_key=admin_api_key, workload_identity=workload_identity, organization=organization, project=project, @@ -583,6 +610,7 @@ def copy( set_default_headers=set_default_headers, default_query=default_query, set_default_query=set_default_query, + _enforce_credentials=_enforce_credentials, _extra_kwargs={ "api_version": api_version or self._api_version, "azure_ad_token": azure_ad_token or self._azure_ad_token, @@ -621,7 +649,7 @@ async def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOp if azure_ad_token is not None: if headers.get("Authorization") is None: headers["Authorization"] = f"Bearer {azure_ad_token}" - elif self.api_key is not API_KEY_SENTINEL: + elif self.api_key is not None and self.api_key is not API_KEY_SENTINEL: if headers.get("api-key") is None: headers["api-key"] = self.api_key else: diff --git a/src/openai/resources/audio/speech.py b/src/openai/resources/audio/speech.py index 80dbb44077..3c05d690dd 100644 --- a/src/openai/resources/audio/speech.py +++ b/src/openai/resources/audio/speech.py @@ -119,7 +119,11 @@ def create( speech_create_params.SpeechCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=_legacy_response.HttpxBinaryResponseContent, ) @@ -219,7 +223,11 @@ async def create( speech_create_params.SpeechCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=_legacy_response.HttpxBinaryResponseContent, ) diff --git a/src/openai/resources/audio/transcriptions.py b/src/openai/resources/audio/transcriptions.py index e5f415f278..ab2480ef11 100644 --- a/src/openai/resources/audio/transcriptions.py +++ b/src/openai/resources/audio/transcriptions.py @@ -492,7 +492,11 @@ def create( ), files=files, options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=_get_response_format_type(response_format), stream=stream or False, @@ -947,7 +951,11 @@ async def create( ), files=files, options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=_get_response_format_type(response_format), stream=stream or False, diff --git a/src/openai/resources/audio/translations.py b/src/openai/resources/audio/translations.py index d6df25c1b7..d0b5738045 100644 --- a/src/openai/resources/audio/translations.py +++ b/src/openai/resources/audio/translations.py @@ -167,7 +167,11 @@ def create( body=maybe_transform(body, translation_create_params.TranslationCreateParams), files=files, options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=_get_response_format_type(response_format), ) @@ -313,7 +317,11 @@ async def create( body=await async_maybe_transform(body, translation_create_params.TranslationCreateParams), files=files, options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=_get_response_format_type(response_format), ) diff --git a/src/openai/resources/batches.py b/src/openai/resources/batches.py index 6cdb50c280..e7146ef35f 100644 --- a/src/openai/resources/batches.py +++ b/src/openai/resources/batches.py @@ -123,7 +123,11 @@ def create( batch_create_params.BatchCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Batch, ) @@ -156,7 +160,11 @@ def retrieve( return self._get( path_template("/batches/{batch_id}", batch_id=batch_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Batch, ) @@ -209,6 +217,7 @@ def list( }, batch_list_params.BatchListParams, ), + security={"bearer_auth": True}, ), model=Batch, ) @@ -244,7 +253,11 @@ def cancel( return self._post( path_template("/batches/{batch_id}/cancel", batch_id=batch_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Batch, ) @@ -351,7 +364,11 @@ async def create( batch_create_params.BatchCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Batch, ) @@ -384,7 +401,11 @@ async def retrieve( return await self._get( path_template("/batches/{batch_id}", batch_id=batch_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Batch, ) @@ -437,6 +458,7 @@ def list( }, batch_list_params.BatchListParams, ), + security={"bearer_auth": True}, ), model=Batch, ) @@ -472,7 +494,11 @@ async def cancel( return await self._post( path_template("/batches/{batch_id}/cancel", batch_id=batch_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Batch, ) diff --git a/src/openai/resources/beta/assistants.py b/src/openai/resources/beta/assistants.py index 7ea8a918ca..6301082fea 100644 --- a/src/openai/resources/beta/assistants.py +++ b/src/openai/resources/beta/assistants.py @@ -182,7 +182,11 @@ def create( assistant_create_params.AssistantCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Assistant, ) @@ -217,7 +221,11 @@ def retrieve( return self._get( path_template("/assistants/{assistant_id}", assistant_id=assistant_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Assistant, ) @@ -401,7 +409,11 @@ def update( assistant_update_params.AssistantUpdateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Assistant, ) @@ -468,6 +480,7 @@ def list( }, assistant_list_params.AssistantListParams, ), + security={"bearer_auth": True}, ), model=Assistant, ) @@ -502,7 +515,11 @@ def delete( return self._delete( path_template("/assistants/{assistant_id}", assistant_id=assistant_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=AssistantDeleted, ) @@ -658,7 +675,11 @@ async def create( assistant_create_params.AssistantCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Assistant, ) @@ -693,7 +714,11 @@ async def retrieve( return await self._get( path_template("/assistants/{assistant_id}", assistant_id=assistant_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Assistant, ) @@ -877,7 +902,11 @@ async def update( assistant_update_params.AssistantUpdateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Assistant, ) @@ -944,6 +973,7 @@ def list( }, assistant_list_params.AssistantListParams, ), + security={"bearer_auth": True}, ), model=Assistant, ) @@ -978,7 +1008,11 @@ async def delete( return await self._delete( path_template("/assistants/{assistant_id}", assistant_id=assistant_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=AssistantDeleted, ) diff --git a/src/openai/resources/beta/chatkit/sessions.py b/src/openai/resources/beta/chatkit/sessions.py index 6e95fd65fb..9049b06a40 100644 --- a/src/openai/resources/beta/chatkit/sessions.py +++ b/src/openai/resources/beta/chatkit/sessions.py @@ -100,7 +100,11 @@ def create( session_create_params.SessionCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ChatSession, ) @@ -136,7 +140,11 @@ def cancel( return self._post( path_template("/chatkit/sessions/{session_id}/cancel", session_id=session_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ChatSession, ) @@ -215,7 +223,11 @@ async def create( session_create_params.SessionCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ChatSession, ) @@ -251,7 +263,11 @@ async def cancel( return await self._post( path_template("/chatkit/sessions/{session_id}/cancel", session_id=session_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ChatSession, ) diff --git a/src/openai/resources/beta/chatkit/threads.py b/src/openai/resources/beta/chatkit/threads.py index 16e0e11a0a..05ebf0fb87 100644 --- a/src/openai/resources/beta/chatkit/threads.py +++ b/src/openai/resources/beta/chatkit/threads.py @@ -72,7 +72,11 @@ def retrieve( return self._get( path_template("/chatkit/threads/{thread_id}", thread_id=thread_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ChatKitThread, ) @@ -136,6 +140,7 @@ def list( }, thread_list_params.ThreadListParams, ), + security={"bearer_auth": True}, ), model=ChatKitThread, ) @@ -169,7 +174,11 @@ def delete( return self._delete( path_template("/chatkit/threads/{thread_id}", thread_id=thread_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ThreadDeleteResponse, ) @@ -231,6 +240,7 @@ def list_items( }, thread_list_items_params.ThreadListItemsParams, ), + security={"bearer_auth": True}, ), model=cast(Any, Data), # Union types cannot be passed in as arguments in the type system ) @@ -285,7 +295,11 @@ async def retrieve( return await self._get( path_template("/chatkit/threads/{thread_id}", thread_id=thread_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ChatKitThread, ) @@ -349,6 +363,7 @@ def list( }, thread_list_params.ThreadListParams, ), + security={"bearer_auth": True}, ), model=ChatKitThread, ) @@ -382,7 +397,11 @@ async def delete( return await self._delete( path_template("/chatkit/threads/{thread_id}", thread_id=thread_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ThreadDeleteResponse, ) @@ -444,6 +463,7 @@ def list_items( }, thread_list_items_params.ThreadListItemsParams, ), + security={"bearer_auth": True}, ), model=cast(Any, Data), # Union types cannot be passed in as arguments in the type system ) diff --git a/src/openai/resources/beta/threads/messages.py b/src/openai/resources/beta/threads/messages.py index 95b750d4e4..e57e783577 100644 --- a/src/openai/resources/beta/threads/messages.py +++ b/src/openai/resources/beta/threads/messages.py @@ -112,7 +112,11 @@ def create( message_create_params.MessageCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Message, ) @@ -150,7 +154,11 @@ def retrieve( return self._get( path_template("/threads/{thread_id}/messages/{message_id}", thread_id=thread_id, message_id=message_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Message, ) @@ -197,7 +205,11 @@ def update( path_template("/threads/{thread_id}/messages/{message_id}", thread_id=thread_id, message_id=message_id), body=maybe_transform({"metadata": metadata}, message_update_params.MessageUpdateParams), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Message, ) @@ -270,6 +282,7 @@ def list( }, message_list_params.MessageListParams, ), + security={"bearer_auth": True}, ), model=Message, ) @@ -307,7 +320,11 @@ def delete( return self._delete( path_template("/threads/{thread_id}/messages/{message_id}", thread_id=thread_id, message_id=message_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=MessageDeleted, ) @@ -397,7 +414,11 @@ async def create( message_create_params.MessageCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Message, ) @@ -435,7 +456,11 @@ async def retrieve( return await self._get( path_template("/threads/{thread_id}/messages/{message_id}", thread_id=thread_id, message_id=message_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Message, ) @@ -482,7 +507,11 @@ async def update( path_template("/threads/{thread_id}/messages/{message_id}", thread_id=thread_id, message_id=message_id), body=await async_maybe_transform({"metadata": metadata}, message_update_params.MessageUpdateParams), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Message, ) @@ -555,6 +584,7 @@ def list( }, message_list_params.MessageListParams, ), + security={"bearer_auth": True}, ), model=Message, ) @@ -592,7 +622,11 @@ async def delete( return await self._delete( path_template("/threads/{thread_id}/messages/{message_id}", thread_id=thread_id, message_id=message_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=MessageDeleted, ) diff --git a/src/openai/resources/beta/threads/runs/runs.py b/src/openai/resources/beta/threads/runs/runs.py index 882e88dfa6..263bc787c2 100644 --- a/src/openai/resources/beta/threads/runs/runs.py +++ b/src/openai/resources/beta/threads/runs/runs.py @@ -624,6 +624,7 @@ def create( extra_body=extra_body, timeout=timeout, query=maybe_transform({"include": include}, run_create_params.RunCreateParams), + security={"bearer_auth": True}, synthesize_event_and_data=True, ), cast_to=Run, @@ -664,7 +665,11 @@ def retrieve( return self._get( path_template("/threads/{thread_id}/runs/{run_id}", thread_id=thread_id, run_id=run_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Run, ) @@ -711,7 +716,11 @@ def update( path_template("/threads/{thread_id}/runs/{run_id}", thread_id=thread_id, run_id=run_id), body=maybe_transform({"metadata": metadata}, run_update_params.RunUpdateParams), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Run, ) @@ -780,6 +789,7 @@ def list( }, run_list_params.RunListParams, ), + security={"bearer_auth": True}, ), model=Run, ) @@ -817,7 +827,11 @@ def cancel( return self._post( path_template("/threads/{thread_id}/runs/{run_id}/cancel", thread_id=thread_id, run_id=run_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Run, ) @@ -1377,6 +1391,7 @@ def submit_tool_outputs( extra_query=extra_query, extra_body=extra_body, timeout=timeout, + security={"bearer_auth": True}, synthesize_event_and_data=True, ), cast_to=Run, @@ -2087,6 +2102,7 @@ async def create( extra_body=extra_body, timeout=timeout, query=await async_maybe_transform({"include": include}, run_create_params.RunCreateParams), + security={"bearer_auth": True}, synthesize_event_and_data=True, ), cast_to=Run, @@ -2127,7 +2143,11 @@ async def retrieve( return await self._get( path_template("/threads/{thread_id}/runs/{run_id}", thread_id=thread_id, run_id=run_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Run, ) @@ -2174,7 +2194,11 @@ async def update( path_template("/threads/{thread_id}/runs/{run_id}", thread_id=thread_id, run_id=run_id), body=await async_maybe_transform({"metadata": metadata}, run_update_params.RunUpdateParams), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Run, ) @@ -2243,6 +2267,7 @@ def list( }, run_list_params.RunListParams, ), + security={"bearer_auth": True}, ), model=Run, ) @@ -2280,7 +2305,11 @@ async def cancel( return await self._post( path_template("/threads/{thread_id}/runs/{run_id}/cancel", thread_id=thread_id, run_id=run_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Run, ) @@ -2839,6 +2868,7 @@ async def submit_tool_outputs( extra_query=extra_query, extra_body=extra_body, timeout=timeout, + security={"bearer_auth": True}, synthesize_event_and_data=True, ), cast_to=Run, diff --git a/src/openai/resources/beta/threads/runs/steps.py b/src/openai/resources/beta/threads/runs/steps.py index 9a6402b263..a251d27bf5 100644 --- a/src/openai/resources/beta/threads/runs/steps.py +++ b/src/openai/resources/beta/threads/runs/steps.py @@ -100,6 +100,7 @@ def retrieve( extra_body=extra_body, timeout=timeout, query=maybe_transform({"include": include}, step_retrieve_params.StepRetrieveParams), + security={"bearer_auth": True}, ), cast_to=RunStep, ) @@ -181,6 +182,7 @@ def list( }, step_list_params.StepListParams, ), + security={"bearer_auth": True}, ), model=RunStep, ) @@ -263,6 +265,7 @@ async def retrieve( extra_body=extra_body, timeout=timeout, query=await async_maybe_transform({"include": include}, step_retrieve_params.StepRetrieveParams), + security={"bearer_auth": True}, ), cast_to=RunStep, ) @@ -344,6 +347,7 @@ def list( }, step_list_params.StepListParams, ), + security={"bearer_auth": True}, ), model=RunStep, ) diff --git a/src/openai/resources/beta/threads/threads.py b/src/openai/resources/beta/threads/threads.py index 4b0f18fe47..dec6f31a38 100644 --- a/src/openai/resources/beta/threads/threads.py +++ b/src/openai/resources/beta/threads/threads.py @@ -144,7 +144,11 @@ def create( thread_create_params.ThreadCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Thread, ) @@ -179,7 +183,11 @@ def retrieve( return self._get( path_template("/threads/{thread_id}", thread_id=thread_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Thread, ) @@ -235,7 +243,11 @@ def update( thread_update_params.ThreadUpdateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Thread, ) @@ -270,7 +282,11 @@ def delete( return self._delete( path_template("/threads/{thread_id}", thread_id=thread_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ThreadDeleted, ) @@ -737,6 +753,7 @@ def create_and_run( extra_query=extra_query, extra_body=extra_body, timeout=timeout, + security={"bearer_auth": True}, synthesize_event_and_data=True, ), cast_to=Run, @@ -1010,7 +1027,11 @@ async def create( thread_create_params.ThreadCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Thread, ) @@ -1045,7 +1066,11 @@ async def retrieve( return await self._get( path_template("/threads/{thread_id}", thread_id=thread_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Thread, ) @@ -1101,7 +1126,11 @@ async def update( thread_update_params.ThreadUpdateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Thread, ) @@ -1136,7 +1165,11 @@ async def delete( return await self._delete( path_template("/threads/{thread_id}", thread_id=thread_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ThreadDeleted, ) @@ -1603,6 +1636,7 @@ async def create_and_run( extra_query=extra_query, extra_body=extra_body, timeout=timeout, + security={"bearer_auth": True}, synthesize_event_and_data=True, ), cast_to=Run, diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index 8b4fc12ae9..4158f032ee 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -1253,7 +1253,11 @@ def create( else completion_create_params.CompletionCreateParamsNonStreaming, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ChatCompletion, stream=stream or False, @@ -1290,7 +1294,11 @@ def retrieve( return self._get( path_template("/chat/completions/{completion_id}", completion_id=completion_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ChatCompletion, ) @@ -1335,7 +1343,11 @@ def update( path_template("/chat/completions/{completion_id}", completion_id=completion_id), body=maybe_transform({"metadata": metadata}, completion_update_params.CompletionUpdateParams), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ChatCompletion, ) @@ -1401,6 +1413,7 @@ def list( }, completion_list_params.CompletionListParams, ), + security={"bearer_auth": True}, ), model=ChatCompletion, ) @@ -1435,7 +1448,11 @@ def delete( return self._delete( path_template("/chat/completions/{completion_id}", completion_id=completion_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ChatCompletionDeleted, ) @@ -2756,7 +2773,11 @@ async def create( else completion_create_params.CompletionCreateParamsNonStreaming, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ChatCompletion, stream=stream or False, @@ -2793,7 +2814,11 @@ async def retrieve( return await self._get( path_template("/chat/completions/{completion_id}", completion_id=completion_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ChatCompletion, ) @@ -2838,7 +2863,11 @@ async def update( path_template("/chat/completions/{completion_id}", completion_id=completion_id), body=await async_maybe_transform({"metadata": metadata}, completion_update_params.CompletionUpdateParams), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ChatCompletion, ) @@ -2904,6 +2933,7 @@ def list( }, completion_list_params.CompletionListParams, ), + security={"bearer_auth": True}, ), model=ChatCompletion, ) @@ -2938,7 +2968,11 @@ async def delete( return await self._delete( path_template("/chat/completions/{completion_id}", completion_id=completion_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ChatCompletionDeleted, ) diff --git a/src/openai/resources/chat/completions/messages.py b/src/openai/resources/chat/completions/messages.py index ffbff566db..05dd23735a 100644 --- a/src/openai/resources/chat/completions/messages.py +++ b/src/openai/resources/chat/completions/messages.py @@ -97,6 +97,7 @@ def list( }, message_list_params.MessageListParams, ), + security={"bearer_auth": True}, ), model=ChatCompletionStoreMessage, ) @@ -179,6 +180,7 @@ def list( }, message_list_params.MessageListParams, ), + security={"bearer_auth": True}, ), model=ChatCompletionStoreMessage, ) diff --git a/src/openai/resources/completions.py b/src/openai/resources/completions.py index 4c9e266787..d2eb646a66 100644 --- a/src/openai/resources/completions.py +++ b/src/openai/resources/completions.py @@ -579,7 +579,11 @@ def create( else completion_create_params.CompletionCreateParamsNonStreaming, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Completion, stream=stream or False, @@ -1142,7 +1146,11 @@ async def create( else completion_create_params.CompletionCreateParamsNonStreaming, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Completion, stream=stream or False, diff --git a/src/openai/resources/containers/containers.py b/src/openai/resources/containers/containers.py index f6b8c33c75..7588ad7240 100644 --- a/src/openai/resources/containers/containers.py +++ b/src/openai/resources/containers/containers.py @@ -109,7 +109,11 @@ def create( container_create_params.ContainerCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ContainerCreateResponse, ) @@ -142,7 +146,11 @@ def retrieve( return self._get( path_template("/containers/{container_id}", container_id=container_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ContainerRetrieveResponse, ) @@ -204,6 +212,7 @@ def list( }, container_list_params.ContainerListParams, ), + security={"bearer_auth": True}, ), model=ContainerListResponse, ) @@ -237,7 +246,11 @@ def delete( return self._delete( path_template("/containers/{container_id}", container_id=container_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=NoneType, ) @@ -321,7 +334,11 @@ async def create( container_create_params.ContainerCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ContainerCreateResponse, ) @@ -354,7 +371,11 @@ async def retrieve( return await self._get( path_template("/containers/{container_id}", container_id=container_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ContainerRetrieveResponse, ) @@ -416,6 +437,7 @@ def list( }, container_list_params.ContainerListParams, ), + security={"bearer_auth": True}, ), model=ContainerListResponse, ) @@ -449,7 +471,11 @@ async def delete( return await self._delete( path_template("/containers/{container_id}", container_id=container_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=NoneType, ) diff --git a/src/openai/resources/containers/files/content.py b/src/openai/resources/containers/files/content.py index eb915b9c13..7df5e4cf2d 100644 --- a/src/openai/resources/containers/files/content.py +++ b/src/openai/resources/containers/files/content.py @@ -74,7 +74,11 @@ def retrieve( "/containers/{container_id}/files/{file_id}/content", container_id=container_id, file_id=file_id ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=_legacy_response.HttpxBinaryResponseContent, ) @@ -134,7 +138,11 @@ async def retrieve( "/containers/{container_id}/files/{file_id}/content", container_id=container_id, file_id=file_id ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=_legacy_response.HttpxBinaryResponseContent, ) diff --git a/src/openai/resources/containers/files/files.py b/src/openai/resources/containers/files/files.py index 80e0d61e0a..736b1fb75b 100644 --- a/src/openai/resources/containers/files/files.py +++ b/src/openai/resources/containers/files/files.py @@ -108,7 +108,11 @@ def create( body=maybe_transform(body, file_create_params.FileCreateParams), files=files, options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=FileCreateResponse, ) @@ -144,7 +148,11 @@ def retrieve( return self._get( path_template("/containers/{container_id}/files/{file_id}", container_id=container_id, file_id=file_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=FileRetrieveResponse, ) @@ -205,6 +213,7 @@ def list( }, file_list_params.FileListParams, ), + security={"bearer_auth": True}, ), model=FileListResponse, ) @@ -241,7 +250,11 @@ def delete( return self._delete( path_template("/containers/{container_id}/files/{file_id}", container_id=container_id, file_id=file_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=NoneType, ) @@ -323,7 +336,11 @@ async def create( body=await async_maybe_transform(body, file_create_params.FileCreateParams), files=files, options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=FileCreateResponse, ) @@ -359,7 +376,11 @@ async def retrieve( return await self._get( path_template("/containers/{container_id}/files/{file_id}", container_id=container_id, file_id=file_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=FileRetrieveResponse, ) @@ -420,6 +441,7 @@ def list( }, file_list_params.FileListParams, ), + security={"bearer_auth": True}, ), model=FileListResponse, ) @@ -456,7 +478,11 @@ async def delete( return await self._delete( path_template("/containers/{container_id}/files/{file_id}", container_id=container_id, file_id=file_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=NoneType, ) diff --git a/src/openai/resources/conversations/conversations.py b/src/openai/resources/conversations/conversations.py index d349f38546..bdc8e1d637 100644 --- a/src/openai/resources/conversations/conversations.py +++ b/src/openai/resources/conversations/conversations.py @@ -101,7 +101,11 @@ def create( conversation_create_params.ConversationCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Conversation, ) @@ -134,7 +138,11 @@ def retrieve( return self._get( path_template("/conversations/{conversation_id}", conversation_id=conversation_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Conversation, ) @@ -176,7 +184,11 @@ def update( path_template("/conversations/{conversation_id}", conversation_id=conversation_id), body=maybe_transform({"metadata": metadata}, conversation_update_params.ConversationUpdateParams), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Conversation, ) @@ -210,7 +222,11 @@ def delete( return self._delete( path_template("/conversations/{conversation_id}", conversation_id=conversation_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ConversationDeletedResource, ) @@ -287,7 +303,11 @@ async def create( conversation_create_params.ConversationCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Conversation, ) @@ -320,7 +340,11 @@ async def retrieve( return await self._get( path_template("/conversations/{conversation_id}", conversation_id=conversation_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Conversation, ) @@ -364,7 +388,11 @@ async def update( {"metadata": metadata}, conversation_update_params.ConversationUpdateParams ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Conversation, ) @@ -398,7 +426,11 @@ async def delete( return await self._delete( path_template("/conversations/{conversation_id}", conversation_id=conversation_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ConversationDeletedResource, ) diff --git a/src/openai/resources/conversations/items.py b/src/openai/resources/conversations/items.py index 7d7c9a4aba..01cdfe0804 100644 --- a/src/openai/resources/conversations/items.py +++ b/src/openai/resources/conversations/items.py @@ -89,6 +89,7 @@ def create( extra_body=extra_body, timeout=timeout, query=maybe_transform({"include": include}, item_create_params.ItemCreateParams), + security={"bearer_auth": True}, ), cast_to=ConversationItemList, ) @@ -138,6 +139,7 @@ def retrieve( extra_body=extra_body, timeout=timeout, query=maybe_transform({"include": include}, item_retrieve_params.ItemRetrieveParams), + security={"bearer_auth": True}, ), cast_to=cast(Any, ConversationItem), # Union types cannot be passed in as arguments in the type system ), @@ -218,6 +220,7 @@ def list( }, item_list_params.ItemListParams, ), + security={"bearer_auth": True}, ), model=cast(Any, ConversationItem), # Union types cannot be passed in as arguments in the type system ) @@ -255,7 +258,11 @@ def delete( "/conversations/{conversation_id}/items/{item_id}", conversation_id=conversation_id, item_id=item_id ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Conversation, ) @@ -325,6 +332,7 @@ async def create( extra_body=extra_body, timeout=timeout, query=await async_maybe_transform({"include": include}, item_create_params.ItemCreateParams), + security={"bearer_auth": True}, ), cast_to=ConversationItemList, ) @@ -374,6 +382,7 @@ async def retrieve( extra_body=extra_body, timeout=timeout, query=await async_maybe_transform({"include": include}, item_retrieve_params.ItemRetrieveParams), + security={"bearer_auth": True}, ), cast_to=cast(Any, ConversationItem), # Union types cannot be passed in as arguments in the type system ), @@ -454,6 +463,7 @@ def list( }, item_list_params.ItemListParams, ), + security={"bearer_auth": True}, ), model=cast(Any, ConversationItem), # Union types cannot be passed in as arguments in the type system ) @@ -491,7 +501,11 @@ async def delete( "/conversations/{conversation_id}/items/{item_id}", conversation_id=conversation_id, item_id=item_id ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Conversation, ) diff --git a/src/openai/resources/embeddings.py b/src/openai/resources/embeddings.py index 86eb949a40..6f44ebac96 100644 --- a/src/openai/resources/embeddings.py +++ b/src/openai/resources/embeddings.py @@ -259,12 +259,14 @@ def parser(obj: CreateEmbeddingResponse) -> CreateEmbeddingResponse: return await self._post( "/embeddings", body=maybe_transform(params, embedding_create_params.EmbeddingCreateParams), + options=make_request_options( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, post_parser=parser, + security={"bearer_auth": True}, ), cast_to=CreateEmbeddingResponse, ) diff --git a/src/openai/resources/evals/evals.py b/src/openai/resources/evals/evals.py index 6acd669a2c..a23c9cdef2 100644 --- a/src/openai/resources/evals/evals.py +++ b/src/openai/resources/evals/evals.py @@ -121,7 +121,11 @@ def create( eval_create_params.EvalCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=EvalCreateResponse, ) @@ -154,7 +158,11 @@ def retrieve( return self._get( path_template("/evals/{eval_id}", eval_id=eval_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=EvalRetrieveResponse, ) @@ -205,7 +213,11 @@ def update( eval_update_params.EvalUpdateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=EvalUpdateResponse, ) @@ -263,6 +275,7 @@ def list( }, eval_list_params.EvalListParams, ), + security={"bearer_auth": True}, ), model=EvalListResponse, ) @@ -295,7 +308,11 @@ def delete( return self._delete( path_template("/evals/{eval_id}", eval_id=eval_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=EvalDeleteResponse, ) @@ -388,7 +405,11 @@ async def create( eval_create_params.EvalCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=EvalCreateResponse, ) @@ -421,7 +442,11 @@ async def retrieve( return await self._get( path_template("/evals/{eval_id}", eval_id=eval_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=EvalRetrieveResponse, ) @@ -472,7 +497,11 @@ async def update( eval_update_params.EvalUpdateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=EvalUpdateResponse, ) @@ -530,6 +559,7 @@ def list( }, eval_list_params.EvalListParams, ), + security={"bearer_auth": True}, ), model=EvalListResponse, ) @@ -562,7 +592,11 @@ async def delete( return await self._delete( path_template("/evals/{eval_id}", eval_id=eval_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=EvalDeleteResponse, ) diff --git a/src/openai/resources/evals/runs/output_items.py b/src/openai/resources/evals/runs/output_items.py index 7a498a7ebf..2f884dd876 100644 --- a/src/openai/resources/evals/runs/output_items.py +++ b/src/openai/resources/evals/runs/output_items.py @@ -82,7 +82,11 @@ def retrieve( output_item_id=output_item_id, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=OutputItemRetrieveResponse, ) @@ -146,6 +150,7 @@ def list( }, output_item_list_params.OutputItemListParams, ), + security={"bearer_auth": True}, ), model=OutputItemListResponse, ) @@ -212,7 +217,11 @@ async def retrieve( output_item_id=output_item_id, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=OutputItemRetrieveResponse, ) @@ -276,6 +285,7 @@ def list( }, output_item_list_params.OutputItemListParams, ), + security={"bearer_auth": True}, ), model=OutputItemListResponse, ) diff --git a/src/openai/resources/evals/runs/runs.py b/src/openai/resources/evals/runs/runs.py index 152ce9cb77..ffba38db2e 100644 --- a/src/openai/resources/evals/runs/runs.py +++ b/src/openai/resources/evals/runs/runs.py @@ -113,7 +113,11 @@ def create( run_create_params.RunCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=RunCreateResponse, ) @@ -149,7 +153,11 @@ def retrieve( return self._get( path_template("/evals/{eval_id}/runs/{run_id}", eval_id=eval_id, run_id=run_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=RunRetrieveResponse, ) @@ -210,6 +218,7 @@ def list( }, run_list_params.RunListParams, ), + security={"bearer_auth": True}, ), model=RunListResponse, ) @@ -245,7 +254,11 @@ def delete( return self._delete( path_template("/evals/{eval_id}/runs/{run_id}", eval_id=eval_id, run_id=run_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=RunDeleteResponse, ) @@ -281,7 +294,11 @@ def cancel( return self._post( path_template("/evals/{eval_id}/runs/{run_id}", eval_id=eval_id, run_id=run_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=RunCancelResponse, ) @@ -366,7 +383,11 @@ async def create( run_create_params.RunCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=RunCreateResponse, ) @@ -402,7 +423,11 @@ async def retrieve( return await self._get( path_template("/evals/{eval_id}/runs/{run_id}", eval_id=eval_id, run_id=run_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=RunRetrieveResponse, ) @@ -463,6 +488,7 @@ def list( }, run_list_params.RunListParams, ), + security={"bearer_auth": True}, ), model=RunListResponse, ) @@ -498,7 +524,11 @@ async def delete( return await self._delete( path_template("/evals/{eval_id}/runs/{run_id}", eval_id=eval_id, run_id=run_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=RunDeleteResponse, ) @@ -534,7 +564,11 @@ async def cancel( return await self._post( path_template("/evals/{eval_id}/runs/{run_id}", eval_id=eval_id, run_id=run_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=RunCancelResponse, ) diff --git a/src/openai/resources/files.py b/src/openai/resources/files.py index 0cceb94b9d..868742f0f0 100644 --- a/src/openai/resources/files.py +++ b/src/openai/resources/files.py @@ -142,7 +142,11 @@ def create( body=maybe_transform(body, file_create_params.FileCreateParams), files=files, options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=FileObject, ) @@ -175,7 +179,11 @@ def retrieve( return self._get( path_template("/files/{file_id}", file_id=file_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=FileObject, ) @@ -237,6 +245,7 @@ def list( }, file_list_params.FileListParams, ), + security={"bearer_auth": True}, ), model=FileObject, ) @@ -269,7 +278,11 @@ def delete( return self._delete( path_template("/files/{file_id}", file_id=file_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=FileDeleted, ) @@ -303,7 +316,11 @@ def content( return self._get( path_template("/files/{file_id}/content", file_id=file_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=_legacy_response.HttpxBinaryResponseContent, ) @@ -337,7 +354,11 @@ def retrieve_content( return self._get( path_template("/files/{file_id}/content", file_id=file_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=str, ) @@ -475,7 +496,11 @@ async def create( body=await async_maybe_transform(body, file_create_params.FileCreateParams), files=files, options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=FileObject, ) @@ -508,7 +533,11 @@ async def retrieve( return await self._get( path_template("/files/{file_id}", file_id=file_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=FileObject, ) @@ -570,6 +599,7 @@ def list( }, file_list_params.FileListParams, ), + security={"bearer_auth": True}, ), model=FileObject, ) @@ -602,7 +632,11 @@ async def delete( return await self._delete( path_template("/files/{file_id}", file_id=file_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=FileDeleted, ) @@ -636,7 +670,11 @@ async def content( return await self._get( path_template("/files/{file_id}/content", file_id=file_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=_legacy_response.HttpxBinaryResponseContent, ) @@ -670,7 +708,11 @@ async def retrieve_content( return await self._get( path_template("/files/{file_id}/content", file_id=file_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=str, ) diff --git a/src/openai/resources/fine_tuning/alpha/graders.py b/src/openai/resources/fine_tuning/alpha/graders.py index e5d5dea5de..51c491b91f 100644 --- a/src/openai/resources/fine_tuning/alpha/graders.py +++ b/src/openai/resources/fine_tuning/alpha/graders.py @@ -88,7 +88,11 @@ def run( grader_run_params.GraderRunParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=GraderRunResponse, ) @@ -122,7 +126,11 @@ def validate( "/fine_tuning/alpha/graders/validate", body=maybe_transform({"grader": grader}, grader_validate_params.GraderValidateParams), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=GraderValidateResponse, ) @@ -198,7 +206,11 @@ async def run( grader_run_params.GraderRunParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=GraderRunResponse, ) @@ -232,7 +244,11 @@ async def validate( "/fine_tuning/alpha/graders/validate", body=await async_maybe_transform({"grader": grader}, grader_validate_params.GraderValidateParams), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=GraderValidateResponse, ) diff --git a/src/openai/resources/fine_tuning/checkpoints/permissions.py b/src/openai/resources/fine_tuning/checkpoints/permissions.py index 15184e130b..49687c15cd 100644 --- a/src/openai/resources/fine_tuning/checkpoints/permissions.py +++ b/src/openai/resources/fine_tuning/checkpoints/permissions.py @@ -91,7 +91,11 @@ def create( page=SyncPage[PermissionCreateResponse], body=maybe_transform({"project_ids": project_ids}, permission_create_params.PermissionCreateParams), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), model=PermissionCreateResponse, method="post", @@ -159,6 +163,7 @@ def retrieve( }, permission_retrieve_params.PermissionRetrieveParams, ), + security={"bearer_auth": True}, ), cast_to=PermissionRetrieveResponse, ) @@ -225,6 +230,7 @@ def list( }, permission_list_params.PermissionListParams, ), + security={"bearer_auth": True}, ), model=PermissionListResponse, ) @@ -269,7 +275,11 @@ def delete( permission_id=permission_id, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=PermissionDeleteResponse, ) @@ -338,7 +348,11 @@ def create( page=AsyncPage[PermissionCreateResponse], body=maybe_transform({"project_ids": project_ids}, permission_create_params.PermissionCreateParams), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), model=PermissionCreateResponse, method="post", @@ -406,6 +420,7 @@ async def retrieve( }, permission_retrieve_params.PermissionRetrieveParams, ), + security={"bearer_auth": True}, ), cast_to=PermissionRetrieveResponse, ) @@ -472,6 +487,7 @@ def list( }, permission_list_params.PermissionListParams, ), + security={"bearer_auth": True}, ), model=PermissionListResponse, ) @@ -516,7 +532,11 @@ async def delete( permission_id=permission_id, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=PermissionDeleteResponse, ) diff --git a/src/openai/resources/fine_tuning/jobs/checkpoints.py b/src/openai/resources/fine_tuning/jobs/checkpoints.py index 0f91a6218a..b679372386 100644 --- a/src/openai/resources/fine_tuning/jobs/checkpoints.py +++ b/src/openai/resources/fine_tuning/jobs/checkpoints.py @@ -89,6 +89,7 @@ def list( }, checkpoint_list_params.CheckpointListParams, ), + security={"bearer_auth": True}, ), model=FineTuningJobCheckpoint, ) @@ -162,6 +163,7 @@ def list( }, checkpoint_list_params.CheckpointListParams, ), + security={"bearer_auth": True}, ), model=FineTuningJobCheckpoint, ) diff --git a/src/openai/resources/fine_tuning/jobs/jobs.py b/src/openai/resources/fine_tuning/jobs/jobs.py index a948b10349..e7e8903a84 100644 --- a/src/openai/resources/fine_tuning/jobs/jobs.py +++ b/src/openai/resources/fine_tuning/jobs/jobs.py @@ -175,7 +175,11 @@ def create( job_create_params.JobCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=FineTuningJob, ) @@ -210,7 +214,11 @@ def retrieve( return self._get( path_template("/fine_tuning/jobs/{fine_tuning_job_id}", fine_tuning_job_id=fine_tuning_job_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=FineTuningJob, ) @@ -263,6 +271,7 @@ def list( }, job_list_params.JobListParams, ), + security={"bearer_auth": True}, ), model=FineTuningJob, ) @@ -295,7 +304,11 @@ def cancel( return self._post( path_template("/fine_tuning/jobs/{fine_tuning_job_id}/cancel", fine_tuning_job_id=fine_tuning_job_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=FineTuningJob, ) @@ -346,6 +359,7 @@ def list_events( }, job_list_events_params.JobListEventsParams, ), + security={"bearer_auth": True}, ), model=FineTuningJobEvent, ) @@ -378,7 +392,11 @@ def pause( return self._post( path_template("/fine_tuning/jobs/{fine_tuning_job_id}/pause", fine_tuning_job_id=fine_tuning_job_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=FineTuningJob, ) @@ -411,7 +429,11 @@ def resume( return self._post( path_template("/fine_tuning/jobs/{fine_tuning_job_id}/resume", fine_tuning_job_id=fine_tuning_job_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=FineTuningJob, ) @@ -558,7 +580,11 @@ async def create( job_create_params.JobCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=FineTuningJob, ) @@ -593,7 +619,11 @@ async def retrieve( return await self._get( path_template("/fine_tuning/jobs/{fine_tuning_job_id}", fine_tuning_job_id=fine_tuning_job_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=FineTuningJob, ) @@ -646,6 +676,7 @@ def list( }, job_list_params.JobListParams, ), + security={"bearer_auth": True}, ), model=FineTuningJob, ) @@ -678,7 +709,11 @@ async def cancel( return await self._post( path_template("/fine_tuning/jobs/{fine_tuning_job_id}/cancel", fine_tuning_job_id=fine_tuning_job_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=FineTuningJob, ) @@ -729,6 +764,7 @@ def list_events( }, job_list_events_params.JobListEventsParams, ), + security={"bearer_auth": True}, ), model=FineTuningJobEvent, ) @@ -761,7 +797,11 @@ async def pause( return await self._post( path_template("/fine_tuning/jobs/{fine_tuning_job_id}/pause", fine_tuning_job_id=fine_tuning_job_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=FineTuningJob, ) @@ -794,7 +834,11 @@ async def resume( return await self._post( path_template("/fine_tuning/jobs/{fine_tuning_job_id}/resume", fine_tuning_job_id=fine_tuning_job_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=FineTuningJob, ) diff --git a/src/openai/resources/images.py b/src/openai/resources/images.py index 2555b6c5db..ec4ca23aa2 100644 --- a/src/openai/resources/images.py +++ b/src/openai/resources/images.py @@ -116,7 +116,11 @@ def create_variation( body=maybe_transform(body, image_create_variation_params.ImageCreateVariationParams), files=files, options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ImagesResponse, ) @@ -519,7 +523,11 @@ def edit( ), files=files, options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ImagesResponse, stream=stream or False, @@ -911,7 +919,11 @@ def generate( else image_generate_params.ImageGenerateParamsNonStreaming, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ImagesResponse, stream=stream or False, @@ -1010,7 +1022,11 @@ async def create_variation( body=await async_maybe_transform(body, image_create_variation_params.ImageCreateVariationParams), files=files, options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ImagesResponse, ) @@ -1413,7 +1429,11 @@ async def edit( ), files=files, options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ImagesResponse, stream=stream or False, @@ -1805,7 +1825,11 @@ async def generate( else image_generate_params.ImageGenerateParamsNonStreaming, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ImagesResponse, stream=stream or False, diff --git a/src/openai/resources/models.py b/src/openai/resources/models.py index a1fe0d395e..a68fd83360 100644 --- a/src/openai/resources/models.py +++ b/src/openai/resources/models.py @@ -72,7 +72,11 @@ def retrieve( return self._get( path_template("/models/{model}", model=model), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Model, ) @@ -95,7 +99,11 @@ def list( "/models", page=SyncPage[Model], options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), model=Model, ) @@ -130,7 +138,11 @@ def delete( return self._delete( path_template("/models/{model}", model=model), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ModelDeleted, ) @@ -187,7 +199,11 @@ async def retrieve( return await self._get( path_template("/models/{model}", model=model), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Model, ) @@ -210,7 +226,11 @@ def list( "/models", page=AsyncPage[Model], options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), model=Model, ) @@ -245,7 +265,11 @@ async def delete( return await self._delete( path_template("/models/{model}", model=model), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ModelDeleted, ) diff --git a/src/openai/resources/moderations.py b/src/openai/resources/moderations.py index 0b9a2d23c7..5ef4efeaa5 100644 --- a/src/openai/resources/moderations.py +++ b/src/openai/resources/moderations.py @@ -89,7 +89,11 @@ def create( moderation_create_params.ModerationCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ModerationCreateResponse, ) @@ -163,7 +167,11 @@ async def create( moderation_create_params.ModerationCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ModerationCreateResponse, ) diff --git a/src/openai/resources/realtime/calls.py b/src/openai/resources/realtime/calls.py index 8fa2569a96..7a4fcc0110 100644 --- a/src/openai/resources/realtime/calls.py +++ b/src/openai/resources/realtime/calls.py @@ -98,7 +98,11 @@ def create( call_create_params.CallCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=_legacy_response.HttpxBinaryResponseContent, ) @@ -250,7 +254,11 @@ def accept( call_accept_params.CallAcceptParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=NoneType, ) @@ -284,7 +292,11 @@ def hangup( return self._post( path_template("/realtime/calls/{call_id}/hangup", call_id=call_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=NoneType, ) @@ -323,7 +335,11 @@ def refer( path_template("/realtime/calls/{call_id}/refer", call_id=call_id), body=maybe_transform({"target_uri": target_uri}, call_refer_params.CallReferParams), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=NoneType, ) @@ -362,7 +378,11 @@ def reject( path_template("/realtime/calls/{call_id}/reject", call_id=call_id), body=maybe_transform({"status_code": status_code}, call_reject_params.CallRejectParams), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=NoneType, ) @@ -428,7 +448,11 @@ async def create( call_create_params.CallCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=_legacy_response.HttpxBinaryResponseContent, ) @@ -580,7 +604,11 @@ async def accept( call_accept_params.CallAcceptParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=NoneType, ) @@ -614,7 +642,11 @@ async def hangup( return await self._post( path_template("/realtime/calls/{call_id}/hangup", call_id=call_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=NoneType, ) @@ -653,7 +685,11 @@ async def refer( path_template("/realtime/calls/{call_id}/refer", call_id=call_id), body=await async_maybe_transform({"target_uri": target_uri}, call_refer_params.CallReferParams), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=NoneType, ) @@ -692,7 +728,11 @@ async def reject( path_template("/realtime/calls/{call_id}/reject", call_id=call_id), body=await async_maybe_transform({"status_code": status_code}, call_reject_params.CallRejectParams), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=NoneType, ) diff --git a/src/openai/resources/realtime/client_secrets.py b/src/openai/resources/realtime/client_secrets.py index d9947dd7e8..7478e35e27 100644 --- a/src/openai/resources/realtime/client_secrets.py +++ b/src/openai/resources/realtime/client_secrets.py @@ -93,7 +93,11 @@ def create( client_secret_create_params.ClientSecretCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ClientSecretCreateResponse, ) @@ -175,7 +179,11 @@ async def create( client_secret_create_params.ClientSecretCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=ClientSecretCreateResponse, ) diff --git a/src/openai/resources/responses/input_items.py b/src/openai/resources/responses/input_items.py index b9ae5eeeae..1d3ed62543 100644 --- a/src/openai/resources/responses/input_items.py +++ b/src/openai/resources/responses/input_items.py @@ -101,6 +101,7 @@ def list( }, input_item_list_params.InputItemListParams, ), + security={"bearer_auth": True}, ), model=cast(Any, ResponseItem), # Union types cannot be passed in as arguments in the type system ) @@ -185,6 +186,7 @@ def list( }, input_item_list_params.InputItemListParams, ), + security={"bearer_auth": True}, ), model=cast(Any, ResponseItem), # Union types cannot be passed in as arguments in the type system ) diff --git a/src/openai/resources/responses/input_tokens.py b/src/openai/resources/responses/input_tokens.py index 0056727fa0..fae71fd59c 100644 --- a/src/openai/resources/responses/input_tokens.py +++ b/src/openai/resources/responses/input_tokens.py @@ -143,7 +143,11 @@ def count( input_token_count_params.InputTokenCountParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=InputTokenCountResponse, ) @@ -269,7 +273,11 @@ async def count( input_token_count_params.InputTokenCountParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=InputTokenCountResponse, ) diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 48705098cc..89a8ceffa1 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -953,7 +953,11 @@ def create( else response_create_params.ResponseCreateParamsNonStreaming, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Response, stream=stream or False, @@ -1505,6 +1509,7 @@ def retrieve( }, response_retrieve_params.ResponseRetrieveParams, ), + security={"bearer_auth": True}, ), cast_to=Response, stream=stream or False, @@ -1540,7 +1545,11 @@ def delete( return self._delete( path_template("/responses/{response_id}", response_id=response_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=NoneType, ) @@ -1576,7 +1585,11 @@ def cancel( return self._post( path_template("/responses/{response_id}/cancel", response_id=response_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Response, ) @@ -1748,7 +1761,11 @@ def compact( response_compact_params.ResponseCompactParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=CompactedResponse, ) @@ -2634,7 +2651,11 @@ async def create( else response_create_params.ResponseCreateParamsNonStreaming, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Response, stream=stream or False, @@ -3190,6 +3211,7 @@ async def retrieve( }, response_retrieve_params.ResponseRetrieveParams, ), + security={"bearer_auth": True}, ), cast_to=Response, stream=stream or False, @@ -3225,7 +3247,11 @@ async def delete( return await self._delete( path_template("/responses/{response_id}", response_id=response_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=NoneType, ) @@ -3261,7 +3287,11 @@ async def cancel( return await self._post( path_template("/responses/{response_id}/cancel", response_id=response_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Response, ) @@ -3433,7 +3463,11 @@ async def compact( response_compact_params.ResponseCompactParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=CompactedResponse, ) diff --git a/src/openai/resources/skills/content.py b/src/openai/resources/skills/content.py index 96b237177e..d0639a5a52 100644 --- a/src/openai/resources/skills/content.py +++ b/src/openai/resources/skills/content.py @@ -69,7 +69,11 @@ def retrieve( return self._get( path_template("/skills/{skill_id}/content", skill_id=skill_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=_legacy_response.HttpxBinaryResponseContent, ) @@ -124,7 +128,11 @@ async def retrieve( return await self._get( path_template("/skills/{skill_id}/content", skill_id=skill_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=_legacy_response.HttpxBinaryResponseContent, ) diff --git a/src/openai/resources/skills/skills.py b/src/openai/resources/skills/skills.py index 764ed65e84..aeea43ca3e 100644 --- a/src/openai/resources/skills/skills.py +++ b/src/openai/resources/skills/skills.py @@ -114,7 +114,11 @@ def create( body=maybe_transform(body, skill_create_params.SkillCreateParams), files=extracted_files, options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Skill, ) @@ -147,7 +151,11 @@ def retrieve( return self._get( path_template("/skills/{skill_id}", skill_id=skill_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Skill, ) @@ -184,7 +192,11 @@ def update( path_template("/skills/{skill_id}", skill_id=skill_id), body=maybe_transform({"default_version": default_version}, skill_update_params.SkillUpdateParams), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Skill, ) @@ -237,6 +249,7 @@ def list( }, skill_list_params.SkillListParams, ), + security={"bearer_auth": True}, ), model=Skill, ) @@ -269,7 +282,11 @@ def delete( return self._delete( path_template("/skills/{skill_id}", skill_id=skill_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=DeletedSkill, ) @@ -340,7 +357,11 @@ async def create( body=await async_maybe_transform(body, skill_create_params.SkillCreateParams), files=extracted_files, options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Skill, ) @@ -373,7 +394,11 @@ async def retrieve( return await self._get( path_template("/skills/{skill_id}", skill_id=skill_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Skill, ) @@ -412,7 +437,11 @@ async def update( {"default_version": default_version}, skill_update_params.SkillUpdateParams ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Skill, ) @@ -465,6 +494,7 @@ def list( }, skill_list_params.SkillListParams, ), + security={"bearer_auth": True}, ), model=Skill, ) @@ -497,7 +527,11 @@ async def delete( return await self._delete( path_template("/skills/{skill_id}", skill_id=skill_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=DeletedSkill, ) diff --git a/src/openai/resources/skills/versions/content.py b/src/openai/resources/skills/versions/content.py index 2f54586718..173f94e4e1 100644 --- a/src/openai/resources/skills/versions/content.py +++ b/src/openai/resources/skills/versions/content.py @@ -74,7 +74,11 @@ def retrieve( return self._get( path_template("/skills/{skill_id}/versions/{version}/content", skill_id=skill_id, version=version), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=_legacy_response.HttpxBinaryResponseContent, ) @@ -134,7 +138,11 @@ async def retrieve( return await self._get( path_template("/skills/{skill_id}/versions/{version}/content", skill_id=skill_id, version=version), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=_legacy_response.HttpxBinaryResponseContent, ) diff --git a/src/openai/resources/skills/versions/versions.py b/src/openai/resources/skills/versions/versions.py index 2259306a86..d688d2917c 100644 --- a/src/openai/resources/skills/versions/versions.py +++ b/src/openai/resources/skills/versions/versions.py @@ -114,7 +114,11 @@ def create( body=maybe_transform(body, version_create_params.VersionCreateParams), files=extracted_files, options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=SkillVersion, ) @@ -152,7 +156,11 @@ def retrieve( return self._get( path_template("/skills/{skill_id}/versions/{version}", skill_id=skill_id, version=version), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=SkillVersion, ) @@ -207,6 +215,7 @@ def list( }, version_list_params.VersionListParams, ), + security={"bearer_auth": True}, ), model=SkillVersion, ) @@ -244,7 +253,11 @@ def delete( return self._delete( path_template("/skills/{skill_id}/versions/{version}", skill_id=skill_id, version=version), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=DeletedSkillVersion, ) @@ -323,7 +336,11 @@ async def create( body=await async_maybe_transform(body, version_create_params.VersionCreateParams), files=extracted_files, options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=SkillVersion, ) @@ -361,7 +378,11 @@ async def retrieve( return await self._get( path_template("/skills/{skill_id}/versions/{version}", skill_id=skill_id, version=version), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=SkillVersion, ) @@ -416,6 +437,7 @@ def list( }, version_list_params.VersionListParams, ), + security={"bearer_auth": True}, ), model=SkillVersion, ) @@ -453,7 +475,11 @@ async def delete( return await self._delete( path_template("/skills/{skill_id}/versions/{version}", skill_id=skill_id, version=version), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=DeletedSkillVersion, ) diff --git a/src/openai/resources/uploads/parts.py b/src/openai/resources/uploads/parts.py index 3891fc028c..a0c1e15223 100644 --- a/src/openai/resources/uploads/parts.py +++ b/src/openai/resources/uploads/parts.py @@ -91,7 +91,11 @@ def create( body=maybe_transform(body, part_create_params.PartCreateParams), files=files, options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=UploadPart, ) @@ -168,7 +172,11 @@ async def create( body=await async_maybe_transform(body, part_create_params.PartCreateParams), files=files, options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=UploadPart, ) diff --git a/src/openai/resources/uploads/uploads.py b/src/openai/resources/uploads/uploads.py index 7778e51539..6c8c347f97 100644 --- a/src/openai/resources/uploads/uploads.py +++ b/src/openai/resources/uploads/uploads.py @@ -242,7 +242,11 @@ def create( upload_create_params.UploadCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Upload, ) @@ -278,7 +282,11 @@ def cancel( return self._post( path_template("/uploads/{upload_id}/cancel", upload_id=upload_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Upload, ) @@ -339,7 +347,11 @@ def complete( upload_complete_params.UploadCompleteParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Upload, ) @@ -558,7 +570,11 @@ async def create( upload_create_params.UploadCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Upload, ) @@ -594,7 +610,11 @@ async def cancel( return await self._post( path_template("/uploads/{upload_id}/cancel", upload_id=upload_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Upload, ) @@ -655,7 +675,11 @@ async def complete( upload_complete_params.UploadCompleteParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Upload, ) diff --git a/src/openai/resources/vector_stores/file_batches.py b/src/openai/resources/vector_stores/file_batches.py index 1ffd7642c0..4bde1a4aa6 100644 --- a/src/openai/resources/vector_stores/file_batches.py +++ b/src/openai/resources/vector_stores/file_batches.py @@ -113,7 +113,11 @@ def create( file_batch_create_params.FileBatchCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=VectorStoreFileBatch, ) @@ -154,7 +158,11 @@ def retrieve( batch_id=batch_id, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=VectorStoreFileBatch, ) @@ -197,7 +205,11 @@ def cancel( batch_id=batch_id, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=VectorStoreFileBatch, ) @@ -311,6 +323,7 @@ def list_files( }, file_batch_list_files_params.FileBatchListFilesParams, ), + security={"bearer_auth": True}, ), model=VectorStoreFile, ) @@ -488,7 +501,11 @@ async def create( file_batch_create_params.FileBatchCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=VectorStoreFileBatch, ) @@ -529,7 +546,11 @@ async def retrieve( batch_id=batch_id, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=VectorStoreFileBatch, ) @@ -572,7 +593,11 @@ async def cancel( batch_id=batch_id, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=VectorStoreFileBatch, ) @@ -686,6 +711,7 @@ def list_files( }, file_batch_list_files_params.FileBatchListFilesParams, ), + security={"bearer_auth": True}, ), model=VectorStoreFile, ) diff --git a/src/openai/resources/vector_stores/files.py b/src/openai/resources/vector_stores/files.py index 3ef6137267..b7e1ea9f92 100644 --- a/src/openai/resources/vector_stores/files.py +++ b/src/openai/resources/vector_stores/files.py @@ -102,7 +102,11 @@ def create( file_create_params.FileCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=VectorStoreFile, ) @@ -141,7 +145,11 @@ def retrieve( "/vector_stores/{vector_store_id}/files/{file_id}", vector_store_id=vector_store_id, file_id=file_id ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=VectorStoreFile, ) @@ -188,7 +196,11 @@ def update( ), body=maybe_transform({"attributes": attributes}, file_update_params.FileUpdateParams), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=VectorStoreFile, ) @@ -260,6 +272,7 @@ def list( }, file_list_params.FileListParams, ), + security={"bearer_auth": True}, ), model=VectorStoreFile, ) @@ -302,7 +315,11 @@ def delete( "/vector_stores/{vector_store_id}/files/{file_id}", vector_store_id=vector_store_id, file_id=file_id ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=VectorStoreFileDeleted, ) @@ -452,7 +469,11 @@ def content( ), page=SyncPage[FileContentResponse], options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), model=FileContentResponse, ) @@ -535,7 +556,11 @@ async def create( file_create_params.FileCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=VectorStoreFile, ) @@ -574,7 +599,11 @@ async def retrieve( "/vector_stores/{vector_store_id}/files/{file_id}", vector_store_id=vector_store_id, file_id=file_id ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=VectorStoreFile, ) @@ -621,7 +650,11 @@ async def update( ), body=await async_maybe_transform({"attributes": attributes}, file_update_params.FileUpdateParams), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=VectorStoreFile, ) @@ -693,6 +726,7 @@ def list( }, file_list_params.FileListParams, ), + security={"bearer_auth": True}, ), model=VectorStoreFile, ) @@ -735,7 +769,11 @@ async def delete( "/vector_stores/{vector_store_id}/files/{file_id}", vector_store_id=vector_store_id, file_id=file_id ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=VectorStoreFileDeleted, ) @@ -887,7 +925,11 @@ def content( ), page=AsyncPage[FileContentResponse], options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), model=FileContentResponse, ) diff --git a/src/openai/resources/vector_stores/vector_stores.py b/src/openai/resources/vector_stores/vector_stores.py index 7fa2ad5274..e4c5d1440c 100644 --- a/src/openai/resources/vector_stores/vector_stores.py +++ b/src/openai/resources/vector_stores/vector_stores.py @@ -139,7 +139,11 @@ def create( vector_store_create_params.VectorStoreCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=VectorStore, ) @@ -173,7 +177,11 @@ def retrieve( return self._get( path_template("/vector_stores/{vector_store_id}", vector_store_id=vector_store_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=VectorStore, ) @@ -229,7 +237,11 @@ def update( vector_store_update_params.VectorStoreUpdateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=VectorStore, ) @@ -295,6 +307,7 @@ def list( }, vector_store_list_params.VectorStoreListParams, ), + security={"bearer_auth": True}, ), model=VectorStore, ) @@ -328,7 +341,11 @@ def delete( return self._delete( path_template("/vector_stores/{vector_store_id}", vector_store_id=vector_store_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=VectorStoreDeleted, ) @@ -390,7 +407,11 @@ def search( vector_store_search_params.VectorStoreSearchParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), model=VectorStoreSearchResponse, method="post", @@ -489,7 +510,11 @@ async def create( vector_store_create_params.VectorStoreCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=VectorStore, ) @@ -523,7 +548,11 @@ async def retrieve( return await self._get( path_template("/vector_stores/{vector_store_id}", vector_store_id=vector_store_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=VectorStore, ) @@ -579,7 +608,11 @@ async def update( vector_store_update_params.VectorStoreUpdateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=VectorStore, ) @@ -645,6 +678,7 @@ def list( }, vector_store_list_params.VectorStoreListParams, ), + security={"bearer_auth": True}, ), model=VectorStore, ) @@ -678,7 +712,11 @@ async def delete( return await self._delete( path_template("/vector_stores/{vector_store_id}", vector_store_id=vector_store_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=VectorStoreDeleted, ) @@ -740,7 +778,11 @@ def search( vector_store_search_params.VectorStoreSearchParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), model=VectorStoreSearchResponse, method="post", diff --git a/src/openai/resources/videos.py b/src/openai/resources/videos.py index 3b80400cac..e9bad80afe 100644 --- a/src/openai/resources/videos.py +++ b/src/openai/resources/videos.py @@ -125,7 +125,11 @@ def create( body=maybe_transform(body, video_create_params.VideoCreateParams), files=files, options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Video, ) @@ -231,7 +235,11 @@ def retrieve( return self._get( path_template("/videos/{video_id}", video_id=video_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Video, ) @@ -284,6 +292,7 @@ def list( }, video_list_params.VideoListParams, ), + security={"bearer_auth": True}, ), model=Video, ) @@ -316,7 +325,11 @@ def delete( return self._delete( path_template("/videos/{video_id}", video_id=video_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=VideoDeleteResponse, ) @@ -366,7 +379,11 @@ def create_character( body=maybe_transform(body, video_create_character_params.VideoCreateCharacterParams), files=files, options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=VideoCreateCharacterResponse, ) @@ -410,6 +427,7 @@ def download_content( extra_body=extra_body, timeout=timeout, query=maybe_transform({"variant": variant}, video_download_content_params.VideoDownloadContentParams), + security={"bearer_auth": True}, ), cast_to=_legacy_response.HttpxBinaryResponseContent, ) @@ -460,7 +478,11 @@ def edit( body=maybe_transform(body, video_edit_params.VideoEditParams), files=files, options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Video, ) @@ -515,7 +537,11 @@ def extend( body=maybe_transform(body, video_extend_params.VideoExtendParams), files=files, options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Video, ) @@ -548,7 +574,11 @@ def get_character( return self._get( path_template("/videos/characters/{character_id}", character_id=character_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=VideoGetCharacterResponse, ) @@ -585,7 +615,11 @@ def remix( path_template("/videos/{video_id}/remix", video_id=video_id), body=maybe_transform({"prompt": prompt}, video_remix_params.VideoRemixParams), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Video, ) @@ -670,7 +704,11 @@ async def create( body=await async_maybe_transform(body, video_create_params.VideoCreateParams), files=files, options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Video, ) @@ -776,7 +814,11 @@ async def retrieve( return await self._get( path_template("/videos/{video_id}", video_id=video_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Video, ) @@ -829,6 +871,7 @@ def list( }, video_list_params.VideoListParams, ), + security={"bearer_auth": True}, ), model=Video, ) @@ -861,7 +904,11 @@ async def delete( return await self._delete( path_template("/videos/{video_id}", video_id=video_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=VideoDeleteResponse, ) @@ -911,7 +958,11 @@ async def create_character( body=await async_maybe_transform(body, video_create_character_params.VideoCreateCharacterParams), files=files, options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=VideoCreateCharacterResponse, ) @@ -957,6 +1008,7 @@ async def download_content( query=await async_maybe_transform( {"variant": variant}, video_download_content_params.VideoDownloadContentParams ), + security={"bearer_auth": True}, ), cast_to=_legacy_response.HttpxBinaryResponseContent, ) @@ -1007,7 +1059,11 @@ async def edit( body=await async_maybe_transform(body, video_edit_params.VideoEditParams), files=files, options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Video, ) @@ -1062,7 +1118,11 @@ async def extend( body=await async_maybe_transform(body, video_extend_params.VideoExtendParams), files=files, options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Video, ) @@ -1095,7 +1155,11 @@ async def get_character( return await self._get( path_template("/videos/characters/{character_id}", character_id=character_id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=VideoGetCharacterResponse, ) @@ -1132,7 +1196,11 @@ async def remix( path_template("/videos/{video_id}/remix", video_id=video_id), body=await async_maybe_transform({"prompt": prompt}, video_remix_params.VideoRemixParams), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Video, ) diff --git a/src/openai/types/admin/__init__.py b/src/openai/types/admin/__init__.py new file mode 100644 index 0000000000..f8ee8b14b1 --- /dev/null +++ b/src/openai/types/admin/__init__.py @@ -0,0 +1,3 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations diff --git a/tests/conftest.py b/tests/conftest.py index 408bcf76c0..1042fe59d9 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -46,6 +46,7 @@ def pytest_collection_modifyitems(items: list[pytest.Function]) -> None: base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") api_key = "My API Key" +admin_api_key = "My Admin API Key" @pytest.fixture(scope="session") @@ -54,7 +55,9 @@ def client(request: FixtureRequest) -> Iterator[OpenAI]: if not isinstance(strict, bool): raise TypeError(f"Unexpected fixture parameter type {type(strict)}, expected {bool}") - with OpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=strict) as client: + with OpenAI( + base_url=base_url, api_key=api_key, admin_api_key=admin_api_key, _strict_response_validation=strict + ) as client: yield client @@ -79,6 +82,10 @@ async def async_client(request: FixtureRequest) -> AsyncIterator[AsyncOpenAI]: raise TypeError(f"Unexpected fixture parameter type {type(param)}, expected bool or dict") async with AsyncOpenAI( - base_url=base_url, api_key=api_key, _strict_response_validation=strict, http_client=http_client + base_url=base_url, + api_key=api_key, + admin_api_key=admin_api_key, + _strict_response_validation=strict, + http_client=http_client, ) as client: yield client diff --git a/tests/test_client.py b/tests/test_client.py index 570042c46a..369d746b2d 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -25,7 +25,7 @@ from openai._utils import asyncify from openai._models import BaseModel, FinalRequestOptions from openai._streaming import Stream, AsyncStream -from openai._exceptions import OpenAIError, APIStatusError, APITimeoutError, APIResponseValidationError +from openai._exceptions import APIStatusError, APITimeoutError, APIResponseValidationError from openai._base_client import ( DEFAULT_TIMEOUT, HTTPX_DEFAULT_TIMEOUT, @@ -42,19 +42,7 @@ T = TypeVar("T") base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") api_key = "My API Key" -workload_identity: WorkloadIdentity = { - "client_id": "client-id", - "identity_provider_id": "identity-provider-id", - "service_account_id": "service-account-id", - "provider": { - "token_type": "jwt", - "get_token": lambda: "external-subject-token", - }, -} - - -class MockRequestCall(Protocol): - request: httpx.Request +admin_api_key = "My Admin API Key" def _get_params(client: BaseClient[Any, Any]) -> dict[str, str]: @@ -155,6 +143,10 @@ def test_copy(self, client: OpenAI) -> None: assert copied.api_key == "another My API Key" assert client.api_key == "My API Key" + copied = client.copy(admin_api_key="another My Admin API Key") + assert copied.admin_api_key == "another My Admin API Key" + assert client.admin_api_key == "My Admin API Key" + def test_copy_default_options(self, client: OpenAI) -> None: # options that have a default are overridden correctly copied = client.copy(max_retries=7) @@ -173,7 +165,11 @@ def test_copy_default_options(self, client: OpenAI) -> None: def test_copy_default_headers(self) -> None: client = OpenAI( - base_url=base_url, api_key=api_key, _strict_response_validation=True, default_headers={"X-Foo": "bar"} + base_url=base_url, + api_key=api_key, + admin_api_key=admin_api_key, + _strict_response_validation=True, + default_headers={"X-Foo": "bar"}, ) assert client.default_headers["X-Foo"] == "bar" @@ -208,7 +204,11 @@ def test_copy_default_headers(self) -> None: def test_copy_default_query(self) -> None: client = OpenAI( - base_url=base_url, api_key=api_key, _strict_response_validation=True, default_query={"foo": "bar"} + base_url=base_url, + api_key=api_key, + admin_api_key=admin_api_key, + _strict_response_validation=True, + default_query={"foo": "bar"}, ) assert _get_params(client)["foo"] == "bar" @@ -333,7 +333,13 @@ def test_request_timeout(self, client: OpenAI) -> None: assert timeout == httpx.Timeout(100.0) def test_client_timeout_option(self) -> None: - client = OpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=True, timeout=httpx.Timeout(0)) + client = OpenAI( + base_url=base_url, + api_key=api_key, + admin_api_key=admin_api_key, + _strict_response_validation=True, + timeout=httpx.Timeout(0), + ) request = client._build_request(FinalRequestOptions(method="get", url="/foo")) timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore @@ -345,7 +351,11 @@ def test_http_client_timeout_option(self) -> None: # custom timeout given to the httpx client should be used with httpx.Client(timeout=None) as http_client: client = OpenAI( - base_url=base_url, api_key=api_key, _strict_response_validation=True, http_client=http_client + base_url=base_url, + api_key=api_key, + admin_api_key=admin_api_key, + _strict_response_validation=True, + http_client=http_client, ) request = client._build_request(FinalRequestOptions(method="get", url="/foo")) @@ -357,7 +367,11 @@ def test_http_client_timeout_option(self) -> None: # no timeout given to the httpx client should not use the httpx default with httpx.Client() as http_client: client = OpenAI( - base_url=base_url, api_key=api_key, _strict_response_validation=True, http_client=http_client + base_url=base_url, + api_key=api_key, + admin_api_key=admin_api_key, + _strict_response_validation=True, + http_client=http_client, ) request = client._build_request(FinalRequestOptions(method="get", url="/foo")) @@ -369,7 +383,11 @@ def test_http_client_timeout_option(self) -> None: # explicitly passing the default timeout currently results in it being ignored with httpx.Client(timeout=HTTPX_DEFAULT_TIMEOUT) as http_client: client = OpenAI( - base_url=base_url, api_key=api_key, _strict_response_validation=True, http_client=http_client + base_url=base_url, + api_key=api_key, + admin_api_key=admin_api_key, + _strict_response_validation=True, + http_client=http_client, ) request = client._build_request(FinalRequestOptions(method="get", url="/foo")) @@ -384,13 +402,18 @@ async def test_invalid_http_client(self) -> None: OpenAI( base_url=base_url, api_key=api_key, + admin_api_key=admin_api_key, _strict_response_validation=True, http_client=cast(Any, http_client), ) def test_default_headers_option(self) -> None: test_client = OpenAI( - base_url=base_url, api_key=api_key, _strict_response_validation=True, default_headers={"X-Foo": "bar"} + base_url=base_url, + api_key=api_key, + admin_api_key=admin_api_key, + _strict_response_validation=True, + default_headers={"X-Foo": "bar"}, ) request = test_client._build_request(FinalRequestOptions(method="get", url="/foo")) assert request.headers.get("x-foo") == "bar" @@ -399,6 +422,7 @@ def test_default_headers_option(self) -> None: test_client2 = OpenAI( base_url=base_url, api_key=api_key, + admin_api_key=admin_api_key, _strict_response_validation=True, default_headers={ "X-Foo": "stainless", @@ -413,16 +437,72 @@ def test_default_headers_option(self) -> None: test_client2.close() def test_validate_headers(self) -> None: - client = OpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=True) + default_headers={ + "X-Foo": "stainless", + "X-Stainless-Lang": "my-overriding-header", + }, + ) + request = test_client2._build_request(FinalRequestOptions(method="get", url="/foo")) + assert request.headers.get("x-foo") == "stainless" + assert request.headers.get("x-stainless-lang") == "my-overriding-header" + + test_client.close() + test_client2.close() + + def test_validate_headers(self) -> None: + client = OpenAI( + base_url=base_url, api_key=api_key, admin_api_key=admin_api_key, _strict_response_validation=True + ) options = client._prepare_options(FinalRequestOptions(method="get", url="/foo")) request = client._build_request(options) assert request.headers.get("Authorization") == f"Bearer {api_key}" - with pytest.raises(OpenAIError): - with update_env(**{"OPENAI_API_KEY": Omit()}): - client2 = OpenAI(base_url=base_url, api_key=None, _strict_response_validation=True) - _ = client2 + admin_request = client._build_request( + FinalRequestOptions( + method="get", + url="/organization/projects", + security={"admin_api_key_auth": True}, + ) + ) + assert admin_request.headers.get("Authorization") == f"Bearer {admin_api_key}" + + with update_env(**{"OPENAI_API_KEY": Omit()}): + admin_only = OpenAI( + base_url=base_url, + api_key=None, + admin_api_key=admin_api_key, + _strict_response_validation=True, + ) + admin_only_request = admin_only._build_request( + FinalRequestOptions( + method="get", + url="/organization/projects", + security={"admin_api_key_auth": True}, + ) + ) + assert admin_only_request.headers.get("Authorization") == f"Bearer {admin_api_key}" + + with pytest.raises( + TypeError, + match="Could not resolve authentication method", + ): + admin_only._build_request( + FinalRequestOptions( + method="post", + url="/responses", + security={"bearer_auth": True}, + ) + ) + + with update_env( + **{ + "OPENAI_API_KEY": Omit(), + "OPENAI_ADMIN_KEY": Omit(), + } + ): + with pytest.raises(OpenAIError, match="Missing credentials"): + OpenAI(base_url=base_url, api_key=None, admin_api_key=None, _strict_response_validation=True) def test_workload_identity_is_mutually_exclusive_with_api_key(self) -> None: with pytest.raises( @@ -439,7 +519,11 @@ def test_workload_identity_is_mutually_exclusive_with_api_key(self) -> None: def test_default_query_option(self) -> None: client = OpenAI( - base_url=base_url, api_key=api_key, _strict_response_validation=True, default_query={"query_param": "bar"} + base_url=base_url, + api_key=api_key, + admin_api_key=admin_api_key, + _strict_response_validation=True, + default_query={"query_param": "bar"}, ) request = client._build_request(FinalRequestOptions(method="get", url="/foo")) url = httpx.URL(request.url) @@ -636,6 +720,7 @@ def mock_handler(request: httpx.Request) -> httpx.Response: with OpenAI( base_url=base_url, api_key=api_key, + admin_api_key=admin_api_key, _strict_response_validation=True, http_client=httpx.Client(transport=MockTransport(handler=mock_handler)), ) as client: @@ -729,7 +814,12 @@ class Model(BaseModel): assert response.foo == 2 def test_base_url_setter(self) -> None: - client = OpenAI(base_url="https://example.com/from_init", api_key=api_key, _strict_response_validation=True) + client = OpenAI( + base_url="https://example.com/from_init", + api_key=api_key, + admin_api_key=admin_api_key, + _strict_response_validation=True, + ) assert client.base_url == "https://example.com/from_init/" client.base_url = "https://example.com/from_setter" # type: ignore[assignment] @@ -740,16 +830,22 @@ def test_base_url_setter(self) -> None: def test_base_url_env(self) -> None: with update_env(OPENAI_BASE_URL="http://localhost:5000/from/env"): - client = OpenAI(api_key=api_key, _strict_response_validation=True) + client = OpenAI(api_key=api_key, admin_api_key=admin_api_key, _strict_response_validation=True) assert client.base_url == "http://localhost:5000/from/env/" @pytest.mark.parametrize( "client", [ - OpenAI(base_url="http://localhost:5000/custom/path/", api_key=api_key, _strict_response_validation=True), OpenAI( base_url="http://localhost:5000/custom/path/", api_key=api_key, + admin_api_key=admin_api_key, + _strict_response_validation=True, + ), + OpenAI( + base_url="http://localhost:5000/custom/path/", + api_key=api_key, + admin_api_key=admin_api_key, _strict_response_validation=True, http_client=httpx.Client(), ), @@ -770,10 +866,16 @@ def test_base_url_trailing_slash(self, client: OpenAI) -> None: @pytest.mark.parametrize( "client", [ - OpenAI(base_url="http://localhost:5000/custom/path/", api_key=api_key, _strict_response_validation=True), OpenAI( base_url="http://localhost:5000/custom/path/", api_key=api_key, + admin_api_key=admin_api_key, + _strict_response_validation=True, + ), + OpenAI( + base_url="http://localhost:5000/custom/path/", + api_key=api_key, + admin_api_key=admin_api_key, _strict_response_validation=True, http_client=httpx.Client(), ), @@ -794,10 +896,16 @@ def test_base_url_no_trailing_slash(self, client: OpenAI) -> None: @pytest.mark.parametrize( "client", [ - OpenAI(base_url="http://localhost:5000/custom/path/", api_key=api_key, _strict_response_validation=True), OpenAI( base_url="http://localhost:5000/custom/path/", api_key=api_key, + admin_api_key=admin_api_key, + _strict_response_validation=True, + ), + OpenAI( + base_url="http://localhost:5000/custom/path/", + api_key=api_key, + admin_api_key=admin_api_key, _strict_response_validation=True, http_client=httpx.Client(), ), @@ -816,7 +924,9 @@ def test_absolute_request_url(self, client: OpenAI) -> None: client.close() def test_copied_client_does_not_close_http(self) -> None: - test_client = OpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=True) + test_client = OpenAI( + base_url=base_url, api_key=api_key, admin_api_key=admin_api_key, _strict_response_validation=True + ) assert not test_client.is_closed() copied = test_client.copy() @@ -827,7 +937,9 @@ def test_copied_client_does_not_close_http(self) -> None: assert not test_client.is_closed() def test_client_context_manager(self) -> None: - test_client = OpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=True) + test_client = OpenAI( + base_url=base_url, api_key=api_key, admin_api_key=admin_api_key, _strict_response_validation=True + ) with test_client as c2: assert c2 is test_client assert not c2.is_closed() @@ -848,7 +960,13 @@ class Model(BaseModel): def test_client_max_retries_validation(self) -> None: with pytest.raises(TypeError, match=r"max_retries cannot be None"): - OpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=True, max_retries=cast(Any, None)) + OpenAI( + base_url=base_url, + api_key=api_key, + admin_api_key=admin_api_key, + _strict_response_validation=True, + max_retries=cast(Any, None), + ) @pytest.mark.respx(base_url=base_url) def test_default_stream_cls(self, respx_mock: MockRouter, client: OpenAI) -> None: @@ -868,12 +986,16 @@ class Model(BaseModel): respx_mock.get("/foo").mock(return_value=httpx.Response(200, text="my-custom-format")) - strict_client = OpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=True) + strict_client = OpenAI( + base_url=base_url, api_key=api_key, admin_api_key=admin_api_key, _strict_response_validation=True + ) with pytest.raises(APIResponseValidationError): strict_client.get("/foo", cast_to=Model) - non_strict_client = OpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=False) + non_strict_client = OpenAI( + base_url=base_url, api_key=api_key, admin_api_key=admin_api_key, _strict_response_validation=False + ) response = non_strict_client.get("/foo", cast_to=Model) assert isinstance(response, str) # type: ignore[unreachable] @@ -1221,6 +1343,10 @@ def test_copy(self, async_client: AsyncOpenAI) -> None: assert copied.api_key == "another My API Key" assert async_client.api_key == "My API Key" + copied = async_client.copy(admin_api_key="another My Admin API Key") + assert copied.admin_api_key == "another My Admin API Key" + assert async_client.admin_api_key == "My Admin API Key" + def test_copy_default_options(self, async_client: AsyncOpenAI) -> None: # options that have a default are overridden correctly copied = async_client.copy(max_retries=7) @@ -1239,7 +1365,11 @@ def test_copy_default_options(self, async_client: AsyncOpenAI) -> None: async def test_copy_default_headers(self) -> None: client = AsyncOpenAI( - base_url=base_url, api_key=api_key, _strict_response_validation=True, default_headers={"X-Foo": "bar"} + base_url=base_url, + api_key=api_key, + admin_api_key=admin_api_key, + _strict_response_validation=True, + default_headers={"X-Foo": "bar"}, ) assert client.default_headers["X-Foo"] == "bar" @@ -1274,7 +1404,11 @@ async def test_copy_default_headers(self) -> None: async def test_copy_default_query(self) -> None: client = AsyncOpenAI( - base_url=base_url, api_key=api_key, _strict_response_validation=True, default_query={"foo": "bar"} + base_url=base_url, + api_key=api_key, + admin_api_key=admin_api_key, + _strict_response_validation=True, + default_query={"foo": "bar"}, ) assert _get_params(client)["foo"] == "bar" @@ -1402,7 +1536,11 @@ async def test_request_timeout(self, async_client: AsyncOpenAI) -> None: async def test_client_timeout_option(self) -> None: client = AsyncOpenAI( - base_url=base_url, api_key=api_key, _strict_response_validation=True, timeout=httpx.Timeout(0) + base_url=base_url, + api_key=api_key, + admin_api_key=admin_api_key, + _strict_response_validation=True, + timeout=httpx.Timeout(0), ) request = client._build_request(FinalRequestOptions(method="get", url="/foo")) @@ -1415,7 +1553,11 @@ async def test_http_client_timeout_option(self) -> None: # custom timeout given to the httpx client should be used async with httpx.AsyncClient(timeout=None) as http_client: client = AsyncOpenAI( - base_url=base_url, api_key=api_key, _strict_response_validation=True, http_client=http_client + base_url=base_url, + api_key=api_key, + admin_api_key=admin_api_key, + _strict_response_validation=True, + http_client=http_client, ) request = client._build_request(FinalRequestOptions(method="get", url="/foo")) @@ -1427,7 +1569,11 @@ async def test_http_client_timeout_option(self) -> None: # no timeout given to the httpx client should not use the httpx default async with httpx.AsyncClient() as http_client: client = AsyncOpenAI( - base_url=base_url, api_key=api_key, _strict_response_validation=True, http_client=http_client + base_url=base_url, + api_key=api_key, + admin_api_key=admin_api_key, + _strict_response_validation=True, + http_client=http_client, ) request = client._build_request(FinalRequestOptions(method="get", url="/foo")) @@ -1439,7 +1585,11 @@ async def test_http_client_timeout_option(self) -> None: # explicitly passing the default timeout currently results in it being ignored async with httpx.AsyncClient(timeout=HTTPX_DEFAULT_TIMEOUT) as http_client: client = AsyncOpenAI( - base_url=base_url, api_key=api_key, _strict_response_validation=True, http_client=http_client + base_url=base_url, + api_key=api_key, + admin_api_key=admin_api_key, + _strict_response_validation=True, + http_client=http_client, ) request = client._build_request(FinalRequestOptions(method="get", url="/foo")) @@ -1454,13 +1604,18 @@ def test_invalid_http_client(self) -> None: AsyncOpenAI( base_url=base_url, api_key=api_key, + admin_api_key=admin_api_key, _strict_response_validation=True, http_client=cast(Any, http_client), ) async def test_default_headers_option(self) -> None: test_client = AsyncOpenAI( - base_url=base_url, api_key=api_key, _strict_response_validation=True, default_headers={"X-Foo": "bar"} + base_url=base_url, + api_key=api_key, + admin_api_key=admin_api_key, + _strict_response_validation=True, + default_headers={"X-Foo": "bar"}, ) request = test_client._build_request(FinalRequestOptions(method="get", url="/foo")) assert request.headers.get("x-foo") == "bar" @@ -1469,6 +1624,7 @@ async def test_default_headers_option(self) -> None: test_client2 = AsyncOpenAI( base_url=base_url, api_key=api_key, + admin_api_key=admin_api_key, _strict_response_validation=True, default_headers={ "X-Foo": "stainless", @@ -1483,19 +1639,66 @@ async def test_default_headers_option(self) -> None: await test_client2.close() async def test_validate_headers(self) -> None: - client = AsyncOpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=True) + client = AsyncOpenAI( + base_url=base_url, api_key=api_key, admin_api_key=admin_api_key, _strict_response_validation=True + ) options = await client._prepare_options(FinalRequestOptions(method="get", url="/foo")) request = client._build_request(options) assert request.headers.get("Authorization") == f"Bearer {api_key}" - with pytest.raises(OpenAIError): - with update_env(**{"OPENAI_API_KEY": Omit()}): - client2 = AsyncOpenAI(base_url=base_url, api_key=None, _strict_response_validation=True) - _ = client2 + admin_request = client._build_request( + FinalRequestOptions( + method="get", + url="/organization/projects", + security={"admin_api_key_auth": True}, + ) + ) + assert admin_request.headers.get("Authorization") == f"Bearer {admin_api_key}" + + with update_env(**{"OPENAI_API_KEY": Omit()}): + admin_only = AsyncOpenAI( + base_url=base_url, + api_key=None, + admin_api_key=admin_api_key, + _strict_response_validation=True, + ) + admin_only_request = admin_only._build_request( + FinalRequestOptions( + method="get", + url="/organization/projects", + security={"admin_api_key_auth": True}, + ) + ) + assert admin_only_request.headers.get("Authorization") == f"Bearer {admin_api_key}" + + with pytest.raises( + TypeError, + match="Could not resolve authentication method", + ): + admin_only._build_request( + FinalRequestOptions( + method="post", + url="/responses", + security={"bearer_auth": True}, + ) + ) + + with update_env( + **{ + "OPENAI_API_KEY": Omit(), + "OPENAI_ADMIN_KEY": Omit(), + } + ): + with pytest.raises(OpenAIError, match="Missing credentials"): + AsyncOpenAI(base_url=base_url, api_key=None, admin_api_key=None, _strict_response_validation=True) async def test_default_query_option(self) -> None: client = AsyncOpenAI( - base_url=base_url, api_key=api_key, _strict_response_validation=True, default_query={"query_param": "bar"} + base_url=base_url, + api_key=api_key, + admin_api_key=admin_api_key, + _strict_response_validation=True, + default_query={"query_param": "bar"}, ) request = client._build_request(FinalRequestOptions(method="get", url="/foo")) url = httpx.URL(request.url) @@ -1692,6 +1895,7 @@ async def mock_handler(request: httpx.Request) -> httpx.Response: async with AsyncOpenAI( base_url=base_url, api_key=api_key, + admin_api_key=admin_api_key, _strict_response_validation=True, http_client=httpx.AsyncClient(transport=MockTransport(handler=mock_handler)), ) as client: @@ -1790,7 +1994,10 @@ class Model(BaseModel): async def test_base_url_setter(self) -> None: client = AsyncOpenAI( - base_url="https://example.com/from_init", api_key=api_key, _strict_response_validation=True + base_url="https://example.com/from_init", + api_key=api_key, + admin_api_key=admin_api_key, + _strict_response_validation=True, ) assert client.base_url == "https://example.com/from_init/" @@ -1802,18 +2009,22 @@ async def test_base_url_setter(self) -> None: async def test_base_url_env(self) -> None: with update_env(OPENAI_BASE_URL="http://localhost:5000/from/env"): - client = AsyncOpenAI(api_key=api_key, _strict_response_validation=True) + client = AsyncOpenAI(api_key=api_key, admin_api_key=admin_api_key, _strict_response_validation=True) assert client.base_url == "http://localhost:5000/from/env/" @pytest.mark.parametrize( "client", [ AsyncOpenAI( - base_url="http://localhost:5000/custom/path/", api_key=api_key, _strict_response_validation=True + base_url="http://localhost:5000/custom/path/", + api_key=api_key, + admin_api_key=admin_api_key, + _strict_response_validation=True, ), AsyncOpenAI( base_url="http://localhost:5000/custom/path/", api_key=api_key, + admin_api_key=admin_api_key, _strict_response_validation=True, http_client=httpx.AsyncClient(), ), @@ -1835,11 +2046,15 @@ async def test_base_url_trailing_slash(self, client: AsyncOpenAI) -> None: "client", [ AsyncOpenAI( - base_url="http://localhost:5000/custom/path/", api_key=api_key, _strict_response_validation=True + base_url="http://localhost:5000/custom/path/", + api_key=api_key, + admin_api_key=admin_api_key, + _strict_response_validation=True, ), AsyncOpenAI( base_url="http://localhost:5000/custom/path/", api_key=api_key, + admin_api_key=admin_api_key, _strict_response_validation=True, http_client=httpx.AsyncClient(), ), @@ -1861,11 +2076,15 @@ async def test_base_url_no_trailing_slash(self, client: AsyncOpenAI) -> None: "client", [ AsyncOpenAI( - base_url="http://localhost:5000/custom/path/", api_key=api_key, _strict_response_validation=True + base_url="http://localhost:5000/custom/path/", + api_key=api_key, + admin_api_key=admin_api_key, + _strict_response_validation=True, ), AsyncOpenAI( base_url="http://localhost:5000/custom/path/", api_key=api_key, + admin_api_key=admin_api_key, _strict_response_validation=True, http_client=httpx.AsyncClient(), ), @@ -1884,7 +2103,9 @@ async def test_absolute_request_url(self, client: AsyncOpenAI) -> None: await client.close() async def test_copied_client_does_not_close_http(self) -> None: - test_client = AsyncOpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=True) + test_client = AsyncOpenAI( + base_url=base_url, api_key=api_key, admin_api_key=admin_api_key, _strict_response_validation=True + ) assert not test_client.is_closed() copied = test_client.copy() @@ -1896,7 +2117,9 @@ async def test_copied_client_does_not_close_http(self) -> None: assert not test_client.is_closed() async def test_client_context_manager(self) -> None: - test_client = AsyncOpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=True) + test_client = AsyncOpenAI( + base_url=base_url, api_key=api_key, admin_api_key=admin_api_key, _strict_response_validation=True + ) async with test_client as c2: assert c2 is test_client assert not c2.is_closed() @@ -1918,7 +2141,11 @@ class Model(BaseModel): async def test_client_max_retries_validation(self) -> None: with pytest.raises(TypeError, match=r"max_retries cannot be None"): AsyncOpenAI( - base_url=base_url, api_key=api_key, _strict_response_validation=True, max_retries=cast(Any, None) + base_url=base_url, + api_key=api_key, + admin_api_key=admin_api_key, + _strict_response_validation=True, + max_retries=cast(Any, None), ) @pytest.mark.respx(base_url=base_url) @@ -1939,12 +2166,16 @@ class Model(BaseModel): respx_mock.get("/foo").mock(return_value=httpx.Response(200, text="my-custom-format")) - strict_client = AsyncOpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=True) + strict_client = AsyncOpenAI( + base_url=base_url, api_key=api_key, admin_api_key=admin_api_key, _strict_response_validation=True + ) with pytest.raises(APIResponseValidationError): await strict_client.get("/foo", cast_to=Model) - non_strict_client = AsyncOpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=False) + non_strict_client = AsyncOpenAI( + base_url=base_url, api_key=api_key, admin_api_key=admin_api_key, _strict_response_validation=False + ) response = await non_strict_client.get("/foo", cast_to=Model) assert isinstance(response, str) # type: ignore[unreachable] diff --git a/tests/test_module_client.py b/tests/test_module_client.py index 9c9a1addab..6371ae7057 100644 --- a/tests/test_module_client.py +++ b/tests/test_module_client.py @@ -14,7 +14,8 @@ def reset_state() -> None: openai._reset_client() - openai.api_key = None or "My API Key" + openai.api_key = None + openai.admin_api_key = None openai.organization = None openai.project = None openai.webhook_secret = None From 20f81f8c64862cf222d625cbc2a15e372939fbea Mon Sep 17 00:00:00 2001 From: Alex Chang Date: Wed, 29 Apr 2026 10:09:07 -0400 Subject: [PATCH 700/769] fix(api): support admin api key auth --- src/openai/_client.py | 170 ++++++++++++++--------------- src/openai/resources/embeddings.py | 1 - tests/test_client.py | 26 ++--- 3 files changed, 92 insertions(+), 105 deletions(-) diff --git a/src/openai/_client.py b/src/openai/_client.py index 3009989beb..8a81a057a3 100644 --- a/src/openai/_client.py +++ b/src/openai/_client.py @@ -29,10 +29,9 @@ get_async_library, ) from ._compat import cached_property - from ._version import __version__ from ._streaming import Stream as Stream, AsyncStream as AsyncStream -from ._exceptions import APIStatusError +from ._exceptions import OpenAIError, APIStatusError from ._base_client import ( DEFAULT_MAX_RETRIES, SyncAPIClient, @@ -89,8 +88,6 @@ WORKLOAD_IDENTITY_API_KEY_PLACEHOLDER = "workload-identity-auth" -class OpenAI(SyncAPIClient): - # client options class OpenAI(SyncAPIClient): # client options api_key: str | None @@ -137,6 +134,7 @@ def __init__( # outlining your use-case to help us decide if it should be # part of our public interface in the future. _strict_response_validation: bool = False, + _enforce_credentials: bool = True, ) -> None: """Construct a new synchronous OpenAI client instance. @@ -173,6 +171,17 @@ def __init__( admin_api_key = os.environ.get("OPENAI_ADMIN_KEY") self.admin_api_key = admin_api_key + if ( + _enforce_credentials + and not self.api_key + and self._api_key_provider is None + and workload_identity is None + and self.admin_api_key is None + ): + raise OpenAIError( + "Missing credentials. Please pass an `api_key`, `workload_identity`, `admin_api_key`, or set the `OPENAI_API_KEY` or `OPENAI_ADMIN_KEY` environment variable." + ) + if organization is None: organization = os.environ.get("OPENAI_ORG_ID") self.organization = organization @@ -371,51 +380,25 @@ def with_streaming_response(self) -> OpenAIWithStreamedResponse: def qs(self) -> Querystring: return Querystring(array_format="brackets") - - @override - def _auth_headers(self, security: SecurityOptions) -> dict[str, str]: - return { - **(self._bearer_auth if security.get("bearer_auth", False) else {}), - **(self._admin_api_key_auth if security.get("admin_api_key_auth", False) else {}), - } - - @property - def _bearer_auth(self) -> dict[str, str]: - api_key = self.api_key - - return {"Authorization": f"Bearer {api_key}"} - - @property - def _admin_api_key_auth(self) -> dict[str, str]: - admin_api_key = self.admin_api_key - if admin_api_key is None: - return {} - return {"Authorization": f"Bearer {admin_api_key}"} - - @property - @override - def default_headers(self) -> dict[str, str | Omit]: - return { - **super().default_headers, - "X-Stainless-Async": "false", - "OpenAI-Organization": self.organization if self.organization is not None else Omit(), - "OpenAI-Project": self.project if self.project is not None else Omit(), - **self._custom_headers, - } - - @override - def _validate_headers(self, headers: Headers, custom_headers: Headers) -> None: - if headers.get("Authorization") or isinstance(custom_headers.get("Authorization"), Omit): - return - - raise TypeError( - '"Could not resolve authentication method. Expected either api_key or admin_api_key to be set. Or for one of the `Authorization` or `Authorization` headers to be explicitly omitted"' - ) - - def copy( + def _send_with_auth_retry( self, + request: httpx.Request, *, + stream: bool, + retried: bool = False, + **kwargs: Unpack[HttpxSendArgs], + ) -> httpx.Response: + if self._api_key_provider is not None: + request.headers["Authorization"] = f"Bearer {self._refresh_api_key()}" + + if self._workload_identity_auth is not None: + request.headers["Authorization"] = f"Bearer {self._workload_identity_auth.get_token()}" + response = super()._send_request(request, stream=stream, **kwargs) + if response.status_code == 401 and self._workload_identity_auth is not None and not retried: + response.close() + self._workload_identity_auth.invalidate_token() + request.headers["Authorization"] = f"Bearer {self._workload_identity_auth.get_token()}" return self._send_with_auth_retry(request, stream=stream, retried=True, **kwargs) return response @@ -480,10 +463,19 @@ def _validate_headers(self, headers: Headers, custom_headers: Headers) -> None: if headers.get("Authorization") or isinstance(custom_headers.get("Authorization"), Omit): return + if self._api_key_provider is not None or self._workload_identity_auth is not None: + return + raise TypeError( '"Could not resolve authentication method. Expected either api_key or admin_api_key to be set. Or for one of the `Authorization` or `Authorization` headers to be explicitly omitted"' ) + def _refresh_api_key(self) -> str | None: + if self._api_key_provider is not None: + self.api_key = self._api_key_provider() + + return self.api_key + def copy( self, *, @@ -502,6 +494,7 @@ def copy( set_default_headers: Mapping[str, str] | None = None, default_query: Mapping[str, object] | None = None, set_default_query: Mapping[str, object] | None = None, + _enforce_credentials: bool | None = None, _extra_kwargs: Mapping[str, Any] = {}, ) -> Self: """ @@ -528,6 +521,7 @@ def copy( http_client = http_client or self._client return self.__class__( + api_key=api_key or self._api_key_provider or self.api_key, admin_api_key=admin_api_key or self.admin_api_key, workload_identity=workload_identity or self.workload_identity, organization=organization or self.organization, @@ -540,6 +534,7 @@ def copy( max_retries=max_retries if is_given(max_retries) else self.max_retries, default_headers=headers, default_query=params, + _enforce_credentials=_enforce_credentials, **_extra_kwargs, ) @@ -586,6 +581,7 @@ class AsyncOpenAI(AsyncAPIClient): # client options api_key: str | None admin_api_key: str | None + workload_identity: WorkloadIdentity | None organization: str | None project: str | None webhook_secret: str | None @@ -602,7 +598,6 @@ class AsyncOpenAI(AsyncAPIClient): def __init__( self, *, - *, api_key: str | Callable[[], Awaitable[str]] | None = None, admin_api_key: str | None = None, workload_identity: WorkloadIdentity | None = None, @@ -628,6 +623,7 @@ def __init__( # outlining your use-case to help us decide if it should be # part of our public interface in the future. _strict_response_validation: bool = False, + _enforce_credentials: bool = True, ) -> None: """Construct a new async AsyncOpenAI client instance. @@ -664,6 +660,17 @@ def __init__( admin_api_key = os.environ.get("OPENAI_ADMIN_KEY") self.admin_api_key = admin_api_key + if ( + _enforce_credentials + and not self.api_key + and self._api_key_provider is None + and workload_identity is None + and self.admin_api_key is None + ): + raise OpenAIError( + "Missing credentials. Please pass an `api_key`, `workload_identity`, `admin_api_key`, or set the `OPENAI_API_KEY` or `OPENAI_ADMIN_KEY` environment variable." + ) + if organization is None: organization = os.environ.get("OPENAI_ORG_ID") self.organization = organization @@ -862,51 +869,25 @@ def with_streaming_response(self) -> AsyncOpenAIWithStreamedResponse: def qs(self) -> Querystring: return Querystring(array_format="brackets") - - @override - def _auth_headers(self, security: SecurityOptions) -> dict[str, str]: - return { - **(self._bearer_auth if security.get("bearer_auth", False) else {}), - **(self._admin_api_key_auth if security.get("admin_api_key_auth", False) else {}), - } - - @property - def _bearer_auth(self) -> dict[str, str]: - api_key = self.api_key - - return {"Authorization": f"Bearer {api_key}"} - - @property - def _admin_api_key_auth(self) -> dict[str, str]: - admin_api_key = self.admin_api_key - if admin_api_key is None: - return {} - return {"Authorization": f"Bearer {admin_api_key}"} - - @property - @override - def default_headers(self) -> dict[str, str | Omit]: - return { - **super().default_headers, - "X-Stainless-Async": f"async:{get_async_library()}", - "OpenAI-Organization": self.organization if self.organization is not None else Omit(), - "OpenAI-Project": self.project if self.project is not None else Omit(), - **self._custom_headers, - } - - @override - def _validate_headers(self, headers: Headers, custom_headers: Headers) -> None: - if headers.get("Authorization") or isinstance(custom_headers.get("Authorization"), Omit): - return - - raise TypeError( - '"Could not resolve authentication method. Expected either api_key or admin_api_key to be set. Or for one of the `Authorization` or `Authorization` headers to be explicitly omitted"' - ) - - def copy( + async def _send_with_auth_retry( self, + request: httpx.Request, *, + stream: bool, + retried: bool = False, + **kwargs: Unpack[HttpxSendArgs], + ) -> httpx.Response: + if self._api_key_provider is not None: + request.headers["Authorization"] = f"Bearer {await self._refresh_api_key()}" + + if self._workload_identity_auth is not None: + request.headers["Authorization"] = f"Bearer {await self._workload_identity_auth.get_token_async()}" + response = await super()._send_request(request, stream=stream, **kwargs) + if response.status_code == 401 and self._workload_identity_auth is not None and not retried: + await response.aclose() + self._workload_identity_auth.invalidate_token() + request.headers["Authorization"] = f"Bearer {await self._workload_identity_auth.get_token_async()}" return await self._send_with_auth_retry(request, stream=stream, retried=True, **kwargs) return response @@ -971,10 +952,19 @@ def _validate_headers(self, headers: Headers, custom_headers: Headers) -> None: if headers.get("Authorization") or isinstance(custom_headers.get("Authorization"), Omit): return + if self._api_key_provider is not None or self._workload_identity_auth is not None: + return + raise TypeError( '"Could not resolve authentication method. Expected either api_key or admin_api_key to be set. Or for one of the `Authorization` or `Authorization` headers to be explicitly omitted"' ) + async def _refresh_api_key(self) -> str | None: + if self._api_key_provider is not None: + self.api_key = await self._api_key_provider() + + return self.api_key + def copy( self, *, @@ -993,6 +983,7 @@ def copy( set_default_headers: Mapping[str, str] | None = None, default_query: Mapping[str, object] | None = None, set_default_query: Mapping[str, object] | None = None, + _enforce_credentials: bool | None = None, _extra_kwargs: Mapping[str, Any] = {}, ) -> Self: """ @@ -1031,6 +1022,7 @@ def copy( max_retries=max_retries if is_given(max_retries) else self.max_retries, default_headers=headers, default_query=params, + _enforce_credentials=_enforce_credentials, **_extra_kwargs, ) diff --git a/src/openai/resources/embeddings.py b/src/openai/resources/embeddings.py index 6f44ebac96..fea6255c0d 100644 --- a/src/openai/resources/embeddings.py +++ b/src/openai/resources/embeddings.py @@ -259,7 +259,6 @@ def parser(obj: CreateEmbeddingResponse) -> CreateEmbeddingResponse: return await self._post( "/embeddings", body=maybe_transform(params, embedding_create_params.EmbeddingCreateParams), - options=make_request_options( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, diff --git a/tests/test_client.py b/tests/test_client.py index 369d746b2d..f969bdea36 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -10,7 +10,7 @@ import inspect import dataclasses import tracemalloc -from typing import Any, Union, TypeVar, Callable, Iterable, Iterator, Optional, Protocol, Coroutine, cast +from typing import Any, Union, TypeVar, Callable, Iterable, Iterator, Optional, Coroutine, cast from unittest import mock from typing_extensions import Literal, AsyncIterator, override @@ -19,7 +19,7 @@ from respx import MockRouter from pydantic import ValidationError -from openai import OpenAI, AsyncOpenAI, APIResponseValidationError +from openai import OpenAI, AsyncOpenAI, OpenAIError, APIResponseValidationError from openai.auth import WorkloadIdentity from openai._types import Omit from openai._utils import asyncify @@ -43,6 +43,15 @@ base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") api_key = "My API Key" admin_api_key = "My Admin API Key" +workload_identity: WorkloadIdentity = { + "client_id": "client_123", + "identity_provider_id": "provider_123", + "service_account_id": "service_account_123", + "provider": { + "get_token": lambda: "external-subject-token", + "token_type": "jwt", + }, +} def _get_params(client: BaseClient[Any, Any]) -> dict[str, str]: @@ -436,19 +445,6 @@ def test_default_headers_option(self) -> None: test_client.close() test_client2.close() - def test_validate_headers(self) -> None: - default_headers={ - "X-Foo": "stainless", - "X-Stainless-Lang": "my-overriding-header", - }, - ) - request = test_client2._build_request(FinalRequestOptions(method="get", url="/foo")) - assert request.headers.get("x-foo") == "stainless" - assert request.headers.get("x-stainless-lang") == "my-overriding-header" - - test_client.close() - test_client2.close() - def test_validate_headers(self) -> None: client = OpenAI( base_url=base_url, api_key=api_key, admin_api_key=admin_api_key, _strict_response_validation=True From 6c51347b20d4fc95ad357056fa0384ed77a68656 Mon Sep 17 00:00:00 2001 From: Alex Chang Date: Wed, 29 Apr 2026 11:28:12 -0400 Subject: [PATCH 701/769] fix(api): resolve python auth type checks --- src/openai/_client.py | 5 +++-- tests/test_client.py | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/openai/_client.py b/src/openai/_client.py index 8a81a057a3..45a4f12945 100644 --- a/src/openai/_client.py +++ b/src/openai/_client.py @@ -29,6 +29,7 @@ get_async_library, ) from ._compat import cached_property +from ._models import SecurityOptions from ._version import __version__ from ._streaming import Stream as Stream, AsyncStream as AsyncStream from ._exceptions import OpenAIError, APIStatusError @@ -534,7 +535,7 @@ def copy( max_retries=max_retries if is_given(max_retries) else self.max_retries, default_headers=headers, default_query=params, - _enforce_credentials=_enforce_credentials, + _enforce_credentials=True if _enforce_credentials is None else _enforce_credentials, **_extra_kwargs, ) @@ -1022,7 +1023,7 @@ def copy( max_retries=max_retries if is_given(max_retries) else self.max_retries, default_headers=headers, default_query=params, - _enforce_credentials=_enforce_credentials, + _enforce_credentials=True if _enforce_credentials is None else _enforce_credentials, **_extra_kwargs, ) diff --git a/tests/test_client.py b/tests/test_client.py index f969bdea36..3f3288158f 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -18,6 +18,7 @@ import pytest from respx import MockRouter from pydantic import ValidationError +from respx.models import Call as MockRequestCall from openai import OpenAI, AsyncOpenAI, OpenAIError, APIResponseValidationError from openai.auth import WorkloadIdentity From 3c1a41a2ee235e73703800917ed3027964f94c12 Mon Sep 17 00:00:00 2001 From: Alex Chang Date: Wed, 29 Apr 2026 11:36:52 -0400 Subject: [PATCH 702/769] fix(api): preserve python api key attribute type --- src/openai/_client.py | 12 ++++++------ src/openai/lib/azure.py | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/openai/_client.py b/src/openai/_client.py index 45a4f12945..2937cd89f2 100644 --- a/src/openai/_client.py +++ b/src/openai/_client.py @@ -91,7 +91,7 @@ class OpenAI(SyncAPIClient): # client options - api_key: str | None + api_key: str admin_api_key: str | None workload_identity: WorkloadIdentity | None organization: str | None @@ -164,7 +164,7 @@ def __init__( self.api_key = "" self._api_key_provider: Callable[[], str] | None = api_key # type: ignore[no-redef] else: - self.api_key = api_key + self.api_key = api_key or "" self._api_key_provider = None self._workload_identity_auth = None @@ -471,7 +471,7 @@ def _validate_headers(self, headers: Headers, custom_headers: Headers) -> None: '"Could not resolve authentication method. Expected either api_key or admin_api_key to be set. Or for one of the `Authorization` or `Authorization` headers to be explicitly omitted"' ) - def _refresh_api_key(self) -> str | None: + def _refresh_api_key(self) -> str: if self._api_key_provider is not None: self.api_key = self._api_key_provider() @@ -580,7 +580,7 @@ def _make_status_error( class AsyncOpenAI(AsyncAPIClient): # client options - api_key: str | None + api_key: str admin_api_key: str | None workload_identity: WorkloadIdentity | None organization: str | None @@ -653,7 +653,7 @@ def __init__( self.api_key = "" self._api_key_provider: Callable[[], Awaitable[str]] | None = api_key # type: ignore[no-redef] else: - self.api_key = api_key + self.api_key = api_key or "" self._api_key_provider = None self._workload_identity_auth = None @@ -960,7 +960,7 @@ def _validate_headers(self, headers: Headers, custom_headers: Headers) -> None: '"Could not resolve authentication method. Expected either api_key or admin_api_key to be set. Or for one of the `Authorization` or `Authorization` headers to be explicitly omitted"' ) - async def _refresh_api_key(self) -> str | None: + async def _refresh_api_key(self) -> str: if self._api_key_provider is not None: self.api_key = await self._api_key_provider() diff --git a/src/openai/lib/azure.py b/src/openai/lib/azure.py index a7b23f8de9..a43316df98 100644 --- a/src/openai/lib/azure.py +++ b/src/openai/lib/azure.py @@ -348,7 +348,7 @@ def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOptions: if azure_ad_token is not None: if headers.get("Authorization") is None: headers["Authorization"] = f"Bearer {azure_ad_token}" - elif self.api_key is not None and self.api_key is not API_KEY_SENTINEL: + elif self.api_key and self.api_key != API_KEY_SENTINEL: if headers.get("api-key") is None: headers["api-key"] = self.api_key else: @@ -649,7 +649,7 @@ async def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOp if azure_ad_token is not None: if headers.get("Authorization") is None: headers["Authorization"] = f"Bearer {azure_ad_token}" - elif self.api_key is not None and self.api_key is not API_KEY_SENTINEL: + elif self.api_key and self.api_key != API_KEY_SENTINEL: if headers.get("api-key") is None: headers["api-key"] = self.api_key else: From daaf92f3fdc127defbb90c9401a785c097d62890 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 30 Apr 2026 16:53:44 +0000 Subject: [PATCH 703/769] ci: pin trigger-release-please github action --- .github/workflows/create-releases.yml | 2 +- .stats.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/create-releases.yml b/.github/workflows/create-releases.yml index f819d07310..f39b4c3e2c 100644 --- a/.github/workflows/create-releases.yml +++ b/.github/workflows/create-releases.yml @@ -16,7 +16,7 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - - uses: stainless-api/trigger-release-please@bb6677c5a04578eec1ccfd9e1913b5b78ed64c61 # v1 + - uses: stainless-api/trigger-release-please@bb6677c5a04578eec1ccfd9e1913b5b78ed64c61 # v1.4.0 id: release with: repo: ${{ github.event.repository.full_name }} diff --git a/.stats.yml b/.stats.yml index 613a7fb245..58e688f32e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 152 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-fa32d6e7d961e6a9090bfd42dada0302b1b11c40308587ea36bd46be854f33ab.yml openapi_spec_hash: e582137699583c1fb37ddb0553a8a2d0 -config_hash: 5dcd82ad6d930cf0a04c3cd7bbda82cc +config_hash: 2b2791e02f87210a840b88c95ccefd31 From efd9803e5a3e412e9f3429d94dce2178d797d3db Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 29 Apr 2026 17:31:53 +0000 Subject: [PATCH 704/769] fix(types): correct timestamp types to int in Response model --- .stats.yml | 4 ++-- src/openai/types/responses/response.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.stats.yml b/.stats.yml index 58e688f32e..7c7f8e0870 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 152 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-fa32d6e7d961e6a9090bfd42dada0302b1b11c40308587ea36bd46be854f33ab.yml -openapi_spec_hash: e582137699583c1fb37ddb0553a8a2d0 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-5b98524f8deee980c0dc96ceef2dd29d3e46c0ef56a3e68c6fef6e0ea6452bd0.yml +openapi_spec_hash: 2ce630b5996b5c36aaf8be25d0c41183 config_hash: 2b2791e02f87210a840b88c95ccefd31 diff --git a/src/openai/types/responses/response.py b/src/openai/types/responses/response.py index 0d2491ea7c..bfcf2460d6 100644 --- a/src/openai/types/responses/response.py +++ b/src/openai/types/responses/response.py @@ -60,7 +60,7 @@ class Response(BaseModel): id: str """Unique identifier for this Response.""" - created_at: float + created_at: int """Unix timestamp (in seconds) of when this Response was created.""" error: Optional[ResponseError] = None @@ -165,7 +165,7 @@ class Response(BaseModel): [Learn more](https://platform.openai.com/docs/guides/background). """ - completed_at: Optional[float] = None + completed_at: Optional[int] = None """ Unix timestamp (in seconds) of when this Response was completed. Only present when the status is `completed`. From 4dcd06747b37d0a87004e729804bc6fbbbc104c6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 29 Apr 2026 18:14:37 +0000 Subject: [PATCH 705/769] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 7c7f8e0870..f7293f7c7e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 152 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-5b98524f8deee980c0dc96ceef2dd29d3e46c0ef56a3e68c6fef6e0ea6452bd0.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-5b98524f8deee980c0dc96ceef2dd29d3e46c0ef56a3e68c6fef6e0ea6452bd0.yml openapi_spec_hash: 2ce630b5996b5c36aaf8be25d0c41183 config_hash: 2b2791e02f87210a840b88c95ccefd31 From 9cefa5c6be6d5e7fff19c63244baf4a82ab2c285 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 29 Apr 2026 22:24:43 +0000 Subject: [PATCH 706/769] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index f7293f7c7e..6f1a2c220a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 152 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-5b98524f8deee980c0dc96ceef2dd29d3e46c0ef56a3e68c6fef6e0ea6452bd0.yml -openapi_spec_hash: 2ce630b5996b5c36aaf8be25d0c41183 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-617ac7ff7388ed68d19955b74d6dd1a3e2313e5bc47eb7c7a138162e29e23b71.yml +openapi_spec_hash: d431cf9d2bf2b01122bb98cc7b7a357b config_hash: 2b2791e02f87210a840b88c95ccefd31 From af5934cfcc5140006aa777dc46297c0a7fa89b9a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 29 Apr 2026 23:41:43 +0000 Subject: [PATCH 707/769] feat(api): manual updates Generate SDK for admin.organization.audit_logs. --- .stats.yml | 4 +- api.md | 16 + src/openai/__init__.py | 1 + src/openai/_client.py | 38 + src/openai/_module_client.py | 8 + src/openai/resources/__init__.py | 14 + src/openai/resources/admin/__init__.py | 33 + src/openai/resources/admin/admin.py | 102 ++ .../resources/admin/organization/__init__.py | 33 + .../admin/organization/audit_logs.py | 387 ++++++ .../admin/organization/organization.py | 108 ++ .../types/admin/organization/__init__.py | 6 + .../organization/audit_log_list_params.py | 143 +++ .../organization/audit_log_list_response.py | 1033 +++++++++++++++++ tests/api_resources/admin/__init__.py | 1 + .../admin/organization/__init__.py | 1 + .../admin/organization/test_audit_logs.py | 115 ++ 17 files changed, 2041 insertions(+), 2 deletions(-) create mode 100644 src/openai/resources/admin/__init__.py create mode 100644 src/openai/resources/admin/admin.py create mode 100644 src/openai/resources/admin/organization/__init__.py create mode 100644 src/openai/resources/admin/organization/audit_logs.py create mode 100644 src/openai/resources/admin/organization/organization.py create mode 100644 src/openai/types/admin/organization/__init__.py create mode 100644 src/openai/types/admin/organization/audit_log_list_params.py create mode 100644 src/openai/types/admin/organization/audit_log_list_response.py create mode 100644 tests/api_resources/admin/__init__.py create mode 100644 tests/api_resources/admin/organization/__init__.py create mode 100644 tests/api_resources/admin/organization/test_audit_logs.py diff --git a/.stats.yml b/.stats.yml index 6f1a2c220a..838ad705ab 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 152 +configured_endpoints: 153 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-617ac7ff7388ed68d19955b74d6dd1a3e2313e5bc47eb7c7a138162e29e23b71.yml openapi_spec_hash: d431cf9d2bf2b01122bb98cc7b7a357b -config_hash: 2b2791e02f87210a840b88c95ccefd31 +config_hash: 88be7d18ee7f33affcdad19572cd0c91 diff --git a/api.md b/api.md index decf4e0129..c1378fa60f 100644 --- a/api.md +++ b/api.md @@ -707,6 +707,22 @@ Methods: - client.uploads.parts.create(upload_id, \*\*params) -> UploadPart +# Admin + +## Organization + +### AuditLogs + +Types: + +```python +from openai.types.admin.organization import AuditLogListResponse +``` + +Methods: + +- client.admin.organization.audit_logs.list(\*\*params) -> SyncConversationCursorPage[AuditLogListResponse] + # [Responses](src/openai/resources/responses/api.md) # [Realtime](src/openai/resources/realtime/api.md) diff --git a/src/openai/__init__.py b/src/openai/__init__.py index 5fc22da800..cbaef0615f 100644 --- a/src/openai/__init__.py +++ b/src/openai/__init__.py @@ -398,6 +398,7 @@ def _reset_client() -> None: # type: ignore[reportUnusedFunction] from ._module_client import ( beta as beta, chat as chat, + admin as admin, audio as audio, evals as evals, files as files, diff --git a/src/openai/_client.py b/src/openai/_client.py index 2937cd89f2..283f39ce2d 100644 --- a/src/openai/_client.py +++ b/src/openai/_client.py @@ -43,6 +43,7 @@ from .resources import ( beta, chat, + admin, audio, evals, files, @@ -70,6 +71,7 @@ from .resources.beta.beta import Beta, AsyncBeta from .resources.chat.chat import Chat, AsyncChat from .resources.embeddings import Embeddings, AsyncEmbeddings + from .resources.admin.admin import Admin, AsyncAdmin from .resources.audio.audio import Audio, AsyncAudio from .resources.completions import Completions, AsyncCompletions from .resources.evals.evals import Evals, AsyncEvals @@ -324,6 +326,12 @@ def uploads(self) -> Uploads: return Uploads(self) + @cached_property + def admin(self) -> Admin: + from .resources.admin import Admin + + return Admin(self) + @cached_property def responses(self) -> Responses: from .resources.responses import Responses @@ -813,6 +821,12 @@ def uploads(self) -> AsyncUploads: return AsyncUploads(self) + @cached_property + def admin(self) -> AsyncAdmin: + from .resources.admin import AsyncAdmin + + return AsyncAdmin(self) + @cached_property def responses(self) -> AsyncResponses: from .resources.responses import AsyncResponses @@ -1166,6 +1180,12 @@ def uploads(self) -> uploads.UploadsWithRawResponse: return UploadsWithRawResponse(self._client.uploads) + @cached_property + def admin(self) -> admin.AdminWithRawResponse: + from .resources.admin import AdminWithRawResponse + + return AdminWithRawResponse(self._client.admin) + @cached_property def responses(self) -> responses.ResponsesWithRawResponse: from .resources.responses import ResponsesWithRawResponse @@ -1311,6 +1331,12 @@ def uploads(self) -> uploads.AsyncUploadsWithRawResponse: return AsyncUploadsWithRawResponse(self._client.uploads) + @cached_property + def admin(self) -> admin.AsyncAdminWithRawResponse: + from .resources.admin import AsyncAdminWithRawResponse + + return AsyncAdminWithRawResponse(self._client.admin) + @cached_property def responses(self) -> responses.AsyncResponsesWithRawResponse: from .resources.responses import AsyncResponsesWithRawResponse @@ -1456,6 +1482,12 @@ def uploads(self) -> uploads.UploadsWithStreamingResponse: return UploadsWithStreamingResponse(self._client.uploads) + @cached_property + def admin(self) -> admin.AdminWithStreamingResponse: + from .resources.admin import AdminWithStreamingResponse + + return AdminWithStreamingResponse(self._client.admin) + @cached_property def responses(self) -> responses.ResponsesWithStreamingResponse: from .resources.responses import ResponsesWithStreamingResponse @@ -1601,6 +1633,12 @@ def uploads(self) -> uploads.AsyncUploadsWithStreamingResponse: return AsyncUploadsWithStreamingResponse(self._client.uploads) + @cached_property + def admin(self) -> admin.AsyncAdminWithStreamingResponse: + from .resources.admin import AsyncAdminWithStreamingResponse + + return AsyncAdminWithStreamingResponse(self._client.admin) + @cached_property def responses(self) -> responses.AsyncResponsesWithStreamingResponse: from .resources.responses import AsyncResponsesWithStreamingResponse diff --git a/src/openai/_module_client.py b/src/openai/_module_client.py index 98901c0446..3554e11e50 100644 --- a/src/openai/_module_client.py +++ b/src/openai/_module_client.py @@ -14,6 +14,7 @@ from .resources.beta.beta import Beta from .resources.chat.chat import Chat from .resources.embeddings import Embeddings + from .resources.admin.admin import Admin from .resources.audio.audio import Audio from .resources.completions import Completions from .resources.evals.evals import Evals @@ -56,6 +57,12 @@ def __load__(self) -> Audio: return _load_client().audio +class AdminProxy(LazyProxy["Admin"]): + @override + def __load__(self) -> Admin: + return _load_client().admin + + class EvalsProxy(LazyProxy["Evals"]): @override def __load__(self) -> Evals: @@ -162,6 +169,7 @@ def __load__(self) -> Conversations: beta: Beta = BetaProxy().__as_proxied__() files: Files = FilesProxy().__as_proxied__() audio: Audio = AudioProxy().__as_proxied__() +admin: Admin = AdminProxy().__as_proxied__() evals: Evals = EvalsProxy().__as_proxied__() images: Images = ImagesProxy().__as_proxied__() models: Models = ModelsProxy().__as_proxied__() diff --git a/src/openai/resources/__init__.py b/src/openai/resources/__init__.py index ed030f7188..e4905152c0 100644 --- a/src/openai/resources/__init__.py +++ b/src/openai/resources/__init__.py @@ -16,6 +16,14 @@ ChatWithStreamingResponse, AsyncChatWithStreamingResponse, ) +from .admin import ( + Admin, + AsyncAdmin, + AdminWithRawResponse, + AsyncAdminWithRawResponse, + AdminWithStreamingResponse, + AsyncAdminWithStreamingResponse, +) from .audio import ( Audio, AsyncAudio, @@ -216,6 +224,12 @@ "AsyncUploadsWithRawResponse", "UploadsWithStreamingResponse", "AsyncUploadsWithStreamingResponse", + "Admin", + "AsyncAdmin", + "AdminWithRawResponse", + "AsyncAdminWithRawResponse", + "AdminWithStreamingResponse", + "AsyncAdminWithStreamingResponse", "Evals", "AsyncEvals", "EvalsWithRawResponse", diff --git a/src/openai/resources/admin/__init__.py b/src/openai/resources/admin/__init__.py new file mode 100644 index 0000000000..730c20540c --- /dev/null +++ b/src/openai/resources/admin/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .admin import ( + Admin, + AsyncAdmin, + AdminWithRawResponse, + AsyncAdminWithRawResponse, + AdminWithStreamingResponse, + AsyncAdminWithStreamingResponse, +) +from .organization import ( + Organization, + AsyncOrganization, + OrganizationWithRawResponse, + AsyncOrganizationWithRawResponse, + OrganizationWithStreamingResponse, + AsyncOrganizationWithStreamingResponse, +) + +__all__ = [ + "Organization", + "AsyncOrganization", + "OrganizationWithRawResponse", + "AsyncOrganizationWithRawResponse", + "OrganizationWithStreamingResponse", + "AsyncOrganizationWithStreamingResponse", + "Admin", + "AsyncAdmin", + "AdminWithRawResponse", + "AsyncAdminWithRawResponse", + "AdminWithStreamingResponse", + "AsyncAdminWithStreamingResponse", +] diff --git a/src/openai/resources/admin/admin.py b/src/openai/resources/admin/admin.py new file mode 100644 index 0000000000..3a3e288c6a --- /dev/null +++ b/src/openai/resources/admin/admin.py @@ -0,0 +1,102 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from .organization.organization import ( + Organization, + AsyncOrganization, + OrganizationWithRawResponse, + AsyncOrganizationWithRawResponse, + OrganizationWithStreamingResponse, + AsyncOrganizationWithStreamingResponse, +) + +__all__ = ["Admin", "AsyncAdmin"] + + +class Admin(SyncAPIResource): + @cached_property + def organization(self) -> Organization: + return Organization(self._client) + + @cached_property + def with_raw_response(self) -> AdminWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AdminWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AdminWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AdminWithStreamingResponse(self) + + +class AsyncAdmin(AsyncAPIResource): + @cached_property + def organization(self) -> AsyncOrganization: + return AsyncOrganization(self._client) + + @cached_property + def with_raw_response(self) -> AsyncAdminWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncAdminWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncAdminWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncAdminWithStreamingResponse(self) + + +class AdminWithRawResponse: + def __init__(self, admin: Admin) -> None: + self._admin = admin + + @cached_property + def organization(self) -> OrganizationWithRawResponse: + return OrganizationWithRawResponse(self._admin.organization) + + +class AsyncAdminWithRawResponse: + def __init__(self, admin: AsyncAdmin) -> None: + self._admin = admin + + @cached_property + def organization(self) -> AsyncOrganizationWithRawResponse: + return AsyncOrganizationWithRawResponse(self._admin.organization) + + +class AdminWithStreamingResponse: + def __init__(self, admin: Admin) -> None: + self._admin = admin + + @cached_property + def organization(self) -> OrganizationWithStreamingResponse: + return OrganizationWithStreamingResponse(self._admin.organization) + + +class AsyncAdminWithStreamingResponse: + def __init__(self, admin: AsyncAdmin) -> None: + self._admin = admin + + @cached_property + def organization(self) -> AsyncOrganizationWithStreamingResponse: + return AsyncOrganizationWithStreamingResponse(self._admin.organization) diff --git a/src/openai/resources/admin/organization/__init__.py b/src/openai/resources/admin/organization/__init__.py new file mode 100644 index 0000000000..d3e8314a44 --- /dev/null +++ b/src/openai/resources/admin/organization/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .audit_logs import ( + AuditLogs, + AsyncAuditLogs, + AuditLogsWithRawResponse, + AsyncAuditLogsWithRawResponse, + AuditLogsWithStreamingResponse, + AsyncAuditLogsWithStreamingResponse, +) +from .organization import ( + Organization, + AsyncOrganization, + OrganizationWithRawResponse, + AsyncOrganizationWithRawResponse, + OrganizationWithStreamingResponse, + AsyncOrganizationWithStreamingResponse, +) + +__all__ = [ + "AuditLogs", + "AsyncAuditLogs", + "AuditLogsWithRawResponse", + "AsyncAuditLogsWithRawResponse", + "AuditLogsWithStreamingResponse", + "AsyncAuditLogsWithStreamingResponse", + "Organization", + "AsyncOrganization", + "OrganizationWithRawResponse", + "AsyncOrganizationWithRawResponse", + "OrganizationWithStreamingResponse", + "AsyncOrganizationWithStreamingResponse", +] diff --git a/src/openai/resources/admin/organization/audit_logs.py b/src/openai/resources/admin/organization/audit_logs.py new file mode 100644 index 0000000000..3cf3127631 --- /dev/null +++ b/src/openai/resources/admin/organization/audit_logs.py @@ -0,0 +1,387 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Literal + +import httpx + +from .... import _legacy_response +from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ...._utils import maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ....pagination import SyncConversationCursorPage, AsyncConversationCursorPage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.admin.organization import audit_log_list_params +from ....types.admin.organization.audit_log_list_response import AuditLogListResponse + +__all__ = ["AuditLogs", "AsyncAuditLogs"] + + +class AuditLogs(SyncAPIResource): + """List user actions and configuration changes within this organization.""" + + @cached_property + def with_raw_response(self) -> AuditLogsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AuditLogsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AuditLogsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AuditLogsWithStreamingResponse(self) + + def list( + self, + *, + actor_emails: SequenceNotStr[str] | Omit = omit, + actor_ids: SequenceNotStr[str] | Omit = omit, + after: str | Omit = omit, + before: str | Omit = omit, + effective_at: audit_log_list_params.EffectiveAt | Omit = omit, + event_types: List[ + Literal[ + "api_key.created", + "api_key.updated", + "api_key.deleted", + "certificate.created", + "certificate.updated", + "certificate.deleted", + "certificates.activated", + "certificates.deactivated", + "checkpoint.permission.created", + "checkpoint.permission.deleted", + "external_key.registered", + "external_key.removed", + "group.created", + "group.updated", + "group.deleted", + "invite.sent", + "invite.accepted", + "invite.deleted", + "ip_allowlist.created", + "ip_allowlist.updated", + "ip_allowlist.deleted", + "ip_allowlist.config.activated", + "ip_allowlist.config.deactivated", + "login.succeeded", + "login.failed", + "logout.succeeded", + "logout.failed", + "organization.updated", + "project.created", + "project.updated", + "project.archived", + "project.deleted", + "rate_limit.updated", + "rate_limit.deleted", + "resource.deleted", + "tunnel.created", + "tunnel.updated", + "tunnel.deleted", + "role.created", + "role.updated", + "role.deleted", + "role.assignment.created", + "role.assignment.deleted", + "scim.enabled", + "scim.disabled", + "service_account.created", + "service_account.updated", + "service_account.deleted", + "user.added", + "user.updated", + "user.deleted", + ] + ] + | Omit = omit, + limit: int | Omit = omit, + project_ids: SequenceNotStr[str] | Omit = omit, + resource_ids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncConversationCursorPage[AuditLogListResponse]: + """ + List user actions and configuration changes within this organization. + + Args: + actor_emails: Return only events performed by users with these emails. + + actor_ids: Return only events performed by these actors. Can be a user ID, a service + account ID, or an api key tracking ID. + + after: A cursor for use in pagination. `after` is an object ID that defines your place + in the list. For instance, if you make a list request and receive 100 objects, + ending with obj_foo, your subsequent call can include after=obj_foo in order to + fetch the next page of the list. + + before: A cursor for use in pagination. `before` is an object ID that defines your place + in the list. For instance, if you make a list request and receive 100 objects, + starting with obj_foo, your subsequent call can include before=obj_foo in order + to fetch the previous page of the list. + + effective_at: Return only events whose `effective_at` (Unix seconds) is in this range. + + event_types: Return only events with a `type` in one of these values. For example, + `project.created`. For all options, see the documentation for the + [audit log object](https://platform.openai.com/docs/api-reference/audit-logs/object). + + limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the default is 20. + + project_ids: Return only events for these projects. + + resource_ids: Return only events performed on these targets. For example, a project ID + updated. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/organization/audit_logs", + page=SyncConversationCursorPage[AuditLogListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "actor_emails": actor_emails, + "actor_ids": actor_ids, + "after": after, + "before": before, + "effective_at": effective_at, + "event_types": event_types, + "limit": limit, + "project_ids": project_ids, + "resource_ids": resource_ids, + }, + audit_log_list_params.AuditLogListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=AuditLogListResponse, + ) + + +class AsyncAuditLogs(AsyncAPIResource): + """List user actions and configuration changes within this organization.""" + + @cached_property + def with_raw_response(self) -> AsyncAuditLogsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncAuditLogsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncAuditLogsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncAuditLogsWithStreamingResponse(self) + + def list( + self, + *, + actor_emails: SequenceNotStr[str] | Omit = omit, + actor_ids: SequenceNotStr[str] | Omit = omit, + after: str | Omit = omit, + before: str | Omit = omit, + effective_at: audit_log_list_params.EffectiveAt | Omit = omit, + event_types: List[ + Literal[ + "api_key.created", + "api_key.updated", + "api_key.deleted", + "certificate.created", + "certificate.updated", + "certificate.deleted", + "certificates.activated", + "certificates.deactivated", + "checkpoint.permission.created", + "checkpoint.permission.deleted", + "external_key.registered", + "external_key.removed", + "group.created", + "group.updated", + "group.deleted", + "invite.sent", + "invite.accepted", + "invite.deleted", + "ip_allowlist.created", + "ip_allowlist.updated", + "ip_allowlist.deleted", + "ip_allowlist.config.activated", + "ip_allowlist.config.deactivated", + "login.succeeded", + "login.failed", + "logout.succeeded", + "logout.failed", + "organization.updated", + "project.created", + "project.updated", + "project.archived", + "project.deleted", + "rate_limit.updated", + "rate_limit.deleted", + "resource.deleted", + "tunnel.created", + "tunnel.updated", + "tunnel.deleted", + "role.created", + "role.updated", + "role.deleted", + "role.assignment.created", + "role.assignment.deleted", + "scim.enabled", + "scim.disabled", + "service_account.created", + "service_account.updated", + "service_account.deleted", + "user.added", + "user.updated", + "user.deleted", + ] + ] + | Omit = omit, + limit: int | Omit = omit, + project_ids: SequenceNotStr[str] | Omit = omit, + resource_ids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[AuditLogListResponse, AsyncConversationCursorPage[AuditLogListResponse]]: + """ + List user actions and configuration changes within this organization. + + Args: + actor_emails: Return only events performed by users with these emails. + + actor_ids: Return only events performed by these actors. Can be a user ID, a service + account ID, or an api key tracking ID. + + after: A cursor for use in pagination. `after` is an object ID that defines your place + in the list. For instance, if you make a list request and receive 100 objects, + ending with obj_foo, your subsequent call can include after=obj_foo in order to + fetch the next page of the list. + + before: A cursor for use in pagination. `before` is an object ID that defines your place + in the list. For instance, if you make a list request and receive 100 objects, + starting with obj_foo, your subsequent call can include before=obj_foo in order + to fetch the previous page of the list. + + effective_at: Return only events whose `effective_at` (Unix seconds) is in this range. + + event_types: Return only events with a `type` in one of these values. For example, + `project.created`. For all options, see the documentation for the + [audit log object](https://platform.openai.com/docs/api-reference/audit-logs/object). + + limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the default is 20. + + project_ids: Return only events for these projects. + + resource_ids: Return only events performed on these targets. For example, a project ID + updated. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/organization/audit_logs", + page=AsyncConversationCursorPage[AuditLogListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "actor_emails": actor_emails, + "actor_ids": actor_ids, + "after": after, + "before": before, + "effective_at": effective_at, + "event_types": event_types, + "limit": limit, + "project_ids": project_ids, + "resource_ids": resource_ids, + }, + audit_log_list_params.AuditLogListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=AuditLogListResponse, + ) + + +class AuditLogsWithRawResponse: + def __init__(self, audit_logs: AuditLogs) -> None: + self._audit_logs = audit_logs + + self.list = _legacy_response.to_raw_response_wrapper( + audit_logs.list, + ) + + +class AsyncAuditLogsWithRawResponse: + def __init__(self, audit_logs: AsyncAuditLogs) -> None: + self._audit_logs = audit_logs + + self.list = _legacy_response.async_to_raw_response_wrapper( + audit_logs.list, + ) + + +class AuditLogsWithStreamingResponse: + def __init__(self, audit_logs: AuditLogs) -> None: + self._audit_logs = audit_logs + + self.list = to_streamed_response_wrapper( + audit_logs.list, + ) + + +class AsyncAuditLogsWithStreamingResponse: + def __init__(self, audit_logs: AsyncAuditLogs) -> None: + self._audit_logs = audit_logs + + self.list = async_to_streamed_response_wrapper( + audit_logs.list, + ) diff --git a/src/openai/resources/admin/organization/organization.py b/src/openai/resources/admin/organization/organization.py new file mode 100644 index 0000000000..41dd0155d9 --- /dev/null +++ b/src/openai/resources/admin/organization/organization.py @@ -0,0 +1,108 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from ...._compat import cached_property +from .audit_logs import ( + AuditLogs, + AsyncAuditLogs, + AuditLogsWithRawResponse, + AsyncAuditLogsWithRawResponse, + AuditLogsWithStreamingResponse, + AsyncAuditLogsWithStreamingResponse, +) +from ...._resource import SyncAPIResource, AsyncAPIResource + +__all__ = ["Organization", "AsyncOrganization"] + + +class Organization(SyncAPIResource): + @cached_property + def audit_logs(self) -> AuditLogs: + """List user actions and configuration changes within this organization.""" + return AuditLogs(self._client) + + @cached_property + def with_raw_response(self) -> OrganizationWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return OrganizationWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> OrganizationWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return OrganizationWithStreamingResponse(self) + + +class AsyncOrganization(AsyncAPIResource): + @cached_property + def audit_logs(self) -> AsyncAuditLogs: + """List user actions and configuration changes within this organization.""" + return AsyncAuditLogs(self._client) + + @cached_property + def with_raw_response(self) -> AsyncOrganizationWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncOrganizationWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncOrganizationWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncOrganizationWithStreamingResponse(self) + + +class OrganizationWithRawResponse: + def __init__(self, organization: Organization) -> None: + self._organization = organization + + @cached_property + def audit_logs(self) -> AuditLogsWithRawResponse: + """List user actions and configuration changes within this organization.""" + return AuditLogsWithRawResponse(self._organization.audit_logs) + + +class AsyncOrganizationWithRawResponse: + def __init__(self, organization: AsyncOrganization) -> None: + self._organization = organization + + @cached_property + def audit_logs(self) -> AsyncAuditLogsWithRawResponse: + """List user actions and configuration changes within this organization.""" + return AsyncAuditLogsWithRawResponse(self._organization.audit_logs) + + +class OrganizationWithStreamingResponse: + def __init__(self, organization: Organization) -> None: + self._organization = organization + + @cached_property + def audit_logs(self) -> AuditLogsWithStreamingResponse: + """List user actions and configuration changes within this organization.""" + return AuditLogsWithStreamingResponse(self._organization.audit_logs) + + +class AsyncOrganizationWithStreamingResponse: + def __init__(self, organization: AsyncOrganization) -> None: + self._organization = organization + + @cached_property + def audit_logs(self) -> AsyncAuditLogsWithStreamingResponse: + """List user actions and configuration changes within this organization.""" + return AsyncAuditLogsWithStreamingResponse(self._organization.audit_logs) diff --git a/src/openai/types/admin/organization/__init__.py b/src/openai/types/admin/organization/__init__.py new file mode 100644 index 0000000000..c402a94c9d --- /dev/null +++ b/src/openai/types/admin/organization/__init__.py @@ -0,0 +1,6 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .audit_log_list_params import AuditLogListParams as AuditLogListParams +from .audit_log_list_response import AuditLogListResponse as AuditLogListResponse diff --git a/src/openai/types/admin/organization/audit_log_list_params.py b/src/openai/types/admin/organization/audit_log_list_params.py new file mode 100644 index 0000000000..bd3bc6d629 --- /dev/null +++ b/src/openai/types/admin/organization/audit_log_list_params.py @@ -0,0 +1,143 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Literal, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["AuditLogListParams", "EffectiveAt"] + + +class AuditLogListParams(TypedDict, total=False): + actor_emails: SequenceNotStr[str] + """Return only events performed by users with these emails.""" + + actor_ids: SequenceNotStr[str] + """Return only events performed by these actors. + + Can be a user ID, a service account ID, or an api key tracking ID. + """ + + after: str + """A cursor for use in pagination. + + `after` is an object ID that defines your place in the list. For instance, if + you make a list request and receive 100 objects, ending with obj_foo, your + subsequent call can include after=obj_foo in order to fetch the next page of the + list. + """ + + before: str + """A cursor for use in pagination. + + `before` is an object ID that defines your place in the list. For instance, if + you make a list request and receive 100 objects, starting with obj_foo, your + subsequent call can include before=obj_foo in order to fetch the previous page + of the list. + """ + + effective_at: EffectiveAt + """Return only events whose `effective_at` (Unix seconds) is in this range.""" + + event_types: List[ + Literal[ + "api_key.created", + "api_key.updated", + "api_key.deleted", + "certificate.created", + "certificate.updated", + "certificate.deleted", + "certificates.activated", + "certificates.deactivated", + "checkpoint.permission.created", + "checkpoint.permission.deleted", + "external_key.registered", + "external_key.removed", + "group.created", + "group.updated", + "group.deleted", + "invite.sent", + "invite.accepted", + "invite.deleted", + "ip_allowlist.created", + "ip_allowlist.updated", + "ip_allowlist.deleted", + "ip_allowlist.config.activated", + "ip_allowlist.config.deactivated", + "login.succeeded", + "login.failed", + "logout.succeeded", + "logout.failed", + "organization.updated", + "project.created", + "project.updated", + "project.archived", + "project.deleted", + "rate_limit.updated", + "rate_limit.deleted", + "resource.deleted", + "tunnel.created", + "tunnel.updated", + "tunnel.deleted", + "role.created", + "role.updated", + "role.deleted", + "role.assignment.created", + "role.assignment.deleted", + "scim.enabled", + "scim.disabled", + "service_account.created", + "service_account.updated", + "service_account.deleted", + "user.added", + "user.updated", + "user.deleted", + ] + ] + """Return only events with a `type` in one of these values. + + For example, `project.created`. For all options, see the documentation for the + [audit log object](https://platform.openai.com/docs/api-reference/audit-logs/object). + """ + + limit: int + """A limit on the number of objects to be returned. + + Limit can range between 1 and 100, and the default is 20. + """ + + project_ids: SequenceNotStr[str] + """Return only events for these projects.""" + + resource_ids: SequenceNotStr[str] + """Return only events performed on these targets. + + For example, a project ID updated. + """ + + +class EffectiveAt(TypedDict, total=False): + """Return only events whose `effective_at` (Unix seconds) is in this range.""" + + gt: int + """ + Return only events whose `effective_at` (Unix seconds) is greater than this + value. + """ + + gte: int + """ + Return only events whose `effective_at` (Unix seconds) is greater than or equal + to this value. + """ + + lt: int + """Return only events whose `effective_at` (Unix seconds) is less than this value.""" + + lte: int + """ + Return only events whose `effective_at` (Unix seconds) is less than or equal to + this value. + """ diff --git a/src/openai/types/admin/organization/audit_log_list_response.py b/src/openai/types/admin/organization/audit_log_list_response.py new file mode 100644 index 0000000000..db4d20b9ef --- /dev/null +++ b/src/openai/types/admin/organization/audit_log_list_response.py @@ -0,0 +1,1033 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from ...._models import BaseModel + +__all__ = [ + "AuditLogListResponse", + "Actor", + "ActorAPIKey", + "ActorAPIKeyServiceAccount", + "ActorAPIKeyUser", + "ActorSession", + "ActorSessionUser", + "APIKeyCreated", + "APIKeyCreatedData", + "APIKeyDeleted", + "APIKeyUpdated", + "APIKeyUpdatedChangesRequested", + "CertificateCreated", + "CertificateDeleted", + "CertificateUpdated", + "CertificatesActivated", + "CertificatesActivatedCertificate", + "CertificatesDeactivated", + "CertificatesDeactivatedCertificate", + "CheckpointPermissionCreated", + "CheckpointPermissionCreatedData", + "CheckpointPermissionDeleted", + "ExternalKeyRegistered", + "ExternalKeyRemoved", + "GroupCreated", + "GroupCreatedData", + "GroupDeleted", + "GroupUpdated", + "GroupUpdatedChangesRequested", + "InviteAccepted", + "InviteDeleted", + "InviteSent", + "InviteSentData", + "IPAllowlistConfigActivated", + "IPAllowlistConfigActivatedConfig", + "IPAllowlistConfigDeactivated", + "IPAllowlistConfigDeactivatedConfig", + "IPAllowlistCreated", + "IPAllowlistDeleted", + "IPAllowlistUpdated", + "LoginFailed", + "LogoutFailed", + "OrganizationUpdated", + "OrganizationUpdatedChangesRequested", + "Project", + "ProjectArchived", + "ProjectCreated", + "ProjectCreatedData", + "ProjectDeleted", + "ProjectUpdated", + "ProjectUpdatedChangesRequested", + "RateLimitDeleted", + "RateLimitUpdated", + "RateLimitUpdatedChangesRequested", + "RoleAssignmentCreated", + "RoleAssignmentDeleted", + "RoleCreated", + "RoleDeleted", + "RoleUpdated", + "RoleUpdatedChangesRequested", + "ScimDisabled", + "ScimEnabled", + "ServiceAccountCreated", + "ServiceAccountCreatedData", + "ServiceAccountDeleted", + "ServiceAccountUpdated", + "ServiceAccountUpdatedChangesRequested", + "UserAdded", + "UserAddedData", + "UserDeleted", + "UserUpdated", + "UserUpdatedChangesRequested", +] + + +class ActorAPIKeyServiceAccount(BaseModel): + """The service account that performed the audit logged action.""" + + id: Optional[str] = None + """The service account id.""" + + +class ActorAPIKeyUser(BaseModel): + """The user who performed the audit logged action.""" + + id: Optional[str] = None + """The user id.""" + + email: Optional[str] = None + """The user email.""" + + +class ActorAPIKey(BaseModel): + """The API Key used to perform the audit logged action.""" + + id: Optional[str] = None + """The tracking id of the API key.""" + + service_account: Optional[ActorAPIKeyServiceAccount] = None + """The service account that performed the audit logged action.""" + + type: Optional[Literal["user", "service_account"]] = None + """The type of API key. Can be either `user` or `service_account`.""" + + user: Optional[ActorAPIKeyUser] = None + """The user who performed the audit logged action.""" + + +class ActorSessionUser(BaseModel): + """The user who performed the audit logged action.""" + + id: Optional[str] = None + """The user id.""" + + email: Optional[str] = None + """The user email.""" + + +class ActorSession(BaseModel): + """The session in which the audit logged action was performed.""" + + ip_address: Optional[str] = None + """The IP address from which the action was performed.""" + + user: Optional[ActorSessionUser] = None + """The user who performed the audit logged action.""" + + +class Actor(BaseModel): + """The actor who performed the audit logged action.""" + + api_key: Optional[ActorAPIKey] = None + """The API Key used to perform the audit logged action.""" + + session: Optional[ActorSession] = None + """The session in which the audit logged action was performed.""" + + type: Optional[Literal["session", "api_key"]] = None + """The type of actor. Is either `session` or `api_key`.""" + + +class APIKeyCreatedData(BaseModel): + """The payload used to create the API key.""" + + scopes: Optional[List[str]] = None + """A list of scopes allowed for the API key, e.g. `["api.model.request"]`""" + + +class APIKeyCreated(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The tracking ID of the API key.""" + + data: Optional[APIKeyCreatedData] = None + """The payload used to create the API key.""" + + +class APIKeyDeleted(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The tracking ID of the API key.""" + + +class APIKeyUpdatedChangesRequested(BaseModel): + """The payload used to update the API key.""" + + scopes: Optional[List[str]] = None + """A list of scopes allowed for the API key, e.g. `["api.model.request"]`""" + + +class APIKeyUpdated(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The tracking ID of the API key.""" + + changes_requested: Optional[APIKeyUpdatedChangesRequested] = None + """The payload used to update the API key.""" + + +class CertificateCreated(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The certificate ID.""" + + name: Optional[str] = None + """The name of the certificate.""" + + +class CertificateDeleted(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The certificate ID.""" + + certificate: Optional[str] = None + """The certificate content in PEM format.""" + + name: Optional[str] = None + """The name of the certificate.""" + + +class CertificateUpdated(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The certificate ID.""" + + name: Optional[str] = None + """The name of the certificate.""" + + +class CertificatesActivatedCertificate(BaseModel): + id: Optional[str] = None + """The certificate ID.""" + + name: Optional[str] = None + """The name of the certificate.""" + + +class CertificatesActivated(BaseModel): + """The details for events with this `type`.""" + + certificates: Optional[List[CertificatesActivatedCertificate]] = None + + +class CertificatesDeactivatedCertificate(BaseModel): + id: Optional[str] = None + """The certificate ID.""" + + name: Optional[str] = None + """The name of the certificate.""" + + +class CertificatesDeactivated(BaseModel): + """The details for events with this `type`.""" + + certificates: Optional[List[CertificatesDeactivatedCertificate]] = None + + +class CheckpointPermissionCreatedData(BaseModel): + """The payload used to create the checkpoint permission.""" + + fine_tuned_model_checkpoint: Optional[str] = None + """The ID of the fine-tuned model checkpoint.""" + + project_id: Optional[str] = None + """The ID of the project that the checkpoint permission was created for.""" + + +class CheckpointPermissionCreated(BaseModel): + """ + The project and fine-tuned model checkpoint that the checkpoint permission was created for. + """ + + id: Optional[str] = None + """The ID of the checkpoint permission.""" + + data: Optional[CheckpointPermissionCreatedData] = None + """The payload used to create the checkpoint permission.""" + + +class CheckpointPermissionDeleted(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The ID of the checkpoint permission.""" + + +class ExternalKeyRegistered(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The ID of the external key configuration.""" + + data: Optional[object] = None + """The configuration for the external key.""" + + +class ExternalKeyRemoved(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The ID of the external key configuration.""" + + +class GroupCreatedData(BaseModel): + """Information about the created group.""" + + group_name: Optional[str] = None + """The group name.""" + + +class GroupCreated(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The ID of the group.""" + + data: Optional[GroupCreatedData] = None + """Information about the created group.""" + + +class GroupDeleted(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The ID of the group.""" + + +class GroupUpdatedChangesRequested(BaseModel): + """The payload used to update the group.""" + + group_name: Optional[str] = None + """The updated group name.""" + + +class GroupUpdated(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The ID of the group.""" + + changes_requested: Optional[GroupUpdatedChangesRequested] = None + """The payload used to update the group.""" + + +class InviteAccepted(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The ID of the invite.""" + + +class InviteDeleted(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The ID of the invite.""" + + +class InviteSentData(BaseModel): + """The payload used to create the invite.""" + + email: Optional[str] = None + """The email invited to the organization.""" + + role: Optional[str] = None + """The role the email was invited to be. Is either `owner` or `member`.""" + + +class InviteSent(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The ID of the invite.""" + + data: Optional[InviteSentData] = None + """The payload used to create the invite.""" + + +class IPAllowlistConfigActivatedConfig(BaseModel): + id: Optional[str] = None + """The ID of the IP allowlist configuration.""" + + name: Optional[str] = None + """The name of the IP allowlist configuration.""" + + +class IPAllowlistConfigActivated(BaseModel): + """The details for events with this `type`.""" + + configs: Optional[List[IPAllowlistConfigActivatedConfig]] = None + """The configurations that were activated.""" + + +class IPAllowlistConfigDeactivatedConfig(BaseModel): + id: Optional[str] = None + """The ID of the IP allowlist configuration.""" + + name: Optional[str] = None + """The name of the IP allowlist configuration.""" + + +class IPAllowlistConfigDeactivated(BaseModel): + """The details for events with this `type`.""" + + configs: Optional[List[IPAllowlistConfigDeactivatedConfig]] = None + """The configurations that were deactivated.""" + + +class IPAllowlistCreated(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The ID of the IP allowlist configuration.""" + + allowed_ips: Optional[List[str]] = None + """The IP addresses or CIDR ranges included in the configuration.""" + + name: Optional[str] = None + """The name of the IP allowlist configuration.""" + + +class IPAllowlistDeleted(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The ID of the IP allowlist configuration.""" + + allowed_ips: Optional[List[str]] = None + """The IP addresses or CIDR ranges that were in the configuration.""" + + name: Optional[str] = None + """The name of the IP allowlist configuration.""" + + +class IPAllowlistUpdated(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The ID of the IP allowlist configuration.""" + + allowed_ips: Optional[List[str]] = None + """The updated set of IP addresses or CIDR ranges in the configuration.""" + + +class LoginFailed(BaseModel): + """The details for events with this `type`.""" + + error_code: Optional[str] = None + """The error code of the failure.""" + + error_message: Optional[str] = None + """The error message of the failure.""" + + +class LogoutFailed(BaseModel): + """The details for events with this `type`.""" + + error_code: Optional[str] = None + """The error code of the failure.""" + + error_message: Optional[str] = None + """The error message of the failure.""" + + +class OrganizationUpdatedChangesRequested(BaseModel): + """The payload used to update the organization settings.""" + + api_call_logging: Optional[str] = None + """How your organization logs data from supported API calls. + + One of `disabled`, `enabled_per_call`, `enabled_for_all_projects`, or + `enabled_for_selected_projects` + """ + + api_call_logging_project_ids: Optional[str] = None + """ + The list of project ids if api_call_logging is set to + `enabled_for_selected_projects` + """ + + description: Optional[str] = None + """The organization description.""" + + name: Optional[str] = None + """The organization name.""" + + threads_ui_visibility: Optional[str] = None + """ + Visibility of the threads page which shows messages created with the Assistants + API and Playground. One of `ANY_ROLE`, `OWNERS`, or `NONE`. + """ + + title: Optional[str] = None + """The organization title.""" + + usage_dashboard_visibility: Optional[str] = None + """ + Visibility of the usage dashboard which shows activity and costs for your + organization. One of `ANY_ROLE` or `OWNERS`. + """ + + +class OrganizationUpdated(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The organization ID.""" + + changes_requested: Optional[OrganizationUpdatedChangesRequested] = None + """The payload used to update the organization settings.""" + + +class Project(BaseModel): + """The project that the action was scoped to. + + Absent for actions not scoped to projects. Note that any admin actions taken via Admin API keys are associated with the default project. + """ + + id: Optional[str] = None + """The project ID.""" + + name: Optional[str] = None + """The project title.""" + + +class ProjectArchived(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The project ID.""" + + +class ProjectCreatedData(BaseModel): + """The payload used to create the project.""" + + name: Optional[str] = None + """The project name.""" + + title: Optional[str] = None + """The title of the project as seen on the dashboard.""" + + +class ProjectCreated(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The project ID.""" + + data: Optional[ProjectCreatedData] = None + """The payload used to create the project.""" + + +class ProjectDeleted(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The project ID.""" + + +class ProjectUpdatedChangesRequested(BaseModel): + """The payload used to update the project.""" + + title: Optional[str] = None + """The title of the project as seen on the dashboard.""" + + +class ProjectUpdated(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The project ID.""" + + changes_requested: Optional[ProjectUpdatedChangesRequested] = None + """The payload used to update the project.""" + + +class RateLimitDeleted(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The rate limit ID""" + + +class RateLimitUpdatedChangesRequested(BaseModel): + """The payload used to update the rate limits.""" + + batch_1_day_max_input_tokens: Optional[int] = None + """The maximum batch input tokens per day. Only relevant for certain models.""" + + max_audio_megabytes_per_1_minute: Optional[int] = None + """The maximum audio megabytes per minute. Only relevant for certain models.""" + + max_images_per_1_minute: Optional[int] = None + """The maximum images per minute. Only relevant for certain models.""" + + max_requests_per_1_day: Optional[int] = None + """The maximum requests per day. Only relevant for certain models.""" + + max_requests_per_1_minute: Optional[int] = None + """The maximum requests per minute.""" + + max_tokens_per_1_minute: Optional[int] = None + """The maximum tokens per minute.""" + + +class RateLimitUpdated(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The rate limit ID""" + + changes_requested: Optional[RateLimitUpdatedChangesRequested] = None + """The payload used to update the rate limits.""" + + +class RoleAssignmentCreated(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The identifier of the role assignment.""" + + principal_id: Optional[str] = None + """The principal (user or group) that received the role.""" + + principal_type: Optional[str] = None + """The type of principal (user or group) that received the role.""" + + resource_id: Optional[str] = None + """The resource the role assignment is scoped to.""" + + resource_type: Optional[str] = None + """The type of resource the role assignment is scoped to.""" + + +class RoleAssignmentDeleted(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The identifier of the role assignment.""" + + principal_id: Optional[str] = None + """The principal (user or group) that had the role removed.""" + + principal_type: Optional[str] = None + """The type of principal (user or group) that had the role removed.""" + + resource_id: Optional[str] = None + """The resource the role assignment was scoped to.""" + + resource_type: Optional[str] = None + """The type of resource the role assignment was scoped to.""" + + +class RoleCreated(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The role ID.""" + + permissions: Optional[List[str]] = None + """The permissions granted by the role.""" + + resource_id: Optional[str] = None + """The resource the role is scoped to.""" + + resource_type: Optional[str] = None + """The type of resource the role belongs to.""" + + role_name: Optional[str] = None + """The name of the role.""" + + +class RoleDeleted(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The role ID.""" + + +class RoleUpdatedChangesRequested(BaseModel): + """The payload used to update the role.""" + + description: Optional[str] = None + """The updated role description, when provided.""" + + metadata: Optional[object] = None + """Additional metadata stored on the role.""" + + permissions_added: Optional[List[str]] = None + """The permissions added to the role.""" + + permissions_removed: Optional[List[str]] = None + """The permissions removed from the role.""" + + resource_id: Optional[str] = None + """The resource the role is scoped to.""" + + resource_type: Optional[str] = None + """The type of resource the role belongs to.""" + + role_name: Optional[str] = None + """The updated role name, when provided.""" + + +class RoleUpdated(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The role ID.""" + + changes_requested: Optional[RoleUpdatedChangesRequested] = None + """The payload used to update the role.""" + + +class ScimDisabled(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The ID of the SCIM was disabled for.""" + + +class ScimEnabled(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The ID of the SCIM was enabled for.""" + + +class ServiceAccountCreatedData(BaseModel): + """The payload used to create the service account.""" + + role: Optional[str] = None + """The role of the service account. Is either `owner` or `member`.""" + + +class ServiceAccountCreated(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The service account ID.""" + + data: Optional[ServiceAccountCreatedData] = None + """The payload used to create the service account.""" + + +class ServiceAccountDeleted(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The service account ID.""" + + +class ServiceAccountUpdatedChangesRequested(BaseModel): + """The payload used to updated the service account.""" + + role: Optional[str] = None + """The role of the service account. Is either `owner` or `member`.""" + + +class ServiceAccountUpdated(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The service account ID.""" + + changes_requested: Optional[ServiceAccountUpdatedChangesRequested] = None + """The payload used to updated the service account.""" + + +class UserAddedData(BaseModel): + """The payload used to add the user to the project.""" + + role: Optional[str] = None + """The role of the user. Is either `owner` or `member`.""" + + +class UserAdded(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The user ID.""" + + data: Optional[UserAddedData] = None + """The payload used to add the user to the project.""" + + +class UserDeleted(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The user ID.""" + + +class UserUpdatedChangesRequested(BaseModel): + """The payload used to update the user.""" + + role: Optional[str] = None + """The role of the user. Is either `owner` or `member`.""" + + +class UserUpdated(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The project ID.""" + + changes_requested: Optional[UserUpdatedChangesRequested] = None + """The payload used to update the user.""" + + +class AuditLogListResponse(BaseModel): + """A log of a user action or configuration change within this organization.""" + + id: str + """The ID of this log.""" + + actor: Actor + """The actor who performed the audit logged action.""" + + effective_at: int + """The Unix timestamp (in seconds) of the event.""" + + type: Literal[ + "api_key.created", + "api_key.updated", + "api_key.deleted", + "certificate.created", + "certificate.updated", + "certificate.deleted", + "certificates.activated", + "certificates.deactivated", + "checkpoint.permission.created", + "checkpoint.permission.deleted", + "external_key.registered", + "external_key.removed", + "group.created", + "group.updated", + "group.deleted", + "invite.sent", + "invite.accepted", + "invite.deleted", + "ip_allowlist.created", + "ip_allowlist.updated", + "ip_allowlist.deleted", + "ip_allowlist.config.activated", + "ip_allowlist.config.deactivated", + "login.succeeded", + "login.failed", + "logout.succeeded", + "logout.failed", + "organization.updated", + "project.created", + "project.updated", + "project.archived", + "project.deleted", + "rate_limit.updated", + "rate_limit.deleted", + "resource.deleted", + "tunnel.created", + "tunnel.updated", + "tunnel.deleted", + "role.created", + "role.updated", + "role.deleted", + "role.assignment.created", + "role.assignment.deleted", + "scim.enabled", + "scim.disabled", + "service_account.created", + "service_account.updated", + "service_account.deleted", + "user.added", + "user.updated", + "user.deleted", + ] + """The event type.""" + + api_key_created: Optional[APIKeyCreated] = FieldInfo(alias="api_key.created", default=None) + """The details for events with this `type`.""" + + api_key_deleted: Optional[APIKeyDeleted] = FieldInfo(alias="api_key.deleted", default=None) + """The details for events with this `type`.""" + + api_key_updated: Optional[APIKeyUpdated] = FieldInfo(alias="api_key.updated", default=None) + """The details for events with this `type`.""" + + certificate_created: Optional[CertificateCreated] = FieldInfo(alias="certificate.created", default=None) + """The details for events with this `type`.""" + + certificate_deleted: Optional[CertificateDeleted] = FieldInfo(alias="certificate.deleted", default=None) + """The details for events with this `type`.""" + + certificate_updated: Optional[CertificateUpdated] = FieldInfo(alias="certificate.updated", default=None) + """The details for events with this `type`.""" + + certificates_activated: Optional[CertificatesActivated] = FieldInfo(alias="certificates.activated", default=None) + """The details for events with this `type`.""" + + certificates_deactivated: Optional[CertificatesDeactivated] = FieldInfo( + alias="certificates.deactivated", default=None + ) + """The details for events with this `type`.""" + + checkpoint_permission_created: Optional[CheckpointPermissionCreated] = FieldInfo( + alias="checkpoint.permission.created", default=None + ) + """ + The project and fine-tuned model checkpoint that the checkpoint permission was + created for. + """ + + checkpoint_permission_deleted: Optional[CheckpointPermissionDeleted] = FieldInfo( + alias="checkpoint.permission.deleted", default=None + ) + """The details for events with this `type`.""" + + external_key_registered: Optional[ExternalKeyRegistered] = FieldInfo(alias="external_key.registered", default=None) + """The details for events with this `type`.""" + + external_key_removed: Optional[ExternalKeyRemoved] = FieldInfo(alias="external_key.removed", default=None) + """The details for events with this `type`.""" + + group_created: Optional[GroupCreated] = FieldInfo(alias="group.created", default=None) + """The details for events with this `type`.""" + + group_deleted: Optional[GroupDeleted] = FieldInfo(alias="group.deleted", default=None) + """The details for events with this `type`.""" + + group_updated: Optional[GroupUpdated] = FieldInfo(alias="group.updated", default=None) + """The details for events with this `type`.""" + + invite_accepted: Optional[InviteAccepted] = FieldInfo(alias="invite.accepted", default=None) + """The details for events with this `type`.""" + + invite_deleted: Optional[InviteDeleted] = FieldInfo(alias="invite.deleted", default=None) + """The details for events with this `type`.""" + + invite_sent: Optional[InviteSent] = FieldInfo(alias="invite.sent", default=None) + """The details for events with this `type`.""" + + ip_allowlist_config_activated: Optional[IPAllowlistConfigActivated] = FieldInfo( + alias="ip_allowlist.config.activated", default=None + ) + """The details for events with this `type`.""" + + ip_allowlist_config_deactivated: Optional[IPAllowlistConfigDeactivated] = FieldInfo( + alias="ip_allowlist.config.deactivated", default=None + ) + """The details for events with this `type`.""" + + ip_allowlist_created: Optional[IPAllowlistCreated] = FieldInfo(alias="ip_allowlist.created", default=None) + """The details for events with this `type`.""" + + ip_allowlist_deleted: Optional[IPAllowlistDeleted] = FieldInfo(alias="ip_allowlist.deleted", default=None) + """The details for events with this `type`.""" + + ip_allowlist_updated: Optional[IPAllowlistUpdated] = FieldInfo(alias="ip_allowlist.updated", default=None) + """The details for events with this `type`.""" + + login_failed: Optional[LoginFailed] = FieldInfo(alias="login.failed", default=None) + """The details for events with this `type`.""" + + login_succeeded: Optional[object] = FieldInfo(alias="login.succeeded", default=None) + """This event has no additional fields beyond the standard audit log attributes.""" + + logout_failed: Optional[LogoutFailed] = FieldInfo(alias="logout.failed", default=None) + """The details for events with this `type`.""" + + logout_succeeded: Optional[object] = FieldInfo(alias="logout.succeeded", default=None) + """This event has no additional fields beyond the standard audit log attributes.""" + + organization_updated: Optional[OrganizationUpdated] = FieldInfo(alias="organization.updated", default=None) + """The details for events with this `type`.""" + + project: Optional[Project] = None + """The project that the action was scoped to. + + Absent for actions not scoped to projects. Note that any admin actions taken via + Admin API keys are associated with the default project. + """ + + project_archived: Optional[ProjectArchived] = FieldInfo(alias="project.archived", default=None) + """The details for events with this `type`.""" + + project_created: Optional[ProjectCreated] = FieldInfo(alias="project.created", default=None) + """The details for events with this `type`.""" + + project_deleted: Optional[ProjectDeleted] = FieldInfo(alias="project.deleted", default=None) + """The details for events with this `type`.""" + + project_updated: Optional[ProjectUpdated] = FieldInfo(alias="project.updated", default=None) + """The details for events with this `type`.""" + + rate_limit_deleted: Optional[RateLimitDeleted] = FieldInfo(alias="rate_limit.deleted", default=None) + """The details for events with this `type`.""" + + rate_limit_updated: Optional[RateLimitUpdated] = FieldInfo(alias="rate_limit.updated", default=None) + """The details for events with this `type`.""" + + role_assignment_created: Optional[RoleAssignmentCreated] = FieldInfo(alias="role.assignment.created", default=None) + """The details for events with this `type`.""" + + role_assignment_deleted: Optional[RoleAssignmentDeleted] = FieldInfo(alias="role.assignment.deleted", default=None) + """The details for events with this `type`.""" + + role_created: Optional[RoleCreated] = FieldInfo(alias="role.created", default=None) + """The details for events with this `type`.""" + + role_deleted: Optional[RoleDeleted] = FieldInfo(alias="role.deleted", default=None) + """The details for events with this `type`.""" + + role_updated: Optional[RoleUpdated] = FieldInfo(alias="role.updated", default=None) + """The details for events with this `type`.""" + + scim_disabled: Optional[ScimDisabled] = FieldInfo(alias="scim.disabled", default=None) + """The details for events with this `type`.""" + + scim_enabled: Optional[ScimEnabled] = FieldInfo(alias="scim.enabled", default=None) + """The details for events with this `type`.""" + + service_account_created: Optional[ServiceAccountCreated] = FieldInfo(alias="service_account.created", default=None) + """The details for events with this `type`.""" + + service_account_deleted: Optional[ServiceAccountDeleted] = FieldInfo(alias="service_account.deleted", default=None) + """The details for events with this `type`.""" + + service_account_updated: Optional[ServiceAccountUpdated] = FieldInfo(alias="service_account.updated", default=None) + """The details for events with this `type`.""" + + user_added: Optional[UserAdded] = FieldInfo(alias="user.added", default=None) + """The details for events with this `type`.""" + + user_deleted: Optional[UserDeleted] = FieldInfo(alias="user.deleted", default=None) + """The details for events with this `type`.""" + + user_updated: Optional[UserUpdated] = FieldInfo(alias="user.updated", default=None) + """The details for events with this `type`.""" diff --git a/tests/api_resources/admin/__init__.py b/tests/api_resources/admin/__init__.py new file mode 100644 index 0000000000..fd8019a9a1 --- /dev/null +++ b/tests/api_resources/admin/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/admin/organization/__init__.py b/tests/api_resources/admin/organization/__init__.py new file mode 100644 index 0000000000..fd8019a9a1 --- /dev/null +++ b/tests/api_resources/admin/organization/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/admin/organization/test_audit_logs.py b/tests/api_resources/admin/organization/test_audit_logs.py new file mode 100644 index 0000000000..5e696461fa --- /dev/null +++ b/tests/api_resources/admin/organization/test_audit_logs.py @@ -0,0 +1,115 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.pagination import SyncConversationCursorPage, AsyncConversationCursorPage +from openai.types.admin.organization import AuditLogListResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestAuditLogs: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + audit_log = client.admin.organization.audit_logs.list() + assert_matches_type(SyncConversationCursorPage[AuditLogListResponse], audit_log, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + audit_log = client.admin.organization.audit_logs.list( + actor_emails=["string"], + actor_ids=["string"], + after="after", + before="before", + effective_at={ + "gt": 0, + "gte": 0, + "lt": 0, + "lte": 0, + }, + event_types=["api_key.created"], + limit=0, + project_ids=["string"], + resource_ids=["string"], + ) + assert_matches_type(SyncConversationCursorPage[AuditLogListResponse], audit_log, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.admin.organization.audit_logs.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + audit_log = response.parse() + assert_matches_type(SyncConversationCursorPage[AuditLogListResponse], audit_log, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.admin.organization.audit_logs.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + audit_log = response.parse() + assert_matches_type(SyncConversationCursorPage[AuditLogListResponse], audit_log, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncAuditLogs: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + audit_log = await async_client.admin.organization.audit_logs.list() + assert_matches_type(AsyncConversationCursorPage[AuditLogListResponse], audit_log, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + audit_log = await async_client.admin.organization.audit_logs.list( + actor_emails=["string"], + actor_ids=["string"], + after="after", + before="before", + effective_at={ + "gt": 0, + "gte": 0, + "lt": 0, + "lte": 0, + }, + event_types=["api_key.created"], + limit=0, + project_ids=["string"], + resource_ids=["string"], + ) + assert_matches_type(AsyncConversationCursorPage[AuditLogListResponse], audit_log, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.audit_logs.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + audit_log = response.parse() + assert_matches_type(AsyncConversationCursorPage[AuditLogListResponse], audit_log, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.audit_logs.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + audit_log = await response.parse() + assert_matches_type(AsyncConversationCursorPage[AuditLogListResponse], audit_log, path=["response"]) + + assert cast(Any, response.is_closed) is True From e459519520e122afe0047cc6a1e3f42f69bab8ee Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 30 Apr 2026 16:21:01 +0000 Subject: [PATCH 708/769] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 838ad705ab..73d7722354 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 153 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-617ac7ff7388ed68d19955b74d6dd1a3e2313e5bc47eb7c7a138162e29e23b71.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-7712c92246b94f811f6e3d33569242e75b22497d51df8cc27b16a6a205b4560a.yml openapi_spec_hash: d431cf9d2bf2b01122bb98cc7b7a357b config_hash: 88be7d18ee7f33affcdad19572cd0c91 From 36752787b3800df3808f67f74d640906ac3e5536 Mon Sep 17 00:00:00 2001 From: Alex Chang Date: Thu, 30 Apr 2026 10:40:27 -0400 Subject: [PATCH 709/769] fix: require bearer auth for stream helpers --- .../resources/beta/threads/runs/runs.py | 26 ++++++++++++++++--- src/openai/resources/beta/threads/threads.py | 12 +++++++-- .../resources/chat/completions/completions.py | 2 ++ src/openai/resources/embeddings.py | 1 + src/openai/resources/responses/responses.py | 2 ++ 5 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/openai/resources/beta/threads/runs/runs.py b/src/openai/resources/beta/threads/runs/runs.py index 263bc787c2..385d4c680c 100644 --- a/src/openai/resources/beta/threads/runs/runs.py +++ b/src/openai/resources/beta/threads/runs/runs.py @@ -1037,7 +1037,11 @@ def create_and_stream( run_create_params.RunCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Run, stream=True, @@ -1229,6 +1233,7 @@ def stream( extra_body=extra_body, timeout=timeout, query=maybe_transform({"include": include}, run_create_params.RunCreateParams), + security={"bearer_auth": True}, ), cast_to=Run, stream=True, @@ -1527,7 +1532,11 @@ def submit_tool_outputs_stream( run_submit_tool_outputs_params.RunSubmitToolOutputsParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Run, stream=True, @@ -2513,7 +2522,11 @@ def create_and_stream( run_create_params.RunCreateParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Run, stream=True, @@ -2706,6 +2719,7 @@ def stream( extra_body=extra_body, timeout=timeout, query=maybe_transform({"include": include}, run_create_params.RunCreateParams), + security={"bearer_auth": True}, ), cast_to=Run, stream=True, @@ -3006,7 +3020,11 @@ def submit_tool_outputs_stream( run_submit_tool_outputs_params.RunSubmitToolOutputsParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Run, stream=True, diff --git a/src/openai/resources/beta/threads/threads.py b/src/openai/resources/beta/threads/threads.py index dec6f31a38..d9425c64bd 100644 --- a/src/openai/resources/beta/threads/threads.py +++ b/src/openai/resources/beta/threads/threads.py @@ -933,7 +933,11 @@ def create_and_run_stream( thread_create_and_run_params.ThreadCreateAndRunParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Run, stream=True, @@ -1820,7 +1824,11 @@ def create_and_run_stream( thread_create_and_run_params.ThreadCreateAndRunParams, ), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"bearer_auth": True}, ), cast_to=Run, stream=True, diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index 4158f032ee..7a551e2459 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -236,6 +236,7 @@ def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseForma extra_body=extra_body, timeout=timeout, post_parser=parser, + security={"bearer_auth": True}, ), # we turn the `ChatCompletion` instance into a `ParsedChatCompletion` # in the `parser` function above @@ -1756,6 +1757,7 @@ def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseForma extra_body=extra_body, timeout=timeout, post_parser=parser, + security={"bearer_auth": True}, ), # we turn the `ChatCompletion` instance into a `ParsedChatCompletion` # in the `parser` function above diff --git a/src/openai/resources/embeddings.py b/src/openai/resources/embeddings.py index fea6255c0d..a51936d809 100644 --- a/src/openai/resources/embeddings.py +++ b/src/openai/resources/embeddings.py @@ -142,6 +142,7 @@ def parser(obj: CreateEmbeddingResponse) -> CreateEmbeddingResponse: extra_body=extra_body, timeout=timeout, post_parser=parser, + security={"bearer_auth": True}, ), cast_to=CreateEmbeddingResponse, ) diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 89a8ceffa1..c0f9855bcf 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -1275,6 +1275,7 @@ def parser(raw_response: Response) -> ParsedResponse[TextFormatT]: extra_body=extra_body, timeout=timeout, post_parser=parser, + security={"bearer_auth": True}, ), # we turn the `Response` instance into a `ParsedResponse` # in the `parser` function above @@ -2977,6 +2978,7 @@ def parser(raw_response: Response) -> ParsedResponse[TextFormatT]: extra_body=extra_body, timeout=timeout, post_parser=parser, + security={"bearer_auth": True}, ), # we turn the `Response` instance into a `ParsedResponse` # in the `parser` function above From c99535c716f90a1e10cc40a8618103ba1c5c2e49 Mon Sep 17 00:00:00 2001 From: Alex Chang Date: Thu, 30 Apr 2026 10:48:01 -0400 Subject: [PATCH 710/769] fix: preserve selected auth credentials --- src/openai/_client.py | 48 ++++++++++++++--- src/openai/lib/azure.py | 4 +- tests/lib/test_azure.py | 51 ++++++++++++++++++ tests/test_client.py | 114 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 207 insertions(+), 10 deletions(-) diff --git a/src/openai/_client.py b/src/openai/_client.py index 283f39ce2d..f999aaab15 100644 --- a/src/openai/_client.py +++ b/src/openai/_client.py @@ -91,6 +91,16 @@ WORKLOAD_IDENTITY_API_KEY_PLACEHOLDER = "workload-identity-auth" +def _has_header(headers: Headers, header: str) -> bool: + header = header.lower() + return any(key.lower() == header for key in headers) + + +def _has_omitted_header(headers: Headers, header: str) -> bool: + header = header.lower() + return any(key.lower() == header and isinstance(value, Omit) for key, value in headers.items()) + + class OpenAI(SyncAPIClient): # client options api_key: str @@ -397,14 +407,25 @@ def _send_with_auth_retry( retried: bool = False, **kwargs: Unpack[HttpxSendArgs], ) -> httpx.Response: + used_workload_identity_auth = False if self._api_key_provider is not None: - request.headers["Authorization"] = f"Bearer {self._refresh_api_key()}" + authorization = request.headers.get("Authorization") + if authorization is None or authorization == f"Bearer {self.api_key}": + request.headers["Authorization"] = f"Bearer {self._refresh_api_key()}" if self._workload_identity_auth is not None: - request.headers["Authorization"] = f"Bearer {self._workload_identity_auth.get_token()}" + authorization = request.headers.get("Authorization") + if authorization is None or authorization == f"Bearer {WORKLOAD_IDENTITY_API_KEY_PLACEHOLDER}": + request.headers["Authorization"] = f"Bearer {self._workload_identity_auth.get_token()}" + used_workload_identity_auth = True response = super()._send_request(request, stream=stream, **kwargs) - if response.status_code == 401 and self._workload_identity_auth is not None and not retried: + if ( + response.status_code == 401 + and self._workload_identity_auth is not None + and used_workload_identity_auth + and not retried + ): response.close() self._workload_identity_auth.invalidate_token() request.headers["Authorization"] = f"Bearer {self._workload_identity_auth.get_token()}" @@ -469,7 +490,7 @@ def default_headers(self) -> dict[str, str | Omit]: @override def _validate_headers(self, headers: Headers, custom_headers: Headers) -> None: - if headers.get("Authorization") or isinstance(custom_headers.get("Authorization"), Omit): + if _has_header(headers, "Authorization") or _has_omitted_header(custom_headers, "Authorization"): return if self._api_key_provider is not None or self._workload_identity_auth is not None: @@ -892,14 +913,25 @@ async def _send_with_auth_retry( retried: bool = False, **kwargs: Unpack[HttpxSendArgs], ) -> httpx.Response: + used_workload_identity_auth = False if self._api_key_provider is not None: - request.headers["Authorization"] = f"Bearer {await self._refresh_api_key()}" + authorization = request.headers.get("Authorization") + if authorization is None or authorization == f"Bearer {self.api_key}": + request.headers["Authorization"] = f"Bearer {await self._refresh_api_key()}" if self._workload_identity_auth is not None: - request.headers["Authorization"] = f"Bearer {await self._workload_identity_auth.get_token_async()}" + authorization = request.headers.get("Authorization") + if authorization is None or authorization == f"Bearer {WORKLOAD_IDENTITY_API_KEY_PLACEHOLDER}": + request.headers["Authorization"] = f"Bearer {await self._workload_identity_auth.get_token_async()}" + used_workload_identity_auth = True response = await super()._send_request(request, stream=stream, **kwargs) - if response.status_code == 401 and self._workload_identity_auth is not None and not retried: + if ( + response.status_code == 401 + and self._workload_identity_auth is not None + and used_workload_identity_auth + and not retried + ): await response.aclose() self._workload_identity_auth.invalidate_token() request.headers["Authorization"] = f"Bearer {await self._workload_identity_auth.get_token_async()}" @@ -964,7 +996,7 @@ def default_headers(self) -> dict[str, str | Omit]: @override def _validate_headers(self, headers: Headers, custom_headers: Headers) -> None: - if headers.get("Authorization") or isinstance(custom_headers.get("Authorization"), Omit): + if _has_header(headers, "Authorization") or _has_omitted_header(custom_headers, "Authorization"): return if self._api_key_provider is not None or self._workload_identity_auth is not None: diff --git a/src/openai/lib/azure.py b/src/openai/lib/azure.py index a43316df98..e0b0956334 100644 --- a/src/openai/lib/azure.py +++ b/src/openai/lib/azure.py @@ -206,7 +206,7 @@ def __init__( if azure_ad_token is None: azure_ad_token = os.environ.get("AZURE_OPENAI_AD_TOKEN") - if api_key is None and azure_ad_token is None and azure_ad_token_provider is None: + if _enforce_credentials and api_key is None and azure_ad_token is None and azure_ad_token_provider is None: raise OpenAIError( "Missing credentials. Please pass one of `api_key`, `azure_ad_token`, `azure_ad_token_provider`, or the `AZURE_OPENAI_API_KEY` or `AZURE_OPENAI_AD_TOKEN` environment variables." ) @@ -505,7 +505,7 @@ def __init__( if azure_ad_token is None: azure_ad_token = os.environ.get("AZURE_OPENAI_AD_TOKEN") - if api_key is None and azure_ad_token is None and azure_ad_token_provider is None: + if _enforce_credentials and api_key is None and azure_ad_token is None and azure_ad_token_provider is None: raise OpenAIError( "Missing credentials. Please pass one of `api_key`, `azure_ad_token`, `azure_ad_token_provider`, or the `AZURE_OPENAI_API_KEY` or `AZURE_OPENAI_AD_TOKEN` environment variables." ) diff --git a/tests/lib/test_azure.py b/tests/lib/test_azure.py index 52c24eba27..17ee885ed4 100644 --- a/tests/lib/test_azure.py +++ b/tests/lib/test_azure.py @@ -8,6 +8,9 @@ import pytest from respx import MockRouter +from openai import OpenAIError +from tests.utils import update_env +from openai._types import Omit from openai._utils import SensitiveHeadersFilter, is_dict from openai._models import FinalRequestOptions from openai.lib.azure import AzureOpenAI, AsyncAzureOpenAI @@ -76,6 +79,54 @@ def test_client_copying_override_options(client: Client) -> None: assert copied._custom_query == {"api-version": "2022-05-01"} +def test_enforce_credentials_false_sync() -> None: + with update_env(AZURE_OPENAI_API_KEY=Omit(), AZURE_OPENAI_AD_TOKEN=Omit()): + AzureOpenAI( + api_version="2024-02-01", + api_key=None, + azure_ad_token=None, + azure_ad_token_provider=None, + azure_endpoint="https://example-resource.azure.openai.com", + _enforce_credentials=False, + ) + + +def test_enforce_credentials_true_sync() -> None: + with update_env(AZURE_OPENAI_API_KEY=Omit(), AZURE_OPENAI_AD_TOKEN=Omit()): + with pytest.raises(OpenAIError, match="Missing credentials"): + AzureOpenAI( + api_version="2024-02-01", + api_key=None, + azure_ad_token=None, + azure_ad_token_provider=None, + azure_endpoint="https://example-resource.azure.openai.com", + ) + + +def test_enforce_credentials_false_async() -> None: + with update_env(AZURE_OPENAI_API_KEY=Omit(), AZURE_OPENAI_AD_TOKEN=Omit()): + AsyncAzureOpenAI( + api_version="2024-02-01", + api_key=None, + azure_ad_token=None, + azure_ad_token_provider=None, + azure_endpoint="https://example-resource.azure.openai.com", + _enforce_credentials=False, + ) + + +def test_enforce_credentials_true_async() -> None: + with update_env(AZURE_OPENAI_API_KEY=Omit(), AZURE_OPENAI_AD_TOKEN=Omit()): + with pytest.raises(OpenAIError, match="Missing credentials"): + AsyncAzureOpenAI( + api_version="2024-02-01", + api_key=None, + azure_ad_token=None, + azure_ad_token_provider=None, + azure_endpoint="https://example-resource.azure.openai.com", + ) + + @pytest.mark.respx() def test_client_token_provider_refresh_sync(respx_mock: MockRouter) -> None: respx_mock.post( diff --git a/tests/test_client.py b/tests/test_client.py index 3f3288158f..99cd5c3b34 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -492,6 +492,29 @@ def test_validate_headers(self) -> None: ) ) + with update_env( + **{ + "OPENAI_API_KEY": Omit(), + "OPENAI_ADMIN_KEY": Omit(), + } + ): + no_credentials = OpenAI( + base_url=base_url, + api_key=None, + admin_api_key=None, + _enforce_credentials=False, + _strict_response_validation=True, + ) + lowercase_auth_request = no_credentials._build_request( + FinalRequestOptions(method="get", url="/foo", headers={"authorization": "Bearer custom"}) + ) + assert lowercase_auth_request.headers.get("Authorization") == "Bearer custom" + + omitted_auth_request = no_credentials._build_request( + FinalRequestOptions(method="get", url="/foo", headers={"authorization": Omit()}) + ) + assert "Authorization" not in omitted_auth_request.headers + with update_env( **{ "OPENAI_API_KEY": Omit(), @@ -501,6 +524,40 @@ def test_validate_headers(self) -> None: with pytest.raises(OpenAIError, match="Missing credentials"): OpenAI(base_url=base_url, api_key=None, admin_api_key=None, _strict_response_validation=True) + @pytest.mark.respx(base_url=base_url) + def test_api_key_provider_preserves_admin_auth(self, respx_mock: MockRouter) -> None: + respx_mock.get("/organization/projects").mock(return_value=httpx.Response(200, json={"ok": True})) + + provider_called = False + + def api_key_provider() -> str: + nonlocal provider_called + provider_called = True + return "dynamic-api-key" + + client = OpenAI(base_url=base_url, api_key=api_key_provider, admin_api_key=admin_api_key) + response = client.get( + "/organization/projects", + cast_to=httpx.Response, + options={"security": {"admin_api_key_auth": True}}, + ) + + assert response.request.headers.get("Authorization") == f"Bearer {admin_api_key}" + assert provider_called is False + + @pytest.mark.respx(base_url=base_url) + def test_workload_identity_preserves_admin_auth(self, respx_mock: MockRouter) -> None: + respx_mock.get("/organization/projects").mock(return_value=httpx.Response(200, json={"ok": True})) + + client = OpenAI(base_url=base_url, workload_identity=workload_identity, admin_api_key=admin_api_key) + response = client.get( + "/organization/projects", + cast_to=httpx.Response, + options={"security": {"admin_api_key_auth": True}}, + ) + + assert response.request.headers.get("Authorization") == f"Bearer {admin_api_key}" + def test_workload_identity_is_mutually_exclusive_with_api_key(self) -> None: with pytest.raises( OpenAIError, @@ -1680,6 +1737,29 @@ async def test_validate_headers(self) -> None: ) ) + with update_env( + **{ + "OPENAI_API_KEY": Omit(), + "OPENAI_ADMIN_KEY": Omit(), + } + ): + no_credentials = AsyncOpenAI( + base_url=base_url, + api_key=None, + admin_api_key=None, + _enforce_credentials=False, + _strict_response_validation=True, + ) + lowercase_auth_request = no_credentials._build_request( + FinalRequestOptions(method="get", url="/foo", headers={"authorization": "Bearer custom"}) + ) + assert lowercase_auth_request.headers.get("Authorization") == "Bearer custom" + + omitted_auth_request = no_credentials._build_request( + FinalRequestOptions(method="get", url="/foo", headers={"authorization": Omit()}) + ) + assert "Authorization" not in omitted_auth_request.headers + with update_env( **{ "OPENAI_API_KEY": Omit(), @@ -1689,6 +1769,40 @@ async def test_validate_headers(self) -> None: with pytest.raises(OpenAIError, match="Missing credentials"): AsyncOpenAI(base_url=base_url, api_key=None, admin_api_key=None, _strict_response_validation=True) + @pytest.mark.respx(base_url=base_url) + async def test_api_key_provider_preserves_admin_auth(self, respx_mock: MockRouter) -> None: + respx_mock.get("/organization/projects").mock(return_value=httpx.Response(200, json={"ok": True})) + + provider_called = False + + async def api_key_provider() -> str: + nonlocal provider_called + provider_called = True + return "dynamic-api-key" + + client = AsyncOpenAI(base_url=base_url, api_key=api_key_provider, admin_api_key=admin_api_key) + response = await client.get( + "/organization/projects", + cast_to=httpx.Response, + options={"security": {"admin_api_key_auth": True}}, + ) + + assert response.request.headers.get("Authorization") == f"Bearer {admin_api_key}" + assert provider_called is False + + @pytest.mark.respx(base_url=base_url) + async def test_workload_identity_preserves_admin_auth(self, respx_mock: MockRouter) -> None: + respx_mock.get("/organization/projects").mock(return_value=httpx.Response(200, json={"ok": True})) + + client = AsyncOpenAI(base_url=base_url, workload_identity=workload_identity, admin_api_key=admin_api_key) + response = await client.get( + "/organization/projects", + cast_to=httpx.Response, + options={"security": {"admin_api_key_auth": True}}, + ) + + assert response.request.headers.get("Authorization") == f"Bearer {admin_api_key}" + async def test_default_query_option(self) -> None: client = AsyncOpenAI( base_url=base_url, From 9e4efd13bca6730d150cffba12151cc7c5f0e70a Mon Sep 17 00:00:00 2001 From: Alex Chang Date: Thu, 30 Apr 2026 11:29:14 -0400 Subject: [PATCH 711/769] fix: avoid bearer fallback for admin auth --- src/openai/_client.py | 34 +++++++++++++++++----------------- tests/test_client.py | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 17 deletions(-) diff --git a/src/openai/_client.py b/src/openai/_client.py index f999aaab15..499a62dfe5 100644 --- a/src/openai/_client.py +++ b/src/openai/_client.py @@ -29,7 +29,7 @@ get_async_library, ) from ._compat import cached_property -from ._models import SecurityOptions +from ._models import SecurityOptions, FinalRequestOptions from ._version import __version__ from ._streaming import Stream as Stream, AsyncStream as AsyncStream from ._exceptions import OpenAIError, APIStatusError @@ -408,14 +408,10 @@ def _send_with_auth_retry( **kwargs: Unpack[HttpxSendArgs], ) -> httpx.Response: used_workload_identity_auth = False - if self._api_key_provider is not None: - authorization = request.headers.get("Authorization") - if authorization is None or authorization == f"Bearer {self.api_key}": - request.headers["Authorization"] = f"Bearer {self._refresh_api_key()}" if self._workload_identity_auth is not None: authorization = request.headers.get("Authorization") - if authorization is None or authorization == f"Bearer {WORKLOAD_IDENTITY_API_KEY_PLACEHOLDER}": + if authorization == f"Bearer {WORKLOAD_IDENTITY_API_KEY_PLACEHOLDER}": request.headers["Authorization"] = f"Bearer {self._workload_identity_auth.get_token()}" used_workload_identity_auth = True @@ -493,13 +489,17 @@ def _validate_headers(self, headers: Headers, custom_headers: Headers) -> None: if _has_header(headers, "Authorization") or _has_omitted_header(custom_headers, "Authorization"): return - if self._api_key_provider is not None or self._workload_identity_auth is not None: - return - raise TypeError( '"Could not resolve authentication method. Expected either api_key or admin_api_key to be set. Or for one of the `Authorization` or `Authorization` headers to be explicitly omitted"' ) + @override + def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOptions: + if self._api_key_provider is not None and options.security.get("bearer_auth", False): + self._refresh_api_key() + + return super()._prepare_options(options) + def _refresh_api_key(self) -> str: if self._api_key_provider is not None: self.api_key = self._api_key_provider() @@ -914,14 +914,10 @@ async def _send_with_auth_retry( **kwargs: Unpack[HttpxSendArgs], ) -> httpx.Response: used_workload_identity_auth = False - if self._api_key_provider is not None: - authorization = request.headers.get("Authorization") - if authorization is None or authorization == f"Bearer {self.api_key}": - request.headers["Authorization"] = f"Bearer {await self._refresh_api_key()}" if self._workload_identity_auth is not None: authorization = request.headers.get("Authorization") - if authorization is None or authorization == f"Bearer {WORKLOAD_IDENTITY_API_KEY_PLACEHOLDER}": + if authorization == f"Bearer {WORKLOAD_IDENTITY_API_KEY_PLACEHOLDER}": request.headers["Authorization"] = f"Bearer {await self._workload_identity_auth.get_token_async()}" used_workload_identity_auth = True @@ -999,13 +995,17 @@ def _validate_headers(self, headers: Headers, custom_headers: Headers) -> None: if _has_header(headers, "Authorization") or _has_omitted_header(custom_headers, "Authorization"): return - if self._api_key_provider is not None or self._workload_identity_auth is not None: - return - raise TypeError( '"Could not resolve authentication method. Expected either api_key or admin_api_key to be set. Or for one of the `Authorization` or `Authorization` headers to be explicitly omitted"' ) + @override + async def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOptions: + if self._api_key_provider is not None and options.security.get("bearer_auth", False): + await self._refresh_api_key() + + return await super()._prepare_options(options) + async def _refresh_api_key(self) -> str: if self._api_key_provider is not None: self.api_key = await self._api_key_provider() diff --git a/tests/test_client.py b/tests/test_client.py index 99cd5c3b34..e2bb6ea966 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -545,6 +545,25 @@ def api_key_provider() -> str: assert response.request.headers.get("Authorization") == f"Bearer {admin_api_key}" assert provider_called is False + def test_api_key_provider_does_not_fill_admin_auth(self) -> None: + provider_called = False + + def api_key_provider() -> str: + nonlocal provider_called + provider_called = True + return "dynamic-api-key" + + with update_env(OPENAI_ADMIN_KEY=Omit()): + client = OpenAI(base_url=base_url, api_key=api_key_provider, admin_api_key=None) + with pytest.raises(TypeError, match="Could not resolve authentication method"): + client.get( + "/organization/projects", + cast_to=httpx.Response, + options={"security": {"admin_api_key_auth": True}}, + ) + + assert provider_called is False + @pytest.mark.respx(base_url=base_url) def test_workload_identity_preserves_admin_auth(self, respx_mock: MockRouter) -> None: respx_mock.get("/organization/projects").mock(return_value=httpx.Response(200, json={"ok": True})) @@ -1790,6 +1809,25 @@ async def api_key_provider() -> str: assert response.request.headers.get("Authorization") == f"Bearer {admin_api_key}" assert provider_called is False + async def test_api_key_provider_does_not_fill_admin_auth(self) -> None: + provider_called = False + + async def api_key_provider() -> str: + nonlocal provider_called + provider_called = True + return "dynamic-api-key" + + with update_env(OPENAI_ADMIN_KEY=Omit()): + client = AsyncOpenAI(base_url=base_url, api_key=api_key_provider, admin_api_key=None) + with pytest.raises(TypeError, match="Could not resolve authentication method"): + await client.get( + "/organization/projects", + cast_to=httpx.Response, + options={"security": {"admin_api_key_auth": True}}, + ) + + assert provider_called is False + @pytest.mark.respx(base_url=base_url) async def test_workload_identity_preserves_admin_auth(self, respx_mock: MockRouter) -> None: respx_mock.get("/organization/projects").mock(return_value=httpx.Response(200, json={"ok": True})) From 15a9e05ada36a126f3ad9fab0eada8ad62b8389c Mon Sep 17 00:00:00 2001 From: Alex Chang Date: Thu, 30 Apr 2026 11:46:31 -0400 Subject: [PATCH 712/769] fix: allow explicit Azure auth headers --- src/openai/lib/azure.py | 63 ++++++++++++++++++++++--- tests/lib/test_azure.py | 100 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+), 6 deletions(-) diff --git a/src/openai/lib/azure.py b/src/openai/lib/azure.py index e0b0956334..4fcae24788 100644 --- a/src/openai/lib/azure.py +++ b/src/openai/lib/azure.py @@ -8,11 +8,11 @@ import httpx from ..auth import WorkloadIdentity -from .._types import NOT_GIVEN, Omit, Query, Timeout, NotGiven +from .._types import NOT_GIVEN, Omit, Query, Headers, Timeout, NotGiven from .._utils import is_given, is_mapping from .._client import OpenAI, AsyncOpenAI from .._compat import model_copy -from .._models import FinalRequestOptions +from .._models import SecurityOptions, FinalRequestOptions from .._streaming import Stream, AsyncStream from .._exceptions import OpenAIError from .._base_client import DEFAULT_MAX_RETRIES, BaseClient @@ -43,6 +43,15 @@ API_KEY_SENTINEL = "".join(["<", "missing API key", ">"]) +def _has_header(headers: Headers, header: str) -> bool: + header = header.lower() + return any(key.lower() == header for key in headers) + + +def _has_auth_header(headers: Headers) -> bool: + return _has_header(headers, "Authorization") or _has_header(headers, "api-key") + + class MutuallyExclusiveAuthError(OpenAIError): def __init__(self) -> None: super().__init__( @@ -337,6 +346,25 @@ def _get_azure_ad_token(self) -> str | None: return None + @override + def _auth_headers(self, security: SecurityOptions) -> dict[str, str]: # noqa: ARG002 + if self._azure_ad_token is not None: + return {"Authorization": f"Bearer {self._azure_ad_token}"} + + if self.api_key and self.api_key != API_KEY_SENTINEL: + return {"api-key": self.api_key} + + return {} + + @override + def _validate_headers(self, headers: Headers, custom_headers: Headers) -> None: + if _has_auth_header(headers) or _has_auth_header(custom_headers): + return + + raise TypeError( + '"Could not resolve authentication method. Expected either api_key, azure_ad_token or azure_ad_token_provider to be set. Or for one of the `Authorization` or `api-key` headers to be explicitly supplied or omitted"' + ) + @override def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOptions: headers: dict[str, str | Omit] = {**options.headers} if is_given(options.headers) else {} @@ -346,11 +374,13 @@ def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOptions: azure_ad_token = self._get_azure_ad_token() if azure_ad_token is not None: - if headers.get("Authorization") is None: + if not _has_header(headers, "Authorization"): headers["Authorization"] = f"Bearer {azure_ad_token}" elif self.api_key and self.api_key != API_KEY_SENTINEL: - if headers.get("api-key") is None: + if not _has_header(headers, "api-key"): headers["api-key"] = self.api_key + elif _has_auth_header(headers) or _has_auth_header(self.default_headers): + pass else: # should never be hit raise ValueError("Unable to handle auth") @@ -638,6 +668,25 @@ async def _get_azure_ad_token(self) -> str | None: return None + @override + def _auth_headers(self, security: SecurityOptions) -> dict[str, str]: # noqa: ARG002 + if self._azure_ad_token is not None: + return {"Authorization": f"Bearer {self._azure_ad_token}"} + + if self.api_key and self.api_key != API_KEY_SENTINEL: + return {"api-key": self.api_key} + + return {} + + @override + def _validate_headers(self, headers: Headers, custom_headers: Headers) -> None: + if _has_auth_header(headers) or _has_auth_header(custom_headers): + return + + raise TypeError( + '"Could not resolve authentication method. Expected either api_key, azure_ad_token or azure_ad_token_provider to be set. Or for one of the `Authorization` or `api-key` headers to be explicitly supplied or omitted"' + ) + @override async def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOptions: headers: dict[str, str | Omit] = {**options.headers} if is_given(options.headers) else {} @@ -647,11 +696,13 @@ async def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOp azure_ad_token = await self._get_azure_ad_token() if azure_ad_token is not None: - if headers.get("Authorization") is None: + if not _has_header(headers, "Authorization"): headers["Authorization"] = f"Bearer {azure_ad_token}" elif self.api_key and self.api_key != API_KEY_SENTINEL: - if headers.get("api-key") is None: + if not _has_header(headers, "api-key"): headers["api-key"] = self.api_key + elif _has_auth_header(headers) or _has_auth_header(self.default_headers): + pass else: # should never be hit raise ValueError("Unable to handle auth") diff --git a/tests/lib/test_azure.py b/tests/lib/test_azure.py index 17ee885ed4..3e1d783e2c 100644 --- a/tests/lib/test_azure.py +++ b/tests/lib/test_azure.py @@ -91,6 +91,55 @@ def test_enforce_credentials_false_sync() -> None: ) +@pytest.mark.respx() +def test_enforce_credentials_false_sync_uses_default_api_key_header(respx_mock: MockRouter) -> None: + respx_mock.post( + "https://example-resource.azure.openai.com/openai/deployments/gpt-4/chat/completions?api-version=2024-02-01" + ).mock(return_value=httpx.Response(200, json={"model": "gpt-4"})) + + with update_env(AZURE_OPENAI_API_KEY=Omit(), AZURE_OPENAI_AD_TOKEN=Omit()): + client = AzureOpenAI( + api_version="2024-02-01", + api_key=None, + azure_ad_token=None, + azure_ad_token_provider=None, + azure_endpoint="https://example-resource.azure.openai.com", + default_headers={"api-key": "manual-api-key"}, + _enforce_credentials=False, + ) + client.chat.completions.create(messages=[], model="gpt-4") + + calls = cast("list[MockRequestCall]", respx_mock.calls) + assert calls[0].request.headers.get("api-key") == "manual-api-key" + assert calls[0].request.headers.get("Authorization") is None + + +@pytest.mark.respx() +def test_enforce_credentials_false_sync_uses_request_authorization_header(respx_mock: MockRouter) -> None: + respx_mock.post( + "https://example-resource.azure.openai.com/openai/deployments/gpt-4/chat/completions?api-version=2024-02-01" + ).mock(return_value=httpx.Response(200, json={"model": "gpt-4"})) + + with update_env(AZURE_OPENAI_API_KEY=Omit(), AZURE_OPENAI_AD_TOKEN=Omit()): + client = AzureOpenAI( + api_version="2024-02-01", + api_key=None, + azure_ad_token=None, + azure_ad_token_provider=None, + azure_endpoint="https://example-resource.azure.openai.com", + _enforce_credentials=False, + ) + client.chat.completions.create( + messages=[], + model="gpt-4", + extra_headers={"authorization": "Bearer manual-token"}, + ) + + calls = cast("list[MockRequestCall]", respx_mock.calls) + assert calls[0].request.headers.get("Authorization") == "Bearer manual-token" + assert calls[0].request.headers.get("api-key") is None + + def test_enforce_credentials_true_sync() -> None: with update_env(AZURE_OPENAI_API_KEY=Omit(), AZURE_OPENAI_AD_TOKEN=Omit()): with pytest.raises(OpenAIError, match="Missing credentials"): @@ -115,6 +164,57 @@ def test_enforce_credentials_false_async() -> None: ) +@pytest.mark.asyncio +@pytest.mark.respx() +async def test_enforce_credentials_false_async_uses_default_api_key_header(respx_mock: MockRouter) -> None: + respx_mock.post( + "https://example-resource.azure.openai.com/openai/deployments/gpt-4/chat/completions?api-version=2024-02-01" + ).mock(return_value=httpx.Response(200, json={"model": "gpt-4"})) + + with update_env(AZURE_OPENAI_API_KEY=Omit(), AZURE_OPENAI_AD_TOKEN=Omit()): + client = AsyncAzureOpenAI( + api_version="2024-02-01", + api_key=None, + azure_ad_token=None, + azure_ad_token_provider=None, + azure_endpoint="https://example-resource.azure.openai.com", + default_headers={"api-key": "manual-api-key"}, + _enforce_credentials=False, + ) + await client.chat.completions.create(messages=[], model="gpt-4") + + calls = cast("list[MockRequestCall]", respx_mock.calls) + assert calls[0].request.headers.get("api-key") == "manual-api-key" + assert calls[0].request.headers.get("Authorization") is None + + +@pytest.mark.asyncio +@pytest.mark.respx() +async def test_enforce_credentials_false_async_uses_request_authorization_header(respx_mock: MockRouter) -> None: + respx_mock.post( + "https://example-resource.azure.openai.com/openai/deployments/gpt-4/chat/completions?api-version=2024-02-01" + ).mock(return_value=httpx.Response(200, json={"model": "gpt-4"})) + + with update_env(AZURE_OPENAI_API_KEY=Omit(), AZURE_OPENAI_AD_TOKEN=Omit()): + client = AsyncAzureOpenAI( + api_version="2024-02-01", + api_key=None, + azure_ad_token=None, + azure_ad_token_provider=None, + azure_endpoint="https://example-resource.azure.openai.com", + _enforce_credentials=False, + ) + await client.chat.completions.create( + messages=[], + model="gpt-4", + extra_headers={"authorization": "Bearer manual-token"}, + ) + + calls = cast("list[MockRequestCall]", respx_mock.calls) + assert calls[0].request.headers.get("Authorization") == "Bearer manual-token" + assert calls[0].request.headers.get("api-key") is None + + def test_enforce_credentials_true_async() -> None: with update_env(AZURE_OPENAI_API_KEY=Omit(), AZURE_OPENAI_AD_TOKEN=Omit()): with pytest.raises(OpenAIError, match="Missing credentials"): From 42b2b60af44566ce3d1d6d37f2bb9d77274e65dd Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 30 Apr 2026 17:32:07 +0000 Subject: [PATCH 713/769] fix(types): correct created_at and completed_at to float in Response --- .stats.yml | 4 ++-- src/openai/types/responses/response.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.stats.yml b/.stats.yml index 73d7722354..fc59bc229a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 153 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-7712c92246b94f811f6e3d33569242e75b22497d51df8cc27b16a6a205b4560a.yml -openapi_spec_hash: d431cf9d2bf2b01122bb98cc7b7a357b +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-39747efaffb2331dfdeb20a8cb4293abaf871f7b6545f8d7230baf7843bc4d09.yml +openapi_spec_hash: 142dc3e8e2e0a4f1017102e1dd49a85b config_hash: 88be7d18ee7f33affcdad19572cd0c91 diff --git a/src/openai/types/responses/response.py b/src/openai/types/responses/response.py index bfcf2460d6..0d2491ea7c 100644 --- a/src/openai/types/responses/response.py +++ b/src/openai/types/responses/response.py @@ -60,7 +60,7 @@ class Response(BaseModel): id: str """Unique identifier for this Response.""" - created_at: int + created_at: float """Unix timestamp (in seconds) of when this Response was created.""" error: Optional[ResponseError] = None @@ -165,7 +165,7 @@ class Response(BaseModel): [Learn more](https://platform.openai.com/docs/guides/background). """ - completed_at: Optional[int] = None + completed_at: Optional[float] = None """ Unix timestamp (in seconds) of when this Response was completed. Only present when the status is `completed`. From d05f3a875fc78519711067350605d6226aed33b8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 30 Apr 2026 18:00:45 +0000 Subject: [PATCH 714/769] feat(api): manual updates Include all admin APIs in the code generation. --- .stats.yml | 6 +- api.md | 324 ++++ .../resources/admin/organization/__init__.py | 112 ++ .../admin/organization/admin_api_keys.py | 468 +++++ .../admin/organization/certificates.py | 815 ++++++++ .../admin/organization/groups/__init__.py | 47 + .../admin/organization/groups/groups.py | 544 ++++++ .../admin/organization/groups/roles.py | 398 ++++ .../admin/organization/groups/users.py | 400 ++++ .../resources/admin/organization/invites.py | 500 +++++ .../admin/organization/organization.py | 256 +++ .../admin/organization/projects/__init__.py | 117 ++ .../admin/organization/projects/api_keys.py | 405 ++++ .../organization/projects/certificates.py | 426 ++++ .../organization/projects/groups/__init__.py | 33 + .../organization/projects/groups/groups.py | 451 +++++ .../organization/projects/groups/roles.py | 426 ++++ .../admin/organization/projects/projects.py | 824 ++++++++ .../organization/projects/rate_limits.py | 379 ++++ .../admin/organization/projects/roles.py | 552 ++++++ .../organization/projects/service_accounts.py | 512 +++++ .../organization/projects/users/__init__.py | 33 + .../organization/projects/users/roles.py | 426 ++++ .../organization/projects/users/users.py | 659 +++++++ .../resources/admin/organization/roles.py | 526 +++++ .../resources/admin/organization/usage.py | 1724 +++++++++++++++++ .../admin/organization/users/__init__.py | 33 + .../admin/organization/users/roles.py | 398 ++++ .../admin/organization/users/users.py | 509 +++++ .../types/admin/organization/__init__.py | 57 + .../types/admin/organization/admin_api_key.py | 54 + .../admin_api_key_create_params.py | 11 + .../admin_api_key_delete_response.py | 15 + .../organization/admin_api_key_list_params.py | 19 + .../types/admin/organization/certificate.py | 51 + .../certificate_activate_params.py | 13 + .../organization/certificate_create_params.py | 15 + .../certificate_deactivate_params.py | 13 + .../certificate_delete_response.py | 15 + .../organization/certificate_list_params.py | 30 + .../certificate_retrieve_params.py | 17 + .../organization/certificate_update_params.py | 12 + src/openai/types/admin/organization/group.py | 24 + .../admin/organization/group_create_params.py | 12 + .../organization/group_delete_response.py | 20 + .../admin/organization/group_list_params.py | 27 + .../admin/organization/group_update_params.py | 12 + .../organization/group_update_response.py | 24 + .../admin/organization/groups/__init__.py | 13 + .../organization/groups/role_create_params.py | 12 + .../groups/role_create_response.py | 40 + .../groups/role_delete_response.py | 18 + .../organization/groups/role_list_params.py | 22 + .../organization/groups/role_list_response.py | 46 + .../organization/groups/user_create_params.py | 12 + .../groups/user_create_response.py | 20 + .../groups/user_delete_response.py | 17 + .../organization/groups/user_list_params.py | 25 + src/openai/types/admin/organization/invite.py | 47 + .../organization/invite_create_params.py | 31 + .../organization/invite_delete_response.py | 16 + .../admin/organization/invite_list_params.py | 24 + .../admin/organization/organization_user.py | 29 + .../types/admin/organization/project.py | 30 + .../organization/project_create_params.py | 21 + .../admin/organization/project_list_params.py | 30 + .../organization/project_update_params.py | 12 + .../admin/organization/projects/__init__.py | 31 + .../projects/api_key_delete_response.py | 15 + .../projects/api_key_list_params.py | 24 + .../projects/certificate_activate_params.py | 13 + .../projects/certificate_deactivate_params.py | 13 + .../projects/certificate_list_params.py | 30 + .../projects/group_create_params.py | 15 + .../projects/group_delete_response.py | 17 + .../projects/group_list_params.py | 22 + .../organization/projects/groups/__init__.py | 9 + .../projects/groups/role_create_params.py | 14 + .../projects/groups/role_create_response.py | 40 + .../projects/groups/role_delete_response.py | 18 + .../projects/groups/role_list_params.py | 24 + .../projects/groups/role_list_response.py | 46 + .../organization/projects/project_api_key.py | 45 + .../organization/projects/project_group.py | 26 + .../projects/project_rate_limit.py | 39 + .../projects/project_service_account.py | 26 + .../organization/projects/project_user.py | 29 + .../rate_limit_list_rate_limits_params.py | 30 + .../rate_limit_update_rate_limit_params.py | 29 + .../projects/role_create_params.py | 21 + .../projects/role_delete_response.py | 20 + .../organization/projects/role_list_params.py | 22 + .../projects/role_update_params.py | 23 + .../projects/service_account_create_params.py | 12 + .../service_account_create_response.py | 35 + .../service_account_delete_response.py | 15 + .../projects/service_account_list_params.py | 24 + .../projects/user_create_params.py | 15 + .../projects/user_delete_response.py | 15 + .../organization/projects/user_list_params.py | 24 + .../projects/user_update_params.py | 14 + .../organization/projects/users/__init__.py | 9 + .../projects/users/role_create_params.py | 14 + .../projects/users/role_create_response.py | 22 + .../projects/users/role_delete_response.py | 18 + .../projects/users/role_list_params.py | 24 + .../projects/users/role_list_response.py | 46 + src/openai/types/admin/organization/role.py | 36 + .../admin/organization/role_create_params.py | 21 + .../organization/role_delete_response.py | 20 + .../admin/organization/role_list_params.py | 22 + .../admin/organization/role_update_params.py | 21 + .../usage_audio_speeches_params.py | 57 + .../usage_audio_speeches_response.py | 390 ++++ .../usage_audio_transcriptions_params.py | 57 + .../usage_audio_transcriptions_response.py | 390 ++++ .../usage_code_interpreter_sessions_params.py | 47 + ...sage_code_interpreter_sessions_response.py | 390 ++++ .../organization/usage_completions_params.py | 63 + .../usage_completions_response.py | 390 ++++ .../admin/organization/usage_costs_params.py | 49 + .../organization/usage_costs_response.py | 390 ++++ .../organization/usage_embeddings_params.py | 57 + .../organization/usage_embeddings_response.py | 390 ++++ .../admin/organization/usage_images_params.py | 71 + .../organization/usage_images_response.py | 390 ++++ .../organization/usage_moderations_params.py | 57 + .../usage_moderations_response.py | 390 ++++ .../usage_vector_stores_params.py | 47 + .../usage_vector_stores_response.py | 390 ++++ .../organization/user_delete_response.py | 15 + .../admin/organization/user_list_params.py | 29 + .../admin/organization/user_update_params.py | 12 + .../admin/organization/users/__init__.py | 9 + .../organization/users/role_create_params.py | 12 + .../users/role_create_response.py | 22 + .../users/role_delete_response.py | 18 + .../organization/users/role_list_params.py | 22 + .../organization/users/role_list_response.py | 46 + .../admin/organization/groups/__init__.py | 1 + .../admin/organization/groups/test_roles.py | 305 +++ .../admin/organization/groups/test_users.py | 305 +++ .../admin/organization/projects/__init__.py | 1 + .../organization/projects/groups/__init__.py | 1 + .../projects/groups/test_roles.py | 373 ++++ .../organization/projects/test_api_keys.py | 311 +++ .../projects/test_certificates.py | 289 +++ .../organization/projects/test_groups.py | 312 +++ .../organization/projects/test_rate_limits.py | 247 +++ .../admin/organization/projects/test_roles.py | 450 +++++ .../projects/test_service_accounts.py | 399 ++++ .../admin/organization/projects/test_users.py | 512 +++++ .../organization/projects/users/__init__.py | 1 + .../organization/projects/users/test_roles.py | 373 ++++ .../admin/organization/test_admin_api_keys.py | 310 +++ .../admin/organization/test_certificates.py | 550 ++++++ .../admin/organization/test_groups.py | 319 +++ .../admin/organization/test_invites.py | 339 ++++ .../admin/organization/test_projects.py | 407 ++++ .../admin/organization/test_roles.py | 354 ++++ .../admin/organization/test_usage.py | 870 +++++++++ .../admin/organization/test_users.py | 329 ++++ .../admin/organization/users/__init__.py | 1 + .../admin/organization/users/test_roles.py | 305 +++ 164 files changed, 26118 insertions(+), 3 deletions(-) create mode 100644 src/openai/resources/admin/organization/admin_api_keys.py create mode 100644 src/openai/resources/admin/organization/certificates.py create mode 100644 src/openai/resources/admin/organization/groups/__init__.py create mode 100644 src/openai/resources/admin/organization/groups/groups.py create mode 100644 src/openai/resources/admin/organization/groups/roles.py create mode 100644 src/openai/resources/admin/organization/groups/users.py create mode 100644 src/openai/resources/admin/organization/invites.py create mode 100644 src/openai/resources/admin/organization/projects/__init__.py create mode 100644 src/openai/resources/admin/organization/projects/api_keys.py create mode 100644 src/openai/resources/admin/organization/projects/certificates.py create mode 100644 src/openai/resources/admin/organization/projects/groups/__init__.py create mode 100644 src/openai/resources/admin/organization/projects/groups/groups.py create mode 100644 src/openai/resources/admin/organization/projects/groups/roles.py create mode 100644 src/openai/resources/admin/organization/projects/projects.py create mode 100644 src/openai/resources/admin/organization/projects/rate_limits.py create mode 100644 src/openai/resources/admin/organization/projects/roles.py create mode 100644 src/openai/resources/admin/organization/projects/service_accounts.py create mode 100644 src/openai/resources/admin/organization/projects/users/__init__.py create mode 100644 src/openai/resources/admin/organization/projects/users/roles.py create mode 100644 src/openai/resources/admin/organization/projects/users/users.py create mode 100644 src/openai/resources/admin/organization/roles.py create mode 100644 src/openai/resources/admin/organization/usage.py create mode 100644 src/openai/resources/admin/organization/users/__init__.py create mode 100644 src/openai/resources/admin/organization/users/roles.py create mode 100644 src/openai/resources/admin/organization/users/users.py create mode 100644 src/openai/types/admin/organization/admin_api_key.py create mode 100644 src/openai/types/admin/organization/admin_api_key_create_params.py create mode 100644 src/openai/types/admin/organization/admin_api_key_delete_response.py create mode 100644 src/openai/types/admin/organization/admin_api_key_list_params.py create mode 100644 src/openai/types/admin/organization/certificate.py create mode 100644 src/openai/types/admin/organization/certificate_activate_params.py create mode 100644 src/openai/types/admin/organization/certificate_create_params.py create mode 100644 src/openai/types/admin/organization/certificate_deactivate_params.py create mode 100644 src/openai/types/admin/organization/certificate_delete_response.py create mode 100644 src/openai/types/admin/organization/certificate_list_params.py create mode 100644 src/openai/types/admin/organization/certificate_retrieve_params.py create mode 100644 src/openai/types/admin/organization/certificate_update_params.py create mode 100644 src/openai/types/admin/organization/group.py create mode 100644 src/openai/types/admin/organization/group_create_params.py create mode 100644 src/openai/types/admin/organization/group_delete_response.py create mode 100644 src/openai/types/admin/organization/group_list_params.py create mode 100644 src/openai/types/admin/organization/group_update_params.py create mode 100644 src/openai/types/admin/organization/group_update_response.py create mode 100644 src/openai/types/admin/organization/groups/__init__.py create mode 100644 src/openai/types/admin/organization/groups/role_create_params.py create mode 100644 src/openai/types/admin/organization/groups/role_create_response.py create mode 100644 src/openai/types/admin/organization/groups/role_delete_response.py create mode 100644 src/openai/types/admin/organization/groups/role_list_params.py create mode 100644 src/openai/types/admin/organization/groups/role_list_response.py create mode 100644 src/openai/types/admin/organization/groups/user_create_params.py create mode 100644 src/openai/types/admin/organization/groups/user_create_response.py create mode 100644 src/openai/types/admin/organization/groups/user_delete_response.py create mode 100644 src/openai/types/admin/organization/groups/user_list_params.py create mode 100644 src/openai/types/admin/organization/invite.py create mode 100644 src/openai/types/admin/organization/invite_create_params.py create mode 100644 src/openai/types/admin/organization/invite_delete_response.py create mode 100644 src/openai/types/admin/organization/invite_list_params.py create mode 100644 src/openai/types/admin/organization/organization_user.py create mode 100644 src/openai/types/admin/organization/project.py create mode 100644 src/openai/types/admin/organization/project_create_params.py create mode 100644 src/openai/types/admin/organization/project_list_params.py create mode 100644 src/openai/types/admin/organization/project_update_params.py create mode 100644 src/openai/types/admin/organization/projects/__init__.py create mode 100644 src/openai/types/admin/organization/projects/api_key_delete_response.py create mode 100644 src/openai/types/admin/organization/projects/api_key_list_params.py create mode 100644 src/openai/types/admin/organization/projects/certificate_activate_params.py create mode 100644 src/openai/types/admin/organization/projects/certificate_deactivate_params.py create mode 100644 src/openai/types/admin/organization/projects/certificate_list_params.py create mode 100644 src/openai/types/admin/organization/projects/group_create_params.py create mode 100644 src/openai/types/admin/organization/projects/group_delete_response.py create mode 100644 src/openai/types/admin/organization/projects/group_list_params.py create mode 100644 src/openai/types/admin/organization/projects/groups/__init__.py create mode 100644 src/openai/types/admin/organization/projects/groups/role_create_params.py create mode 100644 src/openai/types/admin/organization/projects/groups/role_create_response.py create mode 100644 src/openai/types/admin/organization/projects/groups/role_delete_response.py create mode 100644 src/openai/types/admin/organization/projects/groups/role_list_params.py create mode 100644 src/openai/types/admin/organization/projects/groups/role_list_response.py create mode 100644 src/openai/types/admin/organization/projects/project_api_key.py create mode 100644 src/openai/types/admin/organization/projects/project_group.py create mode 100644 src/openai/types/admin/organization/projects/project_rate_limit.py create mode 100644 src/openai/types/admin/organization/projects/project_service_account.py create mode 100644 src/openai/types/admin/organization/projects/project_user.py create mode 100644 src/openai/types/admin/organization/projects/rate_limit_list_rate_limits_params.py create mode 100644 src/openai/types/admin/organization/projects/rate_limit_update_rate_limit_params.py create mode 100644 src/openai/types/admin/organization/projects/role_create_params.py create mode 100644 src/openai/types/admin/organization/projects/role_delete_response.py create mode 100644 src/openai/types/admin/organization/projects/role_list_params.py create mode 100644 src/openai/types/admin/organization/projects/role_update_params.py create mode 100644 src/openai/types/admin/organization/projects/service_account_create_params.py create mode 100644 src/openai/types/admin/organization/projects/service_account_create_response.py create mode 100644 src/openai/types/admin/organization/projects/service_account_delete_response.py create mode 100644 src/openai/types/admin/organization/projects/service_account_list_params.py create mode 100644 src/openai/types/admin/organization/projects/user_create_params.py create mode 100644 src/openai/types/admin/organization/projects/user_delete_response.py create mode 100644 src/openai/types/admin/organization/projects/user_list_params.py create mode 100644 src/openai/types/admin/organization/projects/user_update_params.py create mode 100644 src/openai/types/admin/organization/projects/users/__init__.py create mode 100644 src/openai/types/admin/organization/projects/users/role_create_params.py create mode 100644 src/openai/types/admin/organization/projects/users/role_create_response.py create mode 100644 src/openai/types/admin/organization/projects/users/role_delete_response.py create mode 100644 src/openai/types/admin/organization/projects/users/role_list_params.py create mode 100644 src/openai/types/admin/organization/projects/users/role_list_response.py create mode 100644 src/openai/types/admin/organization/role.py create mode 100644 src/openai/types/admin/organization/role_create_params.py create mode 100644 src/openai/types/admin/organization/role_delete_response.py create mode 100644 src/openai/types/admin/organization/role_list_params.py create mode 100644 src/openai/types/admin/organization/role_update_params.py create mode 100644 src/openai/types/admin/organization/usage_audio_speeches_params.py create mode 100644 src/openai/types/admin/organization/usage_audio_speeches_response.py create mode 100644 src/openai/types/admin/organization/usage_audio_transcriptions_params.py create mode 100644 src/openai/types/admin/organization/usage_audio_transcriptions_response.py create mode 100644 src/openai/types/admin/organization/usage_code_interpreter_sessions_params.py create mode 100644 src/openai/types/admin/organization/usage_code_interpreter_sessions_response.py create mode 100644 src/openai/types/admin/organization/usage_completions_params.py create mode 100644 src/openai/types/admin/organization/usage_completions_response.py create mode 100644 src/openai/types/admin/organization/usage_costs_params.py create mode 100644 src/openai/types/admin/organization/usage_costs_response.py create mode 100644 src/openai/types/admin/organization/usage_embeddings_params.py create mode 100644 src/openai/types/admin/organization/usage_embeddings_response.py create mode 100644 src/openai/types/admin/organization/usage_images_params.py create mode 100644 src/openai/types/admin/organization/usage_images_response.py create mode 100644 src/openai/types/admin/organization/usage_moderations_params.py create mode 100644 src/openai/types/admin/organization/usage_moderations_response.py create mode 100644 src/openai/types/admin/organization/usage_vector_stores_params.py create mode 100644 src/openai/types/admin/organization/usage_vector_stores_response.py create mode 100644 src/openai/types/admin/organization/user_delete_response.py create mode 100644 src/openai/types/admin/organization/user_list_params.py create mode 100644 src/openai/types/admin/organization/user_update_params.py create mode 100644 src/openai/types/admin/organization/users/__init__.py create mode 100644 src/openai/types/admin/organization/users/role_create_params.py create mode 100644 src/openai/types/admin/organization/users/role_create_response.py create mode 100644 src/openai/types/admin/organization/users/role_delete_response.py create mode 100644 src/openai/types/admin/organization/users/role_list_params.py create mode 100644 src/openai/types/admin/organization/users/role_list_response.py create mode 100644 tests/api_resources/admin/organization/groups/__init__.py create mode 100644 tests/api_resources/admin/organization/groups/test_roles.py create mode 100644 tests/api_resources/admin/organization/groups/test_users.py create mode 100644 tests/api_resources/admin/organization/projects/__init__.py create mode 100644 tests/api_resources/admin/organization/projects/groups/__init__.py create mode 100644 tests/api_resources/admin/organization/projects/groups/test_roles.py create mode 100644 tests/api_resources/admin/organization/projects/test_api_keys.py create mode 100644 tests/api_resources/admin/organization/projects/test_certificates.py create mode 100644 tests/api_resources/admin/organization/projects/test_groups.py create mode 100644 tests/api_resources/admin/organization/projects/test_rate_limits.py create mode 100644 tests/api_resources/admin/organization/projects/test_roles.py create mode 100644 tests/api_resources/admin/organization/projects/test_service_accounts.py create mode 100644 tests/api_resources/admin/organization/projects/test_users.py create mode 100644 tests/api_resources/admin/organization/projects/users/__init__.py create mode 100644 tests/api_resources/admin/organization/projects/users/test_roles.py create mode 100644 tests/api_resources/admin/organization/test_admin_api_keys.py create mode 100644 tests/api_resources/admin/organization/test_certificates.py create mode 100644 tests/api_resources/admin/organization/test_groups.py create mode 100644 tests/api_resources/admin/organization/test_invites.py create mode 100644 tests/api_resources/admin/organization/test_projects.py create mode 100644 tests/api_resources/admin/organization/test_roles.py create mode 100644 tests/api_resources/admin/organization/test_usage.py create mode 100644 tests/api_resources/admin/organization/test_users.py create mode 100644 tests/api_resources/admin/organization/users/__init__.py create mode 100644 tests/api_resources/admin/organization/users/test_roles.py diff --git a/.stats.yml b/.stats.yml index fc59bc229a..7b55dfd466 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 153 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-39747efaffb2331dfdeb20a8cb4293abaf871f7b6545f8d7230baf7843bc4d09.yml +configured_endpoints: 233 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-5b00c10325d1747a1b7da6289fe47e18f3d69503925bd3b6c1c67bbadc5a7f8f.yml openapi_spec_hash: 142dc3e8e2e0a4f1017102e1dd49a85b -config_hash: 88be7d18ee7f33affcdad19572cd0c91 +config_hash: 53256195d26013f6fe5ee634fb1c92f6 diff --git a/api.md b/api.md index c1378fa60f..f80a5b12c8 100644 --- a/api.md +++ b/api.md @@ -723,6 +723,330 @@ Methods: - client.admin.organization.audit_logs.list(\*\*params) -> SyncConversationCursorPage[AuditLogListResponse] +### AdminAPIKeys + +Types: + +```python +from openai.types.admin.organization import AdminAPIKey, AdminAPIKeyDeleteResponse +``` + +Methods: + +- client.admin.organization.admin_api_keys.create(\*\*params) -> AdminAPIKey +- client.admin.organization.admin_api_keys.retrieve(key_id) -> AdminAPIKey +- client.admin.organization.admin_api_keys.list(\*\*params) -> SyncCursorPage[AdminAPIKey] +- client.admin.organization.admin_api_keys.delete(key_id) -> AdminAPIKeyDeleteResponse + +### Usage + +Types: + +```python +from openai.types.admin.organization import ( + UsageAudioSpeechesResponse, + UsageAudioTranscriptionsResponse, + UsageCodeInterpreterSessionsResponse, + UsageCompletionsResponse, + UsageCostsResponse, + UsageEmbeddingsResponse, + UsageImagesResponse, + UsageModerationsResponse, + UsageVectorStoresResponse, +) +``` + +Methods: + +- client.admin.organization.usage.audio_speeches(\*\*params) -> UsageAudioSpeechesResponse +- client.admin.organization.usage.audio_transcriptions(\*\*params) -> UsageAudioTranscriptionsResponse +- client.admin.organization.usage.code_interpreter_sessions(\*\*params) -> UsageCodeInterpreterSessionsResponse +- client.admin.organization.usage.completions(\*\*params) -> UsageCompletionsResponse +- client.admin.organization.usage.costs(\*\*params) -> UsageCostsResponse +- client.admin.organization.usage.embeddings(\*\*params) -> UsageEmbeddingsResponse +- client.admin.organization.usage.images(\*\*params) -> UsageImagesResponse +- client.admin.organization.usage.moderations(\*\*params) -> UsageModerationsResponse +- client.admin.organization.usage.vector_stores(\*\*params) -> UsageVectorStoresResponse + +### Invites + +Types: + +```python +from openai.types.admin.organization import Invite, InviteDeleteResponse +``` + +Methods: + +- client.admin.organization.invites.create(\*\*params) -> Invite +- client.admin.organization.invites.retrieve(invite_id) -> Invite +- client.admin.organization.invites.list(\*\*params) -> SyncConversationCursorPage[Invite] +- client.admin.organization.invites.delete(invite_id) -> InviteDeleteResponse + +### Users + +Types: + +```python +from openai.types.admin.organization import OrganizationUser, UserDeleteResponse +``` + +Methods: + +- client.admin.organization.users.retrieve(user_id) -> OrganizationUser +- client.admin.organization.users.update(user_id, \*\*params) -> OrganizationUser +- client.admin.organization.users.list(\*\*params) -> SyncConversationCursorPage[OrganizationUser] +- client.admin.organization.users.delete(user_id) -> UserDeleteResponse + +#### Roles + +Types: + +```python +from openai.types.admin.organization.users import ( + RoleCreateResponse, + RoleListResponse, + RoleDeleteResponse, +) +``` + +Methods: + +- client.admin.organization.users.roles.create(user_id, \*\*params) -> RoleCreateResponse +- client.admin.organization.users.roles.list(user_id, \*\*params) -> SyncCursorPage[RoleListResponse] +- client.admin.organization.users.roles.delete(role_id, \*, user_id) -> RoleDeleteResponse + +### Groups + +Types: + +```python +from openai.types.admin.organization import Group, GroupUpdateResponse, GroupDeleteResponse +``` + +Methods: + +- client.admin.organization.groups.create(\*\*params) -> Group +- client.admin.organization.groups.update(group_id, \*\*params) -> GroupUpdateResponse +- client.admin.organization.groups.list(\*\*params) -> SyncCursorPage[Group] +- client.admin.organization.groups.delete(group_id) -> GroupDeleteResponse + +#### Users + +Types: + +```python +from openai.types.admin.organization.groups import UserCreateResponse, UserDeleteResponse +``` + +Methods: + +- client.admin.organization.groups.users.create(group_id, \*\*params) -> UserCreateResponse +- client.admin.organization.groups.users.list(group_id, \*\*params) -> SyncCursorPage[OrganizationUser] +- client.admin.organization.groups.users.delete(user_id, \*, group_id) -> UserDeleteResponse + +#### Roles + +Types: + +```python +from openai.types.admin.organization.groups import ( + RoleCreateResponse, + RoleListResponse, + RoleDeleteResponse, +) +``` + +Methods: + +- client.admin.organization.groups.roles.create(group_id, \*\*params) -> RoleCreateResponse +- client.admin.organization.groups.roles.list(group_id, \*\*params) -> SyncCursorPage[RoleListResponse] +- client.admin.organization.groups.roles.delete(role_id, \*, group_id) -> RoleDeleteResponse + +### Roles + +Types: + +```python +from openai.types.admin.organization import Role, RoleDeleteResponse +``` + +Methods: + +- client.admin.organization.roles.create(\*\*params) -> Role +- client.admin.organization.roles.update(role_id, \*\*params) -> Role +- client.admin.organization.roles.list(\*\*params) -> SyncCursorPage[Role] +- client.admin.organization.roles.delete(role_id) -> RoleDeleteResponse + +### Certificates + +Types: + +```python +from openai.types.admin.organization import Certificate, CertificateDeleteResponse +``` + +Methods: + +- client.admin.organization.certificates.create(\*\*params) -> Certificate +- client.admin.organization.certificates.retrieve(certificate_id, \*\*params) -> Certificate +- client.admin.organization.certificates.update(certificate_id, \*\*params) -> Certificate +- client.admin.organization.certificates.list(\*\*params) -> SyncConversationCursorPage[Certificate] +- client.admin.organization.certificates.delete(certificate_id) -> CertificateDeleteResponse +- client.admin.organization.certificates.activate(\*\*params) -> SyncPage[Certificate] +- client.admin.organization.certificates.deactivate(\*\*params) -> SyncPage[Certificate] + +### Projects + +Types: + +```python +from openai.types.admin.organization import Project +``` + +Methods: + +- client.admin.organization.projects.create(\*\*params) -> Project +- client.admin.organization.projects.retrieve(project_id) -> Project +- client.admin.organization.projects.update(project_id, \*\*params) -> Project +- client.admin.organization.projects.list(\*\*params) -> SyncConversationCursorPage[Project] +- client.admin.organization.projects.archive(project_id) -> Project + +#### Users + +Types: + +```python +from openai.types.admin.organization.projects import ProjectUser, UserDeleteResponse +``` + +Methods: + +- client.admin.organization.projects.users.create(project_id, \*\*params) -> ProjectUser +- client.admin.organization.projects.users.retrieve(user_id, \*, project_id) -> ProjectUser +- client.admin.organization.projects.users.update(user_id, \*, project_id, \*\*params) -> ProjectUser +- client.admin.organization.projects.users.list(project_id, \*\*params) -> SyncConversationCursorPage[ProjectUser] +- client.admin.organization.projects.users.delete(user_id, \*, project_id) -> UserDeleteResponse + +##### Roles + +Types: + +```python +from openai.types.admin.organization.projects.users import ( + RoleCreateResponse, + RoleListResponse, + RoleDeleteResponse, +) +``` + +Methods: + +- client.admin.organization.projects.users.roles.create(user_id, \*, project_id, \*\*params) -> RoleCreateResponse +- client.admin.organization.projects.users.roles.list(user_id, \*, project_id, \*\*params) -> SyncCursorPage[RoleListResponse] +- client.admin.organization.projects.users.roles.delete(role_id, \*, project_id, user_id) -> RoleDeleteResponse + +#### ServiceAccounts + +Types: + +```python +from openai.types.admin.organization.projects import ( + ProjectServiceAccount, + ServiceAccountCreateResponse, + ServiceAccountDeleteResponse, +) +``` + +Methods: + +- client.admin.organization.projects.service_accounts.create(project_id, \*\*params) -> ServiceAccountCreateResponse +- client.admin.organization.projects.service_accounts.retrieve(service_account_id, \*, project_id) -> ProjectServiceAccount +- client.admin.organization.projects.service_accounts.list(project_id, \*\*params) -> SyncConversationCursorPage[ProjectServiceAccount] +- client.admin.organization.projects.service_accounts.delete(service_account_id, \*, project_id) -> ServiceAccountDeleteResponse + +#### APIKeys + +Types: + +```python +from openai.types.admin.organization.projects import ProjectAPIKey, APIKeyDeleteResponse +``` + +Methods: + +- client.admin.organization.projects.api_keys.retrieve(key_id, \*, project_id) -> ProjectAPIKey +- client.admin.organization.projects.api_keys.list(project_id, \*\*params) -> SyncConversationCursorPage[ProjectAPIKey] +- client.admin.organization.projects.api_keys.delete(key_id, \*, project_id) -> APIKeyDeleteResponse + +#### RateLimits + +Types: + +```python +from openai.types.admin.organization.projects import ProjectRateLimit +``` + +Methods: + +- client.admin.organization.projects.rate_limits.list_rate_limits(project_id, \*\*params) -> SyncConversationCursorPage[ProjectRateLimit] +- client.admin.organization.projects.rate_limits.update_rate_limit(rate_limit_id, \*, project_id, \*\*params) -> ProjectRateLimit + +#### Groups + +Types: + +```python +from openai.types.admin.organization.projects import ProjectGroup, GroupDeleteResponse +``` + +Methods: + +- client.admin.organization.projects.groups.create(project_id, \*\*params) -> ProjectGroup +- client.admin.organization.projects.groups.list(project_id, \*\*params) -> SyncCursorPage[ProjectGroup] +- client.admin.organization.projects.groups.delete(group_id, \*, project_id) -> GroupDeleteResponse + +##### Roles + +Types: + +```python +from openai.types.admin.organization.projects.groups import ( + RoleCreateResponse, + RoleListResponse, + RoleDeleteResponse, +) +``` + +Methods: + +- client.admin.organization.projects.groups.roles.create(group_id, \*, project_id, \*\*params) -> RoleCreateResponse +- client.admin.organization.projects.groups.roles.list(group_id, \*, project_id, \*\*params) -> SyncCursorPage[RoleListResponse] +- client.admin.organization.projects.groups.roles.delete(role_id, \*, project_id, group_id) -> RoleDeleteResponse + +#### Roles + +Types: + +```python +from openai.types.admin.organization.projects import RoleDeleteResponse +``` + +Methods: + +- client.admin.organization.projects.roles.create(project_id, \*\*params) -> Role +- client.admin.organization.projects.roles.update(role_id, \*, project_id, \*\*params) -> Role +- client.admin.organization.projects.roles.list(project_id, \*\*params) -> SyncCursorPage[Role] +- client.admin.organization.projects.roles.delete(role_id, \*, project_id) -> RoleDeleteResponse + +#### Certificates + +Methods: + +- client.admin.organization.projects.certificates.list(project_id, \*\*params) -> SyncConversationCursorPage[Certificate] +- client.admin.organization.projects.certificates.activate(project_id, \*\*params) -> SyncPage[Certificate] +- client.admin.organization.projects.certificates.deactivate(project_id, \*\*params) -> SyncPage[Certificate] + # [Responses](src/openai/resources/responses/api.md) # [Realtime](src/openai/resources/realtime/api.md) diff --git a/src/openai/resources/admin/organization/__init__.py b/src/openai/resources/admin/organization/__init__.py index d3e8314a44..50641088bb 100644 --- a/src/openai/resources/admin/organization/__init__.py +++ b/src/openai/resources/admin/organization/__init__.py @@ -1,5 +1,53 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from .roles import ( + Roles, + AsyncRoles, + RolesWithRawResponse, + AsyncRolesWithRawResponse, + RolesWithStreamingResponse, + AsyncRolesWithStreamingResponse, +) +from .usage import ( + Usage, + AsyncUsage, + UsageWithRawResponse, + AsyncUsageWithRawResponse, + UsageWithStreamingResponse, + AsyncUsageWithStreamingResponse, +) +from .users import ( + Users, + AsyncUsers, + UsersWithRawResponse, + AsyncUsersWithRawResponse, + UsersWithStreamingResponse, + AsyncUsersWithStreamingResponse, +) +from .groups import ( + Groups, + AsyncGroups, + GroupsWithRawResponse, + AsyncGroupsWithRawResponse, + GroupsWithStreamingResponse, + AsyncGroupsWithStreamingResponse, +) +from .invites import ( + Invites, + AsyncInvites, + InvitesWithRawResponse, + AsyncInvitesWithRawResponse, + InvitesWithStreamingResponse, + AsyncInvitesWithStreamingResponse, +) +from .projects import ( + Projects, + AsyncProjects, + ProjectsWithRawResponse, + AsyncProjectsWithRawResponse, + ProjectsWithStreamingResponse, + AsyncProjectsWithStreamingResponse, +) from .audit_logs import ( AuditLogs, AsyncAuditLogs, @@ -8,6 +56,14 @@ AuditLogsWithStreamingResponse, AsyncAuditLogsWithStreamingResponse, ) +from .certificates import ( + Certificates, + AsyncCertificates, + CertificatesWithRawResponse, + AsyncCertificatesWithRawResponse, + CertificatesWithStreamingResponse, + AsyncCertificatesWithStreamingResponse, +) from .organization import ( Organization, AsyncOrganization, @@ -16,6 +72,14 @@ OrganizationWithStreamingResponse, AsyncOrganizationWithStreamingResponse, ) +from .admin_api_keys import ( + AdminAPIKeys, + AsyncAdminAPIKeys, + AdminAPIKeysWithRawResponse, + AsyncAdminAPIKeysWithRawResponse, + AdminAPIKeysWithStreamingResponse, + AsyncAdminAPIKeysWithStreamingResponse, +) __all__ = [ "AuditLogs", @@ -24,6 +88,54 @@ "AsyncAuditLogsWithRawResponse", "AuditLogsWithStreamingResponse", "AsyncAuditLogsWithStreamingResponse", + "AdminAPIKeys", + "AsyncAdminAPIKeys", + "AdminAPIKeysWithRawResponse", + "AsyncAdminAPIKeysWithRawResponse", + "AdminAPIKeysWithStreamingResponse", + "AsyncAdminAPIKeysWithStreamingResponse", + "Usage", + "AsyncUsage", + "UsageWithRawResponse", + "AsyncUsageWithRawResponse", + "UsageWithStreamingResponse", + "AsyncUsageWithStreamingResponse", + "Invites", + "AsyncInvites", + "InvitesWithRawResponse", + "AsyncInvitesWithRawResponse", + "InvitesWithStreamingResponse", + "AsyncInvitesWithStreamingResponse", + "Users", + "AsyncUsers", + "UsersWithRawResponse", + "AsyncUsersWithRawResponse", + "UsersWithStreamingResponse", + "AsyncUsersWithStreamingResponse", + "Groups", + "AsyncGroups", + "GroupsWithRawResponse", + "AsyncGroupsWithRawResponse", + "GroupsWithStreamingResponse", + "AsyncGroupsWithStreamingResponse", + "Roles", + "AsyncRoles", + "RolesWithRawResponse", + "AsyncRolesWithRawResponse", + "RolesWithStreamingResponse", + "AsyncRolesWithStreamingResponse", + "Certificates", + "AsyncCertificates", + "CertificatesWithRawResponse", + "AsyncCertificatesWithRawResponse", + "CertificatesWithStreamingResponse", + "AsyncCertificatesWithStreamingResponse", + "Projects", + "AsyncProjects", + "ProjectsWithRawResponse", + "AsyncProjectsWithRawResponse", + "ProjectsWithStreamingResponse", + "AsyncProjectsWithStreamingResponse", "Organization", "AsyncOrganization", "OrganizationWithRawResponse", diff --git a/src/openai/resources/admin/organization/admin_api_keys.py b/src/openai/resources/admin/organization/admin_api_keys.py new file mode 100644 index 0000000000..bf3ff7abd0 --- /dev/null +++ b/src/openai/resources/admin/organization/admin_api_keys.py @@ -0,0 +1,468 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal + +import httpx + +from .... import _legacy_response +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ...._utils import path_template, maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ....pagination import SyncCursorPage, AsyncCursorPage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.admin.organization import admin_api_key_list_params, admin_api_key_create_params +from ....types.admin.organization.admin_api_key import AdminAPIKey +from ....types.admin.organization.admin_api_key_delete_response import AdminAPIKeyDeleteResponse + +__all__ = ["AdminAPIKeys", "AsyncAdminAPIKeys"] + + +class AdminAPIKeys(SyncAPIResource): + @cached_property + def with_raw_response(self) -> AdminAPIKeysWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AdminAPIKeysWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AdminAPIKeysWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AdminAPIKeysWithStreamingResponse(self) + + def create( + self, + *, + name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AdminAPIKey: + """ + Create an organization admin API key + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/organization/admin_api_keys", + body=maybe_transform({"name": name}, admin_api_key_create_params.AdminAPIKeyCreateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=AdminAPIKey, + ) + + def retrieve( + self, + key_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AdminAPIKey: + """ + Retrieve a single organization API key + + Args: + key_id: The ID of the API key. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not key_id: + raise ValueError(f"Expected a non-empty value for `key_id` but received {key_id!r}") + return self._get( + path_template("/organization/admin_api_keys/{key_id}", key_id=key_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=AdminAPIKey, + ) + + def list( + self, + *, + after: Optional[str] | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncCursorPage[AdminAPIKey]: + """ + List organization API keys + + Args: + after: Return keys with IDs that come after this ID in the pagination order. + + limit: Maximum number of keys to return. + + order: Order results by creation time, ascending or descending. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/organization/admin_api_keys", + page=SyncCursorPage[AdminAPIKey], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + admin_api_key_list_params.AdminAPIKeyListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=AdminAPIKey, + ) + + def delete( + self, + key_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AdminAPIKeyDeleteResponse: + """ + Delete an organization admin API key + + Args: + key_id: The ID of the API key to be deleted. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not key_id: + raise ValueError(f"Expected a non-empty value for `key_id` but received {key_id!r}") + return self._delete( + path_template("/organization/admin_api_keys/{key_id}", key_id=key_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=AdminAPIKeyDeleteResponse, + ) + + +class AsyncAdminAPIKeys(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncAdminAPIKeysWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncAdminAPIKeysWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncAdminAPIKeysWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncAdminAPIKeysWithStreamingResponse(self) + + async def create( + self, + *, + name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AdminAPIKey: + """ + Create an organization admin API key + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/organization/admin_api_keys", + body=await async_maybe_transform({"name": name}, admin_api_key_create_params.AdminAPIKeyCreateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=AdminAPIKey, + ) + + async def retrieve( + self, + key_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AdminAPIKey: + """ + Retrieve a single organization API key + + Args: + key_id: The ID of the API key. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not key_id: + raise ValueError(f"Expected a non-empty value for `key_id` but received {key_id!r}") + return await self._get( + path_template("/organization/admin_api_keys/{key_id}", key_id=key_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=AdminAPIKey, + ) + + def list( + self, + *, + after: Optional[str] | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[AdminAPIKey, AsyncCursorPage[AdminAPIKey]]: + """ + List organization API keys + + Args: + after: Return keys with IDs that come after this ID in the pagination order. + + limit: Maximum number of keys to return. + + order: Order results by creation time, ascending or descending. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/organization/admin_api_keys", + page=AsyncCursorPage[AdminAPIKey], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + admin_api_key_list_params.AdminAPIKeyListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=AdminAPIKey, + ) + + async def delete( + self, + key_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AdminAPIKeyDeleteResponse: + """ + Delete an organization admin API key + + Args: + key_id: The ID of the API key to be deleted. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not key_id: + raise ValueError(f"Expected a non-empty value for `key_id` but received {key_id!r}") + return await self._delete( + path_template("/organization/admin_api_keys/{key_id}", key_id=key_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=AdminAPIKeyDeleteResponse, + ) + + +class AdminAPIKeysWithRawResponse: + def __init__(self, admin_api_keys: AdminAPIKeys) -> None: + self._admin_api_keys = admin_api_keys + + self.create = _legacy_response.to_raw_response_wrapper( + admin_api_keys.create, + ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + admin_api_keys.retrieve, + ) + self.list = _legacy_response.to_raw_response_wrapper( + admin_api_keys.list, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + admin_api_keys.delete, + ) + + +class AsyncAdminAPIKeysWithRawResponse: + def __init__(self, admin_api_keys: AsyncAdminAPIKeys) -> None: + self._admin_api_keys = admin_api_keys + + self.create = _legacy_response.async_to_raw_response_wrapper( + admin_api_keys.create, + ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + admin_api_keys.retrieve, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + admin_api_keys.list, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + admin_api_keys.delete, + ) + + +class AdminAPIKeysWithStreamingResponse: + def __init__(self, admin_api_keys: AdminAPIKeys) -> None: + self._admin_api_keys = admin_api_keys + + self.create = to_streamed_response_wrapper( + admin_api_keys.create, + ) + self.retrieve = to_streamed_response_wrapper( + admin_api_keys.retrieve, + ) + self.list = to_streamed_response_wrapper( + admin_api_keys.list, + ) + self.delete = to_streamed_response_wrapper( + admin_api_keys.delete, + ) + + +class AsyncAdminAPIKeysWithStreamingResponse: + def __init__(self, admin_api_keys: AsyncAdminAPIKeys) -> None: + self._admin_api_keys = admin_api_keys + + self.create = async_to_streamed_response_wrapper( + admin_api_keys.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + admin_api_keys.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + admin_api_keys.list, + ) + self.delete = async_to_streamed_response_wrapper( + admin_api_keys.delete, + ) diff --git a/src/openai/resources/admin/organization/certificates.py b/src/openai/resources/admin/organization/certificates.py new file mode 100644 index 0000000000..1cab1e3610 --- /dev/null +++ b/src/openai/resources/admin/organization/certificates.py @@ -0,0 +1,815 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Literal + +import httpx + +from .... import _legacy_response +from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ...._utils import path_template, maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ....pagination import SyncPage, AsyncPage, SyncConversationCursorPage, AsyncConversationCursorPage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.admin.organization import ( + certificate_list_params, + certificate_create_params, + certificate_update_params, + certificate_activate_params, + certificate_retrieve_params, + certificate_deactivate_params, +) +from ....types.admin.organization.certificate import Certificate +from ....types.admin.organization.certificate_delete_response import CertificateDeleteResponse + +__all__ = ["Certificates", "AsyncCertificates"] + + +class Certificates(SyncAPIResource): + @cached_property + def with_raw_response(self) -> CertificatesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return CertificatesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> CertificatesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return CertificatesWithStreamingResponse(self) + + def create( + self, + *, + content: str, + name: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Certificate: + """Upload a certificate to the organization. + + This does **not** automatically + activate the certificate. + + Organizations can upload up to 50 certificates. + + Args: + content: The certificate content in PEM format + + name: An optional name for the certificate + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/organization/certificates", + body=maybe_transform( + { + "content": content, + "name": name, + }, + certificate_create_params.CertificateCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=Certificate, + ) + + def retrieve( + self, + certificate_id: str, + *, + include: List[Literal["content"]] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Certificate: + """ + Get a certificate that has been uploaded to the organization. + + You can get a certificate regardless of whether it is active or not. + + Args: + include: A list of additional fields to include in the response. Currently the only + supported value is `content` to fetch the PEM content of the certificate. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not certificate_id: + raise ValueError(f"Expected a non-empty value for `certificate_id` but received {certificate_id!r}") + return self._get( + path_template("/organization/certificates/{certificate_id}", certificate_id=certificate_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"include": include}, certificate_retrieve_params.CertificateRetrieveParams), + security={"admin_api_key_auth": True}, + ), + cast_to=Certificate, + ) + + def update( + self, + certificate_id: str, + *, + name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Certificate: + """Modify a certificate. + + Note that only the name can be modified. + + Args: + name: The updated name for the certificate + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not certificate_id: + raise ValueError(f"Expected a non-empty value for `certificate_id` but received {certificate_id!r}") + return self._post( + path_template("/organization/certificates/{certificate_id}", certificate_id=certificate_id), + body=maybe_transform({"name": name}, certificate_update_params.CertificateUpdateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=Certificate, + ) + + def list( + self, + *, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncConversationCursorPage[Certificate]: + """ + List uploaded certificates for this organization. + + Args: + after: A cursor for use in pagination. `after` is an object ID that defines your place + in the list. For instance, if you make a list request and receive 100 objects, + ending with obj_foo, your subsequent call can include after=obj_foo in order to + fetch the next page of the list. + + limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the default is 20. + + order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending + order and `desc` for descending order. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/organization/certificates", + page=SyncConversationCursorPage[Certificate], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + certificate_list_params.CertificateListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=Certificate, + ) + + def delete( + self, + certificate_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CertificateDeleteResponse: + """ + Delete a certificate from the organization. + + The certificate must be inactive for the organization and all projects. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not certificate_id: + raise ValueError(f"Expected a non-empty value for `certificate_id` but received {certificate_id!r}") + return self._delete( + path_template("/organization/certificates/{certificate_id}", certificate_id=certificate_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=CertificateDeleteResponse, + ) + + def activate( + self, + *, + certificate_ids: SequenceNotStr[str], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncPage[Certificate]: + """ + Activate certificates at the organization level. + + You can atomically and idempotently activate up to 10 certificates at a time. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/organization/certificates/activate", + page=SyncPage[Certificate], + body=maybe_transform( + {"certificate_ids": certificate_ids}, certificate_activate_params.CertificateActivateParams + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + model=Certificate, + method="post", + ) + + def deactivate( + self, + *, + certificate_ids: SequenceNotStr[str], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncPage[Certificate]: + """ + Deactivate certificates at the organization level. + + You can atomically and idempotently deactivate up to 10 certificates at a time. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/organization/certificates/deactivate", + page=SyncPage[Certificate], + body=maybe_transform( + {"certificate_ids": certificate_ids}, certificate_deactivate_params.CertificateDeactivateParams + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + model=Certificate, + method="post", + ) + + +class AsyncCertificates(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncCertificatesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncCertificatesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncCertificatesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncCertificatesWithStreamingResponse(self) + + async def create( + self, + *, + content: str, + name: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Certificate: + """Upload a certificate to the organization. + + This does **not** automatically + activate the certificate. + + Organizations can upload up to 50 certificates. + + Args: + content: The certificate content in PEM format + + name: An optional name for the certificate + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/organization/certificates", + body=await async_maybe_transform( + { + "content": content, + "name": name, + }, + certificate_create_params.CertificateCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=Certificate, + ) + + async def retrieve( + self, + certificate_id: str, + *, + include: List[Literal["content"]] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Certificate: + """ + Get a certificate that has been uploaded to the organization. + + You can get a certificate regardless of whether it is active or not. + + Args: + include: A list of additional fields to include in the response. Currently the only + supported value is `content` to fetch the PEM content of the certificate. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not certificate_id: + raise ValueError(f"Expected a non-empty value for `certificate_id` but received {certificate_id!r}") + return await self._get( + path_template("/organization/certificates/{certificate_id}", certificate_id=certificate_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"include": include}, certificate_retrieve_params.CertificateRetrieveParams + ), + security={"admin_api_key_auth": True}, + ), + cast_to=Certificate, + ) + + async def update( + self, + certificate_id: str, + *, + name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Certificate: + """Modify a certificate. + + Note that only the name can be modified. + + Args: + name: The updated name for the certificate + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not certificate_id: + raise ValueError(f"Expected a non-empty value for `certificate_id` but received {certificate_id!r}") + return await self._post( + path_template("/organization/certificates/{certificate_id}", certificate_id=certificate_id), + body=await async_maybe_transform({"name": name}, certificate_update_params.CertificateUpdateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=Certificate, + ) + + def list( + self, + *, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Certificate, AsyncConversationCursorPage[Certificate]]: + """ + List uploaded certificates for this organization. + + Args: + after: A cursor for use in pagination. `after` is an object ID that defines your place + in the list. For instance, if you make a list request and receive 100 objects, + ending with obj_foo, your subsequent call can include after=obj_foo in order to + fetch the next page of the list. + + limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the default is 20. + + order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending + order and `desc` for descending order. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/organization/certificates", + page=AsyncConversationCursorPage[Certificate], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + certificate_list_params.CertificateListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=Certificate, + ) + + async def delete( + self, + certificate_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CertificateDeleteResponse: + """ + Delete a certificate from the organization. + + The certificate must be inactive for the organization and all projects. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not certificate_id: + raise ValueError(f"Expected a non-empty value for `certificate_id` but received {certificate_id!r}") + return await self._delete( + path_template("/organization/certificates/{certificate_id}", certificate_id=certificate_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=CertificateDeleteResponse, + ) + + def activate( + self, + *, + certificate_ids: SequenceNotStr[str], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Certificate, AsyncPage[Certificate]]: + """ + Activate certificates at the organization level. + + You can atomically and idempotently activate up to 10 certificates at a time. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/organization/certificates/activate", + page=AsyncPage[Certificate], + body=maybe_transform( + {"certificate_ids": certificate_ids}, certificate_activate_params.CertificateActivateParams + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + model=Certificate, + method="post", + ) + + def deactivate( + self, + *, + certificate_ids: SequenceNotStr[str], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Certificate, AsyncPage[Certificate]]: + """ + Deactivate certificates at the organization level. + + You can atomically and idempotently deactivate up to 10 certificates at a time. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/organization/certificates/deactivate", + page=AsyncPage[Certificate], + body=maybe_transform( + {"certificate_ids": certificate_ids}, certificate_deactivate_params.CertificateDeactivateParams + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + model=Certificate, + method="post", + ) + + +class CertificatesWithRawResponse: + def __init__(self, certificates: Certificates) -> None: + self._certificates = certificates + + self.create = _legacy_response.to_raw_response_wrapper( + certificates.create, + ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + certificates.retrieve, + ) + self.update = _legacy_response.to_raw_response_wrapper( + certificates.update, + ) + self.list = _legacy_response.to_raw_response_wrapper( + certificates.list, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + certificates.delete, + ) + self.activate = _legacy_response.to_raw_response_wrapper( + certificates.activate, + ) + self.deactivate = _legacy_response.to_raw_response_wrapper( + certificates.deactivate, + ) + + +class AsyncCertificatesWithRawResponse: + def __init__(self, certificates: AsyncCertificates) -> None: + self._certificates = certificates + + self.create = _legacy_response.async_to_raw_response_wrapper( + certificates.create, + ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + certificates.retrieve, + ) + self.update = _legacy_response.async_to_raw_response_wrapper( + certificates.update, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + certificates.list, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + certificates.delete, + ) + self.activate = _legacy_response.async_to_raw_response_wrapper( + certificates.activate, + ) + self.deactivate = _legacy_response.async_to_raw_response_wrapper( + certificates.deactivate, + ) + + +class CertificatesWithStreamingResponse: + def __init__(self, certificates: Certificates) -> None: + self._certificates = certificates + + self.create = to_streamed_response_wrapper( + certificates.create, + ) + self.retrieve = to_streamed_response_wrapper( + certificates.retrieve, + ) + self.update = to_streamed_response_wrapper( + certificates.update, + ) + self.list = to_streamed_response_wrapper( + certificates.list, + ) + self.delete = to_streamed_response_wrapper( + certificates.delete, + ) + self.activate = to_streamed_response_wrapper( + certificates.activate, + ) + self.deactivate = to_streamed_response_wrapper( + certificates.deactivate, + ) + + +class AsyncCertificatesWithStreamingResponse: + def __init__(self, certificates: AsyncCertificates) -> None: + self._certificates = certificates + + self.create = async_to_streamed_response_wrapper( + certificates.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + certificates.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + certificates.update, + ) + self.list = async_to_streamed_response_wrapper( + certificates.list, + ) + self.delete = async_to_streamed_response_wrapper( + certificates.delete, + ) + self.activate = async_to_streamed_response_wrapper( + certificates.activate, + ) + self.deactivate = async_to_streamed_response_wrapper( + certificates.deactivate, + ) diff --git a/src/openai/resources/admin/organization/groups/__init__.py b/src/openai/resources/admin/organization/groups/__init__.py new file mode 100644 index 0000000000..ffeb8b60ec --- /dev/null +++ b/src/openai/resources/admin/organization/groups/__init__.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .roles import ( + Roles, + AsyncRoles, + RolesWithRawResponse, + AsyncRolesWithRawResponse, + RolesWithStreamingResponse, + AsyncRolesWithStreamingResponse, +) +from .users import ( + Users, + AsyncUsers, + UsersWithRawResponse, + AsyncUsersWithRawResponse, + UsersWithStreamingResponse, + AsyncUsersWithStreamingResponse, +) +from .groups import ( + Groups, + AsyncGroups, + GroupsWithRawResponse, + AsyncGroupsWithRawResponse, + GroupsWithStreamingResponse, + AsyncGroupsWithStreamingResponse, +) + +__all__ = [ + "Users", + "AsyncUsers", + "UsersWithRawResponse", + "AsyncUsersWithRawResponse", + "UsersWithStreamingResponse", + "AsyncUsersWithStreamingResponse", + "Roles", + "AsyncRoles", + "RolesWithRawResponse", + "AsyncRolesWithRawResponse", + "RolesWithStreamingResponse", + "AsyncRolesWithStreamingResponse", + "Groups", + "AsyncGroups", + "GroupsWithRawResponse", + "AsyncGroupsWithRawResponse", + "GroupsWithStreamingResponse", + "AsyncGroupsWithStreamingResponse", +] diff --git a/src/openai/resources/admin/organization/groups/groups.py b/src/openai/resources/admin/organization/groups/groups.py new file mode 100644 index 0000000000..1daf07b1ab --- /dev/null +++ b/src/openai/resources/admin/organization/groups/groups.py @@ -0,0 +1,544 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from ..... import _legacy_response +from .roles import ( + Roles, + AsyncRoles, + RolesWithRawResponse, + AsyncRolesWithRawResponse, + RolesWithStreamingResponse, + AsyncRolesWithStreamingResponse, +) +from .users import ( + Users, + AsyncUsers, + UsersWithRawResponse, + AsyncUsersWithRawResponse, + UsersWithStreamingResponse, + AsyncUsersWithStreamingResponse, +) +from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ....._utils import path_template, maybe_transform, async_maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from .....pagination import SyncCursorPage, AsyncCursorPage +from ....._base_client import AsyncPaginator, make_request_options +from .....types.admin.organization import group_list_params, group_create_params, group_update_params +from .....types.admin.organization.group import Group +from .....types.admin.organization.group_delete_response import GroupDeleteResponse +from .....types.admin.organization.group_update_response import GroupUpdateResponse + +__all__ = ["Groups", "AsyncGroups"] + + +class Groups(SyncAPIResource): + @cached_property + def users(self) -> Users: + return Users(self._client) + + @cached_property + def roles(self) -> Roles: + return Roles(self._client) + + @cached_property + def with_raw_response(self) -> GroupsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return GroupsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> GroupsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return GroupsWithStreamingResponse(self) + + def create( + self, + *, + name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Group: + """ + Creates a new group in the organization. + + Args: + name: Human readable name for the group. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/organization/groups", + body=maybe_transform({"name": name}, group_create_params.GroupCreateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=Group, + ) + + def update( + self, + group_id: str, + *, + name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GroupUpdateResponse: + """ + Updates a group's information. + + Args: + name: New display name for the group. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return self._post( + path_template("/organization/groups/{group_id}", group_id=group_id), + body=maybe_transform({"name": name}, group_update_params.GroupUpdateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=GroupUpdateResponse, + ) + + def list( + self, + *, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncCursorPage[Group]: + """ + Lists all groups in the organization. + + Args: + after: A cursor for use in pagination. `after` is a group ID that defines your place in + the list. For instance, if you make a list request and receive 100 objects, + ending with group_abc, your subsequent call can include `after=group_abc` in + order to fetch the next page of the list. + + limit: A limit on the number of groups to be returned. Limit can range between 0 and + 1000, and the default is 100. + + order: Specifies the sort order of the returned groups. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/organization/groups", + page=SyncCursorPage[Group], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + group_list_params.GroupListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=Group, + ) + + def delete( + self, + group_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GroupDeleteResponse: + """ + Deletes a group from the organization. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return self._delete( + path_template("/organization/groups/{group_id}", group_id=group_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=GroupDeleteResponse, + ) + + +class AsyncGroups(AsyncAPIResource): + @cached_property + def users(self) -> AsyncUsers: + return AsyncUsers(self._client) + + @cached_property + def roles(self) -> AsyncRoles: + return AsyncRoles(self._client) + + @cached_property + def with_raw_response(self) -> AsyncGroupsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncGroupsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncGroupsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncGroupsWithStreamingResponse(self) + + async def create( + self, + *, + name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Group: + """ + Creates a new group in the organization. + + Args: + name: Human readable name for the group. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/organization/groups", + body=await async_maybe_transform({"name": name}, group_create_params.GroupCreateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=Group, + ) + + async def update( + self, + group_id: str, + *, + name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GroupUpdateResponse: + """ + Updates a group's information. + + Args: + name: New display name for the group. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return await self._post( + path_template("/organization/groups/{group_id}", group_id=group_id), + body=await async_maybe_transform({"name": name}, group_update_params.GroupUpdateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=GroupUpdateResponse, + ) + + def list( + self, + *, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Group, AsyncCursorPage[Group]]: + """ + Lists all groups in the organization. + + Args: + after: A cursor for use in pagination. `after` is a group ID that defines your place in + the list. For instance, if you make a list request and receive 100 objects, + ending with group_abc, your subsequent call can include `after=group_abc` in + order to fetch the next page of the list. + + limit: A limit on the number of groups to be returned. Limit can range between 0 and + 1000, and the default is 100. + + order: Specifies the sort order of the returned groups. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/organization/groups", + page=AsyncCursorPage[Group], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + group_list_params.GroupListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=Group, + ) + + async def delete( + self, + group_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GroupDeleteResponse: + """ + Deletes a group from the organization. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return await self._delete( + path_template("/organization/groups/{group_id}", group_id=group_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=GroupDeleteResponse, + ) + + +class GroupsWithRawResponse: + def __init__(self, groups: Groups) -> None: + self._groups = groups + + self.create = _legacy_response.to_raw_response_wrapper( + groups.create, + ) + self.update = _legacy_response.to_raw_response_wrapper( + groups.update, + ) + self.list = _legacy_response.to_raw_response_wrapper( + groups.list, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + groups.delete, + ) + + @cached_property + def users(self) -> UsersWithRawResponse: + return UsersWithRawResponse(self._groups.users) + + @cached_property + def roles(self) -> RolesWithRawResponse: + return RolesWithRawResponse(self._groups.roles) + + +class AsyncGroupsWithRawResponse: + def __init__(self, groups: AsyncGroups) -> None: + self._groups = groups + + self.create = _legacy_response.async_to_raw_response_wrapper( + groups.create, + ) + self.update = _legacy_response.async_to_raw_response_wrapper( + groups.update, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + groups.list, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + groups.delete, + ) + + @cached_property + def users(self) -> AsyncUsersWithRawResponse: + return AsyncUsersWithRawResponse(self._groups.users) + + @cached_property + def roles(self) -> AsyncRolesWithRawResponse: + return AsyncRolesWithRawResponse(self._groups.roles) + + +class GroupsWithStreamingResponse: + def __init__(self, groups: Groups) -> None: + self._groups = groups + + self.create = to_streamed_response_wrapper( + groups.create, + ) + self.update = to_streamed_response_wrapper( + groups.update, + ) + self.list = to_streamed_response_wrapper( + groups.list, + ) + self.delete = to_streamed_response_wrapper( + groups.delete, + ) + + @cached_property + def users(self) -> UsersWithStreamingResponse: + return UsersWithStreamingResponse(self._groups.users) + + @cached_property + def roles(self) -> RolesWithStreamingResponse: + return RolesWithStreamingResponse(self._groups.roles) + + +class AsyncGroupsWithStreamingResponse: + def __init__(self, groups: AsyncGroups) -> None: + self._groups = groups + + self.create = async_to_streamed_response_wrapper( + groups.create, + ) + self.update = async_to_streamed_response_wrapper( + groups.update, + ) + self.list = async_to_streamed_response_wrapper( + groups.list, + ) + self.delete = async_to_streamed_response_wrapper( + groups.delete, + ) + + @cached_property + def users(self) -> AsyncUsersWithStreamingResponse: + return AsyncUsersWithStreamingResponse(self._groups.users) + + @cached_property + def roles(self) -> AsyncRolesWithStreamingResponse: + return AsyncRolesWithStreamingResponse(self._groups.roles) diff --git a/src/openai/resources/admin/organization/groups/roles.py b/src/openai/resources/admin/organization/groups/roles.py new file mode 100644 index 0000000000..ca62ee9b35 --- /dev/null +++ b/src/openai/resources/admin/organization/groups/roles.py @@ -0,0 +1,398 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from ..... import _legacy_response +from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ....._utils import path_template, maybe_transform, async_maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from .....pagination import SyncCursorPage, AsyncCursorPage +from ....._base_client import AsyncPaginator, make_request_options +from .....types.admin.organization.groups import role_list_params, role_create_params +from .....types.admin.organization.groups.role_list_response import RoleListResponse +from .....types.admin.organization.groups.role_create_response import RoleCreateResponse +from .....types.admin.organization.groups.role_delete_response import RoleDeleteResponse + +__all__ = ["Roles", "AsyncRoles"] + + +class Roles(SyncAPIResource): + @cached_property + def with_raw_response(self) -> RolesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return RolesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> RolesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return RolesWithStreamingResponse(self) + + def create( + self, + group_id: str, + *, + role_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RoleCreateResponse: + """ + Assigns an organization role to a group within the organization. + + Args: + role_id: Identifier of the role to assign. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return self._post( + path_template("/organization/groups/{group_id}/roles", group_id=group_id), + body=maybe_transform({"role_id": role_id}, role_create_params.RoleCreateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=RoleCreateResponse, + ) + + def list( + self, + group_id: str, + *, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncCursorPage[RoleListResponse]: + """ + Lists the organization roles assigned to a group within the organization. + + Args: + after: Cursor for pagination. Provide the value from the previous response's `next` + field to continue listing organization roles. + + limit: A limit on the number of organization role assignments to return. + + order: Sort order for the returned organization roles. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return self._get_api_list( + path_template("/organization/groups/{group_id}/roles", group_id=group_id), + page=SyncCursorPage[RoleListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + role_list_params.RoleListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=RoleListResponse, + ) + + def delete( + self, + role_id: str, + *, + group_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RoleDeleteResponse: + """ + Unassigns an organization role from a group within the organization. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + if not role_id: + raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") + return self._delete( + path_template("/organization/groups/{group_id}/roles/{role_id}", group_id=group_id, role_id=role_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=RoleDeleteResponse, + ) + + +class AsyncRoles(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncRolesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncRolesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncRolesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncRolesWithStreamingResponse(self) + + async def create( + self, + group_id: str, + *, + role_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RoleCreateResponse: + """ + Assigns an organization role to a group within the organization. + + Args: + role_id: Identifier of the role to assign. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return await self._post( + path_template("/organization/groups/{group_id}/roles", group_id=group_id), + body=await async_maybe_transform({"role_id": role_id}, role_create_params.RoleCreateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=RoleCreateResponse, + ) + + def list( + self, + group_id: str, + *, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[RoleListResponse, AsyncCursorPage[RoleListResponse]]: + """ + Lists the organization roles assigned to a group within the organization. + + Args: + after: Cursor for pagination. Provide the value from the previous response's `next` + field to continue listing organization roles. + + limit: A limit on the number of organization role assignments to return. + + order: Sort order for the returned organization roles. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return self._get_api_list( + path_template("/organization/groups/{group_id}/roles", group_id=group_id), + page=AsyncCursorPage[RoleListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + role_list_params.RoleListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=RoleListResponse, + ) + + async def delete( + self, + role_id: str, + *, + group_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RoleDeleteResponse: + """ + Unassigns an organization role from a group within the organization. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + if not role_id: + raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") + return await self._delete( + path_template("/organization/groups/{group_id}/roles/{role_id}", group_id=group_id, role_id=role_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=RoleDeleteResponse, + ) + + +class RolesWithRawResponse: + def __init__(self, roles: Roles) -> None: + self._roles = roles + + self.create = _legacy_response.to_raw_response_wrapper( + roles.create, + ) + self.list = _legacy_response.to_raw_response_wrapper( + roles.list, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + roles.delete, + ) + + +class AsyncRolesWithRawResponse: + def __init__(self, roles: AsyncRoles) -> None: + self._roles = roles + + self.create = _legacy_response.async_to_raw_response_wrapper( + roles.create, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + roles.list, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + roles.delete, + ) + + +class RolesWithStreamingResponse: + def __init__(self, roles: Roles) -> None: + self._roles = roles + + self.create = to_streamed_response_wrapper( + roles.create, + ) + self.list = to_streamed_response_wrapper( + roles.list, + ) + self.delete = to_streamed_response_wrapper( + roles.delete, + ) + + +class AsyncRolesWithStreamingResponse: + def __init__(self, roles: AsyncRoles) -> None: + self._roles = roles + + self.create = async_to_streamed_response_wrapper( + roles.create, + ) + self.list = async_to_streamed_response_wrapper( + roles.list, + ) + self.delete = async_to_streamed_response_wrapper( + roles.delete, + ) diff --git a/src/openai/resources/admin/organization/groups/users.py b/src/openai/resources/admin/organization/groups/users.py new file mode 100644 index 0000000000..648d6221cf --- /dev/null +++ b/src/openai/resources/admin/organization/groups/users.py @@ -0,0 +1,400 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from ..... import _legacy_response +from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ....._utils import path_template, maybe_transform, async_maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from .....pagination import SyncCursorPage, AsyncCursorPage +from ....._base_client import AsyncPaginator, make_request_options +from .....types.admin.organization.groups import user_list_params, user_create_params +from .....types.admin.organization.organization_user import OrganizationUser +from .....types.admin.organization.groups.user_create_response import UserCreateResponse +from .....types.admin.organization.groups.user_delete_response import UserDeleteResponse + +__all__ = ["Users", "AsyncUsers"] + + +class Users(SyncAPIResource): + @cached_property + def with_raw_response(self) -> UsersWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return UsersWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> UsersWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return UsersWithStreamingResponse(self) + + def create( + self, + group_id: str, + *, + user_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UserCreateResponse: + """ + Adds a user to a group. + + Args: + user_id: Identifier of the user to add to the group. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return self._post( + path_template("/organization/groups/{group_id}/users", group_id=group_id), + body=maybe_transform({"user_id": user_id}, user_create_params.UserCreateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=UserCreateResponse, + ) + + def list( + self, + group_id: str, + *, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncCursorPage[OrganizationUser]: + """ + Lists the users assigned to a group. + + Args: + after: A cursor for use in pagination. Provide the ID of the last user from the + previous list response to retrieve the next page. + + limit: A limit on the number of users to be returned. Limit can range between 0 and + 1000, and the default is 100. + + order: Specifies the sort order of users in the list. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return self._get_api_list( + path_template("/organization/groups/{group_id}/users", group_id=group_id), + page=SyncCursorPage[OrganizationUser], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + user_list_params.UserListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=OrganizationUser, + ) + + def delete( + self, + user_id: str, + *, + group_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UserDeleteResponse: + """ + Removes a user from a group. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + if not user_id: + raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + return self._delete( + path_template("/organization/groups/{group_id}/users/{user_id}", group_id=group_id, user_id=user_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=UserDeleteResponse, + ) + + +class AsyncUsers(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncUsersWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncUsersWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncUsersWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncUsersWithStreamingResponse(self) + + async def create( + self, + group_id: str, + *, + user_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UserCreateResponse: + """ + Adds a user to a group. + + Args: + user_id: Identifier of the user to add to the group. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return await self._post( + path_template("/organization/groups/{group_id}/users", group_id=group_id), + body=await async_maybe_transform({"user_id": user_id}, user_create_params.UserCreateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=UserCreateResponse, + ) + + def list( + self, + group_id: str, + *, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[OrganizationUser, AsyncCursorPage[OrganizationUser]]: + """ + Lists the users assigned to a group. + + Args: + after: A cursor for use in pagination. Provide the ID of the last user from the + previous list response to retrieve the next page. + + limit: A limit on the number of users to be returned. Limit can range between 0 and + 1000, and the default is 100. + + order: Specifies the sort order of users in the list. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return self._get_api_list( + path_template("/organization/groups/{group_id}/users", group_id=group_id), + page=AsyncCursorPage[OrganizationUser], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + user_list_params.UserListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=OrganizationUser, + ) + + async def delete( + self, + user_id: str, + *, + group_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UserDeleteResponse: + """ + Removes a user from a group. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + if not user_id: + raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + return await self._delete( + path_template("/organization/groups/{group_id}/users/{user_id}", group_id=group_id, user_id=user_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=UserDeleteResponse, + ) + + +class UsersWithRawResponse: + def __init__(self, users: Users) -> None: + self._users = users + + self.create = _legacy_response.to_raw_response_wrapper( + users.create, + ) + self.list = _legacy_response.to_raw_response_wrapper( + users.list, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + users.delete, + ) + + +class AsyncUsersWithRawResponse: + def __init__(self, users: AsyncUsers) -> None: + self._users = users + + self.create = _legacy_response.async_to_raw_response_wrapper( + users.create, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + users.list, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + users.delete, + ) + + +class UsersWithStreamingResponse: + def __init__(self, users: Users) -> None: + self._users = users + + self.create = to_streamed_response_wrapper( + users.create, + ) + self.list = to_streamed_response_wrapper( + users.list, + ) + self.delete = to_streamed_response_wrapper( + users.delete, + ) + + +class AsyncUsersWithStreamingResponse: + def __init__(self, users: AsyncUsers) -> None: + self._users = users + + self.create = async_to_streamed_response_wrapper( + users.create, + ) + self.list = async_to_streamed_response_wrapper( + users.list, + ) + self.delete = async_to_streamed_response_wrapper( + users.delete, + ) diff --git a/src/openai/resources/admin/organization/invites.py b/src/openai/resources/admin/organization/invites.py new file mode 100644 index 0000000000..23b83ccb18 --- /dev/null +++ b/src/openai/resources/admin/organization/invites.py @@ -0,0 +1,500 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Literal + +import httpx + +from .... import _legacy_response +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ...._utils import path_template, maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ....pagination import SyncConversationCursorPage, AsyncConversationCursorPage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.admin.organization import invite_list_params, invite_create_params +from ....types.admin.organization.invite import Invite +from ....types.admin.organization.invite_delete_response import InviteDeleteResponse + +__all__ = ["Invites", "AsyncInvites"] + + +class Invites(SyncAPIResource): + @cached_property + def with_raw_response(self) -> InvitesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return InvitesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> InvitesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return InvitesWithStreamingResponse(self) + + def create( + self, + *, + email: str, + role: Literal["reader", "owner"], + projects: Iterable[invite_create_params.Project] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Invite: + """Create an invite for a user to the organization. + + The invite must be accepted by + the user before they have access to the organization. + + Args: + email: Send an email to this address + + role: `owner` or `reader` + + projects: An array of projects to which membership is granted at the same time the org + invite is accepted. If omitted, the user will be invited to the default project + for compatibility with legacy behavior. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/organization/invites", + body=maybe_transform( + { + "email": email, + "role": role, + "projects": projects, + }, + invite_create_params.InviteCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=Invite, + ) + + def retrieve( + self, + invite_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Invite: + """ + Retrieves an invite. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not invite_id: + raise ValueError(f"Expected a non-empty value for `invite_id` but received {invite_id!r}") + return self._get( + path_template("/organization/invites/{invite_id}", invite_id=invite_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=Invite, + ) + + def list( + self, + *, + after: str | Omit = omit, + limit: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncConversationCursorPage[Invite]: + """ + Returns a list of invites in the organization. + + Args: + after: A cursor for use in pagination. `after` is an object ID that defines your place + in the list. For instance, if you make a list request and receive 100 objects, + ending with obj_foo, your subsequent call can include after=obj_foo in order to + fetch the next page of the list. + + limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the default is 20. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/organization/invites", + page=SyncConversationCursorPage[Invite], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + }, + invite_list_params.InviteListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=Invite, + ) + + def delete( + self, + invite_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InviteDeleteResponse: + """Delete an invite. + + If the invite has already been accepted, it cannot be deleted. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not invite_id: + raise ValueError(f"Expected a non-empty value for `invite_id` but received {invite_id!r}") + return self._delete( + path_template("/organization/invites/{invite_id}", invite_id=invite_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=InviteDeleteResponse, + ) + + +class AsyncInvites(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncInvitesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncInvitesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncInvitesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncInvitesWithStreamingResponse(self) + + async def create( + self, + *, + email: str, + role: Literal["reader", "owner"], + projects: Iterable[invite_create_params.Project] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Invite: + """Create an invite for a user to the organization. + + The invite must be accepted by + the user before they have access to the organization. + + Args: + email: Send an email to this address + + role: `owner` or `reader` + + projects: An array of projects to which membership is granted at the same time the org + invite is accepted. If omitted, the user will be invited to the default project + for compatibility with legacy behavior. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/organization/invites", + body=await async_maybe_transform( + { + "email": email, + "role": role, + "projects": projects, + }, + invite_create_params.InviteCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=Invite, + ) + + async def retrieve( + self, + invite_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Invite: + """ + Retrieves an invite. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not invite_id: + raise ValueError(f"Expected a non-empty value for `invite_id` but received {invite_id!r}") + return await self._get( + path_template("/organization/invites/{invite_id}", invite_id=invite_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=Invite, + ) + + def list( + self, + *, + after: str | Omit = omit, + limit: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Invite, AsyncConversationCursorPage[Invite]]: + """ + Returns a list of invites in the organization. + + Args: + after: A cursor for use in pagination. `after` is an object ID that defines your place + in the list. For instance, if you make a list request and receive 100 objects, + ending with obj_foo, your subsequent call can include after=obj_foo in order to + fetch the next page of the list. + + limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the default is 20. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/organization/invites", + page=AsyncConversationCursorPage[Invite], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + }, + invite_list_params.InviteListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=Invite, + ) + + async def delete( + self, + invite_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InviteDeleteResponse: + """Delete an invite. + + If the invite has already been accepted, it cannot be deleted. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not invite_id: + raise ValueError(f"Expected a non-empty value for `invite_id` but received {invite_id!r}") + return await self._delete( + path_template("/organization/invites/{invite_id}", invite_id=invite_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=InviteDeleteResponse, + ) + + +class InvitesWithRawResponse: + def __init__(self, invites: Invites) -> None: + self._invites = invites + + self.create = _legacy_response.to_raw_response_wrapper( + invites.create, + ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + invites.retrieve, + ) + self.list = _legacy_response.to_raw_response_wrapper( + invites.list, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + invites.delete, + ) + + +class AsyncInvitesWithRawResponse: + def __init__(self, invites: AsyncInvites) -> None: + self._invites = invites + + self.create = _legacy_response.async_to_raw_response_wrapper( + invites.create, + ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + invites.retrieve, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + invites.list, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + invites.delete, + ) + + +class InvitesWithStreamingResponse: + def __init__(self, invites: Invites) -> None: + self._invites = invites + + self.create = to_streamed_response_wrapper( + invites.create, + ) + self.retrieve = to_streamed_response_wrapper( + invites.retrieve, + ) + self.list = to_streamed_response_wrapper( + invites.list, + ) + self.delete = to_streamed_response_wrapper( + invites.delete, + ) + + +class AsyncInvitesWithStreamingResponse: + def __init__(self, invites: AsyncInvites) -> None: + self._invites = invites + + self.create = async_to_streamed_response_wrapper( + invites.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + invites.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + invites.list, + ) + self.delete = async_to_streamed_response_wrapper( + invites.delete, + ) diff --git a/src/openai/resources/admin/organization/organization.py b/src/openai/resources/admin/organization/organization.py index 41dd0155d9..abbbadf575 100644 --- a/src/openai/resources/admin/organization/organization.py +++ b/src/openai/resources/admin/organization/organization.py @@ -2,6 +2,30 @@ from __future__ import annotations +from .roles import ( + Roles, + AsyncRoles, + RolesWithRawResponse, + AsyncRolesWithRawResponse, + RolesWithStreamingResponse, + AsyncRolesWithStreamingResponse, +) +from .usage import ( + Usage, + AsyncUsage, + UsageWithRawResponse, + AsyncUsageWithRawResponse, + UsageWithStreamingResponse, + AsyncUsageWithStreamingResponse, +) +from .invites import ( + Invites, + AsyncInvites, + InvitesWithRawResponse, + AsyncInvitesWithRawResponse, + InvitesWithStreamingResponse, + AsyncInvitesWithStreamingResponse, +) from ...._compat import cached_property from .audit_logs import ( AuditLogs, @@ -11,7 +35,47 @@ AuditLogsWithStreamingResponse, AsyncAuditLogsWithStreamingResponse, ) +from .users.users import ( + Users, + AsyncUsers, + UsersWithRawResponse, + AsyncUsersWithRawResponse, + UsersWithStreamingResponse, + AsyncUsersWithStreamingResponse, +) from ...._resource import SyncAPIResource, AsyncAPIResource +from .certificates import ( + Certificates, + AsyncCertificates, + CertificatesWithRawResponse, + AsyncCertificatesWithRawResponse, + CertificatesWithStreamingResponse, + AsyncCertificatesWithStreamingResponse, +) +from .groups.groups import ( + Groups, + AsyncGroups, + GroupsWithRawResponse, + AsyncGroupsWithRawResponse, + GroupsWithStreamingResponse, + AsyncGroupsWithStreamingResponse, +) +from .admin_api_keys import ( + AdminAPIKeys, + AsyncAdminAPIKeys, + AdminAPIKeysWithRawResponse, + AsyncAdminAPIKeysWithRawResponse, + AdminAPIKeysWithStreamingResponse, + AsyncAdminAPIKeysWithStreamingResponse, +) +from .projects.projects import ( + Projects, + AsyncProjects, + ProjectsWithRawResponse, + AsyncProjectsWithRawResponse, + ProjectsWithStreamingResponse, + AsyncProjectsWithStreamingResponse, +) __all__ = ["Organization", "AsyncOrganization"] @@ -22,6 +86,38 @@ def audit_logs(self) -> AuditLogs: """List user actions and configuration changes within this organization.""" return AuditLogs(self._client) + @cached_property + def admin_api_keys(self) -> AdminAPIKeys: + return AdminAPIKeys(self._client) + + @cached_property + def usage(self) -> Usage: + return Usage(self._client) + + @cached_property + def invites(self) -> Invites: + return Invites(self._client) + + @cached_property + def users(self) -> Users: + return Users(self._client) + + @cached_property + def groups(self) -> Groups: + return Groups(self._client) + + @cached_property + def roles(self) -> Roles: + return Roles(self._client) + + @cached_property + def certificates(self) -> Certificates: + return Certificates(self._client) + + @cached_property + def projects(self) -> Projects: + return Projects(self._client) + @cached_property def with_raw_response(self) -> OrganizationWithRawResponse: """ @@ -48,6 +144,38 @@ def audit_logs(self) -> AsyncAuditLogs: """List user actions and configuration changes within this organization.""" return AsyncAuditLogs(self._client) + @cached_property + def admin_api_keys(self) -> AsyncAdminAPIKeys: + return AsyncAdminAPIKeys(self._client) + + @cached_property + def usage(self) -> AsyncUsage: + return AsyncUsage(self._client) + + @cached_property + def invites(self) -> AsyncInvites: + return AsyncInvites(self._client) + + @cached_property + def users(self) -> AsyncUsers: + return AsyncUsers(self._client) + + @cached_property + def groups(self) -> AsyncGroups: + return AsyncGroups(self._client) + + @cached_property + def roles(self) -> AsyncRoles: + return AsyncRoles(self._client) + + @cached_property + def certificates(self) -> AsyncCertificates: + return AsyncCertificates(self._client) + + @cached_property + def projects(self) -> AsyncProjects: + return AsyncProjects(self._client) + @cached_property def with_raw_response(self) -> AsyncOrganizationWithRawResponse: """ @@ -77,6 +205,38 @@ def audit_logs(self) -> AuditLogsWithRawResponse: """List user actions and configuration changes within this organization.""" return AuditLogsWithRawResponse(self._organization.audit_logs) + @cached_property + def admin_api_keys(self) -> AdminAPIKeysWithRawResponse: + return AdminAPIKeysWithRawResponse(self._organization.admin_api_keys) + + @cached_property + def usage(self) -> UsageWithRawResponse: + return UsageWithRawResponse(self._organization.usage) + + @cached_property + def invites(self) -> InvitesWithRawResponse: + return InvitesWithRawResponse(self._organization.invites) + + @cached_property + def users(self) -> UsersWithRawResponse: + return UsersWithRawResponse(self._organization.users) + + @cached_property + def groups(self) -> GroupsWithRawResponse: + return GroupsWithRawResponse(self._organization.groups) + + @cached_property + def roles(self) -> RolesWithRawResponse: + return RolesWithRawResponse(self._organization.roles) + + @cached_property + def certificates(self) -> CertificatesWithRawResponse: + return CertificatesWithRawResponse(self._organization.certificates) + + @cached_property + def projects(self) -> ProjectsWithRawResponse: + return ProjectsWithRawResponse(self._organization.projects) + class AsyncOrganizationWithRawResponse: def __init__(self, organization: AsyncOrganization) -> None: @@ -87,6 +247,38 @@ def audit_logs(self) -> AsyncAuditLogsWithRawResponse: """List user actions and configuration changes within this organization.""" return AsyncAuditLogsWithRawResponse(self._organization.audit_logs) + @cached_property + def admin_api_keys(self) -> AsyncAdminAPIKeysWithRawResponse: + return AsyncAdminAPIKeysWithRawResponse(self._organization.admin_api_keys) + + @cached_property + def usage(self) -> AsyncUsageWithRawResponse: + return AsyncUsageWithRawResponse(self._organization.usage) + + @cached_property + def invites(self) -> AsyncInvitesWithRawResponse: + return AsyncInvitesWithRawResponse(self._organization.invites) + + @cached_property + def users(self) -> AsyncUsersWithRawResponse: + return AsyncUsersWithRawResponse(self._organization.users) + + @cached_property + def groups(self) -> AsyncGroupsWithRawResponse: + return AsyncGroupsWithRawResponse(self._organization.groups) + + @cached_property + def roles(self) -> AsyncRolesWithRawResponse: + return AsyncRolesWithRawResponse(self._organization.roles) + + @cached_property + def certificates(self) -> AsyncCertificatesWithRawResponse: + return AsyncCertificatesWithRawResponse(self._organization.certificates) + + @cached_property + def projects(self) -> AsyncProjectsWithRawResponse: + return AsyncProjectsWithRawResponse(self._organization.projects) + class OrganizationWithStreamingResponse: def __init__(self, organization: Organization) -> None: @@ -97,6 +289,38 @@ def audit_logs(self) -> AuditLogsWithStreamingResponse: """List user actions and configuration changes within this organization.""" return AuditLogsWithStreamingResponse(self._organization.audit_logs) + @cached_property + def admin_api_keys(self) -> AdminAPIKeysWithStreamingResponse: + return AdminAPIKeysWithStreamingResponse(self._organization.admin_api_keys) + + @cached_property + def usage(self) -> UsageWithStreamingResponse: + return UsageWithStreamingResponse(self._organization.usage) + + @cached_property + def invites(self) -> InvitesWithStreamingResponse: + return InvitesWithStreamingResponse(self._organization.invites) + + @cached_property + def users(self) -> UsersWithStreamingResponse: + return UsersWithStreamingResponse(self._organization.users) + + @cached_property + def groups(self) -> GroupsWithStreamingResponse: + return GroupsWithStreamingResponse(self._organization.groups) + + @cached_property + def roles(self) -> RolesWithStreamingResponse: + return RolesWithStreamingResponse(self._organization.roles) + + @cached_property + def certificates(self) -> CertificatesWithStreamingResponse: + return CertificatesWithStreamingResponse(self._organization.certificates) + + @cached_property + def projects(self) -> ProjectsWithStreamingResponse: + return ProjectsWithStreamingResponse(self._organization.projects) + class AsyncOrganizationWithStreamingResponse: def __init__(self, organization: AsyncOrganization) -> None: @@ -106,3 +330,35 @@ def __init__(self, organization: AsyncOrganization) -> None: def audit_logs(self) -> AsyncAuditLogsWithStreamingResponse: """List user actions and configuration changes within this organization.""" return AsyncAuditLogsWithStreamingResponse(self._organization.audit_logs) + + @cached_property + def admin_api_keys(self) -> AsyncAdminAPIKeysWithStreamingResponse: + return AsyncAdminAPIKeysWithStreamingResponse(self._organization.admin_api_keys) + + @cached_property + def usage(self) -> AsyncUsageWithStreamingResponse: + return AsyncUsageWithStreamingResponse(self._organization.usage) + + @cached_property + def invites(self) -> AsyncInvitesWithStreamingResponse: + return AsyncInvitesWithStreamingResponse(self._organization.invites) + + @cached_property + def users(self) -> AsyncUsersWithStreamingResponse: + return AsyncUsersWithStreamingResponse(self._organization.users) + + @cached_property + def groups(self) -> AsyncGroupsWithStreamingResponse: + return AsyncGroupsWithStreamingResponse(self._organization.groups) + + @cached_property + def roles(self) -> AsyncRolesWithStreamingResponse: + return AsyncRolesWithStreamingResponse(self._organization.roles) + + @cached_property + def certificates(self) -> AsyncCertificatesWithStreamingResponse: + return AsyncCertificatesWithStreamingResponse(self._organization.certificates) + + @cached_property + def projects(self) -> AsyncProjectsWithStreamingResponse: + return AsyncProjectsWithStreamingResponse(self._organization.projects) diff --git a/src/openai/resources/admin/organization/projects/__init__.py b/src/openai/resources/admin/organization/projects/__init__.py new file mode 100644 index 0000000000..a64326bfa9 --- /dev/null +++ b/src/openai/resources/admin/organization/projects/__init__.py @@ -0,0 +1,117 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .roles import ( + Roles, + AsyncRoles, + RolesWithRawResponse, + AsyncRolesWithRawResponse, + RolesWithStreamingResponse, + AsyncRolesWithStreamingResponse, +) +from .users import ( + Users, + AsyncUsers, + UsersWithRawResponse, + AsyncUsersWithRawResponse, + UsersWithStreamingResponse, + AsyncUsersWithStreamingResponse, +) +from .groups import ( + Groups, + AsyncGroups, + GroupsWithRawResponse, + AsyncGroupsWithRawResponse, + GroupsWithStreamingResponse, + AsyncGroupsWithStreamingResponse, +) +from .api_keys import ( + APIKeys, + AsyncAPIKeys, + APIKeysWithRawResponse, + AsyncAPIKeysWithRawResponse, + APIKeysWithStreamingResponse, + AsyncAPIKeysWithStreamingResponse, +) +from .projects import ( + Projects, + AsyncProjects, + ProjectsWithRawResponse, + AsyncProjectsWithRawResponse, + ProjectsWithStreamingResponse, + AsyncProjectsWithStreamingResponse, +) +from .rate_limits import ( + RateLimits, + AsyncRateLimits, + RateLimitsWithRawResponse, + AsyncRateLimitsWithRawResponse, + RateLimitsWithStreamingResponse, + AsyncRateLimitsWithStreamingResponse, +) +from .certificates import ( + Certificates, + AsyncCertificates, + CertificatesWithRawResponse, + AsyncCertificatesWithRawResponse, + CertificatesWithStreamingResponse, + AsyncCertificatesWithStreamingResponse, +) +from .service_accounts import ( + ServiceAccounts, + AsyncServiceAccounts, + ServiceAccountsWithRawResponse, + AsyncServiceAccountsWithRawResponse, + ServiceAccountsWithStreamingResponse, + AsyncServiceAccountsWithStreamingResponse, +) + +__all__ = [ + "Users", + "AsyncUsers", + "UsersWithRawResponse", + "AsyncUsersWithRawResponse", + "UsersWithStreamingResponse", + "AsyncUsersWithStreamingResponse", + "ServiceAccounts", + "AsyncServiceAccounts", + "ServiceAccountsWithRawResponse", + "AsyncServiceAccountsWithRawResponse", + "ServiceAccountsWithStreamingResponse", + "AsyncServiceAccountsWithStreamingResponse", + "APIKeys", + "AsyncAPIKeys", + "APIKeysWithRawResponse", + "AsyncAPIKeysWithRawResponse", + "APIKeysWithStreamingResponse", + "AsyncAPIKeysWithStreamingResponse", + "RateLimits", + "AsyncRateLimits", + "RateLimitsWithRawResponse", + "AsyncRateLimitsWithRawResponse", + "RateLimitsWithStreamingResponse", + "AsyncRateLimitsWithStreamingResponse", + "Groups", + "AsyncGroups", + "GroupsWithRawResponse", + "AsyncGroupsWithRawResponse", + "GroupsWithStreamingResponse", + "AsyncGroupsWithStreamingResponse", + "Roles", + "AsyncRoles", + "RolesWithRawResponse", + "AsyncRolesWithRawResponse", + "RolesWithStreamingResponse", + "AsyncRolesWithStreamingResponse", + "Certificates", + "AsyncCertificates", + "CertificatesWithRawResponse", + "AsyncCertificatesWithRawResponse", + "CertificatesWithStreamingResponse", + "AsyncCertificatesWithStreamingResponse", + "Projects", + "AsyncProjects", + "ProjectsWithRawResponse", + "AsyncProjectsWithRawResponse", + "ProjectsWithStreamingResponse", + "AsyncProjectsWithStreamingResponse", +] diff --git a/src/openai/resources/admin/organization/projects/api_keys.py b/src/openai/resources/admin/organization/projects/api_keys.py new file mode 100644 index 0000000000..8902ce56ff --- /dev/null +++ b/src/openai/resources/admin/organization/projects/api_keys.py @@ -0,0 +1,405 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..... import _legacy_response +from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ....._utils import path_template, maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from .....pagination import SyncConversationCursorPage, AsyncConversationCursorPage +from ....._base_client import AsyncPaginator, make_request_options +from .....types.admin.organization.projects import api_key_list_params +from .....types.admin.organization.projects.project_api_key import ProjectAPIKey +from .....types.admin.organization.projects.api_key_delete_response import APIKeyDeleteResponse + +__all__ = ["APIKeys", "AsyncAPIKeys"] + + +class APIKeys(SyncAPIResource): + @cached_property + def with_raw_response(self) -> APIKeysWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return APIKeysWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> APIKeysWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return APIKeysWithStreamingResponse(self) + + def retrieve( + self, + key_id: str, + *, + project_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectAPIKey: + """ + Retrieves an API key in the project. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not key_id: + raise ValueError(f"Expected a non-empty value for `key_id` but received {key_id!r}") + return self._get( + path_template( + "/organization/projects/{project_id}/api_keys/{key_id}", project_id=project_id, key_id=key_id + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectAPIKey, + ) + + def list( + self, + project_id: str, + *, + after: str | Omit = omit, + limit: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncConversationCursorPage[ProjectAPIKey]: + """ + Returns a list of API keys in the project. + + Args: + after: A cursor for use in pagination. `after` is an object ID that defines your place + in the list. For instance, if you make a list request and receive 100 objects, + ending with obj_foo, your subsequent call can include after=obj_foo in order to + fetch the next page of the list. + + limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the default is 20. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._get_api_list( + path_template("/organization/projects/{project_id}/api_keys", project_id=project_id), + page=SyncConversationCursorPage[ProjectAPIKey], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + }, + api_key_list_params.APIKeyListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=ProjectAPIKey, + ) + + def delete( + self, + key_id: str, + *, + project_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> APIKeyDeleteResponse: + """ + Deletes an API key from the project. + + Returns confirmation of the key deletion, or an error if the key belonged to a + service account. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not key_id: + raise ValueError(f"Expected a non-empty value for `key_id` but received {key_id!r}") + return self._delete( + path_template( + "/organization/projects/{project_id}/api_keys/{key_id}", project_id=project_id, key_id=key_id + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=APIKeyDeleteResponse, + ) + + +class AsyncAPIKeys(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncAPIKeysWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncAPIKeysWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncAPIKeysWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncAPIKeysWithStreamingResponse(self) + + async def retrieve( + self, + key_id: str, + *, + project_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectAPIKey: + """ + Retrieves an API key in the project. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not key_id: + raise ValueError(f"Expected a non-empty value for `key_id` but received {key_id!r}") + return await self._get( + path_template( + "/organization/projects/{project_id}/api_keys/{key_id}", project_id=project_id, key_id=key_id + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectAPIKey, + ) + + def list( + self, + project_id: str, + *, + after: str | Omit = omit, + limit: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[ProjectAPIKey, AsyncConversationCursorPage[ProjectAPIKey]]: + """ + Returns a list of API keys in the project. + + Args: + after: A cursor for use in pagination. `after` is an object ID that defines your place + in the list. For instance, if you make a list request and receive 100 objects, + ending with obj_foo, your subsequent call can include after=obj_foo in order to + fetch the next page of the list. + + limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the default is 20. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._get_api_list( + path_template("/organization/projects/{project_id}/api_keys", project_id=project_id), + page=AsyncConversationCursorPage[ProjectAPIKey], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + }, + api_key_list_params.APIKeyListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=ProjectAPIKey, + ) + + async def delete( + self, + key_id: str, + *, + project_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> APIKeyDeleteResponse: + """ + Deletes an API key from the project. + + Returns confirmation of the key deletion, or an error if the key belonged to a + service account. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not key_id: + raise ValueError(f"Expected a non-empty value for `key_id` but received {key_id!r}") + return await self._delete( + path_template( + "/organization/projects/{project_id}/api_keys/{key_id}", project_id=project_id, key_id=key_id + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=APIKeyDeleteResponse, + ) + + +class APIKeysWithRawResponse: + def __init__(self, api_keys: APIKeys) -> None: + self._api_keys = api_keys + + self.retrieve = _legacy_response.to_raw_response_wrapper( + api_keys.retrieve, + ) + self.list = _legacy_response.to_raw_response_wrapper( + api_keys.list, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + api_keys.delete, + ) + + +class AsyncAPIKeysWithRawResponse: + def __init__(self, api_keys: AsyncAPIKeys) -> None: + self._api_keys = api_keys + + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + api_keys.retrieve, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + api_keys.list, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + api_keys.delete, + ) + + +class APIKeysWithStreamingResponse: + def __init__(self, api_keys: APIKeys) -> None: + self._api_keys = api_keys + + self.retrieve = to_streamed_response_wrapper( + api_keys.retrieve, + ) + self.list = to_streamed_response_wrapper( + api_keys.list, + ) + self.delete = to_streamed_response_wrapper( + api_keys.delete, + ) + + +class AsyncAPIKeysWithStreamingResponse: + def __init__(self, api_keys: AsyncAPIKeys) -> None: + self._api_keys = api_keys + + self.retrieve = async_to_streamed_response_wrapper( + api_keys.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + api_keys.list, + ) + self.delete = async_to_streamed_response_wrapper( + api_keys.delete, + ) diff --git a/src/openai/resources/admin/organization/projects/certificates.py b/src/openai/resources/admin/organization/projects/certificates.py new file mode 100644 index 0000000000..3ff2111293 --- /dev/null +++ b/src/openai/resources/admin/organization/projects/certificates.py @@ -0,0 +1,426 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from ..... import _legacy_response +from ....._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ....._utils import path_template, maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from .....pagination import SyncPage, AsyncPage, SyncConversationCursorPage, AsyncConversationCursorPage +from ....._base_client import AsyncPaginator, make_request_options +from .....types.admin.organization.projects import ( + certificate_list_params, + certificate_activate_params, + certificate_deactivate_params, +) +from .....types.admin.organization.certificate import Certificate + +__all__ = ["Certificates", "AsyncCertificates"] + + +class Certificates(SyncAPIResource): + @cached_property + def with_raw_response(self) -> CertificatesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return CertificatesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> CertificatesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return CertificatesWithStreamingResponse(self) + + def list( + self, + project_id: str, + *, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncConversationCursorPage[Certificate]: + """ + List certificates for this project. + + Args: + after: A cursor for use in pagination. `after` is an object ID that defines your place + in the list. For instance, if you make a list request and receive 100 objects, + ending with obj_foo, your subsequent call can include after=obj_foo in order to + fetch the next page of the list. + + limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the default is 20. + + order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending + order and `desc` for descending order. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._get_api_list( + path_template("/organization/projects/{project_id}/certificates", project_id=project_id), + page=SyncConversationCursorPage[Certificate], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + certificate_list_params.CertificateListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=Certificate, + ) + + def activate( + self, + project_id: str, + *, + certificate_ids: SequenceNotStr[str], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncPage[Certificate]: + """ + Activate certificates at the project level. + + You can atomically and idempotently activate up to 10 certificates at a time. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._get_api_list( + path_template("/organization/projects/{project_id}/certificates/activate", project_id=project_id), + page=SyncPage[Certificate], + body=maybe_transform( + {"certificate_ids": certificate_ids}, certificate_activate_params.CertificateActivateParams + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + model=Certificate, + method="post", + ) + + def deactivate( + self, + project_id: str, + *, + certificate_ids: SequenceNotStr[str], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncPage[Certificate]: + """Deactivate certificates at the project level. + + You can atomically and + idempotently deactivate up to 10 certificates at a time. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._get_api_list( + path_template("/organization/projects/{project_id}/certificates/deactivate", project_id=project_id), + page=SyncPage[Certificate], + body=maybe_transform( + {"certificate_ids": certificate_ids}, certificate_deactivate_params.CertificateDeactivateParams + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + model=Certificate, + method="post", + ) + + +class AsyncCertificates(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncCertificatesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncCertificatesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncCertificatesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncCertificatesWithStreamingResponse(self) + + def list( + self, + project_id: str, + *, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Certificate, AsyncConversationCursorPage[Certificate]]: + """ + List certificates for this project. + + Args: + after: A cursor for use in pagination. `after` is an object ID that defines your place + in the list. For instance, if you make a list request and receive 100 objects, + ending with obj_foo, your subsequent call can include after=obj_foo in order to + fetch the next page of the list. + + limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the default is 20. + + order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending + order and `desc` for descending order. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._get_api_list( + path_template("/organization/projects/{project_id}/certificates", project_id=project_id), + page=AsyncConversationCursorPage[Certificate], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + certificate_list_params.CertificateListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=Certificate, + ) + + def activate( + self, + project_id: str, + *, + certificate_ids: SequenceNotStr[str], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Certificate, AsyncPage[Certificate]]: + """ + Activate certificates at the project level. + + You can atomically and idempotently activate up to 10 certificates at a time. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._get_api_list( + path_template("/organization/projects/{project_id}/certificates/activate", project_id=project_id), + page=AsyncPage[Certificate], + body=maybe_transform( + {"certificate_ids": certificate_ids}, certificate_activate_params.CertificateActivateParams + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + model=Certificate, + method="post", + ) + + def deactivate( + self, + project_id: str, + *, + certificate_ids: SequenceNotStr[str], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Certificate, AsyncPage[Certificate]]: + """Deactivate certificates at the project level. + + You can atomically and + idempotently deactivate up to 10 certificates at a time. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._get_api_list( + path_template("/organization/projects/{project_id}/certificates/deactivate", project_id=project_id), + page=AsyncPage[Certificate], + body=maybe_transform( + {"certificate_ids": certificate_ids}, certificate_deactivate_params.CertificateDeactivateParams + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + model=Certificate, + method="post", + ) + + +class CertificatesWithRawResponse: + def __init__(self, certificates: Certificates) -> None: + self._certificates = certificates + + self.list = _legacy_response.to_raw_response_wrapper( + certificates.list, + ) + self.activate = _legacy_response.to_raw_response_wrapper( + certificates.activate, + ) + self.deactivate = _legacy_response.to_raw_response_wrapper( + certificates.deactivate, + ) + + +class AsyncCertificatesWithRawResponse: + def __init__(self, certificates: AsyncCertificates) -> None: + self._certificates = certificates + + self.list = _legacy_response.async_to_raw_response_wrapper( + certificates.list, + ) + self.activate = _legacy_response.async_to_raw_response_wrapper( + certificates.activate, + ) + self.deactivate = _legacy_response.async_to_raw_response_wrapper( + certificates.deactivate, + ) + + +class CertificatesWithStreamingResponse: + def __init__(self, certificates: Certificates) -> None: + self._certificates = certificates + + self.list = to_streamed_response_wrapper( + certificates.list, + ) + self.activate = to_streamed_response_wrapper( + certificates.activate, + ) + self.deactivate = to_streamed_response_wrapper( + certificates.deactivate, + ) + + +class AsyncCertificatesWithStreamingResponse: + def __init__(self, certificates: AsyncCertificates) -> None: + self._certificates = certificates + + self.list = async_to_streamed_response_wrapper( + certificates.list, + ) + self.activate = async_to_streamed_response_wrapper( + certificates.activate, + ) + self.deactivate = async_to_streamed_response_wrapper( + certificates.deactivate, + ) diff --git a/src/openai/resources/admin/organization/projects/groups/__init__.py b/src/openai/resources/admin/organization/projects/groups/__init__.py new file mode 100644 index 0000000000..4feb66239f --- /dev/null +++ b/src/openai/resources/admin/organization/projects/groups/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .roles import ( + Roles, + AsyncRoles, + RolesWithRawResponse, + AsyncRolesWithRawResponse, + RolesWithStreamingResponse, + AsyncRolesWithStreamingResponse, +) +from .groups import ( + Groups, + AsyncGroups, + GroupsWithRawResponse, + AsyncGroupsWithRawResponse, + GroupsWithStreamingResponse, + AsyncGroupsWithStreamingResponse, +) + +__all__ = [ + "Roles", + "AsyncRoles", + "RolesWithRawResponse", + "AsyncRolesWithRawResponse", + "RolesWithStreamingResponse", + "AsyncRolesWithStreamingResponse", + "Groups", + "AsyncGroups", + "GroupsWithRawResponse", + "AsyncGroupsWithRawResponse", + "GroupsWithStreamingResponse", + "AsyncGroupsWithStreamingResponse", +] diff --git a/src/openai/resources/admin/organization/projects/groups/groups.py b/src/openai/resources/admin/organization/projects/groups/groups.py new file mode 100644 index 0000000000..8525a65255 --- /dev/null +++ b/src/openai/resources/admin/organization/projects/groups/groups.py @@ -0,0 +1,451 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from ...... import _legacy_response +from .roles import ( + Roles, + AsyncRoles, + RolesWithRawResponse, + AsyncRolesWithRawResponse, + RolesWithStreamingResponse, + AsyncRolesWithStreamingResponse, +) +from ......_types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ......_utils import path_template, maybe_transform, async_maybe_transform +from ......_compat import cached_property +from ......_resource import SyncAPIResource, AsyncAPIResource +from ......_response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ......pagination import SyncCursorPage, AsyncCursorPage +from ......_base_client import AsyncPaginator, make_request_options +from ......types.admin.organization.projects import group_list_params, group_create_params +from ......types.admin.organization.projects.project_group import ProjectGroup +from ......types.admin.organization.projects.group_delete_response import GroupDeleteResponse + +__all__ = ["Groups", "AsyncGroups"] + + +class Groups(SyncAPIResource): + @cached_property + def roles(self) -> Roles: + return Roles(self._client) + + @cached_property + def with_raw_response(self) -> GroupsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return GroupsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> GroupsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return GroupsWithStreamingResponse(self) + + def create( + self, + project_id: str, + *, + group_id: str, + role: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectGroup: + """ + Grants a group access to a project. + + Args: + group_id: Identifier of the group to add to the project. + + role: Identifier of the project role to grant to the group. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._post( + path_template("/organization/projects/{project_id}/groups", project_id=project_id), + body=maybe_transform( + { + "group_id": group_id, + "role": role, + }, + group_create_params.GroupCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectGroup, + ) + + def list( + self, + project_id: str, + *, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncCursorPage[ProjectGroup]: + """ + Lists the groups that have access to a project. + + Args: + after: Cursor for pagination. Provide the ID of the last group from the previous + response to fetch the next page. + + limit: A limit on the number of project groups to return. Defaults to 20. + + order: Sort order for the returned groups. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._get_api_list( + path_template("/organization/projects/{project_id}/groups", project_id=project_id), + page=SyncCursorPage[ProjectGroup], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + group_list_params.GroupListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=ProjectGroup, + ) + + def delete( + self, + group_id: str, + *, + project_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GroupDeleteResponse: + """ + Revokes a group's access to a project. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return self._delete( + path_template( + "/organization/projects/{project_id}/groups/{group_id}", project_id=project_id, group_id=group_id + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=GroupDeleteResponse, + ) + + +class AsyncGroups(AsyncAPIResource): + @cached_property + def roles(self) -> AsyncRoles: + return AsyncRoles(self._client) + + @cached_property + def with_raw_response(self) -> AsyncGroupsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncGroupsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncGroupsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncGroupsWithStreamingResponse(self) + + async def create( + self, + project_id: str, + *, + group_id: str, + role: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectGroup: + """ + Grants a group access to a project. + + Args: + group_id: Identifier of the group to add to the project. + + role: Identifier of the project role to grant to the group. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return await self._post( + path_template("/organization/projects/{project_id}/groups", project_id=project_id), + body=await async_maybe_transform( + { + "group_id": group_id, + "role": role, + }, + group_create_params.GroupCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectGroup, + ) + + def list( + self, + project_id: str, + *, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[ProjectGroup, AsyncCursorPage[ProjectGroup]]: + """ + Lists the groups that have access to a project. + + Args: + after: Cursor for pagination. Provide the ID of the last group from the previous + response to fetch the next page. + + limit: A limit on the number of project groups to return. Defaults to 20. + + order: Sort order for the returned groups. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._get_api_list( + path_template("/organization/projects/{project_id}/groups", project_id=project_id), + page=AsyncCursorPage[ProjectGroup], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + group_list_params.GroupListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=ProjectGroup, + ) + + async def delete( + self, + group_id: str, + *, + project_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GroupDeleteResponse: + """ + Revokes a group's access to a project. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return await self._delete( + path_template( + "/organization/projects/{project_id}/groups/{group_id}", project_id=project_id, group_id=group_id + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=GroupDeleteResponse, + ) + + +class GroupsWithRawResponse: + def __init__(self, groups: Groups) -> None: + self._groups = groups + + self.create = _legacy_response.to_raw_response_wrapper( + groups.create, + ) + self.list = _legacy_response.to_raw_response_wrapper( + groups.list, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + groups.delete, + ) + + @cached_property + def roles(self) -> RolesWithRawResponse: + return RolesWithRawResponse(self._groups.roles) + + +class AsyncGroupsWithRawResponse: + def __init__(self, groups: AsyncGroups) -> None: + self._groups = groups + + self.create = _legacy_response.async_to_raw_response_wrapper( + groups.create, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + groups.list, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + groups.delete, + ) + + @cached_property + def roles(self) -> AsyncRolesWithRawResponse: + return AsyncRolesWithRawResponse(self._groups.roles) + + +class GroupsWithStreamingResponse: + def __init__(self, groups: Groups) -> None: + self._groups = groups + + self.create = to_streamed_response_wrapper( + groups.create, + ) + self.list = to_streamed_response_wrapper( + groups.list, + ) + self.delete = to_streamed_response_wrapper( + groups.delete, + ) + + @cached_property + def roles(self) -> RolesWithStreamingResponse: + return RolesWithStreamingResponse(self._groups.roles) + + +class AsyncGroupsWithStreamingResponse: + def __init__(self, groups: AsyncGroups) -> None: + self._groups = groups + + self.create = async_to_streamed_response_wrapper( + groups.create, + ) + self.list = async_to_streamed_response_wrapper( + groups.list, + ) + self.delete = async_to_streamed_response_wrapper( + groups.delete, + ) + + @cached_property + def roles(self) -> AsyncRolesWithStreamingResponse: + return AsyncRolesWithStreamingResponse(self._groups.roles) diff --git a/src/openai/resources/admin/organization/projects/groups/roles.py b/src/openai/resources/admin/organization/projects/groups/roles.py new file mode 100644 index 0000000000..20cab5d0e4 --- /dev/null +++ b/src/openai/resources/admin/organization/projects/groups/roles.py @@ -0,0 +1,426 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from ...... import _legacy_response +from ......_types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ......_utils import path_template, maybe_transform, async_maybe_transform +from ......_compat import cached_property +from ......_resource import SyncAPIResource, AsyncAPIResource +from ......_response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ......pagination import SyncCursorPage, AsyncCursorPage +from ......_base_client import AsyncPaginator, make_request_options +from ......types.admin.organization.projects.groups import role_list_params, role_create_params +from ......types.admin.organization.projects.groups.role_list_response import RoleListResponse +from ......types.admin.organization.projects.groups.role_create_response import RoleCreateResponse +from ......types.admin.organization.projects.groups.role_delete_response import RoleDeleteResponse + +__all__ = ["Roles", "AsyncRoles"] + + +class Roles(SyncAPIResource): + @cached_property + def with_raw_response(self) -> RolesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return RolesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> RolesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return RolesWithStreamingResponse(self) + + def create( + self, + group_id: str, + *, + project_id: str, + role_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RoleCreateResponse: + """ + Assigns a project role to a group within a project. + + Args: + role_id: Identifier of the role to assign. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return self._post( + path_template("/projects/{project_id}/groups/{group_id}/roles", project_id=project_id, group_id=group_id), + body=maybe_transform({"role_id": role_id}, role_create_params.RoleCreateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=RoleCreateResponse, + ) + + def list( + self, + group_id: str, + *, + project_id: str, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncCursorPage[RoleListResponse]: + """ + Lists the project roles assigned to a group within a project. + + Args: + after: Cursor for pagination. Provide the value from the previous response's `next` + field to continue listing project roles. + + limit: A limit on the number of project role assignments to return. + + order: Sort order for the returned project roles. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return self._get_api_list( + path_template("/projects/{project_id}/groups/{group_id}/roles", project_id=project_id, group_id=group_id), + page=SyncCursorPage[RoleListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + role_list_params.RoleListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=RoleListResponse, + ) + + def delete( + self, + role_id: str, + *, + project_id: str, + group_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RoleDeleteResponse: + """ + Unassigns a project role from a group within a project. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + if not role_id: + raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") + return self._delete( + path_template( + "/projects/{project_id}/groups/{group_id}/roles/{role_id}", + project_id=project_id, + group_id=group_id, + role_id=role_id, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=RoleDeleteResponse, + ) + + +class AsyncRoles(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncRolesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncRolesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncRolesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncRolesWithStreamingResponse(self) + + async def create( + self, + group_id: str, + *, + project_id: str, + role_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RoleCreateResponse: + """ + Assigns a project role to a group within a project. + + Args: + role_id: Identifier of the role to assign. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return await self._post( + path_template("/projects/{project_id}/groups/{group_id}/roles", project_id=project_id, group_id=group_id), + body=await async_maybe_transform({"role_id": role_id}, role_create_params.RoleCreateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=RoleCreateResponse, + ) + + def list( + self, + group_id: str, + *, + project_id: str, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[RoleListResponse, AsyncCursorPage[RoleListResponse]]: + """ + Lists the project roles assigned to a group within a project. + + Args: + after: Cursor for pagination. Provide the value from the previous response's `next` + field to continue listing project roles. + + limit: A limit on the number of project role assignments to return. + + order: Sort order for the returned project roles. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return self._get_api_list( + path_template("/projects/{project_id}/groups/{group_id}/roles", project_id=project_id, group_id=group_id), + page=AsyncCursorPage[RoleListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + role_list_params.RoleListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=RoleListResponse, + ) + + async def delete( + self, + role_id: str, + *, + project_id: str, + group_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RoleDeleteResponse: + """ + Unassigns a project role from a group within a project. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + if not role_id: + raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") + return await self._delete( + path_template( + "/projects/{project_id}/groups/{group_id}/roles/{role_id}", + project_id=project_id, + group_id=group_id, + role_id=role_id, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=RoleDeleteResponse, + ) + + +class RolesWithRawResponse: + def __init__(self, roles: Roles) -> None: + self._roles = roles + + self.create = _legacy_response.to_raw_response_wrapper( + roles.create, + ) + self.list = _legacy_response.to_raw_response_wrapper( + roles.list, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + roles.delete, + ) + + +class AsyncRolesWithRawResponse: + def __init__(self, roles: AsyncRoles) -> None: + self._roles = roles + + self.create = _legacy_response.async_to_raw_response_wrapper( + roles.create, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + roles.list, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + roles.delete, + ) + + +class RolesWithStreamingResponse: + def __init__(self, roles: Roles) -> None: + self._roles = roles + + self.create = to_streamed_response_wrapper( + roles.create, + ) + self.list = to_streamed_response_wrapper( + roles.list, + ) + self.delete = to_streamed_response_wrapper( + roles.delete, + ) + + +class AsyncRolesWithStreamingResponse: + def __init__(self, roles: AsyncRoles) -> None: + self._roles = roles + + self.create = async_to_streamed_response_wrapper( + roles.create, + ) + self.list = async_to_streamed_response_wrapper( + roles.list, + ) + self.delete = async_to_streamed_response_wrapper( + roles.delete, + ) diff --git a/src/openai/resources/admin/organization/projects/projects.py b/src/openai/resources/admin/organization/projects/projects.py new file mode 100644 index 0000000000..db774338d7 --- /dev/null +++ b/src/openai/resources/admin/organization/projects/projects.py @@ -0,0 +1,824 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from ..... import _legacy_response +from .roles import ( + Roles, + AsyncRoles, + RolesWithRawResponse, + AsyncRolesWithRawResponse, + RolesWithStreamingResponse, + AsyncRolesWithStreamingResponse, +) +from .api_keys import ( + APIKeys, + AsyncAPIKeys, + APIKeysWithRawResponse, + AsyncAPIKeysWithRawResponse, + APIKeysWithStreamingResponse, + AsyncAPIKeysWithStreamingResponse, +) +from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ....._utils import path_template, maybe_transform, async_maybe_transform +from ....._compat import cached_property +from .rate_limits import ( + RateLimits, + AsyncRateLimits, + RateLimitsWithRawResponse, + AsyncRateLimitsWithRawResponse, + RateLimitsWithStreamingResponse, + AsyncRateLimitsWithStreamingResponse, +) +from .users.users import ( + Users, + AsyncUsers, + UsersWithRawResponse, + AsyncUsersWithRawResponse, + UsersWithStreamingResponse, + AsyncUsersWithStreamingResponse, +) +from .certificates import ( + Certificates, + AsyncCertificates, + CertificatesWithRawResponse, + AsyncCertificatesWithRawResponse, + CertificatesWithStreamingResponse, + AsyncCertificatesWithStreamingResponse, +) +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from .groups.groups import ( + Groups, + AsyncGroups, + GroupsWithRawResponse, + AsyncGroupsWithRawResponse, + GroupsWithStreamingResponse, + AsyncGroupsWithStreamingResponse, +) +from .....pagination import SyncConversationCursorPage, AsyncConversationCursorPage +from ....._base_client import AsyncPaginator, make_request_options +from .service_accounts import ( + ServiceAccounts, + AsyncServiceAccounts, + ServiceAccountsWithRawResponse, + AsyncServiceAccountsWithRawResponse, + ServiceAccountsWithStreamingResponse, + AsyncServiceAccountsWithStreamingResponse, +) +from .....types.admin.organization import project_list_params, project_create_params, project_update_params +from .....types.admin.organization.project import Project + +__all__ = ["Projects", "AsyncProjects"] + + +class Projects(SyncAPIResource): + @cached_property + def users(self) -> Users: + return Users(self._client) + + @cached_property + def service_accounts(self) -> ServiceAccounts: + return ServiceAccounts(self._client) + + @cached_property + def api_keys(self) -> APIKeys: + return APIKeys(self._client) + + @cached_property + def rate_limits(self) -> RateLimits: + return RateLimits(self._client) + + @cached_property + def groups(self) -> Groups: + return Groups(self._client) + + @cached_property + def roles(self) -> Roles: + return Roles(self._client) + + @cached_property + def certificates(self) -> Certificates: + return Certificates(self._client) + + @cached_property + def with_raw_response(self) -> ProjectsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return ProjectsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ProjectsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return ProjectsWithStreamingResponse(self) + + def create( + self, + *, + name: str, + geography: Literal["US", "EU", "JP", "IN", "KR", "CA", "AU", "SG"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Project: + """Create a new project in the organization. + + Projects can be created and archived, + but cannot be deleted. + + Args: + name: The friendly name of the project, this name appears in reports. + + geography: Create the project with the specified data residency region. Your organization + must have access to Data residency functionality in order to use. See + [data residency controls](https://platform.openai.com/docs/guides/your-data#data-residency-controls) + to review the functionality and limitations of setting this field. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/organization/projects", + body=maybe_transform( + { + "name": name, + "geography": geography, + }, + project_create_params.ProjectCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=Project, + ) + + def retrieve( + self, + project_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Project: + """ + Retrieves a project. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._get( + path_template("/organization/projects/{project_id}", project_id=project_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=Project, + ) + + def update( + self, + project_id: str, + *, + name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Project: + """ + Modifies a project in the organization. + + Args: + name: The updated name of the project, this name appears in reports. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._post( + path_template("/organization/projects/{project_id}", project_id=project_id), + body=maybe_transform({"name": name}, project_update_params.ProjectUpdateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=Project, + ) + + def list( + self, + *, + after: str | Omit = omit, + include_archived: bool | Omit = omit, + limit: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncConversationCursorPage[Project]: + """Returns a list of projects. + + Args: + after: A cursor for use in pagination. + + `after` is an object ID that defines your place + in the list. For instance, if you make a list request and receive 100 objects, + ending with obj_foo, your subsequent call can include after=obj_foo in order to + fetch the next page of the list. + + include_archived: If `true` returns all projects including those that have been `archived`. + Archived projects are not included by default. + + limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the default is 20. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/organization/projects", + page=SyncConversationCursorPage[Project], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "include_archived": include_archived, + "limit": limit, + }, + project_list_params.ProjectListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=Project, + ) + + def archive( + self, + project_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Project: + """Archives a project in the organization. + + Archived projects cannot be used or + updated. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._post( + path_template("/organization/projects/{project_id}/archive", project_id=project_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=Project, + ) + + +class AsyncProjects(AsyncAPIResource): + @cached_property + def users(self) -> AsyncUsers: + return AsyncUsers(self._client) + + @cached_property + def service_accounts(self) -> AsyncServiceAccounts: + return AsyncServiceAccounts(self._client) + + @cached_property + def api_keys(self) -> AsyncAPIKeys: + return AsyncAPIKeys(self._client) + + @cached_property + def rate_limits(self) -> AsyncRateLimits: + return AsyncRateLimits(self._client) + + @cached_property + def groups(self) -> AsyncGroups: + return AsyncGroups(self._client) + + @cached_property + def roles(self) -> AsyncRoles: + return AsyncRoles(self._client) + + @cached_property + def certificates(self) -> AsyncCertificates: + return AsyncCertificates(self._client) + + @cached_property + def with_raw_response(self) -> AsyncProjectsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncProjectsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncProjectsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncProjectsWithStreamingResponse(self) + + async def create( + self, + *, + name: str, + geography: Literal["US", "EU", "JP", "IN", "KR", "CA", "AU", "SG"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Project: + """Create a new project in the organization. + + Projects can be created and archived, + but cannot be deleted. + + Args: + name: The friendly name of the project, this name appears in reports. + + geography: Create the project with the specified data residency region. Your organization + must have access to Data residency functionality in order to use. See + [data residency controls](https://platform.openai.com/docs/guides/your-data#data-residency-controls) + to review the functionality and limitations of setting this field. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/organization/projects", + body=await async_maybe_transform( + { + "name": name, + "geography": geography, + }, + project_create_params.ProjectCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=Project, + ) + + async def retrieve( + self, + project_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Project: + """ + Retrieves a project. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return await self._get( + path_template("/organization/projects/{project_id}", project_id=project_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=Project, + ) + + async def update( + self, + project_id: str, + *, + name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Project: + """ + Modifies a project in the organization. + + Args: + name: The updated name of the project, this name appears in reports. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return await self._post( + path_template("/organization/projects/{project_id}", project_id=project_id), + body=await async_maybe_transform({"name": name}, project_update_params.ProjectUpdateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=Project, + ) + + def list( + self, + *, + after: str | Omit = omit, + include_archived: bool | Omit = omit, + limit: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Project, AsyncConversationCursorPage[Project]]: + """Returns a list of projects. + + Args: + after: A cursor for use in pagination. + + `after` is an object ID that defines your place + in the list. For instance, if you make a list request and receive 100 objects, + ending with obj_foo, your subsequent call can include after=obj_foo in order to + fetch the next page of the list. + + include_archived: If `true` returns all projects including those that have been `archived`. + Archived projects are not included by default. + + limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the default is 20. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/organization/projects", + page=AsyncConversationCursorPage[Project], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "include_archived": include_archived, + "limit": limit, + }, + project_list_params.ProjectListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=Project, + ) + + async def archive( + self, + project_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Project: + """Archives a project in the organization. + + Archived projects cannot be used or + updated. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return await self._post( + path_template("/organization/projects/{project_id}/archive", project_id=project_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=Project, + ) + + +class ProjectsWithRawResponse: + def __init__(self, projects: Projects) -> None: + self._projects = projects + + self.create = _legacy_response.to_raw_response_wrapper( + projects.create, + ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + projects.retrieve, + ) + self.update = _legacy_response.to_raw_response_wrapper( + projects.update, + ) + self.list = _legacy_response.to_raw_response_wrapper( + projects.list, + ) + self.archive = _legacy_response.to_raw_response_wrapper( + projects.archive, + ) + + @cached_property + def users(self) -> UsersWithRawResponse: + return UsersWithRawResponse(self._projects.users) + + @cached_property + def service_accounts(self) -> ServiceAccountsWithRawResponse: + return ServiceAccountsWithRawResponse(self._projects.service_accounts) + + @cached_property + def api_keys(self) -> APIKeysWithRawResponse: + return APIKeysWithRawResponse(self._projects.api_keys) + + @cached_property + def rate_limits(self) -> RateLimitsWithRawResponse: + return RateLimitsWithRawResponse(self._projects.rate_limits) + + @cached_property + def groups(self) -> GroupsWithRawResponse: + return GroupsWithRawResponse(self._projects.groups) + + @cached_property + def roles(self) -> RolesWithRawResponse: + return RolesWithRawResponse(self._projects.roles) + + @cached_property + def certificates(self) -> CertificatesWithRawResponse: + return CertificatesWithRawResponse(self._projects.certificates) + + +class AsyncProjectsWithRawResponse: + def __init__(self, projects: AsyncProjects) -> None: + self._projects = projects + + self.create = _legacy_response.async_to_raw_response_wrapper( + projects.create, + ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + projects.retrieve, + ) + self.update = _legacy_response.async_to_raw_response_wrapper( + projects.update, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + projects.list, + ) + self.archive = _legacy_response.async_to_raw_response_wrapper( + projects.archive, + ) + + @cached_property + def users(self) -> AsyncUsersWithRawResponse: + return AsyncUsersWithRawResponse(self._projects.users) + + @cached_property + def service_accounts(self) -> AsyncServiceAccountsWithRawResponse: + return AsyncServiceAccountsWithRawResponse(self._projects.service_accounts) + + @cached_property + def api_keys(self) -> AsyncAPIKeysWithRawResponse: + return AsyncAPIKeysWithRawResponse(self._projects.api_keys) + + @cached_property + def rate_limits(self) -> AsyncRateLimitsWithRawResponse: + return AsyncRateLimitsWithRawResponse(self._projects.rate_limits) + + @cached_property + def groups(self) -> AsyncGroupsWithRawResponse: + return AsyncGroupsWithRawResponse(self._projects.groups) + + @cached_property + def roles(self) -> AsyncRolesWithRawResponse: + return AsyncRolesWithRawResponse(self._projects.roles) + + @cached_property + def certificates(self) -> AsyncCertificatesWithRawResponse: + return AsyncCertificatesWithRawResponse(self._projects.certificates) + + +class ProjectsWithStreamingResponse: + def __init__(self, projects: Projects) -> None: + self._projects = projects + + self.create = to_streamed_response_wrapper( + projects.create, + ) + self.retrieve = to_streamed_response_wrapper( + projects.retrieve, + ) + self.update = to_streamed_response_wrapper( + projects.update, + ) + self.list = to_streamed_response_wrapper( + projects.list, + ) + self.archive = to_streamed_response_wrapper( + projects.archive, + ) + + @cached_property + def users(self) -> UsersWithStreamingResponse: + return UsersWithStreamingResponse(self._projects.users) + + @cached_property + def service_accounts(self) -> ServiceAccountsWithStreamingResponse: + return ServiceAccountsWithStreamingResponse(self._projects.service_accounts) + + @cached_property + def api_keys(self) -> APIKeysWithStreamingResponse: + return APIKeysWithStreamingResponse(self._projects.api_keys) + + @cached_property + def rate_limits(self) -> RateLimitsWithStreamingResponse: + return RateLimitsWithStreamingResponse(self._projects.rate_limits) + + @cached_property + def groups(self) -> GroupsWithStreamingResponse: + return GroupsWithStreamingResponse(self._projects.groups) + + @cached_property + def roles(self) -> RolesWithStreamingResponse: + return RolesWithStreamingResponse(self._projects.roles) + + @cached_property + def certificates(self) -> CertificatesWithStreamingResponse: + return CertificatesWithStreamingResponse(self._projects.certificates) + + +class AsyncProjectsWithStreamingResponse: + def __init__(self, projects: AsyncProjects) -> None: + self._projects = projects + + self.create = async_to_streamed_response_wrapper( + projects.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + projects.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + projects.update, + ) + self.list = async_to_streamed_response_wrapper( + projects.list, + ) + self.archive = async_to_streamed_response_wrapper( + projects.archive, + ) + + @cached_property + def users(self) -> AsyncUsersWithStreamingResponse: + return AsyncUsersWithStreamingResponse(self._projects.users) + + @cached_property + def service_accounts(self) -> AsyncServiceAccountsWithStreamingResponse: + return AsyncServiceAccountsWithStreamingResponse(self._projects.service_accounts) + + @cached_property + def api_keys(self) -> AsyncAPIKeysWithStreamingResponse: + return AsyncAPIKeysWithStreamingResponse(self._projects.api_keys) + + @cached_property + def rate_limits(self) -> AsyncRateLimitsWithStreamingResponse: + return AsyncRateLimitsWithStreamingResponse(self._projects.rate_limits) + + @cached_property + def groups(self) -> AsyncGroupsWithStreamingResponse: + return AsyncGroupsWithStreamingResponse(self._projects.groups) + + @cached_property + def roles(self) -> AsyncRolesWithStreamingResponse: + return AsyncRolesWithStreamingResponse(self._projects.roles) + + @cached_property + def certificates(self) -> AsyncCertificatesWithStreamingResponse: + return AsyncCertificatesWithStreamingResponse(self._projects.certificates) diff --git a/src/openai/resources/admin/organization/projects/rate_limits.py b/src/openai/resources/admin/organization/projects/rate_limits.py new file mode 100644 index 0000000000..9fe20f572e --- /dev/null +++ b/src/openai/resources/admin/organization/projects/rate_limits.py @@ -0,0 +1,379 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..... import _legacy_response +from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ....._utils import path_template, maybe_transform, async_maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from .....pagination import SyncConversationCursorPage, AsyncConversationCursorPage +from ....._base_client import AsyncPaginator, make_request_options +from .....types.admin.organization.projects import ( + rate_limit_list_rate_limits_params, + rate_limit_update_rate_limit_params, +) +from .....types.admin.organization.projects.project_rate_limit import ProjectRateLimit + +__all__ = ["RateLimits", "AsyncRateLimits"] + + +class RateLimits(SyncAPIResource): + @cached_property + def with_raw_response(self) -> RateLimitsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return RateLimitsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> RateLimitsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return RateLimitsWithStreamingResponse(self) + + def list_rate_limits( + self, + project_id: str, + *, + after: str | Omit = omit, + before: str | Omit = omit, + limit: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncConversationCursorPage[ProjectRateLimit]: + """ + Returns the rate limits per model for a project. + + Args: + after: A cursor for use in pagination. `after` is an object ID that defines your place + in the list. For instance, if you make a list request and receive 100 objects, + ending with obj_foo, your subsequent call can include after=obj_foo in order to + fetch the next page of the list. + + before: A cursor for use in pagination. `before` is an object ID that defines your place + in the list. For instance, if you make a list request and receive 100 objects, + beginning with obj_foo, your subsequent call can include before=obj_foo in order + to fetch the previous page of the list. + + limit: A limit on the number of objects to be returned. The default is 100. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._get_api_list( + path_template("/organization/projects/{project_id}/rate_limits", project_id=project_id), + page=SyncConversationCursorPage[ProjectRateLimit], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "before": before, + "limit": limit, + }, + rate_limit_list_rate_limits_params.RateLimitListRateLimitsParams, + ), + security={"admin_api_key_auth": True}, + ), + model=ProjectRateLimit, + ) + + def update_rate_limit( + self, + rate_limit_id: str, + *, + project_id: str, + batch_1_day_max_input_tokens: int | Omit = omit, + max_audio_megabytes_per_1_minute: int | Omit = omit, + max_images_per_1_minute: int | Omit = omit, + max_requests_per_1_day: int | Omit = omit, + max_requests_per_1_minute: int | Omit = omit, + max_tokens_per_1_minute: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectRateLimit: + """ + Updates a project rate limit. + + Args: + batch_1_day_max_input_tokens: The maximum batch input tokens per day. Only relevant for certain models. + + max_audio_megabytes_per_1_minute: The maximum audio megabytes per minute. Only relevant for certain models. + + max_images_per_1_minute: The maximum images per minute. Only relevant for certain models. + + max_requests_per_1_day: The maximum requests per day. Only relevant for certain models. + + max_requests_per_1_minute: The maximum requests per minute. + + max_tokens_per_1_minute: The maximum tokens per minute. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not rate_limit_id: + raise ValueError(f"Expected a non-empty value for `rate_limit_id` but received {rate_limit_id!r}") + return self._post( + path_template( + "/organization/projects/{project_id}/rate_limits/{rate_limit_id}", + project_id=project_id, + rate_limit_id=rate_limit_id, + ), + body=maybe_transform( + { + "batch_1_day_max_input_tokens": batch_1_day_max_input_tokens, + "max_audio_megabytes_per_1_minute": max_audio_megabytes_per_1_minute, + "max_images_per_1_minute": max_images_per_1_minute, + "max_requests_per_1_day": max_requests_per_1_day, + "max_requests_per_1_minute": max_requests_per_1_minute, + "max_tokens_per_1_minute": max_tokens_per_1_minute, + }, + rate_limit_update_rate_limit_params.RateLimitUpdateRateLimitParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectRateLimit, + ) + + +class AsyncRateLimits(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncRateLimitsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncRateLimitsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncRateLimitsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncRateLimitsWithStreamingResponse(self) + + def list_rate_limits( + self, + project_id: str, + *, + after: str | Omit = omit, + before: str | Omit = omit, + limit: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[ProjectRateLimit, AsyncConversationCursorPage[ProjectRateLimit]]: + """ + Returns the rate limits per model for a project. + + Args: + after: A cursor for use in pagination. `after` is an object ID that defines your place + in the list. For instance, if you make a list request and receive 100 objects, + ending with obj_foo, your subsequent call can include after=obj_foo in order to + fetch the next page of the list. + + before: A cursor for use in pagination. `before` is an object ID that defines your place + in the list. For instance, if you make a list request and receive 100 objects, + beginning with obj_foo, your subsequent call can include before=obj_foo in order + to fetch the previous page of the list. + + limit: A limit on the number of objects to be returned. The default is 100. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._get_api_list( + path_template("/organization/projects/{project_id}/rate_limits", project_id=project_id), + page=AsyncConversationCursorPage[ProjectRateLimit], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "before": before, + "limit": limit, + }, + rate_limit_list_rate_limits_params.RateLimitListRateLimitsParams, + ), + security={"admin_api_key_auth": True}, + ), + model=ProjectRateLimit, + ) + + async def update_rate_limit( + self, + rate_limit_id: str, + *, + project_id: str, + batch_1_day_max_input_tokens: int | Omit = omit, + max_audio_megabytes_per_1_minute: int | Omit = omit, + max_images_per_1_minute: int | Omit = omit, + max_requests_per_1_day: int | Omit = omit, + max_requests_per_1_minute: int | Omit = omit, + max_tokens_per_1_minute: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectRateLimit: + """ + Updates a project rate limit. + + Args: + batch_1_day_max_input_tokens: The maximum batch input tokens per day. Only relevant for certain models. + + max_audio_megabytes_per_1_minute: The maximum audio megabytes per minute. Only relevant for certain models. + + max_images_per_1_minute: The maximum images per minute. Only relevant for certain models. + + max_requests_per_1_day: The maximum requests per day. Only relevant for certain models. + + max_requests_per_1_minute: The maximum requests per minute. + + max_tokens_per_1_minute: The maximum tokens per minute. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not rate_limit_id: + raise ValueError(f"Expected a non-empty value for `rate_limit_id` but received {rate_limit_id!r}") + return await self._post( + path_template( + "/organization/projects/{project_id}/rate_limits/{rate_limit_id}", + project_id=project_id, + rate_limit_id=rate_limit_id, + ), + body=await async_maybe_transform( + { + "batch_1_day_max_input_tokens": batch_1_day_max_input_tokens, + "max_audio_megabytes_per_1_minute": max_audio_megabytes_per_1_minute, + "max_images_per_1_minute": max_images_per_1_minute, + "max_requests_per_1_day": max_requests_per_1_day, + "max_requests_per_1_minute": max_requests_per_1_minute, + "max_tokens_per_1_minute": max_tokens_per_1_minute, + }, + rate_limit_update_rate_limit_params.RateLimitUpdateRateLimitParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectRateLimit, + ) + + +class RateLimitsWithRawResponse: + def __init__(self, rate_limits: RateLimits) -> None: + self._rate_limits = rate_limits + + self.list_rate_limits = _legacy_response.to_raw_response_wrapper( + rate_limits.list_rate_limits, + ) + self.update_rate_limit = _legacy_response.to_raw_response_wrapper( + rate_limits.update_rate_limit, + ) + + +class AsyncRateLimitsWithRawResponse: + def __init__(self, rate_limits: AsyncRateLimits) -> None: + self._rate_limits = rate_limits + + self.list_rate_limits = _legacy_response.async_to_raw_response_wrapper( + rate_limits.list_rate_limits, + ) + self.update_rate_limit = _legacy_response.async_to_raw_response_wrapper( + rate_limits.update_rate_limit, + ) + + +class RateLimitsWithStreamingResponse: + def __init__(self, rate_limits: RateLimits) -> None: + self._rate_limits = rate_limits + + self.list_rate_limits = to_streamed_response_wrapper( + rate_limits.list_rate_limits, + ) + self.update_rate_limit = to_streamed_response_wrapper( + rate_limits.update_rate_limit, + ) + + +class AsyncRateLimitsWithStreamingResponse: + def __init__(self, rate_limits: AsyncRateLimits) -> None: + self._rate_limits = rate_limits + + self.list_rate_limits = async_to_streamed_response_wrapper( + rate_limits.list_rate_limits, + ) + self.update_rate_limit = async_to_streamed_response_wrapper( + rate_limits.update_rate_limit, + ) diff --git a/src/openai/resources/admin/organization/projects/roles.py b/src/openai/resources/admin/organization/projects/roles.py new file mode 100644 index 0000000000..4242afe052 --- /dev/null +++ b/src/openai/resources/admin/organization/projects/roles.py @@ -0,0 +1,552 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal + +import httpx + +from ..... import _legacy_response +from ....._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ....._utils import path_template, maybe_transform, async_maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from .....pagination import SyncCursorPage, AsyncCursorPage +from ....._base_client import AsyncPaginator, make_request_options +from .....types.admin.organization.role import Role +from .....types.admin.organization.projects import role_list_params, role_create_params, role_update_params +from .....types.admin.organization.projects.role_delete_response import RoleDeleteResponse + +__all__ = ["Roles", "AsyncRoles"] + + +class Roles(SyncAPIResource): + @cached_property + def with_raw_response(self) -> RolesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return RolesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> RolesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return RolesWithStreamingResponse(self) + + def create( + self, + project_id: str, + *, + permissions: SequenceNotStr[str], + role_name: str, + description: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Role: + """ + Creates a custom role for a project. + + Args: + permissions: Permissions to grant to the role. + + role_name: Unique name for the role. + + description: Optional description of the role. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._post( + path_template("/projects/{project_id}/roles", project_id=project_id), + body=maybe_transform( + { + "permissions": permissions, + "role_name": role_name, + "description": description, + }, + role_create_params.RoleCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=Role, + ) + + def update( + self, + role_id: str, + *, + project_id: str, + description: Optional[str] | Omit = omit, + permissions: Optional[SequenceNotStr[str]] | Omit = omit, + role_name: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Role: + """ + Updates an existing project role. + + Args: + description: New description for the role. + + permissions: Updated set of permissions for the role. + + role_name: New name for the role. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not role_id: + raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") + return self._post( + path_template("/projects/{project_id}/roles/{role_id}", project_id=project_id, role_id=role_id), + body=maybe_transform( + { + "description": description, + "permissions": permissions, + "role_name": role_name, + }, + role_update_params.RoleUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=Role, + ) + + def list( + self, + project_id: str, + *, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncCursorPage[Role]: + """Lists the roles configured for a project. + + Args: + after: Cursor for pagination. + + Provide the value from the previous response's `next` + field to continue listing roles. + + limit: A limit on the number of roles to return. Defaults to 1000. + + order: Sort order for the returned roles. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._get_api_list( + path_template("/projects/{project_id}/roles", project_id=project_id), + page=SyncCursorPage[Role], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + role_list_params.RoleListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=Role, + ) + + def delete( + self, + role_id: str, + *, + project_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RoleDeleteResponse: + """ + Deletes a custom role from a project. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not role_id: + raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") + return self._delete( + path_template("/projects/{project_id}/roles/{role_id}", project_id=project_id, role_id=role_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=RoleDeleteResponse, + ) + + +class AsyncRoles(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncRolesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncRolesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncRolesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncRolesWithStreamingResponse(self) + + async def create( + self, + project_id: str, + *, + permissions: SequenceNotStr[str], + role_name: str, + description: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Role: + """ + Creates a custom role for a project. + + Args: + permissions: Permissions to grant to the role. + + role_name: Unique name for the role. + + description: Optional description of the role. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return await self._post( + path_template("/projects/{project_id}/roles", project_id=project_id), + body=await async_maybe_transform( + { + "permissions": permissions, + "role_name": role_name, + "description": description, + }, + role_create_params.RoleCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=Role, + ) + + async def update( + self, + role_id: str, + *, + project_id: str, + description: Optional[str] | Omit = omit, + permissions: Optional[SequenceNotStr[str]] | Omit = omit, + role_name: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Role: + """ + Updates an existing project role. + + Args: + description: New description for the role. + + permissions: Updated set of permissions for the role. + + role_name: New name for the role. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not role_id: + raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") + return await self._post( + path_template("/projects/{project_id}/roles/{role_id}", project_id=project_id, role_id=role_id), + body=await async_maybe_transform( + { + "description": description, + "permissions": permissions, + "role_name": role_name, + }, + role_update_params.RoleUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=Role, + ) + + def list( + self, + project_id: str, + *, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Role, AsyncCursorPage[Role]]: + """Lists the roles configured for a project. + + Args: + after: Cursor for pagination. + + Provide the value from the previous response's `next` + field to continue listing roles. + + limit: A limit on the number of roles to return. Defaults to 1000. + + order: Sort order for the returned roles. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._get_api_list( + path_template("/projects/{project_id}/roles", project_id=project_id), + page=AsyncCursorPage[Role], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + role_list_params.RoleListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=Role, + ) + + async def delete( + self, + role_id: str, + *, + project_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RoleDeleteResponse: + """ + Deletes a custom role from a project. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not role_id: + raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") + return await self._delete( + path_template("/projects/{project_id}/roles/{role_id}", project_id=project_id, role_id=role_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=RoleDeleteResponse, + ) + + +class RolesWithRawResponse: + def __init__(self, roles: Roles) -> None: + self._roles = roles + + self.create = _legacy_response.to_raw_response_wrapper( + roles.create, + ) + self.update = _legacy_response.to_raw_response_wrapper( + roles.update, + ) + self.list = _legacy_response.to_raw_response_wrapper( + roles.list, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + roles.delete, + ) + + +class AsyncRolesWithRawResponse: + def __init__(self, roles: AsyncRoles) -> None: + self._roles = roles + + self.create = _legacy_response.async_to_raw_response_wrapper( + roles.create, + ) + self.update = _legacy_response.async_to_raw_response_wrapper( + roles.update, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + roles.list, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + roles.delete, + ) + + +class RolesWithStreamingResponse: + def __init__(self, roles: Roles) -> None: + self._roles = roles + + self.create = to_streamed_response_wrapper( + roles.create, + ) + self.update = to_streamed_response_wrapper( + roles.update, + ) + self.list = to_streamed_response_wrapper( + roles.list, + ) + self.delete = to_streamed_response_wrapper( + roles.delete, + ) + + +class AsyncRolesWithStreamingResponse: + def __init__(self, roles: AsyncRoles) -> None: + self._roles = roles + + self.create = async_to_streamed_response_wrapper( + roles.create, + ) + self.update = async_to_streamed_response_wrapper( + roles.update, + ) + self.list = async_to_streamed_response_wrapper( + roles.list, + ) + self.delete = async_to_streamed_response_wrapper( + roles.delete, + ) diff --git a/src/openai/resources/admin/organization/projects/service_accounts.py b/src/openai/resources/admin/organization/projects/service_accounts.py new file mode 100644 index 0000000000..9c265fd766 --- /dev/null +++ b/src/openai/resources/admin/organization/projects/service_accounts.py @@ -0,0 +1,512 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..... import _legacy_response +from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ....._utils import path_template, maybe_transform, async_maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from .....pagination import SyncConversationCursorPage, AsyncConversationCursorPage +from ....._base_client import AsyncPaginator, make_request_options +from .....types.admin.organization.projects import service_account_list_params, service_account_create_params +from .....types.admin.organization.projects.project_service_account import ProjectServiceAccount +from .....types.admin.organization.projects.service_account_create_response import ServiceAccountCreateResponse +from .....types.admin.organization.projects.service_account_delete_response import ServiceAccountDeleteResponse + +__all__ = ["ServiceAccounts", "AsyncServiceAccounts"] + + +class ServiceAccounts(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ServiceAccountsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return ServiceAccountsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ServiceAccountsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return ServiceAccountsWithStreamingResponse(self) + + def create( + self, + project_id: str, + *, + name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ServiceAccountCreateResponse: + """Creates a new service account in the project. + + This also returns an unredacted + API key for the service account. + + Args: + name: The name of the service account being created. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._post( + path_template("/organization/projects/{project_id}/service_accounts", project_id=project_id), + body=maybe_transform({"name": name}, service_account_create_params.ServiceAccountCreateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ServiceAccountCreateResponse, + ) + + def retrieve( + self, + service_account_id: str, + *, + project_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectServiceAccount: + """ + Retrieves a service account in the project. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not service_account_id: + raise ValueError(f"Expected a non-empty value for `service_account_id` but received {service_account_id!r}") + return self._get( + path_template( + "/organization/projects/{project_id}/service_accounts/{service_account_id}", + project_id=project_id, + service_account_id=service_account_id, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectServiceAccount, + ) + + def list( + self, + project_id: str, + *, + after: str | Omit = omit, + limit: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncConversationCursorPage[ProjectServiceAccount]: + """ + Returns a list of service accounts in the project. + + Args: + after: A cursor for use in pagination. `after` is an object ID that defines your place + in the list. For instance, if you make a list request and receive 100 objects, + ending with obj_foo, your subsequent call can include after=obj_foo in order to + fetch the next page of the list. + + limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the default is 20. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._get_api_list( + path_template("/organization/projects/{project_id}/service_accounts", project_id=project_id), + page=SyncConversationCursorPage[ProjectServiceAccount], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + }, + service_account_list_params.ServiceAccountListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=ProjectServiceAccount, + ) + + def delete( + self, + service_account_id: str, + *, + project_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ServiceAccountDeleteResponse: + """ + Deletes a service account from the project. + + Returns confirmation of service account deletion, or an error if the project is + archived (archived projects have no service accounts). + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not service_account_id: + raise ValueError(f"Expected a non-empty value for `service_account_id` but received {service_account_id!r}") + return self._delete( + path_template( + "/organization/projects/{project_id}/service_accounts/{service_account_id}", + project_id=project_id, + service_account_id=service_account_id, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ServiceAccountDeleteResponse, + ) + + +class AsyncServiceAccounts(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncServiceAccountsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncServiceAccountsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncServiceAccountsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncServiceAccountsWithStreamingResponse(self) + + async def create( + self, + project_id: str, + *, + name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ServiceAccountCreateResponse: + """Creates a new service account in the project. + + This also returns an unredacted + API key for the service account. + + Args: + name: The name of the service account being created. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return await self._post( + path_template("/organization/projects/{project_id}/service_accounts", project_id=project_id), + body=await async_maybe_transform({"name": name}, service_account_create_params.ServiceAccountCreateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ServiceAccountCreateResponse, + ) + + async def retrieve( + self, + service_account_id: str, + *, + project_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectServiceAccount: + """ + Retrieves a service account in the project. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not service_account_id: + raise ValueError(f"Expected a non-empty value for `service_account_id` but received {service_account_id!r}") + return await self._get( + path_template( + "/organization/projects/{project_id}/service_accounts/{service_account_id}", + project_id=project_id, + service_account_id=service_account_id, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectServiceAccount, + ) + + def list( + self, + project_id: str, + *, + after: str | Omit = omit, + limit: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[ProjectServiceAccount, AsyncConversationCursorPage[ProjectServiceAccount]]: + """ + Returns a list of service accounts in the project. + + Args: + after: A cursor for use in pagination. `after` is an object ID that defines your place + in the list. For instance, if you make a list request and receive 100 objects, + ending with obj_foo, your subsequent call can include after=obj_foo in order to + fetch the next page of the list. + + limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the default is 20. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._get_api_list( + path_template("/organization/projects/{project_id}/service_accounts", project_id=project_id), + page=AsyncConversationCursorPage[ProjectServiceAccount], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + }, + service_account_list_params.ServiceAccountListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=ProjectServiceAccount, + ) + + async def delete( + self, + service_account_id: str, + *, + project_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ServiceAccountDeleteResponse: + """ + Deletes a service account from the project. + + Returns confirmation of service account deletion, or an error if the project is + archived (archived projects have no service accounts). + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not service_account_id: + raise ValueError(f"Expected a non-empty value for `service_account_id` but received {service_account_id!r}") + return await self._delete( + path_template( + "/organization/projects/{project_id}/service_accounts/{service_account_id}", + project_id=project_id, + service_account_id=service_account_id, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ServiceAccountDeleteResponse, + ) + + +class ServiceAccountsWithRawResponse: + def __init__(self, service_accounts: ServiceAccounts) -> None: + self._service_accounts = service_accounts + + self.create = _legacy_response.to_raw_response_wrapper( + service_accounts.create, + ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + service_accounts.retrieve, + ) + self.list = _legacy_response.to_raw_response_wrapper( + service_accounts.list, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + service_accounts.delete, + ) + + +class AsyncServiceAccountsWithRawResponse: + def __init__(self, service_accounts: AsyncServiceAccounts) -> None: + self._service_accounts = service_accounts + + self.create = _legacy_response.async_to_raw_response_wrapper( + service_accounts.create, + ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + service_accounts.retrieve, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + service_accounts.list, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + service_accounts.delete, + ) + + +class ServiceAccountsWithStreamingResponse: + def __init__(self, service_accounts: ServiceAccounts) -> None: + self._service_accounts = service_accounts + + self.create = to_streamed_response_wrapper( + service_accounts.create, + ) + self.retrieve = to_streamed_response_wrapper( + service_accounts.retrieve, + ) + self.list = to_streamed_response_wrapper( + service_accounts.list, + ) + self.delete = to_streamed_response_wrapper( + service_accounts.delete, + ) + + +class AsyncServiceAccountsWithStreamingResponse: + def __init__(self, service_accounts: AsyncServiceAccounts) -> None: + self._service_accounts = service_accounts + + self.create = async_to_streamed_response_wrapper( + service_accounts.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + service_accounts.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + service_accounts.list, + ) + self.delete = async_to_streamed_response_wrapper( + service_accounts.delete, + ) diff --git a/src/openai/resources/admin/organization/projects/users/__init__.py b/src/openai/resources/admin/organization/projects/users/__init__.py new file mode 100644 index 0000000000..d230cb8f34 --- /dev/null +++ b/src/openai/resources/admin/organization/projects/users/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .roles import ( + Roles, + AsyncRoles, + RolesWithRawResponse, + AsyncRolesWithRawResponse, + RolesWithStreamingResponse, + AsyncRolesWithStreamingResponse, +) +from .users import ( + Users, + AsyncUsers, + UsersWithRawResponse, + AsyncUsersWithRawResponse, + UsersWithStreamingResponse, + AsyncUsersWithStreamingResponse, +) + +__all__ = [ + "Roles", + "AsyncRoles", + "RolesWithRawResponse", + "AsyncRolesWithRawResponse", + "RolesWithStreamingResponse", + "AsyncRolesWithStreamingResponse", + "Users", + "AsyncUsers", + "UsersWithRawResponse", + "AsyncUsersWithRawResponse", + "UsersWithStreamingResponse", + "AsyncUsersWithStreamingResponse", +] diff --git a/src/openai/resources/admin/organization/projects/users/roles.py b/src/openai/resources/admin/organization/projects/users/roles.py new file mode 100644 index 0000000000..35cde9b890 --- /dev/null +++ b/src/openai/resources/admin/organization/projects/users/roles.py @@ -0,0 +1,426 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from ...... import _legacy_response +from ......_types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ......_utils import path_template, maybe_transform, async_maybe_transform +from ......_compat import cached_property +from ......_resource import SyncAPIResource, AsyncAPIResource +from ......_response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ......pagination import SyncCursorPage, AsyncCursorPage +from ......_base_client import AsyncPaginator, make_request_options +from ......types.admin.organization.projects.users import role_list_params, role_create_params +from ......types.admin.organization.projects.users.role_list_response import RoleListResponse +from ......types.admin.organization.projects.users.role_create_response import RoleCreateResponse +from ......types.admin.organization.projects.users.role_delete_response import RoleDeleteResponse + +__all__ = ["Roles", "AsyncRoles"] + + +class Roles(SyncAPIResource): + @cached_property + def with_raw_response(self) -> RolesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return RolesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> RolesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return RolesWithStreamingResponse(self) + + def create( + self, + user_id: str, + *, + project_id: str, + role_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RoleCreateResponse: + """ + Assigns a project role to a user within a project. + + Args: + role_id: Identifier of the role to assign. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not user_id: + raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + return self._post( + path_template("/projects/{project_id}/users/{user_id}/roles", project_id=project_id, user_id=user_id), + body=maybe_transform({"role_id": role_id}, role_create_params.RoleCreateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=RoleCreateResponse, + ) + + def list( + self, + user_id: str, + *, + project_id: str, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncCursorPage[RoleListResponse]: + """ + Lists the project roles assigned to a user within a project. + + Args: + after: Cursor for pagination. Provide the value from the previous response's `next` + field to continue listing project roles. + + limit: A limit on the number of project role assignments to return. + + order: Sort order for the returned project roles. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not user_id: + raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + return self._get_api_list( + path_template("/projects/{project_id}/users/{user_id}/roles", project_id=project_id, user_id=user_id), + page=SyncCursorPage[RoleListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + role_list_params.RoleListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=RoleListResponse, + ) + + def delete( + self, + role_id: str, + *, + project_id: str, + user_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RoleDeleteResponse: + """ + Unassigns a project role from a user within a project. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not user_id: + raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + if not role_id: + raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") + return self._delete( + path_template( + "/projects/{project_id}/users/{user_id}/roles/{role_id}", + project_id=project_id, + user_id=user_id, + role_id=role_id, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=RoleDeleteResponse, + ) + + +class AsyncRoles(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncRolesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncRolesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncRolesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncRolesWithStreamingResponse(self) + + async def create( + self, + user_id: str, + *, + project_id: str, + role_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RoleCreateResponse: + """ + Assigns a project role to a user within a project. + + Args: + role_id: Identifier of the role to assign. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not user_id: + raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + return await self._post( + path_template("/projects/{project_id}/users/{user_id}/roles", project_id=project_id, user_id=user_id), + body=await async_maybe_transform({"role_id": role_id}, role_create_params.RoleCreateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=RoleCreateResponse, + ) + + def list( + self, + user_id: str, + *, + project_id: str, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[RoleListResponse, AsyncCursorPage[RoleListResponse]]: + """ + Lists the project roles assigned to a user within a project. + + Args: + after: Cursor for pagination. Provide the value from the previous response's `next` + field to continue listing project roles. + + limit: A limit on the number of project role assignments to return. + + order: Sort order for the returned project roles. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not user_id: + raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + return self._get_api_list( + path_template("/projects/{project_id}/users/{user_id}/roles", project_id=project_id, user_id=user_id), + page=AsyncCursorPage[RoleListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + role_list_params.RoleListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=RoleListResponse, + ) + + async def delete( + self, + role_id: str, + *, + project_id: str, + user_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RoleDeleteResponse: + """ + Unassigns a project role from a user within a project. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not user_id: + raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + if not role_id: + raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") + return await self._delete( + path_template( + "/projects/{project_id}/users/{user_id}/roles/{role_id}", + project_id=project_id, + user_id=user_id, + role_id=role_id, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=RoleDeleteResponse, + ) + + +class RolesWithRawResponse: + def __init__(self, roles: Roles) -> None: + self._roles = roles + + self.create = _legacy_response.to_raw_response_wrapper( + roles.create, + ) + self.list = _legacy_response.to_raw_response_wrapper( + roles.list, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + roles.delete, + ) + + +class AsyncRolesWithRawResponse: + def __init__(self, roles: AsyncRoles) -> None: + self._roles = roles + + self.create = _legacy_response.async_to_raw_response_wrapper( + roles.create, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + roles.list, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + roles.delete, + ) + + +class RolesWithStreamingResponse: + def __init__(self, roles: Roles) -> None: + self._roles = roles + + self.create = to_streamed_response_wrapper( + roles.create, + ) + self.list = to_streamed_response_wrapper( + roles.list, + ) + self.delete = to_streamed_response_wrapper( + roles.delete, + ) + + +class AsyncRolesWithStreamingResponse: + def __init__(self, roles: AsyncRoles) -> None: + self._roles = roles + + self.create = async_to_streamed_response_wrapper( + roles.create, + ) + self.list = async_to_streamed_response_wrapper( + roles.list, + ) + self.delete = async_to_streamed_response_wrapper( + roles.delete, + ) diff --git a/src/openai/resources/admin/organization/projects/users/users.py b/src/openai/resources/admin/organization/projects/users/users.py new file mode 100644 index 0000000000..024fc27043 --- /dev/null +++ b/src/openai/resources/admin/organization/projects/users/users.py @@ -0,0 +1,659 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from ...... import _legacy_response +from .roles import ( + Roles, + AsyncRoles, + RolesWithRawResponse, + AsyncRolesWithRawResponse, + RolesWithStreamingResponse, + AsyncRolesWithStreamingResponse, +) +from ......_types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ......_utils import path_template, maybe_transform, async_maybe_transform +from ......_compat import cached_property +from ......_resource import SyncAPIResource, AsyncAPIResource +from ......_response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ......pagination import SyncConversationCursorPage, AsyncConversationCursorPage +from ......_base_client import AsyncPaginator, make_request_options +from ......types.admin.organization.projects import user_list_params, user_create_params, user_update_params +from ......types.admin.organization.projects.project_user import ProjectUser +from ......types.admin.organization.projects.user_delete_response import UserDeleteResponse + +__all__ = ["Users", "AsyncUsers"] + + +class Users(SyncAPIResource): + @cached_property + def roles(self) -> Roles: + return Roles(self._client) + + @cached_property + def with_raw_response(self) -> UsersWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return UsersWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> UsersWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return UsersWithStreamingResponse(self) + + def create( + self, + project_id: str, + *, + role: Literal["owner", "member"], + user_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectUser: + """Adds a user to the project. + + Users must already be members of the organization to + be added to a project. + + Args: + role: `owner` or `member` + + user_id: The ID of the user. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._post( + path_template("/organization/projects/{project_id}/users", project_id=project_id), + body=maybe_transform( + { + "role": role, + "user_id": user_id, + }, + user_create_params.UserCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectUser, + ) + + def retrieve( + self, + user_id: str, + *, + project_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectUser: + """ + Retrieves a user in the project. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not user_id: + raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + return self._get( + path_template( + "/organization/projects/{project_id}/users/{user_id}", project_id=project_id, user_id=user_id + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectUser, + ) + + def update( + self, + user_id: str, + *, + project_id: str, + role: Literal["owner", "member"], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectUser: + """ + Modifies a user's role in the project. + + Args: + role: `owner` or `member` + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not user_id: + raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + return self._post( + path_template( + "/organization/projects/{project_id}/users/{user_id}", project_id=project_id, user_id=user_id + ), + body=maybe_transform({"role": role}, user_update_params.UserUpdateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectUser, + ) + + def list( + self, + project_id: str, + *, + after: str | Omit = omit, + limit: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncConversationCursorPage[ProjectUser]: + """ + Returns a list of users in the project. + + Args: + after: A cursor for use in pagination. `after` is an object ID that defines your place + in the list. For instance, if you make a list request and receive 100 objects, + ending with obj_foo, your subsequent call can include after=obj_foo in order to + fetch the next page of the list. + + limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the default is 20. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._get_api_list( + path_template("/organization/projects/{project_id}/users", project_id=project_id), + page=SyncConversationCursorPage[ProjectUser], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + }, + user_list_params.UserListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=ProjectUser, + ) + + def delete( + self, + user_id: str, + *, + project_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UserDeleteResponse: + """ + Deletes a user from the project. + + Returns confirmation of project user deletion, or an error if the project is + archived (archived projects have no users). + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not user_id: + raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + return self._delete( + path_template( + "/organization/projects/{project_id}/users/{user_id}", project_id=project_id, user_id=user_id + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=UserDeleteResponse, + ) + + +class AsyncUsers(AsyncAPIResource): + @cached_property + def roles(self) -> AsyncRoles: + return AsyncRoles(self._client) + + @cached_property + def with_raw_response(self) -> AsyncUsersWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncUsersWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncUsersWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncUsersWithStreamingResponse(self) + + async def create( + self, + project_id: str, + *, + role: Literal["owner", "member"], + user_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectUser: + """Adds a user to the project. + + Users must already be members of the organization to + be added to a project. + + Args: + role: `owner` or `member` + + user_id: The ID of the user. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return await self._post( + path_template("/organization/projects/{project_id}/users", project_id=project_id), + body=await async_maybe_transform( + { + "role": role, + "user_id": user_id, + }, + user_create_params.UserCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectUser, + ) + + async def retrieve( + self, + user_id: str, + *, + project_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectUser: + """ + Retrieves a user in the project. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not user_id: + raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + return await self._get( + path_template( + "/organization/projects/{project_id}/users/{user_id}", project_id=project_id, user_id=user_id + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectUser, + ) + + async def update( + self, + user_id: str, + *, + project_id: str, + role: Literal["owner", "member"], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectUser: + """ + Modifies a user's role in the project. + + Args: + role: `owner` or `member` + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not user_id: + raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + return await self._post( + path_template( + "/organization/projects/{project_id}/users/{user_id}", project_id=project_id, user_id=user_id + ), + body=await async_maybe_transform({"role": role}, user_update_params.UserUpdateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectUser, + ) + + def list( + self, + project_id: str, + *, + after: str | Omit = omit, + limit: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[ProjectUser, AsyncConversationCursorPage[ProjectUser]]: + """ + Returns a list of users in the project. + + Args: + after: A cursor for use in pagination. `after` is an object ID that defines your place + in the list. For instance, if you make a list request and receive 100 objects, + ending with obj_foo, your subsequent call can include after=obj_foo in order to + fetch the next page of the list. + + limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the default is 20. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._get_api_list( + path_template("/organization/projects/{project_id}/users", project_id=project_id), + page=AsyncConversationCursorPage[ProjectUser], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + }, + user_list_params.UserListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=ProjectUser, + ) + + async def delete( + self, + user_id: str, + *, + project_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UserDeleteResponse: + """ + Deletes a user from the project. + + Returns confirmation of project user deletion, or an error if the project is + archived (archived projects have no users). + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not user_id: + raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + return await self._delete( + path_template( + "/organization/projects/{project_id}/users/{user_id}", project_id=project_id, user_id=user_id + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=UserDeleteResponse, + ) + + +class UsersWithRawResponse: + def __init__(self, users: Users) -> None: + self._users = users + + self.create = _legacy_response.to_raw_response_wrapper( + users.create, + ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + users.retrieve, + ) + self.update = _legacy_response.to_raw_response_wrapper( + users.update, + ) + self.list = _legacy_response.to_raw_response_wrapper( + users.list, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + users.delete, + ) + + @cached_property + def roles(self) -> RolesWithRawResponse: + return RolesWithRawResponse(self._users.roles) + + +class AsyncUsersWithRawResponse: + def __init__(self, users: AsyncUsers) -> None: + self._users = users + + self.create = _legacy_response.async_to_raw_response_wrapper( + users.create, + ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + users.retrieve, + ) + self.update = _legacy_response.async_to_raw_response_wrapper( + users.update, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + users.list, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + users.delete, + ) + + @cached_property + def roles(self) -> AsyncRolesWithRawResponse: + return AsyncRolesWithRawResponse(self._users.roles) + + +class UsersWithStreamingResponse: + def __init__(self, users: Users) -> None: + self._users = users + + self.create = to_streamed_response_wrapper( + users.create, + ) + self.retrieve = to_streamed_response_wrapper( + users.retrieve, + ) + self.update = to_streamed_response_wrapper( + users.update, + ) + self.list = to_streamed_response_wrapper( + users.list, + ) + self.delete = to_streamed_response_wrapper( + users.delete, + ) + + @cached_property + def roles(self) -> RolesWithStreamingResponse: + return RolesWithStreamingResponse(self._users.roles) + + +class AsyncUsersWithStreamingResponse: + def __init__(self, users: AsyncUsers) -> None: + self._users = users + + self.create = async_to_streamed_response_wrapper( + users.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + users.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + users.update, + ) + self.list = async_to_streamed_response_wrapper( + users.list, + ) + self.delete = async_to_streamed_response_wrapper( + users.delete, + ) + + @cached_property + def roles(self) -> AsyncRolesWithStreamingResponse: + return AsyncRolesWithStreamingResponse(self._users.roles) diff --git a/src/openai/resources/admin/organization/roles.py b/src/openai/resources/admin/organization/roles.py new file mode 100644 index 0000000000..3bfb35fd73 --- /dev/null +++ b/src/openai/resources/admin/organization/roles.py @@ -0,0 +1,526 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal + +import httpx + +from .... import _legacy_response +from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ...._utils import path_template, maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ....pagination import SyncCursorPage, AsyncCursorPage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.admin.organization import role_list_params, role_create_params, role_update_params +from ....types.admin.organization.role import Role +from ....types.admin.organization.role_delete_response import RoleDeleteResponse + +__all__ = ["Roles", "AsyncRoles"] + + +class Roles(SyncAPIResource): + @cached_property + def with_raw_response(self) -> RolesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return RolesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> RolesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return RolesWithStreamingResponse(self) + + def create( + self, + *, + permissions: SequenceNotStr[str], + role_name: str, + description: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Role: + """ + Creates a custom role for the organization. + + Args: + permissions: Permissions to grant to the role. + + role_name: Unique name for the role. + + description: Optional description of the role. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/organization/roles", + body=maybe_transform( + { + "permissions": permissions, + "role_name": role_name, + "description": description, + }, + role_create_params.RoleCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=Role, + ) + + def update( + self, + role_id: str, + *, + description: Optional[str] | Omit = omit, + permissions: Optional[SequenceNotStr[str]] | Omit = omit, + role_name: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Role: + """ + Updates an existing organization role. + + Args: + description: New description for the role. + + permissions: Updated set of permissions for the role. + + role_name: New name for the role. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not role_id: + raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") + return self._post( + path_template("/organization/roles/{role_id}", role_id=role_id), + body=maybe_transform( + { + "description": description, + "permissions": permissions, + "role_name": role_name, + }, + role_update_params.RoleUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=Role, + ) + + def list( + self, + *, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncCursorPage[Role]: + """ + Lists the roles configured for the organization. + + Args: + after: Cursor for pagination. Provide the value from the previous response's `next` + field to continue listing roles. + + limit: A limit on the number of roles to return. Defaults to 1000. + + order: Sort order for the returned roles. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/organization/roles", + page=SyncCursorPage[Role], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + role_list_params.RoleListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=Role, + ) + + def delete( + self, + role_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RoleDeleteResponse: + """ + Deletes a custom role from the organization. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not role_id: + raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") + return self._delete( + path_template("/organization/roles/{role_id}", role_id=role_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=RoleDeleteResponse, + ) + + +class AsyncRoles(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncRolesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncRolesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncRolesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncRolesWithStreamingResponse(self) + + async def create( + self, + *, + permissions: SequenceNotStr[str], + role_name: str, + description: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Role: + """ + Creates a custom role for the organization. + + Args: + permissions: Permissions to grant to the role. + + role_name: Unique name for the role. + + description: Optional description of the role. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/organization/roles", + body=await async_maybe_transform( + { + "permissions": permissions, + "role_name": role_name, + "description": description, + }, + role_create_params.RoleCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=Role, + ) + + async def update( + self, + role_id: str, + *, + description: Optional[str] | Omit = omit, + permissions: Optional[SequenceNotStr[str]] | Omit = omit, + role_name: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Role: + """ + Updates an existing organization role. + + Args: + description: New description for the role. + + permissions: Updated set of permissions for the role. + + role_name: New name for the role. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not role_id: + raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") + return await self._post( + path_template("/organization/roles/{role_id}", role_id=role_id), + body=await async_maybe_transform( + { + "description": description, + "permissions": permissions, + "role_name": role_name, + }, + role_update_params.RoleUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=Role, + ) + + def list( + self, + *, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Role, AsyncCursorPage[Role]]: + """ + Lists the roles configured for the organization. + + Args: + after: Cursor for pagination. Provide the value from the previous response's `next` + field to continue listing roles. + + limit: A limit on the number of roles to return. Defaults to 1000. + + order: Sort order for the returned roles. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/organization/roles", + page=AsyncCursorPage[Role], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + role_list_params.RoleListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=Role, + ) + + async def delete( + self, + role_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RoleDeleteResponse: + """ + Deletes a custom role from the organization. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not role_id: + raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") + return await self._delete( + path_template("/organization/roles/{role_id}", role_id=role_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=RoleDeleteResponse, + ) + + +class RolesWithRawResponse: + def __init__(self, roles: Roles) -> None: + self._roles = roles + + self.create = _legacy_response.to_raw_response_wrapper( + roles.create, + ) + self.update = _legacy_response.to_raw_response_wrapper( + roles.update, + ) + self.list = _legacy_response.to_raw_response_wrapper( + roles.list, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + roles.delete, + ) + + +class AsyncRolesWithRawResponse: + def __init__(self, roles: AsyncRoles) -> None: + self._roles = roles + + self.create = _legacy_response.async_to_raw_response_wrapper( + roles.create, + ) + self.update = _legacy_response.async_to_raw_response_wrapper( + roles.update, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + roles.list, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + roles.delete, + ) + + +class RolesWithStreamingResponse: + def __init__(self, roles: Roles) -> None: + self._roles = roles + + self.create = to_streamed_response_wrapper( + roles.create, + ) + self.update = to_streamed_response_wrapper( + roles.update, + ) + self.list = to_streamed_response_wrapper( + roles.list, + ) + self.delete = to_streamed_response_wrapper( + roles.delete, + ) + + +class AsyncRolesWithStreamingResponse: + def __init__(self, roles: AsyncRoles) -> None: + self._roles = roles + + self.create = async_to_streamed_response_wrapper( + roles.create, + ) + self.update = async_to_streamed_response_wrapper( + roles.update, + ) + self.list = async_to_streamed_response_wrapper( + roles.list, + ) + self.delete = async_to_streamed_response_wrapper( + roles.delete, + ) diff --git a/src/openai/resources/admin/organization/usage.py b/src/openai/resources/admin/organization/usage.py new file mode 100644 index 0000000000..2725d5e884 --- /dev/null +++ b/src/openai/resources/admin/organization/usage.py @@ -0,0 +1,1724 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Literal + +import httpx + +from .... import _legacy_response +from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ...._base_client import make_request_options +from ....types.admin.organization import ( + usage_costs_params, + usage_images_params, + usage_embeddings_params, + usage_completions_params, + usage_moderations_params, + usage_vector_stores_params, + usage_audio_speeches_params, + usage_audio_transcriptions_params, + usage_code_interpreter_sessions_params, +) +from ....types.admin.organization.usage_costs_response import UsageCostsResponse +from ....types.admin.organization.usage_images_response import UsageImagesResponse +from ....types.admin.organization.usage_embeddings_response import UsageEmbeddingsResponse +from ....types.admin.organization.usage_completions_response import UsageCompletionsResponse +from ....types.admin.organization.usage_moderations_response import UsageModerationsResponse +from ....types.admin.organization.usage_vector_stores_response import UsageVectorStoresResponse +from ....types.admin.organization.usage_audio_speeches_response import UsageAudioSpeechesResponse +from ....types.admin.organization.usage_audio_transcriptions_response import UsageAudioTranscriptionsResponse +from ....types.admin.organization.usage_code_interpreter_sessions_response import UsageCodeInterpreterSessionsResponse + +__all__ = ["Usage", "AsyncUsage"] + + +class Usage(SyncAPIResource): + @cached_property + def with_raw_response(self) -> UsageWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return UsageWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> UsageWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return UsageWithStreamingResponse(self) + + def audio_speeches( + self, + *, + start_time: int, + api_key_ids: SequenceNotStr[str] | Omit = omit, + bucket_width: Literal["1m", "1h", "1d"] | Omit = omit, + end_time: int | Omit = omit, + group_by: List[Literal["project_id", "user_id", "api_key_id", "model"]] | Omit = omit, + limit: int | Omit = omit, + models: SequenceNotStr[str] | Omit = omit, + page: str | Omit = omit, + project_ids: SequenceNotStr[str] | Omit = omit, + user_ids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UsageAudioSpeechesResponse: + """ + Get audio speeches usage details for the organization. + + Args: + start_time: Start time (Unix seconds) of the query time range, inclusive. + + api_key_ids: Return only usage for these API keys. + + bucket_width: Width of each time bucket in response. Currently `1m`, `1h` and `1d` are + supported, default to `1d`. + + end_time: End time (Unix seconds) of the query time range, exclusive. + + group_by: Group the usage data by the specified fields. Support fields include + `project_id`, `user_id`, `api_key_id`, `model` or any combination of them. + + limit: Specifies the number of buckets to return. + + - `bucket_width=1d`: default: 7, max: 31 + - `bucket_width=1h`: default: 24, max: 168 + - `bucket_width=1m`: default: 60, max: 1440 + + models: Return only usage for these models. + + page: A cursor for use in pagination. Corresponding to the `next_page` field from the + previous response. + + project_ids: Return only usage for these projects. + + user_ids: Return only usage for these users. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/organization/usage/audio_speeches", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "start_time": start_time, + "api_key_ids": api_key_ids, + "bucket_width": bucket_width, + "end_time": end_time, + "group_by": group_by, + "limit": limit, + "models": models, + "page": page, + "project_ids": project_ids, + "user_ids": user_ids, + }, + usage_audio_speeches_params.UsageAudioSpeechesParams, + ), + security={"admin_api_key_auth": True}, + ), + cast_to=UsageAudioSpeechesResponse, + ) + + def audio_transcriptions( + self, + *, + start_time: int, + api_key_ids: SequenceNotStr[str] | Omit = omit, + bucket_width: Literal["1m", "1h", "1d"] | Omit = omit, + end_time: int | Omit = omit, + group_by: List[Literal["project_id", "user_id", "api_key_id", "model"]] | Omit = omit, + limit: int | Omit = omit, + models: SequenceNotStr[str] | Omit = omit, + page: str | Omit = omit, + project_ids: SequenceNotStr[str] | Omit = omit, + user_ids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UsageAudioTranscriptionsResponse: + """ + Get audio transcriptions usage details for the organization. + + Args: + start_time: Start time (Unix seconds) of the query time range, inclusive. + + api_key_ids: Return only usage for these API keys. + + bucket_width: Width of each time bucket in response. Currently `1m`, `1h` and `1d` are + supported, default to `1d`. + + end_time: End time (Unix seconds) of the query time range, exclusive. + + group_by: Group the usage data by the specified fields. Support fields include + `project_id`, `user_id`, `api_key_id`, `model` or any combination of them. + + limit: Specifies the number of buckets to return. + + - `bucket_width=1d`: default: 7, max: 31 + - `bucket_width=1h`: default: 24, max: 168 + - `bucket_width=1m`: default: 60, max: 1440 + + models: Return only usage for these models. + + page: A cursor for use in pagination. Corresponding to the `next_page` field from the + previous response. + + project_ids: Return only usage for these projects. + + user_ids: Return only usage for these users. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/organization/usage/audio_transcriptions", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "start_time": start_time, + "api_key_ids": api_key_ids, + "bucket_width": bucket_width, + "end_time": end_time, + "group_by": group_by, + "limit": limit, + "models": models, + "page": page, + "project_ids": project_ids, + "user_ids": user_ids, + }, + usage_audio_transcriptions_params.UsageAudioTranscriptionsParams, + ), + security={"admin_api_key_auth": True}, + ), + cast_to=UsageAudioTranscriptionsResponse, + ) + + def code_interpreter_sessions( + self, + *, + start_time: int, + bucket_width: Literal["1m", "1h", "1d"] | Omit = omit, + end_time: int | Omit = omit, + group_by: List[Literal["project_id"]] | Omit = omit, + limit: int | Omit = omit, + page: str | Omit = omit, + project_ids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UsageCodeInterpreterSessionsResponse: + """ + Get code interpreter sessions usage details for the organization. + + Args: + start_time: Start time (Unix seconds) of the query time range, inclusive. + + bucket_width: Width of each time bucket in response. Currently `1m`, `1h` and `1d` are + supported, default to `1d`. + + end_time: End time (Unix seconds) of the query time range, exclusive. + + group_by: Group the usage data by the specified fields. Support fields include + `project_id`. + + limit: Specifies the number of buckets to return. + + - `bucket_width=1d`: default: 7, max: 31 + - `bucket_width=1h`: default: 24, max: 168 + - `bucket_width=1m`: default: 60, max: 1440 + + page: A cursor for use in pagination. Corresponding to the `next_page` field from the + previous response. + + project_ids: Return only usage for these projects. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/organization/usage/code_interpreter_sessions", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "start_time": start_time, + "bucket_width": bucket_width, + "end_time": end_time, + "group_by": group_by, + "limit": limit, + "page": page, + "project_ids": project_ids, + }, + usage_code_interpreter_sessions_params.UsageCodeInterpreterSessionsParams, + ), + security={"admin_api_key_auth": True}, + ), + cast_to=UsageCodeInterpreterSessionsResponse, + ) + + def completions( + self, + *, + start_time: int, + api_key_ids: SequenceNotStr[str] | Omit = omit, + batch: bool | Omit = omit, + bucket_width: Literal["1m", "1h", "1d"] | Omit = omit, + end_time: int | Omit = omit, + group_by: List[Literal["project_id", "user_id", "api_key_id", "model", "batch", "service_tier"]] | Omit = omit, + limit: int | Omit = omit, + models: SequenceNotStr[str] | Omit = omit, + page: str | Omit = omit, + project_ids: SequenceNotStr[str] | Omit = omit, + user_ids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UsageCompletionsResponse: + """ + Get completions usage details for the organization. + + Args: + start_time: Start time (Unix seconds) of the query time range, inclusive. + + api_key_ids: Return only usage for these API keys. + + batch: If `true`, return batch jobs only. If `false`, return non-batch jobs only. By + default, return both. + + bucket_width: Width of each time bucket in response. Currently `1m`, `1h` and `1d` are + supported, default to `1d`. + + end_time: End time (Unix seconds) of the query time range, exclusive. + + group_by: Group the usage data by the specified fields. Support fields include + `project_id`, `user_id`, `api_key_id`, `model`, `batch`, `service_tier` or any + combination of them. + + limit: Specifies the number of buckets to return. + + - `bucket_width=1d`: default: 7, max: 31 + - `bucket_width=1h`: default: 24, max: 168 + - `bucket_width=1m`: default: 60, max: 1440 + + models: Return only usage for these models. + + page: A cursor for use in pagination. Corresponding to the `next_page` field from the + previous response. + + project_ids: Return only usage for these projects. + + user_ids: Return only usage for these users. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/organization/usage/completions", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "start_time": start_time, + "api_key_ids": api_key_ids, + "batch": batch, + "bucket_width": bucket_width, + "end_time": end_time, + "group_by": group_by, + "limit": limit, + "models": models, + "page": page, + "project_ids": project_ids, + "user_ids": user_ids, + }, + usage_completions_params.UsageCompletionsParams, + ), + security={"admin_api_key_auth": True}, + ), + cast_to=UsageCompletionsResponse, + ) + + def costs( + self, + *, + start_time: int, + api_key_ids: SequenceNotStr[str] | Omit = omit, + bucket_width: Literal["1d"] | Omit = omit, + end_time: int | Omit = omit, + group_by: List[Literal["project_id", "line_item", "api_key_id"]] | Omit = omit, + limit: int | Omit = omit, + page: str | Omit = omit, + project_ids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UsageCostsResponse: + """ + Get costs details for the organization. + + Args: + start_time: Start time (Unix seconds) of the query time range, inclusive. + + api_key_ids: Return only costs for these API keys. + + bucket_width: Width of each time bucket in response. Currently only `1d` is supported, default + to `1d`. + + end_time: End time (Unix seconds) of the query time range, exclusive. + + group_by: Group the costs by the specified fields. Support fields include `project_id`, + `line_item`, `api_key_id` and any combination of them. + + limit: A limit on the number of buckets to be returned. Limit can range between 1 and + 180, and the default is 7. + + page: A cursor for use in pagination. Corresponding to the `next_page` field from the + previous response. + + project_ids: Return only costs for these projects. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/organization/costs", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "start_time": start_time, + "api_key_ids": api_key_ids, + "bucket_width": bucket_width, + "end_time": end_time, + "group_by": group_by, + "limit": limit, + "page": page, + "project_ids": project_ids, + }, + usage_costs_params.UsageCostsParams, + ), + security={"admin_api_key_auth": True}, + ), + cast_to=UsageCostsResponse, + ) + + def embeddings( + self, + *, + start_time: int, + api_key_ids: SequenceNotStr[str] | Omit = omit, + bucket_width: Literal["1m", "1h", "1d"] | Omit = omit, + end_time: int | Omit = omit, + group_by: List[Literal["project_id", "user_id", "api_key_id", "model"]] | Omit = omit, + limit: int | Omit = omit, + models: SequenceNotStr[str] | Omit = omit, + page: str | Omit = omit, + project_ids: SequenceNotStr[str] | Omit = omit, + user_ids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UsageEmbeddingsResponse: + """ + Get embeddings usage details for the organization. + + Args: + start_time: Start time (Unix seconds) of the query time range, inclusive. + + api_key_ids: Return only usage for these API keys. + + bucket_width: Width of each time bucket in response. Currently `1m`, `1h` and `1d` are + supported, default to `1d`. + + end_time: End time (Unix seconds) of the query time range, exclusive. + + group_by: Group the usage data by the specified fields. Support fields include + `project_id`, `user_id`, `api_key_id`, `model` or any combination of them. + + limit: Specifies the number of buckets to return. + + - `bucket_width=1d`: default: 7, max: 31 + - `bucket_width=1h`: default: 24, max: 168 + - `bucket_width=1m`: default: 60, max: 1440 + + models: Return only usage for these models. + + page: A cursor for use in pagination. Corresponding to the `next_page` field from the + previous response. + + project_ids: Return only usage for these projects. + + user_ids: Return only usage for these users. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/organization/usage/embeddings", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "start_time": start_time, + "api_key_ids": api_key_ids, + "bucket_width": bucket_width, + "end_time": end_time, + "group_by": group_by, + "limit": limit, + "models": models, + "page": page, + "project_ids": project_ids, + "user_ids": user_ids, + }, + usage_embeddings_params.UsageEmbeddingsParams, + ), + security={"admin_api_key_auth": True}, + ), + cast_to=UsageEmbeddingsResponse, + ) + + def images( + self, + *, + start_time: int, + api_key_ids: SequenceNotStr[str] | Omit = omit, + bucket_width: Literal["1m", "1h", "1d"] | Omit = omit, + end_time: int | Omit = omit, + group_by: List[Literal["project_id", "user_id", "api_key_id", "model", "size", "source"]] | Omit = omit, + limit: int | Omit = omit, + models: SequenceNotStr[str] | Omit = omit, + page: str | Omit = omit, + project_ids: SequenceNotStr[str] | Omit = omit, + sizes: List[Literal["256x256", "512x512", "1024x1024", "1792x1792", "1024x1792"]] | Omit = omit, + sources: List[Literal["image.generation", "image.edit", "image.variation"]] | Omit = omit, + user_ids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UsageImagesResponse: + """ + Get images usage details for the organization. + + Args: + start_time: Start time (Unix seconds) of the query time range, inclusive. + + api_key_ids: Return only usage for these API keys. + + bucket_width: Width of each time bucket in response. Currently `1m`, `1h` and `1d` are + supported, default to `1d`. + + end_time: End time (Unix seconds) of the query time range, exclusive. + + group_by: Group the usage data by the specified fields. Support fields include + `project_id`, `user_id`, `api_key_id`, `model`, `size`, `source` or any + combination of them. + + limit: Specifies the number of buckets to return. + + - `bucket_width=1d`: default: 7, max: 31 + - `bucket_width=1h`: default: 24, max: 168 + - `bucket_width=1m`: default: 60, max: 1440 + + models: Return only usage for these models. + + page: A cursor for use in pagination. Corresponding to the `next_page` field from the + previous response. + + project_ids: Return only usage for these projects. + + sizes: Return only usages for these image sizes. Possible values are `256x256`, + `512x512`, `1024x1024`, `1792x1792`, `1024x1792` or any combination of them. + + sources: Return only usages for these sources. Possible values are `image.generation`, + `image.edit`, `image.variation` or any combination of them. + + user_ids: Return only usage for these users. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/organization/usage/images", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "start_time": start_time, + "api_key_ids": api_key_ids, + "bucket_width": bucket_width, + "end_time": end_time, + "group_by": group_by, + "limit": limit, + "models": models, + "page": page, + "project_ids": project_ids, + "sizes": sizes, + "sources": sources, + "user_ids": user_ids, + }, + usage_images_params.UsageImagesParams, + ), + security={"admin_api_key_auth": True}, + ), + cast_to=UsageImagesResponse, + ) + + def moderations( + self, + *, + start_time: int, + api_key_ids: SequenceNotStr[str] | Omit = omit, + bucket_width: Literal["1m", "1h", "1d"] | Omit = omit, + end_time: int | Omit = omit, + group_by: List[Literal["project_id", "user_id", "api_key_id", "model"]] | Omit = omit, + limit: int | Omit = omit, + models: SequenceNotStr[str] | Omit = omit, + page: str | Omit = omit, + project_ids: SequenceNotStr[str] | Omit = omit, + user_ids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UsageModerationsResponse: + """ + Get moderations usage details for the organization. + + Args: + start_time: Start time (Unix seconds) of the query time range, inclusive. + + api_key_ids: Return only usage for these API keys. + + bucket_width: Width of each time bucket in response. Currently `1m`, `1h` and `1d` are + supported, default to `1d`. + + end_time: End time (Unix seconds) of the query time range, exclusive. + + group_by: Group the usage data by the specified fields. Support fields include + `project_id`, `user_id`, `api_key_id`, `model` or any combination of them. + + limit: Specifies the number of buckets to return. + + - `bucket_width=1d`: default: 7, max: 31 + - `bucket_width=1h`: default: 24, max: 168 + - `bucket_width=1m`: default: 60, max: 1440 + + models: Return only usage for these models. + + page: A cursor for use in pagination. Corresponding to the `next_page` field from the + previous response. + + project_ids: Return only usage for these projects. + + user_ids: Return only usage for these users. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/organization/usage/moderations", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "start_time": start_time, + "api_key_ids": api_key_ids, + "bucket_width": bucket_width, + "end_time": end_time, + "group_by": group_by, + "limit": limit, + "models": models, + "page": page, + "project_ids": project_ids, + "user_ids": user_ids, + }, + usage_moderations_params.UsageModerationsParams, + ), + security={"admin_api_key_auth": True}, + ), + cast_to=UsageModerationsResponse, + ) + + def vector_stores( + self, + *, + start_time: int, + bucket_width: Literal["1m", "1h", "1d"] | Omit = omit, + end_time: int | Omit = omit, + group_by: List[Literal["project_id"]] | Omit = omit, + limit: int | Omit = omit, + page: str | Omit = omit, + project_ids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UsageVectorStoresResponse: + """ + Get vector stores usage details for the organization. + + Args: + start_time: Start time (Unix seconds) of the query time range, inclusive. + + bucket_width: Width of each time bucket in response. Currently `1m`, `1h` and `1d` are + supported, default to `1d`. + + end_time: End time (Unix seconds) of the query time range, exclusive. + + group_by: Group the usage data by the specified fields. Support fields include + `project_id`. + + limit: Specifies the number of buckets to return. + + - `bucket_width=1d`: default: 7, max: 31 + - `bucket_width=1h`: default: 24, max: 168 + - `bucket_width=1m`: default: 60, max: 1440 + + page: A cursor for use in pagination. Corresponding to the `next_page` field from the + previous response. + + project_ids: Return only usage for these projects. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/organization/usage/vector_stores", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "start_time": start_time, + "bucket_width": bucket_width, + "end_time": end_time, + "group_by": group_by, + "limit": limit, + "page": page, + "project_ids": project_ids, + }, + usage_vector_stores_params.UsageVectorStoresParams, + ), + security={"admin_api_key_auth": True}, + ), + cast_to=UsageVectorStoresResponse, + ) + + +class AsyncUsage(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncUsageWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncUsageWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncUsageWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncUsageWithStreamingResponse(self) + + async def audio_speeches( + self, + *, + start_time: int, + api_key_ids: SequenceNotStr[str] | Omit = omit, + bucket_width: Literal["1m", "1h", "1d"] | Omit = omit, + end_time: int | Omit = omit, + group_by: List[Literal["project_id", "user_id", "api_key_id", "model"]] | Omit = omit, + limit: int | Omit = omit, + models: SequenceNotStr[str] | Omit = omit, + page: str | Omit = omit, + project_ids: SequenceNotStr[str] | Omit = omit, + user_ids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UsageAudioSpeechesResponse: + """ + Get audio speeches usage details for the organization. + + Args: + start_time: Start time (Unix seconds) of the query time range, inclusive. + + api_key_ids: Return only usage for these API keys. + + bucket_width: Width of each time bucket in response. Currently `1m`, `1h` and `1d` are + supported, default to `1d`. + + end_time: End time (Unix seconds) of the query time range, exclusive. + + group_by: Group the usage data by the specified fields. Support fields include + `project_id`, `user_id`, `api_key_id`, `model` or any combination of them. + + limit: Specifies the number of buckets to return. + + - `bucket_width=1d`: default: 7, max: 31 + - `bucket_width=1h`: default: 24, max: 168 + - `bucket_width=1m`: default: 60, max: 1440 + + models: Return only usage for these models. + + page: A cursor for use in pagination. Corresponding to the `next_page` field from the + previous response. + + project_ids: Return only usage for these projects. + + user_ids: Return only usage for these users. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/organization/usage/audio_speeches", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "start_time": start_time, + "api_key_ids": api_key_ids, + "bucket_width": bucket_width, + "end_time": end_time, + "group_by": group_by, + "limit": limit, + "models": models, + "page": page, + "project_ids": project_ids, + "user_ids": user_ids, + }, + usage_audio_speeches_params.UsageAudioSpeechesParams, + ), + security={"admin_api_key_auth": True}, + ), + cast_to=UsageAudioSpeechesResponse, + ) + + async def audio_transcriptions( + self, + *, + start_time: int, + api_key_ids: SequenceNotStr[str] | Omit = omit, + bucket_width: Literal["1m", "1h", "1d"] | Omit = omit, + end_time: int | Omit = omit, + group_by: List[Literal["project_id", "user_id", "api_key_id", "model"]] | Omit = omit, + limit: int | Omit = omit, + models: SequenceNotStr[str] | Omit = omit, + page: str | Omit = omit, + project_ids: SequenceNotStr[str] | Omit = omit, + user_ids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UsageAudioTranscriptionsResponse: + """ + Get audio transcriptions usage details for the organization. + + Args: + start_time: Start time (Unix seconds) of the query time range, inclusive. + + api_key_ids: Return only usage for these API keys. + + bucket_width: Width of each time bucket in response. Currently `1m`, `1h` and `1d` are + supported, default to `1d`. + + end_time: End time (Unix seconds) of the query time range, exclusive. + + group_by: Group the usage data by the specified fields. Support fields include + `project_id`, `user_id`, `api_key_id`, `model` or any combination of them. + + limit: Specifies the number of buckets to return. + + - `bucket_width=1d`: default: 7, max: 31 + - `bucket_width=1h`: default: 24, max: 168 + - `bucket_width=1m`: default: 60, max: 1440 + + models: Return only usage for these models. + + page: A cursor for use in pagination. Corresponding to the `next_page` field from the + previous response. + + project_ids: Return only usage for these projects. + + user_ids: Return only usage for these users. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/organization/usage/audio_transcriptions", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "start_time": start_time, + "api_key_ids": api_key_ids, + "bucket_width": bucket_width, + "end_time": end_time, + "group_by": group_by, + "limit": limit, + "models": models, + "page": page, + "project_ids": project_ids, + "user_ids": user_ids, + }, + usage_audio_transcriptions_params.UsageAudioTranscriptionsParams, + ), + security={"admin_api_key_auth": True}, + ), + cast_to=UsageAudioTranscriptionsResponse, + ) + + async def code_interpreter_sessions( + self, + *, + start_time: int, + bucket_width: Literal["1m", "1h", "1d"] | Omit = omit, + end_time: int | Omit = omit, + group_by: List[Literal["project_id"]] | Omit = omit, + limit: int | Omit = omit, + page: str | Omit = omit, + project_ids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UsageCodeInterpreterSessionsResponse: + """ + Get code interpreter sessions usage details for the organization. + + Args: + start_time: Start time (Unix seconds) of the query time range, inclusive. + + bucket_width: Width of each time bucket in response. Currently `1m`, `1h` and `1d` are + supported, default to `1d`. + + end_time: End time (Unix seconds) of the query time range, exclusive. + + group_by: Group the usage data by the specified fields. Support fields include + `project_id`. + + limit: Specifies the number of buckets to return. + + - `bucket_width=1d`: default: 7, max: 31 + - `bucket_width=1h`: default: 24, max: 168 + - `bucket_width=1m`: default: 60, max: 1440 + + page: A cursor for use in pagination. Corresponding to the `next_page` field from the + previous response. + + project_ids: Return only usage for these projects. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/organization/usage/code_interpreter_sessions", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "start_time": start_time, + "bucket_width": bucket_width, + "end_time": end_time, + "group_by": group_by, + "limit": limit, + "page": page, + "project_ids": project_ids, + }, + usage_code_interpreter_sessions_params.UsageCodeInterpreterSessionsParams, + ), + security={"admin_api_key_auth": True}, + ), + cast_to=UsageCodeInterpreterSessionsResponse, + ) + + async def completions( + self, + *, + start_time: int, + api_key_ids: SequenceNotStr[str] | Omit = omit, + batch: bool | Omit = omit, + bucket_width: Literal["1m", "1h", "1d"] | Omit = omit, + end_time: int | Omit = omit, + group_by: List[Literal["project_id", "user_id", "api_key_id", "model", "batch", "service_tier"]] | Omit = omit, + limit: int | Omit = omit, + models: SequenceNotStr[str] | Omit = omit, + page: str | Omit = omit, + project_ids: SequenceNotStr[str] | Omit = omit, + user_ids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UsageCompletionsResponse: + """ + Get completions usage details for the organization. + + Args: + start_time: Start time (Unix seconds) of the query time range, inclusive. + + api_key_ids: Return only usage for these API keys. + + batch: If `true`, return batch jobs only. If `false`, return non-batch jobs only. By + default, return both. + + bucket_width: Width of each time bucket in response. Currently `1m`, `1h` and `1d` are + supported, default to `1d`. + + end_time: End time (Unix seconds) of the query time range, exclusive. + + group_by: Group the usage data by the specified fields. Support fields include + `project_id`, `user_id`, `api_key_id`, `model`, `batch`, `service_tier` or any + combination of them. + + limit: Specifies the number of buckets to return. + + - `bucket_width=1d`: default: 7, max: 31 + - `bucket_width=1h`: default: 24, max: 168 + - `bucket_width=1m`: default: 60, max: 1440 + + models: Return only usage for these models. + + page: A cursor for use in pagination. Corresponding to the `next_page` field from the + previous response. + + project_ids: Return only usage for these projects. + + user_ids: Return only usage for these users. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/organization/usage/completions", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "start_time": start_time, + "api_key_ids": api_key_ids, + "batch": batch, + "bucket_width": bucket_width, + "end_time": end_time, + "group_by": group_by, + "limit": limit, + "models": models, + "page": page, + "project_ids": project_ids, + "user_ids": user_ids, + }, + usage_completions_params.UsageCompletionsParams, + ), + security={"admin_api_key_auth": True}, + ), + cast_to=UsageCompletionsResponse, + ) + + async def costs( + self, + *, + start_time: int, + api_key_ids: SequenceNotStr[str] | Omit = omit, + bucket_width: Literal["1d"] | Omit = omit, + end_time: int | Omit = omit, + group_by: List[Literal["project_id", "line_item", "api_key_id"]] | Omit = omit, + limit: int | Omit = omit, + page: str | Omit = omit, + project_ids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UsageCostsResponse: + """ + Get costs details for the organization. + + Args: + start_time: Start time (Unix seconds) of the query time range, inclusive. + + api_key_ids: Return only costs for these API keys. + + bucket_width: Width of each time bucket in response. Currently only `1d` is supported, default + to `1d`. + + end_time: End time (Unix seconds) of the query time range, exclusive. + + group_by: Group the costs by the specified fields. Support fields include `project_id`, + `line_item`, `api_key_id` and any combination of them. + + limit: A limit on the number of buckets to be returned. Limit can range between 1 and + 180, and the default is 7. + + page: A cursor for use in pagination. Corresponding to the `next_page` field from the + previous response. + + project_ids: Return only costs for these projects. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/organization/costs", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "start_time": start_time, + "api_key_ids": api_key_ids, + "bucket_width": bucket_width, + "end_time": end_time, + "group_by": group_by, + "limit": limit, + "page": page, + "project_ids": project_ids, + }, + usage_costs_params.UsageCostsParams, + ), + security={"admin_api_key_auth": True}, + ), + cast_to=UsageCostsResponse, + ) + + async def embeddings( + self, + *, + start_time: int, + api_key_ids: SequenceNotStr[str] | Omit = omit, + bucket_width: Literal["1m", "1h", "1d"] | Omit = omit, + end_time: int | Omit = omit, + group_by: List[Literal["project_id", "user_id", "api_key_id", "model"]] | Omit = omit, + limit: int | Omit = omit, + models: SequenceNotStr[str] | Omit = omit, + page: str | Omit = omit, + project_ids: SequenceNotStr[str] | Omit = omit, + user_ids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UsageEmbeddingsResponse: + """ + Get embeddings usage details for the organization. + + Args: + start_time: Start time (Unix seconds) of the query time range, inclusive. + + api_key_ids: Return only usage for these API keys. + + bucket_width: Width of each time bucket in response. Currently `1m`, `1h` and `1d` are + supported, default to `1d`. + + end_time: End time (Unix seconds) of the query time range, exclusive. + + group_by: Group the usage data by the specified fields. Support fields include + `project_id`, `user_id`, `api_key_id`, `model` or any combination of them. + + limit: Specifies the number of buckets to return. + + - `bucket_width=1d`: default: 7, max: 31 + - `bucket_width=1h`: default: 24, max: 168 + - `bucket_width=1m`: default: 60, max: 1440 + + models: Return only usage for these models. + + page: A cursor for use in pagination. Corresponding to the `next_page` field from the + previous response. + + project_ids: Return only usage for these projects. + + user_ids: Return only usage for these users. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/organization/usage/embeddings", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "start_time": start_time, + "api_key_ids": api_key_ids, + "bucket_width": bucket_width, + "end_time": end_time, + "group_by": group_by, + "limit": limit, + "models": models, + "page": page, + "project_ids": project_ids, + "user_ids": user_ids, + }, + usage_embeddings_params.UsageEmbeddingsParams, + ), + security={"admin_api_key_auth": True}, + ), + cast_to=UsageEmbeddingsResponse, + ) + + async def images( + self, + *, + start_time: int, + api_key_ids: SequenceNotStr[str] | Omit = omit, + bucket_width: Literal["1m", "1h", "1d"] | Omit = omit, + end_time: int | Omit = omit, + group_by: List[Literal["project_id", "user_id", "api_key_id", "model", "size", "source"]] | Omit = omit, + limit: int | Omit = omit, + models: SequenceNotStr[str] | Omit = omit, + page: str | Omit = omit, + project_ids: SequenceNotStr[str] | Omit = omit, + sizes: List[Literal["256x256", "512x512", "1024x1024", "1792x1792", "1024x1792"]] | Omit = omit, + sources: List[Literal["image.generation", "image.edit", "image.variation"]] | Omit = omit, + user_ids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UsageImagesResponse: + """ + Get images usage details for the organization. + + Args: + start_time: Start time (Unix seconds) of the query time range, inclusive. + + api_key_ids: Return only usage for these API keys. + + bucket_width: Width of each time bucket in response. Currently `1m`, `1h` and `1d` are + supported, default to `1d`. + + end_time: End time (Unix seconds) of the query time range, exclusive. + + group_by: Group the usage data by the specified fields. Support fields include + `project_id`, `user_id`, `api_key_id`, `model`, `size`, `source` or any + combination of them. + + limit: Specifies the number of buckets to return. + + - `bucket_width=1d`: default: 7, max: 31 + - `bucket_width=1h`: default: 24, max: 168 + - `bucket_width=1m`: default: 60, max: 1440 + + models: Return only usage for these models. + + page: A cursor for use in pagination. Corresponding to the `next_page` field from the + previous response. + + project_ids: Return only usage for these projects. + + sizes: Return only usages for these image sizes. Possible values are `256x256`, + `512x512`, `1024x1024`, `1792x1792`, `1024x1792` or any combination of them. + + sources: Return only usages for these sources. Possible values are `image.generation`, + `image.edit`, `image.variation` or any combination of them. + + user_ids: Return only usage for these users. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/organization/usage/images", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "start_time": start_time, + "api_key_ids": api_key_ids, + "bucket_width": bucket_width, + "end_time": end_time, + "group_by": group_by, + "limit": limit, + "models": models, + "page": page, + "project_ids": project_ids, + "sizes": sizes, + "sources": sources, + "user_ids": user_ids, + }, + usage_images_params.UsageImagesParams, + ), + security={"admin_api_key_auth": True}, + ), + cast_to=UsageImagesResponse, + ) + + async def moderations( + self, + *, + start_time: int, + api_key_ids: SequenceNotStr[str] | Omit = omit, + bucket_width: Literal["1m", "1h", "1d"] | Omit = omit, + end_time: int | Omit = omit, + group_by: List[Literal["project_id", "user_id", "api_key_id", "model"]] | Omit = omit, + limit: int | Omit = omit, + models: SequenceNotStr[str] | Omit = omit, + page: str | Omit = omit, + project_ids: SequenceNotStr[str] | Omit = omit, + user_ids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UsageModerationsResponse: + """ + Get moderations usage details for the organization. + + Args: + start_time: Start time (Unix seconds) of the query time range, inclusive. + + api_key_ids: Return only usage for these API keys. + + bucket_width: Width of each time bucket in response. Currently `1m`, `1h` and `1d` are + supported, default to `1d`. + + end_time: End time (Unix seconds) of the query time range, exclusive. + + group_by: Group the usage data by the specified fields. Support fields include + `project_id`, `user_id`, `api_key_id`, `model` or any combination of them. + + limit: Specifies the number of buckets to return. + + - `bucket_width=1d`: default: 7, max: 31 + - `bucket_width=1h`: default: 24, max: 168 + - `bucket_width=1m`: default: 60, max: 1440 + + models: Return only usage for these models. + + page: A cursor for use in pagination. Corresponding to the `next_page` field from the + previous response. + + project_ids: Return only usage for these projects. + + user_ids: Return only usage for these users. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/organization/usage/moderations", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "start_time": start_time, + "api_key_ids": api_key_ids, + "bucket_width": bucket_width, + "end_time": end_time, + "group_by": group_by, + "limit": limit, + "models": models, + "page": page, + "project_ids": project_ids, + "user_ids": user_ids, + }, + usage_moderations_params.UsageModerationsParams, + ), + security={"admin_api_key_auth": True}, + ), + cast_to=UsageModerationsResponse, + ) + + async def vector_stores( + self, + *, + start_time: int, + bucket_width: Literal["1m", "1h", "1d"] | Omit = omit, + end_time: int | Omit = omit, + group_by: List[Literal["project_id"]] | Omit = omit, + limit: int | Omit = omit, + page: str | Omit = omit, + project_ids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UsageVectorStoresResponse: + """ + Get vector stores usage details for the organization. + + Args: + start_time: Start time (Unix seconds) of the query time range, inclusive. + + bucket_width: Width of each time bucket in response. Currently `1m`, `1h` and `1d` are + supported, default to `1d`. + + end_time: End time (Unix seconds) of the query time range, exclusive. + + group_by: Group the usage data by the specified fields. Support fields include + `project_id`. + + limit: Specifies the number of buckets to return. + + - `bucket_width=1d`: default: 7, max: 31 + - `bucket_width=1h`: default: 24, max: 168 + - `bucket_width=1m`: default: 60, max: 1440 + + page: A cursor for use in pagination. Corresponding to the `next_page` field from the + previous response. + + project_ids: Return only usage for these projects. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/organization/usage/vector_stores", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "start_time": start_time, + "bucket_width": bucket_width, + "end_time": end_time, + "group_by": group_by, + "limit": limit, + "page": page, + "project_ids": project_ids, + }, + usage_vector_stores_params.UsageVectorStoresParams, + ), + security={"admin_api_key_auth": True}, + ), + cast_to=UsageVectorStoresResponse, + ) + + +class UsageWithRawResponse: + def __init__(self, usage: Usage) -> None: + self._usage = usage + + self.audio_speeches = _legacy_response.to_raw_response_wrapper( + usage.audio_speeches, + ) + self.audio_transcriptions = _legacy_response.to_raw_response_wrapper( + usage.audio_transcriptions, + ) + self.code_interpreter_sessions = _legacy_response.to_raw_response_wrapper( + usage.code_interpreter_sessions, + ) + self.completions = _legacy_response.to_raw_response_wrapper( + usage.completions, + ) + self.costs = _legacy_response.to_raw_response_wrapper( + usage.costs, + ) + self.embeddings = _legacy_response.to_raw_response_wrapper( + usage.embeddings, + ) + self.images = _legacy_response.to_raw_response_wrapper( + usage.images, + ) + self.moderations = _legacy_response.to_raw_response_wrapper( + usage.moderations, + ) + self.vector_stores = _legacy_response.to_raw_response_wrapper( + usage.vector_stores, + ) + + +class AsyncUsageWithRawResponse: + def __init__(self, usage: AsyncUsage) -> None: + self._usage = usage + + self.audio_speeches = _legacy_response.async_to_raw_response_wrapper( + usage.audio_speeches, + ) + self.audio_transcriptions = _legacy_response.async_to_raw_response_wrapper( + usage.audio_transcriptions, + ) + self.code_interpreter_sessions = _legacy_response.async_to_raw_response_wrapper( + usage.code_interpreter_sessions, + ) + self.completions = _legacy_response.async_to_raw_response_wrapper( + usage.completions, + ) + self.costs = _legacy_response.async_to_raw_response_wrapper( + usage.costs, + ) + self.embeddings = _legacy_response.async_to_raw_response_wrapper( + usage.embeddings, + ) + self.images = _legacy_response.async_to_raw_response_wrapper( + usage.images, + ) + self.moderations = _legacy_response.async_to_raw_response_wrapper( + usage.moderations, + ) + self.vector_stores = _legacy_response.async_to_raw_response_wrapper( + usage.vector_stores, + ) + + +class UsageWithStreamingResponse: + def __init__(self, usage: Usage) -> None: + self._usage = usage + + self.audio_speeches = to_streamed_response_wrapper( + usage.audio_speeches, + ) + self.audio_transcriptions = to_streamed_response_wrapper( + usage.audio_transcriptions, + ) + self.code_interpreter_sessions = to_streamed_response_wrapper( + usage.code_interpreter_sessions, + ) + self.completions = to_streamed_response_wrapper( + usage.completions, + ) + self.costs = to_streamed_response_wrapper( + usage.costs, + ) + self.embeddings = to_streamed_response_wrapper( + usage.embeddings, + ) + self.images = to_streamed_response_wrapper( + usage.images, + ) + self.moderations = to_streamed_response_wrapper( + usage.moderations, + ) + self.vector_stores = to_streamed_response_wrapper( + usage.vector_stores, + ) + + +class AsyncUsageWithStreamingResponse: + def __init__(self, usage: AsyncUsage) -> None: + self._usage = usage + + self.audio_speeches = async_to_streamed_response_wrapper( + usage.audio_speeches, + ) + self.audio_transcriptions = async_to_streamed_response_wrapper( + usage.audio_transcriptions, + ) + self.code_interpreter_sessions = async_to_streamed_response_wrapper( + usage.code_interpreter_sessions, + ) + self.completions = async_to_streamed_response_wrapper( + usage.completions, + ) + self.costs = async_to_streamed_response_wrapper( + usage.costs, + ) + self.embeddings = async_to_streamed_response_wrapper( + usage.embeddings, + ) + self.images = async_to_streamed_response_wrapper( + usage.images, + ) + self.moderations = async_to_streamed_response_wrapper( + usage.moderations, + ) + self.vector_stores = async_to_streamed_response_wrapper( + usage.vector_stores, + ) diff --git a/src/openai/resources/admin/organization/users/__init__.py b/src/openai/resources/admin/organization/users/__init__.py new file mode 100644 index 0000000000..d230cb8f34 --- /dev/null +++ b/src/openai/resources/admin/organization/users/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .roles import ( + Roles, + AsyncRoles, + RolesWithRawResponse, + AsyncRolesWithRawResponse, + RolesWithStreamingResponse, + AsyncRolesWithStreamingResponse, +) +from .users import ( + Users, + AsyncUsers, + UsersWithRawResponse, + AsyncUsersWithRawResponse, + UsersWithStreamingResponse, + AsyncUsersWithStreamingResponse, +) + +__all__ = [ + "Roles", + "AsyncRoles", + "RolesWithRawResponse", + "AsyncRolesWithRawResponse", + "RolesWithStreamingResponse", + "AsyncRolesWithStreamingResponse", + "Users", + "AsyncUsers", + "UsersWithRawResponse", + "AsyncUsersWithRawResponse", + "UsersWithStreamingResponse", + "AsyncUsersWithStreamingResponse", +] diff --git a/src/openai/resources/admin/organization/users/roles.py b/src/openai/resources/admin/organization/users/roles.py new file mode 100644 index 0000000000..4338d1ae1d --- /dev/null +++ b/src/openai/resources/admin/organization/users/roles.py @@ -0,0 +1,398 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from ..... import _legacy_response +from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ....._utils import path_template, maybe_transform, async_maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from .....pagination import SyncCursorPage, AsyncCursorPage +from ....._base_client import AsyncPaginator, make_request_options +from .....types.admin.organization.users import role_list_params, role_create_params +from .....types.admin.organization.users.role_list_response import RoleListResponse +from .....types.admin.organization.users.role_create_response import RoleCreateResponse +from .....types.admin.organization.users.role_delete_response import RoleDeleteResponse + +__all__ = ["Roles", "AsyncRoles"] + + +class Roles(SyncAPIResource): + @cached_property + def with_raw_response(self) -> RolesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return RolesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> RolesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return RolesWithStreamingResponse(self) + + def create( + self, + user_id: str, + *, + role_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RoleCreateResponse: + """ + Assigns an organization role to a user within the organization. + + Args: + role_id: Identifier of the role to assign. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not user_id: + raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + return self._post( + path_template("/organization/users/{user_id}/roles", user_id=user_id), + body=maybe_transform({"role_id": role_id}, role_create_params.RoleCreateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=RoleCreateResponse, + ) + + def list( + self, + user_id: str, + *, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncCursorPage[RoleListResponse]: + """ + Lists the organization roles assigned to a user within the organization. + + Args: + after: Cursor for pagination. Provide the value from the previous response's `next` + field to continue listing organization roles. + + limit: A limit on the number of organization role assignments to return. + + order: Sort order for the returned organization roles. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not user_id: + raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + return self._get_api_list( + path_template("/organization/users/{user_id}/roles", user_id=user_id), + page=SyncCursorPage[RoleListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + role_list_params.RoleListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=RoleListResponse, + ) + + def delete( + self, + role_id: str, + *, + user_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RoleDeleteResponse: + """ + Unassigns an organization role from a user within the organization. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not user_id: + raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + if not role_id: + raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") + return self._delete( + path_template("/organization/users/{user_id}/roles/{role_id}", user_id=user_id, role_id=role_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=RoleDeleteResponse, + ) + + +class AsyncRoles(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncRolesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncRolesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncRolesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncRolesWithStreamingResponse(self) + + async def create( + self, + user_id: str, + *, + role_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RoleCreateResponse: + """ + Assigns an organization role to a user within the organization. + + Args: + role_id: Identifier of the role to assign. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not user_id: + raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + return await self._post( + path_template("/organization/users/{user_id}/roles", user_id=user_id), + body=await async_maybe_transform({"role_id": role_id}, role_create_params.RoleCreateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=RoleCreateResponse, + ) + + def list( + self, + user_id: str, + *, + after: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[RoleListResponse, AsyncCursorPage[RoleListResponse]]: + """ + Lists the organization roles assigned to a user within the organization. + + Args: + after: Cursor for pagination. Provide the value from the previous response's `next` + field to continue listing organization roles. + + limit: A limit on the number of organization role assignments to return. + + order: Sort order for the returned organization roles. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not user_id: + raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + return self._get_api_list( + path_template("/organization/users/{user_id}/roles", user_id=user_id), + page=AsyncCursorPage[RoleListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "order": order, + }, + role_list_params.RoleListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=RoleListResponse, + ) + + async def delete( + self, + role_id: str, + *, + user_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RoleDeleteResponse: + """ + Unassigns an organization role from a user within the organization. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not user_id: + raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + if not role_id: + raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") + return await self._delete( + path_template("/organization/users/{user_id}/roles/{role_id}", user_id=user_id, role_id=role_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=RoleDeleteResponse, + ) + + +class RolesWithRawResponse: + def __init__(self, roles: Roles) -> None: + self._roles = roles + + self.create = _legacy_response.to_raw_response_wrapper( + roles.create, + ) + self.list = _legacy_response.to_raw_response_wrapper( + roles.list, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + roles.delete, + ) + + +class AsyncRolesWithRawResponse: + def __init__(self, roles: AsyncRoles) -> None: + self._roles = roles + + self.create = _legacy_response.async_to_raw_response_wrapper( + roles.create, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + roles.list, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + roles.delete, + ) + + +class RolesWithStreamingResponse: + def __init__(self, roles: Roles) -> None: + self._roles = roles + + self.create = to_streamed_response_wrapper( + roles.create, + ) + self.list = to_streamed_response_wrapper( + roles.list, + ) + self.delete = to_streamed_response_wrapper( + roles.delete, + ) + + +class AsyncRolesWithStreamingResponse: + def __init__(self, roles: AsyncRoles) -> None: + self._roles = roles + + self.create = async_to_streamed_response_wrapper( + roles.create, + ) + self.list = async_to_streamed_response_wrapper( + roles.list, + ) + self.delete = async_to_streamed_response_wrapper( + roles.delete, + ) diff --git a/src/openai/resources/admin/organization/users/users.py b/src/openai/resources/admin/organization/users/users.py new file mode 100644 index 0000000000..bfab2c5ecd --- /dev/null +++ b/src/openai/resources/admin/organization/users/users.py @@ -0,0 +1,509 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from ..... import _legacy_response +from .roles import ( + Roles, + AsyncRoles, + RolesWithRawResponse, + AsyncRolesWithRawResponse, + RolesWithStreamingResponse, + AsyncRolesWithStreamingResponse, +) +from ....._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ....._utils import path_template, maybe_transform, async_maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from .....pagination import SyncConversationCursorPage, AsyncConversationCursorPage +from ....._base_client import AsyncPaginator, make_request_options +from .....types.admin.organization import user_list_params, user_update_params +from .....types.admin.organization.organization_user import OrganizationUser +from .....types.admin.organization.user_delete_response import UserDeleteResponse + +__all__ = ["Users", "AsyncUsers"] + + +class Users(SyncAPIResource): + @cached_property + def roles(self) -> Roles: + return Roles(self._client) + + @cached_property + def with_raw_response(self) -> UsersWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return UsersWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> UsersWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return UsersWithStreamingResponse(self) + + def retrieve( + self, + user_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OrganizationUser: + """ + Retrieves a user by their identifier. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not user_id: + raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + return self._get( + path_template("/organization/users/{user_id}", user_id=user_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=OrganizationUser, + ) + + def update( + self, + user_id: str, + *, + role: Literal["owner", "reader"], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OrganizationUser: + """ + Modifies a user's role in the organization. + + Args: + role: `owner` or `reader` + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not user_id: + raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + return self._post( + path_template("/organization/users/{user_id}", user_id=user_id), + body=maybe_transform({"role": role}, user_update_params.UserUpdateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=OrganizationUser, + ) + + def list( + self, + *, + after: str | Omit = omit, + emails: SequenceNotStr[str] | Omit = omit, + limit: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncConversationCursorPage[OrganizationUser]: + """ + Lists all of the users in the organization. + + Args: + after: A cursor for use in pagination. `after` is an object ID that defines your place + in the list. For instance, if you make a list request and receive 100 objects, + ending with obj_foo, your subsequent call can include after=obj_foo in order to + fetch the next page of the list. + + emails: Filter by the email address of users. + + limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the default is 20. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/organization/users", + page=SyncConversationCursorPage[OrganizationUser], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "emails": emails, + "limit": limit, + }, + user_list_params.UserListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=OrganizationUser, + ) + + def delete( + self, + user_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UserDeleteResponse: + """ + Deletes a user from the organization. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not user_id: + raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + return self._delete( + path_template("/organization/users/{user_id}", user_id=user_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=UserDeleteResponse, + ) + + +class AsyncUsers(AsyncAPIResource): + @cached_property + def roles(self) -> AsyncRoles: + return AsyncRoles(self._client) + + @cached_property + def with_raw_response(self) -> AsyncUsersWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncUsersWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncUsersWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncUsersWithStreamingResponse(self) + + async def retrieve( + self, + user_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OrganizationUser: + """ + Retrieves a user by their identifier. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not user_id: + raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + return await self._get( + path_template("/organization/users/{user_id}", user_id=user_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=OrganizationUser, + ) + + async def update( + self, + user_id: str, + *, + role: Literal["owner", "reader"], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OrganizationUser: + """ + Modifies a user's role in the organization. + + Args: + role: `owner` or `reader` + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not user_id: + raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + return await self._post( + path_template("/organization/users/{user_id}", user_id=user_id), + body=await async_maybe_transform({"role": role}, user_update_params.UserUpdateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=OrganizationUser, + ) + + def list( + self, + *, + after: str | Omit = omit, + emails: SequenceNotStr[str] | Omit = omit, + limit: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[OrganizationUser, AsyncConversationCursorPage[OrganizationUser]]: + """ + Lists all of the users in the organization. + + Args: + after: A cursor for use in pagination. `after` is an object ID that defines your place + in the list. For instance, if you make a list request and receive 100 objects, + ending with obj_foo, your subsequent call can include after=obj_foo in order to + fetch the next page of the list. + + emails: Filter by the email address of users. + + limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the default is 20. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/organization/users", + page=AsyncConversationCursorPage[OrganizationUser], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "emails": emails, + "limit": limit, + }, + user_list_params.UserListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=OrganizationUser, + ) + + async def delete( + self, + user_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UserDeleteResponse: + """ + Deletes a user from the organization. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not user_id: + raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + return await self._delete( + path_template("/organization/users/{user_id}", user_id=user_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=UserDeleteResponse, + ) + + +class UsersWithRawResponse: + def __init__(self, users: Users) -> None: + self._users = users + + self.retrieve = _legacy_response.to_raw_response_wrapper( + users.retrieve, + ) + self.update = _legacy_response.to_raw_response_wrapper( + users.update, + ) + self.list = _legacy_response.to_raw_response_wrapper( + users.list, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + users.delete, + ) + + @cached_property + def roles(self) -> RolesWithRawResponse: + return RolesWithRawResponse(self._users.roles) + + +class AsyncUsersWithRawResponse: + def __init__(self, users: AsyncUsers) -> None: + self._users = users + + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + users.retrieve, + ) + self.update = _legacy_response.async_to_raw_response_wrapper( + users.update, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + users.list, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + users.delete, + ) + + @cached_property + def roles(self) -> AsyncRolesWithRawResponse: + return AsyncRolesWithRawResponse(self._users.roles) + + +class UsersWithStreamingResponse: + def __init__(self, users: Users) -> None: + self._users = users + + self.retrieve = to_streamed_response_wrapper( + users.retrieve, + ) + self.update = to_streamed_response_wrapper( + users.update, + ) + self.list = to_streamed_response_wrapper( + users.list, + ) + self.delete = to_streamed_response_wrapper( + users.delete, + ) + + @cached_property + def roles(self) -> RolesWithStreamingResponse: + return RolesWithStreamingResponse(self._users.roles) + + +class AsyncUsersWithStreamingResponse: + def __init__(self, users: AsyncUsers) -> None: + self._users = users + + self.retrieve = async_to_streamed_response_wrapper( + users.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + users.update, + ) + self.list = async_to_streamed_response_wrapper( + users.list, + ) + self.delete = async_to_streamed_response_wrapper( + users.delete, + ) + + @cached_property + def roles(self) -> AsyncRolesWithStreamingResponse: + return AsyncRolesWithStreamingResponse(self._users.roles) diff --git a/src/openai/types/admin/organization/__init__.py b/src/openai/types/admin/organization/__init__.py index c402a94c9d..3fbd5cf1ac 100644 --- a/src/openai/types/admin/organization/__init__.py +++ b/src/openai/types/admin/organization/__init__.py @@ -2,5 +2,62 @@ from __future__ import annotations +from .role import Role as Role +from .group import Group as Group +from .invite import Invite as Invite +from .project import Project as Project +from .certificate import Certificate as Certificate +from .admin_api_key import AdminAPIKey as AdminAPIKey +from .role_list_params import RoleListParams as RoleListParams +from .user_list_params import UserListParams as UserListParams +from .group_list_params import GroupListParams as GroupListParams +from .organization_user import OrganizationUser as OrganizationUser +from .invite_list_params import InviteListParams as InviteListParams +from .role_create_params import RoleCreateParams as RoleCreateParams +from .role_update_params import RoleUpdateParams as RoleUpdateParams +from .usage_costs_params import UsageCostsParams as UsageCostsParams +from .user_update_params import UserUpdateParams as UserUpdateParams +from .group_create_params import GroupCreateParams as GroupCreateParams +from .group_update_params import GroupUpdateParams as GroupUpdateParams +from .project_list_params import ProjectListParams as ProjectListParams +from .usage_images_params import UsageImagesParams as UsageImagesParams +from .invite_create_params import InviteCreateParams as InviteCreateParams +from .role_delete_response import RoleDeleteResponse as RoleDeleteResponse +from .usage_costs_response import UsageCostsResponse as UsageCostsResponse +from .user_delete_response import UserDeleteResponse as UserDeleteResponse from .audit_log_list_params import AuditLogListParams as AuditLogListParams +from .group_delete_response import GroupDeleteResponse as GroupDeleteResponse +from .group_update_response import GroupUpdateResponse as GroupUpdateResponse +from .project_create_params import ProjectCreateParams as ProjectCreateParams +from .project_update_params import ProjectUpdateParams as ProjectUpdateParams +from .usage_images_response import UsageImagesResponse as UsageImagesResponse +from .invite_delete_response import InviteDeleteResponse as InviteDeleteResponse from .audit_log_list_response import AuditLogListResponse as AuditLogListResponse +from .certificate_list_params import CertificateListParams as CertificateListParams +from .usage_embeddings_params import UsageEmbeddingsParams as UsageEmbeddingsParams +from .usage_completions_params import UsageCompletionsParams as UsageCompletionsParams +from .usage_moderations_params import UsageModerationsParams as UsageModerationsParams +from .admin_api_key_list_params import AdminAPIKeyListParams as AdminAPIKeyListParams +from .certificate_create_params import CertificateCreateParams as CertificateCreateParams +from .certificate_update_params import CertificateUpdateParams as CertificateUpdateParams +from .usage_embeddings_response import UsageEmbeddingsResponse as UsageEmbeddingsResponse +from .usage_completions_response import UsageCompletionsResponse as UsageCompletionsResponse +from .usage_moderations_response import UsageModerationsResponse as UsageModerationsResponse +from .usage_vector_stores_params import UsageVectorStoresParams as UsageVectorStoresParams +from .admin_api_key_create_params import AdminAPIKeyCreateParams as AdminAPIKeyCreateParams +from .certificate_activate_params import CertificateActivateParams as CertificateActivateParams +from .certificate_delete_response import CertificateDeleteResponse as CertificateDeleteResponse +from .certificate_retrieve_params import CertificateRetrieveParams as CertificateRetrieveParams +from .usage_audio_speeches_params import UsageAudioSpeechesParams as UsageAudioSpeechesParams +from .usage_vector_stores_response import UsageVectorStoresResponse as UsageVectorStoresResponse +from .admin_api_key_delete_response import AdminAPIKeyDeleteResponse as AdminAPIKeyDeleteResponse +from .certificate_deactivate_params import CertificateDeactivateParams as CertificateDeactivateParams +from .usage_audio_speeches_response import UsageAudioSpeechesResponse as UsageAudioSpeechesResponse +from .usage_audio_transcriptions_params import UsageAudioTranscriptionsParams as UsageAudioTranscriptionsParams +from .usage_audio_transcriptions_response import UsageAudioTranscriptionsResponse as UsageAudioTranscriptionsResponse +from .usage_code_interpreter_sessions_params import ( + UsageCodeInterpreterSessionsParams as UsageCodeInterpreterSessionsParams, +) +from .usage_code_interpreter_sessions_response import ( + UsageCodeInterpreterSessionsResponse as UsageCodeInterpreterSessionsResponse, +) diff --git a/src/openai/types/admin/organization/admin_api_key.py b/src/openai/types/admin/organization/admin_api_key.py new file mode 100644 index 0000000000..576d591d95 --- /dev/null +++ b/src/openai/types/admin/organization/admin_api_key.py @@ -0,0 +1,54 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ...._models import BaseModel + +__all__ = ["AdminAPIKey", "Owner"] + + +class Owner(BaseModel): + id: Optional[str] = None + """The identifier, which can be referenced in API endpoints""" + + created_at: Optional[int] = None + """The Unix timestamp (in seconds) of when the user was created""" + + name: Optional[str] = None + """The name of the user""" + + object: Optional[str] = None + """The object type, which is always organization.user""" + + role: Optional[str] = None + """Always `owner`""" + + type: Optional[str] = None + """Always `user`""" + + +class AdminAPIKey(BaseModel): + """Represents an individual Admin API key in an org.""" + + id: str + """The identifier, which can be referenced in API endpoints""" + + created_at: int + """The Unix timestamp (in seconds) of when the API key was created""" + + last_used_at: Optional[int] = None + """The Unix timestamp (in seconds) of when the API key was last used""" + + name: str + """The name of the API key""" + + object: str + """The object type, which is always `organization.admin_api_key`""" + + owner: Owner + + redacted_value: str + """The redacted value of the API key""" + + value: Optional[str] = None + """The value of the API key. Only shown on create.""" diff --git a/src/openai/types/admin/organization/admin_api_key_create_params.py b/src/openai/types/admin/organization/admin_api_key_create_params.py new file mode 100644 index 0000000000..dccdfb8a75 --- /dev/null +++ b/src/openai/types/admin/organization/admin_api_key_create_params.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["AdminAPIKeyCreateParams"] + + +class AdminAPIKeyCreateParams(TypedDict, total=False): + name: Required[str] diff --git a/src/openai/types/admin/organization/admin_api_key_delete_response.py b/src/openai/types/admin/organization/admin_api_key_delete_response.py new file mode 100644 index 0000000000..7b4dab86a1 --- /dev/null +++ b/src/openai/types/admin/organization/admin_api_key_delete_response.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ...._models import BaseModel + +__all__ = ["AdminAPIKeyDeleteResponse"] + + +class AdminAPIKeyDeleteResponse(BaseModel): + id: Optional[str] = None + + deleted: Optional[bool] = None + + object: Optional[str] = None diff --git a/src/openai/types/admin/organization/admin_api_key_list_params.py b/src/openai/types/admin/organization/admin_api_key_list_params.py new file mode 100644 index 0000000000..c3b3f51008 --- /dev/null +++ b/src/openai/types/admin/organization/admin_api_key_list_params.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, TypedDict + +__all__ = ["AdminAPIKeyListParams"] + + +class AdminAPIKeyListParams(TypedDict, total=False): + after: Optional[str] + """Return keys with IDs that come after this ID in the pagination order.""" + + limit: int + """Maximum number of keys to return.""" + + order: Literal["asc", "desc"] + """Order results by creation time, ascending or descending.""" diff --git a/src/openai/types/admin/organization/certificate.py b/src/openai/types/admin/organization/certificate.py new file mode 100644 index 0000000000..93347d816b --- /dev/null +++ b/src/openai/types/admin/organization/certificate.py @@ -0,0 +1,51 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["Certificate", "CertificateDetails"] + + +class CertificateDetails(BaseModel): + content: Optional[str] = None + """The content of the certificate in PEM format.""" + + expires_at: Optional[int] = None + """The Unix timestamp (in seconds) of when the certificate expires.""" + + valid_at: Optional[int] = None + """The Unix timestamp (in seconds) of when the certificate becomes valid.""" + + +class Certificate(BaseModel): + """Represents an individual `certificate` uploaded to the organization.""" + + id: str + """The identifier, which can be referenced in API endpoints""" + + certificate_details: CertificateDetails + + created_at: int + """The Unix timestamp (in seconds) of when the certificate was uploaded.""" + + name: str + """The name of the certificate.""" + + object: Literal["certificate", "organization.certificate", "organization.project.certificate"] + """The object type. + + - If creating, updating, or getting a specific certificate, the object type is + `certificate`. + - If listing, activating, or deactivating certificates for the organization, the + object type is `organization.certificate`. + - If listing, activating, or deactivating certificates for a project, the object + type is `organization.project.certificate`. + """ + + active: Optional[bool] = None + """Whether the certificate is currently active at the specified scope. + + Not returned when getting details for a specific certificate. + """ diff --git a/src/openai/types/admin/organization/certificate_activate_params.py b/src/openai/types/admin/organization/certificate_activate_params.py new file mode 100644 index 0000000000..0bb6474c7c --- /dev/null +++ b/src/openai/types/admin/organization/certificate_activate_params.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["CertificateActivateParams"] + + +class CertificateActivateParams(TypedDict, total=False): + certificate_ids: Required[SequenceNotStr[str]] diff --git a/src/openai/types/admin/organization/certificate_create_params.py b/src/openai/types/admin/organization/certificate_create_params.py new file mode 100644 index 0000000000..3af81f03cb --- /dev/null +++ b/src/openai/types/admin/organization/certificate_create_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["CertificateCreateParams"] + + +class CertificateCreateParams(TypedDict, total=False): + content: Required[str] + """The certificate content in PEM format""" + + name: str + """An optional name for the certificate""" diff --git a/src/openai/types/admin/organization/certificate_deactivate_params.py b/src/openai/types/admin/organization/certificate_deactivate_params.py new file mode 100644 index 0000000000..827af54d35 --- /dev/null +++ b/src/openai/types/admin/organization/certificate_deactivate_params.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["CertificateDeactivateParams"] + + +class CertificateDeactivateParams(TypedDict, total=False): + certificate_ids: Required[SequenceNotStr[str]] diff --git a/src/openai/types/admin/organization/certificate_delete_response.py b/src/openai/types/admin/organization/certificate_delete_response.py new file mode 100644 index 0000000000..b0dc1fa018 --- /dev/null +++ b/src/openai/types/admin/organization/certificate_delete_response.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["CertificateDeleteResponse"] + + +class CertificateDeleteResponse(BaseModel): + id: str + """The ID of the certificate that was deleted.""" + + object: Literal["certificate.deleted"] + """The object type, must be `certificate.deleted`.""" diff --git a/src/openai/types/admin/organization/certificate_list_params.py b/src/openai/types/admin/organization/certificate_list_params.py new file mode 100644 index 0000000000..1d9aff4b4a --- /dev/null +++ b/src/openai/types/admin/organization/certificate_list_params.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["CertificateListParams"] + + +class CertificateListParams(TypedDict, total=False): + after: str + """A cursor for use in pagination. + + `after` is an object ID that defines your place in the list. For instance, if + you make a list request and receive 100 objects, ending with obj_foo, your + subsequent call can include after=obj_foo in order to fetch the next page of the + list. + """ + + limit: int + """A limit on the number of objects to be returned. + + Limit can range between 1 and 100, and the default is 20. + """ + + order: Literal["asc", "desc"] + """Sort order by the `created_at` timestamp of the objects. + + `asc` for ascending order and `desc` for descending order. + """ diff --git a/src/openai/types/admin/organization/certificate_retrieve_params.py b/src/openai/types/admin/organization/certificate_retrieve_params.py new file mode 100644 index 0000000000..29bc8dedc5 --- /dev/null +++ b/src/openai/types/admin/organization/certificate_retrieve_params.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Literal, TypedDict + +__all__ = ["CertificateRetrieveParams"] + + +class CertificateRetrieveParams(TypedDict, total=False): + include: List[Literal["content"]] + """A list of additional fields to include in the response. + + Currently the only supported value is `content` to fetch the PEM content of the + certificate. + """ diff --git a/src/openai/types/admin/organization/certificate_update_params.py b/src/openai/types/admin/organization/certificate_update_params.py new file mode 100644 index 0000000000..8a048b52b9 --- /dev/null +++ b/src/openai/types/admin/organization/certificate_update_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["CertificateUpdateParams"] + + +class CertificateUpdateParams(TypedDict, total=False): + name: Required[str] + """The updated name for the certificate""" diff --git a/src/openai/types/admin/organization/group.py b/src/openai/types/admin/organization/group.py new file mode 100644 index 0000000000..ce3b0d41b3 --- /dev/null +++ b/src/openai/types/admin/organization/group.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ...._models import BaseModel + +__all__ = ["Group"] + + +class Group(BaseModel): + """Details about an organization group.""" + + id: str + """Identifier for the group.""" + + created_at: int + """Unix timestamp (in seconds) when the group was created.""" + + is_scim_managed: bool + """ + Whether the group is managed through SCIM and controlled by your identity + provider. + """ + + name: str + """Display name of the group.""" diff --git a/src/openai/types/admin/organization/group_create_params.py b/src/openai/types/admin/organization/group_create_params.py new file mode 100644 index 0000000000..8e27d299d3 --- /dev/null +++ b/src/openai/types/admin/organization/group_create_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["GroupCreateParams"] + + +class GroupCreateParams(TypedDict, total=False): + name: Required[str] + """Human readable name for the group.""" diff --git a/src/openai/types/admin/organization/group_delete_response.py b/src/openai/types/admin/organization/group_delete_response.py new file mode 100644 index 0000000000..6dec56e58d --- /dev/null +++ b/src/openai/types/admin/organization/group_delete_response.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["GroupDeleteResponse"] + + +class GroupDeleteResponse(BaseModel): + """Confirmation payload returned after deleting a group.""" + + id: str + """Identifier of the deleted group.""" + + deleted: bool + """Whether the group was deleted.""" + + object: Literal["group.deleted"] + """Always `group.deleted`.""" diff --git a/src/openai/types/admin/organization/group_list_params.py b/src/openai/types/admin/organization/group_list_params.py new file mode 100644 index 0000000000..198478b35a --- /dev/null +++ b/src/openai/types/admin/organization/group_list_params.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["GroupListParams"] + + +class GroupListParams(TypedDict, total=False): + after: str + """A cursor for use in pagination. + + `after` is a group ID that defines your place in the list. For instance, if you + make a list request and receive 100 objects, ending with group_abc, your + subsequent call can include `after=group_abc` in order to fetch the next page of + the list. + """ + + limit: int + """A limit on the number of groups to be returned. + + Limit can range between 0 and 1000, and the default is 100. + """ + + order: Literal["asc", "desc"] + """Specifies the sort order of the returned groups.""" diff --git a/src/openai/types/admin/organization/group_update_params.py b/src/openai/types/admin/organization/group_update_params.py new file mode 100644 index 0000000000..2bb3a9d8fe --- /dev/null +++ b/src/openai/types/admin/organization/group_update_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["GroupUpdateParams"] + + +class GroupUpdateParams(TypedDict, total=False): + name: Required[str] + """New display name for the group.""" diff --git a/src/openai/types/admin/organization/group_update_response.py b/src/openai/types/admin/organization/group_update_response.py new file mode 100644 index 0000000000..1ae6f86a64 --- /dev/null +++ b/src/openai/types/admin/organization/group_update_response.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ...._models import BaseModel + +__all__ = ["GroupUpdateResponse"] + + +class GroupUpdateResponse(BaseModel): + """Response returned after updating a group.""" + + id: str + """Identifier for the group.""" + + created_at: int + """Unix timestamp (in seconds) when the group was created.""" + + is_scim_managed: bool + """ + Whether the group is managed through SCIM and controlled by your identity + provider. + """ + + name: str + """Updated display name for the group.""" diff --git a/src/openai/types/admin/organization/groups/__init__.py b/src/openai/types/admin/organization/groups/__init__.py new file mode 100644 index 0000000000..a1af586634 --- /dev/null +++ b/src/openai/types/admin/organization/groups/__init__.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .role_list_params import RoleListParams as RoleListParams +from .user_list_params import UserListParams as UserListParams +from .role_create_params import RoleCreateParams as RoleCreateParams +from .role_list_response import RoleListResponse as RoleListResponse +from .user_create_params import UserCreateParams as UserCreateParams +from .role_create_response import RoleCreateResponse as RoleCreateResponse +from .role_delete_response import RoleDeleteResponse as RoleDeleteResponse +from .user_create_response import UserCreateResponse as UserCreateResponse +from .user_delete_response import UserDeleteResponse as UserDeleteResponse diff --git a/src/openai/types/admin/organization/groups/role_create_params.py b/src/openai/types/admin/organization/groups/role_create_params.py new file mode 100644 index 0000000000..0ebc196eef --- /dev/null +++ b/src/openai/types/admin/organization/groups/role_create_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["RoleCreateParams"] + + +class RoleCreateParams(TypedDict, total=False): + role_id: Required[str] + """Identifier of the role to assign.""" diff --git a/src/openai/types/admin/organization/groups/role_create_response.py b/src/openai/types/admin/organization/groups/role_create_response.py new file mode 100644 index 0000000000..8f82bfc542 --- /dev/null +++ b/src/openai/types/admin/organization/groups/role_create_response.py @@ -0,0 +1,40 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..role import Role +from ....._models import BaseModel + +__all__ = ["RoleCreateResponse", "Group"] + + +class Group(BaseModel): + """Summary information about a group returned in role assignment responses.""" + + id: str + """Identifier for the group.""" + + created_at: int + """Unix timestamp (in seconds) when the group was created.""" + + name: str + """Display name of the group.""" + + object: Literal["group"] + """Always `group`.""" + + scim_managed: bool + """Whether the group is managed through SCIM.""" + + +class RoleCreateResponse(BaseModel): + """Role assignment linking a group to a role.""" + + group: Group + """Summary information about a group returned in role assignment responses.""" + + object: Literal["group.role"] + """Always `group.role`.""" + + role: Role + """Details about a role that can be assigned through the public Roles API.""" diff --git a/src/openai/types/admin/organization/groups/role_delete_response.py b/src/openai/types/admin/organization/groups/role_delete_response.py new file mode 100644 index 0000000000..fb6a111614 --- /dev/null +++ b/src/openai/types/admin/organization/groups/role_delete_response.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ....._models import BaseModel + +__all__ = ["RoleDeleteResponse"] + + +class RoleDeleteResponse(BaseModel): + """Confirmation payload returned after unassigning a role.""" + + deleted: bool + """Whether the assignment was removed.""" + + object: str + """ + Identifier for the deleted assignment, such as `group.role.deleted` or + `user.role.deleted`. + """ diff --git a/src/openai/types/admin/organization/groups/role_list_params.py b/src/openai/types/admin/organization/groups/role_list_params.py new file mode 100644 index 0000000000..451a1a2045 --- /dev/null +++ b/src/openai/types/admin/organization/groups/role_list_params.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["RoleListParams"] + + +class RoleListParams(TypedDict, total=False): + after: str + """Cursor for pagination. + + Provide the value from the previous response's `next` field to continue listing + organization roles. + """ + + limit: int + """A limit on the number of organization role assignments to return.""" + + order: Literal["asc", "desc"] + """Sort order for the returned organization roles.""" diff --git a/src/openai/types/admin/organization/groups/role_list_response.py b/src/openai/types/admin/organization/groups/role_list_response.py new file mode 100644 index 0000000000..337d517ba1 --- /dev/null +++ b/src/openai/types/admin/organization/groups/role_list_response.py @@ -0,0 +1,46 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional + +from ....._models import BaseModel + +__all__ = ["RoleListResponse"] + + +class RoleListResponse(BaseModel): + """ + Detailed information about a role assignment entry returned when listing assignments. + """ + + id: str + """Identifier for the role.""" + + created_at: Optional[int] = None + """When the role was created.""" + + created_by: Optional[str] = None + """Identifier of the actor who created the role.""" + + created_by_user_obj: Optional[Dict[str, object]] = None + """User details for the actor that created the role, when available.""" + + description: Optional[str] = None + """Description of the role.""" + + metadata: Optional[Dict[str, object]] = None + """Arbitrary metadata stored on the role.""" + + name: str + """Name of the role.""" + + permissions: List[str] + """Permissions associated with the role.""" + + predefined_role: bool + """Whether the role is predefined by OpenAI.""" + + resource_type: str + """Resource type the role applies to.""" + + updated_at: Optional[int] = None + """When the role was last updated.""" diff --git a/src/openai/types/admin/organization/groups/user_create_params.py b/src/openai/types/admin/organization/groups/user_create_params.py new file mode 100644 index 0000000000..ec30b46f1c --- /dev/null +++ b/src/openai/types/admin/organization/groups/user_create_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["UserCreateParams"] + + +class UserCreateParams(TypedDict, total=False): + user_id: Required[str] + """Identifier of the user to add to the group.""" diff --git a/src/openai/types/admin/organization/groups/user_create_response.py b/src/openai/types/admin/organization/groups/user_create_response.py new file mode 100644 index 0000000000..508f51747e --- /dev/null +++ b/src/openai/types/admin/organization/groups/user_create_response.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ....._models import BaseModel + +__all__ = ["UserCreateResponse"] + + +class UserCreateResponse(BaseModel): + """Confirmation payload returned after adding a user to a group.""" + + group_id: str + """Identifier of the group the user was added to.""" + + object: Literal["group.user"] + """Always `group.user`.""" + + user_id: str + """Identifier of the user that was added.""" diff --git a/src/openai/types/admin/organization/groups/user_delete_response.py b/src/openai/types/admin/organization/groups/user_delete_response.py new file mode 100644 index 0000000000..3b484a9baf --- /dev/null +++ b/src/openai/types/admin/organization/groups/user_delete_response.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ....._models import BaseModel + +__all__ = ["UserDeleteResponse"] + + +class UserDeleteResponse(BaseModel): + """Confirmation payload returned after removing a user from a group.""" + + deleted: bool + """Whether the group membership was removed.""" + + object: Literal["group.user.deleted"] + """Always `group.user.deleted`.""" diff --git a/src/openai/types/admin/organization/groups/user_list_params.py b/src/openai/types/admin/organization/groups/user_list_params.py new file mode 100644 index 0000000000..09bcfb1ba7 --- /dev/null +++ b/src/openai/types/admin/organization/groups/user_list_params.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["UserListParams"] + + +class UserListParams(TypedDict, total=False): + after: str + """A cursor for use in pagination. + + Provide the ID of the last user from the previous list response to retrieve the + next page. + """ + + limit: int + """A limit on the number of users to be returned. + + Limit can range between 0 and 1000, and the default is 100. + """ + + order: Literal["asc", "desc"] + """Specifies the sort order of users in the list.""" diff --git a/src/openai/types/admin/organization/invite.py b/src/openai/types/admin/organization/invite.py new file mode 100644 index 0000000000..5c051500b9 --- /dev/null +++ b/src/openai/types/admin/organization/invite.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["Invite", "Project"] + + +class Project(BaseModel): + id: Optional[str] = None + """Project's public ID""" + + role: Optional[Literal["member", "owner"]] = None + """Project membership role""" + + +class Invite(BaseModel): + """Represents an individual `invite` to the organization.""" + + id: str + """The identifier, which can be referenced in API endpoints""" + + email: str + """The email address of the individual to whom the invite was sent""" + + expires_at: int + """The Unix timestamp (in seconds) of when the invite expires.""" + + invited_at: int + """The Unix timestamp (in seconds) of when the invite was sent.""" + + object: Literal["organization.invite"] + """The object type, which is always `organization.invite`""" + + role: Literal["owner", "reader"] + """`owner` or `reader`""" + + status: Literal["accepted", "expired", "pending"] + """`accepted`,`expired`, or `pending`""" + + accepted_at: Optional[int] = None + """The Unix timestamp (in seconds) of when the invite was accepted.""" + + projects: Optional[List[Project]] = None + """The projects that were granted membership upon acceptance of the invite.""" diff --git a/src/openai/types/admin/organization/invite_create_params.py b/src/openai/types/admin/organization/invite_create_params.py new file mode 100644 index 0000000000..7709003fe3 --- /dev/null +++ b/src/openai/types/admin/organization/invite_create_params.py @@ -0,0 +1,31 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["InviteCreateParams", "Project"] + + +class InviteCreateParams(TypedDict, total=False): + email: Required[str] + """Send an email to this address""" + + role: Required[Literal["reader", "owner"]] + """`owner` or `reader`""" + + projects: Iterable[Project] + """ + An array of projects to which membership is granted at the same time the org + invite is accepted. If omitted, the user will be invited to the default project + for compatibility with legacy behavior. + """ + + +class Project(TypedDict, total=False): + id: Required[str] + """Project's public ID""" + + role: Required[Literal["member", "owner"]] + """Project membership role""" diff --git a/src/openai/types/admin/organization/invite_delete_response.py b/src/openai/types/admin/organization/invite_delete_response.py new file mode 100644 index 0000000000..1a8aa0ce2f --- /dev/null +++ b/src/openai/types/admin/organization/invite_delete_response.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["InviteDeleteResponse"] + + +class InviteDeleteResponse(BaseModel): + id: str + + deleted: bool + + object: Literal["organization.invite.deleted"] + """The object type, which is always `organization.invite.deleted`""" diff --git a/src/openai/types/admin/organization/invite_list_params.py b/src/openai/types/admin/organization/invite_list_params.py new file mode 100644 index 0000000000..678510d655 --- /dev/null +++ b/src/openai/types/admin/organization/invite_list_params.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["InviteListParams"] + + +class InviteListParams(TypedDict, total=False): + after: str + """A cursor for use in pagination. + + `after` is an object ID that defines your place in the list. For instance, if + you make a list request and receive 100 objects, ending with obj_foo, your + subsequent call can include after=obj_foo in order to fetch the next page of the + list. + """ + + limit: int + """A limit on the number of objects to be returned. + + Limit can range between 1 and 100, and the default is 20. + """ diff --git a/src/openai/types/admin/organization/organization_user.py b/src/openai/types/admin/organization/organization_user.py new file mode 100644 index 0000000000..3ffe572465 --- /dev/null +++ b/src/openai/types/admin/organization/organization_user.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["OrganizationUser"] + + +class OrganizationUser(BaseModel): + """Represents an individual `user` within an organization.""" + + id: str + """The identifier, which can be referenced in API endpoints""" + + added_at: int + """The Unix timestamp (in seconds) of when the user was added.""" + + email: str + """The email address of the user""" + + name: str + """The name of the user""" + + object: Literal["organization.user"] + """The object type, which is always `organization.user`""" + + role: Literal["owner", "reader"] + """`owner` or `reader`""" diff --git a/src/openai/types/admin/organization/project.py b/src/openai/types/admin/organization/project.py new file mode 100644 index 0000000000..a1058af3d5 --- /dev/null +++ b/src/openai/types/admin/organization/project.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["Project"] + + +class Project(BaseModel): + """Represents an individual project.""" + + id: str + """The identifier, which can be referenced in API endpoints""" + + created_at: int + """The Unix timestamp (in seconds) of when the project was created.""" + + name: str + """The name of the project. This appears in reporting.""" + + object: Literal["organization.project"] + """The object type, which is always `organization.project`""" + + status: Literal["active", "archived"] + """`active` or `archived`""" + + archived_at: Optional[int] = None + """The Unix timestamp (in seconds) of when the project was archived or `null`.""" diff --git a/src/openai/types/admin/organization/project_create_params.py b/src/openai/types/admin/organization/project_create_params.py new file mode 100644 index 0000000000..8b8d1b44e8 --- /dev/null +++ b/src/openai/types/admin/organization/project_create_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ProjectCreateParams"] + + +class ProjectCreateParams(TypedDict, total=False): + name: Required[str] + """The friendly name of the project, this name appears in reports.""" + + geography: Literal["US", "EU", "JP", "IN", "KR", "CA", "AU", "SG"] + """Create the project with the specified data residency region. + + Your organization must have access to Data residency functionality in order to + use. See + [data residency controls](https://platform.openai.com/docs/guides/your-data#data-residency-controls) + to review the functionality and limitations of setting this field. + """ diff --git a/src/openai/types/admin/organization/project_list_params.py b/src/openai/types/admin/organization/project_list_params.py new file mode 100644 index 0000000000..f55fb8a392 --- /dev/null +++ b/src/openai/types/admin/organization/project_list_params.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["ProjectListParams"] + + +class ProjectListParams(TypedDict, total=False): + after: str + """A cursor for use in pagination. + + `after` is an object ID that defines your place in the list. For instance, if + you make a list request and receive 100 objects, ending with obj_foo, your + subsequent call can include after=obj_foo in order to fetch the next page of the + list. + """ + + include_archived: bool + """If `true` returns all projects including those that have been `archived`. + + Archived projects are not included by default. + """ + + limit: int + """A limit on the number of objects to be returned. + + Limit can range between 1 and 100, and the default is 20. + """ diff --git a/src/openai/types/admin/organization/project_update_params.py b/src/openai/types/admin/organization/project_update_params.py new file mode 100644 index 0000000000..0ba1984a9f --- /dev/null +++ b/src/openai/types/admin/organization/project_update_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["ProjectUpdateParams"] + + +class ProjectUpdateParams(TypedDict, total=False): + name: Required[str] + """The updated name of the project, this name appears in reports.""" diff --git a/src/openai/types/admin/organization/projects/__init__.py b/src/openai/types/admin/organization/projects/__init__.py new file mode 100644 index 0000000000..8af54d8659 --- /dev/null +++ b/src/openai/types/admin/organization/projects/__init__.py @@ -0,0 +1,31 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .project_user import ProjectUser as ProjectUser +from .project_group import ProjectGroup as ProjectGroup +from .project_api_key import ProjectAPIKey as ProjectAPIKey +from .role_list_params import RoleListParams as RoleListParams +from .user_list_params import UserListParams as UserListParams +from .group_list_params import GroupListParams as GroupListParams +from .project_rate_limit import ProjectRateLimit as ProjectRateLimit +from .role_create_params import RoleCreateParams as RoleCreateParams +from .role_update_params import RoleUpdateParams as RoleUpdateParams +from .user_create_params import UserCreateParams as UserCreateParams +from .user_update_params import UserUpdateParams as UserUpdateParams +from .api_key_list_params import APIKeyListParams as APIKeyListParams +from .group_create_params import GroupCreateParams as GroupCreateParams +from .role_delete_response import RoleDeleteResponse as RoleDeleteResponse +from .user_delete_response import UserDeleteResponse as UserDeleteResponse +from .group_delete_response import GroupDeleteResponse as GroupDeleteResponse +from .api_key_delete_response import APIKeyDeleteResponse as APIKeyDeleteResponse +from .certificate_list_params import CertificateListParams as CertificateListParams +from .project_service_account import ProjectServiceAccount as ProjectServiceAccount +from .certificate_activate_params import CertificateActivateParams as CertificateActivateParams +from .service_account_list_params import ServiceAccountListParams as ServiceAccountListParams +from .certificate_deactivate_params import CertificateDeactivateParams as CertificateDeactivateParams +from .service_account_create_params import ServiceAccountCreateParams as ServiceAccountCreateParams +from .service_account_create_response import ServiceAccountCreateResponse as ServiceAccountCreateResponse +from .service_account_delete_response import ServiceAccountDeleteResponse as ServiceAccountDeleteResponse +from .rate_limit_list_rate_limits_params import RateLimitListRateLimitsParams as RateLimitListRateLimitsParams +from .rate_limit_update_rate_limit_params import RateLimitUpdateRateLimitParams as RateLimitUpdateRateLimitParams diff --git a/src/openai/types/admin/organization/projects/api_key_delete_response.py b/src/openai/types/admin/organization/projects/api_key_delete_response.py new file mode 100644 index 0000000000..253a6746ba --- /dev/null +++ b/src/openai/types/admin/organization/projects/api_key_delete_response.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ....._models import BaseModel + +__all__ = ["APIKeyDeleteResponse"] + + +class APIKeyDeleteResponse(BaseModel): + id: str + + deleted: bool + + object: Literal["organization.project.api_key.deleted"] diff --git a/src/openai/types/admin/organization/projects/api_key_list_params.py b/src/openai/types/admin/organization/projects/api_key_list_params.py new file mode 100644 index 0000000000..422a28518e --- /dev/null +++ b/src/openai/types/admin/organization/projects/api_key_list_params.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["APIKeyListParams"] + + +class APIKeyListParams(TypedDict, total=False): + after: str + """A cursor for use in pagination. + + `after` is an object ID that defines your place in the list. For instance, if + you make a list request and receive 100 objects, ending with obj_foo, your + subsequent call can include after=obj_foo in order to fetch the next page of the + list. + """ + + limit: int + """A limit on the number of objects to be returned. + + Limit can range between 1 and 100, and the default is 20. + """ diff --git a/src/openai/types/admin/organization/projects/certificate_activate_params.py b/src/openai/types/admin/organization/projects/certificate_activate_params.py new file mode 100644 index 0000000000..a0e7cd20e8 --- /dev/null +++ b/src/openai/types/admin/organization/projects/certificate_activate_params.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +from ....._types import SequenceNotStr + +__all__ = ["CertificateActivateParams"] + + +class CertificateActivateParams(TypedDict, total=False): + certificate_ids: Required[SequenceNotStr[str]] diff --git a/src/openai/types/admin/organization/projects/certificate_deactivate_params.py b/src/openai/types/admin/organization/projects/certificate_deactivate_params.py new file mode 100644 index 0000000000..75c32708ba --- /dev/null +++ b/src/openai/types/admin/organization/projects/certificate_deactivate_params.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +from ....._types import SequenceNotStr + +__all__ = ["CertificateDeactivateParams"] + + +class CertificateDeactivateParams(TypedDict, total=False): + certificate_ids: Required[SequenceNotStr[str]] diff --git a/src/openai/types/admin/organization/projects/certificate_list_params.py b/src/openai/types/admin/organization/projects/certificate_list_params.py new file mode 100644 index 0000000000..1d9aff4b4a --- /dev/null +++ b/src/openai/types/admin/organization/projects/certificate_list_params.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["CertificateListParams"] + + +class CertificateListParams(TypedDict, total=False): + after: str + """A cursor for use in pagination. + + `after` is an object ID that defines your place in the list. For instance, if + you make a list request and receive 100 objects, ending with obj_foo, your + subsequent call can include after=obj_foo in order to fetch the next page of the + list. + """ + + limit: int + """A limit on the number of objects to be returned. + + Limit can range between 1 and 100, and the default is 20. + """ + + order: Literal["asc", "desc"] + """Sort order by the `created_at` timestamp of the objects. + + `asc` for ascending order and `desc` for descending order. + """ diff --git a/src/openai/types/admin/organization/projects/group_create_params.py b/src/openai/types/admin/organization/projects/group_create_params.py new file mode 100644 index 0000000000..b9f4626d74 --- /dev/null +++ b/src/openai/types/admin/organization/projects/group_create_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["GroupCreateParams"] + + +class GroupCreateParams(TypedDict, total=False): + group_id: Required[str] + """Identifier of the group to add to the project.""" + + role: Required[str] + """Identifier of the project role to grant to the group.""" diff --git a/src/openai/types/admin/organization/projects/group_delete_response.py b/src/openai/types/admin/organization/projects/group_delete_response.py new file mode 100644 index 0000000000..ef1ce0ddb8 --- /dev/null +++ b/src/openai/types/admin/organization/projects/group_delete_response.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ....._models import BaseModel + +__all__ = ["GroupDeleteResponse"] + + +class GroupDeleteResponse(BaseModel): + """Confirmation payload returned after removing a group from a project.""" + + deleted: bool + """Whether the group membership in the project was removed.""" + + object: Literal["project.group.deleted"] + """Always `project.group.deleted`.""" diff --git a/src/openai/types/admin/organization/projects/group_list_params.py b/src/openai/types/admin/organization/projects/group_list_params.py new file mode 100644 index 0000000000..26ab31a88b --- /dev/null +++ b/src/openai/types/admin/organization/projects/group_list_params.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["GroupListParams"] + + +class GroupListParams(TypedDict, total=False): + after: str + """Cursor for pagination. + + Provide the ID of the last group from the previous response to fetch the next + page. + """ + + limit: int + """A limit on the number of project groups to return. Defaults to 20.""" + + order: Literal["asc", "desc"] + """Sort order for the returned groups.""" diff --git a/src/openai/types/admin/organization/projects/groups/__init__.py b/src/openai/types/admin/organization/projects/groups/__init__.py new file mode 100644 index 0000000000..ed464fde83 --- /dev/null +++ b/src/openai/types/admin/organization/projects/groups/__init__.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .role_list_params import RoleListParams as RoleListParams +from .role_create_params import RoleCreateParams as RoleCreateParams +from .role_list_response import RoleListResponse as RoleListResponse +from .role_create_response import RoleCreateResponse as RoleCreateResponse +from .role_delete_response import RoleDeleteResponse as RoleDeleteResponse diff --git a/src/openai/types/admin/organization/projects/groups/role_create_params.py b/src/openai/types/admin/organization/projects/groups/role_create_params.py new file mode 100644 index 0000000000..2aba01e8a4 --- /dev/null +++ b/src/openai/types/admin/organization/projects/groups/role_create_params.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["RoleCreateParams"] + + +class RoleCreateParams(TypedDict, total=False): + project_id: Required[str] + + role_id: Required[str] + """Identifier of the role to assign.""" diff --git a/src/openai/types/admin/organization/projects/groups/role_create_response.py b/src/openai/types/admin/organization/projects/groups/role_create_response.py new file mode 100644 index 0000000000..c6e7a1c048 --- /dev/null +++ b/src/openai/types/admin/organization/projects/groups/role_create_response.py @@ -0,0 +1,40 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...role import Role +from ......_models import BaseModel + +__all__ = ["RoleCreateResponse", "Group"] + + +class Group(BaseModel): + """Summary information about a group returned in role assignment responses.""" + + id: str + """Identifier for the group.""" + + created_at: int + """Unix timestamp (in seconds) when the group was created.""" + + name: str + """Display name of the group.""" + + object: Literal["group"] + """Always `group`.""" + + scim_managed: bool + """Whether the group is managed through SCIM.""" + + +class RoleCreateResponse(BaseModel): + """Role assignment linking a group to a role.""" + + group: Group + """Summary information about a group returned in role assignment responses.""" + + object: Literal["group.role"] + """Always `group.role`.""" + + role: Role + """Details about a role that can be assigned through the public Roles API.""" diff --git a/src/openai/types/admin/organization/projects/groups/role_delete_response.py b/src/openai/types/admin/organization/projects/groups/role_delete_response.py new file mode 100644 index 0000000000..704de05117 --- /dev/null +++ b/src/openai/types/admin/organization/projects/groups/role_delete_response.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ......_models import BaseModel + +__all__ = ["RoleDeleteResponse"] + + +class RoleDeleteResponse(BaseModel): + """Confirmation payload returned after unassigning a role.""" + + deleted: bool + """Whether the assignment was removed.""" + + object: str + """ + Identifier for the deleted assignment, such as `group.role.deleted` or + `user.role.deleted`. + """ diff --git a/src/openai/types/admin/organization/projects/groups/role_list_params.py b/src/openai/types/admin/organization/projects/groups/role_list_params.py new file mode 100644 index 0000000000..ffdbe210d2 --- /dev/null +++ b/src/openai/types/admin/organization/projects/groups/role_list_params.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["RoleListParams"] + + +class RoleListParams(TypedDict, total=False): + project_id: Required[str] + + after: str + """Cursor for pagination. + + Provide the value from the previous response's `next` field to continue listing + project roles. + """ + + limit: int + """A limit on the number of project role assignments to return.""" + + order: Literal["asc", "desc"] + """Sort order for the returned project roles.""" diff --git a/src/openai/types/admin/organization/projects/groups/role_list_response.py b/src/openai/types/admin/organization/projects/groups/role_list_response.py new file mode 100644 index 0000000000..72934bde13 --- /dev/null +++ b/src/openai/types/admin/organization/projects/groups/role_list_response.py @@ -0,0 +1,46 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional + +from ......_models import BaseModel + +__all__ = ["RoleListResponse"] + + +class RoleListResponse(BaseModel): + """ + Detailed information about a role assignment entry returned when listing assignments. + """ + + id: str + """Identifier for the role.""" + + created_at: Optional[int] = None + """When the role was created.""" + + created_by: Optional[str] = None + """Identifier of the actor who created the role.""" + + created_by_user_obj: Optional[Dict[str, object]] = None + """User details for the actor that created the role, when available.""" + + description: Optional[str] = None + """Description of the role.""" + + metadata: Optional[Dict[str, object]] = None + """Arbitrary metadata stored on the role.""" + + name: str + """Name of the role.""" + + permissions: List[str] + """Permissions associated with the role.""" + + predefined_role: bool + """Whether the role is predefined by OpenAI.""" + + resource_type: str + """Resource type the role applies to.""" + + updated_at: Optional[int] = None + """When the role was last updated.""" diff --git a/src/openai/types/admin/organization/projects/project_api_key.py b/src/openai/types/admin/organization/projects/project_api_key.py new file mode 100644 index 0000000000..69cb243ba3 --- /dev/null +++ b/src/openai/types/admin/organization/projects/project_api_key.py @@ -0,0 +1,45 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ....._models import BaseModel +from .project_user import ProjectUser +from .project_service_account import ProjectServiceAccount + +__all__ = ["ProjectAPIKey", "Owner"] + + +class Owner(BaseModel): + service_account: Optional[ProjectServiceAccount] = None + """Represents an individual service account in a project.""" + + type: Optional[Literal["user", "service_account"]] = None + """`user` or `service_account`""" + + user: Optional[ProjectUser] = None + """Represents an individual user in a project.""" + + +class ProjectAPIKey(BaseModel): + """Represents an individual API key in a project.""" + + id: str + """The identifier, which can be referenced in API endpoints""" + + created_at: int + """The Unix timestamp (in seconds) of when the API key was created""" + + last_used_at: int + """The Unix timestamp (in seconds) of when the API key was last used.""" + + name: str + """The name of the API key""" + + object: Literal["organization.project.api_key"] + """The object type, which is always `organization.project.api_key`""" + + owner: Owner + + redacted_value: str + """The redacted value of the API key""" diff --git a/src/openai/types/admin/organization/projects/project_group.py b/src/openai/types/admin/organization/projects/project_group.py new file mode 100644 index 0000000000..e80d815795 --- /dev/null +++ b/src/openai/types/admin/organization/projects/project_group.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ....._models import BaseModel + +__all__ = ["ProjectGroup"] + + +class ProjectGroup(BaseModel): + """Details about a group's membership in a project.""" + + created_at: int + """Unix timestamp (in seconds) when the group was granted project access.""" + + group_id: str + """Identifier of the group that has access to the project.""" + + group_name: str + """Display name of the group.""" + + object: Literal["project.group"] + """Always `project.group`.""" + + project_id: str + """Identifier of the project.""" diff --git a/src/openai/types/admin/organization/projects/project_rate_limit.py b/src/openai/types/admin/organization/projects/project_rate_limit.py new file mode 100644 index 0000000000..46ff1ef036 --- /dev/null +++ b/src/openai/types/admin/organization/projects/project_rate_limit.py @@ -0,0 +1,39 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ....._models import BaseModel + +__all__ = ["ProjectRateLimit"] + + +class ProjectRateLimit(BaseModel): + """Represents a project rate limit config.""" + + id: str + """The identifier, which can be referenced in API endpoints.""" + + max_requests_per_1_minute: int + """The maximum requests per minute.""" + + max_tokens_per_1_minute: int + """The maximum tokens per minute.""" + + model: str + """The model this rate limit applies to.""" + + object: Literal["project.rate_limit"] + """The object type, which is always `project.rate_limit`""" + + batch_1_day_max_input_tokens: Optional[int] = None + """The maximum batch input tokens per day. Only present for relevant models.""" + + max_audio_megabytes_per_1_minute: Optional[int] = None + """The maximum audio megabytes per minute. Only present for relevant models.""" + + max_images_per_1_minute: Optional[int] = None + """The maximum images per minute. Only present for relevant models.""" + + max_requests_per_1_day: Optional[int] = None + """The maximum requests per day. Only present for relevant models.""" diff --git a/src/openai/types/admin/organization/projects/project_service_account.py b/src/openai/types/admin/organization/projects/project_service_account.py new file mode 100644 index 0000000000..ca7bf0bdae --- /dev/null +++ b/src/openai/types/admin/organization/projects/project_service_account.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ....._models import BaseModel + +__all__ = ["ProjectServiceAccount"] + + +class ProjectServiceAccount(BaseModel): + """Represents an individual service account in a project.""" + + id: str + """The identifier, which can be referenced in API endpoints""" + + created_at: int + """The Unix timestamp (in seconds) of when the service account was created""" + + name: str + """The name of the service account""" + + object: Literal["organization.project.service_account"] + """The object type, which is always `organization.project.service_account`""" + + role: Literal["owner", "member"] + """`owner` or `member`""" diff --git a/src/openai/types/admin/organization/projects/project_user.py b/src/openai/types/admin/organization/projects/project_user.py new file mode 100644 index 0000000000..68c73d1c9b --- /dev/null +++ b/src/openai/types/admin/organization/projects/project_user.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ....._models import BaseModel + +__all__ = ["ProjectUser"] + + +class ProjectUser(BaseModel): + """Represents an individual user in a project.""" + + id: str + """The identifier, which can be referenced in API endpoints""" + + added_at: int + """The Unix timestamp (in seconds) of when the project was added.""" + + email: str + """The email address of the user""" + + name: str + """The name of the user""" + + object: Literal["organization.project.user"] + """The object type, which is always `organization.project.user`""" + + role: Literal["owner", "member"] + """`owner` or `member`""" diff --git a/src/openai/types/admin/organization/projects/rate_limit_list_rate_limits_params.py b/src/openai/types/admin/organization/projects/rate_limit_list_rate_limits_params.py new file mode 100644 index 0000000000..198fe94f19 --- /dev/null +++ b/src/openai/types/admin/organization/projects/rate_limit_list_rate_limits_params.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["RateLimitListRateLimitsParams"] + + +class RateLimitListRateLimitsParams(TypedDict, total=False): + after: str + """A cursor for use in pagination. + + `after` is an object ID that defines your place in the list. For instance, if + you make a list request and receive 100 objects, ending with obj_foo, your + subsequent call can include after=obj_foo in order to fetch the next page of the + list. + """ + + before: str + """A cursor for use in pagination. + + `before` is an object ID that defines your place in the list. For instance, if + you make a list request and receive 100 objects, beginning with obj_foo, your + subsequent call can include before=obj_foo in order to fetch the previous page + of the list. + """ + + limit: int + """A limit on the number of objects to be returned. The default is 100.""" diff --git a/src/openai/types/admin/organization/projects/rate_limit_update_rate_limit_params.py b/src/openai/types/admin/organization/projects/rate_limit_update_rate_limit_params.py new file mode 100644 index 0000000000..5d5e515515 --- /dev/null +++ b/src/openai/types/admin/organization/projects/rate_limit_update_rate_limit_params.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["RateLimitUpdateRateLimitParams"] + + +class RateLimitUpdateRateLimitParams(TypedDict, total=False): + project_id: Required[str] + + batch_1_day_max_input_tokens: int + """The maximum batch input tokens per day. Only relevant for certain models.""" + + max_audio_megabytes_per_1_minute: int + """The maximum audio megabytes per minute. Only relevant for certain models.""" + + max_images_per_1_minute: int + """The maximum images per minute. Only relevant for certain models.""" + + max_requests_per_1_day: int + """The maximum requests per day. Only relevant for certain models.""" + + max_requests_per_1_minute: int + """The maximum requests per minute.""" + + max_tokens_per_1_minute: int + """The maximum tokens per minute.""" diff --git a/src/openai/types/admin/organization/projects/role_create_params.py b/src/openai/types/admin/organization/projects/role_create_params.py new file mode 100644 index 0000000000..e05c8c8a63 --- /dev/null +++ b/src/openai/types/admin/organization/projects/role_create_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Required, TypedDict + +from ....._types import SequenceNotStr + +__all__ = ["RoleCreateParams"] + + +class RoleCreateParams(TypedDict, total=False): + permissions: Required[SequenceNotStr[str]] + """Permissions to grant to the role.""" + + role_name: Required[str] + """Unique name for the role.""" + + description: Optional[str] + """Optional description of the role.""" diff --git a/src/openai/types/admin/organization/projects/role_delete_response.py b/src/openai/types/admin/organization/projects/role_delete_response.py new file mode 100644 index 0000000000..87fa8e6200 --- /dev/null +++ b/src/openai/types/admin/organization/projects/role_delete_response.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ....._models import BaseModel + +__all__ = ["RoleDeleteResponse"] + + +class RoleDeleteResponse(BaseModel): + """Confirmation payload returned after deleting a role.""" + + id: str + """Identifier of the deleted role.""" + + deleted: bool + """Whether the role was deleted.""" + + object: Literal["role.deleted"] + """Always `role.deleted`.""" diff --git a/src/openai/types/admin/organization/projects/role_list_params.py b/src/openai/types/admin/organization/projects/role_list_params.py new file mode 100644 index 0000000000..88e957f886 --- /dev/null +++ b/src/openai/types/admin/organization/projects/role_list_params.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["RoleListParams"] + + +class RoleListParams(TypedDict, total=False): + after: str + """Cursor for pagination. + + Provide the value from the previous response's `next` field to continue listing + roles. + """ + + limit: int + """A limit on the number of roles to return. Defaults to 1000.""" + + order: Literal["asc", "desc"] + """Sort order for the returned roles.""" diff --git a/src/openai/types/admin/organization/projects/role_update_params.py b/src/openai/types/admin/organization/projects/role_update_params.py new file mode 100644 index 0000000000..4d440c87cd --- /dev/null +++ b/src/openai/types/admin/organization/projects/role_update_params.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Required, TypedDict + +from ....._types import SequenceNotStr + +__all__ = ["RoleUpdateParams"] + + +class RoleUpdateParams(TypedDict, total=False): + project_id: Required[str] + + description: Optional[str] + """New description for the role.""" + + permissions: Optional[SequenceNotStr[str]] + """Updated set of permissions for the role.""" + + role_name: Optional[str] + """New name for the role.""" diff --git a/src/openai/types/admin/organization/projects/service_account_create_params.py b/src/openai/types/admin/organization/projects/service_account_create_params.py new file mode 100644 index 0000000000..409dcba500 --- /dev/null +++ b/src/openai/types/admin/organization/projects/service_account_create_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["ServiceAccountCreateParams"] + + +class ServiceAccountCreateParams(TypedDict, total=False): + name: Required[str] + """The name of the service account being created.""" diff --git a/src/openai/types/admin/organization/projects/service_account_create_response.py b/src/openai/types/admin/organization/projects/service_account_create_response.py new file mode 100644 index 0000000000..ce9cfa5530 --- /dev/null +++ b/src/openai/types/admin/organization/projects/service_account_create_response.py @@ -0,0 +1,35 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ....._models import BaseModel + +__all__ = ["ServiceAccountCreateResponse", "APIKey"] + + +class APIKey(BaseModel): + id: str + + created_at: int + + name: str + + object: Literal["organization.project.service_account.api_key"] + """The object type, which is always `organization.project.service_account.api_key`""" + + value: str + + +class ServiceAccountCreateResponse(BaseModel): + id: str + + api_key: APIKey + + created_at: int + + name: str + + object: Literal["organization.project.service_account"] + + role: Literal["member"] + """Service accounts can only have one role of type `member`""" diff --git a/src/openai/types/admin/organization/projects/service_account_delete_response.py b/src/openai/types/admin/organization/projects/service_account_delete_response.py new file mode 100644 index 0000000000..e67e635aab --- /dev/null +++ b/src/openai/types/admin/organization/projects/service_account_delete_response.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ....._models import BaseModel + +__all__ = ["ServiceAccountDeleteResponse"] + + +class ServiceAccountDeleteResponse(BaseModel): + id: str + + deleted: bool + + object: Literal["organization.project.service_account.deleted"] diff --git a/src/openai/types/admin/organization/projects/service_account_list_params.py b/src/openai/types/admin/organization/projects/service_account_list_params.py new file mode 100644 index 0000000000..7f808e285a --- /dev/null +++ b/src/openai/types/admin/organization/projects/service_account_list_params.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["ServiceAccountListParams"] + + +class ServiceAccountListParams(TypedDict, total=False): + after: str + """A cursor for use in pagination. + + `after` is an object ID that defines your place in the list. For instance, if + you make a list request and receive 100 objects, ending with obj_foo, your + subsequent call can include after=obj_foo in order to fetch the next page of the + list. + """ + + limit: int + """A limit on the number of objects to be returned. + + Limit can range between 1 and 100, and the default is 20. + """ diff --git a/src/openai/types/admin/organization/projects/user_create_params.py b/src/openai/types/admin/organization/projects/user_create_params.py new file mode 100644 index 0000000000..dee9d126db --- /dev/null +++ b/src/openai/types/admin/organization/projects/user_create_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["UserCreateParams"] + + +class UserCreateParams(TypedDict, total=False): + role: Required[Literal["owner", "member"]] + """`owner` or `member`""" + + user_id: Required[str] + """The ID of the user.""" diff --git a/src/openai/types/admin/organization/projects/user_delete_response.py b/src/openai/types/admin/organization/projects/user_delete_response.py new file mode 100644 index 0000000000..271d3a4126 --- /dev/null +++ b/src/openai/types/admin/organization/projects/user_delete_response.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ....._models import BaseModel + +__all__ = ["UserDeleteResponse"] + + +class UserDeleteResponse(BaseModel): + id: str + + deleted: bool + + object: Literal["organization.project.user.deleted"] diff --git a/src/openai/types/admin/organization/projects/user_list_params.py b/src/openai/types/admin/organization/projects/user_list_params.py new file mode 100644 index 0000000000..d561e907b1 --- /dev/null +++ b/src/openai/types/admin/organization/projects/user_list_params.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["UserListParams"] + + +class UserListParams(TypedDict, total=False): + after: str + """A cursor for use in pagination. + + `after` is an object ID that defines your place in the list. For instance, if + you make a list request and receive 100 objects, ending with obj_foo, your + subsequent call can include after=obj_foo in order to fetch the next page of the + list. + """ + + limit: int + """A limit on the number of objects to be returned. + + Limit can range between 1 and 100, and the default is 20. + """ diff --git a/src/openai/types/admin/organization/projects/user_update_params.py b/src/openai/types/admin/organization/projects/user_update_params.py new file mode 100644 index 0000000000..08b3e1a4e9 --- /dev/null +++ b/src/openai/types/admin/organization/projects/user_update_params.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["UserUpdateParams"] + + +class UserUpdateParams(TypedDict, total=False): + project_id: Required[str] + + role: Required[Literal["owner", "member"]] + """`owner` or `member`""" diff --git a/src/openai/types/admin/organization/projects/users/__init__.py b/src/openai/types/admin/organization/projects/users/__init__.py new file mode 100644 index 0000000000..ed464fde83 --- /dev/null +++ b/src/openai/types/admin/organization/projects/users/__init__.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .role_list_params import RoleListParams as RoleListParams +from .role_create_params import RoleCreateParams as RoleCreateParams +from .role_list_response import RoleListResponse as RoleListResponse +from .role_create_response import RoleCreateResponse as RoleCreateResponse +from .role_delete_response import RoleDeleteResponse as RoleDeleteResponse diff --git a/src/openai/types/admin/organization/projects/users/role_create_params.py b/src/openai/types/admin/organization/projects/users/role_create_params.py new file mode 100644 index 0000000000..2aba01e8a4 --- /dev/null +++ b/src/openai/types/admin/organization/projects/users/role_create_params.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["RoleCreateParams"] + + +class RoleCreateParams(TypedDict, total=False): + project_id: Required[str] + + role_id: Required[str] + """Identifier of the role to assign.""" diff --git a/src/openai/types/admin/organization/projects/users/role_create_response.py b/src/openai/types/admin/organization/projects/users/role_create_response.py new file mode 100644 index 0000000000..533df36500 --- /dev/null +++ b/src/openai/types/admin/organization/projects/users/role_create_response.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...role import Role +from ......_models import BaseModel +from ...organization_user import OrganizationUser + +__all__ = ["RoleCreateResponse"] + + +class RoleCreateResponse(BaseModel): + """Role assignment linking a user to a role.""" + + object: Literal["user.role"] + """Always `user.role`.""" + + role: Role + """Details about a role that can be assigned through the public Roles API.""" + + user: OrganizationUser + """Represents an individual `user` within an organization.""" diff --git a/src/openai/types/admin/organization/projects/users/role_delete_response.py b/src/openai/types/admin/organization/projects/users/role_delete_response.py new file mode 100644 index 0000000000..704de05117 --- /dev/null +++ b/src/openai/types/admin/organization/projects/users/role_delete_response.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ......_models import BaseModel + +__all__ = ["RoleDeleteResponse"] + + +class RoleDeleteResponse(BaseModel): + """Confirmation payload returned after unassigning a role.""" + + deleted: bool + """Whether the assignment was removed.""" + + object: str + """ + Identifier for the deleted assignment, such as `group.role.deleted` or + `user.role.deleted`. + """ diff --git a/src/openai/types/admin/organization/projects/users/role_list_params.py b/src/openai/types/admin/organization/projects/users/role_list_params.py new file mode 100644 index 0000000000..ffdbe210d2 --- /dev/null +++ b/src/openai/types/admin/organization/projects/users/role_list_params.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["RoleListParams"] + + +class RoleListParams(TypedDict, total=False): + project_id: Required[str] + + after: str + """Cursor for pagination. + + Provide the value from the previous response's `next` field to continue listing + project roles. + """ + + limit: int + """A limit on the number of project role assignments to return.""" + + order: Literal["asc", "desc"] + """Sort order for the returned project roles.""" diff --git a/src/openai/types/admin/organization/projects/users/role_list_response.py b/src/openai/types/admin/organization/projects/users/role_list_response.py new file mode 100644 index 0000000000..72934bde13 --- /dev/null +++ b/src/openai/types/admin/organization/projects/users/role_list_response.py @@ -0,0 +1,46 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional + +from ......_models import BaseModel + +__all__ = ["RoleListResponse"] + + +class RoleListResponse(BaseModel): + """ + Detailed information about a role assignment entry returned when listing assignments. + """ + + id: str + """Identifier for the role.""" + + created_at: Optional[int] = None + """When the role was created.""" + + created_by: Optional[str] = None + """Identifier of the actor who created the role.""" + + created_by_user_obj: Optional[Dict[str, object]] = None + """User details for the actor that created the role, when available.""" + + description: Optional[str] = None + """Description of the role.""" + + metadata: Optional[Dict[str, object]] = None + """Arbitrary metadata stored on the role.""" + + name: str + """Name of the role.""" + + permissions: List[str] + """Permissions associated with the role.""" + + predefined_role: bool + """Whether the role is predefined by OpenAI.""" + + resource_type: str + """Resource type the role applies to.""" + + updated_at: Optional[int] = None + """When the role was last updated.""" diff --git a/src/openai/types/admin/organization/role.py b/src/openai/types/admin/organization/role.py new file mode 100644 index 0000000000..4795144c68 --- /dev/null +++ b/src/openai/types/admin/organization/role.py @@ -0,0 +1,36 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["Role"] + + +class Role(BaseModel): + """Details about a role that can be assigned through the public Roles API.""" + + id: str + """Identifier for the role.""" + + description: Optional[str] = None + """Optional description of the role.""" + + name: str + """Unique name for the role.""" + + object: Literal["role"] + """Always `role`.""" + + permissions: List[str] + """Permissions granted by the role.""" + + predefined_role: bool + """Whether the role is predefined and managed by OpenAI.""" + + resource_type: str + """ + Resource type the role is bound to (for example `api.organization` or + `api.project`). + """ diff --git a/src/openai/types/admin/organization/role_create_params.py b/src/openai/types/admin/organization/role_create_params.py new file mode 100644 index 0000000000..60aaeb7383 --- /dev/null +++ b/src/openai/types/admin/organization/role_create_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Required, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["RoleCreateParams"] + + +class RoleCreateParams(TypedDict, total=False): + permissions: Required[SequenceNotStr[str]] + """Permissions to grant to the role.""" + + role_name: Required[str] + """Unique name for the role.""" + + description: Optional[str] + """Optional description of the role.""" diff --git a/src/openai/types/admin/organization/role_delete_response.py b/src/openai/types/admin/organization/role_delete_response.py new file mode 100644 index 0000000000..934140d363 --- /dev/null +++ b/src/openai/types/admin/organization/role_delete_response.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["RoleDeleteResponse"] + + +class RoleDeleteResponse(BaseModel): + """Confirmation payload returned after deleting a role.""" + + id: str + """Identifier of the deleted role.""" + + deleted: bool + """Whether the role was deleted.""" + + object: Literal["role.deleted"] + """Always `role.deleted`.""" diff --git a/src/openai/types/admin/organization/role_list_params.py b/src/openai/types/admin/organization/role_list_params.py new file mode 100644 index 0000000000..88e957f886 --- /dev/null +++ b/src/openai/types/admin/organization/role_list_params.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["RoleListParams"] + + +class RoleListParams(TypedDict, total=False): + after: str + """Cursor for pagination. + + Provide the value from the previous response's `next` field to continue listing + roles. + """ + + limit: int + """A limit on the number of roles to return. Defaults to 1000.""" + + order: Literal["asc", "desc"] + """Sort order for the returned roles.""" diff --git a/src/openai/types/admin/organization/role_update_params.py b/src/openai/types/admin/organization/role_update_params.py new file mode 100644 index 0000000000..955ca170a8 --- /dev/null +++ b/src/openai/types/admin/organization/role_update_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["RoleUpdateParams"] + + +class RoleUpdateParams(TypedDict, total=False): + description: Optional[str] + """New description for the role.""" + + permissions: Optional[SequenceNotStr[str]] + """Updated set of permissions for the role.""" + + role_name: Optional[str] + """New name for the role.""" diff --git a/src/openai/types/admin/organization/usage_audio_speeches_params.py b/src/openai/types/admin/organization/usage_audio_speeches_params.py new file mode 100644 index 0000000000..5d3eff286c --- /dev/null +++ b/src/openai/types/admin/organization/usage_audio_speeches_params.py @@ -0,0 +1,57 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Literal, Required, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["UsageAudioSpeechesParams"] + + +class UsageAudioSpeechesParams(TypedDict, total=False): + start_time: Required[int] + """Start time (Unix seconds) of the query time range, inclusive.""" + + api_key_ids: SequenceNotStr[str] + """Return only usage for these API keys.""" + + bucket_width: Literal["1m", "1h", "1d"] + """Width of each time bucket in response. + + Currently `1m`, `1h` and `1d` are supported, default to `1d`. + """ + + end_time: int + """End time (Unix seconds) of the query time range, exclusive.""" + + group_by: List[Literal["project_id", "user_id", "api_key_id", "model"]] + """Group the usage data by the specified fields. + + Support fields include `project_id`, `user_id`, `api_key_id`, `model` or any + combination of them. + """ + + limit: int + """Specifies the number of buckets to return. + + - `bucket_width=1d`: default: 7, max: 31 + - `bucket_width=1h`: default: 24, max: 168 + - `bucket_width=1m`: default: 60, max: 1440 + """ + + models: SequenceNotStr[str] + """Return only usage for these models.""" + + page: str + """A cursor for use in pagination. + + Corresponding to the `next_page` field from the previous response. + """ + + project_ids: SequenceNotStr[str] + """Return only usage for these projects.""" + + user_ids: SequenceNotStr[str] + """Return only usage for these users.""" diff --git a/src/openai/types/admin/organization/usage_audio_speeches_response.py b/src/openai/types/admin/organization/usage_audio_speeches_response.py new file mode 100644 index 0000000000..f41ecad30d --- /dev/null +++ b/src/openai/types/admin/organization/usage_audio_speeches_response.py @@ -0,0 +1,390 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ...._utils import PropertyInfo +from ...._models import BaseModel + +__all__ = [ + "UsageAudioSpeechesResponse", + "Data", + "DataResult", + "DataResultOrganizationUsageCompletionsResult", + "DataResultOrganizationUsageEmbeddingsResult", + "DataResultOrganizationUsageModerationsResult", + "DataResultOrganizationUsageImagesResult", + "DataResultOrganizationUsageAudioSpeechesResult", + "DataResultOrganizationUsageAudioTranscriptionsResult", + "DataResultOrganizationUsageVectorStoresResult", + "DataResultOrganizationUsageCodeInterpreterSessionsResult", + "DataResultOrganizationCostsResult", + "DataResultOrganizationCostsResultAmount", +] + + +class DataResultOrganizationUsageCompletionsResult(BaseModel): + """The aggregated completions usage details of the specific time bucket.""" + + input_tokens: int + """The aggregated number of text input tokens used, including cached tokens. + + For customers subscribe to scale tier, this includes scale tier tokens. + """ + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.completions.result"] + + output_tokens: int + """The aggregated number of text output tokens used. + + For customers subscribe to scale tier, this includes scale tier tokens. + """ + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + batch: Optional[bool] = None + """ + When `group_by=batch`, this field tells whether the grouped usage result is + batch or not. + """ + + input_audio_tokens: Optional[int] = None + """The aggregated number of audio input tokens used, including cached tokens.""" + + input_cached_tokens: Optional[int] = None + """ + The aggregated number of text input tokens that has been cached from previous + requests. For customers subscribe to scale tier, this includes scale tier + tokens. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + output_audio_tokens: Optional[int] = None + """The aggregated number of audio output tokens used.""" + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + service_tier: Optional[str] = None + """ + When `group_by=service_tier`, this field provides the service tier of the + grouped usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageEmbeddingsResult(BaseModel): + """The aggregated embeddings usage details of the specific time bucket.""" + + input_tokens: int + """The aggregated number of input tokens used.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.embeddings.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageModerationsResult(BaseModel): + """The aggregated moderations usage details of the specific time bucket.""" + + input_tokens: int + """The aggregated number of input tokens used.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.moderations.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageImagesResult(BaseModel): + """The aggregated images usage details of the specific time bucket.""" + + images: int + """The number of images processed.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.images.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + size: Optional[str] = None + """ + When `group_by=size`, this field provides the image size of the grouped usage + result. + """ + + source: Optional[str] = None + """ + When `group_by=source`, this field provides the source of the grouped usage + result, possible values are `image.generation`, `image.edit`, `image.variation`. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageAudioSpeechesResult(BaseModel): + """The aggregated audio speeches usage details of the specific time bucket.""" + + characters: int + """The number of characters processed.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.audio_speeches.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageAudioTranscriptionsResult(BaseModel): + """The aggregated audio transcriptions usage details of the specific time bucket.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.audio_transcriptions.result"] + + seconds: int + """The number of seconds processed.""" + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageVectorStoresResult(BaseModel): + """The aggregated vector stores usage details of the specific time bucket.""" + + object: Literal["organization.usage.vector_stores.result"] + + usage_bytes: int + """The vector stores usage in bytes.""" + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + +class DataResultOrganizationUsageCodeInterpreterSessionsResult(BaseModel): + """ + The aggregated code interpreter sessions usage details of the specific time bucket. + """ + + object: Literal["organization.usage.code_interpreter_sessions.result"] + + num_sessions: Optional[int] = None + """The number of code interpreter sessions.""" + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + +class DataResultOrganizationCostsResultAmount(BaseModel): + """The monetary value in its associated currency.""" + + currency: Optional[str] = None + """Lowercase ISO-4217 currency e.g. "usd" """ + + value: Optional[float] = None + """The numeric value of the cost.""" + + +class DataResultOrganizationCostsResult(BaseModel): + """The aggregated costs details of the specific time bucket.""" + + object: Literal["organization.costs.result"] + + amount: Optional[DataResultOrganizationCostsResultAmount] = None + """The monetary value in its associated currency.""" + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API Key ID of the grouped + costs result. + """ + + line_item: Optional[str] = None + """ + When `group_by=line_item`, this field provides the line item of the grouped + costs result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + costs result. + """ + + +DataResult: TypeAlias = Annotated[ + Union[ + DataResultOrganizationUsageCompletionsResult, + DataResultOrganizationUsageEmbeddingsResult, + DataResultOrganizationUsageModerationsResult, + DataResultOrganizationUsageImagesResult, + DataResultOrganizationUsageAudioSpeechesResult, + DataResultOrganizationUsageAudioTranscriptionsResult, + DataResultOrganizationUsageVectorStoresResult, + DataResultOrganizationUsageCodeInterpreterSessionsResult, + DataResultOrganizationCostsResult, + ], + PropertyInfo(discriminator="object"), +] + + +class Data(BaseModel): + end_time: int + + object: Literal["bucket"] + + result: List[DataResult] + + start_time: int + + +class UsageAudioSpeechesResponse(BaseModel): + data: List[Data] + + has_more: bool + + next_page: str + + object: Literal["page"] diff --git a/src/openai/types/admin/organization/usage_audio_transcriptions_params.py b/src/openai/types/admin/organization/usage_audio_transcriptions_params.py new file mode 100644 index 0000000000..ca5cd13c78 --- /dev/null +++ b/src/openai/types/admin/organization/usage_audio_transcriptions_params.py @@ -0,0 +1,57 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Literal, Required, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["UsageAudioTranscriptionsParams"] + + +class UsageAudioTranscriptionsParams(TypedDict, total=False): + start_time: Required[int] + """Start time (Unix seconds) of the query time range, inclusive.""" + + api_key_ids: SequenceNotStr[str] + """Return only usage for these API keys.""" + + bucket_width: Literal["1m", "1h", "1d"] + """Width of each time bucket in response. + + Currently `1m`, `1h` and `1d` are supported, default to `1d`. + """ + + end_time: int + """End time (Unix seconds) of the query time range, exclusive.""" + + group_by: List[Literal["project_id", "user_id", "api_key_id", "model"]] + """Group the usage data by the specified fields. + + Support fields include `project_id`, `user_id`, `api_key_id`, `model` or any + combination of them. + """ + + limit: int + """Specifies the number of buckets to return. + + - `bucket_width=1d`: default: 7, max: 31 + - `bucket_width=1h`: default: 24, max: 168 + - `bucket_width=1m`: default: 60, max: 1440 + """ + + models: SequenceNotStr[str] + """Return only usage for these models.""" + + page: str + """A cursor for use in pagination. + + Corresponding to the `next_page` field from the previous response. + """ + + project_ids: SequenceNotStr[str] + """Return only usage for these projects.""" + + user_ids: SequenceNotStr[str] + """Return only usage for these users.""" diff --git a/src/openai/types/admin/organization/usage_audio_transcriptions_response.py b/src/openai/types/admin/organization/usage_audio_transcriptions_response.py new file mode 100644 index 0000000000..2d847dd9ae --- /dev/null +++ b/src/openai/types/admin/organization/usage_audio_transcriptions_response.py @@ -0,0 +1,390 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ...._utils import PropertyInfo +from ...._models import BaseModel + +__all__ = [ + "UsageAudioTranscriptionsResponse", + "Data", + "DataResult", + "DataResultOrganizationUsageCompletionsResult", + "DataResultOrganizationUsageEmbeddingsResult", + "DataResultOrganizationUsageModerationsResult", + "DataResultOrganizationUsageImagesResult", + "DataResultOrganizationUsageAudioSpeechesResult", + "DataResultOrganizationUsageAudioTranscriptionsResult", + "DataResultOrganizationUsageVectorStoresResult", + "DataResultOrganizationUsageCodeInterpreterSessionsResult", + "DataResultOrganizationCostsResult", + "DataResultOrganizationCostsResultAmount", +] + + +class DataResultOrganizationUsageCompletionsResult(BaseModel): + """The aggregated completions usage details of the specific time bucket.""" + + input_tokens: int + """The aggregated number of text input tokens used, including cached tokens. + + For customers subscribe to scale tier, this includes scale tier tokens. + """ + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.completions.result"] + + output_tokens: int + """The aggregated number of text output tokens used. + + For customers subscribe to scale tier, this includes scale tier tokens. + """ + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + batch: Optional[bool] = None + """ + When `group_by=batch`, this field tells whether the grouped usage result is + batch or not. + """ + + input_audio_tokens: Optional[int] = None + """The aggregated number of audio input tokens used, including cached tokens.""" + + input_cached_tokens: Optional[int] = None + """ + The aggregated number of text input tokens that has been cached from previous + requests. For customers subscribe to scale tier, this includes scale tier + tokens. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + output_audio_tokens: Optional[int] = None + """The aggregated number of audio output tokens used.""" + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + service_tier: Optional[str] = None + """ + When `group_by=service_tier`, this field provides the service tier of the + grouped usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageEmbeddingsResult(BaseModel): + """The aggregated embeddings usage details of the specific time bucket.""" + + input_tokens: int + """The aggregated number of input tokens used.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.embeddings.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageModerationsResult(BaseModel): + """The aggregated moderations usage details of the specific time bucket.""" + + input_tokens: int + """The aggregated number of input tokens used.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.moderations.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageImagesResult(BaseModel): + """The aggregated images usage details of the specific time bucket.""" + + images: int + """The number of images processed.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.images.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + size: Optional[str] = None + """ + When `group_by=size`, this field provides the image size of the grouped usage + result. + """ + + source: Optional[str] = None + """ + When `group_by=source`, this field provides the source of the grouped usage + result, possible values are `image.generation`, `image.edit`, `image.variation`. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageAudioSpeechesResult(BaseModel): + """The aggregated audio speeches usage details of the specific time bucket.""" + + characters: int + """The number of characters processed.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.audio_speeches.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageAudioTranscriptionsResult(BaseModel): + """The aggregated audio transcriptions usage details of the specific time bucket.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.audio_transcriptions.result"] + + seconds: int + """The number of seconds processed.""" + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageVectorStoresResult(BaseModel): + """The aggregated vector stores usage details of the specific time bucket.""" + + object: Literal["organization.usage.vector_stores.result"] + + usage_bytes: int + """The vector stores usage in bytes.""" + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + +class DataResultOrganizationUsageCodeInterpreterSessionsResult(BaseModel): + """ + The aggregated code interpreter sessions usage details of the specific time bucket. + """ + + object: Literal["organization.usage.code_interpreter_sessions.result"] + + num_sessions: Optional[int] = None + """The number of code interpreter sessions.""" + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + +class DataResultOrganizationCostsResultAmount(BaseModel): + """The monetary value in its associated currency.""" + + currency: Optional[str] = None + """Lowercase ISO-4217 currency e.g. "usd" """ + + value: Optional[float] = None + """The numeric value of the cost.""" + + +class DataResultOrganizationCostsResult(BaseModel): + """The aggregated costs details of the specific time bucket.""" + + object: Literal["organization.costs.result"] + + amount: Optional[DataResultOrganizationCostsResultAmount] = None + """The monetary value in its associated currency.""" + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API Key ID of the grouped + costs result. + """ + + line_item: Optional[str] = None + """ + When `group_by=line_item`, this field provides the line item of the grouped + costs result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + costs result. + """ + + +DataResult: TypeAlias = Annotated[ + Union[ + DataResultOrganizationUsageCompletionsResult, + DataResultOrganizationUsageEmbeddingsResult, + DataResultOrganizationUsageModerationsResult, + DataResultOrganizationUsageImagesResult, + DataResultOrganizationUsageAudioSpeechesResult, + DataResultOrganizationUsageAudioTranscriptionsResult, + DataResultOrganizationUsageVectorStoresResult, + DataResultOrganizationUsageCodeInterpreterSessionsResult, + DataResultOrganizationCostsResult, + ], + PropertyInfo(discriminator="object"), +] + + +class Data(BaseModel): + end_time: int + + object: Literal["bucket"] + + result: List[DataResult] + + start_time: int + + +class UsageAudioTranscriptionsResponse(BaseModel): + data: List[Data] + + has_more: bool + + next_page: str + + object: Literal["page"] diff --git a/src/openai/types/admin/organization/usage_code_interpreter_sessions_params.py b/src/openai/types/admin/organization/usage_code_interpreter_sessions_params.py new file mode 100644 index 0000000000..dd4b59c2ab --- /dev/null +++ b/src/openai/types/admin/organization/usage_code_interpreter_sessions_params.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Literal, Required, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["UsageCodeInterpreterSessionsParams"] + + +class UsageCodeInterpreterSessionsParams(TypedDict, total=False): + start_time: Required[int] + """Start time (Unix seconds) of the query time range, inclusive.""" + + bucket_width: Literal["1m", "1h", "1d"] + """Width of each time bucket in response. + + Currently `1m`, `1h` and `1d` are supported, default to `1d`. + """ + + end_time: int + """End time (Unix seconds) of the query time range, exclusive.""" + + group_by: List[Literal["project_id"]] + """Group the usage data by the specified fields. + + Support fields include `project_id`. + """ + + limit: int + """Specifies the number of buckets to return. + + - `bucket_width=1d`: default: 7, max: 31 + - `bucket_width=1h`: default: 24, max: 168 + - `bucket_width=1m`: default: 60, max: 1440 + """ + + page: str + """A cursor for use in pagination. + + Corresponding to the `next_page` field from the previous response. + """ + + project_ids: SequenceNotStr[str] + """Return only usage for these projects.""" diff --git a/src/openai/types/admin/organization/usage_code_interpreter_sessions_response.py b/src/openai/types/admin/organization/usage_code_interpreter_sessions_response.py new file mode 100644 index 0000000000..e4634d9a6f --- /dev/null +++ b/src/openai/types/admin/organization/usage_code_interpreter_sessions_response.py @@ -0,0 +1,390 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ...._utils import PropertyInfo +from ...._models import BaseModel + +__all__ = [ + "UsageCodeInterpreterSessionsResponse", + "Data", + "DataResult", + "DataResultOrganizationUsageCompletionsResult", + "DataResultOrganizationUsageEmbeddingsResult", + "DataResultOrganizationUsageModerationsResult", + "DataResultOrganizationUsageImagesResult", + "DataResultOrganizationUsageAudioSpeechesResult", + "DataResultOrganizationUsageAudioTranscriptionsResult", + "DataResultOrganizationUsageVectorStoresResult", + "DataResultOrganizationUsageCodeInterpreterSessionsResult", + "DataResultOrganizationCostsResult", + "DataResultOrganizationCostsResultAmount", +] + + +class DataResultOrganizationUsageCompletionsResult(BaseModel): + """The aggregated completions usage details of the specific time bucket.""" + + input_tokens: int + """The aggregated number of text input tokens used, including cached tokens. + + For customers subscribe to scale tier, this includes scale tier tokens. + """ + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.completions.result"] + + output_tokens: int + """The aggregated number of text output tokens used. + + For customers subscribe to scale tier, this includes scale tier tokens. + """ + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + batch: Optional[bool] = None + """ + When `group_by=batch`, this field tells whether the grouped usage result is + batch or not. + """ + + input_audio_tokens: Optional[int] = None + """The aggregated number of audio input tokens used, including cached tokens.""" + + input_cached_tokens: Optional[int] = None + """ + The aggregated number of text input tokens that has been cached from previous + requests. For customers subscribe to scale tier, this includes scale tier + tokens. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + output_audio_tokens: Optional[int] = None + """The aggregated number of audio output tokens used.""" + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + service_tier: Optional[str] = None + """ + When `group_by=service_tier`, this field provides the service tier of the + grouped usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageEmbeddingsResult(BaseModel): + """The aggregated embeddings usage details of the specific time bucket.""" + + input_tokens: int + """The aggregated number of input tokens used.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.embeddings.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageModerationsResult(BaseModel): + """The aggregated moderations usage details of the specific time bucket.""" + + input_tokens: int + """The aggregated number of input tokens used.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.moderations.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageImagesResult(BaseModel): + """The aggregated images usage details of the specific time bucket.""" + + images: int + """The number of images processed.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.images.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + size: Optional[str] = None + """ + When `group_by=size`, this field provides the image size of the grouped usage + result. + """ + + source: Optional[str] = None + """ + When `group_by=source`, this field provides the source of the grouped usage + result, possible values are `image.generation`, `image.edit`, `image.variation`. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageAudioSpeechesResult(BaseModel): + """The aggregated audio speeches usage details of the specific time bucket.""" + + characters: int + """The number of characters processed.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.audio_speeches.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageAudioTranscriptionsResult(BaseModel): + """The aggregated audio transcriptions usage details of the specific time bucket.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.audio_transcriptions.result"] + + seconds: int + """The number of seconds processed.""" + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageVectorStoresResult(BaseModel): + """The aggregated vector stores usage details of the specific time bucket.""" + + object: Literal["organization.usage.vector_stores.result"] + + usage_bytes: int + """The vector stores usage in bytes.""" + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + +class DataResultOrganizationUsageCodeInterpreterSessionsResult(BaseModel): + """ + The aggregated code interpreter sessions usage details of the specific time bucket. + """ + + object: Literal["organization.usage.code_interpreter_sessions.result"] + + num_sessions: Optional[int] = None + """The number of code interpreter sessions.""" + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + +class DataResultOrganizationCostsResultAmount(BaseModel): + """The monetary value in its associated currency.""" + + currency: Optional[str] = None + """Lowercase ISO-4217 currency e.g. "usd" """ + + value: Optional[float] = None + """The numeric value of the cost.""" + + +class DataResultOrganizationCostsResult(BaseModel): + """The aggregated costs details of the specific time bucket.""" + + object: Literal["organization.costs.result"] + + amount: Optional[DataResultOrganizationCostsResultAmount] = None + """The monetary value in its associated currency.""" + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API Key ID of the grouped + costs result. + """ + + line_item: Optional[str] = None + """ + When `group_by=line_item`, this field provides the line item of the grouped + costs result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + costs result. + """ + + +DataResult: TypeAlias = Annotated[ + Union[ + DataResultOrganizationUsageCompletionsResult, + DataResultOrganizationUsageEmbeddingsResult, + DataResultOrganizationUsageModerationsResult, + DataResultOrganizationUsageImagesResult, + DataResultOrganizationUsageAudioSpeechesResult, + DataResultOrganizationUsageAudioTranscriptionsResult, + DataResultOrganizationUsageVectorStoresResult, + DataResultOrganizationUsageCodeInterpreterSessionsResult, + DataResultOrganizationCostsResult, + ], + PropertyInfo(discriminator="object"), +] + + +class Data(BaseModel): + end_time: int + + object: Literal["bucket"] + + result: List[DataResult] + + start_time: int + + +class UsageCodeInterpreterSessionsResponse(BaseModel): + data: List[Data] + + has_more: bool + + next_page: str + + object: Literal["page"] diff --git a/src/openai/types/admin/organization/usage_completions_params.py b/src/openai/types/admin/organization/usage_completions_params.py new file mode 100644 index 0000000000..e7dbe2187e --- /dev/null +++ b/src/openai/types/admin/organization/usage_completions_params.py @@ -0,0 +1,63 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Literal, Required, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["UsageCompletionsParams"] + + +class UsageCompletionsParams(TypedDict, total=False): + start_time: Required[int] + """Start time (Unix seconds) of the query time range, inclusive.""" + + api_key_ids: SequenceNotStr[str] + """Return only usage for these API keys.""" + + batch: bool + """If `true`, return batch jobs only. + + If `false`, return non-batch jobs only. By default, return both. + """ + + bucket_width: Literal["1m", "1h", "1d"] + """Width of each time bucket in response. + + Currently `1m`, `1h` and `1d` are supported, default to `1d`. + """ + + end_time: int + """End time (Unix seconds) of the query time range, exclusive.""" + + group_by: List[Literal["project_id", "user_id", "api_key_id", "model", "batch", "service_tier"]] + """Group the usage data by the specified fields. + + Support fields include `project_id`, `user_id`, `api_key_id`, `model`, `batch`, + `service_tier` or any combination of them. + """ + + limit: int + """Specifies the number of buckets to return. + + - `bucket_width=1d`: default: 7, max: 31 + - `bucket_width=1h`: default: 24, max: 168 + - `bucket_width=1m`: default: 60, max: 1440 + """ + + models: SequenceNotStr[str] + """Return only usage for these models.""" + + page: str + """A cursor for use in pagination. + + Corresponding to the `next_page` field from the previous response. + """ + + project_ids: SequenceNotStr[str] + """Return only usage for these projects.""" + + user_ids: SequenceNotStr[str] + """Return only usage for these users.""" diff --git a/src/openai/types/admin/organization/usage_completions_response.py b/src/openai/types/admin/organization/usage_completions_response.py new file mode 100644 index 0000000000..a79c79c9bb --- /dev/null +++ b/src/openai/types/admin/organization/usage_completions_response.py @@ -0,0 +1,390 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ...._utils import PropertyInfo +from ...._models import BaseModel + +__all__ = [ + "UsageCompletionsResponse", + "Data", + "DataResult", + "DataResultOrganizationUsageCompletionsResult", + "DataResultOrganizationUsageEmbeddingsResult", + "DataResultOrganizationUsageModerationsResult", + "DataResultOrganizationUsageImagesResult", + "DataResultOrganizationUsageAudioSpeechesResult", + "DataResultOrganizationUsageAudioTranscriptionsResult", + "DataResultOrganizationUsageVectorStoresResult", + "DataResultOrganizationUsageCodeInterpreterSessionsResult", + "DataResultOrganizationCostsResult", + "DataResultOrganizationCostsResultAmount", +] + + +class DataResultOrganizationUsageCompletionsResult(BaseModel): + """The aggregated completions usage details of the specific time bucket.""" + + input_tokens: int + """The aggregated number of text input tokens used, including cached tokens. + + For customers subscribe to scale tier, this includes scale tier tokens. + """ + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.completions.result"] + + output_tokens: int + """The aggregated number of text output tokens used. + + For customers subscribe to scale tier, this includes scale tier tokens. + """ + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + batch: Optional[bool] = None + """ + When `group_by=batch`, this field tells whether the grouped usage result is + batch or not. + """ + + input_audio_tokens: Optional[int] = None + """The aggregated number of audio input tokens used, including cached tokens.""" + + input_cached_tokens: Optional[int] = None + """ + The aggregated number of text input tokens that has been cached from previous + requests. For customers subscribe to scale tier, this includes scale tier + tokens. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + output_audio_tokens: Optional[int] = None + """The aggregated number of audio output tokens used.""" + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + service_tier: Optional[str] = None + """ + When `group_by=service_tier`, this field provides the service tier of the + grouped usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageEmbeddingsResult(BaseModel): + """The aggregated embeddings usage details of the specific time bucket.""" + + input_tokens: int + """The aggregated number of input tokens used.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.embeddings.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageModerationsResult(BaseModel): + """The aggregated moderations usage details of the specific time bucket.""" + + input_tokens: int + """The aggregated number of input tokens used.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.moderations.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageImagesResult(BaseModel): + """The aggregated images usage details of the specific time bucket.""" + + images: int + """The number of images processed.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.images.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + size: Optional[str] = None + """ + When `group_by=size`, this field provides the image size of the grouped usage + result. + """ + + source: Optional[str] = None + """ + When `group_by=source`, this field provides the source of the grouped usage + result, possible values are `image.generation`, `image.edit`, `image.variation`. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageAudioSpeechesResult(BaseModel): + """The aggregated audio speeches usage details of the specific time bucket.""" + + characters: int + """The number of characters processed.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.audio_speeches.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageAudioTranscriptionsResult(BaseModel): + """The aggregated audio transcriptions usage details of the specific time bucket.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.audio_transcriptions.result"] + + seconds: int + """The number of seconds processed.""" + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageVectorStoresResult(BaseModel): + """The aggregated vector stores usage details of the specific time bucket.""" + + object: Literal["organization.usage.vector_stores.result"] + + usage_bytes: int + """The vector stores usage in bytes.""" + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + +class DataResultOrganizationUsageCodeInterpreterSessionsResult(BaseModel): + """ + The aggregated code interpreter sessions usage details of the specific time bucket. + """ + + object: Literal["organization.usage.code_interpreter_sessions.result"] + + num_sessions: Optional[int] = None + """The number of code interpreter sessions.""" + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + +class DataResultOrganizationCostsResultAmount(BaseModel): + """The monetary value in its associated currency.""" + + currency: Optional[str] = None + """Lowercase ISO-4217 currency e.g. "usd" """ + + value: Optional[float] = None + """The numeric value of the cost.""" + + +class DataResultOrganizationCostsResult(BaseModel): + """The aggregated costs details of the specific time bucket.""" + + object: Literal["organization.costs.result"] + + amount: Optional[DataResultOrganizationCostsResultAmount] = None + """The monetary value in its associated currency.""" + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API Key ID of the grouped + costs result. + """ + + line_item: Optional[str] = None + """ + When `group_by=line_item`, this field provides the line item of the grouped + costs result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + costs result. + """ + + +DataResult: TypeAlias = Annotated[ + Union[ + DataResultOrganizationUsageCompletionsResult, + DataResultOrganizationUsageEmbeddingsResult, + DataResultOrganizationUsageModerationsResult, + DataResultOrganizationUsageImagesResult, + DataResultOrganizationUsageAudioSpeechesResult, + DataResultOrganizationUsageAudioTranscriptionsResult, + DataResultOrganizationUsageVectorStoresResult, + DataResultOrganizationUsageCodeInterpreterSessionsResult, + DataResultOrganizationCostsResult, + ], + PropertyInfo(discriminator="object"), +] + + +class Data(BaseModel): + end_time: int + + object: Literal["bucket"] + + result: List[DataResult] + + start_time: int + + +class UsageCompletionsResponse(BaseModel): + data: List[Data] + + has_more: bool + + next_page: str + + object: Literal["page"] diff --git a/src/openai/types/admin/organization/usage_costs_params.py b/src/openai/types/admin/organization/usage_costs_params.py new file mode 100644 index 0000000000..e848643339 --- /dev/null +++ b/src/openai/types/admin/organization/usage_costs_params.py @@ -0,0 +1,49 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Literal, Required, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["UsageCostsParams"] + + +class UsageCostsParams(TypedDict, total=False): + start_time: Required[int] + """Start time (Unix seconds) of the query time range, inclusive.""" + + api_key_ids: SequenceNotStr[str] + """Return only costs for these API keys.""" + + bucket_width: Literal["1d"] + """Width of each time bucket in response. + + Currently only `1d` is supported, default to `1d`. + """ + + end_time: int + """End time (Unix seconds) of the query time range, exclusive.""" + + group_by: List[Literal["project_id", "line_item", "api_key_id"]] + """Group the costs by the specified fields. + + Support fields include `project_id`, `line_item`, `api_key_id` and any + combination of them. + """ + + limit: int + """A limit on the number of buckets to be returned. + + Limit can range between 1 and 180, and the default is 7. + """ + + page: str + """A cursor for use in pagination. + + Corresponding to the `next_page` field from the previous response. + """ + + project_ids: SequenceNotStr[str] + """Return only costs for these projects.""" diff --git a/src/openai/types/admin/organization/usage_costs_response.py b/src/openai/types/admin/organization/usage_costs_response.py new file mode 100644 index 0000000000..004e818242 --- /dev/null +++ b/src/openai/types/admin/organization/usage_costs_response.py @@ -0,0 +1,390 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ...._utils import PropertyInfo +from ...._models import BaseModel + +__all__ = [ + "UsageCostsResponse", + "Data", + "DataResult", + "DataResultOrganizationUsageCompletionsResult", + "DataResultOrganizationUsageEmbeddingsResult", + "DataResultOrganizationUsageModerationsResult", + "DataResultOrganizationUsageImagesResult", + "DataResultOrganizationUsageAudioSpeechesResult", + "DataResultOrganizationUsageAudioTranscriptionsResult", + "DataResultOrganizationUsageVectorStoresResult", + "DataResultOrganizationUsageCodeInterpreterSessionsResult", + "DataResultOrganizationCostsResult", + "DataResultOrganizationCostsResultAmount", +] + + +class DataResultOrganizationUsageCompletionsResult(BaseModel): + """The aggregated completions usage details of the specific time bucket.""" + + input_tokens: int + """The aggregated number of text input tokens used, including cached tokens. + + For customers subscribe to scale tier, this includes scale tier tokens. + """ + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.completions.result"] + + output_tokens: int + """The aggregated number of text output tokens used. + + For customers subscribe to scale tier, this includes scale tier tokens. + """ + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + batch: Optional[bool] = None + """ + When `group_by=batch`, this field tells whether the grouped usage result is + batch or not. + """ + + input_audio_tokens: Optional[int] = None + """The aggregated number of audio input tokens used, including cached tokens.""" + + input_cached_tokens: Optional[int] = None + """ + The aggregated number of text input tokens that has been cached from previous + requests. For customers subscribe to scale tier, this includes scale tier + tokens. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + output_audio_tokens: Optional[int] = None + """The aggregated number of audio output tokens used.""" + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + service_tier: Optional[str] = None + """ + When `group_by=service_tier`, this field provides the service tier of the + grouped usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageEmbeddingsResult(BaseModel): + """The aggregated embeddings usage details of the specific time bucket.""" + + input_tokens: int + """The aggregated number of input tokens used.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.embeddings.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageModerationsResult(BaseModel): + """The aggregated moderations usage details of the specific time bucket.""" + + input_tokens: int + """The aggregated number of input tokens used.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.moderations.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageImagesResult(BaseModel): + """The aggregated images usage details of the specific time bucket.""" + + images: int + """The number of images processed.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.images.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + size: Optional[str] = None + """ + When `group_by=size`, this field provides the image size of the grouped usage + result. + """ + + source: Optional[str] = None + """ + When `group_by=source`, this field provides the source of the grouped usage + result, possible values are `image.generation`, `image.edit`, `image.variation`. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageAudioSpeechesResult(BaseModel): + """The aggregated audio speeches usage details of the specific time bucket.""" + + characters: int + """The number of characters processed.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.audio_speeches.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageAudioTranscriptionsResult(BaseModel): + """The aggregated audio transcriptions usage details of the specific time bucket.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.audio_transcriptions.result"] + + seconds: int + """The number of seconds processed.""" + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageVectorStoresResult(BaseModel): + """The aggregated vector stores usage details of the specific time bucket.""" + + object: Literal["organization.usage.vector_stores.result"] + + usage_bytes: int + """The vector stores usage in bytes.""" + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + +class DataResultOrganizationUsageCodeInterpreterSessionsResult(BaseModel): + """ + The aggregated code interpreter sessions usage details of the specific time bucket. + """ + + object: Literal["organization.usage.code_interpreter_sessions.result"] + + num_sessions: Optional[int] = None + """The number of code interpreter sessions.""" + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + +class DataResultOrganizationCostsResultAmount(BaseModel): + """The monetary value in its associated currency.""" + + currency: Optional[str] = None + """Lowercase ISO-4217 currency e.g. "usd" """ + + value: Optional[float] = None + """The numeric value of the cost.""" + + +class DataResultOrganizationCostsResult(BaseModel): + """The aggregated costs details of the specific time bucket.""" + + object: Literal["organization.costs.result"] + + amount: Optional[DataResultOrganizationCostsResultAmount] = None + """The monetary value in its associated currency.""" + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API Key ID of the grouped + costs result. + """ + + line_item: Optional[str] = None + """ + When `group_by=line_item`, this field provides the line item of the grouped + costs result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + costs result. + """ + + +DataResult: TypeAlias = Annotated[ + Union[ + DataResultOrganizationUsageCompletionsResult, + DataResultOrganizationUsageEmbeddingsResult, + DataResultOrganizationUsageModerationsResult, + DataResultOrganizationUsageImagesResult, + DataResultOrganizationUsageAudioSpeechesResult, + DataResultOrganizationUsageAudioTranscriptionsResult, + DataResultOrganizationUsageVectorStoresResult, + DataResultOrganizationUsageCodeInterpreterSessionsResult, + DataResultOrganizationCostsResult, + ], + PropertyInfo(discriminator="object"), +] + + +class Data(BaseModel): + end_time: int + + object: Literal["bucket"] + + result: List[DataResult] + + start_time: int + + +class UsageCostsResponse(BaseModel): + data: List[Data] + + has_more: bool + + next_page: str + + object: Literal["page"] diff --git a/src/openai/types/admin/organization/usage_embeddings_params.py b/src/openai/types/admin/organization/usage_embeddings_params.py new file mode 100644 index 0000000000..56c9107b51 --- /dev/null +++ b/src/openai/types/admin/organization/usage_embeddings_params.py @@ -0,0 +1,57 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Literal, Required, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["UsageEmbeddingsParams"] + + +class UsageEmbeddingsParams(TypedDict, total=False): + start_time: Required[int] + """Start time (Unix seconds) of the query time range, inclusive.""" + + api_key_ids: SequenceNotStr[str] + """Return only usage for these API keys.""" + + bucket_width: Literal["1m", "1h", "1d"] + """Width of each time bucket in response. + + Currently `1m`, `1h` and `1d` are supported, default to `1d`. + """ + + end_time: int + """End time (Unix seconds) of the query time range, exclusive.""" + + group_by: List[Literal["project_id", "user_id", "api_key_id", "model"]] + """Group the usage data by the specified fields. + + Support fields include `project_id`, `user_id`, `api_key_id`, `model` or any + combination of them. + """ + + limit: int + """Specifies the number of buckets to return. + + - `bucket_width=1d`: default: 7, max: 31 + - `bucket_width=1h`: default: 24, max: 168 + - `bucket_width=1m`: default: 60, max: 1440 + """ + + models: SequenceNotStr[str] + """Return only usage for these models.""" + + page: str + """A cursor for use in pagination. + + Corresponding to the `next_page` field from the previous response. + """ + + project_ids: SequenceNotStr[str] + """Return only usage for these projects.""" + + user_ids: SequenceNotStr[str] + """Return only usage for these users.""" diff --git a/src/openai/types/admin/organization/usage_embeddings_response.py b/src/openai/types/admin/organization/usage_embeddings_response.py new file mode 100644 index 0000000000..f14208507c --- /dev/null +++ b/src/openai/types/admin/organization/usage_embeddings_response.py @@ -0,0 +1,390 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ...._utils import PropertyInfo +from ...._models import BaseModel + +__all__ = [ + "UsageEmbeddingsResponse", + "Data", + "DataResult", + "DataResultOrganizationUsageCompletionsResult", + "DataResultOrganizationUsageEmbeddingsResult", + "DataResultOrganizationUsageModerationsResult", + "DataResultOrganizationUsageImagesResult", + "DataResultOrganizationUsageAudioSpeechesResult", + "DataResultOrganizationUsageAudioTranscriptionsResult", + "DataResultOrganizationUsageVectorStoresResult", + "DataResultOrganizationUsageCodeInterpreterSessionsResult", + "DataResultOrganizationCostsResult", + "DataResultOrganizationCostsResultAmount", +] + + +class DataResultOrganizationUsageCompletionsResult(BaseModel): + """The aggregated completions usage details of the specific time bucket.""" + + input_tokens: int + """The aggregated number of text input tokens used, including cached tokens. + + For customers subscribe to scale tier, this includes scale tier tokens. + """ + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.completions.result"] + + output_tokens: int + """The aggregated number of text output tokens used. + + For customers subscribe to scale tier, this includes scale tier tokens. + """ + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + batch: Optional[bool] = None + """ + When `group_by=batch`, this field tells whether the grouped usage result is + batch or not. + """ + + input_audio_tokens: Optional[int] = None + """The aggregated number of audio input tokens used, including cached tokens.""" + + input_cached_tokens: Optional[int] = None + """ + The aggregated number of text input tokens that has been cached from previous + requests. For customers subscribe to scale tier, this includes scale tier + tokens. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + output_audio_tokens: Optional[int] = None + """The aggregated number of audio output tokens used.""" + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + service_tier: Optional[str] = None + """ + When `group_by=service_tier`, this field provides the service tier of the + grouped usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageEmbeddingsResult(BaseModel): + """The aggregated embeddings usage details of the specific time bucket.""" + + input_tokens: int + """The aggregated number of input tokens used.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.embeddings.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageModerationsResult(BaseModel): + """The aggregated moderations usage details of the specific time bucket.""" + + input_tokens: int + """The aggregated number of input tokens used.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.moderations.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageImagesResult(BaseModel): + """The aggregated images usage details of the specific time bucket.""" + + images: int + """The number of images processed.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.images.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + size: Optional[str] = None + """ + When `group_by=size`, this field provides the image size of the grouped usage + result. + """ + + source: Optional[str] = None + """ + When `group_by=source`, this field provides the source of the grouped usage + result, possible values are `image.generation`, `image.edit`, `image.variation`. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageAudioSpeechesResult(BaseModel): + """The aggregated audio speeches usage details of the specific time bucket.""" + + characters: int + """The number of characters processed.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.audio_speeches.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageAudioTranscriptionsResult(BaseModel): + """The aggregated audio transcriptions usage details of the specific time bucket.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.audio_transcriptions.result"] + + seconds: int + """The number of seconds processed.""" + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageVectorStoresResult(BaseModel): + """The aggregated vector stores usage details of the specific time bucket.""" + + object: Literal["organization.usage.vector_stores.result"] + + usage_bytes: int + """The vector stores usage in bytes.""" + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + +class DataResultOrganizationUsageCodeInterpreterSessionsResult(BaseModel): + """ + The aggregated code interpreter sessions usage details of the specific time bucket. + """ + + object: Literal["organization.usage.code_interpreter_sessions.result"] + + num_sessions: Optional[int] = None + """The number of code interpreter sessions.""" + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + +class DataResultOrganizationCostsResultAmount(BaseModel): + """The monetary value in its associated currency.""" + + currency: Optional[str] = None + """Lowercase ISO-4217 currency e.g. "usd" """ + + value: Optional[float] = None + """The numeric value of the cost.""" + + +class DataResultOrganizationCostsResult(BaseModel): + """The aggregated costs details of the specific time bucket.""" + + object: Literal["organization.costs.result"] + + amount: Optional[DataResultOrganizationCostsResultAmount] = None + """The monetary value in its associated currency.""" + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API Key ID of the grouped + costs result. + """ + + line_item: Optional[str] = None + """ + When `group_by=line_item`, this field provides the line item of the grouped + costs result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + costs result. + """ + + +DataResult: TypeAlias = Annotated[ + Union[ + DataResultOrganizationUsageCompletionsResult, + DataResultOrganizationUsageEmbeddingsResult, + DataResultOrganizationUsageModerationsResult, + DataResultOrganizationUsageImagesResult, + DataResultOrganizationUsageAudioSpeechesResult, + DataResultOrganizationUsageAudioTranscriptionsResult, + DataResultOrganizationUsageVectorStoresResult, + DataResultOrganizationUsageCodeInterpreterSessionsResult, + DataResultOrganizationCostsResult, + ], + PropertyInfo(discriminator="object"), +] + + +class Data(BaseModel): + end_time: int + + object: Literal["bucket"] + + result: List[DataResult] + + start_time: int + + +class UsageEmbeddingsResponse(BaseModel): + data: List[Data] + + has_more: bool + + next_page: str + + object: Literal["page"] diff --git a/src/openai/types/admin/organization/usage_images_params.py b/src/openai/types/admin/organization/usage_images_params.py new file mode 100644 index 0000000000..4cce8c456a --- /dev/null +++ b/src/openai/types/admin/organization/usage_images_params.py @@ -0,0 +1,71 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Literal, Required, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["UsageImagesParams"] + + +class UsageImagesParams(TypedDict, total=False): + start_time: Required[int] + """Start time (Unix seconds) of the query time range, inclusive.""" + + api_key_ids: SequenceNotStr[str] + """Return only usage for these API keys.""" + + bucket_width: Literal["1m", "1h", "1d"] + """Width of each time bucket in response. + + Currently `1m`, `1h` and `1d` are supported, default to `1d`. + """ + + end_time: int + """End time (Unix seconds) of the query time range, exclusive.""" + + group_by: List[Literal["project_id", "user_id", "api_key_id", "model", "size", "source"]] + """Group the usage data by the specified fields. + + Support fields include `project_id`, `user_id`, `api_key_id`, `model`, `size`, + `source` or any combination of them. + """ + + limit: int + """Specifies the number of buckets to return. + + - `bucket_width=1d`: default: 7, max: 31 + - `bucket_width=1h`: default: 24, max: 168 + - `bucket_width=1m`: default: 60, max: 1440 + """ + + models: SequenceNotStr[str] + """Return only usage for these models.""" + + page: str + """A cursor for use in pagination. + + Corresponding to the `next_page` field from the previous response. + """ + + project_ids: SequenceNotStr[str] + """Return only usage for these projects.""" + + sizes: List[Literal["256x256", "512x512", "1024x1024", "1792x1792", "1024x1792"]] + """Return only usages for these image sizes. + + Possible values are `256x256`, `512x512`, `1024x1024`, `1792x1792`, `1024x1792` + or any combination of them. + """ + + sources: List[Literal["image.generation", "image.edit", "image.variation"]] + """Return only usages for these sources. + + Possible values are `image.generation`, `image.edit`, `image.variation` or any + combination of them. + """ + + user_ids: SequenceNotStr[str] + """Return only usage for these users.""" diff --git a/src/openai/types/admin/organization/usage_images_response.py b/src/openai/types/admin/organization/usage_images_response.py new file mode 100644 index 0000000000..0188a51bc4 --- /dev/null +++ b/src/openai/types/admin/organization/usage_images_response.py @@ -0,0 +1,390 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ...._utils import PropertyInfo +from ...._models import BaseModel + +__all__ = [ + "UsageImagesResponse", + "Data", + "DataResult", + "DataResultOrganizationUsageCompletionsResult", + "DataResultOrganizationUsageEmbeddingsResult", + "DataResultOrganizationUsageModerationsResult", + "DataResultOrganizationUsageImagesResult", + "DataResultOrganizationUsageAudioSpeechesResult", + "DataResultOrganizationUsageAudioTranscriptionsResult", + "DataResultOrganizationUsageVectorStoresResult", + "DataResultOrganizationUsageCodeInterpreterSessionsResult", + "DataResultOrganizationCostsResult", + "DataResultOrganizationCostsResultAmount", +] + + +class DataResultOrganizationUsageCompletionsResult(BaseModel): + """The aggregated completions usage details of the specific time bucket.""" + + input_tokens: int + """The aggregated number of text input tokens used, including cached tokens. + + For customers subscribe to scale tier, this includes scale tier tokens. + """ + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.completions.result"] + + output_tokens: int + """The aggregated number of text output tokens used. + + For customers subscribe to scale tier, this includes scale tier tokens. + """ + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + batch: Optional[bool] = None + """ + When `group_by=batch`, this field tells whether the grouped usage result is + batch or not. + """ + + input_audio_tokens: Optional[int] = None + """The aggregated number of audio input tokens used, including cached tokens.""" + + input_cached_tokens: Optional[int] = None + """ + The aggregated number of text input tokens that has been cached from previous + requests. For customers subscribe to scale tier, this includes scale tier + tokens. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + output_audio_tokens: Optional[int] = None + """The aggregated number of audio output tokens used.""" + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + service_tier: Optional[str] = None + """ + When `group_by=service_tier`, this field provides the service tier of the + grouped usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageEmbeddingsResult(BaseModel): + """The aggregated embeddings usage details of the specific time bucket.""" + + input_tokens: int + """The aggregated number of input tokens used.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.embeddings.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageModerationsResult(BaseModel): + """The aggregated moderations usage details of the specific time bucket.""" + + input_tokens: int + """The aggregated number of input tokens used.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.moderations.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageImagesResult(BaseModel): + """The aggregated images usage details of the specific time bucket.""" + + images: int + """The number of images processed.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.images.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + size: Optional[str] = None + """ + When `group_by=size`, this field provides the image size of the grouped usage + result. + """ + + source: Optional[str] = None + """ + When `group_by=source`, this field provides the source of the grouped usage + result, possible values are `image.generation`, `image.edit`, `image.variation`. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageAudioSpeechesResult(BaseModel): + """The aggregated audio speeches usage details of the specific time bucket.""" + + characters: int + """The number of characters processed.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.audio_speeches.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageAudioTranscriptionsResult(BaseModel): + """The aggregated audio transcriptions usage details of the specific time bucket.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.audio_transcriptions.result"] + + seconds: int + """The number of seconds processed.""" + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageVectorStoresResult(BaseModel): + """The aggregated vector stores usage details of the specific time bucket.""" + + object: Literal["organization.usage.vector_stores.result"] + + usage_bytes: int + """The vector stores usage in bytes.""" + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + +class DataResultOrganizationUsageCodeInterpreterSessionsResult(BaseModel): + """ + The aggregated code interpreter sessions usage details of the specific time bucket. + """ + + object: Literal["organization.usage.code_interpreter_sessions.result"] + + num_sessions: Optional[int] = None + """The number of code interpreter sessions.""" + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + +class DataResultOrganizationCostsResultAmount(BaseModel): + """The monetary value in its associated currency.""" + + currency: Optional[str] = None + """Lowercase ISO-4217 currency e.g. "usd" """ + + value: Optional[float] = None + """The numeric value of the cost.""" + + +class DataResultOrganizationCostsResult(BaseModel): + """The aggregated costs details of the specific time bucket.""" + + object: Literal["organization.costs.result"] + + amount: Optional[DataResultOrganizationCostsResultAmount] = None + """The monetary value in its associated currency.""" + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API Key ID of the grouped + costs result. + """ + + line_item: Optional[str] = None + """ + When `group_by=line_item`, this field provides the line item of the grouped + costs result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + costs result. + """ + + +DataResult: TypeAlias = Annotated[ + Union[ + DataResultOrganizationUsageCompletionsResult, + DataResultOrganizationUsageEmbeddingsResult, + DataResultOrganizationUsageModerationsResult, + DataResultOrganizationUsageImagesResult, + DataResultOrganizationUsageAudioSpeechesResult, + DataResultOrganizationUsageAudioTranscriptionsResult, + DataResultOrganizationUsageVectorStoresResult, + DataResultOrganizationUsageCodeInterpreterSessionsResult, + DataResultOrganizationCostsResult, + ], + PropertyInfo(discriminator="object"), +] + + +class Data(BaseModel): + end_time: int + + object: Literal["bucket"] + + result: List[DataResult] + + start_time: int + + +class UsageImagesResponse(BaseModel): + data: List[Data] + + has_more: bool + + next_page: str + + object: Literal["page"] diff --git a/src/openai/types/admin/organization/usage_moderations_params.py b/src/openai/types/admin/organization/usage_moderations_params.py new file mode 100644 index 0000000000..acb401b9a8 --- /dev/null +++ b/src/openai/types/admin/organization/usage_moderations_params.py @@ -0,0 +1,57 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Literal, Required, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["UsageModerationsParams"] + + +class UsageModerationsParams(TypedDict, total=False): + start_time: Required[int] + """Start time (Unix seconds) of the query time range, inclusive.""" + + api_key_ids: SequenceNotStr[str] + """Return only usage for these API keys.""" + + bucket_width: Literal["1m", "1h", "1d"] + """Width of each time bucket in response. + + Currently `1m`, `1h` and `1d` are supported, default to `1d`. + """ + + end_time: int + """End time (Unix seconds) of the query time range, exclusive.""" + + group_by: List[Literal["project_id", "user_id", "api_key_id", "model"]] + """Group the usage data by the specified fields. + + Support fields include `project_id`, `user_id`, `api_key_id`, `model` or any + combination of them. + """ + + limit: int + """Specifies the number of buckets to return. + + - `bucket_width=1d`: default: 7, max: 31 + - `bucket_width=1h`: default: 24, max: 168 + - `bucket_width=1m`: default: 60, max: 1440 + """ + + models: SequenceNotStr[str] + """Return only usage for these models.""" + + page: str + """A cursor for use in pagination. + + Corresponding to the `next_page` field from the previous response. + """ + + project_ids: SequenceNotStr[str] + """Return only usage for these projects.""" + + user_ids: SequenceNotStr[str] + """Return only usage for these users.""" diff --git a/src/openai/types/admin/organization/usage_moderations_response.py b/src/openai/types/admin/organization/usage_moderations_response.py new file mode 100644 index 0000000000..fc99593e5d --- /dev/null +++ b/src/openai/types/admin/organization/usage_moderations_response.py @@ -0,0 +1,390 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ...._utils import PropertyInfo +from ...._models import BaseModel + +__all__ = [ + "UsageModerationsResponse", + "Data", + "DataResult", + "DataResultOrganizationUsageCompletionsResult", + "DataResultOrganizationUsageEmbeddingsResult", + "DataResultOrganizationUsageModerationsResult", + "DataResultOrganizationUsageImagesResult", + "DataResultOrganizationUsageAudioSpeechesResult", + "DataResultOrganizationUsageAudioTranscriptionsResult", + "DataResultOrganizationUsageVectorStoresResult", + "DataResultOrganizationUsageCodeInterpreterSessionsResult", + "DataResultOrganizationCostsResult", + "DataResultOrganizationCostsResultAmount", +] + + +class DataResultOrganizationUsageCompletionsResult(BaseModel): + """The aggregated completions usage details of the specific time bucket.""" + + input_tokens: int + """The aggregated number of text input tokens used, including cached tokens. + + For customers subscribe to scale tier, this includes scale tier tokens. + """ + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.completions.result"] + + output_tokens: int + """The aggregated number of text output tokens used. + + For customers subscribe to scale tier, this includes scale tier tokens. + """ + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + batch: Optional[bool] = None + """ + When `group_by=batch`, this field tells whether the grouped usage result is + batch or not. + """ + + input_audio_tokens: Optional[int] = None + """The aggregated number of audio input tokens used, including cached tokens.""" + + input_cached_tokens: Optional[int] = None + """ + The aggregated number of text input tokens that has been cached from previous + requests. For customers subscribe to scale tier, this includes scale tier + tokens. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + output_audio_tokens: Optional[int] = None + """The aggregated number of audio output tokens used.""" + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + service_tier: Optional[str] = None + """ + When `group_by=service_tier`, this field provides the service tier of the + grouped usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageEmbeddingsResult(BaseModel): + """The aggregated embeddings usage details of the specific time bucket.""" + + input_tokens: int + """The aggregated number of input tokens used.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.embeddings.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageModerationsResult(BaseModel): + """The aggregated moderations usage details of the specific time bucket.""" + + input_tokens: int + """The aggregated number of input tokens used.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.moderations.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageImagesResult(BaseModel): + """The aggregated images usage details of the specific time bucket.""" + + images: int + """The number of images processed.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.images.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + size: Optional[str] = None + """ + When `group_by=size`, this field provides the image size of the grouped usage + result. + """ + + source: Optional[str] = None + """ + When `group_by=source`, this field provides the source of the grouped usage + result, possible values are `image.generation`, `image.edit`, `image.variation`. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageAudioSpeechesResult(BaseModel): + """The aggregated audio speeches usage details of the specific time bucket.""" + + characters: int + """The number of characters processed.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.audio_speeches.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageAudioTranscriptionsResult(BaseModel): + """The aggregated audio transcriptions usage details of the specific time bucket.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.audio_transcriptions.result"] + + seconds: int + """The number of seconds processed.""" + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageVectorStoresResult(BaseModel): + """The aggregated vector stores usage details of the specific time bucket.""" + + object: Literal["organization.usage.vector_stores.result"] + + usage_bytes: int + """The vector stores usage in bytes.""" + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + +class DataResultOrganizationUsageCodeInterpreterSessionsResult(BaseModel): + """ + The aggregated code interpreter sessions usage details of the specific time bucket. + """ + + object: Literal["organization.usage.code_interpreter_sessions.result"] + + num_sessions: Optional[int] = None + """The number of code interpreter sessions.""" + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + +class DataResultOrganizationCostsResultAmount(BaseModel): + """The monetary value in its associated currency.""" + + currency: Optional[str] = None + """Lowercase ISO-4217 currency e.g. "usd" """ + + value: Optional[float] = None + """The numeric value of the cost.""" + + +class DataResultOrganizationCostsResult(BaseModel): + """The aggregated costs details of the specific time bucket.""" + + object: Literal["organization.costs.result"] + + amount: Optional[DataResultOrganizationCostsResultAmount] = None + """The monetary value in its associated currency.""" + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API Key ID of the grouped + costs result. + """ + + line_item: Optional[str] = None + """ + When `group_by=line_item`, this field provides the line item of the grouped + costs result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + costs result. + """ + + +DataResult: TypeAlias = Annotated[ + Union[ + DataResultOrganizationUsageCompletionsResult, + DataResultOrganizationUsageEmbeddingsResult, + DataResultOrganizationUsageModerationsResult, + DataResultOrganizationUsageImagesResult, + DataResultOrganizationUsageAudioSpeechesResult, + DataResultOrganizationUsageAudioTranscriptionsResult, + DataResultOrganizationUsageVectorStoresResult, + DataResultOrganizationUsageCodeInterpreterSessionsResult, + DataResultOrganizationCostsResult, + ], + PropertyInfo(discriminator="object"), +] + + +class Data(BaseModel): + end_time: int + + object: Literal["bucket"] + + result: List[DataResult] + + start_time: int + + +class UsageModerationsResponse(BaseModel): + data: List[Data] + + has_more: bool + + next_page: str + + object: Literal["page"] diff --git a/src/openai/types/admin/organization/usage_vector_stores_params.py b/src/openai/types/admin/organization/usage_vector_stores_params.py new file mode 100644 index 0000000000..bfb8dcede4 --- /dev/null +++ b/src/openai/types/admin/organization/usage_vector_stores_params.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Literal, Required, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["UsageVectorStoresParams"] + + +class UsageVectorStoresParams(TypedDict, total=False): + start_time: Required[int] + """Start time (Unix seconds) of the query time range, inclusive.""" + + bucket_width: Literal["1m", "1h", "1d"] + """Width of each time bucket in response. + + Currently `1m`, `1h` and `1d` are supported, default to `1d`. + """ + + end_time: int + """End time (Unix seconds) of the query time range, exclusive.""" + + group_by: List[Literal["project_id"]] + """Group the usage data by the specified fields. + + Support fields include `project_id`. + """ + + limit: int + """Specifies the number of buckets to return. + + - `bucket_width=1d`: default: 7, max: 31 + - `bucket_width=1h`: default: 24, max: 168 + - `bucket_width=1m`: default: 60, max: 1440 + """ + + page: str + """A cursor for use in pagination. + + Corresponding to the `next_page` field from the previous response. + """ + + project_ids: SequenceNotStr[str] + """Return only usage for these projects.""" diff --git a/src/openai/types/admin/organization/usage_vector_stores_response.py b/src/openai/types/admin/organization/usage_vector_stores_response.py new file mode 100644 index 0000000000..f17e867af0 --- /dev/null +++ b/src/openai/types/admin/organization/usage_vector_stores_response.py @@ -0,0 +1,390 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ...._utils import PropertyInfo +from ...._models import BaseModel + +__all__ = [ + "UsageVectorStoresResponse", + "Data", + "DataResult", + "DataResultOrganizationUsageCompletionsResult", + "DataResultOrganizationUsageEmbeddingsResult", + "DataResultOrganizationUsageModerationsResult", + "DataResultOrganizationUsageImagesResult", + "DataResultOrganizationUsageAudioSpeechesResult", + "DataResultOrganizationUsageAudioTranscriptionsResult", + "DataResultOrganizationUsageVectorStoresResult", + "DataResultOrganizationUsageCodeInterpreterSessionsResult", + "DataResultOrganizationCostsResult", + "DataResultOrganizationCostsResultAmount", +] + + +class DataResultOrganizationUsageCompletionsResult(BaseModel): + """The aggregated completions usage details of the specific time bucket.""" + + input_tokens: int + """The aggregated number of text input tokens used, including cached tokens. + + For customers subscribe to scale tier, this includes scale tier tokens. + """ + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.completions.result"] + + output_tokens: int + """The aggregated number of text output tokens used. + + For customers subscribe to scale tier, this includes scale tier tokens. + """ + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + batch: Optional[bool] = None + """ + When `group_by=batch`, this field tells whether the grouped usage result is + batch or not. + """ + + input_audio_tokens: Optional[int] = None + """The aggregated number of audio input tokens used, including cached tokens.""" + + input_cached_tokens: Optional[int] = None + """ + The aggregated number of text input tokens that has been cached from previous + requests. For customers subscribe to scale tier, this includes scale tier + tokens. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + output_audio_tokens: Optional[int] = None + """The aggregated number of audio output tokens used.""" + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + service_tier: Optional[str] = None + """ + When `group_by=service_tier`, this field provides the service tier of the + grouped usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageEmbeddingsResult(BaseModel): + """The aggregated embeddings usage details of the specific time bucket.""" + + input_tokens: int + """The aggregated number of input tokens used.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.embeddings.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageModerationsResult(BaseModel): + """The aggregated moderations usage details of the specific time bucket.""" + + input_tokens: int + """The aggregated number of input tokens used.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.moderations.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageImagesResult(BaseModel): + """The aggregated images usage details of the specific time bucket.""" + + images: int + """The number of images processed.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.images.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + size: Optional[str] = None + """ + When `group_by=size`, this field provides the image size of the grouped usage + result. + """ + + source: Optional[str] = None + """ + When `group_by=source`, this field provides the source of the grouped usage + result, possible values are `image.generation`, `image.edit`, `image.variation`. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageAudioSpeechesResult(BaseModel): + """The aggregated audio speeches usage details of the specific time bucket.""" + + characters: int + """The number of characters processed.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.audio_speeches.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageAudioTranscriptionsResult(BaseModel): + """The aggregated audio transcriptions usage details of the specific time bucket.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.audio_transcriptions.result"] + + seconds: int + """The number of seconds processed.""" + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageVectorStoresResult(BaseModel): + """The aggregated vector stores usage details of the specific time bucket.""" + + object: Literal["organization.usage.vector_stores.result"] + + usage_bytes: int + """The vector stores usage in bytes.""" + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + +class DataResultOrganizationUsageCodeInterpreterSessionsResult(BaseModel): + """ + The aggregated code interpreter sessions usage details of the specific time bucket. + """ + + object: Literal["organization.usage.code_interpreter_sessions.result"] + + num_sessions: Optional[int] = None + """The number of code interpreter sessions.""" + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + +class DataResultOrganizationCostsResultAmount(BaseModel): + """The monetary value in its associated currency.""" + + currency: Optional[str] = None + """Lowercase ISO-4217 currency e.g. "usd" """ + + value: Optional[float] = None + """The numeric value of the cost.""" + + +class DataResultOrganizationCostsResult(BaseModel): + """The aggregated costs details of the specific time bucket.""" + + object: Literal["organization.costs.result"] + + amount: Optional[DataResultOrganizationCostsResultAmount] = None + """The monetary value in its associated currency.""" + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API Key ID of the grouped + costs result. + """ + + line_item: Optional[str] = None + """ + When `group_by=line_item`, this field provides the line item of the grouped + costs result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + costs result. + """ + + +DataResult: TypeAlias = Annotated[ + Union[ + DataResultOrganizationUsageCompletionsResult, + DataResultOrganizationUsageEmbeddingsResult, + DataResultOrganizationUsageModerationsResult, + DataResultOrganizationUsageImagesResult, + DataResultOrganizationUsageAudioSpeechesResult, + DataResultOrganizationUsageAudioTranscriptionsResult, + DataResultOrganizationUsageVectorStoresResult, + DataResultOrganizationUsageCodeInterpreterSessionsResult, + DataResultOrganizationCostsResult, + ], + PropertyInfo(discriminator="object"), +] + + +class Data(BaseModel): + end_time: int + + object: Literal["bucket"] + + result: List[DataResult] + + start_time: int + + +class UsageVectorStoresResponse(BaseModel): + data: List[Data] + + has_more: bool + + next_page: str + + object: Literal["page"] diff --git a/src/openai/types/admin/organization/user_delete_response.py b/src/openai/types/admin/organization/user_delete_response.py new file mode 100644 index 0000000000..b8fc8c994a --- /dev/null +++ b/src/openai/types/admin/organization/user_delete_response.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["UserDeleteResponse"] + + +class UserDeleteResponse(BaseModel): + id: str + + deleted: bool + + object: Literal["organization.user.deleted"] diff --git a/src/openai/types/admin/organization/user_list_params.py b/src/openai/types/admin/organization/user_list_params.py new file mode 100644 index 0000000000..7bcfc78979 --- /dev/null +++ b/src/openai/types/admin/organization/user_list_params.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["UserListParams"] + + +class UserListParams(TypedDict, total=False): + after: str + """A cursor for use in pagination. + + `after` is an object ID that defines your place in the list. For instance, if + you make a list request and receive 100 objects, ending with obj_foo, your + subsequent call can include after=obj_foo in order to fetch the next page of the + list. + """ + + emails: SequenceNotStr[str] + """Filter by the email address of users.""" + + limit: int + """A limit on the number of objects to be returned. + + Limit can range between 1 and 100, and the default is 20. + """ diff --git a/src/openai/types/admin/organization/user_update_params.py b/src/openai/types/admin/organization/user_update_params.py new file mode 100644 index 0000000000..bc276120e3 --- /dev/null +++ b/src/openai/types/admin/organization/user_update_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["UserUpdateParams"] + + +class UserUpdateParams(TypedDict, total=False): + role: Required[Literal["owner", "reader"]] + """`owner` or `reader`""" diff --git a/src/openai/types/admin/organization/users/__init__.py b/src/openai/types/admin/organization/users/__init__.py new file mode 100644 index 0000000000..ed464fde83 --- /dev/null +++ b/src/openai/types/admin/organization/users/__init__.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .role_list_params import RoleListParams as RoleListParams +from .role_create_params import RoleCreateParams as RoleCreateParams +from .role_list_response import RoleListResponse as RoleListResponse +from .role_create_response import RoleCreateResponse as RoleCreateResponse +from .role_delete_response import RoleDeleteResponse as RoleDeleteResponse diff --git a/src/openai/types/admin/organization/users/role_create_params.py b/src/openai/types/admin/organization/users/role_create_params.py new file mode 100644 index 0000000000..0ebc196eef --- /dev/null +++ b/src/openai/types/admin/organization/users/role_create_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["RoleCreateParams"] + + +class RoleCreateParams(TypedDict, total=False): + role_id: Required[str] + """Identifier of the role to assign.""" diff --git a/src/openai/types/admin/organization/users/role_create_response.py b/src/openai/types/admin/organization/users/role_create_response.py new file mode 100644 index 0000000000..0b989ad461 --- /dev/null +++ b/src/openai/types/admin/organization/users/role_create_response.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..role import Role +from ....._models import BaseModel +from ..organization_user import OrganizationUser + +__all__ = ["RoleCreateResponse"] + + +class RoleCreateResponse(BaseModel): + """Role assignment linking a user to a role.""" + + object: Literal["user.role"] + """Always `user.role`.""" + + role: Role + """Details about a role that can be assigned through the public Roles API.""" + + user: OrganizationUser + """Represents an individual `user` within an organization.""" diff --git a/src/openai/types/admin/organization/users/role_delete_response.py b/src/openai/types/admin/organization/users/role_delete_response.py new file mode 100644 index 0000000000..fb6a111614 --- /dev/null +++ b/src/openai/types/admin/organization/users/role_delete_response.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ....._models import BaseModel + +__all__ = ["RoleDeleteResponse"] + + +class RoleDeleteResponse(BaseModel): + """Confirmation payload returned after unassigning a role.""" + + deleted: bool + """Whether the assignment was removed.""" + + object: str + """ + Identifier for the deleted assignment, such as `group.role.deleted` or + `user.role.deleted`. + """ diff --git a/src/openai/types/admin/organization/users/role_list_params.py b/src/openai/types/admin/organization/users/role_list_params.py new file mode 100644 index 0000000000..451a1a2045 --- /dev/null +++ b/src/openai/types/admin/organization/users/role_list_params.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["RoleListParams"] + + +class RoleListParams(TypedDict, total=False): + after: str + """Cursor for pagination. + + Provide the value from the previous response's `next` field to continue listing + organization roles. + """ + + limit: int + """A limit on the number of organization role assignments to return.""" + + order: Literal["asc", "desc"] + """Sort order for the returned organization roles.""" diff --git a/src/openai/types/admin/organization/users/role_list_response.py b/src/openai/types/admin/organization/users/role_list_response.py new file mode 100644 index 0000000000..337d517ba1 --- /dev/null +++ b/src/openai/types/admin/organization/users/role_list_response.py @@ -0,0 +1,46 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional + +from ....._models import BaseModel + +__all__ = ["RoleListResponse"] + + +class RoleListResponse(BaseModel): + """ + Detailed information about a role assignment entry returned when listing assignments. + """ + + id: str + """Identifier for the role.""" + + created_at: Optional[int] = None + """When the role was created.""" + + created_by: Optional[str] = None + """Identifier of the actor who created the role.""" + + created_by_user_obj: Optional[Dict[str, object]] = None + """User details for the actor that created the role, when available.""" + + description: Optional[str] = None + """Description of the role.""" + + metadata: Optional[Dict[str, object]] = None + """Arbitrary metadata stored on the role.""" + + name: str + """Name of the role.""" + + permissions: List[str] + """Permissions associated with the role.""" + + predefined_role: bool + """Whether the role is predefined by OpenAI.""" + + resource_type: str + """Resource type the role applies to.""" + + updated_at: Optional[int] = None + """When the role was last updated.""" diff --git a/tests/api_resources/admin/organization/groups/__init__.py b/tests/api_resources/admin/organization/groups/__init__.py new file mode 100644 index 0000000000..fd8019a9a1 --- /dev/null +++ b/tests/api_resources/admin/organization/groups/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/admin/organization/groups/test_roles.py b/tests/api_resources/admin/organization/groups/test_roles.py new file mode 100644 index 0000000000..73e8feabdb --- /dev/null +++ b/tests/api_resources/admin/organization/groups/test_roles.py @@ -0,0 +1,305 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.pagination import SyncCursorPage, AsyncCursorPage +from openai.types.admin.organization.groups import ( + RoleListResponse, + RoleCreateResponse, + RoleDeleteResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestRoles: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: OpenAI) -> None: + role = client.admin.organization.groups.roles.create( + group_id="group_id", + role_id="role_id", + ) + assert_matches_type(RoleCreateResponse, role, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: OpenAI) -> None: + response = client.admin.organization.groups.roles.with_raw_response.create( + group_id="group_id", + role_id="role_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(RoleCreateResponse, role, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: OpenAI) -> None: + with client.admin.organization.groups.roles.with_streaming_response.create( + group_id="group_id", + role_id="role_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = response.parse() + assert_matches_type(RoleCreateResponse, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_create(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + client.admin.organization.groups.roles.with_raw_response.create( + group_id="", + role_id="role_id", + ) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + role = client.admin.organization.groups.roles.list( + group_id="group_id", + ) + assert_matches_type(SyncCursorPage[RoleListResponse], role, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + role = client.admin.organization.groups.roles.list( + group_id="group_id", + after="after", + limit=0, + order="asc", + ) + assert_matches_type(SyncCursorPage[RoleListResponse], role, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.admin.organization.groups.roles.with_raw_response.list( + group_id="group_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(SyncCursorPage[RoleListResponse], role, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.admin.organization.groups.roles.with_streaming_response.list( + group_id="group_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = response.parse() + assert_matches_type(SyncCursorPage[RoleListResponse], role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + client.admin.organization.groups.roles.with_raw_response.list( + group_id="", + ) + + @parametrize + def test_method_delete(self, client: OpenAI) -> None: + role = client.admin.organization.groups.roles.delete( + role_id="role_id", + group_id="group_id", + ) + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: OpenAI) -> None: + response = client.admin.organization.groups.roles.with_raw_response.delete( + role_id="role_id", + group_id="group_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: OpenAI) -> None: + with client.admin.organization.groups.roles.with_streaming_response.delete( + role_id="role_id", + group_id="group_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = response.parse() + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + client.admin.organization.groups.roles.with_raw_response.delete( + role_id="role_id", + group_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): + client.admin.organization.groups.roles.with_raw_response.delete( + role_id="", + group_id="group_id", + ) + + +class TestAsyncRoles: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.groups.roles.create( + group_id="group_id", + role_id="role_id", + ) + assert_matches_type(RoleCreateResponse, role, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.groups.roles.with_raw_response.create( + group_id="group_id", + role_id="role_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(RoleCreateResponse, role, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.groups.roles.with_streaming_response.create( + group_id="group_id", + role_id="role_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = await response.parse() + assert_matches_type(RoleCreateResponse, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + await async_client.admin.organization.groups.roles.with_raw_response.create( + group_id="", + role_id="role_id", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.groups.roles.list( + group_id="group_id", + ) + assert_matches_type(AsyncCursorPage[RoleListResponse], role, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.groups.roles.list( + group_id="group_id", + after="after", + limit=0, + order="asc", + ) + assert_matches_type(AsyncCursorPage[RoleListResponse], role, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.groups.roles.with_raw_response.list( + group_id="group_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(AsyncCursorPage[RoleListResponse], role, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.groups.roles.with_streaming_response.list( + group_id="group_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = await response.parse() + assert_matches_type(AsyncCursorPage[RoleListResponse], role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + await async_client.admin.organization.groups.roles.with_raw_response.list( + group_id="", + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.groups.roles.delete( + role_id="role_id", + group_id="group_id", + ) + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.groups.roles.with_raw_response.delete( + role_id="role_id", + group_id="group_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.groups.roles.with_streaming_response.delete( + role_id="role_id", + group_id="group_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = await response.parse() + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + await async_client.admin.organization.groups.roles.with_raw_response.delete( + role_id="role_id", + group_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): + await async_client.admin.organization.groups.roles.with_raw_response.delete( + role_id="", + group_id="group_id", + ) diff --git a/tests/api_resources/admin/organization/groups/test_users.py b/tests/api_resources/admin/organization/groups/test_users.py new file mode 100644 index 0000000000..cfa6354f99 --- /dev/null +++ b/tests/api_resources/admin/organization/groups/test_users.py @@ -0,0 +1,305 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.pagination import SyncCursorPage, AsyncCursorPage +from openai.types.admin.organization import OrganizationUser +from openai.types.admin.organization.groups import ( + UserCreateResponse, + UserDeleteResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestUsers: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: OpenAI) -> None: + user = client.admin.organization.groups.users.create( + group_id="group_id", + user_id="user_id", + ) + assert_matches_type(UserCreateResponse, user, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: OpenAI) -> None: + response = client.admin.organization.groups.users.with_raw_response.create( + group_id="group_id", + user_id="user_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(UserCreateResponse, user, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: OpenAI) -> None: + with client.admin.organization.groups.users.with_streaming_response.create( + group_id="group_id", + user_id="user_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = response.parse() + assert_matches_type(UserCreateResponse, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_create(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + client.admin.organization.groups.users.with_raw_response.create( + group_id="", + user_id="user_id", + ) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + user = client.admin.organization.groups.users.list( + group_id="group_id", + ) + assert_matches_type(SyncCursorPage[OrganizationUser], user, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + user = client.admin.organization.groups.users.list( + group_id="group_id", + after="after", + limit=0, + order="asc", + ) + assert_matches_type(SyncCursorPage[OrganizationUser], user, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.admin.organization.groups.users.with_raw_response.list( + group_id="group_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(SyncCursorPage[OrganizationUser], user, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.admin.organization.groups.users.with_streaming_response.list( + group_id="group_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = response.parse() + assert_matches_type(SyncCursorPage[OrganizationUser], user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + client.admin.organization.groups.users.with_raw_response.list( + group_id="", + ) + + @parametrize + def test_method_delete(self, client: OpenAI) -> None: + user = client.admin.organization.groups.users.delete( + user_id="user_id", + group_id="group_id", + ) + assert_matches_type(UserDeleteResponse, user, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: OpenAI) -> None: + response = client.admin.organization.groups.users.with_raw_response.delete( + user_id="user_id", + group_id="group_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(UserDeleteResponse, user, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: OpenAI) -> None: + with client.admin.organization.groups.users.with_streaming_response.delete( + user_id="user_id", + group_id="group_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = response.parse() + assert_matches_type(UserDeleteResponse, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + client.admin.organization.groups.users.with_raw_response.delete( + user_id="user_id", + group_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): + client.admin.organization.groups.users.with_raw_response.delete( + user_id="", + group_id="group_id", + ) + + +class TestAsyncUsers: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncOpenAI) -> None: + user = await async_client.admin.organization.groups.users.create( + group_id="group_id", + user_id="user_id", + ) + assert_matches_type(UserCreateResponse, user, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.groups.users.with_raw_response.create( + group_id="group_id", + user_id="user_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(UserCreateResponse, user, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.groups.users.with_streaming_response.create( + group_id="group_id", + user_id="user_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = await response.parse() + assert_matches_type(UserCreateResponse, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + await async_client.admin.organization.groups.users.with_raw_response.create( + group_id="", + user_id="user_id", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + user = await async_client.admin.organization.groups.users.list( + group_id="group_id", + ) + assert_matches_type(AsyncCursorPage[OrganizationUser], user, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + user = await async_client.admin.organization.groups.users.list( + group_id="group_id", + after="after", + limit=0, + order="asc", + ) + assert_matches_type(AsyncCursorPage[OrganizationUser], user, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.groups.users.with_raw_response.list( + group_id="group_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(AsyncCursorPage[OrganizationUser], user, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.groups.users.with_streaming_response.list( + group_id="group_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = await response.parse() + assert_matches_type(AsyncCursorPage[OrganizationUser], user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + await async_client.admin.organization.groups.users.with_raw_response.list( + group_id="", + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncOpenAI) -> None: + user = await async_client.admin.organization.groups.users.delete( + user_id="user_id", + group_id="group_id", + ) + assert_matches_type(UserDeleteResponse, user, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.groups.users.with_raw_response.delete( + user_id="user_id", + group_id="group_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(UserDeleteResponse, user, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.groups.users.with_streaming_response.delete( + user_id="user_id", + group_id="group_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = await response.parse() + assert_matches_type(UserDeleteResponse, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + await async_client.admin.organization.groups.users.with_raw_response.delete( + user_id="user_id", + group_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): + await async_client.admin.organization.groups.users.with_raw_response.delete( + user_id="", + group_id="group_id", + ) diff --git a/tests/api_resources/admin/organization/projects/__init__.py b/tests/api_resources/admin/organization/projects/__init__.py new file mode 100644 index 0000000000..fd8019a9a1 --- /dev/null +++ b/tests/api_resources/admin/organization/projects/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/admin/organization/projects/groups/__init__.py b/tests/api_resources/admin/organization/projects/groups/__init__.py new file mode 100644 index 0000000000..fd8019a9a1 --- /dev/null +++ b/tests/api_resources/admin/organization/projects/groups/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/admin/organization/projects/groups/test_roles.py b/tests/api_resources/admin/organization/projects/groups/test_roles.py new file mode 100644 index 0000000000..4cfc957962 --- /dev/null +++ b/tests/api_resources/admin/organization/projects/groups/test_roles.py @@ -0,0 +1,373 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.pagination import SyncCursorPage, AsyncCursorPage +from openai.types.admin.organization.projects.groups import ( + RoleListResponse, + RoleCreateResponse, + RoleDeleteResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestRoles: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: OpenAI) -> None: + role = client.admin.organization.projects.groups.roles.create( + group_id="group_id", + project_id="project_id", + role_id="role_id", + ) + assert_matches_type(RoleCreateResponse, role, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: OpenAI) -> None: + response = client.admin.organization.projects.groups.roles.with_raw_response.create( + group_id="group_id", + project_id="project_id", + role_id="role_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(RoleCreateResponse, role, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: OpenAI) -> None: + with client.admin.organization.projects.groups.roles.with_streaming_response.create( + group_id="group_id", + project_id="project_id", + role_id="role_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = response.parse() + assert_matches_type(RoleCreateResponse, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_create(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.groups.roles.with_raw_response.create( + group_id="group_id", + project_id="", + role_id="role_id", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + client.admin.organization.projects.groups.roles.with_raw_response.create( + group_id="", + project_id="project_id", + role_id="role_id", + ) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + role = client.admin.organization.projects.groups.roles.list( + group_id="group_id", + project_id="project_id", + ) + assert_matches_type(SyncCursorPage[RoleListResponse], role, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + role = client.admin.organization.projects.groups.roles.list( + group_id="group_id", + project_id="project_id", + after="after", + limit=0, + order="asc", + ) + assert_matches_type(SyncCursorPage[RoleListResponse], role, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.admin.organization.projects.groups.roles.with_raw_response.list( + group_id="group_id", + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(SyncCursorPage[RoleListResponse], role, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.admin.organization.projects.groups.roles.with_streaming_response.list( + group_id="group_id", + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = response.parse() + assert_matches_type(SyncCursorPage[RoleListResponse], role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.groups.roles.with_raw_response.list( + group_id="group_id", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + client.admin.organization.projects.groups.roles.with_raw_response.list( + group_id="", + project_id="project_id", + ) + + @parametrize + def test_method_delete(self, client: OpenAI) -> None: + role = client.admin.organization.projects.groups.roles.delete( + role_id="role_id", + project_id="project_id", + group_id="group_id", + ) + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: OpenAI) -> None: + response = client.admin.organization.projects.groups.roles.with_raw_response.delete( + role_id="role_id", + project_id="project_id", + group_id="group_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: OpenAI) -> None: + with client.admin.organization.projects.groups.roles.with_streaming_response.delete( + role_id="role_id", + project_id="project_id", + group_id="group_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = response.parse() + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.groups.roles.with_raw_response.delete( + role_id="role_id", + project_id="", + group_id="group_id", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + client.admin.organization.projects.groups.roles.with_raw_response.delete( + role_id="role_id", + project_id="project_id", + group_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): + client.admin.organization.projects.groups.roles.with_raw_response.delete( + role_id="", + project_id="project_id", + group_id="group_id", + ) + + +class TestAsyncRoles: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.projects.groups.roles.create( + group_id="group_id", + project_id="project_id", + role_id="role_id", + ) + assert_matches_type(RoleCreateResponse, role, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.groups.roles.with_raw_response.create( + group_id="group_id", + project_id="project_id", + role_id="role_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(RoleCreateResponse, role, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.groups.roles.with_streaming_response.create( + group_id="group_id", + project_id="project_id", + role_id="role_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = await response.parse() + assert_matches_type(RoleCreateResponse, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.groups.roles.with_raw_response.create( + group_id="group_id", + project_id="", + role_id="role_id", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + await async_client.admin.organization.projects.groups.roles.with_raw_response.create( + group_id="", + project_id="project_id", + role_id="role_id", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.projects.groups.roles.list( + group_id="group_id", + project_id="project_id", + ) + assert_matches_type(AsyncCursorPage[RoleListResponse], role, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.projects.groups.roles.list( + group_id="group_id", + project_id="project_id", + after="after", + limit=0, + order="asc", + ) + assert_matches_type(AsyncCursorPage[RoleListResponse], role, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.groups.roles.with_raw_response.list( + group_id="group_id", + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(AsyncCursorPage[RoleListResponse], role, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.groups.roles.with_streaming_response.list( + group_id="group_id", + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = await response.parse() + assert_matches_type(AsyncCursorPage[RoleListResponse], role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.groups.roles.with_raw_response.list( + group_id="group_id", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + await async_client.admin.organization.projects.groups.roles.with_raw_response.list( + group_id="", + project_id="project_id", + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.projects.groups.roles.delete( + role_id="role_id", + project_id="project_id", + group_id="group_id", + ) + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.groups.roles.with_raw_response.delete( + role_id="role_id", + project_id="project_id", + group_id="group_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.groups.roles.with_streaming_response.delete( + role_id="role_id", + project_id="project_id", + group_id="group_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = await response.parse() + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.groups.roles.with_raw_response.delete( + role_id="role_id", + project_id="", + group_id="group_id", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + await async_client.admin.organization.projects.groups.roles.with_raw_response.delete( + role_id="role_id", + project_id="project_id", + group_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): + await async_client.admin.organization.projects.groups.roles.with_raw_response.delete( + role_id="", + project_id="project_id", + group_id="group_id", + ) diff --git a/tests/api_resources/admin/organization/projects/test_api_keys.py b/tests/api_resources/admin/organization/projects/test_api_keys.py new file mode 100644 index 0000000000..2f8ab56056 --- /dev/null +++ b/tests/api_resources/admin/organization/projects/test_api_keys.py @@ -0,0 +1,311 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.pagination import SyncConversationCursorPage, AsyncConversationCursorPage +from openai.types.admin.organization.projects import ProjectAPIKey, APIKeyDeleteResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestAPIKeys: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + api_key = client.admin.organization.projects.api_keys.retrieve( + key_id="key_id", + project_id="project_id", + ) + assert_matches_type(ProjectAPIKey, api_key, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.admin.organization.projects.api_keys.with_raw_response.retrieve( + key_id="key_id", + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_key = response.parse() + assert_matches_type(ProjectAPIKey, api_key, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.admin.organization.projects.api_keys.with_streaming_response.retrieve( + key_id="key_id", + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_key = response.parse() + assert_matches_type(ProjectAPIKey, api_key, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.api_keys.with_raw_response.retrieve( + key_id="key_id", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `key_id` but received ''"): + client.admin.organization.projects.api_keys.with_raw_response.retrieve( + key_id="", + project_id="project_id", + ) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + api_key = client.admin.organization.projects.api_keys.list( + project_id="project_id", + ) + assert_matches_type(SyncConversationCursorPage[ProjectAPIKey], api_key, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + api_key = client.admin.organization.projects.api_keys.list( + project_id="project_id", + after="after", + limit=0, + ) + assert_matches_type(SyncConversationCursorPage[ProjectAPIKey], api_key, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.admin.organization.projects.api_keys.with_raw_response.list( + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_key = response.parse() + assert_matches_type(SyncConversationCursorPage[ProjectAPIKey], api_key, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.admin.organization.projects.api_keys.with_streaming_response.list( + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_key = response.parse() + assert_matches_type(SyncConversationCursorPage[ProjectAPIKey], api_key, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.api_keys.with_raw_response.list( + project_id="", + ) + + @parametrize + def test_method_delete(self, client: OpenAI) -> None: + api_key = client.admin.organization.projects.api_keys.delete( + key_id="key_id", + project_id="project_id", + ) + assert_matches_type(APIKeyDeleteResponse, api_key, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: OpenAI) -> None: + response = client.admin.organization.projects.api_keys.with_raw_response.delete( + key_id="key_id", + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_key = response.parse() + assert_matches_type(APIKeyDeleteResponse, api_key, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: OpenAI) -> None: + with client.admin.organization.projects.api_keys.with_streaming_response.delete( + key_id="key_id", + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_key = response.parse() + assert_matches_type(APIKeyDeleteResponse, api_key, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.api_keys.with_raw_response.delete( + key_id="key_id", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `key_id` but received ''"): + client.admin.organization.projects.api_keys.with_raw_response.delete( + key_id="", + project_id="project_id", + ) + + +class TestAsyncAPIKeys: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + api_key = await async_client.admin.organization.projects.api_keys.retrieve( + key_id="key_id", + project_id="project_id", + ) + assert_matches_type(ProjectAPIKey, api_key, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.api_keys.with_raw_response.retrieve( + key_id="key_id", + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_key = response.parse() + assert_matches_type(ProjectAPIKey, api_key, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.api_keys.with_streaming_response.retrieve( + key_id="key_id", + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_key = await response.parse() + assert_matches_type(ProjectAPIKey, api_key, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.api_keys.with_raw_response.retrieve( + key_id="key_id", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `key_id` but received ''"): + await async_client.admin.organization.projects.api_keys.with_raw_response.retrieve( + key_id="", + project_id="project_id", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + api_key = await async_client.admin.organization.projects.api_keys.list( + project_id="project_id", + ) + assert_matches_type(AsyncConversationCursorPage[ProjectAPIKey], api_key, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + api_key = await async_client.admin.organization.projects.api_keys.list( + project_id="project_id", + after="after", + limit=0, + ) + assert_matches_type(AsyncConversationCursorPage[ProjectAPIKey], api_key, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.api_keys.with_raw_response.list( + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_key = response.parse() + assert_matches_type(AsyncConversationCursorPage[ProjectAPIKey], api_key, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.api_keys.with_streaming_response.list( + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_key = await response.parse() + assert_matches_type(AsyncConversationCursorPage[ProjectAPIKey], api_key, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.api_keys.with_raw_response.list( + project_id="", + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncOpenAI) -> None: + api_key = await async_client.admin.organization.projects.api_keys.delete( + key_id="key_id", + project_id="project_id", + ) + assert_matches_type(APIKeyDeleteResponse, api_key, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.api_keys.with_raw_response.delete( + key_id="key_id", + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_key = response.parse() + assert_matches_type(APIKeyDeleteResponse, api_key, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.api_keys.with_streaming_response.delete( + key_id="key_id", + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_key = await response.parse() + assert_matches_type(APIKeyDeleteResponse, api_key, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.api_keys.with_raw_response.delete( + key_id="key_id", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `key_id` but received ''"): + await async_client.admin.organization.projects.api_keys.with_raw_response.delete( + key_id="", + project_id="project_id", + ) diff --git a/tests/api_resources/admin/organization/projects/test_certificates.py b/tests/api_resources/admin/organization/projects/test_certificates.py new file mode 100644 index 0000000000..8ed72d6112 --- /dev/null +++ b/tests/api_resources/admin/organization/projects/test_certificates.py @@ -0,0 +1,289 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.pagination import SyncPage, AsyncPage, SyncConversationCursorPage, AsyncConversationCursorPage +from openai.types.admin.organization import Certificate + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestCertificates: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + certificate = client.admin.organization.projects.certificates.list( + project_id="project_id", + ) + assert_matches_type(SyncConversationCursorPage[Certificate], certificate, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + certificate = client.admin.organization.projects.certificates.list( + project_id="project_id", + after="after", + limit=0, + order="asc", + ) + assert_matches_type(SyncConversationCursorPage[Certificate], certificate, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.admin.organization.projects.certificates.with_raw_response.list( + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = response.parse() + assert_matches_type(SyncConversationCursorPage[Certificate], certificate, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.admin.organization.projects.certificates.with_streaming_response.list( + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = response.parse() + assert_matches_type(SyncConversationCursorPage[Certificate], certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.certificates.with_raw_response.list( + project_id="", + ) + + @parametrize + def test_method_activate(self, client: OpenAI) -> None: + certificate = client.admin.organization.projects.certificates.activate( + project_id="project_id", + certificate_ids=["cert_abc"], + ) + assert_matches_type(SyncPage[Certificate], certificate, path=["response"]) + + @parametrize + def test_raw_response_activate(self, client: OpenAI) -> None: + response = client.admin.organization.projects.certificates.with_raw_response.activate( + project_id="project_id", + certificate_ids=["cert_abc"], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = response.parse() + assert_matches_type(SyncPage[Certificate], certificate, path=["response"]) + + @parametrize + def test_streaming_response_activate(self, client: OpenAI) -> None: + with client.admin.organization.projects.certificates.with_streaming_response.activate( + project_id="project_id", + certificate_ids=["cert_abc"], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = response.parse() + assert_matches_type(SyncPage[Certificate], certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_activate(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.certificates.with_raw_response.activate( + project_id="", + certificate_ids=["cert_abc"], + ) + + @parametrize + def test_method_deactivate(self, client: OpenAI) -> None: + certificate = client.admin.organization.projects.certificates.deactivate( + project_id="project_id", + certificate_ids=["cert_abc"], + ) + assert_matches_type(SyncPage[Certificate], certificate, path=["response"]) + + @parametrize + def test_raw_response_deactivate(self, client: OpenAI) -> None: + response = client.admin.organization.projects.certificates.with_raw_response.deactivate( + project_id="project_id", + certificate_ids=["cert_abc"], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = response.parse() + assert_matches_type(SyncPage[Certificate], certificate, path=["response"]) + + @parametrize + def test_streaming_response_deactivate(self, client: OpenAI) -> None: + with client.admin.organization.projects.certificates.with_streaming_response.deactivate( + project_id="project_id", + certificate_ids=["cert_abc"], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = response.parse() + assert_matches_type(SyncPage[Certificate], certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_deactivate(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.certificates.with_raw_response.deactivate( + project_id="", + certificate_ids=["cert_abc"], + ) + + +class TestAsyncCertificates: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + certificate = await async_client.admin.organization.projects.certificates.list( + project_id="project_id", + ) + assert_matches_type(AsyncConversationCursorPage[Certificate], certificate, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + certificate = await async_client.admin.organization.projects.certificates.list( + project_id="project_id", + after="after", + limit=0, + order="asc", + ) + assert_matches_type(AsyncConversationCursorPage[Certificate], certificate, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.certificates.with_raw_response.list( + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = response.parse() + assert_matches_type(AsyncConversationCursorPage[Certificate], certificate, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.certificates.with_streaming_response.list( + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = await response.parse() + assert_matches_type(AsyncConversationCursorPage[Certificate], certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.certificates.with_raw_response.list( + project_id="", + ) + + @parametrize + async def test_method_activate(self, async_client: AsyncOpenAI) -> None: + certificate = await async_client.admin.organization.projects.certificates.activate( + project_id="project_id", + certificate_ids=["cert_abc"], + ) + assert_matches_type(AsyncPage[Certificate], certificate, path=["response"]) + + @parametrize + async def test_raw_response_activate(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.certificates.with_raw_response.activate( + project_id="project_id", + certificate_ids=["cert_abc"], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = response.parse() + assert_matches_type(AsyncPage[Certificate], certificate, path=["response"]) + + @parametrize + async def test_streaming_response_activate(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.certificates.with_streaming_response.activate( + project_id="project_id", + certificate_ids=["cert_abc"], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = await response.parse() + assert_matches_type(AsyncPage[Certificate], certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_activate(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.certificates.with_raw_response.activate( + project_id="", + certificate_ids=["cert_abc"], + ) + + @parametrize + async def test_method_deactivate(self, async_client: AsyncOpenAI) -> None: + certificate = await async_client.admin.organization.projects.certificates.deactivate( + project_id="project_id", + certificate_ids=["cert_abc"], + ) + assert_matches_type(AsyncPage[Certificate], certificate, path=["response"]) + + @parametrize + async def test_raw_response_deactivate(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.certificates.with_raw_response.deactivate( + project_id="project_id", + certificate_ids=["cert_abc"], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = response.parse() + assert_matches_type(AsyncPage[Certificate], certificate, path=["response"]) + + @parametrize + async def test_streaming_response_deactivate(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.certificates.with_streaming_response.deactivate( + project_id="project_id", + certificate_ids=["cert_abc"], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = await response.parse() + assert_matches_type(AsyncPage[Certificate], certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_deactivate(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.certificates.with_raw_response.deactivate( + project_id="", + certificate_ids=["cert_abc"], + ) diff --git a/tests/api_resources/admin/organization/projects/test_groups.py b/tests/api_resources/admin/organization/projects/test_groups.py new file mode 100644 index 0000000000..57d768e738 --- /dev/null +++ b/tests/api_resources/admin/organization/projects/test_groups.py @@ -0,0 +1,312 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.pagination import SyncCursorPage, AsyncCursorPage +from openai.types.admin.organization.projects import ( + ProjectGroup, + GroupDeleteResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestGroups: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: OpenAI) -> None: + group = client.admin.organization.projects.groups.create( + project_id="project_id", + group_id="group_id", + role="role", + ) + assert_matches_type(ProjectGroup, group, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: OpenAI) -> None: + response = client.admin.organization.projects.groups.with_raw_response.create( + project_id="project_id", + group_id="group_id", + role="role", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + group = response.parse() + assert_matches_type(ProjectGroup, group, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: OpenAI) -> None: + with client.admin.organization.projects.groups.with_streaming_response.create( + project_id="project_id", + group_id="group_id", + role="role", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + group = response.parse() + assert_matches_type(ProjectGroup, group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_create(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.groups.with_raw_response.create( + project_id="", + group_id="group_id", + role="role", + ) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + group = client.admin.organization.projects.groups.list( + project_id="project_id", + ) + assert_matches_type(SyncCursorPage[ProjectGroup], group, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + group = client.admin.organization.projects.groups.list( + project_id="project_id", + after="after", + limit=0, + order="asc", + ) + assert_matches_type(SyncCursorPage[ProjectGroup], group, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.admin.organization.projects.groups.with_raw_response.list( + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + group = response.parse() + assert_matches_type(SyncCursorPage[ProjectGroup], group, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.admin.organization.projects.groups.with_streaming_response.list( + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + group = response.parse() + assert_matches_type(SyncCursorPage[ProjectGroup], group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.groups.with_raw_response.list( + project_id="", + ) + + @parametrize + def test_method_delete(self, client: OpenAI) -> None: + group = client.admin.organization.projects.groups.delete( + group_id="group_id", + project_id="project_id", + ) + assert_matches_type(GroupDeleteResponse, group, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: OpenAI) -> None: + response = client.admin.organization.projects.groups.with_raw_response.delete( + group_id="group_id", + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + group = response.parse() + assert_matches_type(GroupDeleteResponse, group, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: OpenAI) -> None: + with client.admin.organization.projects.groups.with_streaming_response.delete( + group_id="group_id", + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + group = response.parse() + assert_matches_type(GroupDeleteResponse, group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.groups.with_raw_response.delete( + group_id="group_id", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + client.admin.organization.projects.groups.with_raw_response.delete( + group_id="", + project_id="project_id", + ) + + +class TestAsyncGroups: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncOpenAI) -> None: + group = await async_client.admin.organization.projects.groups.create( + project_id="project_id", + group_id="group_id", + role="role", + ) + assert_matches_type(ProjectGroup, group, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.groups.with_raw_response.create( + project_id="project_id", + group_id="group_id", + role="role", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + group = response.parse() + assert_matches_type(ProjectGroup, group, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.groups.with_streaming_response.create( + project_id="project_id", + group_id="group_id", + role="role", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + group = await response.parse() + assert_matches_type(ProjectGroup, group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.groups.with_raw_response.create( + project_id="", + group_id="group_id", + role="role", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + group = await async_client.admin.organization.projects.groups.list( + project_id="project_id", + ) + assert_matches_type(AsyncCursorPage[ProjectGroup], group, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + group = await async_client.admin.organization.projects.groups.list( + project_id="project_id", + after="after", + limit=0, + order="asc", + ) + assert_matches_type(AsyncCursorPage[ProjectGroup], group, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.groups.with_raw_response.list( + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + group = response.parse() + assert_matches_type(AsyncCursorPage[ProjectGroup], group, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.groups.with_streaming_response.list( + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + group = await response.parse() + assert_matches_type(AsyncCursorPage[ProjectGroup], group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.groups.with_raw_response.list( + project_id="", + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncOpenAI) -> None: + group = await async_client.admin.organization.projects.groups.delete( + group_id="group_id", + project_id="project_id", + ) + assert_matches_type(GroupDeleteResponse, group, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.groups.with_raw_response.delete( + group_id="group_id", + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + group = response.parse() + assert_matches_type(GroupDeleteResponse, group, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.groups.with_streaming_response.delete( + group_id="group_id", + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + group = await response.parse() + assert_matches_type(GroupDeleteResponse, group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.groups.with_raw_response.delete( + group_id="group_id", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + await async_client.admin.organization.projects.groups.with_raw_response.delete( + group_id="", + project_id="project_id", + ) diff --git a/tests/api_resources/admin/organization/projects/test_rate_limits.py b/tests/api_resources/admin/organization/projects/test_rate_limits.py new file mode 100644 index 0000000000..c06077614b --- /dev/null +++ b/tests/api_resources/admin/organization/projects/test_rate_limits.py @@ -0,0 +1,247 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.pagination import SyncConversationCursorPage, AsyncConversationCursorPage +from openai.types.admin.organization.projects import ( + ProjectRateLimit, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestRateLimits: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list_rate_limits(self, client: OpenAI) -> None: + rate_limit = client.admin.organization.projects.rate_limits.list_rate_limits( + project_id="project_id", + ) + assert_matches_type(SyncConversationCursorPage[ProjectRateLimit], rate_limit, path=["response"]) + + @parametrize + def test_method_list_rate_limits_with_all_params(self, client: OpenAI) -> None: + rate_limit = client.admin.organization.projects.rate_limits.list_rate_limits( + project_id="project_id", + after="after", + before="before", + limit=0, + ) + assert_matches_type(SyncConversationCursorPage[ProjectRateLimit], rate_limit, path=["response"]) + + @parametrize + def test_raw_response_list_rate_limits(self, client: OpenAI) -> None: + response = client.admin.organization.projects.rate_limits.with_raw_response.list_rate_limits( + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rate_limit = response.parse() + assert_matches_type(SyncConversationCursorPage[ProjectRateLimit], rate_limit, path=["response"]) + + @parametrize + def test_streaming_response_list_rate_limits(self, client: OpenAI) -> None: + with client.admin.organization.projects.rate_limits.with_streaming_response.list_rate_limits( + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rate_limit = response.parse() + assert_matches_type(SyncConversationCursorPage[ProjectRateLimit], rate_limit, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list_rate_limits(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.rate_limits.with_raw_response.list_rate_limits( + project_id="", + ) + + @parametrize + def test_method_update_rate_limit(self, client: OpenAI) -> None: + rate_limit = client.admin.organization.projects.rate_limits.update_rate_limit( + rate_limit_id="rate_limit_id", + project_id="project_id", + ) + assert_matches_type(ProjectRateLimit, rate_limit, path=["response"]) + + @parametrize + def test_method_update_rate_limit_with_all_params(self, client: OpenAI) -> None: + rate_limit = client.admin.organization.projects.rate_limits.update_rate_limit( + rate_limit_id="rate_limit_id", + project_id="project_id", + batch_1_day_max_input_tokens=0, + max_audio_megabytes_per_1_minute=0, + max_images_per_1_minute=0, + max_requests_per_1_day=0, + max_requests_per_1_minute=0, + max_tokens_per_1_minute=0, + ) + assert_matches_type(ProjectRateLimit, rate_limit, path=["response"]) + + @parametrize + def test_raw_response_update_rate_limit(self, client: OpenAI) -> None: + response = client.admin.organization.projects.rate_limits.with_raw_response.update_rate_limit( + rate_limit_id="rate_limit_id", + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rate_limit = response.parse() + assert_matches_type(ProjectRateLimit, rate_limit, path=["response"]) + + @parametrize + def test_streaming_response_update_rate_limit(self, client: OpenAI) -> None: + with client.admin.organization.projects.rate_limits.with_streaming_response.update_rate_limit( + rate_limit_id="rate_limit_id", + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rate_limit = response.parse() + assert_matches_type(ProjectRateLimit, rate_limit, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update_rate_limit(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.rate_limits.with_raw_response.update_rate_limit( + rate_limit_id="rate_limit_id", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `rate_limit_id` but received ''"): + client.admin.organization.projects.rate_limits.with_raw_response.update_rate_limit( + rate_limit_id="", + project_id="project_id", + ) + + +class TestAsyncRateLimits: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list_rate_limits(self, async_client: AsyncOpenAI) -> None: + rate_limit = await async_client.admin.organization.projects.rate_limits.list_rate_limits( + project_id="project_id", + ) + assert_matches_type(AsyncConversationCursorPage[ProjectRateLimit], rate_limit, path=["response"]) + + @parametrize + async def test_method_list_rate_limits_with_all_params(self, async_client: AsyncOpenAI) -> None: + rate_limit = await async_client.admin.organization.projects.rate_limits.list_rate_limits( + project_id="project_id", + after="after", + before="before", + limit=0, + ) + assert_matches_type(AsyncConversationCursorPage[ProjectRateLimit], rate_limit, path=["response"]) + + @parametrize + async def test_raw_response_list_rate_limits(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.rate_limits.with_raw_response.list_rate_limits( + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rate_limit = response.parse() + assert_matches_type(AsyncConversationCursorPage[ProjectRateLimit], rate_limit, path=["response"]) + + @parametrize + async def test_streaming_response_list_rate_limits(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.rate_limits.with_streaming_response.list_rate_limits( + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rate_limit = await response.parse() + assert_matches_type(AsyncConversationCursorPage[ProjectRateLimit], rate_limit, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list_rate_limits(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.rate_limits.with_raw_response.list_rate_limits( + project_id="", + ) + + @parametrize + async def test_method_update_rate_limit(self, async_client: AsyncOpenAI) -> None: + rate_limit = await async_client.admin.organization.projects.rate_limits.update_rate_limit( + rate_limit_id="rate_limit_id", + project_id="project_id", + ) + assert_matches_type(ProjectRateLimit, rate_limit, path=["response"]) + + @parametrize + async def test_method_update_rate_limit_with_all_params(self, async_client: AsyncOpenAI) -> None: + rate_limit = await async_client.admin.organization.projects.rate_limits.update_rate_limit( + rate_limit_id="rate_limit_id", + project_id="project_id", + batch_1_day_max_input_tokens=0, + max_audio_megabytes_per_1_minute=0, + max_images_per_1_minute=0, + max_requests_per_1_day=0, + max_requests_per_1_minute=0, + max_tokens_per_1_minute=0, + ) + assert_matches_type(ProjectRateLimit, rate_limit, path=["response"]) + + @parametrize + async def test_raw_response_update_rate_limit(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.rate_limits.with_raw_response.update_rate_limit( + rate_limit_id="rate_limit_id", + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rate_limit = response.parse() + assert_matches_type(ProjectRateLimit, rate_limit, path=["response"]) + + @parametrize + async def test_streaming_response_update_rate_limit(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.rate_limits.with_streaming_response.update_rate_limit( + rate_limit_id="rate_limit_id", + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rate_limit = await response.parse() + assert_matches_type(ProjectRateLimit, rate_limit, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update_rate_limit(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.rate_limits.with_raw_response.update_rate_limit( + rate_limit_id="rate_limit_id", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `rate_limit_id` but received ''"): + await async_client.admin.organization.projects.rate_limits.with_raw_response.update_rate_limit( + rate_limit_id="", + project_id="project_id", + ) diff --git a/tests/api_resources/admin/organization/projects/test_roles.py b/tests/api_resources/admin/organization/projects/test_roles.py new file mode 100644 index 0000000000..697aa09f3a --- /dev/null +++ b/tests/api_resources/admin/organization/projects/test_roles.py @@ -0,0 +1,450 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.pagination import SyncCursorPage, AsyncCursorPage +from openai.types.admin.organization import Role +from openai.types.admin.organization.projects import ( + RoleDeleteResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestRoles: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: OpenAI) -> None: + role = client.admin.organization.projects.roles.create( + project_id="project_id", + permissions=["string"], + role_name="role_name", + ) + assert_matches_type(Role, role, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: OpenAI) -> None: + role = client.admin.organization.projects.roles.create( + project_id="project_id", + permissions=["string"], + role_name="role_name", + description="description", + ) + assert_matches_type(Role, role, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: OpenAI) -> None: + response = client.admin.organization.projects.roles.with_raw_response.create( + project_id="project_id", + permissions=["string"], + role_name="role_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(Role, role, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: OpenAI) -> None: + with client.admin.organization.projects.roles.with_streaming_response.create( + project_id="project_id", + permissions=["string"], + role_name="role_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = response.parse() + assert_matches_type(Role, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_create(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.roles.with_raw_response.create( + project_id="", + permissions=["string"], + role_name="role_name", + ) + + @parametrize + def test_method_update(self, client: OpenAI) -> None: + role = client.admin.organization.projects.roles.update( + role_id="role_id", + project_id="project_id", + ) + assert_matches_type(Role, role, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: OpenAI) -> None: + role = client.admin.organization.projects.roles.update( + role_id="role_id", + project_id="project_id", + description="description", + permissions=["string"], + role_name="role_name", + ) + assert_matches_type(Role, role, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: OpenAI) -> None: + response = client.admin.organization.projects.roles.with_raw_response.update( + role_id="role_id", + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(Role, role, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: OpenAI) -> None: + with client.admin.organization.projects.roles.with_streaming_response.update( + role_id="role_id", + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = response.parse() + assert_matches_type(Role, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.roles.with_raw_response.update( + role_id="role_id", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): + client.admin.organization.projects.roles.with_raw_response.update( + role_id="", + project_id="project_id", + ) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + role = client.admin.organization.projects.roles.list( + project_id="project_id", + ) + assert_matches_type(SyncCursorPage[Role], role, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + role = client.admin.organization.projects.roles.list( + project_id="project_id", + after="after", + limit=0, + order="asc", + ) + assert_matches_type(SyncCursorPage[Role], role, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.admin.organization.projects.roles.with_raw_response.list( + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(SyncCursorPage[Role], role, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.admin.organization.projects.roles.with_streaming_response.list( + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = response.parse() + assert_matches_type(SyncCursorPage[Role], role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.roles.with_raw_response.list( + project_id="", + ) + + @parametrize + def test_method_delete(self, client: OpenAI) -> None: + role = client.admin.organization.projects.roles.delete( + role_id="role_id", + project_id="project_id", + ) + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: OpenAI) -> None: + response = client.admin.organization.projects.roles.with_raw_response.delete( + role_id="role_id", + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: OpenAI) -> None: + with client.admin.organization.projects.roles.with_streaming_response.delete( + role_id="role_id", + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = response.parse() + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.roles.with_raw_response.delete( + role_id="role_id", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): + client.admin.organization.projects.roles.with_raw_response.delete( + role_id="", + project_id="project_id", + ) + + +class TestAsyncRoles: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.projects.roles.create( + project_id="project_id", + permissions=["string"], + role_name="role_name", + ) + assert_matches_type(Role, role, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.projects.roles.create( + project_id="project_id", + permissions=["string"], + role_name="role_name", + description="description", + ) + assert_matches_type(Role, role, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.roles.with_raw_response.create( + project_id="project_id", + permissions=["string"], + role_name="role_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(Role, role, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.roles.with_streaming_response.create( + project_id="project_id", + permissions=["string"], + role_name="role_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = await response.parse() + assert_matches_type(Role, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.roles.with_raw_response.create( + project_id="", + permissions=["string"], + role_name="role_name", + ) + + @parametrize + async def test_method_update(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.projects.roles.update( + role_id="role_id", + project_id="project_id", + ) + assert_matches_type(Role, role, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.projects.roles.update( + role_id="role_id", + project_id="project_id", + description="description", + permissions=["string"], + role_name="role_name", + ) + assert_matches_type(Role, role, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.roles.with_raw_response.update( + role_id="role_id", + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(Role, role, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.roles.with_streaming_response.update( + role_id="role_id", + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = await response.parse() + assert_matches_type(Role, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.roles.with_raw_response.update( + role_id="role_id", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): + await async_client.admin.organization.projects.roles.with_raw_response.update( + role_id="", + project_id="project_id", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.projects.roles.list( + project_id="project_id", + ) + assert_matches_type(AsyncCursorPage[Role], role, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.projects.roles.list( + project_id="project_id", + after="after", + limit=0, + order="asc", + ) + assert_matches_type(AsyncCursorPage[Role], role, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.roles.with_raw_response.list( + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(AsyncCursorPage[Role], role, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.roles.with_streaming_response.list( + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = await response.parse() + assert_matches_type(AsyncCursorPage[Role], role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.roles.with_raw_response.list( + project_id="", + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.projects.roles.delete( + role_id="role_id", + project_id="project_id", + ) + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.roles.with_raw_response.delete( + role_id="role_id", + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.roles.with_streaming_response.delete( + role_id="role_id", + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = await response.parse() + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.roles.with_raw_response.delete( + role_id="role_id", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): + await async_client.admin.organization.projects.roles.with_raw_response.delete( + role_id="", + project_id="project_id", + ) diff --git a/tests/api_resources/admin/organization/projects/test_service_accounts.py b/tests/api_resources/admin/organization/projects/test_service_accounts.py new file mode 100644 index 0000000000..7c94283323 --- /dev/null +++ b/tests/api_resources/admin/organization/projects/test_service_accounts.py @@ -0,0 +1,399 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.pagination import SyncConversationCursorPage, AsyncConversationCursorPage +from openai.types.admin.organization.projects import ( + ProjectServiceAccount, + ServiceAccountCreateResponse, + ServiceAccountDeleteResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestServiceAccounts: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: OpenAI) -> None: + service_account = client.admin.organization.projects.service_accounts.create( + project_id="project_id", + name="name", + ) + assert_matches_type(ServiceAccountCreateResponse, service_account, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: OpenAI) -> None: + response = client.admin.organization.projects.service_accounts.with_raw_response.create( + project_id="project_id", + name="name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + service_account = response.parse() + assert_matches_type(ServiceAccountCreateResponse, service_account, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: OpenAI) -> None: + with client.admin.organization.projects.service_accounts.with_streaming_response.create( + project_id="project_id", + name="name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + service_account = response.parse() + assert_matches_type(ServiceAccountCreateResponse, service_account, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_create(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.service_accounts.with_raw_response.create( + project_id="", + name="name", + ) + + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + service_account = client.admin.organization.projects.service_accounts.retrieve( + service_account_id="service_account_id", + project_id="project_id", + ) + assert_matches_type(ProjectServiceAccount, service_account, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.admin.organization.projects.service_accounts.with_raw_response.retrieve( + service_account_id="service_account_id", + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + service_account = response.parse() + assert_matches_type(ProjectServiceAccount, service_account, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.admin.organization.projects.service_accounts.with_streaming_response.retrieve( + service_account_id="service_account_id", + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + service_account = response.parse() + assert_matches_type(ProjectServiceAccount, service_account, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.service_accounts.with_raw_response.retrieve( + service_account_id="service_account_id", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `service_account_id` but received ''"): + client.admin.organization.projects.service_accounts.with_raw_response.retrieve( + service_account_id="", + project_id="project_id", + ) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + service_account = client.admin.organization.projects.service_accounts.list( + project_id="project_id", + ) + assert_matches_type(SyncConversationCursorPage[ProjectServiceAccount], service_account, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + service_account = client.admin.organization.projects.service_accounts.list( + project_id="project_id", + after="after", + limit=0, + ) + assert_matches_type(SyncConversationCursorPage[ProjectServiceAccount], service_account, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.admin.organization.projects.service_accounts.with_raw_response.list( + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + service_account = response.parse() + assert_matches_type(SyncConversationCursorPage[ProjectServiceAccount], service_account, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.admin.organization.projects.service_accounts.with_streaming_response.list( + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + service_account = response.parse() + assert_matches_type(SyncConversationCursorPage[ProjectServiceAccount], service_account, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.service_accounts.with_raw_response.list( + project_id="", + ) + + @parametrize + def test_method_delete(self, client: OpenAI) -> None: + service_account = client.admin.organization.projects.service_accounts.delete( + service_account_id="service_account_id", + project_id="project_id", + ) + assert_matches_type(ServiceAccountDeleteResponse, service_account, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: OpenAI) -> None: + response = client.admin.organization.projects.service_accounts.with_raw_response.delete( + service_account_id="service_account_id", + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + service_account = response.parse() + assert_matches_type(ServiceAccountDeleteResponse, service_account, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: OpenAI) -> None: + with client.admin.organization.projects.service_accounts.with_streaming_response.delete( + service_account_id="service_account_id", + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + service_account = response.parse() + assert_matches_type(ServiceAccountDeleteResponse, service_account, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.service_accounts.with_raw_response.delete( + service_account_id="service_account_id", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `service_account_id` but received ''"): + client.admin.organization.projects.service_accounts.with_raw_response.delete( + service_account_id="", + project_id="project_id", + ) + + +class TestAsyncServiceAccounts: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncOpenAI) -> None: + service_account = await async_client.admin.organization.projects.service_accounts.create( + project_id="project_id", + name="name", + ) + assert_matches_type(ServiceAccountCreateResponse, service_account, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.service_accounts.with_raw_response.create( + project_id="project_id", + name="name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + service_account = response.parse() + assert_matches_type(ServiceAccountCreateResponse, service_account, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.service_accounts.with_streaming_response.create( + project_id="project_id", + name="name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + service_account = await response.parse() + assert_matches_type(ServiceAccountCreateResponse, service_account, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.service_accounts.with_raw_response.create( + project_id="", + name="name", + ) + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + service_account = await async_client.admin.organization.projects.service_accounts.retrieve( + service_account_id="service_account_id", + project_id="project_id", + ) + assert_matches_type(ProjectServiceAccount, service_account, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.service_accounts.with_raw_response.retrieve( + service_account_id="service_account_id", + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + service_account = response.parse() + assert_matches_type(ProjectServiceAccount, service_account, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.service_accounts.with_streaming_response.retrieve( + service_account_id="service_account_id", + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + service_account = await response.parse() + assert_matches_type(ProjectServiceAccount, service_account, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.service_accounts.with_raw_response.retrieve( + service_account_id="service_account_id", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `service_account_id` but received ''"): + await async_client.admin.organization.projects.service_accounts.with_raw_response.retrieve( + service_account_id="", + project_id="project_id", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + service_account = await async_client.admin.organization.projects.service_accounts.list( + project_id="project_id", + ) + assert_matches_type(AsyncConversationCursorPage[ProjectServiceAccount], service_account, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + service_account = await async_client.admin.organization.projects.service_accounts.list( + project_id="project_id", + after="after", + limit=0, + ) + assert_matches_type(AsyncConversationCursorPage[ProjectServiceAccount], service_account, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.service_accounts.with_raw_response.list( + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + service_account = response.parse() + assert_matches_type(AsyncConversationCursorPage[ProjectServiceAccount], service_account, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.service_accounts.with_streaming_response.list( + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + service_account = await response.parse() + assert_matches_type(AsyncConversationCursorPage[ProjectServiceAccount], service_account, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.service_accounts.with_raw_response.list( + project_id="", + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncOpenAI) -> None: + service_account = await async_client.admin.organization.projects.service_accounts.delete( + service_account_id="service_account_id", + project_id="project_id", + ) + assert_matches_type(ServiceAccountDeleteResponse, service_account, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.service_accounts.with_raw_response.delete( + service_account_id="service_account_id", + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + service_account = response.parse() + assert_matches_type(ServiceAccountDeleteResponse, service_account, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.service_accounts.with_streaming_response.delete( + service_account_id="service_account_id", + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + service_account = await response.parse() + assert_matches_type(ServiceAccountDeleteResponse, service_account, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.service_accounts.with_raw_response.delete( + service_account_id="service_account_id", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `service_account_id` but received ''"): + await async_client.admin.organization.projects.service_accounts.with_raw_response.delete( + service_account_id="", + project_id="project_id", + ) diff --git a/tests/api_resources/admin/organization/projects/test_users.py b/tests/api_resources/admin/organization/projects/test_users.py new file mode 100644 index 0000000000..30ad94fe3b --- /dev/null +++ b/tests/api_resources/admin/organization/projects/test_users.py @@ -0,0 +1,512 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.pagination import SyncConversationCursorPage, AsyncConversationCursorPage +from openai.types.admin.organization.projects import ( + ProjectUser, + UserDeleteResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestUsers: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: OpenAI) -> None: + user = client.admin.organization.projects.users.create( + project_id="project_id", + role="owner", + user_id="user_id", + ) + assert_matches_type(ProjectUser, user, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: OpenAI) -> None: + response = client.admin.organization.projects.users.with_raw_response.create( + project_id="project_id", + role="owner", + user_id="user_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(ProjectUser, user, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: OpenAI) -> None: + with client.admin.organization.projects.users.with_streaming_response.create( + project_id="project_id", + role="owner", + user_id="user_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = response.parse() + assert_matches_type(ProjectUser, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_create(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.users.with_raw_response.create( + project_id="", + role="owner", + user_id="user_id", + ) + + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + user = client.admin.organization.projects.users.retrieve( + user_id="user_id", + project_id="project_id", + ) + assert_matches_type(ProjectUser, user, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.admin.organization.projects.users.with_raw_response.retrieve( + user_id="user_id", + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(ProjectUser, user, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.admin.organization.projects.users.with_streaming_response.retrieve( + user_id="user_id", + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = response.parse() + assert_matches_type(ProjectUser, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.users.with_raw_response.retrieve( + user_id="user_id", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): + client.admin.organization.projects.users.with_raw_response.retrieve( + user_id="", + project_id="project_id", + ) + + @parametrize + def test_method_update(self, client: OpenAI) -> None: + user = client.admin.organization.projects.users.update( + user_id="user_id", + project_id="project_id", + role="owner", + ) + assert_matches_type(ProjectUser, user, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: OpenAI) -> None: + response = client.admin.organization.projects.users.with_raw_response.update( + user_id="user_id", + project_id="project_id", + role="owner", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(ProjectUser, user, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: OpenAI) -> None: + with client.admin.organization.projects.users.with_streaming_response.update( + user_id="user_id", + project_id="project_id", + role="owner", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = response.parse() + assert_matches_type(ProjectUser, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.users.with_raw_response.update( + user_id="user_id", + project_id="", + role="owner", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): + client.admin.organization.projects.users.with_raw_response.update( + user_id="", + project_id="project_id", + role="owner", + ) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + user = client.admin.organization.projects.users.list( + project_id="project_id", + ) + assert_matches_type(SyncConversationCursorPage[ProjectUser], user, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + user = client.admin.organization.projects.users.list( + project_id="project_id", + after="after", + limit=0, + ) + assert_matches_type(SyncConversationCursorPage[ProjectUser], user, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.admin.organization.projects.users.with_raw_response.list( + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(SyncConversationCursorPage[ProjectUser], user, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.admin.organization.projects.users.with_streaming_response.list( + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = response.parse() + assert_matches_type(SyncConversationCursorPage[ProjectUser], user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.users.with_raw_response.list( + project_id="", + ) + + @parametrize + def test_method_delete(self, client: OpenAI) -> None: + user = client.admin.organization.projects.users.delete( + user_id="user_id", + project_id="project_id", + ) + assert_matches_type(UserDeleteResponse, user, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: OpenAI) -> None: + response = client.admin.organization.projects.users.with_raw_response.delete( + user_id="user_id", + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(UserDeleteResponse, user, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: OpenAI) -> None: + with client.admin.organization.projects.users.with_streaming_response.delete( + user_id="user_id", + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = response.parse() + assert_matches_type(UserDeleteResponse, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.users.with_raw_response.delete( + user_id="user_id", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): + client.admin.organization.projects.users.with_raw_response.delete( + user_id="", + project_id="project_id", + ) + + +class TestAsyncUsers: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncOpenAI) -> None: + user = await async_client.admin.organization.projects.users.create( + project_id="project_id", + role="owner", + user_id="user_id", + ) + assert_matches_type(ProjectUser, user, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.users.with_raw_response.create( + project_id="project_id", + role="owner", + user_id="user_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(ProjectUser, user, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.users.with_streaming_response.create( + project_id="project_id", + role="owner", + user_id="user_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = await response.parse() + assert_matches_type(ProjectUser, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.users.with_raw_response.create( + project_id="", + role="owner", + user_id="user_id", + ) + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + user = await async_client.admin.organization.projects.users.retrieve( + user_id="user_id", + project_id="project_id", + ) + assert_matches_type(ProjectUser, user, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.users.with_raw_response.retrieve( + user_id="user_id", + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(ProjectUser, user, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.users.with_streaming_response.retrieve( + user_id="user_id", + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = await response.parse() + assert_matches_type(ProjectUser, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.users.with_raw_response.retrieve( + user_id="user_id", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): + await async_client.admin.organization.projects.users.with_raw_response.retrieve( + user_id="", + project_id="project_id", + ) + + @parametrize + async def test_method_update(self, async_client: AsyncOpenAI) -> None: + user = await async_client.admin.organization.projects.users.update( + user_id="user_id", + project_id="project_id", + role="owner", + ) + assert_matches_type(ProjectUser, user, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.users.with_raw_response.update( + user_id="user_id", + project_id="project_id", + role="owner", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(ProjectUser, user, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.users.with_streaming_response.update( + user_id="user_id", + project_id="project_id", + role="owner", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = await response.parse() + assert_matches_type(ProjectUser, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.users.with_raw_response.update( + user_id="user_id", + project_id="", + role="owner", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): + await async_client.admin.organization.projects.users.with_raw_response.update( + user_id="", + project_id="project_id", + role="owner", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + user = await async_client.admin.organization.projects.users.list( + project_id="project_id", + ) + assert_matches_type(AsyncConversationCursorPage[ProjectUser], user, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + user = await async_client.admin.organization.projects.users.list( + project_id="project_id", + after="after", + limit=0, + ) + assert_matches_type(AsyncConversationCursorPage[ProjectUser], user, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.users.with_raw_response.list( + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(AsyncConversationCursorPage[ProjectUser], user, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.users.with_streaming_response.list( + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = await response.parse() + assert_matches_type(AsyncConversationCursorPage[ProjectUser], user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.users.with_raw_response.list( + project_id="", + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncOpenAI) -> None: + user = await async_client.admin.organization.projects.users.delete( + user_id="user_id", + project_id="project_id", + ) + assert_matches_type(UserDeleteResponse, user, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.users.with_raw_response.delete( + user_id="user_id", + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(UserDeleteResponse, user, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.users.with_streaming_response.delete( + user_id="user_id", + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = await response.parse() + assert_matches_type(UserDeleteResponse, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.users.with_raw_response.delete( + user_id="user_id", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): + await async_client.admin.organization.projects.users.with_raw_response.delete( + user_id="", + project_id="project_id", + ) diff --git a/tests/api_resources/admin/organization/projects/users/__init__.py b/tests/api_resources/admin/organization/projects/users/__init__.py new file mode 100644 index 0000000000..fd8019a9a1 --- /dev/null +++ b/tests/api_resources/admin/organization/projects/users/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/admin/organization/projects/users/test_roles.py b/tests/api_resources/admin/organization/projects/users/test_roles.py new file mode 100644 index 0000000000..c39840646b --- /dev/null +++ b/tests/api_resources/admin/organization/projects/users/test_roles.py @@ -0,0 +1,373 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.pagination import SyncCursorPage, AsyncCursorPage +from openai.types.admin.organization.projects.users import ( + RoleListResponse, + RoleCreateResponse, + RoleDeleteResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestRoles: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: OpenAI) -> None: + role = client.admin.organization.projects.users.roles.create( + user_id="user_id", + project_id="project_id", + role_id="role_id", + ) + assert_matches_type(RoleCreateResponse, role, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: OpenAI) -> None: + response = client.admin.organization.projects.users.roles.with_raw_response.create( + user_id="user_id", + project_id="project_id", + role_id="role_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(RoleCreateResponse, role, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: OpenAI) -> None: + with client.admin.organization.projects.users.roles.with_streaming_response.create( + user_id="user_id", + project_id="project_id", + role_id="role_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = response.parse() + assert_matches_type(RoleCreateResponse, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_create(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.users.roles.with_raw_response.create( + user_id="user_id", + project_id="", + role_id="role_id", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): + client.admin.organization.projects.users.roles.with_raw_response.create( + user_id="", + project_id="project_id", + role_id="role_id", + ) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + role = client.admin.organization.projects.users.roles.list( + user_id="user_id", + project_id="project_id", + ) + assert_matches_type(SyncCursorPage[RoleListResponse], role, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + role = client.admin.organization.projects.users.roles.list( + user_id="user_id", + project_id="project_id", + after="after", + limit=0, + order="asc", + ) + assert_matches_type(SyncCursorPage[RoleListResponse], role, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.admin.organization.projects.users.roles.with_raw_response.list( + user_id="user_id", + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(SyncCursorPage[RoleListResponse], role, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.admin.organization.projects.users.roles.with_streaming_response.list( + user_id="user_id", + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = response.parse() + assert_matches_type(SyncCursorPage[RoleListResponse], role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.users.roles.with_raw_response.list( + user_id="user_id", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): + client.admin.organization.projects.users.roles.with_raw_response.list( + user_id="", + project_id="project_id", + ) + + @parametrize + def test_method_delete(self, client: OpenAI) -> None: + role = client.admin.organization.projects.users.roles.delete( + role_id="role_id", + project_id="project_id", + user_id="user_id", + ) + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: OpenAI) -> None: + response = client.admin.organization.projects.users.roles.with_raw_response.delete( + role_id="role_id", + project_id="project_id", + user_id="user_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: OpenAI) -> None: + with client.admin.organization.projects.users.roles.with_streaming_response.delete( + role_id="role_id", + project_id="project_id", + user_id="user_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = response.parse() + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.users.roles.with_raw_response.delete( + role_id="role_id", + project_id="", + user_id="user_id", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): + client.admin.organization.projects.users.roles.with_raw_response.delete( + role_id="role_id", + project_id="project_id", + user_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): + client.admin.organization.projects.users.roles.with_raw_response.delete( + role_id="", + project_id="project_id", + user_id="user_id", + ) + + +class TestAsyncRoles: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.projects.users.roles.create( + user_id="user_id", + project_id="project_id", + role_id="role_id", + ) + assert_matches_type(RoleCreateResponse, role, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.users.roles.with_raw_response.create( + user_id="user_id", + project_id="project_id", + role_id="role_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(RoleCreateResponse, role, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.users.roles.with_streaming_response.create( + user_id="user_id", + project_id="project_id", + role_id="role_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = await response.parse() + assert_matches_type(RoleCreateResponse, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.users.roles.with_raw_response.create( + user_id="user_id", + project_id="", + role_id="role_id", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): + await async_client.admin.organization.projects.users.roles.with_raw_response.create( + user_id="", + project_id="project_id", + role_id="role_id", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.projects.users.roles.list( + user_id="user_id", + project_id="project_id", + ) + assert_matches_type(AsyncCursorPage[RoleListResponse], role, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.projects.users.roles.list( + user_id="user_id", + project_id="project_id", + after="after", + limit=0, + order="asc", + ) + assert_matches_type(AsyncCursorPage[RoleListResponse], role, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.users.roles.with_raw_response.list( + user_id="user_id", + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(AsyncCursorPage[RoleListResponse], role, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.users.roles.with_streaming_response.list( + user_id="user_id", + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = await response.parse() + assert_matches_type(AsyncCursorPage[RoleListResponse], role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.users.roles.with_raw_response.list( + user_id="user_id", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): + await async_client.admin.organization.projects.users.roles.with_raw_response.list( + user_id="", + project_id="project_id", + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.projects.users.roles.delete( + role_id="role_id", + project_id="project_id", + user_id="user_id", + ) + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.users.roles.with_raw_response.delete( + role_id="role_id", + project_id="project_id", + user_id="user_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.users.roles.with_streaming_response.delete( + role_id="role_id", + project_id="project_id", + user_id="user_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = await response.parse() + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.users.roles.with_raw_response.delete( + role_id="role_id", + project_id="", + user_id="user_id", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): + await async_client.admin.organization.projects.users.roles.with_raw_response.delete( + role_id="role_id", + project_id="project_id", + user_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): + await async_client.admin.organization.projects.users.roles.with_raw_response.delete( + role_id="", + project_id="project_id", + user_id="user_id", + ) diff --git a/tests/api_resources/admin/organization/test_admin_api_keys.py b/tests/api_resources/admin/organization/test_admin_api_keys.py new file mode 100644 index 0000000000..3b6e7dec37 --- /dev/null +++ b/tests/api_resources/admin/organization/test_admin_api_keys.py @@ -0,0 +1,310 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.pagination import SyncCursorPage, AsyncCursorPage +from openai.types.admin.organization import ( + AdminAPIKey, + AdminAPIKeyDeleteResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestAdminAPIKeys: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: OpenAI) -> None: + admin_api_key = client.admin.organization.admin_api_keys.create( + name="New Admin Key", + ) + assert_matches_type(AdminAPIKey, admin_api_key, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: OpenAI) -> None: + response = client.admin.organization.admin_api_keys.with_raw_response.create( + name="New Admin Key", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + admin_api_key = response.parse() + assert_matches_type(AdminAPIKey, admin_api_key, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: OpenAI) -> None: + with client.admin.organization.admin_api_keys.with_streaming_response.create( + name="New Admin Key", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + admin_api_key = response.parse() + assert_matches_type(AdminAPIKey, admin_api_key, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + admin_api_key = client.admin.organization.admin_api_keys.retrieve( + "key_id", + ) + assert_matches_type(AdminAPIKey, admin_api_key, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.admin.organization.admin_api_keys.with_raw_response.retrieve( + "key_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + admin_api_key = response.parse() + assert_matches_type(AdminAPIKey, admin_api_key, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.admin.organization.admin_api_keys.with_streaming_response.retrieve( + "key_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + admin_api_key = response.parse() + assert_matches_type(AdminAPIKey, admin_api_key, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `key_id` but received ''"): + client.admin.organization.admin_api_keys.with_raw_response.retrieve( + "", + ) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + admin_api_key = client.admin.organization.admin_api_keys.list() + assert_matches_type(SyncCursorPage[AdminAPIKey], admin_api_key, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + admin_api_key = client.admin.organization.admin_api_keys.list( + after="after", + limit=0, + order="asc", + ) + assert_matches_type(SyncCursorPage[AdminAPIKey], admin_api_key, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.admin.organization.admin_api_keys.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + admin_api_key = response.parse() + assert_matches_type(SyncCursorPage[AdminAPIKey], admin_api_key, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.admin.organization.admin_api_keys.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + admin_api_key = response.parse() + assert_matches_type(SyncCursorPage[AdminAPIKey], admin_api_key, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: OpenAI) -> None: + admin_api_key = client.admin.organization.admin_api_keys.delete( + "key_id", + ) + assert_matches_type(AdminAPIKeyDeleteResponse, admin_api_key, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: OpenAI) -> None: + response = client.admin.organization.admin_api_keys.with_raw_response.delete( + "key_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + admin_api_key = response.parse() + assert_matches_type(AdminAPIKeyDeleteResponse, admin_api_key, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: OpenAI) -> None: + with client.admin.organization.admin_api_keys.with_streaming_response.delete( + "key_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + admin_api_key = response.parse() + assert_matches_type(AdminAPIKeyDeleteResponse, admin_api_key, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `key_id` but received ''"): + client.admin.organization.admin_api_keys.with_raw_response.delete( + "", + ) + + +class TestAsyncAdminAPIKeys: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncOpenAI) -> None: + admin_api_key = await async_client.admin.organization.admin_api_keys.create( + name="New Admin Key", + ) + assert_matches_type(AdminAPIKey, admin_api_key, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.admin_api_keys.with_raw_response.create( + name="New Admin Key", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + admin_api_key = response.parse() + assert_matches_type(AdminAPIKey, admin_api_key, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.admin_api_keys.with_streaming_response.create( + name="New Admin Key", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + admin_api_key = await response.parse() + assert_matches_type(AdminAPIKey, admin_api_key, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + admin_api_key = await async_client.admin.organization.admin_api_keys.retrieve( + "key_id", + ) + assert_matches_type(AdminAPIKey, admin_api_key, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.admin_api_keys.with_raw_response.retrieve( + "key_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + admin_api_key = response.parse() + assert_matches_type(AdminAPIKey, admin_api_key, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.admin_api_keys.with_streaming_response.retrieve( + "key_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + admin_api_key = await response.parse() + assert_matches_type(AdminAPIKey, admin_api_key, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `key_id` but received ''"): + await async_client.admin.organization.admin_api_keys.with_raw_response.retrieve( + "", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + admin_api_key = await async_client.admin.organization.admin_api_keys.list() + assert_matches_type(AsyncCursorPage[AdminAPIKey], admin_api_key, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + admin_api_key = await async_client.admin.organization.admin_api_keys.list( + after="after", + limit=0, + order="asc", + ) + assert_matches_type(AsyncCursorPage[AdminAPIKey], admin_api_key, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.admin_api_keys.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + admin_api_key = response.parse() + assert_matches_type(AsyncCursorPage[AdminAPIKey], admin_api_key, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.admin_api_keys.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + admin_api_key = await response.parse() + assert_matches_type(AsyncCursorPage[AdminAPIKey], admin_api_key, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncOpenAI) -> None: + admin_api_key = await async_client.admin.organization.admin_api_keys.delete( + "key_id", + ) + assert_matches_type(AdminAPIKeyDeleteResponse, admin_api_key, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.admin_api_keys.with_raw_response.delete( + "key_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + admin_api_key = response.parse() + assert_matches_type(AdminAPIKeyDeleteResponse, admin_api_key, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.admin_api_keys.with_streaming_response.delete( + "key_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + admin_api_key = await response.parse() + assert_matches_type(AdminAPIKeyDeleteResponse, admin_api_key, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `key_id` but received ''"): + await async_client.admin.organization.admin_api_keys.with_raw_response.delete( + "", + ) diff --git a/tests/api_resources/admin/organization/test_certificates.py b/tests/api_resources/admin/organization/test_certificates.py new file mode 100644 index 0000000000..a1f0053f13 --- /dev/null +++ b/tests/api_resources/admin/organization/test_certificates.py @@ -0,0 +1,550 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.pagination import SyncPage, AsyncPage, SyncConversationCursorPage, AsyncConversationCursorPage +from openai.types.admin.organization import ( + Certificate, + CertificateDeleteResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestCertificates: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: OpenAI) -> None: + certificate = client.admin.organization.certificates.create( + content="content", + ) + assert_matches_type(Certificate, certificate, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: OpenAI) -> None: + certificate = client.admin.organization.certificates.create( + content="content", + name="name", + ) + assert_matches_type(Certificate, certificate, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: OpenAI) -> None: + response = client.admin.organization.certificates.with_raw_response.create( + content="content", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = response.parse() + assert_matches_type(Certificate, certificate, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: OpenAI) -> None: + with client.admin.organization.certificates.with_streaming_response.create( + content="content", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = response.parse() + assert_matches_type(Certificate, certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + certificate = client.admin.organization.certificates.retrieve( + certificate_id="certificate_id", + ) + assert_matches_type(Certificate, certificate, path=["response"]) + + @parametrize + def test_method_retrieve_with_all_params(self, client: OpenAI) -> None: + certificate = client.admin.organization.certificates.retrieve( + certificate_id="certificate_id", + include=["content"], + ) + assert_matches_type(Certificate, certificate, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.admin.organization.certificates.with_raw_response.retrieve( + certificate_id="certificate_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = response.parse() + assert_matches_type(Certificate, certificate, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.admin.organization.certificates.with_streaming_response.retrieve( + certificate_id="certificate_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = response.parse() + assert_matches_type(Certificate, certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `certificate_id` but received ''"): + client.admin.organization.certificates.with_raw_response.retrieve( + certificate_id="", + ) + + @parametrize + def test_method_update(self, client: OpenAI) -> None: + certificate = client.admin.organization.certificates.update( + certificate_id="certificate_id", + name="name", + ) + assert_matches_type(Certificate, certificate, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: OpenAI) -> None: + response = client.admin.organization.certificates.with_raw_response.update( + certificate_id="certificate_id", + name="name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = response.parse() + assert_matches_type(Certificate, certificate, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: OpenAI) -> None: + with client.admin.organization.certificates.with_streaming_response.update( + certificate_id="certificate_id", + name="name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = response.parse() + assert_matches_type(Certificate, certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `certificate_id` but received ''"): + client.admin.organization.certificates.with_raw_response.update( + certificate_id="", + name="name", + ) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + certificate = client.admin.organization.certificates.list() + assert_matches_type(SyncConversationCursorPage[Certificate], certificate, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + certificate = client.admin.organization.certificates.list( + after="after", + limit=0, + order="asc", + ) + assert_matches_type(SyncConversationCursorPage[Certificate], certificate, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.admin.organization.certificates.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = response.parse() + assert_matches_type(SyncConversationCursorPage[Certificate], certificate, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.admin.organization.certificates.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = response.parse() + assert_matches_type(SyncConversationCursorPage[Certificate], certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: OpenAI) -> None: + certificate = client.admin.organization.certificates.delete( + "certificate_id", + ) + assert_matches_type(CertificateDeleteResponse, certificate, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: OpenAI) -> None: + response = client.admin.organization.certificates.with_raw_response.delete( + "certificate_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = response.parse() + assert_matches_type(CertificateDeleteResponse, certificate, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: OpenAI) -> None: + with client.admin.organization.certificates.with_streaming_response.delete( + "certificate_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = response.parse() + assert_matches_type(CertificateDeleteResponse, certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `certificate_id` but received ''"): + client.admin.organization.certificates.with_raw_response.delete( + "", + ) + + @parametrize + def test_method_activate(self, client: OpenAI) -> None: + certificate = client.admin.organization.certificates.activate( + certificate_ids=["cert_abc"], + ) + assert_matches_type(SyncPage[Certificate], certificate, path=["response"]) + + @parametrize + def test_raw_response_activate(self, client: OpenAI) -> None: + response = client.admin.organization.certificates.with_raw_response.activate( + certificate_ids=["cert_abc"], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = response.parse() + assert_matches_type(SyncPage[Certificate], certificate, path=["response"]) + + @parametrize + def test_streaming_response_activate(self, client: OpenAI) -> None: + with client.admin.organization.certificates.with_streaming_response.activate( + certificate_ids=["cert_abc"], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = response.parse() + assert_matches_type(SyncPage[Certificate], certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_deactivate(self, client: OpenAI) -> None: + certificate = client.admin.organization.certificates.deactivate( + certificate_ids=["cert_abc"], + ) + assert_matches_type(SyncPage[Certificate], certificate, path=["response"]) + + @parametrize + def test_raw_response_deactivate(self, client: OpenAI) -> None: + response = client.admin.organization.certificates.with_raw_response.deactivate( + certificate_ids=["cert_abc"], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = response.parse() + assert_matches_type(SyncPage[Certificate], certificate, path=["response"]) + + @parametrize + def test_streaming_response_deactivate(self, client: OpenAI) -> None: + with client.admin.organization.certificates.with_streaming_response.deactivate( + certificate_ids=["cert_abc"], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = response.parse() + assert_matches_type(SyncPage[Certificate], certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncCertificates: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncOpenAI) -> None: + certificate = await async_client.admin.organization.certificates.create( + content="content", + ) + assert_matches_type(Certificate, certificate, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: + certificate = await async_client.admin.organization.certificates.create( + content="content", + name="name", + ) + assert_matches_type(Certificate, certificate, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.certificates.with_raw_response.create( + content="content", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = response.parse() + assert_matches_type(Certificate, certificate, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.certificates.with_streaming_response.create( + content="content", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = await response.parse() + assert_matches_type(Certificate, certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + certificate = await async_client.admin.organization.certificates.retrieve( + certificate_id="certificate_id", + ) + assert_matches_type(Certificate, certificate, path=["response"]) + + @parametrize + async def test_method_retrieve_with_all_params(self, async_client: AsyncOpenAI) -> None: + certificate = await async_client.admin.organization.certificates.retrieve( + certificate_id="certificate_id", + include=["content"], + ) + assert_matches_type(Certificate, certificate, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.certificates.with_raw_response.retrieve( + certificate_id="certificate_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = response.parse() + assert_matches_type(Certificate, certificate, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.certificates.with_streaming_response.retrieve( + certificate_id="certificate_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = await response.parse() + assert_matches_type(Certificate, certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `certificate_id` but received ''"): + await async_client.admin.organization.certificates.with_raw_response.retrieve( + certificate_id="", + ) + + @parametrize + async def test_method_update(self, async_client: AsyncOpenAI) -> None: + certificate = await async_client.admin.organization.certificates.update( + certificate_id="certificate_id", + name="name", + ) + assert_matches_type(Certificate, certificate, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.certificates.with_raw_response.update( + certificate_id="certificate_id", + name="name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = response.parse() + assert_matches_type(Certificate, certificate, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.certificates.with_streaming_response.update( + certificate_id="certificate_id", + name="name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = await response.parse() + assert_matches_type(Certificate, certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `certificate_id` but received ''"): + await async_client.admin.organization.certificates.with_raw_response.update( + certificate_id="", + name="name", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + certificate = await async_client.admin.organization.certificates.list() + assert_matches_type(AsyncConversationCursorPage[Certificate], certificate, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + certificate = await async_client.admin.organization.certificates.list( + after="after", + limit=0, + order="asc", + ) + assert_matches_type(AsyncConversationCursorPage[Certificate], certificate, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.certificates.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = response.parse() + assert_matches_type(AsyncConversationCursorPage[Certificate], certificate, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.certificates.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = await response.parse() + assert_matches_type(AsyncConversationCursorPage[Certificate], certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncOpenAI) -> None: + certificate = await async_client.admin.organization.certificates.delete( + "certificate_id", + ) + assert_matches_type(CertificateDeleteResponse, certificate, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.certificates.with_raw_response.delete( + "certificate_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = response.parse() + assert_matches_type(CertificateDeleteResponse, certificate, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.certificates.with_streaming_response.delete( + "certificate_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = await response.parse() + assert_matches_type(CertificateDeleteResponse, certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `certificate_id` but received ''"): + await async_client.admin.organization.certificates.with_raw_response.delete( + "", + ) + + @parametrize + async def test_method_activate(self, async_client: AsyncOpenAI) -> None: + certificate = await async_client.admin.organization.certificates.activate( + certificate_ids=["cert_abc"], + ) + assert_matches_type(AsyncPage[Certificate], certificate, path=["response"]) + + @parametrize + async def test_raw_response_activate(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.certificates.with_raw_response.activate( + certificate_ids=["cert_abc"], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = response.parse() + assert_matches_type(AsyncPage[Certificate], certificate, path=["response"]) + + @parametrize + async def test_streaming_response_activate(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.certificates.with_streaming_response.activate( + certificate_ids=["cert_abc"], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = await response.parse() + assert_matches_type(AsyncPage[Certificate], certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_deactivate(self, async_client: AsyncOpenAI) -> None: + certificate = await async_client.admin.organization.certificates.deactivate( + certificate_ids=["cert_abc"], + ) + assert_matches_type(AsyncPage[Certificate], certificate, path=["response"]) + + @parametrize + async def test_raw_response_deactivate(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.certificates.with_raw_response.deactivate( + certificate_ids=["cert_abc"], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = response.parse() + assert_matches_type(AsyncPage[Certificate], certificate, path=["response"]) + + @parametrize + async def test_streaming_response_deactivate(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.certificates.with_streaming_response.deactivate( + certificate_ids=["cert_abc"], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = await response.parse() + assert_matches_type(AsyncPage[Certificate], certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/admin/organization/test_groups.py b/tests/api_resources/admin/organization/test_groups.py new file mode 100644 index 0000000000..b37469625b --- /dev/null +++ b/tests/api_resources/admin/organization/test_groups.py @@ -0,0 +1,319 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.pagination import SyncCursorPage, AsyncCursorPage +from openai.types.admin.organization import ( + Group, + GroupDeleteResponse, + GroupUpdateResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestGroups: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: OpenAI) -> None: + group = client.admin.organization.groups.create( + name="x", + ) + assert_matches_type(Group, group, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: OpenAI) -> None: + response = client.admin.organization.groups.with_raw_response.create( + name="x", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + group = response.parse() + assert_matches_type(Group, group, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: OpenAI) -> None: + with client.admin.organization.groups.with_streaming_response.create( + name="x", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + group = response.parse() + assert_matches_type(Group, group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: OpenAI) -> None: + group = client.admin.organization.groups.update( + group_id="group_id", + name="x", + ) + assert_matches_type(GroupUpdateResponse, group, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: OpenAI) -> None: + response = client.admin.organization.groups.with_raw_response.update( + group_id="group_id", + name="x", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + group = response.parse() + assert_matches_type(GroupUpdateResponse, group, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: OpenAI) -> None: + with client.admin.organization.groups.with_streaming_response.update( + group_id="group_id", + name="x", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + group = response.parse() + assert_matches_type(GroupUpdateResponse, group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + client.admin.organization.groups.with_raw_response.update( + group_id="", + name="x", + ) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + group = client.admin.organization.groups.list() + assert_matches_type(SyncCursorPage[Group], group, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + group = client.admin.organization.groups.list( + after="after", + limit=0, + order="asc", + ) + assert_matches_type(SyncCursorPage[Group], group, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.admin.organization.groups.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + group = response.parse() + assert_matches_type(SyncCursorPage[Group], group, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.admin.organization.groups.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + group = response.parse() + assert_matches_type(SyncCursorPage[Group], group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: OpenAI) -> None: + group = client.admin.organization.groups.delete( + "group_id", + ) + assert_matches_type(GroupDeleteResponse, group, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: OpenAI) -> None: + response = client.admin.organization.groups.with_raw_response.delete( + "group_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + group = response.parse() + assert_matches_type(GroupDeleteResponse, group, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: OpenAI) -> None: + with client.admin.organization.groups.with_streaming_response.delete( + "group_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + group = response.parse() + assert_matches_type(GroupDeleteResponse, group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + client.admin.organization.groups.with_raw_response.delete( + "", + ) + + +class TestAsyncGroups: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncOpenAI) -> None: + group = await async_client.admin.organization.groups.create( + name="x", + ) + assert_matches_type(Group, group, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.groups.with_raw_response.create( + name="x", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + group = response.parse() + assert_matches_type(Group, group, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.groups.with_streaming_response.create( + name="x", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + group = await response.parse() + assert_matches_type(Group, group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncOpenAI) -> None: + group = await async_client.admin.organization.groups.update( + group_id="group_id", + name="x", + ) + assert_matches_type(GroupUpdateResponse, group, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.groups.with_raw_response.update( + group_id="group_id", + name="x", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + group = response.parse() + assert_matches_type(GroupUpdateResponse, group, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.groups.with_streaming_response.update( + group_id="group_id", + name="x", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + group = await response.parse() + assert_matches_type(GroupUpdateResponse, group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + await async_client.admin.organization.groups.with_raw_response.update( + group_id="", + name="x", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + group = await async_client.admin.organization.groups.list() + assert_matches_type(AsyncCursorPage[Group], group, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + group = await async_client.admin.organization.groups.list( + after="after", + limit=0, + order="asc", + ) + assert_matches_type(AsyncCursorPage[Group], group, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.groups.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + group = response.parse() + assert_matches_type(AsyncCursorPage[Group], group, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.groups.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + group = await response.parse() + assert_matches_type(AsyncCursorPage[Group], group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncOpenAI) -> None: + group = await async_client.admin.organization.groups.delete( + "group_id", + ) + assert_matches_type(GroupDeleteResponse, group, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.groups.with_raw_response.delete( + "group_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + group = response.parse() + assert_matches_type(GroupDeleteResponse, group, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.groups.with_streaming_response.delete( + "group_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + group = await response.parse() + assert_matches_type(GroupDeleteResponse, group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + await async_client.admin.organization.groups.with_raw_response.delete( + "", + ) diff --git a/tests/api_resources/admin/organization/test_invites.py b/tests/api_resources/admin/organization/test_invites.py new file mode 100644 index 0000000000..ddad6e6e31 --- /dev/null +++ b/tests/api_resources/admin/organization/test_invites.py @@ -0,0 +1,339 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.pagination import SyncConversationCursorPage, AsyncConversationCursorPage +from openai.types.admin.organization import Invite, InviteDeleteResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestInvites: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: OpenAI) -> None: + invite = client.admin.organization.invites.create( + email="email", + role="reader", + ) + assert_matches_type(Invite, invite, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: OpenAI) -> None: + invite = client.admin.organization.invites.create( + email="email", + role="reader", + projects=[ + { + "id": "id", + "role": "member", + } + ], + ) + assert_matches_type(Invite, invite, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: OpenAI) -> None: + response = client.admin.organization.invites.with_raw_response.create( + email="email", + role="reader", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + invite = response.parse() + assert_matches_type(Invite, invite, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: OpenAI) -> None: + with client.admin.organization.invites.with_streaming_response.create( + email="email", + role="reader", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + invite = response.parse() + assert_matches_type(Invite, invite, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + invite = client.admin.organization.invites.retrieve( + "invite_id", + ) + assert_matches_type(Invite, invite, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.admin.organization.invites.with_raw_response.retrieve( + "invite_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + invite = response.parse() + assert_matches_type(Invite, invite, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.admin.organization.invites.with_streaming_response.retrieve( + "invite_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + invite = response.parse() + assert_matches_type(Invite, invite, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `invite_id` but received ''"): + client.admin.organization.invites.with_raw_response.retrieve( + "", + ) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + invite = client.admin.organization.invites.list() + assert_matches_type(SyncConversationCursorPage[Invite], invite, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + invite = client.admin.organization.invites.list( + after="after", + limit=0, + ) + assert_matches_type(SyncConversationCursorPage[Invite], invite, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.admin.organization.invites.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + invite = response.parse() + assert_matches_type(SyncConversationCursorPage[Invite], invite, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.admin.organization.invites.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + invite = response.parse() + assert_matches_type(SyncConversationCursorPage[Invite], invite, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: OpenAI) -> None: + invite = client.admin.organization.invites.delete( + "invite_id", + ) + assert_matches_type(InviteDeleteResponse, invite, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: OpenAI) -> None: + response = client.admin.organization.invites.with_raw_response.delete( + "invite_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + invite = response.parse() + assert_matches_type(InviteDeleteResponse, invite, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: OpenAI) -> None: + with client.admin.organization.invites.with_streaming_response.delete( + "invite_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + invite = response.parse() + assert_matches_type(InviteDeleteResponse, invite, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `invite_id` but received ''"): + client.admin.organization.invites.with_raw_response.delete( + "", + ) + + +class TestAsyncInvites: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncOpenAI) -> None: + invite = await async_client.admin.organization.invites.create( + email="email", + role="reader", + ) + assert_matches_type(Invite, invite, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: + invite = await async_client.admin.organization.invites.create( + email="email", + role="reader", + projects=[ + { + "id": "id", + "role": "member", + } + ], + ) + assert_matches_type(Invite, invite, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.invites.with_raw_response.create( + email="email", + role="reader", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + invite = response.parse() + assert_matches_type(Invite, invite, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.invites.with_streaming_response.create( + email="email", + role="reader", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + invite = await response.parse() + assert_matches_type(Invite, invite, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + invite = await async_client.admin.organization.invites.retrieve( + "invite_id", + ) + assert_matches_type(Invite, invite, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.invites.with_raw_response.retrieve( + "invite_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + invite = response.parse() + assert_matches_type(Invite, invite, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.invites.with_streaming_response.retrieve( + "invite_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + invite = await response.parse() + assert_matches_type(Invite, invite, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `invite_id` but received ''"): + await async_client.admin.organization.invites.with_raw_response.retrieve( + "", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + invite = await async_client.admin.organization.invites.list() + assert_matches_type(AsyncConversationCursorPage[Invite], invite, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + invite = await async_client.admin.organization.invites.list( + after="after", + limit=0, + ) + assert_matches_type(AsyncConversationCursorPage[Invite], invite, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.invites.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + invite = response.parse() + assert_matches_type(AsyncConversationCursorPage[Invite], invite, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.invites.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + invite = await response.parse() + assert_matches_type(AsyncConversationCursorPage[Invite], invite, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncOpenAI) -> None: + invite = await async_client.admin.organization.invites.delete( + "invite_id", + ) + assert_matches_type(InviteDeleteResponse, invite, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.invites.with_raw_response.delete( + "invite_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + invite = response.parse() + assert_matches_type(InviteDeleteResponse, invite, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.invites.with_streaming_response.delete( + "invite_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + invite = await response.parse() + assert_matches_type(InviteDeleteResponse, invite, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `invite_id` but received ''"): + await async_client.admin.organization.invites.with_raw_response.delete( + "", + ) diff --git a/tests/api_resources/admin/organization/test_projects.py b/tests/api_resources/admin/organization/test_projects.py new file mode 100644 index 0000000000..49c18827de --- /dev/null +++ b/tests/api_resources/admin/organization/test_projects.py @@ -0,0 +1,407 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.pagination import SyncConversationCursorPage, AsyncConversationCursorPage +from openai.types.admin.organization import Project + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestProjects: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: OpenAI) -> None: + project = client.admin.organization.projects.create( + name="name", + ) + assert_matches_type(Project, project, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: OpenAI) -> None: + project = client.admin.organization.projects.create( + name="name", + geography="US", + ) + assert_matches_type(Project, project, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: OpenAI) -> None: + response = client.admin.organization.projects.with_raw_response.create( + name="name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = response.parse() + assert_matches_type(Project, project, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: OpenAI) -> None: + with client.admin.organization.projects.with_streaming_response.create( + name="name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = response.parse() + assert_matches_type(Project, project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + project = client.admin.organization.projects.retrieve( + "project_id", + ) + assert_matches_type(Project, project, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.admin.organization.projects.with_raw_response.retrieve( + "project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = response.parse() + assert_matches_type(Project, project, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.admin.organization.projects.with_streaming_response.retrieve( + "project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = response.parse() + assert_matches_type(Project, project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.with_raw_response.retrieve( + "", + ) + + @parametrize + def test_method_update(self, client: OpenAI) -> None: + project = client.admin.organization.projects.update( + project_id="project_id", + name="name", + ) + assert_matches_type(Project, project, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: OpenAI) -> None: + response = client.admin.organization.projects.with_raw_response.update( + project_id="project_id", + name="name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = response.parse() + assert_matches_type(Project, project, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: OpenAI) -> None: + with client.admin.organization.projects.with_streaming_response.update( + project_id="project_id", + name="name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = response.parse() + assert_matches_type(Project, project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.with_raw_response.update( + project_id="", + name="name", + ) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + project = client.admin.organization.projects.list() + assert_matches_type(SyncConversationCursorPage[Project], project, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + project = client.admin.organization.projects.list( + after="after", + include_archived=True, + limit=0, + ) + assert_matches_type(SyncConversationCursorPage[Project], project, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.admin.organization.projects.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = response.parse() + assert_matches_type(SyncConversationCursorPage[Project], project, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.admin.organization.projects.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = response.parse() + assert_matches_type(SyncConversationCursorPage[Project], project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_archive(self, client: OpenAI) -> None: + project = client.admin.organization.projects.archive( + "project_id", + ) + assert_matches_type(Project, project, path=["response"]) + + @parametrize + def test_raw_response_archive(self, client: OpenAI) -> None: + response = client.admin.organization.projects.with_raw_response.archive( + "project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = response.parse() + assert_matches_type(Project, project, path=["response"]) + + @parametrize + def test_streaming_response_archive(self, client: OpenAI) -> None: + with client.admin.organization.projects.with_streaming_response.archive( + "project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = response.parse() + assert_matches_type(Project, project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_archive(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.with_raw_response.archive( + "", + ) + + +class TestAsyncProjects: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncOpenAI) -> None: + project = await async_client.admin.organization.projects.create( + name="name", + ) + assert_matches_type(Project, project, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: + project = await async_client.admin.organization.projects.create( + name="name", + geography="US", + ) + assert_matches_type(Project, project, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.with_raw_response.create( + name="name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = response.parse() + assert_matches_type(Project, project, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.with_streaming_response.create( + name="name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = await response.parse() + assert_matches_type(Project, project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + project = await async_client.admin.organization.projects.retrieve( + "project_id", + ) + assert_matches_type(Project, project, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.with_raw_response.retrieve( + "project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = response.parse() + assert_matches_type(Project, project, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.with_streaming_response.retrieve( + "project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = await response.parse() + assert_matches_type(Project, project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.with_raw_response.retrieve( + "", + ) + + @parametrize + async def test_method_update(self, async_client: AsyncOpenAI) -> None: + project = await async_client.admin.organization.projects.update( + project_id="project_id", + name="name", + ) + assert_matches_type(Project, project, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.with_raw_response.update( + project_id="project_id", + name="name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = response.parse() + assert_matches_type(Project, project, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.with_streaming_response.update( + project_id="project_id", + name="name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = await response.parse() + assert_matches_type(Project, project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.with_raw_response.update( + project_id="", + name="name", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + project = await async_client.admin.organization.projects.list() + assert_matches_type(AsyncConversationCursorPage[Project], project, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + project = await async_client.admin.organization.projects.list( + after="after", + include_archived=True, + limit=0, + ) + assert_matches_type(AsyncConversationCursorPage[Project], project, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = response.parse() + assert_matches_type(AsyncConversationCursorPage[Project], project, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = await response.parse() + assert_matches_type(AsyncConversationCursorPage[Project], project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_archive(self, async_client: AsyncOpenAI) -> None: + project = await async_client.admin.organization.projects.archive( + "project_id", + ) + assert_matches_type(Project, project, path=["response"]) + + @parametrize + async def test_raw_response_archive(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.with_raw_response.archive( + "project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = response.parse() + assert_matches_type(Project, project, path=["response"]) + + @parametrize + async def test_streaming_response_archive(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.with_streaming_response.archive( + "project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = await response.parse() + assert_matches_type(Project, project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_archive(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.with_raw_response.archive( + "", + ) diff --git a/tests/api_resources/admin/organization/test_roles.py b/tests/api_resources/admin/organization/test_roles.py new file mode 100644 index 0000000000..1b4b44278b --- /dev/null +++ b/tests/api_resources/admin/organization/test_roles.py @@ -0,0 +1,354 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.pagination import SyncCursorPage, AsyncCursorPage +from openai.types.admin.organization import ( + Role, + RoleDeleteResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestRoles: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: OpenAI) -> None: + role = client.admin.organization.roles.create( + permissions=["string"], + role_name="role_name", + ) + assert_matches_type(Role, role, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: OpenAI) -> None: + role = client.admin.organization.roles.create( + permissions=["string"], + role_name="role_name", + description="description", + ) + assert_matches_type(Role, role, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: OpenAI) -> None: + response = client.admin.organization.roles.with_raw_response.create( + permissions=["string"], + role_name="role_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(Role, role, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: OpenAI) -> None: + with client.admin.organization.roles.with_streaming_response.create( + permissions=["string"], + role_name="role_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = response.parse() + assert_matches_type(Role, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: OpenAI) -> None: + role = client.admin.organization.roles.update( + role_id="role_id", + ) + assert_matches_type(Role, role, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: OpenAI) -> None: + role = client.admin.organization.roles.update( + role_id="role_id", + description="description", + permissions=["string"], + role_name="role_name", + ) + assert_matches_type(Role, role, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: OpenAI) -> None: + response = client.admin.organization.roles.with_raw_response.update( + role_id="role_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(Role, role, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: OpenAI) -> None: + with client.admin.organization.roles.with_streaming_response.update( + role_id="role_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = response.parse() + assert_matches_type(Role, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): + client.admin.organization.roles.with_raw_response.update( + role_id="", + ) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + role = client.admin.organization.roles.list() + assert_matches_type(SyncCursorPage[Role], role, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + role = client.admin.organization.roles.list( + after="after", + limit=0, + order="asc", + ) + assert_matches_type(SyncCursorPage[Role], role, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.admin.organization.roles.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(SyncCursorPage[Role], role, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.admin.organization.roles.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = response.parse() + assert_matches_type(SyncCursorPage[Role], role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: OpenAI) -> None: + role = client.admin.organization.roles.delete( + "role_id", + ) + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: OpenAI) -> None: + response = client.admin.organization.roles.with_raw_response.delete( + "role_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: OpenAI) -> None: + with client.admin.organization.roles.with_streaming_response.delete( + "role_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = response.parse() + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): + client.admin.organization.roles.with_raw_response.delete( + "", + ) + + +class TestAsyncRoles: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.roles.create( + permissions=["string"], + role_name="role_name", + ) + assert_matches_type(Role, role, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.roles.create( + permissions=["string"], + role_name="role_name", + description="description", + ) + assert_matches_type(Role, role, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.roles.with_raw_response.create( + permissions=["string"], + role_name="role_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(Role, role, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.roles.with_streaming_response.create( + permissions=["string"], + role_name="role_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = await response.parse() + assert_matches_type(Role, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.roles.update( + role_id="role_id", + ) + assert_matches_type(Role, role, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.roles.update( + role_id="role_id", + description="description", + permissions=["string"], + role_name="role_name", + ) + assert_matches_type(Role, role, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.roles.with_raw_response.update( + role_id="role_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(Role, role, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.roles.with_streaming_response.update( + role_id="role_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = await response.parse() + assert_matches_type(Role, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): + await async_client.admin.organization.roles.with_raw_response.update( + role_id="", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.roles.list() + assert_matches_type(AsyncCursorPage[Role], role, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.roles.list( + after="after", + limit=0, + order="asc", + ) + assert_matches_type(AsyncCursorPage[Role], role, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.roles.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(AsyncCursorPage[Role], role, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.roles.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = await response.parse() + assert_matches_type(AsyncCursorPage[Role], role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.roles.delete( + "role_id", + ) + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.roles.with_raw_response.delete( + "role_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.roles.with_streaming_response.delete( + "role_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = await response.parse() + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): + await async_client.admin.organization.roles.with_raw_response.delete( + "", + ) diff --git a/tests/api_resources/admin/organization/test_usage.py b/tests/api_resources/admin/organization/test_usage.py new file mode 100644 index 0000000000..f9c4a8e2c5 --- /dev/null +++ b/tests/api_resources/admin/organization/test_usage.py @@ -0,0 +1,870 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.types.admin.organization import ( + UsageCostsResponse, + UsageImagesResponse, + UsageEmbeddingsResponse, + UsageCompletionsResponse, + UsageModerationsResponse, + UsageVectorStoresResponse, + UsageAudioSpeechesResponse, + UsageAudioTranscriptionsResponse, + UsageCodeInterpreterSessionsResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestUsage: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_audio_speeches(self, client: OpenAI) -> None: + usage = client.admin.organization.usage.audio_speeches( + start_time=0, + ) + assert_matches_type(UsageAudioSpeechesResponse, usage, path=["response"]) + + @parametrize + def test_method_audio_speeches_with_all_params(self, client: OpenAI) -> None: + usage = client.admin.organization.usage.audio_speeches( + start_time=0, + api_key_ids=["string"], + bucket_width="1m", + end_time=0, + group_by=["project_id"], + limit=0, + models=["string"], + page="page", + project_ids=["string"], + user_ids=["string"], + ) + assert_matches_type(UsageAudioSpeechesResponse, usage, path=["response"]) + + @parametrize + def test_raw_response_audio_speeches(self, client: OpenAI) -> None: + response = client.admin.organization.usage.with_raw_response.audio_speeches( + start_time=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + usage = response.parse() + assert_matches_type(UsageAudioSpeechesResponse, usage, path=["response"]) + + @parametrize + def test_streaming_response_audio_speeches(self, client: OpenAI) -> None: + with client.admin.organization.usage.with_streaming_response.audio_speeches( + start_time=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + usage = response.parse() + assert_matches_type(UsageAudioSpeechesResponse, usage, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_audio_transcriptions(self, client: OpenAI) -> None: + usage = client.admin.organization.usage.audio_transcriptions( + start_time=0, + ) + assert_matches_type(UsageAudioTranscriptionsResponse, usage, path=["response"]) + + @parametrize + def test_method_audio_transcriptions_with_all_params(self, client: OpenAI) -> None: + usage = client.admin.organization.usage.audio_transcriptions( + start_time=0, + api_key_ids=["string"], + bucket_width="1m", + end_time=0, + group_by=["project_id"], + limit=0, + models=["string"], + page="page", + project_ids=["string"], + user_ids=["string"], + ) + assert_matches_type(UsageAudioTranscriptionsResponse, usage, path=["response"]) + + @parametrize + def test_raw_response_audio_transcriptions(self, client: OpenAI) -> None: + response = client.admin.organization.usage.with_raw_response.audio_transcriptions( + start_time=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + usage = response.parse() + assert_matches_type(UsageAudioTranscriptionsResponse, usage, path=["response"]) + + @parametrize + def test_streaming_response_audio_transcriptions(self, client: OpenAI) -> None: + with client.admin.organization.usage.with_streaming_response.audio_transcriptions( + start_time=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + usage = response.parse() + assert_matches_type(UsageAudioTranscriptionsResponse, usage, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_code_interpreter_sessions(self, client: OpenAI) -> None: + usage = client.admin.organization.usage.code_interpreter_sessions( + start_time=0, + ) + assert_matches_type(UsageCodeInterpreterSessionsResponse, usage, path=["response"]) + + @parametrize + def test_method_code_interpreter_sessions_with_all_params(self, client: OpenAI) -> None: + usage = client.admin.organization.usage.code_interpreter_sessions( + start_time=0, + bucket_width="1m", + end_time=0, + group_by=["project_id"], + limit=0, + page="page", + project_ids=["string"], + ) + assert_matches_type(UsageCodeInterpreterSessionsResponse, usage, path=["response"]) + + @parametrize + def test_raw_response_code_interpreter_sessions(self, client: OpenAI) -> None: + response = client.admin.organization.usage.with_raw_response.code_interpreter_sessions( + start_time=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + usage = response.parse() + assert_matches_type(UsageCodeInterpreterSessionsResponse, usage, path=["response"]) + + @parametrize + def test_streaming_response_code_interpreter_sessions(self, client: OpenAI) -> None: + with client.admin.organization.usage.with_streaming_response.code_interpreter_sessions( + start_time=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + usage = response.parse() + assert_matches_type(UsageCodeInterpreterSessionsResponse, usage, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_completions(self, client: OpenAI) -> None: + usage = client.admin.organization.usage.completions( + start_time=0, + ) + assert_matches_type(UsageCompletionsResponse, usage, path=["response"]) + + @parametrize + def test_method_completions_with_all_params(self, client: OpenAI) -> None: + usage = client.admin.organization.usage.completions( + start_time=0, + api_key_ids=["string"], + batch=True, + bucket_width="1m", + end_time=0, + group_by=["project_id"], + limit=0, + models=["string"], + page="page", + project_ids=["string"], + user_ids=["string"], + ) + assert_matches_type(UsageCompletionsResponse, usage, path=["response"]) + + @parametrize + def test_raw_response_completions(self, client: OpenAI) -> None: + response = client.admin.organization.usage.with_raw_response.completions( + start_time=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + usage = response.parse() + assert_matches_type(UsageCompletionsResponse, usage, path=["response"]) + + @parametrize + def test_streaming_response_completions(self, client: OpenAI) -> None: + with client.admin.organization.usage.with_streaming_response.completions( + start_time=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + usage = response.parse() + assert_matches_type(UsageCompletionsResponse, usage, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_costs(self, client: OpenAI) -> None: + usage = client.admin.organization.usage.costs( + start_time=0, + ) + assert_matches_type(UsageCostsResponse, usage, path=["response"]) + + @parametrize + def test_method_costs_with_all_params(self, client: OpenAI) -> None: + usage = client.admin.organization.usage.costs( + start_time=0, + api_key_ids=["string"], + bucket_width="1d", + end_time=0, + group_by=["project_id"], + limit=0, + page="page", + project_ids=["string"], + ) + assert_matches_type(UsageCostsResponse, usage, path=["response"]) + + @parametrize + def test_raw_response_costs(self, client: OpenAI) -> None: + response = client.admin.organization.usage.with_raw_response.costs( + start_time=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + usage = response.parse() + assert_matches_type(UsageCostsResponse, usage, path=["response"]) + + @parametrize + def test_streaming_response_costs(self, client: OpenAI) -> None: + with client.admin.organization.usage.with_streaming_response.costs( + start_time=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + usage = response.parse() + assert_matches_type(UsageCostsResponse, usage, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_embeddings(self, client: OpenAI) -> None: + usage = client.admin.organization.usage.embeddings( + start_time=0, + ) + assert_matches_type(UsageEmbeddingsResponse, usage, path=["response"]) + + @parametrize + def test_method_embeddings_with_all_params(self, client: OpenAI) -> None: + usage = client.admin.organization.usage.embeddings( + start_time=0, + api_key_ids=["string"], + bucket_width="1m", + end_time=0, + group_by=["project_id"], + limit=0, + models=["string"], + page="page", + project_ids=["string"], + user_ids=["string"], + ) + assert_matches_type(UsageEmbeddingsResponse, usage, path=["response"]) + + @parametrize + def test_raw_response_embeddings(self, client: OpenAI) -> None: + response = client.admin.organization.usage.with_raw_response.embeddings( + start_time=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + usage = response.parse() + assert_matches_type(UsageEmbeddingsResponse, usage, path=["response"]) + + @parametrize + def test_streaming_response_embeddings(self, client: OpenAI) -> None: + with client.admin.organization.usage.with_streaming_response.embeddings( + start_time=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + usage = response.parse() + assert_matches_type(UsageEmbeddingsResponse, usage, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_images(self, client: OpenAI) -> None: + usage = client.admin.organization.usage.images( + start_time=0, + ) + assert_matches_type(UsageImagesResponse, usage, path=["response"]) + + @parametrize + def test_method_images_with_all_params(self, client: OpenAI) -> None: + usage = client.admin.organization.usage.images( + start_time=0, + api_key_ids=["string"], + bucket_width="1m", + end_time=0, + group_by=["project_id"], + limit=0, + models=["string"], + page="page", + project_ids=["string"], + sizes=["256x256"], + sources=["image.generation"], + user_ids=["string"], + ) + assert_matches_type(UsageImagesResponse, usage, path=["response"]) + + @parametrize + def test_raw_response_images(self, client: OpenAI) -> None: + response = client.admin.organization.usage.with_raw_response.images( + start_time=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + usage = response.parse() + assert_matches_type(UsageImagesResponse, usage, path=["response"]) + + @parametrize + def test_streaming_response_images(self, client: OpenAI) -> None: + with client.admin.organization.usage.with_streaming_response.images( + start_time=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + usage = response.parse() + assert_matches_type(UsageImagesResponse, usage, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_moderations(self, client: OpenAI) -> None: + usage = client.admin.organization.usage.moderations( + start_time=0, + ) + assert_matches_type(UsageModerationsResponse, usage, path=["response"]) + + @parametrize + def test_method_moderations_with_all_params(self, client: OpenAI) -> None: + usage = client.admin.organization.usage.moderations( + start_time=0, + api_key_ids=["string"], + bucket_width="1m", + end_time=0, + group_by=["project_id"], + limit=0, + models=["string"], + page="page", + project_ids=["string"], + user_ids=["string"], + ) + assert_matches_type(UsageModerationsResponse, usage, path=["response"]) + + @parametrize + def test_raw_response_moderations(self, client: OpenAI) -> None: + response = client.admin.organization.usage.with_raw_response.moderations( + start_time=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + usage = response.parse() + assert_matches_type(UsageModerationsResponse, usage, path=["response"]) + + @parametrize + def test_streaming_response_moderations(self, client: OpenAI) -> None: + with client.admin.organization.usage.with_streaming_response.moderations( + start_time=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + usage = response.parse() + assert_matches_type(UsageModerationsResponse, usage, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_vector_stores(self, client: OpenAI) -> None: + usage = client.admin.organization.usage.vector_stores( + start_time=0, + ) + assert_matches_type(UsageVectorStoresResponse, usage, path=["response"]) + + @parametrize + def test_method_vector_stores_with_all_params(self, client: OpenAI) -> None: + usage = client.admin.organization.usage.vector_stores( + start_time=0, + bucket_width="1m", + end_time=0, + group_by=["project_id"], + limit=0, + page="page", + project_ids=["string"], + ) + assert_matches_type(UsageVectorStoresResponse, usage, path=["response"]) + + @parametrize + def test_raw_response_vector_stores(self, client: OpenAI) -> None: + response = client.admin.organization.usage.with_raw_response.vector_stores( + start_time=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + usage = response.parse() + assert_matches_type(UsageVectorStoresResponse, usage, path=["response"]) + + @parametrize + def test_streaming_response_vector_stores(self, client: OpenAI) -> None: + with client.admin.organization.usage.with_streaming_response.vector_stores( + start_time=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + usage = response.parse() + assert_matches_type(UsageVectorStoresResponse, usage, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncUsage: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_audio_speeches(self, async_client: AsyncOpenAI) -> None: + usage = await async_client.admin.organization.usage.audio_speeches( + start_time=0, + ) + assert_matches_type(UsageAudioSpeechesResponse, usage, path=["response"]) + + @parametrize + async def test_method_audio_speeches_with_all_params(self, async_client: AsyncOpenAI) -> None: + usage = await async_client.admin.organization.usage.audio_speeches( + start_time=0, + api_key_ids=["string"], + bucket_width="1m", + end_time=0, + group_by=["project_id"], + limit=0, + models=["string"], + page="page", + project_ids=["string"], + user_ids=["string"], + ) + assert_matches_type(UsageAudioSpeechesResponse, usage, path=["response"]) + + @parametrize + async def test_raw_response_audio_speeches(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.usage.with_raw_response.audio_speeches( + start_time=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + usage = response.parse() + assert_matches_type(UsageAudioSpeechesResponse, usage, path=["response"]) + + @parametrize + async def test_streaming_response_audio_speeches(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.usage.with_streaming_response.audio_speeches( + start_time=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + usage = await response.parse() + assert_matches_type(UsageAudioSpeechesResponse, usage, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_audio_transcriptions(self, async_client: AsyncOpenAI) -> None: + usage = await async_client.admin.organization.usage.audio_transcriptions( + start_time=0, + ) + assert_matches_type(UsageAudioTranscriptionsResponse, usage, path=["response"]) + + @parametrize + async def test_method_audio_transcriptions_with_all_params(self, async_client: AsyncOpenAI) -> None: + usage = await async_client.admin.organization.usage.audio_transcriptions( + start_time=0, + api_key_ids=["string"], + bucket_width="1m", + end_time=0, + group_by=["project_id"], + limit=0, + models=["string"], + page="page", + project_ids=["string"], + user_ids=["string"], + ) + assert_matches_type(UsageAudioTranscriptionsResponse, usage, path=["response"]) + + @parametrize + async def test_raw_response_audio_transcriptions(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.usage.with_raw_response.audio_transcriptions( + start_time=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + usage = response.parse() + assert_matches_type(UsageAudioTranscriptionsResponse, usage, path=["response"]) + + @parametrize + async def test_streaming_response_audio_transcriptions(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.usage.with_streaming_response.audio_transcriptions( + start_time=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + usage = await response.parse() + assert_matches_type(UsageAudioTranscriptionsResponse, usage, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_code_interpreter_sessions(self, async_client: AsyncOpenAI) -> None: + usage = await async_client.admin.organization.usage.code_interpreter_sessions( + start_time=0, + ) + assert_matches_type(UsageCodeInterpreterSessionsResponse, usage, path=["response"]) + + @parametrize + async def test_method_code_interpreter_sessions_with_all_params(self, async_client: AsyncOpenAI) -> None: + usage = await async_client.admin.organization.usage.code_interpreter_sessions( + start_time=0, + bucket_width="1m", + end_time=0, + group_by=["project_id"], + limit=0, + page="page", + project_ids=["string"], + ) + assert_matches_type(UsageCodeInterpreterSessionsResponse, usage, path=["response"]) + + @parametrize + async def test_raw_response_code_interpreter_sessions(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.usage.with_raw_response.code_interpreter_sessions( + start_time=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + usage = response.parse() + assert_matches_type(UsageCodeInterpreterSessionsResponse, usage, path=["response"]) + + @parametrize + async def test_streaming_response_code_interpreter_sessions(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.usage.with_streaming_response.code_interpreter_sessions( + start_time=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + usage = await response.parse() + assert_matches_type(UsageCodeInterpreterSessionsResponse, usage, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_completions(self, async_client: AsyncOpenAI) -> None: + usage = await async_client.admin.organization.usage.completions( + start_time=0, + ) + assert_matches_type(UsageCompletionsResponse, usage, path=["response"]) + + @parametrize + async def test_method_completions_with_all_params(self, async_client: AsyncOpenAI) -> None: + usage = await async_client.admin.organization.usage.completions( + start_time=0, + api_key_ids=["string"], + batch=True, + bucket_width="1m", + end_time=0, + group_by=["project_id"], + limit=0, + models=["string"], + page="page", + project_ids=["string"], + user_ids=["string"], + ) + assert_matches_type(UsageCompletionsResponse, usage, path=["response"]) + + @parametrize + async def test_raw_response_completions(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.usage.with_raw_response.completions( + start_time=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + usage = response.parse() + assert_matches_type(UsageCompletionsResponse, usage, path=["response"]) + + @parametrize + async def test_streaming_response_completions(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.usage.with_streaming_response.completions( + start_time=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + usage = await response.parse() + assert_matches_type(UsageCompletionsResponse, usage, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_costs(self, async_client: AsyncOpenAI) -> None: + usage = await async_client.admin.organization.usage.costs( + start_time=0, + ) + assert_matches_type(UsageCostsResponse, usage, path=["response"]) + + @parametrize + async def test_method_costs_with_all_params(self, async_client: AsyncOpenAI) -> None: + usage = await async_client.admin.organization.usage.costs( + start_time=0, + api_key_ids=["string"], + bucket_width="1d", + end_time=0, + group_by=["project_id"], + limit=0, + page="page", + project_ids=["string"], + ) + assert_matches_type(UsageCostsResponse, usage, path=["response"]) + + @parametrize + async def test_raw_response_costs(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.usage.with_raw_response.costs( + start_time=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + usage = response.parse() + assert_matches_type(UsageCostsResponse, usage, path=["response"]) + + @parametrize + async def test_streaming_response_costs(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.usage.with_streaming_response.costs( + start_time=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + usage = await response.parse() + assert_matches_type(UsageCostsResponse, usage, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_embeddings(self, async_client: AsyncOpenAI) -> None: + usage = await async_client.admin.organization.usage.embeddings( + start_time=0, + ) + assert_matches_type(UsageEmbeddingsResponse, usage, path=["response"]) + + @parametrize + async def test_method_embeddings_with_all_params(self, async_client: AsyncOpenAI) -> None: + usage = await async_client.admin.organization.usage.embeddings( + start_time=0, + api_key_ids=["string"], + bucket_width="1m", + end_time=0, + group_by=["project_id"], + limit=0, + models=["string"], + page="page", + project_ids=["string"], + user_ids=["string"], + ) + assert_matches_type(UsageEmbeddingsResponse, usage, path=["response"]) + + @parametrize + async def test_raw_response_embeddings(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.usage.with_raw_response.embeddings( + start_time=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + usage = response.parse() + assert_matches_type(UsageEmbeddingsResponse, usage, path=["response"]) + + @parametrize + async def test_streaming_response_embeddings(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.usage.with_streaming_response.embeddings( + start_time=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + usage = await response.parse() + assert_matches_type(UsageEmbeddingsResponse, usage, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_images(self, async_client: AsyncOpenAI) -> None: + usage = await async_client.admin.organization.usage.images( + start_time=0, + ) + assert_matches_type(UsageImagesResponse, usage, path=["response"]) + + @parametrize + async def test_method_images_with_all_params(self, async_client: AsyncOpenAI) -> None: + usage = await async_client.admin.organization.usage.images( + start_time=0, + api_key_ids=["string"], + bucket_width="1m", + end_time=0, + group_by=["project_id"], + limit=0, + models=["string"], + page="page", + project_ids=["string"], + sizes=["256x256"], + sources=["image.generation"], + user_ids=["string"], + ) + assert_matches_type(UsageImagesResponse, usage, path=["response"]) + + @parametrize + async def test_raw_response_images(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.usage.with_raw_response.images( + start_time=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + usage = response.parse() + assert_matches_type(UsageImagesResponse, usage, path=["response"]) + + @parametrize + async def test_streaming_response_images(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.usage.with_streaming_response.images( + start_time=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + usage = await response.parse() + assert_matches_type(UsageImagesResponse, usage, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_moderations(self, async_client: AsyncOpenAI) -> None: + usage = await async_client.admin.organization.usage.moderations( + start_time=0, + ) + assert_matches_type(UsageModerationsResponse, usage, path=["response"]) + + @parametrize + async def test_method_moderations_with_all_params(self, async_client: AsyncOpenAI) -> None: + usage = await async_client.admin.organization.usage.moderations( + start_time=0, + api_key_ids=["string"], + bucket_width="1m", + end_time=0, + group_by=["project_id"], + limit=0, + models=["string"], + page="page", + project_ids=["string"], + user_ids=["string"], + ) + assert_matches_type(UsageModerationsResponse, usage, path=["response"]) + + @parametrize + async def test_raw_response_moderations(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.usage.with_raw_response.moderations( + start_time=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + usage = response.parse() + assert_matches_type(UsageModerationsResponse, usage, path=["response"]) + + @parametrize + async def test_streaming_response_moderations(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.usage.with_streaming_response.moderations( + start_time=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + usage = await response.parse() + assert_matches_type(UsageModerationsResponse, usage, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_vector_stores(self, async_client: AsyncOpenAI) -> None: + usage = await async_client.admin.organization.usage.vector_stores( + start_time=0, + ) + assert_matches_type(UsageVectorStoresResponse, usage, path=["response"]) + + @parametrize + async def test_method_vector_stores_with_all_params(self, async_client: AsyncOpenAI) -> None: + usage = await async_client.admin.organization.usage.vector_stores( + start_time=0, + bucket_width="1m", + end_time=0, + group_by=["project_id"], + limit=0, + page="page", + project_ids=["string"], + ) + assert_matches_type(UsageVectorStoresResponse, usage, path=["response"]) + + @parametrize + async def test_raw_response_vector_stores(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.usage.with_raw_response.vector_stores( + start_time=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + usage = response.parse() + assert_matches_type(UsageVectorStoresResponse, usage, path=["response"]) + + @parametrize + async def test_streaming_response_vector_stores(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.usage.with_streaming_response.vector_stores( + start_time=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + usage = await response.parse() + assert_matches_type(UsageVectorStoresResponse, usage, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/admin/organization/test_users.py b/tests/api_resources/admin/organization/test_users.py new file mode 100644 index 0000000000..7350b6ecf5 --- /dev/null +++ b/tests/api_resources/admin/organization/test_users.py @@ -0,0 +1,329 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.pagination import SyncConversationCursorPage, AsyncConversationCursorPage +from openai.types.admin.organization import OrganizationUser, UserDeleteResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestUsers: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + user = client.admin.organization.users.retrieve( + "user_id", + ) + assert_matches_type(OrganizationUser, user, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.admin.organization.users.with_raw_response.retrieve( + "user_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(OrganizationUser, user, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.admin.organization.users.with_streaming_response.retrieve( + "user_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = response.parse() + assert_matches_type(OrganizationUser, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): + client.admin.organization.users.with_raw_response.retrieve( + "", + ) + + @parametrize + def test_method_update(self, client: OpenAI) -> None: + user = client.admin.organization.users.update( + user_id="user_id", + role="owner", + ) + assert_matches_type(OrganizationUser, user, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: OpenAI) -> None: + response = client.admin.organization.users.with_raw_response.update( + user_id="user_id", + role="owner", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(OrganizationUser, user, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: OpenAI) -> None: + with client.admin.organization.users.with_streaming_response.update( + user_id="user_id", + role="owner", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = response.parse() + assert_matches_type(OrganizationUser, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): + client.admin.organization.users.with_raw_response.update( + user_id="", + role="owner", + ) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + user = client.admin.organization.users.list() + assert_matches_type(SyncConversationCursorPage[OrganizationUser], user, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + user = client.admin.organization.users.list( + after="after", + emails=["string"], + limit=0, + ) + assert_matches_type(SyncConversationCursorPage[OrganizationUser], user, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.admin.organization.users.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(SyncConversationCursorPage[OrganizationUser], user, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.admin.organization.users.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = response.parse() + assert_matches_type(SyncConversationCursorPage[OrganizationUser], user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: OpenAI) -> None: + user = client.admin.organization.users.delete( + "user_id", + ) + assert_matches_type(UserDeleteResponse, user, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: OpenAI) -> None: + response = client.admin.organization.users.with_raw_response.delete( + "user_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(UserDeleteResponse, user, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: OpenAI) -> None: + with client.admin.organization.users.with_streaming_response.delete( + "user_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = response.parse() + assert_matches_type(UserDeleteResponse, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): + client.admin.organization.users.with_raw_response.delete( + "", + ) + + +class TestAsyncUsers: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + user = await async_client.admin.organization.users.retrieve( + "user_id", + ) + assert_matches_type(OrganizationUser, user, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.users.with_raw_response.retrieve( + "user_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(OrganizationUser, user, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.users.with_streaming_response.retrieve( + "user_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = await response.parse() + assert_matches_type(OrganizationUser, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): + await async_client.admin.organization.users.with_raw_response.retrieve( + "", + ) + + @parametrize + async def test_method_update(self, async_client: AsyncOpenAI) -> None: + user = await async_client.admin.organization.users.update( + user_id="user_id", + role="owner", + ) + assert_matches_type(OrganizationUser, user, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.users.with_raw_response.update( + user_id="user_id", + role="owner", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(OrganizationUser, user, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.users.with_streaming_response.update( + user_id="user_id", + role="owner", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = await response.parse() + assert_matches_type(OrganizationUser, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): + await async_client.admin.organization.users.with_raw_response.update( + user_id="", + role="owner", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + user = await async_client.admin.organization.users.list() + assert_matches_type(AsyncConversationCursorPage[OrganizationUser], user, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + user = await async_client.admin.organization.users.list( + after="after", + emails=["string"], + limit=0, + ) + assert_matches_type(AsyncConversationCursorPage[OrganizationUser], user, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.users.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(AsyncConversationCursorPage[OrganizationUser], user, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.users.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = await response.parse() + assert_matches_type(AsyncConversationCursorPage[OrganizationUser], user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncOpenAI) -> None: + user = await async_client.admin.organization.users.delete( + "user_id", + ) + assert_matches_type(UserDeleteResponse, user, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.users.with_raw_response.delete( + "user_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(UserDeleteResponse, user, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.users.with_streaming_response.delete( + "user_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = await response.parse() + assert_matches_type(UserDeleteResponse, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): + await async_client.admin.organization.users.with_raw_response.delete( + "", + ) diff --git a/tests/api_resources/admin/organization/users/__init__.py b/tests/api_resources/admin/organization/users/__init__.py new file mode 100644 index 0000000000..fd8019a9a1 --- /dev/null +++ b/tests/api_resources/admin/organization/users/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/admin/organization/users/test_roles.py b/tests/api_resources/admin/organization/users/test_roles.py new file mode 100644 index 0000000000..272c0459db --- /dev/null +++ b/tests/api_resources/admin/organization/users/test_roles.py @@ -0,0 +1,305 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.pagination import SyncCursorPage, AsyncCursorPage +from openai.types.admin.organization.users import ( + RoleListResponse, + RoleCreateResponse, + RoleDeleteResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestRoles: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: OpenAI) -> None: + role = client.admin.organization.users.roles.create( + user_id="user_id", + role_id="role_id", + ) + assert_matches_type(RoleCreateResponse, role, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: OpenAI) -> None: + response = client.admin.organization.users.roles.with_raw_response.create( + user_id="user_id", + role_id="role_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(RoleCreateResponse, role, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: OpenAI) -> None: + with client.admin.organization.users.roles.with_streaming_response.create( + user_id="user_id", + role_id="role_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = response.parse() + assert_matches_type(RoleCreateResponse, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_create(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): + client.admin.organization.users.roles.with_raw_response.create( + user_id="", + role_id="role_id", + ) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + role = client.admin.organization.users.roles.list( + user_id="user_id", + ) + assert_matches_type(SyncCursorPage[RoleListResponse], role, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + role = client.admin.organization.users.roles.list( + user_id="user_id", + after="after", + limit=0, + order="asc", + ) + assert_matches_type(SyncCursorPage[RoleListResponse], role, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.admin.organization.users.roles.with_raw_response.list( + user_id="user_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(SyncCursorPage[RoleListResponse], role, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.admin.organization.users.roles.with_streaming_response.list( + user_id="user_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = response.parse() + assert_matches_type(SyncCursorPage[RoleListResponse], role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): + client.admin.organization.users.roles.with_raw_response.list( + user_id="", + ) + + @parametrize + def test_method_delete(self, client: OpenAI) -> None: + role = client.admin.organization.users.roles.delete( + role_id="role_id", + user_id="user_id", + ) + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: OpenAI) -> None: + response = client.admin.organization.users.roles.with_raw_response.delete( + role_id="role_id", + user_id="user_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: OpenAI) -> None: + with client.admin.organization.users.roles.with_streaming_response.delete( + role_id="role_id", + user_id="user_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = response.parse() + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): + client.admin.organization.users.roles.with_raw_response.delete( + role_id="role_id", + user_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): + client.admin.organization.users.roles.with_raw_response.delete( + role_id="", + user_id="user_id", + ) + + +class TestAsyncRoles: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.users.roles.create( + user_id="user_id", + role_id="role_id", + ) + assert_matches_type(RoleCreateResponse, role, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.users.roles.with_raw_response.create( + user_id="user_id", + role_id="role_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(RoleCreateResponse, role, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.users.roles.with_streaming_response.create( + user_id="user_id", + role_id="role_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = await response.parse() + assert_matches_type(RoleCreateResponse, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): + await async_client.admin.organization.users.roles.with_raw_response.create( + user_id="", + role_id="role_id", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.users.roles.list( + user_id="user_id", + ) + assert_matches_type(AsyncCursorPage[RoleListResponse], role, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.users.roles.list( + user_id="user_id", + after="after", + limit=0, + order="asc", + ) + assert_matches_type(AsyncCursorPage[RoleListResponse], role, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.users.roles.with_raw_response.list( + user_id="user_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(AsyncCursorPage[RoleListResponse], role, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.users.roles.with_streaming_response.list( + user_id="user_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = await response.parse() + assert_matches_type(AsyncCursorPage[RoleListResponse], role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): + await async_client.admin.organization.users.roles.with_raw_response.list( + user_id="", + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.users.roles.delete( + role_id="role_id", + user_id="user_id", + ) + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.users.roles.with_raw_response.delete( + role_id="role_id", + user_id="user_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.users.roles.with_streaming_response.delete( + role_id="role_id", + user_id="user_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = await response.parse() + assert_matches_type(RoleDeleteResponse, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): + await async_client.admin.organization.users.roles.with_raw_response.delete( + role_id="role_id", + user_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): + await async_client.admin.organization.users.roles.with_raw_response.delete( + role_id="", + user_id="user_id", + ) From b1417cc7702af9b9edf0519d03bd3d780ecf5047 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 1 May 2026 14:48:54 +0000 Subject: [PATCH 715/769] feat(api): admin API updates --- .stats.yml | 6 +- api.md | 66 +++++++++++----- src/openai/pagination.py | 60 ++++++++++++++ .../admin/organization/admin_api_keys.py | 9 ++- .../admin/organization/certificates.py | 55 +++++++------ .../admin/organization/groups/groups.py | 10 +-- .../admin/organization/groups/roles.py | 10 +-- .../admin/organization/groups/users.py | 16 ++-- .../admin/organization/projects/api_keys.py | 40 ++++++---- .../organization/projects/certificates.py | 40 +++++----- .../organization/projects/groups/groups.py | 10 +-- .../organization/projects/groups/roles.py | 10 +-- .../admin/organization/projects/roles.py | 10 +-- .../organization/projects/users/roles.py | 10 +-- .../resources/admin/organization/roles.py | 10 +-- .../admin/organization/users/roles.py | 10 +-- .../admin/organization/users/users.py | 4 +- .../types/admin/organization/__init__.py | 4 + .../types/admin/organization/admin_api_key.py | 3 +- .../admin_api_key_create_response.py | 12 +++ .../admin_api_key_delete_response.py | 8 +- .../organization/audit_log_list_response.py | 6 +- .../types/admin/organization/certificate.py | 2 +- .../certificate_activate_response.py | 37 +++++++++ .../organization/certificate_create_params.py | 2 +- .../certificate_deactivate_response.py | 37 +++++++++ .../organization/certificate_list_response.py | 37 +++++++++ .../organization/certificate_update_params.py | 4 +- .../admin/organization/groups/__init__.py | 1 + .../groups/organization_group_user.py | 20 +++++ src/openai/types/admin/organization/invite.py | 8 +- .../admin/organization/projects/__init__.py | 3 + .../projects/certificate_activate_response.py | 37 +++++++++ .../certificate_deactivate_response.py | 37 +++++++++ .../projects/certificate_list_response.py | 37 +++++++++ .../organization/projects/project_api_key.py | 49 ++++++++++-- .../service_account_create_response.py | 3 +- .../usage_audio_speeches_response.py | 10 +-- .../usage_audio_transcriptions_response.py | 10 +-- ...sage_code_interpreter_sessions_response.py | 10 +-- .../usage_completions_response.py | 10 +-- .../organization/usage_costs_response.py | 10 +-- .../organization/usage_embeddings_response.py | 10 +-- .../organization/usage_images_response.py | 10 +-- .../usage_moderations_response.py | 10 +-- .../usage_vector_stores_response.py | 10 +-- .../admin/organization/user_update_params.py | 4 +- .../admin/organization/groups/test_roles.py | 18 ++--- .../admin/organization/groups/test_users.py | 20 ++--- .../projects/groups/test_roles.py | 18 ++--- .../organization/projects/test_api_keys.py | 48 +++++------ .../projects/test_certificates.py | 46 ++++++----- .../organization/projects/test_groups.py | 18 ++--- .../admin/organization/projects/test_roles.py | 18 ++--- .../organization/projects/users/test_roles.py | 18 ++--- .../admin/organization/test_admin_api_keys.py | 13 +-- .../admin/organization/test_certificates.py | 79 +++++++++++-------- .../admin/organization/test_groups.py | 18 ++--- .../admin/organization/test_roles.py | 18 ++--- .../admin/organization/test_users.py | 20 +++-- .../admin/organization/users/test_roles.py | 18 ++--- 61 files changed, 803 insertions(+), 384 deletions(-) create mode 100644 src/openai/types/admin/organization/admin_api_key_create_response.py create mode 100644 src/openai/types/admin/organization/certificate_activate_response.py create mode 100644 src/openai/types/admin/organization/certificate_deactivate_response.py create mode 100644 src/openai/types/admin/organization/certificate_list_response.py create mode 100644 src/openai/types/admin/organization/groups/organization_group_user.py create mode 100644 src/openai/types/admin/organization/projects/certificate_activate_response.py create mode 100644 src/openai/types/admin/organization/projects/certificate_deactivate_response.py create mode 100644 src/openai/types/admin/organization/projects/certificate_list_response.py diff --git a/.stats.yml b/.stats.yml index 7b55dfd466..c12fe18621 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 233 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-5b00c10325d1747a1b7da6289fe47e18f3d69503925bd3b6c1c67bbadc5a7f8f.yml -openapi_spec_hash: 142dc3e8e2e0a4f1017102e1dd49a85b -config_hash: 53256195d26013f6fe5ee634fb1c92f6 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-ea3c8bfb9cc34e798c5a473bb68ab5012344b1c99ab95377d0af4d908eb32a5d.yml +openapi_spec_hash: dbab3fdd7781b449ba3e9e1b5180c6ed +config_hash: 5d8a716125a61761563abbfc0d34e57c diff --git a/api.md b/api.md index f80a5b12c8..e04636937c 100644 --- a/api.md +++ b/api.md @@ -728,12 +728,16 @@ Methods: Types: ```python -from openai.types.admin.organization import AdminAPIKey, AdminAPIKeyDeleteResponse +from openai.types.admin.organization import ( + AdminAPIKey, + AdminAPIKeyCreateResponse, + AdminAPIKeyDeleteResponse, +) ``` Methods: -- client.admin.organization.admin_api_keys.create(\*\*params) -> AdminAPIKey +- client.admin.organization.admin_api_keys.create(\*\*params) -> AdminAPIKeyCreateResponse - client.admin.organization.admin_api_keys.retrieve(key_id) -> AdminAPIKey - client.admin.organization.admin_api_keys.list(\*\*params) -> SyncCursorPage[AdminAPIKey] - client.admin.organization.admin_api_keys.delete(key_id) -> AdminAPIKeyDeleteResponse @@ -813,7 +817,7 @@ from openai.types.admin.organization.users import ( Methods: - client.admin.organization.users.roles.create(user_id, \*\*params) -> RoleCreateResponse -- client.admin.organization.users.roles.list(user_id, \*\*params) -> SyncCursorPage[RoleListResponse] +- client.admin.organization.users.roles.list(user_id, \*\*params) -> SyncNextCursorPage[RoleListResponse] - client.admin.organization.users.roles.delete(role_id, \*, user_id) -> RoleDeleteResponse ### Groups @@ -828,7 +832,7 @@ Methods: - client.admin.organization.groups.create(\*\*params) -> Group - client.admin.organization.groups.update(group_id, \*\*params) -> GroupUpdateResponse -- client.admin.organization.groups.list(\*\*params) -> SyncCursorPage[Group] +- client.admin.organization.groups.list(\*\*params) -> SyncNextCursorPage[Group] - client.admin.organization.groups.delete(group_id) -> GroupDeleteResponse #### Users @@ -836,13 +840,17 @@ Methods: Types: ```python -from openai.types.admin.organization.groups import UserCreateResponse, UserDeleteResponse +from openai.types.admin.organization.groups import ( + OrganizationGroupUser, + UserCreateResponse, + UserDeleteResponse, +) ``` Methods: - client.admin.organization.groups.users.create(group_id, \*\*params) -> UserCreateResponse -- client.admin.organization.groups.users.list(group_id, \*\*params) -> SyncCursorPage[OrganizationUser] +- client.admin.organization.groups.users.list(group_id, \*\*params) -> SyncNextCursorPage[OrganizationGroupUser] - client.admin.organization.groups.users.delete(user_id, \*, group_id) -> UserDeleteResponse #### Roles @@ -860,7 +868,7 @@ from openai.types.admin.organization.groups import ( Methods: - client.admin.organization.groups.roles.create(group_id, \*\*params) -> RoleCreateResponse -- client.admin.organization.groups.roles.list(group_id, \*\*params) -> SyncCursorPage[RoleListResponse] +- client.admin.organization.groups.roles.list(group_id, \*\*params) -> SyncNextCursorPage[RoleListResponse] - client.admin.organization.groups.roles.delete(role_id, \*, group_id) -> RoleDeleteResponse ### Roles @@ -875,7 +883,7 @@ Methods: - client.admin.organization.roles.create(\*\*params) -> Role - client.admin.organization.roles.update(role_id, \*\*params) -> Role -- client.admin.organization.roles.list(\*\*params) -> SyncCursorPage[Role] +- client.admin.organization.roles.list(\*\*params) -> SyncNextCursorPage[Role] - client.admin.organization.roles.delete(role_id) -> RoleDeleteResponse ### Certificates @@ -883,7 +891,13 @@ Methods: Types: ```python -from openai.types.admin.organization import Certificate, CertificateDeleteResponse +from openai.types.admin.organization import ( + Certificate, + CertificateListResponse, + CertificateDeleteResponse, + CertificateActivateResponse, + CertificateDeactivateResponse, +) ``` Methods: @@ -891,10 +905,10 @@ Methods: - client.admin.organization.certificates.create(\*\*params) -> Certificate - client.admin.organization.certificates.retrieve(certificate_id, \*\*params) -> Certificate - client.admin.organization.certificates.update(certificate_id, \*\*params) -> Certificate -- client.admin.organization.certificates.list(\*\*params) -> SyncConversationCursorPage[Certificate] +- client.admin.organization.certificates.list(\*\*params) -> SyncConversationCursorPage[CertificateListResponse] - client.admin.organization.certificates.delete(certificate_id) -> CertificateDeleteResponse -- client.admin.organization.certificates.activate(\*\*params) -> SyncPage[Certificate] -- client.admin.organization.certificates.deactivate(\*\*params) -> SyncPage[Certificate] +- client.admin.organization.certificates.activate(\*\*params) -> SyncPage[CertificateActivateResponse] +- client.admin.organization.certificates.deactivate(\*\*params) -> SyncPage[CertificateDeactivateResponse] ### Projects @@ -943,7 +957,7 @@ from openai.types.admin.organization.projects.users import ( Methods: - client.admin.organization.projects.users.roles.create(user_id, \*, project_id, \*\*params) -> RoleCreateResponse -- client.admin.organization.projects.users.roles.list(user_id, \*, project_id, \*\*params) -> SyncCursorPage[RoleListResponse] +- client.admin.organization.projects.users.roles.list(user_id, \*, project_id, \*\*params) -> SyncNextCursorPage[RoleListResponse] - client.admin.organization.projects.users.roles.delete(role_id, \*, project_id, user_id) -> RoleDeleteResponse #### ServiceAccounts @@ -975,9 +989,9 @@ from openai.types.admin.organization.projects import ProjectAPIKey, APIKeyDelete Methods: -- client.admin.organization.projects.api_keys.retrieve(key_id, \*, project_id) -> ProjectAPIKey +- client.admin.organization.projects.api_keys.retrieve(api_key_id, \*, project_id) -> ProjectAPIKey - client.admin.organization.projects.api_keys.list(project_id, \*\*params) -> SyncConversationCursorPage[ProjectAPIKey] -- client.admin.organization.projects.api_keys.delete(key_id, \*, project_id) -> APIKeyDeleteResponse +- client.admin.organization.projects.api_keys.delete(api_key_id, \*, project_id) -> APIKeyDeleteResponse #### RateLimits @@ -1003,7 +1017,7 @@ from openai.types.admin.organization.projects import ProjectGroup, GroupDeleteRe Methods: - client.admin.organization.projects.groups.create(project_id, \*\*params) -> ProjectGroup -- client.admin.organization.projects.groups.list(project_id, \*\*params) -> SyncCursorPage[ProjectGroup] +- client.admin.organization.projects.groups.list(project_id, \*\*params) -> SyncNextCursorPage[ProjectGroup] - client.admin.organization.projects.groups.delete(group_id, \*, project_id) -> GroupDeleteResponse ##### Roles @@ -1021,7 +1035,7 @@ from openai.types.admin.organization.projects.groups import ( Methods: - client.admin.organization.projects.groups.roles.create(group_id, \*, project_id, \*\*params) -> RoleCreateResponse -- client.admin.organization.projects.groups.roles.list(group_id, \*, project_id, \*\*params) -> SyncCursorPage[RoleListResponse] +- client.admin.organization.projects.groups.roles.list(group_id, \*, project_id, \*\*params) -> SyncNextCursorPage[RoleListResponse] - client.admin.organization.projects.groups.roles.delete(role_id, \*, project_id, group_id) -> RoleDeleteResponse #### Roles @@ -1036,16 +1050,26 @@ Methods: - client.admin.organization.projects.roles.create(project_id, \*\*params) -> Role - client.admin.organization.projects.roles.update(role_id, \*, project_id, \*\*params) -> Role -- client.admin.organization.projects.roles.list(project_id, \*\*params) -> SyncCursorPage[Role] +- client.admin.organization.projects.roles.list(project_id, \*\*params) -> SyncNextCursorPage[Role] - client.admin.organization.projects.roles.delete(role_id, \*, project_id) -> RoleDeleteResponse #### Certificates +Types: + +```python +from openai.types.admin.organization.projects import ( + CertificateListResponse, + CertificateActivateResponse, + CertificateDeactivateResponse, +) +``` + Methods: -- client.admin.organization.projects.certificates.list(project_id, \*\*params) -> SyncConversationCursorPage[Certificate] -- client.admin.organization.projects.certificates.activate(project_id, \*\*params) -> SyncPage[Certificate] -- client.admin.organization.projects.certificates.deactivate(project_id, \*\*params) -> SyncPage[Certificate] +- client.admin.organization.projects.certificates.list(project_id, \*\*params) -> SyncConversationCursorPage[CertificateListResponse] +- client.admin.organization.projects.certificates.activate(project_id, \*\*params) -> SyncPage[CertificateActivateResponse] +- client.admin.organization.projects.certificates.deactivate(project_id, \*\*params) -> SyncPage[CertificateDeactivateResponse] # [Responses](src/openai/resources/responses/api.md) diff --git a/src/openai/pagination.py b/src/openai/pagination.py index 4dd3788aa3..6cf0c8e7f5 100644 --- a/src/openai/pagination.py +++ b/src/openai/pagination.py @@ -12,6 +12,8 @@ "AsyncCursorPage", "SyncConversationCursorPage", "AsyncConversationCursorPage", + "SyncNextCursorPage", + "AsyncNextCursorPage", ] _T = TypeVar("_T") @@ -188,3 +190,61 @@ def next_page_info(self) -> Optional[PageInfo]: return None return PageInfo(params={"after": last_id}) + + +class SyncNextCursorPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]): + data: List[_T] + has_more: Optional[bool] = None + next: Optional[str] = None + + @override + def _get_page_items(self) -> List[_T]: + data = self.data + if not data: + 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]: + next = self.next + if not next: + return None + + return PageInfo(params={"after": next}) + + +class AsyncNextCursorPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): + data: List[_T] + has_more: Optional[bool] = None + next: Optional[str] = None + + @override + def _get_page_items(self) -> List[_T]: + data = self.data + if not data: + 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]: + next = self.next + if not next: + return None + + return PageInfo(params={"after": next}) diff --git a/src/openai/resources/admin/organization/admin_api_keys.py b/src/openai/resources/admin/organization/admin_api_keys.py index bf3ff7abd0..80ddc39b49 100644 --- a/src/openai/resources/admin/organization/admin_api_keys.py +++ b/src/openai/resources/admin/organization/admin_api_keys.py @@ -17,6 +17,7 @@ from ...._base_client import AsyncPaginator, make_request_options from ....types.admin.organization import admin_api_key_list_params, admin_api_key_create_params from ....types.admin.organization.admin_api_key import AdminAPIKey +from ....types.admin.organization.admin_api_key_create_response import AdminAPIKeyCreateResponse from ....types.admin.organization.admin_api_key_delete_response import AdminAPIKeyDeleteResponse __all__ = ["AdminAPIKeys", "AsyncAdminAPIKeys"] @@ -52,7 +53,7 @@ def create( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AdminAPIKey: + ) -> AdminAPIKeyCreateResponse: """ Create an organization admin API key @@ -75,7 +76,7 @@ def create( timeout=timeout, security={"admin_api_key_auth": True}, ), - cast_to=AdminAPIKey, + cast_to=AdminAPIKeyCreateResponse, ) def retrieve( @@ -239,7 +240,7 @@ async def create( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AdminAPIKey: + ) -> AdminAPIKeyCreateResponse: """ Create an organization admin API key @@ -262,7 +263,7 @@ async def create( timeout=timeout, security={"admin_api_key_auth": True}, ), - cast_to=AdminAPIKey, + cast_to=AdminAPIKeyCreateResponse, ) async def retrieve( diff --git a/src/openai/resources/admin/organization/certificates.py b/src/openai/resources/admin/organization/certificates.py index 1cab1e3610..aa7826794d 100644 --- a/src/openai/resources/admin/organization/certificates.py +++ b/src/openai/resources/admin/organization/certificates.py @@ -24,7 +24,10 @@ certificate_deactivate_params, ) from ....types.admin.organization.certificate import Certificate +from ....types.admin.organization.certificate_list_response import CertificateListResponse from ....types.admin.organization.certificate_delete_response import CertificateDeleteResponse +from ....types.admin.organization.certificate_activate_response import CertificateActivateResponse +from ....types.admin.organization.certificate_deactivate_response import CertificateDeactivateResponse __all__ = ["Certificates", "AsyncCertificates"] @@ -52,7 +55,7 @@ def with_streaming_response(self) -> CertificatesWithStreamingResponse: def create( self, *, - content: str, + certificate: str, name: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -69,7 +72,7 @@ def create( Organizations can upload up to 50 certificates. Args: - content: The certificate content in PEM format + certificate: The certificate content in PEM format name: An optional name for the certificate @@ -85,7 +88,7 @@ def create( "/organization/certificates", body=maybe_transform( { - "content": content, + "certificate": certificate, "name": name, }, certificate_create_params.CertificateCreateParams, @@ -148,7 +151,7 @@ def update( self, certificate_id: str, *, - name: str, + name: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -198,7 +201,7 @@ def list( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncConversationCursorPage[Certificate]: + ) -> SyncConversationCursorPage[CertificateListResponse]: """ List uploaded certificates for this organization. @@ -224,7 +227,7 @@ def list( """ return self._get_api_list( "/organization/certificates", - page=SyncConversationCursorPage[Certificate], + page=SyncConversationCursorPage[CertificateListResponse], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -240,7 +243,7 @@ def list( ), security={"admin_api_key_auth": True}, ), - model=Certificate, + model=CertificateListResponse, ) def delete( @@ -292,7 +295,7 @@ def activate( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncPage[Certificate]: + ) -> SyncPage[CertificateActivateResponse]: """ Activate certificates at the organization level. @@ -309,7 +312,7 @@ def activate( """ return self._get_api_list( "/organization/certificates/activate", - page=SyncPage[Certificate], + page=SyncPage[CertificateActivateResponse], body=maybe_transform( {"certificate_ids": certificate_ids}, certificate_activate_params.CertificateActivateParams ), @@ -320,7 +323,7 @@ def activate( timeout=timeout, security={"admin_api_key_auth": True}, ), - model=Certificate, + model=CertificateActivateResponse, method="post", ) @@ -334,7 +337,7 @@ def deactivate( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncPage[Certificate]: + ) -> SyncPage[CertificateDeactivateResponse]: """ Deactivate certificates at the organization level. @@ -351,7 +354,7 @@ def deactivate( """ return self._get_api_list( "/organization/certificates/deactivate", - page=SyncPage[Certificate], + page=SyncPage[CertificateDeactivateResponse], body=maybe_transform( {"certificate_ids": certificate_ids}, certificate_deactivate_params.CertificateDeactivateParams ), @@ -362,7 +365,7 @@ def deactivate( timeout=timeout, security={"admin_api_key_auth": True}, ), - model=Certificate, + model=CertificateDeactivateResponse, method="post", ) @@ -390,7 +393,7 @@ def with_streaming_response(self) -> AsyncCertificatesWithStreamingResponse: async def create( self, *, - content: str, + certificate: str, name: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -407,7 +410,7 @@ async def create( Organizations can upload up to 50 certificates. Args: - content: The certificate content in PEM format + certificate: The certificate content in PEM format name: An optional name for the certificate @@ -423,7 +426,7 @@ async def create( "/organization/certificates", body=await async_maybe_transform( { - "content": content, + "certificate": certificate, "name": name, }, certificate_create_params.CertificateCreateParams, @@ -488,7 +491,7 @@ async def update( self, certificate_id: str, *, - name: str, + name: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -538,7 +541,7 @@ def list( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[Certificate, AsyncConversationCursorPage[Certificate]]: + ) -> AsyncPaginator[CertificateListResponse, AsyncConversationCursorPage[CertificateListResponse]]: """ List uploaded certificates for this organization. @@ -564,7 +567,7 @@ def list( """ return self._get_api_list( "/organization/certificates", - page=AsyncConversationCursorPage[Certificate], + page=AsyncConversationCursorPage[CertificateListResponse], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -580,7 +583,7 @@ def list( ), security={"admin_api_key_auth": True}, ), - model=Certificate, + model=CertificateListResponse, ) async def delete( @@ -632,7 +635,7 @@ def activate( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[Certificate, AsyncPage[Certificate]]: + ) -> AsyncPaginator[CertificateActivateResponse, AsyncPage[CertificateActivateResponse]]: """ Activate certificates at the organization level. @@ -649,7 +652,7 @@ def activate( """ return self._get_api_list( "/organization/certificates/activate", - page=AsyncPage[Certificate], + page=AsyncPage[CertificateActivateResponse], body=maybe_transform( {"certificate_ids": certificate_ids}, certificate_activate_params.CertificateActivateParams ), @@ -660,7 +663,7 @@ def activate( timeout=timeout, security={"admin_api_key_auth": True}, ), - model=Certificate, + model=CertificateActivateResponse, method="post", ) @@ -674,7 +677,7 @@ def deactivate( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[Certificate, AsyncPage[Certificate]]: + ) -> AsyncPaginator[CertificateDeactivateResponse, AsyncPage[CertificateDeactivateResponse]]: """ Deactivate certificates at the organization level. @@ -691,7 +694,7 @@ def deactivate( """ return self._get_api_list( "/organization/certificates/deactivate", - page=AsyncPage[Certificate], + page=AsyncPage[CertificateDeactivateResponse], body=maybe_transform( {"certificate_ids": certificate_ids}, certificate_deactivate_params.CertificateDeactivateParams ), @@ -702,7 +705,7 @@ def deactivate( timeout=timeout, security={"admin_api_key_auth": True}, ), - model=Certificate, + model=CertificateDeactivateResponse, method="post", ) diff --git a/src/openai/resources/admin/organization/groups/groups.py b/src/openai/resources/admin/organization/groups/groups.py index 1daf07b1ab..80baa38926 100644 --- a/src/openai/resources/admin/organization/groups/groups.py +++ b/src/openai/resources/admin/organization/groups/groups.py @@ -28,7 +28,7 @@ from ....._compat import cached_property from ....._resource import SyncAPIResource, AsyncAPIResource from ....._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from .....pagination import SyncCursorPage, AsyncCursorPage +from .....pagination import SyncNextCursorPage, AsyncNextCursorPage from ....._base_client import AsyncPaginator, make_request_options from .....types.admin.organization import group_list_params, group_create_params, group_update_params from .....types.admin.organization.group import Group @@ -157,7 +157,7 @@ def list( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[Group]: + ) -> SyncNextCursorPage[Group]: """ Lists all groups in the organization. @@ -182,7 +182,7 @@ def list( """ return self._get_api_list( "/organization/groups", - page=SyncCursorPage[Group], + page=SyncNextCursorPage[Group], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -358,7 +358,7 @@ def list( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[Group, AsyncCursorPage[Group]]: + ) -> AsyncPaginator[Group, AsyncNextCursorPage[Group]]: """ Lists all groups in the organization. @@ -383,7 +383,7 @@ def list( """ return self._get_api_list( "/organization/groups", - page=AsyncCursorPage[Group], + page=AsyncNextCursorPage[Group], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, diff --git a/src/openai/resources/admin/organization/groups/roles.py b/src/openai/resources/admin/organization/groups/roles.py index ca62ee9b35..c85efccfef 100644 --- a/src/openai/resources/admin/organization/groups/roles.py +++ b/src/openai/resources/admin/organization/groups/roles.py @@ -12,7 +12,7 @@ from ....._compat import cached_property from ....._resource import SyncAPIResource, AsyncAPIResource from ....._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from .....pagination import SyncCursorPage, AsyncCursorPage +from .....pagination import SyncNextCursorPage, AsyncNextCursorPage from ....._base_client import AsyncPaginator, make_request_options from .....types.admin.organization.groups import role_list_params, role_create_params from .....types.admin.organization.groups.role_list_response import RoleListResponse @@ -96,7 +96,7 @@ def list( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[RoleListResponse]: + ) -> SyncNextCursorPage[RoleListResponse]: """ Lists the organization roles assigned to a group within the organization. @@ -120,7 +120,7 @@ def list( raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") return self._get_api_list( path_template("/organization/groups/{group_id}/roles", group_id=group_id), - page=SyncCursorPage[RoleListResponse], + page=SyncNextCursorPage[RoleListResponse], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -254,7 +254,7 @@ def list( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[RoleListResponse, AsyncCursorPage[RoleListResponse]]: + ) -> AsyncPaginator[RoleListResponse, AsyncNextCursorPage[RoleListResponse]]: """ Lists the organization roles assigned to a group within the organization. @@ -278,7 +278,7 @@ def list( raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") return self._get_api_list( path_template("/organization/groups/{group_id}/roles", group_id=group_id), - page=AsyncCursorPage[RoleListResponse], + page=AsyncNextCursorPage[RoleListResponse], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, diff --git a/src/openai/resources/admin/organization/groups/users.py b/src/openai/resources/admin/organization/groups/users.py index 648d6221cf..89a2996e13 100644 --- a/src/openai/resources/admin/organization/groups/users.py +++ b/src/openai/resources/admin/organization/groups/users.py @@ -12,12 +12,12 @@ from ....._compat import cached_property from ....._resource import SyncAPIResource, AsyncAPIResource from ....._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from .....pagination import SyncCursorPage, AsyncCursorPage +from .....pagination import SyncNextCursorPage, AsyncNextCursorPage from ....._base_client import AsyncPaginator, make_request_options from .....types.admin.organization.groups import user_list_params, user_create_params -from .....types.admin.organization.organization_user import OrganizationUser from .....types.admin.organization.groups.user_create_response import UserCreateResponse from .....types.admin.organization.groups.user_delete_response import UserDeleteResponse +from .....types.admin.organization.groups.organization_group_user import OrganizationGroupUser __all__ = ["Users", "AsyncUsers"] @@ -96,7 +96,7 @@ def list( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[OrganizationUser]: + ) -> SyncNextCursorPage[OrganizationGroupUser]: """ Lists the users assigned to a group. @@ -121,7 +121,7 @@ def list( raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") return self._get_api_list( path_template("/organization/groups/{group_id}/users", group_id=group_id), - page=SyncCursorPage[OrganizationUser], + page=SyncNextCursorPage[OrganizationGroupUser], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -137,7 +137,7 @@ def list( ), security={"admin_api_key_auth": True}, ), - model=OrganizationUser, + model=OrganizationGroupUser, ) def delete( @@ -255,7 +255,7 @@ def list( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[OrganizationUser, AsyncCursorPage[OrganizationUser]]: + ) -> AsyncPaginator[OrganizationGroupUser, AsyncNextCursorPage[OrganizationGroupUser]]: """ Lists the users assigned to a group. @@ -280,7 +280,7 @@ def list( raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") return self._get_api_list( path_template("/organization/groups/{group_id}/users", group_id=group_id), - page=AsyncCursorPage[OrganizationUser], + page=AsyncNextCursorPage[OrganizationGroupUser], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -296,7 +296,7 @@ def list( ), security={"admin_api_key_auth": True}, ), - model=OrganizationUser, + model=OrganizationGroupUser, ) async def delete( diff --git a/src/openai/resources/admin/organization/projects/api_keys.py b/src/openai/resources/admin/organization/projects/api_keys.py index 8902ce56ff..1517d213e0 100644 --- a/src/openai/resources/admin/organization/projects/api_keys.py +++ b/src/openai/resources/admin/organization/projects/api_keys.py @@ -41,7 +41,7 @@ def with_streaming_response(self) -> APIKeysWithStreamingResponse: def retrieve( self, - key_id: str, + api_key_id: str, *, project_id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -65,11 +65,13 @@ def retrieve( """ if not project_id: raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") - if not key_id: - raise ValueError(f"Expected a non-empty value for `key_id` but received {key_id!r}") + if not api_key_id: + raise ValueError(f"Expected a non-empty value for `api_key_id` but received {api_key_id!r}") return self._get( path_template( - "/organization/projects/{project_id}/api_keys/{key_id}", project_id=project_id, key_id=key_id + "/organization/projects/{project_id}/api_keys/{api_key_id}", + project_id=project_id, + api_key_id=api_key_id, ), options=make_request_options( extra_headers=extra_headers, @@ -138,7 +140,7 @@ def list( def delete( self, - key_id: str, + api_key_id: str, *, project_id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -165,11 +167,13 @@ def delete( """ if not project_id: raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") - if not key_id: - raise ValueError(f"Expected a non-empty value for `key_id` but received {key_id!r}") + if not api_key_id: + raise ValueError(f"Expected a non-empty value for `api_key_id` but received {api_key_id!r}") return self._delete( path_template( - "/organization/projects/{project_id}/api_keys/{key_id}", project_id=project_id, key_id=key_id + "/organization/projects/{project_id}/api_keys/{api_key_id}", + project_id=project_id, + api_key_id=api_key_id, ), options=make_request_options( extra_headers=extra_headers, @@ -204,7 +208,7 @@ def with_streaming_response(self) -> AsyncAPIKeysWithStreamingResponse: async def retrieve( self, - key_id: str, + api_key_id: str, *, project_id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -228,11 +232,13 @@ async def retrieve( """ if not project_id: raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") - if not key_id: - raise ValueError(f"Expected a non-empty value for `key_id` but received {key_id!r}") + if not api_key_id: + raise ValueError(f"Expected a non-empty value for `api_key_id` but received {api_key_id!r}") return await self._get( path_template( - "/organization/projects/{project_id}/api_keys/{key_id}", project_id=project_id, key_id=key_id + "/organization/projects/{project_id}/api_keys/{api_key_id}", + project_id=project_id, + api_key_id=api_key_id, ), options=make_request_options( extra_headers=extra_headers, @@ -301,7 +307,7 @@ def list( async def delete( self, - key_id: str, + api_key_id: str, *, project_id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -328,11 +334,13 @@ async def delete( """ if not project_id: raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") - if not key_id: - raise ValueError(f"Expected a non-empty value for `key_id` but received {key_id!r}") + if not api_key_id: + raise ValueError(f"Expected a non-empty value for `api_key_id` but received {api_key_id!r}") return await self._delete( path_template( - "/organization/projects/{project_id}/api_keys/{key_id}", project_id=project_id, key_id=key_id + "/organization/projects/{project_id}/api_keys/{api_key_id}", + project_id=project_id, + api_key_id=api_key_id, ), options=make_request_options( extra_headers=extra_headers, diff --git a/src/openai/resources/admin/organization/projects/certificates.py b/src/openai/resources/admin/organization/projects/certificates.py index 3ff2111293..ec449d570a 100644 --- a/src/openai/resources/admin/organization/projects/certificates.py +++ b/src/openai/resources/admin/organization/projects/certificates.py @@ -19,7 +19,9 @@ certificate_activate_params, certificate_deactivate_params, ) -from .....types.admin.organization.certificate import Certificate +from .....types.admin.organization.projects.certificate_list_response import CertificateListResponse +from .....types.admin.organization.projects.certificate_activate_response import CertificateActivateResponse +from .....types.admin.organization.projects.certificate_deactivate_response import CertificateDeactivateResponse __all__ = ["Certificates", "AsyncCertificates"] @@ -57,7 +59,7 @@ def list( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncConversationCursorPage[Certificate]: + ) -> SyncConversationCursorPage[CertificateListResponse]: """ List certificates for this project. @@ -85,7 +87,7 @@ def list( raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") return self._get_api_list( path_template("/organization/projects/{project_id}/certificates", project_id=project_id), - page=SyncConversationCursorPage[Certificate], + page=SyncConversationCursorPage[CertificateListResponse], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -101,7 +103,7 @@ def list( ), security={"admin_api_key_auth": True}, ), - model=Certificate, + model=CertificateListResponse, ) def activate( @@ -115,7 +117,7 @@ def activate( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncPage[Certificate]: + ) -> SyncPage[CertificateActivateResponse]: """ Activate certificates at the project level. @@ -134,7 +136,7 @@ def activate( raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") return self._get_api_list( path_template("/organization/projects/{project_id}/certificates/activate", project_id=project_id), - page=SyncPage[Certificate], + page=SyncPage[CertificateActivateResponse], body=maybe_transform( {"certificate_ids": certificate_ids}, certificate_activate_params.CertificateActivateParams ), @@ -145,7 +147,7 @@ def activate( timeout=timeout, security={"admin_api_key_auth": True}, ), - model=Certificate, + model=CertificateActivateResponse, method="post", ) @@ -160,7 +162,7 @@ def deactivate( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncPage[Certificate]: + ) -> SyncPage[CertificateDeactivateResponse]: """Deactivate certificates at the project level. You can atomically and @@ -179,7 +181,7 @@ def deactivate( raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") return self._get_api_list( path_template("/organization/projects/{project_id}/certificates/deactivate", project_id=project_id), - page=SyncPage[Certificate], + page=SyncPage[CertificateDeactivateResponse], body=maybe_transform( {"certificate_ids": certificate_ids}, certificate_deactivate_params.CertificateDeactivateParams ), @@ -190,7 +192,7 @@ def deactivate( timeout=timeout, security={"admin_api_key_auth": True}, ), - model=Certificate, + model=CertificateDeactivateResponse, method="post", ) @@ -228,7 +230,7 @@ def list( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[Certificate, AsyncConversationCursorPage[Certificate]]: + ) -> AsyncPaginator[CertificateListResponse, AsyncConversationCursorPage[CertificateListResponse]]: """ List certificates for this project. @@ -256,7 +258,7 @@ def list( raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") return self._get_api_list( path_template("/organization/projects/{project_id}/certificates", project_id=project_id), - page=AsyncConversationCursorPage[Certificate], + page=AsyncConversationCursorPage[CertificateListResponse], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -272,7 +274,7 @@ def list( ), security={"admin_api_key_auth": True}, ), - model=Certificate, + model=CertificateListResponse, ) def activate( @@ -286,7 +288,7 @@ def activate( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[Certificate, AsyncPage[Certificate]]: + ) -> AsyncPaginator[CertificateActivateResponse, AsyncPage[CertificateActivateResponse]]: """ Activate certificates at the project level. @@ -305,7 +307,7 @@ def activate( raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") return self._get_api_list( path_template("/organization/projects/{project_id}/certificates/activate", project_id=project_id), - page=AsyncPage[Certificate], + page=AsyncPage[CertificateActivateResponse], body=maybe_transform( {"certificate_ids": certificate_ids}, certificate_activate_params.CertificateActivateParams ), @@ -316,7 +318,7 @@ def activate( timeout=timeout, security={"admin_api_key_auth": True}, ), - model=Certificate, + model=CertificateActivateResponse, method="post", ) @@ -331,7 +333,7 @@ def deactivate( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[Certificate, AsyncPage[Certificate]]: + ) -> AsyncPaginator[CertificateDeactivateResponse, AsyncPage[CertificateDeactivateResponse]]: """Deactivate certificates at the project level. You can atomically and @@ -350,7 +352,7 @@ def deactivate( raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") return self._get_api_list( path_template("/organization/projects/{project_id}/certificates/deactivate", project_id=project_id), - page=AsyncPage[Certificate], + page=AsyncPage[CertificateDeactivateResponse], body=maybe_transform( {"certificate_ids": certificate_ids}, certificate_deactivate_params.CertificateDeactivateParams ), @@ -361,7 +363,7 @@ def deactivate( timeout=timeout, security={"admin_api_key_auth": True}, ), - model=Certificate, + model=CertificateDeactivateResponse, method="post", ) diff --git a/src/openai/resources/admin/organization/projects/groups/groups.py b/src/openai/resources/admin/organization/projects/groups/groups.py index 8525a65255..aad9bfd6ec 100644 --- a/src/openai/resources/admin/organization/projects/groups/groups.py +++ b/src/openai/resources/admin/organization/projects/groups/groups.py @@ -20,7 +20,7 @@ from ......_compat import cached_property from ......_resource import SyncAPIResource, AsyncAPIResource from ......_response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ......pagination import SyncCursorPage, AsyncCursorPage +from ......pagination import SyncNextCursorPage, AsyncNextCursorPage from ......_base_client import AsyncPaginator, make_request_options from ......types.admin.organization.projects import group_list_params, group_create_params from ......types.admin.organization.projects.project_group import ProjectGroup @@ -116,7 +116,7 @@ def list( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[ProjectGroup]: + ) -> SyncNextCursorPage[ProjectGroup]: """ Lists the groups that have access to a project. @@ -140,7 +140,7 @@ def list( raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") return self._get_api_list( path_template("/organization/projects/{project_id}/groups", project_id=project_id), - page=SyncCursorPage[ProjectGroup], + page=SyncNextCursorPage[ProjectGroup], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -289,7 +289,7 @@ def list( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[ProjectGroup, AsyncCursorPage[ProjectGroup]]: + ) -> AsyncPaginator[ProjectGroup, AsyncNextCursorPage[ProjectGroup]]: """ Lists the groups that have access to a project. @@ -313,7 +313,7 @@ def list( raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") return self._get_api_list( path_template("/organization/projects/{project_id}/groups", project_id=project_id), - page=AsyncCursorPage[ProjectGroup], + page=AsyncNextCursorPage[ProjectGroup], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, diff --git a/src/openai/resources/admin/organization/projects/groups/roles.py b/src/openai/resources/admin/organization/projects/groups/roles.py index 20cab5d0e4..e3fe3b54fe 100644 --- a/src/openai/resources/admin/organization/projects/groups/roles.py +++ b/src/openai/resources/admin/organization/projects/groups/roles.py @@ -12,7 +12,7 @@ from ......_compat import cached_property from ......_resource import SyncAPIResource, AsyncAPIResource from ......_response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ......pagination import SyncCursorPage, AsyncCursorPage +from ......pagination import SyncNextCursorPage, AsyncNextCursorPage from ......_base_client import AsyncPaginator, make_request_options from ......types.admin.organization.projects.groups import role_list_params, role_create_params from ......types.admin.organization.projects.groups.role_list_response import RoleListResponse @@ -100,7 +100,7 @@ def list( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[RoleListResponse]: + ) -> SyncNextCursorPage[RoleListResponse]: """ Lists the project roles assigned to a group within a project. @@ -126,7 +126,7 @@ def list( raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") return self._get_api_list( path_template("/projects/{project_id}/groups/{group_id}/roles", project_id=project_id, group_id=group_id), - page=SyncCursorPage[RoleListResponse], + page=SyncNextCursorPage[RoleListResponse], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -272,7 +272,7 @@ def list( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[RoleListResponse, AsyncCursorPage[RoleListResponse]]: + ) -> AsyncPaginator[RoleListResponse, AsyncNextCursorPage[RoleListResponse]]: """ Lists the project roles assigned to a group within a project. @@ -298,7 +298,7 @@ def list( raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") return self._get_api_list( path_template("/projects/{project_id}/groups/{group_id}/roles", project_id=project_id, group_id=group_id), - page=AsyncCursorPage[RoleListResponse], + page=AsyncNextCursorPage[RoleListResponse], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, diff --git a/src/openai/resources/admin/organization/projects/roles.py b/src/openai/resources/admin/organization/projects/roles.py index 4242afe052..c958b037bb 100644 --- a/src/openai/resources/admin/organization/projects/roles.py +++ b/src/openai/resources/admin/organization/projects/roles.py @@ -13,7 +13,7 @@ from ....._compat import cached_property from ....._resource import SyncAPIResource, AsyncAPIResource from ....._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from .....pagination import SyncCursorPage, AsyncCursorPage +from .....pagination import SyncNextCursorPage, AsyncNextCursorPage from ....._base_client import AsyncPaginator, make_request_options from .....types.admin.organization.role import Role from .....types.admin.organization.projects import role_list_params, role_create_params, role_update_params @@ -166,7 +166,7 @@ def list( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[Role]: + ) -> SyncNextCursorPage[Role]: """Lists the roles configured for a project. Args: @@ -191,7 +191,7 @@ def list( raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") return self._get_api_list( path_template("/projects/{project_id}/roles", project_id=project_id), - page=SyncCursorPage[Role], + page=SyncNextCursorPage[Role], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -395,7 +395,7 @@ def list( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[Role, AsyncCursorPage[Role]]: + ) -> AsyncPaginator[Role, AsyncNextCursorPage[Role]]: """Lists the roles configured for a project. Args: @@ -420,7 +420,7 @@ def list( raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") return self._get_api_list( path_template("/projects/{project_id}/roles", project_id=project_id), - page=AsyncCursorPage[Role], + page=AsyncNextCursorPage[Role], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, diff --git a/src/openai/resources/admin/organization/projects/users/roles.py b/src/openai/resources/admin/organization/projects/users/roles.py index 35cde9b890..6a3233e275 100644 --- a/src/openai/resources/admin/organization/projects/users/roles.py +++ b/src/openai/resources/admin/organization/projects/users/roles.py @@ -12,7 +12,7 @@ from ......_compat import cached_property from ......_resource import SyncAPIResource, AsyncAPIResource from ......_response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ......pagination import SyncCursorPage, AsyncCursorPage +from ......pagination import SyncNextCursorPage, AsyncNextCursorPage from ......_base_client import AsyncPaginator, make_request_options from ......types.admin.organization.projects.users import role_list_params, role_create_params from ......types.admin.organization.projects.users.role_list_response import RoleListResponse @@ -100,7 +100,7 @@ def list( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[RoleListResponse]: + ) -> SyncNextCursorPage[RoleListResponse]: """ Lists the project roles assigned to a user within a project. @@ -126,7 +126,7 @@ def list( raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") return self._get_api_list( path_template("/projects/{project_id}/users/{user_id}/roles", project_id=project_id, user_id=user_id), - page=SyncCursorPage[RoleListResponse], + page=SyncNextCursorPage[RoleListResponse], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -272,7 +272,7 @@ def list( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[RoleListResponse, AsyncCursorPage[RoleListResponse]]: + ) -> AsyncPaginator[RoleListResponse, AsyncNextCursorPage[RoleListResponse]]: """ Lists the project roles assigned to a user within a project. @@ -298,7 +298,7 @@ def list( raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") return self._get_api_list( path_template("/projects/{project_id}/users/{user_id}/roles", project_id=project_id, user_id=user_id), - page=AsyncCursorPage[RoleListResponse], + page=AsyncNextCursorPage[RoleListResponse], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, diff --git a/src/openai/resources/admin/organization/roles.py b/src/openai/resources/admin/organization/roles.py index 3bfb35fd73..b25bbfb21e 100644 --- a/src/openai/resources/admin/organization/roles.py +++ b/src/openai/resources/admin/organization/roles.py @@ -13,7 +13,7 @@ from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ....pagination import SyncCursorPage, AsyncCursorPage +from ....pagination import SyncNextCursorPage, AsyncNextCursorPage from ...._base_client import AsyncPaginator, make_request_options from ....types.admin.organization import role_list_params, role_create_params, role_update_params from ....types.admin.organization.role import Role @@ -159,7 +159,7 @@ def list( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[Role]: + ) -> SyncNextCursorPage[Role]: """ Lists the roles configured for the organization. @@ -181,7 +181,7 @@ def list( """ return self._get_api_list( "/organization/roles", - page=SyncCursorPage[Role], + page=SyncNextCursorPage[Role], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -375,7 +375,7 @@ def list( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[Role, AsyncCursorPage[Role]]: + ) -> AsyncPaginator[Role, AsyncNextCursorPage[Role]]: """ Lists the roles configured for the organization. @@ -397,7 +397,7 @@ def list( """ return self._get_api_list( "/organization/roles", - page=AsyncCursorPage[Role], + page=AsyncNextCursorPage[Role], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, diff --git a/src/openai/resources/admin/organization/users/roles.py b/src/openai/resources/admin/organization/users/roles.py index 4338d1ae1d..01ea5f4844 100644 --- a/src/openai/resources/admin/organization/users/roles.py +++ b/src/openai/resources/admin/organization/users/roles.py @@ -12,7 +12,7 @@ from ....._compat import cached_property from ....._resource import SyncAPIResource, AsyncAPIResource from ....._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from .....pagination import SyncCursorPage, AsyncCursorPage +from .....pagination import SyncNextCursorPage, AsyncNextCursorPage from ....._base_client import AsyncPaginator, make_request_options from .....types.admin.organization.users import role_list_params, role_create_params from .....types.admin.organization.users.role_list_response import RoleListResponse @@ -96,7 +96,7 @@ def list( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[RoleListResponse]: + ) -> SyncNextCursorPage[RoleListResponse]: """ Lists the organization roles assigned to a user within the organization. @@ -120,7 +120,7 @@ def list( raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") return self._get_api_list( path_template("/organization/users/{user_id}/roles", user_id=user_id), - page=SyncCursorPage[RoleListResponse], + page=SyncNextCursorPage[RoleListResponse], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -254,7 +254,7 @@ def list( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[RoleListResponse, AsyncCursorPage[RoleListResponse]]: + ) -> AsyncPaginator[RoleListResponse, AsyncNextCursorPage[RoleListResponse]]: """ Lists the organization roles assigned to a user within the organization. @@ -278,7 +278,7 @@ def list( raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") return self._get_api_list( path_template("/organization/users/{user_id}/roles", user_id=user_id), - page=AsyncCursorPage[RoleListResponse], + page=AsyncNextCursorPage[RoleListResponse], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, diff --git a/src/openai/resources/admin/organization/users/users.py b/src/openai/resources/admin/organization/users/users.py index bfab2c5ecd..b65a138d1a 100644 --- a/src/openai/resources/admin/organization/users/users.py +++ b/src/openai/resources/admin/organization/users/users.py @@ -94,7 +94,7 @@ def update( self, user_id: str, *, - role: Literal["owner", "reader"], + role: Literal["owner", "reader"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -290,7 +290,7 @@ async def update( self, user_id: str, *, - role: Literal["owner", "reader"], + role: Literal["owner", "reader"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, diff --git a/src/openai/types/admin/organization/__init__.py b/src/openai/types/admin/organization/__init__.py index 3fbd5cf1ac..dbb11795e5 100644 --- a/src/openai/types/admin/organization/__init__.py +++ b/src/openai/types/admin/organization/__init__.py @@ -39,6 +39,7 @@ from .usage_moderations_params import UsageModerationsParams as UsageModerationsParams from .admin_api_key_list_params import AdminAPIKeyListParams as AdminAPIKeyListParams from .certificate_create_params import CertificateCreateParams as CertificateCreateParams +from .certificate_list_response import CertificateListResponse as CertificateListResponse from .certificate_update_params import CertificateUpdateParams as CertificateUpdateParams from .usage_embeddings_response import UsageEmbeddingsResponse as UsageEmbeddingsResponse from .usage_completions_response import UsageCompletionsResponse as UsageCompletionsResponse @@ -50,9 +51,12 @@ from .certificate_retrieve_params import CertificateRetrieveParams as CertificateRetrieveParams from .usage_audio_speeches_params import UsageAudioSpeechesParams as UsageAudioSpeechesParams from .usage_vector_stores_response import UsageVectorStoresResponse as UsageVectorStoresResponse +from .admin_api_key_create_response import AdminAPIKeyCreateResponse as AdminAPIKeyCreateResponse from .admin_api_key_delete_response import AdminAPIKeyDeleteResponse as AdminAPIKeyDeleteResponse +from .certificate_activate_response import CertificateActivateResponse as CertificateActivateResponse from .certificate_deactivate_params import CertificateDeactivateParams as CertificateDeactivateParams from .usage_audio_speeches_response import UsageAudioSpeechesResponse as UsageAudioSpeechesResponse +from .certificate_deactivate_response import CertificateDeactivateResponse as CertificateDeactivateResponse from .usage_audio_transcriptions_params import UsageAudioTranscriptionsParams as UsageAudioTranscriptionsParams from .usage_audio_transcriptions_response import UsageAudioTranscriptionsResponse as UsageAudioTranscriptionsResponse from .usage_code_interpreter_sessions_params import ( diff --git a/src/openai/types/admin/organization/admin_api_key.py b/src/openai/types/admin/organization/admin_api_key.py index 576d591d95..76951a99dd 100644 --- a/src/openai/types/admin/organization/admin_api_key.py +++ b/src/openai/types/admin/organization/admin_api_key.py @@ -1,6 +1,7 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from typing import Optional +from typing_extensions import Literal from ...._models import BaseModel @@ -42,7 +43,7 @@ class AdminAPIKey(BaseModel): name: str """The name of the API key""" - object: str + object: Literal["organization.admin_api_key"] """The object type, which is always `organization.admin_api_key`""" owner: Owner diff --git a/src/openai/types/admin/organization/admin_api_key_create_response.py b/src/openai/types/admin/organization/admin_api_key_create_response.py new file mode 100644 index 0000000000..48b2aaaaba --- /dev/null +++ b/src/openai/types/admin/organization/admin_api_key_create_response.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .admin_api_key import AdminAPIKey + +__all__ = ["AdminAPIKeyCreateResponse"] + + +class AdminAPIKeyCreateResponse(AdminAPIKey): + """Represents an individual Admin API key in an org.""" + + value: str # type: ignore + """The value of the API key. Only shown on create.""" diff --git a/src/openai/types/admin/organization/admin_api_key_delete_response.py b/src/openai/types/admin/organization/admin_api_key_delete_response.py index 7b4dab86a1..df8c5171d4 100644 --- a/src/openai/types/admin/organization/admin_api_key_delete_response.py +++ b/src/openai/types/admin/organization/admin_api_key_delete_response.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional +from typing_extensions import Literal from ...._models import BaseModel @@ -8,8 +8,8 @@ class AdminAPIKeyDeleteResponse(BaseModel): - id: Optional[str] = None + id: str - deleted: Optional[bool] = None + deleted: bool - object: Optional[str] = None + object: Literal["organization.admin_api_key.deleted"] diff --git a/src/openai/types/admin/organization/audit_log_list_response.py b/src/openai/types/admin/organization/audit_log_list_response.py index db4d20b9ef..ec899758a2 100644 --- a/src/openai/types/admin/organization/audit_log_list_response.py +++ b/src/openai/types/admin/organization/audit_log_list_response.py @@ -810,9 +810,6 @@ class AuditLogListResponse(BaseModel): id: str """The ID of this log.""" - actor: Actor - """The actor who performed the audit logged action.""" - effective_at: int """The Unix timestamp (in seconds) of the event.""" @@ -871,6 +868,9 @@ class AuditLogListResponse(BaseModel): ] """The event type.""" + actor: Optional[Actor] = None + """The actor who performed the audit logged action.""" + api_key_created: Optional[APIKeyCreated] = FieldInfo(alias="api_key.created", default=None) """The details for events with this `type`.""" diff --git a/src/openai/types/admin/organization/certificate.py b/src/openai/types/admin/organization/certificate.py index 93347d816b..a8663b4e4a 100644 --- a/src/openai/types/admin/organization/certificate.py +++ b/src/openai/types/admin/organization/certificate.py @@ -30,7 +30,7 @@ class Certificate(BaseModel): created_at: int """The Unix timestamp (in seconds) of when the certificate was uploaded.""" - name: str + name: Optional[str] = None """The name of the certificate.""" object: Literal["certificate", "organization.certificate", "organization.project.certificate"] diff --git a/src/openai/types/admin/organization/certificate_activate_response.py b/src/openai/types/admin/organization/certificate_activate_response.py new file mode 100644 index 0000000000..64239c3a93 --- /dev/null +++ b/src/openai/types/admin/organization/certificate_activate_response.py @@ -0,0 +1,37 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["CertificateActivateResponse", "CertificateDetails"] + + +class CertificateDetails(BaseModel): + expires_at: Optional[int] = None + """The Unix timestamp (in seconds) of when the certificate expires.""" + + valid_at: Optional[int] = None + """The Unix timestamp (in seconds) of when the certificate becomes valid.""" + + +class CertificateActivateResponse(BaseModel): + """Represents an individual certificate configured at the organization level.""" + + id: str + """The identifier, which can be referenced in API endpoints""" + + active: bool + """Whether the certificate is currently active at the organization level.""" + + certificate_details: CertificateDetails + + created_at: int + """The Unix timestamp (in seconds) of when the certificate was uploaded.""" + + name: Optional[str] = None + """The name of the certificate.""" + + object: Literal["organization.certificate"] + """The object type, which is always `organization.certificate`.""" diff --git a/src/openai/types/admin/organization/certificate_create_params.py b/src/openai/types/admin/organization/certificate_create_params.py index 3af81f03cb..9aeb3bbc94 100644 --- a/src/openai/types/admin/organization/certificate_create_params.py +++ b/src/openai/types/admin/organization/certificate_create_params.py @@ -8,7 +8,7 @@ class CertificateCreateParams(TypedDict, total=False): - content: Required[str] + certificate: Required[str] """The certificate content in PEM format""" name: str diff --git a/src/openai/types/admin/organization/certificate_deactivate_response.py b/src/openai/types/admin/organization/certificate_deactivate_response.py new file mode 100644 index 0000000000..874251cadc --- /dev/null +++ b/src/openai/types/admin/organization/certificate_deactivate_response.py @@ -0,0 +1,37 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["CertificateDeactivateResponse", "CertificateDetails"] + + +class CertificateDetails(BaseModel): + expires_at: Optional[int] = None + """The Unix timestamp (in seconds) of when the certificate expires.""" + + valid_at: Optional[int] = None + """The Unix timestamp (in seconds) of when the certificate becomes valid.""" + + +class CertificateDeactivateResponse(BaseModel): + """Represents an individual certificate configured at the organization level.""" + + id: str + """The identifier, which can be referenced in API endpoints""" + + active: bool + """Whether the certificate is currently active at the organization level.""" + + certificate_details: CertificateDetails + + created_at: int + """The Unix timestamp (in seconds) of when the certificate was uploaded.""" + + name: Optional[str] = None + """The name of the certificate.""" + + object: Literal["organization.certificate"] + """The object type, which is always `organization.certificate`.""" diff --git a/src/openai/types/admin/organization/certificate_list_response.py b/src/openai/types/admin/organization/certificate_list_response.py new file mode 100644 index 0000000000..8d9816520f --- /dev/null +++ b/src/openai/types/admin/organization/certificate_list_response.py @@ -0,0 +1,37 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["CertificateListResponse", "CertificateDetails"] + + +class CertificateDetails(BaseModel): + expires_at: Optional[int] = None + """The Unix timestamp (in seconds) of when the certificate expires.""" + + valid_at: Optional[int] = None + """The Unix timestamp (in seconds) of when the certificate becomes valid.""" + + +class CertificateListResponse(BaseModel): + """Represents an individual certificate configured at the organization level.""" + + id: str + """The identifier, which can be referenced in API endpoints""" + + active: bool + """Whether the certificate is currently active at the organization level.""" + + certificate_details: CertificateDetails + + created_at: int + """The Unix timestamp (in seconds) of when the certificate was uploaded.""" + + name: Optional[str] = None + """The name of the certificate.""" + + object: Literal["organization.certificate"] + """The object type, which is always `organization.certificate`.""" diff --git a/src/openai/types/admin/organization/certificate_update_params.py b/src/openai/types/admin/organization/certificate_update_params.py index 8a048b52b9..c55b3aceb2 100644 --- a/src/openai/types/admin/organization/certificate_update_params.py +++ b/src/openai/types/admin/organization/certificate_update_params.py @@ -2,11 +2,11 @@ from __future__ import annotations -from typing_extensions import Required, TypedDict +from typing_extensions import TypedDict __all__ = ["CertificateUpdateParams"] class CertificateUpdateParams(TypedDict, total=False): - name: Required[str] + name: str """The updated name for the certificate""" diff --git a/src/openai/types/admin/organization/groups/__init__.py b/src/openai/types/admin/organization/groups/__init__.py index a1af586634..22189c1085 100644 --- a/src/openai/types/admin/organization/groups/__init__.py +++ b/src/openai/types/admin/organization/groups/__init__.py @@ -11,3 +11,4 @@ from .role_delete_response import RoleDeleteResponse as RoleDeleteResponse from .user_create_response import UserCreateResponse as UserCreateResponse from .user_delete_response import UserDeleteResponse as UserDeleteResponse +from .organization_group_user import OrganizationGroupUser as OrganizationGroupUser diff --git a/src/openai/types/admin/organization/groups/organization_group_user.py b/src/openai/types/admin/organization/groups/organization_group_user.py new file mode 100644 index 0000000000..792022c4a9 --- /dev/null +++ b/src/openai/types/admin/organization/groups/organization_group_user.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ....._models import BaseModel + +__all__ = ["OrganizationGroupUser"] + + +class OrganizationGroupUser(BaseModel): + """Represents an individual user returned when inspecting group membership.""" + + id: str + """The identifier, which can be referenced in API endpoints""" + + email: Optional[str] = None + """The email address of the user.""" + + name: str + """The name of the user.""" diff --git a/src/openai/types/admin/organization/invite.py b/src/openai/types/admin/organization/invite.py index 5c051500b9..dc72dc2b5b 100644 --- a/src/openai/types/admin/organization/invite.py +++ b/src/openai/types/admin/organization/invite.py @@ -22,15 +22,15 @@ class Invite(BaseModel): id: str """The identifier, which can be referenced in API endpoints""" + created_at: int + """The Unix timestamp (in seconds) of when the invite was sent.""" + email: str """The email address of the individual to whom the invite was sent""" - expires_at: int + expires_at: Optional[int] = None """The Unix timestamp (in seconds) of when the invite expires.""" - invited_at: int - """The Unix timestamp (in seconds) of when the invite was sent.""" - object: Literal["organization.invite"] """The object type, which is always `organization.invite`""" diff --git a/src/openai/types/admin/organization/projects/__init__.py b/src/openai/types/admin/organization/projects/__init__.py index 8af54d8659..ea627ce7d6 100644 --- a/src/openai/types/admin/organization/projects/__init__.py +++ b/src/openai/types/admin/organization/projects/__init__.py @@ -21,10 +21,13 @@ from .api_key_delete_response import APIKeyDeleteResponse as APIKeyDeleteResponse from .certificate_list_params import CertificateListParams as CertificateListParams from .project_service_account import ProjectServiceAccount as ProjectServiceAccount +from .certificate_list_response import CertificateListResponse as CertificateListResponse from .certificate_activate_params import CertificateActivateParams as CertificateActivateParams from .service_account_list_params import ServiceAccountListParams as ServiceAccountListParams +from .certificate_activate_response import CertificateActivateResponse as CertificateActivateResponse from .certificate_deactivate_params import CertificateDeactivateParams as CertificateDeactivateParams from .service_account_create_params import ServiceAccountCreateParams as ServiceAccountCreateParams +from .certificate_deactivate_response import CertificateDeactivateResponse as CertificateDeactivateResponse from .service_account_create_response import ServiceAccountCreateResponse as ServiceAccountCreateResponse from .service_account_delete_response import ServiceAccountDeleteResponse as ServiceAccountDeleteResponse from .rate_limit_list_rate_limits_params import RateLimitListRateLimitsParams as RateLimitListRateLimitsParams diff --git a/src/openai/types/admin/organization/projects/certificate_activate_response.py b/src/openai/types/admin/organization/projects/certificate_activate_response.py new file mode 100644 index 0000000000..4ee8ae07f4 --- /dev/null +++ b/src/openai/types/admin/organization/projects/certificate_activate_response.py @@ -0,0 +1,37 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ....._models import BaseModel + +__all__ = ["CertificateActivateResponse", "CertificateDetails"] + + +class CertificateDetails(BaseModel): + expires_at: Optional[int] = None + """The Unix timestamp (in seconds) of when the certificate expires.""" + + valid_at: Optional[int] = None + """The Unix timestamp (in seconds) of when the certificate becomes valid.""" + + +class CertificateActivateResponse(BaseModel): + """Represents an individual certificate configured at the project level.""" + + id: str + """The identifier, which can be referenced in API endpoints""" + + active: bool + """Whether the certificate is currently active at the project level.""" + + certificate_details: CertificateDetails + + created_at: int + """The Unix timestamp (in seconds) of when the certificate was uploaded.""" + + name: Optional[str] = None + """The name of the certificate.""" + + object: Literal["organization.project.certificate"] + """The object type, which is always `organization.project.certificate`.""" diff --git a/src/openai/types/admin/organization/projects/certificate_deactivate_response.py b/src/openai/types/admin/organization/projects/certificate_deactivate_response.py new file mode 100644 index 0000000000..846c7a2ab7 --- /dev/null +++ b/src/openai/types/admin/organization/projects/certificate_deactivate_response.py @@ -0,0 +1,37 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ....._models import BaseModel + +__all__ = ["CertificateDeactivateResponse", "CertificateDetails"] + + +class CertificateDetails(BaseModel): + expires_at: Optional[int] = None + """The Unix timestamp (in seconds) of when the certificate expires.""" + + valid_at: Optional[int] = None + """The Unix timestamp (in seconds) of when the certificate becomes valid.""" + + +class CertificateDeactivateResponse(BaseModel): + """Represents an individual certificate configured at the project level.""" + + id: str + """The identifier, which can be referenced in API endpoints""" + + active: bool + """Whether the certificate is currently active at the project level.""" + + certificate_details: CertificateDetails + + created_at: int + """The Unix timestamp (in seconds) of when the certificate was uploaded.""" + + name: Optional[str] = None + """The name of the certificate.""" + + object: Literal["organization.project.certificate"] + """The object type, which is always `organization.project.certificate`.""" diff --git a/src/openai/types/admin/organization/projects/certificate_list_response.py b/src/openai/types/admin/organization/projects/certificate_list_response.py new file mode 100644 index 0000000000..d4345b3b8c --- /dev/null +++ b/src/openai/types/admin/organization/projects/certificate_list_response.py @@ -0,0 +1,37 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ....._models import BaseModel + +__all__ = ["CertificateListResponse", "CertificateDetails"] + + +class CertificateDetails(BaseModel): + expires_at: Optional[int] = None + """The Unix timestamp (in seconds) of when the certificate expires.""" + + valid_at: Optional[int] = None + """The Unix timestamp (in seconds) of when the certificate becomes valid.""" + + +class CertificateListResponse(BaseModel): + """Represents an individual certificate configured at the project level.""" + + id: str + """The identifier, which can be referenced in API endpoints""" + + active: bool + """Whether the certificate is currently active at the project level.""" + + certificate_details: CertificateDetails + + created_at: int + """The Unix timestamp (in seconds) of when the certificate was uploaded.""" + + name: Optional[str] = None + """The name of the certificate.""" + + object: Literal["organization.project.certificate"] + """The object type, which is always `organization.project.certificate`.""" diff --git a/src/openai/types/admin/organization/projects/project_api_key.py b/src/openai/types/admin/organization/projects/project_api_key.py index 69cb243ba3..7e5e6949eb 100644 --- a/src/openai/types/admin/organization/projects/project_api_key.py +++ b/src/openai/types/admin/organization/projects/project_api_key.py @@ -4,21 +4,54 @@ from typing_extensions import Literal from ....._models import BaseModel -from .project_user import ProjectUser -from .project_service_account import ProjectServiceAccount -__all__ = ["ProjectAPIKey", "Owner"] +__all__ = ["ProjectAPIKey", "Owner", "OwnerServiceAccount", "OwnerUser"] + + +class OwnerServiceAccount(BaseModel): + """The service account that owns a project API key.""" + + id: str + """The identifier, which can be referenced in API endpoints""" + + created_at: int + """The Unix timestamp (in seconds) of when the service account was created.""" + + name: str + """The name of the service account.""" + + role: str + """The service account's project role.""" + + +class OwnerUser(BaseModel): + """The user that owns a project API key.""" + + id: str + """The identifier, which can be referenced in API endpoints""" + + created_at: int + """The Unix timestamp (in seconds) of when the user was created.""" + + email: str + """The email address of the user.""" + + name: str + """The name of the user.""" + + role: str + """The user's project role.""" class Owner(BaseModel): - service_account: Optional[ProjectServiceAccount] = None - """Represents an individual service account in a project.""" + service_account: Optional[OwnerServiceAccount] = None + """The service account that owns a project API key.""" type: Optional[Literal["user", "service_account"]] = None """`user` or `service_account`""" - user: Optional[ProjectUser] = None - """Represents an individual user in a project.""" + user: Optional[OwnerUser] = None + """The user that owns a project API key.""" class ProjectAPIKey(BaseModel): @@ -30,7 +63,7 @@ class ProjectAPIKey(BaseModel): created_at: int """The Unix timestamp (in seconds) of when the API key was created""" - last_used_at: int + last_used_at: Optional[int] = None """The Unix timestamp (in seconds) of when the API key was last used.""" name: str diff --git a/src/openai/types/admin/organization/projects/service_account_create_response.py b/src/openai/types/admin/organization/projects/service_account_create_response.py index ce9cfa5530..430b11f655 100644 --- a/src/openai/types/admin/organization/projects/service_account_create_response.py +++ b/src/openai/types/admin/organization/projects/service_account_create_response.py @@ -1,5 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from typing import Optional from typing_extensions import Literal from ....._models import BaseModel @@ -23,7 +24,7 @@ class APIKey(BaseModel): class ServiceAccountCreateResponse(BaseModel): id: str - api_key: APIKey + api_key: Optional[APIKey] = None created_at: int diff --git a/src/openai/types/admin/organization/usage_audio_speeches_response.py b/src/openai/types/admin/organization/usage_audio_speeches_response.py index f41ecad30d..90e17c89b0 100644 --- a/src/openai/types/admin/organization/usage_audio_speeches_response.py +++ b/src/openai/types/admin/organization/usage_audio_speeches_response.py @@ -305,11 +305,11 @@ class DataResultOrganizationUsageCodeInterpreterSessionsResult(BaseModel): The aggregated code interpreter sessions usage details of the specific time bucket. """ - object: Literal["organization.usage.code_interpreter_sessions.result"] - - num_sessions: Optional[int] = None + num_sessions: int """The number of code interpreter sessions.""" + object: Literal["organization.usage.code_interpreter_sessions.result"] + project_id: Optional[str] = None """ When `group_by=project_id`, this field provides the project ID of the grouped @@ -375,7 +375,7 @@ class Data(BaseModel): object: Literal["bucket"] - result: List[DataResult] + results: List[DataResult] start_time: int @@ -385,6 +385,6 @@ class UsageAudioSpeechesResponse(BaseModel): has_more: bool - next_page: str + next_page: Optional[str] = None object: Literal["page"] diff --git a/src/openai/types/admin/organization/usage_audio_transcriptions_response.py b/src/openai/types/admin/organization/usage_audio_transcriptions_response.py index 2d847dd9ae..abd7c3fb90 100644 --- a/src/openai/types/admin/organization/usage_audio_transcriptions_response.py +++ b/src/openai/types/admin/organization/usage_audio_transcriptions_response.py @@ -305,11 +305,11 @@ class DataResultOrganizationUsageCodeInterpreterSessionsResult(BaseModel): The aggregated code interpreter sessions usage details of the specific time bucket. """ - object: Literal["organization.usage.code_interpreter_sessions.result"] - - num_sessions: Optional[int] = None + num_sessions: int """The number of code interpreter sessions.""" + object: Literal["organization.usage.code_interpreter_sessions.result"] + project_id: Optional[str] = None """ When `group_by=project_id`, this field provides the project ID of the grouped @@ -375,7 +375,7 @@ class Data(BaseModel): object: Literal["bucket"] - result: List[DataResult] + results: List[DataResult] start_time: int @@ -385,6 +385,6 @@ class UsageAudioTranscriptionsResponse(BaseModel): has_more: bool - next_page: str + next_page: Optional[str] = None object: Literal["page"] diff --git a/src/openai/types/admin/organization/usage_code_interpreter_sessions_response.py b/src/openai/types/admin/organization/usage_code_interpreter_sessions_response.py index e4634d9a6f..0cd6c2693c 100644 --- a/src/openai/types/admin/organization/usage_code_interpreter_sessions_response.py +++ b/src/openai/types/admin/organization/usage_code_interpreter_sessions_response.py @@ -305,11 +305,11 @@ class DataResultOrganizationUsageCodeInterpreterSessionsResult(BaseModel): The aggregated code interpreter sessions usage details of the specific time bucket. """ - object: Literal["organization.usage.code_interpreter_sessions.result"] - - num_sessions: Optional[int] = None + num_sessions: int """The number of code interpreter sessions.""" + object: Literal["organization.usage.code_interpreter_sessions.result"] + project_id: Optional[str] = None """ When `group_by=project_id`, this field provides the project ID of the grouped @@ -375,7 +375,7 @@ class Data(BaseModel): object: Literal["bucket"] - result: List[DataResult] + results: List[DataResult] start_time: int @@ -385,6 +385,6 @@ class UsageCodeInterpreterSessionsResponse(BaseModel): has_more: bool - next_page: str + next_page: Optional[str] = None object: Literal["page"] diff --git a/src/openai/types/admin/organization/usage_completions_response.py b/src/openai/types/admin/organization/usage_completions_response.py index a79c79c9bb..d37634bca5 100644 --- a/src/openai/types/admin/organization/usage_completions_response.py +++ b/src/openai/types/admin/organization/usage_completions_response.py @@ -305,11 +305,11 @@ class DataResultOrganizationUsageCodeInterpreterSessionsResult(BaseModel): The aggregated code interpreter sessions usage details of the specific time bucket. """ - object: Literal["organization.usage.code_interpreter_sessions.result"] - - num_sessions: Optional[int] = None + num_sessions: int """The number of code interpreter sessions.""" + object: Literal["organization.usage.code_interpreter_sessions.result"] + project_id: Optional[str] = None """ When `group_by=project_id`, this field provides the project ID of the grouped @@ -375,7 +375,7 @@ class Data(BaseModel): object: Literal["bucket"] - result: List[DataResult] + results: List[DataResult] start_time: int @@ -385,6 +385,6 @@ class UsageCompletionsResponse(BaseModel): has_more: bool - next_page: str + next_page: Optional[str] = None object: Literal["page"] diff --git a/src/openai/types/admin/organization/usage_costs_response.py b/src/openai/types/admin/organization/usage_costs_response.py index 004e818242..68c1f639c1 100644 --- a/src/openai/types/admin/organization/usage_costs_response.py +++ b/src/openai/types/admin/organization/usage_costs_response.py @@ -305,11 +305,11 @@ class DataResultOrganizationUsageCodeInterpreterSessionsResult(BaseModel): The aggregated code interpreter sessions usage details of the specific time bucket. """ - object: Literal["organization.usage.code_interpreter_sessions.result"] - - num_sessions: Optional[int] = None + num_sessions: int """The number of code interpreter sessions.""" + object: Literal["organization.usage.code_interpreter_sessions.result"] + project_id: Optional[str] = None """ When `group_by=project_id`, this field provides the project ID of the grouped @@ -375,7 +375,7 @@ class Data(BaseModel): object: Literal["bucket"] - result: List[DataResult] + results: List[DataResult] start_time: int @@ -385,6 +385,6 @@ class UsageCostsResponse(BaseModel): has_more: bool - next_page: str + next_page: Optional[str] = None object: Literal["page"] diff --git a/src/openai/types/admin/organization/usage_embeddings_response.py b/src/openai/types/admin/organization/usage_embeddings_response.py index f14208507c..905c8f5c6e 100644 --- a/src/openai/types/admin/organization/usage_embeddings_response.py +++ b/src/openai/types/admin/organization/usage_embeddings_response.py @@ -305,11 +305,11 @@ class DataResultOrganizationUsageCodeInterpreterSessionsResult(BaseModel): The aggregated code interpreter sessions usage details of the specific time bucket. """ - object: Literal["organization.usage.code_interpreter_sessions.result"] - - num_sessions: Optional[int] = None + num_sessions: int """The number of code interpreter sessions.""" + object: Literal["organization.usage.code_interpreter_sessions.result"] + project_id: Optional[str] = None """ When `group_by=project_id`, this field provides the project ID of the grouped @@ -375,7 +375,7 @@ class Data(BaseModel): object: Literal["bucket"] - result: List[DataResult] + results: List[DataResult] start_time: int @@ -385,6 +385,6 @@ class UsageEmbeddingsResponse(BaseModel): has_more: bool - next_page: str + next_page: Optional[str] = None object: Literal["page"] diff --git a/src/openai/types/admin/organization/usage_images_response.py b/src/openai/types/admin/organization/usage_images_response.py index 0188a51bc4..55f8d80096 100644 --- a/src/openai/types/admin/organization/usage_images_response.py +++ b/src/openai/types/admin/organization/usage_images_response.py @@ -305,11 +305,11 @@ class DataResultOrganizationUsageCodeInterpreterSessionsResult(BaseModel): The aggregated code interpreter sessions usage details of the specific time bucket. """ - object: Literal["organization.usage.code_interpreter_sessions.result"] - - num_sessions: Optional[int] = None + num_sessions: int """The number of code interpreter sessions.""" + object: Literal["organization.usage.code_interpreter_sessions.result"] + project_id: Optional[str] = None """ When `group_by=project_id`, this field provides the project ID of the grouped @@ -375,7 +375,7 @@ class Data(BaseModel): object: Literal["bucket"] - result: List[DataResult] + results: List[DataResult] start_time: int @@ -385,6 +385,6 @@ class UsageImagesResponse(BaseModel): has_more: bool - next_page: str + next_page: Optional[str] = None object: Literal["page"] diff --git a/src/openai/types/admin/organization/usage_moderations_response.py b/src/openai/types/admin/organization/usage_moderations_response.py index fc99593e5d..87919b50a9 100644 --- a/src/openai/types/admin/organization/usage_moderations_response.py +++ b/src/openai/types/admin/organization/usage_moderations_response.py @@ -305,11 +305,11 @@ class DataResultOrganizationUsageCodeInterpreterSessionsResult(BaseModel): The aggregated code interpreter sessions usage details of the specific time bucket. """ - object: Literal["organization.usage.code_interpreter_sessions.result"] - - num_sessions: Optional[int] = None + num_sessions: int """The number of code interpreter sessions.""" + object: Literal["organization.usage.code_interpreter_sessions.result"] + project_id: Optional[str] = None """ When `group_by=project_id`, this field provides the project ID of the grouped @@ -375,7 +375,7 @@ class Data(BaseModel): object: Literal["bucket"] - result: List[DataResult] + results: List[DataResult] start_time: int @@ -385,6 +385,6 @@ class UsageModerationsResponse(BaseModel): has_more: bool - next_page: str + next_page: Optional[str] = None object: Literal["page"] diff --git a/src/openai/types/admin/organization/usage_vector_stores_response.py b/src/openai/types/admin/organization/usage_vector_stores_response.py index f17e867af0..d3cd853653 100644 --- a/src/openai/types/admin/organization/usage_vector_stores_response.py +++ b/src/openai/types/admin/organization/usage_vector_stores_response.py @@ -305,11 +305,11 @@ class DataResultOrganizationUsageCodeInterpreterSessionsResult(BaseModel): The aggregated code interpreter sessions usage details of the specific time bucket. """ - object: Literal["organization.usage.code_interpreter_sessions.result"] - - num_sessions: Optional[int] = None + num_sessions: int """The number of code interpreter sessions.""" + object: Literal["organization.usage.code_interpreter_sessions.result"] + project_id: Optional[str] = None """ When `group_by=project_id`, this field provides the project ID of the grouped @@ -375,7 +375,7 @@ class Data(BaseModel): object: Literal["bucket"] - result: List[DataResult] + results: List[DataResult] start_time: int @@ -385,6 +385,6 @@ class UsageVectorStoresResponse(BaseModel): has_more: bool - next_page: str + next_page: Optional[str] = None object: Literal["page"] diff --git a/src/openai/types/admin/organization/user_update_params.py b/src/openai/types/admin/organization/user_update_params.py index bc276120e3..ab1f9d0026 100644 --- a/src/openai/types/admin/organization/user_update_params.py +++ b/src/openai/types/admin/organization/user_update_params.py @@ -2,11 +2,11 @@ from __future__ import annotations -from typing_extensions import Literal, Required, TypedDict +from typing_extensions import Literal, TypedDict __all__ = ["UserUpdateParams"] class UserUpdateParams(TypedDict, total=False): - role: Required[Literal["owner", "reader"]] + role: Literal["owner", "reader"] """`owner` or `reader`""" diff --git a/tests/api_resources/admin/organization/groups/test_roles.py b/tests/api_resources/admin/organization/groups/test_roles.py index 73e8feabdb..08702fddd2 100644 --- a/tests/api_resources/admin/organization/groups/test_roles.py +++ b/tests/api_resources/admin/organization/groups/test_roles.py @@ -9,7 +9,7 @@ from openai import OpenAI, AsyncOpenAI from tests.utils import assert_matches_type -from openai.pagination import SyncCursorPage, AsyncCursorPage +from openai.pagination import SyncNextCursorPage, AsyncNextCursorPage from openai.types.admin.organization.groups import ( RoleListResponse, RoleCreateResponse, @@ -69,7 +69,7 @@ def test_method_list(self, client: OpenAI) -> None: role = client.admin.organization.groups.roles.list( group_id="group_id", ) - assert_matches_type(SyncCursorPage[RoleListResponse], role, path=["response"]) + assert_matches_type(SyncNextCursorPage[RoleListResponse], role, path=["response"]) @parametrize def test_method_list_with_all_params(self, client: OpenAI) -> None: @@ -79,7 +79,7 @@ def test_method_list_with_all_params(self, client: OpenAI) -> None: limit=0, order="asc", ) - assert_matches_type(SyncCursorPage[RoleListResponse], role, path=["response"]) + assert_matches_type(SyncNextCursorPage[RoleListResponse], role, path=["response"]) @parametrize def test_raw_response_list(self, client: OpenAI) -> None: @@ -90,7 +90,7 @@ def test_raw_response_list(self, client: OpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" role = response.parse() - assert_matches_type(SyncCursorPage[RoleListResponse], role, path=["response"]) + assert_matches_type(SyncNextCursorPage[RoleListResponse], role, path=["response"]) @parametrize def test_streaming_response_list(self, client: OpenAI) -> None: @@ -101,7 +101,7 @@ def test_streaming_response_list(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" role = response.parse() - assert_matches_type(SyncCursorPage[RoleListResponse], role, path=["response"]) + assert_matches_type(SyncNextCursorPage[RoleListResponse], role, path=["response"]) assert cast(Any, response.is_closed) is True @@ -213,7 +213,7 @@ async def test_method_list(self, async_client: AsyncOpenAI) -> None: role = await async_client.admin.organization.groups.roles.list( group_id="group_id", ) - assert_matches_type(AsyncCursorPage[RoleListResponse], role, path=["response"]) + assert_matches_type(AsyncNextCursorPage[RoleListResponse], role, path=["response"]) @parametrize async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: @@ -223,7 +223,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> N limit=0, order="asc", ) - assert_matches_type(AsyncCursorPage[RoleListResponse], role, path=["response"]) + assert_matches_type(AsyncNextCursorPage[RoleListResponse], role, path=["response"]) @parametrize async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: @@ -234,7 +234,7 @@ async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" role = response.parse() - assert_matches_type(AsyncCursorPage[RoleListResponse], role, path=["response"]) + assert_matches_type(AsyncNextCursorPage[RoleListResponse], role, path=["response"]) @parametrize async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: @@ -245,7 +245,7 @@ async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" role = await response.parse() - assert_matches_type(AsyncCursorPage[RoleListResponse], role, path=["response"]) + assert_matches_type(AsyncNextCursorPage[RoleListResponse], role, path=["response"]) assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/admin/organization/groups/test_users.py b/tests/api_resources/admin/organization/groups/test_users.py index cfa6354f99..eda6be6bbf 100644 --- a/tests/api_resources/admin/organization/groups/test_users.py +++ b/tests/api_resources/admin/organization/groups/test_users.py @@ -9,11 +9,11 @@ from openai import OpenAI, AsyncOpenAI from tests.utils import assert_matches_type -from openai.pagination import SyncCursorPage, AsyncCursorPage -from openai.types.admin.organization import OrganizationUser +from openai.pagination import SyncNextCursorPage, AsyncNextCursorPage from openai.types.admin.organization.groups import ( UserCreateResponse, UserDeleteResponse, + OrganizationGroupUser, ) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -69,7 +69,7 @@ def test_method_list(self, client: OpenAI) -> None: user = client.admin.organization.groups.users.list( group_id="group_id", ) - assert_matches_type(SyncCursorPage[OrganizationUser], user, path=["response"]) + assert_matches_type(SyncNextCursorPage[OrganizationGroupUser], user, path=["response"]) @parametrize def test_method_list_with_all_params(self, client: OpenAI) -> None: @@ -79,7 +79,7 @@ def test_method_list_with_all_params(self, client: OpenAI) -> None: limit=0, order="asc", ) - assert_matches_type(SyncCursorPage[OrganizationUser], user, path=["response"]) + assert_matches_type(SyncNextCursorPage[OrganizationGroupUser], user, path=["response"]) @parametrize def test_raw_response_list(self, client: OpenAI) -> None: @@ -90,7 +90,7 @@ def test_raw_response_list(self, client: OpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" user = response.parse() - assert_matches_type(SyncCursorPage[OrganizationUser], user, path=["response"]) + assert_matches_type(SyncNextCursorPage[OrganizationGroupUser], user, path=["response"]) @parametrize def test_streaming_response_list(self, client: OpenAI) -> None: @@ -101,7 +101,7 @@ def test_streaming_response_list(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" user = response.parse() - assert_matches_type(SyncCursorPage[OrganizationUser], user, path=["response"]) + assert_matches_type(SyncNextCursorPage[OrganizationGroupUser], user, path=["response"]) assert cast(Any, response.is_closed) is True @@ -213,7 +213,7 @@ async def test_method_list(self, async_client: AsyncOpenAI) -> None: user = await async_client.admin.organization.groups.users.list( group_id="group_id", ) - assert_matches_type(AsyncCursorPage[OrganizationUser], user, path=["response"]) + assert_matches_type(AsyncNextCursorPage[OrganizationGroupUser], user, path=["response"]) @parametrize async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: @@ -223,7 +223,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> N limit=0, order="asc", ) - assert_matches_type(AsyncCursorPage[OrganizationUser], user, path=["response"]) + assert_matches_type(AsyncNextCursorPage[OrganizationGroupUser], user, path=["response"]) @parametrize async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: @@ -234,7 +234,7 @@ async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" user = response.parse() - assert_matches_type(AsyncCursorPage[OrganizationUser], user, path=["response"]) + assert_matches_type(AsyncNextCursorPage[OrganizationGroupUser], user, path=["response"]) @parametrize async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: @@ -245,7 +245,7 @@ async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" user = await response.parse() - assert_matches_type(AsyncCursorPage[OrganizationUser], user, path=["response"]) + assert_matches_type(AsyncNextCursorPage[OrganizationGroupUser], user, path=["response"]) assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/admin/organization/projects/groups/test_roles.py b/tests/api_resources/admin/organization/projects/groups/test_roles.py index 4cfc957962..a129142ea9 100644 --- a/tests/api_resources/admin/organization/projects/groups/test_roles.py +++ b/tests/api_resources/admin/organization/projects/groups/test_roles.py @@ -9,7 +9,7 @@ from openai import OpenAI, AsyncOpenAI from tests.utils import assert_matches_type -from openai.pagination import SyncCursorPage, AsyncCursorPage +from openai.pagination import SyncNextCursorPage, AsyncNextCursorPage from openai.types.admin.organization.projects.groups import ( RoleListResponse, RoleCreateResponse, @@ -81,7 +81,7 @@ def test_method_list(self, client: OpenAI) -> None: group_id="group_id", project_id="project_id", ) - assert_matches_type(SyncCursorPage[RoleListResponse], role, path=["response"]) + assert_matches_type(SyncNextCursorPage[RoleListResponse], role, path=["response"]) @parametrize def test_method_list_with_all_params(self, client: OpenAI) -> None: @@ -92,7 +92,7 @@ def test_method_list_with_all_params(self, client: OpenAI) -> None: limit=0, order="asc", ) - assert_matches_type(SyncCursorPage[RoleListResponse], role, path=["response"]) + assert_matches_type(SyncNextCursorPage[RoleListResponse], role, path=["response"]) @parametrize def test_raw_response_list(self, client: OpenAI) -> None: @@ -104,7 +104,7 @@ def test_raw_response_list(self, client: OpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" role = response.parse() - assert_matches_type(SyncCursorPage[RoleListResponse], role, path=["response"]) + assert_matches_type(SyncNextCursorPage[RoleListResponse], role, path=["response"]) @parametrize def test_streaming_response_list(self, client: OpenAI) -> None: @@ -116,7 +116,7 @@ def test_streaming_response_list(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" role = response.parse() - assert_matches_type(SyncCursorPage[RoleListResponse], role, path=["response"]) + assert_matches_type(SyncNextCursorPage[RoleListResponse], role, path=["response"]) assert cast(Any, response.is_closed) is True @@ -259,7 +259,7 @@ async def test_method_list(self, async_client: AsyncOpenAI) -> None: group_id="group_id", project_id="project_id", ) - assert_matches_type(AsyncCursorPage[RoleListResponse], role, path=["response"]) + assert_matches_type(AsyncNextCursorPage[RoleListResponse], role, path=["response"]) @parametrize async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: @@ -270,7 +270,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> N limit=0, order="asc", ) - assert_matches_type(AsyncCursorPage[RoleListResponse], role, path=["response"]) + assert_matches_type(AsyncNextCursorPage[RoleListResponse], role, path=["response"]) @parametrize async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: @@ -282,7 +282,7 @@ async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" role = response.parse() - assert_matches_type(AsyncCursorPage[RoleListResponse], role, path=["response"]) + assert_matches_type(AsyncNextCursorPage[RoleListResponse], role, path=["response"]) @parametrize async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: @@ -294,7 +294,7 @@ async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" role = await response.parse() - assert_matches_type(AsyncCursorPage[RoleListResponse], role, path=["response"]) + assert_matches_type(AsyncNextCursorPage[RoleListResponse], role, path=["response"]) assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/admin/organization/projects/test_api_keys.py b/tests/api_resources/admin/organization/projects/test_api_keys.py index 2f8ab56056..f9aef44216 100644 --- a/tests/api_resources/admin/organization/projects/test_api_keys.py +++ b/tests/api_resources/admin/organization/projects/test_api_keys.py @@ -21,7 +21,7 @@ class TestAPIKeys: @parametrize def test_method_retrieve(self, client: OpenAI) -> None: api_key = client.admin.organization.projects.api_keys.retrieve( - key_id="key_id", + api_key_id="api_key_id", project_id="project_id", ) assert_matches_type(ProjectAPIKey, api_key, path=["response"]) @@ -29,7 +29,7 @@ def test_method_retrieve(self, client: OpenAI) -> None: @parametrize def test_raw_response_retrieve(self, client: OpenAI) -> None: response = client.admin.organization.projects.api_keys.with_raw_response.retrieve( - key_id="key_id", + api_key_id="api_key_id", project_id="project_id", ) @@ -41,7 +41,7 @@ def test_raw_response_retrieve(self, client: OpenAI) -> None: @parametrize def test_streaming_response_retrieve(self, client: OpenAI) -> None: with client.admin.organization.projects.api_keys.with_streaming_response.retrieve( - key_id="key_id", + api_key_id="api_key_id", project_id="project_id", ) as response: assert not response.is_closed @@ -56,13 +56,13 @@ def test_streaming_response_retrieve(self, client: OpenAI) -> None: def test_path_params_retrieve(self, client: OpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): client.admin.organization.projects.api_keys.with_raw_response.retrieve( - key_id="key_id", + api_key_id="api_key_id", project_id="", ) - with pytest.raises(ValueError, match=r"Expected a non-empty value for `key_id` but received ''"): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `api_key_id` but received ''"): client.admin.organization.projects.api_keys.with_raw_response.retrieve( - key_id="", + api_key_id="", project_id="project_id", ) @@ -116,7 +116,7 @@ def test_path_params_list(self, client: OpenAI) -> None: @parametrize def test_method_delete(self, client: OpenAI) -> None: api_key = client.admin.organization.projects.api_keys.delete( - key_id="key_id", + api_key_id="api_key_id", project_id="project_id", ) assert_matches_type(APIKeyDeleteResponse, api_key, path=["response"]) @@ -124,7 +124,7 @@ def test_method_delete(self, client: OpenAI) -> None: @parametrize def test_raw_response_delete(self, client: OpenAI) -> None: response = client.admin.organization.projects.api_keys.with_raw_response.delete( - key_id="key_id", + api_key_id="api_key_id", project_id="project_id", ) @@ -136,7 +136,7 @@ def test_raw_response_delete(self, client: OpenAI) -> None: @parametrize def test_streaming_response_delete(self, client: OpenAI) -> None: with client.admin.organization.projects.api_keys.with_streaming_response.delete( - key_id="key_id", + api_key_id="api_key_id", project_id="project_id", ) as response: assert not response.is_closed @@ -151,13 +151,13 @@ def test_streaming_response_delete(self, client: OpenAI) -> None: def test_path_params_delete(self, client: OpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): client.admin.organization.projects.api_keys.with_raw_response.delete( - key_id="key_id", + api_key_id="api_key_id", project_id="", ) - with pytest.raises(ValueError, match=r"Expected a non-empty value for `key_id` but received ''"): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `api_key_id` but received ''"): client.admin.organization.projects.api_keys.with_raw_response.delete( - key_id="", + api_key_id="", project_id="project_id", ) @@ -170,7 +170,7 @@ class TestAsyncAPIKeys: @parametrize async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: api_key = await async_client.admin.organization.projects.api_keys.retrieve( - key_id="key_id", + api_key_id="api_key_id", project_id="project_id", ) assert_matches_type(ProjectAPIKey, api_key, path=["response"]) @@ -178,7 +178,7 @@ async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: response = await async_client.admin.organization.projects.api_keys.with_raw_response.retrieve( - key_id="key_id", + api_key_id="api_key_id", project_id="project_id", ) @@ -190,7 +190,7 @@ async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: async with async_client.admin.organization.projects.api_keys.with_streaming_response.retrieve( - key_id="key_id", + api_key_id="api_key_id", project_id="project_id", ) as response: assert not response.is_closed @@ -205,13 +205,13 @@ async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> N async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): await async_client.admin.organization.projects.api_keys.with_raw_response.retrieve( - key_id="key_id", + api_key_id="api_key_id", project_id="", ) - with pytest.raises(ValueError, match=r"Expected a non-empty value for `key_id` but received ''"): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `api_key_id` but received ''"): await async_client.admin.organization.projects.api_keys.with_raw_response.retrieve( - key_id="", + api_key_id="", project_id="project_id", ) @@ -265,7 +265,7 @@ async def test_path_params_list(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_method_delete(self, async_client: AsyncOpenAI) -> None: api_key = await async_client.admin.organization.projects.api_keys.delete( - key_id="key_id", + api_key_id="api_key_id", project_id="project_id", ) assert_matches_type(APIKeyDeleteResponse, api_key, path=["response"]) @@ -273,7 +273,7 @@ async def test_method_delete(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: response = await async_client.admin.organization.projects.api_keys.with_raw_response.delete( - key_id="key_id", + api_key_id="api_key_id", project_id="project_id", ) @@ -285,7 +285,7 @@ async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: async with async_client.admin.organization.projects.api_keys.with_streaming_response.delete( - key_id="key_id", + api_key_id="api_key_id", project_id="project_id", ) as response: assert not response.is_closed @@ -300,12 +300,12 @@ async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> Non async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): await async_client.admin.organization.projects.api_keys.with_raw_response.delete( - key_id="key_id", + api_key_id="api_key_id", project_id="", ) - with pytest.raises(ValueError, match=r"Expected a non-empty value for `key_id` but received ''"): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `api_key_id` but received ''"): await async_client.admin.organization.projects.api_keys.with_raw_response.delete( - key_id="", + api_key_id="", project_id="project_id", ) diff --git a/tests/api_resources/admin/organization/projects/test_certificates.py b/tests/api_resources/admin/organization/projects/test_certificates.py index 8ed72d6112..e242b7d6d4 100644 --- a/tests/api_resources/admin/organization/projects/test_certificates.py +++ b/tests/api_resources/admin/organization/projects/test_certificates.py @@ -10,7 +10,11 @@ from openai import OpenAI, AsyncOpenAI from tests.utils import assert_matches_type from openai.pagination import SyncPage, AsyncPage, SyncConversationCursorPage, AsyncConversationCursorPage -from openai.types.admin.organization import Certificate +from openai.types.admin.organization.projects import ( + CertificateListResponse, + CertificateActivateResponse, + CertificateDeactivateResponse, +) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -23,7 +27,7 @@ def test_method_list(self, client: OpenAI) -> None: certificate = client.admin.organization.projects.certificates.list( project_id="project_id", ) - assert_matches_type(SyncConversationCursorPage[Certificate], certificate, path=["response"]) + assert_matches_type(SyncConversationCursorPage[CertificateListResponse], certificate, path=["response"]) @parametrize def test_method_list_with_all_params(self, client: OpenAI) -> None: @@ -33,7 +37,7 @@ def test_method_list_with_all_params(self, client: OpenAI) -> None: limit=0, order="asc", ) - assert_matches_type(SyncConversationCursorPage[Certificate], certificate, path=["response"]) + assert_matches_type(SyncConversationCursorPage[CertificateListResponse], certificate, path=["response"]) @parametrize def test_raw_response_list(self, client: OpenAI) -> None: @@ -44,7 +48,7 @@ def test_raw_response_list(self, client: OpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" certificate = response.parse() - assert_matches_type(SyncConversationCursorPage[Certificate], certificate, path=["response"]) + assert_matches_type(SyncConversationCursorPage[CertificateListResponse], certificate, path=["response"]) @parametrize def test_streaming_response_list(self, client: OpenAI) -> None: @@ -55,7 +59,7 @@ def test_streaming_response_list(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" certificate = response.parse() - assert_matches_type(SyncConversationCursorPage[Certificate], certificate, path=["response"]) + assert_matches_type(SyncConversationCursorPage[CertificateListResponse], certificate, path=["response"]) assert cast(Any, response.is_closed) is True @@ -72,7 +76,7 @@ def test_method_activate(self, client: OpenAI) -> None: project_id="project_id", certificate_ids=["cert_abc"], ) - assert_matches_type(SyncPage[Certificate], certificate, path=["response"]) + assert_matches_type(SyncPage[CertificateActivateResponse], certificate, path=["response"]) @parametrize def test_raw_response_activate(self, client: OpenAI) -> None: @@ -84,7 +88,7 @@ def test_raw_response_activate(self, client: OpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" certificate = response.parse() - assert_matches_type(SyncPage[Certificate], certificate, path=["response"]) + assert_matches_type(SyncPage[CertificateActivateResponse], certificate, path=["response"]) @parametrize def test_streaming_response_activate(self, client: OpenAI) -> None: @@ -96,7 +100,7 @@ def test_streaming_response_activate(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" certificate = response.parse() - assert_matches_type(SyncPage[Certificate], certificate, path=["response"]) + assert_matches_type(SyncPage[CertificateActivateResponse], certificate, path=["response"]) assert cast(Any, response.is_closed) is True @@ -114,7 +118,7 @@ def test_method_deactivate(self, client: OpenAI) -> None: project_id="project_id", certificate_ids=["cert_abc"], ) - assert_matches_type(SyncPage[Certificate], certificate, path=["response"]) + assert_matches_type(SyncPage[CertificateDeactivateResponse], certificate, path=["response"]) @parametrize def test_raw_response_deactivate(self, client: OpenAI) -> None: @@ -126,7 +130,7 @@ def test_raw_response_deactivate(self, client: OpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" certificate = response.parse() - assert_matches_type(SyncPage[Certificate], certificate, path=["response"]) + assert_matches_type(SyncPage[CertificateDeactivateResponse], certificate, path=["response"]) @parametrize def test_streaming_response_deactivate(self, client: OpenAI) -> None: @@ -138,7 +142,7 @@ def test_streaming_response_deactivate(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" certificate = response.parse() - assert_matches_type(SyncPage[Certificate], certificate, path=["response"]) + assert_matches_type(SyncPage[CertificateDeactivateResponse], certificate, path=["response"]) assert cast(Any, response.is_closed) is True @@ -161,7 +165,7 @@ async def test_method_list(self, async_client: AsyncOpenAI) -> None: certificate = await async_client.admin.organization.projects.certificates.list( project_id="project_id", ) - assert_matches_type(AsyncConversationCursorPage[Certificate], certificate, path=["response"]) + assert_matches_type(AsyncConversationCursorPage[CertificateListResponse], certificate, path=["response"]) @parametrize async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: @@ -171,7 +175,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> N limit=0, order="asc", ) - assert_matches_type(AsyncConversationCursorPage[Certificate], certificate, path=["response"]) + assert_matches_type(AsyncConversationCursorPage[CertificateListResponse], certificate, path=["response"]) @parametrize async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: @@ -182,7 +186,7 @@ async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" certificate = response.parse() - assert_matches_type(AsyncConversationCursorPage[Certificate], certificate, path=["response"]) + assert_matches_type(AsyncConversationCursorPage[CertificateListResponse], certificate, path=["response"]) @parametrize async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: @@ -193,7 +197,7 @@ async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" certificate = await response.parse() - assert_matches_type(AsyncConversationCursorPage[Certificate], certificate, path=["response"]) + assert_matches_type(AsyncConversationCursorPage[CertificateListResponse], certificate, path=["response"]) assert cast(Any, response.is_closed) is True @@ -210,7 +214,7 @@ async def test_method_activate(self, async_client: AsyncOpenAI) -> None: project_id="project_id", certificate_ids=["cert_abc"], ) - assert_matches_type(AsyncPage[Certificate], certificate, path=["response"]) + assert_matches_type(AsyncPage[CertificateActivateResponse], certificate, path=["response"]) @parametrize async def test_raw_response_activate(self, async_client: AsyncOpenAI) -> None: @@ -222,7 +226,7 @@ async def test_raw_response_activate(self, async_client: AsyncOpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" certificate = response.parse() - assert_matches_type(AsyncPage[Certificate], certificate, path=["response"]) + assert_matches_type(AsyncPage[CertificateActivateResponse], certificate, path=["response"]) @parametrize async def test_streaming_response_activate(self, async_client: AsyncOpenAI) -> None: @@ -234,7 +238,7 @@ async def test_streaming_response_activate(self, async_client: AsyncOpenAI) -> N assert response.http_request.headers.get("X-Stainless-Lang") == "python" certificate = await response.parse() - assert_matches_type(AsyncPage[Certificate], certificate, path=["response"]) + assert_matches_type(AsyncPage[CertificateActivateResponse], certificate, path=["response"]) assert cast(Any, response.is_closed) is True @@ -252,7 +256,7 @@ async def test_method_deactivate(self, async_client: AsyncOpenAI) -> None: project_id="project_id", certificate_ids=["cert_abc"], ) - assert_matches_type(AsyncPage[Certificate], certificate, path=["response"]) + assert_matches_type(AsyncPage[CertificateDeactivateResponse], certificate, path=["response"]) @parametrize async def test_raw_response_deactivate(self, async_client: AsyncOpenAI) -> None: @@ -264,7 +268,7 @@ async def test_raw_response_deactivate(self, async_client: AsyncOpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" certificate = response.parse() - assert_matches_type(AsyncPage[Certificate], certificate, path=["response"]) + assert_matches_type(AsyncPage[CertificateDeactivateResponse], certificate, path=["response"]) @parametrize async def test_streaming_response_deactivate(self, async_client: AsyncOpenAI) -> None: @@ -276,7 +280,7 @@ async def test_streaming_response_deactivate(self, async_client: AsyncOpenAI) -> assert response.http_request.headers.get("X-Stainless-Lang") == "python" certificate = await response.parse() - assert_matches_type(AsyncPage[Certificate], certificate, path=["response"]) + assert_matches_type(AsyncPage[CertificateDeactivateResponse], certificate, path=["response"]) assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/admin/organization/projects/test_groups.py b/tests/api_resources/admin/organization/projects/test_groups.py index 57d768e738..2db448e9b2 100644 --- a/tests/api_resources/admin/organization/projects/test_groups.py +++ b/tests/api_resources/admin/organization/projects/test_groups.py @@ -9,7 +9,7 @@ from openai import OpenAI, AsyncOpenAI from tests.utils import assert_matches_type -from openai.pagination import SyncCursorPage, AsyncCursorPage +from openai.pagination import SyncNextCursorPage, AsyncNextCursorPage from openai.types.admin.organization.projects import ( ProjectGroup, GroupDeleteResponse, @@ -72,7 +72,7 @@ def test_method_list(self, client: OpenAI) -> None: group = client.admin.organization.projects.groups.list( project_id="project_id", ) - assert_matches_type(SyncCursorPage[ProjectGroup], group, path=["response"]) + assert_matches_type(SyncNextCursorPage[ProjectGroup], group, path=["response"]) @parametrize def test_method_list_with_all_params(self, client: OpenAI) -> None: @@ -82,7 +82,7 @@ def test_method_list_with_all_params(self, client: OpenAI) -> None: limit=0, order="asc", ) - assert_matches_type(SyncCursorPage[ProjectGroup], group, path=["response"]) + assert_matches_type(SyncNextCursorPage[ProjectGroup], group, path=["response"]) @parametrize def test_raw_response_list(self, client: OpenAI) -> None: @@ -93,7 +93,7 @@ def test_raw_response_list(self, client: OpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" group = response.parse() - assert_matches_type(SyncCursorPage[ProjectGroup], group, path=["response"]) + assert_matches_type(SyncNextCursorPage[ProjectGroup], group, path=["response"]) @parametrize def test_streaming_response_list(self, client: OpenAI) -> None: @@ -104,7 +104,7 @@ def test_streaming_response_list(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" group = response.parse() - assert_matches_type(SyncCursorPage[ProjectGroup], group, path=["response"]) + assert_matches_type(SyncNextCursorPage[ProjectGroup], group, path=["response"]) assert cast(Any, response.is_closed) is True @@ -220,7 +220,7 @@ async def test_method_list(self, async_client: AsyncOpenAI) -> None: group = await async_client.admin.organization.projects.groups.list( project_id="project_id", ) - assert_matches_type(AsyncCursorPage[ProjectGroup], group, path=["response"]) + assert_matches_type(AsyncNextCursorPage[ProjectGroup], group, path=["response"]) @parametrize async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: @@ -230,7 +230,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> N limit=0, order="asc", ) - assert_matches_type(AsyncCursorPage[ProjectGroup], group, path=["response"]) + assert_matches_type(AsyncNextCursorPage[ProjectGroup], group, path=["response"]) @parametrize async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: @@ -241,7 +241,7 @@ async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" group = response.parse() - assert_matches_type(AsyncCursorPage[ProjectGroup], group, path=["response"]) + assert_matches_type(AsyncNextCursorPage[ProjectGroup], group, path=["response"]) @parametrize async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: @@ -252,7 +252,7 @@ async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" group = await response.parse() - assert_matches_type(AsyncCursorPage[ProjectGroup], group, path=["response"]) + assert_matches_type(AsyncNextCursorPage[ProjectGroup], group, path=["response"]) assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/admin/organization/projects/test_roles.py b/tests/api_resources/admin/organization/projects/test_roles.py index 697aa09f3a..8c78ea21b4 100644 --- a/tests/api_resources/admin/organization/projects/test_roles.py +++ b/tests/api_resources/admin/organization/projects/test_roles.py @@ -9,7 +9,7 @@ from openai import OpenAI, AsyncOpenAI from tests.utils import assert_matches_type -from openai.pagination import SyncCursorPage, AsyncCursorPage +from openai.pagination import SyncNextCursorPage, AsyncNextCursorPage from openai.types.admin.organization import Role from openai.types.admin.organization.projects import ( RoleDeleteResponse, @@ -141,7 +141,7 @@ def test_method_list(self, client: OpenAI) -> None: role = client.admin.organization.projects.roles.list( project_id="project_id", ) - assert_matches_type(SyncCursorPage[Role], role, path=["response"]) + assert_matches_type(SyncNextCursorPage[Role], role, path=["response"]) @parametrize def test_method_list_with_all_params(self, client: OpenAI) -> None: @@ -151,7 +151,7 @@ def test_method_list_with_all_params(self, client: OpenAI) -> None: limit=0, order="asc", ) - assert_matches_type(SyncCursorPage[Role], role, path=["response"]) + assert_matches_type(SyncNextCursorPage[Role], role, path=["response"]) @parametrize def test_raw_response_list(self, client: OpenAI) -> None: @@ -162,7 +162,7 @@ def test_raw_response_list(self, client: OpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" role = response.parse() - assert_matches_type(SyncCursorPage[Role], role, path=["response"]) + assert_matches_type(SyncNextCursorPage[Role], role, path=["response"]) @parametrize def test_streaming_response_list(self, client: OpenAI) -> None: @@ -173,7 +173,7 @@ def test_streaming_response_list(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" role = response.parse() - assert_matches_type(SyncCursorPage[Role], role, path=["response"]) + assert_matches_type(SyncNextCursorPage[Role], role, path=["response"]) assert cast(Any, response.is_closed) is True @@ -358,7 +358,7 @@ async def test_method_list(self, async_client: AsyncOpenAI) -> None: role = await async_client.admin.organization.projects.roles.list( project_id="project_id", ) - assert_matches_type(AsyncCursorPage[Role], role, path=["response"]) + assert_matches_type(AsyncNextCursorPage[Role], role, path=["response"]) @parametrize async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: @@ -368,7 +368,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> N limit=0, order="asc", ) - assert_matches_type(AsyncCursorPage[Role], role, path=["response"]) + assert_matches_type(AsyncNextCursorPage[Role], role, path=["response"]) @parametrize async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: @@ -379,7 +379,7 @@ async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" role = response.parse() - assert_matches_type(AsyncCursorPage[Role], role, path=["response"]) + assert_matches_type(AsyncNextCursorPage[Role], role, path=["response"]) @parametrize async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: @@ -390,7 +390,7 @@ async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" role = await response.parse() - assert_matches_type(AsyncCursorPage[Role], role, path=["response"]) + assert_matches_type(AsyncNextCursorPage[Role], role, path=["response"]) assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/admin/organization/projects/users/test_roles.py b/tests/api_resources/admin/organization/projects/users/test_roles.py index c39840646b..99c52d494c 100644 --- a/tests/api_resources/admin/organization/projects/users/test_roles.py +++ b/tests/api_resources/admin/organization/projects/users/test_roles.py @@ -9,7 +9,7 @@ from openai import OpenAI, AsyncOpenAI from tests.utils import assert_matches_type -from openai.pagination import SyncCursorPage, AsyncCursorPage +from openai.pagination import SyncNextCursorPage, AsyncNextCursorPage from openai.types.admin.organization.projects.users import ( RoleListResponse, RoleCreateResponse, @@ -81,7 +81,7 @@ def test_method_list(self, client: OpenAI) -> None: user_id="user_id", project_id="project_id", ) - assert_matches_type(SyncCursorPage[RoleListResponse], role, path=["response"]) + assert_matches_type(SyncNextCursorPage[RoleListResponse], role, path=["response"]) @parametrize def test_method_list_with_all_params(self, client: OpenAI) -> None: @@ -92,7 +92,7 @@ def test_method_list_with_all_params(self, client: OpenAI) -> None: limit=0, order="asc", ) - assert_matches_type(SyncCursorPage[RoleListResponse], role, path=["response"]) + assert_matches_type(SyncNextCursorPage[RoleListResponse], role, path=["response"]) @parametrize def test_raw_response_list(self, client: OpenAI) -> None: @@ -104,7 +104,7 @@ def test_raw_response_list(self, client: OpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" role = response.parse() - assert_matches_type(SyncCursorPage[RoleListResponse], role, path=["response"]) + assert_matches_type(SyncNextCursorPage[RoleListResponse], role, path=["response"]) @parametrize def test_streaming_response_list(self, client: OpenAI) -> None: @@ -116,7 +116,7 @@ def test_streaming_response_list(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" role = response.parse() - assert_matches_type(SyncCursorPage[RoleListResponse], role, path=["response"]) + assert_matches_type(SyncNextCursorPage[RoleListResponse], role, path=["response"]) assert cast(Any, response.is_closed) is True @@ -259,7 +259,7 @@ async def test_method_list(self, async_client: AsyncOpenAI) -> None: user_id="user_id", project_id="project_id", ) - assert_matches_type(AsyncCursorPage[RoleListResponse], role, path=["response"]) + assert_matches_type(AsyncNextCursorPage[RoleListResponse], role, path=["response"]) @parametrize async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: @@ -270,7 +270,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> N limit=0, order="asc", ) - assert_matches_type(AsyncCursorPage[RoleListResponse], role, path=["response"]) + assert_matches_type(AsyncNextCursorPage[RoleListResponse], role, path=["response"]) @parametrize async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: @@ -282,7 +282,7 @@ async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" role = response.parse() - assert_matches_type(AsyncCursorPage[RoleListResponse], role, path=["response"]) + assert_matches_type(AsyncNextCursorPage[RoleListResponse], role, path=["response"]) @parametrize async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: @@ -294,7 +294,7 @@ async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" role = await response.parse() - assert_matches_type(AsyncCursorPage[RoleListResponse], role, path=["response"]) + assert_matches_type(AsyncNextCursorPage[RoleListResponse], role, path=["response"]) assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/admin/organization/test_admin_api_keys.py b/tests/api_resources/admin/organization/test_admin_api_keys.py index 3b6e7dec37..59eed910e8 100644 --- a/tests/api_resources/admin/organization/test_admin_api_keys.py +++ b/tests/api_resources/admin/organization/test_admin_api_keys.py @@ -12,6 +12,7 @@ from openai.pagination import SyncCursorPage, AsyncCursorPage from openai.types.admin.organization import ( AdminAPIKey, + AdminAPIKeyCreateResponse, AdminAPIKeyDeleteResponse, ) @@ -26,7 +27,7 @@ def test_method_create(self, client: OpenAI) -> None: admin_api_key = client.admin.organization.admin_api_keys.create( name="New Admin Key", ) - assert_matches_type(AdminAPIKey, admin_api_key, path=["response"]) + assert_matches_type(AdminAPIKeyCreateResponse, admin_api_key, path=["response"]) @parametrize def test_raw_response_create(self, client: OpenAI) -> None: @@ -37,7 +38,7 @@ def test_raw_response_create(self, client: OpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" admin_api_key = response.parse() - assert_matches_type(AdminAPIKey, admin_api_key, path=["response"]) + assert_matches_type(AdminAPIKeyCreateResponse, admin_api_key, path=["response"]) @parametrize def test_streaming_response_create(self, client: OpenAI) -> None: @@ -48,7 +49,7 @@ def test_streaming_response_create(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" admin_api_key = response.parse() - assert_matches_type(AdminAPIKey, admin_api_key, path=["response"]) + assert_matches_type(AdminAPIKeyCreateResponse, admin_api_key, path=["response"]) assert cast(Any, response.is_closed) is True @@ -173,7 +174,7 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None: admin_api_key = await async_client.admin.organization.admin_api_keys.create( name="New Admin Key", ) - assert_matches_type(AdminAPIKey, admin_api_key, path=["response"]) + assert_matches_type(AdminAPIKeyCreateResponse, admin_api_key, path=["response"]) @parametrize async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: @@ -184,7 +185,7 @@ async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" admin_api_key = response.parse() - assert_matches_type(AdminAPIKey, admin_api_key, path=["response"]) + assert_matches_type(AdminAPIKeyCreateResponse, admin_api_key, path=["response"]) @parametrize async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: @@ -195,7 +196,7 @@ async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> Non assert response.http_request.headers.get("X-Stainless-Lang") == "python" admin_api_key = await response.parse() - assert_matches_type(AdminAPIKey, admin_api_key, path=["response"]) + assert_matches_type(AdminAPIKeyCreateResponse, admin_api_key, path=["response"]) assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/admin/organization/test_certificates.py b/tests/api_resources/admin/organization/test_certificates.py index a1f0053f13..209fd9220d 100644 --- a/tests/api_resources/admin/organization/test_certificates.py +++ b/tests/api_resources/admin/organization/test_certificates.py @@ -12,7 +12,10 @@ from openai.pagination import SyncPage, AsyncPage, SyncConversationCursorPage, AsyncConversationCursorPage from openai.types.admin.organization import ( Certificate, + CertificateListResponse, CertificateDeleteResponse, + CertificateActivateResponse, + CertificateDeactivateResponse, ) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -24,14 +27,14 @@ class TestCertificates: @parametrize def test_method_create(self, client: OpenAI) -> None: certificate = client.admin.organization.certificates.create( - content="content", + certificate="certificate", ) assert_matches_type(Certificate, certificate, path=["response"]) @parametrize def test_method_create_with_all_params(self, client: OpenAI) -> None: certificate = client.admin.organization.certificates.create( - content="content", + certificate="certificate", name="name", ) assert_matches_type(Certificate, certificate, path=["response"]) @@ -39,7 +42,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: @parametrize def test_raw_response_create(self, client: OpenAI) -> None: response = client.admin.organization.certificates.with_raw_response.create( - content="content", + certificate="certificate", ) assert response.is_closed is True @@ -50,7 +53,7 @@ def test_raw_response_create(self, client: OpenAI) -> None: @parametrize def test_streaming_response_create(self, client: OpenAI) -> None: with client.admin.organization.certificates.with_streaming_response.create( - content="content", + certificate="certificate", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -108,6 +111,13 @@ def test_path_params_retrieve(self, client: OpenAI) -> None: @parametrize def test_method_update(self, client: OpenAI) -> None: + certificate = client.admin.organization.certificates.update( + certificate_id="certificate_id", + ) + assert_matches_type(Certificate, certificate, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: OpenAI) -> None: certificate = client.admin.organization.certificates.update( certificate_id="certificate_id", name="name", @@ -118,7 +128,6 @@ def test_method_update(self, client: OpenAI) -> None: def test_raw_response_update(self, client: OpenAI) -> None: response = client.admin.organization.certificates.with_raw_response.update( certificate_id="certificate_id", - name="name", ) assert response.is_closed is True @@ -130,7 +139,6 @@ def test_raw_response_update(self, client: OpenAI) -> None: def test_streaming_response_update(self, client: OpenAI) -> None: with client.admin.organization.certificates.with_streaming_response.update( certificate_id="certificate_id", - name="name", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -145,13 +153,12 @@ def test_path_params_update(self, client: OpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `certificate_id` but received ''"): client.admin.organization.certificates.with_raw_response.update( certificate_id="", - name="name", ) @parametrize def test_method_list(self, client: OpenAI) -> None: certificate = client.admin.organization.certificates.list() - assert_matches_type(SyncConversationCursorPage[Certificate], certificate, path=["response"]) + assert_matches_type(SyncConversationCursorPage[CertificateListResponse], certificate, path=["response"]) @parametrize def test_method_list_with_all_params(self, client: OpenAI) -> None: @@ -160,7 +167,7 @@ def test_method_list_with_all_params(self, client: OpenAI) -> None: limit=0, order="asc", ) - assert_matches_type(SyncConversationCursorPage[Certificate], certificate, path=["response"]) + assert_matches_type(SyncConversationCursorPage[CertificateListResponse], certificate, path=["response"]) @parametrize def test_raw_response_list(self, client: OpenAI) -> None: @@ -169,7 +176,7 @@ def test_raw_response_list(self, client: OpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" certificate = response.parse() - assert_matches_type(SyncConversationCursorPage[Certificate], certificate, path=["response"]) + assert_matches_type(SyncConversationCursorPage[CertificateListResponse], certificate, path=["response"]) @parametrize def test_streaming_response_list(self, client: OpenAI) -> None: @@ -178,7 +185,7 @@ def test_streaming_response_list(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" certificate = response.parse() - assert_matches_type(SyncConversationCursorPage[Certificate], certificate, path=["response"]) + assert_matches_type(SyncConversationCursorPage[CertificateListResponse], certificate, path=["response"]) assert cast(Any, response.is_closed) is True @@ -225,7 +232,7 @@ def test_method_activate(self, client: OpenAI) -> None: certificate = client.admin.organization.certificates.activate( certificate_ids=["cert_abc"], ) - assert_matches_type(SyncPage[Certificate], certificate, path=["response"]) + assert_matches_type(SyncPage[CertificateActivateResponse], certificate, path=["response"]) @parametrize def test_raw_response_activate(self, client: OpenAI) -> None: @@ -236,7 +243,7 @@ def test_raw_response_activate(self, client: OpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" certificate = response.parse() - assert_matches_type(SyncPage[Certificate], certificate, path=["response"]) + assert_matches_type(SyncPage[CertificateActivateResponse], certificate, path=["response"]) @parametrize def test_streaming_response_activate(self, client: OpenAI) -> None: @@ -247,7 +254,7 @@ def test_streaming_response_activate(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" certificate = response.parse() - assert_matches_type(SyncPage[Certificate], certificate, path=["response"]) + assert_matches_type(SyncPage[CertificateActivateResponse], certificate, path=["response"]) assert cast(Any, response.is_closed) is True @@ -256,7 +263,7 @@ def test_method_deactivate(self, client: OpenAI) -> None: certificate = client.admin.organization.certificates.deactivate( certificate_ids=["cert_abc"], ) - assert_matches_type(SyncPage[Certificate], certificate, path=["response"]) + assert_matches_type(SyncPage[CertificateDeactivateResponse], certificate, path=["response"]) @parametrize def test_raw_response_deactivate(self, client: OpenAI) -> None: @@ -267,7 +274,7 @@ def test_raw_response_deactivate(self, client: OpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" certificate = response.parse() - assert_matches_type(SyncPage[Certificate], certificate, path=["response"]) + assert_matches_type(SyncPage[CertificateDeactivateResponse], certificate, path=["response"]) @parametrize def test_streaming_response_deactivate(self, client: OpenAI) -> None: @@ -278,7 +285,7 @@ def test_streaming_response_deactivate(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" certificate = response.parse() - assert_matches_type(SyncPage[Certificate], certificate, path=["response"]) + assert_matches_type(SyncPage[CertificateDeactivateResponse], certificate, path=["response"]) assert cast(Any, response.is_closed) is True @@ -291,14 +298,14 @@ class TestAsyncCertificates: @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: certificate = await async_client.admin.organization.certificates.create( - content="content", + certificate="certificate", ) assert_matches_type(Certificate, certificate, path=["response"]) @parametrize async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: certificate = await async_client.admin.organization.certificates.create( - content="content", + certificate="certificate", name="name", ) assert_matches_type(Certificate, certificate, path=["response"]) @@ -306,7 +313,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> @parametrize async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: response = await async_client.admin.organization.certificates.with_raw_response.create( - content="content", + certificate="certificate", ) assert response.is_closed is True @@ -317,7 +324,7 @@ async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: async with async_client.admin.organization.certificates.with_streaming_response.create( - content="content", + certificate="certificate", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -375,6 +382,13 @@ async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_method_update(self, async_client: AsyncOpenAI) -> None: + certificate = await async_client.admin.organization.certificates.update( + certificate_id="certificate_id", + ) + assert_matches_type(Certificate, certificate, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncOpenAI) -> None: certificate = await async_client.admin.organization.certificates.update( certificate_id="certificate_id", name="name", @@ -385,7 +399,6 @@ async def test_method_update(self, async_client: AsyncOpenAI) -> None: async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: response = await async_client.admin.organization.certificates.with_raw_response.update( certificate_id="certificate_id", - name="name", ) assert response.is_closed is True @@ -397,7 +410,6 @@ async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: async def test_streaming_response_update(self, async_client: AsyncOpenAI) -> None: async with async_client.admin.organization.certificates.with_streaming_response.update( certificate_id="certificate_id", - name="name", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -412,13 +424,12 @@ async def test_path_params_update(self, async_client: AsyncOpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `certificate_id` but received ''"): await async_client.admin.organization.certificates.with_raw_response.update( certificate_id="", - name="name", ) @parametrize async def test_method_list(self, async_client: AsyncOpenAI) -> None: certificate = await async_client.admin.organization.certificates.list() - assert_matches_type(AsyncConversationCursorPage[Certificate], certificate, path=["response"]) + assert_matches_type(AsyncConversationCursorPage[CertificateListResponse], certificate, path=["response"]) @parametrize async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: @@ -427,7 +438,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> N limit=0, order="asc", ) - assert_matches_type(AsyncConversationCursorPage[Certificate], certificate, path=["response"]) + assert_matches_type(AsyncConversationCursorPage[CertificateListResponse], certificate, path=["response"]) @parametrize async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: @@ -436,7 +447,7 @@ async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" certificate = response.parse() - assert_matches_type(AsyncConversationCursorPage[Certificate], certificate, path=["response"]) + assert_matches_type(AsyncConversationCursorPage[CertificateListResponse], certificate, path=["response"]) @parametrize async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: @@ -445,7 +456,7 @@ async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" certificate = await response.parse() - assert_matches_type(AsyncConversationCursorPage[Certificate], certificate, path=["response"]) + assert_matches_type(AsyncConversationCursorPage[CertificateListResponse], certificate, path=["response"]) assert cast(Any, response.is_closed) is True @@ -492,7 +503,7 @@ async def test_method_activate(self, async_client: AsyncOpenAI) -> None: certificate = await async_client.admin.organization.certificates.activate( certificate_ids=["cert_abc"], ) - assert_matches_type(AsyncPage[Certificate], certificate, path=["response"]) + assert_matches_type(AsyncPage[CertificateActivateResponse], certificate, path=["response"]) @parametrize async def test_raw_response_activate(self, async_client: AsyncOpenAI) -> None: @@ -503,7 +514,7 @@ async def test_raw_response_activate(self, async_client: AsyncOpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" certificate = response.parse() - assert_matches_type(AsyncPage[Certificate], certificate, path=["response"]) + assert_matches_type(AsyncPage[CertificateActivateResponse], certificate, path=["response"]) @parametrize async def test_streaming_response_activate(self, async_client: AsyncOpenAI) -> None: @@ -514,7 +525,7 @@ async def test_streaming_response_activate(self, async_client: AsyncOpenAI) -> N assert response.http_request.headers.get("X-Stainless-Lang") == "python" certificate = await response.parse() - assert_matches_type(AsyncPage[Certificate], certificate, path=["response"]) + assert_matches_type(AsyncPage[CertificateActivateResponse], certificate, path=["response"]) assert cast(Any, response.is_closed) is True @@ -523,7 +534,7 @@ async def test_method_deactivate(self, async_client: AsyncOpenAI) -> None: certificate = await async_client.admin.organization.certificates.deactivate( certificate_ids=["cert_abc"], ) - assert_matches_type(AsyncPage[Certificate], certificate, path=["response"]) + assert_matches_type(AsyncPage[CertificateDeactivateResponse], certificate, path=["response"]) @parametrize async def test_raw_response_deactivate(self, async_client: AsyncOpenAI) -> None: @@ -534,7 +545,7 @@ async def test_raw_response_deactivate(self, async_client: AsyncOpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" certificate = response.parse() - assert_matches_type(AsyncPage[Certificate], certificate, path=["response"]) + assert_matches_type(AsyncPage[CertificateDeactivateResponse], certificate, path=["response"]) @parametrize async def test_streaming_response_deactivate(self, async_client: AsyncOpenAI) -> None: @@ -545,6 +556,6 @@ async def test_streaming_response_deactivate(self, async_client: AsyncOpenAI) -> assert response.http_request.headers.get("X-Stainless-Lang") == "python" certificate = await response.parse() - assert_matches_type(AsyncPage[Certificate], certificate, path=["response"]) + assert_matches_type(AsyncPage[CertificateDeactivateResponse], certificate, path=["response"]) assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/admin/organization/test_groups.py b/tests/api_resources/admin/organization/test_groups.py index b37469625b..0eca89f06c 100644 --- a/tests/api_resources/admin/organization/test_groups.py +++ b/tests/api_resources/admin/organization/test_groups.py @@ -9,7 +9,7 @@ from openai import OpenAI, AsyncOpenAI from tests.utils import assert_matches_type -from openai.pagination import SyncCursorPage, AsyncCursorPage +from openai.pagination import SyncNextCursorPage, AsyncNextCursorPage from openai.types.admin.organization import ( Group, GroupDeleteResponse, @@ -98,7 +98,7 @@ def test_path_params_update(self, client: OpenAI) -> None: @parametrize def test_method_list(self, client: OpenAI) -> None: group = client.admin.organization.groups.list() - assert_matches_type(SyncCursorPage[Group], group, path=["response"]) + assert_matches_type(SyncNextCursorPage[Group], group, path=["response"]) @parametrize def test_method_list_with_all_params(self, client: OpenAI) -> None: @@ -107,7 +107,7 @@ def test_method_list_with_all_params(self, client: OpenAI) -> None: limit=0, order="asc", ) - assert_matches_type(SyncCursorPage[Group], group, path=["response"]) + assert_matches_type(SyncNextCursorPage[Group], group, path=["response"]) @parametrize def test_raw_response_list(self, client: OpenAI) -> None: @@ -116,7 +116,7 @@ def test_raw_response_list(self, client: OpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" group = response.parse() - assert_matches_type(SyncCursorPage[Group], group, path=["response"]) + assert_matches_type(SyncNextCursorPage[Group], group, path=["response"]) @parametrize def test_streaming_response_list(self, client: OpenAI) -> None: @@ -125,7 +125,7 @@ def test_streaming_response_list(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" group = response.parse() - assert_matches_type(SyncCursorPage[Group], group, path=["response"]) + assert_matches_type(SyncNextCursorPage[Group], group, path=["response"]) assert cast(Any, response.is_closed) is True @@ -249,7 +249,7 @@ async def test_path_params_update(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_method_list(self, async_client: AsyncOpenAI) -> None: group = await async_client.admin.organization.groups.list() - assert_matches_type(AsyncCursorPage[Group], group, path=["response"]) + assert_matches_type(AsyncNextCursorPage[Group], group, path=["response"]) @parametrize async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: @@ -258,7 +258,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> N limit=0, order="asc", ) - assert_matches_type(AsyncCursorPage[Group], group, path=["response"]) + assert_matches_type(AsyncNextCursorPage[Group], group, path=["response"]) @parametrize async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: @@ -267,7 +267,7 @@ async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" group = response.parse() - assert_matches_type(AsyncCursorPage[Group], group, path=["response"]) + assert_matches_type(AsyncNextCursorPage[Group], group, path=["response"]) @parametrize async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: @@ -276,7 +276,7 @@ async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" group = await response.parse() - assert_matches_type(AsyncCursorPage[Group], group, path=["response"]) + assert_matches_type(AsyncNextCursorPage[Group], group, path=["response"]) assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/admin/organization/test_roles.py b/tests/api_resources/admin/organization/test_roles.py index 1b4b44278b..ee70020c23 100644 --- a/tests/api_resources/admin/organization/test_roles.py +++ b/tests/api_resources/admin/organization/test_roles.py @@ -9,7 +9,7 @@ from openai import OpenAI, AsyncOpenAI from tests.utils import assert_matches_type -from openai.pagination import SyncCursorPage, AsyncCursorPage +from openai.pagination import SyncNextCursorPage, AsyncNextCursorPage from openai.types.admin.organization import ( Role, RoleDeleteResponse, @@ -115,7 +115,7 @@ def test_path_params_update(self, client: OpenAI) -> None: @parametrize def test_method_list(self, client: OpenAI) -> None: role = client.admin.organization.roles.list() - assert_matches_type(SyncCursorPage[Role], role, path=["response"]) + assert_matches_type(SyncNextCursorPage[Role], role, path=["response"]) @parametrize def test_method_list_with_all_params(self, client: OpenAI) -> None: @@ -124,7 +124,7 @@ def test_method_list_with_all_params(self, client: OpenAI) -> None: limit=0, order="asc", ) - assert_matches_type(SyncCursorPage[Role], role, path=["response"]) + assert_matches_type(SyncNextCursorPage[Role], role, path=["response"]) @parametrize def test_raw_response_list(self, client: OpenAI) -> None: @@ -133,7 +133,7 @@ def test_raw_response_list(self, client: OpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" role = response.parse() - assert_matches_type(SyncCursorPage[Role], role, path=["response"]) + assert_matches_type(SyncNextCursorPage[Role], role, path=["response"]) @parametrize def test_streaming_response_list(self, client: OpenAI) -> None: @@ -142,7 +142,7 @@ def test_streaming_response_list(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" role = response.parse() - assert_matches_type(SyncCursorPage[Role], role, path=["response"]) + assert_matches_type(SyncNextCursorPage[Role], role, path=["response"]) assert cast(Any, response.is_closed) is True @@ -284,7 +284,7 @@ async def test_path_params_update(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_method_list(self, async_client: AsyncOpenAI) -> None: role = await async_client.admin.organization.roles.list() - assert_matches_type(AsyncCursorPage[Role], role, path=["response"]) + assert_matches_type(AsyncNextCursorPage[Role], role, path=["response"]) @parametrize async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: @@ -293,7 +293,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> N limit=0, order="asc", ) - assert_matches_type(AsyncCursorPage[Role], role, path=["response"]) + assert_matches_type(AsyncNextCursorPage[Role], role, path=["response"]) @parametrize async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: @@ -302,7 +302,7 @@ async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" role = response.parse() - assert_matches_type(AsyncCursorPage[Role], role, path=["response"]) + assert_matches_type(AsyncNextCursorPage[Role], role, path=["response"]) @parametrize async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: @@ -311,7 +311,7 @@ async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" role = await response.parse() - assert_matches_type(AsyncCursorPage[Role], role, path=["response"]) + assert_matches_type(AsyncNextCursorPage[Role], role, path=["response"]) assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/admin/organization/test_users.py b/tests/api_resources/admin/organization/test_users.py index 7350b6ecf5..8107bc5e53 100644 --- a/tests/api_resources/admin/organization/test_users.py +++ b/tests/api_resources/admin/organization/test_users.py @@ -58,6 +58,13 @@ def test_path_params_retrieve(self, client: OpenAI) -> None: @parametrize def test_method_update(self, client: OpenAI) -> None: + user = client.admin.organization.users.update( + user_id="user_id", + ) + assert_matches_type(OrganizationUser, user, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: OpenAI) -> None: user = client.admin.organization.users.update( user_id="user_id", role="owner", @@ -68,7 +75,6 @@ def test_method_update(self, client: OpenAI) -> None: def test_raw_response_update(self, client: OpenAI) -> None: response = client.admin.organization.users.with_raw_response.update( user_id="user_id", - role="owner", ) assert response.is_closed is True @@ -80,7 +86,6 @@ def test_raw_response_update(self, client: OpenAI) -> None: def test_streaming_response_update(self, client: OpenAI) -> None: with client.admin.organization.users.with_streaming_response.update( user_id="user_id", - role="owner", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -95,7 +100,6 @@ def test_path_params_update(self, client: OpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): client.admin.organization.users.with_raw_response.update( user_id="", - role="owner", ) @parametrize @@ -216,6 +220,13 @@ async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_method_update(self, async_client: AsyncOpenAI) -> None: + user = await async_client.admin.organization.users.update( + user_id="user_id", + ) + assert_matches_type(OrganizationUser, user, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncOpenAI) -> None: user = await async_client.admin.organization.users.update( user_id="user_id", role="owner", @@ -226,7 +237,6 @@ async def test_method_update(self, async_client: AsyncOpenAI) -> None: async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: response = await async_client.admin.organization.users.with_raw_response.update( user_id="user_id", - role="owner", ) assert response.is_closed is True @@ -238,7 +248,6 @@ async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: async def test_streaming_response_update(self, async_client: AsyncOpenAI) -> None: async with async_client.admin.organization.users.with_streaming_response.update( user_id="user_id", - role="owner", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -253,7 +262,6 @@ async def test_path_params_update(self, async_client: AsyncOpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): await async_client.admin.organization.users.with_raw_response.update( user_id="", - role="owner", ) @parametrize diff --git a/tests/api_resources/admin/organization/users/test_roles.py b/tests/api_resources/admin/organization/users/test_roles.py index 272c0459db..2455a38cff 100644 --- a/tests/api_resources/admin/organization/users/test_roles.py +++ b/tests/api_resources/admin/organization/users/test_roles.py @@ -9,7 +9,7 @@ from openai import OpenAI, AsyncOpenAI from tests.utils import assert_matches_type -from openai.pagination import SyncCursorPage, AsyncCursorPage +from openai.pagination import SyncNextCursorPage, AsyncNextCursorPage from openai.types.admin.organization.users import ( RoleListResponse, RoleCreateResponse, @@ -69,7 +69,7 @@ def test_method_list(self, client: OpenAI) -> None: role = client.admin.organization.users.roles.list( user_id="user_id", ) - assert_matches_type(SyncCursorPage[RoleListResponse], role, path=["response"]) + assert_matches_type(SyncNextCursorPage[RoleListResponse], role, path=["response"]) @parametrize def test_method_list_with_all_params(self, client: OpenAI) -> None: @@ -79,7 +79,7 @@ def test_method_list_with_all_params(self, client: OpenAI) -> None: limit=0, order="asc", ) - assert_matches_type(SyncCursorPage[RoleListResponse], role, path=["response"]) + assert_matches_type(SyncNextCursorPage[RoleListResponse], role, path=["response"]) @parametrize def test_raw_response_list(self, client: OpenAI) -> None: @@ -90,7 +90,7 @@ def test_raw_response_list(self, client: OpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" role = response.parse() - assert_matches_type(SyncCursorPage[RoleListResponse], role, path=["response"]) + assert_matches_type(SyncNextCursorPage[RoleListResponse], role, path=["response"]) @parametrize def test_streaming_response_list(self, client: OpenAI) -> None: @@ -101,7 +101,7 @@ def test_streaming_response_list(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" role = response.parse() - assert_matches_type(SyncCursorPage[RoleListResponse], role, path=["response"]) + assert_matches_type(SyncNextCursorPage[RoleListResponse], role, path=["response"]) assert cast(Any, response.is_closed) is True @@ -213,7 +213,7 @@ async def test_method_list(self, async_client: AsyncOpenAI) -> None: role = await async_client.admin.organization.users.roles.list( user_id="user_id", ) - assert_matches_type(AsyncCursorPage[RoleListResponse], role, path=["response"]) + assert_matches_type(AsyncNextCursorPage[RoleListResponse], role, path=["response"]) @parametrize async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: @@ -223,7 +223,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> N limit=0, order="asc", ) - assert_matches_type(AsyncCursorPage[RoleListResponse], role, path=["response"]) + assert_matches_type(AsyncNextCursorPage[RoleListResponse], role, path=["response"]) @parametrize async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: @@ -234,7 +234,7 @@ async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" role = response.parse() - assert_matches_type(AsyncCursorPage[RoleListResponse], role, path=["response"]) + assert_matches_type(AsyncNextCursorPage[RoleListResponse], role, path=["response"]) @parametrize async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: @@ -245,7 +245,7 @@ async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" role = await response.parse() - assert_matches_type(AsyncCursorPage[RoleListResponse], role, path=["response"]) + assert_matches_type(AsyncNextCursorPage[RoleListResponse], role, path=["response"]) assert cast(Any, response.is_closed) is True From a4c01ec71e19af034af09ab6fa00bac693f8d66a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 1 May 2026 21:19:22 +0000 Subject: [PATCH 716/769] feat(api): add external_key_id to projects, email/metadata params to users, update types --- .stats.yml | 4 +- .../admin/organization/projects/projects.py | 48 +++++++++-- .../organization/projects/users/users.py | 22 ++++-- .../admin/organization/users/users.py | 44 +++++++++-- .../types/admin/organization/admin_api_key.py | 13 ++- .../admin_api_key_create_response.py | 2 +- src/openai/types/admin/organization/group.py | 3 + src/openai/types/admin/organization/invite.py | 14 ++-- .../admin/organization/organization_user.py | 79 +++++++++++++++++-- .../types/admin/organization/project.py | 15 ++-- .../organization/project_create_params.py | 8 +- .../organization/project_update_params.py | 11 ++- .../organization/projects/project_group.py | 3 + .../organization/projects/project_user.py | 15 ++-- .../projects/user_create_params.py | 10 ++- .../projects/user_update_params.py | 5 +- .../admin/organization/user_update_params.py | 14 +++- .../admin/organization/projects/test_users.py | 68 ++++++++++------ .../admin/organization/test_projects.py | 30 +++++-- .../admin/organization/test_users.py | 10 ++- 20 files changed, 317 insertions(+), 101 deletions(-) diff --git a/.stats.yml b/.stats.yml index c12fe18621..81cc0efb25 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 233 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-ea3c8bfb9cc34e798c5a473bb68ab5012344b1c99ab95377d0af4d908eb32a5d.yml -openapi_spec_hash: dbab3fdd7781b449ba3e9e1b5180c6ed +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-9a3e2bb9ea36990c39d7b633e6c10eb63d8918080560640a5b4cdccfac164761.yml +openapi_spec_hash: 0fa82e4dacd57a6d551e79d745860eb8 config_hash: 5d8a716125a61761563abbfc0d34e57c diff --git a/src/openai/resources/admin/organization/projects/projects.py b/src/openai/resources/admin/organization/projects/projects.py index db774338d7..60d252cd46 100644 --- a/src/openai/resources/admin/organization/projects/projects.py +++ b/src/openai/resources/admin/organization/projects/projects.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing_extensions import Literal +from typing import Optional import httpx @@ -128,7 +128,8 @@ def create( self, *, name: str, - geography: Literal["US", "EU", "JP", "IN", "KR", "CA", "AU", "SG"] | Omit = omit, + external_key_id: Optional[str] | Omit = omit, + geography: Optional[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -144,6 +145,8 @@ def create( Args: name: The friendly name of the project, this name appears in reports. + external_key_id: External key ID to associate with the project. + geography: Create the project with the specified data residency region. Your organization must have access to Data residency functionality in order to use. See [data residency controls](https://platform.openai.com/docs/guides/your-data#data-residency-controls) @@ -162,6 +165,7 @@ def create( body=maybe_transform( { "name": name, + "external_key_id": external_key_id, "geography": geography, }, project_create_params.ProjectCreateParams, @@ -217,7 +221,9 @@ def update( self, project_id: str, *, - name: str, + external_key_id: Optional[str] | Omit = omit, + geography: Optional[str] | Omit = omit, + name: Optional[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -229,6 +235,10 @@ def update( Modifies a project in the organization. Args: + external_key_id: External key ID to associate with the project. + + geography: Geography for the project. + name: The updated name of the project, this name appears in reports. extra_headers: Send extra headers @@ -243,7 +253,14 @@ def update( raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") return self._post( path_template("/organization/projects/{project_id}", project_id=project_id), - body=maybe_transform({"name": name}, project_update_params.ProjectUpdateParams), + body=maybe_transform( + { + "external_key_id": external_key_id, + "geography": geography, + "name": name, + }, + project_update_params.ProjectUpdateParams, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -404,7 +421,8 @@ async def create( self, *, name: str, - geography: Literal["US", "EU", "JP", "IN", "KR", "CA", "AU", "SG"] | Omit = omit, + external_key_id: Optional[str] | Omit = omit, + geography: Optional[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -420,6 +438,8 @@ async def create( Args: name: The friendly name of the project, this name appears in reports. + external_key_id: External key ID to associate with the project. + geography: Create the project with the specified data residency region. Your organization must have access to Data residency functionality in order to use. See [data residency controls](https://platform.openai.com/docs/guides/your-data#data-residency-controls) @@ -438,6 +458,7 @@ async def create( body=await async_maybe_transform( { "name": name, + "external_key_id": external_key_id, "geography": geography, }, project_create_params.ProjectCreateParams, @@ -493,7 +514,9 @@ async def update( self, project_id: str, *, - name: str, + external_key_id: Optional[str] | Omit = omit, + geography: Optional[str] | Omit = omit, + name: Optional[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -505,6 +528,10 @@ async def update( Modifies a project in the organization. Args: + external_key_id: External key ID to associate with the project. + + geography: Geography for the project. + name: The updated name of the project, this name appears in reports. extra_headers: Send extra headers @@ -519,7 +546,14 @@ async def update( raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") return await self._post( path_template("/organization/projects/{project_id}", project_id=project_id), - body=await async_maybe_transform({"name": name}, project_update_params.ProjectUpdateParams), + body=await async_maybe_transform( + { + "external_key_id": external_key_id, + "geography": geography, + "name": name, + }, + project_update_params.ProjectUpdateParams, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, diff --git a/src/openai/resources/admin/organization/projects/users/users.py b/src/openai/resources/admin/organization/projects/users/users.py index 024fc27043..3852bfb8c0 100644 --- a/src/openai/resources/admin/organization/projects/users/users.py +++ b/src/openai/resources/admin/organization/projects/users/users.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing_extensions import Literal +from typing import Optional import httpx @@ -57,8 +57,9 @@ def create( self, project_id: str, *, - role: Literal["owner", "member"], - user_id: str, + role: str, + email: Optional[str] | Omit = omit, + user_id: Optional[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -74,6 +75,8 @@ def create( Args: role: `owner` or `member` + email: Email of the user to add. + user_id: The ID of the user. extra_headers: Send extra headers @@ -91,6 +94,7 @@ def create( body=maybe_transform( { "role": role, + "email": email, "user_id": user_id, }, user_create_params.UserCreateParams, @@ -152,7 +156,7 @@ def update( user_id: str, *, project_id: str, - role: Literal["owner", "member"], + role: Optional[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -322,8 +326,9 @@ async def create( self, project_id: str, *, - role: Literal["owner", "member"], - user_id: str, + role: str, + email: Optional[str] | Omit = omit, + user_id: Optional[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -339,6 +344,8 @@ async def create( Args: role: `owner` or `member` + email: Email of the user to add. + user_id: The ID of the user. extra_headers: Send extra headers @@ -356,6 +363,7 @@ async def create( body=await async_maybe_transform( { "role": role, + "email": email, "user_id": user_id, }, user_create_params.UserCreateParams, @@ -417,7 +425,7 @@ async def update( user_id: str, *, project_id: str, - role: Literal["owner", "member"], + role: Optional[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, diff --git a/src/openai/resources/admin/organization/users/users.py b/src/openai/resources/admin/organization/users/users.py index b65a138d1a..94eab69e83 100644 --- a/src/openai/resources/admin/organization/users/users.py +++ b/src/openai/resources/admin/organization/users/users.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing_extensions import Literal +from typing import Optional import httpx @@ -94,7 +94,10 @@ def update( self, user_id: str, *, - role: Literal["owner", "reader"] | Omit = omit, + developer_persona: Optional[str] | Omit = omit, + role: Optional[str] | Omit = omit, + role_id: Optional[str] | Omit = omit, + technical_level: Optional[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -106,8 +109,14 @@ def update( Modifies a user's role in the organization. Args: + developer_persona: Developer persona metadata. + role: `owner` or `reader` + role_id: Role ID to assign to the user. + + technical_level: Technical level metadata. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -120,7 +129,15 @@ def update( raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") return self._post( path_template("/organization/users/{user_id}", user_id=user_id), - body=maybe_transform({"role": role}, user_update_params.UserUpdateParams), + body=maybe_transform( + { + "developer_persona": developer_persona, + "role": role, + "role_id": role_id, + "technical_level": technical_level, + }, + user_update_params.UserUpdateParams, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -290,7 +307,10 @@ async def update( self, user_id: str, *, - role: Literal["owner", "reader"] | Omit = omit, + developer_persona: Optional[str] | Omit = omit, + role: Optional[str] | Omit = omit, + role_id: Optional[str] | Omit = omit, + technical_level: Optional[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -302,8 +322,14 @@ async def update( Modifies a user's role in the organization. Args: + developer_persona: Developer persona metadata. + role: `owner` or `reader` + role_id: Role ID to assign to the user. + + technical_level: Technical level metadata. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -316,7 +342,15 @@ async def update( raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") return await self._post( path_template("/organization/users/{user_id}", user_id=user_id), - body=await async_maybe_transform({"role": role}, user_update_params.UserUpdateParams), + body=await async_maybe_transform( + { + "developer_persona": developer_persona, + "role": role, + "role_id": role_id, + "technical_level": technical_level, + }, + user_update_params.UserUpdateParams, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, diff --git a/src/openai/types/admin/organization/admin_api_key.py b/src/openai/types/admin/organization/admin_api_key.py index 76951a99dd..5d2e5840f9 100644 --- a/src/openai/types/admin/organization/admin_api_key.py +++ b/src/openai/types/admin/organization/admin_api_key.py @@ -37,12 +37,6 @@ class AdminAPIKey(BaseModel): created_at: int """The Unix timestamp (in seconds) of when the API key was created""" - last_used_at: Optional[int] = None - """The Unix timestamp (in seconds) of when the API key was last used""" - - name: str - """The name of the API key""" - object: Literal["organization.admin_api_key"] """The object type, which is always `organization.admin_api_key`""" @@ -51,5 +45,8 @@ class AdminAPIKey(BaseModel): redacted_value: str """The redacted value of the API key""" - value: Optional[str] = None - """The value of the API key. Only shown on create.""" + last_used_at: Optional[int] = None + """The Unix timestamp (in seconds) of when the API key was last used""" + + name: Optional[str] = None + """The name of the API key""" diff --git a/src/openai/types/admin/organization/admin_api_key_create_response.py b/src/openai/types/admin/organization/admin_api_key_create_response.py index 48b2aaaaba..58101a9e0a 100644 --- a/src/openai/types/admin/organization/admin_api_key_create_response.py +++ b/src/openai/types/admin/organization/admin_api_key_create_response.py @@ -8,5 +8,5 @@ class AdminAPIKeyCreateResponse(AdminAPIKey): """Represents an individual Admin API key in an org.""" - value: str # type: ignore + value: str """The value of the API key. Only shown on create.""" diff --git a/src/openai/types/admin/organization/group.py b/src/openai/types/admin/organization/group.py index ce3b0d41b3..a5823b1442 100644 --- a/src/openai/types/admin/organization/group.py +++ b/src/openai/types/admin/organization/group.py @@ -14,6 +14,9 @@ class Group(BaseModel): created_at: int """Unix timestamp (in seconds) when the group was created.""" + group_type: str + """The type of the group.""" + is_scim_managed: bool """ Whether the group is managed through SCIM and controlled by your identity diff --git a/src/openai/types/admin/organization/invite.py b/src/openai/types/admin/organization/invite.py index dc72dc2b5b..a3d2c50438 100644 --- a/src/openai/types/admin/organization/invite.py +++ b/src/openai/types/admin/organization/invite.py @@ -9,10 +9,10 @@ class Project(BaseModel): - id: Optional[str] = None + id: str """Project's public ID""" - role: Optional[Literal["member", "owner"]] = None + role: Literal["member", "owner"] """Project membership role""" @@ -28,12 +28,12 @@ class Invite(BaseModel): email: str """The email address of the individual to whom the invite was sent""" - expires_at: Optional[int] = None - """The Unix timestamp (in seconds) of when the invite expires.""" - object: Literal["organization.invite"] """The object type, which is always `organization.invite`""" + projects: List[Project] + """The projects that were granted membership upon acceptance of the invite.""" + role: Literal["owner", "reader"] """`owner` or `reader`""" @@ -43,5 +43,5 @@ class Invite(BaseModel): accepted_at: Optional[int] = None """The Unix timestamp (in seconds) of when the invite was accepted.""" - projects: Optional[List[Project]] = None - """The projects that were granted membership upon acceptance of the invite.""" + expires_at: Optional[int] = None + """The Unix timestamp (in seconds) of when the invite expires.""" diff --git a/src/openai/types/admin/organization/organization_user.py b/src/openai/types/admin/organization/organization_user.py index 3ffe572465..3d1d43a8b6 100644 --- a/src/openai/types/admin/organization/organization_user.py +++ b/src/openai/types/admin/organization/organization_user.py @@ -1,10 +1,47 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from typing import List, Optional from typing_extensions import Literal from ...._models import BaseModel -__all__ = ["OrganizationUser"] +__all__ = ["OrganizationUser", "Projects", "ProjectsData", "User"] + + +class ProjectsData(BaseModel): + id: Optional[str] = None + + name: Optional[str] = None + + role: Optional[str] = None + + +class Projects(BaseModel): + """Projects associated with the user, if included.""" + + data: List[ProjectsData] + + object: Literal["list"] + + +class User(BaseModel): + """Nested user details.""" + + id: str + + object: Literal["user"] + + banned: Optional[bool] = None + + banned_at: Optional[int] = None + + email: Optional[str] = None + + enabled: Optional[bool] = None + + name: Optional[str] = None + + picture: Optional[str] = None class OrganizationUser(BaseModel): @@ -16,14 +53,44 @@ class OrganizationUser(BaseModel): added_at: int """The Unix timestamp (in seconds) of when the user was added.""" - email: str + object: Literal["organization.user"] + """The object type, which is always `organization.user`""" + + api_key_last_used_at: Optional[int] = None + """The Unix timestamp (in seconds) of the user's last API key usage.""" + + created: Optional[int] = None + """The Unix timestamp (in seconds) of when the user was created.""" + + developer_persona: Optional[str] = None + """The developer persona metadata for the user.""" + + email: Optional[str] = None """The email address of the user""" - name: str + is_default: Optional[bool] = None + """Whether this is the organization's default user.""" + + is_scale_tier_authorized_purchaser: Optional[bool] = None + """Whether the user is an authorized purchaser for Scale Tier.""" + + is_scim_managed: Optional[bool] = None + """Whether the user is managed through SCIM.""" + + is_service_account: Optional[bool] = None + """Whether the user is a service account.""" + + name: Optional[str] = None """The name of the user""" - object: Literal["organization.user"] - """The object type, which is always `organization.user`""" + projects: Optional[Projects] = None + """Projects associated with the user, if included.""" - role: Literal["owner", "reader"] + role: Optional[str] = None """`owner` or `reader`""" + + technical_level: Optional[str] = None + """The technical level metadata for the user.""" + + user: Optional[User] = None + """Nested user details.""" diff --git a/src/openai/types/admin/organization/project.py b/src/openai/types/admin/organization/project.py index a1058af3d5..982bb1e4b3 100644 --- a/src/openai/types/admin/organization/project.py +++ b/src/openai/types/admin/organization/project.py @@ -17,14 +17,17 @@ class Project(BaseModel): created_at: int """The Unix timestamp (in seconds) of when the project was created.""" - name: str - """The name of the project. This appears in reporting.""" - object: Literal["organization.project"] """The object type, which is always `organization.project`""" - status: Literal["active", "archived"] - """`active` or `archived`""" - archived_at: Optional[int] = None """The Unix timestamp (in seconds) of when the project was archived or `null`.""" + + external_key_id: Optional[str] = None + """The external key associated with the project.""" + + name: Optional[str] = None + """The name of the project. This appears in reporting.""" + + status: Optional[str] = None + """`active` or `archived`""" diff --git a/src/openai/types/admin/organization/project_create_params.py b/src/openai/types/admin/organization/project_create_params.py index 8b8d1b44e8..a4b7b2d424 100644 --- a/src/openai/types/admin/organization/project_create_params.py +++ b/src/openai/types/admin/organization/project_create_params.py @@ -2,7 +2,8 @@ from __future__ import annotations -from typing_extensions import Literal, Required, TypedDict +from typing import Optional +from typing_extensions import Required, TypedDict __all__ = ["ProjectCreateParams"] @@ -11,7 +12,10 @@ class ProjectCreateParams(TypedDict, total=False): name: Required[str] """The friendly name of the project, this name appears in reports.""" - geography: Literal["US", "EU", "JP", "IN", "KR", "CA", "AU", "SG"] + external_key_id: Optional[str] + """External key ID to associate with the project.""" + + geography: Optional[str] """Create the project with the specified data residency region. Your organization must have access to Data residency functionality in order to diff --git a/src/openai/types/admin/organization/project_update_params.py b/src/openai/types/admin/organization/project_update_params.py index 0ba1984a9f..2ebdd09f4a 100644 --- a/src/openai/types/admin/organization/project_update_params.py +++ b/src/openai/types/admin/organization/project_update_params.py @@ -2,11 +2,18 @@ from __future__ import annotations -from typing_extensions import Required, TypedDict +from typing import Optional +from typing_extensions import TypedDict __all__ = ["ProjectUpdateParams"] class ProjectUpdateParams(TypedDict, total=False): - name: Required[str] + external_key_id: Optional[str] + """External key ID to associate with the project.""" + + geography: Optional[str] + """Geography for the project.""" + + name: Optional[str] """The updated name of the project, this name appears in reports.""" diff --git a/src/openai/types/admin/organization/projects/project_group.py b/src/openai/types/admin/organization/projects/project_group.py index e80d815795..b3da08ca32 100644 --- a/src/openai/types/admin/organization/projects/project_group.py +++ b/src/openai/types/admin/organization/projects/project_group.py @@ -19,6 +19,9 @@ class ProjectGroup(BaseModel): group_name: str """Display name of the group.""" + group_type: str + """The type of the group.""" + object: Literal["project.group"] """Always `project.group`.""" diff --git a/src/openai/types/admin/organization/projects/project_user.py b/src/openai/types/admin/organization/projects/project_user.py index 68c73d1c9b..7aaa9fc05b 100644 --- a/src/openai/types/admin/organization/projects/project_user.py +++ b/src/openai/types/admin/organization/projects/project_user.py @@ -1,5 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from typing import Optional from typing_extensions import Literal from ....._models import BaseModel @@ -16,14 +17,14 @@ class ProjectUser(BaseModel): added_at: int """The Unix timestamp (in seconds) of when the project was added.""" - email: str - """The email address of the user""" - - name: str - """The name of the user""" - object: Literal["organization.project.user"] """The object type, which is always `organization.project.user`""" - role: Literal["owner", "member"] + role: str """`owner` or `member`""" + + email: Optional[str] = None + """The email address of the user""" + + name: Optional[str] = None + """The name of the user""" diff --git a/src/openai/types/admin/organization/projects/user_create_params.py b/src/openai/types/admin/organization/projects/user_create_params.py index dee9d126db..4266ed01f9 100644 --- a/src/openai/types/admin/organization/projects/user_create_params.py +++ b/src/openai/types/admin/organization/projects/user_create_params.py @@ -2,14 +2,18 @@ from __future__ import annotations -from typing_extensions import Literal, Required, TypedDict +from typing import Optional +from typing_extensions import Required, TypedDict __all__ = ["UserCreateParams"] class UserCreateParams(TypedDict, total=False): - role: Required[Literal["owner", "member"]] + role: Required[str] """`owner` or `member`""" - user_id: Required[str] + email: Optional[str] + """Email of the user to add.""" + + user_id: Optional[str] """The ID of the user.""" diff --git a/src/openai/types/admin/organization/projects/user_update_params.py b/src/openai/types/admin/organization/projects/user_update_params.py index 08b3e1a4e9..20a4276567 100644 --- a/src/openai/types/admin/organization/projects/user_update_params.py +++ b/src/openai/types/admin/organization/projects/user_update_params.py @@ -2,7 +2,8 @@ from __future__ import annotations -from typing_extensions import Literal, Required, TypedDict +from typing import Optional +from typing_extensions import Required, TypedDict __all__ = ["UserUpdateParams"] @@ -10,5 +11,5 @@ class UserUpdateParams(TypedDict, total=False): project_id: Required[str] - role: Required[Literal["owner", "member"]] + role: Optional[str] """`owner` or `member`""" diff --git a/src/openai/types/admin/organization/user_update_params.py b/src/openai/types/admin/organization/user_update_params.py index ab1f9d0026..24181b0649 100644 --- a/src/openai/types/admin/organization/user_update_params.py +++ b/src/openai/types/admin/organization/user_update_params.py @@ -2,11 +2,21 @@ from __future__ import annotations -from typing_extensions import Literal, TypedDict +from typing import Optional +from typing_extensions import TypedDict __all__ = ["UserUpdateParams"] class UserUpdateParams(TypedDict, total=False): - role: Literal["owner", "reader"] + developer_persona: Optional[str] + """Developer persona metadata.""" + + role: Optional[str] """`owner` or `reader`""" + + role_id: Optional[str] + """Role ID to assign to the user.""" + + technical_level: Optional[str] + """Technical level metadata.""" diff --git a/tests/api_resources/admin/organization/projects/test_users.py b/tests/api_resources/admin/organization/projects/test_users.py index 30ad94fe3b..66005bf657 100644 --- a/tests/api_resources/admin/organization/projects/test_users.py +++ b/tests/api_resources/admin/organization/projects/test_users.py @@ -25,7 +25,16 @@ class TestUsers: def test_method_create(self, client: OpenAI) -> None: user = client.admin.organization.projects.users.create( project_id="project_id", - role="owner", + role="role", + ) + assert_matches_type(ProjectUser, user, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: OpenAI) -> None: + user = client.admin.organization.projects.users.create( + project_id="project_id", + role="role", + email="email", user_id="user_id", ) assert_matches_type(ProjectUser, user, path=["response"]) @@ -34,8 +43,7 @@ def test_method_create(self, client: OpenAI) -> None: def test_raw_response_create(self, client: OpenAI) -> None: response = client.admin.organization.projects.users.with_raw_response.create( project_id="project_id", - role="owner", - user_id="user_id", + role="role", ) assert response.is_closed is True @@ -47,8 +55,7 @@ def test_raw_response_create(self, client: OpenAI) -> None: def test_streaming_response_create(self, client: OpenAI) -> None: with client.admin.organization.projects.users.with_streaming_response.create( project_id="project_id", - role="owner", - user_id="user_id", + role="role", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -63,8 +70,7 @@ def test_path_params_create(self, client: OpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): client.admin.organization.projects.users.with_raw_response.create( project_id="", - role="owner", - user_id="user_id", + role="role", ) @parametrize @@ -120,7 +126,15 @@ def test_method_update(self, client: OpenAI) -> None: user = client.admin.organization.projects.users.update( user_id="user_id", project_id="project_id", - role="owner", + ) + assert_matches_type(ProjectUser, user, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: OpenAI) -> None: + user = client.admin.organization.projects.users.update( + user_id="user_id", + project_id="project_id", + role="role", ) assert_matches_type(ProjectUser, user, path=["response"]) @@ -129,7 +143,6 @@ def test_raw_response_update(self, client: OpenAI) -> None: response = client.admin.organization.projects.users.with_raw_response.update( user_id="user_id", project_id="project_id", - role="owner", ) assert response.is_closed is True @@ -142,7 +155,6 @@ def test_streaming_response_update(self, client: OpenAI) -> None: with client.admin.organization.projects.users.with_streaming_response.update( user_id="user_id", project_id="project_id", - role="owner", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -158,14 +170,12 @@ def test_path_params_update(self, client: OpenAI) -> None: client.admin.organization.projects.users.with_raw_response.update( user_id="user_id", project_id="", - role="owner", ) with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): client.admin.organization.projects.users.with_raw_response.update( user_id="", project_id="project_id", - role="owner", ) @parametrize @@ -273,7 +283,16 @@ class TestAsyncUsers: async def test_method_create(self, async_client: AsyncOpenAI) -> None: user = await async_client.admin.organization.projects.users.create( project_id="project_id", - role="owner", + role="role", + ) + assert_matches_type(ProjectUser, user, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: + user = await async_client.admin.organization.projects.users.create( + project_id="project_id", + role="role", + email="email", user_id="user_id", ) assert_matches_type(ProjectUser, user, path=["response"]) @@ -282,8 +301,7 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None: async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: response = await async_client.admin.organization.projects.users.with_raw_response.create( project_id="project_id", - role="owner", - user_id="user_id", + role="role", ) assert response.is_closed is True @@ -295,8 +313,7 @@ async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: async with async_client.admin.organization.projects.users.with_streaming_response.create( project_id="project_id", - role="owner", - user_id="user_id", + role="role", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -311,8 +328,7 @@ async def test_path_params_create(self, async_client: AsyncOpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): await async_client.admin.organization.projects.users.with_raw_response.create( project_id="", - role="owner", - user_id="user_id", + role="role", ) @parametrize @@ -368,7 +384,15 @@ async def test_method_update(self, async_client: AsyncOpenAI) -> None: user = await async_client.admin.organization.projects.users.update( user_id="user_id", project_id="project_id", - role="owner", + ) + assert_matches_type(ProjectUser, user, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncOpenAI) -> None: + user = await async_client.admin.organization.projects.users.update( + user_id="user_id", + project_id="project_id", + role="role", ) assert_matches_type(ProjectUser, user, path=["response"]) @@ -377,7 +401,6 @@ async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: response = await async_client.admin.organization.projects.users.with_raw_response.update( user_id="user_id", project_id="project_id", - role="owner", ) assert response.is_closed is True @@ -390,7 +413,6 @@ async def test_streaming_response_update(self, async_client: AsyncOpenAI) -> Non async with async_client.admin.organization.projects.users.with_streaming_response.update( user_id="user_id", project_id="project_id", - role="owner", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -406,14 +428,12 @@ async def test_path_params_update(self, async_client: AsyncOpenAI) -> None: await async_client.admin.organization.projects.users.with_raw_response.update( user_id="user_id", project_id="", - role="owner", ) with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): await async_client.admin.organization.projects.users.with_raw_response.update( user_id="", project_id="project_id", - role="owner", ) @parametrize diff --git a/tests/api_resources/admin/organization/test_projects.py b/tests/api_resources/admin/organization/test_projects.py index 49c18827de..5e07ff1496 100644 --- a/tests/api_resources/admin/organization/test_projects.py +++ b/tests/api_resources/admin/organization/test_projects.py @@ -29,7 +29,8 @@ def test_method_create(self, client: OpenAI) -> None: def test_method_create_with_all_params(self, client: OpenAI) -> None: project = client.admin.organization.projects.create( name="name", - geography="US", + external_key_id="external_key_id", + geography="geography", ) assert_matches_type(Project, project, path=["response"]) @@ -99,6 +100,15 @@ def test_path_params_retrieve(self, client: OpenAI) -> None: def test_method_update(self, client: OpenAI) -> None: project = client.admin.organization.projects.update( project_id="project_id", + ) + assert_matches_type(Project, project, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: OpenAI) -> None: + project = client.admin.organization.projects.update( + project_id="project_id", + external_key_id="external_key_id", + geography="geography", name="name", ) assert_matches_type(Project, project, path=["response"]) @@ -107,7 +117,6 @@ def test_method_update(self, client: OpenAI) -> None: def test_raw_response_update(self, client: OpenAI) -> None: response = client.admin.organization.projects.with_raw_response.update( project_id="project_id", - name="name", ) assert response.is_closed is True @@ -119,7 +128,6 @@ def test_raw_response_update(self, client: OpenAI) -> None: def test_streaming_response_update(self, client: OpenAI) -> None: with client.admin.organization.projects.with_streaming_response.update( project_id="project_id", - name="name", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -134,7 +142,6 @@ def test_path_params_update(self, client: OpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): client.admin.organization.projects.with_raw_response.update( project_id="", - name="name", ) @parametrize @@ -226,7 +233,8 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None: async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: project = await async_client.admin.organization.projects.create( name="name", - geography="US", + external_key_id="external_key_id", + geography="geography", ) assert_matches_type(Project, project, path=["response"]) @@ -296,6 +304,15 @@ async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: async def test_method_update(self, async_client: AsyncOpenAI) -> None: project = await async_client.admin.organization.projects.update( project_id="project_id", + ) + assert_matches_type(Project, project, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncOpenAI) -> None: + project = await async_client.admin.organization.projects.update( + project_id="project_id", + external_key_id="external_key_id", + geography="geography", name="name", ) assert_matches_type(Project, project, path=["response"]) @@ -304,7 +321,6 @@ async def test_method_update(self, async_client: AsyncOpenAI) -> None: async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: response = await async_client.admin.organization.projects.with_raw_response.update( project_id="project_id", - name="name", ) assert response.is_closed is True @@ -316,7 +332,6 @@ async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: async def test_streaming_response_update(self, async_client: AsyncOpenAI) -> None: async with async_client.admin.organization.projects.with_streaming_response.update( project_id="project_id", - name="name", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -331,7 +346,6 @@ async def test_path_params_update(self, async_client: AsyncOpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): await async_client.admin.organization.projects.with_raw_response.update( project_id="", - name="name", ) @parametrize diff --git a/tests/api_resources/admin/organization/test_users.py b/tests/api_resources/admin/organization/test_users.py index 8107bc5e53..308b199bc6 100644 --- a/tests/api_resources/admin/organization/test_users.py +++ b/tests/api_resources/admin/organization/test_users.py @@ -67,7 +67,10 @@ def test_method_update(self, client: OpenAI) -> None: def test_method_update_with_all_params(self, client: OpenAI) -> None: user = client.admin.organization.users.update( user_id="user_id", - role="owner", + developer_persona="developer_persona", + role="role", + role_id="role_id", + technical_level="technical_level", ) assert_matches_type(OrganizationUser, user, path=["response"]) @@ -229,7 +232,10 @@ async def test_method_update(self, async_client: AsyncOpenAI) -> None: async def test_method_update_with_all_params(self, async_client: AsyncOpenAI) -> None: user = await async_client.admin.organization.users.update( user_id="user_id", - role="owner", + developer_persona="developer_persona", + role="role", + role_id="role_id", + technical_level="technical_level", ) assert_matches_type(OrganizationUser, user, path=["response"]) From 8428b0f2cf64f3d9a8ce188823e034ee35eac110 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 1 May 2026 21:39:01 +0000 Subject: [PATCH 717/769] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 81cc0efb25..151eefd946 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 233 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-9a3e2bb9ea36990c39d7b633e6c10eb63d8918080560640a5b4cdccfac164761.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-183d8a06e082c4d50be9b29533adf1f0806646ee0a9582fc51386d629b1e9ffe.yml openapi_spec_hash: 0fa82e4dacd57a6d551e79d745860eb8 -config_hash: 5d8a716125a61761563abbfc0d34e57c +config_hash: dd484e2cc01206d26516338d0f4596b0 From 529e3b746c5c1bf562eba6e37f8a30eab2a0106b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 1 May 2026 23:04:37 +0000 Subject: [PATCH 718/769] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 151eefd946..723cea85fe 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 233 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-183d8a06e082c4d50be9b29533adf1f0806646ee0a9582fc51386d629b1e9ffe.yml -openapi_spec_hash: 0fa82e4dacd57a6d551e79d745860eb8 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-21ecab7aeb61612b9da5e52ea4c0cb75a33d443d975022934b9305e97d1a7d62.yml +openapi_spec_hash: cfc868a0bb3567183510c9b5629c510f config_hash: dd484e2cc01206d26516338d0f4596b0 From 9370977d155464e499de2ac05ee3e99fcd694fa3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 4 May 2026 14:25:08 +0000 Subject: [PATCH 719/769] release: 2.34.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 46 +++++++++++++++++++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 49 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 7ef8288ed5..7a1c4674e4 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.33.0" + ".": "2.34.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index effb1cc263..237a8c00a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,51 @@ # Changelog +## 2.34.0 (2026-05-04) + +Full Changelog: [v2.33.0...v2.34.0](https://github.com/openai/openai-python/compare/v2.33.0...v2.34.0) + +### Features + +* **api:** add external_key_id to projects, email/metadata params to users, update types ([2d232ee](https://github.com/openai/openai-python/commit/2d232eebb2fe021bb21f2576b17d1d588f81a608)) +* **api:** add support for Admin API Keys per endpoint ([b8b176a](https://github.com/openai/openai-python/commit/b8b176af84172f27d2fde8dca062ca4c41f94bf7)) +* **api:** admin API updates ([4ae1138](https://github.com/openai/openai-python/commit/4ae1138ae1f76e81a2267e4deb45b435c10774d5)) +* **api:** manual updates ([c1870f1](https://github.com/openai/openai-python/commit/c1870f1b881bb914e4e62a6c8b08d4c2b9a6fd54)) +* **api:** manual updates ([f6bb9c7](https://github.com/openai/openai-python/commit/f6bb9c7d7bdcc45425d37722358bed097e83d493)) +* support setting headers via env ([1e89d8b](https://github.com/openai/openai-python/commit/1e89d8b56aba12f99a8ef2b1b78fdee84751275a)) + + +### Bug Fixes + +* allow explicit Azure auth headers ([a0626ba](https://github.com/openai/openai-python/commit/a0626babf0548fb03cf3c2d054da116dd6466701)) +* **api:** correct prompt_cache_retention enum value from in-memory to in_memory ([d47d9f0](https://github.com/openai/openai-python/commit/d47d9f0f79c612c4d14005a0a3cf44e1968c9bff)) +* **api:** preserve python api key attribute type ([62607f6](https://github.com/openai/openai-python/commit/62607f61c542ed559ef114849e31307c0c290286)) +* **api:** resolve python auth type checks ([42a31a7](https://github.com/openai/openai-python/commit/42a31a7efb6784633108c1a73e1779ed79ab8bed)) +* **api:** support admin api key auth ([f029eb9](https://github.com/openai/openai-python/commit/f029eb937f976110c1a67b9342525a38a214072e)) +* avoid bearer fallback for admin auth ([22e01a8](https://github.com/openai/openai-python/commit/22e01a8cf791a143ecc576f46de50eee9b3c2147)) +* preserve selected auth credentials ([0d27f9d](https://github.com/openai/openai-python/commit/0d27f9dbd3b2ae82b2e8c2eeb9e7e78f3edecdf1)) +* require bearer auth for stream helpers ([d055539](https://github.com/openai/openai-python/commit/d0555390bcf4a704c10d318c7de2fe006750c3d0)) +* **types:** correct created_at and completed_at to float in Response ([7da4b88](https://github.com/openai/openai-python/commit/7da4b88c1985028f7ee9a98b919e71f863f979f0)) +* **types:** correct timestamp types to int in Response model ([e55631c](https://github.com/openai/openai-python/commit/e55631c868b1d0b720fda0abdbc342787cd95e2c)) +* use correct field name format for multipart file arrays ([9ee4825](https://github.com/openai/openai-python/commit/9ee482576c2bd6b33b6cf7458c37ab2e7d5bc725)) + + +### Performance Improvements + +* **client:** optimize file structure copying in multipart requests ([dca474e](https://github.com/openai/openai-python/commit/dca474e5beac7cc8e05855f042c3227843030c1b)) + + +### Chores + +* **internal:** more robust bootstrap script ([9ec1600](https://github.com/openai/openai-python/commit/9ec1600d48fda10abb144b2a62d07c5abd7e9ab1)) +* **internal:** reformat pyproject.toml ([12ad57b](https://github.com/openai/openai-python/commit/12ad57b8da5b5c0615641af273d4bbf2981d6bf7)) +* **tests:** bump steady to v0.22.1 ([486dfed](https://github.com/openai/openai-python/commit/486dfedfec8484bb00318b0ea798c2260f7a720c)) + + +### Documentation + +* **api:** add rate limit and vector store info to files create ([4f776df](https://github.com/openai/openai-python/commit/4f776df78d757fdbf25662c4be98b5c98183aaaf)) +* **api:** update files rate limit documentation ([b141a20](https://github.com/openai/openai-python/commit/b141a20e948b5af3b8fbe4261798c191d2857b4a)) + ## 2.33.0 (2026-04-28) Full Changelog: [v2.32.0...v2.33.0](https://github.com/openai/openai-python/compare/v2.32.0...v2.33.0) diff --git a/pyproject.toml b/pyproject.toml index b2f4dd11cb..7fbf3bd49b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.33.0" +version = "2.34.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 b73f7aa7bd..857aeb7dff 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__ = "2.33.0" # x-release-please-version +__version__ = "2.34.0" # x-release-please-version From a229b37a1af8b4efe5e59672be7b473d1bb44edd Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 4 May 2026 19:09:50 +0000 Subject: [PATCH 720/769] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 723cea85fe..ff1ede1c54 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 233 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-21ecab7aeb61612b9da5e52ea4c0cb75a33d443d975022934b9305e97d1a7d62.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-81b872fc8a50941a72f77f3fa0791f7234b9180db95b451b38ced94279e947c5.yml openapi_spec_hash: cfc868a0bb3567183510c9b5629c510f -config_hash: dd484e2cc01206d26516338d0f4596b0 +config_hash: 4a32815d42629ed593422278834dcca4 From 6069e19a816e12c076fda6f1207094fdfb4692fe Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 4 May 2026 20:44:50 +0000 Subject: [PATCH 721/769] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index ff1ede1c54..3e1ed4b9e5 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 233 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-81b872fc8a50941a72f77f3fa0791f7234b9180db95b451b38ced94279e947c5.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-b29ed93b301b4a89daf4fb5bb6463cbc059ce944ff9808639679794c10e60dd6.yml openapi_spec_hash: cfc868a0bb3567183510c9b5629c510f -config_hash: 4a32815d42629ed593422278834dcca4 +config_hash: 2524657a4d3e2779f4a70cc581c33d80 From 6dd268a36ae6c4dd73cfcf2086e5a8c49ba7c116 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 4 May 2026 21:31:50 +0000 Subject: [PATCH 722/769] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 3e1ed4b9e5..1c61ea53ec 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 233 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-b29ed93b301b4a89daf4fb5bb6463cbc059ce944ff9808639679794c10e60dd6.yml -openapi_spec_hash: cfc868a0bb3567183510c9b5629c510f +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-70926f399403fb20d9cee460500dad50a9555dd72b5abb768215e9f541a648ea.yml +openapi_spec_hash: ae4a7852e20f39c14adbf6f253b8a004 config_hash: 2524657a4d3e2779f4a70cc581c33d80 From 641c8c487f1e0e786bac17c55f5d8536c5e0336d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 5 May 2026 00:42:06 +0000 Subject: [PATCH 723/769] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 1c61ea53ec..0b6e9119d8 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 233 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-70926f399403fb20d9cee460500dad50a9555dd72b5abb768215e9f541a648ea.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-61d75f384a1e6bee387e9e02168257426facdbbb9677b9b5cb30a3863da40b10.yml openapi_spec_hash: ae4a7852e20f39c14adbf6f253b8a004 -config_hash: 2524657a4d3e2779f4a70cc581c33d80 +config_hash: 51d639d7939b6ab974d1ee45e96c532b From 408dce57fe849024b6a4e9e45797b62c8dc6d97f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 5 May 2026 08:07:54 +0000 Subject: [PATCH 724/769] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 0b6e9119d8..85f4cd414b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 233 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-61d75f384a1e6bee387e9e02168257426facdbbb9677b9b5cb30a3863da40b10.yml -openapi_spec_hash: ae4a7852e20f39c14adbf6f253b8a004 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-1405c20d24646f71eecd0f7ed222426973b8806ef70a3865a2428c0c57b1f050.yml +openapi_spec_hash: 92713b0825f6b8760836778e6d27e837 config_hash: 51d639d7939b6ab974d1ee45e96c532b From 0ba55d7569565045426e1587906a70d5682a4bba Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 5 May 2026 15:49:42 +0000 Subject: [PATCH 725/769] feat(api): launch realtime translate + update image 2 --- .stats.yml | 4 +- src/openai/resources/images.py | 108 +++++++++++------- src/openai/types/image_edit_params.py | 15 ++- src/openai/types/image_generate_params.py | 5 +- src/openai/types/image_model.py | 11 +- .../types/realtime/translations/__init__.py | 3 + src/openai/types/responses/tool.py | 13 ++- src/openai/types/responses/tool_param.py | 12 +- tests/api_resources/test_images.py | 20 ++-- 9 files changed, 127 insertions(+), 64 deletions(-) create mode 100644 src/openai/types/realtime/translations/__init__.py diff --git a/.stats.yml b/.stats.yml index 85f4cd414b..1dee1de615 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 233 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-1405c20d24646f71eecd0f7ed222426973b8806ef70a3865a2428c0c57b1f050.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-5ae2eda70e6a4a375842fb8bf3e88deab8e0aad1b3871b86e73274f131bb37ce.yml openapi_spec_hash: 92713b0825f6b8760836778e6d27e837 -config_hash: 51d639d7939b6ab974d1ee45e96c532b +config_hash: c15a744b2771a3948032b2438475b330 diff --git a/src/openai/resources/images.py b/src/openai/resources/images.py index ec4ca23aa2..1b3ade12c9 100644 --- a/src/openai/resources/images.py +++ b/src/openai/resources/images.py @@ -160,10 +160,10 @@ def edit( Args: image: The image(s) to edit. Must be a supported image file or an array of images. - For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, and - `gpt-image-1.5`), each image should be a `png`, `webp`, or `jpg` file less than - 50MB. You can provide up to 16 images. `chatgpt-image-latest` follows the same - input constraints as GPT image models. + For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`, + `gpt-image-2`, `gpt-image-2-2026-04-21`, and `chatgpt-image-latest`), each image + should be a `png`, `webp`, or `jpg` file less than 50MB. You can provide up to + 16 images. For `dall-e-2`, you can only provide one image, and it should be a square `png` file less than 4MB. @@ -189,7 +189,10 @@ def edit( the mask will be applied on the first image. Must be a valid PNG file, less than 4MB, and have the same dimensions as `image`. - model: The model to use for image generation. Defaults to `gpt-image-1.5`. + model: The model to use for image generation. One of `dall-e-2` or a GPT image model + (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`, `gpt-image-2`, + `gpt-image-2-2026-04-21`, or `chatgpt-image-latest`). Defaults to + `gpt-image-1.5`. n: The number of images to generate. Must be between 1 and 10. @@ -273,10 +276,10 @@ def edit( Args: image: The image(s) to edit. Must be a supported image file or an array of images. - For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, and - `gpt-image-1.5`), each image should be a `png`, `webp`, or `jpg` file less than - 50MB. You can provide up to 16 images. `chatgpt-image-latest` follows the same - input constraints as GPT image models. + For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`, + `gpt-image-2`, `gpt-image-2-2026-04-21`, and `chatgpt-image-latest`), each image + should be a `png`, `webp`, or `jpg` file less than 50MB. You can provide up to + 16 images. For `dall-e-2`, you can only provide one image, and it should be a square `png` file less than 4MB. @@ -306,7 +309,10 @@ def edit( the mask will be applied on the first image. Must be a valid PNG file, less than 4MB, and have the same dimensions as `image`. - model: The model to use for image generation. Defaults to `gpt-image-1.5`. + model: The model to use for image generation. One of `dall-e-2` or a GPT image model + (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`, `gpt-image-2`, + `gpt-image-2-2026-04-21`, or `chatgpt-image-latest`). Defaults to + `gpt-image-1.5`. n: The number of images to generate. Must be between 1 and 10. @@ -386,10 +392,10 @@ def edit( Args: image: The image(s) to edit. Must be a supported image file or an array of images. - For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, and - `gpt-image-1.5`), each image should be a `png`, `webp`, or `jpg` file less than - 50MB. You can provide up to 16 images. `chatgpt-image-latest` follows the same - input constraints as GPT image models. + For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`, + `gpt-image-2`, `gpt-image-2-2026-04-21`, and `chatgpt-image-latest`), each image + should be a `png`, `webp`, or `jpg` file less than 50MB. You can provide up to + 16 images. For `dall-e-2`, you can only provide one image, and it should be a square `png` file less than 4MB. @@ -419,7 +425,10 @@ def edit( the mask will be applied on the first image. Must be a valid PNG file, less than 4MB, and have the same dimensions as `image`. - model: The model to use for image generation. Defaults to `gpt-image-1.5`. + model: The model to use for image generation. One of `dall-e-2` or a GPT image model + (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`, `gpt-image-2`, + `gpt-image-2-2026-04-21`, or `chatgpt-image-latest`). Defaults to + `gpt-image-1.5`. n: The number of images to generate. Must be between 1 and 10. @@ -580,8 +589,9 @@ def generate( be set to either `png` (default value) or `webp`. model: The model to use for image generation. One of `dall-e-2`, `dall-e-3`, or a GPT - image model (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`). Defaults to - `dall-e-2` unless a parameter specific to the GPT image models is used. + image model (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`, `gpt-image-2`, + or `gpt-image-2-2026-04-21`). Defaults to `dall-e-2` unless a parameter specific + to the GPT image models is used. moderation: Control the content-moderation level for images generated by the GPT image models. Must be either `low` for less restrictive filtering or `auto` (default @@ -695,8 +705,9 @@ def generate( be set to either `png` (default value) or `webp`. model: The model to use for image generation. One of `dall-e-2`, `dall-e-3`, or a GPT - image model (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`). Defaults to - `dall-e-2` unless a parameter specific to the GPT image models is used. + image model (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`, `gpt-image-2`, + or `gpt-image-2-2026-04-21`). Defaults to `dall-e-2` unless a parameter specific + to the GPT image models is used. moderation: Control the content-moderation level for images generated by the GPT image models. Must be either `low` for less restrictive filtering or `auto` (default @@ -806,8 +817,9 @@ def generate( be set to either `png` (default value) or `webp`. model: The model to use for image generation. One of `dall-e-2`, `dall-e-3`, or a GPT - image model (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`). Defaults to - `dall-e-2` unless a parameter specific to the GPT image models is used. + image model (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`, `gpt-image-2`, + or `gpt-image-2-2026-04-21`). Defaults to `dall-e-2` unless a parameter specific + to the GPT image models is used. moderation: Control the content-moderation level for images generated by the GPT image models. Must be either `low` for less restrictive filtering or `auto` (default @@ -1066,10 +1078,10 @@ async def edit( Args: image: The image(s) to edit. Must be a supported image file or an array of images. - For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, and - `gpt-image-1.5`), each image should be a `png`, `webp`, or `jpg` file less than - 50MB. You can provide up to 16 images. `chatgpt-image-latest` follows the same - input constraints as GPT image models. + For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`, + `gpt-image-2`, `gpt-image-2-2026-04-21`, and `chatgpt-image-latest`), each image + should be a `png`, `webp`, or `jpg` file less than 50MB. You can provide up to + 16 images. For `dall-e-2`, you can only provide one image, and it should be a square `png` file less than 4MB. @@ -1095,7 +1107,10 @@ async def edit( the mask will be applied on the first image. Must be a valid PNG file, less than 4MB, and have the same dimensions as `image`. - model: The model to use for image generation. Defaults to `gpt-image-1.5`. + model: The model to use for image generation. One of `dall-e-2` or a GPT image model + (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`, `gpt-image-2`, + `gpt-image-2-2026-04-21`, or `chatgpt-image-latest`). Defaults to + `gpt-image-1.5`. n: The number of images to generate. Must be between 1 and 10. @@ -1179,10 +1194,10 @@ async def edit( Args: image: The image(s) to edit. Must be a supported image file or an array of images. - For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, and - `gpt-image-1.5`), each image should be a `png`, `webp`, or `jpg` file less than - 50MB. You can provide up to 16 images. `chatgpt-image-latest` follows the same - input constraints as GPT image models. + For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`, + `gpt-image-2`, `gpt-image-2-2026-04-21`, and `chatgpt-image-latest`), each image + should be a `png`, `webp`, or `jpg` file less than 50MB. You can provide up to + 16 images. For `dall-e-2`, you can only provide one image, and it should be a square `png` file less than 4MB. @@ -1212,7 +1227,10 @@ async def edit( the mask will be applied on the first image. Must be a valid PNG file, less than 4MB, and have the same dimensions as `image`. - model: The model to use for image generation. Defaults to `gpt-image-1.5`. + model: The model to use for image generation. One of `dall-e-2` or a GPT image model + (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`, `gpt-image-2`, + `gpt-image-2-2026-04-21`, or `chatgpt-image-latest`). Defaults to + `gpt-image-1.5`. n: The number of images to generate. Must be between 1 and 10. @@ -1292,10 +1310,10 @@ async def edit( Args: image: The image(s) to edit. Must be a supported image file or an array of images. - For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, and - `gpt-image-1.5`), each image should be a `png`, `webp`, or `jpg` file less than - 50MB. You can provide up to 16 images. `chatgpt-image-latest` follows the same - input constraints as GPT image models. + For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`, + `gpt-image-2`, `gpt-image-2-2026-04-21`, and `chatgpt-image-latest`), each image + should be a `png`, `webp`, or `jpg` file less than 50MB. You can provide up to + 16 images. For `dall-e-2`, you can only provide one image, and it should be a square `png` file less than 4MB. @@ -1325,7 +1343,10 @@ async def edit( the mask will be applied on the first image. Must be a valid PNG file, less than 4MB, and have the same dimensions as `image`. - model: The model to use for image generation. Defaults to `gpt-image-1.5`. + model: The model to use for image generation. One of `dall-e-2` or a GPT image model + (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`, `gpt-image-2`, + `gpt-image-2-2026-04-21`, or `chatgpt-image-latest`). Defaults to + `gpt-image-1.5`. n: The number of images to generate. Must be between 1 and 10. @@ -1486,8 +1507,9 @@ async def generate( be set to either `png` (default value) or `webp`. model: The model to use for image generation. One of `dall-e-2`, `dall-e-3`, or a GPT - image model (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`). Defaults to - `dall-e-2` unless a parameter specific to the GPT image models is used. + image model (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`, `gpt-image-2`, + or `gpt-image-2-2026-04-21`). Defaults to `dall-e-2` unless a parameter specific + to the GPT image models is used. moderation: Control the content-moderation level for images generated by the GPT image models. Must be either `low` for less restrictive filtering or `auto` (default @@ -1601,8 +1623,9 @@ async def generate( be set to either `png` (default value) or `webp`. model: The model to use for image generation. One of `dall-e-2`, `dall-e-3`, or a GPT - image model (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`). Defaults to - `dall-e-2` unless a parameter specific to the GPT image models is used. + image model (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`, `gpt-image-2`, + or `gpt-image-2-2026-04-21`). Defaults to `dall-e-2` unless a parameter specific + to the GPT image models is used. moderation: Control the content-moderation level for images generated by the GPT image models. Must be either `low` for less restrictive filtering or `auto` (default @@ -1712,8 +1735,9 @@ async def generate( be set to either `png` (default value) or `webp`. model: The model to use for image generation. One of `dall-e-2`, `dall-e-3`, or a GPT - image model (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`). Defaults to - `dall-e-2` unless a parameter specific to the GPT image models is used. + image model (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`, `gpt-image-2`, + or `gpt-image-2-2026-04-21`). Defaults to `dall-e-2` unless a parameter specific + to the GPT image models is used. moderation: Control the content-moderation level for images generated by the GPT image models. Must be either `low` for less restrictive filtering or `auto` (default diff --git a/src/openai/types/image_edit_params.py b/src/openai/types/image_edit_params.py index 05f3401d2d..ab70789fe6 100644 --- a/src/openai/types/image_edit_params.py +++ b/src/openai/types/image_edit_params.py @@ -15,10 +15,10 @@ class ImageEditParamsBase(TypedDict, total=False): image: Required[Union[FileTypes, SequenceNotStr[FileTypes]]] """The image(s) to edit. Must be a supported image file or an array of images. - For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, and - `gpt-image-1.5`), each image should be a `png`, `webp`, or `jpg` file less than - 50MB. You can provide up to 16 images. `chatgpt-image-latest` follows the same - input constraints as GPT image models. + For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`, + `gpt-image-2`, `gpt-image-2-2026-04-21`, and `chatgpt-image-latest`), each image + should be a `png`, `webp`, or `jpg` file less than 50MB. You can provide up to + 16 images. For `dall-e-2`, you can only provide one image, and it should be a square `png` file less than 4MB. @@ -59,7 +59,12 @@ class ImageEditParamsBase(TypedDict, total=False): """ model: Union[str, ImageModel, None] - """The model to use for image generation. Defaults to `gpt-image-1.5`.""" + """The model to use for image generation. + + One of `dall-e-2` or a GPT image model (`gpt-image-1`, `gpt-image-1-mini`, + `gpt-image-1.5`, `gpt-image-2`, `gpt-image-2-2026-04-21`, or + `chatgpt-image-latest`). Defaults to `gpt-image-1.5`. + """ n: Optional[int] """The number of images to generate. Must be between 1 and 10.""" diff --git a/src/openai/types/image_generate_params.py b/src/openai/types/image_generate_params.py index 7a95b3dd3d..30a514cffb 100644 --- a/src/openai/types/image_generate_params.py +++ b/src/openai/types/image_generate_params.py @@ -33,8 +33,9 @@ class ImageGenerateParamsBase(TypedDict, total=False): """The model to use for image generation. One of `dall-e-2`, `dall-e-3`, or a GPT image model (`gpt-image-1`, - `gpt-image-1-mini`, `gpt-image-1.5`). Defaults to `dall-e-2` unless a parameter - specific to the GPT image models is used. + `gpt-image-1-mini`, `gpt-image-1.5`, `gpt-image-2`, or + `gpt-image-2-2026-04-21`). Defaults to `dall-e-2` unless a parameter specific to + the GPT image models is used. """ moderation: Optional[Literal["low", "auto"]] diff --git a/src/openai/types/image_model.py b/src/openai/types/image_model.py index 8ea486fbb6..4586fdebdf 100644 --- a/src/openai/types/image_model.py +++ b/src/openai/types/image_model.py @@ -4,4 +4,13 @@ __all__ = ["ImageModel"] -ImageModel: TypeAlias = Literal["gpt-image-1.5", "dall-e-2", "dall-e-3", "gpt-image-1", "gpt-image-1-mini"] +ImageModel: TypeAlias = Literal[ + "gpt-image-1", + "gpt-image-1-mini", + "gpt-image-2", + "gpt-image-2-2026-04-21", + "gpt-image-1.5", + "chatgpt-image-latest", + "dall-e-2", + "dall-e-3", +] diff --git a/src/openai/types/realtime/translations/__init__.py b/src/openai/types/realtime/translations/__init__.py new file mode 100644 index 0000000000..f8ee8b14b1 --- /dev/null +++ b/src/openai/types/realtime/translations/__init__.py @@ -0,0 +1,3 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations diff --git a/src/openai/types/responses/tool.py b/src/openai/types/responses/tool.py index 34120a287e..90929123c6 100644 --- a/src/openai/types/responses/tool.py +++ b/src/openai/types/responses/tool.py @@ -267,7 +267,18 @@ class ImageGeneration(BaseModel): Contains `image_url` (string, optional) and `file_id` (string, optional). """ - model: Union[str, Literal["gpt-image-1", "gpt-image-1-mini", "gpt-image-1.5"], None] = None + model: Union[ + str, + Literal[ + "gpt-image-1", + "gpt-image-1-mini", + "gpt-image-2", + "gpt-image-2-2026-04-21", + "gpt-image-1.5", + "chatgpt-image-latest", + ], + None, + ] = None """The image generation model to use. Default: `gpt-image-1`.""" moderation: Optional[Literal["auto", "low"]] = None diff --git a/src/openai/types/responses/tool_param.py b/src/openai/types/responses/tool_param.py index c0f33c4513..8e6c6591a9 100644 --- a/src/openai/types/responses/tool_param.py +++ b/src/openai/types/responses/tool_param.py @@ -267,7 +267,17 @@ class ImageGeneration(TypedDict, total=False): Contains `image_url` (string, optional) and `file_id` (string, optional). """ - model: Union[str, Literal["gpt-image-1", "gpt-image-1-mini", "gpt-image-1.5"]] + model: Union[ + str, + Literal[ + "gpt-image-1", + "gpt-image-1-mini", + "gpt-image-2", + "gpt-image-2-2026-04-21", + "gpt-image-1.5", + "chatgpt-image-latest", + ], + ] """The image generation model to use. Default: `gpt-image-1`.""" moderation: Literal["auto", "low"] diff --git a/tests/api_resources/test_images.py b/tests/api_resources/test_images.py index 13cbc0acb7..6f6e700517 100644 --- a/tests/api_resources/test_images.py +++ b/tests/api_resources/test_images.py @@ -28,7 +28,7 @@ def test_method_create_variation(self, client: OpenAI) -> None: def test_method_create_variation_with_all_params(self, client: OpenAI) -> None: image = client.images.create_variation( image=b"Example data", - model="gpt-image-1.5", + model="gpt-image-1", n=1, response_format="url", size="1024x1024", @@ -76,7 +76,7 @@ def test_method_edit_with_all_params_overload_1(self, client: OpenAI) -> None: background="transparent", input_fidelity="high", mask=b"Example data", - model="gpt-image-1.5", + model="gpt-image-2", n=1, output_compression=100, output_format="png", @@ -133,7 +133,7 @@ def test_method_edit_with_all_params_overload_2(self, client: OpenAI) -> None: background="transparent", input_fidelity="high", mask=b"Example data", - model="gpt-image-1.5", + model="gpt-image-2", n=1, output_compression=100, output_format="png", @@ -184,7 +184,7 @@ def test_method_generate_with_all_params_overload_1(self, client: OpenAI) -> Non image = client.images.generate( prompt="A cute baby sea otter", background="transparent", - model="gpt-image-1.5", + model="gpt-image-2", moderation="low", n=1, output_compression=100, @@ -237,7 +237,7 @@ def test_method_generate_with_all_params_overload_2(self, client: OpenAI) -> Non prompt="A cute baby sea otter", stream=True, background="transparent", - model="gpt-image-1.5", + model="gpt-image-2", moderation="low", n=1, output_compression=100, @@ -293,7 +293,7 @@ async def test_method_create_variation(self, async_client: AsyncOpenAI) -> None: async def test_method_create_variation_with_all_params(self, async_client: AsyncOpenAI) -> None: image = await async_client.images.create_variation( image=b"Example data", - model="gpt-image-1.5", + model="gpt-image-1", n=1, response_format="url", size="1024x1024", @@ -341,7 +341,7 @@ async def test_method_edit_with_all_params_overload_1(self, async_client: AsyncO background="transparent", input_fidelity="high", mask=b"Example data", - model="gpt-image-1.5", + model="gpt-image-2", n=1, output_compression=100, output_format="png", @@ -398,7 +398,7 @@ async def test_method_edit_with_all_params_overload_2(self, async_client: AsyncO background="transparent", input_fidelity="high", mask=b"Example data", - model="gpt-image-1.5", + model="gpt-image-2", n=1, output_compression=100, output_format="png", @@ -449,7 +449,7 @@ async def test_method_generate_with_all_params_overload_1(self, async_client: As image = await async_client.images.generate( prompt="A cute baby sea otter", background="transparent", - model="gpt-image-1.5", + model="gpt-image-2", moderation="low", n=1, output_compression=100, @@ -502,7 +502,7 @@ async def test_method_generate_with_all_params_overload_2(self, async_client: As prompt="A cute baby sea otter", stream=True, background="transparent", - model="gpt-image-1.5", + model="gpt-image-2", moderation="low", n=1, output_compression=100, From 72bf67acbc9f030c20db3d5a1a74ea6d67d55f51 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 5 May 2026 17:11:30 +0000 Subject: [PATCH 726/769] feat(api): manual updates --- .stats.yml | 4 +- src/openai/resources/images.py | 362 ++++++++++++------ src/openai/types/image_edit_params.py | 26 +- src/openai/types/image_generate_params.py | 29 +- .../types/realtime/translations/__init__.py | 3 - src/openai/types/responses/tool.py | 33 +- src/openai/types/responses/tool_param.py | 33 +- 7 files changed, 336 insertions(+), 154 deletions(-) delete mode 100644 src/openai/types/realtime/translations/__init__.py diff --git a/.stats.yml b/.stats.yml index 1dee1de615..e4dba3d576 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 233 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-5ae2eda70e6a4a375842fb8bf3e88deab8e0aad1b3871b86e73274f131bb37ce.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-5002c7ce1688cf372f6c268507494c5e6396f38db8d85d79029d949b7bb06fe3.yml openapi_spec_hash: 92713b0825f6b8760836778e6d27e837 -config_hash: c15a744b2771a3948032b2438475b330 +config_hash: c6cf65d9b19a16ce4313602a2204d48f diff --git a/src/openai/resources/images.py b/src/openai/resources/images.py index 1b3ade12c9..6ac622ee1e 100644 --- a/src/openai/resources/images.py +++ b/src/openai/resources/images.py @@ -141,7 +141,7 @@ def edit( partial_images: Optional[int] | Omit = omit, quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | Omit = omit, response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] | Omit = omit, + size: Optional[str] | Omit = omit, stream: Optional[Literal[False]] | Omit = omit, user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -172,9 +172,14 @@ def edit( characters for `dall-e-2`, and 32000 characters for the GPT image models. background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for the GPT image models. Must be one of - `transparent`, `opaque` or `auto` (default value). When `auto` is used, the - model will automatically determine the best background for the image. + parameter is only supported for GPT image models that support transparent + backgrounds. Must be one of `transparent`, `opaque`, or `auto` (default value). + When `auto` is used, the model will automatically determine the best background + for the image. + + `gpt-image-2` and `gpt-image-2-2026-04-21` do not support transparent + backgrounds. Requests with `background` set to `transparent` will return an + error for these models; use `opaque` or `auto` instead. If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. @@ -219,9 +224,17 @@ def edit( generated. This parameter is only supported for `dall-e-2` (default is `url` for `dall-e-2`), as GPT image models always return base64-encoded images. - size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image - models, and one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`. + size: The size of the generated images. For `gpt-image-2` and + `gpt-image-2-2026-04-21`, arbitrary resolutions are supported as `WIDTHxHEIGHT` + strings, for example `1536x864`. Width and height must both be divisible by 16 + and the requested aspect ratio must be between 1:3 and 3:1. Resolutions above + `2560x1440` are experimental, and the maximum supported resolution is + `3840x2160`. The requested size must also satisfy the model's current pixel and + edge limits. The standard sizes `1024x1024`, `1536x1024`, and `1024x1536` are + supported by the GPT image models; `auto` is supported for models that allow + automatic sizing. For `dall-e-2`, use one of `256x256`, `512x512`, or + `1024x1024`. For `dall-e-3`, use one of `1024x1024`, `1792x1024`, or + `1024x1792`. stream: Edit the image in streaming mode. Defaults to `false`. See the [Image generation guide](https://platform.openai.com/docs/guides/image-generation) @@ -258,7 +271,7 @@ def edit( partial_images: Optional[int] | Omit = omit, quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | Omit = omit, response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] | Omit = omit, + size: Optional[str] | Omit = omit, user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -292,9 +305,14 @@ def edit( for more information. background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for the GPT image models. Must be one of - `transparent`, `opaque` or `auto` (default value). When `auto` is used, the - model will automatically determine the best background for the image. + parameter is only supported for GPT image models that support transparent + backgrounds. Must be one of `transparent`, `opaque`, or `auto` (default value). + When `auto` is used, the model will automatically determine the best background + for the image. + + `gpt-image-2` and `gpt-image-2-2026-04-21` do not support transparent + backgrounds. Requests with `background` set to `transparent` will return an + error for these models; use `opaque` or `auto` instead. If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. @@ -339,9 +357,17 @@ def edit( generated. This parameter is only supported for `dall-e-2` (default is `url` for `dall-e-2`), as GPT image models always return base64-encoded images. - size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image - models, and one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`. + size: The size of the generated images. For `gpt-image-2` and + `gpt-image-2-2026-04-21`, arbitrary resolutions are supported as `WIDTHxHEIGHT` + strings, for example `1536x864`. Width and height must both be divisible by 16 + and the requested aspect ratio must be between 1:3 and 3:1. Resolutions above + `2560x1440` are experimental, and the maximum supported resolution is + `3840x2160`. The requested size must also satisfy the model's current pixel and + edge limits. The standard sizes `1024x1024`, `1536x1024`, and `1024x1536` are + supported by the GPT image models; `auto` is supported for models that allow + automatic sizing. For `dall-e-2`, use one of `256x256`, `512x512`, or + `1024x1024`. For `dall-e-3`, use one of `1024x1024`, `1792x1024`, or + `1024x1792`. user: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. @@ -374,7 +400,7 @@ def edit( partial_images: Optional[int] | Omit = omit, quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | Omit = omit, response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] | Omit = omit, + size: Optional[str] | Omit = omit, user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -408,9 +434,14 @@ def edit( for more information. background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for the GPT image models. Must be one of - `transparent`, `opaque` or `auto` (default value). When `auto` is used, the - model will automatically determine the best background for the image. + parameter is only supported for GPT image models that support transparent + backgrounds. Must be one of `transparent`, `opaque`, or `auto` (default value). + When `auto` is used, the model will automatically determine the best background + for the image. + + `gpt-image-2` and `gpt-image-2-2026-04-21` do not support transparent + backgrounds. Requests with `background` set to `transparent` will return an + error for these models; use `opaque` or `auto` instead. If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. @@ -455,9 +486,17 @@ def edit( generated. This parameter is only supported for `dall-e-2` (default is `url` for `dall-e-2`), as GPT image models always return base64-encoded images. - size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image - models, and one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`. + size: The size of the generated images. For `gpt-image-2` and + `gpt-image-2-2026-04-21`, arbitrary resolutions are supported as `WIDTHxHEIGHT` + strings, for example `1536x864`. Width and height must both be divisible by 16 + and the requested aspect ratio must be between 1:3 and 3:1. Resolutions above + `2560x1440` are experimental, and the maximum supported resolution is + `3840x2160`. The requested size must also satisfy the model's current pixel and + edge limits. The standard sizes `1024x1024`, `1536x1024`, and `1024x1536` are + supported by the GPT image models; `auto` is supported for models that allow + automatic sizing. For `dall-e-2`, use one of `256x256`, `512x512`, or + `1024x1024`. For `dall-e-3`, use one of `1024x1024`, `1792x1024`, or + `1024x1792`. user: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. @@ -489,7 +528,7 @@ def edit( partial_images: Optional[int] | Omit = omit, quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | Omit = omit, response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] | Omit = omit, + size: Optional[str] | Omit = omit, stream: Optional[Literal[False]] | Literal[True] | Omit = omit, user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -557,10 +596,7 @@ def generate( partial_images: Optional[int] | Omit = omit, quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | Omit = omit, response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[ - Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] - ] - | Omit = omit, + size: Optional[str] | Omit = omit, stream: Optional[Literal[False]] | Omit = omit, style: Optional[Literal["vivid", "natural"]] | Omit = omit, user: str | Omit = omit, @@ -581,9 +617,14 @@ def generate( characters for `dall-e-3`. background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for the GPT image models. Must be one of - `transparent`, `opaque` or `auto` (default value). When `auto` is used, the - model will automatically determine the best background for the image. + parameter is only supported for GPT image models that support transparent + backgrounds. Must be one of `transparent`, `opaque`, or `auto` (default value). + When `auto` is used, the model will automatically determine the best background + for the image. + + `gpt-image-2` and `gpt-image-2-2026-04-21` do not support transparent + backgrounds. Requests with `background` set to `transparent` will return an + error for these models; use `opaque` or `auto` instead. If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. @@ -627,10 +668,17 @@ def generate( after the image has been generated. This parameter isn't supported for the GPT image models, which always return base64-encoded images. - size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image - models, one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`, and one of - `1024x1024`, `1792x1024`, or `1024x1792` for `dall-e-3`. + size: The size of the generated images. For `gpt-image-2` and + `gpt-image-2-2026-04-21`, arbitrary resolutions are supported as `WIDTHxHEIGHT` + strings, for example `1536x864`. Width and height must both be divisible by 16 + and the requested aspect ratio must be between 1:3 and 3:1. Resolutions above + `2560x1440` are experimental, and the maximum supported resolution is + `3840x2160`. The requested size must also satisfy the model's current pixel and + edge limits. The standard sizes `1024x1024`, `1536x1024`, and `1024x1536` are + supported by the GPT image models; `auto` is supported for models that allow + automatic sizing. For `dall-e-2`, use one of `256x256`, `512x512`, or + `1024x1024`. For `dall-e-3`, use one of `1024x1024`, `1792x1024`, or + `1024x1792`. stream: Generate the image in streaming mode. Defaults to `false`. See the [Image generation guide](https://platform.openai.com/docs/guides/image-generation) @@ -670,10 +718,7 @@ def generate( partial_images: Optional[int] | Omit = omit, quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | Omit = omit, response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[ - Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] - ] - | Omit = omit, + size: Optional[str] | Omit = omit, style: Optional[Literal["vivid", "natural"]] | Omit = omit, user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -697,9 +742,14 @@ def generate( for more information. This parameter is only supported for the GPT image models. background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for the GPT image models. Must be one of - `transparent`, `opaque` or `auto` (default value). When `auto` is used, the - model will automatically determine the best background for the image. + parameter is only supported for GPT image models that support transparent + backgrounds. Must be one of `transparent`, `opaque`, or `auto` (default value). + When `auto` is used, the model will automatically determine the best background + for the image. + + `gpt-image-2` and `gpt-image-2-2026-04-21` do not support transparent + backgrounds. Requests with `background` set to `transparent` will return an + error for these models; use `opaque` or `auto` instead. If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. @@ -743,10 +793,17 @@ def generate( after the image has been generated. This parameter isn't supported for the GPT image models, which always return base64-encoded images. - size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image - models, one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`, and one of - `1024x1024`, `1792x1024`, or `1024x1792` for `dall-e-3`. + size: The size of the generated images. For `gpt-image-2` and + `gpt-image-2-2026-04-21`, arbitrary resolutions are supported as `WIDTHxHEIGHT` + strings, for example `1536x864`. Width and height must both be divisible by 16 + and the requested aspect ratio must be between 1:3 and 3:1. Resolutions above + `2560x1440` are experimental, and the maximum supported resolution is + `3840x2160`. The requested size must also satisfy the model's current pixel and + edge limits. The standard sizes `1024x1024`, `1536x1024`, and `1024x1536` are + supported by the GPT image models; `auto` is supported for models that allow + automatic sizing. For `dall-e-2`, use one of `256x256`, `512x512`, or + `1024x1024`. For `dall-e-3`, use one of `1024x1024`, `1792x1024`, or + `1024x1792`. style: The style of the generated images. This parameter is only supported for `dall-e-3`. Must be one of `vivid` or `natural`. Vivid causes the model to lean @@ -782,10 +839,7 @@ def generate( partial_images: Optional[int] | Omit = omit, quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | Omit = omit, response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[ - Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] - ] - | Omit = omit, + size: Optional[str] | Omit = omit, style: Optional[Literal["vivid", "natural"]] | Omit = omit, user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -809,9 +863,14 @@ def generate( for more information. This parameter is only supported for the GPT image models. background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for the GPT image models. Must be one of - `transparent`, `opaque` or `auto` (default value). When `auto` is used, the - model will automatically determine the best background for the image. + parameter is only supported for GPT image models that support transparent + backgrounds. Must be one of `transparent`, `opaque`, or `auto` (default value). + When `auto` is used, the model will automatically determine the best background + for the image. + + `gpt-image-2` and `gpt-image-2-2026-04-21` do not support transparent + backgrounds. Requests with `background` set to `transparent` will return an + error for these models; use `opaque` or `auto` instead. If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. @@ -855,10 +914,17 @@ def generate( after the image has been generated. This parameter isn't supported for the GPT image models, which always return base64-encoded images. - size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image - models, one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`, and one of - `1024x1024`, `1792x1024`, or `1024x1792` for `dall-e-3`. + size: The size of the generated images. For `gpt-image-2` and + `gpt-image-2-2026-04-21`, arbitrary resolutions are supported as `WIDTHxHEIGHT` + strings, for example `1536x864`. Width and height must both be divisible by 16 + and the requested aspect ratio must be between 1:3 and 3:1. Resolutions above + `2560x1440` are experimental, and the maximum supported resolution is + `3840x2160`. The requested size must also satisfy the model's current pixel and + edge limits. The standard sizes `1024x1024`, `1536x1024`, and `1024x1536` are + supported by the GPT image models; `auto` is supported for models that allow + automatic sizing. For `dall-e-2`, use one of `256x256`, `512x512`, or + `1024x1024`. For `dall-e-3`, use one of `1024x1024`, `1792x1024`, or + `1024x1792`. style: The style of the generated images. This parameter is only supported for `dall-e-3`. Must be one of `vivid` or `natural`. Vivid causes the model to lean @@ -893,10 +959,7 @@ def generate( partial_images: Optional[int] | Omit = omit, quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | Omit = omit, response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[ - Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] - ] - | Omit = omit, + size: Optional[str] | Omit = omit, stream: Optional[Literal[False]] | Literal[True] | Omit = omit, style: Optional[Literal["vivid", "natural"]] | Omit = omit, user: str | Omit = omit, @@ -1059,7 +1122,7 @@ async def edit( partial_images: Optional[int] | Omit = omit, quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | Omit = omit, response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] | Omit = omit, + size: Optional[str] | Omit = omit, stream: Optional[Literal[False]] | Omit = omit, user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -1090,9 +1153,14 @@ async def edit( characters for `dall-e-2`, and 32000 characters for the GPT image models. background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for the GPT image models. Must be one of - `transparent`, `opaque` or `auto` (default value). When `auto` is used, the - model will automatically determine the best background for the image. + parameter is only supported for GPT image models that support transparent + backgrounds. Must be one of `transparent`, `opaque`, or `auto` (default value). + When `auto` is used, the model will automatically determine the best background + for the image. + + `gpt-image-2` and `gpt-image-2-2026-04-21` do not support transparent + backgrounds. Requests with `background` set to `transparent` will return an + error for these models; use `opaque` or `auto` instead. If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. @@ -1137,9 +1205,17 @@ async def edit( generated. This parameter is only supported for `dall-e-2` (default is `url` for `dall-e-2`), as GPT image models always return base64-encoded images. - size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image - models, and one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`. + size: The size of the generated images. For `gpt-image-2` and + `gpt-image-2-2026-04-21`, arbitrary resolutions are supported as `WIDTHxHEIGHT` + strings, for example `1536x864`. Width and height must both be divisible by 16 + and the requested aspect ratio must be between 1:3 and 3:1. Resolutions above + `2560x1440` are experimental, and the maximum supported resolution is + `3840x2160`. The requested size must also satisfy the model's current pixel and + edge limits. The standard sizes `1024x1024`, `1536x1024`, and `1024x1536` are + supported by the GPT image models; `auto` is supported for models that allow + automatic sizing. For `dall-e-2`, use one of `256x256`, `512x512`, or + `1024x1024`. For `dall-e-3`, use one of `1024x1024`, `1792x1024`, or + `1024x1792`. stream: Edit the image in streaming mode. Defaults to `false`. See the [Image generation guide](https://platform.openai.com/docs/guides/image-generation) @@ -1176,7 +1252,7 @@ async def edit( partial_images: Optional[int] | Omit = omit, quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | Omit = omit, response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] | Omit = omit, + size: Optional[str] | Omit = omit, user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -1210,9 +1286,14 @@ async def edit( for more information. background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for the GPT image models. Must be one of - `transparent`, `opaque` or `auto` (default value). When `auto` is used, the - model will automatically determine the best background for the image. + parameter is only supported for GPT image models that support transparent + backgrounds. Must be one of `transparent`, `opaque`, or `auto` (default value). + When `auto` is used, the model will automatically determine the best background + for the image. + + `gpt-image-2` and `gpt-image-2-2026-04-21` do not support transparent + backgrounds. Requests with `background` set to `transparent` will return an + error for these models; use `opaque` or `auto` instead. If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. @@ -1257,9 +1338,17 @@ async def edit( generated. This parameter is only supported for `dall-e-2` (default is `url` for `dall-e-2`), as GPT image models always return base64-encoded images. - size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image - models, and one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`. + size: The size of the generated images. For `gpt-image-2` and + `gpt-image-2-2026-04-21`, arbitrary resolutions are supported as `WIDTHxHEIGHT` + strings, for example `1536x864`. Width and height must both be divisible by 16 + and the requested aspect ratio must be between 1:3 and 3:1. Resolutions above + `2560x1440` are experimental, and the maximum supported resolution is + `3840x2160`. The requested size must also satisfy the model's current pixel and + edge limits. The standard sizes `1024x1024`, `1536x1024`, and `1024x1536` are + supported by the GPT image models; `auto` is supported for models that allow + automatic sizing. For `dall-e-2`, use one of `256x256`, `512x512`, or + `1024x1024`. For `dall-e-3`, use one of `1024x1024`, `1792x1024`, or + `1024x1792`. user: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. @@ -1292,7 +1381,7 @@ async def edit( partial_images: Optional[int] | Omit = omit, quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | Omit = omit, response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] | Omit = omit, + size: Optional[str] | Omit = omit, user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -1326,9 +1415,14 @@ async def edit( for more information. background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for the GPT image models. Must be one of - `transparent`, `opaque` or `auto` (default value). When `auto` is used, the - model will automatically determine the best background for the image. + parameter is only supported for GPT image models that support transparent + backgrounds. Must be one of `transparent`, `opaque`, or `auto` (default value). + When `auto` is used, the model will automatically determine the best background + for the image. + + `gpt-image-2` and `gpt-image-2-2026-04-21` do not support transparent + backgrounds. Requests with `background` set to `transparent` will return an + error for these models; use `opaque` or `auto` instead. If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. @@ -1373,9 +1467,17 @@ async def edit( generated. This parameter is only supported for `dall-e-2` (default is `url` for `dall-e-2`), as GPT image models always return base64-encoded images. - size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image - models, and one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`. + size: The size of the generated images. For `gpt-image-2` and + `gpt-image-2-2026-04-21`, arbitrary resolutions are supported as `WIDTHxHEIGHT` + strings, for example `1536x864`. Width and height must both be divisible by 16 + and the requested aspect ratio must be between 1:3 and 3:1. Resolutions above + `2560x1440` are experimental, and the maximum supported resolution is + `3840x2160`. The requested size must also satisfy the model's current pixel and + edge limits. The standard sizes `1024x1024`, `1536x1024`, and `1024x1536` are + supported by the GPT image models; `auto` is supported for models that allow + automatic sizing. For `dall-e-2`, use one of `256x256`, `512x512`, or + `1024x1024`. For `dall-e-3`, use one of `1024x1024`, `1792x1024`, or + `1024x1792`. user: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. @@ -1407,7 +1509,7 @@ async def edit( partial_images: Optional[int] | Omit = omit, quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | Omit = omit, response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] | Omit = omit, + size: Optional[str] | Omit = omit, stream: Optional[Literal[False]] | Literal[True] | Omit = omit, user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -1475,10 +1577,7 @@ async def generate( partial_images: Optional[int] | Omit = omit, quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | Omit = omit, response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[ - Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] - ] - | Omit = omit, + size: Optional[str] | Omit = omit, stream: Optional[Literal[False]] | Omit = omit, style: Optional[Literal["vivid", "natural"]] | Omit = omit, user: str | Omit = omit, @@ -1499,9 +1598,14 @@ async def generate( characters for `dall-e-3`. background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for the GPT image models. Must be one of - `transparent`, `opaque` or `auto` (default value). When `auto` is used, the - model will automatically determine the best background for the image. + parameter is only supported for GPT image models that support transparent + backgrounds. Must be one of `transparent`, `opaque`, or `auto` (default value). + When `auto` is used, the model will automatically determine the best background + for the image. + + `gpt-image-2` and `gpt-image-2-2026-04-21` do not support transparent + backgrounds. Requests with `background` set to `transparent` will return an + error for these models; use `opaque` or `auto` instead. If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. @@ -1545,10 +1649,17 @@ async def generate( after the image has been generated. This parameter isn't supported for the GPT image models, which always return base64-encoded images. - size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image - models, one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`, and one of - `1024x1024`, `1792x1024`, or `1024x1792` for `dall-e-3`. + size: The size of the generated images. For `gpt-image-2` and + `gpt-image-2-2026-04-21`, arbitrary resolutions are supported as `WIDTHxHEIGHT` + strings, for example `1536x864`. Width and height must both be divisible by 16 + and the requested aspect ratio must be between 1:3 and 3:1. Resolutions above + `2560x1440` are experimental, and the maximum supported resolution is + `3840x2160`. The requested size must also satisfy the model's current pixel and + edge limits. The standard sizes `1024x1024`, `1536x1024`, and `1024x1536` are + supported by the GPT image models; `auto` is supported for models that allow + automatic sizing. For `dall-e-2`, use one of `256x256`, `512x512`, or + `1024x1024`. For `dall-e-3`, use one of `1024x1024`, `1792x1024`, or + `1024x1792`. stream: Generate the image in streaming mode. Defaults to `false`. See the [Image generation guide](https://platform.openai.com/docs/guides/image-generation) @@ -1588,10 +1699,7 @@ async def generate( partial_images: Optional[int] | Omit = omit, quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | Omit = omit, response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[ - Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] - ] - | Omit = omit, + size: Optional[str] | Omit = omit, style: Optional[Literal["vivid", "natural"]] | Omit = omit, user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -1615,9 +1723,14 @@ async def generate( for more information. This parameter is only supported for the GPT image models. background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for the GPT image models. Must be one of - `transparent`, `opaque` or `auto` (default value). When `auto` is used, the - model will automatically determine the best background for the image. + parameter is only supported for GPT image models that support transparent + backgrounds. Must be one of `transparent`, `opaque`, or `auto` (default value). + When `auto` is used, the model will automatically determine the best background + for the image. + + `gpt-image-2` and `gpt-image-2-2026-04-21` do not support transparent + backgrounds. Requests with `background` set to `transparent` will return an + error for these models; use `opaque` or `auto` instead. If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. @@ -1661,10 +1774,17 @@ async def generate( after the image has been generated. This parameter isn't supported for the GPT image models, which always return base64-encoded images. - size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image - models, one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`, and one of - `1024x1024`, `1792x1024`, or `1024x1792` for `dall-e-3`. + size: The size of the generated images. For `gpt-image-2` and + `gpt-image-2-2026-04-21`, arbitrary resolutions are supported as `WIDTHxHEIGHT` + strings, for example `1536x864`. Width and height must both be divisible by 16 + and the requested aspect ratio must be between 1:3 and 3:1. Resolutions above + `2560x1440` are experimental, and the maximum supported resolution is + `3840x2160`. The requested size must also satisfy the model's current pixel and + edge limits. The standard sizes `1024x1024`, `1536x1024`, and `1024x1536` are + supported by the GPT image models; `auto` is supported for models that allow + automatic sizing. For `dall-e-2`, use one of `256x256`, `512x512`, or + `1024x1024`. For `dall-e-3`, use one of `1024x1024`, `1792x1024`, or + `1024x1792`. style: The style of the generated images. This parameter is only supported for `dall-e-3`. Must be one of `vivid` or `natural`. Vivid causes the model to lean @@ -1700,10 +1820,7 @@ async def generate( partial_images: Optional[int] | Omit = omit, quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | Omit = omit, response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[ - Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] - ] - | Omit = omit, + size: Optional[str] | Omit = omit, style: Optional[Literal["vivid", "natural"]] | Omit = omit, user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -1727,9 +1844,14 @@ async def generate( for more information. This parameter is only supported for the GPT image models. background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for the GPT image models. Must be one of - `transparent`, `opaque` or `auto` (default value). When `auto` is used, the - model will automatically determine the best background for the image. + parameter is only supported for GPT image models that support transparent + backgrounds. Must be one of `transparent`, `opaque`, or `auto` (default value). + When `auto` is used, the model will automatically determine the best background + for the image. + + `gpt-image-2` and `gpt-image-2-2026-04-21` do not support transparent + backgrounds. Requests with `background` set to `transparent` will return an + error for these models; use `opaque` or `auto` instead. If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. @@ -1773,10 +1895,17 @@ async def generate( after the image has been generated. This parameter isn't supported for the GPT image models, which always return base64-encoded images. - size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image - models, one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`, and one of - `1024x1024`, `1792x1024`, or `1024x1792` for `dall-e-3`. + size: The size of the generated images. For `gpt-image-2` and + `gpt-image-2-2026-04-21`, arbitrary resolutions are supported as `WIDTHxHEIGHT` + strings, for example `1536x864`. Width and height must both be divisible by 16 + and the requested aspect ratio must be between 1:3 and 3:1. Resolutions above + `2560x1440` are experimental, and the maximum supported resolution is + `3840x2160`. The requested size must also satisfy the model's current pixel and + edge limits. The standard sizes `1024x1024`, `1536x1024`, and `1024x1536` are + supported by the GPT image models; `auto` is supported for models that allow + automatic sizing. For `dall-e-2`, use one of `256x256`, `512x512`, or + `1024x1024`. For `dall-e-3`, use one of `1024x1024`, `1792x1024`, or + `1024x1792`. style: The style of the generated images. This parameter is only supported for `dall-e-3`. Must be one of `vivid` or `natural`. Vivid causes the model to lean @@ -1811,10 +1940,7 @@ async def generate( partial_images: Optional[int] | Omit = omit, quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | Omit = omit, response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[ - Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] - ] - | Omit = omit, + size: Optional[str] | Omit = omit, stream: Optional[Literal[False]] | Literal[True] | Omit = omit, style: Optional[Literal["vivid", "natural"]] | Omit = omit, user: str | Omit = omit, diff --git a/src/openai/types/image_edit_params.py b/src/openai/types/image_edit_params.py index ab70789fe6..3c0e41d572 100644 --- a/src/openai/types/image_edit_params.py +++ b/src/openai/types/image_edit_params.py @@ -34,9 +34,14 @@ class ImageEditParamsBase(TypedDict, total=False): background: Optional[Literal["transparent", "opaque", "auto"]] """ Allows to set transparency for the background of the generated image(s). This - parameter is only supported for the GPT image models. Must be one of - `transparent`, `opaque` or `auto` (default value). When `auto` is used, the - model will automatically determine the best background for the image. + parameter is only supported for GPT image models that support transparent + backgrounds. Must be one of `transparent`, `opaque`, or `auto` (default value). + When `auto` is used, the model will automatically determine the best background + for the image. + + `gpt-image-2` and `gpt-image-2-2026-04-21` do not support transparent + backgrounds. Requests with `background` set to `transparent` will return an + error for these models; use `opaque` or `auto` instead. If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. @@ -109,12 +114,19 @@ class ImageEditParamsBase(TypedDict, total=False): base64-encoded images. """ - size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] + size: Optional[str] """The size of the generated images. - Must be one of `1024x1024`, `1536x1024` (landscape), `1024x1536` (portrait), or - `auto` (default value) for the GPT image models, and one of `256x256`, - `512x512`, or `1024x1024` for `dall-e-2`. + For `gpt-image-2` and `gpt-image-2-2026-04-21`, arbitrary resolutions are + supported as `WIDTHxHEIGHT` strings, for example `1536x864`. Width and height + must both be divisible by 16 and the requested aspect ratio must be between 1:3 + and 3:1. Resolutions above `2560x1440` are experimental, and the maximum + supported resolution is `3840x2160`. The requested size must also satisfy the + model's current pixel and edge limits. The standard sizes `1024x1024`, + `1536x1024`, and `1024x1536` are supported by the GPT image models; `auto` is + supported for models that allow automatic sizing. For `dall-e-2`, use one of + `256x256`, `512x512`, or `1024x1024`. For `dall-e-3`, use one of `1024x1024`, + `1792x1024`, or `1024x1792`. """ user: str diff --git a/src/openai/types/image_generate_params.py b/src/openai/types/image_generate_params.py index 30a514cffb..4ac573ce61 100644 --- a/src/openai/types/image_generate_params.py +++ b/src/openai/types/image_generate_params.py @@ -21,9 +21,14 @@ class ImageGenerateParamsBase(TypedDict, total=False): background: Optional[Literal["transparent", "opaque", "auto"]] """ Allows to set transparency for the background of the generated image(s). This - parameter is only supported for the GPT image models. Must be one of - `transparent`, `opaque` or `auto` (default value). When `auto` is used, the - model will automatically determine the best background for the image. + parameter is only supported for GPT image models that support transparent + backgrounds. Must be one of `transparent`, `opaque`, or `auto` (default value). + When `auto` is used, the model will automatically determine the best background + for the image. + + `gpt-image-2` and `gpt-image-2-2026-04-21` do not support transparent + backgrounds. Requests with `background` set to `transparent` will return an + error for these models; use `opaque` or `auto` instead. If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. @@ -95,15 +100,19 @@ class ImageGenerateParamsBase(TypedDict, total=False): models, which always return base64-encoded images. """ - size: Optional[ - Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] - ] + size: Optional[str] """The size of the generated images. - Must be one of `1024x1024`, `1536x1024` (landscape), `1024x1536` (portrait), or - `auto` (default value) for the GPT image models, one of `256x256`, `512x512`, or - `1024x1024` for `dall-e-2`, and one of `1024x1024`, `1792x1024`, or `1024x1792` - for `dall-e-3`. + For `gpt-image-2` and `gpt-image-2-2026-04-21`, arbitrary resolutions are + supported as `WIDTHxHEIGHT` strings, for example `1536x864`. Width and height + must both be divisible by 16 and the requested aspect ratio must be between 1:3 + and 3:1. Resolutions above `2560x1440` are experimental, and the maximum + supported resolution is `3840x2160`. The requested size must also satisfy the + model's current pixel and edge limits. The standard sizes `1024x1024`, + `1536x1024`, and `1024x1536` are supported by the GPT image models; `auto` is + supported for models that allow automatic sizing. For `dall-e-2`, use one of + `256x256`, `512x512`, or `1024x1024`. For `dall-e-3`, use one of `1024x1024`, + `1792x1024`, or `1024x1792`. """ style: Optional[Literal["vivid", "natural"]] diff --git a/src/openai/types/realtime/translations/__init__.py b/src/openai/types/realtime/translations/__init__.py deleted file mode 100644 index f8ee8b14b1..0000000000 --- a/src/openai/types/realtime/translations/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations diff --git a/src/openai/types/responses/tool.py b/src/openai/types/responses/tool.py index 90929123c6..839ed26ba2 100644 --- a/src/openai/types/responses/tool.py +++ b/src/openai/types/responses/tool.py @@ -248,9 +248,19 @@ class ImageGeneration(BaseModel): """Whether to generate a new image or edit an existing image. Default: `auto`.""" background: Optional[Literal["transparent", "opaque", "auto"]] = None - """Background type for the generated image. - - One of `transparent`, `opaque`, or `auto`. Default: `auto`. + """ + Allows to set transparency for the background of the generated image(s). This + parameter is only supported for GPT image models that support transparent + backgrounds. Must be one of `transparent`, `opaque`, or `auto` (default value). + When `auto` is used, the model will automatically determine the best background + for the image. + + `gpt-image-2` and `gpt-image-2-2026-04-21` do not support transparent + backgrounds. Requests with `background` set to `transparent` will return an + error for these models; use `opaque` or `auto` instead. + + If `transparent`, the output format needs to support transparency, so it should + be set to either `png` (default value) or `webp`. """ input_fidelity: Optional[Literal["high", "low"]] = None @@ -305,10 +315,19 @@ class ImageGeneration(BaseModel): One of `low`, `medium`, `high`, or `auto`. Default: `auto`. """ - size: Optional[Literal["1024x1024", "1024x1536", "1536x1024", "auto"]] = None - """The size of the generated image. - - One of `1024x1024`, `1024x1536`, `1536x1024`, or `auto`. Default: `auto`. + size: Optional[str] = None + """The size of the generated images. + + For `gpt-image-2` and `gpt-image-2-2026-04-21`, arbitrary resolutions are + supported as `WIDTHxHEIGHT` strings, for example `1536x864`. Width and height + must both be divisible by 16 and the requested aspect ratio must be between 1:3 + and 3:1. Resolutions above `2560x1440` are experimental, and the maximum + supported resolution is `3840x2160`. The requested size must also satisfy the + model's current pixel and edge limits. The standard sizes `1024x1024`, + `1536x1024`, and `1024x1536` are supported by the GPT image models; `auto` is + supported for models that allow automatic sizing. For `dall-e-2`, use one of + `256x256`, `512x512`, or `1024x1024`. For `dall-e-3`, use one of `1024x1024`, + `1792x1024`, or `1024x1792`. """ diff --git a/src/openai/types/responses/tool_param.py b/src/openai/types/responses/tool_param.py index 8e6c6591a9..cdbf5bd1ff 100644 --- a/src/openai/types/responses/tool_param.py +++ b/src/openai/types/responses/tool_param.py @@ -248,9 +248,19 @@ class ImageGeneration(TypedDict, total=False): """Whether to generate a new image or edit an existing image. Default: `auto`.""" background: Literal["transparent", "opaque", "auto"] - """Background type for the generated image. - - One of `transparent`, `opaque`, or `auto`. Default: `auto`. + """ + Allows to set transparency for the background of the generated image(s). This + parameter is only supported for GPT image models that support transparent + backgrounds. Must be one of `transparent`, `opaque`, or `auto` (default value). + When `auto` is used, the model will automatically determine the best background + for the image. + + `gpt-image-2` and `gpt-image-2-2026-04-21` do not support transparent + backgrounds. Requests with `background` set to `transparent` will return an + error for these models; use `opaque` or `auto` instead. + + If `transparent`, the output format needs to support transparency, so it should + be set to either `png` (default value) or `webp`. """ input_fidelity: Optional[Literal["high", "low"]] @@ -304,10 +314,19 @@ class ImageGeneration(TypedDict, total=False): One of `low`, `medium`, `high`, or `auto`. Default: `auto`. """ - size: Literal["1024x1024", "1024x1536", "1536x1024", "auto"] - """The size of the generated image. - - One of `1024x1024`, `1024x1536`, `1536x1024`, or `auto`. Default: `auto`. + size: str + """The size of the generated images. + + For `gpt-image-2` and `gpt-image-2-2026-04-21`, arbitrary resolutions are + supported as `WIDTHxHEIGHT` strings, for example `1536x864`. Width and height + must both be divisible by 16 and the requested aspect ratio must be between 1:3 + and 3:1. Resolutions above `2560x1440` are experimental, and the maximum + supported resolution is `3840x2160`. The requested size must also satisfy the + model's current pixel and edge limits. The standard sizes `1024x1024`, + `1536x1024`, and `1024x1536` are supported by the GPT image models; `auto` is + supported for models that allow automatic sizing. For `dall-e-2`, use one of + `256x256`, `512x512`, or `1024x1024`. For `dall-e-3`, use one of `1024x1024`, + `1792x1024`, or `1024x1792`. """ From f9d339fcea63feaa1bdf918a4599f2b032c83517 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 6 May 2026 08:58:03 +0000 Subject: [PATCH 727/769] docs(api): update top_logprobs parameter description across chat and responses --- .stats.yml | 4 +-- .../resources/chat/completions/completions.py | 30 +++++++++++-------- src/openai/resources/responses/responses.py | 30 +++++++++++-------- .../usage_audio_speeches_response.py | 6 ++++ .../usage_audio_transcriptions_response.py | 6 ++++ ...sage_code_interpreter_sessions_response.py | 6 ++++ .../usage_completions_response.py | 6 ++++ .../organization/usage_costs_response.py | 6 ++++ .../organization/usage_embeddings_response.py | 6 ++++ .../organization/usage_images_response.py | 6 ++++ .../usage_moderations_response.py | 6 ++++ .../usage_vector_stores_response.py | 6 ++++ .../chat/chat_completion_token_logprob.py | 3 +- .../types/chat/completion_create_params.py | 5 ++-- src/openai/types/responses/response.py | 5 ++-- .../types/responses/response_create_params.py | 5 ++-- .../responses/response_text_delta_event.py | 2 +- .../responses/response_text_done_event.py | 2 +- .../types/responses/responses_client_event.py | 5 ++-- .../responses/responses_client_event_param.py | 5 ++-- 20 files changed, 110 insertions(+), 40 deletions(-) diff --git a/.stats.yml b/.stats.yml index e4dba3d576..201feabd36 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 233 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-5002c7ce1688cf372f6c268507494c5e6396f38db8d85d79029d949b7bb06fe3.yml -openapi_spec_hash: 92713b0825f6b8760836778e6d27e837 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-578515408e7ee6ac115f3768b358ff2cd4f5699cbfb527fe58b19806e7d1f713.yml +openapi_spec_hash: b2df68d6233a18b475590978f5682c04 config_hash: c6cf65d9b19a16ce4313602a2204d48f diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index 7a551e2459..c85ac45cdb 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -516,8 +516,9 @@ def create( [custom tools](https://platform.openai.com/docs/guides/function-calling#custom-tools) or [function tools](https://platform.openai.com/docs/guides/function-calling). - top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to - return at each token position, each with an associated log probability. + top_logprobs: An integer between 0 and 20 specifying the maximum number of most likely tokens + to return at each token position, each with an associated log probability. In + some cases, the number of returned tokens may be fewer than requested. `logprobs` must be set to `true` if this parameter is used. top_p: An alternative to sampling with temperature, called nucleus sampling, where the @@ -822,8 +823,9 @@ def create( [custom tools](https://platform.openai.com/docs/guides/function-calling#custom-tools) or [function tools](https://platform.openai.com/docs/guides/function-calling). - top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to - return at each token position, each with an associated log probability. + top_logprobs: An integer between 0 and 20 specifying the maximum number of most likely tokens + to return at each token position, each with an associated log probability. In + some cases, the number of returned tokens may be fewer than requested. `logprobs` must be set to `true` if this parameter is used. top_p: An alternative to sampling with temperature, called nucleus sampling, where the @@ -1128,8 +1130,9 @@ def create( [custom tools](https://platform.openai.com/docs/guides/function-calling#custom-tools) or [function tools](https://platform.openai.com/docs/guides/function-calling). - top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to - return at each token position, each with an associated log probability. + top_logprobs: An integer between 0 and 20 specifying the maximum number of most likely tokens + to return at each token position, each with an associated log probability. In + some cases, the number of returned tokens may be fewer than requested. `logprobs` must be set to `true` if this parameter is used. top_p: An alternative to sampling with temperature, called nucleus sampling, where the @@ -2037,8 +2040,9 @@ async def create( [custom tools](https://platform.openai.com/docs/guides/function-calling#custom-tools) or [function tools](https://platform.openai.com/docs/guides/function-calling). - top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to - return at each token position, each with an associated log probability. + top_logprobs: An integer between 0 and 20 specifying the maximum number of most likely tokens + to return at each token position, each with an associated log probability. In + some cases, the number of returned tokens may be fewer than requested. `logprobs` must be set to `true` if this parameter is used. top_p: An alternative to sampling with temperature, called nucleus sampling, where the @@ -2343,8 +2347,9 @@ async def create( [custom tools](https://platform.openai.com/docs/guides/function-calling#custom-tools) or [function tools](https://platform.openai.com/docs/guides/function-calling). - top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to - return at each token position, each with an associated log probability. + top_logprobs: An integer between 0 and 20 specifying the maximum number of most likely tokens + to return at each token position, each with an associated log probability. In + some cases, the number of returned tokens may be fewer than requested. `logprobs` must be set to `true` if this parameter is used. top_p: An alternative to sampling with temperature, called nucleus sampling, where the @@ -2649,8 +2654,9 @@ async def create( [custom tools](https://platform.openai.com/docs/guides/function-calling#custom-tools) or [function tools](https://platform.openai.com/docs/guides/function-calling). - top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to - return at each token position, each with an associated log probability. + top_logprobs: An integer between 0 and 20 specifying the maximum number of most likely tokens + to return at each token position, each with an associated log probability. In + some cases, the number of returned tokens may be fewer than requested. `logprobs` must be set to `true` if this parameter is used. top_p: An alternative to sampling with temperature, called nucleus sampling, where the diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index c0f9855bcf..4b8bd9af21 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -344,8 +344,9 @@ def create( [function calling](https://platform.openai.com/docs/guides/function-calling). You can also use custom tools to call your own code. - top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to - return at each token position, each with an associated log probability. + top_logprobs: An integer between 0 and 20 specifying the maximum number of most likely tokens + to return at each token position, each with an associated log probability. In + some cases, the number of returned tokens may be fewer than requested. top_p: An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 @@ -593,8 +594,9 @@ def create( [function calling](https://platform.openai.com/docs/guides/function-calling). You can also use custom tools to call your own code. - top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to - return at each token position, each with an associated log probability. + top_logprobs: An integer between 0 and 20 specifying the maximum number of most likely tokens + to return at each token position, each with an associated log probability. In + some cases, the number of returned tokens may be fewer than requested. top_p: An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 @@ -842,8 +844,9 @@ def create( [function calling](https://platform.openai.com/docs/guides/function-calling). You can also use custom tools to call your own code. - top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to - return at each token position, each with an associated log probability. + top_logprobs: An integer between 0 and 20 specifying the maximum number of most likely tokens + to return at each token position, each with an associated log probability. In + some cases, the number of returned tokens may be fewer than requested. top_p: An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 @@ -2043,8 +2046,9 @@ async def create( [function calling](https://platform.openai.com/docs/guides/function-calling). You can also use custom tools to call your own code. - top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to - return at each token position, each with an associated log probability. + top_logprobs: An integer between 0 and 20 specifying the maximum number of most likely tokens + to return at each token position, each with an associated log probability. In + some cases, the number of returned tokens may be fewer than requested. top_p: An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 @@ -2292,8 +2296,9 @@ async def create( [function calling](https://platform.openai.com/docs/guides/function-calling). You can also use custom tools to call your own code. - top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to - return at each token position, each with an associated log probability. + top_logprobs: An integer between 0 and 20 specifying the maximum number of most likely tokens + to return at each token position, each with an associated log probability. In + some cases, the number of returned tokens may be fewer than requested. top_p: An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 @@ -2541,8 +2546,9 @@ async def create( [function calling](https://platform.openai.com/docs/guides/function-calling). You can also use custom tools to call your own code. - top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to - return at each token position, each with an associated log probability. + top_logprobs: An integer between 0 and 20 specifying the maximum number of most likely tokens + to return at each token position, each with an associated log probability. In + some cases, the number of returned tokens may be fewer than requested. top_p: An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 diff --git a/src/openai/types/admin/organization/usage_audio_speeches_response.py b/src/openai/types/admin/organization/usage_audio_speeches_response.py index 90e17c89b0..e5fed36b03 100644 --- a/src/openai/types/admin/organization/usage_audio_speeches_response.py +++ b/src/openai/types/admin/organization/usage_audio_speeches_response.py @@ -353,6 +353,12 @@ class DataResultOrganizationCostsResult(BaseModel): costs result. """ + quantity: Optional[float] = None + """ + When `group_by=line_item`, this field provides the quantity of the grouped costs + result. + """ + DataResult: TypeAlias = Annotated[ Union[ diff --git a/src/openai/types/admin/organization/usage_audio_transcriptions_response.py b/src/openai/types/admin/organization/usage_audio_transcriptions_response.py index abd7c3fb90..c5b77f34e1 100644 --- a/src/openai/types/admin/organization/usage_audio_transcriptions_response.py +++ b/src/openai/types/admin/organization/usage_audio_transcriptions_response.py @@ -353,6 +353,12 @@ class DataResultOrganizationCostsResult(BaseModel): costs result. """ + quantity: Optional[float] = None + """ + When `group_by=line_item`, this field provides the quantity of the grouped costs + result. + """ + DataResult: TypeAlias = Annotated[ Union[ diff --git a/src/openai/types/admin/organization/usage_code_interpreter_sessions_response.py b/src/openai/types/admin/organization/usage_code_interpreter_sessions_response.py index 0cd6c2693c..aafda6f113 100644 --- a/src/openai/types/admin/organization/usage_code_interpreter_sessions_response.py +++ b/src/openai/types/admin/organization/usage_code_interpreter_sessions_response.py @@ -353,6 +353,12 @@ class DataResultOrganizationCostsResult(BaseModel): costs result. """ + quantity: Optional[float] = None + """ + When `group_by=line_item`, this field provides the quantity of the grouped costs + result. + """ + DataResult: TypeAlias = Annotated[ Union[ diff --git a/src/openai/types/admin/organization/usage_completions_response.py b/src/openai/types/admin/organization/usage_completions_response.py index d37634bca5..f179149995 100644 --- a/src/openai/types/admin/organization/usage_completions_response.py +++ b/src/openai/types/admin/organization/usage_completions_response.py @@ -353,6 +353,12 @@ class DataResultOrganizationCostsResult(BaseModel): costs result. """ + quantity: Optional[float] = None + """ + When `group_by=line_item`, this field provides the quantity of the grouped costs + result. + """ + DataResult: TypeAlias = Annotated[ Union[ diff --git a/src/openai/types/admin/organization/usage_costs_response.py b/src/openai/types/admin/organization/usage_costs_response.py index 68c1f639c1..fd1d344e26 100644 --- a/src/openai/types/admin/organization/usage_costs_response.py +++ b/src/openai/types/admin/organization/usage_costs_response.py @@ -353,6 +353,12 @@ class DataResultOrganizationCostsResult(BaseModel): costs result. """ + quantity: Optional[float] = None + """ + When `group_by=line_item`, this field provides the quantity of the grouped costs + result. + """ + DataResult: TypeAlias = Annotated[ Union[ diff --git a/src/openai/types/admin/organization/usage_embeddings_response.py b/src/openai/types/admin/organization/usage_embeddings_response.py index 905c8f5c6e..adbc389d89 100644 --- a/src/openai/types/admin/organization/usage_embeddings_response.py +++ b/src/openai/types/admin/organization/usage_embeddings_response.py @@ -353,6 +353,12 @@ class DataResultOrganizationCostsResult(BaseModel): costs result. """ + quantity: Optional[float] = None + """ + When `group_by=line_item`, this field provides the quantity of the grouped costs + result. + """ + DataResult: TypeAlias = Annotated[ Union[ diff --git a/src/openai/types/admin/organization/usage_images_response.py b/src/openai/types/admin/organization/usage_images_response.py index 55f8d80096..7c6a096c98 100644 --- a/src/openai/types/admin/organization/usage_images_response.py +++ b/src/openai/types/admin/organization/usage_images_response.py @@ -353,6 +353,12 @@ class DataResultOrganizationCostsResult(BaseModel): costs result. """ + quantity: Optional[float] = None + """ + When `group_by=line_item`, this field provides the quantity of the grouped costs + result. + """ + DataResult: TypeAlias = Annotated[ Union[ diff --git a/src/openai/types/admin/organization/usage_moderations_response.py b/src/openai/types/admin/organization/usage_moderations_response.py index 87919b50a9..5e40ef1164 100644 --- a/src/openai/types/admin/organization/usage_moderations_response.py +++ b/src/openai/types/admin/organization/usage_moderations_response.py @@ -353,6 +353,12 @@ class DataResultOrganizationCostsResult(BaseModel): costs result. """ + quantity: Optional[float] = None + """ + When `group_by=line_item`, this field provides the quantity of the grouped costs + result. + """ + DataResult: TypeAlias = Annotated[ Union[ diff --git a/src/openai/types/admin/organization/usage_vector_stores_response.py b/src/openai/types/admin/organization/usage_vector_stores_response.py index d3cd853653..089aa23119 100644 --- a/src/openai/types/admin/organization/usage_vector_stores_response.py +++ b/src/openai/types/admin/organization/usage_vector_stores_response.py @@ -353,6 +353,12 @@ class DataResultOrganizationCostsResult(BaseModel): costs result. """ + quantity: Optional[float] = None + """ + When `group_by=line_item`, this field provides the quantity of the grouped costs + result. + """ + DataResult: TypeAlias = Annotated[ Union[ diff --git a/src/openai/types/chat/chat_completion_token_logprob.py b/src/openai/types/chat/chat_completion_token_logprob.py index c69e258910..4ce582366a 100644 --- a/src/openai/types/chat/chat_completion_token_logprob.py +++ b/src/openai/types/chat/chat_completion_token_logprob.py @@ -52,6 +52,5 @@ class ChatCompletionTokenLogprob(BaseModel): """List of the most likely tokens and their log probability, at this token position. - In rare cases, there may be fewer than the number of requested `top_logprobs` - returned. + The number of entries may be fewer than the requested `top_logprobs`. """ diff --git a/src/openai/types/chat/completion_create_params.py b/src/openai/types/chat/completion_create_params.py index 0379ee0865..3c541b96b4 100644 --- a/src/openai/types/chat/completion_create_params.py +++ b/src/openai/types/chat/completion_create_params.py @@ -311,8 +311,9 @@ class CompletionCreateParamsBase(TypedDict, total=False): top_logprobs: Optional[int] """ - An integer between 0 and 20 specifying the number of most likely tokens to - return at each token position, each with an associated log probability. + An integer between 0 and 20 specifying the maximum number of most likely tokens + to return at each token position, each with an associated log probability. In + some cases, the number of returned tokens may be fewer than requested. `logprobs` must be set to `true` if this parameter is used. """ diff --git a/src/openai/types/responses/response.py b/src/openai/types/responses/response.py index 0d2491ea7c..dac3e09a89 100644 --- a/src/openai/types/responses/response.py +++ b/src/openai/types/responses/response.py @@ -276,8 +276,9 @@ class Response(BaseModel): top_logprobs: Optional[int] = None """ - An integer between 0 and 20 specifying the number of most likely tokens to - return at each token position, each with an associated log probability. + An integer between 0 and 20 specifying the maximum number of most likely tokens + to return at each token position, each with an associated log probability. In + some cases, the number of returned tokens may be fewer than requested. """ truncation: Optional[Literal["auto", "disabled"]] = None diff --git a/src/openai/types/responses/response_create_params.py b/src/openai/types/responses/response_create_params.py index a04495f40a..5f9b948ae9 100644 --- a/src/openai/types/responses/response_create_params.py +++ b/src/openai/types/responses/response_create_params.py @@ -251,8 +251,9 @@ class ResponseCreateParamsBase(TypedDict, total=False): top_logprobs: Optional[int] """ - An integer between 0 and 20 specifying the number of most likely tokens to - return at each token position, each with an associated log probability. + An integer between 0 and 20 specifying the maximum number of most likely tokens + to return at each token position, each with an associated log probability. In + some cases, the number of returned tokens may be fewer than requested. """ top_p: Optional[float] diff --git a/src/openai/types/responses/response_text_delta_event.py b/src/openai/types/responses/response_text_delta_event.py index 4f802abfd2..9b0b83de59 100644 --- a/src/openai/types/responses/response_text_delta_event.py +++ b/src/openai/types/responses/response_text_delta_event.py @@ -30,7 +30,7 @@ class Logprob(BaseModel): """The log probability of this token.""" top_logprobs: Optional[List[LogprobTopLogprob]] = None - """The log probability of the top 20 most likely tokens.""" + """The log probabilities of up to 20 of the most likely tokens.""" class ResponseTextDeltaEvent(BaseModel): diff --git a/src/openai/types/responses/response_text_done_event.py b/src/openai/types/responses/response_text_done_event.py index 75bd479870..3a202af67a 100644 --- a/src/openai/types/responses/response_text_done_event.py +++ b/src/openai/types/responses/response_text_done_event.py @@ -30,7 +30,7 @@ class Logprob(BaseModel): """The log probability of this token.""" top_logprobs: Optional[List[LogprobTopLogprob]] = None - """The log probability of the top 20 most likely tokens.""" + """The log probabilities of up to 20 of the most likely tokens.""" class ResponseTextDoneEvent(BaseModel): diff --git a/src/openai/types/responses/responses_client_event.py b/src/openai/types/responses/responses_client_event.py index 5f9e73c61f..0a5dcb4ddd 100644 --- a/src/openai/types/responses/responses_client_event.py +++ b/src/openai/types/responses/responses_client_event.py @@ -293,8 +293,9 @@ class ResponsesClientEvent(BaseModel): top_logprobs: Optional[int] = None """ - An integer between 0 and 20 specifying the number of most likely tokens to - return at each token position, each with an associated log probability. + An integer between 0 and 20 specifying the maximum number of most likely tokens + to return at each token position, each with an associated log probability. In + some cases, the number of returned tokens may be fewer than requested. """ top_p: Optional[float] = None diff --git a/src/openai/types/responses/responses_client_event_param.py b/src/openai/types/responses/responses_client_event_param.py index 249c812116..59d8f205ae 100644 --- a/src/openai/types/responses/responses_client_event_param.py +++ b/src/openai/types/responses/responses_client_event_param.py @@ -294,8 +294,9 @@ class ResponsesClientEventParam(TypedDict, total=False): top_logprobs: Optional[int] """ - An integer between 0 and 20 specifying the number of most likely tokens to - return at each token position, each with an associated log probability. + An integer between 0 and 20 specifying the maximum number of most likely tokens + to return at each token position, each with an associated log probability. In + some cases, the number of returned tokens may be fewer than requested. """ top_p: Optional[float] From a3b182d6d2c2e6fe1d53ca7550b2d43e0f8b2cd3 Mon Sep 17 00:00:00 2001 From: Alex Chang Date: Wed, 6 May 2026 10:06:24 -0400 Subject: [PATCH 728/769] chore: rename legacy python cli entrypoint --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 7fbf3bd49b..38314d2869 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,7 +43,7 @@ Homepage = "https://github.com/openai/openai-python" Repository = "https://github.com/openai/openai-python" [project.scripts] -openai = "openai.cli:main" +openai-python = "openai.cli:main" [project.optional-dependencies] aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.9"] From 32f36e447d02c3124af8ab48fcc3537df2fed66e Mon Sep 17 00:00:00 2001 From: Alex Chang Date: Wed, 6 May 2026 10:43:49 -0400 Subject: [PATCH 729/769] chore: remove legacy python cli --- pyproject.toml | 3 - src/openai/__main__.py | 3 - src/openai/cli/__init__.py | 1 - src/openai/cli/_api/__init__.py | 1 - src/openai/cli/_api/_main.py | 17 -- src/openai/cli/_api/audio.py | 108 --------- src/openai/cli/_api/chat/__init__.py | 13 -- src/openai/cli/_api/chat/completions.py | 160 -------------- src/openai/cli/_api/completions.py | 173 --------------- src/openai/cli/_api/files.py | 80 ------- src/openai/cli/_api/fine_tuning/__init__.py | 13 -- src/openai/cli/_api/fine_tuning/jobs.py | 170 -------------- src/openai/cli/_api/image.py | 139 ------------ src/openai/cli/_api/models.py | 45 ---- src/openai/cli/_cli.py | 233 -------------------- src/openai/cli/_errors.py | 21 -- src/openai/cli/_models.py | 17 -- src/openai/cli/_progress.py | 59 ----- src/openai/cli/_tools/__init__.py | 1 - src/openai/cli/_tools/_main.py | 17 -- src/openai/cli/_tools/fine_tunes.py | 63 ------ src/openai/cli/_tools/migrate.py | 164 -------------- src/openai/cli/_utils.py | 45 ---- 23 files changed, 1546 deletions(-) delete mode 100644 src/openai/__main__.py delete mode 100644 src/openai/cli/__init__.py delete mode 100644 src/openai/cli/_api/__init__.py delete mode 100644 src/openai/cli/_api/_main.py delete mode 100644 src/openai/cli/_api/audio.py delete mode 100644 src/openai/cli/_api/chat/__init__.py delete mode 100644 src/openai/cli/_api/chat/completions.py delete mode 100644 src/openai/cli/_api/completions.py delete mode 100644 src/openai/cli/_api/files.py delete mode 100644 src/openai/cli/_api/fine_tuning/__init__.py delete mode 100644 src/openai/cli/_api/fine_tuning/jobs.py delete mode 100644 src/openai/cli/_api/image.py delete mode 100644 src/openai/cli/_api/models.py delete mode 100644 src/openai/cli/_cli.py delete mode 100644 src/openai/cli/_errors.py delete mode 100644 src/openai/cli/_models.py delete mode 100644 src/openai/cli/_progress.py delete mode 100644 src/openai/cli/_tools/__init__.py delete mode 100644 src/openai/cli/_tools/_main.py delete mode 100644 src/openai/cli/_tools/fine_tunes.py delete mode 100644 src/openai/cli/_tools/migrate.py delete mode 100644 src/openai/cli/_utils.py diff --git a/pyproject.toml b/pyproject.toml index 38314d2869..1f7c145039 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,9 +42,6 @@ classifiers = [ Homepage = "https://github.com/openai/openai-python" Repository = "https://github.com/openai/openai-python" -[project.scripts] -openai-python = "openai.cli:main" - [project.optional-dependencies] aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.9"] realtime = ["websockets >= 13, < 16"] diff --git a/src/openai/__main__.py b/src/openai/__main__.py deleted file mode 100644 index 4e28416e10..0000000000 --- a/src/openai/__main__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .cli import main - -main() diff --git a/src/openai/cli/__init__.py b/src/openai/cli/__init__.py deleted file mode 100644 index d453d5e179..0000000000 --- a/src/openai/cli/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from ._cli import main as main diff --git a/src/openai/cli/_api/__init__.py b/src/openai/cli/_api/__init__.py deleted file mode 100644 index 56a0260a6d..0000000000 --- a/src/openai/cli/_api/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from ._main import register_commands as register_commands diff --git a/src/openai/cli/_api/_main.py b/src/openai/cli/_api/_main.py deleted file mode 100644 index b04a3e52a4..0000000000 --- a/src/openai/cli/_api/_main.py +++ /dev/null @@ -1,17 +0,0 @@ -from __future__ import annotations - -from argparse import ArgumentParser - -from . import chat, audio, files, image, models, completions, fine_tuning - - -def register_commands(parser: ArgumentParser) -> None: - subparsers = parser.add_subparsers(help="All API subcommands") - - chat.register(subparsers) - image.register(subparsers) - audio.register(subparsers) - files.register(subparsers) - models.register(subparsers) - completions.register(subparsers) - fine_tuning.register(subparsers) diff --git a/src/openai/cli/_api/audio.py b/src/openai/cli/_api/audio.py deleted file mode 100644 index e7c3734e75..0000000000 --- a/src/openai/cli/_api/audio.py +++ /dev/null @@ -1,108 +0,0 @@ -from __future__ import annotations - -import sys -from typing import TYPE_CHECKING, Any, Optional, cast -from argparse import ArgumentParser - -from .._utils import get_client, print_model -from ..._types import omit -from .._models import BaseModel -from .._progress import BufferReader -from ...types.audio import Transcription - -if TYPE_CHECKING: - from argparse import _SubParsersAction - - -def register(subparser: _SubParsersAction[ArgumentParser]) -> None: - # transcriptions - sub = subparser.add_parser("audio.transcriptions.create") - - # Required - sub.add_argument("-m", "--model", type=str, default="whisper-1") - sub.add_argument("-f", "--file", type=str, required=True) - # Optional - sub.add_argument("--response-format", type=str) - sub.add_argument("--language", type=str) - sub.add_argument("-t", "--temperature", type=float) - sub.add_argument("--prompt", type=str) - sub.set_defaults(func=CLIAudio.transcribe, args_model=CLITranscribeArgs) - - # translations - sub = subparser.add_parser("audio.translations.create") - - # Required - sub.add_argument("-f", "--file", type=str, required=True) - # Optional - sub.add_argument("-m", "--model", type=str, default="whisper-1") - sub.add_argument("--response-format", type=str) - # TODO: doesn't seem to be supported by the API - # sub.add_argument("--language", type=str) - sub.add_argument("-t", "--temperature", type=float) - sub.add_argument("--prompt", type=str) - sub.set_defaults(func=CLIAudio.translate, args_model=CLITranslationArgs) - - -class CLITranscribeArgs(BaseModel): - model: str - file: str - response_format: Optional[str] = None - language: Optional[str] = None - temperature: Optional[float] = None - prompt: Optional[str] = None - - -class CLITranslationArgs(BaseModel): - model: str - file: str - response_format: Optional[str] = None - language: Optional[str] = None - temperature: Optional[float] = None - prompt: Optional[str] = None - - -class CLIAudio: - @staticmethod - def transcribe(args: CLITranscribeArgs) -> None: - with open(args.file, "rb") as file_reader: - buffer_reader = BufferReader(file_reader.read(), desc="Upload progress") - - model = cast( - "Transcription | str", - get_client().audio.transcriptions.create( - file=(args.file, buffer_reader), - model=args.model, - language=args.language or omit, - temperature=args.temperature or omit, - prompt=args.prompt or omit, - # casts required because the API is typed for enums - # but we don't want to validate that here for forwards-compat - response_format=cast(Any, args.response_format), - ), - ) - if isinstance(model, str): - sys.stdout.write(model + "\n") - else: - print_model(model) - - @staticmethod - def translate(args: CLITranslationArgs) -> None: - with open(args.file, "rb") as file_reader: - buffer_reader = BufferReader(file_reader.read(), desc="Upload progress") - - model = cast( - "Transcription | str", - get_client().audio.translations.create( - file=(args.file, buffer_reader), - model=args.model, - temperature=args.temperature or omit, - prompt=args.prompt or omit, - # casts required because the API is typed for enums - # but we don't want to validate that here for forwards-compat - response_format=cast(Any, args.response_format), - ), - ) - if isinstance(model, str): - sys.stdout.write(model + "\n") - else: - print_model(model) diff --git a/src/openai/cli/_api/chat/__init__.py b/src/openai/cli/_api/chat/__init__.py deleted file mode 100644 index 87d971630a..0000000000 --- a/src/openai/cli/_api/chat/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING -from argparse import ArgumentParser - -from . import completions - -if TYPE_CHECKING: - from argparse import _SubParsersAction - - -def register(subparser: _SubParsersAction[ArgumentParser]) -> None: - completions.register(subparser) diff --git a/src/openai/cli/_api/chat/completions.py b/src/openai/cli/_api/chat/completions.py deleted file mode 100644 index 344eeff37c..0000000000 --- a/src/openai/cli/_api/chat/completions.py +++ /dev/null @@ -1,160 +0,0 @@ -from __future__ import annotations - -import sys -from typing import TYPE_CHECKING, List, Optional, cast -from argparse import ArgumentParser -from typing_extensions import Literal, NamedTuple - -from ..._utils import get_client -from ..._models import BaseModel -from ...._streaming import Stream -from ....types.chat import ( - ChatCompletionRole, - ChatCompletionChunk, - CompletionCreateParams, -) -from ....types.chat.completion_create_params import ( - CompletionCreateParamsStreaming, - CompletionCreateParamsNonStreaming, -) - -if TYPE_CHECKING: - from argparse import _SubParsersAction - - -def register(subparser: _SubParsersAction[ArgumentParser]) -> None: - sub = subparser.add_parser("chat.completions.create") - - sub._action_groups.pop() - req = sub.add_argument_group("required arguments") - opt = sub.add_argument_group("optional arguments") - - req.add_argument( - "-g", - "--message", - action="append", - nargs=2, - metavar=("ROLE", "CONTENT"), - help="A message in `{role} {content}` format. Use this argument multiple times to add multiple messages.", - required=True, - ) - req.add_argument( - "-m", - "--model", - help="The model to use.", - required=True, - ) - - opt.add_argument( - "-n", - "--n", - help="How many completions to generate for the conversation.", - type=int, - ) - opt.add_argument("-M", "--max-tokens", help="The maximum number of tokens to generate.", type=int) - opt.add_argument( - "-t", - "--temperature", - help="""What sampling temperature to use. Higher values means the model will take more risks. Try 0.9 for more creative applications, and 0 (argmax sampling) for ones with a well-defined answer. - -Mutually exclusive with `top_p`.""", - type=float, - ) - opt.add_argument( - "-P", - "--top_p", - help="""An alternative to sampling with temperature, called nucleus sampling, where the considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10%% probability mass are considered. - - Mutually exclusive with `temperature`.""", - type=float, - ) - opt.add_argument( - "--stop", - help="A stop sequence at which to stop generating tokens for the message.", - ) - opt.add_argument("--stream", help="Stream messages as they're ready.", action="store_true") - sub.set_defaults(func=CLIChatCompletion.create, args_model=CLIChatCompletionCreateArgs) - - -class CLIMessage(NamedTuple): - role: ChatCompletionRole - content: str - - -class CLIChatCompletionCreateArgs(BaseModel): - message: List[CLIMessage] - model: str - n: Optional[int] = None - max_tokens: Optional[int] = None - temperature: Optional[float] = None - top_p: Optional[float] = None - stop: Optional[str] = None - stream: bool = False - - -class CLIChatCompletion: - @staticmethod - def create(args: CLIChatCompletionCreateArgs) -> None: - params: CompletionCreateParams = { - "model": args.model, - "messages": [ - {"role": cast(Literal["user"], message.role), "content": message.content} for message in args.message - ], - # type checkers are not good at inferring union types so we have to set stream afterwards - "stream": False, - } - if args.temperature is not None: - params["temperature"] = args.temperature - if args.stop is not None: - params["stop"] = args.stop - if args.top_p is not None: - params["top_p"] = args.top_p - if args.n is not None: - params["n"] = args.n - if args.stream: - params["stream"] = args.stream # type: ignore - if args.max_tokens is not None: - params["max_tokens"] = args.max_tokens - - if args.stream: - return CLIChatCompletion._stream_create(cast(CompletionCreateParamsStreaming, params)) - - return CLIChatCompletion._create(cast(CompletionCreateParamsNonStreaming, params)) - - @staticmethod - def _create(params: CompletionCreateParamsNonStreaming) -> None: - completion = get_client().chat.completions.create(**params) - should_print_header = len(completion.choices) > 1 - for choice in completion.choices: - if should_print_header: - sys.stdout.write("===== Chat Completion {} =====\n".format(choice.index)) - - content = choice.message.content if choice.message.content is not None else "None" - sys.stdout.write(content) - - if should_print_header or not content.endswith("\n"): - sys.stdout.write("\n") - - sys.stdout.flush() - - @staticmethod - def _stream_create(params: CompletionCreateParamsStreaming) -> None: - # cast is required for mypy - stream = cast( # pyright: ignore[reportUnnecessaryCast] - Stream[ChatCompletionChunk], get_client().chat.completions.create(**params) - ) - for chunk in stream: - should_print_header = len(chunk.choices) > 1 - for choice in chunk.choices: - if should_print_header: - sys.stdout.write("===== Chat Completion {} =====\n".format(choice.index)) - - content = choice.delta.content or "" - sys.stdout.write(content) - - if should_print_header: - sys.stdout.write("\n") - - sys.stdout.flush() - - sys.stdout.write("\n") diff --git a/src/openai/cli/_api/completions.py b/src/openai/cli/_api/completions.py deleted file mode 100644 index b22ecde9ef..0000000000 --- a/src/openai/cli/_api/completions.py +++ /dev/null @@ -1,173 +0,0 @@ -from __future__ import annotations - -import sys -from typing import TYPE_CHECKING, Optional, cast -from argparse import ArgumentParser -from functools import partial - -from openai.types.completion import Completion - -from .._utils import get_client -from ..._types import Omittable, omit -from ..._utils import is_given -from .._errors import CLIError -from .._models import BaseModel -from ..._streaming import Stream - -if TYPE_CHECKING: - from argparse import _SubParsersAction - - -def register(subparser: _SubParsersAction[ArgumentParser]) -> None: - sub = subparser.add_parser("completions.create") - - # Required - sub.add_argument( - "-m", - "--model", - help="The model to use", - required=True, - ) - - # Optional - sub.add_argument("-p", "--prompt", help="An optional prompt to complete from") - sub.add_argument("--stream", help="Stream tokens as they're ready.", action="store_true") - sub.add_argument("-M", "--max-tokens", help="The maximum number of tokens to generate", type=int) - sub.add_argument( - "-t", - "--temperature", - help="""What sampling temperature to use. Higher values means the model will take more risks. Try 0.9 for more creative applications, and 0 (argmax sampling) for ones with a well-defined answer. - -Mutually exclusive with `top_p`.""", - type=float, - ) - sub.add_argument( - "-P", - "--top_p", - help="""An alternative to sampling with temperature, called nucleus sampling, where the considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10%% probability mass are considered. - - Mutually exclusive with `temperature`.""", - type=float, - ) - sub.add_argument( - "-n", - "--n", - help="How many sub-completions to generate for each prompt.", - type=int, - ) - sub.add_argument( - "--logprobs", - help="Include the log probabilities on the `logprobs` most likely tokens, as well the chosen tokens. So for example, if `logprobs` is 10, the API will return a list of the 10 most likely tokens. If `logprobs` is 0, only the chosen tokens will have logprobs returned.", - type=int, - ) - sub.add_argument( - "--best_of", - help="Generates `best_of` completions server-side and returns the 'best' (the one with the highest log probability per token). Results cannot be streamed.", - type=int, - ) - sub.add_argument( - "--echo", - help="Echo back the prompt in addition to the completion", - action="store_true", - ) - sub.add_argument( - "--frequency_penalty", - help="Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim.", - type=float, - ) - sub.add_argument( - "--presence_penalty", - help="Positive values penalize new tokens based on whether they appear in the text so far, increasing the model's likelihood to talk about new topics.", - type=float, - ) - sub.add_argument("--suffix", help="The suffix that comes after a completion of inserted text.") - sub.add_argument("--stop", help="A stop sequence at which to stop generating tokens.") - sub.add_argument( - "--user", - help="A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse.", - ) - # TODO: add support for logit_bias - sub.set_defaults(func=CLICompletions.create, args_model=CLICompletionCreateArgs) - - -class CLICompletionCreateArgs(BaseModel): - model: str - stream: bool = False - - prompt: Optional[str] = None - n: Omittable[int] = omit - stop: Omittable[str] = omit - user: Omittable[str] = omit - echo: Omittable[bool] = omit - suffix: Omittable[str] = omit - best_of: Omittable[int] = omit - top_p: Omittable[float] = omit - logprobs: Omittable[int] = omit - max_tokens: Omittable[int] = omit - temperature: Omittable[float] = omit - presence_penalty: Omittable[float] = omit - frequency_penalty: Omittable[float] = omit - - -class CLICompletions: - @staticmethod - def create(args: CLICompletionCreateArgs) -> None: - if is_given(args.n) and args.n > 1 and args.stream: - raise CLIError("Can't stream completions with n>1 with the current CLI") - - make_request = partial( - get_client().completions.create, - n=args.n, - echo=args.echo, - stop=args.stop, - user=args.user, - model=args.model, - top_p=args.top_p, - prompt=args.prompt, - suffix=args.suffix, - best_of=args.best_of, - logprobs=args.logprobs, - max_tokens=args.max_tokens, - temperature=args.temperature, - presence_penalty=args.presence_penalty, - frequency_penalty=args.frequency_penalty, - ) - - if args.stream: - return CLICompletions._stream_create( - # mypy doesn't understand the `partial` function but pyright does - cast(Stream[Completion], make_request(stream=True)) # pyright: ignore[reportUnnecessaryCast] - ) - - return CLICompletions._create(make_request()) - - @staticmethod - def _create(completion: Completion) -> None: - should_print_header = len(completion.choices) > 1 - for choice in completion.choices: - if should_print_header: - sys.stdout.write("===== Completion {} =====\n".format(choice.index)) - - sys.stdout.write(choice.text) - - if should_print_header or not choice.text.endswith("\n"): - sys.stdout.write("\n") - - sys.stdout.flush() - - @staticmethod - def _stream_create(stream: Stream[Completion]) -> None: - for completion in stream: - should_print_header = len(completion.choices) > 1 - for choice in sorted(completion.choices, key=lambda c: c.index): - if should_print_header: - sys.stdout.write("===== Chat Completion {} =====\n".format(choice.index)) - - sys.stdout.write(choice.text) - - if should_print_header: - sys.stdout.write("\n") - - sys.stdout.flush() - - sys.stdout.write("\n") diff --git a/src/openai/cli/_api/files.py b/src/openai/cli/_api/files.py deleted file mode 100644 index 5f3631b284..0000000000 --- a/src/openai/cli/_api/files.py +++ /dev/null @@ -1,80 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING, Any, cast -from argparse import ArgumentParser - -from .._utils import get_client, print_model -from .._models import BaseModel -from .._progress import BufferReader - -if TYPE_CHECKING: - from argparse import _SubParsersAction - - -def register(subparser: _SubParsersAction[ArgumentParser]) -> None: - sub = subparser.add_parser("files.create") - - sub.add_argument( - "-f", - "--file", - required=True, - help="File to upload", - ) - sub.add_argument( - "-p", - "--purpose", - help="Why are you uploading this file? (see https://platform.openai.com/docs/api-reference/ for purposes)", - required=True, - ) - sub.set_defaults(func=CLIFile.create, args_model=CLIFileCreateArgs) - - sub = subparser.add_parser("files.retrieve") - sub.add_argument("-i", "--id", required=True, help="The files ID") - sub.set_defaults(func=CLIFile.get, args_model=CLIFileCreateArgs) - - sub = subparser.add_parser("files.delete") - sub.add_argument("-i", "--id", required=True, help="The files ID") - sub.set_defaults(func=CLIFile.delete, args_model=CLIFileCreateArgs) - - sub = subparser.add_parser("files.list") - sub.set_defaults(func=CLIFile.list) - - -class CLIFileIDArgs(BaseModel): - id: str - - -class CLIFileCreateArgs(BaseModel): - file: str - purpose: str - - -class CLIFile: - @staticmethod - def create(args: CLIFileCreateArgs) -> None: - with open(args.file, "rb") as file_reader: - buffer_reader = BufferReader(file_reader.read(), desc="Upload progress") - - file = get_client().files.create( - file=(args.file, buffer_reader), - # casts required because the API is typed for enums - # but we don't want to validate that here for forwards-compat - purpose=cast(Any, args.purpose), - ) - print_model(file) - - @staticmethod - def get(args: CLIFileIDArgs) -> None: - file = get_client().files.retrieve(file_id=args.id) - print_model(file) - - @staticmethod - def delete(args: CLIFileIDArgs) -> None: - file = get_client().files.delete(file_id=args.id) - print_model(file) - - @staticmethod - def list() -> None: - files = get_client().files.list() - for file in files: - print_model(file) diff --git a/src/openai/cli/_api/fine_tuning/__init__.py b/src/openai/cli/_api/fine_tuning/__init__.py deleted file mode 100644 index 11a2dfccbd..0000000000 --- a/src/openai/cli/_api/fine_tuning/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING -from argparse import ArgumentParser - -from . import jobs - -if TYPE_CHECKING: - from argparse import _SubParsersAction - - -def register(subparser: _SubParsersAction[ArgumentParser]) -> None: - jobs.register(subparser) diff --git a/src/openai/cli/_api/fine_tuning/jobs.py b/src/openai/cli/_api/fine_tuning/jobs.py deleted file mode 100644 index a4e429108a..0000000000 --- a/src/openai/cli/_api/fine_tuning/jobs.py +++ /dev/null @@ -1,170 +0,0 @@ -from __future__ import annotations - -import json -from typing import TYPE_CHECKING -from argparse import ArgumentParser - -from ..._utils import get_client, print_model -from ...._types import Omittable, omit -from ...._utils import is_given -from ..._models import BaseModel -from ....pagination import SyncCursorPage -from ....types.fine_tuning import ( - FineTuningJob, - FineTuningJobEvent, -) - -if TYPE_CHECKING: - from argparse import _SubParsersAction - - -def register(subparser: _SubParsersAction[ArgumentParser]) -> None: - sub = subparser.add_parser("fine_tuning.jobs.create") - sub.add_argument( - "-m", - "--model", - help="The model to fine-tune.", - required=True, - ) - sub.add_argument( - "-F", - "--training-file", - help="The training file to fine-tune the model on.", - required=True, - ) - sub.add_argument( - "-H", - "--hyperparameters", - help="JSON string of hyperparameters to use for fine-tuning.", - type=str, - ) - sub.add_argument( - "-s", - "--suffix", - help="A suffix to add to the fine-tuned model name.", - ) - sub.add_argument( - "-V", - "--validation-file", - help="The validation file to use for fine-tuning.", - ) - sub.set_defaults(func=CLIFineTuningJobs.create, args_model=CLIFineTuningJobsCreateArgs) - - sub = subparser.add_parser("fine_tuning.jobs.retrieve") - sub.add_argument( - "-i", - "--id", - help="The ID of the fine-tuning job to retrieve.", - required=True, - ) - sub.set_defaults(func=CLIFineTuningJobs.retrieve, args_model=CLIFineTuningJobsRetrieveArgs) - - sub = subparser.add_parser("fine_tuning.jobs.list") - sub.add_argument( - "-a", - "--after", - help="Identifier for the last job from the previous pagination request. If provided, only jobs created after this job will be returned.", - ) - sub.add_argument( - "-l", - "--limit", - help="Number of fine-tuning jobs to retrieve.", - type=int, - ) - sub.set_defaults(func=CLIFineTuningJobs.list, args_model=CLIFineTuningJobsListArgs) - - sub = subparser.add_parser("fine_tuning.jobs.cancel") - sub.add_argument( - "-i", - "--id", - help="The ID of the fine-tuning job to cancel.", - required=True, - ) - sub.set_defaults(func=CLIFineTuningJobs.cancel, args_model=CLIFineTuningJobsCancelArgs) - - sub = subparser.add_parser("fine_tuning.jobs.list_events") - sub.add_argument( - "-i", - "--id", - help="The ID of the fine-tuning job to list events for.", - required=True, - ) - sub.add_argument( - "-a", - "--after", - help="Identifier for the last event from the previous pagination request. If provided, only events created after this event will be returned.", - ) - sub.add_argument( - "-l", - "--limit", - help="Number of fine-tuning job events to retrieve.", - type=int, - ) - sub.set_defaults(func=CLIFineTuningJobs.list_events, args_model=CLIFineTuningJobsListEventsArgs) - - -class CLIFineTuningJobsCreateArgs(BaseModel): - model: str - training_file: str - hyperparameters: Omittable[str] = omit - suffix: Omittable[str] = omit - validation_file: Omittable[str] = omit - - -class CLIFineTuningJobsRetrieveArgs(BaseModel): - id: str - - -class CLIFineTuningJobsListArgs(BaseModel): - after: Omittable[str] = omit - limit: Omittable[int] = omit - - -class CLIFineTuningJobsCancelArgs(BaseModel): - id: str - - -class CLIFineTuningJobsListEventsArgs(BaseModel): - id: str - after: Omittable[str] = omit - limit: Omittable[int] = omit - - -class CLIFineTuningJobs: - @staticmethod - def create(args: CLIFineTuningJobsCreateArgs) -> None: - hyperparameters = json.loads(str(args.hyperparameters)) if is_given(args.hyperparameters) else omit - fine_tuning_job: FineTuningJob = get_client().fine_tuning.jobs.create( - model=args.model, - training_file=args.training_file, - hyperparameters=hyperparameters, - suffix=args.suffix, - validation_file=args.validation_file, - ) - print_model(fine_tuning_job) - - @staticmethod - def retrieve(args: CLIFineTuningJobsRetrieveArgs) -> None: - fine_tuning_job: FineTuningJob = get_client().fine_tuning.jobs.retrieve(fine_tuning_job_id=args.id) - print_model(fine_tuning_job) - - @staticmethod - def list(args: CLIFineTuningJobsListArgs) -> None: - fine_tuning_jobs: SyncCursorPage[FineTuningJob] = get_client().fine_tuning.jobs.list( - after=args.after or omit, limit=args.limit or omit - ) - print_model(fine_tuning_jobs) - - @staticmethod - def cancel(args: CLIFineTuningJobsCancelArgs) -> None: - fine_tuning_job: FineTuningJob = get_client().fine_tuning.jobs.cancel(fine_tuning_job_id=args.id) - print_model(fine_tuning_job) - - @staticmethod - def list_events(args: CLIFineTuningJobsListEventsArgs) -> None: - fine_tuning_job_events: SyncCursorPage[FineTuningJobEvent] = get_client().fine_tuning.jobs.list_events( - fine_tuning_job_id=args.id, - after=args.after or omit, - limit=args.limit or omit, - ) - print_model(fine_tuning_job_events) diff --git a/src/openai/cli/_api/image.py b/src/openai/cli/_api/image.py deleted file mode 100644 index 1d0cf810c1..0000000000 --- a/src/openai/cli/_api/image.py +++ /dev/null @@ -1,139 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING, Any, cast -from argparse import ArgumentParser - -from .._utils import get_client, print_model -from ..._types import Omit, Omittable, omit -from .._models import BaseModel -from .._progress import BufferReader - -if TYPE_CHECKING: - from argparse import _SubParsersAction - - -def register(subparser: _SubParsersAction[ArgumentParser]) -> None: - sub = subparser.add_parser("images.generate") - sub.add_argument("-m", "--model", type=str) - sub.add_argument("-p", "--prompt", type=str, required=True) - sub.add_argument("-n", "--num-images", type=int, default=1) - sub.add_argument("-s", "--size", type=str, default="1024x1024", help="Size of the output image") - sub.add_argument("--response-format", type=str, default="url") - sub.set_defaults(func=CLIImage.create, args_model=CLIImageCreateArgs) - - sub = subparser.add_parser("images.edit") - sub.add_argument("-m", "--model", type=str) - sub.add_argument("-p", "--prompt", type=str, required=True) - sub.add_argument("-n", "--num-images", type=int, default=1) - sub.add_argument( - "-I", - "--image", - type=str, - required=True, - help="Image to modify. Should be a local path and a PNG encoded image.", - ) - sub.add_argument("-s", "--size", type=str, default="1024x1024", help="Size of the output image") - sub.add_argument("--response-format", type=str, default="url") - sub.add_argument( - "-M", - "--mask", - type=str, - required=False, - help="Path to a mask image. It should be the same size as the image you're editing and a RGBA PNG image. The Alpha channel acts as the mask.", - ) - sub.set_defaults(func=CLIImage.edit, args_model=CLIImageEditArgs) - - sub = subparser.add_parser("images.create_variation") - sub.add_argument("-m", "--model", type=str) - sub.add_argument("-n", "--num-images", type=int, default=1) - sub.add_argument( - "-I", - "--image", - type=str, - required=True, - help="Image to modify. Should be a local path and a PNG encoded image.", - ) - sub.add_argument("-s", "--size", type=str, default="1024x1024", help="Size of the output image") - sub.add_argument("--response-format", type=str, default="url") - sub.set_defaults(func=CLIImage.create_variation, args_model=CLIImageCreateVariationArgs) - - -class CLIImageCreateArgs(BaseModel): - prompt: str - num_images: int - size: str - response_format: str - model: Omittable[str] = omit - - -class CLIImageCreateVariationArgs(BaseModel): - image: str - num_images: int - size: str - response_format: str - model: Omittable[str] = omit - - -class CLIImageEditArgs(BaseModel): - image: str - num_images: int - size: str - response_format: str - prompt: str - mask: Omittable[str] = omit - model: Omittable[str] = omit - - -class CLIImage: - @staticmethod - def create(args: CLIImageCreateArgs) -> None: - image = get_client().images.generate( - model=args.model, - prompt=args.prompt, - n=args.num_images, - # casts required because the API is typed for enums - # but we don't want to validate that here for forwards-compat - size=cast(Any, args.size), - response_format=cast(Any, args.response_format), - ) - print_model(image) - - @staticmethod - def create_variation(args: CLIImageCreateVariationArgs) -> None: - with open(args.image, "rb") as file_reader: - buffer_reader = BufferReader(file_reader.read(), desc="Upload progress") - - image = get_client().images.create_variation( - model=args.model, - image=("image", buffer_reader), - n=args.num_images, - # casts required because the API is typed for enums - # but we don't want to validate that here for forwards-compat - size=cast(Any, args.size), - response_format=cast(Any, args.response_format), - ) - print_model(image) - - @staticmethod - def edit(args: CLIImageEditArgs) -> None: - with open(args.image, "rb") as file_reader: - buffer_reader = BufferReader(file_reader.read(), desc="Image upload progress") - - if isinstance(args.mask, Omit): - mask: Omittable[BufferReader] = omit - else: - with open(args.mask, "rb") as file_reader: - mask = BufferReader(file_reader.read(), desc="Mask progress") - - image = get_client().images.edit( - model=args.model, - prompt=args.prompt, - image=("image", buffer_reader), - n=args.num_images, - mask=("mask", mask) if not isinstance(mask, Omit) else mask, - # casts required because the API is typed for enums - # but we don't want to validate that here for forwards-compat - size=cast(Any, args.size), - response_format=cast(Any, args.response_format), - ) - print_model(image) diff --git a/src/openai/cli/_api/models.py b/src/openai/cli/_api/models.py deleted file mode 100644 index 017218fa6e..0000000000 --- a/src/openai/cli/_api/models.py +++ /dev/null @@ -1,45 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING -from argparse import ArgumentParser - -from .._utils import get_client, print_model -from .._models import BaseModel - -if TYPE_CHECKING: - from argparse import _SubParsersAction - - -def register(subparser: _SubParsersAction[ArgumentParser]) -> None: - sub = subparser.add_parser("models.list") - sub.set_defaults(func=CLIModels.list) - - sub = subparser.add_parser("models.retrieve") - sub.add_argument("-i", "--id", required=True, help="The model ID") - sub.set_defaults(func=CLIModels.get, args_model=CLIModelIDArgs) - - sub = subparser.add_parser("models.delete") - sub.add_argument("-i", "--id", required=True, help="The model ID") - sub.set_defaults(func=CLIModels.delete, args_model=CLIModelIDArgs) - - -class CLIModelIDArgs(BaseModel): - id: str - - -class CLIModels: - @staticmethod - def get(args: CLIModelIDArgs) -> None: - model = get_client().models.retrieve(model=args.id) - print_model(model) - - @staticmethod - def delete(args: CLIModelIDArgs) -> None: - model = get_client().models.delete(model=args.id) - print_model(model) - - @staticmethod - def list() -> None: - models = get_client().models.list() - for model in models: - print_model(model) diff --git a/src/openai/cli/_cli.py b/src/openai/cli/_cli.py deleted file mode 100644 index d31196da50..0000000000 --- a/src/openai/cli/_cli.py +++ /dev/null @@ -1,233 +0,0 @@ -from __future__ import annotations - -import sys -import logging -import argparse -from typing import Any, List, Type, Optional -from typing_extensions import ClassVar - -import httpx -import pydantic - -import openai - -from . import _tools -from .. import _ApiType, __version__ -from ._api import register_commands -from ._utils import can_use_http2 -from ._errors import CLIError, display_error -from .._compat import PYDANTIC_V1, ConfigDict, model_parse -from .._models import BaseModel -from .._exceptions import APIError - -logger = logging.getLogger() -formatter = logging.Formatter("[%(asctime)s] %(message)s") -handler = logging.StreamHandler(sys.stderr) -handler.setFormatter(formatter) -logger.addHandler(handler) - - -class Arguments(BaseModel): - if PYDANTIC_V1: - - class Config(pydantic.BaseConfig): # type: ignore - extra: Any = pydantic.Extra.ignore # type: ignore - else: - model_config: ClassVar[ConfigDict] = ConfigDict( - extra="ignore", - ) - - verbosity: int - version: Optional[str] = None - - api_key: Optional[str] - api_base: Optional[str] - organization: Optional[str] - proxy: Optional[List[str]] - api_type: Optional[_ApiType] = None - api_version: Optional[str] = None - - # azure - azure_endpoint: Optional[str] = None - azure_ad_token: Optional[str] = None - - # internal, set by subparsers to parse their specific args - args_model: Optional[Type[BaseModel]] = None - - # internal, used so that subparsers can forward unknown arguments - unknown_args: List[str] = [] - allow_unknown_args: bool = False - - -def _build_parser() -> argparse.ArgumentParser: - parser = argparse.ArgumentParser(description=None, prog="openai") - parser.add_argument( - "-v", - "--verbose", - action="count", - dest="verbosity", - default=0, - help="Set verbosity.", - ) - parser.add_argument("-b", "--api-base", help="What API base url to use.") - parser.add_argument("-k", "--api-key", help="What API key to use.") - parser.add_argument("-p", "--proxy", nargs="+", help="What proxy to use.") - parser.add_argument( - "-o", - "--organization", - help="Which organization to run as (will use your default organization if not specified)", - ) - parser.add_argument( - "-t", - "--api-type", - type=str, - choices=("openai", "azure"), - help="The backend API to call, must be `openai` or `azure`", - ) - parser.add_argument( - "--api-version", - help="The Azure API version, e.g. 'https://learn.microsoft.com/en-us/azure/ai-services/openai/reference#rest-api-versioning'", - ) - - # azure - parser.add_argument( - "--azure-endpoint", - help="The Azure endpoint, e.g. 'https://endpoint.openai.azure.com'", - ) - parser.add_argument( - "--azure-ad-token", - help="A token from Azure Active Directory, https://www.microsoft.com/en-us/security/business/identity-access/microsoft-entra-id", - ) - - # prints the package version - parser.add_argument( - "-V", - "--version", - action="version", - version="%(prog)s " + __version__, - ) - - def help() -> None: - parser.print_help() - - parser.set_defaults(func=help) - - subparsers = parser.add_subparsers() - sub_api = subparsers.add_parser("api", help="Direct API calls") - - register_commands(sub_api) - - sub_tools = subparsers.add_parser("tools", help="Client side tools for convenience") - _tools.register_commands(sub_tools, subparsers) - - return parser - - -def main() -> int: - try: - _main() - except (APIError, CLIError, pydantic.ValidationError) as err: - display_error(err) - return 1 - except KeyboardInterrupt: - sys.stderr.write("\n") - return 1 - return 0 - - -def _parse_args(parser: argparse.ArgumentParser) -> tuple[argparse.Namespace, Arguments, list[str]]: - # argparse by default will strip out the `--` but we want to keep it for unknown arguments - if "--" in sys.argv: - idx = sys.argv.index("--") - known_args = sys.argv[1:idx] - unknown_args = sys.argv[idx:] - else: - known_args = sys.argv[1:] - unknown_args = [] - - parsed, remaining_unknown = parser.parse_known_args(known_args) - - # append any remaining unknown arguments from the initial parsing - remaining_unknown.extend(unknown_args) - - args = model_parse(Arguments, vars(parsed)) - if not args.allow_unknown_args: - # we have to parse twice to ensure any unknown arguments - # result in an error if that behaviour is desired - parser.parse_args() - - return parsed, args, remaining_unknown - - -def _main() -> None: - parser = _build_parser() - parsed, args, unknown = _parse_args(parser) - - if args.verbosity != 0: - sys.stderr.write("Warning: --verbosity isn't supported yet\n") - - proxies: dict[str, httpx.BaseTransport] = {} - if args.proxy is not None: - for proxy in args.proxy: - key = "https://" if proxy.startswith("https") else "http://" - if key in proxies: - raise CLIError(f"Multiple {key} proxies given - only the last one would be used") - - proxies[key] = httpx.HTTPTransport(proxy=httpx.Proxy(httpx.URL(proxy))) - - http_client = httpx.Client( - mounts=proxies or None, - http2=can_use_http2(), - ) - openai.http_client = http_client - - if args.organization: - openai.organization = args.organization - - if args.api_key: - openai.api_key = args.api_key - - if args.api_base: - openai.base_url = args.api_base - - # azure - if args.api_type is not None: - openai.api_type = args.api_type - - if args.azure_endpoint is not None: - openai.azure_endpoint = args.azure_endpoint - - if args.api_version is not None: - openai.api_version = args.api_version - - if args.azure_ad_token is not None: - openai.azure_ad_token = args.azure_ad_token - - try: - if args.args_model: - parsed.func( - model_parse( - args.args_model, - { - **{ - # we omit None values so that they can be defaulted to `NotGiven` - # and we'll strip it from the API request - key: value - for key, value in vars(parsed).items() - if value is not None - }, - "unknown_args": unknown, - }, - ) - ) - else: - parsed.func() - finally: - try: - http_client.close() - except Exception: - pass - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/src/openai/cli/_errors.py b/src/openai/cli/_errors.py deleted file mode 100644 index 7d0292dab2..0000000000 --- a/src/openai/cli/_errors.py +++ /dev/null @@ -1,21 +0,0 @@ -from __future__ import annotations - -import sys - -import pydantic - -from ._utils import Colors, organization_info -from .._exceptions import APIError, OpenAIError - - -class CLIError(OpenAIError): ... - - -class SilentCLIError(CLIError): ... - - -def display_error(err: CLIError | APIError | pydantic.ValidationError) -> None: - if isinstance(err, SilentCLIError): - return - - sys.stderr.write("{}{}Error:{} {}\n".format(organization_info(), Colors.FAIL, Colors.ENDC, err)) diff --git a/src/openai/cli/_models.py b/src/openai/cli/_models.py deleted file mode 100644 index a88608961b..0000000000 --- a/src/openai/cli/_models.py +++ /dev/null @@ -1,17 +0,0 @@ -from typing import Any -from typing_extensions import ClassVar - -import pydantic - -from .. import _models -from .._compat import PYDANTIC_V1, ConfigDict - - -class BaseModel(_models.BaseModel): - if PYDANTIC_V1: - - class Config(pydantic.BaseConfig): # type: ignore - extra: Any = pydantic.Extra.ignore # type: ignore - arbitrary_types_allowed: bool = True - else: - model_config: ClassVar[ConfigDict] = ConfigDict(extra="ignore", arbitrary_types_allowed=True) diff --git a/src/openai/cli/_progress.py b/src/openai/cli/_progress.py deleted file mode 100644 index 8a7f2525de..0000000000 --- a/src/openai/cli/_progress.py +++ /dev/null @@ -1,59 +0,0 @@ -from __future__ import annotations - -import io -from typing import Callable -from typing_extensions import override - - -class CancelledError(Exception): - def __init__(self, msg: str) -> None: - self.msg = msg - super().__init__(msg) - - @override - def __str__(self) -> str: - return self.msg - - __repr__ = __str__ - - -class BufferReader(io.BytesIO): - def __init__(self, buf: bytes = b"", desc: str | None = None) -> None: - super().__init__(buf) - self._len = len(buf) - self._progress = 0 - self._callback = progress(len(buf), desc=desc) - - def __len__(self) -> int: - return self._len - - @override - def read(self, n: int | None = -1) -> bytes: - chunk = io.BytesIO.read(self, n) - self._progress += len(chunk) - - try: - self._callback(self._progress) - except Exception as e: # catches exception from the callback - raise CancelledError("The upload was cancelled: {}".format(e)) from e - - return chunk - - -def progress(total: float, desc: str | None) -> Callable[[float], None]: - import tqdm - - meter = tqdm.tqdm(total=total, unit_scale=True, desc=desc) - - def incr(progress: float) -> None: - meter.n = progress - if progress == total: - meter.close() - else: - meter.refresh() - - return incr - - -def MB(i: int) -> int: - return int(i // 1024**2) diff --git a/src/openai/cli/_tools/__init__.py b/src/openai/cli/_tools/__init__.py deleted file mode 100644 index 56a0260a6d..0000000000 --- a/src/openai/cli/_tools/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from ._main import register_commands as register_commands diff --git a/src/openai/cli/_tools/_main.py b/src/openai/cli/_tools/_main.py deleted file mode 100644 index bd6cda408f..0000000000 --- a/src/openai/cli/_tools/_main.py +++ /dev/null @@ -1,17 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING -from argparse import ArgumentParser - -from . import migrate, fine_tunes - -if TYPE_CHECKING: - from argparse import _SubParsersAction - - -def register_commands(parser: ArgumentParser, subparser: _SubParsersAction[ArgumentParser]) -> None: - migrate.register(subparser) - - namespaced = parser.add_subparsers(title="Tools", help="Convenience client side tools") - - fine_tunes.register(namespaced) diff --git a/src/openai/cli/_tools/fine_tunes.py b/src/openai/cli/_tools/fine_tunes.py deleted file mode 100644 index 2128b88952..0000000000 --- a/src/openai/cli/_tools/fine_tunes.py +++ /dev/null @@ -1,63 +0,0 @@ -from __future__ import annotations - -import sys -from typing import TYPE_CHECKING -from argparse import ArgumentParser - -from .._models import BaseModel -from ...lib._validators import ( - get_validators, - write_out_file, - read_any_format, - apply_validators, - apply_necessary_remediation, -) - -if TYPE_CHECKING: - from argparse import _SubParsersAction - - -def register(subparser: _SubParsersAction[ArgumentParser]) -> None: - sub = subparser.add_parser("fine_tunes.prepare_data") - sub.add_argument( - "-f", - "--file", - required=True, - help="JSONL, JSON, CSV, TSV, TXT or XLSX file containing prompt-completion examples to be analyzed." - "This should be the local file path.", - ) - sub.add_argument( - "-q", - "--quiet", - required=False, - action="store_true", - help="Auto accepts all suggestions, without asking for user input. To be used within scripts.", - ) - sub.set_defaults(func=prepare_data, args_model=PrepareDataArgs) - - -class PrepareDataArgs(BaseModel): - file: str - - quiet: bool - - -def prepare_data(args: PrepareDataArgs) -> None: - sys.stdout.write("Analyzing...\n") - fname = args.file - auto_accept = args.quiet - df, remediation = read_any_format(fname) - apply_necessary_remediation(None, remediation) - - validators = get_validators() - - assert df is not None - - apply_validators( - df, - fname, - remediation, - validators, - auto_accept, - write_out_file_func=write_out_file, - ) diff --git a/src/openai/cli/_tools/migrate.py b/src/openai/cli/_tools/migrate.py deleted file mode 100644 index 841b777528..0000000000 --- a/src/openai/cli/_tools/migrate.py +++ /dev/null @@ -1,164 +0,0 @@ -from __future__ import annotations - -import os -import sys -import shutil -import tarfile -import platform -import subprocess -from typing import TYPE_CHECKING, List -from pathlib import Path -from argparse import ArgumentParser - -import httpx - -from .._errors import CLIError, SilentCLIError -from .._models import BaseModel - -if TYPE_CHECKING: - from argparse import _SubParsersAction - - -def register(subparser: _SubParsersAction[ArgumentParser]) -> None: - sub = subparser.add_parser("migrate") - sub.set_defaults(func=migrate, args_model=MigrateArgs, allow_unknown_args=True) - - sub = subparser.add_parser("grit") - sub.set_defaults(func=grit, args_model=GritArgs, allow_unknown_args=True) - - -class GritArgs(BaseModel): - # internal - unknown_args: List[str] = [] - - -def grit(args: GritArgs) -> None: - grit_path = install() - - try: - subprocess.check_call([grit_path, *args.unknown_args]) - except subprocess.CalledProcessError: - # stdout and stderr are forwarded by subprocess so an error will already - # have been displayed - raise SilentCLIError() from None - - -class MigrateArgs(BaseModel): - # internal - unknown_args: List[str] = [] - - -def migrate(args: MigrateArgs) -> None: - grit_path = install() - - try: - subprocess.check_call([grit_path, "apply", "openai", *args.unknown_args]) - except subprocess.CalledProcessError: - # stdout and stderr are forwarded by subprocess so an error will already - # have been displayed - raise SilentCLIError() from None - - -# handles downloading the Grit CLI until they provide their own PyPi package - -KEYGEN_ACCOUNT = "custodian-dev" - - -def _cache_dir() -> Path: - xdg = os.environ.get("XDG_CACHE_HOME") - if xdg is not None: - return Path(xdg) - - return Path.home() / ".cache" - - -def _debug(message: str) -> None: - if not os.environ.get("DEBUG"): - return - - sys.stdout.write(f"[DEBUG]: {message}\n") - - -def install() -> Path: - """Installs the Grit CLI and returns the location of the binary""" - if sys.platform == "win32": - raise CLIError("Windows is not supported yet in the migration CLI") - - _debug("Using Grit installer from GitHub") - - platform = "apple-darwin" if sys.platform == "darwin" else "unknown-linux-gnu" - - dir_name = _cache_dir() / "openai-python" - install_dir = dir_name / ".install" - target_dir = install_dir / "bin" - - target_path = target_dir / "grit" - temp_file = target_dir / "grit.tmp" - - if target_path.exists(): - _debug(f"{target_path} already exists") - sys.stdout.flush() - return target_path - - _debug(f"Using Grit CLI path: {target_path}") - - target_dir.mkdir(parents=True, exist_ok=True) - - if temp_file.exists(): - temp_file.unlink() - - arch = _get_arch() - _debug(f"Using architecture {arch}") - - file_name = f"grit-{arch}-{platform}" - download_url = f"https://github.com/getgrit/gritql/releases/latest/download/{file_name}.tar.gz" - - sys.stdout.write(f"Downloading Grit CLI from {download_url}\n") - with httpx.Client() as client: - download_response = client.get(download_url, follow_redirects=True) - if download_response.status_code != 200: - raise CLIError(f"Failed to download Grit CLI from {download_url}") - with open(temp_file, "wb") as file: - for chunk in download_response.iter_bytes(): - file.write(chunk) - - unpacked_dir = target_dir / "cli-bin" - unpacked_dir.mkdir(parents=True, exist_ok=True) - - with tarfile.open(temp_file, "r:gz") as archive: - if sys.version_info >= (3, 12): - archive.extractall(unpacked_dir, filter="data") - else: - archive.extractall(unpacked_dir) - - _move_files_recursively(unpacked_dir, target_dir) - - shutil.rmtree(unpacked_dir) - os.remove(temp_file) - os.chmod(target_path, 0o755) - - sys.stdout.flush() - - return target_path - - -def _move_files_recursively(source_dir: Path, target_dir: Path) -> None: - for item in source_dir.iterdir(): - if item.is_file(): - item.rename(target_dir / item.name) - elif item.is_dir(): - _move_files_recursively(item, target_dir) - - -def _get_arch() -> str: - architecture = platform.machine().lower() - - # Map the architecture names to Grit equivalents - arch_map = { - "x86_64": "x86_64", - "amd64": "x86_64", - "armv7l": "aarch64", - "arm64": "aarch64", - } - - return arch_map.get(architecture, architecture) diff --git a/src/openai/cli/_utils.py b/src/openai/cli/_utils.py deleted file mode 100644 index 673eed613c..0000000000 --- a/src/openai/cli/_utils.py +++ /dev/null @@ -1,45 +0,0 @@ -from __future__ import annotations - -import sys - -import openai - -from .. import OpenAI, _load_client -from .._compat import model_json -from .._models import BaseModel - - -class Colors: - HEADER = "\033[95m" - OKBLUE = "\033[94m" - OKGREEN = "\033[92m" - WARNING = "\033[93m" - FAIL = "\033[91m" - ENDC = "\033[0m" - BOLD = "\033[1m" - UNDERLINE = "\033[4m" - - -def get_client() -> OpenAI: - return _load_client() - - -def organization_info() -> str: - organization = openai.organization - if organization is not None: - return "[organization={}] ".format(organization) - - return "" - - -def print_model(model: BaseModel) -> None: - sys.stdout.write(model_json(model, indent=2) + "\n") - - -def can_use_http2() -> bool: - try: - import h2 # type: ignore # noqa - except ImportError: - return False - - return True From d07d4a8b1611cea5cd2e345dbc09882d61bdcab4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 6 May 2026 14:48:00 +0000 Subject: [PATCH 730/769] release: 2.35.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 20 ++++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 7a1c4674e4..517b0cf98a 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.34.0" + ".": "2.35.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 237a8c00a4..462cb2c24d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,25 @@ # Changelog +## 2.35.0 (2026-05-06) + +Full Changelog: [v2.34.0...v2.35.0](https://github.com/openai/openai-python/compare/v2.34.0...v2.35.0) + +### Features + +* **api:** launch realtime translate + update image 2 ([0ba55d7](https://github.com/openai/openai-python/commit/0ba55d7569565045426e1587906a70d5682a4bba)) +* **api:** manual updates ([72bf67a](https://github.com/openai/openai-python/commit/72bf67acbc9f030c20db3d5a1a74ea6d67d55f51)) + + +### Chores + +* remove legacy python cli ([32f36e4](https://github.com/openai/openai-python/commit/32f36e447d02c3124af8ab48fcc3537df2fed66e)) +* rename legacy python cli entrypoint ([a3b182d](https://github.com/openai/openai-python/commit/a3b182d6d2c2e6fe1d53ca7550b2d43e0f8b2cd3)) + + +### Documentation + +* **api:** update top_logprobs parameter description across chat and responses ([f9d339f](https://github.com/openai/openai-python/commit/f9d339fcea63feaa1bdf918a4599f2b032c83517)) + ## 2.34.0 (2026-05-04) Full Changelog: [v2.33.0...v2.34.0](https://github.com/openai/openai-python/compare/v2.33.0...v2.34.0) diff --git a/pyproject.toml b/pyproject.toml index 1f7c145039..1313a78507 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.34.0" +version = "2.35.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 857aeb7dff..e2c1c47531 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__ = "2.34.0" # x-release-please-version +__version__ = "2.35.0" # x-release-please-version From 45ac986243ac038f12b47ada0578b25e6e94523b Mon Sep 17 00:00:00 2001 From: Alex Chang Date: Wed, 6 May 2026 11:46:19 -0400 Subject: [PATCH 731/769] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 462cb2c24d..add3d25f2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ Full Changelog: [v2.34.0...v2.35.0](https://github.com/openai/openai-python/comp ### Features -* **api:** launch realtime translate + update image 2 ([0ba55d7](https://github.com/openai/openai-python/commit/0ba55d7569565045426e1587906a70d5682a4bba)) +* **api:** update image 2 ([0ba55d7](https://github.com/openai/openai-python/commit/0ba55d7569565045426e1587906a70d5682a4bba)) * **api:** manual updates ([72bf67a](https://github.com/openai/openai-python/commit/72bf67acbc9f030c20db3d5a1a74ea6d67d55f51)) From 99b9c422f385aa5126b6b525f066a9750e463e1e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 6 May 2026 20:58:07 +0000 Subject: [PATCH 732/769] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 201feabd36..d0a34eab82 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 233 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-578515408e7ee6ac115f3768b358ff2cd4f5699cbfb527fe58b19806e7d1f713.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-feda36af0554900ba4ab2b74d82db104f65cfcddf1eef391c55fec82182414f3.yml openapi_spec_hash: b2df68d6233a18b475590978f5682c04 -config_hash: c6cf65d9b19a16ce4313602a2204d48f +config_hash: 632ca30e38686c90bef7622b1a2009ce From 14b8afce7f17a9748a3d2946eee4d2d0b180e1d8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 6 May 2026 21:26:00 +0000 Subject: [PATCH 733/769] fix(api): fix imagegen `size` enum regression --- .stats.yml | 6 +- src/openai/resources/images.py | 80 ++++++++++++++++++----- src/openai/types/image_edit_params.py | 2 +- src/openai/types/image_generate_params.py | 6 +- src/openai/types/responses/tool.py | 2 +- src/openai/types/responses/tool_param.py | 2 +- tests/api_resources/test_images.py | 16 ++--- 7 files changed, 83 insertions(+), 31 deletions(-) diff --git a/.stats.yml b/.stats.yml index d0a34eab82..f3c3b26134 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 233 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-feda36af0554900ba4ab2b74d82db104f65cfcddf1eef391c55fec82182414f3.yml -openapi_spec_hash: b2df68d6233a18b475590978f5682c04 -config_hash: 632ca30e38686c90bef7622b1a2009ce +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-84d31411083374ec6cdb4a722f8b8b83c1230741157306b1ca7ba1a3cf246672.yml +openapi_spec_hash: 051fce676f959b8207e2317225ec4bdc +config_hash: a2916f18a94ff65c8116ca2fe3256f10 diff --git a/src/openai/resources/images.py b/src/openai/resources/images.py index 6ac622ee1e..8140b5863f 100644 --- a/src/openai/resources/images.py +++ b/src/openai/resources/images.py @@ -141,7 +141,8 @@ def edit( partial_images: Optional[int] | Omit = omit, quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | Omit = omit, response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[str] | Omit = omit, + size: Union[str, Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"], None] + | Omit = omit, stream: Optional[Literal[False]] | Omit = omit, user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -271,7 +272,8 @@ def edit( partial_images: Optional[int] | Omit = omit, quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | Omit = omit, response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[str] | Omit = omit, + size: Union[str, Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"], None] + | Omit = omit, user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -400,7 +402,8 @@ def edit( partial_images: Optional[int] | Omit = omit, quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | Omit = omit, response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[str] | Omit = omit, + size: Union[str, Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"], None] + | Omit = omit, user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -528,7 +531,8 @@ def edit( partial_images: Optional[int] | Omit = omit, quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | Omit = omit, response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[str] | Omit = omit, + size: Union[str, Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"], None] + | Omit = omit, stream: Optional[Literal[False]] | Literal[True] | Omit = omit, user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -596,7 +600,12 @@ def generate( partial_images: Optional[int] | Omit = omit, quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | Omit = omit, response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[str] | Omit = omit, + size: Union[ + str, + Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"], + None, + ] + | Omit = omit, stream: Optional[Literal[False]] | Omit = omit, style: Optional[Literal["vivid", "natural"]] | Omit = omit, user: str | Omit = omit, @@ -718,7 +727,12 @@ def generate( partial_images: Optional[int] | Omit = omit, quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | Omit = omit, response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[str] | Omit = omit, + size: Union[ + str, + Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"], + None, + ] + | Omit = omit, style: Optional[Literal["vivid", "natural"]] | Omit = omit, user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -839,7 +853,12 @@ def generate( partial_images: Optional[int] | Omit = omit, quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | Omit = omit, response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[str] | Omit = omit, + size: Union[ + str, + Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"], + None, + ] + | Omit = omit, style: Optional[Literal["vivid", "natural"]] | Omit = omit, user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -959,7 +978,12 @@ def generate( partial_images: Optional[int] | Omit = omit, quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | Omit = omit, response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[str] | Omit = omit, + size: Union[ + str, + Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"], + None, + ] + | Omit = omit, stream: Optional[Literal[False]] | Literal[True] | Omit = omit, style: Optional[Literal["vivid", "natural"]] | Omit = omit, user: str | Omit = omit, @@ -1122,7 +1146,8 @@ async def edit( partial_images: Optional[int] | Omit = omit, quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | Omit = omit, response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[str] | Omit = omit, + size: Union[str, Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"], None] + | Omit = omit, stream: Optional[Literal[False]] | Omit = omit, user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -1252,7 +1277,8 @@ async def edit( partial_images: Optional[int] | Omit = omit, quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | Omit = omit, response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[str] | Omit = omit, + size: Union[str, Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"], None] + | Omit = omit, user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -1381,7 +1407,8 @@ async def edit( partial_images: Optional[int] | Omit = omit, quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | Omit = omit, response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[str] | Omit = omit, + size: Union[str, Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"], None] + | Omit = omit, user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -1509,7 +1536,8 @@ async def edit( partial_images: Optional[int] | Omit = omit, quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | Omit = omit, response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[str] | Omit = omit, + size: Union[str, Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"], None] + | Omit = omit, stream: Optional[Literal[False]] | Literal[True] | Omit = omit, user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -1577,7 +1605,12 @@ async def generate( partial_images: Optional[int] | Omit = omit, quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | Omit = omit, response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[str] | Omit = omit, + size: Union[ + str, + Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"], + None, + ] + | Omit = omit, stream: Optional[Literal[False]] | Omit = omit, style: Optional[Literal["vivid", "natural"]] | Omit = omit, user: str | Omit = omit, @@ -1699,7 +1732,12 @@ async def generate( partial_images: Optional[int] | Omit = omit, quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | Omit = omit, response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[str] | Omit = omit, + size: Union[ + str, + Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"], + None, + ] + | Omit = omit, style: Optional[Literal["vivid", "natural"]] | Omit = omit, user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -1820,7 +1858,12 @@ async def generate( partial_images: Optional[int] | Omit = omit, quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | Omit = omit, response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[str] | Omit = omit, + size: Union[ + str, + Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"], + None, + ] + | Omit = omit, style: Optional[Literal["vivid", "natural"]] | Omit = omit, user: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -1940,7 +1983,12 @@ async def generate( partial_images: Optional[int] | Omit = omit, quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | Omit = omit, response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[str] | Omit = omit, + size: Union[ + str, + Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"], + None, + ] + | Omit = omit, stream: Optional[Literal[False]] | Literal[True] | Omit = omit, style: Optional[Literal["vivid", "natural"]] | Omit = omit, user: str | Omit = omit, diff --git a/src/openai/types/image_edit_params.py b/src/openai/types/image_edit_params.py index 3c0e41d572..1bd6dfd320 100644 --- a/src/openai/types/image_edit_params.py +++ b/src/openai/types/image_edit_params.py @@ -114,7 +114,7 @@ class ImageEditParamsBase(TypedDict, total=False): base64-encoded images. """ - size: Optional[str] + size: Union[str, Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"], None] """The size of the generated images. For `gpt-image-2` and `gpt-image-2-2026-04-21`, arbitrary resolutions are diff --git a/src/openai/types/image_generate_params.py b/src/openai/types/image_generate_params.py index 4ac573ce61..0c5070b130 100644 --- a/src/openai/types/image_generate_params.py +++ b/src/openai/types/image_generate_params.py @@ -100,7 +100,11 @@ class ImageGenerateParamsBase(TypedDict, total=False): models, which always return base64-encoded images. """ - size: Optional[str] + size: Union[ + str, + Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"], + None, + ] """The size of the generated images. For `gpt-image-2` and `gpt-image-2-2026-04-21`, arbitrary resolutions are diff --git a/src/openai/types/responses/tool.py b/src/openai/types/responses/tool.py index 839ed26ba2..92e6fb29a7 100644 --- a/src/openai/types/responses/tool.py +++ b/src/openai/types/responses/tool.py @@ -315,7 +315,7 @@ class ImageGeneration(BaseModel): One of `low`, `medium`, `high`, or `auto`. Default: `auto`. """ - size: Optional[str] = None + size: Union[str, Literal["1024x1024", "1024x1536", "1536x1024", "auto"], None] = None """The size of the generated images. For `gpt-image-2` and `gpt-image-2-2026-04-21`, arbitrary resolutions are diff --git a/src/openai/types/responses/tool_param.py b/src/openai/types/responses/tool_param.py index cdbf5bd1ff..7a9a566b16 100644 --- a/src/openai/types/responses/tool_param.py +++ b/src/openai/types/responses/tool_param.py @@ -314,7 +314,7 @@ class ImageGeneration(TypedDict, total=False): One of `low`, `medium`, `high`, or `auto`. Default: `auto`. """ - size: str + size: Union[str, Literal["1024x1024", "1024x1536", "1536x1024", "auto"]] """The size of the generated images. For `gpt-image-2` and `gpt-image-2-2026-04-21`, arbitrary resolutions are diff --git a/tests/api_resources/test_images.py b/tests/api_resources/test_images.py index 6f6e700517..fa8054c01d 100644 --- a/tests/api_resources/test_images.py +++ b/tests/api_resources/test_images.py @@ -83,7 +83,7 @@ def test_method_edit_with_all_params_overload_1(self, client: OpenAI) -> None: partial_images=1, quality="high", response_format="url", - size="1024x1024", + size="256x256", stream=False, user="user-1234", ) @@ -140,7 +140,7 @@ def test_method_edit_with_all_params_overload_2(self, client: OpenAI) -> None: partial_images=1, quality="high", response_format="url", - size="1024x1024", + size="256x256", user="user-1234", ) image_stream.response.close() @@ -192,7 +192,7 @@ def test_method_generate_with_all_params_overload_1(self, client: OpenAI) -> Non partial_images=1, quality="medium", response_format="url", - size="1024x1024", + size="auto", stream=False, style="vivid", user="user-1234", @@ -245,7 +245,7 @@ def test_method_generate_with_all_params_overload_2(self, client: OpenAI) -> Non partial_images=1, quality="medium", response_format="url", - size="1024x1024", + size="auto", style="vivid", user="user-1234", ) @@ -348,7 +348,7 @@ async def test_method_edit_with_all_params_overload_1(self, async_client: AsyncO partial_images=1, quality="high", response_format="url", - size="1024x1024", + size="256x256", stream=False, user="user-1234", ) @@ -405,7 +405,7 @@ async def test_method_edit_with_all_params_overload_2(self, async_client: AsyncO partial_images=1, quality="high", response_format="url", - size="1024x1024", + size="256x256", user="user-1234", ) await image_stream.response.aclose() @@ -457,7 +457,7 @@ async def test_method_generate_with_all_params_overload_1(self, async_client: As partial_images=1, quality="medium", response_format="url", - size="1024x1024", + size="auto", stream=False, style="vivid", user="user-1234", @@ -510,7 +510,7 @@ async def test_method_generate_with_all_params_overload_2(self, async_client: As partial_images=1, quality="medium", response_format="url", - size="1024x1024", + size="auto", style="vivid", user="user-1234", ) From 5e8f09c2c8f65d2e93722270963f4a19a760736f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 6 May 2026 21:26:53 +0000 Subject: [PATCH 734/769] release: 2.35.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 517b0cf98a..0c6e1a8623 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.35.0" + ".": "2.35.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index add3d25f2a..5b5e6afda7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 2.35.1 (2026-05-06) + +Full Changelog: [v2.35.0...v2.35.1](https://github.com/openai/openai-python/compare/v2.35.0...v2.35.1) + +### Bug Fixes + +* **api:** fix imagegen `size` enum regression ([4484653](https://github.com/openai/openai-python/commit/44846536bc3b02c393daa5bae70a85de04c7f621)) + ## 2.35.0 (2026-05-06) Full Changelog: [v2.34.0...v2.35.0](https://github.com/openai/openai-python/compare/v2.34.0...v2.35.0) diff --git a/pyproject.toml b/pyproject.toml index 1313a78507..cb8c01191d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.35.0" +version = "2.35.1" 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 e2c1c47531..7f151cf0cd 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__ = "2.35.0" # x-release-please-version +__version__ = "2.35.1" # x-release-please-version From 12fc3e41f28ae433f41a88d71e1a29f6745c7640 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 6 May 2026 21:54:11 +0000 Subject: [PATCH 735/769] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index f3c3b26134..ee0acc70c1 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 233 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-84d31411083374ec6cdb4a722f8b8b83c1230741157306b1ca7ba1a3cf246672.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-3c2b379de00a99101907866ecbe816bff4957f949691e641c6a4e809559386db.yml openapi_spec_hash: 051fce676f959b8207e2317225ec4bdc -config_hash: a2916f18a94ff65c8116ca2fe3256f10 +config_hash: 0970c9a530a7880eb4ca75ff96bcf61b From 19cda34ccc9fee540bad3523b223da3ae85f273c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 6 May 2026 22:21:03 +0000 Subject: [PATCH 736/769] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index ee0acc70c1..324998514f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 233 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-3c2b379de00a99101907866ecbe816bff4957f949691e641c6a4e809559386db.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-2388e437ea21ac4b945762c2c3d65d276f26014e7aee70e173e921193362b2b9.yml openapi_spec_hash: 051fce676f959b8207e2317225ec4bdc -config_hash: 0970c9a530a7880eb4ca75ff96bcf61b +config_hash: c8fd630a06acd84b4384186b926e3277 From 2f1dd2814f8d5af989dfa2077f9f748d94fd472a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 6 May 2026 22:31:32 +0000 Subject: [PATCH 737/769] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 324998514f..8422e8dff5 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 233 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-2388e437ea21ac4b945762c2c3d65d276f26014e7aee70e173e921193362b2b9.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-2f2e274f51df9ef4e7531b9e5c597bb9cd182fc56bb87ca617e2677a6abda72c.yml openapi_spec_hash: 051fce676f959b8207e2317225ec4bdc -config_hash: c8fd630a06acd84b4384186b926e3277 +config_hash: 5238a19104ff62c65ed1cb4b0aa46f4f From 13c639cc7d57e4fbd4406563511e15eeb88a54b2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 7 May 2026 14:52:31 +0000 Subject: [PATCH 738/769] feat(api): manual updates --- .stats.yml | 6 +++--- src/openai/resources/realtime/api.md | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/.stats.yml b/.stats.yml index 8422e8dff5..19bfc5fd04 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 233 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-2f2e274f51df9ef4e7531b9e5c597bb9cd182fc56bb87ca617e2677a6abda72c.yml -openapi_spec_hash: 051fce676f959b8207e2317225ec4bdc -config_hash: 5238a19104ff62c65ed1cb4b0aa46f4f +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-08cb8ed18dfe4a9fa518e278576d3cfe5710cb5c22789cf80826c900569bcf56.yml +openapi_spec_hash: 20f820c94f54741b75d719f6a7371c12 +config_hash: f291a449469edfe61a28424e548899b2 diff --git a/src/openai/resources/realtime/api.md b/src/openai/resources/realtime/api.md index 1a178384db..1d1b23430b 100644 --- a/src/openai/resources/realtime/api.md +++ b/src/openai/resources/realtime/api.md @@ -77,6 +77,22 @@ from openai.types.realtime import ( RealtimeTranscriptionSessionAudioInput, RealtimeTranscriptionSessionAudioInputTurnDetection, RealtimeTranscriptionSessionCreateRequest, + RealtimeTranslationClientEvent, + RealtimeTranslationClientSecretCreateRequest, + RealtimeTranslationClientSecretCreateResponse, + RealtimeTranslationInputAudioBufferAppendEvent, + RealtimeTranslationInputTranscriptDeltaEvent, + RealtimeTranslationOutputAudioDeltaEvent, + RealtimeTranslationOutputTranscriptDeltaEvent, + RealtimeTranslationServerEvent, + RealtimeTranslationSession, + RealtimeTranslationSessionCloseEvent, + RealtimeTranslationSessionClosedEvent, + RealtimeTranslationSessionCreateRequest, + RealtimeTranslationSessionCreatedEvent, + RealtimeTranslationSessionUpdateEvent, + RealtimeTranslationSessionUpdateRequest, + RealtimeTranslationSessionUpdatedEvent, RealtimeTruncation, RealtimeTruncationRetentionRatio, ResponseAudioDeltaEvent, From 8fe0ab87e67eeb3cc27426b50093845229520f0e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 7 May 2026 17:20:33 +0000 Subject: [PATCH 739/769] feat(api): realtime 2 --- .stats.yml | 6 ++-- src/openai/resources/realtime/api.md | 3 +- src/openai/resources/realtime/calls.py | 21 ++++++++++++ src/openai/types/realtime/__init__.py | 4 ++- .../types/realtime/audio_transcription.py | 15 +++++++-- .../realtime/audio_transcription_param.py | 15 +++++++-- .../types/realtime/call_accept_params.py | 11 +++++++ .../realtime/realtime_audio_config_input.py | 3 ++ .../realtime_audio_config_input_param.py | 3 ++ .../types/realtime/realtime_reasoning.py | 18 ++++++++++ .../realtime/realtime_reasoning_effort.py | 7 ++++ .../realtime/realtime_reasoning_param.py | 19 +++++++++++ .../realtime_response_create_params.py | 10 ++++++ .../realtime_response_create_params_param.py | 10 ++++++ .../realtime_session_client_secret.py | 22 ------------- .../realtime_session_create_request.py | 11 +++++++ .../realtime_session_create_request_param.py | 11 +++++++ .../realtime_session_create_response.py | 33 +++++++++---------- ...ltime_transcription_session_audio_input.py | 3 ++ ...transcription_session_audio_input_param.py | 3 ++ ...e_transcription_session_create_response.py | 3 +- ...me_transcription_session_turn_detection.py | 2 +- tests/api_resources/realtime/test_calls.py | 12 +++++++ .../realtime/test_client_secrets.py | 6 ++++ 24 files changed, 198 insertions(+), 53 deletions(-) create mode 100644 src/openai/types/realtime/realtime_reasoning.py create mode 100644 src/openai/types/realtime/realtime_reasoning_effort.py create mode 100644 src/openai/types/realtime/realtime_reasoning_param.py delete mode 100644 src/openai/types/realtime/realtime_session_client_secret.py diff --git a/.stats.yml b/.stats.yml index 19bfc5fd04..9b6dc7e58b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 233 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-08cb8ed18dfe4a9fa518e278576d3cfe5710cb5c22789cf80826c900569bcf56.yml -openapi_spec_hash: 20f820c94f54741b75d719f6a7371c12 -config_hash: f291a449469edfe61a28424e548899b2 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-371f497afe4d6070f6e252e5febbe8f453c7058a8dff0c26a01b4d88442a4ac2.yml +openapi_spec_hash: d39f46e8fda45f77096448105efd175a +config_hash: b64135fff1fe9cf4069b9ecf59ae8b07 diff --git a/src/openai/resources/realtime/api.md b/src/openai/resources/realtime/api.md index 1d1b23430b..2be1b85cbf 100644 --- a/src/openai/resources/realtime/api.md +++ b/src/openai/resources/realtime/api.md @@ -58,6 +58,8 @@ from openai.types.realtime import ( RealtimeMcpToolCall, RealtimeMcpToolExecutionError, RealtimeMcphttpError, + RealtimeReasoning, + RealtimeReasoningEffort, RealtimeResponse, RealtimeResponseCreateAudioOutput, RealtimeResponseCreateMcpTool, @@ -130,7 +132,6 @@ Types: ```python from openai.types.realtime import ( - RealtimeSessionClientSecret, RealtimeSessionCreateResponse, RealtimeTranscriptionSessionCreateResponse, RealtimeTranscriptionSessionTurnDetection, diff --git a/src/openai/resources/realtime/calls.py b/src/openai/resources/realtime/calls.py index 7a4fcc0110..0674b2b010 100644 --- a/src/openai/resources/realtime/calls.py +++ b/src/openai/resources/realtime/calls.py @@ -28,6 +28,7 @@ call_reject_params, ) from ...types.responses.response_prompt_param import ResponsePromptParam +from ...types.realtime.realtime_reasoning_param import RealtimeReasoningParam from ...types.realtime.realtime_truncation_param import RealtimeTruncationParam from ...types.realtime.realtime_audio_config_param import RealtimeAudioConfigParam from ...types.realtime.realtime_tools_config_param import RealtimeToolsConfigParam @@ -121,6 +122,7 @@ def accept( Literal[ "gpt-realtime", "gpt-realtime-1.5", + "gpt-realtime-2", "gpt-realtime-2025-08-28", "gpt-4o-realtime-preview", "gpt-4o-realtime-preview-2024-10-01", @@ -139,7 +141,9 @@ def accept( ] | Omit = omit, output_modalities: List[Literal["text", "audio"]] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, + reasoning: RealtimeReasoningParam | Omit = omit, tool_choice: RealtimeToolChoiceConfigParam | Omit = omit, tools: RealtimeToolsConfigParam | Omit = omit, tracing: Optional[RealtimeTracingConfigParam] | Omit = omit, @@ -188,9 +192,14 @@ def accept( can be used to make the model respond with text only. It is not possible to request both `text` and `audio` at the same time. + parallel_tool_calls: Whether the model may call multiple tools in parallel. Only supported by + reasoning Realtime models such as `gpt-realtime-2`. + prompt: Reference to a prompt template and its variables. [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). + reasoning: Configuration for reasoning-capable Realtime models such as `gpt-realtime-2`. + tool_choice: How the model chooses tools. Provide one of the string modes or force a specific function/MCP tool. @@ -245,7 +254,9 @@ def accept( "max_output_tokens": max_output_tokens, "model": model, "output_modalities": output_modalities, + "parallel_tool_calls": parallel_tool_calls, "prompt": prompt, + "reasoning": reasoning, "tool_choice": tool_choice, "tools": tools, "tracing": tracing, @@ -471,6 +482,7 @@ async def accept( Literal[ "gpt-realtime", "gpt-realtime-1.5", + "gpt-realtime-2", "gpt-realtime-2025-08-28", "gpt-4o-realtime-preview", "gpt-4o-realtime-preview-2024-10-01", @@ -489,7 +501,9 @@ async def accept( ] | Omit = omit, output_modalities: List[Literal["text", "audio"]] | Omit = omit, + parallel_tool_calls: bool | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, + reasoning: RealtimeReasoningParam | Omit = omit, tool_choice: RealtimeToolChoiceConfigParam | Omit = omit, tools: RealtimeToolsConfigParam | Omit = omit, tracing: Optional[RealtimeTracingConfigParam] | Omit = omit, @@ -538,9 +552,14 @@ async def accept( can be used to make the model respond with text only. It is not possible to request both `text` and `audio` at the same time. + parallel_tool_calls: Whether the model may call multiple tools in parallel. Only supported by + reasoning Realtime models such as `gpt-realtime-2`. + prompt: Reference to a prompt template and its variables. [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). + reasoning: Configuration for reasoning-capable Realtime models such as `gpt-realtime-2`. + tool_choice: How the model chooses tools. Provide one of the string modes or force a specific function/MCP tool. @@ -595,7 +614,9 @@ async def accept( "max_output_tokens": max_output_tokens, "model": model, "output_modalities": output_modalities, + "parallel_tool_calls": parallel_tool_calls, "prompt": prompt, + "reasoning": reasoning, "tool_choice": tool_choice, "tools": tools, "tracing": tracing, diff --git a/src/openai/types/realtime/__init__.py b/src/openai/types/realtime/__init__.py index c2a141d727..d7a087ba9a 100644 --- a/src/openai/types/realtime/__init__.py +++ b/src/openai/types/realtime/__init__.py @@ -9,6 +9,7 @@ from .call_accept_params import CallAcceptParams as CallAcceptParams from .call_create_params import CallCreateParams as CallCreateParams from .call_reject_params import CallRejectParams as CallRejectParams +from .realtime_reasoning import RealtimeReasoning as RealtimeReasoning from .audio_transcription import AudioTranscription as AudioTranscription from .log_prob_properties import LogProbProperties as LogProbProperties from .realtime_truncation import RealtimeTruncation as RealtimeTruncation @@ -38,11 +39,13 @@ from .realtime_response_usage import RealtimeResponseUsage as RealtimeResponseUsage from .realtime_tracing_config import RealtimeTracingConfig as RealtimeTracingConfig from .mcp_list_tools_completed import McpListToolsCompleted as McpListToolsCompleted +from .realtime_reasoning_param import RealtimeReasoningParam as RealtimeReasoningParam from .realtime_response_status import RealtimeResponseStatus as RealtimeResponseStatus from .response_mcp_call_failed import ResponseMcpCallFailed as ResponseMcpCallFailed from .response_text_done_event import ResponseTextDoneEvent as ResponseTextDoneEvent from .audio_transcription_param import AudioTranscriptionParam as AudioTranscriptionParam from .rate_limits_updated_event import RateLimitsUpdatedEvent as RateLimitsUpdatedEvent +from .realtime_reasoning_effort import RealtimeReasoningEffort as RealtimeReasoningEffort from .realtime_truncation_param import RealtimeTruncationParam as RealtimeTruncationParam from .response_audio_done_event import ResponseAudioDoneEvent as ResponseAudioDoneEvent from .response_text_delta_event import ResponseTextDeltaEvent as ResponseTextDeltaEvent @@ -75,7 +78,6 @@ from .conversation_item_delete_event import ConversationItemDeleteEvent as ConversationItemDeleteEvent from .input_audio_buffer_clear_event import InputAudioBufferClearEvent as InputAudioBufferClearEvent from .realtime_mcp_approval_response import RealtimeMcpApprovalResponse as RealtimeMcpApprovalResponse -from .realtime_session_client_secret import RealtimeSessionClientSecret as RealtimeSessionClientSecret from .conversation_item_created_event import ConversationItemCreatedEvent as ConversationItemCreatedEvent from .conversation_item_deleted_event import ConversationItemDeletedEvent as ConversationItemDeletedEvent from .input_audio_buffer_append_event import InputAudioBufferAppendEvent as InputAudioBufferAppendEvent diff --git a/src/openai/types/realtime/audio_transcription.py b/src/openai/types/realtime/audio_transcription.py index 0a8c1371e0..45e2e388ca 100644 --- a/src/openai/types/realtime/audio_transcription.py +++ b/src/openai/types/realtime/audio_transcription.py @@ -9,6 +9,13 @@ class AudioTranscription(BaseModel): + delay: Optional[Literal["minimal", "low", "medium", "high", "xhigh"]] = None + """ + Controls how long the model waits before emitting transcription text. Higher + values can improve transcription accuracy at the cost of latency. Only supported + with `gpt-realtime-whisper` in GA Realtime sessions. + """ + language: Optional[str] = None """The language of the input audio. @@ -25,15 +32,16 @@ class AudioTranscription(BaseModel): "gpt-4o-mini-transcribe-2025-12-15", "gpt-4o-transcribe", "gpt-4o-transcribe-diarize", + "gpt-realtime-whisper", ], None, ] = None """The model to use for transcription. Current options are `whisper-1`, `gpt-4o-mini-transcribe`, - `gpt-4o-mini-transcribe-2025-12-15`, `gpt-4o-transcribe`, and - `gpt-4o-transcribe-diarize`. Use `gpt-4o-transcribe-diarize` when you need - diarization with speaker labels. + `gpt-4o-mini-transcribe-2025-12-15`, `gpt-4o-transcribe`, + `gpt-4o-transcribe-diarize`, and `gpt-realtime-whisper`. Use + `gpt-4o-transcribe-diarize` when you need diarization with speaker labels. """ prompt: Optional[str] = None @@ -43,4 +51,5 @@ class AudioTranscription(BaseModel): [prompt is a list of keywords](https://platform.openai.com/docs/guides/speech-to-text#prompting). For `gpt-4o-transcribe` models (excluding `gpt-4o-transcribe-diarize`), the prompt is a free text string, for example "expect words related to technology". + Prompt is not supported with `gpt-realtime-whisper` in GA Realtime sessions. """ diff --git a/src/openai/types/realtime/audio_transcription_param.py b/src/openai/types/realtime/audio_transcription_param.py index 7e60a003ce..9206921542 100644 --- a/src/openai/types/realtime/audio_transcription_param.py +++ b/src/openai/types/realtime/audio_transcription_param.py @@ -9,6 +9,13 @@ class AudioTranscriptionParam(TypedDict, total=False): + delay: Literal["minimal", "low", "medium", "high", "xhigh"] + """ + Controls how long the model waits before emitting transcription text. Higher + values can improve transcription accuracy at the cost of latency. Only supported + with `gpt-realtime-whisper` in GA Realtime sessions. + """ + language: str """The language of the input audio. @@ -25,14 +32,15 @@ class AudioTranscriptionParam(TypedDict, total=False): "gpt-4o-mini-transcribe-2025-12-15", "gpt-4o-transcribe", "gpt-4o-transcribe-diarize", + "gpt-realtime-whisper", ], ] """The model to use for transcription. Current options are `whisper-1`, `gpt-4o-mini-transcribe`, - `gpt-4o-mini-transcribe-2025-12-15`, `gpt-4o-transcribe`, and - `gpt-4o-transcribe-diarize`. Use `gpt-4o-transcribe-diarize` when you need - diarization with speaker labels. + `gpt-4o-mini-transcribe-2025-12-15`, `gpt-4o-transcribe`, + `gpt-4o-transcribe-diarize`, and `gpt-realtime-whisper`. Use + `gpt-4o-transcribe-diarize` when you need diarization with speaker labels. """ prompt: str @@ -42,4 +50,5 @@ class AudioTranscriptionParam(TypedDict, total=False): [prompt is a list of keywords](https://platform.openai.com/docs/guides/speech-to-text#prompting). For `gpt-4o-transcribe` models (excluding `gpt-4o-transcribe-diarize`), the prompt is a free text string, for example "expect words related to technology". + Prompt is not supported with `gpt-realtime-whisper` in GA Realtime sessions. """ diff --git a/src/openai/types/realtime/call_accept_params.py b/src/openai/types/realtime/call_accept_params.py index 1baddbfc2c..b4a48fc8b5 100644 --- a/src/openai/types/realtime/call_accept_params.py +++ b/src/openai/types/realtime/call_accept_params.py @@ -5,6 +5,7 @@ from typing import List, Union, Optional from typing_extensions import Literal, Required, TypedDict +from .realtime_reasoning_param import RealtimeReasoningParam from .realtime_truncation_param import RealtimeTruncationParam from .realtime_audio_config_param import RealtimeAudioConfigParam from .realtime_tools_config_param import RealtimeToolsConfigParam @@ -57,6 +58,7 @@ class CallAcceptParams(TypedDict, total=False): Literal[ "gpt-realtime", "gpt-realtime-1.5", + "gpt-realtime-2", "gpt-realtime-2025-08-28", "gpt-4o-realtime-preview", "gpt-4o-realtime-preview-2024-10-01", @@ -83,12 +85,21 @@ class CallAcceptParams(TypedDict, total=False): only. It is not possible to request both `text` and `audio` at the same time. """ + parallel_tool_calls: bool + """Whether the model may call multiple tools in parallel. + + Only supported by reasoning Realtime models such as `gpt-realtime-2`. + """ + prompt: Optional[ResponsePromptParam] """ Reference to a prompt template and its variables. [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). """ + reasoning: RealtimeReasoningParam + """Configuration for reasoning-capable Realtime models such as `gpt-realtime-2`.""" + tool_choice: RealtimeToolChoiceConfigParam """How the model chooses tools. diff --git a/src/openai/types/realtime/realtime_audio_config_input.py b/src/openai/types/realtime/realtime_audio_config_input.py index 08e1b14601..ba7d211d0d 100644 --- a/src/openai/types/realtime/realtime_audio_config_input.py +++ b/src/openai/types/realtime/realtime_audio_config_input.py @@ -67,4 +67,7 @@ class RealtimeAudioConfigInput(BaseModel): trails off with "uhhm", the model will score a low probability of turn end and wait longer for the user to continue speaking. This can be useful for more natural conversations, but may have a higher latency. + + For `gpt-realtime-whisper` transcription sessions, turn detection must be set to + `null`; VAD is not supported. """ diff --git a/src/openai/types/realtime/realtime_audio_config_input_param.py b/src/openai/types/realtime/realtime_audio_config_input_param.py index 73495e6cd3..5cea9f0efe 100644 --- a/src/openai/types/realtime/realtime_audio_config_input_param.py +++ b/src/openai/types/realtime/realtime_audio_config_input_param.py @@ -69,4 +69,7 @@ class RealtimeAudioConfigInputParam(TypedDict, total=False): trails off with "uhhm", the model will score a low probability of turn end and wait longer for the user to continue speaking. This can be useful for more natural conversations, but may have a higher latency. + + For `gpt-realtime-whisper` transcription sessions, turn detection must be set to + `null`; VAD is not supported. """ diff --git a/src/openai/types/realtime/realtime_reasoning.py b/src/openai/types/realtime/realtime_reasoning.py new file mode 100644 index 0000000000..5d49c9bd0b --- /dev/null +++ b/src/openai/types/realtime/realtime_reasoning.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel +from .realtime_reasoning_effort import RealtimeReasoningEffort + +__all__ = ["RealtimeReasoning"] + + +class RealtimeReasoning(BaseModel): + """Configuration for reasoning-capable Realtime models such as `gpt-realtime-2`.""" + + effort: Optional[RealtimeReasoningEffort] = None + """ + Constrains effort on reasoning for reasoning-capable Realtime models such as + `gpt-realtime-2`. + """ diff --git a/src/openai/types/realtime/realtime_reasoning_effort.py b/src/openai/types/realtime/realtime_reasoning_effort.py new file mode 100644 index 0000000000..dcf9e303a7 --- /dev/null +++ b/src/openai/types/realtime/realtime_reasoning_effort.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["RealtimeReasoningEffort"] + +RealtimeReasoningEffort: TypeAlias = Literal["minimal", "low", "medium", "high", "xhigh"] diff --git a/src/openai/types/realtime/realtime_reasoning_param.py b/src/openai/types/realtime/realtime_reasoning_param.py new file mode 100644 index 0000000000..f6de89c99a --- /dev/null +++ b/src/openai/types/realtime/realtime_reasoning_param.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +from .realtime_reasoning_effort import RealtimeReasoningEffort + +__all__ = ["RealtimeReasoningParam"] + + +class RealtimeReasoningParam(TypedDict, total=False): + """Configuration for reasoning-capable Realtime models such as `gpt-realtime-2`.""" + + effort: RealtimeReasoningEffort + """ + Constrains effort on reasoning for reasoning-capable Realtime models such as + `gpt-realtime-2`. + """ diff --git a/src/openai/types/realtime/realtime_response_create_params.py b/src/openai/types/realtime/realtime_response_create_params.py index deec8c9280..8e20168e34 100644 --- a/src/openai/types/realtime/realtime_response_create_params.py +++ b/src/openai/types/realtime/realtime_response_create_params.py @@ -6,6 +6,7 @@ from ..._models import BaseModel from ..shared.metadata import Metadata from .conversation_item import ConversationItem +from .realtime_reasoning import RealtimeReasoning from .realtime_function_tool import RealtimeFunctionTool from ..responses.response_prompt import ResponsePrompt from ..responses.tool_choice_mcp import ToolChoiceMcp @@ -84,12 +85,21 @@ class RealtimeResponseCreateParams(BaseModel): model. """ + parallel_tool_calls: Optional[bool] = None + """Whether the model may call multiple tools in parallel. + + Only supported by reasoning Realtime models such as `gpt-realtime-2`. + """ + prompt: Optional[ResponsePrompt] = None """ Reference to a prompt template and its variables. [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). """ + reasoning: Optional[RealtimeReasoning] = None + """Configuration for reasoning-capable Realtime models such as `gpt-realtime-2`.""" + tool_choice: Optional[ToolChoice] = None """How the model chooses tools. diff --git a/src/openai/types/realtime/realtime_response_create_params_param.py b/src/openai/types/realtime/realtime_response_create_params_param.py index caad5bc900..aafa3d4e25 100644 --- a/src/openai/types/realtime/realtime_response_create_params_param.py +++ b/src/openai/types/realtime/realtime_response_create_params_param.py @@ -7,6 +7,7 @@ from ..shared_params.metadata import Metadata from .conversation_item_param import ConversationItemParam +from .realtime_reasoning_param import RealtimeReasoningParam from .realtime_function_tool_param import RealtimeFunctionToolParam from ..responses.tool_choice_options import ToolChoiceOptions from ..responses.response_prompt_param import ResponsePromptParam @@ -85,12 +86,21 @@ class RealtimeResponseCreateParamsParam(TypedDict, total=False): model. """ + parallel_tool_calls: bool + """Whether the model may call multiple tools in parallel. + + Only supported by reasoning Realtime models such as `gpt-realtime-2`. + """ + prompt: Optional[ResponsePromptParam] """ Reference to a prompt template and its variables. [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). """ + reasoning: RealtimeReasoningParam + """Configuration for reasoning-capable Realtime models such as `gpt-realtime-2`.""" + tool_choice: ToolChoice """How the model chooses tools. diff --git a/src/openai/types/realtime/realtime_session_client_secret.py b/src/openai/types/realtime/realtime_session_client_secret.py deleted file mode 100644 index 13a12f5502..0000000000 --- a/src/openai/types/realtime/realtime_session_client_secret.py +++ /dev/null @@ -1,22 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel - -__all__ = ["RealtimeSessionClientSecret"] - - -class RealtimeSessionClientSecret(BaseModel): - """Ephemeral key returned by the API.""" - - expires_at: int - """Timestamp for when the token expires. - - Currently, all tokens expire after one minute. - """ - - value: str - """ - Ephemeral key usable in client environments to authenticate connections to the - Realtime API. Use this in client-side environments rather than a standard API - token, which should only be used server-side. - """ diff --git a/src/openai/types/realtime/realtime_session_create_request.py b/src/openai/types/realtime/realtime_session_create_request.py index 163a0d16d8..cf681e99a1 100644 --- a/src/openai/types/realtime/realtime_session_create_request.py +++ b/src/openai/types/realtime/realtime_session_create_request.py @@ -4,6 +4,7 @@ from typing_extensions import Literal from ..._models import BaseModel +from .realtime_reasoning import RealtimeReasoning from .realtime_truncation import RealtimeTruncation from .realtime_audio_config import RealtimeAudioConfig from .realtime_tools_config import RealtimeToolsConfig @@ -58,6 +59,7 @@ class RealtimeSessionCreateRequest(BaseModel): Literal[ "gpt-realtime", "gpt-realtime-1.5", + "gpt-realtime-2", "gpt-realtime-2025-08-28", "gpt-4o-realtime-preview", "gpt-4o-realtime-preview-2024-10-01", @@ -85,12 +87,21 @@ class RealtimeSessionCreateRequest(BaseModel): only. It is not possible to request both `text` and `audio` at the same time. """ + parallel_tool_calls: Optional[bool] = None + """Whether the model may call multiple tools in parallel. + + Only supported by reasoning Realtime models such as `gpt-realtime-2`. + """ + prompt: Optional[ResponsePrompt] = None """ Reference to a prompt template and its variables. [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). """ + reasoning: Optional[RealtimeReasoning] = None + """Configuration for reasoning-capable Realtime models such as `gpt-realtime-2`.""" + tool_choice: Optional[RealtimeToolChoiceConfig] = None """How the model chooses tools. diff --git a/src/openai/types/realtime/realtime_session_create_request_param.py b/src/openai/types/realtime/realtime_session_create_request_param.py index 19c73b909b..ab7de47c3c 100644 --- a/src/openai/types/realtime/realtime_session_create_request_param.py +++ b/src/openai/types/realtime/realtime_session_create_request_param.py @@ -5,6 +5,7 @@ from typing import List, Union, Optional from typing_extensions import Literal, Required, TypedDict +from .realtime_reasoning_param import RealtimeReasoningParam from .realtime_truncation_param import RealtimeTruncationParam from .realtime_audio_config_param import RealtimeAudioConfigParam from .realtime_tools_config_param import RealtimeToolsConfigParam @@ -59,6 +60,7 @@ class RealtimeSessionCreateRequestParam(TypedDict, total=False): Literal[ "gpt-realtime", "gpt-realtime-1.5", + "gpt-realtime-2", "gpt-realtime-2025-08-28", "gpt-4o-realtime-preview", "gpt-4o-realtime-preview-2024-10-01", @@ -85,12 +87,21 @@ class RealtimeSessionCreateRequestParam(TypedDict, total=False): only. It is not possible to request both `text` and `audio` at the same time. """ + parallel_tool_calls: bool + """Whether the model may call multiple tools in parallel. + + Only supported by reasoning Realtime models such as `gpt-realtime-2`. + """ + prompt: Optional[ResponsePromptParam] """ Reference to a prompt template and its variables. [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). """ + reasoning: RealtimeReasoningParam + """Configuration for reasoning-capable Realtime models such as `gpt-realtime-2`.""" + tool_choice: RealtimeToolChoiceConfigParam """How the model chooses tools. diff --git a/src/openai/types/realtime/realtime_session_create_response.py b/src/openai/types/realtime/realtime_session_create_response.py index e2ed5ddce5..7193eafcc1 100644 --- a/src/openai/types/realtime/realtime_session_create_response.py +++ b/src/openai/types/realtime/realtime_session_create_response.py @@ -5,6 +5,7 @@ from ..._utils import PropertyInfo from ..._models import BaseModel +from .realtime_reasoning import RealtimeReasoning from .audio_transcription import AudioTranscription from .realtime_truncation import RealtimeTruncation from .noise_reduction_type import NoiseReductionType @@ -13,7 +14,6 @@ from ..responses.response_prompt import ResponsePrompt from ..responses.tool_choice_mcp import ToolChoiceMcp from ..responses.tool_choice_options import ToolChoiceOptions -from .realtime_session_client_secret import RealtimeSessionClientSecret from ..responses.tool_choice_function import ToolChoiceFunction __all__ = [ @@ -176,16 +176,6 @@ class AudioInput(BaseModel): """ transcription: Optional[AudioTranscription] = None - """ - Configuration for input audio transcription, defaults to off and can be set to - `null` to turn off once on. Input audio transcription is not native to the - model, since the model consumes audio directly. Transcription runs - asynchronously through - [the /audio/transcriptions endpoint](https://platform.openai.com/docs/api-reference/audio/createTranscription) - and should be treated as guidance of input audio content rather than precisely - what the model heard. The client can optionally set the language and prompt for - transcription, these offer additional guidance to the transcription service. - """ turn_detection: Optional[AudioInputTurnDetection] = None """Configuration for turn detection, ether Server VAD or Semantic VAD. @@ -202,6 +192,9 @@ class AudioInput(BaseModel): trails off with "uhhm", the model will score a low probability of turn end and wait longer for the user to continue speaking. This can be useful for more natural conversations, but may have a higher latency. + + For `gpt-realtime-whisper` transcription sessions, turn detection must be set to + `null`; VAD is not supported. """ @@ -414,14 +407,13 @@ class TracingTracingConfiguration(BaseModel): class RealtimeSessionCreateResponse(BaseModel): - """A new Realtime session configuration, with an ephemeral key. + """A Realtime session configuration object.""" - Default TTL - for keys is one minute. - """ + id: str + """Unique identifier for the session that looks like `sess_1234567890abcdef`.""" - client_secret: RealtimeSessionClientSecret - """Ephemeral key returned by the API.""" + object: Literal["realtime.session"] + """The object type. Always `realtime.session`.""" type: Literal["realtime"] """The type of session to create. Always `realtime` for the Realtime API.""" @@ -429,6 +421,9 @@ class RealtimeSessionCreateResponse(BaseModel): audio: Optional[Audio] = None """Configuration for input and output audio.""" + expires_at: Optional[int] = None + """Expiration timestamp for the session, in seconds since epoch.""" + include: Optional[List[Literal["item.input_audio_transcription.logprobs"]]] = None """Additional fields to include in server outputs. @@ -464,6 +459,7 @@ class RealtimeSessionCreateResponse(BaseModel): Literal[ "gpt-realtime", "gpt-realtime-1.5", + "gpt-realtime-2", "gpt-realtime-2025-08-28", "gpt-4o-realtime-preview", "gpt-4o-realtime-preview-2024-10-01", @@ -497,6 +493,9 @@ class RealtimeSessionCreateResponse(BaseModel): [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). """ + reasoning: Optional[RealtimeReasoning] = None + """Configuration for reasoning-capable Realtime models such as `gpt-realtime-2`.""" + tool_choice: Optional[ToolChoice] = None """How the model chooses tools. diff --git a/src/openai/types/realtime/realtime_transcription_session_audio_input.py b/src/openai/types/realtime/realtime_transcription_session_audio_input.py index 80ff223590..e6f044bc22 100644 --- a/src/openai/types/realtime/realtime_transcription_session_audio_input.py +++ b/src/openai/types/realtime/realtime_transcription_session_audio_input.py @@ -69,4 +69,7 @@ class RealtimeTranscriptionSessionAudioInput(BaseModel): trails off with "uhhm", the model will score a low probability of turn end and wait longer for the user to continue speaking. This can be useful for more natural conversations, but may have a higher latency. + + For `gpt-realtime-whisper` transcription sessions, turn detection must be set to + `null`; VAD is not supported. """ diff --git a/src/openai/types/realtime/realtime_transcription_session_audio_input_param.py b/src/openai/types/realtime/realtime_transcription_session_audio_input_param.py index dd908c72f6..cacb38dc22 100644 --- a/src/openai/types/realtime/realtime_transcription_session_audio_input_param.py +++ b/src/openai/types/realtime/realtime_transcription_session_audio_input_param.py @@ -71,4 +71,7 @@ class RealtimeTranscriptionSessionAudioInputParam(TypedDict, total=False): trails off with "uhhm", the model will score a low probability of turn end and wait longer for the user to continue speaking. This can be useful for more natural conversations, but may have a higher latency. + + For `gpt-realtime-whisper` transcription sessions, turn detection must be set to + `null`; VAD is not supported. """ diff --git a/src/openai/types/realtime/realtime_transcription_session_create_response.py b/src/openai/types/realtime/realtime_transcription_session_create_response.py index 6ca6c3808b..68f7e71a54 100644 --- a/src/openai/types/realtime/realtime_transcription_session_create_response.py +++ b/src/openai/types/realtime/realtime_transcription_session_create_response.py @@ -31,14 +31,13 @@ class AudioInput(BaseModel): """Configuration for input audio noise reduction.""" transcription: Optional[AudioTranscription] = None - """Configuration of the transcription model.""" turn_detection: Optional[RealtimeTranscriptionSessionTurnDetection] = None """Configuration for turn detection. Can be set to `null` to turn off. Server VAD means that the model will detect the start and end of speech based on audio volume and respond at the end of user - speech. + speech. For `gpt-realtime-whisper`, this must be `null`; VAD is not supported. """ diff --git a/src/openai/types/realtime/realtime_transcription_session_turn_detection.py b/src/openai/types/realtime/realtime_transcription_session_turn_detection.py index 8dacd60a07..0f3d5b1c00 100644 --- a/src/openai/types/realtime/realtime_transcription_session_turn_detection.py +++ b/src/openai/types/realtime/realtime_transcription_session_turn_detection.py @@ -12,7 +12,7 @@ class RealtimeTranscriptionSessionTurnDetection(BaseModel): Can be set to `null` to turn off. Server VAD means that the model will detect the start and end of speech based on - audio volume and respond at the end of user speech. + audio volume and respond at the end of user speech. For `gpt-realtime-whisper`, this must be `null`; VAD is not supported. """ prefix_padding_ms: Optional[int] = None diff --git a/tests/api_resources/realtime/test_calls.py b/tests/api_resources/realtime/test_calls.py index 43ab9afe01..3d87a77f3b 100644 --- a/tests/api_resources/realtime/test_calls.py +++ b/tests/api_resources/realtime/test_calls.py @@ -47,6 +47,7 @@ def test_method_create_with_all_params(self, client: OpenAI, respx_mock: MockRou }, "noise_reduction": {"type": "near_field"}, "transcription": { + "delay": "minimal", "language": "language", "model": "whisper-1", "prompt": "prompt", @@ -75,11 +76,13 @@ def test_method_create_with_all_params(self, client: OpenAI, respx_mock: MockRou "max_output_tokens": "inf", "model": "gpt-realtime", "output_modalities": ["text"], + "parallel_tool_calls": True, "prompt": { "id": "id", "variables": {"foo": "string"}, "version": "version", }, + "reasoning": {"effort": "minimal"}, "tool_choice": "none", "tools": [ { @@ -146,6 +149,7 @@ def test_method_accept_with_all_params(self, client: OpenAI) -> None: }, "noise_reduction": {"type": "near_field"}, "transcription": { + "delay": "minimal", "language": "language", "model": "whisper-1", "prompt": "prompt", @@ -174,11 +178,13 @@ def test_method_accept_with_all_params(self, client: OpenAI) -> None: max_output_tokens="inf", model="gpt-realtime", output_modalities=["text"], + parallel_tool_calls=True, prompt={ "id": "id", "variables": {"foo": "string"}, "version": "version", }, + reasoning={"effort": "minimal"}, tool_choice="none", tools=[ { @@ -385,6 +391,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI, re }, "noise_reduction": {"type": "near_field"}, "transcription": { + "delay": "minimal", "language": "language", "model": "whisper-1", "prompt": "prompt", @@ -413,11 +420,13 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI, re "max_output_tokens": "inf", "model": "gpt-realtime", "output_modalities": ["text"], + "parallel_tool_calls": True, "prompt": { "id": "id", "variables": {"foo": "string"}, "version": "version", }, + "reasoning": {"effort": "minimal"}, "tool_choice": "none", "tools": [ { @@ -484,6 +493,7 @@ async def test_method_accept_with_all_params(self, async_client: AsyncOpenAI) -> }, "noise_reduction": {"type": "near_field"}, "transcription": { + "delay": "minimal", "language": "language", "model": "whisper-1", "prompt": "prompt", @@ -512,11 +522,13 @@ async def test_method_accept_with_all_params(self, async_client: AsyncOpenAI) -> max_output_tokens="inf", model="gpt-realtime", output_modalities=["text"], + parallel_tool_calls=True, prompt={ "id": "id", "variables": {"foo": "string"}, "version": "version", }, + reasoning={"effort": "minimal"}, tool_choice="none", tools=[ { diff --git a/tests/api_resources/realtime/test_client_secrets.py b/tests/api_resources/realtime/test_client_secrets.py index a354019eac..c8ec8f3d3b 100644 --- a/tests/api_resources/realtime/test_client_secrets.py +++ b/tests/api_resources/realtime/test_client_secrets.py @@ -39,6 +39,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: }, "noise_reduction": {"type": "near_field"}, "transcription": { + "delay": "minimal", "language": "language", "model": "whisper-1", "prompt": "prompt", @@ -67,11 +68,13 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: "max_output_tokens": "inf", "model": "gpt-realtime", "output_modalities": ["text"], + "parallel_tool_calls": True, "prompt": { "id": "id", "variables": {"foo": "string"}, "version": "version", }, + "reasoning": {"effort": "minimal"}, "tool_choice": "none", "tools": [ { @@ -135,6 +138,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> }, "noise_reduction": {"type": "near_field"}, "transcription": { + "delay": "minimal", "language": "language", "model": "whisper-1", "prompt": "prompt", @@ -163,11 +167,13 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> "max_output_tokens": "inf", "model": "gpt-realtime", "output_modalities": ["text"], + "parallel_tool_calls": True, "prompt": { "id": "id", "variables": {"foo": "string"}, "version": "version", }, + "reasoning": {"effort": "minimal"}, "tool_choice": "none", "tools": [ { From ff683ffbeba94fc01d93966b774c05a3471f2495 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 7 May 2026 17:24:54 +0000 Subject: [PATCH 740/769] release: 2.36.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 9 +++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 0c6e1a8623..986390db98 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.35.1" + ".": "2.36.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b5e6afda7..af067330f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 2.36.0 (2026-05-07) + +Full Changelog: [v2.35.1...v2.36.0](https://github.com/openai/openai-python/compare/v2.35.1...v2.36.0) + +### Features + +* **api:** manual updates ([13c639c](https://github.com/openai/openai-python/commit/13c639cc7d57e4fbd4406563511e15eeb88a54b2)) +* **api:** realtime 2 ([8fe0ab8](https://github.com/openai/openai-python/commit/8fe0ab87e67eeb3cc27426b50093845229520f0e)) + ## 2.35.1 (2026-05-06) Full Changelog: [v2.35.0...v2.35.1](https://github.com/openai/openai-python/compare/v2.35.0...v2.35.1) diff --git a/pyproject.toml b/pyproject.toml index cb8c01191d..ec1af48c8b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.35.1" +version = "2.36.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 7f151cf0cd..a6435eede3 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__ = "2.35.1" # x-release-please-version +__version__ = "2.36.0" # x-release-please-version From c85ebd935cb4b80e7e97ce255437684f6411fb00 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 8 May 2026 16:32:52 +0000 Subject: [PATCH 741/769] fix(client): add missing f-string prefix in file type error message --- src/openai/_files.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openai/_files.py b/src/openai/_files.py index 4cc4f35d8f..1a2cc77478 100644 --- a/src/openai/_files.py +++ b/src/openai/_files.py @@ -99,7 +99,7 @@ async def async_to_httpx_files(files: RequestFiles | None) -> HttpxRequestFiles elif is_sequence_t(files): files = [(key, await _async_transform_file(file)) for key, file in files] else: - raise TypeError("Unexpected file type input {type(files)}, expected mapping or sequence") + raise TypeError(f"Unexpected file type input {type(files)}, expected mapping or sequence") return files From b279c591de38014c284ca33920f2cf22ac9a616f Mon Sep 17 00:00:00 2001 From: Romain Huet Date: Fri, 8 May 2026 23:28:51 -0700 Subject: [PATCH 742/769] Update README models to gpt-5.5 and gpt-realtime-2 --- README.md | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 9450c0bc51..ea48b247dd 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ client = OpenAI( ) response = client.responses.create( - model="gpt-5.2", + model="gpt-5.5", instructions="You are a coding assistant that talks like a pirate.", input="How do I check if a Python object is an instance of a class?", ) @@ -52,7 +52,7 @@ from openai import OpenAI client = OpenAI() completion = client.chat.completions.create( - model="gpt-5.2", + model="gpt-5.5", messages=[ {"role": "developer", "content": "Talk like a pirate."}, { @@ -95,7 +95,7 @@ client = OpenAI( ) response = client.chat.completions.create( - model="gpt-4", + model="gpt-5.5", messages=[{"role": "user", "content": "Hello!"}], ) ``` @@ -183,7 +183,7 @@ prompt = "What is in this image?" img_url = "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d5/2023_06_08_Raccoon1.jpg/1599px-2023_06_08_Raccoon1.jpg" response = client.responses.create( - model="gpt-5.2", + model="gpt-5.5", input=[ { "role": "user", @@ -209,7 +209,7 @@ with open("path/to/image.png", "rb") as image_file: b64_image = base64.b64encode(image_file.read()).decode("utf-8") response = client.responses.create( - model="gpt-5.2", + model="gpt-5.5", input=[ { "role": "user", @@ -239,7 +239,7 @@ client = AsyncOpenAI( async def main() -> None: response = await client.responses.create( - model="gpt-5.2", input="Explain disestablishmentarianism to a smart five year old." + model="gpt-5.5", input="Explain disestablishmentarianism to a smart five year old." ) print(response.output_text) @@ -281,7 +281,7 @@ async def main() -> None: "content": "Say this is a test", } ], - model="gpt-5.2", + model="gpt-5.5", ) @@ -298,7 +298,7 @@ from openai import OpenAI client = OpenAI() stream = client.responses.create( - model="gpt-5.2", + model="gpt-5.5", input="Write a one-sentence bedtime story about a unicorn.", stream=True, ) @@ -318,7 +318,7 @@ client = AsyncOpenAI() async def main(): stream = await client.responses.create( - model="gpt-5.2", + model="gpt-5.5", input="Write a one-sentence bedtime story about a unicorn.", stream=True, ) @@ -347,7 +347,7 @@ from openai import AsyncOpenAI async def main(): client = AsyncOpenAI() - async with client.realtime.connect(model="gpt-realtime") as connection: + async with client.realtime.connect(model="gpt-realtime-2") as connection: await connection.session.update( session={"type": "realtime", "output_modalities": ["text"]} ) @@ -383,7 +383,7 @@ Whenever an error occurs, the Realtime API will send an [`error` event](https:// ```py client = AsyncOpenAI() -async with client.realtime.connect(model="gpt-realtime") as connection: +async with client.realtime.connect(model="gpt-realtime-2") as connection: ... async for event in connection: if event.type == 'error': @@ -482,15 +482,15 @@ from openai import OpenAI client = OpenAI() -response = client.chat.responses.create( +response = client.responses.create( input=[ { "role": "user", "content": "How much ?", } ], - model="gpt-5.2", - response_format={"type": "json_object"}, + model="gpt-5.5", + text={"format": {"type": "json_object"}}, ) ``` @@ -644,7 +644,7 @@ All object responses in the SDK provide a `_request_id` property which is added ```python response = await client.responses.create( - model="gpt-5.2", + model="gpt-5.5", input="Say 'this is a test'.", ) print(response._request_id) # req_123 @@ -662,7 +662,7 @@ import openai try: completion = await client.chat.completions.create( - messages=[{"role": "user", "content": "Say this is a test"}], model="gpt-5.2" + messages=[{"role": "user", "content": "Say this is a test"}], model="gpt-5.5" ) except openai.APIStatusError as exc: print(exc.request_id) # req_123 @@ -694,7 +694,7 @@ client.with_options(max_retries=5).chat.completions.create( "content": "How can I get the name of the current day in JavaScript?", } ], - model="gpt-5.2", + model="gpt-5.5", ) ``` @@ -725,7 +725,7 @@ client.with_options(timeout=5.0).chat.completions.create( "content": "How can I list all files in a directory using Python?", } ], - model="gpt-5.2", + model="gpt-5.5", ) ``` @@ -772,7 +772,7 @@ response = client.chat.completions.with_raw_response.create( "role": "user", "content": "Say this is a test", }], - model="gpt-5.2", + model="gpt-5.5", ) print(response.headers.get('X-My-Header')) @@ -805,7 +805,7 @@ with client.chat.completions.with_streaming_response.create( "content": "Say this is a test", } ], - model="gpt-5.2", + model="gpt-5.5", ) as response: print(response.headers.get("X-My-Header")) From 625827c5509ece3c40e5002be37a9bd9d91b5374 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 11 May 2026 14:32:02 +0000 Subject: [PATCH 743/769] feat(api): add service_tier parameter to responses compact method --- .stats.yml | 4 ++-- src/openai/resources/responses/responses.py | 8 ++++++++ src/openai/types/responses/response_compact_params.py | 3 +++ tests/api_resources/test_responses.py | 2 ++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 9b6dc7e58b..38a36fd922 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 233 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-371f497afe4d6070f6e252e5febbe8f453c7058a8dff0c26a01b4d88442a4ac2.yml -openapi_spec_hash: d39f46e8fda45f77096448105efd175a +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-50d816559ef0935e64d07789ff936a2b762e26ab0714a2fa6bc06d06d4484294.yml +openapi_spec_hash: c5d8f37edbf66c1fef627d787b4c54fd config_hash: b64135fff1fe9cf4069b9ecf59ae8b07 diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 4b8bd9af21..e83f9824be 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -1704,6 +1704,7 @@ def compact( previous_response_id: Optional[str] | Omit = omit, prompt_cache_key: Optional[str] | Omit = omit, prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit, + service_tier: Optional[Literal["auto", "default", "flex", "priority"]] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1743,6 +1744,8 @@ def compact( prompt_cache_retention: How long to retain a prompt cache entry created by this request. + service_tier: The service tier to use for this request. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -1761,6 +1764,7 @@ def compact( "previous_response_id": previous_response_id, "prompt_cache_key": prompt_cache_key, "prompt_cache_retention": prompt_cache_retention, + "service_tier": service_tier, }, response_compact_params.ResponseCompactParams, ), @@ -3410,6 +3414,7 @@ async def compact( previous_response_id: Optional[str] | Omit = omit, prompt_cache_key: Optional[str] | Omit = omit, prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit, + service_tier: Optional[Literal["auto", "default", "flex", "priority"]] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -3449,6 +3454,8 @@ async def compact( prompt_cache_retention: How long to retain a prompt cache entry created by this request. + service_tier: The service tier to use for this request. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -3467,6 +3474,7 @@ async def compact( "previous_response_id": previous_response_id, "prompt_cache_key": prompt_cache_key, "prompt_cache_retention": prompt_cache_retention, + "service_tier": service_tier, }, response_compact_params.ResponseCompactParams, ), diff --git a/src/openai/types/responses/response_compact_params.py b/src/openai/types/responses/response_compact_params.py index 2575438b34..923a09e56d 100644 --- a/src/openai/types/responses/response_compact_params.py +++ b/src/openai/types/responses/response_compact_params.py @@ -143,3 +143,6 @@ class ResponseCompactParams(TypedDict, total=False): prompt_cache_retention: Optional[Literal["in_memory", "24h"]] """How long to retain a prompt cache entry created by this request.""" + + service_tier: Optional[Literal["auto", "default", "flex", "priority"]] + """The service tier to use for this request.""" diff --git a/tests/api_resources/test_responses.py b/tests/api_resources/test_responses.py index 40405f61b2..094687c2c6 100644 --- a/tests/api_resources/test_responses.py +++ b/tests/api_resources/test_responses.py @@ -389,6 +389,7 @@ def test_method_compact_with_all_params(self, client: OpenAI) -> None: previous_response_id="resp_123", prompt_cache_key="prompt_cache_key", prompt_cache_retention="in_memory", + service_tier="auto", ) assert_matches_type(CompactedResponse, response, path=["response"]) @@ -801,6 +802,7 @@ async def test_method_compact_with_all_params(self, async_client: AsyncOpenAI) - previous_response_id="resp_123", prompt_cache_key="prompt_cache_key", prompt_cache_retention="in_memory", + service_tier="auto", ) assert_matches_type(CompactedResponse, response, path=["response"]) From 7e527bc927cc58b74d7619abf7f1fbcfff8bddfa Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 11 May 2026 17:38:40 +0000 Subject: [PATCH 744/769] feat(internal/types): support eagerly validating pydantic iterators --- src/openai/_models.py | 80 +++++++++++++++++++++++++++++++++++++++++++ tests/test_models.py | 60 ++++++++++++++++++++++++++++++-- 2 files changed, 137 insertions(+), 3 deletions(-) diff --git a/src/openai/_models.py b/src/openai/_models.py index 5f12232437..ed4c1f82d6 100644 --- a/src/openai/_models.py +++ b/src/openai/_models.py @@ -27,7 +27,9 @@ Protocol, Required, Sequence, + Annotated, ParamSpec, + TypeAlias, TypedDict, TypeGuard, final, @@ -81,7 +83,15 @@ from ._constants import RAW_RESPONSE_HEADER if TYPE_CHECKING: + from pydantic import GetCoreSchemaHandler, ValidatorFunctionWrapHandler + from pydantic_core import CoreSchema, core_schema from pydantic_core.core_schema import ModelField, ModelSchema, LiteralSchema, ModelFieldsSchema +else: + try: + from pydantic_core import CoreSchema, core_schema + except ImportError: + CoreSchema = None + core_schema = None __all__ = ["BaseModel", "GenericModel"] @@ -422,6 +432,76 @@ def model_dump_json( ) +class _EagerIterable(list[_T], Generic[_T]): + """ + Accepts any Iterable[T] input (including generators), consumes it + eagerly, and validates all items upfront. + + Validation preserves the original container type where possible + (e.g. a set[T] stays a set[T]). Serialization (model_dump / JSON) + always emits a list — round-tripping through model_dump() will not + restore the original container type. + """ + + @classmethod + def __get_pydantic_core_schema__( + cls, + source_type: Any, + handler: GetCoreSchemaHandler, + ) -> CoreSchema: + (item_type,) = get_args(source_type) or (Any,) + item_schema: CoreSchema = handler.generate_schema(item_type) + list_of_items_schema: CoreSchema = core_schema.list_schema(item_schema) + + return core_schema.no_info_wrap_validator_function( + cls._validate, + list_of_items_schema, + serialization=core_schema.plain_serializer_function_ser_schema( + cls._serialize, + info_arg=False, + ), + ) + + @staticmethod + def _validate(v: Iterable[_T], handler: "ValidatorFunctionWrapHandler") -> Any: + original_type: type[Any] = type(v) + + # Normalize to list so list_schema can validate each item + if isinstance(v, list): + items: list[_T] = v + else: + try: + items = list(v) + except TypeError as e: + raise TypeError("Value is not iterable") from e + + # Validate items against the inner schema + validated: list[_T] = handler(items) + + # Reconstruct original container type + if original_type is list: + return validated + # str(list) produces the list's repr, not a string built from items, + # so skip reconstruction for str and its subclasses. + if issubclass(original_type, str): + return validated + try: + return original_type(validated) + except (TypeError, ValueError): + # If the type cannot be reconstructed, just return the validated list + return validated + + @staticmethod + def _serialize(v: Iterable[_T]) -> list[_T]: + """Always serialize as a list so Pydantic's JSON encoder is happy.""" + if isinstance(v, list): + return v + return list(v) + + +EagerIterable: TypeAlias = Annotated[Iterable[_T], _EagerIterable] + + def _construct_field(value: object, field: FieldInfo, key: str) -> object: if value is None: return field_get_default(field) diff --git a/tests/test_models.py b/tests/test_models.py index 588869ee35..cc204bac1d 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -1,7 +1,8 @@ import json -from typing import TYPE_CHECKING, Any, Dict, List, Union, Optional, cast +from typing import TYPE_CHECKING, Any, Dict, List, Union, Iterable, Optional, cast from datetime import datetime, timezone -from typing_extensions import Literal, Annotated, TypeAliasType +from collections import deque +from typing_extensions import Literal, Annotated, TypedDict, TypeAliasType import pytest import pydantic @@ -9,7 +10,7 @@ from openai._utils import PropertyInfo from openai._compat import PYDANTIC_V1, parse_obj, model_dump, model_json -from openai._models import DISCRIMINATOR_CACHE, BaseModel, construct_type +from openai._models import DISCRIMINATOR_CACHE, BaseModel, EagerIterable, construct_type class BasicModel(BaseModel): @@ -961,3 +962,56 @@ def __getattr__(self, attr: str) -> Item: ... assert model.a.prop == 1 assert isinstance(model.a, Item) assert model.other == "foo" + + +# NOTE: Workaround for Pydantic Iterable behavior. +# Iterable fields are replaced with a ValidatorIterator and may be consumed +# during serialization, which can cause subsequent dumps to return empty data. +# See: https://github.com/pydantic/pydantic/issues/9541 +@pytest.mark.parametrize( + "data, expected_validated", + [ + ([1, 2, 3], [1, 2, 3]), + ((1, 2, 3), (1, 2, 3)), + (set([1, 2, 3]), set([1, 2, 3])), + (iter([1, 2, 3]), [1, 2, 3]), + ([], []), + ((x for x in [1, 2, 3]), [1, 2, 3]), + (map(lambda x: x, [1, 2, 3]), [1, 2, 3]), + (frozenset([1, 2, 3]), frozenset([1, 2, 3])), + (deque([1, 2, 3]), deque([1, 2, 3])), + ], + ids=["list", "tuple", "set", "iterator", "empty", "generator", "map", "frozenset", "deque"], +) +@pytest.mark.skipif(PYDANTIC_V1, reason="this is only supported in pydantic v2") +def test_iterable_construction(data: Iterable[int], expected_validated: Iterable[int]) -> None: + class TypeWithIterable(TypedDict): + items: EagerIterable[int] + + class Model(BaseModel): + data: TypeWithIterable + + m = Model.model_validate({"data": {"items": data}}) + assert m.data["items"] == expected_validated + + # Verify repeated dumps don't lose data (the original bug) + assert m.model_dump()["data"]["items"] == list(expected_validated) + assert m.model_dump()["data"]["items"] == list(expected_validated) + + +@pytest.mark.skipif(PYDANTIC_V1, reason="this is only supported in pydantic v2") +def test_iterable_construction_str_falls_back_to_list() -> None: + # str is iterable (over chars), but str(list_of_chars) produces the list's repr + # rather than reconstructing a string from items. We special-case str to fall + # back to list instead of attempting reconstruction. + class TypeWithIterable(TypedDict): + items: EagerIterable[str] + + class Model(BaseModel): + data: TypeWithIterable + + m = Model.model_validate({"data": {"items": "hello"}}) + + # falls back to list of chars rather than calling str(["h", "e", "l", "l", "o"]) + assert m.data["items"] == ["h", "e", "l", "l", "o"] + assert m.model_dump()["data"]["items"] == ["h", "e", "l", "l", "o"] From c39ea8d12a010052d7f02cebe8daabd2d1f89597 Mon Sep 17 00:00:00 2001 From: Jingjing Tian Date: Tue, 12 May 2026 12:17:28 -0700 Subject: [PATCH 745/769] feat: Remove unnecessary client_id when using workload identity provider for auth --- README.md | 7 ------- src/openai/auth/_workload.py | 5 ----- tests/test_auth.py | 4 ---- tests/test_client.py | 1 - 4 files changed, 17 deletions(-) diff --git a/README.md b/README.md index 9450c0bc51..90f1c2cbd9 100644 --- a/README.md +++ b/README.md @@ -83,15 +83,12 @@ from openai.auth import k8s_service_account_token_provider client = OpenAI( workload_identity={ - "client_id": "your-client-id", "identity_provider_id": "idp-123", "service_account_id": "sa-456", "provider": k8s_service_account_token_provider( "/var/run/secrets/kubernetes.io/serviceaccount/token" ), }, - organization="org-xyz", - project="proj-abc", ) response = client.chat.completions.create( @@ -108,7 +105,6 @@ from openai.auth import azure_managed_identity_token_provider client = OpenAI( workload_identity={ - "client_id": "your-client-id", "identity_provider_id": "idp-123", "service_account_id": "sa-456", "provider": azure_managed_identity_token_provider( @@ -126,7 +122,6 @@ from openai.auth import gcp_id_token_provider client = OpenAI( workload_identity={ - "client_id": "your-client-id", "identity_provider_id": "idp-123", "service_account_id": "sa-456", "provider": gcp_id_token_provider(audience="https://api.openai.com/v1"), @@ -146,7 +141,6 @@ def get_custom_token() -> str: client = OpenAI( workload_identity={ - "client_id": "your-client-id", "identity_provider_id": "idp-123", "service_account_id": "sa-456", "provider": { @@ -165,7 +159,6 @@ from openai.auth import k8s_service_account_token_provider client = OpenAI( workload_identity={ - "client_id": "your-client-id", "identity_provider_id": "idp-123", "service_account_id": "sa-456", "provider": k8s_service_account_token_provider("/var/token"), diff --git a/src/openai/auth/_workload.py b/src/openai/auth/_workload.py index e3f6f7fb75..6c142a82ed 100644 --- a/src/openai/auth/_workload.py +++ b/src/openai/auth/_workload.py @@ -27,10 +27,6 @@ class SubjectTokenProvider(TypedDict): class WorkloadIdentity(TypedDict): - """A unique string that identifies the client.""" - - client_id: str - """Identity provider resource id in WIFAPI.""" identity_provider_id: str @@ -253,7 +249,6 @@ def _fetch_token_from_exchange(self) -> dict[str, Any]: self.token_exchange_url, json={ "grant_type": TOKEN_EXCHANGE_GRANT_TYPE, - "client_id": self.workload_identity["client_id"], "subject_token": subject_token, "subject_token_type": subject_token_type, "identity_provider_id": self.workload_identity["identity_provider_id"], diff --git a/tests/test_auth.py b/tests/test_auth.py index c8f4f2d7cf..17e9cd814c 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -36,7 +36,6 @@ def test_basic_auth(): client = OpenAI( workload_identity={ - "client_id": "client_123", "identity_provider_id": "idp_123", "service_account_id": "sa_123", "provider": { @@ -82,7 +81,6 @@ def provider() -> str: client = OpenAI( workload_identity={ - "client_id": "client_123", "identity_provider_id": "idp_123", "service_account_id": "sa_123", "provider": { @@ -103,7 +101,6 @@ def provider() -> str: assert json.loads(exchange_request.content) == snapshot( { "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange", - "client_id": "client_123", "subject_token": "fake_subject_token", "subject_token_type": "urn:ietf:params:oauth:token-type:jwt", "identity_provider_id": "idp_123", @@ -136,7 +133,6 @@ def test_workload_identity_exchange_error() -> None: client = OpenAI( workload_identity={ - "client_id": "client_123", "identity_provider_id": "idp_123", "service_account_id": "sa_123", "provider": { diff --git a/tests/test_client.py b/tests/test_client.py index e2bb6ea966..2d8955a58e 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -45,7 +45,6 @@ api_key = "My API Key" admin_api_key = "My Admin API Key" workload_identity: WorkloadIdentity = { - "client_id": "client_123", "identity_provider_id": "provider_123", "service_account_id": "service_account_123", "provider": { From 8a7cac34cbc64fe02854beb3659f4bb5f46815f9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 13 May 2026 15:55:14 +0000 Subject: [PATCH 746/769] release: 2.37.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 15 +++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 986390db98..28c811f943 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.36.0" + ".": "2.37.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index af067330f6..803d3d3a39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## 2.37.0 (2026-05-13) + +Full Changelog: [v2.36.0...v2.37.0](https://github.com/openai/openai-python/compare/v2.36.0...v2.37.0) + +### Features + +* **api:** add service_tier parameter to responses compact method ([625827c](https://github.com/openai/openai-python/commit/625827c5509ece3c40e5002be37a9bd9d91b5374)) +* **internal/types:** support eagerly validating pydantic iterators ([7e527bc](https://github.com/openai/openai-python/commit/7e527bc927cc58b74d7619abf7f1fbcfff8bddfa)) +* Remove unnecessary client_id when using workload identity provider for auth ([c39ea8d](https://github.com/openai/openai-python/commit/c39ea8d12a010052d7f02cebe8daabd2d1f89597)) + + +### Bug Fixes + +* **client:** add missing f-string prefix in file type error message ([c85ebd9](https://github.com/openai/openai-python/commit/c85ebd935cb4b80e7e97ce255437684f6411fb00)) + ## 2.36.0 (2026-05-07) Full Changelog: [v2.35.1...v2.36.0](https://github.com/openai/openai-python/compare/v2.35.1...v2.36.0) diff --git a/pyproject.toml b/pyproject.toml index ec1af48c8b..452ac3125a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.36.0" +version = "2.37.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 a6435eede3..43d6a12d19 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__ = "2.36.0" # x-release-please-version +__version__ = "2.37.0" # x-release-please-version From c336bcb78c39f2d35d62f06014d096051e2688af Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 13 May 2026 04:09:10 +0000 Subject: [PATCH 747/769] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 38a36fd922..4bfc577213 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 233 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-50d816559ef0935e64d07789ff936a2b762e26ab0714a2fa6bc06d06d4484294.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-7f30f2390f57603d13ed862d360185cfb4f48b4bf9e56e73d1d17ae7e3dfc423.yml openapi_spec_hash: c5d8f37edbf66c1fef627d787b4c54fd -config_hash: b64135fff1fe9cf4069b9ecf59ae8b07 +config_hash: b496fe9c594a1820ad169a6f2d841a32 From a2f1d6c56980713619760c60a5c7bfb580b0adcb Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 13 May 2026 17:26:19 +0000 Subject: [PATCH 748/769] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 4bfc577213..a3e07379dd 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 233 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-7f30f2390f57603d13ed862d360185cfb4f48b4bf9e56e73d1d17ae7e3dfc423.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-0127d9dfdff671141b07eb8fda98f6297f70267d2fa9249f4b0defb6826e5aba.yml openapi_spec_hash: c5d8f37edbf66c1fef627d787b4c54fd -config_hash: b496fe9c594a1820ad169a6f2d841a32 +config_hash: 70ff4da62a6a6ef9f91d566c38b7bddf From 2897485d445f2924c5c2a8e6a9f40eec633ff345 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 15 May 2026 23:12:26 +0000 Subject: [PATCH 749/769] feat(api): update OpenAPI spec or Stainless config --- .stats.yml | 4 +- .../resources/admin/organization/invites.py | 6 +- .../organization/invite_create_params.py | 3 +- .../usage_audio_speeches_response.py | 79 +++++++++++++++++++ .../usage_audio_transcriptions_response.py | 79 +++++++++++++++++++ ...sage_code_interpreter_sessions_response.py | 79 +++++++++++++++++++ .../usage_completions_response.py | 79 +++++++++++++++++++ .../organization/usage_costs_response.py | 79 +++++++++++++++++++ .../organization/usage_embeddings_response.py | 79 +++++++++++++++++++ .../organization/usage_images_response.py | 79 +++++++++++++++++++ .../usage_moderations_response.py | 79 +++++++++++++++++++ .../usage_vector_stores_response.py | 79 +++++++++++++++++++ .../types/responses/response_input_item.py | 9 +++ .../responses/response_input_item_param.py | 9 +++ .../types/responses/response_input_param.py | 9 +++ 15 files changed, 746 insertions(+), 5 deletions(-) diff --git a/.stats.yml b/.stats.yml index a3e07379dd..f805dd3c95 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 233 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-0127d9dfdff671141b07eb8fda98f6297f70267d2fa9249f4b0defb6826e5aba.yml -openapi_spec_hash: c5d8f37edbf66c1fef627d787b4c54fd +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-fcfdf0bb920ca15a6d01d1cfe988accb7559b2d991b6e2ad6b25cfae81ac2ae9.yml +openapi_spec_hash: 72ee7d4fe582e75d16e67b6c97881fed config_hash: 70ff4da62a6a6ef9f91d566c38b7bddf diff --git a/src/openai/resources/admin/organization/invites.py b/src/openai/resources/admin/organization/invites.py index 23b83ccb18..b9db8c622c 100644 --- a/src/openai/resources/admin/organization/invites.py +++ b/src/openai/resources/admin/organization/invites.py @@ -67,7 +67,8 @@ def create( projects: An array of projects to which membership is granted at the same time the org invite is accepted. If omitted, the user will be invited to the default project - for compatibility with legacy behavior. + for compatibility with legacy behavior. If empty list is passed, the user will + not be invited to any projects, including the default one. extra_headers: Send extra headers @@ -270,7 +271,8 @@ async def create( projects: An array of projects to which membership is granted at the same time the org invite is accepted. If omitted, the user will be invited to the default project - for compatibility with legacy behavior. + for compatibility with legacy behavior. If empty list is passed, the user will + not be invited to any projects, including the default one. extra_headers: Send extra headers diff --git a/src/openai/types/admin/organization/invite_create_params.py b/src/openai/types/admin/organization/invite_create_params.py index 7709003fe3..51430d8694 100644 --- a/src/openai/types/admin/organization/invite_create_params.py +++ b/src/openai/types/admin/organization/invite_create_params.py @@ -19,7 +19,8 @@ class InviteCreateParams(TypedDict, total=False): """ An array of projects to which membership is granted at the same time the org invite is accepted. If omitted, the user will be invited to the default project - for compatibility with legacy behavior. + for compatibility with legacy behavior. If empty list is passed, the user will + not be invited to any projects, including the default one. """ diff --git a/src/openai/types/admin/organization/usage_audio_speeches_response.py b/src/openai/types/admin/organization/usage_audio_speeches_response.py index e5fed36b03..f99a73eeb0 100644 --- a/src/openai/types/admin/organization/usage_audio_speeches_response.py +++ b/src/openai/types/admin/organization/usage_audio_speeches_response.py @@ -18,6 +18,8 @@ "DataResultOrganizationUsageAudioTranscriptionsResult", "DataResultOrganizationUsageVectorStoresResult", "DataResultOrganizationUsageCodeInterpreterSessionsResult", + "DataResultOrganizationUsageFileSearchesResult", + "DataResultOrganizationUsageWebSearchesResult", "DataResultOrganizationCostsResult", "DataResultOrganizationCostsResultAmount", ] @@ -317,6 +319,81 @@ class DataResultOrganizationUsageCodeInterpreterSessionsResult(BaseModel): """ +class DataResultOrganizationUsageFileSearchesResult(BaseModel): + """The aggregated file search calls usage details of the specific time bucket.""" + + num_requests: int + """The count of file search calls.""" + + object: Literal["organization.usage.file_searches.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + vector_store_id: Optional[str] = None + """ + When `group_by=vector_store_id`, this field provides the vector store ID of the + grouped usage result. + """ + + +class DataResultOrganizationUsageWebSearchesResult(BaseModel): + """The aggregated web search calls usage details of the specific time bucket.""" + + num_model_requests: int + """The count of model requests.""" + + num_requests: int + """The count of web search calls.""" + + object: Literal["organization.usage.web_searches.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + context_level: Optional[str] = None + """ + When `group_by=context_level`, this field provides the search context size of + the grouped usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + class DataResultOrganizationCostsResultAmount(BaseModel): """The monetary value in its associated currency.""" @@ -370,6 +447,8 @@ class DataResultOrganizationCostsResult(BaseModel): DataResultOrganizationUsageAudioTranscriptionsResult, DataResultOrganizationUsageVectorStoresResult, DataResultOrganizationUsageCodeInterpreterSessionsResult, + DataResultOrganizationUsageFileSearchesResult, + DataResultOrganizationUsageWebSearchesResult, DataResultOrganizationCostsResult, ], PropertyInfo(discriminator="object"), diff --git a/src/openai/types/admin/organization/usage_audio_transcriptions_response.py b/src/openai/types/admin/organization/usage_audio_transcriptions_response.py index c5b77f34e1..d8f436b0b5 100644 --- a/src/openai/types/admin/organization/usage_audio_transcriptions_response.py +++ b/src/openai/types/admin/organization/usage_audio_transcriptions_response.py @@ -18,6 +18,8 @@ "DataResultOrganizationUsageAudioTranscriptionsResult", "DataResultOrganizationUsageVectorStoresResult", "DataResultOrganizationUsageCodeInterpreterSessionsResult", + "DataResultOrganizationUsageFileSearchesResult", + "DataResultOrganizationUsageWebSearchesResult", "DataResultOrganizationCostsResult", "DataResultOrganizationCostsResultAmount", ] @@ -317,6 +319,81 @@ class DataResultOrganizationUsageCodeInterpreterSessionsResult(BaseModel): """ +class DataResultOrganizationUsageFileSearchesResult(BaseModel): + """The aggregated file search calls usage details of the specific time bucket.""" + + num_requests: int + """The count of file search calls.""" + + object: Literal["organization.usage.file_searches.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + vector_store_id: Optional[str] = None + """ + When `group_by=vector_store_id`, this field provides the vector store ID of the + grouped usage result. + """ + + +class DataResultOrganizationUsageWebSearchesResult(BaseModel): + """The aggregated web search calls usage details of the specific time bucket.""" + + num_model_requests: int + """The count of model requests.""" + + num_requests: int + """The count of web search calls.""" + + object: Literal["organization.usage.web_searches.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + context_level: Optional[str] = None + """ + When `group_by=context_level`, this field provides the search context size of + the grouped usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + class DataResultOrganizationCostsResultAmount(BaseModel): """The monetary value in its associated currency.""" @@ -370,6 +447,8 @@ class DataResultOrganizationCostsResult(BaseModel): DataResultOrganizationUsageAudioTranscriptionsResult, DataResultOrganizationUsageVectorStoresResult, DataResultOrganizationUsageCodeInterpreterSessionsResult, + DataResultOrganizationUsageFileSearchesResult, + DataResultOrganizationUsageWebSearchesResult, DataResultOrganizationCostsResult, ], PropertyInfo(discriminator="object"), diff --git a/src/openai/types/admin/organization/usage_code_interpreter_sessions_response.py b/src/openai/types/admin/organization/usage_code_interpreter_sessions_response.py index aafda6f113..0c92f61446 100644 --- a/src/openai/types/admin/organization/usage_code_interpreter_sessions_response.py +++ b/src/openai/types/admin/organization/usage_code_interpreter_sessions_response.py @@ -18,6 +18,8 @@ "DataResultOrganizationUsageAudioTranscriptionsResult", "DataResultOrganizationUsageVectorStoresResult", "DataResultOrganizationUsageCodeInterpreterSessionsResult", + "DataResultOrganizationUsageFileSearchesResult", + "DataResultOrganizationUsageWebSearchesResult", "DataResultOrganizationCostsResult", "DataResultOrganizationCostsResultAmount", ] @@ -317,6 +319,81 @@ class DataResultOrganizationUsageCodeInterpreterSessionsResult(BaseModel): """ +class DataResultOrganizationUsageFileSearchesResult(BaseModel): + """The aggregated file search calls usage details of the specific time bucket.""" + + num_requests: int + """The count of file search calls.""" + + object: Literal["organization.usage.file_searches.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + vector_store_id: Optional[str] = None + """ + When `group_by=vector_store_id`, this field provides the vector store ID of the + grouped usage result. + """ + + +class DataResultOrganizationUsageWebSearchesResult(BaseModel): + """The aggregated web search calls usage details of the specific time bucket.""" + + num_model_requests: int + """The count of model requests.""" + + num_requests: int + """The count of web search calls.""" + + object: Literal["organization.usage.web_searches.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + context_level: Optional[str] = None + """ + When `group_by=context_level`, this field provides the search context size of + the grouped usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + class DataResultOrganizationCostsResultAmount(BaseModel): """The monetary value in its associated currency.""" @@ -370,6 +447,8 @@ class DataResultOrganizationCostsResult(BaseModel): DataResultOrganizationUsageAudioTranscriptionsResult, DataResultOrganizationUsageVectorStoresResult, DataResultOrganizationUsageCodeInterpreterSessionsResult, + DataResultOrganizationUsageFileSearchesResult, + DataResultOrganizationUsageWebSearchesResult, DataResultOrganizationCostsResult, ], PropertyInfo(discriminator="object"), diff --git a/src/openai/types/admin/organization/usage_completions_response.py b/src/openai/types/admin/organization/usage_completions_response.py index f179149995..57f0b699ec 100644 --- a/src/openai/types/admin/organization/usage_completions_response.py +++ b/src/openai/types/admin/organization/usage_completions_response.py @@ -18,6 +18,8 @@ "DataResultOrganizationUsageAudioTranscriptionsResult", "DataResultOrganizationUsageVectorStoresResult", "DataResultOrganizationUsageCodeInterpreterSessionsResult", + "DataResultOrganizationUsageFileSearchesResult", + "DataResultOrganizationUsageWebSearchesResult", "DataResultOrganizationCostsResult", "DataResultOrganizationCostsResultAmount", ] @@ -317,6 +319,81 @@ class DataResultOrganizationUsageCodeInterpreterSessionsResult(BaseModel): """ +class DataResultOrganizationUsageFileSearchesResult(BaseModel): + """The aggregated file search calls usage details of the specific time bucket.""" + + num_requests: int + """The count of file search calls.""" + + object: Literal["organization.usage.file_searches.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + vector_store_id: Optional[str] = None + """ + When `group_by=vector_store_id`, this field provides the vector store ID of the + grouped usage result. + """ + + +class DataResultOrganizationUsageWebSearchesResult(BaseModel): + """The aggregated web search calls usage details of the specific time bucket.""" + + num_model_requests: int + """The count of model requests.""" + + num_requests: int + """The count of web search calls.""" + + object: Literal["organization.usage.web_searches.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + context_level: Optional[str] = None + """ + When `group_by=context_level`, this field provides the search context size of + the grouped usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + class DataResultOrganizationCostsResultAmount(BaseModel): """The monetary value in its associated currency.""" @@ -370,6 +447,8 @@ class DataResultOrganizationCostsResult(BaseModel): DataResultOrganizationUsageAudioTranscriptionsResult, DataResultOrganizationUsageVectorStoresResult, DataResultOrganizationUsageCodeInterpreterSessionsResult, + DataResultOrganizationUsageFileSearchesResult, + DataResultOrganizationUsageWebSearchesResult, DataResultOrganizationCostsResult, ], PropertyInfo(discriminator="object"), diff --git a/src/openai/types/admin/organization/usage_costs_response.py b/src/openai/types/admin/organization/usage_costs_response.py index fd1d344e26..71eee1188a 100644 --- a/src/openai/types/admin/organization/usage_costs_response.py +++ b/src/openai/types/admin/organization/usage_costs_response.py @@ -18,6 +18,8 @@ "DataResultOrganizationUsageAudioTranscriptionsResult", "DataResultOrganizationUsageVectorStoresResult", "DataResultOrganizationUsageCodeInterpreterSessionsResult", + "DataResultOrganizationUsageFileSearchesResult", + "DataResultOrganizationUsageWebSearchesResult", "DataResultOrganizationCostsResult", "DataResultOrganizationCostsResultAmount", ] @@ -317,6 +319,81 @@ class DataResultOrganizationUsageCodeInterpreterSessionsResult(BaseModel): """ +class DataResultOrganizationUsageFileSearchesResult(BaseModel): + """The aggregated file search calls usage details of the specific time bucket.""" + + num_requests: int + """The count of file search calls.""" + + object: Literal["organization.usage.file_searches.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + vector_store_id: Optional[str] = None + """ + When `group_by=vector_store_id`, this field provides the vector store ID of the + grouped usage result. + """ + + +class DataResultOrganizationUsageWebSearchesResult(BaseModel): + """The aggregated web search calls usage details of the specific time bucket.""" + + num_model_requests: int + """The count of model requests.""" + + num_requests: int + """The count of web search calls.""" + + object: Literal["organization.usage.web_searches.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + context_level: Optional[str] = None + """ + When `group_by=context_level`, this field provides the search context size of + the grouped usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + class DataResultOrganizationCostsResultAmount(BaseModel): """The monetary value in its associated currency.""" @@ -370,6 +447,8 @@ class DataResultOrganizationCostsResult(BaseModel): DataResultOrganizationUsageAudioTranscriptionsResult, DataResultOrganizationUsageVectorStoresResult, DataResultOrganizationUsageCodeInterpreterSessionsResult, + DataResultOrganizationUsageFileSearchesResult, + DataResultOrganizationUsageWebSearchesResult, DataResultOrganizationCostsResult, ], PropertyInfo(discriminator="object"), diff --git a/src/openai/types/admin/organization/usage_embeddings_response.py b/src/openai/types/admin/organization/usage_embeddings_response.py index adbc389d89..69697ee4e7 100644 --- a/src/openai/types/admin/organization/usage_embeddings_response.py +++ b/src/openai/types/admin/organization/usage_embeddings_response.py @@ -18,6 +18,8 @@ "DataResultOrganizationUsageAudioTranscriptionsResult", "DataResultOrganizationUsageVectorStoresResult", "DataResultOrganizationUsageCodeInterpreterSessionsResult", + "DataResultOrganizationUsageFileSearchesResult", + "DataResultOrganizationUsageWebSearchesResult", "DataResultOrganizationCostsResult", "DataResultOrganizationCostsResultAmount", ] @@ -317,6 +319,81 @@ class DataResultOrganizationUsageCodeInterpreterSessionsResult(BaseModel): """ +class DataResultOrganizationUsageFileSearchesResult(BaseModel): + """The aggregated file search calls usage details of the specific time bucket.""" + + num_requests: int + """The count of file search calls.""" + + object: Literal["organization.usage.file_searches.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + vector_store_id: Optional[str] = None + """ + When `group_by=vector_store_id`, this field provides the vector store ID of the + grouped usage result. + """ + + +class DataResultOrganizationUsageWebSearchesResult(BaseModel): + """The aggregated web search calls usage details of the specific time bucket.""" + + num_model_requests: int + """The count of model requests.""" + + num_requests: int + """The count of web search calls.""" + + object: Literal["organization.usage.web_searches.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + context_level: Optional[str] = None + """ + When `group_by=context_level`, this field provides the search context size of + the grouped usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + class DataResultOrganizationCostsResultAmount(BaseModel): """The monetary value in its associated currency.""" @@ -370,6 +447,8 @@ class DataResultOrganizationCostsResult(BaseModel): DataResultOrganizationUsageAudioTranscriptionsResult, DataResultOrganizationUsageVectorStoresResult, DataResultOrganizationUsageCodeInterpreterSessionsResult, + DataResultOrganizationUsageFileSearchesResult, + DataResultOrganizationUsageWebSearchesResult, DataResultOrganizationCostsResult, ], PropertyInfo(discriminator="object"), diff --git a/src/openai/types/admin/organization/usage_images_response.py b/src/openai/types/admin/organization/usage_images_response.py index 7c6a096c98..33c3ebb130 100644 --- a/src/openai/types/admin/organization/usage_images_response.py +++ b/src/openai/types/admin/organization/usage_images_response.py @@ -18,6 +18,8 @@ "DataResultOrganizationUsageAudioTranscriptionsResult", "DataResultOrganizationUsageVectorStoresResult", "DataResultOrganizationUsageCodeInterpreterSessionsResult", + "DataResultOrganizationUsageFileSearchesResult", + "DataResultOrganizationUsageWebSearchesResult", "DataResultOrganizationCostsResult", "DataResultOrganizationCostsResultAmount", ] @@ -317,6 +319,81 @@ class DataResultOrganizationUsageCodeInterpreterSessionsResult(BaseModel): """ +class DataResultOrganizationUsageFileSearchesResult(BaseModel): + """The aggregated file search calls usage details of the specific time bucket.""" + + num_requests: int + """The count of file search calls.""" + + object: Literal["organization.usage.file_searches.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + vector_store_id: Optional[str] = None + """ + When `group_by=vector_store_id`, this field provides the vector store ID of the + grouped usage result. + """ + + +class DataResultOrganizationUsageWebSearchesResult(BaseModel): + """The aggregated web search calls usage details of the specific time bucket.""" + + num_model_requests: int + """The count of model requests.""" + + num_requests: int + """The count of web search calls.""" + + object: Literal["organization.usage.web_searches.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + context_level: Optional[str] = None + """ + When `group_by=context_level`, this field provides the search context size of + the grouped usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + class DataResultOrganizationCostsResultAmount(BaseModel): """The monetary value in its associated currency.""" @@ -370,6 +447,8 @@ class DataResultOrganizationCostsResult(BaseModel): DataResultOrganizationUsageAudioTranscriptionsResult, DataResultOrganizationUsageVectorStoresResult, DataResultOrganizationUsageCodeInterpreterSessionsResult, + DataResultOrganizationUsageFileSearchesResult, + DataResultOrganizationUsageWebSearchesResult, DataResultOrganizationCostsResult, ], PropertyInfo(discriminator="object"), diff --git a/src/openai/types/admin/organization/usage_moderations_response.py b/src/openai/types/admin/organization/usage_moderations_response.py index 5e40ef1164..3aa5d9193d 100644 --- a/src/openai/types/admin/organization/usage_moderations_response.py +++ b/src/openai/types/admin/organization/usage_moderations_response.py @@ -18,6 +18,8 @@ "DataResultOrganizationUsageAudioTranscriptionsResult", "DataResultOrganizationUsageVectorStoresResult", "DataResultOrganizationUsageCodeInterpreterSessionsResult", + "DataResultOrganizationUsageFileSearchesResult", + "DataResultOrganizationUsageWebSearchesResult", "DataResultOrganizationCostsResult", "DataResultOrganizationCostsResultAmount", ] @@ -317,6 +319,81 @@ class DataResultOrganizationUsageCodeInterpreterSessionsResult(BaseModel): """ +class DataResultOrganizationUsageFileSearchesResult(BaseModel): + """The aggregated file search calls usage details of the specific time bucket.""" + + num_requests: int + """The count of file search calls.""" + + object: Literal["organization.usage.file_searches.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + vector_store_id: Optional[str] = None + """ + When `group_by=vector_store_id`, this field provides the vector store ID of the + grouped usage result. + """ + + +class DataResultOrganizationUsageWebSearchesResult(BaseModel): + """The aggregated web search calls usage details of the specific time bucket.""" + + num_model_requests: int + """The count of model requests.""" + + num_requests: int + """The count of web search calls.""" + + object: Literal["organization.usage.web_searches.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + context_level: Optional[str] = None + """ + When `group_by=context_level`, this field provides the search context size of + the grouped usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + class DataResultOrganizationCostsResultAmount(BaseModel): """The monetary value in its associated currency.""" @@ -370,6 +447,8 @@ class DataResultOrganizationCostsResult(BaseModel): DataResultOrganizationUsageAudioTranscriptionsResult, DataResultOrganizationUsageVectorStoresResult, DataResultOrganizationUsageCodeInterpreterSessionsResult, + DataResultOrganizationUsageFileSearchesResult, + DataResultOrganizationUsageWebSearchesResult, DataResultOrganizationCostsResult, ], PropertyInfo(discriminator="object"), diff --git a/src/openai/types/admin/organization/usage_vector_stores_response.py b/src/openai/types/admin/organization/usage_vector_stores_response.py index 089aa23119..a5ecc31185 100644 --- a/src/openai/types/admin/organization/usage_vector_stores_response.py +++ b/src/openai/types/admin/organization/usage_vector_stores_response.py @@ -18,6 +18,8 @@ "DataResultOrganizationUsageAudioTranscriptionsResult", "DataResultOrganizationUsageVectorStoresResult", "DataResultOrganizationUsageCodeInterpreterSessionsResult", + "DataResultOrganizationUsageFileSearchesResult", + "DataResultOrganizationUsageWebSearchesResult", "DataResultOrganizationCostsResult", "DataResultOrganizationCostsResultAmount", ] @@ -317,6 +319,81 @@ class DataResultOrganizationUsageCodeInterpreterSessionsResult(BaseModel): """ +class DataResultOrganizationUsageFileSearchesResult(BaseModel): + """The aggregated file search calls usage details of the specific time bucket.""" + + num_requests: int + """The count of file search calls.""" + + object: Literal["organization.usage.file_searches.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + vector_store_id: Optional[str] = None + """ + When `group_by=vector_store_id`, this field provides the vector store ID of the + grouped usage result. + """ + + +class DataResultOrganizationUsageWebSearchesResult(BaseModel): + """The aggregated web search calls usage details of the specific time bucket.""" + + num_model_requests: int + """The count of model requests.""" + + num_requests: int + """The count of web search calls.""" + + object: Literal["organization.usage.web_searches.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + context_level: Optional[str] = None + """ + When `group_by=context_level`, this field provides the search context size of + the grouped usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + class DataResultOrganizationCostsResultAmount(BaseModel): """The monetary value in its associated currency.""" @@ -370,6 +447,8 @@ class DataResultOrganizationCostsResult(BaseModel): DataResultOrganizationUsageAudioTranscriptionsResult, DataResultOrganizationUsageVectorStoresResult, DataResultOrganizationUsageCodeInterpreterSessionsResult, + DataResultOrganizationUsageFileSearchesResult, + DataResultOrganizationUsageWebSearchesResult, DataResultOrganizationCostsResult, ], PropertyInfo(discriminator="object"), diff --git a/src/openai/types/responses/response_input_item.py b/src/openai/types/responses/response_input_item.py index af3ce5bdc9..9f12b429bd 100644 --- a/src/openai/types/responses/response_input_item.py +++ b/src/openai/types/responses/response_input_item.py @@ -50,6 +50,7 @@ "McpApprovalRequest", "McpApprovalResponse", "McpCall", + "CompactionTrigger", "ItemReference", ] @@ -527,6 +528,13 @@ class McpCall(BaseModel): """ +class CompactionTrigger(BaseModel): + """Compacts the current context. Must be the final input item.""" + + type: Literal["compaction_trigger"] + """The type of the item. Always `compaction_trigger`.""" + + class ItemReference(BaseModel): """An internal identifier for an item to reference.""" @@ -566,6 +574,7 @@ class ItemReference(BaseModel): McpCall, ResponseCustomToolCallOutput, ResponseCustomToolCall, + CompactionTrigger, ItemReference, ], PropertyInfo(discriminator="type"), diff --git a/src/openai/types/responses/response_input_item_param.py b/src/openai/types/responses/response_input_item_param.py index 87ea1bc572..156ac92d39 100644 --- a/src/openai/types/responses/response_input_item_param.py +++ b/src/openai/types/responses/response_input_item_param.py @@ -51,6 +51,7 @@ "McpApprovalRequest", "McpApprovalResponse", "McpCall", + "CompactionTrigger", "ItemReference", ] @@ -525,6 +526,13 @@ class McpCall(TypedDict, total=False): """ +class CompactionTrigger(TypedDict, total=False): + """Compacts the current context. Must be the final input item.""" + + type: Required[Literal["compaction_trigger"]] + """The type of the item. Always `compaction_trigger`.""" + + class ItemReference(TypedDict, total=False): """An internal identifier for an item to reference.""" @@ -563,5 +571,6 @@ class ItemReference(TypedDict, total=False): McpCall, ResponseCustomToolCallOutputParam, ResponseCustomToolCallParam, + CompactionTrigger, ItemReference, ] diff --git a/src/openai/types/responses/response_input_param.py b/src/openai/types/responses/response_input_param.py index cf4d529521..656c70359b 100644 --- a/src/openai/types/responses/response_input_param.py +++ b/src/openai/types/responses/response_input_param.py @@ -52,6 +52,7 @@ "McpApprovalRequest", "McpApprovalResponse", "McpCall", + "CompactionTrigger", "ItemReference", ] @@ -526,6 +527,13 @@ class McpCall(TypedDict, total=False): """ +class CompactionTrigger(TypedDict, total=False): + """Compacts the current context. Must be the final input item.""" + + type: Required[Literal["compaction_trigger"]] + """The type of the item. Always `compaction_trigger`.""" + + class ItemReference(TypedDict, total=False): """An internal identifier for an item to reference.""" @@ -564,6 +572,7 @@ class ItemReference(TypedDict, total=False): McpCall, ResponseCustomToolCallOutputParam, ResponseCustomToolCallParam, + CompactionTrigger, ItemReference, ] From a6f899aa1e046dd0cc18b89c4f73260463888db6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 18 May 2026 18:55:17 +0000 Subject: [PATCH 750/769] feat(api): manual updates Update specs --- .stats.yml | 6 +- api.md | 34 ++ .../admin/organization/projects/__init__.py | 28 ++ .../projects/hosted_tool_permissions.py | 307 +++++++++++ .../projects/model_permissions.py | 370 ++++++++++++++ .../admin/organization/projects/projects.py | 64 +++ .../resources/admin/organization/usage.py | 384 ++++++++++++++ .../types/admin/organization/__init__.py | 4 + .../admin/organization/projects/__init__.py | 5 + .../hosted_tool_permission_update_params.py | 60 +++ .../model_permission_update_params.py | 17 + .../project_hosted_tool_permissions.py | 59 +++ .../projects/project_model_permissions.py | 23 + .../project_model_permissions_deleted.py | 17 + .../usage_file_search_calls_params.py | 57 +++ .../usage_file_search_calls_response.py | 475 ++++++++++++++++++ .../usage_web_search_calls_params.py | 60 +++ .../usage_web_search_calls_response.py | 475 ++++++++++++++++++ .../projects/test_hosted_tool_permissions.py | 200 ++++++++ .../projects/test_model_permissions.py | 271 ++++++++++ .../admin/organization/test_usage.py | 192 +++++++ 21 files changed, 3105 insertions(+), 3 deletions(-) create mode 100644 src/openai/resources/admin/organization/projects/hosted_tool_permissions.py create mode 100644 src/openai/resources/admin/organization/projects/model_permissions.py create mode 100644 src/openai/types/admin/organization/projects/hosted_tool_permission_update_params.py create mode 100644 src/openai/types/admin/organization/projects/model_permission_update_params.py create mode 100644 src/openai/types/admin/organization/projects/project_hosted_tool_permissions.py create mode 100644 src/openai/types/admin/organization/projects/project_model_permissions.py create mode 100644 src/openai/types/admin/organization/projects/project_model_permissions_deleted.py create mode 100644 src/openai/types/admin/organization/usage_file_search_calls_params.py create mode 100644 src/openai/types/admin/organization/usage_file_search_calls_response.py create mode 100644 src/openai/types/admin/organization/usage_web_search_calls_params.py create mode 100644 src/openai/types/admin/organization/usage_web_search_calls_response.py create mode 100644 tests/api_resources/admin/organization/projects/test_hosted_tool_permissions.py create mode 100644 tests/api_resources/admin/organization/projects/test_model_permissions.py diff --git a/.stats.yml b/.stats.yml index f805dd3c95..60770c0e7a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 233 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-fcfdf0bb920ca15a6d01d1cfe988accb7559b2d991b6e2ad6b25cfae81ac2ae9.yml +configured_endpoints: 240 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-d7d5adb20c516e7aca6e35ed9f58aba0bc14dd5aa0096fd980061c4a5ab406e3.yml openapi_spec_hash: 72ee7d4fe582e75d16e67b6c97881fed -config_hash: 70ff4da62a6a6ef9f91d566c38b7bddf +config_hash: af72288617facaeed4d014024a9c946d diff --git a/api.md b/api.md index e04636937c..ab2f3f75a2 100644 --- a/api.md +++ b/api.md @@ -754,9 +754,11 @@ from openai.types.admin.organization import ( UsageCompletionsResponse, UsageCostsResponse, UsageEmbeddingsResponse, + UsageFileSearchCallsResponse, UsageImagesResponse, UsageModerationsResponse, UsageVectorStoresResponse, + UsageWebSearchCallsResponse, ) ``` @@ -768,9 +770,11 @@ Methods: - client.admin.organization.usage.completions(\*\*params) -> UsageCompletionsResponse - client.admin.organization.usage.costs(\*\*params) -> UsageCostsResponse - client.admin.organization.usage.embeddings(\*\*params) -> UsageEmbeddingsResponse +- client.admin.organization.usage.file_search_calls(\*\*params) -> UsageFileSearchCallsResponse - client.admin.organization.usage.images(\*\*params) -> UsageImagesResponse - client.admin.organization.usage.moderations(\*\*params) -> UsageModerationsResponse - client.admin.organization.usage.vector_stores(\*\*params) -> UsageVectorStoresResponse +- client.admin.organization.usage.web_search_calls(\*\*params) -> UsageWebSearchCallsResponse ### Invites @@ -1006,6 +1010,36 @@ Methods: - client.admin.organization.projects.rate_limits.list_rate_limits(project_id, \*\*params) -> SyncConversationCursorPage[ProjectRateLimit] - client.admin.organization.projects.rate_limits.update_rate_limit(rate_limit_id, \*, project_id, \*\*params) -> ProjectRateLimit +#### ModelPermissions + +Types: + +```python +from openai.types.admin.organization.projects import ( + ProjectModelPermissions, + ProjectModelPermissionsDeleted, +) +``` + +Methods: + +- client.admin.organization.projects.model_permissions.retrieve(project_id) -> ProjectModelPermissions +- client.admin.organization.projects.model_permissions.update(project_id, \*\*params) -> ProjectModelPermissions +- client.admin.organization.projects.model_permissions.delete(project_id) -> ProjectModelPermissionsDeleted + +#### HostedToolPermissions + +Types: + +```python +from openai.types.admin.organization.projects import ProjectHostedToolPermissions +``` + +Methods: + +- client.admin.organization.projects.hosted_tool_permissions.retrieve(project_id) -> ProjectHostedToolPermissions +- client.admin.organization.projects.hosted_tool_permissions.update(project_id, \*\*params) -> ProjectHostedToolPermissions + #### Groups Types: diff --git a/src/openai/resources/admin/organization/projects/__init__.py b/src/openai/resources/admin/organization/projects/__init__.py index a64326bfa9..7f77863a2d 100644 --- a/src/openai/resources/admin/organization/projects/__init__.py +++ b/src/openai/resources/admin/organization/projects/__init__.py @@ -64,6 +64,22 @@ ServiceAccountsWithStreamingResponse, AsyncServiceAccountsWithStreamingResponse, ) +from .model_permissions import ( + ModelPermissions, + AsyncModelPermissions, + ModelPermissionsWithRawResponse, + AsyncModelPermissionsWithRawResponse, + ModelPermissionsWithStreamingResponse, + AsyncModelPermissionsWithStreamingResponse, +) +from .hosted_tool_permissions import ( + HostedToolPermissions, + AsyncHostedToolPermissions, + HostedToolPermissionsWithRawResponse, + AsyncHostedToolPermissionsWithRawResponse, + HostedToolPermissionsWithStreamingResponse, + AsyncHostedToolPermissionsWithStreamingResponse, +) __all__ = [ "Users", @@ -90,6 +106,18 @@ "AsyncRateLimitsWithRawResponse", "RateLimitsWithStreamingResponse", "AsyncRateLimitsWithStreamingResponse", + "ModelPermissions", + "AsyncModelPermissions", + "ModelPermissionsWithRawResponse", + "AsyncModelPermissionsWithRawResponse", + "ModelPermissionsWithStreamingResponse", + "AsyncModelPermissionsWithStreamingResponse", + "HostedToolPermissions", + "AsyncHostedToolPermissions", + "HostedToolPermissionsWithRawResponse", + "AsyncHostedToolPermissionsWithRawResponse", + "HostedToolPermissionsWithStreamingResponse", + "AsyncHostedToolPermissionsWithStreamingResponse", "Groups", "AsyncGroups", "GroupsWithRawResponse", diff --git a/src/openai/resources/admin/organization/projects/hosted_tool_permissions.py b/src/openai/resources/admin/organization/projects/hosted_tool_permissions.py new file mode 100644 index 0000000000..27bcee5f5e --- /dev/null +++ b/src/openai/resources/admin/organization/projects/hosted_tool_permissions.py @@ -0,0 +1,307 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional + +import httpx + +from ..... import _legacy_response +from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ....._utils import path_template, maybe_transform, async_maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ....._base_client import make_request_options +from .....types.admin.organization.projects import hosted_tool_permission_update_params +from .....types.admin.organization.projects.project_hosted_tool_permissions import ProjectHostedToolPermissions + +__all__ = ["HostedToolPermissions", "AsyncHostedToolPermissions"] + + +class HostedToolPermissions(SyncAPIResource): + @cached_property + def with_raw_response(self) -> HostedToolPermissionsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return HostedToolPermissionsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> HostedToolPermissionsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return HostedToolPermissionsWithStreamingResponse(self) + + def retrieve( + self, + project_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectHostedToolPermissions: + """ + Returns hosted tool permissions for a project. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._get( + path_template("/organization/projects/{project_id}/hosted_tool_permissions", project_id=project_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectHostedToolPermissions, + ) + + def update( + self, + project_id: str, + *, + code_interpreter: Optional[hosted_tool_permission_update_params.CodeInterpreter] | Omit = omit, + file_search: Optional[hosted_tool_permission_update_params.FileSearch] | Omit = omit, + image_generation: Optional[hosted_tool_permission_update_params.ImageGeneration] | Omit = omit, + mcp: Optional[hosted_tool_permission_update_params.Mcp] | Omit = omit, + web_search: Optional[hosted_tool_permission_update_params.WebSearch] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectHostedToolPermissions: + """ + Updates hosted tool permissions for a project. + + Args: + code_interpreter: The code interpreter permission update. + + file_search: The file search permission update. + + image_generation: The image generation permission update. + + mcp: The MCP permission update. + + web_search: The web search permission update. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._post( + path_template("/organization/projects/{project_id}/hosted_tool_permissions", project_id=project_id), + body=maybe_transform( + { + "code_interpreter": code_interpreter, + "file_search": file_search, + "image_generation": image_generation, + "mcp": mcp, + "web_search": web_search, + }, + hosted_tool_permission_update_params.HostedToolPermissionUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectHostedToolPermissions, + ) + + +class AsyncHostedToolPermissions(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncHostedToolPermissionsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncHostedToolPermissionsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncHostedToolPermissionsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncHostedToolPermissionsWithStreamingResponse(self) + + async def retrieve( + self, + project_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectHostedToolPermissions: + """ + Returns hosted tool permissions for a project. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return await self._get( + path_template("/organization/projects/{project_id}/hosted_tool_permissions", project_id=project_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectHostedToolPermissions, + ) + + async def update( + self, + project_id: str, + *, + code_interpreter: Optional[hosted_tool_permission_update_params.CodeInterpreter] | Omit = omit, + file_search: Optional[hosted_tool_permission_update_params.FileSearch] | Omit = omit, + image_generation: Optional[hosted_tool_permission_update_params.ImageGeneration] | Omit = omit, + mcp: Optional[hosted_tool_permission_update_params.Mcp] | Omit = omit, + web_search: Optional[hosted_tool_permission_update_params.WebSearch] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectHostedToolPermissions: + """ + Updates hosted tool permissions for a project. + + Args: + code_interpreter: The code interpreter permission update. + + file_search: The file search permission update. + + image_generation: The image generation permission update. + + mcp: The MCP permission update. + + web_search: The web search permission update. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return await self._post( + path_template("/organization/projects/{project_id}/hosted_tool_permissions", project_id=project_id), + body=await async_maybe_transform( + { + "code_interpreter": code_interpreter, + "file_search": file_search, + "image_generation": image_generation, + "mcp": mcp, + "web_search": web_search, + }, + hosted_tool_permission_update_params.HostedToolPermissionUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectHostedToolPermissions, + ) + + +class HostedToolPermissionsWithRawResponse: + def __init__(self, hosted_tool_permissions: HostedToolPermissions) -> None: + self._hosted_tool_permissions = hosted_tool_permissions + + self.retrieve = _legacy_response.to_raw_response_wrapper( + hosted_tool_permissions.retrieve, + ) + self.update = _legacy_response.to_raw_response_wrapper( + hosted_tool_permissions.update, + ) + + +class AsyncHostedToolPermissionsWithRawResponse: + def __init__(self, hosted_tool_permissions: AsyncHostedToolPermissions) -> None: + self._hosted_tool_permissions = hosted_tool_permissions + + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + hosted_tool_permissions.retrieve, + ) + self.update = _legacy_response.async_to_raw_response_wrapper( + hosted_tool_permissions.update, + ) + + +class HostedToolPermissionsWithStreamingResponse: + def __init__(self, hosted_tool_permissions: HostedToolPermissions) -> None: + self._hosted_tool_permissions = hosted_tool_permissions + + self.retrieve = to_streamed_response_wrapper( + hosted_tool_permissions.retrieve, + ) + self.update = to_streamed_response_wrapper( + hosted_tool_permissions.update, + ) + + +class AsyncHostedToolPermissionsWithStreamingResponse: + def __init__(self, hosted_tool_permissions: AsyncHostedToolPermissions) -> None: + self._hosted_tool_permissions = hosted_tool_permissions + + self.retrieve = async_to_streamed_response_wrapper( + hosted_tool_permissions.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + hosted_tool_permissions.update, + ) diff --git a/src/openai/resources/admin/organization/projects/model_permissions.py b/src/openai/resources/admin/organization/projects/model_permissions.py new file mode 100644 index 0000000000..157b4a4f72 --- /dev/null +++ b/src/openai/resources/admin/organization/projects/model_permissions.py @@ -0,0 +1,370 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from ..... import _legacy_response +from ....._types import Body, Query, Headers, NotGiven, SequenceNotStr, not_given +from ....._utils import path_template, maybe_transform, async_maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ....._base_client import make_request_options +from .....types.admin.organization.projects import model_permission_update_params +from .....types.admin.organization.projects.project_model_permissions import ProjectModelPermissions +from .....types.admin.organization.projects.project_model_permissions_deleted import ProjectModelPermissionsDeleted + +__all__ = ["ModelPermissions", "AsyncModelPermissions"] + + +class ModelPermissions(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ModelPermissionsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return ModelPermissionsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ModelPermissionsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return ModelPermissionsWithStreamingResponse(self) + + def retrieve( + self, + project_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectModelPermissions: + """ + Returns model permissions for a project. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._get( + path_template("/organization/projects/{project_id}/model_permissions", project_id=project_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectModelPermissions, + ) + + def update( + self, + project_id: str, + *, + mode: Literal["allow_list", "deny_list"], + model_ids: SequenceNotStr[str], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectModelPermissions: + """ + Updates model permissions for a project. + + Args: + mode: The model permissions mode to apply. + + model_ids: The model IDs included in this permissions policy. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._post( + path_template("/organization/projects/{project_id}/model_permissions", project_id=project_id), + body=maybe_transform( + { + "mode": mode, + "model_ids": model_ids, + }, + model_permission_update_params.ModelPermissionUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectModelPermissions, + ) + + def delete( + self, + project_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectModelPermissionsDeleted: + """ + Deletes model permissions for a project. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._delete( + path_template("/organization/projects/{project_id}/model_permissions", project_id=project_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectModelPermissionsDeleted, + ) + + +class AsyncModelPermissions(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncModelPermissionsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncModelPermissionsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncModelPermissionsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncModelPermissionsWithStreamingResponse(self) + + async def retrieve( + self, + project_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectModelPermissions: + """ + Returns model permissions for a project. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return await self._get( + path_template("/organization/projects/{project_id}/model_permissions", project_id=project_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectModelPermissions, + ) + + async def update( + self, + project_id: str, + *, + mode: Literal["allow_list", "deny_list"], + model_ids: SequenceNotStr[str], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectModelPermissions: + """ + Updates model permissions for a project. + + Args: + mode: The model permissions mode to apply. + + model_ids: The model IDs included in this permissions policy. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return await self._post( + path_template("/organization/projects/{project_id}/model_permissions", project_id=project_id), + body=await async_maybe_transform( + { + "mode": mode, + "model_ids": model_ids, + }, + model_permission_update_params.ModelPermissionUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectModelPermissions, + ) + + async def delete( + self, + project_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectModelPermissionsDeleted: + """ + Deletes model permissions for a project. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return await self._delete( + path_template("/organization/projects/{project_id}/model_permissions", project_id=project_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectModelPermissionsDeleted, + ) + + +class ModelPermissionsWithRawResponse: + def __init__(self, model_permissions: ModelPermissions) -> None: + self._model_permissions = model_permissions + + self.retrieve = _legacy_response.to_raw_response_wrapper( + model_permissions.retrieve, + ) + self.update = _legacy_response.to_raw_response_wrapper( + model_permissions.update, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + model_permissions.delete, + ) + + +class AsyncModelPermissionsWithRawResponse: + def __init__(self, model_permissions: AsyncModelPermissions) -> None: + self._model_permissions = model_permissions + + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + model_permissions.retrieve, + ) + self.update = _legacy_response.async_to_raw_response_wrapper( + model_permissions.update, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + model_permissions.delete, + ) + + +class ModelPermissionsWithStreamingResponse: + def __init__(self, model_permissions: ModelPermissions) -> None: + self._model_permissions = model_permissions + + self.retrieve = to_streamed_response_wrapper( + model_permissions.retrieve, + ) + self.update = to_streamed_response_wrapper( + model_permissions.update, + ) + self.delete = to_streamed_response_wrapper( + model_permissions.delete, + ) + + +class AsyncModelPermissionsWithStreamingResponse: + def __init__(self, model_permissions: AsyncModelPermissions) -> None: + self._model_permissions = model_permissions + + self.retrieve = async_to_streamed_response_wrapper( + model_permissions.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + model_permissions.update, + ) + self.delete = async_to_streamed_response_wrapper( + model_permissions.delete, + ) diff --git a/src/openai/resources/admin/organization/projects/projects.py b/src/openai/resources/admin/organization/projects/projects.py index 60d252cd46..b69e69d0dd 100644 --- a/src/openai/resources/admin/organization/projects/projects.py +++ b/src/openai/resources/admin/organization/projects/projects.py @@ -70,6 +70,22 @@ ServiceAccountsWithStreamingResponse, AsyncServiceAccountsWithStreamingResponse, ) +from .model_permissions import ( + ModelPermissions, + AsyncModelPermissions, + ModelPermissionsWithRawResponse, + AsyncModelPermissionsWithRawResponse, + ModelPermissionsWithStreamingResponse, + AsyncModelPermissionsWithStreamingResponse, +) +from .hosted_tool_permissions import ( + HostedToolPermissions, + AsyncHostedToolPermissions, + HostedToolPermissionsWithRawResponse, + AsyncHostedToolPermissionsWithRawResponse, + HostedToolPermissionsWithStreamingResponse, + AsyncHostedToolPermissionsWithStreamingResponse, +) from .....types.admin.organization import project_list_params, project_create_params, project_update_params from .....types.admin.organization.project import Project @@ -93,6 +109,14 @@ def api_keys(self) -> APIKeys: def rate_limits(self) -> RateLimits: return RateLimits(self._client) + @cached_property + def model_permissions(self) -> ModelPermissions: + return ModelPermissions(self._client) + + @cached_property + def hosted_tool_permissions(self) -> HostedToolPermissions: + return HostedToolPermissions(self._client) + @cached_property def groups(self) -> Groups: return Groups(self._client) @@ -386,6 +410,14 @@ def api_keys(self) -> AsyncAPIKeys: def rate_limits(self) -> AsyncRateLimits: return AsyncRateLimits(self._client) + @cached_property + def model_permissions(self) -> AsyncModelPermissions: + return AsyncModelPermissions(self._client) + + @cached_property + def hosted_tool_permissions(self) -> AsyncHostedToolPermissions: + return AsyncHostedToolPermissions(self._client) + @cached_property def groups(self) -> AsyncGroups: return AsyncGroups(self._client) @@ -698,6 +730,14 @@ def api_keys(self) -> APIKeysWithRawResponse: def rate_limits(self) -> RateLimitsWithRawResponse: return RateLimitsWithRawResponse(self._projects.rate_limits) + @cached_property + def model_permissions(self) -> ModelPermissionsWithRawResponse: + return ModelPermissionsWithRawResponse(self._projects.model_permissions) + + @cached_property + def hosted_tool_permissions(self) -> HostedToolPermissionsWithRawResponse: + return HostedToolPermissionsWithRawResponse(self._projects.hosted_tool_permissions) + @cached_property def groups(self) -> GroupsWithRawResponse: return GroupsWithRawResponse(self._projects.groups) @@ -747,6 +787,14 @@ def api_keys(self) -> AsyncAPIKeysWithRawResponse: def rate_limits(self) -> AsyncRateLimitsWithRawResponse: return AsyncRateLimitsWithRawResponse(self._projects.rate_limits) + @cached_property + def model_permissions(self) -> AsyncModelPermissionsWithRawResponse: + return AsyncModelPermissionsWithRawResponse(self._projects.model_permissions) + + @cached_property + def hosted_tool_permissions(self) -> AsyncHostedToolPermissionsWithRawResponse: + return AsyncHostedToolPermissionsWithRawResponse(self._projects.hosted_tool_permissions) + @cached_property def groups(self) -> AsyncGroupsWithRawResponse: return AsyncGroupsWithRawResponse(self._projects.groups) @@ -796,6 +844,14 @@ def api_keys(self) -> APIKeysWithStreamingResponse: def rate_limits(self) -> RateLimitsWithStreamingResponse: return RateLimitsWithStreamingResponse(self._projects.rate_limits) + @cached_property + def model_permissions(self) -> ModelPermissionsWithStreamingResponse: + return ModelPermissionsWithStreamingResponse(self._projects.model_permissions) + + @cached_property + def hosted_tool_permissions(self) -> HostedToolPermissionsWithStreamingResponse: + return HostedToolPermissionsWithStreamingResponse(self._projects.hosted_tool_permissions) + @cached_property def groups(self) -> GroupsWithStreamingResponse: return GroupsWithStreamingResponse(self._projects.groups) @@ -845,6 +901,14 @@ def api_keys(self) -> AsyncAPIKeysWithStreamingResponse: def rate_limits(self) -> AsyncRateLimitsWithStreamingResponse: return AsyncRateLimitsWithStreamingResponse(self._projects.rate_limits) + @cached_property + def model_permissions(self) -> AsyncModelPermissionsWithStreamingResponse: + return AsyncModelPermissionsWithStreamingResponse(self._projects.model_permissions) + + @cached_property + def hosted_tool_permissions(self) -> AsyncHostedToolPermissionsWithStreamingResponse: + return AsyncHostedToolPermissionsWithStreamingResponse(self._projects.hosted_tool_permissions) + @cached_property def groups(self) -> AsyncGroupsWithStreamingResponse: return AsyncGroupsWithStreamingResponse(self._projects.groups) diff --git a/src/openai/resources/admin/organization/usage.py b/src/openai/resources/admin/organization/usage.py index 2725d5e884..99306c6828 100644 --- a/src/openai/resources/admin/organization/usage.py +++ b/src/openai/resources/admin/organization/usage.py @@ -22,6 +22,8 @@ usage_moderations_params, usage_vector_stores_params, usage_audio_speeches_params, + usage_web_search_calls_params, + usage_file_search_calls_params, usage_audio_transcriptions_params, usage_code_interpreter_sessions_params, ) @@ -32,6 +34,8 @@ from ....types.admin.organization.usage_moderations_response import UsageModerationsResponse from ....types.admin.organization.usage_vector_stores_response import UsageVectorStoresResponse from ....types.admin.organization.usage_audio_speeches_response import UsageAudioSpeechesResponse +from ....types.admin.organization.usage_web_search_calls_response import UsageWebSearchCallsResponse +from ....types.admin.organization.usage_file_search_calls_response import UsageFileSearchCallsResponse from ....types.admin.organization.usage_audio_transcriptions_response import UsageAudioTranscriptionsResponse from ....types.admin.organization.usage_code_interpreter_sessions_response import UsageCodeInterpreterSessionsResponse @@ -557,6 +561,93 @@ def embeddings( cast_to=UsageEmbeddingsResponse, ) + def file_search_calls( + self, + *, + start_time: int, + api_key_ids: SequenceNotStr[str] | Omit = omit, + bucket_width: Literal["1m", "1h", "1d"] | Omit = omit, + end_time: int | Omit = omit, + group_by: List[Literal["project_id", "user_id", "api_key_id", "vector_store_id"]] | Omit = omit, + limit: int | Omit = omit, + page: str | Omit = omit, + project_ids: SequenceNotStr[str] | Omit = omit, + user_ids: SequenceNotStr[str] | Omit = omit, + vector_store_ids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UsageFileSearchCallsResponse: + """ + Get file search calls usage details for the organization. + + Args: + start_time: Start time (Unix seconds) of the query time range, inclusive. + + api_key_ids: Return only usage for these API keys. + + bucket_width: Width of each time bucket in response. Currently `1m`, `1h` and `1d` are + supported, default to `1d`. + + end_time: End time (Unix seconds) of the query time range, exclusive. + + group_by: Group the usage data by the specified fields. Support fields include + `project_id`, `user_id`, `api_key_id`, `vector_store_id` or any combination of + them. + + limit: Specifies the number of buckets to return. + + - `bucket_width=1d`: default: 7, max: 31 + - `bucket_width=1h`: default: 24, max: 168 + - `bucket_width=1m`: default: 60, max: 1440 + + page: A cursor for use in pagination. Corresponding to the `next_page` field from the + previous response. + + project_ids: Return only usage for these projects. + + user_ids: Return only usage for these users. + + vector_store_ids: Return only usage for these vector stores. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/organization/usage/file_search_calls", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "start_time": start_time, + "api_key_ids": api_key_ids, + "bucket_width": bucket_width, + "end_time": end_time, + "group_by": group_by, + "limit": limit, + "page": page, + "project_ids": project_ids, + "user_ids": user_ids, + "vector_store_ids": vector_store_ids, + }, + usage_file_search_calls_params.UsageFileSearchCallsParams, + ), + security={"admin_api_key_auth": True}, + ), + cast_to=UsageFileSearchCallsResponse, + ) + def images( self, *, @@ -814,6 +905,97 @@ def vector_stores( cast_to=UsageVectorStoresResponse, ) + def web_search_calls( + self, + *, + start_time: int, + api_key_ids: SequenceNotStr[str] | Omit = omit, + bucket_width: Literal["1m", "1h", "1d"] | Omit = omit, + context_levels: List[Literal["low", "medium", "high"]] | Omit = omit, + end_time: int | Omit = omit, + group_by: List[Literal["project_id", "user_id", "api_key_id", "model", "context_level"]] | Omit = omit, + limit: int | Omit = omit, + models: SequenceNotStr[str] | Omit = omit, + page: str | Omit = omit, + project_ids: SequenceNotStr[str] | Omit = omit, + user_ids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UsageWebSearchCallsResponse: + """ + Get web search calls usage details for the organization. + + Args: + start_time: Start time (Unix seconds) of the query time range, inclusive. + + api_key_ids: Return only usage for these API keys. + + bucket_width: Width of each time bucket in response. Currently `1m`, `1h` and `1d` are + supported, default to `1d`. + + context_levels: Return only web search usage for these context levels. + + end_time: End time (Unix seconds) of the query time range, exclusive. + + group_by: Group the usage data by the specified fields. Support fields include + `project_id`, `user_id`, `api_key_id`, `model`, `context_level` or any + combination of them. + + limit: Specifies the number of buckets to return. + + - `bucket_width=1d`: default: 7, max: 31 + - `bucket_width=1h`: default: 24, max: 168 + - `bucket_width=1m`: default: 60, max: 1440 + + models: Return only usage for these models. + + page: A cursor for use in pagination. Corresponding to the `next_page` field from the + previous response. + + project_ids: Return only usage for these projects. + + user_ids: Return only usage for these users. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/organization/usage/web_search_calls", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "start_time": start_time, + "api_key_ids": api_key_ids, + "bucket_width": bucket_width, + "context_levels": context_levels, + "end_time": end_time, + "group_by": group_by, + "limit": limit, + "models": models, + "page": page, + "project_ids": project_ids, + "user_ids": user_ids, + }, + usage_web_search_calls_params.UsageWebSearchCallsParams, + ), + security={"admin_api_key_auth": True}, + ), + cast_to=UsageWebSearchCallsResponse, + ) + class AsyncUsage(AsyncAPIResource): @cached_property @@ -1334,6 +1516,93 @@ async def embeddings( cast_to=UsageEmbeddingsResponse, ) + async def file_search_calls( + self, + *, + start_time: int, + api_key_ids: SequenceNotStr[str] | Omit = omit, + bucket_width: Literal["1m", "1h", "1d"] | Omit = omit, + end_time: int | Omit = omit, + group_by: List[Literal["project_id", "user_id", "api_key_id", "vector_store_id"]] | Omit = omit, + limit: int | Omit = omit, + page: str | Omit = omit, + project_ids: SequenceNotStr[str] | Omit = omit, + user_ids: SequenceNotStr[str] | Omit = omit, + vector_store_ids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UsageFileSearchCallsResponse: + """ + Get file search calls usage details for the organization. + + Args: + start_time: Start time (Unix seconds) of the query time range, inclusive. + + api_key_ids: Return only usage for these API keys. + + bucket_width: Width of each time bucket in response. Currently `1m`, `1h` and `1d` are + supported, default to `1d`. + + end_time: End time (Unix seconds) of the query time range, exclusive. + + group_by: Group the usage data by the specified fields. Support fields include + `project_id`, `user_id`, `api_key_id`, `vector_store_id` or any combination of + them. + + limit: Specifies the number of buckets to return. + + - `bucket_width=1d`: default: 7, max: 31 + - `bucket_width=1h`: default: 24, max: 168 + - `bucket_width=1m`: default: 60, max: 1440 + + page: A cursor for use in pagination. Corresponding to the `next_page` field from the + previous response. + + project_ids: Return only usage for these projects. + + user_ids: Return only usage for these users. + + vector_store_ids: Return only usage for these vector stores. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/organization/usage/file_search_calls", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "start_time": start_time, + "api_key_ids": api_key_ids, + "bucket_width": bucket_width, + "end_time": end_time, + "group_by": group_by, + "limit": limit, + "page": page, + "project_ids": project_ids, + "user_ids": user_ids, + "vector_store_ids": vector_store_ids, + }, + usage_file_search_calls_params.UsageFileSearchCallsParams, + ), + security={"admin_api_key_auth": True}, + ), + cast_to=UsageFileSearchCallsResponse, + ) + async def images( self, *, @@ -1591,6 +1860,97 @@ async def vector_stores( cast_to=UsageVectorStoresResponse, ) + async def web_search_calls( + self, + *, + start_time: int, + api_key_ids: SequenceNotStr[str] | Omit = omit, + bucket_width: Literal["1m", "1h", "1d"] | Omit = omit, + context_levels: List[Literal["low", "medium", "high"]] | Omit = omit, + end_time: int | Omit = omit, + group_by: List[Literal["project_id", "user_id", "api_key_id", "model", "context_level"]] | Omit = omit, + limit: int | Omit = omit, + models: SequenceNotStr[str] | Omit = omit, + page: str | Omit = omit, + project_ids: SequenceNotStr[str] | Omit = omit, + user_ids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UsageWebSearchCallsResponse: + """ + Get web search calls usage details for the organization. + + Args: + start_time: Start time (Unix seconds) of the query time range, inclusive. + + api_key_ids: Return only usage for these API keys. + + bucket_width: Width of each time bucket in response. Currently `1m`, `1h` and `1d` are + supported, default to `1d`. + + context_levels: Return only web search usage for these context levels. + + end_time: End time (Unix seconds) of the query time range, exclusive. + + group_by: Group the usage data by the specified fields. Support fields include + `project_id`, `user_id`, `api_key_id`, `model`, `context_level` or any + combination of them. + + limit: Specifies the number of buckets to return. + + - `bucket_width=1d`: default: 7, max: 31 + - `bucket_width=1h`: default: 24, max: 168 + - `bucket_width=1m`: default: 60, max: 1440 + + models: Return only usage for these models. + + page: A cursor for use in pagination. Corresponding to the `next_page` field from the + previous response. + + project_ids: Return only usage for these projects. + + user_ids: Return only usage for these users. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/organization/usage/web_search_calls", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "start_time": start_time, + "api_key_ids": api_key_ids, + "bucket_width": bucket_width, + "context_levels": context_levels, + "end_time": end_time, + "group_by": group_by, + "limit": limit, + "models": models, + "page": page, + "project_ids": project_ids, + "user_ids": user_ids, + }, + usage_web_search_calls_params.UsageWebSearchCallsParams, + ), + security={"admin_api_key_auth": True}, + ), + cast_to=UsageWebSearchCallsResponse, + ) + class UsageWithRawResponse: def __init__(self, usage: Usage) -> None: @@ -1614,6 +1974,9 @@ def __init__(self, usage: Usage) -> None: self.embeddings = _legacy_response.to_raw_response_wrapper( usage.embeddings, ) + self.file_search_calls = _legacy_response.to_raw_response_wrapper( + usage.file_search_calls, + ) self.images = _legacy_response.to_raw_response_wrapper( usage.images, ) @@ -1623,6 +1986,9 @@ def __init__(self, usage: Usage) -> None: self.vector_stores = _legacy_response.to_raw_response_wrapper( usage.vector_stores, ) + self.web_search_calls = _legacy_response.to_raw_response_wrapper( + usage.web_search_calls, + ) class AsyncUsageWithRawResponse: @@ -1647,6 +2013,9 @@ def __init__(self, usage: AsyncUsage) -> None: self.embeddings = _legacy_response.async_to_raw_response_wrapper( usage.embeddings, ) + self.file_search_calls = _legacy_response.async_to_raw_response_wrapper( + usage.file_search_calls, + ) self.images = _legacy_response.async_to_raw_response_wrapper( usage.images, ) @@ -1656,6 +2025,9 @@ def __init__(self, usage: AsyncUsage) -> None: self.vector_stores = _legacy_response.async_to_raw_response_wrapper( usage.vector_stores, ) + self.web_search_calls = _legacy_response.async_to_raw_response_wrapper( + usage.web_search_calls, + ) class UsageWithStreamingResponse: @@ -1680,6 +2052,9 @@ def __init__(self, usage: Usage) -> None: self.embeddings = to_streamed_response_wrapper( usage.embeddings, ) + self.file_search_calls = to_streamed_response_wrapper( + usage.file_search_calls, + ) self.images = to_streamed_response_wrapper( usage.images, ) @@ -1689,6 +2064,9 @@ def __init__(self, usage: Usage) -> None: self.vector_stores = to_streamed_response_wrapper( usage.vector_stores, ) + self.web_search_calls = to_streamed_response_wrapper( + usage.web_search_calls, + ) class AsyncUsageWithStreamingResponse: @@ -1713,6 +2091,9 @@ def __init__(self, usage: AsyncUsage) -> None: self.embeddings = async_to_streamed_response_wrapper( usage.embeddings, ) + self.file_search_calls = async_to_streamed_response_wrapper( + usage.file_search_calls, + ) self.images = async_to_streamed_response_wrapper( usage.images, ) @@ -1722,3 +2103,6 @@ def __init__(self, usage: AsyncUsage) -> None: self.vector_stores = async_to_streamed_response_wrapper( usage.vector_stores, ) + self.web_search_calls = async_to_streamed_response_wrapper( + usage.web_search_calls, + ) diff --git a/src/openai/types/admin/organization/__init__.py b/src/openai/types/admin/organization/__init__.py index dbb11795e5..ebb62b0eb8 100644 --- a/src/openai/types/admin/organization/__init__.py +++ b/src/openai/types/admin/organization/__init__.py @@ -56,7 +56,11 @@ from .certificate_activate_response import CertificateActivateResponse as CertificateActivateResponse from .certificate_deactivate_params import CertificateDeactivateParams as CertificateDeactivateParams from .usage_audio_speeches_response import UsageAudioSpeechesResponse as UsageAudioSpeechesResponse +from .usage_web_search_calls_params import UsageWebSearchCallsParams as UsageWebSearchCallsParams +from .usage_file_search_calls_params import UsageFileSearchCallsParams as UsageFileSearchCallsParams from .certificate_deactivate_response import CertificateDeactivateResponse as CertificateDeactivateResponse +from .usage_web_search_calls_response import UsageWebSearchCallsResponse as UsageWebSearchCallsResponse +from .usage_file_search_calls_response import UsageFileSearchCallsResponse as UsageFileSearchCallsResponse from .usage_audio_transcriptions_params import UsageAudioTranscriptionsParams as UsageAudioTranscriptionsParams from .usage_audio_transcriptions_response import UsageAudioTranscriptionsResponse as UsageAudioTranscriptionsResponse from .usage_code_interpreter_sessions_params import ( diff --git a/src/openai/types/admin/organization/projects/__init__.py b/src/openai/types/admin/organization/projects/__init__.py index ea627ce7d6..1b78bae7a8 100644 --- a/src/openai/types/admin/organization/projects/__init__.py +++ b/src/openai/types/admin/organization/projects/__init__.py @@ -22,13 +22,18 @@ from .certificate_list_params import CertificateListParams as CertificateListParams from .project_service_account import ProjectServiceAccount as ProjectServiceAccount from .certificate_list_response import CertificateListResponse as CertificateListResponse +from .project_model_permissions import ProjectModelPermissions as ProjectModelPermissions from .certificate_activate_params import CertificateActivateParams as CertificateActivateParams from .service_account_list_params import ServiceAccountListParams as ServiceAccountListParams from .certificate_activate_response import CertificateActivateResponse as CertificateActivateResponse from .certificate_deactivate_params import CertificateDeactivateParams as CertificateDeactivateParams from .service_account_create_params import ServiceAccountCreateParams as ServiceAccountCreateParams +from .model_permission_update_params import ModelPermissionUpdateParams as ModelPermissionUpdateParams from .certificate_deactivate_response import CertificateDeactivateResponse as CertificateDeactivateResponse +from .project_hosted_tool_permissions import ProjectHostedToolPermissions as ProjectHostedToolPermissions from .service_account_create_response import ServiceAccountCreateResponse as ServiceAccountCreateResponse from .service_account_delete_response import ServiceAccountDeleteResponse as ServiceAccountDeleteResponse +from .project_model_permissions_deleted import ProjectModelPermissionsDeleted as ProjectModelPermissionsDeleted from .rate_limit_list_rate_limits_params import RateLimitListRateLimitsParams as RateLimitListRateLimitsParams from .rate_limit_update_rate_limit_params import RateLimitUpdateRateLimitParams as RateLimitUpdateRateLimitParams +from .hosted_tool_permission_update_params import HostedToolPermissionUpdateParams as HostedToolPermissionUpdateParams diff --git a/src/openai/types/admin/organization/projects/hosted_tool_permission_update_params.py b/src/openai/types/admin/organization/projects/hosted_tool_permission_update_params.py new file mode 100644 index 0000000000..e14f03741f --- /dev/null +++ b/src/openai/types/admin/organization/projects/hosted_tool_permission_update_params.py @@ -0,0 +1,60 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Required, TypedDict + +__all__ = ["HostedToolPermissionUpdateParams", "CodeInterpreter", "FileSearch", "ImageGeneration", "Mcp", "WebSearch"] + + +class HostedToolPermissionUpdateParams(TypedDict, total=False): + code_interpreter: Optional[CodeInterpreter] + """The code interpreter permission update.""" + + file_search: Optional[FileSearch] + """The file search permission update.""" + + image_generation: Optional[ImageGeneration] + """The image generation permission update.""" + + mcp: Optional[Mcp] + """The MCP permission update.""" + + web_search: Optional[WebSearch] + """The web search permission update.""" + + +class CodeInterpreter(TypedDict, total=False): + """The code interpreter permission update.""" + + enabled: Required[bool] + """Whether to enable the hosted tool for the project.""" + + +class FileSearch(TypedDict, total=False): + """The file search permission update.""" + + enabled: Required[bool] + """Whether to enable the hosted tool for the project.""" + + +class ImageGeneration(TypedDict, total=False): + """The image generation permission update.""" + + enabled: Required[bool] + """Whether to enable the hosted tool for the project.""" + + +class Mcp(TypedDict, total=False): + """The MCP permission update.""" + + enabled: Required[bool] + """Whether to enable the hosted tool for the project.""" + + +class WebSearch(TypedDict, total=False): + """The web search permission update.""" + + enabled: Required[bool] + """Whether to enable the hosted tool for the project.""" diff --git a/src/openai/types/admin/organization/projects/model_permission_update_params.py b/src/openai/types/admin/organization/projects/model_permission_update_params.py new file mode 100644 index 0000000000..bf7cb1d56c --- /dev/null +++ b/src/openai/types/admin/organization/projects/model_permission_update_params.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +from ....._types import SequenceNotStr + +__all__ = ["ModelPermissionUpdateParams"] + + +class ModelPermissionUpdateParams(TypedDict, total=False): + mode: Required[Literal["allow_list", "deny_list"]] + """The model permissions mode to apply.""" + + model_ids: Required[SequenceNotStr[str]] + """The model IDs included in this permissions policy.""" diff --git a/src/openai/types/admin/organization/projects/project_hosted_tool_permissions.py b/src/openai/types/admin/organization/projects/project_hosted_tool_permissions.py new file mode 100644 index 0000000000..e89ed18af0 --- /dev/null +++ b/src/openai/types/admin/organization/projects/project_hosted_tool_permissions.py @@ -0,0 +1,59 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ....._models import BaseModel + +__all__ = ["ProjectHostedToolPermissions", "CodeInterpreter", "FileSearch", "ImageGeneration", "Mcp", "WebSearch"] + + +class CodeInterpreter(BaseModel): + """Permission state for a single hosted tool on a project.""" + + enabled: bool + """Whether the hosted tool is enabled for the project.""" + + +class FileSearch(BaseModel): + """Permission state for a single hosted tool on a project.""" + + enabled: bool + """Whether the hosted tool is enabled for the project.""" + + +class ImageGeneration(BaseModel): + """Permission state for a single hosted tool on a project.""" + + enabled: bool + """Whether the hosted tool is enabled for the project.""" + + +class Mcp(BaseModel): + """Permission state for a single hosted tool on a project.""" + + enabled: bool + """Whether the hosted tool is enabled for the project.""" + + +class WebSearch(BaseModel): + """Permission state for a single hosted tool on a project.""" + + enabled: bool + """Whether the hosted tool is enabled for the project.""" + + +class ProjectHostedToolPermissions(BaseModel): + """Represents hosted tool permissions for a project.""" + + code_interpreter: CodeInterpreter + """Permission state for a single hosted tool on a project.""" + + file_search: FileSearch + """Permission state for a single hosted tool on a project.""" + + image_generation: ImageGeneration + """Permission state for a single hosted tool on a project.""" + + mcp: Mcp + """Permission state for a single hosted tool on a project.""" + + web_search: WebSearch + """Permission state for a single hosted tool on a project.""" diff --git a/src/openai/types/admin/organization/projects/project_model_permissions.py b/src/openai/types/admin/organization/projects/project_model_permissions.py new file mode 100644 index 0000000000..597ae4e257 --- /dev/null +++ b/src/openai/types/admin/organization/projects/project_model_permissions.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from ....._models import BaseModel + +__all__ = ["ProjectModelPermissions"] + + +class ProjectModelPermissions(BaseModel): + """Represents the model allowlist or denylist policy for a project.""" + + mode: Literal["allow_list", "deny_list"] + """Whether the project uses an allowlist or a denylist.""" + + api_model_ids: List[str] = FieldInfo(alias="model_ids") + """The model IDs included in the model permissions policy.""" + + object: Literal["project.model_permissions"] + """The object type, which is always `project.model_permissions`.""" diff --git a/src/openai/types/admin/organization/projects/project_model_permissions_deleted.py b/src/openai/types/admin/organization/projects/project_model_permissions_deleted.py new file mode 100644 index 0000000000..cb3972dce8 --- /dev/null +++ b/src/openai/types/admin/organization/projects/project_model_permissions_deleted.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ....._models import BaseModel + +__all__ = ["ProjectModelPermissionsDeleted"] + + +class ProjectModelPermissionsDeleted(BaseModel): + """Confirmation payload returned after deleting project model permissions.""" + + deleted: bool + """Whether the project model permissions were deleted.""" + + object: Literal["project.model_permissions.deleted"] + """The object type, which is always `project.model_permissions.deleted`.""" diff --git a/src/openai/types/admin/organization/usage_file_search_calls_params.py b/src/openai/types/admin/organization/usage_file_search_calls_params.py new file mode 100644 index 0000000000..914d568c33 --- /dev/null +++ b/src/openai/types/admin/organization/usage_file_search_calls_params.py @@ -0,0 +1,57 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Literal, Required, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["UsageFileSearchCallsParams"] + + +class UsageFileSearchCallsParams(TypedDict, total=False): + start_time: Required[int] + """Start time (Unix seconds) of the query time range, inclusive.""" + + api_key_ids: SequenceNotStr[str] + """Return only usage for these API keys.""" + + bucket_width: Literal["1m", "1h", "1d"] + """Width of each time bucket in response. + + Currently `1m`, `1h` and `1d` are supported, default to `1d`. + """ + + end_time: int + """End time (Unix seconds) of the query time range, exclusive.""" + + group_by: List[Literal["project_id", "user_id", "api_key_id", "vector_store_id"]] + """Group the usage data by the specified fields. + + Support fields include `project_id`, `user_id`, `api_key_id`, `vector_store_id` + or any combination of them. + """ + + limit: int + """Specifies the number of buckets to return. + + - `bucket_width=1d`: default: 7, max: 31 + - `bucket_width=1h`: default: 24, max: 168 + - `bucket_width=1m`: default: 60, max: 1440 + """ + + page: str + """A cursor for use in pagination. + + Corresponding to the `next_page` field from the previous response. + """ + + project_ids: SequenceNotStr[str] + """Return only usage for these projects.""" + + user_ids: SequenceNotStr[str] + """Return only usage for these users.""" + + vector_store_ids: SequenceNotStr[str] + """Return only usage for these vector stores.""" diff --git a/src/openai/types/admin/organization/usage_file_search_calls_response.py b/src/openai/types/admin/organization/usage_file_search_calls_response.py new file mode 100644 index 0000000000..0e093b8346 --- /dev/null +++ b/src/openai/types/admin/organization/usage_file_search_calls_response.py @@ -0,0 +1,475 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ...._utils import PropertyInfo +from ...._models import BaseModel + +__all__ = [ + "UsageFileSearchCallsResponse", + "Data", + "DataResult", + "DataResultOrganizationUsageCompletionsResult", + "DataResultOrganizationUsageEmbeddingsResult", + "DataResultOrganizationUsageModerationsResult", + "DataResultOrganizationUsageImagesResult", + "DataResultOrganizationUsageAudioSpeechesResult", + "DataResultOrganizationUsageAudioTranscriptionsResult", + "DataResultOrganizationUsageVectorStoresResult", + "DataResultOrganizationUsageCodeInterpreterSessionsResult", + "DataResultOrganizationUsageFileSearchesResult", + "DataResultOrganizationUsageWebSearchesResult", + "DataResultOrganizationCostsResult", + "DataResultOrganizationCostsResultAmount", +] + + +class DataResultOrganizationUsageCompletionsResult(BaseModel): + """The aggregated completions usage details of the specific time bucket.""" + + input_tokens: int + """The aggregated number of text input tokens used, including cached tokens. + + For customers subscribe to scale tier, this includes scale tier tokens. + """ + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.completions.result"] + + output_tokens: int + """The aggregated number of text output tokens used. + + For customers subscribe to scale tier, this includes scale tier tokens. + """ + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + batch: Optional[bool] = None + """ + When `group_by=batch`, this field tells whether the grouped usage result is + batch or not. + """ + + input_audio_tokens: Optional[int] = None + """The aggregated number of audio input tokens used, including cached tokens.""" + + input_cached_tokens: Optional[int] = None + """ + The aggregated number of text input tokens that has been cached from previous + requests. For customers subscribe to scale tier, this includes scale tier + tokens. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + output_audio_tokens: Optional[int] = None + """The aggregated number of audio output tokens used.""" + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + service_tier: Optional[str] = None + """ + When `group_by=service_tier`, this field provides the service tier of the + grouped usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageEmbeddingsResult(BaseModel): + """The aggregated embeddings usage details of the specific time bucket.""" + + input_tokens: int + """The aggregated number of input tokens used.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.embeddings.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageModerationsResult(BaseModel): + """The aggregated moderations usage details of the specific time bucket.""" + + input_tokens: int + """The aggregated number of input tokens used.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.moderations.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageImagesResult(BaseModel): + """The aggregated images usage details of the specific time bucket.""" + + images: int + """The number of images processed.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.images.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + size: Optional[str] = None + """ + When `group_by=size`, this field provides the image size of the grouped usage + result. + """ + + source: Optional[str] = None + """ + When `group_by=source`, this field provides the source of the grouped usage + result, possible values are `image.generation`, `image.edit`, `image.variation`. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageAudioSpeechesResult(BaseModel): + """The aggregated audio speeches usage details of the specific time bucket.""" + + characters: int + """The number of characters processed.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.audio_speeches.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageAudioTranscriptionsResult(BaseModel): + """The aggregated audio transcriptions usage details of the specific time bucket.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.audio_transcriptions.result"] + + seconds: int + """The number of seconds processed.""" + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageVectorStoresResult(BaseModel): + """The aggregated vector stores usage details of the specific time bucket.""" + + object: Literal["organization.usage.vector_stores.result"] + + usage_bytes: int + """The vector stores usage in bytes.""" + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + +class DataResultOrganizationUsageCodeInterpreterSessionsResult(BaseModel): + """ + The aggregated code interpreter sessions usage details of the specific time bucket. + """ + + num_sessions: int + """The number of code interpreter sessions.""" + + object: Literal["organization.usage.code_interpreter_sessions.result"] + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + +class DataResultOrganizationUsageFileSearchesResult(BaseModel): + """The aggregated file search calls usage details of the specific time bucket.""" + + num_requests: int + """The count of file search calls.""" + + object: Literal["organization.usage.file_searches.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + vector_store_id: Optional[str] = None + """ + When `group_by=vector_store_id`, this field provides the vector store ID of the + grouped usage result. + """ + + +class DataResultOrganizationUsageWebSearchesResult(BaseModel): + """The aggregated web search calls usage details of the specific time bucket.""" + + num_model_requests: int + """The count of model requests.""" + + num_requests: int + """The count of web search calls.""" + + object: Literal["organization.usage.web_searches.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + context_level: Optional[str] = None + """ + When `group_by=context_level`, this field provides the search context size of + the grouped usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationCostsResultAmount(BaseModel): + """The monetary value in its associated currency.""" + + currency: Optional[str] = None + """Lowercase ISO-4217 currency e.g. "usd" """ + + value: Optional[float] = None + """The numeric value of the cost.""" + + +class DataResultOrganizationCostsResult(BaseModel): + """The aggregated costs details of the specific time bucket.""" + + object: Literal["organization.costs.result"] + + amount: Optional[DataResultOrganizationCostsResultAmount] = None + """The monetary value in its associated currency.""" + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API Key ID of the grouped + costs result. + """ + + line_item: Optional[str] = None + """ + When `group_by=line_item`, this field provides the line item of the grouped + costs result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + costs result. + """ + + quantity: Optional[float] = None + """ + When `group_by=line_item`, this field provides the quantity of the grouped costs + result. + """ + + +DataResult: TypeAlias = Annotated[ + Union[ + DataResultOrganizationUsageCompletionsResult, + DataResultOrganizationUsageEmbeddingsResult, + DataResultOrganizationUsageModerationsResult, + DataResultOrganizationUsageImagesResult, + DataResultOrganizationUsageAudioSpeechesResult, + DataResultOrganizationUsageAudioTranscriptionsResult, + DataResultOrganizationUsageVectorStoresResult, + DataResultOrganizationUsageCodeInterpreterSessionsResult, + DataResultOrganizationUsageFileSearchesResult, + DataResultOrganizationUsageWebSearchesResult, + DataResultOrganizationCostsResult, + ], + PropertyInfo(discriminator="object"), +] + + +class Data(BaseModel): + end_time: int + + object: Literal["bucket"] + + results: List[DataResult] + + start_time: int + + +class UsageFileSearchCallsResponse(BaseModel): + data: List[Data] + + has_more: bool + + next_page: Optional[str] = None + + object: Literal["page"] diff --git a/src/openai/types/admin/organization/usage_web_search_calls_params.py b/src/openai/types/admin/organization/usage_web_search_calls_params.py new file mode 100644 index 0000000000..544060ade4 --- /dev/null +++ b/src/openai/types/admin/organization/usage_web_search_calls_params.py @@ -0,0 +1,60 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Literal, Required, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["UsageWebSearchCallsParams"] + + +class UsageWebSearchCallsParams(TypedDict, total=False): + start_time: Required[int] + """Start time (Unix seconds) of the query time range, inclusive.""" + + api_key_ids: SequenceNotStr[str] + """Return only usage for these API keys.""" + + bucket_width: Literal["1m", "1h", "1d"] + """Width of each time bucket in response. + + Currently `1m`, `1h` and `1d` are supported, default to `1d`. + """ + + context_levels: List[Literal["low", "medium", "high"]] + """Return only web search usage for these context levels.""" + + end_time: int + """End time (Unix seconds) of the query time range, exclusive.""" + + group_by: List[Literal["project_id", "user_id", "api_key_id", "model", "context_level"]] + """Group the usage data by the specified fields. + + Support fields include `project_id`, `user_id`, `api_key_id`, `model`, + `context_level` or any combination of them. + """ + + limit: int + """Specifies the number of buckets to return. + + - `bucket_width=1d`: default: 7, max: 31 + - `bucket_width=1h`: default: 24, max: 168 + - `bucket_width=1m`: default: 60, max: 1440 + """ + + models: SequenceNotStr[str] + """Return only usage for these models.""" + + page: str + """A cursor for use in pagination. + + Corresponding to the `next_page` field from the previous response. + """ + + project_ids: SequenceNotStr[str] + """Return only usage for these projects.""" + + user_ids: SequenceNotStr[str] + """Return only usage for these users.""" diff --git a/src/openai/types/admin/organization/usage_web_search_calls_response.py b/src/openai/types/admin/organization/usage_web_search_calls_response.py new file mode 100644 index 0000000000..b6fcd4ac6c --- /dev/null +++ b/src/openai/types/admin/organization/usage_web_search_calls_response.py @@ -0,0 +1,475 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ...._utils import PropertyInfo +from ...._models import BaseModel + +__all__ = [ + "UsageWebSearchCallsResponse", + "Data", + "DataResult", + "DataResultOrganizationUsageCompletionsResult", + "DataResultOrganizationUsageEmbeddingsResult", + "DataResultOrganizationUsageModerationsResult", + "DataResultOrganizationUsageImagesResult", + "DataResultOrganizationUsageAudioSpeechesResult", + "DataResultOrganizationUsageAudioTranscriptionsResult", + "DataResultOrganizationUsageVectorStoresResult", + "DataResultOrganizationUsageCodeInterpreterSessionsResult", + "DataResultOrganizationUsageFileSearchesResult", + "DataResultOrganizationUsageWebSearchesResult", + "DataResultOrganizationCostsResult", + "DataResultOrganizationCostsResultAmount", +] + + +class DataResultOrganizationUsageCompletionsResult(BaseModel): + """The aggregated completions usage details of the specific time bucket.""" + + input_tokens: int + """The aggregated number of text input tokens used, including cached tokens. + + For customers subscribe to scale tier, this includes scale tier tokens. + """ + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.completions.result"] + + output_tokens: int + """The aggregated number of text output tokens used. + + For customers subscribe to scale tier, this includes scale tier tokens. + """ + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + batch: Optional[bool] = None + """ + When `group_by=batch`, this field tells whether the grouped usage result is + batch or not. + """ + + input_audio_tokens: Optional[int] = None + """The aggregated number of audio input tokens used, including cached tokens.""" + + input_cached_tokens: Optional[int] = None + """ + The aggregated number of text input tokens that has been cached from previous + requests. For customers subscribe to scale tier, this includes scale tier + tokens. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + output_audio_tokens: Optional[int] = None + """The aggregated number of audio output tokens used.""" + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + service_tier: Optional[str] = None + """ + When `group_by=service_tier`, this field provides the service tier of the + grouped usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageEmbeddingsResult(BaseModel): + """The aggregated embeddings usage details of the specific time bucket.""" + + input_tokens: int + """The aggregated number of input tokens used.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.embeddings.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageModerationsResult(BaseModel): + """The aggregated moderations usage details of the specific time bucket.""" + + input_tokens: int + """The aggregated number of input tokens used.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.moderations.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageImagesResult(BaseModel): + """The aggregated images usage details of the specific time bucket.""" + + images: int + """The number of images processed.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.images.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + size: Optional[str] = None + """ + When `group_by=size`, this field provides the image size of the grouped usage + result. + """ + + source: Optional[str] = None + """ + When `group_by=source`, this field provides the source of the grouped usage + result, possible values are `image.generation`, `image.edit`, `image.variation`. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageAudioSpeechesResult(BaseModel): + """The aggregated audio speeches usage details of the specific time bucket.""" + + characters: int + """The number of characters processed.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.audio_speeches.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageAudioTranscriptionsResult(BaseModel): + """The aggregated audio transcriptions usage details of the specific time bucket.""" + + num_model_requests: int + """The count of requests made to the model.""" + + object: Literal["organization.usage.audio_transcriptions.result"] + + seconds: int + """The number of seconds processed.""" + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationUsageVectorStoresResult(BaseModel): + """The aggregated vector stores usage details of the specific time bucket.""" + + object: Literal["organization.usage.vector_stores.result"] + + usage_bytes: int + """The vector stores usage in bytes.""" + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + +class DataResultOrganizationUsageCodeInterpreterSessionsResult(BaseModel): + """ + The aggregated code interpreter sessions usage details of the specific time bucket. + """ + + num_sessions: int + """The number of code interpreter sessions.""" + + object: Literal["organization.usage.code_interpreter_sessions.result"] + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + +class DataResultOrganizationUsageFileSearchesResult(BaseModel): + """The aggregated file search calls usage details of the specific time bucket.""" + + num_requests: int + """The count of file search calls.""" + + object: Literal["organization.usage.file_searches.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + vector_store_id: Optional[str] = None + """ + When `group_by=vector_store_id`, this field provides the vector store ID of the + grouped usage result. + """ + + +class DataResultOrganizationUsageWebSearchesResult(BaseModel): + """The aggregated web search calls usage details of the specific time bucket.""" + + num_model_requests: int + """The count of model requests.""" + + num_requests: int + """The count of web search calls.""" + + object: Literal["organization.usage.web_searches.result"] + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API key ID of the grouped + usage result. + """ + + context_level: Optional[str] = None + """ + When `group_by=context_level`, this field provides the search context size of + the grouped usage result. + """ + + model: Optional[str] = None + """ + When `group_by=model`, this field provides the model name of the grouped usage + result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + usage result. + """ + + user_id: Optional[str] = None + """ + When `group_by=user_id`, this field provides the user ID of the grouped usage + result. + """ + + +class DataResultOrganizationCostsResultAmount(BaseModel): + """The monetary value in its associated currency.""" + + currency: Optional[str] = None + """Lowercase ISO-4217 currency e.g. "usd" """ + + value: Optional[float] = None + """The numeric value of the cost.""" + + +class DataResultOrganizationCostsResult(BaseModel): + """The aggregated costs details of the specific time bucket.""" + + object: Literal["organization.costs.result"] + + amount: Optional[DataResultOrganizationCostsResultAmount] = None + """The monetary value in its associated currency.""" + + api_key_id: Optional[str] = None + """ + When `group_by=api_key_id`, this field provides the API Key ID of the grouped + costs result. + """ + + line_item: Optional[str] = None + """ + When `group_by=line_item`, this field provides the line item of the grouped + costs result. + """ + + project_id: Optional[str] = None + """ + When `group_by=project_id`, this field provides the project ID of the grouped + costs result. + """ + + quantity: Optional[float] = None + """ + When `group_by=line_item`, this field provides the quantity of the grouped costs + result. + """ + + +DataResult: TypeAlias = Annotated[ + Union[ + DataResultOrganizationUsageCompletionsResult, + DataResultOrganizationUsageEmbeddingsResult, + DataResultOrganizationUsageModerationsResult, + DataResultOrganizationUsageImagesResult, + DataResultOrganizationUsageAudioSpeechesResult, + DataResultOrganizationUsageAudioTranscriptionsResult, + DataResultOrganizationUsageVectorStoresResult, + DataResultOrganizationUsageCodeInterpreterSessionsResult, + DataResultOrganizationUsageFileSearchesResult, + DataResultOrganizationUsageWebSearchesResult, + DataResultOrganizationCostsResult, + ], + PropertyInfo(discriminator="object"), +] + + +class Data(BaseModel): + end_time: int + + object: Literal["bucket"] + + results: List[DataResult] + + start_time: int + + +class UsageWebSearchCallsResponse(BaseModel): + data: List[Data] + + has_more: bool + + next_page: Optional[str] = None + + object: Literal["page"] diff --git a/tests/api_resources/admin/organization/projects/test_hosted_tool_permissions.py b/tests/api_resources/admin/organization/projects/test_hosted_tool_permissions.py new file mode 100644 index 0000000000..d7d2486874 --- /dev/null +++ b/tests/api_resources/admin/organization/projects/test_hosted_tool_permissions.py @@ -0,0 +1,200 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.types.admin.organization.projects import ProjectHostedToolPermissions + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestHostedToolPermissions: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + hosted_tool_permission = client.admin.organization.projects.hosted_tool_permissions.retrieve( + "project_id", + ) + assert_matches_type(ProjectHostedToolPermissions, hosted_tool_permission, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.admin.organization.projects.hosted_tool_permissions.with_raw_response.retrieve( + "project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + hosted_tool_permission = response.parse() + assert_matches_type(ProjectHostedToolPermissions, hosted_tool_permission, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.admin.organization.projects.hosted_tool_permissions.with_streaming_response.retrieve( + "project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + hosted_tool_permission = response.parse() + assert_matches_type(ProjectHostedToolPermissions, hosted_tool_permission, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.hosted_tool_permissions.with_raw_response.retrieve( + "", + ) + + @parametrize + def test_method_update(self, client: OpenAI) -> None: + hosted_tool_permission = client.admin.organization.projects.hosted_tool_permissions.update( + project_id="project_id", + ) + assert_matches_type(ProjectHostedToolPermissions, hosted_tool_permission, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: OpenAI) -> None: + hosted_tool_permission = client.admin.organization.projects.hosted_tool_permissions.update( + project_id="project_id", + code_interpreter={"enabled": True}, + file_search={"enabled": True}, + image_generation={"enabled": True}, + mcp={"enabled": True}, + web_search={"enabled": True}, + ) + assert_matches_type(ProjectHostedToolPermissions, hosted_tool_permission, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: OpenAI) -> None: + response = client.admin.organization.projects.hosted_tool_permissions.with_raw_response.update( + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + hosted_tool_permission = response.parse() + assert_matches_type(ProjectHostedToolPermissions, hosted_tool_permission, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: OpenAI) -> None: + with client.admin.organization.projects.hosted_tool_permissions.with_streaming_response.update( + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + hosted_tool_permission = response.parse() + assert_matches_type(ProjectHostedToolPermissions, hosted_tool_permission, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.hosted_tool_permissions.with_raw_response.update( + project_id="", + ) + + +class TestAsyncHostedToolPermissions: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + hosted_tool_permission = await async_client.admin.organization.projects.hosted_tool_permissions.retrieve( + "project_id", + ) + assert_matches_type(ProjectHostedToolPermissions, hosted_tool_permission, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.hosted_tool_permissions.with_raw_response.retrieve( + "project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + hosted_tool_permission = response.parse() + assert_matches_type(ProjectHostedToolPermissions, hosted_tool_permission, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.hosted_tool_permissions.with_streaming_response.retrieve( + "project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + hosted_tool_permission = await response.parse() + assert_matches_type(ProjectHostedToolPermissions, hosted_tool_permission, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.hosted_tool_permissions.with_raw_response.retrieve( + "", + ) + + @parametrize + async def test_method_update(self, async_client: AsyncOpenAI) -> None: + hosted_tool_permission = await async_client.admin.organization.projects.hosted_tool_permissions.update( + project_id="project_id", + ) + assert_matches_type(ProjectHostedToolPermissions, hosted_tool_permission, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncOpenAI) -> None: + hosted_tool_permission = await async_client.admin.organization.projects.hosted_tool_permissions.update( + project_id="project_id", + code_interpreter={"enabled": True}, + file_search={"enabled": True}, + image_generation={"enabled": True}, + mcp={"enabled": True}, + web_search={"enabled": True}, + ) + assert_matches_type(ProjectHostedToolPermissions, hosted_tool_permission, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.hosted_tool_permissions.with_raw_response.update( + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + hosted_tool_permission = response.parse() + assert_matches_type(ProjectHostedToolPermissions, hosted_tool_permission, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.hosted_tool_permissions.with_streaming_response.update( + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + hosted_tool_permission = await response.parse() + assert_matches_type(ProjectHostedToolPermissions, hosted_tool_permission, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.hosted_tool_permissions.with_raw_response.update( + project_id="", + ) diff --git a/tests/api_resources/admin/organization/projects/test_model_permissions.py b/tests/api_resources/admin/organization/projects/test_model_permissions.py new file mode 100644 index 0000000000..1749a70fa5 --- /dev/null +++ b/tests/api_resources/admin/organization/projects/test_model_permissions.py @@ -0,0 +1,271 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.types.admin.organization.projects import ( + ProjectModelPermissions, + ProjectModelPermissionsDeleted, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestModelPermissions: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + model_permission = client.admin.organization.projects.model_permissions.retrieve( + "project_id", + ) + assert_matches_type(ProjectModelPermissions, model_permission, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.admin.organization.projects.model_permissions.with_raw_response.retrieve( + "project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + model_permission = response.parse() + assert_matches_type(ProjectModelPermissions, model_permission, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.admin.organization.projects.model_permissions.with_streaming_response.retrieve( + "project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + model_permission = response.parse() + assert_matches_type(ProjectModelPermissions, model_permission, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.model_permissions.with_raw_response.retrieve( + "", + ) + + @parametrize + def test_method_update(self, client: OpenAI) -> None: + model_permission = client.admin.organization.projects.model_permissions.update( + project_id="project_id", + mode="allow_list", + model_ids=["string"], + ) + assert_matches_type(ProjectModelPermissions, model_permission, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: OpenAI) -> None: + response = client.admin.organization.projects.model_permissions.with_raw_response.update( + project_id="project_id", + mode="allow_list", + model_ids=["string"], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + model_permission = response.parse() + assert_matches_type(ProjectModelPermissions, model_permission, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: OpenAI) -> None: + with client.admin.organization.projects.model_permissions.with_streaming_response.update( + project_id="project_id", + mode="allow_list", + model_ids=["string"], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + model_permission = response.parse() + assert_matches_type(ProjectModelPermissions, model_permission, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.model_permissions.with_raw_response.update( + project_id="", + mode="allow_list", + model_ids=["string"], + ) + + @parametrize + def test_method_delete(self, client: OpenAI) -> None: + model_permission = client.admin.organization.projects.model_permissions.delete( + "project_id", + ) + assert_matches_type(ProjectModelPermissionsDeleted, model_permission, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: OpenAI) -> None: + response = client.admin.organization.projects.model_permissions.with_raw_response.delete( + "project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + model_permission = response.parse() + assert_matches_type(ProjectModelPermissionsDeleted, model_permission, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: OpenAI) -> None: + with client.admin.organization.projects.model_permissions.with_streaming_response.delete( + "project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + model_permission = response.parse() + assert_matches_type(ProjectModelPermissionsDeleted, model_permission, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.model_permissions.with_raw_response.delete( + "", + ) + + +class TestAsyncModelPermissions: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + model_permission = await async_client.admin.organization.projects.model_permissions.retrieve( + "project_id", + ) + assert_matches_type(ProjectModelPermissions, model_permission, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.model_permissions.with_raw_response.retrieve( + "project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + model_permission = response.parse() + assert_matches_type(ProjectModelPermissions, model_permission, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.model_permissions.with_streaming_response.retrieve( + "project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + model_permission = await response.parse() + assert_matches_type(ProjectModelPermissions, model_permission, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.model_permissions.with_raw_response.retrieve( + "", + ) + + @parametrize + async def test_method_update(self, async_client: AsyncOpenAI) -> None: + model_permission = await async_client.admin.organization.projects.model_permissions.update( + project_id="project_id", + mode="allow_list", + model_ids=["string"], + ) + assert_matches_type(ProjectModelPermissions, model_permission, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.model_permissions.with_raw_response.update( + project_id="project_id", + mode="allow_list", + model_ids=["string"], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + model_permission = response.parse() + assert_matches_type(ProjectModelPermissions, model_permission, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.model_permissions.with_streaming_response.update( + project_id="project_id", + mode="allow_list", + model_ids=["string"], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + model_permission = await response.parse() + assert_matches_type(ProjectModelPermissions, model_permission, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.model_permissions.with_raw_response.update( + project_id="", + mode="allow_list", + model_ids=["string"], + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncOpenAI) -> None: + model_permission = await async_client.admin.organization.projects.model_permissions.delete( + "project_id", + ) + assert_matches_type(ProjectModelPermissionsDeleted, model_permission, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.model_permissions.with_raw_response.delete( + "project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + model_permission = response.parse() + assert_matches_type(ProjectModelPermissionsDeleted, model_permission, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.model_permissions.with_streaming_response.delete( + "project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + model_permission = await response.parse() + assert_matches_type(ProjectModelPermissionsDeleted, model_permission, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.model_permissions.with_raw_response.delete( + "", + ) diff --git a/tests/api_resources/admin/organization/test_usage.py b/tests/api_resources/admin/organization/test_usage.py index f9c4a8e2c5..b7aef88dcb 100644 --- a/tests/api_resources/admin/organization/test_usage.py +++ b/tests/api_resources/admin/organization/test_usage.py @@ -17,6 +17,8 @@ UsageModerationsResponse, UsageVectorStoresResponse, UsageAudioSpeechesResponse, + UsageWebSearchCallsResponse, + UsageFileSearchCallsResponse, UsageAudioTranscriptionsResponse, UsageCodeInterpreterSessionsResponse, ) @@ -305,6 +307,53 @@ def test_streaming_response_embeddings(self, client: OpenAI) -> None: assert cast(Any, response.is_closed) is True + @parametrize + def test_method_file_search_calls(self, client: OpenAI) -> None: + usage = client.admin.organization.usage.file_search_calls( + start_time=0, + ) + assert_matches_type(UsageFileSearchCallsResponse, usage, path=["response"]) + + @parametrize + def test_method_file_search_calls_with_all_params(self, client: OpenAI) -> None: + usage = client.admin.organization.usage.file_search_calls( + start_time=0, + api_key_ids=["string"], + bucket_width="1m", + end_time=0, + group_by=["project_id"], + limit=0, + page="page", + project_ids=["string"], + user_ids=["string"], + vector_store_ids=["string"], + ) + assert_matches_type(UsageFileSearchCallsResponse, usage, path=["response"]) + + @parametrize + def test_raw_response_file_search_calls(self, client: OpenAI) -> None: + response = client.admin.organization.usage.with_raw_response.file_search_calls( + start_time=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + usage = response.parse() + assert_matches_type(UsageFileSearchCallsResponse, usage, path=["response"]) + + @parametrize + def test_streaming_response_file_search_calls(self, client: OpenAI) -> None: + with client.admin.organization.usage.with_streaming_response.file_search_calls( + start_time=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + usage = response.parse() + assert_matches_type(UsageFileSearchCallsResponse, usage, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize def test_method_images(self, client: OpenAI) -> None: usage = client.admin.organization.usage.images( @@ -445,6 +494,54 @@ def test_streaming_response_vector_stores(self, client: OpenAI) -> None: assert cast(Any, response.is_closed) is True + @parametrize + def test_method_web_search_calls(self, client: OpenAI) -> None: + usage = client.admin.organization.usage.web_search_calls( + start_time=0, + ) + assert_matches_type(UsageWebSearchCallsResponse, usage, path=["response"]) + + @parametrize + def test_method_web_search_calls_with_all_params(self, client: OpenAI) -> None: + usage = client.admin.organization.usage.web_search_calls( + start_time=0, + api_key_ids=["string"], + bucket_width="1m", + context_levels=["low"], + end_time=0, + group_by=["project_id"], + limit=0, + models=["string"], + page="page", + project_ids=["string"], + user_ids=["string"], + ) + assert_matches_type(UsageWebSearchCallsResponse, usage, path=["response"]) + + @parametrize + def test_raw_response_web_search_calls(self, client: OpenAI) -> None: + response = client.admin.organization.usage.with_raw_response.web_search_calls( + start_time=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + usage = response.parse() + assert_matches_type(UsageWebSearchCallsResponse, usage, path=["response"]) + + @parametrize + def test_streaming_response_web_search_calls(self, client: OpenAI) -> None: + with client.admin.organization.usage.with_streaming_response.web_search_calls( + start_time=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + usage = response.parse() + assert_matches_type(UsageWebSearchCallsResponse, usage, path=["response"]) + + assert cast(Any, response.is_closed) is True + class TestAsyncUsage: parametrize = pytest.mark.parametrize( @@ -729,6 +826,53 @@ async def test_streaming_response_embeddings(self, async_client: AsyncOpenAI) -> assert cast(Any, response.is_closed) is True + @parametrize + async def test_method_file_search_calls(self, async_client: AsyncOpenAI) -> None: + usage = await async_client.admin.organization.usage.file_search_calls( + start_time=0, + ) + assert_matches_type(UsageFileSearchCallsResponse, usage, path=["response"]) + + @parametrize + async def test_method_file_search_calls_with_all_params(self, async_client: AsyncOpenAI) -> None: + usage = await async_client.admin.organization.usage.file_search_calls( + start_time=0, + api_key_ids=["string"], + bucket_width="1m", + end_time=0, + group_by=["project_id"], + limit=0, + page="page", + project_ids=["string"], + user_ids=["string"], + vector_store_ids=["string"], + ) + assert_matches_type(UsageFileSearchCallsResponse, usage, path=["response"]) + + @parametrize + async def test_raw_response_file_search_calls(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.usage.with_raw_response.file_search_calls( + start_time=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + usage = response.parse() + assert_matches_type(UsageFileSearchCallsResponse, usage, path=["response"]) + + @parametrize + async def test_streaming_response_file_search_calls(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.usage.with_streaming_response.file_search_calls( + start_time=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + usage = await response.parse() + assert_matches_type(UsageFileSearchCallsResponse, usage, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize async def test_method_images(self, async_client: AsyncOpenAI) -> None: usage = await async_client.admin.organization.usage.images( @@ -868,3 +1012,51 @@ async def test_streaming_response_vector_stores(self, async_client: AsyncOpenAI) assert_matches_type(UsageVectorStoresResponse, usage, path=["response"]) assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_web_search_calls(self, async_client: AsyncOpenAI) -> None: + usage = await async_client.admin.organization.usage.web_search_calls( + start_time=0, + ) + assert_matches_type(UsageWebSearchCallsResponse, usage, path=["response"]) + + @parametrize + async def test_method_web_search_calls_with_all_params(self, async_client: AsyncOpenAI) -> None: + usage = await async_client.admin.organization.usage.web_search_calls( + start_time=0, + api_key_ids=["string"], + bucket_width="1m", + context_levels=["low"], + end_time=0, + group_by=["project_id"], + limit=0, + models=["string"], + page="page", + project_ids=["string"], + user_ids=["string"], + ) + assert_matches_type(UsageWebSearchCallsResponse, usage, path=["response"]) + + @parametrize + async def test_raw_response_web_search_calls(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.usage.with_raw_response.web_search_calls( + start_time=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + usage = response.parse() + assert_matches_type(UsageWebSearchCallsResponse, usage, path=["response"]) + + @parametrize + async def test_streaming_response_web_search_calls(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.usage.with_streaming_response.web_search_calls( + start_time=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + usage = await response.parse() + assert_matches_type(UsageWebSearchCallsResponse, usage, path=["response"]) + + assert cast(Any, response.is_closed) is True From bab18af787cd5d962aedeb4b5b86df4f6cf28003 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 19 May 2026 19:53:09 +0000 Subject: [PATCH 751/769] chore(api): docs updates --- .stats.yml | 6 +++--- src/openai/types/responses/response_function_web_search.py | 2 +- .../types/responses/response_function_web_search_param.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.stats.yml b/.stats.yml index 60770c0e7a..fb3f316cec 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 240 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-d7d5adb20c516e7aca6e35ed9f58aba0bc14dd5aa0096fd980061c4a5ab406e3.yml -openapi_spec_hash: 72ee7d4fe582e75d16e67b6c97881fed -config_hash: af72288617facaeed4d014024a9c946d +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-66f110677cd924205b0a4e2a1f567c8b56349ee9658bd0ce86561a413a2aabfe.yml +openapi_spec_hash: ab8f320a7a6b2d30d5f1665b8a8bf84e +config_hash: 425042cc0e99cf31866f6c98fef2be27 diff --git a/src/openai/types/responses/response_function_web_search.py b/src/openai/types/responses/response_function_web_search.py index de6001e146..d3d4afbee3 100644 --- a/src/openai/types/responses/response_function_web_search.py +++ b/src/openai/types/responses/response_function_web_search.py @@ -46,7 +46,7 @@ class ActionOpenPage(BaseModel): """Action type "open_page" - Opens a specific URL from search results.""" type: Literal["open_page"] - """The action type.""" + """The action type. Always `open_page`.""" url: Optional[str] = None """The URL opened by the model.""" diff --git a/src/openai/types/responses/response_function_web_search_param.py b/src/openai/types/responses/response_function_web_search_param.py index 15e313b0d3..e0d50757a3 100644 --- a/src/openai/types/responses/response_function_web_search_param.py +++ b/src/openai/types/responses/response_function_web_search_param.py @@ -47,7 +47,7 @@ class ActionOpenPage(TypedDict, total=False): """Action type "open_page" - Opens a specific URL from search results.""" type: Required[Literal["open_page"]] - """The action type.""" + """The action type. Always `open_page`.""" url: Optional[str] """The URL opened by the model.""" From 74978f055a7adf004dec718e80bb46241e54d9ca Mon Sep 17 00:00:00 2001 From: Alex Chang Date: Tue, 19 May 2026 16:33:19 -0400 Subject: [PATCH 752/769] chore: trigger release automation --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 90f1c2cbd9..13b508e81f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # OpenAI Python API library + + [![PyPI version](https://img.shields.io/pypi/v/openai.svg?label=pypi%20(stable))](https://pypi.org/project/openai/) From 48888380cdfc01e4f22f9ed7fbd5250231472e0d Mon Sep 17 00:00:00 2001 From: Alex Chang Date: Tue, 19 May 2026 16:41:41 -0400 Subject: [PATCH 753/769] chore: remove release automation trigger --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 13b508e81f..90f1c2cbd9 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@ # OpenAI Python API library - - [![PyPI version](https://img.shields.io/pypi/v/openai.svg?label=pypi%20(stable))](https://pypi.org/project/openai/) From d4a322816ad637330e40fdcdee9ca48bc92a2a4f Mon Sep 17 00:00:00 2001 From: Alex Chang Date: Tue, 19 May 2026 16:50:17 -0400 Subject: [PATCH 754/769] chore: check release PR custom code sync --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 90f1c2cbd9..8a956145c2 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # OpenAI Python API library + + [![PyPI version](https://img.shields.io/pypi/v/openai.svg?label=pypi%20(stable))](https://pypi.org/project/openai/) From d881c67866083ae187e14664e289e68a3ba04686 Mon Sep 17 00:00:00 2001 From: Alex Chang Date: Tue, 19 May 2026 16:55:01 -0400 Subject: [PATCH 755/769] Revert "chore: check release PR custom code sync" This reverts commit 2638779a5b8fffaa8fdb6eebc1d734f15d2491f8. --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 8a956145c2..90f1c2cbd9 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@ # OpenAI Python API library - - [![PyPI version](https://img.shields.io/pypi/v/openai.svg?label=pypi%20(stable))](https://pypi.org/project/openai/) From b85b647b5312debb951814dfb9ed13f906d6bf43 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 21 May 2026 07:31:42 +0000 Subject: [PATCH 756/769] feat(api): api update --- .stats.yml | 8 +- api.md | 71 +++ .../resources/admin/organization/__init__.py | 28 + .../admin/organization/data_retention.py | 245 ++++++++ .../admin/organization/groups/groups.py | 86 +++ .../admin/organization/groups/roles.py | 93 +++ .../admin/organization/groups/users.py | 93 +++ .../admin/organization/organization.py | 64 ++ .../admin/organization/projects/__init__.py | 28 + .../organization/projects/data_retention.py | 283 +++++++++ .../organization/projects/groups/groups.py | 108 +++- .../organization/projects/groups/roles.py | 109 ++++ .../admin/organization/projects/projects.py | 64 ++ .../admin/organization/projects/roles.py | 92 +++ .../organization/projects/service_accounts.py | 134 +++- .../organization/projects/spend_alerts.py | 589 ++++++++++++++++++ .../organization/projects/users/roles.py | 109 ++++ .../resources/admin/organization/roles.py | 86 +++ .../admin/organization/spend_alerts.py | 553 ++++++++++++++++ .../admin/organization/users/roles.py | 93 +++ .../types/admin/organization/__init__.py | 7 + .../data_retention_update_params.py | 19 + src/openai/types/admin/organization/group.py | 4 +- .../admin/organization/groups/__init__.py | 2 + .../organization/groups/role_list_response.py | 11 +- .../groups/role_retrieve_response.py | 55 ++ .../groups/user_retrieve_response.py | 30 + .../organization_data_retention.py | 22 + .../organization/organization_spend_alert.py | 43 ++ .../organization_spend_alert_deleted.py | 20 + .../admin/organization/projects/__init__.py | 9 + .../projects/data_retention_update_params.py | 21 + .../projects/group_retrieve_params.py | 14 + .../organization/projects/groups/__init__.py | 1 + .../projects/groups/role_list_response.py | 11 +- .../projects/groups/role_retrieve_response.py | 55 ++ .../projects/project_data_retention.py | 24 + .../organization/projects/project_group.py | 2 +- .../projects/project_spend_alert.py | 43 ++ .../projects/project_spend_alert_deleted.py | 20 + .../projects/service_account_update_params.py | 17 + .../projects/spend_alert_create_params.py | 37 ++ .../projects/spend_alert_list_params.py | 29 + .../projects/spend_alert_update_params.py | 39 ++ .../organization/projects/users/__init__.py | 1 + .../projects/users/role_list_response.py | 11 +- .../projects/users/role_retrieve_response.py | 55 ++ .../organization/spend_alert_create_params.py | 37 ++ .../organization/spend_alert_list_params.py | 29 + .../organization/spend_alert_update_params.py | 37 ++ .../admin/organization/users/__init__.py | 1 + .../organization/users/role_list_response.py | 11 +- .../users/role_retrieve_response.py | 55 ++ .../responses/response_function_web_search.py | 2 +- .../response_function_web_search_param.py | 2 +- .../admin/organization/groups/test_roles.py | 97 +++ .../admin/organization/groups/test_users.py | 97 +++ .../projects/groups/test_roles.py | 121 ++++ .../projects/test_data_retention.py | 184 ++++++ .../organization/projects/test_groups.py | 114 ++++ .../admin/organization/projects/test_roles.py | 96 +++ .../projects/test_service_accounts.py | 116 ++++ .../projects/test_spend_alerts.py | 582 +++++++++++++++++ .../organization/projects/users/test_roles.py | 121 ++++ .../admin/organization/test_data_retention.py | 136 ++++ .../admin/organization/test_groups.py | 76 +++ .../admin/organization/test_roles.py | 76 +++ .../admin/organization/test_spend_alerts.py | 462 ++++++++++++++ .../admin/organization/users/test_roles.py | 97 +++ 69 files changed, 6073 insertions(+), 14 deletions(-) create mode 100644 src/openai/resources/admin/organization/data_retention.py create mode 100644 src/openai/resources/admin/organization/projects/data_retention.py create mode 100644 src/openai/resources/admin/organization/projects/spend_alerts.py create mode 100644 src/openai/resources/admin/organization/spend_alerts.py create mode 100644 src/openai/types/admin/organization/data_retention_update_params.py create mode 100644 src/openai/types/admin/organization/groups/role_retrieve_response.py create mode 100644 src/openai/types/admin/organization/groups/user_retrieve_response.py create mode 100644 src/openai/types/admin/organization/organization_data_retention.py create mode 100644 src/openai/types/admin/organization/organization_spend_alert.py create mode 100644 src/openai/types/admin/organization/organization_spend_alert_deleted.py create mode 100644 src/openai/types/admin/organization/projects/data_retention_update_params.py create mode 100644 src/openai/types/admin/organization/projects/group_retrieve_params.py create mode 100644 src/openai/types/admin/organization/projects/groups/role_retrieve_response.py create mode 100644 src/openai/types/admin/organization/projects/project_data_retention.py create mode 100644 src/openai/types/admin/organization/projects/project_spend_alert.py create mode 100644 src/openai/types/admin/organization/projects/project_spend_alert_deleted.py create mode 100644 src/openai/types/admin/organization/projects/service_account_update_params.py create mode 100644 src/openai/types/admin/organization/projects/spend_alert_create_params.py create mode 100644 src/openai/types/admin/organization/projects/spend_alert_list_params.py create mode 100644 src/openai/types/admin/organization/projects/spend_alert_update_params.py create mode 100644 src/openai/types/admin/organization/projects/users/role_retrieve_response.py create mode 100644 src/openai/types/admin/organization/spend_alert_create_params.py create mode 100644 src/openai/types/admin/organization/spend_alert_list_params.py create mode 100644 src/openai/types/admin/organization/spend_alert_update_params.py create mode 100644 src/openai/types/admin/organization/users/role_retrieve_response.py create mode 100644 tests/api_resources/admin/organization/projects/test_data_retention.py create mode 100644 tests/api_resources/admin/organization/projects/test_spend_alerts.py create mode 100644 tests/api_resources/admin/organization/test_data_retention.py create mode 100644 tests/api_resources/admin/organization/test_spend_alerts.py diff --git a/.stats.yml b/.stats.yml index fb3f316cec..b9d21daa06 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 240 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-66f110677cd924205b0a4e2a1f567c8b56349ee9658bd0ce86561a413a2aabfe.yml -openapi_spec_hash: ab8f320a7a6b2d30d5f1665b8a8bf84e -config_hash: 425042cc0e99cf31866f6c98fef2be27 +configured_endpoints: 262 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-afacc4343d0efc074c8c5667eb83570642c8b9acaa7792ca8e075c6d18ef9f3a.yml +openapi_spec_hash: a62a557c61532681963fd21e748b0eb4 +config_hash: bb69d8d0771dbac4a84fc6dca11e3ceb diff --git a/api.md b/api.md index ab2f3f75a2..10a729d995 100644 --- a/api.md +++ b/api.md @@ -813,6 +813,7 @@ Types: ```python from openai.types.admin.organization.users import ( RoleCreateResponse, + RoleRetrieveResponse, RoleListResponse, RoleDeleteResponse, ) @@ -821,6 +822,7 @@ from openai.types.admin.organization.users import ( Methods: - client.admin.organization.users.roles.create(user_id, \*\*params) -> RoleCreateResponse +- client.admin.organization.users.roles.retrieve(role_id, \*, user_id) -> RoleRetrieveResponse - client.admin.organization.users.roles.list(user_id, \*\*params) -> SyncNextCursorPage[RoleListResponse] - client.admin.organization.users.roles.delete(role_id, \*, user_id) -> RoleDeleteResponse @@ -835,6 +837,7 @@ from openai.types.admin.organization import Group, GroupUpdateResponse, GroupDel Methods: - client.admin.organization.groups.create(\*\*params) -> Group +- client.admin.organization.groups.retrieve(group_id) -> Group - client.admin.organization.groups.update(group_id, \*\*params) -> GroupUpdateResponse - client.admin.organization.groups.list(\*\*params) -> SyncNextCursorPage[Group] - client.admin.organization.groups.delete(group_id) -> GroupDeleteResponse @@ -847,6 +850,7 @@ Types: from openai.types.admin.organization.groups import ( OrganizationGroupUser, UserCreateResponse, + UserRetrieveResponse, UserDeleteResponse, ) ``` @@ -854,6 +858,7 @@ from openai.types.admin.organization.groups import ( Methods: - client.admin.organization.groups.users.create(group_id, \*\*params) -> UserCreateResponse +- client.admin.organization.groups.users.retrieve(user_id, \*, group_id) -> UserRetrieveResponse - client.admin.organization.groups.users.list(group_id, \*\*params) -> SyncNextCursorPage[OrganizationGroupUser] - client.admin.organization.groups.users.delete(user_id, \*, group_id) -> UserDeleteResponse @@ -864,6 +869,7 @@ Types: ```python from openai.types.admin.organization.groups import ( RoleCreateResponse, + RoleRetrieveResponse, RoleListResponse, RoleDeleteResponse, ) @@ -872,6 +878,7 @@ from openai.types.admin.organization.groups import ( Methods: - client.admin.organization.groups.roles.create(group_id, \*\*params) -> RoleCreateResponse +- client.admin.organization.groups.roles.retrieve(role_id, \*, group_id) -> RoleRetrieveResponse - client.admin.organization.groups.roles.list(group_id, \*\*params) -> SyncNextCursorPage[RoleListResponse] - client.admin.organization.groups.roles.delete(role_id, \*, group_id) -> RoleDeleteResponse @@ -886,10 +893,39 @@ from openai.types.admin.organization import Role, RoleDeleteResponse Methods: - client.admin.organization.roles.create(\*\*params) -> Role +- client.admin.organization.roles.retrieve(role_id) -> Role - client.admin.organization.roles.update(role_id, \*\*params) -> Role - client.admin.organization.roles.list(\*\*params) -> SyncNextCursorPage[Role] - client.admin.organization.roles.delete(role_id) -> RoleDeleteResponse +### DataRetention + +Types: + +```python +from openai.types.admin.organization import OrganizationDataRetention +``` + +Methods: + +- client.admin.organization.data_retention.retrieve() -> OrganizationDataRetention +- client.admin.organization.data_retention.update(\*\*params) -> OrganizationDataRetention + +### SpendAlerts + +Types: + +```python +from openai.types.admin.organization import OrganizationSpendAlert, OrganizationSpendAlertDeleted +``` + +Methods: + +- client.admin.organization.spend_alerts.create(\*\*params) -> OrganizationSpendAlert +- client.admin.organization.spend_alerts.update(alert_id, \*\*params) -> OrganizationSpendAlert +- client.admin.organization.spend_alerts.list(\*\*params) -> SyncConversationCursorPage[OrganizationSpendAlert] +- client.admin.organization.spend_alerts.delete(alert_id) -> OrganizationSpendAlertDeleted + ### Certificates Types: @@ -953,6 +989,7 @@ Types: ```python from openai.types.admin.organization.projects.users import ( RoleCreateResponse, + RoleRetrieveResponse, RoleListResponse, RoleDeleteResponse, ) @@ -961,6 +998,7 @@ from openai.types.admin.organization.projects.users import ( Methods: - client.admin.organization.projects.users.roles.create(user_id, \*, project_id, \*\*params) -> RoleCreateResponse +- client.admin.organization.projects.users.roles.retrieve(role_id, \*, project_id, user_id) -> RoleRetrieveResponse - client.admin.organization.projects.users.roles.list(user_id, \*, project_id, \*\*params) -> SyncNextCursorPage[RoleListResponse] - client.admin.organization.projects.users.roles.delete(role_id, \*, project_id, user_id) -> RoleDeleteResponse @@ -980,6 +1018,7 @@ Methods: - client.admin.organization.projects.service_accounts.create(project_id, \*\*params) -> ServiceAccountCreateResponse - client.admin.organization.projects.service_accounts.retrieve(service_account_id, \*, project_id) -> ProjectServiceAccount +- client.admin.organization.projects.service_accounts.update(service_account_id, \*, project_id, \*\*params) -> ProjectServiceAccount - client.admin.organization.projects.service_accounts.list(project_id, \*\*params) -> SyncConversationCursorPage[ProjectServiceAccount] - client.admin.organization.projects.service_accounts.delete(service_account_id, \*, project_id) -> ServiceAccountDeleteResponse @@ -1051,6 +1090,7 @@ from openai.types.admin.organization.projects import ProjectGroup, GroupDeleteRe Methods: - client.admin.organization.projects.groups.create(project_id, \*\*params) -> ProjectGroup +- client.admin.organization.projects.groups.retrieve(group_id, \*, project_id, \*\*params) -> ProjectGroup - client.admin.organization.projects.groups.list(project_id, \*\*params) -> SyncNextCursorPage[ProjectGroup] - client.admin.organization.projects.groups.delete(group_id, \*, project_id) -> GroupDeleteResponse @@ -1061,6 +1101,7 @@ Types: ```python from openai.types.admin.organization.projects.groups import ( RoleCreateResponse, + RoleRetrieveResponse, RoleListResponse, RoleDeleteResponse, ) @@ -1069,6 +1110,7 @@ from openai.types.admin.organization.projects.groups import ( Methods: - client.admin.organization.projects.groups.roles.create(group_id, \*, project_id, \*\*params) -> RoleCreateResponse +- client.admin.organization.projects.groups.roles.retrieve(role_id, \*, project_id, group_id) -> RoleRetrieveResponse - client.admin.organization.projects.groups.roles.list(group_id, \*, project_id, \*\*params) -> SyncNextCursorPage[RoleListResponse] - client.admin.organization.projects.groups.roles.delete(role_id, \*, project_id, group_id) -> RoleDeleteResponse @@ -1083,10 +1125,39 @@ from openai.types.admin.organization.projects import RoleDeleteResponse Methods: - client.admin.organization.projects.roles.create(project_id, \*\*params) -> Role +- client.admin.organization.projects.roles.retrieve(role_id, \*, project_id) -> Role - client.admin.organization.projects.roles.update(role_id, \*, project_id, \*\*params) -> Role - client.admin.organization.projects.roles.list(project_id, \*\*params) -> SyncNextCursorPage[Role] - client.admin.organization.projects.roles.delete(role_id, \*, project_id) -> RoleDeleteResponse +#### DataRetention + +Types: + +```python +from openai.types.admin.organization.projects import ProjectDataRetention +``` + +Methods: + +- client.admin.organization.projects.data_retention.retrieve(project_id) -> ProjectDataRetention +- client.admin.organization.projects.data_retention.update(project_id, \*\*params) -> ProjectDataRetention + +#### SpendAlerts + +Types: + +```python +from openai.types.admin.organization.projects import ProjectSpendAlert, ProjectSpendAlertDeleted +``` + +Methods: + +- client.admin.organization.projects.spend_alerts.create(project_id, \*\*params) -> ProjectSpendAlert +- client.admin.organization.projects.spend_alerts.update(alert_id, \*, project_id, \*\*params) -> ProjectSpendAlert +- client.admin.organization.projects.spend_alerts.list(project_id, \*\*params) -> SyncConversationCursorPage[ProjectSpendAlert] +- client.admin.organization.projects.spend_alerts.delete(alert_id, \*, project_id) -> ProjectSpendAlertDeleted + #### Certificates Types: diff --git a/src/openai/resources/admin/organization/__init__.py b/src/openai/resources/admin/organization/__init__.py index 50641088bb..d87fbbc81d 100644 --- a/src/openai/resources/admin/organization/__init__.py +++ b/src/openai/resources/admin/organization/__init__.py @@ -72,6 +72,14 @@ OrganizationWithStreamingResponse, AsyncOrganizationWithStreamingResponse, ) +from .spend_alerts import ( + SpendAlerts, + AsyncSpendAlerts, + SpendAlertsWithRawResponse, + AsyncSpendAlertsWithRawResponse, + SpendAlertsWithStreamingResponse, + AsyncSpendAlertsWithStreamingResponse, +) from .admin_api_keys import ( AdminAPIKeys, AsyncAdminAPIKeys, @@ -80,6 +88,14 @@ AdminAPIKeysWithStreamingResponse, AsyncAdminAPIKeysWithStreamingResponse, ) +from .data_retention import ( + DataRetention, + AsyncDataRetention, + DataRetentionWithRawResponse, + AsyncDataRetentionWithRawResponse, + DataRetentionWithStreamingResponse, + AsyncDataRetentionWithStreamingResponse, +) __all__ = [ "AuditLogs", @@ -124,6 +140,18 @@ "AsyncRolesWithRawResponse", "RolesWithStreamingResponse", "AsyncRolesWithStreamingResponse", + "DataRetention", + "AsyncDataRetention", + "DataRetentionWithRawResponse", + "AsyncDataRetentionWithRawResponse", + "DataRetentionWithStreamingResponse", + "AsyncDataRetentionWithStreamingResponse", + "SpendAlerts", + "AsyncSpendAlerts", + "SpendAlertsWithRawResponse", + "AsyncSpendAlertsWithRawResponse", + "SpendAlertsWithStreamingResponse", + "AsyncSpendAlertsWithStreamingResponse", "Certificates", "AsyncCertificates", "CertificatesWithRawResponse", diff --git a/src/openai/resources/admin/organization/data_retention.py b/src/openai/resources/admin/organization/data_retention.py new file mode 100644 index 0000000000..c3b7325a92 --- /dev/null +++ b/src/openai/resources/admin/organization/data_retention.py @@ -0,0 +1,245 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from .... import _legacy_response +from ...._types import Body, Query, Headers, NotGiven, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ...._base_client import make_request_options +from ....types.admin.organization import data_retention_update_params +from ....types.admin.organization.organization_data_retention import OrganizationDataRetention + +__all__ = ["DataRetention", "AsyncDataRetention"] + + +class DataRetention(SyncAPIResource): + @cached_property + def with_raw_response(self) -> DataRetentionWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return DataRetentionWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> DataRetentionWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return DataRetentionWithStreamingResponse(self) + + def retrieve( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OrganizationDataRetention: + """Retrieves organization data retention controls.""" + return self._get( + "/organization/data_retention", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=OrganizationDataRetention, + ) + + def update( + self, + *, + retention_type: Literal[ + "zero_data_retention", + "modified_abuse_monitoring", + "enhanced_zero_data_retention", + "enhanced_modified_abuse_monitoring", + ], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OrganizationDataRetention: + """ + Updates organization data retention controls. + + Args: + retention_type: The desired organization data retention type. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/organization/data_retention", + body=maybe_transform( + {"retention_type": retention_type}, data_retention_update_params.DataRetentionUpdateParams + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=OrganizationDataRetention, + ) + + +class AsyncDataRetention(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncDataRetentionWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncDataRetentionWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncDataRetentionWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncDataRetentionWithStreamingResponse(self) + + async def retrieve( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OrganizationDataRetention: + """Retrieves organization data retention controls.""" + return await self._get( + "/organization/data_retention", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=OrganizationDataRetention, + ) + + async def update( + self, + *, + retention_type: Literal[ + "zero_data_retention", + "modified_abuse_monitoring", + "enhanced_zero_data_retention", + "enhanced_modified_abuse_monitoring", + ], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OrganizationDataRetention: + """ + Updates organization data retention controls. + + Args: + retention_type: The desired organization data retention type. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/organization/data_retention", + body=await async_maybe_transform( + {"retention_type": retention_type}, data_retention_update_params.DataRetentionUpdateParams + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=OrganizationDataRetention, + ) + + +class DataRetentionWithRawResponse: + def __init__(self, data_retention: DataRetention) -> None: + self._data_retention = data_retention + + self.retrieve = _legacy_response.to_raw_response_wrapper( + data_retention.retrieve, + ) + self.update = _legacy_response.to_raw_response_wrapper( + data_retention.update, + ) + + +class AsyncDataRetentionWithRawResponse: + def __init__(self, data_retention: AsyncDataRetention) -> None: + self._data_retention = data_retention + + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + data_retention.retrieve, + ) + self.update = _legacy_response.async_to_raw_response_wrapper( + data_retention.update, + ) + + +class DataRetentionWithStreamingResponse: + def __init__(self, data_retention: DataRetention) -> None: + self._data_retention = data_retention + + self.retrieve = to_streamed_response_wrapper( + data_retention.retrieve, + ) + self.update = to_streamed_response_wrapper( + data_retention.update, + ) + + +class AsyncDataRetentionWithStreamingResponse: + def __init__(self, data_retention: AsyncDataRetention) -> None: + self._data_retention = data_retention + + self.retrieve = async_to_streamed_response_wrapper( + data_retention.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + data_retention.update, + ) diff --git a/src/openai/resources/admin/organization/groups/groups.py b/src/openai/resources/admin/organization/groups/groups.py index 80baa38926..fa7a6b2354 100644 --- a/src/openai/resources/admin/organization/groups/groups.py +++ b/src/openai/resources/admin/organization/groups/groups.py @@ -104,6 +104,43 @@ def create( cast_to=Group, ) + def retrieve( + self, + group_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Group: + """ + Retrieves a group. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return self._get( + path_template("/organization/groups/{group_id}", group_id=group_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=Group, + ) + def update( self, group_id: str, @@ -305,6 +342,43 @@ async def create( cast_to=Group, ) + async def retrieve( + self, + group_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Group: + """ + Retrieves a group. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return await self._get( + path_template("/organization/groups/{group_id}", group_id=group_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=Group, + ) + async def update( self, group_id: str, @@ -447,6 +521,9 @@ def __init__(self, groups: Groups) -> None: self.create = _legacy_response.to_raw_response_wrapper( groups.create, ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + groups.retrieve, + ) self.update = _legacy_response.to_raw_response_wrapper( groups.update, ) @@ -473,6 +550,9 @@ def __init__(self, groups: AsyncGroups) -> None: self.create = _legacy_response.async_to_raw_response_wrapper( groups.create, ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + groups.retrieve, + ) self.update = _legacy_response.async_to_raw_response_wrapper( groups.update, ) @@ -499,6 +579,9 @@ def __init__(self, groups: Groups) -> None: self.create = to_streamed_response_wrapper( groups.create, ) + self.retrieve = to_streamed_response_wrapper( + groups.retrieve, + ) self.update = to_streamed_response_wrapper( groups.update, ) @@ -525,6 +608,9 @@ def __init__(self, groups: AsyncGroups) -> None: self.create = async_to_streamed_response_wrapper( groups.create, ) + self.retrieve = async_to_streamed_response_wrapper( + groups.retrieve, + ) self.update = async_to_streamed_response_wrapper( groups.update, ) diff --git a/src/openai/resources/admin/organization/groups/roles.py b/src/openai/resources/admin/organization/groups/roles.py index c85efccfef..c4405c487c 100644 --- a/src/openai/resources/admin/organization/groups/roles.py +++ b/src/openai/resources/admin/organization/groups/roles.py @@ -18,6 +18,7 @@ from .....types.admin.organization.groups.role_list_response import RoleListResponse from .....types.admin.organization.groups.role_create_response import RoleCreateResponse from .....types.admin.organization.groups.role_delete_response import RoleDeleteResponse +from .....types.admin.organization.groups.role_retrieve_response import RoleRetrieveResponse __all__ = ["Roles", "AsyncRoles"] @@ -83,6 +84,46 @@ def create( cast_to=RoleCreateResponse, ) + def retrieve( + self, + role_id: str, + *, + group_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RoleRetrieveResponse: + """ + Retrieves an organization role assigned to a group. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + if not role_id: + raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") + return self._get( + path_template("/organization/groups/{group_id}/roles/{role_id}", group_id=group_id, role_id=role_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=RoleRetrieveResponse, + ) + def list( self, group_id: str, @@ -241,6 +282,46 @@ async def create( cast_to=RoleCreateResponse, ) + async def retrieve( + self, + role_id: str, + *, + group_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RoleRetrieveResponse: + """ + Retrieves an organization role assigned to a group. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + if not role_id: + raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") + return await self._get( + path_template("/organization/groups/{group_id}/roles/{role_id}", group_id=group_id, role_id=role_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=RoleRetrieveResponse, + ) + def list( self, group_id: str, @@ -345,6 +426,9 @@ def __init__(self, roles: Roles) -> None: self.create = _legacy_response.to_raw_response_wrapper( roles.create, ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + roles.retrieve, + ) self.list = _legacy_response.to_raw_response_wrapper( roles.list, ) @@ -360,6 +444,9 @@ def __init__(self, roles: AsyncRoles) -> None: self.create = _legacy_response.async_to_raw_response_wrapper( roles.create, ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + roles.retrieve, + ) self.list = _legacy_response.async_to_raw_response_wrapper( roles.list, ) @@ -375,6 +462,9 @@ def __init__(self, roles: Roles) -> None: self.create = to_streamed_response_wrapper( roles.create, ) + self.retrieve = to_streamed_response_wrapper( + roles.retrieve, + ) self.list = to_streamed_response_wrapper( roles.list, ) @@ -390,6 +480,9 @@ def __init__(self, roles: AsyncRoles) -> None: self.create = async_to_streamed_response_wrapper( roles.create, ) + self.retrieve = async_to_streamed_response_wrapper( + roles.retrieve, + ) self.list = async_to_streamed_response_wrapper( roles.list, ) diff --git a/src/openai/resources/admin/organization/groups/users.py b/src/openai/resources/admin/organization/groups/users.py index 89a2996e13..e0ac71afd9 100644 --- a/src/openai/resources/admin/organization/groups/users.py +++ b/src/openai/resources/admin/organization/groups/users.py @@ -17,6 +17,7 @@ from .....types.admin.organization.groups import user_list_params, user_create_params from .....types.admin.organization.groups.user_create_response import UserCreateResponse from .....types.admin.organization.groups.user_delete_response import UserDeleteResponse +from .....types.admin.organization.groups.user_retrieve_response import UserRetrieveResponse from .....types.admin.organization.groups.organization_group_user import OrganizationGroupUser __all__ = ["Users", "AsyncUsers"] @@ -83,6 +84,46 @@ def create( cast_to=UserCreateResponse, ) + def retrieve( + self, + user_id: str, + *, + group_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UserRetrieveResponse: + """ + Retrieves a user in a group. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + if not user_id: + raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + return self._get( + path_template("/organization/groups/{group_id}/users/{user_id}", group_id=group_id, user_id=user_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=UserRetrieveResponse, + ) + def list( self, group_id: str, @@ -242,6 +283,46 @@ async def create( cast_to=UserCreateResponse, ) + async def retrieve( + self, + user_id: str, + *, + group_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UserRetrieveResponse: + """ + Retrieves a user in a group. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + if not user_id: + raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + return await self._get( + path_template("/organization/groups/{group_id}/users/{user_id}", group_id=group_id, user_id=user_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=UserRetrieveResponse, + ) + def list( self, group_id: str, @@ -347,6 +428,9 @@ def __init__(self, users: Users) -> None: self.create = _legacy_response.to_raw_response_wrapper( users.create, ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + users.retrieve, + ) self.list = _legacy_response.to_raw_response_wrapper( users.list, ) @@ -362,6 +446,9 @@ def __init__(self, users: AsyncUsers) -> None: self.create = _legacy_response.async_to_raw_response_wrapper( users.create, ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + users.retrieve, + ) self.list = _legacy_response.async_to_raw_response_wrapper( users.list, ) @@ -377,6 +464,9 @@ def __init__(self, users: Users) -> None: self.create = to_streamed_response_wrapper( users.create, ) + self.retrieve = to_streamed_response_wrapper( + users.retrieve, + ) self.list = to_streamed_response_wrapper( users.list, ) @@ -392,6 +482,9 @@ def __init__(self, users: AsyncUsers) -> None: self.create = async_to_streamed_response_wrapper( users.create, ) + self.retrieve = async_to_streamed_response_wrapper( + users.retrieve, + ) self.list = async_to_streamed_response_wrapper( users.list, ) diff --git a/src/openai/resources/admin/organization/organization.py b/src/openai/resources/admin/organization/organization.py index abbbadf575..62bba207cb 100644 --- a/src/openai/resources/admin/organization/organization.py +++ b/src/openai/resources/admin/organization/organization.py @@ -52,6 +52,14 @@ CertificatesWithStreamingResponse, AsyncCertificatesWithStreamingResponse, ) +from .spend_alerts import ( + SpendAlerts, + AsyncSpendAlerts, + SpendAlertsWithRawResponse, + AsyncSpendAlertsWithRawResponse, + SpendAlertsWithStreamingResponse, + AsyncSpendAlertsWithStreamingResponse, +) from .groups.groups import ( Groups, AsyncGroups, @@ -68,6 +76,14 @@ AdminAPIKeysWithStreamingResponse, AsyncAdminAPIKeysWithStreamingResponse, ) +from .data_retention import ( + DataRetention, + AsyncDataRetention, + DataRetentionWithRawResponse, + AsyncDataRetentionWithRawResponse, + DataRetentionWithStreamingResponse, + AsyncDataRetentionWithStreamingResponse, +) from .projects.projects import ( Projects, AsyncProjects, @@ -110,6 +126,14 @@ def groups(self) -> Groups: def roles(self) -> Roles: return Roles(self._client) + @cached_property + def data_retention(self) -> DataRetention: + return DataRetention(self._client) + + @cached_property + def spend_alerts(self) -> SpendAlerts: + return SpendAlerts(self._client) + @cached_property def certificates(self) -> Certificates: return Certificates(self._client) @@ -168,6 +192,14 @@ def groups(self) -> AsyncGroups: def roles(self) -> AsyncRoles: return AsyncRoles(self._client) + @cached_property + def data_retention(self) -> AsyncDataRetention: + return AsyncDataRetention(self._client) + + @cached_property + def spend_alerts(self) -> AsyncSpendAlerts: + return AsyncSpendAlerts(self._client) + @cached_property def certificates(self) -> AsyncCertificates: return AsyncCertificates(self._client) @@ -229,6 +261,14 @@ def groups(self) -> GroupsWithRawResponse: def roles(self) -> RolesWithRawResponse: return RolesWithRawResponse(self._organization.roles) + @cached_property + def data_retention(self) -> DataRetentionWithRawResponse: + return DataRetentionWithRawResponse(self._organization.data_retention) + + @cached_property + def spend_alerts(self) -> SpendAlertsWithRawResponse: + return SpendAlertsWithRawResponse(self._organization.spend_alerts) + @cached_property def certificates(self) -> CertificatesWithRawResponse: return CertificatesWithRawResponse(self._organization.certificates) @@ -271,6 +311,14 @@ def groups(self) -> AsyncGroupsWithRawResponse: def roles(self) -> AsyncRolesWithRawResponse: return AsyncRolesWithRawResponse(self._organization.roles) + @cached_property + def data_retention(self) -> AsyncDataRetentionWithRawResponse: + return AsyncDataRetentionWithRawResponse(self._organization.data_retention) + + @cached_property + def spend_alerts(self) -> AsyncSpendAlertsWithRawResponse: + return AsyncSpendAlertsWithRawResponse(self._organization.spend_alerts) + @cached_property def certificates(self) -> AsyncCertificatesWithRawResponse: return AsyncCertificatesWithRawResponse(self._organization.certificates) @@ -313,6 +361,14 @@ def groups(self) -> GroupsWithStreamingResponse: def roles(self) -> RolesWithStreamingResponse: return RolesWithStreamingResponse(self._organization.roles) + @cached_property + def data_retention(self) -> DataRetentionWithStreamingResponse: + return DataRetentionWithStreamingResponse(self._organization.data_retention) + + @cached_property + def spend_alerts(self) -> SpendAlertsWithStreamingResponse: + return SpendAlertsWithStreamingResponse(self._organization.spend_alerts) + @cached_property def certificates(self) -> CertificatesWithStreamingResponse: return CertificatesWithStreamingResponse(self._organization.certificates) @@ -355,6 +411,14 @@ def groups(self) -> AsyncGroupsWithStreamingResponse: def roles(self) -> AsyncRolesWithStreamingResponse: return AsyncRolesWithStreamingResponse(self._organization.roles) + @cached_property + def data_retention(self) -> AsyncDataRetentionWithStreamingResponse: + return AsyncDataRetentionWithStreamingResponse(self._organization.data_retention) + + @cached_property + def spend_alerts(self) -> AsyncSpendAlertsWithStreamingResponse: + return AsyncSpendAlertsWithStreamingResponse(self._organization.spend_alerts) + @cached_property def certificates(self) -> AsyncCertificatesWithStreamingResponse: return AsyncCertificatesWithStreamingResponse(self._organization.certificates) diff --git a/src/openai/resources/admin/organization/projects/__init__.py b/src/openai/resources/admin/organization/projects/__init__.py index 7f77863a2d..3bc97170fd 100644 --- a/src/openai/resources/admin/organization/projects/__init__.py +++ b/src/openai/resources/admin/organization/projects/__init__.py @@ -56,6 +56,22 @@ CertificatesWithStreamingResponse, AsyncCertificatesWithStreamingResponse, ) +from .spend_alerts import ( + SpendAlerts, + AsyncSpendAlerts, + SpendAlertsWithRawResponse, + AsyncSpendAlertsWithRawResponse, + SpendAlertsWithStreamingResponse, + AsyncSpendAlertsWithStreamingResponse, +) +from .data_retention import ( + DataRetention, + AsyncDataRetention, + DataRetentionWithRawResponse, + AsyncDataRetentionWithRawResponse, + DataRetentionWithStreamingResponse, + AsyncDataRetentionWithStreamingResponse, +) from .service_accounts import ( ServiceAccounts, AsyncServiceAccounts, @@ -130,6 +146,18 @@ "AsyncRolesWithRawResponse", "RolesWithStreamingResponse", "AsyncRolesWithStreamingResponse", + "DataRetention", + "AsyncDataRetention", + "DataRetentionWithRawResponse", + "AsyncDataRetentionWithRawResponse", + "DataRetentionWithStreamingResponse", + "AsyncDataRetentionWithStreamingResponse", + "SpendAlerts", + "AsyncSpendAlerts", + "SpendAlertsWithRawResponse", + "AsyncSpendAlertsWithRawResponse", + "SpendAlertsWithStreamingResponse", + "AsyncSpendAlertsWithStreamingResponse", "Certificates", "AsyncCertificates", "CertificatesWithRawResponse", diff --git a/src/openai/resources/admin/organization/projects/data_retention.py b/src/openai/resources/admin/organization/projects/data_retention.py new file mode 100644 index 0000000000..2d0df3e7e2 --- /dev/null +++ b/src/openai/resources/admin/organization/projects/data_retention.py @@ -0,0 +1,283 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from ..... import _legacy_response +from ....._types import Body, Query, Headers, NotGiven, not_given +from ....._utils import path_template, maybe_transform, async_maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ....._base_client import make_request_options +from .....types.admin.organization.projects import data_retention_update_params +from .....types.admin.organization.projects.project_data_retention import ProjectDataRetention + +__all__ = ["DataRetention", "AsyncDataRetention"] + + +class DataRetention(SyncAPIResource): + @cached_property + def with_raw_response(self) -> DataRetentionWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return DataRetentionWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> DataRetentionWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return DataRetentionWithStreamingResponse(self) + + def retrieve( + self, + project_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectDataRetention: + """ + Retrieves project data retention controls. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._get( + path_template("/organization/projects/{project_id}/data_retention", project_id=project_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectDataRetention, + ) + + def update( + self, + project_id: str, + *, + retention_type: Literal[ + "organization_default", + "none", + "zero_data_retention", + "modified_abuse_monitoring", + "enhanced_zero_data_retention", + "enhanced_modified_abuse_monitoring", + ], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectDataRetention: + """ + Updates project data retention controls. + + Args: + retention_type: The desired project data retention type. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._post( + path_template("/organization/projects/{project_id}/data_retention", project_id=project_id), + body=maybe_transform( + {"retention_type": retention_type}, data_retention_update_params.DataRetentionUpdateParams + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectDataRetention, + ) + + +class AsyncDataRetention(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncDataRetentionWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncDataRetentionWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncDataRetentionWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncDataRetentionWithStreamingResponse(self) + + async def retrieve( + self, + project_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectDataRetention: + """ + Retrieves project data retention controls. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return await self._get( + path_template("/organization/projects/{project_id}/data_retention", project_id=project_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectDataRetention, + ) + + async def update( + self, + project_id: str, + *, + retention_type: Literal[ + "organization_default", + "none", + "zero_data_retention", + "modified_abuse_monitoring", + "enhanced_zero_data_retention", + "enhanced_modified_abuse_monitoring", + ], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectDataRetention: + """ + Updates project data retention controls. + + Args: + retention_type: The desired project data retention type. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return await self._post( + path_template("/organization/projects/{project_id}/data_retention", project_id=project_id), + body=await async_maybe_transform( + {"retention_type": retention_type}, data_retention_update_params.DataRetentionUpdateParams + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectDataRetention, + ) + + +class DataRetentionWithRawResponse: + def __init__(self, data_retention: DataRetention) -> None: + self._data_retention = data_retention + + self.retrieve = _legacy_response.to_raw_response_wrapper( + data_retention.retrieve, + ) + self.update = _legacy_response.to_raw_response_wrapper( + data_retention.update, + ) + + +class AsyncDataRetentionWithRawResponse: + def __init__(self, data_retention: AsyncDataRetention) -> None: + self._data_retention = data_retention + + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + data_retention.retrieve, + ) + self.update = _legacy_response.async_to_raw_response_wrapper( + data_retention.update, + ) + + +class DataRetentionWithStreamingResponse: + def __init__(self, data_retention: DataRetention) -> None: + self._data_retention = data_retention + + self.retrieve = to_streamed_response_wrapper( + data_retention.retrieve, + ) + self.update = to_streamed_response_wrapper( + data_retention.update, + ) + + +class AsyncDataRetentionWithStreamingResponse: + def __init__(self, data_retention: AsyncDataRetention) -> None: + self._data_retention = data_retention + + self.retrieve = async_to_streamed_response_wrapper( + data_retention.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + data_retention.update, + ) diff --git a/src/openai/resources/admin/organization/projects/groups/groups.py b/src/openai/resources/admin/organization/projects/groups/groups.py index aad9bfd6ec..a7ef36fd64 100644 --- a/src/openai/resources/admin/organization/projects/groups/groups.py +++ b/src/openai/resources/admin/organization/projects/groups/groups.py @@ -22,7 +22,7 @@ from ......_response import to_streamed_response_wrapper, async_to_streamed_response_wrapper from ......pagination import SyncNextCursorPage, AsyncNextCursorPage from ......_base_client import AsyncPaginator, make_request_options -from ......types.admin.organization.projects import group_list_params, group_create_params +from ......types.admin.organization.projects import group_list_params, group_create_params, group_retrieve_params from ......types.admin.organization.projects.project_group import ProjectGroup from ......types.admin.organization.projects.group_delete_response import GroupDeleteResponse @@ -103,6 +103,52 @@ def create( cast_to=ProjectGroup, ) + def retrieve( + self, + group_id: str, + *, + project_id: str, + group_type: Literal["group", "tenant_group"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectGroup: + """ + Retrieves a project's group. + + Args: + group_type: The type of group to retrieve. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return self._get( + path_template( + "/organization/projects/{project_id}/groups/{group_id}", project_id=project_id, group_id=group_id + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"group_type": group_type}, group_retrieve_params.GroupRetrieveParams), + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectGroup, + ) + def list( self, project_id: str, @@ -276,6 +322,54 @@ async def create( cast_to=ProjectGroup, ) + async def retrieve( + self, + group_id: str, + *, + project_id: str, + group_type: Literal["group", "tenant_group"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectGroup: + """ + Retrieves a project's group. + + Args: + group_type: The type of group to retrieve. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return await self._get( + path_template( + "/organization/projects/{project_id}/groups/{group_id}", project_id=project_id, group_id=group_id + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"group_type": group_type}, group_retrieve_params.GroupRetrieveParams + ), + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectGroup, + ) + def list( self, project_id: str, @@ -382,6 +476,9 @@ def __init__(self, groups: Groups) -> None: self.create = _legacy_response.to_raw_response_wrapper( groups.create, ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + groups.retrieve, + ) self.list = _legacy_response.to_raw_response_wrapper( groups.list, ) @@ -401,6 +498,9 @@ def __init__(self, groups: AsyncGroups) -> None: self.create = _legacy_response.async_to_raw_response_wrapper( groups.create, ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + groups.retrieve, + ) self.list = _legacy_response.async_to_raw_response_wrapper( groups.list, ) @@ -420,6 +520,9 @@ def __init__(self, groups: Groups) -> None: self.create = to_streamed_response_wrapper( groups.create, ) + self.retrieve = to_streamed_response_wrapper( + groups.retrieve, + ) self.list = to_streamed_response_wrapper( groups.list, ) @@ -439,6 +542,9 @@ def __init__(self, groups: AsyncGroups) -> None: self.create = async_to_streamed_response_wrapper( groups.create, ) + self.retrieve = async_to_streamed_response_wrapper( + groups.retrieve, + ) self.list = async_to_streamed_response_wrapper( groups.list, ) diff --git a/src/openai/resources/admin/organization/projects/groups/roles.py b/src/openai/resources/admin/organization/projects/groups/roles.py index e3fe3b54fe..5961d05e70 100644 --- a/src/openai/resources/admin/organization/projects/groups/roles.py +++ b/src/openai/resources/admin/organization/projects/groups/roles.py @@ -18,6 +18,7 @@ from ......types.admin.organization.projects.groups.role_list_response import RoleListResponse from ......types.admin.organization.projects.groups.role_create_response import RoleCreateResponse from ......types.admin.organization.projects.groups.role_delete_response import RoleDeleteResponse +from ......types.admin.organization.projects.groups.role_retrieve_response import RoleRetrieveResponse __all__ = ["Roles", "AsyncRoles"] @@ -86,6 +87,54 @@ def create( cast_to=RoleCreateResponse, ) + def retrieve( + self, + role_id: str, + *, + project_id: str, + group_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RoleRetrieveResponse: + """ + Retrieves a project role assigned to a group. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + if not role_id: + raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") + return self._get( + path_template( + "/projects/{project_id}/groups/{group_id}/roles/{role_id}", + project_id=project_id, + group_id=group_id, + role_id=role_id, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=RoleRetrieveResponse, + ) + def list( self, group_id: str, @@ -258,6 +307,54 @@ async def create( cast_to=RoleCreateResponse, ) + async def retrieve( + self, + role_id: str, + *, + project_id: str, + group_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RoleRetrieveResponse: + """ + Retrieves a project role assigned to a group. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + if not role_id: + raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") + return await self._get( + path_template( + "/projects/{project_id}/groups/{group_id}/roles/{role_id}", + project_id=project_id, + group_id=group_id, + role_id=role_id, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=RoleRetrieveResponse, + ) + def list( self, group_id: str, @@ -373,6 +470,9 @@ def __init__(self, roles: Roles) -> None: self.create = _legacy_response.to_raw_response_wrapper( roles.create, ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + roles.retrieve, + ) self.list = _legacy_response.to_raw_response_wrapper( roles.list, ) @@ -388,6 +488,9 @@ def __init__(self, roles: AsyncRoles) -> None: self.create = _legacy_response.async_to_raw_response_wrapper( roles.create, ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + roles.retrieve, + ) self.list = _legacy_response.async_to_raw_response_wrapper( roles.list, ) @@ -403,6 +506,9 @@ def __init__(self, roles: Roles) -> None: self.create = to_streamed_response_wrapper( roles.create, ) + self.retrieve = to_streamed_response_wrapper( + roles.retrieve, + ) self.list = to_streamed_response_wrapper( roles.list, ) @@ -418,6 +524,9 @@ def __init__(self, roles: AsyncRoles) -> None: self.create = async_to_streamed_response_wrapper( roles.create, ) + self.retrieve = async_to_streamed_response_wrapper( + roles.retrieve, + ) self.list = async_to_streamed_response_wrapper( roles.list, ) diff --git a/src/openai/resources/admin/organization/projects/projects.py b/src/openai/resources/admin/organization/projects/projects.py index b69e69d0dd..6ffd4c0f85 100644 --- a/src/openai/resources/admin/organization/projects/projects.py +++ b/src/openai/resources/admin/organization/projects/projects.py @@ -50,6 +50,14 @@ CertificatesWithStreamingResponse, AsyncCertificatesWithStreamingResponse, ) +from .spend_alerts import ( + SpendAlerts, + AsyncSpendAlerts, + SpendAlertsWithRawResponse, + AsyncSpendAlertsWithRawResponse, + SpendAlertsWithStreamingResponse, + AsyncSpendAlertsWithStreamingResponse, +) from ....._resource import SyncAPIResource, AsyncAPIResource from ....._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper from .groups.groups import ( @@ -61,6 +69,14 @@ AsyncGroupsWithStreamingResponse, ) from .....pagination import SyncConversationCursorPage, AsyncConversationCursorPage +from .data_retention import ( + DataRetention, + AsyncDataRetention, + DataRetentionWithRawResponse, + AsyncDataRetentionWithRawResponse, + DataRetentionWithStreamingResponse, + AsyncDataRetentionWithStreamingResponse, +) from ....._base_client import AsyncPaginator, make_request_options from .service_accounts import ( ServiceAccounts, @@ -125,6 +141,14 @@ def groups(self) -> Groups: def roles(self) -> Roles: return Roles(self._client) + @cached_property + def data_retention(self) -> DataRetention: + return DataRetention(self._client) + + @cached_property + def spend_alerts(self) -> SpendAlerts: + return SpendAlerts(self._client) + @cached_property def certificates(self) -> Certificates: return Certificates(self._client) @@ -426,6 +450,14 @@ def groups(self) -> AsyncGroups: def roles(self) -> AsyncRoles: return AsyncRoles(self._client) + @cached_property + def data_retention(self) -> AsyncDataRetention: + return AsyncDataRetention(self._client) + + @cached_property + def spend_alerts(self) -> AsyncSpendAlerts: + return AsyncSpendAlerts(self._client) + @cached_property def certificates(self) -> AsyncCertificates: return AsyncCertificates(self._client) @@ -746,6 +778,14 @@ def groups(self) -> GroupsWithRawResponse: def roles(self) -> RolesWithRawResponse: return RolesWithRawResponse(self._projects.roles) + @cached_property + def data_retention(self) -> DataRetentionWithRawResponse: + return DataRetentionWithRawResponse(self._projects.data_retention) + + @cached_property + def spend_alerts(self) -> SpendAlertsWithRawResponse: + return SpendAlertsWithRawResponse(self._projects.spend_alerts) + @cached_property def certificates(self) -> CertificatesWithRawResponse: return CertificatesWithRawResponse(self._projects.certificates) @@ -803,6 +843,14 @@ def groups(self) -> AsyncGroupsWithRawResponse: def roles(self) -> AsyncRolesWithRawResponse: return AsyncRolesWithRawResponse(self._projects.roles) + @cached_property + def data_retention(self) -> AsyncDataRetentionWithRawResponse: + return AsyncDataRetentionWithRawResponse(self._projects.data_retention) + + @cached_property + def spend_alerts(self) -> AsyncSpendAlertsWithRawResponse: + return AsyncSpendAlertsWithRawResponse(self._projects.spend_alerts) + @cached_property def certificates(self) -> AsyncCertificatesWithRawResponse: return AsyncCertificatesWithRawResponse(self._projects.certificates) @@ -860,6 +908,14 @@ def groups(self) -> GroupsWithStreamingResponse: def roles(self) -> RolesWithStreamingResponse: return RolesWithStreamingResponse(self._projects.roles) + @cached_property + def data_retention(self) -> DataRetentionWithStreamingResponse: + return DataRetentionWithStreamingResponse(self._projects.data_retention) + + @cached_property + def spend_alerts(self) -> SpendAlertsWithStreamingResponse: + return SpendAlertsWithStreamingResponse(self._projects.spend_alerts) + @cached_property def certificates(self) -> CertificatesWithStreamingResponse: return CertificatesWithStreamingResponse(self._projects.certificates) @@ -917,6 +973,14 @@ def groups(self) -> AsyncGroupsWithStreamingResponse: def roles(self) -> AsyncRolesWithStreamingResponse: return AsyncRolesWithStreamingResponse(self._projects.roles) + @cached_property + def data_retention(self) -> AsyncDataRetentionWithStreamingResponse: + return AsyncDataRetentionWithStreamingResponse(self._projects.data_retention) + + @cached_property + def spend_alerts(self) -> AsyncSpendAlertsWithStreamingResponse: + return AsyncSpendAlertsWithStreamingResponse(self._projects.spend_alerts) + @cached_property def certificates(self) -> AsyncCertificatesWithStreamingResponse: return AsyncCertificatesWithStreamingResponse(self._projects.certificates) diff --git a/src/openai/resources/admin/organization/projects/roles.py b/src/openai/resources/admin/organization/projects/roles.py index c958b037bb..4c603ec5b1 100644 --- a/src/openai/resources/admin/organization/projects/roles.py +++ b/src/openai/resources/admin/organization/projects/roles.py @@ -96,6 +96,46 @@ def create( cast_to=Role, ) + def retrieve( + self, + role_id: str, + *, + project_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Role: + """ + Retrieves a project role. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not role_id: + raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") + return self._get( + path_template("/projects/{project_id}/roles/{role_id}", project_id=project_id, role_id=role_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=Role, + ) + def update( self, role_id: str, @@ -325,6 +365,46 @@ async def create( cast_to=Role, ) + async def retrieve( + self, + role_id: str, + *, + project_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Role: + """ + Retrieves a project role. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not role_id: + raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") + return await self._get( + path_template("/projects/{project_id}/roles/{role_id}", project_id=project_id, role_id=role_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=Role, + ) + async def update( self, role_id: str, @@ -487,6 +567,9 @@ def __init__(self, roles: Roles) -> None: self.create = _legacy_response.to_raw_response_wrapper( roles.create, ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + roles.retrieve, + ) self.update = _legacy_response.to_raw_response_wrapper( roles.update, ) @@ -505,6 +588,9 @@ def __init__(self, roles: AsyncRoles) -> None: self.create = _legacy_response.async_to_raw_response_wrapper( roles.create, ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + roles.retrieve, + ) self.update = _legacy_response.async_to_raw_response_wrapper( roles.update, ) @@ -523,6 +609,9 @@ def __init__(self, roles: Roles) -> None: self.create = to_streamed_response_wrapper( roles.create, ) + self.retrieve = to_streamed_response_wrapper( + roles.retrieve, + ) self.update = to_streamed_response_wrapper( roles.update, ) @@ -541,6 +630,9 @@ def __init__(self, roles: AsyncRoles) -> None: self.create = async_to_streamed_response_wrapper( roles.create, ) + self.retrieve = async_to_streamed_response_wrapper( + roles.retrieve, + ) self.update = async_to_streamed_response_wrapper( roles.update, ) diff --git a/src/openai/resources/admin/organization/projects/service_accounts.py b/src/openai/resources/admin/organization/projects/service_accounts.py index 9c265fd766..0de0ced9cf 100644 --- a/src/openai/resources/admin/organization/projects/service_accounts.py +++ b/src/openai/resources/admin/organization/projects/service_accounts.py @@ -2,6 +2,8 @@ from __future__ import annotations +from typing_extensions import Literal + import httpx from ..... import _legacy_response @@ -12,7 +14,11 @@ from ....._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper from .....pagination import SyncConversationCursorPage, AsyncConversationCursorPage from ....._base_client import AsyncPaginator, make_request_options -from .....types.admin.organization.projects import service_account_list_params, service_account_create_params +from .....types.admin.organization.projects import ( + service_account_list_params, + service_account_create_params, + service_account_update_params, +) from .....types.admin.organization.projects.project_service_account import ProjectServiceAccount from .....types.admin.organization.projects.service_account_create_response import ServiceAccountCreateResponse from .....types.admin.organization.projects.service_account_delete_response import ServiceAccountDeleteResponse @@ -127,6 +133,63 @@ def retrieve( cast_to=ProjectServiceAccount, ) + def update( + self, + service_account_id: str, + *, + project_id: str, + name: str | Omit = omit, + role: Literal["member", "owner"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectServiceAccount: + """ + Updates a service account in the project. + + Args: + name: The updated service account name. + + role: The updated service account role. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not service_account_id: + raise ValueError(f"Expected a non-empty value for `service_account_id` but received {service_account_id!r}") + return self._post( + path_template( + "/organization/projects/{project_id}/service_accounts/{service_account_id}", + project_id=project_id, + service_account_id=service_account_id, + ), + body=maybe_transform( + { + "name": name, + "role": role, + }, + service_account_update_params.ServiceAccountUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectServiceAccount, + ) + def list( self, project_id: str, @@ -337,6 +400,63 @@ async def retrieve( cast_to=ProjectServiceAccount, ) + async def update( + self, + service_account_id: str, + *, + project_id: str, + name: str | Omit = omit, + role: Literal["member", "owner"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectServiceAccount: + """ + Updates a service account in the project. + + Args: + name: The updated service account name. + + role: The updated service account role. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not service_account_id: + raise ValueError(f"Expected a non-empty value for `service_account_id` but received {service_account_id!r}") + return await self._post( + path_template( + "/organization/projects/{project_id}/service_accounts/{service_account_id}", + project_id=project_id, + service_account_id=service_account_id, + ), + body=await async_maybe_transform( + { + "name": name, + "role": role, + }, + service_account_update_params.ServiceAccountUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectServiceAccount, + ) + def list( self, project_id: str, @@ -450,6 +570,9 @@ def __init__(self, service_accounts: ServiceAccounts) -> None: self.retrieve = _legacy_response.to_raw_response_wrapper( service_accounts.retrieve, ) + self.update = _legacy_response.to_raw_response_wrapper( + service_accounts.update, + ) self.list = _legacy_response.to_raw_response_wrapper( service_accounts.list, ) @@ -468,6 +591,9 @@ def __init__(self, service_accounts: AsyncServiceAccounts) -> None: self.retrieve = _legacy_response.async_to_raw_response_wrapper( service_accounts.retrieve, ) + self.update = _legacy_response.async_to_raw_response_wrapper( + service_accounts.update, + ) self.list = _legacy_response.async_to_raw_response_wrapper( service_accounts.list, ) @@ -486,6 +612,9 @@ def __init__(self, service_accounts: ServiceAccounts) -> None: self.retrieve = to_streamed_response_wrapper( service_accounts.retrieve, ) + self.update = to_streamed_response_wrapper( + service_accounts.update, + ) self.list = to_streamed_response_wrapper( service_accounts.list, ) @@ -504,6 +633,9 @@ def __init__(self, service_accounts: AsyncServiceAccounts) -> None: self.retrieve = async_to_streamed_response_wrapper( service_accounts.retrieve, ) + self.update = async_to_streamed_response_wrapper( + service_accounts.update, + ) self.list = async_to_streamed_response_wrapper( service_accounts.list, ) diff --git a/src/openai/resources/admin/organization/projects/spend_alerts.py b/src/openai/resources/admin/organization/projects/spend_alerts.py new file mode 100644 index 0000000000..3bc5d0c1f9 --- /dev/null +++ b/src/openai/resources/admin/organization/projects/spend_alerts.py @@ -0,0 +1,589 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from ..... import _legacy_response +from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ....._utils import path_template, maybe_transform, async_maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from .....pagination import SyncConversationCursorPage, AsyncConversationCursorPage +from ....._base_client import AsyncPaginator, make_request_options +from .....types.admin.organization.projects import ( + spend_alert_list_params, + spend_alert_create_params, + spend_alert_update_params, +) +from .....types.admin.organization.projects.project_spend_alert import ProjectSpendAlert +from .....types.admin.organization.projects.project_spend_alert_deleted import ProjectSpendAlertDeleted + +__all__ = ["SpendAlerts", "AsyncSpendAlerts"] + + +class SpendAlerts(SyncAPIResource): + @cached_property + def with_raw_response(self) -> SpendAlertsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return SpendAlertsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> SpendAlertsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return SpendAlertsWithStreamingResponse(self) + + def create( + self, + project_id: str, + *, + currency: Literal["USD"], + interval: Literal["month"], + notification_channel: spend_alert_create_params.NotificationChannel, + threshold_amount: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectSpendAlert: + """ + Creates a project spend alert. + + Args: + currency: The currency for the threshold amount. + + interval: The time interval for evaluating spend against the threshold. + + notification_channel: Email notification settings for a spend alert. + + threshold_amount: The alert threshold amount, in cents. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._post( + path_template("/organization/projects/{project_id}/spend_alerts", project_id=project_id), + body=maybe_transform( + { + "currency": currency, + "interval": interval, + "notification_channel": notification_channel, + "threshold_amount": threshold_amount, + }, + spend_alert_create_params.SpendAlertCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectSpendAlert, + ) + + def update( + self, + alert_id: str, + *, + project_id: str, + currency: Literal["USD"], + interval: Literal["month"], + notification_channel: spend_alert_update_params.NotificationChannel, + threshold_amount: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectSpendAlert: + """ + Updates a project spend alert. + + Args: + currency: The currency for the threshold amount. + + interval: The time interval for evaluating spend against the threshold. + + notification_channel: Email notification settings for a spend alert. + + threshold_amount: The alert threshold amount, in cents. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not alert_id: + raise ValueError(f"Expected a non-empty value for `alert_id` but received {alert_id!r}") + return self._post( + path_template( + "/organization/projects/{project_id}/spend_alerts/{alert_id}", project_id=project_id, alert_id=alert_id + ), + body=maybe_transform( + { + "currency": currency, + "interval": interval, + "notification_channel": notification_channel, + "threshold_amount": threshold_amount, + }, + spend_alert_update_params.SpendAlertUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectSpendAlert, + ) + + def list( + self, + project_id: str, + *, + after: str | Omit = omit, + before: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncConversationCursorPage[ProjectSpendAlert]: + """Lists project spend alerts. + + Args: + after: Cursor for pagination. + + Provide the ID of the last spend alert from the previous + response to fetch the next page. + + before: Cursor for pagination. Provide the ID of the first spend alert from the previous + response to fetch the previous page. + + limit: A limit on the number of spend alerts to return. Defaults to 20. + + order: Sort order for the returned spend alerts. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._get_api_list( + path_template("/organization/projects/{project_id}/spend_alerts", project_id=project_id), + page=SyncConversationCursorPage[ProjectSpendAlert], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "before": before, + "limit": limit, + "order": order, + }, + spend_alert_list_params.SpendAlertListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=ProjectSpendAlert, + ) + + def delete( + self, + alert_id: str, + *, + project_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectSpendAlertDeleted: + """ + Deletes a project spend alert. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not alert_id: + raise ValueError(f"Expected a non-empty value for `alert_id` but received {alert_id!r}") + return self._delete( + path_template( + "/organization/projects/{project_id}/spend_alerts/{alert_id}", project_id=project_id, alert_id=alert_id + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectSpendAlertDeleted, + ) + + +class AsyncSpendAlerts(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncSpendAlertsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncSpendAlertsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncSpendAlertsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncSpendAlertsWithStreamingResponse(self) + + async def create( + self, + project_id: str, + *, + currency: Literal["USD"], + interval: Literal["month"], + notification_channel: spend_alert_create_params.NotificationChannel, + threshold_amount: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectSpendAlert: + """ + Creates a project spend alert. + + Args: + currency: The currency for the threshold amount. + + interval: The time interval for evaluating spend against the threshold. + + notification_channel: Email notification settings for a spend alert. + + threshold_amount: The alert threshold amount, in cents. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return await self._post( + path_template("/organization/projects/{project_id}/spend_alerts", project_id=project_id), + body=await async_maybe_transform( + { + "currency": currency, + "interval": interval, + "notification_channel": notification_channel, + "threshold_amount": threshold_amount, + }, + spend_alert_create_params.SpendAlertCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectSpendAlert, + ) + + async def update( + self, + alert_id: str, + *, + project_id: str, + currency: Literal["USD"], + interval: Literal["month"], + notification_channel: spend_alert_update_params.NotificationChannel, + threshold_amount: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectSpendAlert: + """ + Updates a project spend alert. + + Args: + currency: The currency for the threshold amount. + + interval: The time interval for evaluating spend against the threshold. + + notification_channel: Email notification settings for a spend alert. + + threshold_amount: The alert threshold amount, in cents. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not alert_id: + raise ValueError(f"Expected a non-empty value for `alert_id` but received {alert_id!r}") + return await self._post( + path_template( + "/organization/projects/{project_id}/spend_alerts/{alert_id}", project_id=project_id, alert_id=alert_id + ), + body=await async_maybe_transform( + { + "currency": currency, + "interval": interval, + "notification_channel": notification_channel, + "threshold_amount": threshold_amount, + }, + spend_alert_update_params.SpendAlertUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectSpendAlert, + ) + + def list( + self, + project_id: str, + *, + after: str | Omit = omit, + before: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[ProjectSpendAlert, AsyncConversationCursorPage[ProjectSpendAlert]]: + """Lists project spend alerts. + + Args: + after: Cursor for pagination. + + Provide the ID of the last spend alert from the previous + response to fetch the next page. + + before: Cursor for pagination. Provide the ID of the first spend alert from the previous + response to fetch the previous page. + + limit: A limit on the number of spend alerts to return. Defaults to 20. + + order: Sort order for the returned spend alerts. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._get_api_list( + path_template("/organization/projects/{project_id}/spend_alerts", project_id=project_id), + page=AsyncConversationCursorPage[ProjectSpendAlert], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "before": before, + "limit": limit, + "order": order, + }, + spend_alert_list_params.SpendAlertListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=ProjectSpendAlert, + ) + + async def delete( + self, + alert_id: str, + *, + project_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectSpendAlertDeleted: + """ + Deletes a project spend alert. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not alert_id: + raise ValueError(f"Expected a non-empty value for `alert_id` but received {alert_id!r}") + return await self._delete( + path_template( + "/organization/projects/{project_id}/spend_alerts/{alert_id}", project_id=project_id, alert_id=alert_id + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectSpendAlertDeleted, + ) + + +class SpendAlertsWithRawResponse: + def __init__(self, spend_alerts: SpendAlerts) -> None: + self._spend_alerts = spend_alerts + + self.create = _legacy_response.to_raw_response_wrapper( + spend_alerts.create, + ) + self.update = _legacy_response.to_raw_response_wrapper( + spend_alerts.update, + ) + self.list = _legacy_response.to_raw_response_wrapper( + spend_alerts.list, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + spend_alerts.delete, + ) + + +class AsyncSpendAlertsWithRawResponse: + def __init__(self, spend_alerts: AsyncSpendAlerts) -> None: + self._spend_alerts = spend_alerts + + self.create = _legacy_response.async_to_raw_response_wrapper( + spend_alerts.create, + ) + self.update = _legacy_response.async_to_raw_response_wrapper( + spend_alerts.update, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + spend_alerts.list, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + spend_alerts.delete, + ) + + +class SpendAlertsWithStreamingResponse: + def __init__(self, spend_alerts: SpendAlerts) -> None: + self._spend_alerts = spend_alerts + + self.create = to_streamed_response_wrapper( + spend_alerts.create, + ) + self.update = to_streamed_response_wrapper( + spend_alerts.update, + ) + self.list = to_streamed_response_wrapper( + spend_alerts.list, + ) + self.delete = to_streamed_response_wrapper( + spend_alerts.delete, + ) + + +class AsyncSpendAlertsWithStreamingResponse: + def __init__(self, spend_alerts: AsyncSpendAlerts) -> None: + self._spend_alerts = spend_alerts + + self.create = async_to_streamed_response_wrapper( + spend_alerts.create, + ) + self.update = async_to_streamed_response_wrapper( + spend_alerts.update, + ) + self.list = async_to_streamed_response_wrapper( + spend_alerts.list, + ) + self.delete = async_to_streamed_response_wrapper( + spend_alerts.delete, + ) diff --git a/src/openai/resources/admin/organization/projects/users/roles.py b/src/openai/resources/admin/organization/projects/users/roles.py index 6a3233e275..38b79acec3 100644 --- a/src/openai/resources/admin/organization/projects/users/roles.py +++ b/src/openai/resources/admin/organization/projects/users/roles.py @@ -18,6 +18,7 @@ from ......types.admin.organization.projects.users.role_list_response import RoleListResponse from ......types.admin.organization.projects.users.role_create_response import RoleCreateResponse from ......types.admin.organization.projects.users.role_delete_response import RoleDeleteResponse +from ......types.admin.organization.projects.users.role_retrieve_response import RoleRetrieveResponse __all__ = ["Roles", "AsyncRoles"] @@ -86,6 +87,54 @@ def create( cast_to=RoleCreateResponse, ) + def retrieve( + self, + role_id: str, + *, + project_id: str, + user_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RoleRetrieveResponse: + """ + Retrieves a project role assigned to a user. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not user_id: + raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + if not role_id: + raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") + return self._get( + path_template( + "/projects/{project_id}/users/{user_id}/roles/{role_id}", + project_id=project_id, + user_id=user_id, + role_id=role_id, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=RoleRetrieveResponse, + ) + def list( self, user_id: str, @@ -258,6 +307,54 @@ async def create( cast_to=RoleCreateResponse, ) + async def retrieve( + self, + role_id: str, + *, + project_id: str, + user_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RoleRetrieveResponse: + """ + Retrieves a project role assigned to a user. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not user_id: + raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + if not role_id: + raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") + return await self._get( + path_template( + "/projects/{project_id}/users/{user_id}/roles/{role_id}", + project_id=project_id, + user_id=user_id, + role_id=role_id, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=RoleRetrieveResponse, + ) + def list( self, user_id: str, @@ -373,6 +470,9 @@ def __init__(self, roles: Roles) -> None: self.create = _legacy_response.to_raw_response_wrapper( roles.create, ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + roles.retrieve, + ) self.list = _legacy_response.to_raw_response_wrapper( roles.list, ) @@ -388,6 +488,9 @@ def __init__(self, roles: AsyncRoles) -> None: self.create = _legacy_response.async_to_raw_response_wrapper( roles.create, ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + roles.retrieve, + ) self.list = _legacy_response.async_to_raw_response_wrapper( roles.list, ) @@ -403,6 +506,9 @@ def __init__(self, roles: Roles) -> None: self.create = to_streamed_response_wrapper( roles.create, ) + self.retrieve = to_streamed_response_wrapper( + roles.retrieve, + ) self.list = to_streamed_response_wrapper( roles.list, ) @@ -418,6 +524,9 @@ def __init__(self, roles: AsyncRoles) -> None: self.create = async_to_streamed_response_wrapper( roles.create, ) + self.retrieve = async_to_streamed_response_wrapper( + roles.retrieve, + ) self.list = async_to_streamed_response_wrapper( roles.list, ) diff --git a/src/openai/resources/admin/organization/roles.py b/src/openai/resources/admin/organization/roles.py index b25bbfb21e..056a47d7b2 100644 --- a/src/openai/resources/admin/organization/roles.py +++ b/src/openai/resources/admin/organization/roles.py @@ -93,6 +93,43 @@ def create( cast_to=Role, ) + def retrieve( + self, + role_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Role: + """ + Retrieves an organization role. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not role_id: + raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") + return self._get( + path_template("/organization/roles/{role_id}", role_id=role_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=Role, + ) + def update( self, role_id: str, @@ -309,6 +346,43 @@ async def create( cast_to=Role, ) + async def retrieve( + self, + role_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Role: + """ + Retrieves an organization role. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not role_id: + raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") + return await self._get( + path_template("/organization/roles/{role_id}", role_id=role_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=Role, + ) + async def update( self, role_id: str, @@ -461,6 +535,9 @@ def __init__(self, roles: Roles) -> None: self.create = _legacy_response.to_raw_response_wrapper( roles.create, ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + roles.retrieve, + ) self.update = _legacy_response.to_raw_response_wrapper( roles.update, ) @@ -479,6 +556,9 @@ def __init__(self, roles: AsyncRoles) -> None: self.create = _legacy_response.async_to_raw_response_wrapper( roles.create, ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + roles.retrieve, + ) self.update = _legacy_response.async_to_raw_response_wrapper( roles.update, ) @@ -497,6 +577,9 @@ def __init__(self, roles: Roles) -> None: self.create = to_streamed_response_wrapper( roles.create, ) + self.retrieve = to_streamed_response_wrapper( + roles.retrieve, + ) self.update = to_streamed_response_wrapper( roles.update, ) @@ -515,6 +598,9 @@ def __init__(self, roles: AsyncRoles) -> None: self.create = async_to_streamed_response_wrapper( roles.create, ) + self.retrieve = async_to_streamed_response_wrapper( + roles.retrieve, + ) self.update = async_to_streamed_response_wrapper( roles.update, ) diff --git a/src/openai/resources/admin/organization/spend_alerts.py b/src/openai/resources/admin/organization/spend_alerts.py new file mode 100644 index 0000000000..4f3e223269 --- /dev/null +++ b/src/openai/resources/admin/organization/spend_alerts.py @@ -0,0 +1,553 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from .... import _legacy_response +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ...._utils import path_template, maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ....pagination import SyncConversationCursorPage, AsyncConversationCursorPage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.admin.organization import spend_alert_list_params, spend_alert_create_params, spend_alert_update_params +from ....types.admin.organization.organization_spend_alert import OrganizationSpendAlert +from ....types.admin.organization.organization_spend_alert_deleted import OrganizationSpendAlertDeleted + +__all__ = ["SpendAlerts", "AsyncSpendAlerts"] + + +class SpendAlerts(SyncAPIResource): + @cached_property + def with_raw_response(self) -> SpendAlertsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return SpendAlertsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> SpendAlertsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return SpendAlertsWithStreamingResponse(self) + + def create( + self, + *, + currency: Literal["USD"], + interval: Literal["month"], + notification_channel: spend_alert_create_params.NotificationChannel, + threshold_amount: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OrganizationSpendAlert: + """ + Creates an organization spend alert. + + Args: + currency: The currency for the threshold amount. + + interval: The time interval for evaluating spend against the threshold. + + notification_channel: Email notification settings for a spend alert. + + threshold_amount: The alert threshold amount, in cents. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/organization/spend_alerts", + body=maybe_transform( + { + "currency": currency, + "interval": interval, + "notification_channel": notification_channel, + "threshold_amount": threshold_amount, + }, + spend_alert_create_params.SpendAlertCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=OrganizationSpendAlert, + ) + + def update( + self, + alert_id: str, + *, + currency: Literal["USD"], + interval: Literal["month"], + notification_channel: spend_alert_update_params.NotificationChannel, + threshold_amount: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OrganizationSpendAlert: + """ + Updates an organization spend alert. + + Args: + currency: The currency for the threshold amount. + + interval: The time interval for evaluating spend against the threshold. + + notification_channel: Email notification settings for a spend alert. + + threshold_amount: The alert threshold amount, in cents. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not alert_id: + raise ValueError(f"Expected a non-empty value for `alert_id` but received {alert_id!r}") + return self._post( + path_template("/organization/spend_alerts/{alert_id}", alert_id=alert_id), + body=maybe_transform( + { + "currency": currency, + "interval": interval, + "notification_channel": notification_channel, + "threshold_amount": threshold_amount, + }, + spend_alert_update_params.SpendAlertUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=OrganizationSpendAlert, + ) + + def list( + self, + *, + after: str | Omit = omit, + before: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncConversationCursorPage[OrganizationSpendAlert]: + """Lists organization spend alerts. + + Args: + after: Cursor for pagination. + + Provide the ID of the last spend alert from the previous + response to fetch the next page. + + before: Cursor for pagination. Provide the ID of the first spend alert from the previous + response to fetch the previous page. + + limit: A limit on the number of spend alerts to return. Defaults to 20. + + order: Sort order for the returned spend alerts. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/organization/spend_alerts", + page=SyncConversationCursorPage[OrganizationSpendAlert], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "before": before, + "limit": limit, + "order": order, + }, + spend_alert_list_params.SpendAlertListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=OrganizationSpendAlert, + ) + + def delete( + self, + alert_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OrganizationSpendAlertDeleted: + """ + Deletes an organization spend alert. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not alert_id: + raise ValueError(f"Expected a non-empty value for `alert_id` but received {alert_id!r}") + return self._delete( + path_template("/organization/spend_alerts/{alert_id}", alert_id=alert_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=OrganizationSpendAlertDeleted, + ) + + +class AsyncSpendAlerts(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncSpendAlertsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers + """ + return AsyncSpendAlertsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncSpendAlertsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openai/openai-python#with_streaming_response + """ + return AsyncSpendAlertsWithStreamingResponse(self) + + async def create( + self, + *, + currency: Literal["USD"], + interval: Literal["month"], + notification_channel: spend_alert_create_params.NotificationChannel, + threshold_amount: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OrganizationSpendAlert: + """ + Creates an organization spend alert. + + Args: + currency: The currency for the threshold amount. + + interval: The time interval for evaluating spend against the threshold. + + notification_channel: Email notification settings for a spend alert. + + threshold_amount: The alert threshold amount, in cents. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/organization/spend_alerts", + body=await async_maybe_transform( + { + "currency": currency, + "interval": interval, + "notification_channel": notification_channel, + "threshold_amount": threshold_amount, + }, + spend_alert_create_params.SpendAlertCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=OrganizationSpendAlert, + ) + + async def update( + self, + alert_id: str, + *, + currency: Literal["USD"], + interval: Literal["month"], + notification_channel: spend_alert_update_params.NotificationChannel, + threshold_amount: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OrganizationSpendAlert: + """ + Updates an organization spend alert. + + Args: + currency: The currency for the threshold amount. + + interval: The time interval for evaluating spend against the threshold. + + notification_channel: Email notification settings for a spend alert. + + threshold_amount: The alert threshold amount, in cents. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not alert_id: + raise ValueError(f"Expected a non-empty value for `alert_id` but received {alert_id!r}") + return await self._post( + path_template("/organization/spend_alerts/{alert_id}", alert_id=alert_id), + body=await async_maybe_transform( + { + "currency": currency, + "interval": interval, + "notification_channel": notification_channel, + "threshold_amount": threshold_amount, + }, + spend_alert_update_params.SpendAlertUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=OrganizationSpendAlert, + ) + + def list( + self, + *, + after: str | Omit = omit, + before: str | Omit = omit, + limit: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[OrganizationSpendAlert, AsyncConversationCursorPage[OrganizationSpendAlert]]: + """Lists organization spend alerts. + + Args: + after: Cursor for pagination. + + Provide the ID of the last spend alert from the previous + response to fetch the next page. + + before: Cursor for pagination. Provide the ID of the first spend alert from the previous + response to fetch the previous page. + + limit: A limit on the number of spend alerts to return. Defaults to 20. + + order: Sort order for the returned spend alerts. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/organization/spend_alerts", + page=AsyncConversationCursorPage[OrganizationSpendAlert], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "before": before, + "limit": limit, + "order": order, + }, + spend_alert_list_params.SpendAlertListParams, + ), + security={"admin_api_key_auth": True}, + ), + model=OrganizationSpendAlert, + ) + + async def delete( + self, + alert_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OrganizationSpendAlertDeleted: + """ + Deletes an organization spend alert. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not alert_id: + raise ValueError(f"Expected a non-empty value for `alert_id` but received {alert_id!r}") + return await self._delete( + path_template("/organization/spend_alerts/{alert_id}", alert_id=alert_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=OrganizationSpendAlertDeleted, + ) + + +class SpendAlertsWithRawResponse: + def __init__(self, spend_alerts: SpendAlerts) -> None: + self._spend_alerts = spend_alerts + + self.create = _legacy_response.to_raw_response_wrapper( + spend_alerts.create, + ) + self.update = _legacy_response.to_raw_response_wrapper( + spend_alerts.update, + ) + self.list = _legacy_response.to_raw_response_wrapper( + spend_alerts.list, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + spend_alerts.delete, + ) + + +class AsyncSpendAlertsWithRawResponse: + def __init__(self, spend_alerts: AsyncSpendAlerts) -> None: + self._spend_alerts = spend_alerts + + self.create = _legacy_response.async_to_raw_response_wrapper( + spend_alerts.create, + ) + self.update = _legacy_response.async_to_raw_response_wrapper( + spend_alerts.update, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + spend_alerts.list, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + spend_alerts.delete, + ) + + +class SpendAlertsWithStreamingResponse: + def __init__(self, spend_alerts: SpendAlerts) -> None: + self._spend_alerts = spend_alerts + + self.create = to_streamed_response_wrapper( + spend_alerts.create, + ) + self.update = to_streamed_response_wrapper( + spend_alerts.update, + ) + self.list = to_streamed_response_wrapper( + spend_alerts.list, + ) + self.delete = to_streamed_response_wrapper( + spend_alerts.delete, + ) + + +class AsyncSpendAlertsWithStreamingResponse: + def __init__(self, spend_alerts: AsyncSpendAlerts) -> None: + self._spend_alerts = spend_alerts + + self.create = async_to_streamed_response_wrapper( + spend_alerts.create, + ) + self.update = async_to_streamed_response_wrapper( + spend_alerts.update, + ) + self.list = async_to_streamed_response_wrapper( + spend_alerts.list, + ) + self.delete = async_to_streamed_response_wrapper( + spend_alerts.delete, + ) diff --git a/src/openai/resources/admin/organization/users/roles.py b/src/openai/resources/admin/organization/users/roles.py index 01ea5f4844..6a20ab52ff 100644 --- a/src/openai/resources/admin/organization/users/roles.py +++ b/src/openai/resources/admin/organization/users/roles.py @@ -18,6 +18,7 @@ from .....types.admin.organization.users.role_list_response import RoleListResponse from .....types.admin.organization.users.role_create_response import RoleCreateResponse from .....types.admin.organization.users.role_delete_response import RoleDeleteResponse +from .....types.admin.organization.users.role_retrieve_response import RoleRetrieveResponse __all__ = ["Roles", "AsyncRoles"] @@ -83,6 +84,46 @@ def create( cast_to=RoleCreateResponse, ) + def retrieve( + self, + role_id: str, + *, + user_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RoleRetrieveResponse: + """ + Retrieves an organization role assigned to a user. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not user_id: + raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + if not role_id: + raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") + return self._get( + path_template("/organization/users/{user_id}/roles/{role_id}", user_id=user_id, role_id=role_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=RoleRetrieveResponse, + ) + def list( self, user_id: str, @@ -241,6 +282,46 @@ async def create( cast_to=RoleCreateResponse, ) + async def retrieve( + self, + role_id: str, + *, + user_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RoleRetrieveResponse: + """ + Retrieves an organization role assigned to a user. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not user_id: + raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") + if not role_id: + raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") + return await self._get( + path_template("/organization/users/{user_id}/roles/{role_id}", user_id=user_id, role_id=role_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=RoleRetrieveResponse, + ) + def list( self, user_id: str, @@ -345,6 +426,9 @@ def __init__(self, roles: Roles) -> None: self.create = _legacy_response.to_raw_response_wrapper( roles.create, ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + roles.retrieve, + ) self.list = _legacy_response.to_raw_response_wrapper( roles.list, ) @@ -360,6 +444,9 @@ def __init__(self, roles: AsyncRoles) -> None: self.create = _legacy_response.async_to_raw_response_wrapper( roles.create, ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + roles.retrieve, + ) self.list = _legacy_response.async_to_raw_response_wrapper( roles.list, ) @@ -375,6 +462,9 @@ def __init__(self, roles: Roles) -> None: self.create = to_streamed_response_wrapper( roles.create, ) + self.retrieve = to_streamed_response_wrapper( + roles.retrieve, + ) self.list = to_streamed_response_wrapper( roles.list, ) @@ -390,6 +480,9 @@ def __init__(self, roles: AsyncRoles) -> None: self.create = async_to_streamed_response_wrapper( roles.create, ) + self.retrieve = async_to_streamed_response_wrapper( + roles.retrieve, + ) self.list = async_to_streamed_response_wrapper( roles.list, ) diff --git a/src/openai/types/admin/organization/__init__.py b/src/openai/types/admin/organization/__init__.py index ebb62b0eb8..d14d8dce41 100644 --- a/src/openai/types/admin/organization/__init__.py +++ b/src/openai/types/admin/organization/__init__.py @@ -34,13 +34,17 @@ from .invite_delete_response import InviteDeleteResponse as InviteDeleteResponse from .audit_log_list_response import AuditLogListResponse as AuditLogListResponse from .certificate_list_params import CertificateListParams as CertificateListParams +from .spend_alert_list_params import SpendAlertListParams as SpendAlertListParams from .usage_embeddings_params import UsageEmbeddingsParams as UsageEmbeddingsParams +from .organization_spend_alert import OrganizationSpendAlert as OrganizationSpendAlert from .usage_completions_params import UsageCompletionsParams as UsageCompletionsParams from .usage_moderations_params import UsageModerationsParams as UsageModerationsParams from .admin_api_key_list_params import AdminAPIKeyListParams as AdminAPIKeyListParams from .certificate_create_params import CertificateCreateParams as CertificateCreateParams from .certificate_list_response import CertificateListResponse as CertificateListResponse from .certificate_update_params import CertificateUpdateParams as CertificateUpdateParams +from .spend_alert_create_params import SpendAlertCreateParams as SpendAlertCreateParams +from .spend_alert_update_params import SpendAlertUpdateParams as SpendAlertUpdateParams from .usage_embeddings_response import UsageEmbeddingsResponse as UsageEmbeddingsResponse from .usage_completions_response import UsageCompletionsResponse as UsageCompletionsResponse from .usage_moderations_response import UsageModerationsResponse as UsageModerationsResponse @@ -49,7 +53,9 @@ from .certificate_activate_params import CertificateActivateParams as CertificateActivateParams from .certificate_delete_response import CertificateDeleteResponse as CertificateDeleteResponse from .certificate_retrieve_params import CertificateRetrieveParams as CertificateRetrieveParams +from .organization_data_retention import OrganizationDataRetention as OrganizationDataRetention from .usage_audio_speeches_params import UsageAudioSpeechesParams as UsageAudioSpeechesParams +from .data_retention_update_params import DataRetentionUpdateParams as DataRetentionUpdateParams from .usage_vector_stores_response import UsageVectorStoresResponse as UsageVectorStoresResponse from .admin_api_key_create_response import AdminAPIKeyCreateResponse as AdminAPIKeyCreateResponse from .admin_api_key_delete_response import AdminAPIKeyDeleteResponse as AdminAPIKeyDeleteResponse @@ -60,6 +66,7 @@ from .usage_file_search_calls_params import UsageFileSearchCallsParams as UsageFileSearchCallsParams from .certificate_deactivate_response import CertificateDeactivateResponse as CertificateDeactivateResponse from .usage_web_search_calls_response import UsageWebSearchCallsResponse as UsageWebSearchCallsResponse +from .organization_spend_alert_deleted import OrganizationSpendAlertDeleted as OrganizationSpendAlertDeleted from .usage_file_search_calls_response import UsageFileSearchCallsResponse as UsageFileSearchCallsResponse from .usage_audio_transcriptions_params import UsageAudioTranscriptionsParams as UsageAudioTranscriptionsParams from .usage_audio_transcriptions_response import UsageAudioTranscriptionsResponse as UsageAudioTranscriptionsResponse diff --git a/src/openai/types/admin/organization/data_retention_update_params.py b/src/openai/types/admin/organization/data_retention_update_params.py new file mode 100644 index 0000000000..b6510e7955 --- /dev/null +++ b/src/openai/types/admin/organization/data_retention_update_params.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["DataRetentionUpdateParams"] + + +class DataRetentionUpdateParams(TypedDict, total=False): + retention_type: Required[ + Literal[ + "zero_data_retention", + "modified_abuse_monitoring", + "enhanced_zero_data_retention", + "enhanced_modified_abuse_monitoring", + ] + ] + """The desired organization data retention type.""" diff --git a/src/openai/types/admin/organization/group.py b/src/openai/types/admin/organization/group.py index a5823b1442..045980478f 100644 --- a/src/openai/types/admin/organization/group.py +++ b/src/openai/types/admin/organization/group.py @@ -1,5 +1,7 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from typing_extensions import Literal + from ...._models import BaseModel __all__ = ["Group"] @@ -14,7 +16,7 @@ class Group(BaseModel): created_at: int """Unix timestamp (in seconds) when the group was created.""" - group_type: str + group_type: Literal["group", "tenant_group"] """The type of the group.""" is_scim_managed: bool diff --git a/src/openai/types/admin/organization/groups/__init__.py b/src/openai/types/admin/organization/groups/__init__.py index 22189c1085..884cc0d92f 100644 --- a/src/openai/types/admin/organization/groups/__init__.py +++ b/src/openai/types/admin/organization/groups/__init__.py @@ -11,4 +11,6 @@ from .role_delete_response import RoleDeleteResponse as RoleDeleteResponse from .user_create_response import UserCreateResponse as UserCreateResponse from .user_delete_response import UserDeleteResponse as UserDeleteResponse +from .role_retrieve_response import RoleRetrieveResponse as RoleRetrieveResponse +from .user_retrieve_response import UserRetrieveResponse as UserRetrieveResponse from .organization_group_user import OrganizationGroupUser as OrganizationGroupUser diff --git a/src/openai/types/admin/organization/groups/role_list_response.py b/src/openai/types/admin/organization/groups/role_list_response.py index 337d517ba1..fc64f8e9a0 100644 --- a/src/openai/types/admin/organization/groups/role_list_response.py +++ b/src/openai/types/admin/organization/groups/role_list_response.py @@ -4,7 +4,13 @@ from ....._models import BaseModel -__all__ = ["RoleListResponse"] +__all__ = ["RoleListResponse", "AssignmentSource"] + + +class AssignmentSource(BaseModel): + principal_id: str + + principal_type: str class RoleListResponse(BaseModel): @@ -15,6 +21,9 @@ class RoleListResponse(BaseModel): id: str """Identifier for the role.""" + assignment_sources: Optional[List[AssignmentSource]] = None + """Principals from which the role assignment is inherited, when available.""" + created_at: Optional[int] = None """When the role was created.""" diff --git a/src/openai/types/admin/organization/groups/role_retrieve_response.py b/src/openai/types/admin/organization/groups/role_retrieve_response.py new file mode 100644 index 0000000000..576010daad --- /dev/null +++ b/src/openai/types/admin/organization/groups/role_retrieve_response.py @@ -0,0 +1,55 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional + +from ....._models import BaseModel + +__all__ = ["RoleRetrieveResponse", "AssignmentSource"] + + +class AssignmentSource(BaseModel): + principal_id: str + + principal_type: str + + +class RoleRetrieveResponse(BaseModel): + """ + Detailed information about a role assignment entry returned when listing assignments. + """ + + id: str + """Identifier for the role.""" + + assignment_sources: Optional[List[AssignmentSource]] = None + """Principals from which the role assignment is inherited, when available.""" + + created_at: Optional[int] = None + """When the role was created.""" + + created_by: Optional[str] = None + """Identifier of the actor who created the role.""" + + created_by_user_obj: Optional[Dict[str, object]] = None + """User details for the actor that created the role, when available.""" + + description: Optional[str] = None + """Description of the role.""" + + metadata: Optional[Dict[str, object]] = None + """Arbitrary metadata stored on the role.""" + + name: str + """Name of the role.""" + + permissions: List[str] + """Permissions associated with the role.""" + + predefined_role: bool + """Whether the role is predefined by OpenAI.""" + + resource_type: str + """Resource type the role applies to.""" + + updated_at: Optional[int] = None + """When the role was last updated.""" diff --git a/src/openai/types/admin/organization/groups/user_retrieve_response.py b/src/openai/types/admin/organization/groups/user_retrieve_response.py new file mode 100644 index 0000000000..977db3577f --- /dev/null +++ b/src/openai/types/admin/organization/groups/user_retrieve_response.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ....._models import BaseModel + +__all__ = ["UserRetrieveResponse"] + + +class UserRetrieveResponse(BaseModel): + """Details about a user returned from an organization group membership lookup.""" + + id: str + """Identifier for the user.""" + + email: Optional[str] = None + """Email address of the user, or `null` for users without an email.""" + + is_service_account: Optional[bool] = None + """Whether the user is a service account.""" + + name: str + """Display name of the user.""" + + picture: Optional[str] = None + """URL of the user's profile picture, if available.""" + + user_type: Literal["user", "tenant_user"] + """The type of user.""" diff --git a/src/openai/types/admin/organization/organization_data_retention.py b/src/openai/types/admin/organization/organization_data_retention.py new file mode 100644 index 0000000000..0022094f69 --- /dev/null +++ b/src/openai/types/admin/organization/organization_data_retention.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["OrganizationDataRetention"] + + +class OrganizationDataRetention(BaseModel): + """Represents the organization's data retention control setting.""" + + object: Literal["organization.data_retention"] + """The object type, which is always `organization.data_retention`.""" + + type: Literal[ + "zero_data_retention", + "modified_abuse_monitoring", + "enhanced_zero_data_retention", + "enhanced_modified_abuse_monitoring", + ] + """The configured organization data retention type.""" diff --git a/src/openai/types/admin/organization/organization_spend_alert.py b/src/openai/types/admin/organization/organization_spend_alert.py new file mode 100644 index 0000000000..a541926a01 --- /dev/null +++ b/src/openai/types/admin/organization/organization_spend_alert.py @@ -0,0 +1,43 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["OrganizationSpendAlert", "NotificationChannel"] + + +class NotificationChannel(BaseModel): + """Email notification settings for a spend alert.""" + + recipients: List[str] + """Email addresses that receive the spend alert notification.""" + + type: Literal["email"] + """The notification channel type. Currently only `email` is supported.""" + + subject_prefix: Optional[str] = None + """Optional subject prefix for alert emails.""" + + +class OrganizationSpendAlert(BaseModel): + """Represents a spend alert configured at the organization level.""" + + id: str + """The identifier, which can be referenced in API endpoints.""" + + currency: Literal["USD"] + """The currency for the threshold amount.""" + + interval: Literal["month"] + """The time interval for evaluating spend against the threshold.""" + + notification_channel: NotificationChannel + """Email notification settings for a spend alert.""" + + object: Literal["organization.spend_alert"] + """The object type, which is always `organization.spend_alert`.""" + + threshold_amount: int + """The alert threshold amount, in cents.""" diff --git a/src/openai/types/admin/organization/organization_spend_alert_deleted.py b/src/openai/types/admin/organization/organization_spend_alert_deleted.py new file mode 100644 index 0000000000..74fab027ee --- /dev/null +++ b/src/openai/types/admin/organization/organization_spend_alert_deleted.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["OrganizationSpendAlertDeleted"] + + +class OrganizationSpendAlertDeleted(BaseModel): + """Confirmation payload returned after deleting an organization spend alert.""" + + id: str + """The deleted spend alert ID.""" + + deleted: bool + """Whether the spend alert was deleted.""" + + object: Literal["organization.spend_alert.deleted"] + """Always `organization.spend_alert.deleted`.""" diff --git a/src/openai/types/admin/organization/projects/__init__.py b/src/openai/types/admin/organization/projects/__init__.py index 1b78bae7a8..1c510be58d 100644 --- a/src/openai/types/admin/organization/projects/__init__.py +++ b/src/openai/types/admin/organization/projects/__init__.py @@ -15,19 +15,28 @@ from .user_update_params import UserUpdateParams as UserUpdateParams from .api_key_list_params import APIKeyListParams as APIKeyListParams from .group_create_params import GroupCreateParams as GroupCreateParams +from .project_spend_alert import ProjectSpendAlert as ProjectSpendAlert from .role_delete_response import RoleDeleteResponse as RoleDeleteResponse from .user_delete_response import UserDeleteResponse as UserDeleteResponse from .group_delete_response import GroupDeleteResponse as GroupDeleteResponse +from .group_retrieve_params import GroupRetrieveParams as GroupRetrieveParams +from .project_data_retention import ProjectDataRetention as ProjectDataRetention from .api_key_delete_response import APIKeyDeleteResponse as APIKeyDeleteResponse from .certificate_list_params import CertificateListParams as CertificateListParams from .project_service_account import ProjectServiceAccount as ProjectServiceAccount +from .spend_alert_list_params import SpendAlertListParams as SpendAlertListParams from .certificate_list_response import CertificateListResponse as CertificateListResponse from .project_model_permissions import ProjectModelPermissions as ProjectModelPermissions +from .spend_alert_create_params import SpendAlertCreateParams as SpendAlertCreateParams +from .spend_alert_update_params import SpendAlertUpdateParams as SpendAlertUpdateParams from .certificate_activate_params import CertificateActivateParams as CertificateActivateParams +from .project_spend_alert_deleted import ProjectSpendAlertDeleted as ProjectSpendAlertDeleted from .service_account_list_params import ServiceAccountListParams as ServiceAccountListParams +from .data_retention_update_params import DataRetentionUpdateParams as DataRetentionUpdateParams from .certificate_activate_response import CertificateActivateResponse as CertificateActivateResponse from .certificate_deactivate_params import CertificateDeactivateParams as CertificateDeactivateParams from .service_account_create_params import ServiceAccountCreateParams as ServiceAccountCreateParams +from .service_account_update_params import ServiceAccountUpdateParams as ServiceAccountUpdateParams from .model_permission_update_params import ModelPermissionUpdateParams as ModelPermissionUpdateParams from .certificate_deactivate_response import CertificateDeactivateResponse as CertificateDeactivateResponse from .project_hosted_tool_permissions import ProjectHostedToolPermissions as ProjectHostedToolPermissions diff --git a/src/openai/types/admin/organization/projects/data_retention_update_params.py b/src/openai/types/admin/organization/projects/data_retention_update_params.py new file mode 100644 index 0000000000..e7291d207a --- /dev/null +++ b/src/openai/types/admin/organization/projects/data_retention_update_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["DataRetentionUpdateParams"] + + +class DataRetentionUpdateParams(TypedDict, total=False): + retention_type: Required[ + Literal[ + "organization_default", + "none", + "zero_data_retention", + "modified_abuse_monitoring", + "enhanced_zero_data_retention", + "enhanced_modified_abuse_monitoring", + ] + ] + """The desired project data retention type.""" diff --git a/src/openai/types/admin/organization/projects/group_retrieve_params.py b/src/openai/types/admin/organization/projects/group_retrieve_params.py new file mode 100644 index 0000000000..084f345f43 --- /dev/null +++ b/src/openai/types/admin/organization/projects/group_retrieve_params.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["GroupRetrieveParams"] + + +class GroupRetrieveParams(TypedDict, total=False): + project_id: Required[str] + + group_type: Literal["group", "tenant_group"] + """The type of group to retrieve.""" diff --git a/src/openai/types/admin/organization/projects/groups/__init__.py b/src/openai/types/admin/organization/projects/groups/__init__.py index ed464fde83..5e67517593 100644 --- a/src/openai/types/admin/organization/projects/groups/__init__.py +++ b/src/openai/types/admin/organization/projects/groups/__init__.py @@ -7,3 +7,4 @@ from .role_list_response import RoleListResponse as RoleListResponse from .role_create_response import RoleCreateResponse as RoleCreateResponse from .role_delete_response import RoleDeleteResponse as RoleDeleteResponse +from .role_retrieve_response import RoleRetrieveResponse as RoleRetrieveResponse diff --git a/src/openai/types/admin/organization/projects/groups/role_list_response.py b/src/openai/types/admin/organization/projects/groups/role_list_response.py index 72934bde13..d43d0f806b 100644 --- a/src/openai/types/admin/organization/projects/groups/role_list_response.py +++ b/src/openai/types/admin/organization/projects/groups/role_list_response.py @@ -4,7 +4,13 @@ from ......_models import BaseModel -__all__ = ["RoleListResponse"] +__all__ = ["RoleListResponse", "AssignmentSource"] + + +class AssignmentSource(BaseModel): + principal_id: str + + principal_type: str class RoleListResponse(BaseModel): @@ -15,6 +21,9 @@ class RoleListResponse(BaseModel): id: str """Identifier for the role.""" + assignment_sources: Optional[List[AssignmentSource]] = None + """Principals from which the role assignment is inherited, when available.""" + created_at: Optional[int] = None """When the role was created.""" diff --git a/src/openai/types/admin/organization/projects/groups/role_retrieve_response.py b/src/openai/types/admin/organization/projects/groups/role_retrieve_response.py new file mode 100644 index 0000000000..0c10cf0092 --- /dev/null +++ b/src/openai/types/admin/organization/projects/groups/role_retrieve_response.py @@ -0,0 +1,55 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional + +from ......_models import BaseModel + +__all__ = ["RoleRetrieveResponse", "AssignmentSource"] + + +class AssignmentSource(BaseModel): + principal_id: str + + principal_type: str + + +class RoleRetrieveResponse(BaseModel): + """ + Detailed information about a role assignment entry returned when listing assignments. + """ + + id: str + """Identifier for the role.""" + + assignment_sources: Optional[List[AssignmentSource]] = None + """Principals from which the role assignment is inherited, when available.""" + + created_at: Optional[int] = None + """When the role was created.""" + + created_by: Optional[str] = None + """Identifier of the actor who created the role.""" + + created_by_user_obj: Optional[Dict[str, object]] = None + """User details for the actor that created the role, when available.""" + + description: Optional[str] = None + """Description of the role.""" + + metadata: Optional[Dict[str, object]] = None + """Arbitrary metadata stored on the role.""" + + name: str + """Name of the role.""" + + permissions: List[str] + """Permissions associated with the role.""" + + predefined_role: bool + """Whether the role is predefined by OpenAI.""" + + resource_type: str + """Resource type the role applies to.""" + + updated_at: Optional[int] = None + """When the role was last updated.""" diff --git a/src/openai/types/admin/organization/projects/project_data_retention.py b/src/openai/types/admin/organization/projects/project_data_retention.py new file mode 100644 index 0000000000..30329e60f4 --- /dev/null +++ b/src/openai/types/admin/organization/projects/project_data_retention.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ....._models import BaseModel + +__all__ = ["ProjectDataRetention"] + + +class ProjectDataRetention(BaseModel): + """Represents a project's data retention control setting.""" + + object: Literal["project.data_retention"] + """The object type, which is always `project.data_retention`.""" + + type: Literal[ + "organization_default", + "none", + "zero_data_retention", + "modified_abuse_monitoring", + "enhanced_zero_data_retention", + "enhanced_modified_abuse_monitoring", + ] + """The configured project data retention type.""" diff --git a/src/openai/types/admin/organization/projects/project_group.py b/src/openai/types/admin/organization/projects/project_group.py index b3da08ca32..4efb29f91e 100644 --- a/src/openai/types/admin/organization/projects/project_group.py +++ b/src/openai/types/admin/organization/projects/project_group.py @@ -19,7 +19,7 @@ class ProjectGroup(BaseModel): group_name: str """Display name of the group.""" - group_type: str + group_type: Literal["group", "tenant_group"] """The type of the group.""" object: Literal["project.group"] diff --git a/src/openai/types/admin/organization/projects/project_spend_alert.py b/src/openai/types/admin/organization/projects/project_spend_alert.py new file mode 100644 index 0000000000..269ea54db5 --- /dev/null +++ b/src/openai/types/admin/organization/projects/project_spend_alert.py @@ -0,0 +1,43 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ....._models import BaseModel + +__all__ = ["ProjectSpendAlert", "NotificationChannel"] + + +class NotificationChannel(BaseModel): + """Email notification settings for a spend alert.""" + + recipients: List[str] + """Email addresses that receive the spend alert notification.""" + + type: Literal["email"] + """The notification channel type. Currently only `email` is supported.""" + + subject_prefix: Optional[str] = None + """Optional subject prefix for alert emails.""" + + +class ProjectSpendAlert(BaseModel): + """Represents a spend alert configured at the project level.""" + + id: str + """The identifier, which can be referenced in API endpoints.""" + + currency: Literal["USD"] + """The currency for the threshold amount.""" + + interval: Literal["month"] + """The time interval for evaluating spend against the threshold.""" + + notification_channel: NotificationChannel + """Email notification settings for a spend alert.""" + + object: Literal["project.spend_alert"] + """The object type, which is always `project.spend_alert`.""" + + threshold_amount: int + """The alert threshold amount, in cents.""" diff --git a/src/openai/types/admin/organization/projects/project_spend_alert_deleted.py b/src/openai/types/admin/organization/projects/project_spend_alert_deleted.py new file mode 100644 index 0000000000..68be581307 --- /dev/null +++ b/src/openai/types/admin/organization/projects/project_spend_alert_deleted.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ....._models import BaseModel + +__all__ = ["ProjectSpendAlertDeleted"] + + +class ProjectSpendAlertDeleted(BaseModel): + """Confirmation payload returned after deleting a project spend alert.""" + + id: str + """The deleted spend alert ID.""" + + deleted: bool + """Whether the spend alert was deleted.""" + + object: Literal["project.spend_alert.deleted"] + """Always `project.spend_alert.deleted`.""" diff --git a/src/openai/types/admin/organization/projects/service_account_update_params.py b/src/openai/types/admin/organization/projects/service_account_update_params.py new file mode 100644 index 0000000000..852e5d5a5a --- /dev/null +++ b/src/openai/types/admin/organization/projects/service_account_update_params.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ServiceAccountUpdateParams"] + + +class ServiceAccountUpdateParams(TypedDict, total=False): + project_id: Required[str] + + name: str + """The updated service account name.""" + + role: Literal["member", "owner"] + """The updated service account role.""" diff --git a/src/openai/types/admin/organization/projects/spend_alert_create_params.py b/src/openai/types/admin/organization/projects/spend_alert_create_params.py new file mode 100644 index 0000000000..74914d8646 --- /dev/null +++ b/src/openai/types/admin/organization/projects/spend_alert_create_params.py @@ -0,0 +1,37 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +from ....._types import SequenceNotStr + +__all__ = ["SpendAlertCreateParams", "NotificationChannel"] + + +class SpendAlertCreateParams(TypedDict, total=False): + currency: Required[Literal["USD"]] + """The currency for the threshold amount.""" + + interval: Required[Literal["month"]] + """The time interval for evaluating spend against the threshold.""" + + notification_channel: Required[NotificationChannel] + """Email notification settings for a spend alert.""" + + threshold_amount: Required[int] + """The alert threshold amount, in cents.""" + + +class NotificationChannel(TypedDict, total=False): + """Email notification settings for a spend alert.""" + + recipients: Required[SequenceNotStr[str]] + """Email addresses that receive the spend alert notification.""" + + type: Required[Literal["email"]] + """The notification channel type. Currently only `email` is supported.""" + + subject_prefix: Optional[str] + """Optional subject prefix for alert emails.""" diff --git a/src/openai/types/admin/organization/projects/spend_alert_list_params.py b/src/openai/types/admin/organization/projects/spend_alert_list_params.py new file mode 100644 index 0000000000..a37bad5879 --- /dev/null +++ b/src/openai/types/admin/organization/projects/spend_alert_list_params.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["SpendAlertListParams"] + + +class SpendAlertListParams(TypedDict, total=False): + after: str + """Cursor for pagination. + + Provide the ID of the last spend alert from the previous response to fetch the + next page. + """ + + before: str + """Cursor for pagination. + + Provide the ID of the first spend alert from the previous response to fetch the + previous page. + """ + + limit: int + """A limit on the number of spend alerts to return. Defaults to 20.""" + + order: Literal["asc", "desc"] + """Sort order for the returned spend alerts.""" diff --git a/src/openai/types/admin/organization/projects/spend_alert_update_params.py b/src/openai/types/admin/organization/projects/spend_alert_update_params.py new file mode 100644 index 0000000000..1611c531e8 --- /dev/null +++ b/src/openai/types/admin/organization/projects/spend_alert_update_params.py @@ -0,0 +1,39 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +from ....._types import SequenceNotStr + +__all__ = ["SpendAlertUpdateParams", "NotificationChannel"] + + +class SpendAlertUpdateParams(TypedDict, total=False): + project_id: Required[str] + + currency: Required[Literal["USD"]] + """The currency for the threshold amount.""" + + interval: Required[Literal["month"]] + """The time interval for evaluating spend against the threshold.""" + + notification_channel: Required[NotificationChannel] + """Email notification settings for a spend alert.""" + + threshold_amount: Required[int] + """The alert threshold amount, in cents.""" + + +class NotificationChannel(TypedDict, total=False): + """Email notification settings for a spend alert.""" + + recipients: Required[SequenceNotStr[str]] + """Email addresses that receive the spend alert notification.""" + + type: Required[Literal["email"]] + """The notification channel type. Currently only `email` is supported.""" + + subject_prefix: Optional[str] + """Optional subject prefix for alert emails.""" diff --git a/src/openai/types/admin/organization/projects/users/__init__.py b/src/openai/types/admin/organization/projects/users/__init__.py index ed464fde83..5e67517593 100644 --- a/src/openai/types/admin/organization/projects/users/__init__.py +++ b/src/openai/types/admin/organization/projects/users/__init__.py @@ -7,3 +7,4 @@ from .role_list_response import RoleListResponse as RoleListResponse from .role_create_response import RoleCreateResponse as RoleCreateResponse from .role_delete_response import RoleDeleteResponse as RoleDeleteResponse +from .role_retrieve_response import RoleRetrieveResponse as RoleRetrieveResponse diff --git a/src/openai/types/admin/organization/projects/users/role_list_response.py b/src/openai/types/admin/organization/projects/users/role_list_response.py index 72934bde13..d43d0f806b 100644 --- a/src/openai/types/admin/organization/projects/users/role_list_response.py +++ b/src/openai/types/admin/organization/projects/users/role_list_response.py @@ -4,7 +4,13 @@ from ......_models import BaseModel -__all__ = ["RoleListResponse"] +__all__ = ["RoleListResponse", "AssignmentSource"] + + +class AssignmentSource(BaseModel): + principal_id: str + + principal_type: str class RoleListResponse(BaseModel): @@ -15,6 +21,9 @@ class RoleListResponse(BaseModel): id: str """Identifier for the role.""" + assignment_sources: Optional[List[AssignmentSource]] = None + """Principals from which the role assignment is inherited, when available.""" + created_at: Optional[int] = None """When the role was created.""" diff --git a/src/openai/types/admin/organization/projects/users/role_retrieve_response.py b/src/openai/types/admin/organization/projects/users/role_retrieve_response.py new file mode 100644 index 0000000000..0c10cf0092 --- /dev/null +++ b/src/openai/types/admin/organization/projects/users/role_retrieve_response.py @@ -0,0 +1,55 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional + +from ......_models import BaseModel + +__all__ = ["RoleRetrieveResponse", "AssignmentSource"] + + +class AssignmentSource(BaseModel): + principal_id: str + + principal_type: str + + +class RoleRetrieveResponse(BaseModel): + """ + Detailed information about a role assignment entry returned when listing assignments. + """ + + id: str + """Identifier for the role.""" + + assignment_sources: Optional[List[AssignmentSource]] = None + """Principals from which the role assignment is inherited, when available.""" + + created_at: Optional[int] = None + """When the role was created.""" + + created_by: Optional[str] = None + """Identifier of the actor who created the role.""" + + created_by_user_obj: Optional[Dict[str, object]] = None + """User details for the actor that created the role, when available.""" + + description: Optional[str] = None + """Description of the role.""" + + metadata: Optional[Dict[str, object]] = None + """Arbitrary metadata stored on the role.""" + + name: str + """Name of the role.""" + + permissions: List[str] + """Permissions associated with the role.""" + + predefined_role: bool + """Whether the role is predefined by OpenAI.""" + + resource_type: str + """Resource type the role applies to.""" + + updated_at: Optional[int] = None + """When the role was last updated.""" diff --git a/src/openai/types/admin/organization/spend_alert_create_params.py b/src/openai/types/admin/organization/spend_alert_create_params.py new file mode 100644 index 0000000000..f787abdfe1 --- /dev/null +++ b/src/openai/types/admin/organization/spend_alert_create_params.py @@ -0,0 +1,37 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["SpendAlertCreateParams", "NotificationChannel"] + + +class SpendAlertCreateParams(TypedDict, total=False): + currency: Required[Literal["USD"]] + """The currency for the threshold amount.""" + + interval: Required[Literal["month"]] + """The time interval for evaluating spend against the threshold.""" + + notification_channel: Required[NotificationChannel] + """Email notification settings for a spend alert.""" + + threshold_amount: Required[int] + """The alert threshold amount, in cents.""" + + +class NotificationChannel(TypedDict, total=False): + """Email notification settings for a spend alert.""" + + recipients: Required[SequenceNotStr[str]] + """Email addresses that receive the spend alert notification.""" + + type: Required[Literal["email"]] + """The notification channel type. Currently only `email` is supported.""" + + subject_prefix: Optional[str] + """Optional subject prefix for alert emails.""" diff --git a/src/openai/types/admin/organization/spend_alert_list_params.py b/src/openai/types/admin/organization/spend_alert_list_params.py new file mode 100644 index 0000000000..a37bad5879 --- /dev/null +++ b/src/openai/types/admin/organization/spend_alert_list_params.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["SpendAlertListParams"] + + +class SpendAlertListParams(TypedDict, total=False): + after: str + """Cursor for pagination. + + Provide the ID of the last spend alert from the previous response to fetch the + next page. + """ + + before: str + """Cursor for pagination. + + Provide the ID of the first spend alert from the previous response to fetch the + previous page. + """ + + limit: int + """A limit on the number of spend alerts to return. Defaults to 20.""" + + order: Literal["asc", "desc"] + """Sort order for the returned spend alerts.""" diff --git a/src/openai/types/admin/organization/spend_alert_update_params.py b/src/openai/types/admin/organization/spend_alert_update_params.py new file mode 100644 index 0000000000..ddba8a81e1 --- /dev/null +++ b/src/openai/types/admin/organization/spend_alert_update_params.py @@ -0,0 +1,37 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["SpendAlertUpdateParams", "NotificationChannel"] + + +class SpendAlertUpdateParams(TypedDict, total=False): + currency: Required[Literal["USD"]] + """The currency for the threshold amount.""" + + interval: Required[Literal["month"]] + """The time interval for evaluating spend against the threshold.""" + + notification_channel: Required[NotificationChannel] + """Email notification settings for a spend alert.""" + + threshold_amount: Required[int] + """The alert threshold amount, in cents.""" + + +class NotificationChannel(TypedDict, total=False): + """Email notification settings for a spend alert.""" + + recipients: Required[SequenceNotStr[str]] + """Email addresses that receive the spend alert notification.""" + + type: Required[Literal["email"]] + """The notification channel type. Currently only `email` is supported.""" + + subject_prefix: Optional[str] + """Optional subject prefix for alert emails.""" diff --git a/src/openai/types/admin/organization/users/__init__.py b/src/openai/types/admin/organization/users/__init__.py index ed464fde83..5e67517593 100644 --- a/src/openai/types/admin/organization/users/__init__.py +++ b/src/openai/types/admin/organization/users/__init__.py @@ -7,3 +7,4 @@ from .role_list_response import RoleListResponse as RoleListResponse from .role_create_response import RoleCreateResponse as RoleCreateResponse from .role_delete_response import RoleDeleteResponse as RoleDeleteResponse +from .role_retrieve_response import RoleRetrieveResponse as RoleRetrieveResponse diff --git a/src/openai/types/admin/organization/users/role_list_response.py b/src/openai/types/admin/organization/users/role_list_response.py index 337d517ba1..fc64f8e9a0 100644 --- a/src/openai/types/admin/organization/users/role_list_response.py +++ b/src/openai/types/admin/organization/users/role_list_response.py @@ -4,7 +4,13 @@ from ....._models import BaseModel -__all__ = ["RoleListResponse"] +__all__ = ["RoleListResponse", "AssignmentSource"] + + +class AssignmentSource(BaseModel): + principal_id: str + + principal_type: str class RoleListResponse(BaseModel): @@ -15,6 +21,9 @@ class RoleListResponse(BaseModel): id: str """Identifier for the role.""" + assignment_sources: Optional[List[AssignmentSource]] = None + """Principals from which the role assignment is inherited, when available.""" + created_at: Optional[int] = None """When the role was created.""" diff --git a/src/openai/types/admin/organization/users/role_retrieve_response.py b/src/openai/types/admin/organization/users/role_retrieve_response.py new file mode 100644 index 0000000000..576010daad --- /dev/null +++ b/src/openai/types/admin/organization/users/role_retrieve_response.py @@ -0,0 +1,55 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional + +from ....._models import BaseModel + +__all__ = ["RoleRetrieveResponse", "AssignmentSource"] + + +class AssignmentSource(BaseModel): + principal_id: str + + principal_type: str + + +class RoleRetrieveResponse(BaseModel): + """ + Detailed information about a role assignment entry returned when listing assignments. + """ + + id: str + """Identifier for the role.""" + + assignment_sources: Optional[List[AssignmentSource]] = None + """Principals from which the role assignment is inherited, when available.""" + + created_at: Optional[int] = None + """When the role was created.""" + + created_by: Optional[str] = None + """Identifier of the actor who created the role.""" + + created_by_user_obj: Optional[Dict[str, object]] = None + """User details for the actor that created the role, when available.""" + + description: Optional[str] = None + """Description of the role.""" + + metadata: Optional[Dict[str, object]] = None + """Arbitrary metadata stored on the role.""" + + name: str + """Name of the role.""" + + permissions: List[str] + """Permissions associated with the role.""" + + predefined_role: bool + """Whether the role is predefined by OpenAI.""" + + resource_type: str + """Resource type the role applies to.""" + + updated_at: Optional[int] = None + """When the role was last updated.""" diff --git a/src/openai/types/responses/response_function_web_search.py b/src/openai/types/responses/response_function_web_search.py index d3d4afbee3..de6001e146 100644 --- a/src/openai/types/responses/response_function_web_search.py +++ b/src/openai/types/responses/response_function_web_search.py @@ -46,7 +46,7 @@ class ActionOpenPage(BaseModel): """Action type "open_page" - Opens a specific URL from search results.""" type: Literal["open_page"] - """The action type. Always `open_page`.""" + """The action type.""" url: Optional[str] = None """The URL opened by the model.""" diff --git a/src/openai/types/responses/response_function_web_search_param.py b/src/openai/types/responses/response_function_web_search_param.py index e0d50757a3..15e313b0d3 100644 --- a/src/openai/types/responses/response_function_web_search_param.py +++ b/src/openai/types/responses/response_function_web_search_param.py @@ -47,7 +47,7 @@ class ActionOpenPage(TypedDict, total=False): """Action type "open_page" - Opens a specific URL from search results.""" type: Required[Literal["open_page"]] - """The action type. Always `open_page`.""" + """The action type.""" url: Optional[str] """The URL opened by the model.""" diff --git a/tests/api_resources/admin/organization/groups/test_roles.py b/tests/api_resources/admin/organization/groups/test_roles.py index 08702fddd2..6f2235a468 100644 --- a/tests/api_resources/admin/organization/groups/test_roles.py +++ b/tests/api_resources/admin/organization/groups/test_roles.py @@ -14,6 +14,7 @@ RoleListResponse, RoleCreateResponse, RoleDeleteResponse, + RoleRetrieveResponse, ) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -64,6 +65,54 @@ def test_path_params_create(self, client: OpenAI) -> None: role_id="role_id", ) + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + role = client.admin.organization.groups.roles.retrieve( + role_id="role_id", + group_id="group_id", + ) + assert_matches_type(RoleRetrieveResponse, role, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.admin.organization.groups.roles.with_raw_response.retrieve( + role_id="role_id", + group_id="group_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(RoleRetrieveResponse, role, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.admin.organization.groups.roles.with_streaming_response.retrieve( + role_id="role_id", + group_id="group_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = response.parse() + assert_matches_type(RoleRetrieveResponse, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + client.admin.organization.groups.roles.with_raw_response.retrieve( + role_id="role_id", + group_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): + client.admin.organization.groups.roles.with_raw_response.retrieve( + role_id="", + group_id="group_id", + ) + @parametrize def test_method_list(self, client: OpenAI) -> None: role = client.admin.organization.groups.roles.list( @@ -208,6 +257,54 @@ async def test_path_params_create(self, async_client: AsyncOpenAI) -> None: role_id="role_id", ) + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.groups.roles.retrieve( + role_id="role_id", + group_id="group_id", + ) + assert_matches_type(RoleRetrieveResponse, role, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.groups.roles.with_raw_response.retrieve( + role_id="role_id", + group_id="group_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(RoleRetrieveResponse, role, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.groups.roles.with_streaming_response.retrieve( + role_id="role_id", + group_id="group_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = await response.parse() + assert_matches_type(RoleRetrieveResponse, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + await async_client.admin.organization.groups.roles.with_raw_response.retrieve( + role_id="role_id", + group_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): + await async_client.admin.organization.groups.roles.with_raw_response.retrieve( + role_id="", + group_id="group_id", + ) + @parametrize async def test_method_list(self, async_client: AsyncOpenAI) -> None: role = await async_client.admin.organization.groups.roles.list( diff --git a/tests/api_resources/admin/organization/groups/test_users.py b/tests/api_resources/admin/organization/groups/test_users.py index eda6be6bbf..5003db2ad1 100644 --- a/tests/api_resources/admin/organization/groups/test_users.py +++ b/tests/api_resources/admin/organization/groups/test_users.py @@ -13,6 +13,7 @@ from openai.types.admin.organization.groups import ( UserCreateResponse, UserDeleteResponse, + UserRetrieveResponse, OrganizationGroupUser, ) @@ -64,6 +65,54 @@ def test_path_params_create(self, client: OpenAI) -> None: user_id="user_id", ) + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + user = client.admin.organization.groups.users.retrieve( + user_id="user_id", + group_id="group_id", + ) + assert_matches_type(UserRetrieveResponse, user, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.admin.organization.groups.users.with_raw_response.retrieve( + user_id="user_id", + group_id="group_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(UserRetrieveResponse, user, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.admin.organization.groups.users.with_streaming_response.retrieve( + user_id="user_id", + group_id="group_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = response.parse() + assert_matches_type(UserRetrieveResponse, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + client.admin.organization.groups.users.with_raw_response.retrieve( + user_id="user_id", + group_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): + client.admin.organization.groups.users.with_raw_response.retrieve( + user_id="", + group_id="group_id", + ) + @parametrize def test_method_list(self, client: OpenAI) -> None: user = client.admin.organization.groups.users.list( @@ -208,6 +257,54 @@ async def test_path_params_create(self, async_client: AsyncOpenAI) -> None: user_id="user_id", ) + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + user = await async_client.admin.organization.groups.users.retrieve( + user_id="user_id", + group_id="group_id", + ) + assert_matches_type(UserRetrieveResponse, user, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.groups.users.with_raw_response.retrieve( + user_id="user_id", + group_id="group_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(UserRetrieveResponse, user, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.groups.users.with_streaming_response.retrieve( + user_id="user_id", + group_id="group_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = await response.parse() + assert_matches_type(UserRetrieveResponse, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + await async_client.admin.organization.groups.users.with_raw_response.retrieve( + user_id="user_id", + group_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): + await async_client.admin.organization.groups.users.with_raw_response.retrieve( + user_id="", + group_id="group_id", + ) + @parametrize async def test_method_list(self, async_client: AsyncOpenAI) -> None: user = await async_client.admin.organization.groups.users.list( diff --git a/tests/api_resources/admin/organization/projects/groups/test_roles.py b/tests/api_resources/admin/organization/projects/groups/test_roles.py index a129142ea9..4e62facc55 100644 --- a/tests/api_resources/admin/organization/projects/groups/test_roles.py +++ b/tests/api_resources/admin/organization/projects/groups/test_roles.py @@ -14,6 +14,7 @@ RoleListResponse, RoleCreateResponse, RoleDeleteResponse, + RoleRetrieveResponse, ) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -75,6 +76,66 @@ def test_path_params_create(self, client: OpenAI) -> None: role_id="role_id", ) + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + role = client.admin.organization.projects.groups.roles.retrieve( + role_id="role_id", + project_id="project_id", + group_id="group_id", + ) + assert_matches_type(RoleRetrieveResponse, role, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.admin.organization.projects.groups.roles.with_raw_response.retrieve( + role_id="role_id", + project_id="project_id", + group_id="group_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(RoleRetrieveResponse, role, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.admin.organization.projects.groups.roles.with_streaming_response.retrieve( + role_id="role_id", + project_id="project_id", + group_id="group_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = response.parse() + assert_matches_type(RoleRetrieveResponse, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.groups.roles.with_raw_response.retrieve( + role_id="role_id", + project_id="", + group_id="group_id", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + client.admin.organization.projects.groups.roles.with_raw_response.retrieve( + role_id="role_id", + project_id="project_id", + group_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): + client.admin.organization.projects.groups.roles.with_raw_response.retrieve( + role_id="", + project_id="project_id", + group_id="group_id", + ) + @parametrize def test_method_list(self, client: OpenAI) -> None: role = client.admin.organization.projects.groups.roles.list( @@ -253,6 +314,66 @@ async def test_path_params_create(self, async_client: AsyncOpenAI) -> None: role_id="role_id", ) + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.projects.groups.roles.retrieve( + role_id="role_id", + project_id="project_id", + group_id="group_id", + ) + assert_matches_type(RoleRetrieveResponse, role, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.groups.roles.with_raw_response.retrieve( + role_id="role_id", + project_id="project_id", + group_id="group_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(RoleRetrieveResponse, role, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.groups.roles.with_streaming_response.retrieve( + role_id="role_id", + project_id="project_id", + group_id="group_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = await response.parse() + assert_matches_type(RoleRetrieveResponse, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.groups.roles.with_raw_response.retrieve( + role_id="role_id", + project_id="", + group_id="group_id", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + await async_client.admin.organization.projects.groups.roles.with_raw_response.retrieve( + role_id="role_id", + project_id="project_id", + group_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): + await async_client.admin.organization.projects.groups.roles.with_raw_response.retrieve( + role_id="", + project_id="project_id", + group_id="group_id", + ) + @parametrize async def test_method_list(self, async_client: AsyncOpenAI) -> None: role = await async_client.admin.organization.projects.groups.roles.list( diff --git a/tests/api_resources/admin/organization/projects/test_data_retention.py b/tests/api_resources/admin/organization/projects/test_data_retention.py new file mode 100644 index 0000000000..d640e78e8d --- /dev/null +++ b/tests/api_resources/admin/organization/projects/test_data_retention.py @@ -0,0 +1,184 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.types.admin.organization.projects import ProjectDataRetention + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestDataRetention: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + data_retention = client.admin.organization.projects.data_retention.retrieve( + "project_id", + ) + assert_matches_type(ProjectDataRetention, data_retention, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.admin.organization.projects.data_retention.with_raw_response.retrieve( + "project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + data_retention = response.parse() + assert_matches_type(ProjectDataRetention, data_retention, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.admin.organization.projects.data_retention.with_streaming_response.retrieve( + "project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + data_retention = response.parse() + assert_matches_type(ProjectDataRetention, data_retention, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.data_retention.with_raw_response.retrieve( + "", + ) + + @parametrize + def test_method_update(self, client: OpenAI) -> None: + data_retention = client.admin.organization.projects.data_retention.update( + project_id="project_id", + retention_type="organization_default", + ) + assert_matches_type(ProjectDataRetention, data_retention, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: OpenAI) -> None: + response = client.admin.organization.projects.data_retention.with_raw_response.update( + project_id="project_id", + retention_type="organization_default", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + data_retention = response.parse() + assert_matches_type(ProjectDataRetention, data_retention, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: OpenAI) -> None: + with client.admin.organization.projects.data_retention.with_streaming_response.update( + project_id="project_id", + retention_type="organization_default", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + data_retention = response.parse() + assert_matches_type(ProjectDataRetention, data_retention, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.data_retention.with_raw_response.update( + project_id="", + retention_type="organization_default", + ) + + +class TestAsyncDataRetention: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + data_retention = await async_client.admin.organization.projects.data_retention.retrieve( + "project_id", + ) + assert_matches_type(ProjectDataRetention, data_retention, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.data_retention.with_raw_response.retrieve( + "project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + data_retention = response.parse() + assert_matches_type(ProjectDataRetention, data_retention, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.data_retention.with_streaming_response.retrieve( + "project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + data_retention = await response.parse() + assert_matches_type(ProjectDataRetention, data_retention, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.data_retention.with_raw_response.retrieve( + "", + ) + + @parametrize + async def test_method_update(self, async_client: AsyncOpenAI) -> None: + data_retention = await async_client.admin.organization.projects.data_retention.update( + project_id="project_id", + retention_type="organization_default", + ) + assert_matches_type(ProjectDataRetention, data_retention, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.data_retention.with_raw_response.update( + project_id="project_id", + retention_type="organization_default", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + data_retention = response.parse() + assert_matches_type(ProjectDataRetention, data_retention, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.data_retention.with_streaming_response.update( + project_id="project_id", + retention_type="organization_default", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + data_retention = await response.parse() + assert_matches_type(ProjectDataRetention, data_retention, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.data_retention.with_raw_response.update( + project_id="", + retention_type="organization_default", + ) diff --git a/tests/api_resources/admin/organization/projects/test_groups.py b/tests/api_resources/admin/organization/projects/test_groups.py index 2db448e9b2..46a68076df 100644 --- a/tests/api_resources/admin/organization/projects/test_groups.py +++ b/tests/api_resources/admin/organization/projects/test_groups.py @@ -67,6 +67,63 @@ def test_path_params_create(self, client: OpenAI) -> None: role="role", ) + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + group = client.admin.organization.projects.groups.retrieve( + group_id="group_id", + project_id="project_id", + ) + assert_matches_type(ProjectGroup, group, path=["response"]) + + @parametrize + def test_method_retrieve_with_all_params(self, client: OpenAI) -> None: + group = client.admin.organization.projects.groups.retrieve( + group_id="group_id", + project_id="project_id", + group_type="group", + ) + assert_matches_type(ProjectGroup, group, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.admin.organization.projects.groups.with_raw_response.retrieve( + group_id="group_id", + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + group = response.parse() + assert_matches_type(ProjectGroup, group, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.admin.organization.projects.groups.with_streaming_response.retrieve( + group_id="group_id", + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + group = response.parse() + assert_matches_type(ProjectGroup, group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.groups.with_raw_response.retrieve( + group_id="group_id", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + client.admin.organization.projects.groups.with_raw_response.retrieve( + group_id="", + project_id="project_id", + ) + @parametrize def test_method_list(self, client: OpenAI) -> None: group = client.admin.organization.projects.groups.list( @@ -215,6 +272,63 @@ async def test_path_params_create(self, async_client: AsyncOpenAI) -> None: role="role", ) + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + group = await async_client.admin.organization.projects.groups.retrieve( + group_id="group_id", + project_id="project_id", + ) + assert_matches_type(ProjectGroup, group, path=["response"]) + + @parametrize + async def test_method_retrieve_with_all_params(self, async_client: AsyncOpenAI) -> None: + group = await async_client.admin.organization.projects.groups.retrieve( + group_id="group_id", + project_id="project_id", + group_type="group", + ) + assert_matches_type(ProjectGroup, group, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.groups.with_raw_response.retrieve( + group_id="group_id", + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + group = response.parse() + assert_matches_type(ProjectGroup, group, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.groups.with_streaming_response.retrieve( + group_id="group_id", + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + group = await response.parse() + assert_matches_type(ProjectGroup, group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.groups.with_raw_response.retrieve( + group_id="group_id", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + await async_client.admin.organization.projects.groups.with_raw_response.retrieve( + group_id="", + project_id="project_id", + ) + @parametrize async def test_method_list(self, async_client: AsyncOpenAI) -> None: group = await async_client.admin.organization.projects.groups.list( diff --git a/tests/api_resources/admin/organization/projects/test_roles.py b/tests/api_resources/admin/organization/projects/test_roles.py index 8c78ea21b4..862ea1f412 100644 --- a/tests/api_resources/admin/organization/projects/test_roles.py +++ b/tests/api_resources/admin/organization/projects/test_roles.py @@ -77,6 +77,54 @@ def test_path_params_create(self, client: OpenAI) -> None: role_name="role_name", ) + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + role = client.admin.organization.projects.roles.retrieve( + role_id="role_id", + project_id="project_id", + ) + assert_matches_type(Role, role, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.admin.organization.projects.roles.with_raw_response.retrieve( + role_id="role_id", + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(Role, role, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.admin.organization.projects.roles.with_streaming_response.retrieve( + role_id="role_id", + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = response.parse() + assert_matches_type(Role, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.roles.with_raw_response.retrieve( + role_id="role_id", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): + client.admin.organization.projects.roles.with_raw_response.retrieve( + role_id="", + project_id="project_id", + ) + @parametrize def test_method_update(self, client: OpenAI) -> None: role = client.admin.organization.projects.roles.update( @@ -294,6 +342,54 @@ async def test_path_params_create(self, async_client: AsyncOpenAI) -> None: role_name="role_name", ) + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.projects.roles.retrieve( + role_id="role_id", + project_id="project_id", + ) + assert_matches_type(Role, role, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.roles.with_raw_response.retrieve( + role_id="role_id", + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(Role, role, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.roles.with_streaming_response.retrieve( + role_id="role_id", + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = await response.parse() + assert_matches_type(Role, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.roles.with_raw_response.retrieve( + role_id="role_id", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): + await async_client.admin.organization.projects.roles.with_raw_response.retrieve( + role_id="", + project_id="project_id", + ) + @parametrize async def test_method_update(self, async_client: AsyncOpenAI) -> None: role = await async_client.admin.organization.projects.roles.update( diff --git a/tests/api_resources/admin/organization/projects/test_service_accounts.py b/tests/api_resources/admin/organization/projects/test_service_accounts.py index 7c94283323..e8e68596a2 100644 --- a/tests/api_resources/admin/organization/projects/test_service_accounts.py +++ b/tests/api_resources/admin/organization/projects/test_service_accounts.py @@ -112,6 +112,64 @@ def test_path_params_retrieve(self, client: OpenAI) -> None: project_id="project_id", ) + @parametrize + def test_method_update(self, client: OpenAI) -> None: + service_account = client.admin.organization.projects.service_accounts.update( + service_account_id="service_account_id", + project_id="project_id", + ) + assert_matches_type(ProjectServiceAccount, service_account, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: OpenAI) -> None: + service_account = client.admin.organization.projects.service_accounts.update( + service_account_id="service_account_id", + project_id="project_id", + name="name", + role="member", + ) + assert_matches_type(ProjectServiceAccount, service_account, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: OpenAI) -> None: + response = client.admin.organization.projects.service_accounts.with_raw_response.update( + service_account_id="service_account_id", + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + service_account = response.parse() + assert_matches_type(ProjectServiceAccount, service_account, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: OpenAI) -> None: + with client.admin.organization.projects.service_accounts.with_streaming_response.update( + service_account_id="service_account_id", + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + service_account = response.parse() + assert_matches_type(ProjectServiceAccount, service_account, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.service_accounts.with_raw_response.update( + service_account_id="service_account_id", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `service_account_id` but received ''"): + client.admin.organization.projects.service_accounts.with_raw_response.update( + service_account_id="", + project_id="project_id", + ) + @parametrize def test_method_list(self, client: OpenAI) -> None: service_account = client.admin.organization.projects.service_accounts.list( @@ -303,6 +361,64 @@ async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: project_id="project_id", ) + @parametrize + async def test_method_update(self, async_client: AsyncOpenAI) -> None: + service_account = await async_client.admin.organization.projects.service_accounts.update( + service_account_id="service_account_id", + project_id="project_id", + ) + assert_matches_type(ProjectServiceAccount, service_account, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncOpenAI) -> None: + service_account = await async_client.admin.organization.projects.service_accounts.update( + service_account_id="service_account_id", + project_id="project_id", + name="name", + role="member", + ) + assert_matches_type(ProjectServiceAccount, service_account, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.service_accounts.with_raw_response.update( + service_account_id="service_account_id", + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + service_account = response.parse() + assert_matches_type(ProjectServiceAccount, service_account, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.service_accounts.with_streaming_response.update( + service_account_id="service_account_id", + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + service_account = await response.parse() + assert_matches_type(ProjectServiceAccount, service_account, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.service_accounts.with_raw_response.update( + service_account_id="service_account_id", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `service_account_id` but received ''"): + await async_client.admin.organization.projects.service_accounts.with_raw_response.update( + service_account_id="", + project_id="project_id", + ) + @parametrize async def test_method_list(self, async_client: AsyncOpenAI) -> None: service_account = await async_client.admin.organization.projects.service_accounts.list( diff --git a/tests/api_resources/admin/organization/projects/test_spend_alerts.py b/tests/api_resources/admin/organization/projects/test_spend_alerts.py new file mode 100644 index 0000000000..c763401af3 --- /dev/null +++ b/tests/api_resources/admin/organization/projects/test_spend_alerts.py @@ -0,0 +1,582 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.pagination import SyncConversationCursorPage, AsyncConversationCursorPage +from openai.types.admin.organization.projects import ( + ProjectSpendAlert, + ProjectSpendAlertDeleted, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestSpendAlerts: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: OpenAI) -> None: + spend_alert = client.admin.organization.projects.spend_alerts.create( + project_id="project_id", + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + }, + threshold_amount=0, + ) + assert_matches_type(ProjectSpendAlert, spend_alert, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: OpenAI) -> None: + spend_alert = client.admin.organization.projects.spend_alerts.create( + project_id="project_id", + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + "subject_prefix": "subject_prefix", + }, + threshold_amount=0, + ) + assert_matches_type(ProjectSpendAlert, spend_alert, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: OpenAI) -> None: + response = client.admin.organization.projects.spend_alerts.with_raw_response.create( + project_id="project_id", + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + }, + threshold_amount=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + spend_alert = response.parse() + assert_matches_type(ProjectSpendAlert, spend_alert, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: OpenAI) -> None: + with client.admin.organization.projects.spend_alerts.with_streaming_response.create( + project_id="project_id", + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + }, + threshold_amount=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + spend_alert = response.parse() + assert_matches_type(ProjectSpendAlert, spend_alert, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_create(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.spend_alerts.with_raw_response.create( + project_id="", + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + }, + threshold_amount=0, + ) + + @parametrize + def test_method_update(self, client: OpenAI) -> None: + spend_alert = client.admin.organization.projects.spend_alerts.update( + alert_id="alert_id", + project_id="project_id", + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + }, + threshold_amount=0, + ) + assert_matches_type(ProjectSpendAlert, spend_alert, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: OpenAI) -> None: + spend_alert = client.admin.organization.projects.spend_alerts.update( + alert_id="alert_id", + project_id="project_id", + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + "subject_prefix": "subject_prefix", + }, + threshold_amount=0, + ) + assert_matches_type(ProjectSpendAlert, spend_alert, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: OpenAI) -> None: + response = client.admin.organization.projects.spend_alerts.with_raw_response.update( + alert_id="alert_id", + project_id="project_id", + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + }, + threshold_amount=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + spend_alert = response.parse() + assert_matches_type(ProjectSpendAlert, spend_alert, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: OpenAI) -> None: + with client.admin.organization.projects.spend_alerts.with_streaming_response.update( + alert_id="alert_id", + project_id="project_id", + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + }, + threshold_amount=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + spend_alert = response.parse() + assert_matches_type(ProjectSpendAlert, spend_alert, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.spend_alerts.with_raw_response.update( + alert_id="alert_id", + project_id="", + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + }, + threshold_amount=0, + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `alert_id` but received ''"): + client.admin.organization.projects.spend_alerts.with_raw_response.update( + alert_id="", + project_id="project_id", + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + }, + threshold_amount=0, + ) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + spend_alert = client.admin.organization.projects.spend_alerts.list( + project_id="project_id", + ) + assert_matches_type(SyncConversationCursorPage[ProjectSpendAlert], spend_alert, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + spend_alert = client.admin.organization.projects.spend_alerts.list( + project_id="project_id", + after="after", + before="before", + limit=0, + order="asc", + ) + assert_matches_type(SyncConversationCursorPage[ProjectSpendAlert], spend_alert, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.admin.organization.projects.spend_alerts.with_raw_response.list( + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + spend_alert = response.parse() + assert_matches_type(SyncConversationCursorPage[ProjectSpendAlert], spend_alert, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.admin.organization.projects.spend_alerts.with_streaming_response.list( + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + spend_alert = response.parse() + assert_matches_type(SyncConversationCursorPage[ProjectSpendAlert], spend_alert, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.spend_alerts.with_raw_response.list( + project_id="", + ) + + @parametrize + def test_method_delete(self, client: OpenAI) -> None: + spend_alert = client.admin.organization.projects.spend_alerts.delete( + alert_id="alert_id", + project_id="project_id", + ) + assert_matches_type(ProjectSpendAlertDeleted, spend_alert, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: OpenAI) -> None: + response = client.admin.organization.projects.spend_alerts.with_raw_response.delete( + alert_id="alert_id", + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + spend_alert = response.parse() + assert_matches_type(ProjectSpendAlertDeleted, spend_alert, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: OpenAI) -> None: + with client.admin.organization.projects.spend_alerts.with_streaming_response.delete( + alert_id="alert_id", + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + spend_alert = response.parse() + assert_matches_type(ProjectSpendAlertDeleted, spend_alert, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.spend_alerts.with_raw_response.delete( + alert_id="alert_id", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `alert_id` but received ''"): + client.admin.organization.projects.spend_alerts.with_raw_response.delete( + alert_id="", + project_id="project_id", + ) + + +class TestAsyncSpendAlerts: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncOpenAI) -> None: + spend_alert = await async_client.admin.organization.projects.spend_alerts.create( + project_id="project_id", + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + }, + threshold_amount=0, + ) + assert_matches_type(ProjectSpendAlert, spend_alert, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: + spend_alert = await async_client.admin.organization.projects.spend_alerts.create( + project_id="project_id", + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + "subject_prefix": "subject_prefix", + }, + threshold_amount=0, + ) + assert_matches_type(ProjectSpendAlert, spend_alert, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.spend_alerts.with_raw_response.create( + project_id="project_id", + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + }, + threshold_amount=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + spend_alert = response.parse() + assert_matches_type(ProjectSpendAlert, spend_alert, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.spend_alerts.with_streaming_response.create( + project_id="project_id", + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + }, + threshold_amount=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + spend_alert = await response.parse() + assert_matches_type(ProjectSpendAlert, spend_alert, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.spend_alerts.with_raw_response.create( + project_id="", + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + }, + threshold_amount=0, + ) + + @parametrize + async def test_method_update(self, async_client: AsyncOpenAI) -> None: + spend_alert = await async_client.admin.organization.projects.spend_alerts.update( + alert_id="alert_id", + project_id="project_id", + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + }, + threshold_amount=0, + ) + assert_matches_type(ProjectSpendAlert, spend_alert, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncOpenAI) -> None: + spend_alert = await async_client.admin.organization.projects.spend_alerts.update( + alert_id="alert_id", + project_id="project_id", + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + "subject_prefix": "subject_prefix", + }, + threshold_amount=0, + ) + assert_matches_type(ProjectSpendAlert, spend_alert, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.spend_alerts.with_raw_response.update( + alert_id="alert_id", + project_id="project_id", + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + }, + threshold_amount=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + spend_alert = response.parse() + assert_matches_type(ProjectSpendAlert, spend_alert, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.spend_alerts.with_streaming_response.update( + alert_id="alert_id", + project_id="project_id", + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + }, + threshold_amount=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + spend_alert = await response.parse() + assert_matches_type(ProjectSpendAlert, spend_alert, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.spend_alerts.with_raw_response.update( + alert_id="alert_id", + project_id="", + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + }, + threshold_amount=0, + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `alert_id` but received ''"): + await async_client.admin.organization.projects.spend_alerts.with_raw_response.update( + alert_id="", + project_id="project_id", + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + }, + threshold_amount=0, + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + spend_alert = await async_client.admin.organization.projects.spend_alerts.list( + project_id="project_id", + ) + assert_matches_type(AsyncConversationCursorPage[ProjectSpendAlert], spend_alert, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + spend_alert = await async_client.admin.organization.projects.spend_alerts.list( + project_id="project_id", + after="after", + before="before", + limit=0, + order="asc", + ) + assert_matches_type(AsyncConversationCursorPage[ProjectSpendAlert], spend_alert, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.spend_alerts.with_raw_response.list( + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + spend_alert = response.parse() + assert_matches_type(AsyncConversationCursorPage[ProjectSpendAlert], spend_alert, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.spend_alerts.with_streaming_response.list( + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + spend_alert = await response.parse() + assert_matches_type(AsyncConversationCursorPage[ProjectSpendAlert], spend_alert, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.spend_alerts.with_raw_response.list( + project_id="", + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncOpenAI) -> None: + spend_alert = await async_client.admin.organization.projects.spend_alerts.delete( + alert_id="alert_id", + project_id="project_id", + ) + assert_matches_type(ProjectSpendAlertDeleted, spend_alert, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.spend_alerts.with_raw_response.delete( + alert_id="alert_id", + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + spend_alert = response.parse() + assert_matches_type(ProjectSpendAlertDeleted, spend_alert, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.spend_alerts.with_streaming_response.delete( + alert_id="alert_id", + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + spend_alert = await response.parse() + assert_matches_type(ProjectSpendAlertDeleted, spend_alert, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.spend_alerts.with_raw_response.delete( + alert_id="alert_id", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `alert_id` but received ''"): + await async_client.admin.organization.projects.spend_alerts.with_raw_response.delete( + alert_id="", + project_id="project_id", + ) diff --git a/tests/api_resources/admin/organization/projects/users/test_roles.py b/tests/api_resources/admin/organization/projects/users/test_roles.py index 99c52d494c..5212e5a59c 100644 --- a/tests/api_resources/admin/organization/projects/users/test_roles.py +++ b/tests/api_resources/admin/organization/projects/users/test_roles.py @@ -14,6 +14,7 @@ RoleListResponse, RoleCreateResponse, RoleDeleteResponse, + RoleRetrieveResponse, ) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -75,6 +76,66 @@ def test_path_params_create(self, client: OpenAI) -> None: role_id="role_id", ) + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + role = client.admin.organization.projects.users.roles.retrieve( + role_id="role_id", + project_id="project_id", + user_id="user_id", + ) + assert_matches_type(RoleRetrieveResponse, role, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.admin.organization.projects.users.roles.with_raw_response.retrieve( + role_id="role_id", + project_id="project_id", + user_id="user_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(RoleRetrieveResponse, role, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.admin.organization.projects.users.roles.with_streaming_response.retrieve( + role_id="role_id", + project_id="project_id", + user_id="user_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = response.parse() + assert_matches_type(RoleRetrieveResponse, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.users.roles.with_raw_response.retrieve( + role_id="role_id", + project_id="", + user_id="user_id", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): + client.admin.organization.projects.users.roles.with_raw_response.retrieve( + role_id="role_id", + project_id="project_id", + user_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): + client.admin.organization.projects.users.roles.with_raw_response.retrieve( + role_id="", + project_id="project_id", + user_id="user_id", + ) + @parametrize def test_method_list(self, client: OpenAI) -> None: role = client.admin.organization.projects.users.roles.list( @@ -253,6 +314,66 @@ async def test_path_params_create(self, async_client: AsyncOpenAI) -> None: role_id="role_id", ) + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.projects.users.roles.retrieve( + role_id="role_id", + project_id="project_id", + user_id="user_id", + ) + assert_matches_type(RoleRetrieveResponse, role, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.users.roles.with_raw_response.retrieve( + role_id="role_id", + project_id="project_id", + user_id="user_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(RoleRetrieveResponse, role, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.users.roles.with_streaming_response.retrieve( + role_id="role_id", + project_id="project_id", + user_id="user_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = await response.parse() + assert_matches_type(RoleRetrieveResponse, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.users.roles.with_raw_response.retrieve( + role_id="role_id", + project_id="", + user_id="user_id", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): + await async_client.admin.organization.projects.users.roles.with_raw_response.retrieve( + role_id="role_id", + project_id="project_id", + user_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): + await async_client.admin.organization.projects.users.roles.with_raw_response.retrieve( + role_id="", + project_id="project_id", + user_id="user_id", + ) + @parametrize async def test_method_list(self, async_client: AsyncOpenAI) -> None: role = await async_client.admin.organization.projects.users.roles.list( diff --git a/tests/api_resources/admin/organization/test_data_retention.py b/tests/api_resources/admin/organization/test_data_retention.py new file mode 100644 index 0000000000..8d943832e6 --- /dev/null +++ b/tests/api_resources/admin/organization/test_data_retention.py @@ -0,0 +1,136 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.types.admin.organization import OrganizationDataRetention + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestDataRetention: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + data_retention = client.admin.organization.data_retention.retrieve() + assert_matches_type(OrganizationDataRetention, data_retention, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.admin.organization.data_retention.with_raw_response.retrieve() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + data_retention = response.parse() + assert_matches_type(OrganizationDataRetention, data_retention, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.admin.organization.data_retention.with_streaming_response.retrieve() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + data_retention = response.parse() + assert_matches_type(OrganizationDataRetention, data_retention, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: OpenAI) -> None: + data_retention = client.admin.organization.data_retention.update( + retention_type="zero_data_retention", + ) + assert_matches_type(OrganizationDataRetention, data_retention, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: OpenAI) -> None: + response = client.admin.organization.data_retention.with_raw_response.update( + retention_type="zero_data_retention", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + data_retention = response.parse() + assert_matches_type(OrganizationDataRetention, data_retention, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: OpenAI) -> None: + with client.admin.organization.data_retention.with_streaming_response.update( + retention_type="zero_data_retention", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + data_retention = response.parse() + assert_matches_type(OrganizationDataRetention, data_retention, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncDataRetention: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + data_retention = await async_client.admin.organization.data_retention.retrieve() + assert_matches_type(OrganizationDataRetention, data_retention, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.data_retention.with_raw_response.retrieve() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + data_retention = response.parse() + assert_matches_type(OrganizationDataRetention, data_retention, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.data_retention.with_streaming_response.retrieve() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + data_retention = await response.parse() + assert_matches_type(OrganizationDataRetention, data_retention, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncOpenAI) -> None: + data_retention = await async_client.admin.organization.data_retention.update( + retention_type="zero_data_retention", + ) + assert_matches_type(OrganizationDataRetention, data_retention, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.data_retention.with_raw_response.update( + retention_type="zero_data_retention", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + data_retention = response.parse() + assert_matches_type(OrganizationDataRetention, data_retention, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.data_retention.with_streaming_response.update( + retention_type="zero_data_retention", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + data_retention = await response.parse() + assert_matches_type(OrganizationDataRetention, data_retention, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/admin/organization/test_groups.py b/tests/api_resources/admin/organization/test_groups.py index 0eca89f06c..d97ddf579e 100644 --- a/tests/api_resources/admin/organization/test_groups.py +++ b/tests/api_resources/admin/organization/test_groups.py @@ -53,6 +53,44 @@ def test_streaming_response_create(self, client: OpenAI) -> None: assert cast(Any, response.is_closed) is True + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + group = client.admin.organization.groups.retrieve( + "group_id", + ) + assert_matches_type(Group, group, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.admin.organization.groups.with_raw_response.retrieve( + "group_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + group = response.parse() + assert_matches_type(Group, group, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.admin.organization.groups.with_streaming_response.retrieve( + "group_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + group = response.parse() + assert_matches_type(Group, group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + client.admin.organization.groups.with_raw_response.retrieve( + "", + ) + @parametrize def test_method_update(self, client: OpenAI) -> None: group = client.admin.organization.groups.update( @@ -204,6 +242,44 @@ async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> Non assert cast(Any, response.is_closed) is True + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + group = await async_client.admin.organization.groups.retrieve( + "group_id", + ) + assert_matches_type(Group, group, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.groups.with_raw_response.retrieve( + "group_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + group = response.parse() + assert_matches_type(Group, group, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.groups.with_streaming_response.retrieve( + "group_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + group = await response.parse() + assert_matches_type(Group, group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + await async_client.admin.organization.groups.with_raw_response.retrieve( + "", + ) + @parametrize async def test_method_update(self, async_client: AsyncOpenAI) -> None: group = await async_client.admin.organization.groups.update( diff --git a/tests/api_resources/admin/organization/test_roles.py b/tests/api_resources/admin/organization/test_roles.py index ee70020c23..fbb8515f1c 100644 --- a/tests/api_resources/admin/organization/test_roles.py +++ b/tests/api_resources/admin/organization/test_roles.py @@ -64,6 +64,44 @@ def test_streaming_response_create(self, client: OpenAI) -> None: assert cast(Any, response.is_closed) is True + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + role = client.admin.organization.roles.retrieve( + "role_id", + ) + assert_matches_type(Role, role, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.admin.organization.roles.with_raw_response.retrieve( + "role_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(Role, role, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.admin.organization.roles.with_streaming_response.retrieve( + "role_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = response.parse() + assert_matches_type(Role, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): + client.admin.organization.roles.with_raw_response.retrieve( + "", + ) + @parametrize def test_method_update(self, client: OpenAI) -> None: role = client.admin.organization.roles.update( @@ -233,6 +271,44 @@ async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> Non assert cast(Any, response.is_closed) is True + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.roles.retrieve( + "role_id", + ) + assert_matches_type(Role, role, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.roles.with_raw_response.retrieve( + "role_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(Role, role, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.roles.with_streaming_response.retrieve( + "role_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = await response.parse() + assert_matches_type(Role, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): + await async_client.admin.organization.roles.with_raw_response.retrieve( + "", + ) + @parametrize async def test_method_update(self, async_client: AsyncOpenAI) -> None: role = await async_client.admin.organization.roles.update( diff --git a/tests/api_resources/admin/organization/test_spend_alerts.py b/tests/api_resources/admin/organization/test_spend_alerts.py new file mode 100644 index 0000000000..08a3c445c3 --- /dev/null +++ b/tests/api_resources/admin/organization/test_spend_alerts.py @@ -0,0 +1,462 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.pagination import SyncConversationCursorPage, AsyncConversationCursorPage +from openai.types.admin.organization import ( + OrganizationSpendAlert, + OrganizationSpendAlertDeleted, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestSpendAlerts: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: OpenAI) -> None: + spend_alert = client.admin.organization.spend_alerts.create( + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + }, + threshold_amount=0, + ) + assert_matches_type(OrganizationSpendAlert, spend_alert, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: OpenAI) -> None: + spend_alert = client.admin.organization.spend_alerts.create( + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + "subject_prefix": "subject_prefix", + }, + threshold_amount=0, + ) + assert_matches_type(OrganizationSpendAlert, spend_alert, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: OpenAI) -> None: + response = client.admin.organization.spend_alerts.with_raw_response.create( + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + }, + threshold_amount=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + spend_alert = response.parse() + assert_matches_type(OrganizationSpendAlert, spend_alert, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: OpenAI) -> None: + with client.admin.organization.spend_alerts.with_streaming_response.create( + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + }, + threshold_amount=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + spend_alert = response.parse() + assert_matches_type(OrganizationSpendAlert, spend_alert, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: OpenAI) -> None: + spend_alert = client.admin.organization.spend_alerts.update( + alert_id="alert_id", + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + }, + threshold_amount=0, + ) + assert_matches_type(OrganizationSpendAlert, spend_alert, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: OpenAI) -> None: + spend_alert = client.admin.organization.spend_alerts.update( + alert_id="alert_id", + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + "subject_prefix": "subject_prefix", + }, + threshold_amount=0, + ) + assert_matches_type(OrganizationSpendAlert, spend_alert, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: OpenAI) -> None: + response = client.admin.organization.spend_alerts.with_raw_response.update( + alert_id="alert_id", + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + }, + threshold_amount=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + spend_alert = response.parse() + assert_matches_type(OrganizationSpendAlert, spend_alert, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: OpenAI) -> None: + with client.admin.organization.spend_alerts.with_streaming_response.update( + alert_id="alert_id", + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + }, + threshold_amount=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + spend_alert = response.parse() + assert_matches_type(OrganizationSpendAlert, spend_alert, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `alert_id` but received ''"): + client.admin.organization.spend_alerts.with_raw_response.update( + alert_id="", + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + }, + threshold_amount=0, + ) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + spend_alert = client.admin.organization.spend_alerts.list() + assert_matches_type(SyncConversationCursorPage[OrganizationSpendAlert], spend_alert, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + spend_alert = client.admin.organization.spend_alerts.list( + after="after", + before="before", + limit=0, + order="asc", + ) + assert_matches_type(SyncConversationCursorPage[OrganizationSpendAlert], spend_alert, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.admin.organization.spend_alerts.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + spend_alert = response.parse() + assert_matches_type(SyncConversationCursorPage[OrganizationSpendAlert], spend_alert, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.admin.organization.spend_alerts.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + spend_alert = response.parse() + assert_matches_type(SyncConversationCursorPage[OrganizationSpendAlert], spend_alert, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: OpenAI) -> None: + spend_alert = client.admin.organization.spend_alerts.delete( + "alert_id", + ) + assert_matches_type(OrganizationSpendAlertDeleted, spend_alert, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: OpenAI) -> None: + response = client.admin.organization.spend_alerts.with_raw_response.delete( + "alert_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + spend_alert = response.parse() + assert_matches_type(OrganizationSpendAlertDeleted, spend_alert, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: OpenAI) -> None: + with client.admin.organization.spend_alerts.with_streaming_response.delete( + "alert_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + spend_alert = response.parse() + assert_matches_type(OrganizationSpendAlertDeleted, spend_alert, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `alert_id` but received ''"): + client.admin.organization.spend_alerts.with_raw_response.delete( + "", + ) + + +class TestAsyncSpendAlerts: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncOpenAI) -> None: + spend_alert = await async_client.admin.organization.spend_alerts.create( + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + }, + threshold_amount=0, + ) + assert_matches_type(OrganizationSpendAlert, spend_alert, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: + spend_alert = await async_client.admin.organization.spend_alerts.create( + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + "subject_prefix": "subject_prefix", + }, + threshold_amount=0, + ) + assert_matches_type(OrganizationSpendAlert, spend_alert, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.spend_alerts.with_raw_response.create( + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + }, + threshold_amount=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + spend_alert = response.parse() + assert_matches_type(OrganizationSpendAlert, spend_alert, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.spend_alerts.with_streaming_response.create( + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + }, + threshold_amount=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + spend_alert = await response.parse() + assert_matches_type(OrganizationSpendAlert, spend_alert, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncOpenAI) -> None: + spend_alert = await async_client.admin.organization.spend_alerts.update( + alert_id="alert_id", + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + }, + threshold_amount=0, + ) + assert_matches_type(OrganizationSpendAlert, spend_alert, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncOpenAI) -> None: + spend_alert = await async_client.admin.organization.spend_alerts.update( + alert_id="alert_id", + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + "subject_prefix": "subject_prefix", + }, + threshold_amount=0, + ) + assert_matches_type(OrganizationSpendAlert, spend_alert, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.spend_alerts.with_raw_response.update( + alert_id="alert_id", + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + }, + threshold_amount=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + spend_alert = response.parse() + assert_matches_type(OrganizationSpendAlert, spend_alert, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.spend_alerts.with_streaming_response.update( + alert_id="alert_id", + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + }, + threshold_amount=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + spend_alert = await response.parse() + assert_matches_type(OrganizationSpendAlert, spend_alert, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `alert_id` but received ''"): + await async_client.admin.organization.spend_alerts.with_raw_response.update( + alert_id="", + currency="USD", + interval="month", + notification_channel={ + "recipients": ["string"], + "type": "email", + }, + threshold_amount=0, + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + spend_alert = await async_client.admin.organization.spend_alerts.list() + assert_matches_type(AsyncConversationCursorPage[OrganizationSpendAlert], spend_alert, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + spend_alert = await async_client.admin.organization.spend_alerts.list( + after="after", + before="before", + limit=0, + order="asc", + ) + assert_matches_type(AsyncConversationCursorPage[OrganizationSpendAlert], spend_alert, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.spend_alerts.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + spend_alert = response.parse() + assert_matches_type(AsyncConversationCursorPage[OrganizationSpendAlert], spend_alert, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.spend_alerts.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + spend_alert = await response.parse() + assert_matches_type(AsyncConversationCursorPage[OrganizationSpendAlert], spend_alert, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncOpenAI) -> None: + spend_alert = await async_client.admin.organization.spend_alerts.delete( + "alert_id", + ) + assert_matches_type(OrganizationSpendAlertDeleted, spend_alert, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.spend_alerts.with_raw_response.delete( + "alert_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + spend_alert = response.parse() + assert_matches_type(OrganizationSpendAlertDeleted, spend_alert, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.spend_alerts.with_streaming_response.delete( + "alert_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + spend_alert = await response.parse() + assert_matches_type(OrganizationSpendAlertDeleted, spend_alert, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `alert_id` but received ''"): + await async_client.admin.organization.spend_alerts.with_raw_response.delete( + "", + ) diff --git a/tests/api_resources/admin/organization/users/test_roles.py b/tests/api_resources/admin/organization/users/test_roles.py index 2455a38cff..81247b2416 100644 --- a/tests/api_resources/admin/organization/users/test_roles.py +++ b/tests/api_resources/admin/organization/users/test_roles.py @@ -14,6 +14,7 @@ RoleListResponse, RoleCreateResponse, RoleDeleteResponse, + RoleRetrieveResponse, ) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -64,6 +65,54 @@ def test_path_params_create(self, client: OpenAI) -> None: role_id="role_id", ) + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + role = client.admin.organization.users.roles.retrieve( + role_id="role_id", + user_id="user_id", + ) + assert_matches_type(RoleRetrieveResponse, role, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.admin.organization.users.roles.with_raw_response.retrieve( + role_id="role_id", + user_id="user_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(RoleRetrieveResponse, role, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.admin.organization.users.roles.with_streaming_response.retrieve( + role_id="role_id", + user_id="user_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = response.parse() + assert_matches_type(RoleRetrieveResponse, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): + client.admin.organization.users.roles.with_raw_response.retrieve( + role_id="role_id", + user_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): + client.admin.organization.users.roles.with_raw_response.retrieve( + role_id="", + user_id="user_id", + ) + @parametrize def test_method_list(self, client: OpenAI) -> None: role = client.admin.organization.users.roles.list( @@ -208,6 +257,54 @@ async def test_path_params_create(self, async_client: AsyncOpenAI) -> None: role_id="role_id", ) + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + role = await async_client.admin.organization.users.roles.retrieve( + role_id="role_id", + user_id="user_id", + ) + assert_matches_type(RoleRetrieveResponse, role, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.users.roles.with_raw_response.retrieve( + role_id="role_id", + user_id="user_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role = response.parse() + assert_matches_type(RoleRetrieveResponse, role, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.users.roles.with_streaming_response.retrieve( + role_id="role_id", + user_id="user_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role = await response.parse() + assert_matches_type(RoleRetrieveResponse, role, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"): + await async_client.admin.organization.users.roles.with_raw_response.retrieve( + role_id="role_id", + user_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): + await async_client.admin.organization.users.roles.with_raw_response.retrieve( + role_id="", + user_id="user_id", + ) + @parametrize async def test_method_list(self, async_client: AsyncOpenAI) -> None: role = await async_client.admin.organization.users.roles.list( From e75766769547601a25ed83b666c4d0fd046881f0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 21 May 2026 17:00:15 +0000 Subject: [PATCH 757/769] release: 2.38.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 18 ++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 28c811f943..0e1c697558 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.37.0" + ".": "2.38.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 803d3d3a39..b4f9d758d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ # Changelog +## 2.38.0 (2026-05-21) + +Full Changelog: [v2.37.0...v2.38.0](https://github.com/openai/openai-python/compare/v2.37.0...v2.38.0) + +### Features + +* **api:** api update ([33d1d01](https://github.com/openai/openai-python/commit/33d1d013250053886a73d178136e6bd1b09df059)) +* **api:** manual updates ([a21700a](https://github.com/openai/openai-python/commit/a21700a2cd510cb9e6c88065ac8e942d4c041aa8)) +* **api:** update OpenAPI spec or Stainless config ([00265c5](https://github.com/openai/openai-python/commit/00265c5daba4d2481452ad35220f1556dab6bcf6)) + + +### Chores + +* **api:** docs updates ([ee10152](https://github.com/openai/openai-python/commit/ee101520d49e22c09cf8096f8cbb3848ea58a1f9)) +* check release PR custom code sync ([2638779](https://github.com/openai/openai-python/commit/2638779a5b8fffaa8fdb6eebc1d734f15d2491f8)) +* remove release automation trigger ([bd6eea5](https://github.com/openai/openai-python/commit/bd6eea559f2996d914258a65e645981bdce3cad4)) +* trigger release automation ([f62d082](https://github.com/openai/openai-python/commit/f62d08201eea8e08d4bb3385662f934d4adccb29)) + ## 2.37.0 (2026-05-13) Full Changelog: [v2.36.0...v2.37.0](https://github.com/openai/openai-python/compare/v2.36.0...v2.37.0) diff --git a/pyproject.toml b/pyproject.toml index 452ac3125a..aedb6d8f51 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.37.0" +version = "2.38.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 43d6a12d19..ba9c5f3a3c 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__ = "2.37.0" # x-release-please-version +__version__ = "2.38.0" # x-release-please-version From 8be32d38e1eaf43ee32639eb4f8c9090f4f707f5 Mon Sep 17 00:00:00 2001 From: Jim Blomo Date: Thu, 28 May 2026 16:35:20 -0700 Subject: [PATCH 758/769] [codex] Add Amazon Bedrock provider support --- README.md | 31 +++ examples/bedrock.py | 13 ++ src/openai/__init__.py | 42 +++- src/openai/lib/bedrock.py | 417 ++++++++++++++++++++++++++++++++++ tests/lib/test_bedrock.py | 439 ++++++++++++++++++++++++++++++++++++ tests/test_module_client.py | 64 ++++++ 6 files changed, 1003 insertions(+), 3 deletions(-) create mode 100644 examples/bedrock.py create mode 100644 src/openai/lib/bedrock.py create mode 100644 tests/lib/test_bedrock.py diff --git a/README.md b/README.md index 7af6143c88..6f87246470 100644 --- a/README.md +++ b/README.md @@ -926,6 +926,37 @@ In addition to the options provided in the base `OpenAI` client, the following o An example of using the client with Microsoft Entra ID (formerly known as Azure Active Directory) can be found [here](https://github.com/openai/openai-python/blob/main/examples/azure_ad.py). +## Amazon Bedrock + +To use this library with [Amazon Bedrock's OpenAI-compatible API](https://docs.aws.amazon.com/bedrock/latest/userguide/models-api-compatibility.html), use the `BedrockOpenAI` class instead of the `OpenAI` class. + +```py +from openai import BedrockOpenAI + +# gets the bearer token from AWS_BEARER_TOKEN_BEDROCK and the region from AWS_REGION/AWS_DEFAULT_REGION +client = BedrockOpenAI() + +response = client.responses.create( + model="openai.gpt-5.4", + input="Say hello!", +) + +print(response.output_text) +``` + +`BedrockOpenAI` configures AWS bearer auth and the Bedrock Mantle endpoint, then uses the normal SDK resources. AWS controls which endpoints and features are supported; unsupported calls surface the provider's normal HTTP errors through the SDK. + +Pass `base_url` or set `AWS_BEDROCK_BASE_URL` to override the derived `https://bedrock-mantle..api.aws/openai/v1` endpoint. The legacy module client supports `openai.api_type = "amazon-bedrock"` or `OPENAI_API_TYPE=amazon-bedrock`. + +Set `AWS_BEARER_TOKEN_BEDROCK` to an [Amazon Bedrock API key](https://docs.aws.amazon.com/bedrock/latest/userguide/api-keys.html). To refresh tokens yourself, pass a provider instead of `api_key`: + +```py +client = BedrockOpenAI( + aws_region="us-west-2", + bedrock_token_provider=lambda: refresh_bedrock_token(), +) +``` + ## Versioning This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions: diff --git a/examples/bedrock.py b/examples/bedrock.py new file mode 100644 index 0000000000..24dafb5b80 --- /dev/null +++ b/examples/bedrock.py @@ -0,0 +1,13 @@ +from openai import BedrockOpenAI + +client = BedrockOpenAI() + +# For refreshed Bedrock bearer tokens: +# client = BedrockOpenAI(aws_region="us-west-2", bedrock_token_provider=get_bedrock_token) + +response = client.responses.create( + model="openai.gpt-5.4", + input="Say hello!", +) + +print(response.output_text) diff --git a/src/openai/__init__.py b/src/openai/__init__.py index cbaef0615f..8d4265970e 100644 --- a/src/openai/__init__.py +++ b/src/openai/__init__.py @@ -79,6 +79,8 @@ "AsyncStream", "OpenAI", "AsyncOpenAI", + "BedrockOpenAI", + "AsyncBedrockOpenAI", "file_from_path", "BaseModel", "DEFAULT_TIMEOUT", @@ -96,9 +98,10 @@ if not _t.TYPE_CHECKING: from ._utils._resources_proxy import resources as resources -from .lib import azure as _azure, pydantic_function_tool as pydantic_function_tool +from .lib import azure as _azure, bedrock as _bedrock, pydantic_function_tool as pydantic_function_tool from .version import VERSION as VERSION from .lib.azure import AzureOpenAI as AzureOpenAI, AsyncAzureOpenAI as AsyncAzureOpenAI +from .lib.bedrock import BedrockOpenAI as BedrockOpenAI, AsyncBedrockOpenAI as AsyncBedrockOpenAI from .lib._old_api import * from .lib.streaming import ( AssistantEventHandler as AssistantEventHandler, @@ -150,7 +153,7 @@ http_client: _httpx.Client | None = None -_ApiType = _te.Literal["openai", "azure"] +_ApiType = _te.Literal["openai", "azure", "amazon-bedrock"] api_type: _ApiType | None = _t.cast(_ApiType, _os.environ.get("OPENAI_API_TYPE")) @@ -162,6 +165,10 @@ azure_ad_token_provider: _azure.AzureADTokenProvider | None = None +_bedrock_api_key: str | None = None + +bedrock_token_provider: _bedrock.BedrockTokenProvider | None = None + class _ModuleClient(OpenAI): # Note: we have to use type: ignores here as overriding class members @@ -294,10 +301,23 @@ class _AzureModuleClient(_ModuleClient, AzureOpenAI): # type: ignore ... +class _BedrockModuleClient(_ModuleClient, BedrockOpenAI): # type: ignore + @property # type: ignore + @override + def api_key(self) -> str | None: + return _bedrock_api_key if _bedrock_api_key is not None else api_key + + @api_key.setter # type: ignore + def api_key(self, value: str | None) -> None: # type: ignore + global _bedrock_api_key + + _bedrock_api_key = value + + class _AmbiguousModuleClientUsageError(OpenAIError): def __init__(self) -> None: super().__init__( - "Ambiguous use of module client; please set `openai.api_type` or the `OPENAI_API_TYPE` environment variable to `openai` or `azure`" + "Ambiguous use of module client; please set `openai.api_type` or the `OPENAI_API_TYPE` environment variable to `openai`, `azure`, or `amazon-bedrock`" ) @@ -370,6 +390,22 @@ def _load_client() -> OpenAI: # type: ignore[reportUnusedFunction] ) return _client + if api_type == "amazon-bedrock": + _client = _BedrockModuleClient( # type: ignore + api_key=api_key, + bedrock_token_provider=bedrock_token_provider, + organization=organization, + project=project, + webhook_secret=webhook_secret, + base_url=base_url, + timeout=timeout, + max_retries=max_retries, + default_headers=default_headers, + default_query=default_query, + http_client=http_client, + ) + return _client + _client = _ModuleClient( api_key=api_key, admin_api_key=admin_api_key, diff --git a/src/openai/lib/bedrock.py b/src/openai/lib/bedrock.py new file mode 100644 index 0000000000..0a1aec36ee --- /dev/null +++ b/src/openai/lib/bedrock.py @@ -0,0 +1,417 @@ +from __future__ import annotations + +import os +import re +import inspect +from typing import Any, Mapping, Callable, Awaitable, cast +from typing_extensions import Self, override + +import httpx + +from ..auth import WorkloadIdentity +from .._types import NOT_GIVEN, Timeout, NotGiven +from .._utils import is_given +from .._client import OpenAI, AsyncOpenAI +from .._models import SecurityOptions, FinalRequestOptions +from .._exceptions import OpenAIError +from .._base_client import DEFAULT_MAX_RETRIES + +BedrockTokenProvider = Callable[[], str] +AsyncBedrockTokenProvider = Callable[[], "str | Awaitable[str]"] + + +def _normalize_bedrock_base_url(base_url: str | httpx.URL) -> httpx.URL: + """Normalize a Bedrock Responses URL variant back to the provider API root.""" + url = httpx.URL(base_url) + path = url.path.rstrip("/") + responses_match = re.search(r"/responses(?:/.*)?$", path) + if responses_match is not None: + path = path[: responses_match.start()] + + return url.copy_with(path=path or "/") + + +def _resolve_bedrock_base_url(base_url: str | httpx.URL | None, aws_region: str | None) -> httpx.URL: + """Resolve Bedrock base URL precedence from explicit, env, then region config.""" + if isinstance(base_url, str) and not base_url.strip(): + base_url = None + + if base_url is None: + env_base_url = os.environ.get("AWS_BEDROCK_BASE_URL") + if env_base_url is not None and env_base_url.strip(): + base_url = env_base_url + + if base_url is None: + region = aws_region or os.environ.get("AWS_REGION") or os.environ.get("AWS_DEFAULT_REGION") + if region is None or not region.strip(): + raise OpenAIError( + "Must provide one of the `base_url` or `aws_region` arguments, or set the " + "`AWS_BEDROCK_BASE_URL`, `AWS_REGION`, or `AWS_DEFAULT_REGION` environment variable." + ) + + base_url = f"https://bedrock-mantle.{region}.api.aws/openai/v1" + + return _normalize_bedrock_base_url(base_url) + + +def _bedrock_token_provider(provider: BedrockTokenProvider) -> BedrockTokenProvider: + """Adapt a sync Bedrock token provider to the base client's api_key callback.""" + + def get_token() -> str: + token = cast(object, provider()) + if not isinstance(token, str) or not token: + raise ValueError(f"Expected `bedrock_token_provider` argument to return a string but it returned {token}") + + return token + + return get_token + + +def _async_bedrock_token_provider(provider: AsyncBedrockTokenProvider) -> Callable[[], Awaitable[str]]: + """Adapt a sync or async Bedrock token provider to the async api_key callback.""" + + async def get_token() -> str: + token = cast(object, provider()) + if inspect.isawaitable(token): + token = await token + + if not isinstance(token, str) or not token: + raise ValueError(f"Expected `bedrock_token_provider` argument to return a string but it returned {token}") + + return token + + return get_token + + +class BedrockOpenAI(OpenAI): + """API client for Amazon Bedrock's OpenAI-compatible endpoint.""" + + _bedrock_token_provider: BedrockTokenProvider | None + aws_region: str | None + + def __init__( + self, + *, + api_key: str | None = None, + bedrock_token_provider: BedrockTokenProvider | None = None, + aws_region: str | None = None, + organization: str | None = None, + project: str | None = None, + webhook_secret: str | None = None, + base_url: str | httpx.URL | None = None, + websocket_base_url: str | httpx.URL | None = None, + timeout: float | Timeout | None | NotGiven = NOT_GIVEN, + max_retries: int = DEFAULT_MAX_RETRIES, + default_headers: Mapping[str, str] | None = None, + default_query: Mapping[str, object] | None = None, + http_client: httpx.Client | None = None, + _strict_response_validation: bool = False, + _enforce_credentials: bool = True, + ) -> None: + """Construct a new synchronous Amazon Bedrock client instance. + + This automatically infers the following arguments from their corresponding environment variables if they are not provided: + - `api_key` from `AWS_BEARER_TOKEN_BEDROCK` + - `aws_region` from `AWS_REGION` or `AWS_DEFAULT_REGION` when `base_url` and `AWS_BEDROCK_BASE_URL` are not set + - `base_url` from `AWS_BEDROCK_BASE_URL` + + `bedrock_token_provider` is invoked before each request when provided. + """ + if api_key is None and bedrock_token_provider is None: + api_key = os.environ.get("AWS_BEARER_TOKEN_BEDROCK") + + if callable(cast(object, api_key)): + raise OpenAIError("Pass refreshable Bedrock credentials via `bedrock_token_provider`, not `api_key`.") + + if api_key is not None and bedrock_token_provider is not None: + raise OpenAIError("The `api_key` and `bedrock_token_provider` arguments are mutually exclusive.") + + if _enforce_credentials and not api_key and bedrock_token_provider is None: + raise OpenAIError( + "Missing credentials. Please pass an `api_key` or `bedrock_token_provider`, or set the " + "`AWS_BEARER_TOKEN_BEDROCK` environment variable." + ) + + self._bedrock_token_provider = bedrock_token_provider + self.aws_region = aws_region + + super().__init__( + api_key=_bedrock_token_provider(bedrock_token_provider) + if bedrock_token_provider is not None + else api_key or "", + admin_api_key="", + organization=organization, + project=project, + webhook_secret=webhook_secret, + base_url=_resolve_bedrock_base_url(base_url, aws_region), + websocket_base_url=websocket_base_url, + timeout=timeout, + max_retries=max_retries, + default_headers=default_headers, + default_query=default_query, + http_client=http_client, + _strict_response_validation=_strict_response_validation, + _enforce_credentials=False, + ) + + @override + def _auth_headers(self, security: SecurityOptions) -> dict[str, str]: + if security.get("bearer_auth", False) or security.get("admin_api_key_auth", False): + return self._bearer_auth + + return {} + + @override + def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOptions: + if ( + self._api_key_provider is not None + and options.security.get("admin_api_key_auth", False) + and not options.security.get("bearer_auth", False) + ): + self._refresh_api_key() + + return super()._prepare_options(options) + + @override + def copy( + self, + *, + api_key: str | BedrockTokenProvider | None = None, + admin_api_key: str | None = None, + workload_identity: WorkloadIdentity | None = None, + bedrock_token_provider: BedrockTokenProvider | None = None, + aws_region: str | None = None, + organization: str | None = None, + project: str | None = None, + webhook_secret: str | None = None, + websocket_base_url: str | httpx.URL | None = None, + base_url: str | httpx.URL | None = None, + timeout: float | Timeout | None | NotGiven = NOT_GIVEN, + http_client: httpx.Client | None = None, + max_retries: int | NotGiven = NOT_GIVEN, + default_headers: Mapping[str, str] | None = None, + set_default_headers: Mapping[str, str] | None = None, + default_query: Mapping[str, object] | None = None, + set_default_query: Mapping[str, object] | None = None, + _enforce_credentials: bool | None = None, + _extra_kwargs: Mapping[str, Any] = {}, + ) -> Self: + if default_headers is not None and set_default_headers is not None: + raise ValueError("The `default_headers` and `set_default_headers` arguments are mutually exclusive") + + if default_query is not None and set_default_query is not None: + raise ValueError("The `default_query` and `set_default_query` arguments are mutually exclusive") + + if callable(api_key): + raise OpenAIError("Pass refreshable Bedrock credentials via `bedrock_token_provider`, not `api_key`.") + + if admin_api_key is not None or workload_identity is not None: + raise OpenAIError("BedrockOpenAI only supports Bedrock bearer token authentication.") + + if api_key is not None and bedrock_token_provider is not None: + raise OpenAIError("The `api_key` and `bedrock_token_provider` arguments are mutually exclusive.") + + headers = self._custom_headers + if default_headers is not None: + headers = {**headers, **default_headers} + elif set_default_headers is not None: + headers = set_default_headers + + params = self._custom_query + if default_query is not None: + params = {**params, **default_query} + elif set_default_query is not None: + params = set_default_query + + next_token_provider = ( + bedrock_token_provider if bedrock_token_provider is not None else self._bedrock_token_provider + ) + next_api_key = api_key if api_key is not None else (None if next_token_provider is not None else self.api_key) + + return self.__class__( + api_key=next_api_key, + bedrock_token_provider=next_token_provider, + aws_region=aws_region if aws_region is not None else self.aws_region, + organization=organization if organization is not None else self.organization, + project=project if project is not None else self.project, + webhook_secret=webhook_secret if webhook_secret is not None else self.webhook_secret, + websocket_base_url=websocket_base_url if websocket_base_url is not None else self.websocket_base_url, + base_url=base_url if base_url is not None else self.base_url, + timeout=self.timeout if isinstance(timeout, NotGiven) else timeout, + http_client=http_client or self._client, + max_retries=max_retries if is_given(max_retries) else self.max_retries, + default_headers=headers, + default_query=params, + _enforce_credentials=True if _enforce_credentials is None else _enforce_credentials, + **_extra_kwargs, + ) + + with_options = copy + + +class AsyncBedrockOpenAI(AsyncOpenAI): + """Async API client for Amazon Bedrock's OpenAI-compatible endpoint.""" + + _bedrock_token_provider: AsyncBedrockTokenProvider | None + aws_region: str | None + + def __init__( + self, + *, + api_key: str | None = None, + bedrock_token_provider: AsyncBedrockTokenProvider | None = None, + aws_region: str | None = None, + organization: str | None = None, + project: str | None = None, + webhook_secret: str | None = None, + base_url: str | httpx.URL | None = None, + websocket_base_url: str | httpx.URL | None = None, + timeout: float | Timeout | None | NotGiven = NOT_GIVEN, + max_retries: int = DEFAULT_MAX_RETRIES, + default_headers: Mapping[str, str] | None = None, + default_query: Mapping[str, object] | None = None, + http_client: httpx.AsyncClient | None = None, + _strict_response_validation: bool = False, + _enforce_credentials: bool = True, + ) -> None: + """Construct a new asynchronous Amazon Bedrock client instance. + + This automatically infers the following arguments from their corresponding environment variables if they are not provided: + - `api_key` from `AWS_BEARER_TOKEN_BEDROCK` + - `aws_region` from `AWS_REGION` or `AWS_DEFAULT_REGION` when `base_url` and `AWS_BEDROCK_BASE_URL` are not set + - `base_url` from `AWS_BEDROCK_BASE_URL` + + `bedrock_token_provider` is invoked before each request when provided. + """ + if api_key is None and bedrock_token_provider is None: + api_key = os.environ.get("AWS_BEARER_TOKEN_BEDROCK") + + if callable(cast(object, api_key)): + raise OpenAIError("Pass refreshable Bedrock credentials via `bedrock_token_provider`, not `api_key`.") + + if api_key is not None and bedrock_token_provider is not None: + raise OpenAIError("The `api_key` and `bedrock_token_provider` arguments are mutually exclusive.") + + if _enforce_credentials and not api_key and bedrock_token_provider is None: + raise OpenAIError( + "Missing credentials. Please pass an `api_key` or `bedrock_token_provider`, or set the " + "`AWS_BEARER_TOKEN_BEDROCK` environment variable." + ) + + self._bedrock_token_provider = bedrock_token_provider + self.aws_region = aws_region + + super().__init__( + api_key=( + _async_bedrock_token_provider(bedrock_token_provider) + if bedrock_token_provider is not None + else api_key or "" + ), + admin_api_key="", + organization=organization, + project=project, + webhook_secret=webhook_secret, + base_url=_resolve_bedrock_base_url(base_url, aws_region), + websocket_base_url=websocket_base_url, + timeout=timeout, + max_retries=max_retries, + default_headers=default_headers, + default_query=default_query, + http_client=http_client, + _strict_response_validation=_strict_response_validation, + _enforce_credentials=False, + ) + + @override + def _auth_headers(self, security: SecurityOptions) -> dict[str, str]: + if security.get("bearer_auth", False) or security.get("admin_api_key_auth", False): + return self._bearer_auth + + return {} + + @override + async def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOptions: + if ( + self._api_key_provider is not None + and options.security.get("admin_api_key_auth", False) + and not options.security.get("bearer_auth", False) + ): + await self._refresh_api_key() + + return await super()._prepare_options(options) + + @override + def copy( + self, + *, + api_key: str | AsyncBedrockTokenProvider | None = None, + admin_api_key: str | None = None, + workload_identity: WorkloadIdentity | None = None, + bedrock_token_provider: AsyncBedrockTokenProvider | None = None, + aws_region: str | None = None, + organization: str | None = None, + project: str | None = None, + webhook_secret: str | None = None, + websocket_base_url: str | httpx.URL | None = None, + base_url: str | httpx.URL | None = None, + timeout: float | Timeout | None | NotGiven = NOT_GIVEN, + http_client: httpx.AsyncClient | None = None, + max_retries: int | NotGiven = NOT_GIVEN, + default_headers: Mapping[str, str] | None = None, + set_default_headers: Mapping[str, str] | None = None, + default_query: Mapping[str, object] | None = None, + set_default_query: Mapping[str, object] | None = None, + _enforce_credentials: bool | None = None, + _extra_kwargs: Mapping[str, Any] = {}, + ) -> Self: + if default_headers is not None and set_default_headers is not None: + raise ValueError("The `default_headers` and `set_default_headers` arguments are mutually exclusive") + + if default_query is not None and set_default_query is not None: + raise ValueError("The `default_query` and `set_default_query` arguments are mutually exclusive") + + if callable(api_key): + raise OpenAIError("Pass refreshable Bedrock credentials via `bedrock_token_provider`, not `api_key`.") + + if admin_api_key is not None or workload_identity is not None: + raise OpenAIError("AsyncBedrockOpenAI only supports Bedrock bearer token authentication.") + + if api_key is not None and bedrock_token_provider is not None: + raise OpenAIError("The `api_key` and `bedrock_token_provider` arguments are mutually exclusive.") + + headers = self._custom_headers + if default_headers is not None: + headers = {**headers, **default_headers} + elif set_default_headers is not None: + headers = set_default_headers + + params = self._custom_query + if default_query is not None: + params = {**params, **default_query} + elif set_default_query is not None: + params = set_default_query + + next_token_provider = ( + bedrock_token_provider if bedrock_token_provider is not None else self._bedrock_token_provider + ) + next_api_key = api_key if api_key is not None else (None if next_token_provider is not None else self.api_key) + + return self.__class__( + api_key=next_api_key, + bedrock_token_provider=next_token_provider, + aws_region=aws_region if aws_region is not None else self.aws_region, + organization=organization if organization is not None else self.organization, + project=project if project is not None else self.project, + webhook_secret=webhook_secret if webhook_secret is not None else self.webhook_secret, + websocket_base_url=websocket_base_url if websocket_base_url is not None else self.websocket_base_url, + base_url=base_url if base_url is not None else self.base_url, + timeout=self.timeout if isinstance(timeout, NotGiven) else timeout, + http_client=http_client or self._client, + max_retries=max_retries if is_given(max_retries) else self.max_retries, + default_headers=headers, + default_query=params, + _enforce_credentials=True if _enforce_credentials is None else _enforce_credentials, + **_extra_kwargs, + ) + + with_options = copy diff --git a/tests/lib/test_bedrock.py b/tests/lib/test_bedrock.py new file mode 100644 index 0000000000..9995e4c431 --- /dev/null +++ b/tests/lib/test_bedrock.py @@ -0,0 +1,439 @@ +from __future__ import annotations + +import json +from typing import Any, Union, Protocol, cast + +import httpx +import pytest +from httpx import URL +from respx import MockRouter + +from openai import OpenAIError, NotFoundError +from tests.utils import update_env +from openai._types import Omit +from openai.lib.bedrock import BedrockOpenAI, AsyncBedrockOpenAI + +Client = Union[BedrockOpenAI, AsyncBedrockOpenAI] + +RESPONSE_BODY: dict[str, Any] = { + "id": "resp_123", + "object": "response", + "created_at": 0, + "status": "completed", + "background": False, + "error": None, + "incomplete_details": None, + "instructions": None, + "max_output_tokens": None, + "max_tool_calls": None, + "model": "gpt-4o", + "output": [], + "parallel_tool_calls": True, + "previous_response_id": None, + "prompt_cache_key": None, + "reasoning": {"effort": None, "summary": None}, + "safety_identifier": None, + "service_tier": "default", + "store": True, + "temperature": 1.0, + "text": {"format": {"type": "text"}, "verbosity": "medium"}, + "tool_choice": "auto", + "tools": [], + "top_logprobs": 0, + "top_p": 1.0, + "truncation": "disabled", + "usage": { + "input_tokens": 0, + "input_tokens_details": {"cached_tokens": 0}, + "output_tokens": 0, + "output_tokens_details": {"reasoning_tokens": 0}, + "total_tokens": 0, + }, + "user": None, + "metadata": {}, +} +COMPACTED_RESPONSE_BODY: dict[str, Any] = { + "id": "resp_123", + "created_at": 0, + "object": "response.compaction", + "output": [], + "usage": RESPONSE_BODY["usage"], +} +INPUT_ITEMS_BODY: dict[str, Any] = { + "object": "list", + "data": [], + "first_id": "item_123", + "last_id": "item_123", + "has_more": False, +} +INPUT_TOKENS_BODY: dict[str, Any] = { + "object": "response.input_tokens", + "input_tokens": 1, +} + + +class MockRequestCall(Protocol): + request: httpx.Request + + +def make_sync_client(**kwargs: Any) -> BedrockOpenAI: + return BedrockOpenAI(http_client=httpx.Client(trust_env=False), **kwargs) + + +def make_async_client(**kwargs: Any) -> AsyncBedrockOpenAI: + return AsyncBedrockOpenAI(http_client=httpx.AsyncClient(trust_env=False), **kwargs) + + +def response_created_sse() -> str: + event: dict[str, Any] = {"type": "response.created", "sequence_number": 0, "response": RESPONSE_BODY} + return f"event: response.created\ndata: {json.dumps(event)}\n\n" + + +@pytest.mark.parametrize("client_cls", [BedrockOpenAI, AsyncBedrockOpenAI]) +def test_region_derived_base_url(client_cls: type[Client]) -> None: + with update_env(AWS_BEDROCK_BASE_URL=Omit(), AWS_REGION="us-east-1", AWS_DEFAULT_REGION=Omit()): + client = ( + make_sync_client(api_key="token") if client_cls is BedrockOpenAI else make_async_client(api_key="token") + ) + + assert client.base_url == URL("https://bedrock-mantle.us-east-1.api.aws/openai/v1/") + + +@pytest.mark.parametrize("client_cls", [BedrockOpenAI, AsyncBedrockOpenAI]) +def test_bedrock_config_precedence(client_cls: type[Client]) -> None: + with update_env( + AWS_BEDROCK_BASE_URL="https://env.example.com/openai/v1", + AWS_BEARER_TOKEN_BEDROCK="env token", + AWS_REGION="us-east-1", + AWS_DEFAULT_REGION="us-west-2", + ): + client = ( + make_sync_client( + base_url="https://explicit.example.com/openai/v1/responses", + api_key="explicit token", + ) + if client_cls is BedrockOpenAI + else make_async_client( + base_url="https://explicit.example.com/openai/v1/responses", + api_key="explicit token", + ) + ) + + assert client.base_url == URL("https://explicit.example.com/openai/v1/") + assert client.api_key == "explicit token" + + +@pytest.mark.parametrize("client_cls", [BedrockOpenAI, AsyncBedrockOpenAI]) +def test_bedrock_region_precedence(client_cls: type[Client]) -> None: + with update_env(AWS_BEDROCK_BASE_URL=Omit(), AWS_REGION="us-east-1", AWS_DEFAULT_REGION="us-west-2"): + explicit_region_client = ( + make_sync_client(aws_region="eu-west-1", api_key="token") + if client_cls is BedrockOpenAI + else make_async_client(aws_region="eu-west-1", api_key="token") + ) + aws_region_client = ( + make_sync_client(api_key="token") if client_cls is BedrockOpenAI else make_async_client(api_key="token") + ) + + with update_env(AWS_BEDROCK_BASE_URL=Omit(), AWS_REGION=Omit(), AWS_DEFAULT_REGION="us-west-2"): + default_region_client = ( + make_sync_client(api_key="token") if client_cls is BedrockOpenAI else make_async_client(api_key="token") + ) + + assert explicit_region_client.base_url == URL("https://bedrock-mantle.eu-west-1.api.aws/openai/v1/") + assert aws_region_client.base_url == URL("https://bedrock-mantle.us-east-1.api.aws/openai/v1/") + assert default_region_client.base_url == URL("https://bedrock-mantle.us-west-2.api.aws/openai/v1/") + + +@pytest.mark.parametrize("client_cls", [BedrockOpenAI, AsyncBedrockOpenAI]) +def test_normalizes_responses_url(client_cls: type[Client]) -> None: + client = ( + make_sync_client(base_url="https://example.com/openai/v1/responses", api_key="token") + if client_cls is BedrockOpenAI + else make_async_client(base_url="https://example.com/openai/v1/responses", api_key="token") + ) + + assert client.base_url == URL("https://example.com/openai/v1/") + + +@pytest.mark.parametrize("client_cls", [BedrockOpenAI, AsyncBedrockOpenAI]) +def test_requires_endpoint_configuration(client_cls: type[Client]) -> None: + with update_env(AWS_BEDROCK_BASE_URL=Omit(), AWS_REGION=Omit(), AWS_DEFAULT_REGION=Omit()): + with pytest.raises(OpenAIError, match="Must provide one of the `base_url` or `aws_region`"): + client_cls(api_key="token") + + +@pytest.mark.parametrize("client_cls", [BedrockOpenAI, AsyncBedrockOpenAI]) +def test_does_not_use_openai_api_key(client_cls: type[Client]) -> None: + with update_env( + OPENAI_API_KEY="openai token", + AWS_BEARER_TOKEN_BEDROCK=Omit(), + AWS_BEDROCK_BASE_URL="https://example.com/openai/v1", + ): + with pytest.raises(OpenAIError, match="AWS_BEARER_TOKEN_BEDROCK"): + client_cls() + + +@pytest.mark.parametrize("client_cls", [BedrockOpenAI, AsyncBedrockOpenAI]) +def test_rejects_static_token_and_provider(client_cls: type[Client]) -> None: + with pytest.raises(OpenAIError, match="mutually exclusive"): + client_cls( + base_url="https://example.com/openai/v1", + api_key="token", + bedrock_token_provider=lambda: "provider token", + ) + + +@pytest.mark.parametrize("client_cls", [BedrockOpenAI, AsyncBedrockOpenAI]) +def test_requires_refreshable_tokens_to_use_provider_option(client_cls: type[Client]) -> None: + with pytest.raises(OpenAIError, match="bedrock_token_provider"): + client_cls( + base_url="https://example.com/openai/v1", + api_key=lambda: "provider token", # type: ignore[arg-type] + ) + + +@pytest.mark.respx() +def test_token_provider_refresh_sync(respx_mock: MockRouter) -> None: + respx_mock.post("https://example.com/openai/v1/responses").mock( + side_effect=[ + httpx.Response(500, json={"error": "server error"}), + httpx.Response(200, json=RESPONSE_BODY), + ] + ) + tokens = iter(["first", "second"]) + client = BedrockOpenAI( + base_url="https://example.com/openai/v1", + bedrock_token_provider=lambda: next(tokens), + http_client=httpx.Client(trust_env=False), + max_retries=1, + ) + + client.responses.create(model="gpt-4o", input="hello") + + calls = cast("list[MockRequestCall]", respx_mock.calls) + assert calls[0].request.headers["Authorization"] == "Bearer first" + assert calls[1].request.headers["Authorization"] == "Bearer second" + + +@pytest.mark.asyncio +@pytest.mark.respx() +async def test_token_provider_refresh_async(respx_mock: MockRouter) -> None: + respx_mock.post("https://example.com/openai/v1/responses").mock( + side_effect=[ + httpx.Response(500, json={"error": "server error"}), + httpx.Response(200, json=RESPONSE_BODY), + ] + ) + tokens = iter(["first", "second"]) + client = AsyncBedrockOpenAI( + base_url="https://example.com/openai/v1", + bedrock_token_provider=lambda: next(tokens), + http_client=httpx.AsyncClient(trust_env=False), + max_retries=1, + ) + + await client.responses.create(model="gpt-4o", input="hello") + + calls = cast("list[MockRequestCall]", respx_mock.calls) + assert calls[0].request.headers["Authorization"] == "Bearer first" + assert calls[1].request.headers["Authorization"] == "Bearer second" + + +def test_preserves_token_provider_across_with_options() -> None: + client = BedrockOpenAI( + base_url="https://example.com/openai/v1", + bedrock_token_provider=lambda: "provider token", + http_client=httpx.Client(trust_env=False), + ) + + copied_client = client.with_options(timeout=1) + + assert copied_client._refresh_api_key() == "provider token" + + +@pytest.mark.parametrize( + "copy_kwargs", + [ + {"admin_api_key": "admin token"}, + {"workload_identity": cast(Any, {})}, + ], +) +def test_rejects_non_bedrock_copy_auth(copy_kwargs: dict[str, Any]) -> None: + client = make_sync_client(base_url="https://example.com/openai/v1", api_key="token") + + with pytest.raises(OpenAIError, match="only supports Bedrock bearer token authentication"): + client.with_options(**copy_kwargs) + + +@pytest.mark.respx() +def test_passes_non_responses_resources_through(respx_mock: MockRouter) -> None: + respx_mock.post("https://example.com/openai/v1/chat/completions").mock( + return_value=httpx.Response( + 404, + json={"error": {"message": "AWS does not support chat completions here"}}, + headers={"x-request-id": "req_chat"}, + ) + ) + client = make_sync_client(base_url="https://example.com/openai/v1", api_key="token") + + with pytest.raises(NotFoundError, match="AWS does not support chat completions here") as exc: + client.chat.completions.create(model="gpt-4o", messages=[]) + + assert exc.value.request_id == "req_chat" + calls = cast("list[MockRequestCall]", respx_mock.calls) + assert calls[0].request.url == URL("https://example.com/openai/v1/chat/completions") + + +@pytest.mark.asyncio +@pytest.mark.respx() +async def test_passes_non_responses_resources_through_async(respx_mock: MockRouter) -> None: + respx_mock.post("https://example.com/openai/v1/chat/completions").mock( + return_value=httpx.Response( + 404, + json={"error": {"message": "AWS does not support chat completions here"}}, + headers={"x-request-id": "req_chat"}, + ) + ) + client = make_async_client(base_url="https://example.com/openai/v1", api_key="token") + + with pytest.raises(NotFoundError, match="AWS does not support chat completions here") as exc: + await client.chat.completions.create(model="gpt-4o", messages=[]) + + assert exc.value.request_id == "req_chat" + calls = cast("list[MockRequestCall]", respx_mock.calls) + assert calls[0].request.url == URL("https://example.com/openai/v1/chat/completions") + + +@pytest.mark.respx() +def test_passes_responses_features_through(respx_mock: MockRouter) -> None: + respx_mock.post("https://example.com/openai/v1/responses").mock( + return_value=httpx.Response(200, json=RESPONSE_BODY) + ) + client = make_sync_client(base_url="https://example.com/openai/v1", api_key="token") + + response = client.responses.create( + model="gpt-4o", + input="hello", + tools=[{"type": "web_search_preview"}], # type: ignore[list-item] + ) + + assert response.id == "resp_123" + calls = cast("list[MockRequestCall]", respx_mock.calls) + assert json.loads(calls[0].request.content)["tools"] == [{"type": "web_search_preview"}] + + +@pytest.mark.respx() +def test_passes_admin_security_routes_through(respx_mock: MockRouter) -> None: + respx_mock.get("https://example.com/openai/v1/organization/invites").mock( + return_value=httpx.Response( + 404, + json={"error": {"message": "AWS does not support organization invites here"}}, + headers={"x-request-id": "req_admin"}, + ) + ) + client = make_sync_client(base_url="https://example.com/openai/v1", api_key="token") + + with pytest.raises(NotFoundError, match="AWS does not support organization invites here"): + list(client.admin.organization.invites.list()) + + calls = cast("list[MockRequestCall]", respx_mock.calls) + assert calls[0].request.headers["Authorization"] == "Bearer token" + + +@pytest.mark.respx() +def test_refreshes_token_provider_for_admin_security_routes(respx_mock: MockRouter) -> None: + respx_mock.get("https://example.com/openai/v1/organization/invites").mock( + side_effect=[ + httpx.Response(500, json={"error": "server error"}), + httpx.Response( + 404, + json={"error": {"message": "AWS does not support organization invites here"}}, + headers={"x-request-id": "req_admin"}, + ), + ] + ) + tokens = iter(["first", "second"]) + client = BedrockOpenAI( + base_url="https://example.com/openai/v1", + bedrock_token_provider=lambda: next(tokens), + http_client=httpx.Client(trust_env=False), + max_retries=1, + ) + + with pytest.raises(NotFoundError, match="AWS does not support organization invites here"): + list(client.admin.organization.invites.list()) + + calls = cast("list[MockRequestCall]", respx_mock.calls) + assert calls[0].request.headers["Authorization"] == "Bearer first" + assert calls[1].request.headers["Authorization"] == "Bearer second" + + +@pytest.mark.respx() +def test_allows_responses_http_methods(respx_mock: MockRouter) -> None: + respx_mock.post("https://example.com/openai/v1/responses").mock( + return_value=httpx.Response(200, json=RESPONSE_BODY) + ) + respx_mock.get("https://example.com/openai/v1/responses/resp_123?starting_after=1&stream=true").mock( + return_value=httpx.Response(200, text=response_created_sse(), headers={"Content-Type": "text/event-stream"}) + ) + respx_mock.get("https://example.com/openai/v1/responses/resp_123?stream=true").mock( + return_value=httpx.Response(200, text=response_created_sse(), headers={"Content-Type": "text/event-stream"}) + ) + respx_mock.get("https://example.com/openai/v1/responses/resp_123").mock( + return_value=httpx.Response(200, json=RESPONSE_BODY) + ) + respx_mock.post("https://example.com/openai/v1/responses/resp_123/cancel").mock( + return_value=httpx.Response(200, json=RESPONSE_BODY) + ) + respx_mock.post("https://example.com/openai/v1/responses/compact").mock( + return_value=httpx.Response(200, json=COMPACTED_RESPONSE_BODY) + ) + respx_mock.get("https://example.com/openai/v1/responses/resp_123/input_items").mock( + return_value=httpx.Response(200, json=INPUT_ITEMS_BODY) + ) + respx_mock.post("https://example.com/openai/v1/responses/input_tokens").mock( + return_value=httpx.Response(200, json=INPUT_TOKENS_BODY) + ) + client = make_sync_client(base_url="https://example.com/openai/v1", api_key="token") + + assert client.responses.create(model="gpt-4o", input="hello", background=True).id == "resp_123" + assert client.responses.retrieve("resp_123").id == "resp_123" + assert [event.type for event in client.responses.retrieve("resp_123", starting_after=1, stream=True)] == [ + "response.created" + ] + assert [event.type for event in client.responses.retrieve("resp_123", stream=True)] == ["response.created"] + assert client.responses.cancel("resp_123").id == "resp_123" + assert client.responses.compact(model="gpt-4o").object == "response.compaction" + assert list(client.responses.input_items.list("resp_123")) == [] + assert client.responses.input_tokens.count(model="gpt-4o", input="hello").input_tokens == 1 + + calls = cast("list[MockRequestCall]", respx_mock.calls) + assert {call.request.headers["Authorization"] for call in calls} == {"Bearer token"} + + +@pytest.mark.respx() +def test_allows_sse_and_response_wrappers(respx_mock: MockRouter) -> None: + respx_mock.post("https://example.com/openai/v1/responses").mock( + side_effect=[ + httpx.Response(200, text=response_created_sse(), headers={"Content-Type": "text/event-stream"}), + httpx.Response(200, json=RESPONSE_BODY), + httpx.Response(200, json=RESPONSE_BODY), + ] + ) + client = make_sync_client(base_url="https://example.com/openai/v1", api_key="token") + + events = list(client.responses.create(model="gpt-4o", input="hello", stream=True)) + assert [event.type for event in events] == ["response.created"] + + raw_response = client.responses.with_raw_response.create(model="gpt-4o", input="hello") + assert raw_response.parse().id == "resp_123" + + with client.responses.with_streaming_response.create(model="gpt-4o", input="hello") as response: + assert response.parse().id == "resp_123" + + +def test_does_not_guard_responses_connect() -> None: + client = make_sync_client(base_url="https://example.com/openai/v1", api_key="token") + + assert client.responses.connect() is not None diff --git a/tests/test_module_client.py b/tests/test_module_client.py index 6371ae7057..7889d4b41e 100644 --- a/tests/test_module_client.py +++ b/tests/test_module_client.py @@ -30,6 +30,8 @@ def reset_state() -> None: openai.azure_endpoint = None openai.azure_ad_token = None openai.azure_ad_token_provider = None + openai._bedrock_api_key = None + openai.bedrock_token_provider = None @pytest.fixture(autouse=True) @@ -102,6 +104,7 @@ def test_http_client_option() -> None: from typing import Iterator from openai.lib.azure import AzureOpenAI +from openai.lib.bedrock import BedrockOpenAI @contextlib.contextmanager @@ -184,3 +187,64 @@ def test_azure_azure_ad_token_provider_version_and_endpoint_env() -> None: assert isinstance(client, AzureOpenAI) assert client._azure_ad_token_provider is not None assert client._azure_ad_token_provider() == "token" + + +def test_bedrock_token_and_region_env() -> None: + with fresh_env(): + openai.api_type = "amazon-bedrock" + _os.environ["AWS_BEARER_TOKEN_BEDROCK"] = "example Bedrock token" + _os.environ["AWS_REGION"] = "us-west-2" + + client = openai.responses._client + assert isinstance(client, BedrockOpenAI) + assert client.base_url == URL("https://bedrock-mantle.us-west-2.api.aws/openai/v1/") + + +def test_bedrock_api_type_env() -> None: + with fresh_env(): + _os.environ["OPENAI_API_TYPE"] = "amazon-bedrock" + _os.environ["AWS_BEARER_TOKEN_BEDROCK"] = "example Bedrock token" + _os.environ["AWS_REGION"] = "us-west-2" + reset_state() + + client = openai.responses._client + assert isinstance(client, BedrockOpenAI) + assert openai.api_type == "amazon-bedrock" + + +def test_bedrock_api_type_uses_bedrock_credentials() -> None: + with fresh_env(): + openai.api_type = "amazon-bedrock" + _os.environ["OPENAI_API_KEY"] = "openai api key" + _os.environ["AWS_BEARER_TOKEN_BEDROCK"] = "example Bedrock token" + _os.environ["AWS_REGION"] = "us-west-2" + + client = openai.responses._client + assert isinstance(client, BedrockOpenAI) + assert client.api_key == "example Bedrock token" + assert openai.api_key is None + + +def test_bedrock_api_type_uses_explicit_module_api_key() -> None: + with fresh_env(): + openai.api_type = "amazon-bedrock" + openai.api_key = "explicit Bedrock token" + _os.environ["AWS_BEARER_TOKEN_BEDROCK"] = "env Bedrock token" + _os.environ["AWS_REGION"] = "us-west-2" + + client = openai.responses._client + assert isinstance(client, BedrockOpenAI) + assert client.api_key == "explicit Bedrock token" + assert openai.api_key == "explicit Bedrock token" + + +def test_bedrock_api_type_uses_token_provider_without_mutating_module_api_key() -> None: + with fresh_env(): + openai.api_type = "amazon-bedrock" + openai.bedrock_token_provider = lambda: "provider Bedrock token" + _os.environ["AWS_REGION"] = "us-west-2" + + client = openai.responses._client + assert isinstance(client, BedrockOpenAI) + assert client._refresh_api_key() == "provider Bedrock token" + assert openai.api_key is None From 268de687ddfc8ab937372987ef71b99a57c05b0e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 1 Jun 2026 18:41:18 +0000 Subject: [PATCH 759/769] feat(api): workload identity in audit logs, additional_tools item in responses, fix ActionSearch.query to be optional. --- .stats.yml | 4 +- src/openai/lib/_parsing/_responses.py | 1 + .../admin/organization/audit_logs.py | 12 ++ .../resources/chat/completions/completions.py | 48 ++++++++ .../resources/responses/input_tokens.py | 12 ++ src/openai/resources/responses/responses.py | 48 ++++++++ .../organization/audit_log_list_params.py | 6 + .../organization/audit_log_list_response.py | 114 ++++++++++++++++++ .../types/chat/completion_create_params.py | 8 ++ .../types/conversations/conversation_item.py | 17 +++ .../responses/input_token_count_params.py | 7 ++ src/openai/types/responses/parsed_response.py | 2 + src/openai/types/responses/response.py | 8 ++ .../types/responses/response_create_params.py | 8 ++ .../responses/response_function_web_search.py | 6 +- .../response_function_web_search_param.py | 6 +- .../types/responses/response_input_item.py | 17 +++ .../responses/response_input_item_param.py | 17 +++ .../types/responses/response_input_param.py | 17 +++ src/openai/types/responses/response_item.py | 17 +++ .../types/responses/response_output_item.py | 17 +++ .../types/responses/responses_client_event.py | 8 ++ .../responses/responses_client_event_param.py | 8 ++ .../responses/test_input_tokens.py | 2 + 24 files changed, 402 insertions(+), 8 deletions(-) diff --git a/.stats.yml b/.stats.yml index b9d21daa06..1accdac38a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 262 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-afacc4343d0efc074c8c5667eb83570642c8b9acaa7792ca8e075c6d18ef9f3a.yml -openapi_spec_hash: a62a557c61532681963fd21e748b0eb4 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-2a971ccbb946726988e96654eaecceb6d9b5ad27f5793c0064b864f5686d4fc1.yml +openapi_spec_hash: a712e4ee68f829570b3f5b267afa5a05 config_hash: bb69d8d0771dbac4a84fc6dca11e3ceb diff --git a/src/openai/lib/_parsing/_responses.py b/src/openai/lib/_parsing/_responses.py index 8853a0749f..232718cef6 100644 --- a/src/openai/lib/_parsing/_responses.py +++ b/src/openai/lib/_parsing/_responses.py @@ -103,6 +103,7 @@ def parse_response( or output.type == "web_search_call" or output.type == "tool_search_call" or output.type == "tool_search_output" + or output.type == "additional_tools" or output.type == "reasoning" or output.type == "compaction" or output.type == "mcp_call" diff --git a/src/openai/resources/admin/organization/audit_logs.py b/src/openai/resources/admin/organization/audit_logs.py index 3cf3127631..760fb4b034 100644 --- a/src/openai/resources/admin/organization/audit_logs.py +++ b/src/openai/resources/admin/organization/audit_logs.py @@ -91,6 +91,12 @@ def list( "tunnel.created", "tunnel.updated", "tunnel.deleted", + "workload_identity_provider.created", + "workload_identity_provider.updated", + "workload_identity_provider.deleted", + "workload_identity_provider_mapping.created", + "workload_identity_provider_mapping.updated", + "workload_identity_provider_mapping.deleted", "role.created", "role.updated", "role.deleted", @@ -256,6 +262,12 @@ def list( "tunnel.created", "tunnel.updated", "tunnel.deleted", + "workload_identity_provider.created", + "workload_identity_provider.updated", + "workload_identity_provider.deleted", + "workload_identity_provider_mapping.created", + "workload_identity_provider_mapping.updated", + "workload_identity_provider_mapping.deleted", "role.created", "role.updated", "role.deleted", diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index c85ac45cdb..9a2973c2a9 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -419,6 +419,14 @@ def create( prompt caching, which keeps cached prefixes active for longer, up to a maximum of 24 hours. [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). + For `gpt-5.5`, `gpt-5.5-pro`, and future models, only `24h` is supported. + + For older models that support both `in_memory` and `24h`, the default depends on + your organization's data retention policy: + + - Organizations without ZDR enabled default to `24h`. + - Organizations with ZDR enabled default to `in_memory` when + `prompt_cache_retention` is not specified. reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently @@ -735,6 +743,14 @@ def create( prompt caching, which keeps cached prefixes active for longer, up to a maximum of 24 hours. [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). + For `gpt-5.5`, `gpt-5.5-pro`, and future models, only `24h` is supported. + + For older models that support both `in_memory` and `24h`, the default depends on + your organization's data retention policy: + + - Organizations without ZDR enabled default to `24h`. + - Organizations with ZDR enabled default to `in_memory` when + `prompt_cache_retention` is not specified. reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently @@ -1042,6 +1058,14 @@ def create( prompt caching, which keeps cached prefixes active for longer, up to a maximum of 24 hours. [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). + For `gpt-5.5`, `gpt-5.5-pro`, and future models, only `24h` is supported. + + For older models that support both `in_memory` and `24h`, the default depends on + your organization's data retention policy: + + - Organizations without ZDR enabled default to `24h`. + - Organizations with ZDR enabled default to `in_memory` when + `prompt_cache_retention` is not specified. reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently @@ -1943,6 +1967,14 @@ async def create( prompt caching, which keeps cached prefixes active for longer, up to a maximum of 24 hours. [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). + For `gpt-5.5`, `gpt-5.5-pro`, and future models, only `24h` is supported. + + For older models that support both `in_memory` and `24h`, the default depends on + your organization's data retention policy: + + - Organizations without ZDR enabled default to `24h`. + - Organizations with ZDR enabled default to `in_memory` when + `prompt_cache_retention` is not specified. reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently @@ -2259,6 +2291,14 @@ async def create( prompt caching, which keeps cached prefixes active for longer, up to a maximum of 24 hours. [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). + For `gpt-5.5`, `gpt-5.5-pro`, and future models, only `24h` is supported. + + For older models that support both `in_memory` and `24h`, the default depends on + your organization's data retention policy: + + - Organizations without ZDR enabled default to `24h`. + - Organizations with ZDR enabled default to `in_memory` when + `prompt_cache_retention` is not specified. reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently @@ -2566,6 +2606,14 @@ async def create( prompt caching, which keeps cached prefixes active for longer, up to a maximum of 24 hours. [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). + For `gpt-5.5`, `gpt-5.5-pro`, and future models, only `24h` is supported. + + For older models that support both `in_memory` and `24h`, the default depends on + your organization's data retention policy: + + - Organizations without ZDR enabled default to `24h`. + - Organizations with ZDR enabled default to `in_memory` when + `prompt_cache_retention` is not specified. reasoning_effort: Constrains effort on reasoning for [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently diff --git a/src/openai/resources/responses/input_tokens.py b/src/openai/resources/responses/input_tokens.py index fae71fd59c..3306dfcd65 100644 --- a/src/openai/resources/responses/input_tokens.py +++ b/src/openai/resources/responses/input_tokens.py @@ -51,6 +51,7 @@ def count( instructions: Optional[str] | Omit = omit, model: Optional[str] | Omit = omit, parallel_tool_calls: Optional[bool] | Omit = omit, + personality: Union[str, Literal["friendly", "pragmatic"]] | Omit = omit, previous_response_id: Optional[str] | Omit = omit, reasoning: Optional[Reasoning] | Omit = omit, text: Optional[input_token_count_params.Text] | Omit = omit, @@ -91,6 +92,10 @@ def count( parallel_tool_calls: Whether to allow the model to run tool calls in parallel. + personality: A model-owned style preset to apply to this request. Omit this parameter to use + the model's default style. Supported values may expand over time. Values must be + at most 64 characters. + previous_response_id: The unique ID of the previous response to the model. Use this to create multi-turn conversations. Learn more about [conversation state](https://platform.openai.com/docs/guides/conversation-state). @@ -133,6 +138,7 @@ def count( "instructions": instructions, "model": model, "parallel_tool_calls": parallel_tool_calls, + "personality": personality, "previous_response_id": previous_response_id, "reasoning": reasoning, "text": text, @@ -181,6 +187,7 @@ async def count( instructions: Optional[str] | Omit = omit, model: Optional[str] | Omit = omit, parallel_tool_calls: Optional[bool] | Omit = omit, + personality: Union[str, Literal["friendly", "pragmatic"]] | Omit = omit, previous_response_id: Optional[str] | Omit = omit, reasoning: Optional[Reasoning] | Omit = omit, text: Optional[input_token_count_params.Text] | Omit = omit, @@ -221,6 +228,10 @@ async def count( parallel_tool_calls: Whether to allow the model to run tool calls in parallel. + personality: A model-owned style preset to apply to this request. Omit this parameter to use + the model's default style. Supported values may expand over time. Values must be + at most 64 characters. + previous_response_id: The unique ID of the previous response to the model. Use this to create multi-turn conversations. Learn more about [conversation state](https://platform.openai.com/docs/guides/conversation-state). @@ -263,6 +274,7 @@ async def count( "instructions": instructions, "model": model, "parallel_tool_calls": parallel_tool_calls, + "personality": personality, "previous_response_id": previous_response_id, "reasoning": reasoning, "text": text, diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index e83f9824be..9caadacd66 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -268,6 +268,14 @@ def create( prompt caching, which keeps cached prefixes active for longer, up to a maximum of 24 hours. [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). + For `gpt-5.5`, `gpt-5.5-pro`, and future models, only `24h` is supported. + + For older models that support both `in_memory` and `24h`, the default depends on + your organization's data retention policy: + + - Organizations without ZDR enabled default to `24h`. + - Organizations with ZDR enabled default to `in_memory` when + `prompt_cache_retention` is not specified. reasoning: **gpt-5 and o-series models only** @@ -525,6 +533,14 @@ def create( prompt caching, which keeps cached prefixes active for longer, up to a maximum of 24 hours. [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). + For `gpt-5.5`, `gpt-5.5-pro`, and future models, only `24h` is supported. + + For older models that support both `in_memory` and `24h`, the default depends on + your organization's data retention policy: + + - Organizations without ZDR enabled default to `24h`. + - Organizations with ZDR enabled default to `in_memory` when + `prompt_cache_retention` is not specified. reasoning: **gpt-5 and o-series models only** @@ -775,6 +791,14 @@ def create( prompt caching, which keeps cached prefixes active for longer, up to a maximum of 24 hours. [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). + For `gpt-5.5`, `gpt-5.5-pro`, and future models, only `24h` is supported. + + For older models that support both `in_memory` and `24h`, the default depends on + your organization's data retention policy: + + - Organizations without ZDR enabled default to `24h`. + - Organizations with ZDR enabled default to `in_memory` when + `prompt_cache_retention` is not specified. reasoning: **gpt-5 and o-series models only** @@ -1974,6 +1998,14 @@ async def create( prompt caching, which keeps cached prefixes active for longer, up to a maximum of 24 hours. [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). + For `gpt-5.5`, `gpt-5.5-pro`, and future models, only `24h` is supported. + + For older models that support both `in_memory` and `24h`, the default depends on + your organization's data retention policy: + + - Organizations without ZDR enabled default to `24h`. + - Organizations with ZDR enabled default to `in_memory` when + `prompt_cache_retention` is not specified. reasoning: **gpt-5 and o-series models only** @@ -2231,6 +2263,14 @@ async def create( prompt caching, which keeps cached prefixes active for longer, up to a maximum of 24 hours. [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). + For `gpt-5.5`, `gpt-5.5-pro`, and future models, only `24h` is supported. + + For older models that support both `in_memory` and `24h`, the default depends on + your organization's data retention policy: + + - Organizations without ZDR enabled default to `24h`. + - Organizations with ZDR enabled default to `in_memory` when + `prompt_cache_retention` is not specified. reasoning: **gpt-5 and o-series models only** @@ -2481,6 +2521,14 @@ async def create( prompt caching, which keeps cached prefixes active for longer, up to a maximum of 24 hours. [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). + For `gpt-5.5`, `gpt-5.5-pro`, and future models, only `24h` is supported. + + For older models that support both `in_memory` and `24h`, the default depends on + your organization's data retention policy: + + - Organizations without ZDR enabled default to `24h`. + - Organizations with ZDR enabled default to `in_memory` when + `prompt_cache_retention` is not specified. reasoning: **gpt-5 and o-series models only** diff --git a/src/openai/types/admin/organization/audit_log_list_params.py b/src/openai/types/admin/organization/audit_log_list_params.py index bd3bc6d629..25224d47dc 100644 --- a/src/openai/types/admin/organization/audit_log_list_params.py +++ b/src/openai/types/admin/organization/audit_log_list_params.py @@ -81,6 +81,12 @@ class AuditLogListParams(TypedDict, total=False): "tunnel.created", "tunnel.updated", "tunnel.deleted", + "workload_identity_provider.created", + "workload_identity_provider.updated", + "workload_identity_provider.deleted", + "workload_identity_provider_mapping.created", + "workload_identity_provider_mapping.updated", + "workload_identity_provider_mapping.deleted", "role.created", "role.updated", "role.deleted", diff --git a/src/openai/types/admin/organization/audit_log_list_response.py b/src/openai/types/admin/organization/audit_log_list_response.py index ec899758a2..9fa99bd677 100644 --- a/src/openai/types/admin/organization/audit_log_list_response.py +++ b/src/openai/types/admin/organization/audit_log_list_response.py @@ -80,6 +80,12 @@ "UserDeleted", "UserUpdated", "UserUpdatedChangesRequested", + "WorkloadIdentityProviderMappingCreated", + "WorkloadIdentityProviderMappingDeleted", + "WorkloadIdentityProviderMappingUpdated", + "WorkloadIdentityProviderCreated", + "WorkloadIdentityProviderDeleted", + "WorkloadIdentityProviderUpdated", ] @@ -804,6 +810,78 @@ class UserUpdated(BaseModel): """The payload used to update the user.""" +class WorkloadIdentityProviderMappingCreated(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The workload identity provider mapping ID.""" + + data: Optional[object] = None + """The payload used to create the workload identity provider mapping.""" + + identity_provider_id: Optional[str] = None + """The workload identity provider ID.""" + + +class WorkloadIdentityProviderMappingDeleted(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The workload identity provider mapping ID.""" + + identity_provider_id: Optional[str] = None + """The workload identity provider ID.""" + + project_id: Optional[str] = None + """The project ID.""" + + service_account_id: Optional[str] = None + """The mapped service account ID.""" + + +class WorkloadIdentityProviderMappingUpdated(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The workload identity provider mapping ID.""" + + changes_requested: Optional[object] = None + """The payload used to update the workload identity provider mapping.""" + + identity_provider_id: Optional[str] = None + """The workload identity provider ID.""" + + +class WorkloadIdentityProviderCreated(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The workload identity provider ID.""" + + data: Optional[object] = None + """The payload used to create the workload identity provider.""" + + +class WorkloadIdentityProviderDeleted(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The workload identity provider ID.""" + + name: Optional[str] = None + """The workload identity provider name.""" + + +class WorkloadIdentityProviderUpdated(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The workload identity provider ID.""" + + changes_requested: Optional[object] = None + """The payload used to update the workload identity provider.""" + + class AuditLogListResponse(BaseModel): """A log of a user action or configuration change within this organization.""" @@ -852,6 +930,12 @@ class AuditLogListResponse(BaseModel): "tunnel.created", "tunnel.updated", "tunnel.deleted", + "workload_identity_provider.created", + "workload_identity_provider.updated", + "workload_identity_provider.deleted", + "workload_identity_provider_mapping.created", + "workload_identity_provider_mapping.updated", + "workload_identity_provider_mapping.deleted", "role.created", "role.updated", "role.deleted", @@ -1031,3 +1115,33 @@ class AuditLogListResponse(BaseModel): user_updated: Optional[UserUpdated] = FieldInfo(alias="user.updated", default=None) """The details for events with this `type`.""" + + workload_identity_provider_mapping_created: Optional[WorkloadIdentityProviderMappingCreated] = FieldInfo( + alias="workload_identity_provider_mapping.created", default=None + ) + """The details for events with this `type`.""" + + workload_identity_provider_mapping_deleted: Optional[WorkloadIdentityProviderMappingDeleted] = FieldInfo( + alias="workload_identity_provider_mapping.deleted", default=None + ) + """The details for events with this `type`.""" + + workload_identity_provider_mapping_updated: Optional[WorkloadIdentityProviderMappingUpdated] = FieldInfo( + alias="workload_identity_provider_mapping.updated", default=None + ) + """The details for events with this `type`.""" + + workload_identity_provider_created: Optional[WorkloadIdentityProviderCreated] = FieldInfo( + alias="workload_identity_provider.created", default=None + ) + """The details for events with this `type`.""" + + workload_identity_provider_deleted: Optional[WorkloadIdentityProviderDeleted] = FieldInfo( + alias="workload_identity_provider.deleted", default=None + ) + """The details for events with this `type`.""" + + workload_identity_provider_updated: Optional[WorkloadIdentityProviderUpdated] = FieldInfo( + alias="workload_identity_provider.updated", default=None + ) + """The details for events with this `type`.""" diff --git a/src/openai/types/chat/completion_create_params.py b/src/openai/types/chat/completion_create_params.py index 3c541b96b4..5ec1a1ae91 100644 --- a/src/openai/types/chat/completion_create_params.py +++ b/src/openai/types/chat/completion_create_params.py @@ -191,6 +191,14 @@ class CompletionCreateParamsBase(TypedDict, total=False): Set to `24h` to enable extended prompt caching, which keeps cached prefixes active for longer, up to a maximum of 24 hours. [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). + For `gpt-5.5`, `gpt-5.5-pro`, and future models, only `24h` is supported. + + For older models that support both `in_memory` and `24h`, the default depends on + your organization's data retention policy: + + - Organizations without ZDR enabled default to `24h`. + - Organizations with ZDR enabled default to `in_memory` when + `prompt_cache_retention` is not specified. """ reasoning_effort: Optional[ReasoningEffort] diff --git a/src/openai/types/conversations/conversation_item.py b/src/openai/types/conversations/conversation_item.py index 52e87ccb0b..9bc0495a34 100644 --- a/src/openai/types/conversations/conversation_item.py +++ b/src/openai/types/conversations/conversation_item.py @@ -6,6 +6,7 @@ from .message import Message from ..._utils import PropertyInfo from ..._models import BaseModel +from ..responses.tool import Tool from ..responses.response_reasoning_item import ResponseReasoningItem from ..responses.response_compaction_item import ResponseCompactionItem from ..responses.response_custom_tool_call import ResponseCustomToolCall @@ -27,6 +28,7 @@ __all__ = [ "ConversationItem", "ImageGenerationCall", + "AdditionalTools", "LocalShellCall", "LocalShellCallAction", "LocalShellCallOutput", @@ -54,6 +56,20 @@ class ImageGenerationCall(BaseModel): """The type of the image generation call. Always `image_generation_call`.""" +class AdditionalTools(BaseModel): + id: str + """The unique ID of the additional tools item.""" + + role: Literal["unknown", "user", "assistant", "system", "critic", "discriminator", "developer", "tool"] + """The role that provided the additional tools.""" + + tools: List[Tool] + """The additional tool definitions made available at this item.""" + + type: Literal["additional_tools"] + """The type of the item. Always `additional_tools`.""" + + class LocalShellCallAction(BaseModel): """Execute a shell command on the server.""" @@ -234,6 +250,7 @@ class McpCall(BaseModel): ResponseComputerToolCallOutputItem, ResponseToolSearchCall, ResponseToolSearchOutputItem, + AdditionalTools, ResponseReasoningItem, ResponseCompactionItem, ResponseCodeInterpreterToolCall, diff --git a/src/openai/types/responses/input_token_count_params.py b/src/openai/types/responses/input_token_count_params.py index f8a2026537..d94eea689c 100644 --- a/src/openai/types/responses/input_token_count_params.py +++ b/src/openai/types/responses/input_token_count_params.py @@ -54,6 +54,13 @@ class InputTokenCountParams(TypedDict, total=False): parallel_tool_calls: Optional[bool] """Whether to allow the model to run tool calls in parallel.""" + personality: Union[str, Literal["friendly", "pragmatic"]] + """A model-owned style preset to apply to this request. + + Omit this parameter to use the model's default style. Supported values may + expand over time. Values must be at most 64 characters. + """ + previous_response_id: Optional[str] """The unique ID of the previous response to the model. diff --git a/src/openai/types/responses/parsed_response.py b/src/openai/types/responses/parsed_response.py index 4100a8d9d0..0d1f18b472 100644 --- a/src/openai/types/responses/parsed_response.py +++ b/src/openai/types/responses/parsed_response.py @@ -10,6 +10,7 @@ McpCall, McpListTools, LocalShellCall, + AdditionalTools, McpApprovalRequest, ImageGenerationCall, McpApprovalResponse, @@ -80,6 +81,7 @@ class ParsedResponseFunctionToolCall(ResponseFunctionToolCall): ResponseComputerToolCallOutputItem, ResponseToolSearchCall, ResponseToolSearchOutputItem, + AdditionalTools, ResponseReasoningItem, McpCall, McpApprovalRequest, diff --git a/src/openai/types/responses/response.py b/src/openai/types/responses/response.py index dac3e09a89..bb4a4b3952 100644 --- a/src/openai/types/responses/response.py +++ b/src/openai/types/responses/response.py @@ -220,6 +220,14 @@ class Response(BaseModel): Set to `24h` to enable extended prompt caching, which keeps cached prefixes active for longer, up to a maximum of 24 hours. [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). + For `gpt-5.5`, `gpt-5.5-pro`, and future models, only `24h` is supported. + + For older models that support both `in_memory` and `24h`, the default depends on + your organization's data retention policy: + + - Organizations without ZDR enabled default to `24h`. + - Organizations with ZDR enabled default to `in_memory` when + `prompt_cache_retention` is not specified. """ reasoning: Optional[Reasoning] = None diff --git a/src/openai/types/responses/response_create_params.py b/src/openai/types/responses/response_create_params.py index 5f9b948ae9..b85ee87741 100644 --- a/src/openai/types/responses/response_create_params.py +++ b/src/openai/types/responses/response_create_params.py @@ -158,6 +158,14 @@ class ResponseCreateParamsBase(TypedDict, total=False): Set to `24h` to enable extended prompt caching, which keeps cached prefixes active for longer, up to a maximum of 24 hours. [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). + For `gpt-5.5`, `gpt-5.5-pro`, and future models, only `24h` is supported. + + For older models that support both `in_memory` and `24h`, the default depends on + your organization's data retention policy: + + - Organizations without ZDR enabled default to `24h`. + - Organizations with ZDR enabled default to `in_memory` when + `prompt_cache_retention` is not specified. """ reasoning: Optional[Reasoning] diff --git a/src/openai/types/responses/response_function_web_search.py b/src/openai/types/responses/response_function_web_search.py index de6001e146..3584992b7d 100644 --- a/src/openai/types/responses/response_function_web_search.py +++ b/src/openai/types/responses/response_function_web_search.py @@ -29,15 +29,15 @@ class ActionSearchSource(BaseModel): class ActionSearch(BaseModel): """Action type "search" - Performs a web search query.""" - query: str - """[DEPRECATED] The search query.""" - type: Literal["search"] """The action type.""" queries: Optional[List[str]] = None """The search queries.""" + query: Optional[str] = None + """The search query.""" + sources: Optional[List[ActionSearchSource]] = None """The sources used in the search.""" diff --git a/src/openai/types/responses/response_function_web_search_param.py b/src/openai/types/responses/response_function_web_search_param.py index 15e313b0d3..9e31a46be1 100644 --- a/src/openai/types/responses/response_function_web_search_param.py +++ b/src/openai/types/responses/response_function_web_search_param.py @@ -30,15 +30,15 @@ class ActionSearchSource(TypedDict, total=False): class ActionSearch(TypedDict, total=False): """Action type "search" - Performs a web search query.""" - query: Required[str] - """[DEPRECATED] The search query.""" - type: Required[Literal["search"]] """The action type.""" queries: SequenceNotStr[str] """The search queries.""" + query: str + """The search query.""" + sources: Iterable[ActionSearchSource] """The sources used in the search.""" diff --git a/src/openai/types/responses/response_input_item.py b/src/openai/types/responses/response_input_item.py index 9f12b429bd..f7f67c3414 100644 --- a/src/openai/types/responses/response_input_item.py +++ b/src/openai/types/responses/response_input_item.py @@ -3,6 +3,7 @@ from typing import Dict, List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias +from .tool import Tool from ..._utils import PropertyInfo from ..._models import BaseModel from .local_environment import LocalEnvironment @@ -31,6 +32,7 @@ "ComputerCallOutputAcknowledgedSafetyCheck", "FunctionCallOutput", "ToolSearchCall", + "AdditionalTools", "ImageGenerationCall", "LocalShellCall", "LocalShellCallAction", @@ -170,6 +172,20 @@ class ToolSearchCall(BaseModel): """The status of the tool search call.""" +class AdditionalTools(BaseModel): + role: Literal["developer"] + """The role that provided the additional tools. Only `developer` is supported.""" + + tools: List[Tool] + """A list of additional tools made available at this item.""" + + type: Literal["additional_tools"] + """The item type. Always `additional_tools`.""" + + id: Optional[str] = None + """The unique ID of this additional tools item.""" + + class ImageGenerationCall(BaseModel): """An image generation request made by the model.""" @@ -558,6 +574,7 @@ class ItemReference(BaseModel): FunctionCallOutput, ToolSearchCall, ResponseToolSearchOutputItemParam, + AdditionalTools, ResponseReasoningItem, ResponseCompactionItemParam, ImageGenerationCall, diff --git a/src/openai/types/responses/response_input_item_param.py b/src/openai/types/responses/response_input_item_param.py index 156ac92d39..0b0d68cdbd 100644 --- a/src/openai/types/responses/response_input_item_param.py +++ b/src/openai/types/responses/response_input_item_param.py @@ -6,6 +6,7 @@ from typing_extensions import Literal, Required, TypeAlias, TypedDict from ..._types import SequenceNotStr +from .tool_param import ToolParam from .local_environment_param import LocalEnvironmentParam from .easy_input_message_param import EasyInputMessageParam from .container_reference_param import ContainerReferenceParam @@ -32,6 +33,7 @@ "ComputerCallOutputAcknowledgedSafetyCheck", "FunctionCallOutput", "ToolSearchCall", + "AdditionalTools", "ImageGenerationCall", "LocalShellCall", "LocalShellCallAction", @@ -171,6 +173,20 @@ class ToolSearchCall(TypedDict, total=False): """The status of the tool search call.""" +class AdditionalTools(TypedDict, total=False): + role: Required[Literal["developer"]] + """The role that provided the additional tools. Only `developer` is supported.""" + + tools: Required[Iterable[ToolParam]] + """A list of additional tools made available at this item.""" + + type: Required[Literal["additional_tools"]] + """The item type. Always `additional_tools`.""" + + id: Optional[str] + """The unique ID of this additional tools item.""" + + class ImageGenerationCall(TypedDict, total=False): """An image generation request made by the model.""" @@ -555,6 +571,7 @@ class ItemReference(TypedDict, total=False): FunctionCallOutput, ToolSearchCall, ResponseToolSearchOutputItemParamParam, + AdditionalTools, ResponseReasoningItemParam, ResponseCompactionItemParamParam, ImageGenerationCall, diff --git a/src/openai/types/responses/response_input_param.py b/src/openai/types/responses/response_input_param.py index 656c70359b..f45aa276c8 100644 --- a/src/openai/types/responses/response_input_param.py +++ b/src/openai/types/responses/response_input_param.py @@ -6,6 +6,7 @@ from typing_extensions import Literal, Required, TypeAlias, TypedDict from ..._types import SequenceNotStr +from .tool_param import ToolParam from .local_environment_param import LocalEnvironmentParam from .easy_input_message_param import EasyInputMessageParam from .container_reference_param import ContainerReferenceParam @@ -33,6 +34,7 @@ "ComputerCallOutputAcknowledgedSafetyCheck", "FunctionCallOutput", "ToolSearchCall", + "AdditionalTools", "ImageGenerationCall", "LocalShellCall", "LocalShellCallAction", @@ -172,6 +174,20 @@ class ToolSearchCall(TypedDict, total=False): """The status of the tool search call.""" +class AdditionalTools(TypedDict, total=False): + role: Required[Literal["developer"]] + """The role that provided the additional tools. Only `developer` is supported.""" + + tools: Required[Iterable[ToolParam]] + """A list of additional tools made available at this item.""" + + type: Required[Literal["additional_tools"]] + """The item type. Always `additional_tools`.""" + + id: Optional[str] + """The unique ID of this additional tools item.""" + + class ImageGenerationCall(TypedDict, total=False): """An image generation request made by the model.""" @@ -556,6 +572,7 @@ class ItemReference(TypedDict, total=False): FunctionCallOutput, ToolSearchCall, ResponseToolSearchOutputItemParamParam, + AdditionalTools, ResponseReasoningItemParam, ResponseCompactionItemParamParam, ImageGenerationCall, diff --git a/src/openai/types/responses/response_item.py b/src/openai/types/responses/response_item.py index 721bf02ecb..eb2cd44192 100644 --- a/src/openai/types/responses/response_item.py +++ b/src/openai/types/responses/response_item.py @@ -3,6 +3,7 @@ from typing import Dict, List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias +from .tool import Tool from ..._utils import PropertyInfo from ..._models import BaseModel from .response_output_message import ResponseOutputMessage @@ -27,6 +28,7 @@ __all__ = [ "ResponseItem", + "AdditionalTools", "ImageGenerationCall", "LocalShellCall", "LocalShellCallAction", @@ -39,6 +41,20 @@ ] +class AdditionalTools(BaseModel): + id: str + """The unique ID of the additional tools item.""" + + role: Literal["unknown", "user", "assistant", "system", "critic", "discriminator", "developer", "tool"] + """The role that provided the additional tools.""" + + tools: List[Tool] + """The additional tool definitions made available at this item.""" + + type: Literal["additional_tools"] + """The type of the item. Always `additional_tools`.""" + + class ImageGenerationCall(BaseModel): """An image generation request made by the model.""" @@ -235,6 +251,7 @@ class McpCall(BaseModel): ResponseFunctionToolCallOutputItem, ResponseToolSearchCall, ResponseToolSearchOutputItem, + AdditionalTools, ResponseReasoningItem, ResponseCompactionItem, ImageGenerationCall, diff --git a/src/openai/types/responses/response_output_item.py b/src/openai/types/responses/response_output_item.py index a4b23f26fd..ee7057348b 100644 --- a/src/openai/types/responses/response_output_item.py +++ b/src/openai/types/responses/response_output_item.py @@ -3,6 +3,7 @@ from typing import Dict, List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias +from .tool import Tool from ..._utils import PropertyInfo from ..._models import BaseModel from .response_output_message import ResponseOutputMessage @@ -26,6 +27,7 @@ __all__ = [ "ResponseOutputItem", + "AdditionalTools", "ImageGenerationCall", "LocalShellCall", "LocalShellCallAction", @@ -38,6 +40,20 @@ ] +class AdditionalTools(BaseModel): + id: str + """The unique ID of the additional tools item.""" + + role: Literal["unknown", "user", "assistant", "system", "critic", "discriminator", "developer", "tool"] + """The role that provided the additional tools.""" + + tools: List[Tool] + """The additional tool definitions made available at this item.""" + + type: Literal["additional_tools"] + """The type of the item. Always `additional_tools`.""" + + class ImageGenerationCall(BaseModel): """An image generation request made by the model.""" @@ -234,6 +250,7 @@ class McpApprovalResponse(BaseModel): ResponseReasoningItem, ResponseToolSearchCall, ResponseToolSearchOutputItem, + AdditionalTools, ResponseCompactionItem, ImageGenerationCall, ResponseCodeInterpreterToolCall, diff --git a/src/openai/types/responses/responses_client_event.py b/src/openai/types/responses/responses_client_event.py index 0a5dcb4ddd..8f50848d9d 100644 --- a/src/openai/types/responses/responses_client_event.py +++ b/src/openai/types/responses/responses_client_event.py @@ -190,6 +190,14 @@ class ResponsesClientEvent(BaseModel): Set to `24h` to enable extended prompt caching, which keeps cached prefixes active for longer, up to a maximum of 24 hours. [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). + For `gpt-5.5`, `gpt-5.5-pro`, and future models, only `24h` is supported. + + For older models that support both `in_memory` and `24h`, the default depends on + your organization's data retention policy: + + - Organizations without ZDR enabled default to `24h`. + - Organizations with ZDR enabled default to `in_memory` when + `prompt_cache_retention` is not specified. """ reasoning: Optional[Reasoning] = None diff --git a/src/openai/types/responses/responses_client_event_param.py b/src/openai/types/responses/responses_client_event_param.py index 59d8f205ae..632807aedf 100644 --- a/src/openai/types/responses/responses_client_event_param.py +++ b/src/openai/types/responses/responses_client_event_param.py @@ -191,6 +191,14 @@ class ResponsesClientEventParam(TypedDict, total=False): Set to `24h` to enable extended prompt caching, which keeps cached prefixes active for longer, up to a maximum of 24 hours. [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). + For `gpt-5.5`, `gpt-5.5-pro`, and future models, only `24h` is supported. + + For older models that support both `in_memory` and `24h`, the default depends on + your organization's data retention policy: + + - Organizations without ZDR enabled default to `24h`. + - Organizations with ZDR enabled default to `in_memory` when + `prompt_cache_retention` is not specified. """ reasoning: Optional[Reasoning] diff --git a/tests/api_resources/responses/test_input_tokens.py b/tests/api_resources/responses/test_input_tokens.py index b4bc627837..04c0bb698e 100644 --- a/tests/api_resources/responses/test_input_tokens.py +++ b/tests/api_resources/responses/test_input_tokens.py @@ -30,6 +30,7 @@ def test_method_count_with_all_params(self, client: OpenAI) -> None: instructions="instructions", model="model", parallel_tool_calls=True, + personality="friendly", previous_response_id="resp_123", reasoning={ "effort": "none", @@ -94,6 +95,7 @@ async def test_method_count_with_all_params(self, async_client: AsyncOpenAI) -> instructions="instructions", model="model", parallel_tool_calls=True, + personality="friendly", previous_response_id="resp_123", reasoning={ "effort": "none", From e4bccc79d09fec54ad5ff8ec5c55ebdda2ecbef9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 1 Jun 2026 18:43:01 +0000 Subject: [PATCH 760/769] release: 2.39.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 0e1c697558..9f6026f1c7 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.38.0" + ".": "2.39.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index b4f9d758d8..13992c0e52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 2.39.0 (2026-06-01) + +Full Changelog: [v2.38.0...v2.39.0](https://github.com/openai/openai-python/compare/v2.38.0...v2.39.0) + +### Features + +* **api:** workload identity in audit logs, additional_tools item in responses, fix ActionSearch.query to be optional. ([ab60d7a](https://github.com/openai/openai-python/commit/ab60d7a52c310bb0490ff36b8bdc33b8d4ea725f)) + ## 2.38.0 (2026-05-21) Full Changelog: [v2.37.0...v2.38.0](https://github.com/openai/openai-python/compare/v2.37.0...v2.38.0) diff --git a/pyproject.toml b/pyproject.toml index aedb6d8f51..39c6b5174d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.38.0" +version = "2.39.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 ba9c5f3a3c..8f492efa5d 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__ = "2.38.0" # x-release-please-version +__version__ = "2.39.0" # x-release-please-version From fdf4901e301fa01b368ede0b5b407dca42f07acc Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 1 Jun 2026 19:09:39 +0000 Subject: [PATCH 761/769] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 1accdac38a..7345dd30b5 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 262 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-2a971ccbb946726988e96654eaecceb6d9b5ad27f5793c0064b864f5686d4fc1.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-a6fedde02dc6241719ebb2589062ba2892baa8dbe928a2d718643beede85e7b3.yml openapi_spec_hash: a712e4ee68f829570b3f5b267afa5a05 -config_hash: bb69d8d0771dbac4a84fc6dca11e3ceb +config_hash: e02ca1082421dfe55b145c45e95d6126 From a50ff0a19084306a09012ff85f730ea2c129eef9 Mon Sep 17 00:00:00 2001 From: Alex Chang Date: Mon, 1 Jun 2026 17:25:30 -0400 Subject: [PATCH 762/769] Fix Bedrock with_options overrides --- src/openai/lib/bedrock.py | 45 ++++++++++++++++++++++++++++------- tests/lib/test_bedrock.py | 49 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 8 deletions(-) diff --git a/src/openai/lib/bedrock.py b/src/openai/lib/bedrock.py index 0a1aec36ee..266a2e9358 100644 --- a/src/openai/lib/bedrock.py +++ b/src/openai/lib/bedrock.py @@ -54,6 +54,17 @@ def _resolve_bedrock_base_url(base_url: str | httpx.URL | None, aws_region: str return _normalize_bedrock_base_url(base_url) +def _uses_region_derived_bedrock_base_url(base_url: str | httpx.URL | None) -> bool: + if isinstance(base_url, str) and not base_url.strip(): + base_url = None + + if base_url is not None: + return False + + env_base_url = os.environ.get("AWS_BEDROCK_BASE_URL") + return env_base_url is None or not env_base_url.strip() + + def _bedrock_token_provider(provider: BedrockTokenProvider) -> BedrockTokenProvider: """Adapt a sync Bedrock token provider to the base client's api_key callback.""" @@ -87,6 +98,7 @@ class BedrockOpenAI(OpenAI): """API client for Amazon Bedrock's OpenAI-compatible endpoint.""" _bedrock_token_provider: BedrockTokenProvider | None + _uses_region_derived_base_url: bool aws_region: str | None def __init__( @@ -133,6 +145,7 @@ def __init__( ) self._bedrock_token_provider = bedrock_token_provider + self._uses_region_derived_base_url = _uses_region_derived_bedrock_base_url(base_url) self.aws_region = aws_region super().__init__( @@ -223,10 +236,17 @@ def copy( elif set_default_query is not None: params = set_default_query - next_token_provider = ( - bedrock_token_provider if bedrock_token_provider is not None else self._bedrock_token_provider - ) + if api_key is not None: + next_token_provider = None + elif bedrock_token_provider is not None: + next_token_provider = bedrock_token_provider + else: + next_token_provider = self._bedrock_token_provider + next_api_key = api_key if api_key is not None else (None if next_token_provider is not None else self.api_key) + next_base_url = base_url + if next_base_url is None and not (aws_region is not None and self._uses_region_derived_base_url): + next_base_url = self.base_url return self.__class__( api_key=next_api_key, @@ -236,7 +256,7 @@ def copy( project=project if project is not None else self.project, webhook_secret=webhook_secret if webhook_secret is not None else self.webhook_secret, websocket_base_url=websocket_base_url if websocket_base_url is not None else self.websocket_base_url, - base_url=base_url if base_url is not None else self.base_url, + base_url=next_base_url, timeout=self.timeout if isinstance(timeout, NotGiven) else timeout, http_client=http_client or self._client, max_retries=max_retries if is_given(max_retries) else self.max_retries, @@ -253,6 +273,7 @@ class AsyncBedrockOpenAI(AsyncOpenAI): """Async API client for Amazon Bedrock's OpenAI-compatible endpoint.""" _bedrock_token_provider: AsyncBedrockTokenProvider | None + _uses_region_derived_base_url: bool aws_region: str | None def __init__( @@ -299,6 +320,7 @@ def __init__( ) self._bedrock_token_provider = bedrock_token_provider + self._uses_region_derived_base_url = _uses_region_derived_bedrock_base_url(base_url) self.aws_region = aws_region super().__init__( @@ -391,10 +413,17 @@ def copy( elif set_default_query is not None: params = set_default_query - next_token_provider = ( - bedrock_token_provider if bedrock_token_provider is not None else self._bedrock_token_provider - ) + if api_key is not None: + next_token_provider = None + elif bedrock_token_provider is not None: + next_token_provider = bedrock_token_provider + else: + next_token_provider = self._bedrock_token_provider + next_api_key = api_key if api_key is not None else (None if next_token_provider is not None else self.api_key) + next_base_url = base_url + if next_base_url is None and not (aws_region is not None and self._uses_region_derived_base_url): + next_base_url = self.base_url return self.__class__( api_key=next_api_key, @@ -404,7 +433,7 @@ def copy( project=project if project is not None else self.project, webhook_secret=webhook_secret if webhook_secret is not None else self.webhook_secret, websocket_base_url=websocket_base_url if websocket_base_url is not None else self.websocket_base_url, - base_url=base_url if base_url is not None else self.base_url, + base_url=next_base_url, timeout=self.timeout if isinstance(timeout, NotGiven) else timeout, http_client=http_client or self._client, max_retries=max_retries if is_given(max_retries) else self.max_retries, diff --git a/tests/lib/test_bedrock.py b/tests/lib/test_bedrock.py index 9995e4c431..dab9abd1cf 100644 --- a/tests/lib/test_bedrock.py +++ b/tests/lib/test_bedrock.py @@ -252,6 +252,55 @@ def test_preserves_token_provider_across_with_options() -> None: assert copied_client._refresh_api_key() == "provider token" +@pytest.mark.parametrize("client_cls", [BedrockOpenAI, AsyncBedrockOpenAI]) +def test_with_options_api_key_replaces_token_provider(client_cls: type[Client]) -> None: + client = ( + make_sync_client( + base_url="https://example.com/openai/v1", + bedrock_token_provider=lambda: "provider token", + ) + if client_cls is BedrockOpenAI + else make_async_client( + base_url="https://example.com/openai/v1", + bedrock_token_provider=lambda: "provider token", + ) + ) + + copied_client = client.with_options(api_key="static token") + + assert copied_client.api_key == "static token" + assert copied_client._bedrock_token_provider is None + + +@pytest.mark.parametrize("client_cls", [BedrockOpenAI, AsyncBedrockOpenAI]) +def test_with_options_aws_region_recomputes_region_derived_base_url(client_cls: type[Client]) -> None: + with update_env(AWS_BEDROCK_BASE_URL=Omit(), AWS_REGION=Omit(), AWS_DEFAULT_REGION=Omit()): + client = ( + make_sync_client(aws_region="us-east-1", api_key="token") + if client_cls is BedrockOpenAI + else make_async_client(aws_region="us-east-1", api_key="token") + ) + + copied_client = client.with_options(aws_region="eu-west-1") + + assert copied_client.aws_region == "eu-west-1" + assert copied_client.base_url == URL("https://bedrock-mantle.eu-west-1.api.aws/openai/v1/") + + +@pytest.mark.parametrize("client_cls", [BedrockOpenAI, AsyncBedrockOpenAI]) +def test_with_options_aws_region_keeps_explicit_base_url(client_cls: type[Client]) -> None: + client = ( + make_sync_client(base_url="https://example.com/openai/v1", aws_region="us-east-1", api_key="token") + if client_cls is BedrockOpenAI + else make_async_client(base_url="https://example.com/openai/v1", aws_region="us-east-1", api_key="token") + ) + + copied_client = client.with_options(aws_region="eu-west-1") + + assert copied_client.aws_region == "eu-west-1" + assert copied_client.base_url == URL("https://example.com/openai/v1/") + + @pytest.mark.parametrize( "copy_kwargs", [ From 4d5bfdec37fa8a2b2a0413724755e586e627e28d Mon Sep 17 00:00:00 2001 From: Alex Chang Date: Mon, 1 Jun 2026 17:39:17 -0400 Subject: [PATCH 763/769] fix(api): allow setting bedrock api keys on the client directly --- src/openai/__init__.py | 2 +- tests/test_module_client.py | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/openai/__init__.py b/src/openai/__init__.py index 8d4265970e..3786d106cb 100644 --- a/src/openai/__init__.py +++ b/src/openai/__init__.py @@ -305,7 +305,7 @@ class _BedrockModuleClient(_ModuleClient, BedrockOpenAI): # type: ignore @property # type: ignore @override def api_key(self) -> str | None: - return _bedrock_api_key if _bedrock_api_key is not None else api_key + return api_key if api_key is not None else _bedrock_api_key @api_key.setter # type: ignore def api_key(self, value: str | None) -> None: # type: ignore diff --git a/tests/test_module_client.py b/tests/test_module_client.py index 7889d4b41e..23bcb61716 100644 --- a/tests/test_module_client.py +++ b/tests/test_module_client.py @@ -238,6 +238,21 @@ def test_bedrock_api_type_uses_explicit_module_api_key() -> None: assert openai.api_key == "explicit Bedrock token" +def test_bedrock_module_api_key_overrides_cached_env_token_after_load() -> None: + with fresh_env(): + openai.api_type = "amazon-bedrock" + _os.environ["AWS_BEARER_TOKEN_BEDROCK"] = "env Bedrock token" + _os.environ["AWS_REGION"] = "us-west-2" + + client = openai.responses._client + assert isinstance(client, BedrockOpenAI) + assert client.api_key == "env Bedrock token" + + openai.api_key = "new Bedrock token" + + assert client.api_key == "new Bedrock token" + + def test_bedrock_api_type_uses_token_provider_without_mutating_module_api_key() -> None: with fresh_env(): openai.api_type = "amazon-bedrock" From 2264f700dad91e4f570eb7c0a6f10bbd22d34520 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 1 Jun 2026 21:40:16 +0000 Subject: [PATCH 764/769] release: 2.40.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 9f6026f1c7..69efe8f538 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.39.0" + ".": "2.40.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 13992c0e52..0517344e33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 2.40.0 (2026-06-01) + +Full Changelog: [v2.39.0...v2.40.0](https://github.com/openai/openai-python/compare/v2.39.0...v2.40.0) + +### Bug Fixes + +* **api:** allow setting bedrock api keys on the client directly ([4d5bfde](https://github.com/openai/openai-python/commit/4d5bfdec37fa8a2b2a0413724755e586e627e28d)) + ## 2.39.0 (2026-06-01) Full Changelog: [v2.38.0...v2.39.0](https://github.com/openai/openai-python/compare/v2.38.0...v2.39.0) diff --git a/pyproject.toml b/pyproject.toml index 39c6b5174d..37cd1a8db1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.39.0" +version = "2.40.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 8f492efa5d..7db77fcfff 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__ = "2.39.0" # x-release-please-version +__version__ = "2.40.0" # x-release-please-version From db6ccafa7b74b72caefbda6fb63bd5c904521770 Mon Sep 17 00:00:00 2001 From: Alex Chang Date: Mon, 1 Jun 2026 17:41:39 -0400 Subject: [PATCH 765/769] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0517344e33..5d1dc4baba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ Full Changelog: [v2.39.0...v2.40.0](https://github.com/openai/openai-python/compare/v2.39.0...v2.40.0) +### Features +* **api:** Add Amazon Bedrock Responses support + ### Bug Fixes * **api:** allow setting bedrock api keys on the client directly ([4d5bfde](https://github.com/openai/openai-python/commit/4d5bfdec37fa8a2b2a0413724755e586e627e28d)) From 87e46c25ac9ca8cff407b52ad9fb33e326c059d6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 3 Jun 2026 22:32:39 +0000 Subject: [PATCH 766/769] feat(api): responses.moderation and chat_completions.moderation --- .stats.yml | 4 +- src/openai/auth/_workload.py | 1 + .../resources/chat/completions/completions.py | 30 ++++ src/openai/resources/responses/responses.py | 38 +++++ src/openai/types/chat/chat_completion.py | 160 +++++++++++++++++- .../types/chat/chat_completion_chunk.py | 152 ++++++++++++++++- .../types/chat/completion_create_params.py | 14 ++ src/openai/types/responses/response.py | 129 +++++++++++++- .../types/responses/response_create_params.py | 14 ++ .../types/responses/responses_client_event.py | 15 +- .../responses/responses_client_event_param.py | 22 ++- tests/api_resources/chat/test_completions.py | 4 + tests/api_resources/test_responses.py | 4 + tests/lib/chat/test_completions.py | 6 + tests/lib/chat/test_completions_streaming.py | 1 + 15 files changed, 581 insertions(+), 13 deletions(-) diff --git a/.stats.yml b/.stats.yml index 7345dd30b5..a62e7b979c 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 262 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-a6fedde02dc6241719ebb2589062ba2892baa8dbe928a2d718643beede85e7b3.yml -openapi_spec_hash: a712e4ee68f829570b3f5b267afa5a05 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-0161cb2a0faadedfc17ff59c7fcad9671962dbd170f83811003c23702148cf36.yml +openapi_spec_hash: 1023c7442d0e2e7e213e8b3a253921c5 config_hash: e02ca1082421dfe55b145c45e95d6126 diff --git a/src/openai/auth/_workload.py b/src/openai/auth/_workload.py index 6c142a82ed..6b13ededb2 100644 --- a/src/openai/auth/_workload.py +++ b/src/openai/auth/_workload.py @@ -28,6 +28,7 @@ class SubjectTokenProvider(TypedDict): class WorkloadIdentity(TypedDict): """Identity provider resource id in WIFAPI.""" + identity_provider_id: str """Service account id to bind the verified external identity to.""" diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index 9a2973c2a9..835adfde1c 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -104,6 +104,7 @@ def parse( max_tokens: Optional[int] | Omit = omit, metadata: Optional[Metadata] | Omit = omit, modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, + moderation: Optional[completion_create_params.Moderation] | Omit = omit, n: Optional[int] | Omit = omit, parallel_tool_calls: bool | Omit = omit, prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, @@ -204,6 +205,7 @@ def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseForma "max_tokens": max_tokens, "metadata": metadata, "modalities": modalities, + "moderation": moderation, "n": n, "parallel_tool_calls": parallel_tool_calls, "prediction": prediction, @@ -260,6 +262,7 @@ def create( max_tokens: Optional[int] | Omit = omit, metadata: Optional[Metadata] | Omit = omit, modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, + moderation: Optional[completion_create_params.Moderation] | Omit = omit, n: Optional[int] | Omit = omit, parallel_tool_calls: bool | Omit = omit, prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, @@ -396,6 +399,8 @@ def create( `["text", "audio"]` + moderation: Configuration for running moderation on the request input and generated output. + n: How many chat completion choices to generate for each input message. Note that you will be charged based on the number of generated tokens across all of the choices. Keep `n` as `1` to minimize costs. @@ -576,6 +581,7 @@ def create( max_tokens: Optional[int] | Omit = omit, metadata: Optional[Metadata] | Omit = omit, modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, + moderation: Optional[completion_create_params.Moderation] | Omit = omit, n: Optional[int] | Omit = omit, parallel_tool_calls: bool | Omit = omit, prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, @@ -720,6 +726,8 @@ def create( `["text", "audio"]` + moderation: Configuration for running moderation on the request input and generated output. + n: How many chat completion choices to generate for each input message. Note that you will be charged based on the number of generated tokens across all of the choices. Keep `n` as `1` to minimize costs. @@ -891,6 +899,7 @@ def create( max_tokens: Optional[int] | Omit = omit, metadata: Optional[Metadata] | Omit = omit, modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, + moderation: Optional[completion_create_params.Moderation] | Omit = omit, n: Optional[int] | Omit = omit, parallel_tool_calls: bool | Omit = omit, prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, @@ -1035,6 +1044,8 @@ def create( `["text", "audio"]` + moderation: Configuration for running moderation on the request input and generated output. + n: How many chat completion choices to generate for each input message. Note that you will be charged based on the number of generated tokens across all of the choices. Keep `n` as `1` to minimize costs. @@ -1205,6 +1216,7 @@ def create( max_tokens: Optional[int] | Omit = omit, metadata: Optional[Metadata] | Omit = omit, modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, + moderation: Optional[completion_create_params.Moderation] | Omit = omit, n: Optional[int] | Omit = omit, parallel_tool_calls: bool | Omit = omit, prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, @@ -1252,6 +1264,7 @@ def create( "max_tokens": max_tokens, "metadata": metadata, "modalities": modalities, + "moderation": moderation, "n": n, "parallel_tool_calls": parallel_tool_calls, "prediction": prediction, @@ -1501,6 +1514,7 @@ def stream( max_tokens: Optional[int] | Omit = omit, metadata: Optional[Metadata] | Omit = omit, modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, + moderation: Optional[completion_create_params.Moderation] | Omit = omit, n: Optional[int] | Omit = omit, parallel_tool_calls: bool | Omit = omit, prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, @@ -1572,6 +1586,7 @@ def stream( max_tokens=max_tokens, metadata=metadata, modalities=modalities, + moderation=moderation, n=n, parallel_tool_calls=parallel_tool_calls, prediction=prediction, @@ -1652,6 +1667,7 @@ async def parse( max_tokens: Optional[int] | Omit = omit, metadata: Optional[Metadata] | Omit = omit, modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, + moderation: Optional[completion_create_params.Moderation] | Omit = omit, n: Optional[int] | Omit = omit, parallel_tool_calls: bool | Omit = omit, prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, @@ -1752,6 +1768,7 @@ def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseForma "max_tokens": max_tokens, "metadata": metadata, "modalities": modalities, + "moderation": moderation, "n": n, "parallel_tool_calls": parallel_tool_calls, "prediction": prediction, @@ -1808,6 +1825,7 @@ async def create( max_tokens: Optional[int] | Omit = omit, metadata: Optional[Metadata] | Omit = omit, modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, + moderation: Optional[completion_create_params.Moderation] | Omit = omit, n: Optional[int] | Omit = omit, parallel_tool_calls: bool | Omit = omit, prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, @@ -1944,6 +1962,8 @@ async def create( `["text", "audio"]` + moderation: Configuration for running moderation on the request input and generated output. + n: How many chat completion choices to generate for each input message. Note that you will be charged based on the number of generated tokens across all of the choices. Keep `n` as `1` to minimize costs. @@ -2124,6 +2144,7 @@ async def create( max_tokens: Optional[int] | Omit = omit, metadata: Optional[Metadata] | Omit = omit, modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, + moderation: Optional[completion_create_params.Moderation] | Omit = omit, n: Optional[int] | Omit = omit, parallel_tool_calls: bool | Omit = omit, prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, @@ -2268,6 +2289,8 @@ async def create( `["text", "audio"]` + moderation: Configuration for running moderation on the request input and generated output. + n: How many chat completion choices to generate for each input message. Note that you will be charged based on the number of generated tokens across all of the choices. Keep `n` as `1` to minimize costs. @@ -2439,6 +2462,7 @@ async def create( max_tokens: Optional[int] | Omit = omit, metadata: Optional[Metadata] | Omit = omit, modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, + moderation: Optional[completion_create_params.Moderation] | Omit = omit, n: Optional[int] | Omit = omit, parallel_tool_calls: bool | Omit = omit, prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, @@ -2583,6 +2607,8 @@ async def create( `["text", "audio"]` + moderation: Configuration for running moderation on the request input and generated output. + n: How many chat completion choices to generate for each input message. Note that you will be charged based on the number of generated tokens across all of the choices. Keep `n` as `1` to minimize costs. @@ -2753,6 +2779,7 @@ async def create( max_tokens: Optional[int] | Omit = omit, metadata: Optional[Metadata] | Omit = omit, modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, + moderation: Optional[completion_create_params.Moderation] | Omit = omit, n: Optional[int] | Omit = omit, parallel_tool_calls: bool | Omit = omit, prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, @@ -2800,6 +2827,7 @@ async def create( "max_tokens": max_tokens, "metadata": metadata, "modalities": modalities, + "moderation": moderation, "n": n, "parallel_tool_calls": parallel_tool_calls, "prediction": prediction, @@ -3049,6 +3077,7 @@ def stream( max_tokens: Optional[int] | Omit = omit, metadata: Optional[Metadata] | Omit = omit, modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, + moderation: Optional[completion_create_params.Moderation] | Omit = omit, n: Optional[int] | Omit = omit, parallel_tool_calls: bool | Omit = omit, prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, @@ -3121,6 +3150,7 @@ def stream( max_tokens=max_tokens, metadata=metadata, modalities=modalities, + moderation=moderation, n=n, parallel_tool_calls=parallel_tool_calls, prediction=prediction, diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 9caadacd66..5019d7e831 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -142,6 +142,7 @@ def create( max_tool_calls: Optional[int] | Omit = omit, metadata: Optional[Metadata] | Omit = omit, model: ResponsesModel | Omit = omit, + moderation: Optional[response_create_params.Moderation] | Omit = omit, parallel_tool_calls: Optional[bool] | Omit = omit, previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, @@ -250,6 +251,8 @@ def create( [model guide](https://platform.openai.com/docs/models) to browse and compare available models. + moderation: Configuration for running moderation on the input and output of this response. + parallel_tool_calls: Whether to allow the model to run tool calls in parallel. previous_response_id: The unique ID of the previous response to the model. Use this to create @@ -401,6 +404,7 @@ def create( max_tool_calls: Optional[int] | Omit = omit, metadata: Optional[Metadata] | Omit = omit, model: ResponsesModel | Omit = omit, + moderation: Optional[response_create_params.Moderation] | Omit = omit, parallel_tool_calls: Optional[bool] | Omit = omit, previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, @@ -515,6 +519,8 @@ def create( [model guide](https://platform.openai.com/docs/models) to browse and compare available models. + moderation: Configuration for running moderation on the input and output of this response. + parallel_tool_calls: Whether to allow the model to run tool calls in parallel. previous_response_id: The unique ID of the previous response to the model. Use this to create @@ -659,6 +665,7 @@ def create( max_tool_calls: Optional[int] | Omit = omit, metadata: Optional[Metadata] | Omit = omit, model: ResponsesModel | Omit = omit, + moderation: Optional[response_create_params.Moderation] | Omit = omit, parallel_tool_calls: Optional[bool] | Omit = omit, previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, @@ -773,6 +780,8 @@ def create( [model guide](https://platform.openai.com/docs/models) to browse and compare available models. + moderation: Configuration for running moderation on the input and output of this response. + parallel_tool_calls: Whether to allow the model to run tool calls in parallel. previous_response_id: The unique ID of the previous response to the model. Use this to create @@ -915,6 +924,7 @@ def create( max_tool_calls: Optional[int] | Omit = omit, metadata: Optional[Metadata] | Omit = omit, model: ResponsesModel | Omit = omit, + moderation: Optional[response_create_params.Moderation] | Omit = omit, parallel_tool_calls: Optional[bool] | Omit = omit, previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, @@ -955,6 +965,7 @@ def create( "max_tool_calls": max_tool_calls, "metadata": metadata, "model": model, + "moderation": moderation, "parallel_tool_calls": parallel_tool_calls, "previous_response_id": previous_response_id, "prompt": prompt, @@ -1023,6 +1034,7 @@ def stream( max_tool_calls: Optional[int] | Omit = omit, metadata: Optional[Metadata] | Omit = omit, parallel_tool_calls: Optional[bool] | Omit = omit, + moderation: Optional[response_create_params.Moderation] | Omit = omit, previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, prompt_cache_key: str | Omit = omit, @@ -1064,6 +1076,7 @@ def stream( max_tool_calls: Optional[int] | Omit = omit, metadata: Optional[Metadata] | Omit = omit, parallel_tool_calls: Optional[bool] | Omit = omit, + moderation: Optional[response_create_params.Moderation] | Omit = omit, previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, prompt_cache_key: str | Omit = omit, @@ -1098,6 +1111,7 @@ def stream( "max_output_tokens": max_output_tokens, "max_tool_calls": max_tool_calls, "metadata": metadata, + "moderation": moderation, "parallel_tool_calls": parallel_tool_calls, "previous_response_id": previous_response_id, "prompt": prompt, @@ -1154,6 +1168,7 @@ def stream( max_output_tokens=max_output_tokens, max_tool_calls=max_tool_calls, metadata=metadata, + moderation=moderation, parallel_tool_calls=parallel_tool_calls, previous_response_id=previous_response_id, prompt=prompt, @@ -1214,6 +1229,7 @@ def parse( max_tool_calls: Optional[int] | Omit = omit, metadata: Optional[Metadata] | Omit = omit, model: ResponsesModel | Omit = omit, + moderation: Optional[response_create_params.Moderation] | Omit = omit, parallel_tool_calls: Optional[bool] | Omit = omit, previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, @@ -1273,6 +1289,7 @@ def parser(raw_response: Response) -> ParsedResponse[TextFormatT]: "max_tool_calls": max_tool_calls, "metadata": metadata, "model": model, + "moderation": moderation, "parallel_tool_calls": parallel_tool_calls, "previous_response_id": previous_response_id, "prompt": prompt, @@ -1872,6 +1889,7 @@ async def create( max_tool_calls: Optional[int] | Omit = omit, metadata: Optional[Metadata] | Omit = omit, model: ResponsesModel | Omit = omit, + moderation: Optional[response_create_params.Moderation] | Omit = omit, parallel_tool_calls: Optional[bool] | Omit = omit, previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, @@ -1980,6 +1998,8 @@ async def create( [model guide](https://platform.openai.com/docs/models) to browse and compare available models. + moderation: Configuration for running moderation on the input and output of this response. + parallel_tool_calls: Whether to allow the model to run tool calls in parallel. previous_response_id: The unique ID of the previous response to the model. Use this to create @@ -2131,6 +2151,7 @@ async def create( max_tool_calls: Optional[int] | Omit = omit, metadata: Optional[Metadata] | Omit = omit, model: ResponsesModel | Omit = omit, + moderation: Optional[response_create_params.Moderation] | Omit = omit, parallel_tool_calls: Optional[bool] | Omit = omit, previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, @@ -2245,6 +2266,8 @@ async def create( [model guide](https://platform.openai.com/docs/models) to browse and compare available models. + moderation: Configuration for running moderation on the input and output of this response. + parallel_tool_calls: Whether to allow the model to run tool calls in parallel. previous_response_id: The unique ID of the previous response to the model. Use this to create @@ -2389,6 +2412,7 @@ async def create( max_tool_calls: Optional[int] | Omit = omit, metadata: Optional[Metadata] | Omit = omit, model: ResponsesModel | Omit = omit, + moderation: Optional[response_create_params.Moderation] | Omit = omit, parallel_tool_calls: Optional[bool] | Omit = omit, previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, @@ -2503,6 +2527,8 @@ async def create( [model guide](https://platform.openai.com/docs/models) to browse and compare available models. + moderation: Configuration for running moderation on the input and output of this response. + parallel_tool_calls: Whether to allow the model to run tool calls in parallel. previous_response_id: The unique ID of the previous response to the model. Use this to create @@ -2645,6 +2671,7 @@ async def create( max_tool_calls: Optional[int] | Omit = omit, metadata: Optional[Metadata] | Omit = omit, model: ResponsesModel | Omit = omit, + moderation: Optional[response_create_params.Moderation] | Omit = omit, parallel_tool_calls: Optional[bool] | Omit = omit, previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, @@ -2685,6 +2712,7 @@ async def create( "max_tool_calls": max_tool_calls, "metadata": metadata, "model": model, + "moderation": moderation, "parallel_tool_calls": parallel_tool_calls, "previous_response_id": previous_response_id, "prompt": prompt, @@ -2753,6 +2781,7 @@ def stream( max_tool_calls: Optional[int] | Omit = omit, metadata: Optional[Metadata] | Omit = omit, parallel_tool_calls: Optional[bool] | Omit = omit, + moderation: Optional[response_create_params.Moderation] | Omit = omit, previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, prompt_cache_key: str | Omit = omit, @@ -2794,6 +2823,7 @@ def stream( max_tool_calls: Optional[int] | Omit = omit, metadata: Optional[Metadata] | Omit = omit, parallel_tool_calls: Optional[bool] | Omit = omit, + moderation: Optional[response_create_params.Moderation] | Omit = omit, previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, prompt_cache_key: str | Omit = omit, @@ -2828,6 +2858,7 @@ def stream( "max_output_tokens": max_output_tokens, "max_tool_calls": max_tool_calls, "metadata": metadata, + "moderation": moderation, "parallel_tool_calls": parallel_tool_calls, "previous_response_id": previous_response_id, "prompt": prompt, @@ -2884,6 +2915,7 @@ def stream( max_output_tokens=max_output_tokens, max_tool_calls=max_tool_calls, metadata=metadata, + moderation=moderation, parallel_tool_calls=parallel_tool_calls, previous_response_id=previous_response_id, prompt=prompt, @@ -2948,6 +2980,7 @@ async def parse( max_tool_calls: Optional[int] | Omit = omit, metadata: Optional[Metadata] | Omit = omit, model: ResponsesModel | Omit = omit, + moderation: Optional[response_create_params.Moderation] | Omit = omit, parallel_tool_calls: Optional[bool] | Omit = omit, previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, @@ -3007,6 +3040,7 @@ def parser(raw_response: Response) -> ParsedResponse[TextFormatT]: "max_tool_calls": max_tool_calls, "metadata": metadata, "model": model, + "moderation": moderation, "parallel_tool_calls": parallel_tool_calls, "previous_response_id": previous_response_id, "prompt": prompt, @@ -4645,6 +4679,7 @@ def create( max_tool_calls: Optional[int] | Omit = omit, metadata: Optional[Metadata] | Omit = omit, model: ResponsesModel | Omit = omit, + moderation: Optional[responses_client_event_param.Moderation] | Omit = omit, parallel_tool_calls: Optional[bool] | Omit = omit, previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, @@ -4681,6 +4716,7 @@ def create( "max_tool_calls": max_tool_calls, "metadata": metadata, "model": model, + "moderation": moderation, "parallel_tool_calls": parallel_tool_calls, "previous_response_id": previous_response_id, "prompt": prompt, @@ -4725,6 +4761,7 @@ async def create( max_tool_calls: Optional[int] | Omit = omit, metadata: Optional[Metadata] | Omit = omit, model: ResponsesModel | Omit = omit, + moderation: Optional[responses_client_event_param.Moderation] | Omit = omit, parallel_tool_calls: Optional[bool] | Omit = omit, previous_response_id: Optional[str] | Omit = omit, prompt: Optional[ResponsePromptParam] | Omit = omit, @@ -4761,6 +4798,7 @@ async def create( "max_tool_calls": max_tool_calls, "metadata": metadata, "model": model, + "moderation": moderation, "parallel_tool_calls": parallel_tool_calls, "previous_response_id": previous_response_id, "prompt": prompt, diff --git a/src/openai/types/chat/chat_completion.py b/src/openai/types/chat/chat_completion.py index 31219aa812..2c4a78cd35 100644 --- a/src/openai/types/chat/chat_completion.py +++ b/src/openai/types/chat/chat_completion.py @@ -1,14 +1,28 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Optional -from typing_extensions import Literal +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias +from ..._utils import PropertyInfo from ..._models import BaseModel from ..completion_usage import CompletionUsage from .chat_completion_message import ChatCompletionMessage from .chat_completion_token_logprob import ChatCompletionTokenLogprob -__all__ = ["ChatCompletion", "Choice", "ChoiceLogprobs"] +__all__ = [ + "ChatCompletion", + "Choice", + "ChoiceLogprobs", + "Moderation", + "ModerationInput", + "ModerationInputModerationResults", + "ModerationInputModerationResultsResult", + "ModerationInputError", + "ModerationOutput", + "ModerationOutputModerationResults", + "ModerationOutputModerationResultsResult", + "ModerationOutputError", +] class ChoiceLogprobs(BaseModel): @@ -29,7 +43,8 @@ class Choice(BaseModel): sequence, `length` if the maximum number of tokens specified in the request was reached, `content_filter` if content was omitted due to a flag from our content filters, `tool_calls` if the model called a tool, or `function_call` - (deprecated) if the model called a function. + (deprecated) if the model called a function. Read the + [Model Spec](https://model-spec.openai.com/2025-12-18.html) for more. """ index: int @@ -42,6 +57,137 @@ class Choice(BaseModel): """A chat completion message generated by the model.""" +class ModerationInputModerationResultsResult(BaseModel): + """A moderation result produced for the response input or output.""" + + categories: Dict[str, bool] + """ + A dictionary of moderation categories to booleans, True if the input is flagged + under this category. + """ + + category_applied_input_types: Dict[str, List[Literal["text", "image"]]] + """Which modalities of input are reflected by the score for each category.""" + + category_scores: Dict[str, float] + """A dictionary of moderation categories to scores.""" + + flagged: bool + """A boolean indicating whether the content was flagged by any category.""" + + model: str + """The moderation model that produced this result.""" + + type: Literal["moderation_result"] + """ + The object type, which was always `moderation_result` for successful moderation + results. + """ + + +class ModerationInputModerationResults(BaseModel): + """Successful moderation results for the request input or generated output.""" + + model: str + """The moderation model used to generate the results.""" + + results: List[ModerationInputModerationResultsResult] + """A list of moderation results.""" + + type: Literal["moderation_results"] + """The object type, which is always `moderation_results`.""" + + +class ModerationInputError(BaseModel): + """An error produced while attempting moderation.""" + + code: str + """The error code.""" + + message: str + """The error message.""" + + type: Literal["error"] + """The object type, which is always `error`.""" + + +ModerationInput: TypeAlias = Annotated[ + Union[ModerationInputModerationResults, ModerationInputError], PropertyInfo(discriminator="type") +] + + +class ModerationOutputModerationResultsResult(BaseModel): + """A moderation result produced for the response input or output.""" + + categories: Dict[str, bool] + """ + A dictionary of moderation categories to booleans, True if the input is flagged + under this category. + """ + + category_applied_input_types: Dict[str, List[Literal["text", "image"]]] + """Which modalities of input are reflected by the score for each category.""" + + category_scores: Dict[str, float] + """A dictionary of moderation categories to scores.""" + + flagged: bool + """A boolean indicating whether the content was flagged by any category.""" + + model: str + """The moderation model that produced this result.""" + + type: Literal["moderation_result"] + """ + The object type, which was always `moderation_result` for successful moderation + results. + """ + + +class ModerationOutputModerationResults(BaseModel): + """Successful moderation results for the request input or generated output.""" + + model: str + """The moderation model used to generate the results.""" + + results: List[ModerationOutputModerationResultsResult] + """A list of moderation results.""" + + type: Literal["moderation_results"] + """The object type, which is always `moderation_results`.""" + + +class ModerationOutputError(BaseModel): + """An error produced while attempting moderation.""" + + code: str + """The error code.""" + + message: str + """The error message.""" + + type: Literal["error"] + """The object type, which is always `error`.""" + + +ModerationOutput: TypeAlias = Annotated[ + Union[ModerationOutputModerationResults, ModerationOutputError], PropertyInfo(discriminator="type") +] + + +class Moderation(BaseModel): + """ + Moderation results for the request input and generated output, if moderated + completions were requested. + """ + + input: ModerationInput + """Moderation for the request input.""" + + output: ModerationOutput + """Moderation for the generated output.""" + + class ChatCompletion(BaseModel): """ Represents a chat completion response returned by model, based on the provided input. @@ -65,6 +211,12 @@ class ChatCompletion(BaseModel): object: Literal["chat.completion"] """The object type, which is always `chat.completion`.""" + moderation: Optional[Moderation] = None + """ + Moderation results for the request input and generated output, if moderated + completions were requested. + """ + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] = None """Specifies the processing type used for serving the request. diff --git a/src/openai/types/chat/chat_completion_chunk.py b/src/openai/types/chat/chat_completion_chunk.py index ecbfd0a5aa..d983336fab 100644 --- a/src/openai/types/chat/chat_completion_chunk.py +++ b/src/openai/types/chat/chat_completion_chunk.py @@ -1,8 +1,9 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Optional -from typing_extensions import Literal +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias +from ..._utils import PropertyInfo from ..._models import BaseModel from ..completion_usage import CompletionUsage from .chat_completion_token_logprob import ChatCompletionTokenLogprob @@ -15,6 +16,15 @@ "ChoiceDeltaToolCall", "ChoiceDeltaToolCallFunction", "ChoiceLogprobs", + "Moderation", + "ModerationInput", + "ModerationInputModerationResults", + "ModerationInputModerationResultsResult", + "ModerationInputError", + "ModerationOutput", + "ModerationOutputModerationResults", + "ModerationOutputModerationResultsResult", + "ModerationOutputError", ] @@ -114,6 +124,138 @@ class Choice(BaseModel): """Log probability information for the choice.""" +class ModerationInputModerationResultsResult(BaseModel): + """A moderation result produced for the response input or output.""" + + categories: Dict[str, bool] + """ + A dictionary of moderation categories to booleans, True if the input is flagged + under this category. + """ + + category_applied_input_types: Dict[str, List[Literal["text", "image"]]] + """Which modalities of input are reflected by the score for each category.""" + + category_scores: Dict[str, float] + """A dictionary of moderation categories to scores.""" + + flagged: bool + """A boolean indicating whether the content was flagged by any category.""" + + model: str + """The moderation model that produced this result.""" + + type: Literal["moderation_result"] + """ + The object type, which was always `moderation_result` for successful moderation + results. + """ + + +class ModerationInputModerationResults(BaseModel): + """Successful moderation results for the request input or generated output.""" + + model: str + """The moderation model used to generate the results.""" + + results: List[ModerationInputModerationResultsResult] + """A list of moderation results.""" + + type: Literal["moderation_results"] + """The object type, which is always `moderation_results`.""" + + +class ModerationInputError(BaseModel): + """An error produced while attempting moderation.""" + + code: str + """The error code.""" + + message: str + """The error message.""" + + type: Literal["error"] + """The object type, which is always `error`.""" + + +ModerationInput: TypeAlias = Annotated[ + Union[ModerationInputModerationResults, ModerationInputError], PropertyInfo(discriminator="type") +] + + +class ModerationOutputModerationResultsResult(BaseModel): + """A moderation result produced for the response input or output.""" + + categories: Dict[str, bool] + """ + A dictionary of moderation categories to booleans, True if the input is flagged + under this category. + """ + + category_applied_input_types: Dict[str, List[Literal["text", "image"]]] + """Which modalities of input are reflected by the score for each category.""" + + category_scores: Dict[str, float] + """A dictionary of moderation categories to scores.""" + + flagged: bool + """A boolean indicating whether the content was flagged by any category.""" + + model: str + """The moderation model that produced this result.""" + + type: Literal["moderation_result"] + """ + The object type, which was always `moderation_result` for successful moderation + results. + """ + + +class ModerationOutputModerationResults(BaseModel): + """Successful moderation results for the request input or generated output.""" + + model: str + """The moderation model used to generate the results.""" + + results: List[ModerationOutputModerationResultsResult] + """A list of moderation results.""" + + type: Literal["moderation_results"] + """The object type, which is always `moderation_results`.""" + + +class ModerationOutputError(BaseModel): + """An error produced while attempting moderation.""" + + code: str + """The error code.""" + + message: str + """The error message.""" + + type: Literal["error"] + """The object type, which is always `error`.""" + + +ModerationOutput: TypeAlias = Annotated[ + Union[ModerationOutputModerationResults, ModerationOutputError], PropertyInfo(discriminator="type") +] + + +class Moderation(BaseModel): + """Moderation results for the request input and generated output. + + Present + on the moderation chunk when moderated completions are requested. + """ + + input: ModerationInput + """Moderation for the request input.""" + + output: ModerationOutput + """Moderation for the generated output.""" + + class ChatCompletionChunk(BaseModel): """ Represents a streamed chunk of a chat completion response returned @@ -143,6 +285,12 @@ class ChatCompletionChunk(BaseModel): object: Literal["chat.completion.chunk"] """The object type, which is always `chat.completion.chunk`.""" + moderation: Optional[Moderation] = None + """Moderation results for the request input and generated output. + + Present on the moderation chunk when moderated completions are requested. + """ + service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] = None """Specifies the processing type used for serving the request. diff --git a/src/openai/types/chat/completion_create_params.py b/src/openai/types/chat/completion_create_params.py index 5ec1a1ae91..b7de79be72 100644 --- a/src/openai/types/chat/completion_create_params.py +++ b/src/openai/types/chat/completion_create_params.py @@ -25,6 +25,7 @@ "CompletionCreateParamsBase", "FunctionCall", "Function", + "Moderation", "ResponseFormat", "WebSearchOptions", "WebSearchOptionsUserLocation", @@ -151,6 +152,9 @@ class CompletionCreateParamsBase(TypedDict, total=False): `["text", "audio"]` """ + moderation: Optional[Moderation] + """Configuration for running moderation on the request input and generated output.""" + n: Optional[int] """How many chat completion choices to generate for each input message. @@ -388,6 +392,16 @@ class Function(TypedDict, total=False): """ +class Moderation(TypedDict, total=False): + """Configuration for running moderation on the request input and generated output.""" + + model: Required[str] + """The moderation model to use for moderated completions, e.g. + + 'omni-moderation-latest'. + """ + + ResponseFormat: TypeAlias = Union[ResponseFormatText, ResponseFormatJSONSchema, ResponseFormatJSONObject] diff --git a/src/openai/types/responses/response.py b/src/openai/types/responses/response.py index bb4a4b3952..67102d2628 100644 --- a/src/openai/types/responses/response.py +++ b/src/openai/types/responses/response.py @@ -1,9 +1,10 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union, Optional -from typing_extensions import Literal, TypeAlias +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias from .tool import Tool +from ..._utils import PropertyInfo from ..._models import BaseModel from .response_error import ResponseError from .response_usage import ResponseUsage @@ -24,7 +25,19 @@ from ..shared.responses_model import ResponsesModel from .tool_choice_apply_patch import ToolChoiceApplyPatch -__all__ = ["Response", "IncompleteDetails", "ToolChoice", "Conversation"] +__all__ = [ + "Response", + "IncompleteDetails", + "ToolChoice", + "Conversation", + "Moderation", + "ModerationInput", + "ModerationInputModerationResult", + "ModerationInputError", + "ModerationOutput", + "ModerationOutputModerationResult", + "ModerationOutputError", +] class IncompleteDetails(BaseModel): @@ -56,6 +69,110 @@ class Conversation(BaseModel): """The unique ID of the conversation that this response was associated with.""" +class ModerationInputModerationResult(BaseModel): + """A moderation result produced for the response input or output.""" + + categories: Dict[str, bool] + """ + A dictionary of moderation categories to booleans, True if the input is flagged + under this category. + """ + + category_applied_input_types: Dict[str, List[Literal["text", "image"]]] + """Which modalities of input are reflected by the score for each category.""" + + category_scores: Dict[str, float] + """A dictionary of moderation categories to scores.""" + + flagged: bool + """A boolean indicating whether the content was flagged by any category.""" + + model: str + """The moderation model that produced this result.""" + + type: Literal["moderation_result"] + """ + The object type, which was always `moderation_result` for successful moderation + results. + """ + + +class ModerationInputError(BaseModel): + """An error produced while attempting moderation for the response input or output.""" + + code: str + """The error code.""" + + message: str + """The error message.""" + + type: Literal["error"] + """The object type, which was always `error` for moderation failures.""" + + +ModerationInput: TypeAlias = Annotated[ + Union[ModerationInputModerationResult, ModerationInputError], PropertyInfo(discriminator="type") +] + + +class ModerationOutputModerationResult(BaseModel): + """A moderation result produced for the response input or output.""" + + categories: Dict[str, bool] + """ + A dictionary of moderation categories to booleans, True if the input is flagged + under this category. + """ + + category_applied_input_types: Dict[str, List[Literal["text", "image"]]] + """Which modalities of input are reflected by the score for each category.""" + + category_scores: Dict[str, float] + """A dictionary of moderation categories to scores.""" + + flagged: bool + """A boolean indicating whether the content was flagged by any category.""" + + model: str + """The moderation model that produced this result.""" + + type: Literal["moderation_result"] + """ + The object type, which was always `moderation_result` for successful moderation + results. + """ + + +class ModerationOutputError(BaseModel): + """An error produced while attempting moderation for the response input or output.""" + + code: str + """The error code.""" + + message: str + """The error message.""" + + type: Literal["error"] + """The object type, which was always `error` for moderation failures.""" + + +ModerationOutput: TypeAlias = Annotated[ + Union[ModerationOutputModerationResult, ModerationOutputError], PropertyInfo(discriminator="type") +] + + +class Moderation(BaseModel): + """ + Moderation results for the response input and output, if moderated completions were requested. + """ + + input: ModerationInput + """Moderation for the response input.""" + + output: ModerationOutput + """Moderation for the response output.""" + + class Response(BaseModel): id: str """Unique identifier for this Response.""" @@ -193,6 +310,12 @@ class Response(BaseModel): ignored. """ + moderation: Optional[Moderation] = None + """ + Moderation results for the response input and output, if moderated completions + were requested. + """ + previous_response_id: Optional[str] = None """The unique ID of the previous response to the model. diff --git a/src/openai/types/responses/response_create_params.py b/src/openai/types/responses/response_create_params.py index b85ee87741..1b273928a1 100644 --- a/src/openai/types/responses/response_create_params.py +++ b/src/openai/types/responses/response_create_params.py @@ -27,6 +27,7 @@ "ResponseCreateParamsBase", "ContextManagement", "Conversation", + "Moderation", "StreamOptions", "ToolChoice", "ResponseCreateParamsNonStreaming", @@ -128,6 +129,9 @@ class ResponseCreateParamsBase(TypedDict, total=False): available models. """ + moderation: Optional[Moderation] + """Configuration for running moderation on the input and output of this response.""" + parallel_tool_calls: Optional[bool] """Whether to allow the model to run tool calls in parallel.""" @@ -304,6 +308,16 @@ class ContextManagement(TypedDict, total=False): Conversation: TypeAlias = Union[str, ResponseConversationParamParam] +class Moderation(TypedDict, total=False): + """Configuration for running moderation on the input and output of this response.""" + + model: Required[str] + """The moderation model to use for moderated completions, e.g. + + 'omni-moderation-latest'. + """ + + class StreamOptions(TypedDict, total=False): """Options for streaming responses. Only set this when you set `stream: true`.""" diff --git a/src/openai/types/responses/responses_client_event.py b/src/openai/types/responses/responses_client_event.py index 8f50848d9d..df33c019f1 100644 --- a/src/openai/types/responses/responses_client_event.py +++ b/src/openai/types/responses/responses_client_event.py @@ -22,7 +22,7 @@ from .tool_choice_apply_patch import ToolChoiceApplyPatch from .response_conversation_param import ResponseConversationParam -__all__ = ["ResponsesClientEvent", "ContextManagement", "Conversation", "StreamOptions", "ToolChoice"] +__all__ = ["ResponsesClientEvent", "ContextManagement", "Conversation", "Moderation", "StreamOptions", "ToolChoice"] class ContextManagement(BaseModel): @@ -36,6 +36,16 @@ class ContextManagement(BaseModel): Conversation: TypeAlias = Union[str, ResponseConversationParam, None] +class Moderation(BaseModel): + """Configuration for running moderation on the input and output of this response.""" + + model: str + """The moderation model to use for moderated completions, e.g. + + 'omni-moderation-latest'. + """ + + class StreamOptions(BaseModel): """Options for streaming responses. Only set this when you set `stream: true`.""" @@ -160,6 +170,9 @@ class ResponsesClientEvent(BaseModel): available models. """ + moderation: Optional[Moderation] = None + """Configuration for running moderation on the input and output of this response.""" + parallel_tool_calls: Optional[bool] = None """Whether to allow the model to run tool calls in parallel.""" diff --git a/src/openai/types/responses/responses_client_event_param.py b/src/openai/types/responses/responses_client_event_param.py index 632807aedf..55aeafc33d 100644 --- a/src/openai/types/responses/responses_client_event_param.py +++ b/src/openai/types/responses/responses_client_event_param.py @@ -23,7 +23,14 @@ from ..shared_params.responses_model import ResponsesModel from .response_conversation_param_param import ResponseConversationParamParam -__all__ = ["ResponsesClientEventParam", "ContextManagement", "Conversation", "StreamOptions", "ToolChoice"] +__all__ = [ + "ResponsesClientEventParam", + "ContextManagement", + "Conversation", + "Moderation", + "StreamOptions", + "ToolChoice", +] class ContextManagement(TypedDict, total=False): @@ -37,6 +44,16 @@ class ContextManagement(TypedDict, total=False): Conversation: TypeAlias = Union[str, ResponseConversationParamParam] +class Moderation(TypedDict, total=False): + """Configuration for running moderation on the input and output of this response.""" + + model: Required[str] + """The moderation model to use for moderated completions, e.g. + + 'omni-moderation-latest'. + """ + + class StreamOptions(TypedDict, total=False): """Options for streaming responses. Only set this when you set `stream: true`.""" @@ -161,6 +178,9 @@ class ResponsesClientEventParam(TypedDict, total=False): available models. """ + moderation: Optional[Moderation] + """Configuration for running moderation on the input and output of this response.""" + parallel_tool_calls: Optional[bool] """Whether to allow the model to run tool calls in parallel.""" diff --git a/tests/api_resources/chat/test_completions.py b/tests/api_resources/chat/test_completions.py index ea3066a505..3cba000ae6 100644 --- a/tests/api_resources/chat/test_completions.py +++ b/tests/api_resources/chat/test_completions.py @@ -65,6 +65,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: max_tokens=0, metadata={"foo": "string"}, modalities=["text"], + moderation={"model": "model"}, n=1, parallel_tool_calls=True, prediction={ @@ -199,6 +200,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: max_tokens=0, metadata={"foo": "string"}, modalities=["text"], + moderation={"model": "model"}, n=1, parallel_tool_calls=True, prediction={ @@ -508,6 +510,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn max_tokens=0, metadata={"foo": "string"}, modalities=["text"], + moderation={"model": "model"}, n=1, parallel_tool_calls=True, prediction={ @@ -642,6 +645,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn max_tokens=0, metadata={"foo": "string"}, modalities=["text"], + moderation={"model": "model"}, n=1, parallel_tool_calls=True, prediction={ diff --git a/tests/api_resources/test_responses.py b/tests/api_resources/test_responses.py index 094687c2c6..dc6083e78c 100644 --- a/tests/api_resources/test_responses.py +++ b/tests/api_resources/test_responses.py @@ -44,6 +44,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: max_tool_calls=0, metadata={"foo": "string"}, model="gpt-5.1", + moderation={"model": "model"}, parallel_tool_calls=True, previous_response_id="previous_response_id", prompt={ @@ -132,6 +133,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: max_tool_calls=0, metadata={"foo": "string"}, model="gpt-5.1", + moderation={"model": "model"}, parallel_tool_calls=True, previous_response_id="previous_response_id", prompt={ @@ -457,6 +459,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn max_tool_calls=0, metadata={"foo": "string"}, model="gpt-5.1", + moderation={"model": "model"}, parallel_tool_calls=True, previous_response_id="previous_response_id", prompt={ @@ -545,6 +548,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn max_tool_calls=0, metadata={"foo": "string"}, model="gpt-5.1", + moderation={"model": "model"}, parallel_tool_calls=True, previous_response_id="previous_response_id", prompt={ diff --git a/tests/lib/chat/test_completions.py b/tests/lib/chat/test_completions.py index 85bab4f095..741f5eaa75 100644 --- a/tests/lib/chat/test_completions.py +++ b/tests/lib/chat/test_completions.py @@ -72,6 +72,7 @@ def test_parse_nothing(client: OpenAI, respx_mock: MockRouter, monkeypatch: pyte created=1727346142, id='chatcmpl-ABfvaueLEMLNYbT8YzpJxsmiQ6HSY', model='gpt-4o-2024-08-06', + moderation=None, object='chat.completion', service_tier=None, system_fingerprint='fp_b40fb1c6fb', @@ -141,6 +142,7 @@ class Location(BaseModel): created=1727346143, id='chatcmpl-ABfvbtVnTu5DeC4EFnRYj8mtfOM99', model='gpt-4o-2024-08-06', + moderation=None, object='chat.completion', service_tier=None, system_fingerprint='fp_5050236cbd', @@ -212,6 +214,7 @@ class Location(BaseModel): created=1727346144, id='chatcmpl-ABfvcC8grKYsRkSoMp9CCAhbXAd0b', model='gpt-4o-2024-08-06', + moderation=None, object='chat.completion', service_tier=None, system_fingerprint='fp_b40fb1c6fb', @@ -418,6 +421,7 @@ class CalendarEvent: created=1727346158, id='chatcmpl-ABfvqhz4uUUWsw8Ohw2Mp9B4sKKV8', model='gpt-4o-2024-08-06', + moderation=None, object='chat.completion', service_tier=None, system_fingerprint='fp_7568d46099', @@ -887,6 +891,7 @@ class Location(BaseModel): created=1727389540, id='chatcmpl-ABrDYCa8W1w66eUxKDO8TQF1m6trT', model='gpt-4o-2024-08-06', + moderation=None, object='chat.completion', service_tier=None, system_fingerprint='fp_5050236cbd', @@ -964,6 +969,7 @@ class Location(BaseModel): created=1727389532, id='chatcmpl-ABrDQWOiw0PK5JOsxl1D9ooeQgznq', model='gpt-4o-2024-08-06', + moderation=None, object='chat.completion', service_tier=None, system_fingerprint='fp_5050236cbd', diff --git a/tests/lib/chat/test_completions_streaming.py b/tests/lib/chat/test_completions_streaming.py index eb3a0973ac..598a41ee2b 100644 --- a/tests/lib/chat/test_completions_streaming.py +++ b/tests/lib/chat/test_completions_streaming.py @@ -161,6 +161,7 @@ def on_event(stream: ChatCompletionStream[Location], event: ChatCompletionStream created=1727346169, id='chatcmpl-ABfw1e5abtU8OwGr15vOreYVb2MiF', model='gpt-4o-2024-08-06', + moderation=None, object='chat.completion', service_tier=None, system_fingerprint='fp_5050236cbd', From 519cd027919fa5b73bd8fe237e80c7a01b3e0b2f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 3 Jun 2026 22:33:34 +0000 Subject: [PATCH 767/769] release: 2.41.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 69efe8f538..29ad411bac 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.40.0" + ".": "2.41.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d1dc4baba..1a9e138e0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 2.41.0 (2026-06-03) + +Full Changelog: [v2.40.0...v2.41.0](https://github.com/openai/openai-python/compare/v2.40.0...v2.41.0) + +### Features + +* **api:** responses.moderation and chat_completions.moderation ([87e46c2](https://github.com/openai/openai-python/commit/87e46c25ac9ca8cff407b52ad9fb33e326c059d6)) + ## 2.40.0 (2026-06-01) Full Changelog: [v2.39.0...v2.40.0](https://github.com/openai/openai-python/compare/v2.39.0...v2.40.0) diff --git a/pyproject.toml b/pyproject.toml index 37cd1a8db1..d3a6a58a76 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.40.0" +version = "2.41.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 7db77fcfff..57fb9f9cca 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__ = "2.40.0" # x-release-please-version +__version__ = "2.41.0" # x-release-please-version From 2a91011abc21032db9566b98068afefb5fbb9b24 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Fri, 5 Jun 2026 08:50:28 -0700 Subject: [PATCH 768/769] build: Remove scheduled release workflow trigger (#3366) --- .github/workflows/create-releases.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/create-releases.yml b/.github/workflows/create-releases.yml index f39b4c3e2c..7c42b4d6a6 100644 --- a/.github/workflows/create-releases.yml +++ b/.github/workflows/create-releases.yml @@ -1,7 +1,5 @@ name: Create releases on: - schedule: - - cron: '0 5 * * *' # every day at 5am UTC push: branches: - main From 3842a5ea01e8ecb7d6b159b9236c0c60ceff5de3 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Fri, 5 Jun 2026 09:47:36 -0700 Subject: [PATCH 769/769] ci: use PyPI trusted publishing (#3365) --- .github/workflows/create-releases.yml | 55 ++++++++++++++++++++++++--- .github/workflows/publish-pypi.yml | 47 +++++++++++++++++++---- CONTRIBUTING.md | 5 +-- bin/publish-pypi | 6 --- 4 files changed, 91 insertions(+), 22 deletions(-) delete mode 100644 bin/publish-pypi diff --git a/.github/workflows/create-releases.yml b/.github/workflows/create-releases.yml index 7c42b4d6a6..9d65ef4e8e 100644 --- a/.github/workflows/create-releases.yml +++ b/.github/workflows/create-releases.yml @@ -10,6 +10,10 @@ jobs: if: github.ref == 'refs/heads/main' && github.repository == 'openai/openai-python' runs-on: ubuntu-latest environment: publish + outputs: + releases_created: ${{ steps.release.outputs.releases_created }} + permissions: + contents: read steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 @@ -20,16 +24,55 @@ jobs: repo: ${{ github.event.repository.full_name }} stainless-api-key: ${{ secrets.STAINLESS_API_KEY }} + build: + name: build + needs: release + if: ${{ needs.release.outputs.releases_created == 'true' }} + runs-on: ubuntu-latest + # Build distributions without OIDC access so package build code cannot mint + # a PyPI publishing token. The publish job handles only the upload. + permissions: + contents: read + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - name: Set up Rye - if: ${{ steps.release.outputs.releases_created }} uses: eifinger/setup-rye@c694239a43768373e87d0103d7f547027a23f3c8 with: version: '0.44.0' enable-cache: true - - name: Publish to PyPI - if: ${{ steps.release.outputs.releases_created }} + - name: Build package run: | - bash ./bin/publish-pypi - env: - PYPI_TOKEN: ${{ secrets.OPENAI_PYPI_TOKEN || secrets.PYPI_TOKEN }} + mkdir -p dist + rye build --clean + + - name: Upload package distributions + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: python-package-distributions + path: dist/ + if-no-files-found: error + retention-days: 1 + + publish: + name: publish + needs: build + runs-on: ubuntu-latest + environment: publish + # PyPI Trusted Publishing requires id-token: write. Keep it scoped to this + # minimal upload-only job rather than the build job. + permissions: + contents: read + id-token: write + + steps: + - name: Download package distributions + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: python-package-distributions + path: dist/ + + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0 diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml index a7c62c4c4d..d23cd66942 100644 --- a/.github/workflows/publish-pypi.yml +++ b/.github/workflows/publish-pypi.yml @@ -5,10 +5,14 @@ on: workflow_dispatch: jobs: - publish: - name: publish + build: + name: build + if: github.ref == 'refs/heads/main' && github.repository == 'openai/openai-python' runs-on: ubuntu-latest - environment: publish + # Build distributions without OIDC access so package build code cannot mint + # a PyPI publishing token. The publish job handles only the upload. + permissions: + contents: read steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 @@ -19,8 +23,37 @@ jobs: version: '0.44.0' enable-cache: true - - name: Publish to PyPI + - name: Build package run: | - bash ./bin/publish-pypi - env: - PYPI_TOKEN: ${{ secrets.OPENAI_PYPI_TOKEN || secrets.PYPI_TOKEN }} + mkdir -p dist + rye build --clean + + - name: Upload package distributions + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: python-package-distributions + path: dist/ + if-no-files-found: error + retention-days: 1 + + publish: + name: publish + needs: build + if: github.ref == 'refs/heads/main' && github.repository == 'openai/openai-python' + runs-on: ubuntu-latest + environment: publish + # PyPI Trusted Publishing requires id-token: write. Keep it scoped to this + # minimal upload-only job rather than the build job. + permissions: + contents: read + id-token: write + + steps: + - name: Download package distributions + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: python-package-distributions + path: dist/ + + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 253b9ce5e6..f92377d459 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -119,9 +119,8 @@ the changes aren't made through the automated pipeline, you may want to make rel ### Publish with a GitHub workflow -You can release to package managers by using [the `Publish PyPI` GitHub action](https://www.github.com/openai/openai-python/actions/workflows/publish-pypi.yml). This requires a setup organization or repository secret to be set up. +You can release to package managers by using [the `Publish PyPI` GitHub action](https://www.github.com/openai/openai-python/actions/workflows/publish-pypi.yml). PyPI publishing uses Trusted Publishing, so the PyPI project must trust this repository's GitHub Actions workflow and the `publish` environment. ### Publish manually -If you need to manually release a package, you can run the `bin/publish-pypi` script with a `PYPI_TOKEN` set on -the environment. +If you need to retry a PyPI release, use the `Publish PyPI` GitHub action. Local manual publishing is not the standard release path because the GitHub workflow uses OIDC instead of a long-lived PyPI token. diff --git a/bin/publish-pypi b/bin/publish-pypi deleted file mode 100644 index 826054e924..0000000000 --- a/bin/publish-pypi +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash - -set -eux -mkdir -p dist -rye build --clean -rye publish --yes --token=$PYPI_TOKEN